[U-Boot] [PATCH 20/28] powerpc/mpc8xxx: Fix DDR driver handling quad-rank DIMMs and address calculation

York Sun yorksun at freescale.com
Mon Oct 8 19:44:23 CEST 2012


Fix handling quad-rank DIMMs in a system with two DIMM slots and first
slot supports both dual-rank DIMM and quad-rank DIMM.

For systems with quad-rank DIMM and double dual-rank DIMMs, cs_config
registers need to be enabled to maintain proper ODT operation. The
inactive CS should have bnds registers cleared.

Fix the turnaround timing for systems with all chip-selects enabled. This
wasn't an issue before because DDR was running lower than 1600MT/s with
this interleaving mode.

Fix DDR address calculation. It wasn't an issue until we have multiple
controllers with each more than 4GB and interleaving is disabled.

It also fixes the message of DDR: 2 GiB (DDR3, 64-bit, CL=0.5, ECC off)
when debugging DDR and first DDR controller is disabled. With the fix,
the first enabled controller information will be displayed.

Signed-off-by: York Sun <yorksun at freescale.com>
---
 arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c           |   62 +++++++++++++++-----
 .../cpu/mpc8xxx/ddr/lc_common_dimm_params.c        |   16 ++++-
 arch/powerpc/cpu/mpc8xxx/ddr/options.c             |   12 ++++
 arch/powerpc/cpu/mpc8xxx/ddr/util.c                |   12 ++++
 arch/powerpc/include/asm/fsl_ddr_sdram.h           |    2 +
 5 files changed, 87 insertions(+), 17 deletions(-)

diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c b/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c
index c28f9cd..5928eb8 100644
--- a/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c
+++ b/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c
@@ -229,6 +229,26 @@ static void set_csn_config_2(int i, fsl_ddr_cfg_regs_t *ddr)
 /* -3E = 667 CL5, -25 = CL6 800, -25E = CL5 800 */
 
 #if !defined(CONFIG_FSL_DDR1)
+static inline int avoid_odt_overlap(const dimm_params_t *dimm_params)
+{
+#if CONFIG_DIMM_SLOTS_PER_CTLR == 1
+	if (dimm_params[0].n_ranks == 4)
+		return 1;
+#endif
+
+#if CONFIG_DIMM_SLOTS_PER_CTLR == 2
+	if ((dimm_params[0].n_ranks == 2) &&
+		(dimm_params[1].n_ranks == 2))
+		return 1;
+
+#ifdef CONFIG_FSL_DDR_FIRST_SLOT_QUAD_CAPABLE
+	if (dimm_params[0].n_ranks == 4)
+		return 1;
+#endif
+#endif
+	return 0;
+}
+
 /*
  * DDR SDRAM Timing Configuration 0 (TIMING_CFG_0)
  *
@@ -236,7 +256,8 @@ static void set_csn_config_2(int i, fsl_ddr_cfg_regs_t *ddr)
  * dreams up non-zero default values to be backwards compatible.
  */
 static void set_timing_cfg_0(fsl_ddr_cfg_regs_t *ddr,
-				const memctl_options_t *popts)
+				const memctl_options_t *popts,
+				const dimm_params_t *dimm_params)
 {
 	unsigned char trwt_mclk = 0;   /* Read-to-write turnaround */
 	unsigned char twrt_mclk = 0;   /* Write-to-read turnaround */
@@ -266,7 +287,18 @@ static void set_timing_cfg_0(fsl_ddr_cfg_regs_t *ddr,
 	unsigned int data_rate = get_ddr_freq(0);
 	tmrd_mclk = 4;
 	/* set the turnaround time */
-	trwt_mclk = 1;
+
+	/*
+	 * for single quad-rank DIMM and two dual-rank DIMMs
+	 * to avoid ODT overlap
+	 */
+	if (avoid_odt_overlap(dimm_params)) {
+		twwt_mclk = 2;
+		trrt_mclk = 1;
+	}
+	/* for faster clock, need more time for data setup */
+	trwt_mclk = (data_rate/1000000 > 1800) ? 2 : 1;
+
 	if ((data_rate/1000000 > 1150) || (popts->memctl_interleaving))
 		twrt_mclk = 1;
 
@@ -1483,7 +1515,7 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts,
 				break;
 			}
 			sa = common_dimm->base_address;
-			ea = common_dimm->total_mem - 1;
+			ea = sa + common_dimm->total_mem - 1;
 		} else if (!popts->memctl_interleaving) {
 			/*
 			 * If memory interleaving between controllers is NOT
@@ -1497,7 +1529,7 @@ 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:
 				sa = common_dimm->base_address;
-				ea = common_dimm->total_mem - 1;
+				ea = sa + common_dimm->total_mem - 1;
 				break;
 			case FSL_DDR_CS0_CS1_AND_CS2_CS3:
 				if ((i >= 2) && (dimm_number == 0)) {
@@ -1554,17 +1586,19 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts,
 		sa >>= 24;
 		ea >>= 24;
 
-		ddr->cs[i].bnds = (0
-			| ((sa & 0xFFF) << 16)	/* starting address MSB */
-			| ((ea & 0xFFF) << 0)	/* ending address MSB */
-			);
+		if (cs_en) {
+			ddr->cs[i].bnds = (0
+				| ((sa & 0xFFF) << 16)/* starting address MSB */
+				| ((ea & 0xFFF) << 0)	/* ending address MSB */
+				);
+		} else {
+			debug("FSLDDR: setting bnds to 0 for inactive CS\n");
+			ddr->cs[i].bnds = 0;
+		}
 
 		debug("FSLDDR: cs[%d]_bnds = 0x%08x\n", i, ddr->cs[i].bnds);
-		if (cs_en) {
-			set_csn_config(dimm_number, i, ddr, popts, dimm_params);
-			set_csn_config_2(i, ddr);
-		} else
-			debug("CS%d is disabled.\n", i);
+		set_csn_config(dimm_number, i, ddr, popts, dimm_params);
+		set_csn_config_2(i, ddr);
 	}
 
 	/*
@@ -1577,7 +1611,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, popts);
+	set_timing_cfg_0(ddr, popts, dimm_params);
 #endif
 
 	set_timing_cfg_3(ddr, popts, common_dimm, cas_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 03a784c..6a1f4e4 100644
--- a/arch/powerpc/cpu/mpc8xxx/ddr/lc_common_dimm_params.c
+++ b/arch/powerpc/cpu/mpc8xxx/ddr/lc_common_dimm_params.c
@@ -76,7 +76,7 @@ compute_cas_latency_ddr3(const dimm_params_t *dimm_params,
 unsigned int
 compute_lowest_common_dimm_parameters(const dimm_params_t *dimm_params,
 				      common_timing_params_t *outpdimm,
-				      unsigned int number_of_dimms)
+				      const unsigned int number_of_dimms)
 {
 	unsigned int i, j;
 
@@ -126,13 +126,20 @@ compute_lowest_common_dimm_parameters(const dimm_params_t *dimm_params,
 			temp1++;
 			continue;
 		}
+
+		/*
+		 * check if quad-rank DIMM is plugged if
+		 * CONFIG_CHIP_SELECT_QUAD_CAPABLE is not defined
+		 * Only the board with proper design is capable
+		 */
+#ifndef CONFIG_FSL_DDR_FIRST_SLOT_QUAD_CAPABLE
 		if (dimm_params[i].n_ranks == 4 && \
 		  CONFIG_CHIP_SELECTS_PER_CTRL/CONFIG_DIMM_SLOTS_PER_CTLR < 4) {
 			printf("Found Quad-rank DIMM, not able to support.");
 			temp1++;
 			continue;
 		}
-
+#endif
 		/*
 		 * Find minimum tCKmax_ps to find fastest slow speed,
 		 * i.e., this is the slowest the whole system can go.
@@ -236,11 +243,14 @@ compute_lowest_common_dimm_parameters(const dimm_params_t *dimm_params,
 	if (outpdimm->all_DIMMs_registered)
 		for (j = 0; j < 16; j++) {
 			outpdimm->rcw[j] = dimm_params[0].rcw[j];
-			for (i = 1; i < number_of_dimms; i++)
+			for (i = 1; i < number_of_dimms; i++) {
+				if (!dimm_params[i].n_ranks)
+					continue;
 				if (dimm_params[i].rcw[j] != dimm_params[0].rcw[j]) {
 					temp1 = 1;
 					break;
 				}
+			}
 		}
 
 	if (temp1 != 0)
diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/options.c b/arch/powerpc/cpu/mpc8xxx/ddr/options.c
index 13e4825..1188df9 100644
--- a/arch/powerpc/cpu/mpc8xxx/ddr/options.c
+++ b/arch/powerpc/cpu/mpc8xxx/ddr/options.c
@@ -510,6 +510,14 @@ unsigned int populate_memctl_options(int all_DIMMs_registered,
 		}
 	} else if (CONFIG_DIMM_SLOTS_PER_CTLR == 2) {
 		switch (pdimm[0].n_ranks) {
+#ifdef CONFIG_FSL_DDR_FIRST_SLOT_QUAD_CAPABLE
+		case 4:
+			pdodt = single_Q;
+			if (pdimm[1].n_ranks)
+				printf("Error: Quad- and Dual-rank DIMMs "
+					"cannot be used together\n");
+			break;
+#endif
 		case 2:
 			switch (pdimm[1].n_ranks) {
 			case 2:
@@ -912,6 +920,10 @@ done:
 					"interleaving disabled!\n", ctrl_num);
 			}
 #elif (CONFIG_DIMM_SLOTS_PER_CTLR == 2)
+#ifdef CONFIG_FSL_DDR_FIRST_SLOT_QUAD_CAPABLE
+			if (pdimm[0].n_ranks == 4)
+				break;
+#endif
 			if ((pdimm[0].n_ranks < 2) && (pdimm[1].n_ranks < 2)) {
 				popts->ba_intlv_ctl = 0;
 				printf("Not enough bank(chip-select) for "
diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/util.c b/arch/powerpc/cpu/mpc8xxx/ddr/util.c
index 664ad09..b439cc9 100644
--- a/arch/powerpc/cpu/mpc8xxx/ddr/util.c
+++ b/arch/powerpc/cpu/mpc8xxx/ddr/util.c
@@ -140,6 +140,18 @@ void board_add_ram_info(int use_default)
 	uint32_t sdram_cfg = in_be32(&ddr->sdram_cfg);
 	int cas_lat;
 
+#if CONFIG_NUM_DDR_CONTROLLERS >= 2
+	if (!(sdram_cfg & SDRAM_CFG_MEM_EN)) {
+		ddr = (void *)CONFIG_SYS_MPC85xx_DDR2_ADDR;
+		sdram_cfg = in_be32(&ddr->sdram_cfg);
+	}
+#endif
+#if CONFIG_NUM_DDR_CONTROLLERS >= 3
+	if (!(sdram_cfg & SDRAM_CFG_MEM_EN)) {
+		ddr = (void *)CONFIG_SYS_MPC85xx_DDR3_ADDR;
+		sdram_cfg = in_be32(&ddr->sdram_cfg);
+	}
+#endif
 	puts(" (DDR");
 	switch ((sdram_cfg & SDRAM_CFG_SDRAM_TYPE_MASK) >>
 		SDRAM_CFG_SDRAM_TYPE_SHIFT) {
diff --git a/arch/powerpc/include/asm/fsl_ddr_sdram.h b/arch/powerpc/include/asm/fsl_ddr_sdram.h
index 9cf9bd4..bb79335 100644
--- a/arch/powerpc/include/asm/fsl_ddr_sdram.h
+++ b/arch/powerpc/include/asm/fsl_ddr_sdram.h
@@ -84,6 +84,8 @@ typedef ddr3_spd_eeprom_t generic_spd_eeprom_t;
 #define FSL_DDR_4WAY_4KB_INTERLEAVING	0x1C
 #define FSL_DDR_4WAY_8KB_INTERLEAVING	0x1D
 
+#define SDRAM_CS_CONFIG_EN		0x80000000
+
 /* DDR_SDRAM_CFG - DDR SDRAM Control Configuration
  */
 #define SDRAM_CFG_MEM_EN		0x80000000
-- 
1.7.9.5




More information about the U-Boot mailing list