
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