[U-Boot] [PATCH 01/10] 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 1291863340-4354-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.
What does this mean? "temporarily fix" ? Do you have another, permanent fix in the works
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
Is this really, really necessary? Memory is a scarce resource pre relocation.
Best regards,
Wolfgang Denk

Wolfgang,
On Thu, 2010-12-09 at 11:12 +0100, Wolfgang Denk wrote:
Dear York Sun,
In message 1291863340-4354-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.
What does this mean? "temporarily fix" ? Do you have another, permanent fix in the works
I am not happy with this "fix" either. Kumar changed the code to use deeper buffer as a workaround. This is the only way I can make it work following him.
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
Is this really, really necessary? Memory is a scarce resource pre relocation.
Let me work with Kumar on this.
York

On Dec 10, 2010, at 12:50 PM, York Sun wrote:
Wolfgang,
On Thu, 2010-12-09 at 11:12 +0100, Wolfgang Denk wrote:
Dear York Sun,
In message 1291863340-4354-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.
What does this mean? "temporarily fix" ? Do you have another, permanent fix in the works
I am not happy with this "fix" either. Kumar changed the code to use deeper buffer as a workaround. This is the only way I can make it work following him.
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
Is this really, really necessary? Memory is a scarce resource pre relocation.
Let me work with Kumar on this.
Got any ideas? I'm not a fan but not sure what else we can do.
- k

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 ca5f63e..f876e20 100644 --- a/arch/powerpc/cpu/mpc8xxx/ddr/options.c +++ b/arch/powerpc/cpu/mpc8xxx/ddr/options.c @@ -82,10 +82,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 ==================================

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 registeres.
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 | 19 +------------------ 3 files changed, 21 insertions(+), 20 deletions(-)
diff --git a/arch/powerpc/cpu/mpc85xx/ddr-gen3.c b/arch/powerpc/cpu/mpc85xx/ddr-gen3.c index 5805b3f..14a905d 100644 --- a/arch/powerpc/cpu/mpc85xx/ddr-gen3.c +++ b/arch/powerpc/cpu/mpc85xx/ddr-gen3.c @@ -80,6 +80,13 @@ 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 < 18; i++) + out_be32(&ddr->debug[i], regs->debug[i]); + #ifdef CONFIG_SYS_P4080_ERRATUM_DDR7 /* * Do not use automatic driver calibration, Instead of @@ -104,8 +111,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..6ec95b6 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[18]; } 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 ee7338a..474082f 100644 --- a/arch/powerpc/include/asm/immap_85xx.h +++ b/arch/powerpc/include/asm/immap_85xx.h @@ -222,24 +222,7 @@ 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; + u32 debug[18]; /* debug_1 to debug_18 */ u8 res12[184]; } ccsr_ddr_t;

On Dec 8, 2010, at 8:55 PM, York Sun 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 registeres.
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 | 19 +------------------ 3 files changed, 21 insertions(+), 20 deletions(-)
this probably breaks boards. Did you do a build all on 85xx and 86xx?
- k

On Mon, 2010-12-13 at 23:10 -0600, Kumar Gala wrote:
On Dec 8, 2010, at 8:55 PM, York Sun 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 registeres.
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 | 19 +------------------ 3 files changed, 21 insertions(+), 20 deletions(-)
this probably breaks boards. Did you do a build all on 85xx and 86xx?
No, I didn't try on other boards. The registers have default value of 0, which shouldn't hurt.
York

On Dec 14, 2010, at 12:30 AM, York Sun wrote:
On Mon, 2010-12-13 at 23:10 -0600, Kumar Gala wrote:
On Dec 8, 2010, at 8:55 PM, York Sun 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 registeres.
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 | 19 +------------------ 3 files changed, 21 insertions(+), 20 deletions(-)
this probably breaks boards. Did you do a build all on 85xx and 86xx?
No, I didn't try on other boards. The registers have default value of 0, which shouldn't hurt.
York
Its not that, I think we fail to even compile.
For example:
[galak@right u-boot]$ git grep debug_ board/tqc/ board/tqc/tqm85xx/sdram.c: ddr->debug_3 |= 0x00000400; board/tqc/tqm85xx/sdram.c: ddr->debug_3 &= ~0x00000400; board/tqc/tqm85xx/sdram.c: ddr->debug_2 |= 0x00000400; board/tqc/tqm85xx/sdram.c: while (ddr->debug_2 & 0x00000400)
- k

On Tue, 2010-12-14 at 00:37 -0600, Kumar Gala wrote:
On Dec 14, 2010, at 12:30 AM, York Sun wrote:
On Mon, 2010-12-13 at 23:10 -0600, Kumar Gala wrote:
On Dec 8, 2010, at 8:55 PM, York Sun 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 registeres.
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 | 19 +------------------ 3 files changed, 21 insertions(+), 20 deletions(-)
this probably breaks boards. Did you do a build all on 85xx and 86xx?
No, I didn't try on other boards. The registers have default value of 0, which shouldn't hurt.
York
Its not that, I think we fail to even compile.
For example:
[galak@right u-boot]$ git grep debug_ board/tqc/ board/tqc/tqm85xx/sdram.c: ddr->debug_3 |= 0x00000400; board/tqc/tqm85xx/sdram.c: ddr->debug_3 &= ~0x00000400; board/tqc/tqm85xx/sdram.c: ddr->debug_2 |= 0x00000400; board/tqc/tqm85xx/sdram.c: while (ddr->debug_2 & 0x00000400)
You are right. I didn't think there are other boards out of freescale folder. Do you want to me revert back to debug_x or change all of them to debug[x]?
York

On Dec 14, 2010, at 12:42 AM, York Sun wrote:
On Tue, 2010-12-14 at 00:37 -0600, Kumar Gala wrote:
On Dec 14, 2010, at 12:30 AM, York Sun wrote:
On Mon, 2010-12-13 at 23:10 -0600, Kumar Gala wrote:
On Dec 8, 2010, at 8:55 PM, York Sun 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 registeres.
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 | 19 +------------------ 3 files changed, 21 insertions(+), 20 deletions(-)
this probably breaks boards. Did you do a build all on 85xx and 86xx?
No, I didn't try on other boards. The registers have default value of 0, which shouldn't hurt.
York
Its not that, I think we fail to even compile.
For example:
[galak@right u-boot]$ git grep debug_ board/tqc/ board/tqc/tqm85xx/sdram.c: ddr->debug_3 |= 0x00000400; board/tqc/tqm85xx/sdram.c: ddr->debug_3 &= ~0x00000400; board/tqc/tqm85xx/sdram.c: ddr->debug_2 |= 0x00000400; board/tqc/tqm85xx/sdram.c: while (ddr->debug_2 & 0x00000400)
You are right. I didn't think there are other boards out of freescale folder. Do you want to me revert back to debug_x or change all of them to debug[x]?
Just change to debug[x] for the other places that are impacted.
- k

Added fsl_ddr_get_version() function to poll DDRC IP version (major, minor, errata) to determine if unique mode registers are available. This function may be needed for future other platforms if such a feature exists. If true, always use unique mode registers. Dynamic ODT is enabled if needed. The table is documented in doc/README.fsl-ddr.
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 | 18 ++ arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c | 305 +++++++++++++++++++++++++---- arch/powerpc/cpu/mpc8xxx/ddr/options.c | 308 +++++++++++++++++++++++++++++- arch/powerpc/include/asm/fsl_ddr_sdram.h | 18 ++ board/freescale/corenet_ds/ddr.c | 125 ++++++------- doc/README.fsl-ddr | 67 +++++++- 6 files changed, 723 insertions(+), 118 deletions(-)
diff --git a/arch/powerpc/cpu/mpc85xx/ddr-gen3.c b/arch/powerpc/cpu/mpc85xx/ddr-gen3.c index 14a905d..568f9f4 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); @@ -133,3 +139,15 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs, udelay(10000); /* throttle polling rate */ } } + +u32 fsl_ddr_get_version(void) +{ + ccsr_ddr_t *ddr; + u32 ver_major_minor_errata; + + ddr = (void *)CONFIG_SYS_MPC85xx_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; +} diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c b/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c index 3fec100..2132986 100644 --- a/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c +++ b/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c @@ -18,7 +18,13 @@
#include "ddr.h"
-extern unsigned int picos_to_mclk(unsigned int picos); +u32 __attribute__((weak)) fsl_ddr_get_version(void) +{ + return 0; +} + +unsigned int picos_to_mclk(unsigned int picos); + /* * Determine Rtt value. * @@ -187,7 +193,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 +211,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 +221,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 +465,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 +530,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 +557,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 +584,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 +625,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 +646,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 +655,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 +681,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 +697,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 +893,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 +911,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 +1221,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 +1229,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 +1266,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 +1312,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 +1335,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 +1353,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 +1391,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 +1606,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 +1614,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 f876e20..e5b04c8 100644 --- a/arch/powerpc/cpu/mpc8xxx/ddr/options.c +++ b/arch/powerpc/cpu/mpc8xxx/ddr/options.c @@ -19,23 +19,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; }
@@ -163,6 +456,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 6ec95b6..cd0675f 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/board/freescale/corenet_ds/ddr.c b/board/freescale/corenet_ds/ddr.c index 2ee0188..0eb290d 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 = 0x80000000; 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 = 0x80000000; fsl_ddr_set_memctl_regs(&ddr_cfg_regs, 1); #endif
@@ -165,54 +167,54 @@ 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} + { 0, 333, 4, 5, 0xff, 2, 0}, + {334, 400, 4, 5, 0xff, 2, 0}, + {401, 549, 4, 5, 0xff, 2, 0}, + {550, 680, 4, 5, 0xff, 2, 0}, + {681, 850, 4, 5, 0xff, 2, 0}, + {851, 1050, 4, 5, 0xff, 2, 0}, + {1051, 1250, 4, 5, 0xff, 2, 0}, + {1251, 1350, 4, 5, 0xff, 2, 0}, + { 0, 333, 2, 5, 0xff, 2, 0}, + {334, 400, 2, 5, 0xff, 2, 0}, + {401, 549, 2, 5, 0xff, 2, 0}, + {550, 680, 2, 5, 0xff, 2, 0}, + {681, 850, 2, 5, 0xff, 2, 0}, + {851, 1050, 2, 5, 0xff, 2, 0}, + {1051, 1250, 2, 5, 0xff, 2, 0}, + {1251, 1350, 2, 5, 0xff, 2, 0}, + { 0, 333, 1, 5, 0xff, 2, 0}, + {334, 400, 1, 5, 0xff, 2, 0}, + {401, 549, 1, 5, 0xff, 2, 0}, + {550, 680, 1, 5, 0xff, 2, 0}, + {681, 850, 1, 5, 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} + { 0, 333, 4, 5, 0xff, 2, 0}, + {334, 400, 4, 5, 0xff, 2, 0}, + {401, 549, 4, 5, 0xff, 2, 0}, + {550, 680, 4, 5, 0xff, 2, 0}, + {681, 850, 4, 5, 0xff, 2, 0}, + {851, 1050, 4, 5, 0xff, 2, 0}, + {1051, 1250, 4, 5, 0xff, 2, 0}, + {1251, 1350, 4, 5, 0xff, 2, 0}, + { 0, 333, 2, 5, 0xff, 2, 0}, + {334, 400, 2, 5, 0xff, 2, 0}, + {401, 549, 2, 5, 0xff, 2, 0}, + {550, 680, 2, 5, 0xff, 2, 0}, + {681, 850, 2, 5, 0xff, 2, 0}, + {851, 1050, 2, 5, 0xff, 2, 0}, + {1051, 1250, 2, 5, 0xff, 2, 0}, + {1251, 1350, 2, 5, 0xff, 2, 0}, + { 0, 333, 1, 5, 0xff, 2, 0}, + {334, 400, 1, 5, 0xff, 2, 0}, + {401, 549, 1, 5, 0xff, 2, 0}, + {550, 680, 1, 5, 0xff, 2, 0}, + {681, 850, 1, 5, 0xff, 2, 0} } };
@@ -227,26 +229,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. */ @@ -255,10 +237,11 @@ void fsl_ddr_board_options(memctl_options_t *popts, 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 */ + popts->cpo_override = pbsp->cpo; + popts->write_data_delay = pbsp->write_data_delay; + popts->clk_adjust = pbsp->clk_adjust; popts->twoT_en = pbsp->force_2T; + popts->wrlvl_start = pbsp->clk_adjust + 2; } pbsp++; } @@ -273,16 +256,20 @@ void fsl_ddr_board_options(memctl_options_t *popts, */ popts->wrlvl_override = 1; popts->wrlvl_sample = 0xa; - popts->wrlvl_start = 0x7; /* * 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 = 0x80080000; + + popts->rcw_override = 1; + popts->rcw_1 = 0x000a5000; + popts->rcw_2 = 0x00100000; }
phys_size_t initdram(int board_type) 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

On Dec 8, 2010, at 8:55 PM, York Sun wrote:
Added fsl_ddr_get_version() function to poll DDRC IP version (major, minor, errata) to determine if unique mode registers are available. This function may be needed for future other platforms if such a feature exists. If true, always use unique mode registers. Dynamic ODT is enabled if needed. The table is documented in doc/README.fsl-ddr.
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 | 18 ++ arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c | 305 +++++++++++++++++++++++++---- arch/powerpc/cpu/mpc8xxx/ddr/options.c | 308 +++++++++++++++++++++++++++++- arch/powerpc/include/asm/fsl_ddr_sdram.h | 18 ++ board/freescale/corenet_ds/ddr.c | 125 ++++++-------
do we really need to mix corenet_ds/ddr.c in this patch?
doc/README.fsl-ddr | 67 +++++++- 6 files changed, 723 insertions(+), 118 deletions(-)
What about other DDR3 boards like P2020DS? Are they impacted by this patch?
- k

On Mon, 2010-12-13 at 23:13 -0600, Kumar Gala wrote:
On Dec 8, 2010, at 8:55 PM, York Sun wrote:
Added fsl_ddr_get_version() function to poll DDRC IP version (major, minor, errata) to determine if unique mode registers are available. This function may be needed for future other platforms if such a feature exists. If true, always use unique mode registers. Dynamic ODT is enabled if needed. The table is documented in doc/README.fsl-ddr.
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 | 18 ++ arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c | 305 +++++++++++++++++++++++++---- arch/powerpc/cpu/mpc8xxx/ddr/options.c | 308 +++++++++++++++++++++++++++++- arch/powerpc/include/asm/fsl_ddr_sdram.h | 18 ++ board/freescale/corenet_ds/ddr.c | 125 ++++++-------
do we really need to mix corenet_ds/ddr.c in this patch?
doc/README.fsl-ddr | 67 +++++++- 6 files changed, 723 insertions(+), 118 deletions(-)
What about other DDR3 boards like P2020DS? Are they impacted by this patch?
No. The unique mode registers are only used if DDRC supports it.
York

Dear York Sun,
In message 1291863340-4354-6-git-send-email-yorksun@freescale.com you wrote:
Added fsl_ddr_get_version() function to poll DDRC IP version (major, minor, errata) to determine if unique mode registers are available. This function may be needed for future other platforms if such a feature exists. If true, always
Then please resubmit when any platform gets added that actually uses this. Until then it would be just dead 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..9fa305e 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; /* 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 1291863340-4354-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(-)
diff --git a/include/ddr_spd.h b/include/ddr_spd.h index 710e528..9fa305e 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; /* SDRAM device type */
for consistency: make the comment "33 SDRAM device type".
Best regards,
Wolfgang Denk

Erratum DDRA003 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/ddr-gen3.c | 53 ++++++++++++++++++++++++++++++++++- include/configs/P4080DS.h | 1 + 2 files changed, 53 insertions(+), 1 deletions(-)
diff --git a/arch/powerpc/cpu/mpc85xx/ddr-gen3.c b/arch/powerpc/cpu/mpc85xx/ddr-gen3.c index 568f9f4..0815ba4 100644 --- a/arch/powerpc/cpu/mpc85xx/ddr-gen3.c +++ b/arch/powerpc/cpu/mpc85xx/ddr-gen3.c @@ -108,6 +108,55 @@ 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_P4080_ERRATUM_DDRA003 + 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, 0xc4080002); + break; + case 0x00100000: + out_be32(&ddr->sdram_md_cntl, 0xc408000a); + break; + case 0x00200000: + out_be32(&ddr->sdram_md_cntl, 0xc4080012); + break; + case 0x00300000: + out_be32(&ddr->sdram_md_cntl, 0xc408001a); + break; + default: + out_be32(&ddr->sdram_md_cntl, 0xc4080002); + 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, @@ -131,8 +180,10 @@ 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/include/configs/P4080DS.h b/include/configs/P4080DS.h index d210016..c19bd39 100644 --- a/include/configs/P4080DS.h +++ b/include/configs/P4080DS.h @@ -45,6 +45,7 @@ #define CONFIG_SYS_P4080_ERRATUM_CPC9 #define CONFIG_SYS_P4080_ERRATUM_DDR1 #define CONFIG_SYS_P4080_ERRATUM_DDR7 +#define CONFIG_SYS_P4080_ERRATUM_DDRA003 #define CONFIG_SYS_P4080_ERRATUM_ESDHC1 #define CONFIG_SYS_P4080_ERRATUM_ESDHC9 #define CONFIG_SYS_P4080_ERRATUM_ESDHC11

On Dec 8, 2010, at 8:55 PM, York Sun wrote:
Erratum DDRA003 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/ddr-gen3.c | 53 ++++++++++++++++++++++++++++++++++- include/configs/P4080DS.h | 1 + 2 files changed, 53 insertions(+), 1 deletions(-)
diff --git a/arch/powerpc/cpu/mpc85xx/ddr-gen3.c b/arch/powerpc/cpu/mpc85xx/ddr-gen3.c index 568f9f4..0815ba4 100644 --- a/arch/powerpc/cpu/mpc85xx/ddr-gen3.c +++ b/arch/powerpc/cpu/mpc85xx/ddr-gen3.c @@ -108,6 +108,55 @@ 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_P4080_ERRATUM_DDRA003
Name this:
#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, 0xc4080002);
break;
case 0x00100000:
out_be32(&ddr->sdram_md_cntl, 0xc408000a);
break;
case 0x00200000:
out_be32(&ddr->sdram_md_cntl, 0xc4080012);
break;
case 0x00300000:
out_be32(&ddr->sdram_md_cntl, 0xc408001a);
break;
default:
out_be32(&ddr->sdram_md_cntl, 0xc4080002);
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, @@ -131,8 +180,10 @@ 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/include/configs/P4080DS.h b/include/configs/P4080DS.h index d210016..c19bd39 100644 --- a/include/configs/P4080DS.h +++ b/include/configs/P4080DS.h @@ -45,6 +45,7 @@ #define CONFIG_SYS_P4080_ERRATUM_CPC9 #define CONFIG_SYS_P4080_ERRATUM_DDR1 #define CONFIG_SYS_P4080_ERRATUM_DDR7 +#define CONFIG_SYS_P4080_ERRATUM_DDRA003 #define CONFIG_SYS_P4080_ERRATUM_ESDHC1 #define CONFIG_SYS_P4080_ERRATUM_ESDHC9
#define CONFIG_SYS_P4080_ERRATUM_ESDHC11
1.7.0.4
You need to update arch/powerpc/cpu/mpc85xx/cmd_errata.c
- k

Use environment variable to active the interactive debugging.
Signed-off-by: York Sun yorksun@freescale.com --- arch/powerpc/cpu/mpc8xxx/ddr/Makefile | 6 +- arch/powerpc/cpu/mpc8xxx/ddr/interactive.c | 1882 ++++++++++++++++++++++++++++ arch/powerpc/cpu/mpc8xxx/ddr/main.c | 8 +- doc/README.fsl-ddr | 20 + 4 files changed, 1910 insertions(+), 6 deletions(-) create mode 100644 arch/powerpc/cpu/mpc8xxx/ddr/interactive.c
diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/Makefile b/arch/powerpc/cpu/mpc8xxx/ddr/Makefile index cb7f856..4bd416a 100644 --- a/arch/powerpc/cpu/mpc8xxx/ddr/Makefile +++ b/arch/powerpc/cpu/mpc8xxx/ddr/Makefile @@ -11,15 +11,15 @@ include $(TOPDIR)/config.mk LIB = $(obj)libddr.a
COBJS-$(CONFIG_FSL_DDR1) += main.o util.o ctrl_regs.o options.o \ - lc_common_dimm_params.o + lc_common_dimm_params.o interactive.o COBJS-$(CONFIG_FSL_DDR1) += ddr1_dimm_params.o
COBJS-$(CONFIG_FSL_DDR2) += main.o util.o ctrl_regs.o options.o \ - lc_common_dimm_params.o + lc_common_dimm_params.o interactive.o COBJS-$(CONFIG_FSL_DDR2) += ddr2_dimm_params.o
COBJS-$(CONFIG_FSL_DDR3) += main.o util.o ctrl_regs.o options.o \ - lc_common_dimm_params.o + lc_common_dimm_params.o interactive.o COBJS-$(CONFIG_FSL_DDR3) += ddr3_dimm_params.o
SRCS := $(START:.o=.S) $(SOBJS-y:.o=.S) $(COBJS-y:.o=.c) diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/interactive.c b/arch/powerpc/cpu/mpc8xxx/ddr/interactive.c new file mode 100644 index 0000000..7d492a9 --- /dev/null +++ b/arch/powerpc/cpu/mpc8xxx/ddr/interactive.c @@ -0,0 +1,1882 @@ +/* + * Copyright 2010 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * Version 2 as published by the Free Software Foundation. + */ + +/* + * Generic driver for Freescale DDR/DDR2/DDR3 memory controller. + * Based on code from spd_sdram.c + * Author: James Yang [at freescale.com] + * Maintainer: York Sun yorksun@freescale.com + */ + +#include <common.h> +#include <linux/ctype.h> +#include <asm/types.h> + +#include <asm/fsl_ddr_sdram.h> +#include "ddr.h" + +/* Option parameter Structures */ +typedef struct { + const char *option_name; + size_t offset; +} options_strings_t; + +int do_reset(void *cmdtp, int flag, int argc, char *argv[]); +unsigned int check_fsl_memctl_config_regs(const fsl_ddr_cfg_regs_t *ddr); +const char *step_to_string(unsigned int step); + +static unsigned int picos_to_mhz(unsigned int picos) +{ + return 1000000 / picos; +} + +static int handle_uint_option_table(const options_strings_t *table, + int table_size, + u32 base, + const char *opt, + const char *val) +{ + unsigned int i; + unsigned int value, *ptr; + + for (i = 0; i < table_size; i++) { + if (strcmp(table[i].option_name, opt) == 0) { + value = simple_strtoul(val, NULL, 0); + ptr = (unsigned int *)(base + table[i].offset); + *ptr = value; + return 1; + } + } + + return 0; +} + +static int handle_ull_option_table(const options_strings_t *table, + int table_size, + u32 base, + const char *opt, + const char *val) +{ + unsigned int i; + unsigned long long value, *ptr; + + for (i = 0; i < table_size; i++) { + if (strcmp(table[i].option_name, opt) == 0) { + value = simple_strtoull(val, NULL, 0); + ptr = (unsigned long long *)(base + table[i].offset); + *ptr = value; + return 1; + } + } + + return 0; +} + +static void fsl_ddr_generic_edit(void *pdata, + void *pend, + unsigned int element_size, + unsigned int element_num, + unsigned int value) +{ + char *pcdata = (char *)pdata; /* BIG ENDIAN ONLY */ + + pcdata += element_num * element_size; + if ((pcdata + element_size) > (char *) pend) { + debug("trying to write past end of data\n"); + return; + } + + switch (element_size) { + case 1: + __raw_writeb(value, pcdata); + break; + case 2: + __raw_writew(value, pcdata); + break; + case 4: + __raw_writel(value, pcdata); + break; + default: + debug("unexpected element size %u\n", element_size); + break; + } +} + +static void fsl_ddr_spd_edit(fsl_ddr_info_t *pinfo, + unsigned int ctrl_num, + unsigned int dimm_num, + unsigned int element_num, + unsigned int value) +{ + generic_spd_eeprom_t *pspd; + + pspd = &(pinfo->spd_installed_dimms[ctrl_num][dimm_num]); + fsl_ddr_generic_edit(pspd, pspd + 1, + sizeof(char), element_num, value); +} +#define OPTIONS_UNIT(x) {#x, offsetof(common_timing_params_t, x)} +static void lowest_common_dimm_parameters_edit(fsl_ddr_info_t *pinfo, + unsigned int ctrl_num, + const char *optname_str, + const char *value_str) +{ + common_timing_params_t *p = &pinfo->common_timing_params[ctrl_num]; + + static const options_strings_t options_uint[] = { + OPTIONS_UNIT(tCKmin_X_ps), + OPTIONS_UNIT(tCKmax_ps), + OPTIONS_UNIT(tCKmax_max_ps), + OPTIONS_UNIT(tRCD_ps), + OPTIONS_UNIT(tRP_ps), + OPTIONS_UNIT(tRAS_ps), + OPTIONS_UNIT(tWR_ps), + OPTIONS_UNIT(tWTR_ps), + OPTIONS_UNIT(tRFC_ps), + OPTIONS_UNIT(tRRD_ps), + OPTIONS_UNIT(tRC_ps), + OPTIONS_UNIT(refresh_rate_ps), + OPTIONS_UNIT(tIS_ps), + OPTIONS_UNIT(tIH_ps), + OPTIONS_UNIT(tDS_ps), + OPTIONS_UNIT(tDH_ps), + OPTIONS_UNIT(tRTP_ps), + OPTIONS_UNIT(tDQSQ_max_ps), + OPTIONS_UNIT(tQHS_ps), + OPTIONS_UNIT(ndimms_present), + OPTIONS_UNIT(lowest_common_SPD_caslat), + OPTIONS_UNIT(highest_common_derated_caslat), + OPTIONS_UNIT(additive_latency), + OPTIONS_UNIT(all_DIMMs_burst_lengths_bitmask), + OPTIONS_UNIT(all_DIMMs_registered), + OPTIONS_UNIT(all_DIMMs_unbuffered), + OPTIONS_UNIT(all_DIMMs_ECC_capable), + }; + + static const unsigned int n_uint_opts = ARRAY_SIZE(options_uint); + + static const options_strings_t options_ull[] = { + OPTIONS_UNIT(total_mem), + OPTIONS_UNIT(base_address), + }; + + static const unsigned int n_ull_opts = ARRAY_SIZE(options_ull); + + if (handle_uint_option_table(options_uint, n_uint_opts, (u32) p, + optname_str, value_str)) + return; + + if (handle_ull_option_table(options_ull, n_ull_opts, (u32) p, + optname_str, value_str)) + return; + + printf("Error: couldn't find option string %s\n", optname_str); +} + +#undef OPTIONS_UNIT +#define OPTIONS_UNIT(x) {#x, offsetof(dimm_params_t, x)} + +static void fsl_ddr_dimm_parameters_edit(fsl_ddr_info_t *pinfo, + unsigned int ctrl_num, + unsigned int dimm_num, + const char *optname_str, + const char *value_str) +{ + dimm_params_t *p = &(pinfo->dimm_params[ctrl_num][dimm_num]); + + static const options_strings_t options_uint[] = { + OPTIONS_UNIT(n_ranks), + OPTIONS_UNIT(data_width), + OPTIONS_UNIT(primary_sdram_width), + OPTIONS_UNIT(ec_sdram_width), + OPTIONS_UNIT(registered_dimm), + + OPTIONS_UNIT(n_row_addr), + OPTIONS_UNIT(n_col_addr), + OPTIONS_UNIT(edc_config), + OPTIONS_UNIT(n_banks_per_sdram_device), + OPTIONS_UNIT(burst_lengths_bitmask), + OPTIONS_UNIT(row_density), + + OPTIONS_UNIT(tCKmin_X_ps), + OPTIONS_UNIT(tCKmin_X_minus_1_ps), + OPTIONS_UNIT(tCKmin_X_minus_2_ps), + OPTIONS_UNIT(tCKmax_ps), + + OPTIONS_UNIT(caslat_X), + OPTIONS_UNIT(caslat_X_minus_1), + OPTIONS_UNIT(caslat_X_minus_2), + + OPTIONS_UNIT(caslat_lowest_derated), + + OPTIONS_UNIT(tRCD_ps), + OPTIONS_UNIT(tRP_ps), + OPTIONS_UNIT(tRAS_ps), + OPTIONS_UNIT(tWR_ps), + OPTIONS_UNIT(tWTR_ps), + OPTIONS_UNIT(tRFC_ps), + OPTIONS_UNIT(tRRD_ps), + OPTIONS_UNIT(tRC_ps), + OPTIONS_UNIT(refresh_rate_ps), + + OPTIONS_UNIT(tIS_ps), + OPTIONS_UNIT(tIH_ps), + OPTIONS_UNIT(tDS_ps), + OPTIONS_UNIT(tDH_ps), + OPTIONS_UNIT(tRTP_ps), + OPTIONS_UNIT(tDQSQ_max_ps), + OPTIONS_UNIT(tQHS_ps), + }; + + static const unsigned int n_uint_opts = ARRAY_SIZE(options_uint); + + static const options_strings_t options_ull[] = { + OPTIONS_UNIT(rank_density), + OPTIONS_UNIT(capacity), + OPTIONS_UNIT(base_address), + }; + + static const unsigned int n_ull_opts = ARRAY_SIZE(options_ull); + + if (handle_uint_option_table(options_uint, n_uint_opts, (u32) p, + optname_str, value_str)) + return; + + if (handle_ull_option_table(options_ull, n_ull_opts, (u32) p, + optname_str, value_str)) + return; + + printf("couldn't find option string %s\n", optname_str); +} + +static void print_dimm_parameters(const dimm_params_t *pdimm) +{ + if (pdimm->n_ranks == 0) { + printf("DIMM not present\n"); + return; + } + + printf("DIMM organization parameters:\n"); + + printf("module part name = %s\n", pdimm->mpart); + printf("n_ranks = %u\n", pdimm->n_ranks); + printf("rank_density = %llu bytes (%llu megabytes)\n", + pdimm->rank_density, pdimm->rank_density / 0x100000); + printf("capacity = %llu bytes (%llu megabytes)\n", + pdimm->capacity, pdimm->capacity / 0x100000); + printf("data_width = %u\n", pdimm->data_width); + printf("primary_sdram_width = %u\n", pdimm->primary_sdram_width); + printf("ec_sdram_width = %u\n", pdimm->ec_sdram_width); + printf("registered_dimm = %u\n", pdimm->registered_dimm); + + printf("SDRAM device parameters:\n"); + printf("n_row_addr = %u\n", pdimm->n_row_addr); + printf("n_col_addr = %u\n", pdimm->n_col_addr); + printf("edc_config = %u\n", pdimm->edc_config); + printf("n_banks_per_sdram_device = %u\n", + pdimm->n_banks_per_sdram_device); + printf("burst_lengths_bitmask = %02X\n", + pdimm->burst_lengths_bitmask); + + printf("base_addresss = %llu (%08llX %08llX)\n", + pdimm->base_address, + (pdimm->base_address >> 32), + pdimm->base_address & 0xFFFFFFFF); + + printf("SDRAM clock periods:\n"); + printf("tCKmin_X_ps = %u ps\n", pdimm->tCKmin_X_ps); + printf("tCKmin_X_minus_1_ps = %u ps\n", pdimm->tCKmin_X_minus_1_ps); + printf("tCKmin_X_minus_2_ps = %u ps\n", pdimm->tCKmin_X_minus_2_ps); + printf("tCKmax_ps = %u ps\n", pdimm->tCKmax_ps); + + printf("SDRAM CAS latencies:\n"); + printf("caslat_X = %u\n", pdimm->caslat_X); + printf("caslat_X_minus_1 = %u\n", pdimm->caslat_X_minus_1); + printf("caslat_X_minus_2 = %u\n", pdimm->caslat_X_minus_2); + printf("caslat_lowest_derated = %u\n", pdimm->caslat_lowest_derated); + + printf("SDRAM timing parameters:\n"); + printf("tRCD_ps = %u\n", pdimm->tRCD_ps); + printf("tRP_ps = %u\n", pdimm->tRP_ps); + printf("tRAS_ps = %u\n", pdimm->tRAS_ps); + printf("tWR_ps = %u\n", pdimm->tWR_ps); + printf("tWTR_ps = %u\n", pdimm->tWTR_ps); + printf("tRFC_ps = %u\n", pdimm->tRFC_ps); + printf("tRC_ps = %u\n", pdimm->tRC_ps); + printf("tRRD_ps = %u\n", pdimm->tRRD_ps); + printf("refresh_rate_ps = %u\n", pdimm->refresh_rate_ps); + + printf("SDRAM even more timing parameters:\n"); + printf("tIS_ps = %u\n", pdimm->tIS_ps); + printf("tIH_ps = %u\n", pdimm->tIH_ps); + printf("tDS_ps = %u\n", pdimm->tDS_ps); + printf("tDH_ps = %u\n", pdimm->tDH_ps); + printf("tRTP_ps = %u\n", pdimm->tRTP_ps); + printf("tDQSQ_max_ps = %u\n", pdimm->tDQSQ_max_ps); + printf("tQHS_ps = %u\n", pdimm->tQHS_ps); +} + +static void print_lowest_common_dimm_parameters( + const common_timing_params_t *plcd_dimm_params) +{ + + /* Clock frequencies */ + printf("tCKmin_X_ps = %u (%u MHz)\n", + plcd_dimm_params->tCKmin_X_ps, + picos_to_mhz(plcd_dimm_params->tCKmin_X_ps)); + printf("tCKmax_ps = %u (%u MHz)\n", + plcd_dimm_params->tCKmax_ps, + picos_to_mhz(plcd_dimm_params->tCKmax_ps)); + printf("tCKmax_max_ps = %u\n", plcd_dimm_params->tCKmax_max_ps); + + /* Basic timing parameters */ + printf("tRCD_ps = %u\n", plcd_dimm_params->tRCD_ps); + printf("tRP_ps = %u\n", plcd_dimm_params->tRP_ps); + printf("tRAS_ps = %u\n", plcd_dimm_params->tRAS_ps); + + /* maximum = 63750 ps */ + printf("tWR_ps = %u\n", plcd_dimm_params->tWR_ps); + + /* maximum = 63750 ps */ + printf("tWTR_ps = %u\n", plcd_dimm_params->tWTR_ps); + + /* maximum = 255 ns + 256 ns + .75 ns = 511750 ps */ + printf("tRFC_ps = %u\n", plcd_dimm_params->tRFC_ps); + + /* maximum = 63750 ps */ + printf("tRRD_ps = %u\n", plcd_dimm_params->tRRD_ps); + + /* maximum = 254 ns + .75 ns = 254750 ps */ + printf("tRC_ps = %u\n", plcd_dimm_params->tRC_ps); + + printf("refresh_rate_ps = %u\n", plcd_dimm_params->refresh_rate_ps); + + /* byte 32, spd->ca_setup */ + printf("tIS_ps = %u\n", plcd_dimm_params->tIS_ps); + /* byte 33, spd->ca_hold */ + printf("tIH_ps = %u\n", plcd_dimm_params->tIH_ps); + /* byte 34, spd->data_setup */ + printf("tDS_ps = %u\n", plcd_dimm_params->tDS_ps); + /* byte 35, spd->data_hold */ + printf("tDH_ps = %u\n", plcd_dimm_params->tDH_ps); + /* byte 38, spd->trtp */ + printf("tRTP_ps = %u\n", plcd_dimm_params->tRTP_ps); + /* byte 44, spd->tdqsq */ + printf("tDQSQ_max_ps = %u\n", plcd_dimm_params->tDQSQ_max_ps); + /* byte 45, spd->tqhs */ + printf("tQHS_ps = %u\n", plcd_dimm_params->tQHS_ps); + + printf("lowest_common_SPD_caslat = %u\n", + plcd_dimm_params->lowest_common_SPD_caslat); + printf("highest_common_derated_caslat = %u\n", + plcd_dimm_params->highest_common_derated_caslat); + printf("additive_latency = %u\n", plcd_dimm_params->additive_latency); + + printf("ndimms_present = %u\n", plcd_dimm_params->ndimms_present); + printf("all_DIMMs_burst_lengths_bitmask = %02X\n", + plcd_dimm_params->all_DIMMs_burst_lengths_bitmask); + printf("all_DIMMs_registered = %u\n", + plcd_dimm_params->all_DIMMs_registered); + printf("all_DIMMs_unbuffered = %u\n", + plcd_dimm_params->all_DIMMs_unbuffered); + printf("all_DIMMs_ECC_capable = %u\n", + plcd_dimm_params->all_DIMMs_ECC_capable); + + printf("total_mem = %llu (%llu megabytes)\n", + plcd_dimm_params->total_mem, + plcd_dimm_params->total_mem / 0x100000); + printf("base_address = %llu (%llu megabytes)\n", + plcd_dimm_params->base_address, + plcd_dimm_params->base_address / 0x100000); +} + +#undef OPTIONS_UNIT +#define OPTIONS_UNIT(x) {#x, offsetof(memctl_options_t, x)} + +static void fsl_ddr_options_edit(fsl_ddr_info_t *pinfo, + unsigned int ctl_num, + const char *optname_str, + const char *value_str) +{ + memctl_options_t *p = &(pinfo->memctl_opts[ctl_num]); + /* + * This array all on the stack and *computed* each time this + * function is rung. + */ + static const options_strings_t options[] = { + {"cs0_odt_rd_cfg", offsetof(memctl_options_t, cs_local_opts[0].odt_rd_cfg)}, + {"cs0_odt_wr_cfg", offsetof(memctl_options_t, cs_local_opts[0].odt_wr_cfg)}, + {"cs0_odt_rtt_norm", offsetof(memctl_options_t, cs_local_opts[0].odt_rtt_norm)}, + {"cs0_odt_rtt_wr", offsetof(memctl_options_t, cs_local_opts[0].odt_rtt_wr)}, + {"cs1_odt_rd_cfg", offsetof(memctl_options_t, cs_local_opts[1].odt_rd_cfg)}, + {"cs1_odt_wr_cfg", offsetof(memctl_options_t, cs_local_opts[1].odt_wr_cfg)}, + {"cs1_odt_rtt_norm", offsetof(memctl_options_t, cs_local_opts[1].odt_rtt_norm)}, + {"cs1_odt_rtt_wr", offsetof(memctl_options_t, cs_local_opts[1].odt_rtt_wr)}, + {"cs2_odt_rd_cfg", offsetof(memctl_options_t, cs_local_opts[2].odt_rd_cfg)}, + {"cs2_odt_wr_cfg", offsetof(memctl_options_t, cs_local_opts[2].odt_wr_cfg)}, + {"cs2_odt_rtt_norm", offsetof(memctl_options_t, cs_local_opts[2].odt_rtt_norm)}, + {"cs2_odt_rtt_wr", offsetof(memctl_options_t, cs_local_opts[2].odt_rtt_wr)}, + {"cs3_odt_rd_cfg", offsetof(memctl_options_t, cs_local_opts[3].odt_rd_cfg)}, + {"cs3_odt_wr_cfg", offsetof(memctl_options_t, cs_local_opts[3].odt_wr_cfg)}, + {"cs3_odt_rtt_norm", offsetof(memctl_options_t, cs_local_opts[3].odt_rtt_norm)}, + {"cs3_odt_rtt_wr", offsetof(memctl_options_t, cs_local_opts[3].odt_rtt_wr)}, + OPTIONS_UNIT(memctl_interleaving), + OPTIONS_UNIT(memctl_interleaving_mode), + OPTIONS_UNIT(ba_intlv_ctl), + OPTIONS_UNIT(ECC_mode), + OPTIONS_UNIT(ECC_init_using_memctl), + OPTIONS_UNIT(DQS_config), + OPTIONS_UNIT(self_refresh_in_sleep), + OPTIONS_UNIT(dynamic_power), + OPTIONS_UNIT(data_bus_width), + OPTIONS_UNIT(burst_length), + OPTIONS_UNIT(cas_latency_override), + OPTIONS_UNIT(cas_latency_override_value), + OPTIONS_UNIT(use_derated_caslat), + OPTIONS_UNIT(additive_latency_override), + OPTIONS_UNIT(additive_latency_override_value), + OPTIONS_UNIT(clk_adjust), + OPTIONS_UNIT(cpo_override), + OPTIONS_UNIT(write_data_delay), + OPTIONS_UNIT(half_strength_driver_enable), + + /* + * These can probably be changed to 2T_EN and 3T_EN + * (using a leading numerical character) without problem + */ + OPTIONS_UNIT(twoT_en), + OPTIONS_UNIT(threeT_en), + OPTIONS_UNIT(ap_en), + OPTIONS_UNIT(bstopre), + OPTIONS_UNIT(wrlvl_override), + OPTIONS_UNIT(wrlvl_sample), + OPTIONS_UNIT(wrlvl_start), + OPTIONS_UNIT(rcw_override), + OPTIONS_UNIT(rcw_1), + OPTIONS_UNIT(rcw_2), + OPTIONS_UNIT(tCKE_clock_pulse_width_ps), + OPTIONS_UNIT(tFAW_window_four_activates_ps), + }; + + static const unsigned int nopts = ARRAY_SIZE(options); + + if (handle_uint_option_table(options, nopts, (u32) p, + optname_str, value_str)) + return; + + printf("couldn't find option string %s\n", optname_str); +} + +static void print_fsl_memctl_config_regs(const fsl_ddr_cfg_regs_t *ddr) +{ + unsigned int i; + + for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { + printf("cs%u_bnds = %08X\n", i, ddr->cs[i].bnds); + printf("cs%u_config = %08X\n", i, ddr->cs[i].config); + printf("cs%u_config_2 = %08X\n", i, ddr->cs[i].config_2); + } + + printf("timing_cfg_3 = %08X\n", ddr->timing_cfg_3); + printf("timing_cfg_0 = %08X\n", ddr->timing_cfg_0); + printf("timing_cfg_1 = %08X\n", ddr->timing_cfg_1); + printf("timing_cfg_2 = %08X\n", ddr->timing_cfg_2); + printf("ddr_sdram_cfg = %08X\n", ddr->ddr_sdram_cfg); + printf("ddr_sdram_cfg_2 = %08X\n", ddr->ddr_sdram_cfg_2); + printf("ddr_sdram_mode = %08X\n", ddr->ddr_sdram_mode); + printf("ddr_sdram_mode_2 = %08X\n", ddr->ddr_sdram_mode_2); + printf("ddr_sdram_mode_3 = %08X\n", ddr->ddr_sdram_mode_3); + printf("ddr_sdram_mode_4 = %08X\n", ddr->ddr_sdram_mode_4); + printf("ddr_sdram_mode_5 = %08X\n", ddr->ddr_sdram_mode_5); + printf("ddr_sdram_mode_6 = %08X\n", ddr->ddr_sdram_mode_6); + printf("ddr_sdram_mode_7 = %08X\n", ddr->ddr_sdram_mode_7); + printf("ddr_sdram_mode_8 = %08X\n", ddr->ddr_sdram_mode_8); + printf("ddr_sdram_interval = %08X\n", ddr->ddr_sdram_interval); + printf("ddr_data_init = %08X\n", ddr->ddr_data_init); + printf("ddr_sdram_clk_cntl = %08X\n", ddr->ddr_sdram_clk_cntl); + printf("ddr_init_addr = %08X\n", ddr->ddr_init_addr); + printf("ddr_init_ext_addr = %08X\n", ddr->ddr_init_ext_addr); + printf("timing_cfg_4 = %08X\n", ddr->timing_cfg_4); + printf("timing_cfg_5 = %08X\n", ddr->timing_cfg_5); + printf("ddr_zq_cntl = %08X\n", ddr->ddr_zq_cntl); + printf("ddr_wrlvl_cntl = %08X\n", ddr->ddr_wrlvl_cntl); + printf("ddr_sr_cntr = %08X\n", ddr->ddr_sr_cntr); + printf("ddr_sdram_rcw_1 = %08X\n", ddr->ddr_sdram_rcw_1); + printf("ddr_sdram_rcw_2 = %08X\n", ddr->ddr_sdram_rcw_2); + printf("ddr_cdr1 = %08X\n", ddr->ddr_cdr1); + printf("ddr_cdr2 = %08X\n", ddr->ddr_cdr2); + printf("err_disable = %08X\n", ddr->err_disable); + printf("err_int_en = %08X\n", ddr->err_int_en); + for (i = 0; i < 18; i++) + printf("debug_%02d = %08X\n", i+1, ddr->debug[i]); +} + +static void fsl_ddr_regs_edit(fsl_ddr_info_t *pinfo, + unsigned int ctrl_num, + const char *regname, + unsigned int value) +{ + unsigned int i; + fsl_ddr_cfg_regs_t *ddr; + char buf[20]; + + debug("fsl_ddr_regs_edit: ctrl_num = %u, " + "regname = %s, value = 0x%08X\n", + ctrl_num, regname, value); + if (ctrl_num > CONFIG_NUM_DDR_CONTROLLERS) + return; + + /* FIXME: Change this into struct like the other editing functions */ + ddr = &(pinfo->fsl_ddr_config_reg[ctrl_num]); + + for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { + sprintf(buf, "cs%u_bnds", i); + if (strcmp(buf, regname) == 0) { + ddr->cs[i].bnds = value; + return; + } + + sprintf(buf, "cs%u_config", i); + if (strcmp(buf, regname) == 0) { + ddr->cs[i].config = value; + return; + } + + sprintf(buf, "cs%u_config_2", i); + if (strcmp(buf, regname) == 0) { + ddr->cs[i].config_2 = value; + return; + } + } + + if (strcmp("timing_cfg_3", regname) == 0) { + ddr->timing_cfg_3 = value; + return; + } + + if (strcmp("timing_cfg_0", regname) == 0) { + ddr->timing_cfg_0 = value; + return; + } + + if (strcmp("timing_cfg_1", regname) == 0) { + ddr->timing_cfg_1 = value; + return; + } + + if (strcmp("timing_cfg_2", regname) == 0) { + ddr->timing_cfg_2 = value; + return; + } + + if (strcmp("ddr_sdram_cfg", regname) == 0) { + ddr->ddr_sdram_cfg = value; + return; + } + + if (strcmp("ddr_sdram_cfg_2", regname) == 0) { + ddr->ddr_sdram_cfg_2 = value; + return; + } + + if (strcmp("ddr_sdram_mode", regname) == 0) { + ddr->ddr_sdram_mode = value; + return; + } + + if (strcmp("ddr_sdram_mode_2", regname) == 0) { + ddr->ddr_sdram_mode_2 = value; + return; + } + + if (strcmp("ddr_sdram_mode_3", regname) == 0) { + ddr->ddr_sdram_mode_3 = value; + return; + } + + if (strcmp("ddr_sdram_mode_4", regname) == 0) { + ddr->ddr_sdram_mode_4 = value; + return; + } + + if (strcmp("ddr_sdram_mode_5", regname) == 0) { + ddr->ddr_sdram_mode_5 = value; + return; + } + + if (strcmp("ddr_sdram_mode_6", regname) == 0) { + ddr->ddr_sdram_mode_6 = value; + return; + } + + if (strcmp("ddr_sdram_mode_7", regname) == 0) { + ddr->ddr_sdram_mode_7 = value; + return; + } + + if (strcmp("ddr_sdram_mode_8", regname) == 0) { + ddr->ddr_sdram_mode_8 = value; + return; + } + + if (strcmp("ddr_sdram_interval", regname) == 0) { + ddr->ddr_sdram_interval = value; + return; + } + + if (strcmp("ddr_data_init", regname) == 0) { + ddr->ddr_data_init = value; + return; + } + + if (strcmp("ddr_sdram_clk_cntl", regname) == 0) { + ddr->ddr_sdram_clk_cntl = value; + return; + } + + if (strcmp("ddr_init_addr", regname) == 0) { + ddr->ddr_init_addr = value; + return; + } + + if (strcmp("ddr_init_ext_addr", regname) == 0) { + ddr->ddr_init_ext_addr = value; + return; + } + + if (strcmp("timing_cfg_4", regname) == 0) { + ddr->timing_cfg_4 = value; + return; + } + + if (strcmp("timing_cfg_5", regname) == 0) { + ddr->timing_cfg_5 = value; + return; + } + + if (strcmp("ddr_zq_cntl", regname) == 0) { + ddr->ddr_zq_cntl = value; + return; + } + + if (strcmp("ddr_wrlvl_cntl", regname) == 0) { + ddr->ddr_wrlvl_cntl = value; + return; + } + + if (strcmp("ddr_sr_cntr", regname) == 0) { + ddr->ddr_sr_cntr = value; + return; + } + + if (strcmp("ddr_sdram_rcw_1", regname) == 0) { + ddr->ddr_sdram_rcw_1 = value; + return; + } + + if (strcmp("ddr_sdram_rcw_2", regname) == 0) { + ddr->ddr_sdram_rcw_2 = value; + return; + } + + if (strcmp("ddr_cdr1", regname) == 0) { + ddr->ddr_cdr1 = value; + return; + } + + if (strcmp("ddr_cdr2", regname) == 0) { + ddr->ddr_cdr2 = value; + return; + } + + if (strcmp("err_disable", regname) == 0) { + ddr->err_disable = value; + return; + } + + if (strcmp("err_int_en", regname) == 0) { + ddr->err_int_en = value; + return; + } + + for (i = 0; i < 18; i++) { + sprintf(buf, "debug_%u", i + 1); + if (strcmp(buf, regname) == 0) { + ddr->debug[i] = value; + return; + } + } +} + +static void print_memctl_options(const memctl_options_t *popts) +{ + int i; + for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { + printf("cs%d_odt_rd_cfg = %u\n", i, popts->cs_local_opts[i].odt_rd_cfg); + printf("cs%d_odt_wr_cfg = %u\n", i, popts->cs_local_opts[i].odt_wr_cfg); +#if defined(CONFIG_FSL_DDR3) + printf("cs%d_odt_rtt_norm = %u\n", i, popts->cs_local_opts[i].odt_rtt_norm); + printf("cs%d_odt_rtt_wr = %u\n", i, popts->cs_local_opts[i].odt_rtt_wr); +#endif + } + /* Special configurations for chip select */ + printf("memctl_interleaving = %u\n", popts->memctl_interleaving); + printf("memctl_interleaving_mode = %u\n", + popts->memctl_interleaving_mode); + printf("ba_intlv_ctl = 0x%02X\n", popts->ba_intlv_ctl); + + printf("ECC_mode = %u\n", popts->ECC_mode); /* Use ECC? */ + + /* Initialize ECC using memory controller? */ + printf("ECC_init_using_memctl = %u\n", popts->ECC_init_using_memctl); + + /* Use DQS? maybe only with DDR2? */ + printf("DQS_config = %u\n", popts->DQS_config); + + /* SREN - self-refresh during sleep */ + printf("self_refresh_in_sleep = %u\n", popts->self_refresh_in_sleep); + + /* DYN_PWR */ + printf("dynamic_power = %u\n", popts->dynamic_power); + + /* memory data width to use (16-bit, 32-bit, 64-bit) */ + printf("data_bus_width = %u\n", popts->data_bus_width); + + /* 4, 8 */ + printf("burst_length = %u\n", popts->burst_length); + + /* Global Timing Parameters */ + printf("cas_latency_override = %u\n", popts->cas_latency_override); + printf("cas_latency_override_value = %u\n", + popts->cas_latency_override_value); + printf("use_derated_caslat = %u\n", popts->use_derated_caslat); + printf("additive_latency_override = %u\n", + popts->additive_latency_override); + printf("additive_latency_override_value = %u\n", + popts->additive_latency_override_value); + printf("clk_adjust = %u\n", popts->clk_adjust); + printf("cpo_override = %u\n", popts->cpo_override); + /* DQS adjust */ + printf("write_data_delay = %u\n", popts->write_data_delay); + printf("half_strength_driver_enable = %u\n", + popts->half_strength_driver_enable); + printf("twoT_en = %u\n", popts->twoT_en); + printf("threeT_en = %u\n", popts->threeT_en); + printf("ap_en = %u\n", popts->ap_en); + printf("bstopre = %u\n", popts->bstopre); + /* wrlvl */ + printf("wrlvl_override = %u\n", popts->wrlvl_override); + printf("wrlvl_sample = %u\n", popts->wrlvl_sample); + printf("wrlvl_start = %u\n", popts->wrlvl_start); + /* rcw */ + printf("rcw_override = %u\n", popts->rcw_override); + printf("rcw_1 = 0x%08x\n", popts->rcw_1); + printf("rcw_2 = 0x%08x\n", popts->rcw_2); + /* tCKE */ + printf("tCKE_clock_pulse_width_ps = %u\n", + popts->tCKE_clock_pulse_width_ps); + /* tFAW -- FOUR_ACT */ + printf("tFAW_window_four_activates_ps = %u\n", + popts->tFAW_window_four_activates_ps); +} + +#ifdef CONFIG_FSL_DDR1 +void ddr1_spd_dump(const ddr1_spd_eeprom_t *spd) +{ + unsigned int i; + + printf("%-3d : %02x %s\n", + 0, spd->info_size, + " spd->info_size, * 0 # bytes written into serial memory *"); + printf("%-3d : %02x %s\n", + 1, spd->chip_size, + " spd->chip_size, * 1 Total # bytes of SPD memory device *"); + printf("%-3d : %02x %s\n", + 2, spd->mem_type, + " spd->mem_type, * 2 Fundamental memory type *"); + printf("%-3d : %02x %s\n", + 3, spd->nrow_addr, + " spd->nrow_addr, * 3 # of Row Addresses on this assembly *"); + printf("%-3d : %02x %s\n", + 4, spd->ncol_addr, + " spd->ncol_addr, * 4 # of Column Addrs on this assembly *"); + printf("%-3d : %02x %s\n", + 5, spd->nrows, + " spd->nrows * 5 # of DIMM Banks *"); + printf("%-3d : %02x %s\n", + 6, spd->dataw_lsb, + " spd->dataw_lsb, * 6 Data Width lsb of this assembly *"); + printf("%-3d : %02x %s\n", + 7, spd->dataw_msb, + " spd->dataw_msb, * 7 Data Width msb of this assembly *"); + printf("%-3d : %02x %s\n", + 8, spd->voltage, + " spd->voltage, * 8 Voltage intf std of this assembly *"); + printf("%-3d : %02x %s\n", + 9, spd->clk_cycle, + " spd->clk_cycle, * 9 SDRAM Cycle time at CL=X *"); + printf("%-3d : %02x %s\n", + 10, spd->clk_access, + " spd->clk_access, * 10 SDRAM Access from Clock at CL=X *"); + printf("%-3d : %02x %s\n", + 11, spd->config, + " spd->config, * 11 DIMM Configuration type *"); + printf("%-3d : %02x %s\n", + 12, spd->refresh, + " spd->refresh, * 12 Refresh Rate/Type *"); + printf("%-3d : %02x %s\n", + 13, spd->primw, + " spd->primw, * 13 Primary SDRAM Width *"); + printf("%-3d : %02x %s\n", + 14, spd->ecw, + " spd->ecw, * 14 Error Checking SDRAM width *"); + printf("%-3d : %02x %s\n", + 15, spd->min_delay, + " spd->min_delay, * 15 Back to Back Random Access *"); + printf("%-3d : %02x %s\n", + 16, spd->burstl, + " spd->burstl, * 16 Burst Lengths Supported *"); + printf("%-3d : %02x %s\n", + 17, spd->nbanks, + " spd->nbanks, * 17 # of Banks on Each SDRAM Device *"); + printf("%-3d : %02x %s\n", + 18, spd->cas_lat, + " spd->cas_lat, * 18 CAS# Latencies Supported *"); + printf("%-3d : %02x %s\n", + 19, spd->cs_lat, + " spd->cs_lat, * 19 Chip Select Latency *"); + printf("%-3d : %02x %s\n", + 20, spd->write_lat, + " spd->write_lat, * 20 Write Latency/Recovery *"); + printf("%-3d : %02x %s\n", + 21, spd->mod_attr, + " spd->mod_attr, * 21 SDRAM Module Attributes *"); + printf("%-3d : %02x %s\n", + 22, spd->dev_attr, + " spd->dev_attr, * 22 SDRAM Device Attributes *"); + printf("%-3d : %02x %s\n", + 23, spd->clk_cycle2, + " spd->clk_cycle2, * 23 Min SDRAM Cycle time at CL=X-1 *"); + printf("%-3d : %02x %s\n", + 24, spd->clk_access2, + " spd->clk_access2, * 24 SDRAM Access from Clock at CL=X-1 *"); + printf("%-3d : %02x %s\n", + 25, spd->clk_cycle3, + " spd->clk_cycle3, * 25 Min SDRAM Cycle time at CL=X-2 *"); + printf("%-3d : %02x %s\n", + 26, spd->clk_access3, + " spd->clk_access3, * 26 Max Access from Clock at CL=X-2 *"); + printf("%-3d : %02x %s\n", + 27, spd->trp, + " spd->trp, * 27 Min Row Precharge Time (tRP)*"); + printf("%-3d : %02x %s\n", + 28, spd->trrd, + " spd->trrd, * 28 Min Row Active to Row Active (tRRD) *"); + printf("%-3d : %02x %s\n", + 29, spd->trcd, + " spd->trcd, * 29 Min RAS to CAS Delay (tRCD) *"); + printf("%-3d : %02x %s\n", + 30, spd->tras, + " spd->tras, * 30 Minimum RAS Pulse Width (tRAS) *"); + printf("%-3d : %02x %s\n", + 31, spd->bank_dens, + " spd->bank_dens, * 31 Density of each bank on module *"); + printf("%-3d : %02x %s\n", + 32, spd->ca_setup, + " spd->ca_setup, * 32 Cmd + Addr signal input setup time *"); + printf("%-3d : %02x %s\n", + 33, spd->ca_hold, + " spd->ca_hold, * 33 Cmd and Addr signal input hold time *"); + printf("%-3d : %02x %s\n", + 34, spd->data_setup, + " spd->data_setup, * 34 Data signal input setup time *"); + printf("%-3d : %02x %s\n", + 35, spd->data_hold, + " spd->data_hold, * 35 Data signal input hold time *"); + printf("%-3d : %02x %s\n", + 36, spd->res_36_40[0], + " spd->res_36_40[0], * 36 Reserved / tWR *"); + printf("%-3d : %02x %s\n", + 37, spd->res_36_40[1], + " spd->res_36_40[1], * 37 Reserved / tWTR *"); + printf("%-3d : %02x %s\n", + 38, spd->res_36_40[2], + " spd->res_36_40[2], * 38 Reserved / tRTP *"); + printf("%-3d : %02x %s\n", + 39, spd->res_36_40[3], + " spd->res_36_40[3], * 39 Reserved / mem_probe *"); + printf("%-3d : %02x %s\n", + 40, spd->res_36_40[4], + " spd->res_36_40[4], * 40 Reserved / trc,trfc extensions *"); + printf("%-3d : %02x %s\n", + 41, spd->trc, + " spd->trc, * 41 Min Active to Auto refresh time tRC *"); + printf("%-3d : %02x %s\n", + 42, spd->trfc, + " spd->trfc, * 42 Min Auto to Active period tRFC *"); + printf("%-3d : %02x %s\n", + 43, spd->tckmax, + " spd->tckmax, * 43 Max device cycle time tCKmax *"); + printf("%-3d : %02x %s\n", + 44, spd->tdqsq, + " spd->tdqsq, * 44 Max DQS to DQ skew *"); + printf("%-3d : %02x %s\n", + 45, spd->tqhs, + " spd->tqhs, * 45 Max Read DataHold skew tQHS *"); + printf("%-3d : %02x %s\n", + 46, spd->res_46, + " spd->res_46, * 46 Reserved/ PLL Relock time *"); + printf("%-3d : %02x %s\n", + 47, spd->dimm_height, + " spd->dimm_height * 47 SDRAM DIMM Height *"); + + printf("%-3d-%3d: ", 48, 61); + + for (i = 0; i < 14; i++) + printf("%02x", spd->res_48_61[i]); + + printf(" * 48-61 IDD in SPD and Reserved space *\n"); + + printf("%-3d : %02x %s\n", + 62, spd->spd_rev, + " spd->spd_rev, * 62 SPD Data Revision Code *"); + printf("%-3d : %02x %s\n", + 63, spd->cksum, + " spd->cksum, * 63 Checksum for bytes 0-62 *"); + printf("%-3d-%3d: ", 64, 71); + + for (i = 0; i < 8; i++) + printf("%02x", spd->mid[i]); + + printf("* 64 Mfr's JEDEC ID code per JEP-108E *\n"); + printf("%-3d : %02x %s\n", + 72, spd->mloc, + " spd->mloc, * 72 Manufacturing Location *"); + + printf("%-3d-%3d: >>", 73, 90); + + for (i = 0; i < 18; i++) + printf("%c", spd->mpart[i]); + + printf("<<* 73 Manufacturer's Part Number *\n"); + + printf("%-3d-%3d: %02x %02x %s\n", + 91, 92, spd->rev[0], spd->rev[1], + "* 91 Revision Code *"); + printf("%-3d-%3d: %02x %02x %s\n", + 93, 94, spd->mdate[0], spd->mdate[1], + "* 93 Manufacturing Date *"); + printf("%-3d-%3d: ", 95, 98); + + for (i = 0; i < 4; i++) + printf("%02x", spd->sernum[i]); + + printf("* 95 Assembly Serial Number *\n"); + + printf("%-3d-%3d: ", 99, 127); + + for (i = 0; i < 27; i++) + printf("%02x", spd->mspec[i]); + + printf("* 99 Manufacturer Specific Data *\n"); +} +#endif + +#ifdef CONFIG_FSL_DDR2 +void ddr2_spd_dump(const ddr2_spd_eeprom_t *spd) +{ + unsigned int i; + + printf("%-3d : %02x %s\n", + 0, spd->info_size, + " spd->info_size, * 0 # bytes written into serial memory *"); + printf("%-3d : %02x %s\n", + 1, spd->chip_size, + " spd->chip_size, * 1 Total # bytes of SPD memory device *"); + printf("%-3d : %02x %s\n", + 2, spd->mem_type, + " spd->mem_type, * 2 Fundamental memory type *"); + printf("%-3d : %02x %s\n", + 3, spd->nrow_addr, + " spd->nrow_addr, * 3 # of Row Addresses on this assembly *"); + printf("%-3d : %02x %s\n", + 4, spd->ncol_addr, + " spd->ncol_addr, * 4 # of Column Addrs on this assembly *"); + printf("%-3d : %02x %s\n", + 5, spd->mod_ranks, + " spd->mod_ranks * 5 # of Module Rows on this assembly *"); + printf("%-3d : %02x %s\n", + 6, spd->dataw, + " spd->dataw, * 6 Data Width of this assembly *"); + printf("%-3d : %02x %s\n", + 7, spd->res_7, + " spd->res_7, * 7 Reserved *"); + printf("%-3d : %02x %s\n", + 8, spd->voltage, + " spd->voltage, * 8 Voltage intf std of this assembly *"); + printf("%-3d : %02x %s\n", + 9, spd->clk_cycle, + " spd->clk_cycle, * 9 SDRAM Cycle time at CL=X *"); + printf("%-3d : %02x %s\n", + 10, spd->clk_access, + " spd->clk_access, * 10 SDRAM Access from Clock at CL=X *"); + printf("%-3d : %02x %s\n", + 11, spd->config, + " spd->config, * 11 DIMM Configuration type *"); + printf("%-3d : %02x %s\n", + 12, spd->refresh, + " spd->refresh, * 12 Refresh Rate/Type *"); + printf("%-3d : %02x %s\n", + 13, spd->primw, + " spd->primw, * 13 Primary SDRAM Width *"); + printf("%-3d : %02x %s\n", + 14, spd->ecw, + " spd->ecw, * 14 Error Checking SDRAM width *"); + printf("%-3d : %02x %s\n", + 15, spd->res_15, + " spd->res_15, * 15 Reserved *"); + printf("%-3d : %02x %s\n", + 16, spd->burstl, + " spd->burstl, * 16 Burst Lengths Supported *"); + printf("%-3d : %02x %s\n", + 17, spd->nbanks, + " spd->nbanks, * 17 # of Banks on Each SDRAM Device *"); + printf("%-3d : %02x %s\n", + 18, spd->cas_lat, + " spd->cas_lat, * 18 CAS# Latencies Supported *"); + printf("%-3d : %02x %s\n", + 19, spd->mech_char, + " spd->mech_char, * 19 Mechanical Characteristics *"); + printf("%-3d : %02x %s\n", + 20, spd->dimm_type, + " spd->dimm_type, * 20 DIMM type *"); + printf("%-3d : %02x %s\n", + 21, spd->mod_attr, + " spd->mod_attr, * 21 SDRAM Module Attributes *"); + printf("%-3d : %02x %s\n", + 22, spd->dev_attr, + " spd->dev_attr, * 22 SDRAM Device Attributes *"); + printf("%-3d : %02x %s\n", + 23, spd->clk_cycle2, + " spd->clk_cycle2, * 23 Min SDRAM Cycle time at CL=X-1 *"); + printf("%-3d : %02x %s\n", + 24, spd->clk_access2, + " spd->clk_access2, * 24 SDRAM Access from Clock at CL=X-1 *"); + printf("%-3d : %02x %s\n", + 25, spd->clk_cycle3, + " spd->clk_cycle3, * 25 Min SDRAM Cycle time at CL=X-2 *"); + printf("%-3d : %02x %s\n", + 26, spd->clk_access3, + " spd->clk_access3, * 26 Max Access from Clock at CL=X-2 *"); + printf("%-3d : %02x %s\n", + 27, spd->trp, + " spd->trp, * 27 Min Row Precharge Time (tRP)*"); + printf("%-3d : %02x %s\n", + 28, spd->trrd, + " spd->trrd, * 28 Min Row Active to Row Active (tRRD) *"); + printf("%-3d : %02x %s\n", + 29, spd->trcd, + " spd->trcd, * 29 Min RAS to CAS Delay (tRCD) *"); + printf("%-3d : %02x %s\n", + 30, spd->tras, + " spd->tras, * 30 Minimum RAS Pulse Width (tRAS) *"); + printf("%-3d : %02x %s\n", + 31, spd->rank_dens, + " spd->rank_dens, * 31 Density of each rank on module *"); + printf("%-3d : %02x %s\n", + 32, spd->ca_setup, + " spd->ca_setup, * 32 Cmd + Addr signal input setup time *"); + printf("%-3d : %02x %s\n", + 33, spd->ca_hold, + " spd->ca_hold, * 33 Cmd and Addr signal input hold time *"); + printf("%-3d : %02x %s\n", + 34, spd->data_setup, + " spd->data_setup, * 34 Data signal input setup time *"); + printf("%-3d : %02x %s\n", + 35, spd->data_hold, + " spd->data_hold, * 35 Data signal input hold time *"); + printf("%-3d : %02x %s\n", + 36, spd->twr, + " spd->twr, * 36 Write Recovery time tWR *"); + printf("%-3d : %02x %s\n", + 37, spd->twtr, + " spd->twtr, * 37 Int write to read delay tWTR *"); + printf("%-3d : %02x %s\n", + 38, spd->trtp, + " spd->trtp, * 38 Int read to precharge delay tRTP *"); + printf("%-3d : %02x %s\n", + 39, spd->mem_probe, + " spd->mem_probe, * 39 Mem analysis probe characteristics *"); + printf("%-3d : %02x %s\n", + 40, spd->trctrfc_ext, + " spd->trctrfc_ext, * 40 Extensions to trc and trfc *"); + printf("%-3d : %02x %s\n", + 41, spd->trc, + " spd->trc, * 41 Min Active to Auto refresh time tRC *"); + printf("%-3d : %02x %s\n", + 42, spd->trfc, + " spd->trfc, * 42 Min Auto to Active period tRFC *"); + printf("%-3d : %02x %s\n", + 43, spd->tckmax, + " spd->tckmax, * 43 Max device cycle time tCKmax *"); + printf("%-3d : %02x %s\n", + 44, spd->tdqsq, + " spd->tdqsq, * 44 Max DQS to DQ skew *"); + printf("%-3d : %02x %s\n", + 45, spd->tqhs, + " spd->tqhs, * 45 Max Read DataHold skew tQHS *"); + printf("%-3d : %02x %s\n", + 46, spd->pll_relock, + " spd->pll_relock, * 46 PLL Relock time *"); + printf("%-3d : %02x %s\n", + 47, spd->Tcasemax, + " spd->Tcasemax, * 47 Tcasemax *"); + printf("%-3d : %02x %s\n", + 48, spd->psiTAdram, + " spd->psiTAdram, * 48 Thermal Resistance of DRAM Package " + "from Top (Case) to Ambient (Psi T-A DRAM) *"); + printf("%-3d : %02x %s\n", + 49, spd->dt0_mode, + " spd->dt0_mode, * 49 DRAM Case Temperature Rise from " + "Ambient due to Activate-Precharge/Mode Bits " + "(DT0/Mode Bits) *)"); + printf("%-3d : %02x %s\n", + 50, spd->dt2n_dt2q, + " spd->dt2n_dt2q, * 50 DRAM Case Temperature Rise from " + "Ambient due to Precharge/Quiet Standby " + "(DT2N/DT2Q) *"); + printf("%-3d : %02x %s\n", + 51, spd->dt2p, + " spd->dt2p, * 51 DRAM Case Temperature Rise from " + "Ambient due to Precharge Power-Down (DT2P) *"); + printf("%-3d : %02x %s\n", + 52, spd->dt3n, + " spd->dt3n, * 52 DRAM Case Temperature Rise from " + "Ambient due to Active Standby (DT3N) *"); + printf("%-3d : %02x %s\n", + 53, spd->dt3pfast, + " spd->dt3pfast, * 53 DRAM Case Temperature Rise from " + "Ambient due to Active Power-Down with Fast PDN Exit " + "(DT3Pfast) *"); + printf("%-3d : %02x %s\n", + 54, spd->dt3pslow, + " spd->dt3pslow, * 54 DRAM Case Temperature Rise from " + "Ambient due to Active Power-Down with Slow PDN Exit " + "(DT3Pslow) *"); + printf("%-3d : %02x %s\n", + 55, spd->dt4r_dt4r4w, + " spd->dt4r_dt4r4w, * 55 DRAM Case Temperature Rise from " + "Ambient due to Page Open Burst Read/DT4R4W Mode Bit " + "(DT4R/DT4R4W Mode Bit) *"); + printf("%-3d : %02x %s\n", + 56, spd->dt5b, + " spd->dt5b, * 56 DRAM Case Temperature Rise from " + "Ambient due to Burst Refresh (DT5B) *"); + printf("%-3d : %02x %s\n", + 57, spd->dt7, + " spd->dt7, * 57 DRAM Case Temperature Rise from " + "Ambient due to Bank Interleave Reads with " + "Auto-Precharge (DT7) *"); + printf("%-3d : %02x %s\n", + 58, spd->psiTApll, + " spd->psiTApll, * 58 Thermal Resistance of PLL Package form" + " Top (Case) to Ambient (Psi T-A PLL) *"); + printf("%-3d : %02x %s\n", + 59, spd->psiTAreg, + " spd->psiTAreg, * 59 Thermal Reisitance of Register Package" + " from Top (Case) to Ambient (Psi T-A Register) *"); + printf("%-3d : %02x %s\n", + 60, spd->dtpllactive, + " spd->dtpllactive, * 60 PLL Case Temperature Rise from " + "Ambient due to PLL Active (DT PLL Active) *"); + printf("%-3d : %02x %s\n", + 61, spd->dtregact, + " spd->dtregact, " + "* 61 Register Case Temperature Rise from Ambient due to " + "Register Active/Mode Bit (DT Register Active/Mode Bit) *"); + printf("%-3d : %02x %s\n", + 62, spd->spd_rev, + " spd->spd_rev, * 62 SPD Data Revision Code *"); + printf("%-3d : %02x %s\n", + 63, spd->cksum, + " spd->cksum, * 63 Checksum for bytes 0-62 *"); + + printf("%-3d-%3d: ", 64, 71); + + for (i = 0; i < 8; i++) + printf("%02x", spd->mid[i]); + + printf("* 64 Mfr's JEDEC ID code per JEP-108E *\n"); + + printf("%-3d : %02x %s\n", + 72, spd->mloc, + " spd->mloc, * 72 Manufacturing Location *"); + + printf("%-3d-%3d: >>", 73, 90); + for (i = 0; i < 18; i++) + printf("%c", spd->mpart[i]); + + + printf("<<* 73 Manufacturer's Part Number *\n"); + + printf("%-3d-%3d: %02x %02x %s\n", + 91, 92, spd->rev[0], spd->rev[1], + "* 91 Revision Code *"); + printf("%-3d-%3d: %02x %02x %s\n", + 93, 94, spd->mdate[0], spd->mdate[1], + "* 93 Manufacturing Date *"); + printf("%-3d-%3d: ", 95, 98); + + for (i = 0; i < 4; i++) + printf("%02x", spd->sernum[i]); + + printf("* 95 Assembly Serial Number *\n"); + + printf("%-3d-%3d: ", 99, 127); + for (i = 0; i < 27; i++) + printf("%02x", spd->mspec[i]); + + + printf("* 99 Manufacturer Specific Data *\n"); +} +#endif + +#ifdef CONFIG_FSL_DDR3 +void ddr3_spd_dump(const ddr3_spd_eeprom_t *spd) +{ + unsigned int i; + + /* General Section: Bytes 0-59 */ + +#define PRINT_NXS(x, y, z) printf("%-3d : %02x %s\n", x, y, z); +#define PRINT_NNXXS(n0, n1, x0, x1, s) printf("%-3d-%3d: %02x %02x %s\n", n0, n1, x0, x1, s); +#define PRINT_SNNlots(x, y, z, arr) do {printf(x); printf("%-3d-%3d: ", y, z); for (i = y; i <= z; i++) printf("%02x", arr[i - y]); } while (0) + + PRINT_NXS(0, spd->info_size_crc, "info_size_crc bytes written into serial memory, CRC coverage"); + PRINT_NXS(1, spd->spd_rev, "spd_rev SPD Revision"); + PRINT_NXS(2, spd->mem_type, "mem_type Key Byte / DRAM Device Type"); + PRINT_NXS(3, spd->module_type, "module_type Key Byte / Module Type"); + PRINT_NXS(4, spd->density_banks, "density_banks SDRAM Density and Banks"); + PRINT_NXS(5, spd->addressing, "addressing SDRAM Addressing"); + PRINT_NXS(6, spd->module_vdd, "module_vdd Module Nominal Voltage, VDD"); + PRINT_NXS(7, spd->organization, "organization Module Organization"); + PRINT_NXS(8, spd->bus_width, "bus_width Module Memory Bus Width"); + PRINT_NXS(9, spd->ftb_div, "ftb_div Fine Timebase (FTB) Dividend / Divisor"); + PRINT_NXS(10, spd->mtb_dividend, "mtb_dividend Medium Timebase (MTB) Dividend"); + PRINT_NXS(11, spd->mtb_divisor, "mtb_divisor Medium Timebase (MTB) Divisor"); + PRINT_NXS(12, spd->tCK_min, "tCK_min SDRAM Minimum Cycle Time"); + PRINT_NXS(13, spd->res_13, "res_13 Reserved"); + PRINT_NXS(14, spd->caslat_lsb, "caslat_lsb CAS Latencies Supported, LSB"); + PRINT_NXS(15, spd->caslat_msb, "caslat_msb CAS Latencies Supported, MSB"); + PRINT_NXS(16, spd->tAA_min, "tAA_min Min CAS Latency Time"); + PRINT_NXS(17, spd->tWR_min, "tWR_min Min Write REcovery Time"); + PRINT_NXS(18, spd->tRCD_min, "tRCD_min Min RAS# to CAS# Delay Time"); + PRINT_NXS(19, spd->tRRD_min, "tRRD_min Min Row Active to Row Active Delay Time"); + PRINT_NXS(20, spd->tRP_min, "tRP_min Min Row Precharge Delay Time"); + PRINT_NXS(21, spd->tRAS_tRC_ext, "tRAS_tRC_ext Upper Nibbles for tRAS and tRC"); + PRINT_NXS(22, spd->tRAS_min_lsb, "tRAS_min_lsb Min Active to Precharge Delay Time, LSB"); + PRINT_NXS(23, spd->tRC_min_lsb, "tRC_min_lsb Min Active to Active/Refresh Delay Time, LSB"); + PRINT_NXS(24, spd->tRFC_min_lsb, "tRFC_min_lsb Min Refresh Recovery Delay Time LSB"); + PRINT_NXS(25, spd->tRFC_min_msb, "tRFC_min_msb Min Refresh Recovery Delay Time MSB"); + PRINT_NXS(26, spd->tWTR_min, "tWTR_min Min Internal Write to Read Command Delay Time"); + PRINT_NXS(27, spd->tRTP_min, "tRTP_min Min Internal Read to Precharge Command Delay Time"); + PRINT_NXS(28, spd->tFAW_msb, "tFAW_msb Upper Nibble for tFAW"); + PRINT_NXS(29, spd->tFAW_min, "tFAW_min Min Four Activate Window Delay Time"); + PRINT_NXS(30, spd->opt_features, "opt_features SDRAM Optional Features"); + PRINT_NXS(31, spd->therm_ref_opt, "therm_ref_opt SDRAM Thermal and Refresh Opts"); + PRINT_NXS(32, spd->therm_sensor, "therm_sensor SDRAM Thermal Sensor"); + PRINT_NXS(33, spd->device_type, "device_type SDRAM Device Type"); + + printf("%-3d-%3d: ", 34, 59); /* Reserved, General Section */ + + for (i = 34; i <= 59; i++) + printf("%02x", spd->res_34_59[i - 34]); + + puts("\n"); + + switch (spd->module_type) { + case 0x02: /* UDIMM */ + case 0x03: /* SO-DIMM */ + case 0x04: /* Micro-DIMM */ + case 0x06: /* Mini-UDIMM */ + PRINT_NXS(60, spd->mod_section.unbuffered.mod_height, "mod_height (Unbuffered) Module Nominal Height"); + PRINT_NXS(61, spd->mod_section.unbuffered.mod_thickness, "mod_thickness (Unbuffered) Module Maximum Thickness"); + PRINT_NXS(62, spd->mod_section.unbuffered.ref_raw_card, "ref_raw_card (Unbuffered) Reference Raw Card Used"); + PRINT_NXS(63, spd->mod_section.unbuffered.addr_mapping, "addr_mapping (Unbuffered) Address mapping from Edge Connector to DRAM"); + break; + case 0x01: /* RDIMM */ + case 0x05: /* Mini-RDIMM */ + PRINT_NXS(60, spd->mod_section.registered.mod_height, "mod_height (Registered) Module Nominal Height"); + PRINT_NXS(61, spd->mod_section.registered.mod_thickness, "mod_thickness (Registered) Module Maximum Thickness"); + PRINT_NXS(62, spd->mod_section.registered.ref_raw_card, "ref_raw_card (Registered) Reference Raw Card Used"); + PRINT_NXS(63, spd->mod_section.registered.modu_attr, "modu_attr (Registered) DIMM Module Attributes"); + PRINT_NXS(64, spd->mod_section.registered.thermal, "thermal (Registered) Thermal Heat Spreader Solution"); + PRINT_NXS(65, spd->mod_section.registered.reg_id_lo, "reg_id_lo (Registered) Register Manufacturer ID Code, LSB"); + PRINT_NXS(66, spd->mod_section.registered.reg_id_hi, "reg_id_hi (Registered) Register Manufacturer ID Code, MSB"); + PRINT_NXS(67, spd->mod_section.registered.reg_rev, "reg_rev (Registered) Register Revision Number"); + PRINT_NXS(68, spd->mod_section.registered.reg_type, "reg_type (Registered) Register Type"); + for (i = 69; i <= 76; i++) + printf("%-3d : %02x rcw[%d]\n", i, spd->mod_section.registered.rcw[i-69], i-69); + break; + default: + printf("%-3d-%3d: ", 60, 116); /* Module-specific Section, Unsupported Module Type */ + + for (i = 60; i <= 116; i++) + printf("%02x", spd->mod_section.uc[i - 60]); + + break; + } + + /* Unique Module ID: Bytes 117-125 */ + PRINT_NXS(117, spd->mmid_lsb, "Module MfgID Code LSB - JEP-106"); + PRINT_NXS(118, spd->mmid_msb, "Module MfgID Code MSB - JEP-106"); + PRINT_NXS(119, spd->mloc, "Mfg Location"); + PRINT_NNXXS(120, 121, spd->mdate[0], spd->mdate[1], "Mfg Date"); + + printf("122-125 Module Serial Number\n"); + printf("%-3d-%3d: ", 122, 125); + + for (i = 122; i <= 125; i++) + printf("%02x", spd->sernum[i - 122]); + + + /* CRC: Bytes 126-127 */ + PRINT_NNXXS(126, 127, spd->crc[0], spd->crc[1], "SPD CRC"); + + /* Other Manufacturer Fields and User Space: Bytes 128-255 */ + + printf("128-145 Mfg's Module Part Number\n"); + printf("%-3d-%3d: ", 128, 145); + + for (i = 128; i <= 145; i++) + printf("%02x", spd->mpart[i - 128]); + + puts("\n"); + PRINT_NNXXS(146, 147, spd->mrev[0], spd->mrev[1], "Module Revision code"); + + PRINT_NXS(148, spd->dmid_lsb, "DRAM MfgID Code LSB - JEP-106"); + PRINT_NXS(149, spd->dmid_msb, "DRAM MfgID Code MSB - JEP-106"); + + printf("150-175 Mfg's Specific Data\n"); + printf("%-3d-%3d: ", 150, 175); + + for (i = 150; i <= 175; i++) + printf("%02x", spd->msd[i - 150]); + + puts("\n"); + printf("176-255 Mfg's Specific Data\n"); + printf("%-3d-%3d: ", 176, 255); + for (i = 176; i <= 255; i++) + printf("%02x", spd->cust[i - 176]); + +} +#endif + +static __inline__ void generic_spd_dump(const generic_spd_eeprom_t *spd) +{ +#if defined(CONFIG_FSL_DDR1) + ddr1_spd_dump(spd); +#elif defined(CONFIG_FSL_DDR2) + ddr2_spd_dump(spd); +#elif defined(CONFIG_FSL_DDR3) + ddr3_spd_dump(spd); +#endif +} + +static void fsl_ddr_printinfo(const fsl_ddr_info_t *pinfo, + unsigned int ctrl_mask, + unsigned int dimm_mask, + unsigned int do_mask) +{ + unsigned int i, j, retval; + + /* STEP 1: DIMM SPD data */ + if (do_mask & STEP_GET_SPD) { + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + if (!(ctrl_mask & (1 << i))) + continue; + + /* + * FIXME: find a way to make this generate more + * optimal powerpc code (i.e. rlwimi.) + */ + for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) { + if (!(dimm_mask & (1 << j))) + continue; + + printf("SPD info: Controller=%u " + "DIMM=%u\n", i, j); + generic_spd_dump( + &(pinfo->spd_installed_dimms[i][j])); + printf("\n"); + } + printf("\n"); + } + printf("\n"); + } + + /* STEP 2: DIMM Parameters */ + if (do_mask & STEP_COMPUTE_DIMM_PARMS) { + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + if (!(ctrl_mask & (1 << i))) + continue; + for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) { + if (!(dimm_mask & (1 << j))) + continue; + printf("DIMM parameters: Controller=%u " + "DIMM=%u\n", i, j); + print_dimm_parameters( + &(pinfo->dimm_params[i][j])); + printf("\n"); + } + printf("\n"); + } + printf("\n"); + } + + /* STEP 3: Common Parameters */ + if (do_mask & STEP_COMPUTE_COMMON_PARMS) { + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + if (!(ctrl_mask & (1 << i))) + continue; + printf(""lowest common" DIMM parameters: " + "Controller=%u\n", i); + print_lowest_common_dimm_parameters( + &pinfo->common_timing_params[i]); + printf("\n"); + } + printf("\n"); + } + + /* STEP 4: User Configuration Options */ + if (do_mask & STEP_GATHER_OPTS) { + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + if (!(ctrl_mask & (1 << i))) + continue; + printf("User Config Options: Controller=%u\n", i); + print_memctl_options(&pinfo->memctl_opts[i]); + printf("\n"); + } + printf("\n"); + } + + /* STEP 5: Address assignment */ + if (do_mask & STEP_ASSIGN_ADDRESSES) { + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + if (!(ctrl_mask & (1 << i))) + continue; + for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) { + printf("Address Assignment: Controller=%u " + "DIMM=%u\n", i, j); + printf("Don't have this functionality yet\n"); + } + printf("\n"); + } + printf("\n"); + } + + /* STEP 6: computed controller register values */ + if (do_mask & STEP_COMPUTE_REGS) { + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + if (!(ctrl_mask & (1 << i))) + continue; + printf("Computed Register Values: Controller=%u\n", i); + print_fsl_memctl_config_regs( + &pinfo->fsl_ddr_config_reg[i]); + retval = check_fsl_memctl_config_regs( + &pinfo->fsl_ddr_config_reg[i]); + if (retval) { + printf("check_fsl_memctl_config_regs " + "result = %u\n", retval); + } + printf("\n"); + } + printf("\n"); + } +} + +phys_size_t fsl_ddr_interactive(fsl_ddr_info_t *pinfo) +{ + phys_size_t ddrsize; + const char *prompt = "FSL DDR>"; + unsigned int len; + char buffer[CONFIG_SYS_CBSIZE]; + char *argv[CONFIG_SYS_MAXARGS + 1]; /* NULL terminated */ + int argc; + unsigned int next_step = STEP_GET_SPD; + + /* + * The strategy for next_step is that it points to the next + * step in the computation process that needs to be done. + */ + while (1) { + /* + * No need to worry for buffer overflow here in + * this function; readline() maxes out at CFG_CBSIZE + */ + len = readline_into_buffer(prompt, buffer); + argc = parse_line(buffer, argv); + if (argc == 0) + continue; + + + if (strcmp(argv[0], "help") == 0) { + + /* + * FIXME: For some reason printing this whole + * thing causes the machine to freeze. + * Splitting it into two printfs seems to make + * it work. Does printf() have limits on the + * length of the string? + */ + printf( + "commands:\n" + "print print SPD and intermediate computed data\n" + "reset reboot machine\n" + "recompute reload SPD and options to default and recompute regs\n"); + printf( + "edit modify spd, parameter, or option\n"); + printf( + "compute recompute registers from current next_step to end\n" + "next_step shows current next_step\n" + "help this message\n" + "go program the memory controller and continue with u-boot\n"); + continue; + } + + if (strcmp(argv[0], "next_step") == 0) { + printf("next_step = 0x%02X (%s)\n", + next_step, + step_to_string(next_step)); + continue; + } + + if (strcmp(argv[0], "edit") == 0) { + unsigned int i; + unsigned int error = 0; + unsigned int step_mask = 0; + unsigned int ctlr_mask = 0; + unsigned int dimm_mask = 0; + char *p_element = NULL; + char *p_value = NULL; + unsigned int dimm_number_required = 0; + unsigned int ctrl_num; + unsigned int dimm_num; + + if (argc == 1) { + /* Only the element and value must be last */ + printf("edit <c#> <d#> " + "<spd|dimmparms|commonparms|opts|" + "addresses|regs> <element> <value>\n"); + printf("for spd, specify byte number for element\n"); + continue; + } + + for (i = 1; i < argc - 2; i++) { + if (strcmp(argv[i], "spd") == 0) { + step_mask |= STEP_GET_SPD; + dimm_number_required = 1; + continue; + } + + if (strcmp(argv[i], "dimmparms") == 0) { + step_mask |= STEP_COMPUTE_DIMM_PARMS; + dimm_number_required = 1; + continue; + } + + if (strcmp(argv[i], "commonparms") == 0) { + step_mask |= STEP_COMPUTE_COMMON_PARMS; + continue; + } + + if (strcmp(argv[i], "opts") == 0) { + step_mask |= STEP_GATHER_OPTS; + continue; + } + + if (strcmp(argv[i], "addresses") == 0) { + step_mask |= STEP_ASSIGN_ADDRESSES; + /* FIXME: not done yet */ + continue; + } + + if (strcmp(argv[i], "regs") == 0) { + step_mask |= STEP_COMPUTE_REGS; + continue; + } + + if (argv[i][0] == 'c') { + char c = argv[i][1]; + if (isdigit(c)) + ctlr_mask |= 1 << (c - '0'); + continue; + } + + if (argv[i][0] == 'd') { + char c = argv[i][1]; + if (isdigit(c)) + dimm_mask |= 1 << (c - '0'); + continue; + } + + printf("unknown arg %s\n", argv[i]); + step_mask = 0; + error = 1; + break; + } + + + if (error) + continue; + + + /* Check arguments */ + + /* ERROR: If no steps were found */ + if (step_mask == 0) { + printf("Error: No valid steps were specified " + "in argument.\n"); + continue; + } + + /* ERROR: If multiple steps were found */ + if (step_mask & (step_mask - 1)) { + printf("Error: Multiple steps specified in " + "argument.\n"); + continue; + } + + /* ERROR: Controller not specified */ + if (ctlr_mask == 0) { + printf("Error: controller number not " + "specified or no element and " + "value specified\n"); + continue; + } + + if (ctlr_mask & (ctlr_mask - 1)) { + printf("Error: multiple controllers " + "specified, %X\n", ctlr_mask); + continue; + } + + /* ERROR: DIMM number not specified */ + if (dimm_number_required && dimm_mask == 0) { + printf("Error: DIMM number number not " + "specified or no element and " + "value specified\n"); + continue; + } + + if (dimm_mask & (dimm_mask - 1)) { + printf("Error: multipled DIMMs specified\n"); + continue; + } + + p_element = argv[argc - 2]; + p_value = argv[argc - 1]; + + ctrl_num = __ilog2(ctlr_mask); + dimm_num = __ilog2(dimm_mask); + + switch (step_mask) { + case STEP_GET_SPD: + { + unsigned int element_num; + unsigned int value; + + element_num = simple_strtoul(p_element, + NULL, 0); + value = simple_strtoul(p_value, + NULL, 0); + fsl_ddr_spd_edit(pinfo, + ctrl_num, + dimm_num, + element_num, + value); + next_step = STEP_COMPUTE_DIMM_PARMS; + } + break; + + case STEP_COMPUTE_DIMM_PARMS: + fsl_ddr_dimm_parameters_edit( + pinfo, ctrl_num, dimm_num, + p_element, p_value); + next_step = STEP_COMPUTE_COMMON_PARMS; + break; + + case STEP_COMPUTE_COMMON_PARMS: + lowest_common_dimm_parameters_edit(pinfo, + ctrl_num, p_element, p_value); + next_step = STEP_GATHER_OPTS; + break; + + case STEP_GATHER_OPTS: + fsl_ddr_options_edit(pinfo, ctrl_num, + p_element, p_value); + next_step = STEP_ASSIGN_ADDRESSES; + break; + + case STEP_ASSIGN_ADDRESSES: + printf("editing of address assignment " + "not yet implemented\n"); + break; + + case STEP_COMPUTE_REGS: + { + unsigned int value; + + value = simple_strtoul(p_value, + NULL, 0); + fsl_ddr_regs_edit(pinfo, + ctrl_num, + p_element, + value); + next_step = STEP_PROGRAM_REGS; + } + break; + + default: + printf("programming error\n"); + while (1); + break; + } + continue; + } + + if (strcmp(argv[0], "reset") == 0) { + /* + * Reboot machine. + * Args don't seem to matter because this + * doesn't return + */ + do_reset(NULL, 0, 0, NULL); + } + + if (strcmp(argv[0], "recompute") == 0) { + /* + * Recalculate everything, starting with + * loading SPD EEPROM from DIMMs + */ + next_step = STEP_GET_SPD; + ddrsize = fsl_ddr_compute(pinfo, next_step); + /* + * FIXME: There some problems with this. + * For exmaple, what happens if there is + * an error inside fsl_ddr_compute? + */ + continue; + } + + if (strcmp(argv[0], "compute") == 0) { + /* + * Compute rest of steps starting at + * the current next_step/ + */ + ddrsize = fsl_ddr_compute(pinfo, next_step); + continue; + } + + if (strcmp(argv[0], "print") == 0) { + unsigned int i; + unsigned int error = 0; + unsigned int step_mask = 0; + unsigned int ctlr_mask = 0; + unsigned int dimm_mask = 0; + + if (argc == 1) { + printf("print [c<n>] [d<n>] [spd] [dimmparms] " + "[commonparms] [opts] [addresses] [regs]\n"); + continue; + } + + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "spd") == 0) { + step_mask |= STEP_GET_SPD; + continue; + } + + if (strcmp(argv[i], "dimmparms") == 0) { + step_mask |= STEP_COMPUTE_DIMM_PARMS; + continue; + } + + if (strcmp(argv[i], "commonparms") == 0) { + step_mask |= STEP_COMPUTE_COMMON_PARMS; + continue; + } + + if (strcmp(argv[i], "opts") == 0) { + step_mask |= STEP_GATHER_OPTS; + continue; + } + + if (strcmp(argv[i], "addresses") == 0) { + step_mask |= STEP_ASSIGN_ADDRESSES; + continue; + } + + if (strcmp(argv[i], "regs") == 0) { + step_mask |= STEP_COMPUTE_REGS; + continue; + } + + if (argv[i][0] == 'c') { + char c = argv[i][1]; + if (isdigit(c)) + ctlr_mask |= 1 << (c - '0'); + continue; + } + + if (argv[i][0] == 'd') { + char c = argv[i][1]; + if (isdigit(c)) + dimm_mask |= 1 << (c - '0'); + continue; + } + + printf("unknown arg %s\n", argv[i]); + step_mask = 0; + error = 1; + break; + } + + if (error) + continue; + + /* If no particular controller was found, print all */ + if (ctlr_mask == 0) + ctlr_mask = 0xFF; + + /* If no particular dimm was found, print all dimms. */ + if (dimm_mask == 0) + dimm_mask = 0xFF; + + /* If no steps were found, print all steps. */ + if (step_mask == 0) + step_mask = STEP_ALL; + + fsl_ddr_printinfo(pinfo, ctlr_mask, + dimm_mask, step_mask); + continue; + } + + if (strcmp(argv[0], "go") == 0) { + if (next_step) { + ddrsize = fsl_ddr_compute(pinfo, next_step); + } + break; + } + + printf("unknown command %s\n", argv[0]); + } + + debug("end of memory = %llu\n", (u64)ddrsize); + + return ddrsize; +} diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/main.c b/arch/powerpc/cpu/mpc8xxx/ddr/main.c index 6d582e9..83a6dd4 100644 --- a/arch/powerpc/cpu/mpc8xxx/ddr/main.c +++ b/arch/powerpc/cpu/mpc8xxx/ddr/main.c @@ -21,6 +21,7 @@ extern void fsl_ddr_set_lawbar( const common_timing_params_t *memctl_common_params, unsigned int memctl_interleaved, unsigned int ctrl_num); +extern phys_size_t fsl_ddr_interactive(fsl_ddr_info_t *pinfo);
/* processor specific function */ extern void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs, @@ -75,7 +76,6 @@ extern void fsl_ddr_get_spd(generic_spd_eeprom_t *ctrl_dimms_spd, * | interleaving */
-#ifdef DEBUG const char *step_string_tbl[] = { "STEP_GET_SPD", "STEP_COMPUTE_DIMM_PARMS", @@ -96,7 +96,6 @@ const char * step_to_string(unsigned int step) {
return step_string_tbl[s]; } -#endif
int step_assign_addresses(fsl_ddr_info_t *pinfo, unsigned int dbw_cap_adj[], @@ -405,7 +404,10 @@ phys_size_t fsl_ddr_sdram(void) memset(&info, 0, sizeof(fsl_ddr_info_t));
/* Compute it once normally. */ - total_memory = fsl_ddr_compute(&info, STEP_GET_SPD); + if (getenv("ddr_interactive")) + total_memory = fsl_ddr_interactive(&info); + else + total_memory = fsl_ddr_compute(&info, STEP_GET_SPD);
/* Check for memory controller interleaving. */ memctl_interleaved = 0; diff --git a/doc/README.fsl-ddr b/doc/README.fsl-ddr index a7ba193..13c9013 100644 --- a/doc/README.fsl-ddr +++ b/doc/README.fsl-ddr @@ -170,3 +170,23 @@ Single slot system
Reference http://www.xrosstalkmag.com/mag_issues/xrosstalk_oct08_final.pdf http://download.micron.com/pdf/technotes/ddr3/tn4108_ddr3_design_guide.pdf + + +Interactive DDR debugging +=========================== + +For DDR parameter tuning up and debugging, the interactive DDR debugging can +be activated by saving an environment variable "ddr_interactive". The value +doesn't matter. Once activated, U-boot prompts "FSL DDR>" before enabling DDR +controller. The available commands can be seen by typing "help". + +The example flow of using interactive debugging is +type command "compute" to calculate the parameters from the default +type command "print" with arguments to show SPD, options, registers +type command "edit" with arguments to change any if desired +type command "go" to continue calculation and enable DDR controller + +Note, check "next_step" to show the flow. For example, after editing registers, +DDR controller will be enabled with current setting without further +calculation. +

On Dec 8, 2010, at 8:55 PM, York Sun wrote:
Use environment variable to active the interactive debugging.
Signed-off-by: York Sun yorksun@freescale.com
arch/powerpc/cpu/mpc8xxx/ddr/Makefile | 6 +- arch/powerpc/cpu/mpc8xxx/ddr/interactive.c | 1882 ++++++++++++++++++++++++++++ arch/powerpc/cpu/mpc8xxx/ddr/main.c | 8 +- doc/README.fsl-ddr | 20 + 4 files changed, 1910 insertions(+), 6 deletions(-) create mode 100644 arch/powerpc/cpu/mpc8xxx/ddr/interactive.c
Can you make this the last patch.
- k

Dear York Sun,
In message 1291863340-4354-9-git-send-email-yorksun@freescale.com you wrote:
Use environment variable to active the interactive debugging.
...
s/active/activate/
diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/Makefile b/arch/powerpc/cpu/mpc8xxx/ddr/Makefile index cb7f856..4bd416a 100644 --- a/arch/powerpc/cpu/mpc8xxx/ddr/Makefile +++ b/arch/powerpc/cpu/mpc8xxx/ddr/Makefile @@ -11,15 +11,15 @@ include $(TOPDIR)/config.mk LIB = $(obj)libddr.a
COBJS-$(CONFIG_FSL_DDR1) += main.o util.o ctrl_regs.o options.o \
lc_common_dimm_params.o
lc_common_dimm_params.o interactive.o
COBJS-$(CONFIG_FSL_DDR1) += ddr1_dimm_params.o
COBJS-$(CONFIG_FSL_DDR2) += main.o util.o ctrl_regs.o options.o \
lc_common_dimm_params.o
lc_common_dimm_params.o interactive.o
COBJS-$(CONFIG_FSL_DDR2) += ddr2_dimm_params.o
COBJS-$(CONFIG_FSL_DDR3) += main.o util.o ctrl_regs.o options.o \
lc_common_dimm_params.o
lc_common_dimm_params.o interactive.o
COBJS-$(CONFIG_FSL_DDR3) += ddr3_dimm_params.o
Building interactive.o should depend on CONFIG_FSL_DDR_INTERACTIVE being set.
SRCS := $(START:.o=.S) $(SOBJS-y:.o=.S) $(COBJS-y:.o=.c) diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/interactive.c b/arch/powerpc/cpu/mpc8xxx/ddr/interactive.c new file mode 100644 index 0000000..7d492a9 --- /dev/null +++ b/arch/powerpc/cpu/mpc8xxx/ddr/interactive.c @@ -0,0 +1,1882 @@ +/*
- Copyright 2010 Freescale Semiconductor, Inc.
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- Version 2 as published by the Free Software Foundation.
- */
NAK. V2 or later is mandatory.
+static void fsl_ddr_generic_edit(void *pdata,
void *pend,
unsigned int element_size,
unsigned int element_num,
unsigned int value)
+{
- char *pcdata = (char *)pdata; /* BIG ENDIAN ONLY */
- pcdata += element_num * element_size;
- if ((pcdata + element_size) > (char *) pend) {
debug("trying to write past end of data\n");
return;
Should that not be an error message that is always enabled?
- default:
debug("unexpected element size %u\n", element_size);
break;
Ditto?
- static const options_strings_t options[] = {
{"cs0_odt_rd_cfg", offsetof(memctl_options_t, cs_local_opts[0].odt_rd_cfg)},
{"cs0_odt_wr_cfg", offsetof(memctl_options_t, cs_local_opts[0].odt_wr_cfg)},
{"cs0_odt_rtt_norm", offsetof(memctl_options_t, cs_local_opts[0].odt_rtt_norm)},
{"cs0_odt_rtt_wr", offsetof(memctl_options_t, cs_local_opts[0].odt_rtt_wr)},
{"cs1_odt_rd_cfg", offsetof(memctl_options_t, cs_local_opts[1].odt_rd_cfg)},
{"cs1_odt_wr_cfg", offsetof(memctl_options_t, cs_local_opts[1].odt_wr_cfg)},
{"cs1_odt_rtt_norm", offsetof(memctl_options_t, cs_local_opts[1].odt_rtt_norm)},
{"cs1_odt_rtt_wr", offsetof(memctl_options_t, cs_local_opts[1].odt_rtt_wr)},
{"cs2_odt_rd_cfg", offsetof(memctl_options_t, cs_local_opts[2].odt_rd_cfg)},
{"cs2_odt_wr_cfg", offsetof(memctl_options_t, cs_local_opts[2].odt_wr_cfg)},
{"cs2_odt_rtt_norm", offsetof(memctl_options_t, cs_local_opts[2].odt_rtt_norm)},
{"cs2_odt_rtt_wr", offsetof(memctl_options_t, cs_local_opts[2].odt_rtt_wr)},
{"cs3_odt_rd_cfg", offsetof(memctl_options_t, cs_local_opts[3].odt_rd_cfg)},
{"cs3_odt_wr_cfg", offsetof(memctl_options_t, cs_local_opts[3].odt_wr_cfg)},
{"cs3_odt_rtt_norm", offsetof(memctl_options_t, cs_local_opts[3].odt_rtt_norm)},
{"cs3_odt_rtt_wr", offsetof(memctl_options_t, cs_local_opts[3].odt_rtt_wr)},
Lines too long.
- if (handle_uint_option_table(options, nopts, (u32) p,
optname_str, value_str))
return;
Please use braces for multiline statements.
- printf("couldn't find option string %s\n", optname_str);
+}
+static void print_fsl_memctl_config_regs(const fsl_ddr_cfg_regs_t *ddr) +{
- unsigned int i;
- for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
printf("cs%u_bnds = %08X\n", i, ddr->cs[i].bnds);
printf("cs%u_config = %08X\n", i, ddr->cs[i].config);
printf("cs%u_config_2 = %08X\n", i, ddr->cs[i].config_2);
- }
- printf("timing_cfg_3 = %08X\n", ddr->timing_cfg_3);
- printf("timing_cfg_0 = %08X\n", ddr->timing_cfg_0);
- printf("timing_cfg_1 = %08X\n", ddr->timing_cfg_1);
- printf("timing_cfg_2 = %08X\n", ddr->timing_cfg_2);
- printf("ddr_sdram_cfg = %08X\n", ddr->ddr_sdram_cfg);
- printf("ddr_sdram_cfg_2 = %08X\n", ddr->ddr_sdram_cfg_2);
- printf("ddr_sdram_mode = %08X\n", ddr->ddr_sdram_mode);
- printf("ddr_sdram_mode_2 = %08X\n", ddr->ddr_sdram_mode_2);
- printf("ddr_sdram_mode_3 = %08X\n", ddr->ddr_sdram_mode_3);
- printf("ddr_sdram_mode_4 = %08X\n", ddr->ddr_sdram_mode_4);
- printf("ddr_sdram_mode_5 = %08X\n", ddr->ddr_sdram_mode_5);
- printf("ddr_sdram_mode_6 = %08X\n", ddr->ddr_sdram_mode_6);
- printf("ddr_sdram_mode_7 = %08X\n", ddr->ddr_sdram_mode_7);
- printf("ddr_sdram_mode_8 = %08X\n", ddr->ddr_sdram_mode_8);
- printf("ddr_sdram_interval = %08X\n", ddr->ddr_sdram_interval);
- printf("ddr_data_init = %08X\n", ddr->ddr_data_init);
- printf("ddr_sdram_clk_cntl = %08X\n", ddr->ddr_sdram_clk_cntl);
- printf("ddr_init_addr = %08X\n", ddr->ddr_init_addr);
- printf("ddr_init_ext_addr = %08X\n", ddr->ddr_init_ext_addr);
- printf("timing_cfg_4 = %08X\n", ddr->timing_cfg_4);
- printf("timing_cfg_5 = %08X\n", ddr->timing_cfg_5);
- printf("ddr_zq_cntl = %08X\n", ddr->ddr_zq_cntl);
- printf("ddr_wrlvl_cntl = %08X\n", ddr->ddr_wrlvl_cntl);
- printf("ddr_sr_cntr = %08X\n", ddr->ddr_sr_cntr);
- printf("ddr_sdram_rcw_1 = %08X\n", ddr->ddr_sdram_rcw_1);
- printf("ddr_sdram_rcw_2 = %08X\n", ddr->ddr_sdram_rcw_2);
- printf("ddr_cdr1 = %08X\n", ddr->ddr_cdr1);
- printf("ddr_cdr2 = %08X\n", ddr->ddr_cdr2);
- printf("err_disable = %08X\n", ddr->err_disable);
- printf("err_int_en = %08X\n", ddr->err_int_en);
- for (i = 0; i < 18; i++)
printf("debug_%02d = %08X\n", i+1, ddr->debug[i]);
+}
+static void fsl_ddr_regs_edit(fsl_ddr_info_t *pinfo,
unsigned int ctrl_num,
const char *regname,
unsigned int value)
+{
- unsigned int i;
- fsl_ddr_cfg_regs_t *ddr;
- char buf[20];
- debug("fsl_ddr_regs_edit: ctrl_num = %u, "
"regname = %s, value = 0x%08X\n",
ctrl_num, regname, value);
- if (ctrl_num > CONFIG_NUM_DDR_CONTROLLERS)
return;
- /* FIXME: Change this into struct like the other editing functions */
- ddr = &(pinfo->fsl_ddr_config_reg[ctrl_num]);
- for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
sprintf(buf, "cs%u_bnds", i);
if (strcmp(buf, regname) == 0) {
ddr->cs[i].bnds = value;
return;
}
sprintf(buf, "cs%u_config", i);
if (strcmp(buf, regname) == 0) {
ddr->cs[i].config = value;
return;
}
sprintf(buf, "cs%u_config_2", i);
if (strcmp(buf, regname) == 0) {
ddr->cs[i].config_2 = value;
return;
}
- }
Use format string / pointer table and a loop.
- if (strcmp("timing_cfg_3", regname) == 0) {
ddr->timing_cfg_3 = value;
return;
- }
- if (strcmp("timing_cfg_0", regname) == 0) {
ddr->timing_cfg_0 = value;
return;
- }
- if (strcmp("timing_cfg_1", regname) == 0) {
ddr->timing_cfg_1 = value;
return;
- }
- if (strcmp("timing_cfg_2", regname) == 0) {
ddr->timing_cfg_2 = value;
return;
- }
- if (strcmp("ddr_sdram_cfg", regname) == 0) {
ddr->ddr_sdram_cfg = value;
return;
- }
- if (strcmp("ddr_sdram_cfg_2", regname) == 0) {
ddr->ddr_sdram_cfg_2 = value;
return;
- }
- if (strcmp("ddr_sdram_mode", regname) == 0) {
ddr->ddr_sdram_mode = value;
return;
- }
- if (strcmp("ddr_sdram_mode_2", regname) == 0) {
ddr->ddr_sdram_mode_2 = value;
return;
- }
- if (strcmp("ddr_sdram_mode_3", regname) == 0) {
ddr->ddr_sdram_mode_3 = value;
return;
- }
- if (strcmp("ddr_sdram_mode_4", regname) == 0) {
ddr->ddr_sdram_mode_4 = value;
return;
- }
- if (strcmp("ddr_sdram_mode_5", regname) == 0) {
ddr->ddr_sdram_mode_5 = value;
return;
- }
- if (strcmp("ddr_sdram_mode_6", regname) == 0) {
ddr->ddr_sdram_mode_6 = value;
return;
- }
- if (strcmp("ddr_sdram_mode_7", regname) == 0) {
ddr->ddr_sdram_mode_7 = value;
return;
- }
- if (strcmp("ddr_sdram_mode_8", regname) == 0) {
ddr->ddr_sdram_mode_8 = value;
return;
- }
- if (strcmp("ddr_sdram_interval", regname) == 0) {
ddr->ddr_sdram_interval = value;
return;
- }
- if (strcmp("ddr_data_init", regname) == 0) {
ddr->ddr_data_init = value;
return;
- }
- if (strcmp("ddr_sdram_clk_cntl", regname) == 0) {
ddr->ddr_sdram_clk_cntl = value;
return;
- }
- if (strcmp("ddr_init_addr", regname) == 0) {
ddr->ddr_init_addr = value;
return;
- }
- if (strcmp("ddr_init_ext_addr", regname) == 0) {
ddr->ddr_init_ext_addr = value;
return;
- }
- if (strcmp("timing_cfg_4", regname) == 0) {
ddr->timing_cfg_4 = value;
return;
- }
- if (strcmp("timing_cfg_5", regname) == 0) {
ddr->timing_cfg_5 = value;
return;
- }
- if (strcmp("ddr_zq_cntl", regname) == 0) {
ddr->ddr_zq_cntl = value;
return;
- }
- if (strcmp("ddr_wrlvl_cntl", regname) == 0) {
ddr->ddr_wrlvl_cntl = value;
return;
- }
- if (strcmp("ddr_sr_cntr", regname) == 0) {
ddr->ddr_sr_cntr = value;
return;
- }
- if (strcmp("ddr_sdram_rcw_1", regname) == 0) {
ddr->ddr_sdram_rcw_1 = value;
return;
- }
- if (strcmp("ddr_sdram_rcw_2", regname) == 0) {
ddr->ddr_sdram_rcw_2 = value;
return;
- }
- if (strcmp("ddr_cdr1", regname) == 0) {
ddr->ddr_cdr1 = value;
return;
- }
- if (strcmp("ddr_cdr2", regname) == 0) {
ddr->ddr_cdr2 = value;
return;
- }
- if (strcmp("err_disable", regname) == 0) {
ddr->err_disable = value;
return;
- }
- if (strcmp("err_int_en", regname) == 0) {
ddr->err_int_en = value;
return;
- }
Use string / pointer table and a loop.
...
+#define PRINT_NXS(x, y, z) printf("%-3d : %02x %s\n", x, y, z); +#define PRINT_NNXXS(n0, n1, x0, x1, s) printf("%-3d-%3d: %02x %02x %s\n", n0, n1, x0, x1, s); +#define PRINT_SNNlots(x, y, z, arr) do {printf(x); printf("%-3d-%3d: ", y, z); for (i = y; i <= z; i++) printf("%02x", arr[i - y]); } while (0)
Lines way too long; please fix globally.
...
if (strcmp(argv[i], "dimmparms") == 0) {
step_mask |= STEP_COMPUTE_DIMM_PARMS;
continue;
}
if (strcmp(argv[i], "commonparms") == 0) {
step_mask |= STEP_COMPUTE_COMMON_PARMS;
continue;
}
if (strcmp(argv[i], "opts") == 0) {
step_mask |= STEP_GATHER_OPTS;
continue;
}
if (strcmp(argv[i], "addresses") == 0) {
step_mask |= STEP_ASSIGN_ADDRESSES;
continue;
}
if (strcmp(argv[i], "regs") == 0) {
step_mask |= STEP_COMPUTE_REGS;
continue;
}
Here again the code could be made much smaller and easier to read by using a data (table) driven approach and a loop through the table. Please consider using this technique globally.
Best regards,
Wolfgang Denk

On Dec 14, 2010, at 1:47 AM, Wolfgang Denk wrote:
Dear York Sun,
In message 1291863340-4354-9-git-send-email-yorksun@freescale.com you wrote:
Use environment variable to active the interactive debugging.
...
s/active/activate/
diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/Makefile b/arch/powerpc/cpu/mpc8xxx/ddr/Makefile index cb7f856..4bd416a 100644 --- a/arch/powerpc/cpu/mpc8xxx/ddr/Makefile +++ b/arch/powerpc/cpu/mpc8xxx/ddr/Makefile @@ -11,15 +11,15 @@ include $(TOPDIR)/config.mk LIB = $(obj)libddr.a
COBJS-$(CONFIG_FSL_DDR1) += main.o util.o ctrl_regs.o options.o \
lc_common_dimm_params.o
lc_common_dimm_params.o interactive.o
COBJS-$(CONFIG_FSL_DDR1) += ddr1_dimm_params.o
COBJS-$(CONFIG_FSL_DDR2) += main.o util.o ctrl_regs.o options.o \
lc_common_dimm_params.o
lc_common_dimm_params.o interactive.o
COBJS-$(CONFIG_FSL_DDR2) += ddr2_dimm_params.o
COBJS-$(CONFIG_FSL_DDR3) += main.o util.o ctrl_regs.o options.o \
lc_common_dimm_params.o
lc_common_dimm_params.o interactive.o
COBJS-$(CONFIG_FSL_DDR3) += ddr3_dimm_params.o
Building interactive.o should depend on CONFIG_FSL_DDR_INTERACTIVE being set.
Agreed
SRCS := $(START:.o=.S) $(SOBJS-y:.o=.S) $(COBJS-y:.o=.c) diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/interactive.c b/arch/powerpc/cpu/mpc8xxx/ddr/interactive.c new file mode 100644 index 0000000..7d492a9 --- /dev/null +++ b/arch/powerpc/cpu/mpc8xxx/ddr/interactive.c @@ -0,0 +1,1882 @@ +/*
- Copyright 2010 Freescale Semiconductor, Inc.
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- Version 2 as published by the Free Software Foundation.
- */
NAK. V2 or later is mandatory.
Yes, we will fix.
- k

Extend board specific parameters to include write leveling start override Extend write leveling sample to 0xf Adding rcw overrid for quad-rank RDIMMs
Signed-off-by: York Sun yorksun@freescale.com --- board/freescale/corenet_ds/ddr.c | 120 +++++++++++++++++++++----------------- 1 files changed, 66 insertions(+), 54 deletions(-)
diff --git a/board/freescale/corenet_ds/ddr.c b/board/freescale/corenet_ds/ddr.c index 0eb290d..74339b5 100644 --- a/board/freescale/corenet_ds/ddr.c +++ b/board/freescale/corenet_ds/ddr.c @@ -145,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; @@ -164,57 +165,57 @@ 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, 5, 0xff, 2, 0}, - {334, 400, 4, 5, 0xff, 2, 0}, - {401, 549, 4, 5, 0xff, 2, 0}, - {550, 680, 4, 5, 0xff, 2, 0}, - {681, 850, 4, 5, 0xff, 2, 0}, - {851, 1050, 4, 5, 0xff, 2, 0}, - {1051, 1250, 4, 5, 0xff, 2, 0}, - {1251, 1350, 4, 5, 0xff, 2, 0}, - { 0, 333, 2, 5, 0xff, 2, 0}, - {334, 400, 2, 5, 0xff, 2, 0}, - {401, 549, 2, 5, 0xff, 2, 0}, - {550, 680, 2, 5, 0xff, 2, 0}, - {681, 850, 2, 5, 0xff, 2, 0}, - {851, 1050, 2, 5, 0xff, 2, 0}, - {1051, 1250, 2, 5, 0xff, 2, 0}, - {1251, 1350, 2, 5, 0xff, 2, 0}, - { 0, 333, 1, 5, 0xff, 2, 0}, - {334, 400, 1, 5, 0xff, 2, 0}, - {401, 549, 1, 5, 0xff, 2, 0}, - {550, 680, 1, 5, 0xff, 2, 0}, - {681, 850, 1, 5, 0xff, 2, 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, 5, 0xff, 2, 0}, - {334, 400, 4, 5, 0xff, 2, 0}, - {401, 549, 4, 5, 0xff, 2, 0}, - {550, 680, 4, 5, 0xff, 2, 0}, - {681, 850, 4, 5, 0xff, 2, 0}, - {851, 1050, 4, 5, 0xff, 2, 0}, - {1051, 1250, 4, 5, 0xff, 2, 0}, - {1251, 1350, 4, 5, 0xff, 2, 0}, - { 0, 333, 2, 5, 0xff, 2, 0}, - {334, 400, 2, 5, 0xff, 2, 0}, - {401, 549, 2, 5, 0xff, 2, 0}, - {550, 680, 2, 5, 0xff, 2, 0}, - {681, 850, 2, 5, 0xff, 2, 0}, - {851, 1050, 2, 5, 0xff, 2, 0}, - {1051, 1250, 2, 5, 0xff, 2, 0}, - {1251, 1350, 2, 5, 0xff, 2, 0}, - { 0, 333, 1, 5, 0xff, 2, 0}, - {334, 400, 1, 5, 0xff, 2, 0}, - {401, 549, 1, 5, 0xff, 2, 0}, - {550, 680, 1, 5, 0xff, 2, 0}, - {681, 850, 1, 5, 0xff, 2, 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} } };
@@ -236,12 +237,12 @@ 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) { + 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; - popts->wrlvl_start = pbsp->clk_adjust + 2; } pbsp++; } @@ -255,7 +256,8 @@ void fsl_ddr_board_options(memctl_options_t *popts, * Write leveling override */ popts->wrlvl_override = 1; - popts->wrlvl_sample = 0xa; + popts->wrlvl_sample = 0xf; + /* * Rtt and Rtt_WR override */ @@ -267,9 +269,19 @@ void fsl_ddr_board_options(memctl_options_t *popts, /* DHC_EN =1, ODT = 60 Ohm */ popts->ddr_cdr1 = 0x80080000;
- popts->rcw_override = 1; - popts->rcw_1 = 0x000a5000; - popts->rcw_2 = 0x00100000; + /* 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 1291863340-4354-10-git-send-email-yorksun@freescale.com you wrote:
Extend board specific parameters to include write leveling start override Extend write leveling sample to 0xf Adding rcw overrid for quad-rank RDIMMs
Signed-off-by: York Sun yorksun@freescale.com
...
- /* memory controller 0 */
- /* lo| hi| num| clk| wrlvl | cpo |wrdata|2T */
- /* mhz| mhz|ranks|adjst| start | delay| */
Incorrect multiline comment style. Please fix globally.
Best regards,
Wolfgang Denk

Dear York Sun,
In message 1291863340-4354-1-git-send-email-yorksun@freescale.com you wrote:
Print a message when a RDIMM is detected.
Please put an indication of affected boards / processors / architectures in the Subject: ; like "mpc8xxx: ..."
(applies to all patches).
Best regards,
Wolfgang Denk
participants (3)
-
Kumar Gala
-
Wolfgang Denk
-
York Sun