Patchwork [U-Boot,06/10] Enable unique mode registers and dynamic ODT for DDR3

login
register
mail settings
Submitter York Sun
Date Dec. 9, 2010, 2:55 a.m.
Message ID <1291863340-4354-6-git-send-email-yorksun@freescale.com>
Download mbox | patch
Permalink /patch/74838/
State Changes Requested
Delegated to: Kumar Gala
Headers show

Comments

York Sun - Dec. 9, 2010, 2:55 a.m.
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(-)
Kumar Gala - Dec. 14, 2010, 5:13 a.m.
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
York Sun - Dec. 14, 2010, 6:33 a.m.
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
Wolfgang Denk - Dec. 14, 2010, 7:54 a.m.
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

Patch

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