[U-Boot] [PATCH v2 1/9] mpc8xxx: Display RDIMM if detected

Print a message when a RDIMM is detected.
Signed-off-by: York Sun yorksun@freescale.com --- .../cpu/mpc8xxx/ddr/lc_common_dimm_params.c | 19 +++++++------------ 1 files changed, 7 insertions(+), 12 deletions(-)
diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/lc_common_dimm_params.c b/arch/powerpc/cpu/mpc8xxx/ddr/lc_common_dimm_params.c index 029e566..af0250d 100644 --- a/arch/powerpc/cpu/mpc8xxx/ddr/lc_common_dimm_params.c +++ b/arch/powerpc/cpu/mpc8xxx/ddr/lc_common_dimm_params.c @@ -98,7 +98,7 @@ compute_lowest_common_dimm_parameters(const dimm_params_t *dimm_params, unsigned int tDQSQ_max_ps = 0; unsigned int tQHS_ps = 0;
- unsigned int temp1, temp2, temp3; + unsigned int temp1, temp2; unsigned int additive_latency = 0; #if !defined(CONFIG_FSL_DDR3) const unsigned int mclk_ps = get_memory_clk_period_ps(); @@ -215,21 +215,16 @@ compute_lowest_common_dimm_parameters(const dimm_params_t *dimm_params, }
outpdimm->all_DIMMs_registered = 0; + outpdimm->all_DIMMs_unbuffered = 0; if (temp1 && !temp2) { outpdimm->all_DIMMs_registered = 1; - } - - outpdimm->all_DIMMs_unbuffered = 0; - if (!temp1 && temp2) { + printf("Detected RDIMM(s)\n"); + } else if (!temp1 && temp2) { outpdimm->all_DIMMs_unbuffered = 1; - } - - /* CHECKME: */ - if (!outpdimm->all_DIMMs_registered - && !outpdimm->all_DIMMs_unbuffered) { + printf("Detected UDIMM(s)\n"); + } else printf("ERROR: Mix of registered buffered and unbuffered " "DIMMs detected!\n"); - }
temp1 = 0; if (outpdimm->all_DIMMs_registered) @@ -237,7 +232,7 @@ compute_lowest_common_dimm_parameters(const dimm_params_t *dimm_params, outpdimm->rcw[j] = dimm_params[0].rcw[j]; for (i = 1; i < number_of_dimms; i++) if (dimm_params[i].rcw[j] != dimm_params[0].rcw[j]) { - temp3 = 1; + temp1 = 1; break; } }

To temporarily fix buffer issue when running at flash, use bigger buffer to push down the stack deeper.
Signed-off-by: York Sun yorksun@freescale.com --- common/hwconfig.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/common/hwconfig.c b/common/hwconfig.c index 3c9759f..1b33d95 100644 --- a/common/hwconfig.c +++ b/common/hwconfig.c @@ -71,7 +71,7 @@ next: const char *cpu_hwconfig __attribute__((weak)); const char *board_hwconfig __attribute__((weak));
-#define HWCONFIG_PRE_RELOC_BUF_SIZE 128 +#define HWCONFIG_PRE_RELOC_BUF_SIZE 256
static const char *__hwconfig(const char *opt, size_t *arglen) {

Dear York Sun,
In message 1292630381-23022-2-git-send-email-yorksun@freescale.com you wrote:
To temporarily fix buffer issue when running at flash, use bigger buffer to push down the stack deeper.
Signed-off-by: York Sun yorksun@freescale.com
Please explain 1) why this is needed and 2) what it has to do with running "at" (from?) flash?
hwconfig is intended for simple h/w configurations. In which case do you need more than 128 characters for such settings? And is this really needed / reasonable?
Best regards,
Wolfgang Denk

On Sat, 2010-12-18 at 16:25 -0600, Wolfgang Denk wrote:
Dear York Sun,
In message 1292630381-23022-2-git-send-email-yorksun@freescale.com you wrote:
To temporarily fix buffer issue when running at flash, use bigger buffer to push down the stack deeper.
Signed-off-by: York Sun yorksun@freescale.com
Please explain 1) why this is needed and 2) what it has to do with running "at" (from?) flash?
hwconfig is intended for simple h/w configurations. In which case do you need more than 128 characters for such settings? And is this really needed / reasonable?
First of all, I don't need more than 128 characters for hwconfig. I think the buggy code makes the buffer less usable.
If you look into the common/hwconfig.c, you will notice the _current_ code uses the stack as temporary memory to hold the variable. Even I don't agree with this way, I don't have a quick fix either. There may be two ways or more to fix it. One is to create wrapper functions to deal with pre-relocation and post-relocation functions. Another way is to allocate more space in gd. Which way do you think is better?
York

Dear York Sun,
In message 1294085287.24386.52.camel@oslab-l1 you wrote:
Please explain 1) why this is needed and 2) what it has to do with running "at" (from?) flash?
hwconfig is intended for simple h/w configurations. In which case do you need more than 128 characters for such settings? And is this really needed / reasonable?
First of all, I don't need more than 128 characters for hwconfig. I think the buggy code makes the buffer less usable.
Hm... I have no idea whish sort of "buggy code" you are referring to here, but in this case we shoul start and fix that buggy code, right?
If you look into the common/hwconfig.c, you will notice the _current_ code uses the stack as temporary memory to hold the variable. Even I don't agree with this way, I don't have a quick fix either. There may be
What's wrong with putting it on the stack? This prevents a permanent allocation, so the memory can easily be reused once that function returns.
two ways or more to fix it. One is to create wrapper functions to deal with pre-relocation and post-relocation functions. Another way is to allocate more space in gd. Which way do you think is better?
You fail to explain why we should change anything when you "don't need more than 128 characters for hwconfig" in the first place?
Best regards,
Wolfgang Denk

On Mon, 2011-01-03 at 22:11 +0100, Wolfgang Denk wrote:
Dear York Sun,
In message 1294085287.24386.52.camel@oslab-l1 you wrote:
Please explain 1) why this is needed and 2) what it has to do with running "at" (from?) flash?
hwconfig is intended for simple h/w configurations. In which case do you need more than 128 characters for such settings? And is this really needed / reasonable?
First of all, I don't need more than 128 characters for hwconfig. I think the buggy code makes the buffer less usable.
Hm... I have no idea whish sort of "buggy code" you are referring to here, but in this case we shoul start and fix that buggy code, right?
Making a buffer in a function's stack and make use of it out of the scope, that's the buggy code I am referring.
If you look into the common/hwconfig.c, you will notice the _current_ code uses the stack as temporary memory to hold the variable. Even I don't agree with this way, I don't have a quick fix either. There may be
What's wrong with putting it on the stack? This prevents a permanent allocation, so the memory can easily be reused once that function returns.
How can the content be guaranteed? The stack can be trashed when the function returns.
two ways or more to fix it. One is to create wrapper functions to deal with pre-relocation and post-relocation functions. Another way is to allocate more space in gd. Which way do you think is better?
You fail to explain why we should change anything when you "don't need more than 128 characters for hwconfig" in the first place?
I don't need more than 128 characters. However, the stack is trashed by other functions. I have to push the stack deeper to keep the content unchanged. I am not happy with it.
York

Dear York Sun,
In message 1294089991.24386.58.camel@oslab-l1 you wrote:
Hm... I have no idea whish sort of "buggy code" you are referring to here, but in this case we shoul start and fix that buggy code, right?
Making a buffer in a function's stack and make use of it out of the scope, that's the buggy code I am referring.
That is bad indeed, and needs to be fixed.
You fail to explain why we should change anything when you "don't need more than 128 characters for hwconfig" in the first place?
I don't need more than 128 characters. However, the stack is trashed by other functions. I have to push the stack deeper to keep the content unchanged. I am not happy with it.
Now I understand what you mean.
But we do not need a bigger buffer, or store another copy of the whole content of the "hwconfig" variable - we just need room to for the return value of hwconfig_parse(), which usually should be (much) smaller than the content of the "hwconfig" variable.
Best regards,
Wolfgang Denk

On Jan 3, 2011, at 3:47 PM, Wolfgang Denk wrote:
Dear York Sun,
In message 1294089991.24386.58.camel@oslab-l1 you wrote:
Hm... I have no idea whish sort of "buggy code" you are referring to here, but in this case we shoul start and fix that buggy code, right?
Making a buffer in a function's stack and make use of it out of the scope, that's the buggy code I am referring.
That is bad indeed, and needs to be fixed.
Where is that happening?
You fail to explain why we should change anything when you "don't need more than 128 characters for hwconfig" in the first place?
I don't need more than 128 characters. However, the stack is trashed by other functions. I have to push the stack deeper to keep the content unchanged. I am not happy with it.
Now I understand what you mean.
But we do not need a bigger buffer, or store another copy of the whole content of the "hwconfig" variable - we just need room to for the return value of hwconfig_parse(), which usually should be (much) smaller than the content of the "hwconfig" variable.
I agree with WD, I'm confused. Can you provide the hwconfig string you are using that has issues with 128 but works at 256.
- k

On Fri, 2011-01-07 at 09:14 -0600, Kumar Gala wrote:
On Jan 3, 2011, at 3:47 PM, Wolfgang Denk wrote:
Dear York Sun,
In message 1294089991.24386.58.camel@oslab-l1 you wrote:
Hm... I have no idea whish sort of "buggy code" you are referring to here, but in this case we shoul start and fix that buggy code, right?
Making a buffer in a function's stack and make use of it out of the scope, that's the buggy code I am referring.
That is bad indeed, and needs to be fixed.
Where is that happening?
You fail to explain why we should change anything when you "don't need more than 128 characters for hwconfig" in the first place?
I don't need more than 128 characters. However, the stack is trashed by other functions. I have to push the stack deeper to keep the content unchanged. I am not happy with it.
Now I understand what you mean.
But we do not need a bigger buffer, or store another copy of the whole content of the "hwconfig" variable - we just need room to for the return value of hwconfig_parse(), which usually should be (much) smaller than the content of the "hwconfig" variable.
I agree with WD, I'm confused. Can you provide the hwconfig string you are using that has issues with 128 but works at 256.
- k
fsl_ddr:ctlr_intlv=cacheline,bank_intlv=cs0_cs1_cs2_cs3,ecc=off,addr_hash=false
With the buffer size 128, the sub function gets "ctlr_intlv=cacheline,bank_intlv=cs0_". It is not because the buffer is not enough, but the stack has been trashed. I have debug log if you need it.
York

Dear York Sun,
In message 1294418957.8466.8.camel@oslab-l1 you wrote:
fsl_ddr:ctlr_intlv=cacheline,bank_intlv=cs0_cs1_cs2_cs3,ecc=off,addr_hash=false
With the buffer size 128, the sub function gets "ctlr_intlv=cacheline,bank_intlv=cs0_". It is not because the buffer is not enough, but the stack has been trashed. I have debug log if you need it.
This is yet another problem, then.
Best regards,
Wolfgang Denk

On Jan 7, 2011, at 11:52 AM, Wolfgang Denk wrote:
Dear York Sun,
In message 1294418957.8466.8.camel@oslab-l1 you wrote:
fsl_ddr:ctlr_intlv=cacheline,bank_intlv=cs0_cs1_cs2_cs3,ecc=off,addr_hash=false
With the buffer size 128, the sub function gets "ctlr_intlv=cacheline,bank_intlv=cs0_". It is not because the buffer is not enough, but the stack has been trashed. I have debug log if you need it.
This is yet another problem, then.
So I figured the problem out and need to rework the hwconfig API to fix it.
We need some new versions of the APIs that take a buffer for use early before boot.
- k

On Jan 7, 2011, at 5:23 PM, Kumar Gala wrote:
On Jan 7, 2011, at 11:52 AM, Wolfgang Denk wrote:
Dear York Sun,
In message 1294418957.8466.8.camel@oslab-l1 you wrote:
fsl_ddr:ctlr_intlv=cacheline,bank_intlv=cs0_cs1_cs2_cs3,ecc=off,addr_hash=false
With the buffer size 128, the sub function gets "ctlr_intlv=cacheline,bank_intlv=cs0_". It is not because the buffer is not enough, but the stack has been trashed. I have debug log if you need it.
This is yet another problem, then.
So I figured the problem out and need to rework the hwconfig API to fix it.
We need some new versions of the APIs that take a buffer for use early before boot.
I've posted:
http://patchwork.ozlabs.org/patch/78045/ http://patchwork.ozlabs.org/patch/78046/
Which should resolve the hwconfig issue and not require the patch to bump the size up.
- k

On Sun, 2011-01-09 at 15:00 -0600, Kumar Gala wrote:
On Jan 7, 2011, at 5:23 PM, Kumar Gala wrote:
On Jan 7, 2011, at 11:52 AM, Wolfgang Denk wrote:
Dear York Sun,
In message 1294418957.8466.8.camel@oslab-l1 you wrote:
fsl_ddr:ctlr_intlv=cacheline,bank_intlv=cs0_cs1_cs2_cs3,ecc=off,addr_hash=false
With the buffer size 128, the sub function gets "ctlr_intlv=cacheline,bank_intlv=cs0_". It is not because the buffer is not enough, but the stack has been trashed. I have debug log if you need it.
This is yet another problem, then.
So I figured the problem out and need to rework the hwconfig API to fix it.
We need some new versions of the APIs that take a buffer for use early before boot.
I've posted:
http://patchwork.ozlabs.org/patch/78045/ http://patchwork.ozlabs.org/patch/78046/
Which should resolve the hwconfig issue and not require the patch to bump the size up.
I have confirmed your patches. I will drop this patch and resubmit the rest.
York

Dear Kumar Gala,
In message 740DF509-6661-4611-BE1B-BBB629012697@kernel.crashing.org you wrote:
Making a buffer in a function's stack and make use of it out of the scope, that's the buggy code I am referring.
That is bad indeed, and needs to be fixed.
Where is that happening?
__hwconfig() calls hwconfig_parse() an passes a local stack buffer (buf) as argument; hwconfig_parse() returns a pointer into this buffer; then __hwconfig() returns the return value from hwconfig_parse() - but here the local stack buffer gots out of scope.
Best regards,
Wolfgang Denk

Add fsl_ddr:ecc=on in hwconfig. If ECC is enabled in board configuration file, ECC can be turned on/off by this switch. If this switch is omitted, it is ON by default.
Syntax is hwconfig=fsl_ddr:ecc=on
Signed-off-by: York Sun yorksun@freescale.com --- arch/powerpc/cpu/mpc8xxx/ddr/options.c | 9 ++++++--- doc/README.fsl-ddr | 7 +++++++ 2 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/options.c b/arch/powerpc/cpu/mpc8xxx/ddr/options.c index 774c0e4..38260f5 100644 --- a/arch/powerpc/cpu/mpc8xxx/ddr/options.c +++ b/arch/powerpc/cpu/mpc8xxx/ddr/options.c @@ -81,10 +81,13 @@ unsigned int populate_memctl_options(int all_DIMMs_registered, /* Operational Mode Paramters */
/* Pick ECC modes */ -#ifdef CONFIG_DDR_ECC - popts->ECC_mode = 1; /* 0 = disabled, 1 = enabled */ -#else popts->ECC_mode = 0; /* 0 = disabled, 1 = enabled */ +#ifdef CONFIG_DDR_ECC + if (hwconfig_sub("fsl_ddr", "ecc")) { + if (hwconfig_subarg_cmp("fsl_ddr", "ecc", "on")) + popts->ECC_mode = 1; + } else + popts->ECC_mode = 1; #endif popts->ECC_init_using_memctl = 1; /* 0 = use DMA, 1 = use memctl */
diff --git a/doc/README.fsl-ddr b/doc/README.fsl-ddr index 1657ef6..9e3c539 100644 --- a/doc/README.fsl-ddr +++ b/doc/README.fsl-ddr @@ -78,6 +78,13 @@ If the DDR controller supports address hashing, it can be enabled by hwconfig. Syntax is: hwconfig=fsl_ddr:addr_hash=true
+Memory controller ECC on/off +============================ +If ECC is enabled in board configuratoin file, i.e. #define CONFIG_DDR_ECC, +ECC can be turned on/off by hwconfig. + +Syntax is +hwconfig=fsl_ddr:ecc=off
Memory testing options for mpc85xx ==================================

On Dec 17, 2010, at 5:59 PM, York Sun wrote:
diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/options.c b/arch/powerpc/cpu/mpc8xxx/ddr/options.c index 774c0e4..38260f5 100644 --- a/arch/powerpc/cpu/mpc8xxx/ddr/options.c +++ b/arch/powerpc/cpu/mpc8xxx/ddr/options.c @@ -81,10 +81,13 @@ unsigned int populate_memctl_options(int all_DIMMs_registered, /* Operational Mode Paramters */
/* Pick ECC modes */ -#ifdef CONFIG_DDR_ECC
- popts->ECC_mode = 1; /* 0 = disabled, 1 = enabled */
-#else popts->ECC_mode = 0; /* 0 = disabled, 1 = enabled */ +#ifdef CONFIG_DDR_ECC
- if (hwconfig_sub("fsl_ddr", "ecc")) {
if (hwconfig_subarg_cmp("fsl_ddr", "ecc", "on"))
popts->ECC_mode = 1;
- } else
popts->ECC_mode = 1;
#endif popts->ECC_init_using_memctl = 1; /* 0 = use DMA, 1 = use memctl */
You'll need to update to use hwconfig_sub_f() & hwconfig_subarg_cmp_f()
- k

ECC can be turned on/off by hwconfig without recompiling. So enable it by default.
Signed-off-by: York Sun yorksun@freescale.com --- include/configs/corenet_ds.h | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/include/configs/corenet_ds.h b/include/configs/corenet_ds.h index 454a30a..49f0a26 100644 --- a/include/configs/corenet_ds.h +++ b/include/configs/corenet_ds.h @@ -76,7 +76,7 @@ #define CONFIG_BACKSIDE_L2_CACHE #define CONFIG_SYS_INIT_L2CSR0 L2CSR0_L2E #define CONFIG_BTB /* toggle branch predition */ -/*#define CONFIG_DDR_ECC*/ +#define CONFIG_DDR_ECC #ifdef CONFIG_DDR_ECC #define CONFIG_ECC_INIT_VIA_DDRCONTROLLER #define CONFIG_MEM_INIT_VALUE 0xdeadbeef

Add writing to cdr1, cdr2, err_disable, err_int_en and debug registers Add options to override rcw, address parity to RDIMMs. Use array for debug registers.
Signed-off-by: York Sun yorksun@freescale.com --- arch/powerpc/cpu/mpc85xx/ddr-gen3.c | 10 ++++++++-- arch/powerpc/include/asm/fsl_ddr_sdram.h | 12 ++++++++++++ arch/powerpc/include/asm/immap_85xx.h | 21 ++------------------- board/tqc/tqm85xx/sdram.c | 8 ++++---- 4 files changed, 26 insertions(+), 25 deletions(-)
diff --git a/arch/powerpc/cpu/mpc85xx/ddr-gen3.c b/arch/powerpc/cpu/mpc85xx/ddr-gen3.c index e46dcb7..23c87af 100644 --- a/arch/powerpc/cpu/mpc85xx/ddr-gen3.c +++ b/arch/powerpc/cpu/mpc85xx/ddr-gen3.c @@ -9,6 +9,7 @@ #include <common.h> #include <asm/io.h> #include <asm/fsl_ddr_sdram.h> +#include <asm/processor.h>
#if (CONFIG_CHIP_SELECTS_PER_CTRL > 4) #error Invalid setting for CONFIG_CHIP_SELECTS_PER_CTRL @@ -79,6 +80,12 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs, out_be32(&ddr->ddr_sr_cntr, regs->ddr_sr_cntr); out_be32(&ddr->ddr_sdram_rcw_1, regs->ddr_sdram_rcw_1); out_be32(&ddr->ddr_sdram_rcw_2, regs->ddr_sdram_rcw_2); + out_be32(&ddr->ddr_cdr1, regs->ddr_cdr1); + out_be32(&ddr->ddr_cdr2, regs->ddr_cdr2); + out_be32(&ddr->err_disable, regs->err_disable); + out_be32(&ddr->err_int_en, regs->err_int_en); + for (i = 0; i < 32; i++) + out_be32(&ddr->debug[i], regs->debug[i]);
/* Set, but do not enable the memory */ temp_sdram_cfg = regs->ddr_sdram_cfg; @@ -93,8 +100,7 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs, if ((((in_be32(&ddr->sdram_cfg) >> 24) & 0x7) == SDRAM_TYPE_DDR2) && in_be32(&ddr->sdram_cfg) & 0x80000) { /* set DEBUG_1[31] */ - u32 temp = in_be32(&ddr->debug_1); - out_be32(&ddr->debug_1, temp | 1); + setbits_be32(&ddr->debug[0], 1); } #endif
diff --git a/arch/powerpc/include/asm/fsl_ddr_sdram.h b/arch/powerpc/include/asm/fsl_ddr_sdram.h index 17d4b31..769549f 100644 --- a/arch/powerpc/include/asm/fsl_ddr_sdram.h +++ b/arch/powerpc/include/asm/fsl_ddr_sdram.h @@ -120,6 +120,11 @@ typedef struct fsl_ddr_cfg_regs_s { unsigned int ddr_sdram_rcw_1; unsigned int ddr_sdram_rcw_2; unsigned int ddr_eor; + unsigned int ddr_cdr1; + unsigned int ddr_cdr2; + unsigned int err_disable; + unsigned int err_int_en; + unsigned int debug[32]; } fsl_ddr_cfg_regs_t;
typedef struct memctl_options_partial_s { @@ -175,6 +180,7 @@ typedef struct memctl_options_s { /* mirrior DIMMs for DDR3 */ unsigned int mirrored_dimm; unsigned int quad_rank_present; + unsigned int ap_en; /* address parity enable for RDIMM */
/* Global Timing Parameters */ unsigned int cas_latency_override; @@ -210,6 +216,12 @@ typedef struct memctl_options_s { unsigned int zq_en; /* Write leveling */ unsigned int wrlvl_en; + /* RCW override for RDIMM */ + unsigned int rcw_override; + unsigned int rcw_1; + unsigned int rcw_2; + /* control register 1 */ + unsigned int ddr_cdr1; } memctl_options_t;
extern phys_size_t fsl_ddr_sdram(void); diff --git a/arch/powerpc/include/asm/immap_85xx.h b/arch/powerpc/include/asm/immap_85xx.h index 30c64eb..0069d50 100644 --- a/arch/powerpc/include/asm/immap_85xx.h +++ b/arch/powerpc/include/asm/immap_85xx.h @@ -222,25 +222,8 @@ typedef struct ccsr_ddr { u32 capture_ext_address; /* Error Extended Addr Capture */ u32 err_sbe; /* Single-Bit ECC Error Management */ u8 res11[164]; - u32 debug_1; - u32 debug_2; - u32 debug_3; - u32 debug_4; - u32 debug_5; - u32 debug_6; - u32 debug_7; - u32 debug_8; - u32 debug_9; - u32 debug_10; - u32 debug_11; - u32 debug_12; - u32 debug_13; - u32 debug_14; - u32 debug_15; - u32 debug_16; - u32 debug_17; - u32 debug_18; - u8 res12[184]; + u32 debug[32]; /* debug_1 to debug_32 */ + u8 res12[128]; } ccsr_ddr_t;
#define DDR_EOR_RD_BDW_OPT_DIS 0x80000000 /* Read BDW Opt. disable */ diff --git a/board/tqc/tqm85xx/sdram.c b/board/tqc/tqm85xx/sdram.c index 503c5e5..d2af127 100644 --- a/board/tqc/tqm85xx/sdram.c +++ b/board/tqc/tqm85xx/sdram.c @@ -220,7 +220,7 @@ long int sdram_setup (int casl) * 4. Before DDR_SDRAM_CFG[MEM_EN] set, write D3[21] to disable data * training */ - ddr->debug_3 |= 0x00000400; + ddr->debug[2] |= 0x00000400;
/* * 5. Wait 200 micro-seconds @@ -262,18 +262,18 @@ long int sdram_setup (int casl) /* * 8. Clear D3[21] to re-enable data training */ - ddr->debug_3 &= ~0x00000400; + ddr->debug[2] &= ~0x00000400;
/* * 9. Set D2(21) to force data training to run */ - ddr->debug_2 |= 0x00000400; + ddr->debug[1] |= 0x00000400;
/* * 10. Poll on D2[21] until it is cleared by hardware */ asm ("sync;isync;msync"); - while (ddr->debug_2 & 0x00000400) + while (ddr->debug[1] & 0x00000400) asm ("eieio");
/*

Dear York Sun,
In message 1292630381-23022-5-git-send-email-yorksun@freescale.com you wrote:
Add writing to cdr1, cdr2, err_disable, err_int_en and debug registers Add options to override rcw, address parity to RDIMMs. Use array for debug registers.
Can you please explain what this patch is good for?
"Adding more registers and options" is not really helpful to understand what you are trying to acchived here, and neither is the rest of the commit massage.
Best regards,
Wolfgang Denk

Added fsl_ddr_get_version() function to for DDR3 to poll DDRC IP version (major, minor, errata) to determine if unique mode registers are available. If true, always use unique mode registers. Dynamic ODT is enabled if needed. The table is documented in doc/README.fsl-ddr. This function may also need to be extend for future other platforms if such a feature exists.
Enable address parity and RCW by default for RDIMMs.
Change default output driver impedance from 34 ohm to 40ohm. Make it 34ohm for quad-rank RDIMMs.
Use a formula to calculate rodt_on for timing_cfg_5.
Signed-off-by: York Sun yorksun@freescale.com --- arch/powerpc/cpu/mpc85xx/ddr-gen3.c | 6 + arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c | 320 ++++++++++++++++++++++++++---- arch/powerpc/cpu/mpc8xxx/ddr/options.c | 308 ++++++++++++++++++++++++++++- arch/powerpc/include/asm/fsl_ddr_sdram.h | 18 ++ doc/README.fsl-ddr | 67 ++++++- 5 files changed, 670 insertions(+), 49 deletions(-)
diff --git a/arch/powerpc/cpu/mpc85xx/ddr-gen3.c b/arch/powerpc/cpu/mpc85xx/ddr-gen3.c index 23c87af..5f1848f 100644 --- a/arch/powerpc/cpu/mpc85xx/ddr-gen3.c +++ b/arch/powerpc/cpu/mpc85xx/ddr-gen3.c @@ -66,6 +66,12 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs, out_be32(&ddr->sdram_cfg_2, regs->ddr_sdram_cfg_2); out_be32(&ddr->sdram_mode, regs->ddr_sdram_mode); out_be32(&ddr->sdram_mode_2, regs->ddr_sdram_mode_2); + out_be32(&ddr->sdram_mode_3, regs->ddr_sdram_mode_3); + out_be32(&ddr->sdram_mode_4, regs->ddr_sdram_mode_4); + out_be32(&ddr->sdram_mode_5, regs->ddr_sdram_mode_5); + out_be32(&ddr->sdram_mode_6, regs->ddr_sdram_mode_6); + out_be32(&ddr->sdram_mode_7, regs->ddr_sdram_mode_7); + out_be32(&ddr->sdram_mode_8, regs->ddr_sdram_mode_8); out_be32(&ddr->sdram_md_cntl, regs->ddr_sdram_md_cntl); out_be32(&ddr->sdram_interval, regs->ddr_sdram_interval); out_be32(&ddr->sdram_data_init, regs->ddr_data_init); diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c b/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c index 3fec100..c527563 100644 --- a/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c +++ b/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c @@ -18,7 +18,28 @@
#include "ddr.h"
-extern unsigned int picos_to_mclk(unsigned int picos); +#ifdef CONFIG_MPC85xx + #define _DDR_ADDR CONFIG_SYS_MPC85xx_DDR_ADDR +#elif defined(CONFIG_MPC86xx) + #define _DDR_ADDR CONFIG_SYS_MPC86xx_DDR_ADDR +#else + #error "Undefined _DDR_ADDR" +#endif + +u32 fsl_ddr_get_version(void) +{ + ccsr_ddr_t *ddr; + u32 ver_major_minor_errata; + + ddr = (void *)_DDR_ADDR; + ver_major_minor_errata = (in_be32(&ddr->ip_rev1) & 0xFFFF) << 8; + ver_major_minor_errata |= (in_be32(&ddr->ip_rev2) & 0xFF00) >> 8; + + return ver_major_minor_errata; +} + +unsigned int picos_to_mclk(unsigned int picos); + /* * Determine Rtt value. * @@ -187,7 +208,8 @@ static void set_csn_config_2(int i, fsl_ddr_cfg_regs_t *ddr) * Avoid writing for DDR I. The new PQ38 DDR controller * dreams up non-zero default values to be backwards compatible. */ -static void set_timing_cfg_0(fsl_ddr_cfg_regs_t *ddr) +static void set_timing_cfg_0(fsl_ddr_cfg_regs_t *ddr, + const memctl_options_t *popts) { unsigned char trwt_mclk = 0; /* Read-to-write turnaround */ unsigned char twrt_mclk = 0; /* Write-to-read turnaround */ @@ -204,7 +226,7 @@ static void set_timing_cfg_0(fsl_ddr_cfg_regs_t *ddr) /* Mode register set cycle time (tMRD). */ unsigned char tmrd_mclk;
-#if defined(CONFIG_FSL_DDR3) +#ifdef CONFIG_FSL_DDR3 /* * (tXARD and tXARDS). Empirical? * The DDR3 spec has not tXARD, @@ -214,13 +236,21 @@ static void set_timing_cfg_0(fsl_ddr_cfg_regs_t *ddr) * tAXPD=1, need design to confirm. */ int tXP = max((get_memory_clk_period_ps() * 3), 7500); /* unit=ps */ - act_pd_exit_mclk = picos_to_mclk(tXP); - /* Mode register MR0[A12] is '1' - fast exit */ - pre_pd_exit_mclk = act_pd_exit_mclk; - taxpd_mclk = 1; tmrd_mclk = 4; /* set the turnaround time */ trwt_mclk = 1; + + if (popts->dynamic_power == 0) { /* powerdown is not used */ + act_pd_exit_mclk = 1; + pre_pd_exit_mclk = 1; + taxpd_mclk = 1; + } else { + /* act_pd_exit_mclk = tXARD, see above */ + act_pd_exit_mclk = picos_to_mclk(tXP); + /* Mode register MR0[A12] is '1' - fast exit */ + pre_pd_exit_mclk = act_pd_exit_mclk; + taxpd_mclk = 1; + } #else /* CONFIG_FSL_DDR2 */ /* * (tXARD and tXARDS). Empirical? @@ -450,28 +480,34 @@ static void set_timing_cfg_2(fsl_ddr_cfg_regs_t *ddr,
/* DDR SDRAM Register Control Word */ static void set_ddr_sdram_rcw(fsl_ddr_cfg_regs_t *ddr, + const memctl_options_t *popts, const common_timing_params_t *common_dimm) { if (common_dimm->all_DIMMs_registered && !common_dimm->all_DIMMs_unbuffered) { - ddr->ddr_sdram_rcw_1 = - common_dimm->rcw[0] << 28 | \ - common_dimm->rcw[1] << 24 | \ - common_dimm->rcw[2] << 20 | \ - common_dimm->rcw[3] << 16 | \ - common_dimm->rcw[4] << 12 | \ - common_dimm->rcw[5] << 8 | \ - common_dimm->rcw[6] << 4 | \ - common_dimm->rcw[7]; - ddr->ddr_sdram_rcw_2 = - common_dimm->rcw[8] << 28 | \ - common_dimm->rcw[9] << 24 | \ - common_dimm->rcw[10] << 20 | \ - common_dimm->rcw[11] << 16 | \ - common_dimm->rcw[12] << 12 | \ - common_dimm->rcw[13] << 8 | \ - common_dimm->rcw[14] << 4 | \ - common_dimm->rcw[15]; + if (popts->rcw_override) { + ddr->ddr_sdram_rcw_1 = popts->rcw_1; + ddr->ddr_sdram_rcw_2 = popts->rcw_2; + } else { + ddr->ddr_sdram_rcw_1 = + common_dimm->rcw[0] << 28 | \ + common_dimm->rcw[1] << 24 | \ + common_dimm->rcw[2] << 20 | \ + common_dimm->rcw[3] << 16 | \ + common_dimm->rcw[4] << 12 | \ + common_dimm->rcw[5] << 8 | \ + common_dimm->rcw[6] << 4 | \ + common_dimm->rcw[7]; + ddr->ddr_sdram_rcw_2 = + common_dimm->rcw[8] << 28 | \ + common_dimm->rcw[9] << 24 | \ + common_dimm->rcw[10] << 20 | \ + common_dimm->rcw[11] << 16 | \ + common_dimm->rcw[12] << 12 | \ + common_dimm->rcw[13] << 8 | \ + common_dimm->rcw[14] << 4 | \ + common_dimm->rcw[15]; + } debug("FSLDDR: ddr_sdram_rcw_1 = 0x%08x\n", ddr->ddr_sdram_rcw_1); debug("FSLDDR: ddr_sdram_rcw_2 = 0x%08x\n", ddr->ddr_sdram_rcw_2); } @@ -509,8 +545,14 @@ static void set_ddr_sdram_cfg(fsl_ddr_cfg_regs_t *ddr, ecc_en = 0; }
- rd_en = (common_dimm->all_DIMMs_registered - && !common_dimm->all_DIMMs_unbuffered); + if (common_dimm->all_DIMMs_registered + && !common_dimm->all_DIMMs_unbuffered) { + rd_en = 1; + twoT_en = 0; + } else { + rd_en = 0; + twoT_en = popts->twoT_en; + }
sdram_type = CONFIG_FSL_SDRAM_TYPE;
@@ -530,7 +572,6 @@ static void set_ddr_sdram_cfg(fsl_ddr_cfg_regs_t *ddr, }
threeT_en = popts->threeT_en; - twoT_en = popts->twoT_en; ba_intlv_ctl = popts->ba_intlv_ctl; hse = popts->half_strength_driver_enable;
@@ -558,7 +599,8 @@ static void set_ddr_sdram_cfg(fsl_ddr_cfg_regs_t *ddr,
/* DDR SDRAM control configuration 2 (DDR_SDRAM_CFG_2) */ static void set_ddr_sdram_cfg_2(fsl_ddr_cfg_regs_t *ddr, - const memctl_options_t *popts) + const memctl_options_t *popts, + unsigned int unq_mrs_en) { unsigned int frc_sr = 0; /* Force self refresh */ unsigned int sr_ie = 0; /* Self-refresh interrupt enable */ @@ -598,11 +640,17 @@ static void set_ddr_sdram_cfg_2(fsl_ddr_cfg_regs_t *ddr, obc_cfg = 0; #endif
- ap_en = 0; /* Make this configurable? */ + if (popts->registered_dimm_en) { + rcw_en = 1; + ap_en = popts->ap_en; + } else { + rcw_en = 0; + ap_en = 0; + }
#if defined(CONFIG_ECC_INIT_VIA_DDRCONTROLLER) /* Use the DDR controller to auto initialize memory. */ - d_init = 1; + d_init = popts->ECC_init_using_memctl; ddr->ddr_data_init = CONFIG_MEM_INIT_VALUE; debug("DDR: ddr_data_init = 0x%08x\n", ddr->ddr_data_init); #else @@ -613,7 +661,6 @@ static void set_ddr_sdram_cfg_2(fsl_ddr_cfg_regs_t *ddr, #if defined(CONFIG_FSL_DDR3) md_en = popts->mirrored_dimm; #endif - rcw_en = popts->registered_dimm_en; qd_en = popts->quad_rank_present ? 1 : 0; ddr->ddr_sdram_cfg_2 = (0 | ((frc_sr & 0x1) << 31) @@ -623,6 +670,7 @@ static void set_ddr_sdram_cfg_2(fsl_ddr_cfg_regs_t *ddr, | ((odt_cfg & 0x3) << 21) | ((num_pr & 0xf) << 12) | (qd_en << 9) + | (unq_mrs_en << 8) | ((obc_cfg & 0x1) << 6) | ((ap_en & 0x1) << 5) | ((d_init & 0x1) << 4) @@ -648,7 +696,8 @@ static void set_ddr_sdram_mode_2(fsl_ddr_cfg_regs_t *ddr,
if (popts->rtt_override) rtt_wr = popts->rtt_wr_override_value; - + else + rtt_wr = popts->cs_local_opts[0].odt_rtt_wr; esdmode2 = (0 | ((rtt_wr & 0x3) << 9) | ((srt & 0x1) << 7) @@ -663,6 +712,165 @@ static void set_ddr_sdram_mode_2(fsl_ddr_cfg_regs_t *ddr, debug("FSLDDR: ddr_sdram_mode_2 = 0x%08x\n", ddr->ddr_sdram_mode_2); }
+static void set_ddr_sdram_mode_3(fsl_ddr_cfg_regs_t *ddr, + const memctl_options_t *popts) +{ + u16 esdmode; /* Extended SDRAM mode */ + u16 sdmode; /* SDRAM mode */ + u32 rtt; + + sdmode = ddr->ddr_sdram_mode & 0xFFFF; + esdmode = (ddr->ddr_sdram_mode >> 16) & 0xFFFF; + + if (popts->rtt_override) + rtt = popts->rtt_override_value; + else + rtt = popts->cs_local_opts[1].odt_rtt_norm; + + esdmode &= 0xFDBB; /* clear bit 9,6,2 */ + esdmode |= (0 + | ((rtt & 0x4) << 7) /* rtt field is split */ + | ((rtt & 0x2) << 5) /* rtt field is split */ + | ((rtt & 0x1) << 2) /* rtt field is split */ + ); + + ddr->ddr_sdram_mode_3 = (0 + | ((esdmode & 0xFFFF) << 16) + | ((sdmode & 0xFFFF) << 0) + ); + debug("FSLDDR: ddr_sdram_mode_3 = 0x%08x\n", ddr->ddr_sdram_mode_3); +} + +static void set_ddr_sdram_mode_4(fsl_ddr_cfg_regs_t *ddr, + const memctl_options_t *popts) +{ + u16 esdmode2 = 0; /* Extended SDRAM mode 2 */ + u16 esdmode3 = 0; /* Extended SDRAM mode 3 */ + u32 rtt_wr = 0; /* Dynamic ODT off */ + + esdmode2 = (ddr->ddr_sdram_mode_2 >> 16) & 0xFFFF; + esdmode3 = ddr->ddr_sdram_mode_2 & 0xFFFF; + + if (popts->rtt_override) + rtt_wr = popts->rtt_wr_override_value; + else + rtt_wr = popts->cs_local_opts[1].odt_rtt_wr; + + esdmode2 &= 0xF9FF; /* clear bit 10, 9 */ + esdmode2 |= (rtt_wr & 0x3) << 9; + ddr->ddr_sdram_mode_4 = (0 + | ((esdmode2 & 0xFFFF) << 16) + | ((esdmode3 & 0xFFFF) << 0) + ); + debug("FSLDDR: ddr_sdram_mode_4 = 0x%08x\n", ddr->ddr_sdram_mode_4); +} + +static void set_ddr_sdram_mode_5(fsl_ddr_cfg_regs_t *ddr, + const memctl_options_t *popts) +{ + u16 esdmode; /* Extended SDRAM mode */ + u16 sdmode; /* SDRAM mode */ + u32 rtt; + + sdmode = ddr->ddr_sdram_mode & 0xFFFF; + esdmode = (ddr->ddr_sdram_mode >> 16) & 0xFFFF; + + if (popts->rtt_override) + rtt = popts->rtt_override_value; + else + rtt = popts->cs_local_opts[2].odt_rtt_norm; + + esdmode &= 0xFDBB; /* clear bit 9,6,2 */ + esdmode |= (0 + | ((rtt & 0x4) << 7) /* rtt field is split */ + | ((rtt & 0x2) << 5) /* rtt field is split */ + | ((rtt & 0x1) << 2) /* rtt field is split */ + ); + + ddr->ddr_sdram_mode_5 = (0 + | ((esdmode & 0xFFFF) << 16) + | ((sdmode & 0xFFFF) << 0) + ); + debug("FSLDDR: ddr_sdram_mode_5 = 0x%08x\n", ddr->ddr_sdram_mode_5); +} + +static void set_ddr_sdram_mode_6(fsl_ddr_cfg_regs_t *ddr, + const memctl_options_t *popts) +{ + u16 esdmode2 = 0; /* Extended SDRAM mode 2 */ + u16 esdmode3 = 0; /* Extended SDRAM mode 3 */ + u32 rtt_wr = 0; /* Dynamic ODT off */ + + esdmode2 = (ddr->ddr_sdram_mode_2 >> 16) & 0xFFFF; + esdmode3 = ddr->ddr_sdram_mode_2 & 0xFFFF; + + if (popts->rtt_override) + rtt_wr = popts->rtt_wr_override_value; + else + rtt_wr = popts->cs_local_opts[2].odt_rtt_wr; + + esdmode2 &= 0xF9FF; /* clear bit 10, 9 */ + esdmode2 |= (rtt_wr & 0x3) << 9; + ddr->ddr_sdram_mode_6 = (0 + | ((esdmode2 & 0xFFFF) << 16) + | ((esdmode3 & 0xFFFF) << 0) + ); + debug("FSLDDR: ddr_sdram_mode_6 = 0x%08x\n", ddr->ddr_sdram_mode_6); +} + +static void set_ddr_sdram_mode_7(fsl_ddr_cfg_regs_t *ddr, + const memctl_options_t *popts) +{ + u16 esdmode; /* Extended SDRAM mode */ + u16 sdmode; /* SDRAM mode */ + u32 rtt; + + sdmode = ddr->ddr_sdram_mode & 0xFFFF; + esdmode = (ddr->ddr_sdram_mode >> 16) & 0xFFFF; + + if (popts->rtt_override) + rtt = popts->rtt_override_value; + else + rtt = popts->cs_local_opts[3].odt_rtt_norm; + + esdmode &= 0xFDBB; /* clear bit 9,6,2 */ + esdmode |= (0 + | ((rtt & 0x4) << 7) /* rtt field is split */ + | ((rtt & 0x2) << 5) /* rtt field is split */ + | ((rtt & 0x1) << 2) /* rtt field is split */ + ); + + ddr->ddr_sdram_mode_7 = (0 + | ((esdmode & 0xFFFF) << 16) + | ((sdmode & 0xFFFF) << 0) + ); + debug("FSLDDR: ddr_sdram_mode_7 = 0x%08x\n", ddr->ddr_sdram_mode_7); +} + +static void set_ddr_sdram_mode_8(fsl_ddr_cfg_regs_t *ddr, + const memctl_options_t *popts) +{ + u16 esdmode2 = 0; /* Extended SDRAM mode 2 */ + u16 esdmode3 = 0; /* Extended SDRAM mode 3 */ + u32 rtt_wr = 0; /* Rtt_WR - dynamic ODT off */ + + esdmode2 = (ddr->ddr_sdram_mode_2 >> 16) & 0xFFFF; + esdmode3 = ddr->ddr_sdram_mode_2 & 0xFFFF; + + if (popts->rtt_override) + rtt_wr = popts->rtt_wr_override_value; + else + rtt_wr = popts->cs_local_opts[3].odt_rtt_wr; + + esdmode2 &= 0xF9FF; /* clear bit 10, 9 */ + esdmode2 |= (rtt_wr & 0x3) << 9; + ddr->ddr_sdram_mode_8 = (0 + | ((esdmode2 & 0xFFFF) << 16) + | ((esdmode3 & 0xFFFF) << 0) + ); + debug("FSLDDR: ddr_sdram_mode_8 = 0x%08x\n", ddr->ddr_sdram_mode_8); +} + /* DDR SDRAM Interval Configuration (DDR_SDRAM_INTERVAL) */ static void set_ddr_sdram_interval(fsl_ddr_cfg_regs_t *ddr, const memctl_options_t *popts, @@ -700,7 +908,7 @@ static void set_ddr_sdram_mode(fsl_ddr_cfg_regs_t *ddr, unsigned int rtt; unsigned int wrlvl_en = 0; /* Write level enable: 0=no, 1=yes */ unsigned int al = 0; /* Posted CAS# additive latency (AL) */ - unsigned int dic = 1; /* Output driver impedance, 34ohm */ + unsigned int dic = 0; /* Output driver impedance, 40ohm */ unsigned int dll_en = 0; /* DLL Enable 0=Enable (Normal), 1=Disable (Test/Debug) */
@@ -718,15 +926,19 @@ static void set_ddr_sdram_mode(fsl_ddr_cfg_regs_t *ddr,
const unsigned int mclk_ps = get_memory_clk_period_ps();
- rtt = fsl_ddr_get_rtt(); if (popts->rtt_override) rtt = popts->rtt_override_value; + else + rtt = popts->cs_local_opts[0].odt_rtt_norm;
if (additive_latency == (cas_latency - 1)) al = 1; if (additive_latency == (cas_latency - 2)) al = 2;
+ if (popts->quad_rank_present) + dic = 1; /* output driver impedance 240/7 ohm */ + /* * The esdmode value will also be used for writing * MR1 during write leveling for DDR3, although the @@ -1024,7 +1236,7 @@ static void set_timing_cfg_4(fsl_ddr_cfg_regs_t *ddr, }
/* DDR SDRAM Timing Configuration 5 (TIMING_CFG_5) */ -static void set_timing_cfg_5(fsl_ddr_cfg_regs_t *ddr) +static void set_timing_cfg_5(fsl_ddr_cfg_regs_t *ddr, unsigned int cas_latency) { unsigned int rodt_on = 0; /* Read to ODT on */ unsigned int rodt_off = 0; /* Read to ODT off */ @@ -1032,7 +1244,8 @@ static void set_timing_cfg_5(fsl_ddr_cfg_regs_t *ddr) unsigned int wodt_off = 0; /* Write to ODT off */
#if defined(CONFIG_FSL_DDR3) - rodt_on = 2; /* 2 clocks */ + /* rodt_on = timing_cfg_1[caslat] - timing_cfg_2[wrlat] + 1 */ + rodt_on = cas_latency - ((ddr->timing_cfg_2 & 0x00780000) >> 19) + 1; rodt_off = 4; /* 4 clocks */ wodt_on = 1; /* 1 clocks */ wodt_off = 4; /* 4 clocks */ @@ -1068,6 +1281,7 @@ static void set_ddr_zq_cntl(fsl_ddr_cfg_regs_t *ddr, unsigned int zq_en) | ((zqoper & 0xF) << 16) | ((zqcs & 0xF) << 8) ); + debug("FSLDDR: zq_cntl = 0x%08x\n", ddr->ddr_zq_cntl); }
/* DDR Write Leveling Control (DDR_WRLVL_CNTL) */ @@ -1113,7 +1327,8 @@ static void set_ddr_wrlvl_cntl(fsl_ddr_cfg_regs_t *ddr, unsigned int wrlvl_en, /* * Write leveling start time * The value use for the DQS_ADJUST for the first sample - * when write leveling is enabled. + * when write leveling is enabled. It probably needs to be + * overriden per platform. */ wrlvl_start = 0x8; /* @@ -1135,6 +1350,7 @@ static void set_ddr_wrlvl_cntl(fsl_ddr_cfg_regs_t *ddr, unsigned int wrlvl_en, | ((wrlvl_wlr & 0x7) << 8) | ((wrlvl_start & 0x1F) << 0) ); + debug("FSLDDR: wrlvl_cntl = 0x%08x\n", ddr->ddr_wrlvl_cntl); }
/* DDR Self Refresh Counter (DDR_SR_CNTR) */ @@ -1152,6 +1368,12 @@ static void set_ddr_eor(fsl_ddr_cfg_regs_t *ddr, const memctl_options_t *popts) } }
+static void set_ddr_cdr1(fsl_ddr_cfg_regs_t *ddr, const memctl_options_t *popts) +{ + ddr->ddr_cdr1 = popts->ddr_cdr1; + debug("FSLDDR: ddr_cdr1 = 0x%08x\n", ddr->ddr_cdr1); +} + unsigned int check_fsl_memctl_config_regs(const fsl_ddr_cfg_regs_t *ddr) { @@ -1184,6 +1406,8 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts, unsigned int sr_it; unsigned int zq_en; unsigned int wrlvl_en; + unsigned int ip_rev = 0; + unsigned int unq_mrs_en = 0; int cs_en = 1;
memset(ddr, 0, sizeof(fsl_ddr_cfg_regs_t)); @@ -1397,7 +1621,7 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts, set_ddr_eor(ddr, popts);
#if !defined(CONFIG_FSL_DDR1) - set_timing_cfg_0(ddr); + set_timing_cfg_0(ddr, popts); #endif
set_timing_cfg_3(ddr, common_dimm, cas_latency); @@ -1405,26 +1629,38 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts, set_timing_cfg_2(ddr, popts, common_dimm, cas_latency, additive_latency);
+ set_ddr_cdr1(ddr, popts); set_ddr_sdram_cfg(ddr, popts, common_dimm); + ip_rev = fsl_ddr_get_version(); + if (ip_rev > 0x40400) + unq_mrs_en = 1;
- set_ddr_sdram_cfg_2(ddr, popts); + set_ddr_sdram_cfg_2(ddr, popts, unq_mrs_en); set_ddr_sdram_mode(ddr, popts, common_dimm, cas_latency, additive_latency); set_ddr_sdram_mode_2(ddr, popts); + if (unq_mrs_en) { + set_ddr_sdram_mode_3(ddr, popts); + set_ddr_sdram_mode_4(ddr, popts); + set_ddr_sdram_mode_5(ddr, popts); + set_ddr_sdram_mode_6(ddr, popts); + set_ddr_sdram_mode_7(ddr, popts); + set_ddr_sdram_mode_8(ddr, popts); + } set_ddr_sdram_interval(ddr, popts, common_dimm); set_ddr_data_init(ddr); set_ddr_sdram_clk_cntl(ddr, popts); set_ddr_init_addr(ddr); set_ddr_init_ext_addr(ddr); set_timing_cfg_4(ddr, popts); - set_timing_cfg_5(ddr); + set_timing_cfg_5(ddr, cas_latency);
set_ddr_zq_cntl(ddr, zq_en); set_ddr_wrlvl_cntl(ddr, wrlvl_en, popts);
set_ddr_sr_cntr(ddr, sr_it);
- set_ddr_sdram_rcw(ddr, common_dimm); + set_ddr_sdram_rcw(ddr, popts, common_dimm);
return check_fsl_memctl_config_regs(ddr); } diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/options.c b/arch/powerpc/cpu/mpc8xxx/ddr/options.c index 38260f5..9ae190d 100644 --- a/arch/powerpc/cpu/mpc8xxx/ddr/options.c +++ b/arch/powerpc/cpu/mpc8xxx/ddr/options.c @@ -18,23 +18,316 @@ extern void fsl_ddr_board_options(memctl_options_t *popts, dimm_params_t *pdimm, unsigned int ctrl_num);
+typedef struct { + unsigned int odt_rd_cfg; + unsigned int odt_wr_cfg; + unsigned int odt_rtt_norm; + unsigned int odt_rtt_wr; +} dynamic_odt_t; + +static const dynamic_odt_t single_Q[4] = { + { /* cs0 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_CS_AND_OTHER_DIMM, + DDR3_RTT_20_OHM, + DDR3_RTT_120_OHM + }, + { /* cs1 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_NEVER, /* tied high */ + DDR3_RTT_OFF, + DDR3_RTT_120_OHM + }, + { /* cs2 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_CS_AND_OTHER_DIMM, + DDR3_RTT_20_OHM, + DDR3_RTT_120_OHM + }, + { /* cs3 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_NEVER, /* tied high */ + DDR3_RTT_OFF, + DDR3_RTT_120_OHM + } +}; + +static const dynamic_odt_t single_D[4] = { + { /* cs0 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_ALL, + DDR3_RTT_40_OHM, + DDR3_RTT_OFF + }, + { /* cs1 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_NEVER, + DDR3_RTT_OFF, + DDR3_RTT_OFF + }, + {0, 0, 0, 0}, + {0, 0, 0, 0} +}; + +static const dynamic_odt_t single_S[4] = { + { /* cs0 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_ALL, + DDR3_RTT_40_OHM, + DDR3_RTT_OFF + }, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, +}; + +static const dynamic_odt_t dual_DD[4] = { + { /* cs0 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_SAME_DIMM, + DDR3_RTT_120_OHM, + DDR3_RTT_OFF + }, + { /* cs1 */ + FSL_DDR_ODT_OTHER_DIMM, + FSL_DDR_ODT_OTHER_DIMM, + DDR3_RTT_30_OHM, + DDR3_RTT_OFF + }, + { /* cs2 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_SAME_DIMM, + DDR3_RTT_120_OHM, + DDR3_RTT_OFF + }, + { /* cs3 */ + FSL_DDR_ODT_OTHER_DIMM, + FSL_DDR_ODT_OTHER_DIMM, + DDR3_RTT_30_OHM, + DDR3_RTT_OFF + } +}; + +static const dynamic_odt_t dual_DS[4] = { + { /* cs0 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_SAME_DIMM, + DDR3_RTT_120_OHM, + DDR3_RTT_OFF + }, + { /* cs1 */ + FSL_DDR_ODT_OTHER_DIMM, + FSL_DDR_ODT_OTHER_DIMM, + DDR3_RTT_30_OHM, + DDR3_RTT_OFF + }, + { /* cs2 */ + FSL_DDR_ODT_OTHER_DIMM, + FSL_DDR_ODT_ALL, + DDR3_RTT_20_OHM, + DDR3_RTT_120_OHM + }, + {0, 0, 0, 0} +}; +static const dynamic_odt_t dual_SD[4] = { + { /* cs0 */ + FSL_DDR_ODT_OTHER_DIMM, + FSL_DDR_ODT_ALL, + DDR3_RTT_20_OHM, + DDR3_RTT_120_OHM + }, + {0, 0, 0, 0}, + { /* cs2 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_SAME_DIMM, + DDR3_RTT_120_OHM, + DDR3_RTT_OFF + }, + { /* cs3 */ + FSL_DDR_ODT_OTHER_DIMM, + FSL_DDR_ODT_OTHER_DIMM, + DDR3_RTT_20_OHM, + DDR3_RTT_OFF + } +}; + +static const dynamic_odt_t dual_SS[4] = { + { /* cs0 */ + FSL_DDR_ODT_OTHER_DIMM, + FSL_DDR_ODT_ALL, + DDR3_RTT_30_OHM, + DDR3_RTT_120_OHM + }, + {0, 0, 0, 0}, + { /* cs2 */ + FSL_DDR_ODT_OTHER_DIMM, + FSL_DDR_ODT_ALL, + DDR3_RTT_30_OHM, + DDR3_RTT_120_OHM + }, + {0, 0, 0, 0} +}; + +static const dynamic_odt_t dual_D0[4] = { + { /* cs0 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_SAME_DIMM, + DDR3_RTT_40_OHM, + DDR3_RTT_OFF + }, + { /* cs1 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_NEVER, + DDR3_RTT_OFF, + DDR3_RTT_OFF + }, + {0, 0, 0, 0}, + {0, 0, 0, 0} +}; + +static const dynamic_odt_t dual_0D[4] = { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + { /* cs2 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_SAME_DIMM, + DDR3_RTT_40_OHM, + DDR3_RTT_OFF + }, + { /* cs3 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_NEVER, + DDR3_RTT_OFF, + DDR3_RTT_OFF + } +}; + +static const dynamic_odt_t dual_S0[4] = { + { /* cs0 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_CS, + DDR3_RTT_40_OHM, + DDR3_RTT_OFF + }, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0} + +}; + +static const dynamic_odt_t dual_0S[4] = { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + { /* cs2 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_CS, + DDR3_RTT_40_OHM, + DDR3_RTT_OFF + }, + {0, 0, 0, 0} + +}; + +static const dynamic_odt_t odt_unknown[4] = { + { /* cs0 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_CS, + DDR3_RTT_120_OHM, + DDR3_RTT_OFF + }, + { /* cs1 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_CS, + DDR3_RTT_120_OHM, + DDR3_RTT_OFF + }, + { /* cs2 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_CS, + DDR3_RTT_120_OHM, + DDR3_RTT_OFF + }, + { /* cs3 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_CS, + DDR3_RTT_120_OHM, + DDR3_RTT_OFF + } +}; + unsigned int populate_memctl_options(int all_DIMMs_registered, memctl_options_t *popts, dimm_params_t *pdimm, unsigned int ctrl_num) { unsigned int i; + const dynamic_odt_t *pdodt = odt_unknown;
/* Chip select options. */
+ if (CONFIG_DIMM_SLOTS_PER_CTLR == 1) { + switch (pdimm[0].n_ranks) { + case 1: + pdodt = single_S; + break; + case 2: + pdodt = single_D; + break; + case 4: + pdodt = single_Q; + break; + } + } else if (CONFIG_DIMM_SLOTS_PER_CTLR == 2) { + switch (pdimm[0].n_ranks) { + case 2: + switch (pdimm[1].n_ranks) { + case 2: + pdodt = dual_DD; + break; + case 1: + pdodt = dual_DS; + break; + case 0: + pdodt = dual_D0; + break; + } + break; + case 1: + switch (pdimm[1].n_ranks) { + case 2: + pdodt = dual_SD; + break; + case 1: + pdodt = dual_SS; + break; + case 0: + pdodt = dual_S0; + break; + } + break; + case 0: + switch (pdimm[1].n_ranks) { + case 2: + pdodt = dual_0D; + break; + case 1: + pdodt = dual_0S; + break; + } + break; + } + } /* Pick chip-select local options. */ for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { - /* If not DDR2, odt_rd_cfg and odt_wr_cfg need to be 0. */ - - /* only for single CS? */ - popts->cs_local_opts[i].odt_rd_cfg = 0; - - popts->cs_local_opts[i].odt_wr_cfg = 1; +#if defined(CONFIG_FSL_DDR3) + popts->cs_local_opts[i].odt_rd_cfg = pdodt[i].odt_rd_cfg; + popts->cs_local_opts[i].odt_wr_cfg = pdodt[i].odt_wr_cfg; + popts->cs_local_opts[i].odt_rtt_norm = pdodt[i].odt_rtt_norm; + popts->cs_local_opts[i].odt_rtt_wr = pdodt[i].odt_rtt_wr; +#else + popts->cs_local_opts[i].odt_rd_cfg = FSL_DDR_ODT_NEVER; + popts->cs_local_opts[i].odt_wr_cfg = FSL_DDR_ODT_CS; +#endif popts->cs_local_opts[i].auto_precharge = 0; }
@@ -162,6 +455,9 @@ unsigned int populate_memctl_options(int all_DIMMs_registered, popts->twoT_en = 0; popts->threeT_en = 0;
+ /* for RDIMM, address parity enable */ + popts->ap_en = 1; + /* * BSTTOPRE precharge interval * diff --git a/arch/powerpc/include/asm/fsl_ddr_sdram.h b/arch/powerpc/include/asm/fsl_ddr_sdram.h index 769549f..e8b9c04 100644 --- a/arch/powerpc/include/asm/fsl_ddr_sdram.h +++ b/arch/powerpc/include/asm/fsl_ddr_sdram.h @@ -24,6 +24,7 @@ #define DDR_OTF 6 /* on-the-fly BC4 and BL8 */ #define DDR_BL8 8 /* burst length 8 */
+#define DDR3_RTT_OFF 0 #define DDR3_RTT_60_OHM 1 /* RTT_Nom = RZQ/4 */ #define DDR3_RTT_120_OHM 2 /* RTT_Nom = RZQ/2 */ #define DDR3_RTT_40_OHM 3 /* RTT_Nom = RZQ/6 */ @@ -50,6 +51,15 @@ typedef ddr3_spd_eeprom_t generic_spd_eeprom_t; #endif #endif /* #if defined(CONFIG_FSL_DDR1) */
+#define FSL_DDR_ODT_NEVER 0x0 +#define FSL_DDR_ODT_CS 0x1 +#define FSL_DDR_ODT_ALL_OTHER_CS 0x2 +#define FSL_DDR_ODT_OTHER_DIMM 0x3 +#define FSL_DDR_ODT_ALL 0x4 +#define FSL_DDR_ODT_SAME_DIMM 0x5 +#define FSL_DDR_ODT_CS_AND_OTHER_DIMM 0x6 +#define FSL_DDR_ODT_OTHER_CS_ONSAMEDIMM 0x7 + /* define bank(chip select) interleaving mode */ #define FSL_DDR_CS0_CS1 0x40 #define FSL_DDR_CS2_CS3 0x20 @@ -106,6 +116,12 @@ typedef struct fsl_ddr_cfg_regs_s { unsigned int ddr_sdram_cfg_2; unsigned int ddr_sdram_mode; unsigned int ddr_sdram_mode_2; + unsigned int ddr_sdram_mode_3; + unsigned int ddr_sdram_mode_4; + unsigned int ddr_sdram_mode_5; + unsigned int ddr_sdram_mode_6; + unsigned int ddr_sdram_mode_7; + unsigned int ddr_sdram_mode_8; unsigned int ddr_sdram_md_cntl; unsigned int ddr_sdram_interval; unsigned int ddr_data_init; @@ -156,6 +172,8 @@ typedef struct memctl_options_s { unsigned int auto_precharge; unsigned int odt_rd_cfg; unsigned int odt_wr_cfg; + unsigned int odt_rtt_norm; + unsigned int odt_rtt_wr; } cs_local_opts[CONFIG_CHIP_SELECTS_PER_CTRL];
/* Special configurations for chip select */ diff --git a/doc/README.fsl-ddr b/doc/README.fsl-ddr index 9e3c539..a7ba193 100644 --- a/doc/README.fsl-ddr +++ b/doc/README.fsl-ddr @@ -104,4 +104,69 @@ Combination of hwconfig Hwconfig can be combined with multiple parameters, for example, on a supported platform
-hwconfig=fsl_ddr:addr_hash=true,ctlr_intlv=cacheline,bank_intlv=cs0_cs1_cs2_cs3 +hwconfig=fsl_ddr:addr_hash=true,ctlr_intlv=cacheline,bank_intlv=cs0_cs1_cs2_cs3,ecc=on + +Table for dynamic ODT for DDR3 +============================== +For single-slot system with quad-rank DIMM and dual-slot system, dynamic ODT may +be needed, depending on the configuration. The numbers in the following tables are +in Ohms. + +* denotes dynamic ODT + +Two slots system ++-----------------------+----------+---------------+-----------------------------+-----------------------------+ +| Configuration | |DRAM controller| Slot 1 | Slot 2 | ++-----------+-----------+----------+-------+-------+--------------+--------------+--------------+--------------+ +| | | | | | Rank 1 | Rank 2 | Rank 1 | Rank 2 | ++ Slot 1 | Slot 2 |Write/Read| Write | Read |-------+------+-------+------+-------+------+-------+------+ +| | | | | | Write | Read | Write | Read | Write | Read | Write | Read | ++-----------+-----------+----------+-------+-------+-------+------+-------+------+-------+------+-------+------+ +| | | Slot 1 | off | 75 | 120 | off | off | off | off | off | 30 | 30 | +| Dual Rank | Dual Rank |----------+-------+-------+-------+------+-------+------+-------+------+-------+------+ +| | | Slot 2 | off | 75 | off | off | 30 | 30 | 120 | off | off | off | ++-----------+-----------+----------+-------+-------+-------+------+-------+------+-------+------+-------+------+ +| | | Slot 1 | off | 75 | 120 | off | off | off | 20 | 20 | | | +| Dual Rank |Single Rank|----------+-------+-------+-------+------+-------+------+-------+------+-------+------+ +| | | Slot 2 | off | 75 | off | off | 20 | 20 | 120 *| off | | | ++-----------+-----------+----------+-------+-------+-------+------+-------+------+-------+------+-------+------+ +| | | Slot 1 | off | 75 | 120 *| off | | | off | off | 20 | 20 | +|Single Rank| Dual Rank |----------+-------+-------+-------+------+-------+------+-------+------+-------+------+ +| | | Slot 2 | off | 75 | 20 | 20 | | | 120 | off | off | off | ++-----------+-----------+----------+-------+-------+-------+------+-------+------+-------+------+-------+------+ +| | | Slot 1 | off | 75 | 120 *| off | | | 30 | 30 | | | +|Single Rank|Single Rank|----------+-------+-------+-------+------+-------+------+-------+------+-------+------+ +| | | Slot 2 | off | 75 | 30 | 30 | | | 120 *| off | | | ++-----------+-----------+----------+-------+-------+-------+------+-------+------+-------+------+-------+------+ +| Dual Rank | Empty | Slot 1 | off | 75 | 40 | off | off | off | | | | | ++-----------+-----------+----------+-------+-------+-------+------+-------+------+-------+------+-------+------+ +| Empty | Dual Rank | Slot 2 | off | 75 | | | | | 40 | off | off | off | ++-----------+-----------+----------+-------+-------+-------+------+-------+------+-------+------+-------+------+ +|Single Rank| Empty | Slot 1 | off | 75 | 40 | off | | | | | | | ++-----------+-----------+----------+-------+-------+-------+------+-------+------+-------+------+-------+------+ +| Empty |Single Rank| Slot 2 | off | 75 | | | | | 40 | off | | | ++-----------+-----------+----------+-------+-------+-------+------+-------+------+-------+------+-------+------+ + +Single slot system ++-------------+------------+---------------+-----------------------------+-----------------------------+ +| | |DRAM controller| Rank 1 | Rank 2 | Rank 3 | Rank 4 | +|Configuration| Write/Read |-------+-------+-------+------+-------+------+-------+------+-------+------+ +| | | Write | Read | Write | Read | Write | Read | Write | Read | Write | Read | ++-------------+------------+-------+-------+-------+------+-------+------+-------+------+-------+------+ +| | R1 | off | 75 | 120 *| off | off | off | 20 | 20 | off | off | +| |------------+-------+-------+-------+------+-------+------+-------+------+-------+------+ +| | R2 | off | 75 | off | 20 | 120 | off | 20 | 20 | off | off | +| Quad Rank |------------+-------+-------+-------+------+-------+------+-------+------+-------+------+ +| | R3 | off | 75 | 20 | 20 | off | off | 120 *| off | off | off | +| |------------+-------+-------+-------+------+-------+------+-------+------+-------+------+ +| | R4 | off | 75 | 20 | 20 | off | off | off | 20 | 120 | off | ++-------------+------------+-------+-------+-------+------+-------+------+-------+------+-------+------+ +| | R1 | off | 75 | 40 | off | off | off | +| Dual Rank |------------+-------+-------+-------+------+-------+------+ +| | R2 | off | 75 | 40 | off | off | off | ++-------------+------------+-------+-------+-------+------+-------+------+ +| Single Rank | R1 | off | 75 | 40 | off | ++-------------+------------+-------+-------+-------+------+ + +Reference http://www.xrosstalkmag.com/mag_issues/xrosstalk_oct08_final.pdf + http://download.micron.com/pdf/technotes/ddr3/tn4108_ddr3_design_guide.pdf

Dear York Sun,
In message 1292630381-23022-6-git-send-email-yorksun@freescale.com you wrote:
Added fsl_ddr_get_version() function to for DDR3 to poll DDRC IP version (major, minor, errata) to determine if unique mode registers are available. If true, always use unique mode registers. Dynamic ODT is enabled if needed. The table is documented in doc/README.fsl-ddr. This function may also need to be extend for future other platforms if such a feature exists.
Enable address parity and RCW by default for RDIMMs.
Change default output driver impedance from 34 ohm to 40ohm. Make it 34ohm for quad-rank RDIMMs.
...
+static void set_ddr_sdram_mode_3(fsl_ddr_cfg_regs_t *ddr,
const memctl_options_t *popts)
+{
- u16 esdmode; /* Extended SDRAM mode */
- u16 sdmode; /* SDRAM mode */
- u32 rtt;
- sdmode = ddr->ddr_sdram_mode & 0xFFFF;
- esdmode = (ddr->ddr_sdram_mode >> 16) & 0xFFFF;
- if (popts->rtt_override)
rtt = popts->rtt_override_value;
- else
rtt = popts->cs_local_opts[1].odt_rtt_norm;
- esdmode &= 0xFDBB; /* clear bit 9,6,2 */
- esdmode |= (0
| ((rtt & 0x4) << 7) /* rtt field is split */
| ((rtt & 0x2) << 5) /* rtt field is split */
| ((rtt & 0x1) << 2) /* rtt field is split */
);
- ddr->ddr_sdram_mode_3 = (0
| ((esdmode & 0xFFFF) << 16)
| ((sdmode & 0xFFFF) << 0)
);
- debug("FSLDDR: ddr_sdram_mode_3 = 0x%08x\n", ddr->ddr_sdram_mode_3);
+}
...
+static void set_ddr_sdram_mode_5(fsl_ddr_cfg_regs_t *ddr,
const memctl_options_t *popts)
+{
- u16 esdmode; /* Extended SDRAM mode */
- u16 sdmode; /* SDRAM mode */
- u32 rtt;
- sdmode = ddr->ddr_sdram_mode & 0xFFFF;
- esdmode = (ddr->ddr_sdram_mode >> 16) & 0xFFFF;
- if (popts->rtt_override)
rtt = popts->rtt_override_value;
- else
rtt = popts->cs_local_opts[2].odt_rtt_norm;
- esdmode &= 0xFDBB; /* clear bit 9,6,2 */
- esdmode |= (0
| ((rtt & 0x4) << 7) /* rtt field is split */
| ((rtt & 0x2) << 5) /* rtt field is split */
| ((rtt & 0x1) << 2) /* rtt field is split */
);
- ddr->ddr_sdram_mode_5 = (0
| ((esdmode & 0xFFFF) << 16)
| ((sdmode & 0xFFFF) << 0)
);
- debug("FSLDDR: ddr_sdram_mode_5 = 0x%08x\n", ddr->ddr_sdram_mode_5);
+}
Seems the only difference between these functions is the index into the array?
+static void set_ddr_sdram_mode_4(fsl_ddr_cfg_regs_t *ddr,
const memctl_options_t *popts)
+{
- u16 esdmode2 = 0; /* Extended SDRAM mode 2 */
- u16 esdmode3 = 0; /* Extended SDRAM mode 3 */
- u32 rtt_wr = 0; /* Dynamic ODT off */
- esdmode2 = (ddr->ddr_sdram_mode_2 >> 16) & 0xFFFF;
- esdmode3 = ddr->ddr_sdram_mode_2 & 0xFFFF;
- if (popts->rtt_override)
rtt_wr = popts->rtt_wr_override_value;
- else
rtt_wr = popts->cs_local_opts[1].odt_rtt_wr;
- esdmode2 &= 0xF9FF; /* clear bit 10, 9 */
- esdmode2 |= (rtt_wr & 0x3) << 9;
- ddr->ddr_sdram_mode_4 = (0
| ((esdmode2 & 0xFFFF) << 16)
| ((esdmode3 & 0xFFFF) << 0)
);
- debug("FSLDDR: ddr_sdram_mode_4 = 0x%08x\n", ddr->ddr_sdram_mode_4);
+}
...
+static void set_ddr_sdram_mode_6(fsl_ddr_cfg_regs_t *ddr,
const memctl_options_t *popts)
+{
- u16 esdmode2 = 0; /* Extended SDRAM mode 2 */
- u16 esdmode3 = 0; /* Extended SDRAM mode 3 */
- u32 rtt_wr = 0; /* Dynamic ODT off */
- esdmode2 = (ddr->ddr_sdram_mode_2 >> 16) & 0xFFFF;
- esdmode3 = ddr->ddr_sdram_mode_2 & 0xFFFF;
- if (popts->rtt_override)
rtt_wr = popts->rtt_wr_override_value;
- else
rtt_wr = popts->cs_local_opts[2].odt_rtt_wr;
- esdmode2 &= 0xF9FF; /* clear bit 10, 9 */
- esdmode2 |= (rtt_wr & 0x3) << 9;
- ddr->ddr_sdram_mode_6 = (0
| ((esdmode2 & 0xFFFF) << 16)
| ((esdmode3 & 0xFFFF) << 0)
);
- debug("FSLDDR: ddr_sdram_mode_6 = 0x%08x\n", ddr->ddr_sdram_mode_6);
+}
Same here.
+static void set_ddr_sdram_mode_7(fsl_ddr_cfg_regs_t *ddr,
const memctl_options_t *popts)
+{
- u16 esdmode; /* Extended SDRAM mode */
- u16 sdmode; /* SDRAM mode */
- u32 rtt;
- sdmode = ddr->ddr_sdram_mode & 0xFFFF;
- esdmode = (ddr->ddr_sdram_mode >> 16) & 0xFFFF;
- if (popts->rtt_override)
rtt = popts->rtt_override_value;
- else
rtt = popts->cs_local_opts[3].odt_rtt_norm;
- esdmode &= 0xFDBB; /* clear bit 9,6,2 */
- esdmode |= (0
| ((rtt & 0x4) << 7) /* rtt field is split */
| ((rtt & 0x2) << 5) /* rtt field is split */
| ((rtt & 0x1) << 2) /* rtt field is split */
);
- ddr->ddr_sdram_mode_7 = (0
| ((esdmode & 0xFFFF) << 16)
| ((sdmode & 0xFFFF) << 0)
);
- debug("FSLDDR: ddr_sdram_mode_7 = 0x%08x\n", ddr->ddr_sdram_mode_7);
+}
+static void set_ddr_sdram_mode_8(fsl_ddr_cfg_regs_t *ddr,
const memctl_options_t *popts)
+{
- u16 esdmode2 = 0; /* Extended SDRAM mode 2 */
- u16 esdmode3 = 0; /* Extended SDRAM mode 3 */
- u32 rtt_wr = 0; /* Rtt_WR - dynamic ODT off */
- esdmode2 = (ddr->ddr_sdram_mode_2 >> 16) & 0xFFFF;
- esdmode3 = ddr->ddr_sdram_mode_2 & 0xFFFF;
- if (popts->rtt_override)
rtt_wr = popts->rtt_wr_override_value;
- else
rtt_wr = popts->cs_local_opts[3].odt_rtt_wr;
- esdmode2 &= 0xF9FF; /* clear bit 10, 9 */
- esdmode2 |= (rtt_wr & 0x3) << 9;
- ddr->ddr_sdram_mode_8 = (0
| ((esdmode2 & 0xFFFF) << 16)
| ((esdmode3 & 0xFFFF) << 0)
);
- debug("FSLDDR: ddr_sdram_mode_8 = 0x%08x\n", ddr->ddr_sdram_mode_8);
+}
And two more copies...
Please do not duplicate code.
Best regards,
Wolfgang Denk

Adding byte 32 and 33
Signed-off-by: York Sun yorksun@freescale.com --- include/ddr_spd.h | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/include/ddr_spd.h b/include/ddr_spd.h index 710e528..d632a1e 100644 --- a/include/ddr_spd.h +++ b/include/ddr_spd.h @@ -219,7 +219,9 @@ typedef struct ddr3_spd_eeprom_s { Delay Time*/ unsigned char opt_features; /* 30 SDRAM Optional Features */ unsigned char therm_ref_opt; /* 31 SDRAM Thermal and Refresh Opts */ - unsigned char res_32_59[28]; /* 32-59 Reserved, General Section */ + unsigned char therm_sensor; /* 32 Module Thermal Sensor */ + unsigned char device_type; /* 33 SDRAM device type */ + unsigned char res_34_59[26]; /* 34-59 Reserved, General Section */
/* Module-Specific Section: Bytes 60-116 */ union {

Dear York Sun,
In message 1292630381-23022-7-git-send-email-yorksun@freescale.com you wrote:
Adding byte 32 and 33
Signed-off-by: York Sun yorksun@freescale.com
include/ddr_spd.h | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-)
Where are these new definitions used?
Best regards,
Wolfgang Denk

Erratum DDR-A003 requires workaround to correctly set RCW10 for registered DIMM. Also adding polling after enabling DDR controller to ensure completion.
Signed-off-by: York Sun yorksun@freescale.com --- arch/powerpc/cpu/mpc85xx/cmd_errata.c | 4 ++ arch/powerpc/cpu/mpc85xx/ddr-gen3.c | 81 +++++++++++++++++++++++++++++- arch/powerpc/include/asm/fsl_ddr_sdram.h | 19 +++++++ include/configs/P4080DS.h | 1 + 4 files changed, 104 insertions(+), 1 deletions(-)
diff --git a/arch/powerpc/cpu/mpc85xx/cmd_errata.c b/arch/powerpc/cpu/mpc85xx/cmd_errata.c index d73f3d7..9edaa0b 100644 --- a/arch/powerpc/cpu/mpc85xx/cmd_errata.c +++ b/arch/powerpc/cpu/mpc85xx/cmd_errata.c @@ -47,6 +47,10 @@ static int do_errata(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) #if defined(CONFIG_SYS_P4080_ERRATUM_CPU22) puts("Work-around for Erratum CPU22 enabled\n"); #endif +#ifdef CONFIG_SYS_FSL_NMG_DDR_A003 + puts("Work-around for Erratum DDR-A003 enabled\n"); +#endif + return 0; }
diff --git a/arch/powerpc/cpu/mpc85xx/ddr-gen3.c b/arch/powerpc/cpu/mpc85xx/ddr-gen3.c index 5f1848f..a7c9024 100644 --- a/arch/powerpc/cpu/mpc85xx/ddr-gen3.c +++ b/arch/powerpc/cpu/mpc85xx/ddr-gen3.c @@ -97,6 +97,82 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs, temp_sdram_cfg = regs->ddr_sdram_cfg; temp_sdram_cfg &= ~(SDRAM_CFG_MEM_EN); out_be32(&ddr->sdram_cfg, temp_sdram_cfg); +#ifdef CONFIG_SYS_FSL_NMG_DDR_A003 + if (regs->ddr_sdram_rcw_2 & 0x00f00000) { + out_be32(&ddr->timing_cfg_2, regs->timing_cfg_2 & 0xf07fffff); + out_be32(&ddr->debug[2], 0x00000400); + out_be32(&ddr->ddr_zq_cntl, regs->ddr_zq_cntl & 0x7fffffff); + out_be32(&ddr->ddr_wrlvl_cntl, regs->ddr_wrlvl_cntl & 0x7fffffff); + out_be32(&ddr->sdram_cfg_2, regs->ddr_sdram_cfg_2 & 0xffffffeb); + out_be32(&ddr->mtcr, 0); + out_be32(&ddr->debug[12], 0x00000015); + out_be32(&ddr->debug[21], 0x24000000); + out_be32(&ddr->sdram_interval, regs->ddr_sdram_interval & 0xffff); + out_be32(&ddr->sdram_cfg, temp_sdram_cfg | SDRAM_CFG_BI | SDRAM_CFG_MEM_EN); + + asm volatile("sync;isync"); + while (!(in_be32(&ddr->debug[1]) & 0x2)) + ; + + switch (regs->ddr_sdram_rcw_2 & 0x00f00000) { + case 0x00000000: + out_be32(&ddr->sdram_md_cntl, + MD_CNTL_MD_EN | + MD_CNTL_CS_SEL_CS0_CS1 | + 0x04000000 | + MD_CNTL_WRCW | + MD_CNTL_MD_VALUE(0x02)); + break; + case 0x00100000: + out_be32(&ddr->sdram_md_cntl, + MD_CNTL_MD_EN | + MD_CNTL_CS_SEL_CS0_CS1 | + 0x04000000 | + MD_CNTL_WRCW | + MD_CNTL_MD_VALUE(0x0a)); + break; + case 0x00200000: + out_be32(&ddr->sdram_md_cntl, + MD_CNTL_MD_EN | + MD_CNTL_CS_SEL_CS0_CS1 | + 0x04000000 | + MD_CNTL_WRCW | + MD_CNTL_MD_VALUE(0x12)); + break; + case 0x00300000: + out_be32(&ddr->sdram_md_cntl, + MD_CNTL_MD_EN | + MD_CNTL_CS_SEL_CS0_CS1 | + 0x04000000 | + MD_CNTL_WRCW | + MD_CNTL_MD_VALUE(0x1a)); + break; + default: + out_be32(&ddr->sdram_md_cntl, + MD_CNTL_MD_EN | + MD_CNTL_CS_SEL_CS0_CS1 | + 0x04000000 | + MD_CNTL_WRCW | + MD_CNTL_MD_VALUE(0x02)); + printf("Unsupported RC10\n"); + break; + } + + while (in_be32(&ddr->sdram_md_cntl) & 0x80000000) + ; + udelay(6); + out_be32(&ddr->sdram_cfg, temp_sdram_cfg); + out_be32(&ddr->timing_cfg_2, regs->timing_cfg_2); + out_be32(&ddr->debug[2], 0x0); + out_be32(&ddr->ddr_zq_cntl, regs->ddr_zq_cntl); + out_be32(&ddr->ddr_wrlvl_cntl, regs->ddr_wrlvl_cntl); + out_be32(&ddr->sdram_cfg_2, regs->ddr_sdram_cfg_2); + out_be32(&ddr->debug[12], 0x0); + out_be32(&ddr->debug[21], 0x0); + out_be32(&ddr->sdram_interval, regs->ddr_sdram_interval); + + } +#endif /* * For 8572 DDR1 erratum - DDR controller may enter illegal state * when operatiing in 32-bit bus mode with 4-beat bursts, @@ -120,8 +196,11 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs, asm volatile("sync;isync");
/* Let the controller go */ - temp_sdram_cfg = in_be32(&ddr->sdram_cfg); + temp_sdram_cfg = in_be32(&ddr->sdram_cfg) & ~SDRAM_CFG_BI; out_be32(&ddr->sdram_cfg, temp_sdram_cfg | SDRAM_CFG_MEM_EN); + asm volatile("sync;isync"); + while (!(in_be32(&ddr->debug[1]) & 0x2)) + ;
/* Poll DDR_SDRAM_CFG_2[D_INIT] bit until auto-data init is done. */ while (in_be32(&ddr->sdram_cfg_2) & 0x10) { diff --git a/arch/powerpc/include/asm/fsl_ddr_sdram.h b/arch/powerpc/include/asm/fsl_ddr_sdram.h index e8b9c04..7d6048a 100644 --- a/arch/powerpc/include/asm/fsl_ddr_sdram.h +++ b/arch/powerpc/include/asm/fsl_ddr_sdram.h @@ -101,6 +101,25 @@ typedef ddr3_spd_eeprom_t generic_spd_eeprom_t; #define WR_DATA_DELAY_SHIFT 10 #endif
+/* DDR_MD_CNTL */ +#define MD_CNTL_MD_EN 0x80000000 +#define MD_CNTL_CS_SEL_CS0 0x00000000 +#define MD_CNTL_CS_SEL_CS1 0x10000000 +#define MD_CNTL_CS_SEL_CS2 0x20000000 +#define MD_CNTL_CS_SEL_CS3 0x30000000 +#define MD_CNTL_CS_SEL_CS0_CS1 0x40000000 +#define MD_CNTL_CS_SEL_CS2_CS3 0x50000000 +#define MD_CNTL_MD_SEL_MR 0x00000000 +#define MD_CNTL_MD_SEL_EMR 0x01000000 +#define MD_CNTL_MD_SEL_EMR2 0x02000000 +#define MD_CNTL_MD_SEL_EMR3 0x03000000 +#define MD_CNTL_SET_REF 0x00800000 +#define MD_CNTL_SET_PRE 0x00400000 +#define MD_CNTL_CKE_CNTL_LOW 0x00100000 +#define MD_CNTL_CKE_CNTL_HIGH 0x00200000 +#define MD_CNTL_WRCW 0x00080000 +#define MD_CNTL_MD_VALUE(x) (x & 0x0000FFFF) + /* Record of register values computed */ typedef struct fsl_ddr_cfg_regs_s { struct { diff --git a/include/configs/P4080DS.h b/include/configs/P4080DS.h index 21b48e9..f1e8a17 100644 --- a/include/configs/P4080DS.h +++ b/include/configs/P4080DS.h @@ -37,5 +37,6 @@
#define CONFIG_SYS_P4080_ERRATUM_CPU22 #define CONFIG_SYS_P4080_ERRATUM_SERDES8 +#define CONFIG_SYS_FSL_NMG_DDR_A003
#include "corenet_ds.h"

On Dec 17, 2010, at 5:59 PM, York Sun wrote:
Erratum DDR-A003 requires workaround to correctly set RCW10 for registered DIMM. Also adding polling after enabling DDR controller to ensure completion.
Signed-off-by: York Sun yorksun@freescale.com
arch/powerpc/cpu/mpc85xx/cmd_errata.c | 4 ++ arch/powerpc/cpu/mpc85xx/ddr-gen3.c | 81 +++++++++++++++++++++++++++++- arch/powerpc/include/asm/fsl_ddr_sdram.h | 19 +++++++ include/configs/P4080DS.h | 1 + 4 files changed, 104 insertions(+), 1 deletions(-)
diff --git a/arch/powerpc/cpu/mpc85xx/cmd_errata.c b/arch/powerpc/cpu/mpc85xx/cmd_errata.c index d73f3d7..9edaa0b 100644 --- a/arch/powerpc/cpu/mpc85xx/cmd_errata.c +++ b/arch/powerpc/cpu/mpc85xx/cmd_errata.c @@ -47,6 +47,10 @@ static int do_errata(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) #if defined(CONFIG_SYS_P4080_ERRATUM_CPU22) puts("Work-around for Erratum CPU22 enabled\n"); #endif +#ifdef CONFIG_SYS_FSL_NMG_DDR_A003
change this to CONFIG_SYS_FSL_ERRATUM_DDR_A003
- puts("Work-around for Erratum DDR-A003 enabled\n");
+#endif
- return 0;
}
- k

Extend board specific parameters to include cpo, write leveling override Extend write leveling sample to 0xf Adding rcw overrid for quad-rank RDIMMs
Signed-off-by: York Sun yorksun@freescale.com --- arch/powerpc/include/asm/fsl_ddr_sdram.h | 3 + board/freescale/corenet_ds/ddr.c | 155 +++++++++++++++--------------- 2 files changed, 81 insertions(+), 77 deletions(-)
diff --git a/arch/powerpc/include/asm/fsl_ddr_sdram.h b/arch/powerpc/include/asm/fsl_ddr_sdram.h index 7d6048a..0cfe95a 100644 --- a/arch/powerpc/include/asm/fsl_ddr_sdram.h +++ b/arch/powerpc/include/asm/fsl_ddr_sdram.h @@ -120,6 +120,9 @@ typedef ddr3_spd_eeprom_t generic_spd_eeprom_t; #define MD_CNTL_WRCW 0x00080000 #define MD_CNTL_MD_VALUE(x) (x & 0x0000FFFF)
+/* DDR_CDR1 */ +#define DDR_CDR1_DHC_EN 0x80000000 + /* Record of register values computed */ typedef struct fsl_ddr_cfg_regs_s { struct { diff --git a/board/freescale/corenet_ds/ddr.c b/board/freescale/corenet_ds/ddr.c index 2ee0188..30e1baa 100644 --- a/board/freescale/corenet_ds/ddr.c +++ b/board/freescale/corenet_ds/ddr.c @@ -56,12 +56,14 @@ phys_size_t fixed_sdram(void) strmhz(buf, sysinfo.freqDDRBus));
ddr_size = (phys_size_t) CONFIG_SYS_SDRAM_SIZE * 1024 * 1024; + ddr_cfg_regs.ddr_cdr1 = DDR_CDR1_DHC_EN; fsl_ddr_set_memctl_regs(&ddr_cfg_regs, 0);
#if (CONFIG_NUM_DDR_CONTROLLERS == 2) memcpy(&ddr_cfg_regs, fixed_ddr_parm_1[i].ddr_settings, sizeof(ddr_cfg_regs)); + ddr_cfg_regs.ddr_cdr1 = DDR_CDR1_DHC_EN; fsl_ddr_set_memctl_regs(&ddr_cfg_regs, 1); #endif
@@ -143,6 +145,7 @@ typedef struct { u32 datarate_mhz_high; u32 n_ranks; u32 clk_adjust; + u32 wrlvl_start; u32 cpo; u32 write_data_delay; u32 force_2T; @@ -162,57 +165,59 @@ typedef struct { /* XXX: Single rank at 800 MHz is OK. */ const board_specific_parameters_t board_specific_parameters[][30] = { { - /* memory controller 0 */ - /* lo| hi| num| clk| cpo|wrdata|2T */ - /* mhz| mhz|ranks|adjst| | delay| */ - { 0, 333, 4, 6, 7, 3, 0}, - {334, 400, 4, 6, 9, 3, 0}, - {401, 549, 4, 6, 11, 3, 0}, - {550, 680, 4, 1, 10, 5, 0}, - {681, 850, 4, 1, 12, 5, 0}, - {851, 1050, 4, 1, 12, 5, 0}, - {1051, 1250, 4, 1, 15, 4, 0}, - {1251, 1350, 4, 1, 15, 4, 0}, - { 0, 333, 2, 6, 7, 3, 0}, - {334, 400, 2, 6, 9, 3, 0}, - {401, 549, 2, 6, 11, 3, 0}, - {550, 680, 2, 1, 10, 5, 0}, - {681, 850, 2, 1, 12, 5, 0}, - {851, 1050, 2, 1, 12, 5, 0}, - {1051, 1250, 2, 1, 15, 4, 0}, - {1251, 1350, 2, 1, 15, 4, 0}, - { 0, 333, 1, 6, 7, 3, 0}, - {334, 400, 1, 6, 9, 3, 0}, - {401, 549, 1, 6, 11, 3, 0}, - {550, 680, 1, 1, 10, 5, 0}, - {681, 850, 1, 1, 12, 5, 0} + /* memory controller 0 + * lo| hi| num| clk| wrlvl | cpo |wrdata|2T + * mhz| mhz|ranks|adjst| start | delay| + */ + { 0, 333, 4, 5, 7, 0xff, 2, 0}, + {334, 400, 4, 5, 7, 0xff, 2, 0}, + {401, 549, 4, 5, 7, 0xff, 2, 0}, + {550, 680, 4, 5, 7, 0xff, 2, 0}, + {681, 850, 4, 5, 7, 0xff, 2, 0}, + {851, 1050, 4, 5, 7, 0xff, 2, 0}, + {1051, 1250, 4, 5, 8, 0xff, 2, 0}, + {1251, 1350, 4, 5, 9, 0xff, 2, 0}, + { 0, 333, 2, 5, 7, 0xff, 2, 0}, + {334, 400, 2, 5, 7, 0xff, 2, 0}, + {401, 549, 2, 5, 7, 0xff, 2, 0}, + {550, 680, 2, 5, 7, 0xff, 2, 0}, + {681, 850, 2, 5, 7, 0xff, 2, 0}, + {851, 1050, 2, 5, 7, 0xff, 2, 0}, + {1051, 1250, 2, 5, 7, 0xff, 2, 0}, + {1251, 1350, 2, 5, 7, 0xff, 2, 0}, + { 0, 333, 1, 5, 7, 0xff, 2, 0}, + {334, 400, 1, 5, 7, 0xff, 2, 0}, + {401, 549, 1, 5, 7, 0xff, 2, 0}, + {550, 680, 1, 5, 7, 0xff, 2, 0}, + {681, 850, 1, 5, 7, 0xff, 2, 0} },
{ - /* memory controller 1 */ - /* lo| hi| num| clk| cpo|wrdata|2T */ - /* mhz| mhz|ranks|adjst| | delay| */ - { 0, 333, 4, 6, 7, 3, 0}, - {334, 400, 4, 6, 9, 3, 0}, - {401, 549, 4, 6, 11, 3, 0}, - {550, 680, 4, 1, 10, 5, 0}, - {681, 850, 4, 1, 12, 5, 0}, - {851, 1050, 4, 1, 12, 5, 0}, - {1051, 1250, 4, 1, 15, 4, 0}, - {1251, 1350, 4, 1, 15, 4, 0}, - { 0, 333, 2, 6, 7, 3, 0}, - {334, 400, 2, 6, 9, 3, 0}, - {401, 549, 2, 6, 11, 3, 0}, - {550, 680, 2, 1, 11, 6, 0}, - {681, 850, 2, 1, 13, 6, 0}, - {851, 1050, 2, 1, 13, 6, 0}, - {1051, 1250, 2, 1, 15, 4, 0}, - {1251, 1350, 2, 1, 15, 4, 0}, - { 0, 333, 1, 6, 7, 3, 0}, - {334, 400, 1, 6, 9, 3, 0}, - {401, 549, 1, 6, 11, 3, 0}, - {550, 680, 1, 1, 11, 6, 0}, - {681, 850, 1, 1, 13, 6, 0} + /* memory controller 1 + * lo| hi| num| clk| wrlvl | cpo |wrdata|2T + * mhz| mhz|ranks|adjst| start | delay| + */ + { 0, 333, 4, 5, 7, 0xff, 2, 0}, + {334, 400, 4, 5, 7, 0xff, 2, 0}, + {401, 549, 4, 5, 7, 0xff, 2, 0}, + {550, 680, 4, 5, 7, 0xff, 2, 0}, + {681, 850, 4, 5, 7, 0xff, 2, 0}, + {851, 1050, 4, 5, 7, 0xff, 2, 0}, + {1051, 1250, 4, 5, 8, 0xff, 2, 0}, + {1251, 1350, 4, 5, 9, 0xff, 2, 0}, + { 0, 333, 2, 5, 7, 0xff, 2, 0}, + {334, 400, 2, 5, 7, 0xff, 2, 0}, + {401, 549, 2, 5, 7, 0xff, 2, 0}, + {550, 680, 2, 5, 7, 0xff, 2, 0}, + {681, 850, 2, 5, 7, 0xff, 2, 0}, + {851, 1050, 2, 5, 7, 0xff, 2, 0}, + {1051, 1250, 2, 5, 7, 0xff, 2, 0}, + {1251, 1350, 2, 5, 7, 0xff, 2, 0}, + { 0, 333, 1, 5, 7, 0xff, 2, 0}, + {334, 400, 1, 5, 7, 0xff, 2, 0}, + {401, 549, 1, 5, 7, 0xff, 2, 0}, + {550, 680, 1, 5, 7, 0xff, 2, 0}, + {681, 850, 1, 5, 7, 0xff, 2, 0} } };
@@ -227,26 +232,6 @@ void fsl_ddr_board_options(memctl_options_t *popts, u32 i; ulong ddr_freq;
- /* set odt_rd_cfg and odt_wr_cfg. If the there is only one dimm in - * that controller, set odt_wr_cfg to 4 for CS0, and 0 to CS1. If - * there are two dimms in the controller, set odt_rd_cfg to 3 and - * odt_wr_cfg to 3 for the even CS, 0 for the odd CS. - */ - for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { - if (i&1) { /* odd CS */ - popts->cs_local_opts[i].odt_rd_cfg = 0; - popts->cs_local_opts[i].odt_wr_cfg = 1; - } else { /* even CS */ - if (CONFIG_DIMM_SLOTS_PER_CTLR == 1) { - popts->cs_local_opts[i].odt_rd_cfg = 0; - popts->cs_local_opts[i].odt_wr_cfg = 1; - } else if (CONFIG_DIMM_SLOTS_PER_CTLR == 2) { - popts->cs_local_opts[i].odt_rd_cfg = 3; - popts->cs_local_opts[i].odt_wr_cfg = 3; - } - } - } - /* Get clk_adjust, cpo, write_data_delay,2T, according to the board ddr * freqency and n_banks specified in board_specific_parameters table. */ @@ -254,10 +239,11 @@ void fsl_ddr_board_options(memctl_options_t *popts, for (i = 0; i < num_params; i++) { if (ddr_freq >= pbsp->datarate_mhz_low && ddr_freq <= pbsp->datarate_mhz_high && - pdimm->n_ranks == pbsp->n_ranks) { - popts->cpo_override = 0xff; /* force auto CPO calibration */ - popts->write_data_delay = 2; - popts->clk_adjust = 5; /* Force value to be 5/8 clock cycle */ + pdimm[0].n_ranks == pbsp->n_ranks) { + popts->cpo_override = pbsp->cpo; + popts->write_data_delay = pbsp->write_data_delay; + popts->clk_adjust = pbsp->clk_adjust; + popts->wrlvl_start = pbsp->wrlvl_start; popts->twoT_en = pbsp->force_2T; } pbsp++; @@ -272,17 +258,32 @@ void fsl_ddr_board_options(memctl_options_t *popts, * Write leveling override */ popts->wrlvl_override = 1; - popts->wrlvl_sample = 0xa; - popts->wrlvl_start = 0x7; + popts->wrlvl_sample = 0xf; + /* * Rtt and Rtt_WR override */ - popts->rtt_override = 1; - popts->rtt_override_value = DDR3_RTT_120_OHM; - popts->rtt_wr_override_value = 0; /* Rtt_WR= dynamic ODT off */ + popts->rtt_override = 0;
/* Enable ZQ calibration */ popts->zq_en = 1; + + /* DHC_EN =1, ODT = 60 Ohm */ + popts->ddr_cdr1 = DDR_CDR1_DHC_EN; + + /* override SPD values. rcw_2 should vary at differnt speed */ + if (pdimm[0].n_ranks == 4) { + popts->rcw_override = 1; + popts->rcw_1 = 0x000a5a00; + if (ddr_freq <= 800) + popts->rcw_2 = 0x00000000; + else if (ddr_freq <= 1066) + popts->rcw_2 = 0x00100000; + else if (ddr_freq <= 1333) + popts->rcw_2 = 0x00200000; + else + popts->rcw_2 = 0x00300000; + } }
phys_size_t initdram(int board_type)

Dear York Sun,
In message 1292630381-23022-9-git-send-email-yorksun@freescale.com you wrote:
Extend board specific parameters to include cpo, write leveling override Extend write leveling sample to 0xf Adding rcw overrid for quad-rank RDIMMs
...
- /* memory controller 0
* lo| hi| num| clk| wrlvl | cpo |wrdata|2T
* mhz| mhz|ranks|adjst| start | delay|
*/
Incorrect multi-line comment style. Please fix globally.
pdimm[0].n_ranks == pbsp->n_ranks) {
popts->cpo_override = pbsp->cpo;
popts->write_data_delay = pbsp->write_data_delay;
popts->clk_adjust = pbsp->clk_adjust;
popts->wrlvl_start = pbsp->wrlvl_start;
Indentation by TAB only. Please fix globally.
Best regards,
Wolfgang Denk

Dear York Sun,
In message 1292630381-23022-1-git-send-email-yorksun@freescale.com you wrote:
Print a message when a RDIMM is detected.
...
- } else printf("ERROR: Mix of registered buffered and unbuffered " "DIMMs detected!\n");
- }
Mutli-line statement needs braces.
Best regards,
Wolfgang Denk

Hello.
On 19-12-2010 1:21, Wolfgang Denk wrote:
Print a message when a RDIMM is detected.
...
- } else printf("ERROR: Mix of registered buffered and unbuffered " "DIMMs detected!\n");
- }
Mutli-line statement needs braces.
Well, not only that. CodingStyle requires that if some parts of the *if* statement used {}, then all parts need to use {}.
Best regards,
Wolfgang Denk
WBR, Sergei
participants (4)
-
Kumar Gala
-
Sergei Shtylyov
-
Wolfgang Denk
-
York Sun