All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH 1/8] powerpc/mpc85xx: Skip zero values for DDR debug registers
@ 2012-08-17 18:22 York Sun
  2012-08-17 18:22 ` [U-Boot] [PATCH 2/8] powerpc/mpc8xxx: Add fine timing support for DDR3 York Sun
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ messages in thread
From: York Sun @ 2012-08-17 18:22 UTC (permalink / raw)
  To: u-boot

Some debug registers have non-zero default out of reset. If software is
not setting debug registers, skip writing to them to avoid unnecessary
overriding.

Also add debug messages for workarounds and debug registers.

Signed-off-by: York Sun <yorksun@freescale.com>
---
 arch/powerpc/cpu/mpc85xx/ddr-gen3.c |   14 +++++++++++---
 1 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/arch/powerpc/cpu/mpc85xx/ddr-gen3.c b/arch/powerpc/cpu/mpc85xx/ddr-gen3.c
index 81961de..0761d70 100644
--- a/arch/powerpc/cpu/mpc85xx/ddr-gen3.c
+++ b/arch/powerpc/cpu/mpc85xx/ddr-gen3.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008-2011 Freescale Semiconductor, Inc.
+ * Copyright 2008-2012 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
@@ -43,6 +43,7 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
 	out_be32(&ddr->eor, regs->ddr_eor);
 
 #ifdef CONFIG_SYS_FSL_ERRATUM_DDR111_DDR134
+	debug("Workaround for ERRATUM_DDR111_DDR134\n");
 	for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
 		cs_sa = (regs->cs[i].bnds >> 16) & 0xfff;
 		cs_ea = regs->cs[i].bnds & 0xfff;
@@ -115,8 +116,12 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
 	out_be32(&ddr->ddr_cdr2, regs->ddr_cdr2);
 	out_be32(&ddr->err_disable, regs->err_disable);
 	out_be32(&ddr->err_int_en, regs->err_int_en);
-	for (i = 0; i < 32; i++)
-		out_be32(&ddr->debug[i], regs->debug[i]);
+	for (i = 0; i < 32; i++) {
+		if (regs->debug[i]) {
+			debug("Write to debug_%d as %08x\n", i+1, regs->debug[i]);
+			out_be32(&ddr->debug[i], regs->debug[i]);
+		}
+	}
 
 #ifdef CONFIG_SYS_FSL_ERRATUM_DDR_A003474
 	out_be32(&ddr->debug[12], 0x00000015);
@@ -128,6 +133,7 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
 	temp_sdram_cfg &= ~(SDRAM_CFG_MEM_EN);
 	out_be32(&ddr->sdram_cfg, temp_sdram_cfg);
 #ifdef CONFIG_SYS_FSL_ERRATUM_DDR_A003
+	debug("Workaround for ERRATUM_DDR_A003\n");
 	if (regs->ddr_sdram_rcw_2 & 0x00f00000) {
 		out_be32(&ddr->timing_cfg_2, regs->timing_cfg_2 & 0xf07fffff);
 		out_be32(&ddr->debug[2], 0x00000400);
@@ -209,6 +215,7 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
 	 * This erratum does not affect DDR3 mode, only for DDR2 mode.
 	 */
 #ifdef CONFIG_SYS_FSL_ERRATUM_DDR_115
+	debug("Workaround for ERRATUM_DDR_115\n");
 	if ((((in_be32(&ddr->sdram_cfg) >> 24) & 0x7) == SDRAM_TYPE_DDR2)
 	    && in_be32(&ddr->sdram_cfg) & 0x80000) {
 		/* set DEBUG_1[31] */
@@ -216,6 +223,7 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
 	}
 #endif
 #ifdef CONFIG_SYS_FSL_ERRATUM_DDR111_DDR134
+	debug("Workaround for ERRATUM_DDR111_DDR134\n");
 	/*
 	 * This is the combined workaround for DDR111 and DDR134
 	 * following the published errata for MPC8572
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [U-Boot] [PATCH 2/8] powerpc/mpc8xxx: Add fine timing support for DDR3
  2012-08-17 18:22 [U-Boot] [PATCH 1/8] powerpc/mpc85xx: Skip zero values for DDR debug registers York Sun
@ 2012-08-17 18:22 ` York Sun
  2012-08-17 18:22 ` [U-Boot] [PATCH 3/8] powerpc/mpc8xxx: Add support for cas latency 12 and above York Sun
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: York Sun @ 2012-08-17 18:22 UTC (permalink / raw)
  To: u-boot

When the DDR3 speed goes higher, we need to utilize fine offset
from SPD.

Signed-off-by: York Sun <yorksun@freescale.com>
---
 arch/powerpc/cpu/mpc8xxx/ddr/ddr3_dimm_params.c |   25 +++++++++++++++++-----
 arch/powerpc/cpu/mpc8xxx/ddr/interactive.c      |   22 ++++++++++++++-----
 arch/powerpc/include/asm/fsl_ddr_dimm_params.h  |    1 +
 include/ddr_spd.h                               |    7 +++++-
 4 files changed, 42 insertions(+), 13 deletions(-)

diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/ddr3_dimm_params.c b/arch/powerpc/cpu/mpc8xxx/ddr/ddr3_dimm_params.c
index d0a5466..3e7c269 100644
--- a/arch/powerpc/cpu/mpc8xxx/ddr/ddr3_dimm_params.c
+++ b/arch/powerpc/cpu/mpc8xxx/ddr/ddr3_dimm_params.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008-2009 Freescale Semiconductor, Inc.
+ * Copyright 2008-2012 Freescale Semiconductor, Inc.
  *	Dave Liu <daveliu@freescale.com>
  *
  * calculate the organization and timing parameter
@@ -90,6 +90,7 @@ ddr_compute_dimm_parameters(const ddr3_spd_eeprom_t *spd,
 {
 	unsigned int retval;
 	unsigned int mtb_ps;
+	int ftb_10th_ps;
 	int i;
 
 	if (spd->mem_type) {
@@ -197,6 +198,14 @@ ddr_compute_dimm_parameters(const ddr3_spd_eeprom_t *spd,
 	pdimm->mtb_ps = mtb_ps;
 
 	/*
+	 * FTB - fine timebase
+	 * use 1/10th of ps as our unit to avoid floating point
+	 * eg, 10 for 1ps, 25 for 2.5ps, 50 for 5ps
+	 */
+	ftb_10th_ps =
+		((spd->ftb_div & 0xf0) >> 4) * 10 / (spd->ftb_div & 0x0f);
+	pdimm->ftb_10th_ps = ftb_10th_ps;
+	/*
 	 * sdram minimum cycle time
 	 * we assume the MTB is 0.125ns
 	 * eg:
@@ -204,7 +213,8 @@ ddr_compute_dimm_parameters(const ddr3_spd_eeprom_t *spd,
 	 *        =12 MTB (1.5ns) ->DDR3-1333
 	 *        =10 MTB (1.25ns) ->DDR3-1600
 	 */
-	pdimm->tCKmin_X_ps = spd->tCK_min * mtb_ps;
+	pdimm->tCKmin_X_ps = spd->tCK_min * mtb_ps +
+		(spd->fine_tCK_min * ftb_10th_ps) / 10;
 
 	/*
 	 * CAS latency supported
@@ -222,7 +232,8 @@ ddr_compute_dimm_parameters(const ddr3_spd_eeprom_t *spd,
 	 * DDR3-1333H	108 MTB (13.5ns)
 	 * DDR3-1600H	90 MTB (11.25ns)
 	 */
-	pdimm->tAA_ps = spd->tAA_min * mtb_ps;
+	pdimm->tAA_ps = spd->tAA_min * mtb_ps +
+		(spd->fine_tAA_min * ftb_10th_ps) / 10;
 
 	/*
 	 * min write recovery time
@@ -239,7 +250,8 @@ ddr_compute_dimm_parameters(const ddr3_spd_eeprom_t *spd,
 	 * DDR3-1333H	108 MTB (13.5ns)
 	 * DDR3-1600H	90 MTB (11.25)
 	 */
-	pdimm->tRCD_ps = spd->tRCD_min * mtb_ps;
+	pdimm->tRCD_ps = spd->tRCD_min * mtb_ps +
+		(spd->fine_tRCD_min * ftb_10th_ps) / 10;
 
 	/*
 	 * min row active to row active delay time
@@ -257,7 +269,8 @@ ddr_compute_dimm_parameters(const ddr3_spd_eeprom_t *spd,
 	 * DDR3-1333H	108 MTB (13.5ns)
 	 * DDR3-1600H	90 MTB (11.25ns)
 	 */
-	pdimm->tRP_ps = spd->tRP_min * mtb_ps;
+	pdimm->tRP_ps = spd->tRP_min * mtb_ps +
+		(spd->fine_tRP_min * ftb_10th_ps) / 10;
 
 	/* min active to precharge delay time
 	 * eg: tRAS_min =
@@ -277,7 +290,7 @@ ddr_compute_dimm_parameters(const ddr3_spd_eeprom_t *spd,
 	 * DDR3-1600H	370 MTB (46.25ns)
 	 */
 	pdimm->tRC_ps = (((spd->tRAS_tRC_ext & 0xf0) << 4) | spd->tRC_min_lsb)
-			* mtb_ps;
+			* mtb_ps + (spd->fine_tRC_min * ftb_10th_ps) / 10;
 	/*
 	 * min refresh recovery delay time
 	 * eg: tRFC_min =
diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/interactive.c b/arch/powerpc/cpu/mpc8xxx/ddr/interactive.c
index 5b72437..738c808 100644
--- a/arch/powerpc/cpu/mpc8xxx/ddr/interactive.c
+++ b/arch/powerpc/cpu/mpc8xxx/ddr/interactive.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2010-2011 Freescale Semiconductor, Inc.
+ * Copyright 2010-2012 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
@@ -1121,11 +1121,21 @@ void ddr3_spd_dump(const ddr3_spd_eeprom_t *spd)
 		"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]);
+	PRINT_NXS(34, spd->fine_tCK_min,
+		"fine_tCK_min  Fine offset for tCKmin");
+	PRINT_NXS(35, spd->fine_tAA_min,
+		"fine_tAA_min  Fine offset for tAAmin");
+	PRINT_NXS(36, spd->fine_tRCD_min,
+		"fine_tRCD_min Fine offset for tRCDmin");
+	PRINT_NXS(37, spd->fine_tRP_min,
+		"fine_tRP_min  Fine offset for tRPmin");
+	PRINT_NXS(38, spd->fine_tRC_min,
+		"fine_tRC_min  Fine offset for tRCmin");
+
+	printf("%-3d-%3d: ",  39, 59);  /* Reserved, General Section */
+
+	for (i = 39; i <= 59; i++)
+		printf("%02x ", spd->res_39_59[i - 39]);
 
 	puts("\n");
 
diff --git a/arch/powerpc/include/asm/fsl_ddr_dimm_params.h b/arch/powerpc/include/asm/fsl_ddr_dimm_params.h
index 982b809..ffe4db8 100644
--- a/arch/powerpc/include/asm/fsl_ddr_dimm_params.h
+++ b/arch/powerpc/include/asm/fsl_ddr_dimm_params.h
@@ -43,6 +43,7 @@ typedef struct dimm_params_s {
 	/* DIMM timing parameters */
 
 	unsigned int mtb_ps;	/* medium timebase ps, only for ddr3 */
+	unsigned int ftb_10th_ps; /* fine timebase, in 1/10 ps, only for ddr3 */
 	unsigned int tAA_ps;	/* minimum CAS latency time, only for ddr3 */
 	unsigned int tFAW_ps;	/* four active window delay, only for ddr3 */
 
diff --git a/include/ddr_spd.h b/include/ddr_spd.h
index a9230b9..9e74d87 100644
--- a/include/ddr_spd.h
+++ b/include/ddr_spd.h
@@ -221,7 +221,12 @@ typedef struct ddr3_spd_eeprom_s {
 	unsigned char therm_ref_opt;   /* 31 SDRAM Thermal and Refresh Opts */
 	unsigned char therm_sensor;    /* 32 Module Thermal Sensor */
 	unsigned char device_type;     /* 33 SDRAM device type */
-	unsigned char res_34_59[26];   /* 34-59 Reserved, General Section */
+	int8_t fine_tCK_min;	       /* 34 Fine offset for tCKmin */
+	int8_t fine_tAA_min;	       /* 35 Fine offset for tAAmin */
+	int8_t fine_tRCD_min;	       /* 36 Fine offset for tRCDmin */
+	int8_t fine_tRP_min;	       /* 37 Fine offset for tRPmin */
+	int8_t fine_tRC_min;	       /* 38 Fine offset for tRCmin */
+	unsigned char res_39_59[21];   /* 39-59 Reserved, General Section */
 
 	/* Module-Specific Section: Bytes 60-116 */
 	union {
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [U-Boot] [PATCH 3/8] powerpc/mpc8xxx: Add support for cas latency 12 and above
  2012-08-17 18:22 [U-Boot] [PATCH 1/8] powerpc/mpc85xx: Skip zero values for DDR debug registers York Sun
  2012-08-17 18:22 ` [U-Boot] [PATCH 2/8] powerpc/mpc8xxx: Add fine timing support for DDR3 York Sun
@ 2012-08-17 18:22 ` York Sun
  2012-08-17 18:22 ` [U-Boot] [PATCH 4/8] powerpc/mpc8xxx: Enable 3-way and 4-way DDR interleaving York Sun
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: York Sun @ 2012-08-17 18:22 UTC (permalink / raw)
  To: u-boot

Required by JEDEC 79-3E for high speed DDR3.
Also change "CSn disabled" message to debug.

Signed-off-by: York Sun <yorksun@freescale.com>
---
 arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c |   28 +++++++++++++++++++++-------
 1 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c b/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c
index 2067d53..a8b2132 100644
--- a/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c
+++ b/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008-2011 Freescale Semiconductor, Inc.
+ * Copyright 2008-2012 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 as published by the Free
@@ -825,7 +825,7 @@ static void set_ddr_sdram_mode(fsl_ddr_cfg_regs_t *ddr,
 
 	/* Mode Register - MR0 */
 	unsigned int dll_on;	/* DLL control for precharge PD, 0=off, 1=on */
-	unsigned int wr;	/* Write Recovery */
+	unsigned int wr = 0;	/* Write Recovery */
 	unsigned int dll_rst;	/* DLL Reset */
 	unsigned int mode;	/* Normal=0 or Test=1 */
 	unsigned int caslat = 4;/* CAS# latency, default set as 6 cycles */
@@ -885,24 +885,37 @@ static void set_ddr_sdram_mode(fsl_ddr_cfg_regs_t *ddr,
 	dll_on = 1;
 
 	wr_mclk = (common_dimm->tWR_ps + mclk_ps - 1) / mclk_ps;
-	wr = wr_table[wr_mclk - 5];
+	if (wr_mclk <= 16) {
+		wr = wr_table[wr_mclk - 5];
+	} else {
+		printf("Error: unsupported write recovery for mode register "
+		       "wr_mclk = %d\n", wr_mclk);
+	}
 
 	dll_rst = 0;	/* dll no reset */
 	mode = 0;	/* normal mode */
 
 	/* look up table to get the cas latency bits */
-	if (cas_latency >= 5 && cas_latency <= 11) {
-		unsigned char cas_latency_table[7] = {
+	if (cas_latency >= 5 && cas_latency <= 16) {
+		unsigned char cas_latency_table[] = {
 			0x2,	/* 5 clocks */
 			0x4,	/* 6 clocks */
 			0x6,	/* 7 clocks */
 			0x8,	/* 8 clocks */
 			0xa,	/* 9 clocks */
 			0xc,	/* 10 clocks */
-			0xe	/* 11 clocks */
+			0xe,	/* 11 clocks */
+			0x1,	/* 12 clocks */
+			0x3,	/* 13 clocks */
+			0x5,	/* 14 clocks */
+			0x7,	/* 15 clocks */
+			0x9,	/* 16 clocks */
 		};
 		caslat = cas_latency_table[cas_latency - 5];
+	} else {
+		printf("Error: unsupported cas latency for mode register\n");
 	}
+
 	bt = 0;	/* Nibble sequential */
 
 	switch (popts->burst_length) {
@@ -930,6 +943,7 @@ static void set_ddr_sdram_mode(fsl_ddr_cfg_regs_t *ddr,
 		  | ((mode & 0x1) << 7)
 		  | (((caslat >> 1) & 0x7) << 4)
 		  | ((bt & 0x1) << 3)
+		  | ((caslat & 1) << 2)
 		  | ((bl & 0x3) << 0)
 		  );
 
@@ -1574,7 +1588,7 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts,
 			set_csn_config(dimm_number, i, ddr, popts, dimm_params);
 			set_csn_config_2(i, ddr);
 		} else
-			printf("CS%d is disabled.\n", i);
+			debug("CS%d is disabled.\n", i);
 	}
 
 	/*
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [U-Boot] [PATCH 4/8] powerpc/mpc8xxx: Enable 3-way and 4-way DDR interleaving
  2012-08-17 18:22 [U-Boot] [PATCH 1/8] powerpc/mpc85xx: Skip zero values for DDR debug registers York Sun
  2012-08-17 18:22 ` [U-Boot] [PATCH 2/8] powerpc/mpc8xxx: Add fine timing support for DDR3 York Sun
  2012-08-17 18:22 ` [U-Boot] [PATCH 3/8] powerpc/mpc8xxx: Add support for cas latency 12 and above York Sun
@ 2012-08-17 18:22 ` York Sun
  2012-08-17 18:22 ` [U-Boot] [PATCH 5/8] powerpc/mpc8xxx: Fix bug for extended DDR timing York Sun
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: York Sun @ 2012-08-17 18:22 UTC (permalink / raw)
  To: u-boot

Restructure DDR interleaving option to support 3 and 4 DDR controllers
for 2-, 3- and 4-way interleaving.

Signed-off-by: York Sun <yorksun@freescale.com>
---
 arch/powerpc/cpu/mpc85xx/cpu.c           |   12 +-
 arch/powerpc/cpu/mpc85xx/ddr-gen3.c      |   12 ++
 arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c |  144 +++++----------
 arch/powerpc/cpu/mpc8xxx/ddr/main.c      |  305 +++++++++++++++++-------------
 arch/powerpc/cpu/mpc8xxx/ddr/options.c   |  211 +++++++++++++++------
 arch/powerpc/cpu/mpc8xxx/ddr/util.c      |   67 +++++---
 arch/powerpc/include/asm/fsl_ddr_sdram.h |    7 +
 arch/powerpc/include/asm/fsl_law.h       |   12 +-
 arch/powerpc/include/asm/immap_85xx.h    |    3 +
 doc/README.fsl-ddr                       |   34 ++++-
 10 files changed, 488 insertions(+), 319 deletions(-)

diff --git a/arch/powerpc/cpu/mpc85xx/cpu.c b/arch/powerpc/cpu/mpc85xx/cpu.c
index 6faa984..515dd41 100644
--- a/arch/powerpc/cpu/mpc85xx/cpu.c
+++ b/arch/powerpc/cpu/mpc85xx/cpu.c
@@ -434,11 +434,21 @@ static void dump_spd_ddr_reg(void)
 		case 0:
 			ddr[i] = (void *)CONFIG_SYS_MPC85xx_DDR_ADDR;
 			break;
-#ifdef CONFIG_SYS_MPC85xx_DDR2_ADDR
+#if defined(CONFIG_SYS_MPC85xx_DDR2_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 1)
 		case 1:
 			ddr[i] = (void *)CONFIG_SYS_MPC85xx_DDR2_ADDR;
 			break;
 #endif
+#if defined(CONFIG_SYS_MPC85xx_DDR3_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 2)
+		case 2:
+			ddr[i] = (void *)CONFIG_SYS_MPC85xx_DDR3_ADDR;
+			break;
+#endif
+#if defined(CONFIG_SYS_MPC85xx_DDR4_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 3)
+		case 3:
+			ddr[i] = (void *)CONFIG_SYS_MPC85xx_DDR4_ADDR;
+			break;
+#endif
 		default:
 			printf("%s unexpected controller number = %u\n",
 				__func__, i);
diff --git a/arch/powerpc/cpu/mpc85xx/ddr-gen3.c b/arch/powerpc/cpu/mpc85xx/ddr-gen3.c
index 0761d70..ca4ed62 100644
--- a/arch/powerpc/cpu/mpc85xx/ddr-gen3.c
+++ b/arch/powerpc/cpu/mpc85xx/ddr-gen3.c
@@ -32,9 +32,21 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
 	case 0:
 		ddr = (void *)CONFIG_SYS_MPC85xx_DDR_ADDR;
 		break;
+#if defined(CONFIG_SYS_MPC85xx_DDR2_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 1)
 	case 1:
 		ddr = (void *)CONFIG_SYS_MPC85xx_DDR2_ADDR;
 		break;
+#endif
+#if defined(CONFIG_SYS_MPC85xx_DDR3_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 2)
+	case 2:
+		ddr = (void *)CONFIG_SYS_MPC85xx_DDR3_ADDR;
+		break;
+#endif
+#if defined(CONFIG_SYS_MPC85xx_DDR4_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 3)
+	case 3:
+		ddr = (void *)CONFIG_SYS_MPC85xx_DDR4_ADDR;
+		break;
+#endif
 	default:
 		printf("%s unexpected ctrl_num = %u\n", __FUNCTION__, ctrl_num);
 		return;
diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c b/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c
index a8b2132..5938c44 100644
--- a/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c
+++ b/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c
@@ -151,8 +151,19 @@ static void set_csn_config(int dimm_number, int i, fsl_ddr_cfg_regs_t *ddr,
 		if (dimm_params[dimm_number].n_ranks > 0) {
 			go_config = 1;
 			/* These fields only available in CS0_CONFIG */
-			intlv_en = popts->memctl_interleaving;
-			intlv_ctl = popts->memctl_interleaving_mode;
+			if (!popts->memctl_interleaving)
+				break;
+			switch (popts->memctl_interleaving_mode) {
+			case FSL_DDR_CACHE_LINE_INTERLEAVING:
+			case FSL_DDR_PAGE_INTERLEAVING:
+			case FSL_DDR_BANK_INTERLEAVING:
+			case FSL_DDR_SUPERBANK_INTERLEAVING:
+				intlv_en = popts->memctl_interleaving;
+				intlv_ctl = popts->memctl_interleaving_mode;
+				break;
+			default:
+				break;
+			}
 		}
 		break;
 	case 1:
@@ -1413,73 +1424,37 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts,
 
 	/* Chip Select Memory Bounds (CSn_BNDS) */
 	for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
-		unsigned long long ea = 0, sa = 0;
+		unsigned long long ea, sa;
 		unsigned int cs_per_dimm
 			= CONFIG_CHIP_SELECTS_PER_CTRL / CONFIG_DIMM_SLOTS_PER_CTLR;
 		unsigned int dimm_number
 			= i / cs_per_dimm;
 		unsigned long long rank_density
-			= dimm_params[dimm_number].rank_density;
+			= dimm_params[dimm_number].rank_density >> dbw_cap_adj;
 
-		if (((i == 1) && (popts->ba_intlv_ctl & FSL_DDR_CS0_CS1)) ||
-			((i == 2) && (popts->ba_intlv_ctl & 0x04)) ||
-			((i == 3) && (popts->ba_intlv_ctl & FSL_DDR_CS2_CS3))) {
-			/*
-			 * Don't set up boundaries for unused CS
-			 * cs1 for cs0_cs1, cs0_cs1_and_cs2_cs3, cs0_cs1_cs2_cs3
-			 * cs2 for cs0_cs1_cs2_cs3
-			 * cs3 for cs2_cs3, cs0_cs1_and_cs2_cs3, cs0_cs1_cs2_cs3
-			 * But we need to set the ODT_RD_CFG and
-			 * ODT_WR_CFG for CS1_CONFIG here.
-			 */
-			set_csn_config(dimm_number, i, ddr, popts, dimm_params);
-			continue;
-		}
 		if (dimm_params[dimm_number].n_ranks == 0) {
 			debug("Skipping setup of CS%u "
 				"because n_ranks on DIMM %u is 0\n", i, dimm_number);
 			continue;
 		}
-		if (popts->memctl_interleaving && popts->ba_intlv_ctl) {
-			/*
-			 * This works superbank 2CS
-			 * There are 2 or more memory controllers configured
-			 * identically, memory is interleaved between them,
-			 * and each controller uses rank interleaving within
-			 * itself. Therefore the starting and ending address
-			 * on each controller is twice the amount present on
-			 * each controller. If any CS is not included in the
-			 * interleaving, the memory on that CS is not accssible
-			 * and the total memory size is reduced. The CS is also
-			 * disabled.
-			 */
-			unsigned long long ctlr_density = 0;
+		if (popts->memctl_interleaving) {
 			switch (popts->ba_intlv_ctl & FSL_DDR_CS0_CS1_CS2_CS3) {
+			case FSL_DDR_CS0_CS1_CS2_CS3:
+				break;
 			case FSL_DDR_CS0_CS1:
 			case FSL_DDR_CS0_CS1_AND_CS2_CS3:
-				ctlr_density = dimm_params[0].rank_density * 2;
 				if (i > 1)
 					cs_en = 0;
 				break;
 			case FSL_DDR_CS2_CS3:
-				ctlr_density = dimm_params[0].rank_density;
+			default:
 				if (i > 0)
 					cs_en = 0;
 				break;
-			case FSL_DDR_CS0_CS1_CS2_CS3:
-				/*
-				 * The four CS interleaving should have been verified by
-				 * populate_memctl_options()
-				 */
-				ctlr_density = dimm_params[0].rank_density * 4;
-				break;
-			default:
-				break;
 			}
-			ea = (CONFIG_NUM_DDR_CONTROLLERS *
-				(ctlr_density >> dbw_cap_adj)) - 1;
-		}
-		else if (!popts->memctl_interleaving && popts->ba_intlv_ctl) {
+			sa = common_dimm->base_address;
+			ea = common_dimm->total_mem - 1;
+		} else if (!popts->memctl_interleaving) {
 			/*
 			 * If memory interleaving between controllers is NOT
 			 * enabled, the starting address for each memory
@@ -1491,49 +1466,40 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts,
 			 */
 			switch (popts->ba_intlv_ctl & FSL_DDR_CS0_CS1_CS2_CS3) {
 			case FSL_DDR_CS0_CS1_CS2_CS3:
-				/* CS0+CS1+CS2+CS3 interleaving, only CS0_CNDS
-				 * needs to be set.
-				 */
 				sa = common_dimm->base_address;
-				ea = sa + (4 * (rank_density >> dbw_cap_adj))-1;
+				ea = common_dimm->total_mem - 1;
 				break;
 			case FSL_DDR_CS0_CS1_AND_CS2_CS3:
-				/* CS0+CS1 and CS2+CS3 interleaving, CS0_CNDS
-				 * and CS2_CNDS need to be set.
-				 */
-				if ((i == 2) && (dimm_number == 0)) {
+				if ((i >= 2) && (dimm_number == 0)) {
 					sa = dimm_params[dimm_number].base_address +
-					      2 * (rank_density >> dbw_cap_adj);
-					ea = sa + 2 * (rank_density >> dbw_cap_adj) - 1;
+					      2 * rank_density;
+					ea = sa + 2 * rank_density - 1;
 				} else {
 					sa = dimm_params[dimm_number].base_address;
-					ea = sa + (2 * (rank_density >>
-						dbw_cap_adj)) - 1;
+					ea = sa + 2 * rank_density - 1;
 				}
 				break;
 			case FSL_DDR_CS0_CS1:
-				/* CS0+CS1 interleaving, CS0_CNDS needs
-				 * to be set
-				 */
 				if (dimm_params[dimm_number].n_ranks > (i % cs_per_dimm)) {
 					sa = dimm_params[dimm_number].base_address;
-					ea = sa + (rank_density >> dbw_cap_adj) - 1;
-					sa += (i % cs_per_dimm) * (rank_density >> dbw_cap_adj);
-					ea += (i % cs_per_dimm) * (rank_density >> dbw_cap_adj);
+					ea = sa + rank_density - 1;
+					if (i != 1)
+						sa += (i % cs_per_dimm) * rank_density;
+					ea += (i % cs_per_dimm) * rank_density;
 				} else {
 					sa = 0;
 					ea = 0;
 				}
 				if (i == 0)
-					ea += (rank_density >> dbw_cap_adj);
+					ea += rank_density;
 				break;
 			case FSL_DDR_CS2_CS3:
-				/* CS2+CS3 interleaving*/
 				if (dimm_params[dimm_number].n_ranks > (i % cs_per_dimm)) {
 					sa = dimm_params[dimm_number].base_address;
-					ea = sa + (rank_density >> dbw_cap_adj) - 1;
-					sa += (i % cs_per_dimm) * (rank_density >> dbw_cap_adj);
-					ea += (i % cs_per_dimm) * (rank_density >> dbw_cap_adj);
+					ea = sa + rank_density - 1;
+					if (i != 3)
+						sa += (i % cs_per_dimm) * rank_density;
+					ea += (i % cs_per_dimm) * rank_density;
 				} else {
 					sa = 0;
 					ea = 0;
@@ -1542,38 +1508,18 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts,
 					ea += (rank_density >> dbw_cap_adj);
 				break;
 			default:  /* No bank(chip-select) interleaving */
+				sa = dimm_params[dimm_number].base_address;
+				ea = sa + rank_density - 1;
+				if (dimm_params[dimm_number].n_ranks > (i % cs_per_dimm)) {
+					sa += (i % cs_per_dimm) * rank_density;
+					ea += (i % cs_per_dimm) * rank_density;
+				} else {
+					sa = 0;
+					ea = 0;
+				}
 				break;
 			}
 		}
-		else if (popts->memctl_interleaving && !popts->ba_intlv_ctl) {
-			/*
-			 * Only the rank on CS0 of each memory controller may
-			 * be used if memory controller interleaving is used
-			 * without rank interleaving within each memory
-			 * controller.  However, the ending address programmed
-			 * into each CS0 must be the sum of the amount of
-			 * memory in the two CS0 ranks.
-			 */
-			if (i == 0) {
-				ea = (2 * (rank_density >> dbw_cap_adj)) - 1;
-			}
-
-		}
-		else if (!popts->memctl_interleaving && !popts->ba_intlv_ctl) {
-			/*
-			 * No rank interleaving and no memory controller
-			 * interleaving.
-			 */
-			sa = dimm_params[dimm_number].base_address;
-			ea = sa + (rank_density >> dbw_cap_adj) - 1;
-			if (dimm_params[dimm_number].n_ranks > (i % cs_per_dimm)) {
-				sa += (i % cs_per_dimm) * (rank_density >> dbw_cap_adj);
-				ea += (i % cs_per_dimm) * (rank_density >> dbw_cap_adj);
-			} else {
-				sa = 0;
-				ea = 0;
-			}
-		}
 
 		sa >>= 24;
 		ea >>= 24;
diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/main.c b/arch/powerpc/cpu/mpc8xxx/ddr/main.c
index c2a03e3..4fd4f8f 100644
--- a/arch/powerpc/cpu/mpc8xxx/ddr/main.c
+++ b/arch/powerpc/cpu/mpc8xxx/ddr/main.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008-2011 Freescale Semiconductor, Inc.
+ * Copyright 2008-2012 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
@@ -15,13 +15,15 @@
 #include <common.h>
 #include <i2c.h>
 #include <asm/fsl_ddr_sdram.h>
+#include <asm/fsl_law.h>
 
 #include "ddr.h"
 
-extern void fsl_ddr_set_lawbar(
+void fsl_ddr_set_lawbar(
 		const common_timing_params_t *memctl_common_params,
 		unsigned int memctl_interleaved,
 		unsigned int ctrl_num);
+void fsl_ddr_set_intl3r(const unsigned int granule_size);
 
 /* processor specific function */
 extern void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
@@ -51,6 +53,22 @@ u8 spd_i2c_addr[CONFIG_NUM_DDR_CONTROLLERS][CONFIG_DIMM_SLOTS_PER_CTLR] = {
 	[1][0] = SPD_EEPROM_ADDRESS3,	/* controller 2 */
 	[1][1] = SPD_EEPROM_ADDRESS4,	/* controller 2 */
 };
+#elif (CONFIG_NUM_DDR_CONTROLLERS == 3) && (CONFIG_DIMM_SLOTS_PER_CTLR == 1)
+u8 spd_i2c_addr[CONFIG_NUM_DDR_CONTROLLERS][CONFIG_DIMM_SLOTS_PER_CTLR] = {
+	[0][0] = SPD_EEPROM_ADDRESS1,	/* controller 1 */
+	[1][0] = SPD_EEPROM_ADDRESS2,	/* controller 2 */
+	[2][0] = SPD_EEPROM_ADDRESS3,	/* controller 3 */
+};
+#elif (CONFIG_NUM_DDR_CONTROLLERS == 3) && (CONFIG_DIMM_SLOTS_PER_CTLR == 2)
+u8 spd_i2c_addr[CONFIG_NUM_DDR_CONTROLLERS][CONFIG_DIMM_SLOTS_PER_CTLR] = {
+	[0][0] = SPD_EEPROM_ADDRESS1,	/* controller 1 */
+	[0][1] = SPD_EEPROM_ADDRESS2,	/* controller 1 */
+	[1][0] = SPD_EEPROM_ADDRESS3,	/* controller 2 */
+	[1][1] = SPD_EEPROM_ADDRESS4,	/* controller 2 */
+	[2][0] = SPD_EEPROM_ADDRESS5,	/* controller 3 */
+	[2][1] = SPD_EEPROM_ADDRESS6,	/* controller 3 */
+};
+
 #endif
 
 static void __get_spd(generic_spd_eeprom_t *spd, u8 i2c_address)
@@ -156,12 +174,12 @@ const char * step_to_string(unsigned int step) {
 	return step_string_tbl[s];
 }
 
-int step_assign_addresses(fsl_ddr_info_t *pinfo,
-			  unsigned int dbw_cap_adj[],
-			  unsigned int *all_memctl_interleaving,
-			  unsigned int *all_ctlr_rank_interleaving)
+unsigned long long step_assign_addresses(fsl_ddr_info_t *pinfo,
+			  unsigned int dbw_cap_adj[])
 {
 	int i, j;
+	unsigned long long total_mem, current_mem_base, total_ctlr_mem;
+	unsigned long long rank_density, ctlr_density = 0;
 
 	/*
 	 * If a reduced data width is requested, but the SPD
@@ -220,86 +238,108 @@ int step_assign_addresses(fsl_ddr_info_t *pinfo,
 				"specified controller %u\n", i);
 			return 1;
 		}
+		debug("dbw_cap_adj[%d]=%d\n", i, dbw_cap_adj[i]);
 	}
 
-	j = 0;
-	for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++)
-		if (pinfo->memctl_opts[i].memctl_interleaving)
-			j++;
-	/*
-	 * Not support less than all memory controllers interleaving
-	 * if more than two controllers
-	 */
-	if (j == CONFIG_NUM_DDR_CONTROLLERS)
-		*all_memctl_interleaving = 1;
-
-	/* Check that all controllers are rank interleaving. */
-	j = 0;
-	for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++)
-		if (pinfo->memctl_opts[i].ba_intlv_ctl)
-			j++;
-	/*
-	 * All memory controllers must be populated to qualify for
-	 * all controller rank interleaving
-	 */
-	 if (j == CONFIG_NUM_DDR_CONTROLLERS)
-		*all_ctlr_rank_interleaving = 1;
-
-	if (*all_memctl_interleaving) {
-		unsigned long long addr, total_mem_per_ctlr = 0;
-		/*
-		 * If interleaving between memory controllers,
-		 * make each controller start at a base address
-		 * of 0.
-		 *
-		 * Also, if bank interleaving (chip select
-		 * interleaving) is enabled on each memory
-		 * controller, CS0 needs to be programmed to
-		 * cover the entire memory range on that memory
-		 * controller
-		 *
-		 * Bank interleaving also implies that each
-		 * addressed chip select is identical in size.
-		 */
-
+	current_mem_base = 0ull;
+	total_mem = 0;
+	if (pinfo->memctl_opts[0].memctl_interleaving) {
+		rank_density = pinfo->dimm_params[0][0].rank_density >>
+					dbw_cap_adj[0];
+		switch (pinfo->memctl_opts[0].ba_intlv_ctl &
+					FSL_DDR_CS0_CS1_CS2_CS3) {
+		case FSL_DDR_CS0_CS1_CS2_CS3:
+			ctlr_density = 4 * rank_density;
+			break;
+		case FSL_DDR_CS0_CS1:
+		case FSL_DDR_CS0_CS1_AND_CS2_CS3:
+			ctlr_density = 2 * rank_density;
+			break;
+		case FSL_DDR_CS2_CS3:
+		default:
+			ctlr_density = rank_density;
+			break;
+		}
+		debug("rank density is 0x%llx, ctlr density is 0x%llx\n",
+			rank_density, ctlr_density);
 		for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
-			addr = 0;
-			pinfo->common_timing_params[i].base_address = 0ull;
-			for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) {
-				unsigned long long cap
-					= pinfo->dimm_params[i][j].capacity;
-
-				pinfo->dimm_params[i][j].base_address = addr;
-				addr += cap >> dbw_cap_adj[i];
-				total_mem_per_ctlr += cap >> dbw_cap_adj[i];
+			if (pinfo->memctl_opts[i].memctl_interleaving) {
+				switch (pinfo->memctl_opts[i].memctl_interleaving_mode) {
+				case FSL_DDR_CACHE_LINE_INTERLEAVING:
+				case FSL_DDR_PAGE_INTERLEAVING:
+				case FSL_DDR_BANK_INTERLEAVING:
+				case FSL_DDR_SUPERBANK_INTERLEAVING:
+					total_ctlr_mem = 2 * ctlr_density;
+					break;
+				case FSL_DDR_3WAY_1KB_INTERLEAVING:
+				case FSL_DDR_3WAY_4KB_INTERLEAVING:
+				case FSL_DDR_3WAY_8KB_INTERLEAVING:
+					total_ctlr_mem = 3 * ctlr_density;
+					break;
+				case FSL_DDR_4WAY_1KB_INTERLEAVING:
+				case FSL_DDR_4WAY_4KB_INTERLEAVING:
+				case FSL_DDR_4WAY_8KB_INTERLEAVING:
+					total_ctlr_mem = 4 * ctlr_density;
+					break;
+				default:
+					panic("Unknown interleaving mode");
+				}
+				pinfo->common_timing_params[i].base_address =
+							current_mem_base;
+				pinfo->common_timing_params[i].total_mem =
+							total_ctlr_mem;
+				total_mem = current_mem_base + total_ctlr_mem;
+				debug("ctrl %d base 0x%llx\n", i, current_mem_base);
+				debug("ctrl %d total 0x%llx\n", i, total_ctlr_mem);
+			} else {
+				/* when 3rd controller not interleaved */
+				current_mem_base = total_mem;
+				total_ctlr_mem = 0;
+				pinfo->common_timing_params[i].base_address =
+							current_mem_base;
+				for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) {
+					unsigned long long cap =
+						pinfo->dimm_params[i][j].capacity >> dbw_cap_adj[i];
+					pinfo->dimm_params[i][j].base_address =
+						current_mem_base;
+					debug("ctrl %d dimm %d base 0x%llx\n", i, j, current_mem_base);
+					current_mem_base += cap;
+					total_ctlr_mem += cap;
+				}
+				debug("ctrl %d total 0x%llx\n", i, total_ctlr_mem);
+				pinfo->common_timing_params[i].total_mem =
+							total_ctlr_mem;
+				total_mem += total_ctlr_mem;
 			}
 		}
-		pinfo->common_timing_params[0].total_mem = total_mem_per_ctlr;
 	} else {
 		/*
 		 * Simple linear assignment if memory
 		 * controllers are not interleaved.
 		 */
-		unsigned long long cur_memsize = 0;
 		for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
-			u64 total_mem_per_ctlr = 0;
+			total_ctlr_mem = 0;
 			pinfo->common_timing_params[i].base_address =
-						cur_memsize;
+						current_mem_base;
 			for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) {
 				/* Compute DIMM base addresses. */
 				unsigned long long cap =
-					pinfo->dimm_params[i][j].capacity;
+					pinfo->dimm_params[i][j].capacity >> dbw_cap_adj[i];
 				pinfo->dimm_params[i][j].base_address =
-					cur_memsize;
-				cur_memsize += cap >> dbw_cap_adj[i];
-				total_mem_per_ctlr += cap >> dbw_cap_adj[i];
+					current_mem_base;
+				debug("ctrl %d dimm %d base 0x%llx\n", i, j, current_mem_base);
+				current_mem_base += cap;
+				total_ctlr_mem += cap;
 			}
+			debug("ctrl %d total 0x%llx\n", i, total_ctlr_mem);
 			pinfo->common_timing_params[i].total_mem =
-							total_mem_per_ctlr;
+							total_ctlr_mem;
+			total_mem += total_ctlr_mem;
 		}
 	}
+	debug("Total mem by %s is 0x%llx\n", __func__, total_mem);
 
-	return 0;
+	return total_mem;
 }
 
 unsigned long long
@@ -307,8 +347,6 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,
 				       unsigned int size_only)
 {
 	unsigned int i, j;
-	unsigned int all_controllers_memctl_interleaving = 0;
-	unsigned int all_controllers_rank_interleaving = 0;
 	unsigned long long total_mem = 0;
 
 	fsl_ddr_cfg_regs_t *ddr_reg = pinfo->fsl_ddr_config_reg;
@@ -346,8 +384,9 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,
 				retval = compute_dimm_parameters(spd, pdimm, i);
 #ifdef CONFIG_SYS_DDR_RAW_TIMING
 				if (retval != 0) {
-					printf("SPD error! Trying fallback to "
-					"raw timing calculation\n");
+					printf("SPD error on controller %d! "
+					"Trying fallback to raw timing "
+					"calculation\n", i);
 					fsl_ddr_get_dimm_params(pdimm, i, j);
 				}
 #else
@@ -407,17 +446,14 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,
 					&pinfo->memctl_opts[i],
 					pinfo->dimm_params[i], i);
 		}
-		check_interleaving_options(pinfo);
 	case STEP_ASSIGN_ADDRESSES:
 		/* STEP 5:  Assign addresses to chip selects */
-		step_assign_addresses(pinfo,
-				dbw_capacity_adjust,
-				&all_controllers_memctl_interleaving,
-				&all_controllers_rank_interleaving);
+		check_interleaving_options(pinfo);
+		total_mem = step_assign_addresses(pinfo, dbw_capacity_adjust);
 
 	case STEP_COMPUTE_REGS:
 		/* STEP 6:  compute controller register values */
-		debug("FSL Memory ctrl cg register computation\n");
+		debug("FSL Memory ctrl register computation\n");
 		for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
 			if (timing_params[i].ndimms_present == 0) {
 				memset(&ddr_reg[i], 0,
@@ -437,21 +473,7 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,
 		break;
 	}
 
-	/* Compute the total amount of memory. */
-
-	/*
-	 * If bank interleaving but NOT memory controller interleaving
-	 * CS_BNDS describe the quantity of memory on each memory
-	 * controller, so the total is the sum across.
-	 */
-	if (!all_controllers_memctl_interleaving
-	    && all_controllers_rank_interleaving) {
-		total_mem = 0;
-		for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
-			total_mem += timing_params[i].total_mem;
-		}
-
-	} else {
+	{
 		/*
 		 * Compute the amount of memory available just by
 		 * looking for the highest valid CSn_BNDS value.
@@ -489,7 +511,7 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,
 phys_size_t fsl_ddr_sdram(void)
 {
 	unsigned int i;
-	unsigned int memctl_interleaved;
+	unsigned int law_memctl = LAW_TRGT_IF_DDR_1;
 	unsigned long long total_memory;
 	fsl_ddr_info_t info;
 
@@ -504,34 +526,6 @@ phys_size_t fsl_ddr_sdram(void)
 #endif
 		total_memory = fsl_ddr_compute(&info, STEP_GET_SPD, 0);
 
-	/* Check for memory controller interleaving. */
-	memctl_interleaved = 0;
-	for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
-		memctl_interleaved +=
-			info.memctl_opts[i].memctl_interleaving;
-	}
-
-	if (memctl_interleaved) {
-		if (memctl_interleaved == CONFIG_NUM_DDR_CONTROLLERS) {
-			debug("memctl interleaving\n");
-			/*
-			 * Change the meaning of memctl_interleaved
-			 * to be "boolean".
-			 */
-			memctl_interleaved = 1;
-		} else {
-			printf("Warning: memctl interleaving not "
-				"properly configured on all controllers\n");
-			memctl_interleaved = 0;
-			for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++)
-				info.memctl_opts[i].memctl_interleaving = 0;
-			debug("Recomputing with memctl_interleaving off.\n");
-			total_memory = fsl_ddr_compute(&info,
-						       STEP_ASSIGN_ADDRESSES,
-						       0);
-		}
-	}
-
 	/* Program configuration registers. */
 	for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
 		debug("Programming controller %u\n", i);
@@ -544,24 +538,69 @@ phys_size_t fsl_ddr_sdram(void)
 		fsl_ddr_set_memctl_regs(&(info.fsl_ddr_config_reg[i]), i);
 	}
 
-	if (memctl_interleaved) {
-		const unsigned int ctrl_num = 0;
-
-		/* Only set LAWBAR1 if memory controller interleaving is on. */
-		fsl_ddr_set_lawbar(&info.common_timing_params[0],
-					 memctl_interleaved, ctrl_num);
-	} else {
-		/*
-		 * Memory controller interleaving is NOT on;
-		 * set each lawbar individually.
-		 */
-		for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+	/* program LAWs */
+	for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+		if (info.memctl_opts[i].memctl_interleaving) {
+			switch (info.memctl_opts[i].memctl_interleaving_mode) {
+			case FSL_DDR_CACHE_LINE_INTERLEAVING:
+			case FSL_DDR_PAGE_INTERLEAVING:
+			case FSL_DDR_BANK_INTERLEAVING:
+			case FSL_DDR_SUPERBANK_INTERLEAVING:
+				if (i == 0) {
+					law_memctl = LAW_TRGT_IF_DDR_INTRLV;
+					fsl_ddr_set_lawbar(&info.common_timing_params[i],
+						law_memctl, i);
+				} else if (i == 2) {
+					law_memctl = LAW_TRGT_IF_DDR_INTLV_34;
+					fsl_ddr_set_lawbar(&info.common_timing_params[i],
+						law_memctl, i);
+				}
+				break;
+			case FSL_DDR_3WAY_1KB_INTERLEAVING:
+			case FSL_DDR_3WAY_4KB_INTERLEAVING:
+			case FSL_DDR_3WAY_8KB_INTERLEAVING:
+				law_memctl = LAW_TRGT_IF_DDR_INTLV_123;
+				if (i == 0) {
+					fsl_ddr_set_intl3r(info.memctl_opts[i].memctl_interleaving_mode);
+					fsl_ddr_set_lawbar(&info.common_timing_params[i],
+						law_memctl, i);
+				}
+				break;
+			case FSL_DDR_4WAY_1KB_INTERLEAVING:
+			case FSL_DDR_4WAY_4KB_INTERLEAVING:
+			case FSL_DDR_4WAY_8KB_INTERLEAVING:
+				law_memctl = LAW_TRGT_IF_DDR_INTLV_1234;
+				if (i == 0)
+					fsl_ddr_set_lawbar(&info.common_timing_params[i],
+						law_memctl, i);
+				/* place holder for future 4-way interleaving */
+				break;
+			default:
+				break;
+			}
+		} else {
+			switch (i) {
+			case 0:
+				law_memctl = LAW_TRGT_IF_DDR_1;
+				break;
+			case 1:
+				law_memctl = LAW_TRGT_IF_DDR_2;
+				break;
+			case 2:
+				law_memctl = LAW_TRGT_IF_DDR_3;
+				break;
+			case 3:
+				law_memctl = LAW_TRGT_IF_DDR_4;
+				break;
+			default:
+				break;
+			}
 			fsl_ddr_set_lawbar(&info.common_timing_params[i],
-						 0, i);
+					law_memctl, i);
 		}
 	}
 
-	debug("total_memory = %llu\n", total_memory);
+	debug("total_memory by %s = %llu\n", __func__, total_memory);
 
 #if !defined(CONFIG_PHYS_64BIT)
 	/* Check for 4G or more.  Bad. */
diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/options.c b/arch/powerpc/cpu/mpc8xxx/ddr/options.c
index 00ec57b..2923456 100644
--- a/arch/powerpc/cpu/mpc8xxx/ddr/options.c
+++ b/arch/powerpc/cpu/mpc8xxx/ddr/options.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008, 2010-2011 Freescale Semiconductor, Inc.
+ * Copyright 2008, 2010-2012 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 as published by the Free
@@ -790,46 +790,97 @@ unsigned int populate_memctl_options(int all_DIMMs_registered,
 	 * should be a subset of the requested configuration.
 	 */
 #if (CONFIG_NUM_DDR_CONTROLLERS > 1)
-	if (hwconfig_sub_f("fsl_ddr", "ctlr_intlv", buf)) {
-		if (pdimm[0].n_ranks == 0) {
-			printf("There is no rank on CS0 for controller %d. Because only"
-				" rank on CS0 and ranks chip-select interleaved with CS0"
-				" are controller interleaved, force non memory "
-				"controller interleaving\n", ctrl_num);
-			popts->memctl_interleaving = 0;
-		} else {
-			popts->memctl_interleaving = 1;
-			/*
-			 * test null first. if CONFIG_HWCONFIG is not defined
-			 * hwconfig_arg_cmp returns non-zero
-			 */
-			if (hwconfig_subarg_cmp_f("fsl_ddr", "ctlr_intlv",
-						    "null", buf)) {
-				popts->memctl_interleaving = 0;
-				debug("memory controller interleaving disabled.\n");
-			} else if (hwconfig_subarg_cmp_f("fsl_ddr",
-							 "ctlr_intlv",
-							 "cacheline", buf))
-				popts->memctl_interleaving_mode =
-					FSL_DDR_CACHE_LINE_INTERLEAVING;
-			else if (hwconfig_subarg_cmp_f("fsl_ddr", "ctlr_intlv",
-						       "page", buf))
-				popts->memctl_interleaving_mode =
-					FSL_DDR_PAGE_INTERLEAVING;
-			else if (hwconfig_subarg_cmp_f("fsl_ddr", "ctlr_intlv",
-						       "bank", buf))
-				popts->memctl_interleaving_mode =
-					FSL_DDR_BANK_INTERLEAVING;
-			else if (hwconfig_subarg_cmp_f("fsl_ddr", "ctlr_intlv",
-						       "superbank", buf))
-				popts->memctl_interleaving_mode =
-					FSL_DDR_SUPERBANK_INTERLEAVING;
-			else {
-				popts->memctl_interleaving = 0;
-				printf("hwconfig has unrecognized parameter for ctlr_intlv.\n");
-			}
-		}
+	if (!hwconfig_sub_f("fsl_ddr", "ctlr_intlv", buf))
+		goto done;
+
+	if (pdimm[0].n_ranks == 0) {
+		printf("There is no rank on CS0 for controller %d.\n", ctrl_num);
+		popts->memctl_interleaving = 0;
+		goto done;
+	}
+	popts->memctl_interleaving = 1;
+	/*
+	 * test null first. if CONFIG_HWCONFIG is not defined
+	 * hwconfig_arg_cmp returns non-zero
+	 */
+	if (hwconfig_subarg_cmp_f("fsl_ddr", "ctlr_intlv",
+				    "null", buf)) {
+		popts->memctl_interleaving = 0;
+		debug("memory controller interleaving disabled.\n");
+	} else if (hwconfig_subarg_cmp_f("fsl_ddr",
+					"ctlr_intlv",
+					"cacheline", buf)) {
+		popts->memctl_interleaving_mode =
+			((CONFIG_NUM_DDR_CONTROLLERS == 3) && ctrl_num == 2) ?
+			0 : FSL_DDR_CACHE_LINE_INTERLEAVING;
+		popts->memctl_interleaving =
+			((CONFIG_NUM_DDR_CONTROLLERS == 3) && ctrl_num == 2) ?
+			0 : 1;
+	} else if (hwconfig_subarg_cmp_f("fsl_ddr",
+					"ctlr_intlv",
+					"page", buf)) {
+		popts->memctl_interleaving_mode =
+			((CONFIG_NUM_DDR_CONTROLLERS == 3) && ctrl_num == 2) ?
+			0 : FSL_DDR_PAGE_INTERLEAVING;
+		popts->memctl_interleaving =
+			((CONFIG_NUM_DDR_CONTROLLERS == 3) && ctrl_num == 2) ?
+			0 : 1;
+	} else if (hwconfig_subarg_cmp_f("fsl_ddr",
+					"ctlr_intlv",
+					"bank", buf)) {
+		popts->memctl_interleaving_mode =
+			((CONFIG_NUM_DDR_CONTROLLERS == 3) && ctrl_num == 2) ?
+			0 : FSL_DDR_BANK_INTERLEAVING;
+		popts->memctl_interleaving =
+			((CONFIG_NUM_DDR_CONTROLLERS == 3) && ctrl_num == 2) ?
+			0 : 1;
+	} else if (hwconfig_subarg_cmp_f("fsl_ddr",
+					"ctlr_intlv",
+					"superbank", buf)) {
+		popts->memctl_interleaving_mode =
+			((CONFIG_NUM_DDR_CONTROLLERS == 3) && ctrl_num == 2) ?
+			0 : FSL_DDR_SUPERBANK_INTERLEAVING;
+		popts->memctl_interleaving =
+			((CONFIG_NUM_DDR_CONTROLLERS == 3) && ctrl_num == 2) ?
+			0 : 1;
+#if (CONFIG_NUM_DDR_CONTROLLERS == 3)
+	} else if (hwconfig_subarg_cmp_f("fsl_ddr",
+					"ctlr_intlv",
+					"3way_1KB", buf)) {
+		popts->memctl_interleaving_mode =
+			FSL_DDR_3WAY_1KB_INTERLEAVING;
+	} else if (hwconfig_subarg_cmp_f("fsl_ddr",
+					"ctlr_intlv",
+					"3way_4KB", buf)) {
+		popts->memctl_interleaving_mode =
+			FSL_DDR_3WAY_4KB_INTERLEAVING;
+	} else if (hwconfig_subarg_cmp_f("fsl_ddr",
+					"ctlr_intlv",
+					"3way_8KB", buf)) {
+		popts->memctl_interleaving_mode =
+			FSL_DDR_3WAY_8KB_INTERLEAVING;
+#elif (CONFIG_NUM_DDR_CONTROLLERS == 4)
+	} else if (hwconfig_subarg_cmp_f("fsl_ddr",
+					"ctlr_intlv",
+					"4way_1KB", buf)) {
+		popts->memctl_interleaving_mode =
+			FSL_DDR_4WAY_1KB_INTERLEAVING;
+	} else if (hwconfig_subarg_cmp_f("fsl_ddr",
+					"ctlr_intlv",
+					"4way_4KB", buf)) {
+		popts->memctl_interleaving_mode =
+			FSL_DDR_4WAY_4KB_INTERLEAVING;
+	} else if (hwconfig_subarg_cmp_f("fsl_ddr",
+					"ctlr_intlv",
+					"4way_8KB", buf)) {
+		popts->memctl_interleaving_mode =
+			FSL_DDR_4WAY_8KB_INTERLEAVING;
+#endif
+	} else {
+		popts->memctl_interleaving = 0;
+		printf("hwconfig has unrecognized parameter for ctlr_intlv.\n");
 	}
+done:
 #endif
 	if ((hwconfig_sub_f("fsl_ddr", "bank_intlv", buf)) &&
 		(CONFIG_CHIP_SELECTS_PER_CTRL > 1)) {
@@ -859,20 +910,20 @@ unsigned int populate_memctl_options(int all_DIMMs_registered,
 				popts->ba_intlv_ctl = 0;
 				printf("Not enough bank(chip-select) for "
 					"CS0+CS1+CS2+CS3 on controller %d, "
-					"force non-interleaving!\n", ctrl_num);
+					"interleaving disabled!\n", ctrl_num);
 			}
 #elif (CONFIG_DIMM_SLOTS_PER_CTLR == 2)
 			if ((pdimm[0].n_ranks < 2) && (pdimm[1].n_ranks < 2)) {
 				popts->ba_intlv_ctl = 0;
 				printf("Not enough bank(chip-select) for "
 					"CS0+CS1+CS2+CS3 on controller %d, "
-					"force non-interleaving!\n", ctrl_num);
+					"interleaving disabled!\n", ctrl_num);
 			}
 			if (pdimm[0].capacity != pdimm[1].capacity) {
 				popts->ba_intlv_ctl = 0;
 				printf("Not identical DIMM size for "
 					"CS0+CS1+CS2+CS3 on controller %d, "
-					"force non-interleaving!\n", ctrl_num);
+					"interleaving disabled!\n", ctrl_num);
 			}
 #endif
 			break;
@@ -881,7 +932,7 @@ unsigned int populate_memctl_options(int all_DIMMs_registered,
 				popts->ba_intlv_ctl = 0;
 				printf("Not enough bank(chip-select) for "
 					"CS0+CS1 on controller %d, "
-					"force non-interleaving!\n", ctrl_num);
+					"interleaving disabled!\n", ctrl_num);
 			}
 			break;
 		case FSL_DDR_CS2_CS3:
@@ -889,13 +940,13 @@ unsigned int populate_memctl_options(int all_DIMMs_registered,
 			if (pdimm[0].n_ranks < 4) {
 				popts->ba_intlv_ctl = 0;
 				printf("Not enough bank(chip-select) for CS2+CS3 "
-					"on controller %d, force non-interleaving!\n", ctrl_num);
+					"on controller %d, interleaving disabled!\n", ctrl_num);
 			}
 #elif (CONFIG_DIMM_SLOTS_PER_CTLR == 2)
 			if (pdimm[1].n_ranks < 2) {
 				popts->ba_intlv_ctl = 0;
 				printf("Not enough bank(chip-select) for CS2+CS3 "
-					"on controller %d, force non-interleaving!\n", ctrl_num);
+					"on controller %d, interleaving disabled!\n", ctrl_num);
 			}
 #endif
 			break;
@@ -905,14 +956,14 @@ unsigned int populate_memctl_options(int all_DIMMs_registered,
 				popts->ba_intlv_ctl = 0;
 				printf("Not enough bank(CS) for CS0+CS1 and "
 					"CS2+CS3 on controller %d, "
-					"force non-interleaving!\n", ctrl_num);
+					"interleaving disabled!\n", ctrl_num);
 			}
 #elif (CONFIG_DIMM_SLOTS_PER_CTLR == 2)
 			if ((pdimm[0].n_ranks < 2) || (pdimm[1].n_ranks < 2)) {
 				popts->ba_intlv_ctl = 0;
 				printf("Not enough bank(CS) for CS0+CS1 and "
 					"CS2+CS3 on controller %d, "
-					"force non-interleaving!\n", ctrl_num);
+					"interleaving disabled!\n", ctrl_num);
 			}
 #endif
 			break;
@@ -954,33 +1005,73 @@ unsigned int populate_memctl_options(int all_DIMMs_registered,
 
 void check_interleaving_options(fsl_ddr_info_t *pinfo)
 {
-	int i, j, check_n_ranks, intlv_fixed = 0;
+	int i, j, k, check_n_ranks, intlv_invalid = 0;
+	unsigned int check_intlv, check_n_row_addr, check_n_col_addr;
 	unsigned long long check_rank_density;
+	struct dimm_params_s *dimm;
 	/*
 	 * Check if all controllers are configured for memory
 	 * controller interleaving. Identical dimms are recommended. At least
-	 * the size should be checked.
+	 * the size, row and col address should be checked.
 	 */
 	j = 0;
 	check_n_ranks = pinfo->dimm_params[0][0].n_ranks;
 	check_rank_density = pinfo->dimm_params[0][0].rank_density;
+	check_n_row_addr =  pinfo->dimm_params[0][0].n_row_addr;
+	check_n_col_addr = pinfo->dimm_params[0][0].n_col_addr;
+	check_intlv = pinfo->memctl_opts[0].memctl_interleaving_mode;
 	for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
-		if ((pinfo->memctl_opts[i].memctl_interleaving) && \
-		    (check_rank_density == pinfo->dimm_params[i][0].rank_density) && \
-		    (check_n_ranks == pinfo->dimm_params[i][0].n_ranks)) {
+		dimm = &pinfo->dimm_params[i][0];
+		if (!pinfo->memctl_opts[i].memctl_interleaving) {
+			continue;
+		} else if (((check_rank_density != dimm->rank_density) ||
+		     (check_n_ranks != dimm->n_ranks) ||
+		     (check_n_row_addr != dimm->n_row_addr) ||
+		     (check_n_col_addr != dimm->n_col_addr) ||
+		     (check_intlv !=
+			pinfo->memctl_opts[i].memctl_interleaving_mode))){
+			intlv_invalid = 1;
+			break;
+		} else {
 			j++;
 		}
+
 	}
-	if (j != CONFIG_NUM_DDR_CONTROLLERS) {
+	if (intlv_invalid) {
 		for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++)
-			if (pinfo->memctl_opts[i].memctl_interleaving) {
+			pinfo->memctl_opts[i].memctl_interleaving = 0;
+		printf("Not all DIMMs are identical. "
+			"Memory controller interleaving disabled.\n");
+	} else {
+		switch (check_intlv) {
+		case FSL_DDR_CACHE_LINE_INTERLEAVING:
+		case FSL_DDR_PAGE_INTERLEAVING:
+		case FSL_DDR_BANK_INTERLEAVING:
+		case FSL_DDR_SUPERBANK_INTERLEAVING:
+			if (3 == CONFIG_NUM_DDR_CONTROLLERS)
+				k = 2;
+			else
+				k = CONFIG_NUM_DDR_CONTROLLERS;
+			break;
+		case FSL_DDR_3WAY_1KB_INTERLEAVING:
+		case FSL_DDR_3WAY_4KB_INTERLEAVING:
+		case FSL_DDR_3WAY_8KB_INTERLEAVING:
+		case FSL_DDR_4WAY_1KB_INTERLEAVING:
+		case FSL_DDR_4WAY_4KB_INTERLEAVING:
+		case FSL_DDR_4WAY_8KB_INTERLEAVING:
+		default:
+			k = CONFIG_NUM_DDR_CONTROLLERS;
+			break;
+		}
+		debug("%d of %d controllers are interleaving.\n", j, k);
+		if (j != k) {
+			for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++)
 				pinfo->memctl_opts[i].memctl_interleaving = 0;
-				intlv_fixed = 1;
-			}
-		if (intlv_fixed)
-			printf("Not all DIMMs are identical in size. "
-				"Memory controller interleaving disabled.\n");
+			printf("Not all controllers have compatible "
+				"interleaving mode. All disabled.\n");
+		}
 	}
+	debug("Checking interleaving options completed\n");
 }
 
 int fsl_use_spd(void)
diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/util.c b/arch/powerpc/cpu/mpc8xxx/ddr/util.c
index eb6a17a..664ad09 100644
--- a/arch/powerpc/cpu/mpc8xxx/ddr/util.c
+++ b/arch/powerpc/cpu/mpc8xxx/ddr/util.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008-2011 Freescale Semiconductor, Inc.
+ * Copyright 2008-2012 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
@@ -79,7 +79,7 @@ unsigned int mclk_to_picos(unsigned int mclk)
 
 void
 __fsl_ddr_set_lawbar(const common_timing_params_t *memctl_common_params,
-			   unsigned int memctl_interleaved,
+			   unsigned int law_memctl,
 			   unsigned int ctrl_num)
 {
 	unsigned long long base = memctl_common_params->base_address;
@@ -98,28 +98,13 @@ __fsl_ddr_set_lawbar(const common_timing_params_t *memctl_common_params,
 	if ((base + size) >= CONFIG_MAX_MEM_MAPPED)
 		size = CONFIG_MAX_MEM_MAPPED - base;
 #endif
-
-	if (ctrl_num == 0) {
-		/*
-		 * Set up LAW for DDR controller 1 space.
-		 */
-		unsigned int lawbar1_target_id = memctl_interleaved
-			? LAW_TRGT_IF_DDR_INTRLV : LAW_TRGT_IF_DDR_1;
-
-		if (set_ddr_laws(base, size, lawbar1_target_id) < 0) {
-			printf("%s: ERROR (ctrl #0, intrlv=%d)\n", __func__,
-				memctl_interleaved);
-			return ;
-		}
-	} else if (ctrl_num == 1) {
-		if (set_ddr_laws(base, size, LAW_TRGT_IF_DDR_2) < 0) {
-			printf("%s: ERROR (ctrl #1)\n", __func__);
-			return ;
-		}
-	} else {
-		printf("%s: unexpected DDR controller number (%u)\n", __func__,
-			ctrl_num);
+	if (set_ddr_laws(base, size, law_memctl) < 0) {
+		printf("%s: ERROR (ctrl #%d, TRGT ID=%x)\n", __func__, ctrl_num,
+			law_memctl);
+		return ;
 	}
+	debug("setup ddr law base = 0x%llx, size 0x%llx, TRGT_ID 0x%x\n",
+		base, size, law_memctl);
 }
 
 __attribute__((weak, alias("__fsl_ddr_set_lawbar"))) void
@@ -127,6 +112,15 @@ fsl_ddr_set_lawbar(const common_timing_params_t *memctl_common_params,
 			 unsigned int memctl_interleaved,
 			 unsigned int ctrl_num);
 
+void fsl_ddr_set_intl3r(const unsigned int granule_size)
+{
+#ifdef CONFIG_E6500
+	u32 *mcintl3r = (void *) (CONFIG_SYS_IMMR + 0x18004);
+	*mcintl3r = 0x80000000 | (granule_size & 0x1f);
+	debug("Enable MCINTL3R with granule size 0x%x\n", granule_size);
+#endif
+}
+
 void board_add_ram_info(int use_default)
 {
 #if defined(CONFIG_MPC83xx)
@@ -137,6 +131,9 @@ void board_add_ram_info(int use_default)
 #elif defined(CONFIG_MPC86xx)
 	ccsr_ddr_t *ddr = (void *)(CONFIG_SYS_MPC86xx_DDR_ADDR);
 #endif
+#if	defined(CONFIG_E6500) && (CONFIG_NUM_DDR_CONTROLLERS == 3)
+	u32 *mcintl3r = (void *) (CONFIG_SYS_IMMR + 0x18004);
+#endif
 #if (CONFIG_NUM_DDR_CONTROLLERS > 1)
 	uint32_t cs0_config = in_be32(&ddr->cs0_config);
 #endif
@@ -180,7 +177,29 @@ void board_add_ram_info(int use_default)
 	else
 		puts(", ECC off)");
 
-#if (CONFIG_NUM_DDR_CONTROLLERS > 1)
+#if (CONFIG_NUM_DDR_CONTROLLERS == 3)
+#ifdef CONFIG_E6500
+	if (*mcintl3r & 0x80000000) {
+		puts("\n");
+		puts("       DDR Controller Interleaving Mode: ");
+		switch (*mcintl3r & 0x1f) {
+		case FSL_DDR_3WAY_1KB_INTERLEAVING:
+			puts("3-way 1KB");
+			break;
+		case FSL_DDR_3WAY_4KB_INTERLEAVING:
+			puts("3-way 4KB");
+			break;
+		case FSL_DDR_3WAY_8KB_INTERLEAVING:
+			puts("3-way 8KB");
+			break;
+		default:
+			puts("3-way UNKNOWN");
+			break;
+		}
+	}
+#endif
+#endif
+#if (CONFIG_NUM_DDR_CONTROLLERS >= 2)
 	if (cs0_config & 0x20000000) {
 		puts("\n");
 		puts("       DDR Controller Interleaving Mode: ");
diff --git a/arch/powerpc/include/asm/fsl_ddr_sdram.h b/arch/powerpc/include/asm/fsl_ddr_sdram.h
index 157ae24..e271342 100644
--- a/arch/powerpc/include/asm/fsl_ddr_sdram.h
+++ b/arch/powerpc/include/asm/fsl_ddr_sdram.h
@@ -76,6 +76,13 @@ typedef ddr3_spd_eeprom_t generic_spd_eeprom_t;
 #define FSL_DDR_PAGE_INTERLEAVING	0x1
 #define FSL_DDR_BANK_INTERLEAVING	0x2
 #define FSL_DDR_SUPERBANK_INTERLEAVING	0x3
+#define FSL_DDR_3WAY_1KB_INTERLEAVING	0xA
+#define FSL_DDR_3WAY_4KB_INTERLEAVING	0xC
+#define FSL_DDR_3WAY_8KB_INTERLEAVING	0xD
+/* placeholder for 4-way interleaving */
+#define FSL_DDR_4WAY_1KB_INTERLEAVING	0x1A
+#define FSL_DDR_4WAY_4KB_INTERLEAVING	0x1C
+#define FSL_DDR_4WAY_8KB_INTERLEAVING	0x1D
 
 /* DDR_SDRAM_CFG - DDR SDRAM Control Configuration
  */
diff --git a/arch/powerpc/include/asm/fsl_law.h b/arch/powerpc/include/asm/fsl_law.h
index 13caffd..cffe4f1 100644
--- a/arch/powerpc/include/asm/fsl_law.h
+++ b/arch/powerpc/include/asm/fsl_law.h
@@ -60,8 +60,12 @@ enum law_trgt_if {
 
 	LAW_TRGT_IF_DDR_1 = 0x10,
 	LAW_TRGT_IF_DDR_2 = 0x11,	/* 2nd controller */
+	LAW_TRGT_IF_DDR_3 = 0x12,
+	LAW_TRGT_IF_DDR_4 = 0x13,
 	LAW_TRGT_IF_DDR_INTRLV = 0x14,
-
+	LAW_TRGT_IF_DDR_INTLV_34 = 0x15,
+	LAW_TRGT_IF_DDR_INTLV_123 = 0x17,
+	LAW_TRGT_IF_DDR_INTLV_1234 = 0x16,
 	LAW_TRGT_IF_BMAN = 0x18,
 	LAW_TRGT_IF_DCSR = 0x1d,
 	LAW_TRGT_IF_LBC = 0x1f,
@@ -86,6 +90,12 @@ enum law_trgt_if {
 	LAW_TRGT_IF_DPAA_SWP_SRAM = 0x0e,
 	LAW_TRGT_IF_DDR = 0x0f,
 	LAW_TRGT_IF_DDR_2 = 0x16,	/* 2nd controller */
+	/* place holder for 3-way and 4-way interleaving */
+	LAW_TRGT_IF_DDR_3,
+	LAW_TRGT_IF_DDR_4,
+	LAW_TRGT_IF_DDR_INTLV_34,
+	LAW_TRGT_IF_DDR_INTLV_123,
+	LAW_TRGT_IF_DDR_INTLV_1234,
 };
 #define LAW_TRGT_IF_DDR_1	LAW_TRGT_IF_DDR
 #define LAW_TRGT_IF_PCI_1	LAW_TRGT_IF_PCI
diff --git a/arch/powerpc/include/asm/immap_85xx.h b/arch/powerpc/include/asm/immap_85xx.h
index 63bcfda..7ce27db 100644
--- a/arch/powerpc/include/asm/immap_85xx.h
+++ b/arch/powerpc/include/asm/immap_85xx.h
@@ -2735,6 +2735,7 @@ typedef struct ccsr_snvs_regs {
 #define CONFIG_SYS_FSL_CORENET_CCM_OFFSET	0x0000
 #define CONFIG_SYS_MPC85xx_DDR_OFFSET		0x8000
 #define CONFIG_SYS_MPC85xx_DDR2_OFFSET		0x9000
+#define CONFIG_SYS_MPC85xx_DDR3_OFFSET		0xA000
 #define CONFIG_SYS_FSL_CORENET_CLK_OFFSET	0xE1000
 #define CONFIG_SYS_FSL_CORENET_RCPM_OFFSET	0xE2000
 #ifdef	CONFIG_SECURE_BOOT
@@ -2865,6 +2866,8 @@ typedef struct ccsr_snvs_regs {
 	(CONFIG_SYS_IMMR + CONFIG_SYS_MPC85xx_DDR_OFFSET)
 #define CONFIG_SYS_MPC85xx_DDR2_ADDR \
 	(CONFIG_SYS_IMMR + CONFIG_SYS_MPC85xx_DDR2_OFFSET)
+#define CONFIG_SYS_MPC85xx_DDR3_ADDR \
+	(CONFIG_SYS_IMMR + CONFIG_SYS_MPC85xx_DDR3_OFFSET)
 #define CONFIG_SYS_LBC_ADDR \
 	(CONFIG_SYS_IMMR + CONFIG_SYS_MPC85xx_LBC_OFFSET)
 #define CONFIG_SYS_IFC_ADDR \
diff --git a/doc/README.fsl-ddr b/doc/README.fsl-ddr
index 5e21658..f94b56f 100644
--- a/doc/README.fsl-ddr
+++ b/doc/README.fsl-ddr
@@ -1,5 +1,28 @@
-
-Table of interleaving modes supported in cpu/8xxx/ddr/
+Table of interleaving 2-4 controllers
+=====================================
+  +--------------+-----------------------------------------------------------+
+  |Configuration |                    Memory Controller                      |
+  |              |       1              2              3             4       |
+  |--------------+--------------+--------------+-----------------------------+
+  | Two memory   | Not Intlv'ed | Not Intlv'ed |                             |
+  | complexes    +--------------+--------------+                             |
+  |              |      2-way Intlv'ed         |                             |
+  |--------------+--------------+--------------+--------------+              |
+  |              | Not Intlv'ed | Not Intlv'ed | Not Intlv'ed |              |
+  | Three memory +--------------+--------------+--------------+              |
+  | complexes    |         2-way Intlv'ed      | Not Intlv'ed |              |
+  |              +-----------------------------+--------------+              |
+  |              |                  3-way Intlv'ed            |              |
+  +--------------+--------------+--------------+--------------+--------------+
+  |              | Not Intlv'ed | Not Intlv'ed | Not Intlv'ed | Not Intlv'ed |
+  | Four memory  +--------------+--------------+--------------+--------------+
+  | complexes    |       2-way Intlv'ed        |       2-way Intlv'ed        |
+  |              +-----------------------------+-----------------------------+
+  |              |                      4-way Intlv'ed                       |
+  +--------------+-----------------------------------------------------------+
+
+
+Table of 2-way interleaving modes supported in cpu/8xxx/ddr/
 ======================================================
   +-------------+---------------------------------------------------------+
   |		|		    Rank Interleaving			  |
@@ -56,6 +79,15 @@ The ways to configure the ddr interleaving mode
   # superbank
   setenv hwconfig "fsl_ddr:ctlr_intlv=superbank"
 
+  # 1KB 3-way interleaving
+  setenv hwconfig "fsl_ddr:ctlr_intlv=3way_1KB"
+
+  # 4KB 3-way interleaving
+  setenv hwconfig "fsl_ddr:ctlr_intlv=3way_4KB"
+
+  # 8KB 3-way interleaving
+  setenv hwconfig "fsl_ddr:ctlr_intlv=3way_8KB"
+
   # disable bank (chip-select) interleaving
   setenv hwconfig "fsl_ddr:bank_intlv=null"
 
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [U-Boot] [PATCH 5/8] powerpc/mpc8xxx: Fix bug for extended DDR timing
  2012-08-17 18:22 [U-Boot] [PATCH 1/8] powerpc/mpc85xx: Skip zero values for DDR debug registers York Sun
                   ` (2 preceding siblings ...)
  2012-08-17 18:22 ` [U-Boot] [PATCH 4/8] powerpc/mpc8xxx: Enable 3-way and 4-way DDR interleaving York Sun
@ 2012-08-17 18:22 ` York Sun
  2012-08-17 18:22 ` [U-Boot] [PATCH 6/8] powerpc/mpc8xxx DDR: Fix CAS latency calculation York Sun
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: York Sun @ 2012-08-17 18:22 UTC (permalink / raw)
  To: u-boot

Faster DDR3 timing requires parameters exceeding previously defined
range. Extended parameters are fixed. Added some debug messages.

Signed-off-by: York Sun <yorksun@freescale.com>
---
 arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c           |   51 ++++++++++++-------
 .../cpu/mpc8xxx/ddr/lc_common_dimm_params.c        |   12 ++++-
 2 files changed, 43 insertions(+), 20 deletions(-)

diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c b/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c
index 5938c44..2592873 100644
--- a/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c
+++ b/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c
@@ -313,29 +313,41 @@ static void set_timing_cfg_0(fsl_ddr_cfg_regs_t *ddr,
 
 /* DDR SDRAM Timing Configuration 3 (TIMING_CFG_3) */
 static void set_timing_cfg_3(fsl_ddr_cfg_regs_t *ddr,
+			       const memctl_options_t *popts,
 			       const common_timing_params_t *common_dimm,
 			       unsigned int cas_latency)
 {
+	/* Extended precharge to activate interval (tRP) */
+	unsigned int ext_pretoact = 0;
 	/* Extended Activate to precharge interval (tRAS) */
 	unsigned int ext_acttopre = 0;
-	unsigned int ext_refrec; /* Extended refresh recovery time (tRFC) */
-	unsigned int ext_caslat = 0; /* Extended MCAS latency from READ cmd */
-	unsigned int cntl_adj = 0; /* Control Adjust */
-
-	/* If the tRAS > 19 MCLK, we use the ext mode */
-	if (picos_to_mclk(common_dimm->tRAS_ps) > 0x13)
-		ext_acttopre = 1;
-
+	/* Extended activate to read/write interval (tRCD) */
+	unsigned int ext_acttorw = 0;
+	/* Extended refresh recovery time (tRFC) */
+	unsigned int ext_refrec;
+	/* Extended MCAS latency from READ cmd */
+	unsigned int ext_caslat = 0;
+	/* Extended last data to precharge interval (tWR) */
+	unsigned int ext_wrrec = 0;
+	/* Control Adjust */
+	unsigned int cntl_adj = 0;
+
+	ext_pretoact = picos_to_mclk(common_dimm->tRP_ps) >> 4;
+	ext_acttopre = picos_to_mclk(common_dimm->tRAS_ps) >> 4;
+	ext_acttorw = picos_to_mclk(common_dimm->tRCD_ps) >> 4;
+	ext_caslat = (2 * cas_latency - 1) >> 4;
 	ext_refrec = (picos_to_mclk(common_dimm->tRFC_ps) - 8) >> 4;
-
-	/* If the CAS latency more than 8, use the ext mode */
-	if (cas_latency > 8)
-		ext_caslat = 1;
+	/* ext_wrrec only deals with 16 clock and above, or 14 with OTF */
+	ext_wrrec = (picos_to_mclk(common_dimm->tWR_ps) +
+		(popts->OTF_burst_chop_en ? 2 : 0)) >> 4;
 
 	ddr->timing_cfg_3 = (0
-		| ((ext_acttopre & 0x1) << 24)
-		| ((ext_refrec & 0xF) << 16)
-		| ((ext_caslat & 0x1) << 12)
+		| ((ext_pretoact & 0x1) << 28)
+		| ((ext_acttopre & 0x2) << 24)
+		| ((ext_acttorw & 0x1) << 22)
+		| ((ext_refrec & 0x1F) << 16)
+		| ((ext_caslat & 0x3) << 12)
+		| ((ext_wrrec & 0x1) << 8)
 		| ((cntl_adj & 0x7) << 0)
 		);
 	debug("FSLDDR: timing_cfg_3 = 0x%08x\n", ddr->timing_cfg_3);
@@ -397,15 +409,16 @@ static void set_timing_cfg_1(fsl_ddr_cfg_regs_t *ddr,
 	 * we need set extend bit for it at
 	 * TIMING_CFG_3[EXT_CASLAT]
 	 */
-	if (cas_latency > 8)
-		cas_latency -= 8;
 	caslat_ctrl = 2 * cas_latency - 1;
 #endif
 
 	refrec_ctrl = picos_to_mclk(common_dimm->tRFC_ps) - 8;
 	wrrec_mclk = picos_to_mclk(common_dimm->tWR_ps);
 
-	wrrec_mclk = wrrec_table[wrrec_mclk - 1];
+	if (wrrec_mclk > 16)
+		printf("Error: WRREC doesn't support more than 16 clocks\n");
+	else
+		wrrec_mclk = wrrec_table[wrrec_mclk - 1];
 	if (popts->OTF_burst_chop_en)
 		wrrec_mclk += 2;
 
@@ -1550,7 +1563,7 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts,
 	set_timing_cfg_0(ddr, popts);
 #endif
 
-	set_timing_cfg_3(ddr, common_dimm, cas_latency);
+	set_timing_cfg_3(ddr, popts, common_dimm, cas_latency);
 	set_timing_cfg_1(ddr, popts, common_dimm, cas_latency);
 	set_timing_cfg_2(ddr, popts, common_dimm,
 				cas_latency, additive_latency);
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 20c7db0..a474a65 100644
--- a/arch/powerpc/cpu/mpc8xxx/ddr/lc_common_dimm_params.c
+++ b/arch/powerpc/cpu/mpc8xxx/ddr/lc_common_dimm_params.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008-2011 Freescale Semiconductor, Inc.
+ * Copyright 2008-2012 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
@@ -491,5 +491,15 @@ compute_lowest_common_dimm_parameters(const dimm_params_t *dimm_params,
 	 */
 	outpdimm->additive_latency = additive_latency;
 
+	debug("tCKmin_ps = %u\n", outpdimm->tCKmin_X_ps);
+	debug("tRCD_ps   = %u\n", outpdimm->tRCD_ps);
+	debug("tRP_ps    = %u\n", outpdimm->tRP_ps);
+	debug("tRAS_ps   = %u\n", outpdimm->tRAS_ps);
+	debug("tWR_ps    = %u\n", outpdimm->tWR_ps);
+	debug("tWTR_ps   = %u\n", outpdimm->tWTR_ps);
+	debug("tRFC_ps   = %u\n", outpdimm->tRFC_ps);
+	debug("tRRD_ps   = %u\n", outpdimm->tRRD_ps);
+	debug("tRC_ps    = %u\n", outpdimm->tRC_ps);
+
 	return 0;
 }
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [U-Boot] [PATCH 6/8] powerpc/mpc8xxx DDR: Fix CAS latency calculation
  2012-08-17 18:22 [U-Boot] [PATCH 1/8] powerpc/mpc85xx: Skip zero values for DDR debug registers York Sun
                   ` (3 preceding siblings ...)
  2012-08-17 18:22 ` [U-Boot] [PATCH 5/8] powerpc/mpc8xxx: Fix bug for extended DDR timing York Sun
@ 2012-08-17 18:22 ` York Sun
  2012-08-17 18:22 ` [U-Boot] [PATCH 7/8] powerpc/mpc8xxx DDR: Fall back to raw timing for first controller only York Sun
  2012-08-17 18:22 ` [U-Boot] [PATCH 8/8] powerpc/mpc8xxx DDR: Fix interactive DDR debugging York Sun
  6 siblings, 0 replies; 8+ messages in thread
From: York Sun @ 2012-08-17 18:22 UTC (permalink / raw)
  To: u-boot

Empty slot should be skipped when calculating CAS latency.

Signed-off-by: York Sun <yorksun@freescale.com>
---
 .../cpu/mpc8xxx/ddr/lc_common_dimm_params.c        |    6 ++++--
 1 files changed, 4 insertions(+), 2 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 a474a65..03a784c 100644
--- a/arch/powerpc/cpu/mpc8xxx/ddr/lc_common_dimm_params.c
+++ b/arch/powerpc/cpu/mpc8xxx/ddr/lc_common_dimm_params.c
@@ -27,8 +27,10 @@ compute_cas_latency_ddr3(const dimm_params_t *dimm_params,
 
 	/* compute the common CAS latency supported between slots */
 	tmp = dimm_params[0].caslat_X;
-	for (i = 1; i < number_of_dimms; i++)
-		 tmp &= dimm_params[i].caslat_X;
+	for (i = 1; i < number_of_dimms; i++) {
+		if (dimm_params[i].n_ranks)
+			tmp &= dimm_params[i].caslat_X;
+	}
 	common_caslat = tmp;
 
 	/* compute the max tAAmin tCKmin between slots */
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [U-Boot] [PATCH 7/8] powerpc/mpc8xxx DDR: Fall back to raw timing for first controller only
  2012-08-17 18:22 [U-Boot] [PATCH 1/8] powerpc/mpc85xx: Skip zero values for DDR debug registers York Sun
                   ` (4 preceding siblings ...)
  2012-08-17 18:22 ` [U-Boot] [PATCH 6/8] powerpc/mpc8xxx DDR: Fix CAS latency calculation York Sun
@ 2012-08-17 18:22 ` York Sun
  2012-08-17 18:22 ` [U-Boot] [PATCH 8/8] powerpc/mpc8xxx DDR: Fix interactive DDR debugging York Sun
  6 siblings, 0 replies; 8+ messages in thread
From: York Sun @ 2012-08-17 18:22 UTC (permalink / raw)
  To: u-boot

Only the first DIMM of first controller should fall back to raw timing
parameters if SPD is missing or corrupted.

Signed-off-by: York Sun <yorksun@freescale.com>
---
 arch/powerpc/cpu/mpc8xxx/ddr/main.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/main.c b/arch/powerpc/cpu/mpc8xxx/ddr/main.c
index 4fd4f8f..b47268c 100644
--- a/arch/powerpc/cpu/mpc8xxx/ddr/main.c
+++ b/arch/powerpc/cpu/mpc8xxx/ddr/main.c
@@ -383,7 +383,7 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,
 
 				retval = compute_dimm_parameters(spd, pdimm, i);
 #ifdef CONFIG_SYS_DDR_RAW_TIMING
-				if (retval != 0) {
+				if (!i && !j && retval) {
 					printf("SPD error on controller %d! "
 					"Trying fallback to raw timing "
 					"calculation\n", i);
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [U-Boot] [PATCH 8/8] powerpc/mpc8xxx DDR: Fix interactive DDR debugging
  2012-08-17 18:22 [U-Boot] [PATCH 1/8] powerpc/mpc85xx: Skip zero values for DDR debug registers York Sun
                   ` (5 preceding siblings ...)
  2012-08-17 18:22 ` [U-Boot] [PATCH 7/8] powerpc/mpc8xxx DDR: Fall back to raw timing for first controller only York Sun
@ 2012-08-17 18:22 ` York Sun
  6 siblings, 0 replies; 8+ messages in thread
From: York Sun @ 2012-08-17 18:22 UTC (permalink / raw)
  To: u-boot

Add one more argument to call function readline_into_buffer().
Fix print SPD format for negative values.

Signed-off-by: York Sun <yorksun@freescale.com>
---
 arch/powerpc/cpu/mpc8xxx/ddr/interactive.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/interactive.c b/arch/powerpc/cpu/mpc8xxx/ddr/interactive.c
index 738c808..f59d105 100644
--- a/arch/powerpc/cpu/mpc8xxx/ddr/interactive.c
+++ b/arch/powerpc/cpu/mpc8xxx/ddr/interactive.c
@@ -1047,7 +1047,7 @@ void ddr3_spd_dump(const ddr3_spd_eeprom_t *spd)
 
 	/* General Section: Bytes 0-59 */
 
-#define PRINT_NXS(x, y, z...) printf("%-3d    : %02x " z "\n", x, y);
+#define PRINT_NXS(x, y, z...) printf("%-3d    : %02x " z "\n", x, (u8)y);
 #define PRINT_NNXXS(n0, n1, x0, x1, s) \
 	printf("%-3d-%3d: %02x %02x " s "\n", n0, n1, x0, x1);
 
@@ -1398,7 +1398,7 @@ unsigned long long fsl_ddr_interactive(fsl_ddr_info_t *pinfo)
 		 * No need to worry for buffer overflow here in
 		 * this function;  readline() maxes out at CFG_CBSIZE
 		 */
-		readline_into_buffer(prompt,  buffer);
+		readline_into_buffer(prompt, buffer, 0);
 		argc = parse_line(buffer, argv);
 		if (argc == 0)
 			continue;
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2012-08-17 18:22 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-08-17 18:22 [U-Boot] [PATCH 1/8] powerpc/mpc85xx: Skip zero values for DDR debug registers York Sun
2012-08-17 18:22 ` [U-Boot] [PATCH 2/8] powerpc/mpc8xxx: Add fine timing support for DDR3 York Sun
2012-08-17 18:22 ` [U-Boot] [PATCH 3/8] powerpc/mpc8xxx: Add support for cas latency 12 and above York Sun
2012-08-17 18:22 ` [U-Boot] [PATCH 4/8] powerpc/mpc8xxx: Enable 3-way and 4-way DDR interleaving York Sun
2012-08-17 18:22 ` [U-Boot] [PATCH 5/8] powerpc/mpc8xxx: Fix bug for extended DDR timing York Sun
2012-08-17 18:22 ` [U-Boot] [PATCH 6/8] powerpc/mpc8xxx DDR: Fix CAS latency calculation York Sun
2012-08-17 18:22 ` [U-Boot] [PATCH 7/8] powerpc/mpc8xxx DDR: Fall back to raw timing for first controller only York Sun
2012-08-17 18:22 ` [U-Boot] [PATCH 8/8] powerpc/mpc8xxx DDR: Fix interactive DDR debugging York Sun

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.