diff mbox

[U-Boot,10/11] powerpc/mpc8xxx: Add memory reset control

Message ID 1372185469-14161-10-git-send-email-yorksun@freescale.com
State Accepted
Delegated to: Andy Fleming
Headers show

Commit Message

York Sun June 25, 2013, 6:37 p.m. UTC
JEDEC spec requires the clocks to be stable before deasserting reset
signal for RDIMMs. Clocks start when any chip select is enabled and
clock control register is set. This patch also adds the interface to
toggle memory reset signal if needed by the boards.

Signed-off-by: York Sun <yorksun@freescale.com>
---
 arch/powerpc/cpu/mpc85xx/ddr-gen1.c      |    2 +-
 arch/powerpc/cpu/mpc85xx/ddr-gen2.c      |    2 +-
 arch/powerpc/cpu/mpc85xx/ddr-gen3.c      |   29 +++++++++++++++-
 arch/powerpc/cpu/mpc86xx/ddr-8641.c      |    2 +-
 arch/powerpc/cpu/mpc8xxx/ddr/ddr.h       |    2 +-
 arch/powerpc/cpu/mpc8xxx/ddr/main.c      |   54 ++++++++++++++++++++++++++----
 arch/powerpc/include/asm/fsl_ddr_sdram.h |   24 ++++++++++++-
 board/freescale/bsc9131rdb/ddr.c         |    2 +-
 board/freescale/bsc9132qds/ddr.c         |    2 +-
 board/freescale/common/qixis.c           |   20 +++++++++++
 board/freescale/corenet_ds/ddr.c         |    4 +--
 board/freescale/p1010rdb/ddr.c           |    2 +-
 board/freescale/p1_p2_rdb/ddr.c          |    2 +-
 board/freescale/p1_p2_rdb_pc/ddr.c       |    2 +-
 include/configs/T4240QDS.h               |    1 +
 15 files changed, 130 insertions(+), 20 deletions(-)
diff mbox

Patch

diff --git a/arch/powerpc/cpu/mpc85xx/ddr-gen1.c b/arch/powerpc/cpu/mpc85xx/ddr-gen1.c
index 8a86819..4dd8c0b 100644
--- a/arch/powerpc/cpu/mpc85xx/ddr-gen1.c
+++ b/arch/powerpc/cpu/mpc85xx/ddr-gen1.c
@@ -15,7 +15,7 @@ 
 #endif
 
 void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
-			     unsigned int ctrl_num)
+			     unsigned int ctrl_num, int step)
 {
 	unsigned int i;
 	volatile ccsr_ddr_t *ddr = (void *)CONFIG_SYS_MPC8xxx_DDR_ADDR;
diff --git a/arch/powerpc/cpu/mpc85xx/ddr-gen2.c b/arch/powerpc/cpu/mpc85xx/ddr-gen2.c
index a705862..542bc84 100644
--- a/arch/powerpc/cpu/mpc85xx/ddr-gen2.c
+++ b/arch/powerpc/cpu/mpc85xx/ddr-gen2.c
@@ -16,7 +16,7 @@ 
 #endif
 
 void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
-			     unsigned int ctrl_num)
+			     unsigned int ctrl_num, int step)
 {
 	unsigned int i;
 	ccsr_ddr_t *ddr = (void *)CONFIG_SYS_MPC8xxx_DDR_ADDR;
diff --git a/arch/powerpc/cpu/mpc85xx/ddr-gen3.c b/arch/powerpc/cpu/mpc85xx/ddr-gen3.c
index 3e7a564..1be51d3 100644
--- a/arch/powerpc/cpu/mpc85xx/ddr-gen3.c
+++ b/arch/powerpc/cpu/mpc85xx/ddr-gen3.c
@@ -15,8 +15,18 @@ 
 #error Invalid setting for CONFIG_CHIP_SELECTS_PER_CTRL
 #endif
 
+
+/*
+ * regs has the to-be-set values for DDR controller registers
+ * ctrl_num is the DDR controller number
+ * step: 0 goes through the initialization in one pass
+ *       1 sets registers and returns before enabling controller
+ *       2 resumes from step 1 and continues to initialize
+ * Dividing the initialization to two steps to deassert DDR reset signal
+ * to comply with JEDEC specs for RDIMMs.
+ */
 void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
-			     unsigned int ctrl_num)
+			     unsigned int ctrl_num, int step)
 {
 	unsigned int i, bus_width;
 	volatile ccsr_ddr_t *ddr;
@@ -54,6 +64,9 @@  void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
 		return;
 	}
 
+	if (step == 2)
+		goto step2;
+
 	if (regs->ddr_eor)
 		out_be32(&ddr->eor, regs->ddr_eor);
 #ifdef CONFIG_SYS_FSL_ERRATUM_DDR111_DDR134
@@ -157,6 +170,20 @@  void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
 	out_be32(&ddr->debug[21], 0x24000000);
 #endif /* CONFIG_SYS_FSL_ERRATUM_DDR_A003474 */
 
+	/*
+	 * For RDIMMs, JEDEC spec requires clocks to be stable before reset is
+	 * deasserted. Clocks start when any chip select is enabled and clock
+	 * control register is set. Because all DDR components are connected to
+	 * one reset signal, this needs to be done in two steps. Step 1 is to
+	 * get the clocks started. Step 2 resumes after reset signal is
+	 * deasserted.
+	 */
+	if (step == 1) {
+		udelay(200);
+		return;
+	}
+
+step2:
 	/* Set, but do not enable the memory */
 	temp_sdram_cfg = regs->ddr_sdram_cfg;
 	temp_sdram_cfg &= ~(SDRAM_CFG_MEM_EN);
diff --git a/arch/powerpc/cpu/mpc86xx/ddr-8641.c b/arch/powerpc/cpu/mpc86xx/ddr-8641.c
index 92ba26d..33a91f9 100644
--- a/arch/powerpc/cpu/mpc86xx/ddr-8641.c
+++ b/arch/powerpc/cpu/mpc86xx/ddr-8641.c
@@ -15,7 +15,7 @@ 
 #endif
 
 void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
-			     unsigned int ctrl_num)
+			     unsigned int ctrl_num, int step)
 {
 	unsigned int i;
 	volatile ccsr_ddr_t *ddr;
diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/ddr.h b/arch/powerpc/cpu/mpc8xxx/ddr/ddr.h
index 4dd55fc..c173a5a 100644
--- a/arch/powerpc/cpu/mpc8xxx/ddr/ddr.h
+++ b/arch/powerpc/cpu/mpc8xxx/ddr/ddr.h
@@ -96,7 +96,7 @@  unsigned int check_fsl_memctl_config_regs(const fsl_ddr_cfg_regs_t *ddr);
 
 /* processor specific function */
 void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
-				   unsigned int ctrl_num);
+				   unsigned int ctrl_num, int step);
 
 /* board specific function */
 int fsl_ddr_get_dimm_params(dimm_params_t *pdimm,
diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/main.c b/arch/powerpc/cpu/mpc8xxx/ddr/main.c
index c35405d..9f4f253 100644
--- a/arch/powerpc/cpu/mpc8xxx/ddr/main.c
+++ b/arch/powerpc/cpu/mpc8xxx/ddr/main.c
@@ -25,10 +25,6 @@  void fsl_ddr_set_lawbar(
 		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,
-				   unsigned int ctrl_num);
-
 #if defined(SPD_EEPROM_ADDRESS) || \
     defined(SPD_EEPROM_ADDRESS1) || defined(SPD_EEPROM_ADDRESS2) || \
     defined(SPD_EEPROM_ADDRESS3) || defined(SPD_EEPROM_ADDRESS4)
@@ -365,9 +361,11 @@  fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,
 {
 	unsigned int i, j;
 	unsigned long long total_mem = 0;
+	int assert_reset;
 
 	fsl_ddr_cfg_regs_t *ddr_reg = pinfo->fsl_ddr_config_reg;
 	common_timing_params_t *timing_params = pinfo->common_timing_params;
+	assert_reset = board_need_mem_reset();
 
 	/* data bus width capacity adjust shift amount */
 	unsigned int dbw_capacity_adjust[CONFIG_NUM_DDR_CONTROLLERS];
@@ -462,7 +460,20 @@  fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,
 					timing_params[i].all_DIMMs_registered,
 					&pinfo->memctl_opts[i],
 					pinfo->dimm_params[i], i);
+			/*
+			 * For RDIMMs, JEDEC spec requires clocks to be stable
+			 * before reset signal is deasserted. For the boards
+			 * using fixed parameters, this function should be
+			 * be called from board init file.
+			 */
+			if (timing_params[i].all_DIMMs_registered)
+				assert_reset = 1;
+		}
+		if (assert_reset) {
+			debug("Asserting mem reset\n");
+			board_assert_mem_reset();
 		}
+
 	case STEP_ASSIGN_ADDRESSES:
 		/* STEP 5:  Assign addresses to chip selects */
 		check_interleaving_options(pinfo);
@@ -537,6 +548,7 @@  phys_size_t fsl_ddr_sdram(void)
 	unsigned int law_memctl = LAW_TRGT_IF_DDR_1;
 	unsigned long long total_memory;
 	fsl_ddr_info_t info;
+	int deassert_reset;
 
 	/* Reset info structure. */
 	memset(&info, 0, sizeof(fsl_ddr_info_t));
@@ -565,7 +577,21 @@  phys_size_t fsl_ddr_sdram(void)
 		}
 	}
 
-	/* Program configuration registers. */
+	/*
+	 * Program configuration registers.
+	 * JEDEC specs requires clocks to be stable before deasserting reset
+	 * for RDIMMs. Clocks start after chip select is enabled and clock
+	 * control register is set. During step 1, all controllers have their
+	 * registers set but not enabled. Step 2 proceeds after deasserting
+	 * reset through board FPGA or GPIO.
+	 * For non-registered DIMMs, initialization can go through but it is
+	 * also OK to follow the same flow.
+	 */
+	deassert_reset = board_need_mem_reset();
+	for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+		if (info.common_timing_params[i].all_DIMMs_registered)
+			deassert_reset = 1;
+	}
 	for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
 		debug("Programming controller %u\n", i);
 		if (info.common_timing_params[i].ndimms_present == 0) {
@@ -573,8 +599,22 @@  phys_size_t fsl_ddr_sdram(void)
 					"skipping programming\n", i);
 			continue;
 		}
-
-		fsl_ddr_set_memctl_regs(&(info.fsl_ddr_config_reg[i]), i);
+		/*
+		 * The following call with step = 1 returns before enabling
+		 * the controller. It has to finish with step = 2 later.
+		 */
+		fsl_ddr_set_memctl_regs(&(info.fsl_ddr_config_reg[i]), i,
+					deassert_reset ? 1 : 0);
+	}
+	if (deassert_reset) {
+		/* Use board FPGA or GPIO to deassert reset signal */
+		debug("Deasserting mem reset\n");
+		board_deassert_mem_reset();
+		for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+			/* Call with step = 2 to continue initialization */
+			fsl_ddr_set_memctl_regs(&(info.fsl_ddr_config_reg[i]),
+						i, 2);
+		}
 	}
 
 	/* program LAWs */
diff --git a/arch/powerpc/include/asm/fsl_ddr_sdram.h b/arch/powerpc/include/asm/fsl_ddr_sdram.h
index bac22fc..f4eec82 100644
--- a/arch/powerpc/include/asm/fsl_ddr_sdram.h
+++ b/arch/powerpc/include/asm/fsl_ddr_sdram.h
@@ -331,9 +331,31 @@  extern phys_size_t fsl_ddr_sdram(void);
 extern phys_size_t fsl_ddr_sdram_size(void);
 extern int fsl_use_spd(void);
 extern void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
-					unsigned int ctrl_num);
+					unsigned int ctrl_num, int step);
 u32 fsl_ddr_get_intl3r(void);
 
+static void __board_assert_mem_reset(void)
+{
+}
+
+static void __board_deassert_mem_reset(void)
+{
+}
+
+void board_assert_mem_reset(void)
+	__attribute__((weak, alias("__board_assert_mem_reset")));
+
+void board_deassert_mem_reset(void)
+	__attribute__((weak, alias("__board_deassert_mem_reset")));
+
+static int __board_need_mem_reset(void)
+{
+	return 0;
+}
+
+int board_need_mem_reset(void)
+	__attribute__((weak, alias("__board_need_mem_reset")));
+
 /*
  * The 85xx boards have a common prototype for fixed_sdram so put the
  * declaration here.
diff --git a/board/freescale/bsc9131rdb/ddr.c b/board/freescale/bsc9131rdb/ddr.c
index c753edf..5296986 100644
--- a/board/freescale/bsc9131rdb/ddr.c
+++ b/board/freescale/bsc9131rdb/ddr.c
@@ -103,7 +103,7 @@  phys_size_t fixed_sdram(void)
 	}
 
 	ddr_size = (phys_size_t) CONFIG_SYS_SDRAM_SIZE * 1024 * 1024;
-	fsl_ddr_set_memctl_regs(&ddr_cfg_regs, 0);
+	fsl_ddr_set_memctl_regs(&ddr_cfg_regs, 0, 0);
 
 	if (set_ddr_laws(CONFIG_SYS_DDR_SDRAM_BASE, ddr_size,
 					LAW_TRGT_IF_DDR_1) < 0) {
diff --git a/board/freescale/bsc9132qds/ddr.c b/board/freescale/bsc9132qds/ddr.c
index 946ad19..60abaa6 100644
--- a/board/freescale/bsc9132qds/ddr.c
+++ b/board/freescale/bsc9132qds/ddr.c
@@ -125,7 +125,7 @@  phys_size_t fixed_sdram(void)
 					strmhz(buf, ddr_freq));
 
 	ddr_size = (phys_size_t) CONFIG_SYS_SDRAM_SIZE * 1024 * 1024;
-	fsl_ddr_set_memctl_regs(&ddr_cfg_regs, 0);
+	fsl_ddr_set_memctl_regs(&ddr_cfg_regs, 0, 0);
 
 	if (set_ddr_laws(CONFIG_SYS_DDR_SDRAM_BASE, ddr_size,
 					LAW_TRGT_IF_DDR_1) < 0) {
diff --git a/board/freescale/common/qixis.c b/board/freescale/common/qixis.c
index 2b74d02..0dea660 100644
--- a/board/freescale/common/qixis.c
+++ b/board/freescale/common/qixis.c
@@ -111,6 +111,26 @@  const char *byte_to_binary_mask(u8 val, u8 mask, char *buf)
 	return buf;
 }
 
+#ifdef QIXIS_RST_FORCE_MEM
+void board_assert_mem_reset(void)
+{
+	u8 rst;
+
+	rst = QIXIS_READ(rst_frc[0]);
+	if (!(rst & QIXIS_RST_FORCE_MEM))
+		QIXIS_WRITE(rst_frc[0], rst | QIXIS_RST_FORCE_MEM);
+}
+
+void board_deassert_mem_reset(void)
+{
+	u8 rst;
+
+	rst = QIXIS_READ(rst_frc[0]);
+	if (rst & QIXIS_RST_FORCE_MEM)
+		QIXIS_WRITE(rst_frc[0], rst & ~QIXIS_RST_FORCE_MEM);
+}
+#endif
+
 void qixis_reset(void)
 {
 	QIXIS_WRITE(rst_ctl, QIXIS_RST_CTL_RESET);
diff --git a/board/freescale/corenet_ds/ddr.c b/board/freescale/corenet_ds/ddr.c
index da284cd..517e87f 100644
--- a/board/freescale/corenet_ds/ddr.c
+++ b/board/freescale/corenet_ds/ddr.c
@@ -56,14 +56,14 @@  phys_size_t fixed_sdram(void)
 
 	ddr_size = (phys_size_t) CONFIG_SYS_SDRAM_SIZE * 1024 * 1024;
 	ddr_cfg_regs.ddr_cdr1 = DDR_CDR1_DHC_EN;
-	fsl_ddr_set_memctl_regs(&ddr_cfg_regs, 0);
+	fsl_ddr_set_memctl_regs(&ddr_cfg_regs, 0, 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 = DDR_CDR1_DHC_EN;
-	fsl_ddr_set_memctl_regs(&ddr_cfg_regs, 1);
+	fsl_ddr_set_memctl_regs(&ddr_cfg_regs, 1, 0);
 #endif
 
 	/*
diff --git a/board/freescale/p1010rdb/ddr.c b/board/freescale/p1010rdb/ddr.c
index 49310bd..72c46f1 100644
--- a/board/freescale/p1010rdb/ddr.c
+++ b/board/freescale/p1010rdb/ddr.c
@@ -155,7 +155,7 @@  phys_size_t fixed_sdram(void)
 	}
 
 	ddr_size = (phys_size_t) CONFIG_SYS_SDRAM_SIZE * 1024 * 1024;
-	fsl_ddr_set_memctl_regs(&ddr_cfg_regs, 0);
+	fsl_ddr_set_memctl_regs(&ddr_cfg_regs, 0, 0);
 
 	if (set_ddr_laws(CONFIG_SYS_DDR_SDRAM_BASE, ddr_size,
 					LAW_TRGT_IF_DDR_1) < 0) {
diff --git a/board/freescale/p1_p2_rdb/ddr.c b/board/freescale/p1_p2_rdb/ddr.c
index b16b8c8..9c7fc0e 100644
--- a/board/freescale/p1_p2_rdb/ddr.c
+++ b/board/freescale/p1_p2_rdb/ddr.c
@@ -236,7 +236,7 @@  phys_size_t fixed_sdram (void)
 		ddr_cfg_regs.cs[0].bnds = 0x0000001F;
 	}
 
-	fsl_ddr_set_memctl_regs(&ddr_cfg_regs, 0);
+	fsl_ddr_set_memctl_regs(&ddr_cfg_regs, 0, 0);
 
 	set_ddr_laws(0, ddr_size, LAW_TRGT_IF_DDR_1);
 	return ddr_size;
diff --git a/board/freescale/p1_p2_rdb_pc/ddr.c b/board/freescale/p1_p2_rdb_pc/ddr.c
index 9355536..14f0539 100644
--- a/board/freescale/p1_p2_rdb_pc/ddr.c
+++ b/board/freescale/p1_p2_rdb_pc/ddr.c
@@ -251,7 +251,7 @@  phys_size_t fixed_sdram(void)
 
 	ddr_size = CONFIG_SYS_SDRAM_SIZE * 1024 * 1024;
 
-	fsl_ddr_set_memctl_regs(&ddr_cfg_regs, 0);
+	fsl_ddr_set_memctl_regs(&ddr_cfg_regs, 0, 0);
 
 	if (set_ddr_laws(CONFIG_SYS_DDR_SDRAM_BASE,
 				ddr_size, LAW_TRGT_IF_DDR_1) < 0) {
diff --git a/include/configs/T4240QDS.h b/include/configs/T4240QDS.h
index 6294f2b..d849e24 100644
--- a/include/configs/T4240QDS.h
+++ b/include/configs/T4240QDS.h
@@ -177,6 +177,7 @@  unsigned long get_board_ddr_clk(void);
 #define QIXIS_LBMAP_DFLTBANK		0x00
 #define QIXIS_LBMAP_ALTBANK		0x04
 #define QIXIS_RST_CTL_RESET		0x83
+#define QIXIS_RST_FORCE_MEM		0x1
 #define QIXIS_RCFG_CTL_RECONFIG_IDLE	0x20
 #define QIXIS_RCFG_CTL_RECONFIG_START	0x21
 #define QIXIS_RCFG_CTL_WATCHDOG_ENBLE	0x08