powerpc/mpc8xxx: Fix DDR initialization waiting for D_INIT
When ECC is enabled, DDR controller needs to initialize the data and ecc.
The wait time can be calcuated with total memory size, bus width, bus speed
and interleaving mode. If it went wrong, it is bettert to timeout than
waiting for D_INIT to clear, where it probably hangs.
Signed-off-by: York Sun <yorksun@freescale.com>
Signed-off-by: Andy Fleming <afleming@freescale.com>
diff --git a/arch/powerpc/cpu/mpc85xx/ddr-gen3.c b/arch/powerpc/cpu/mpc85xx/ddr-gen3.c
index 088cf45..8bed5fe 100644
--- a/arch/powerpc/cpu/mpc85xx/ddr-gen3.c
+++ b/arch/powerpc/cpu/mpc85xx/ddr-gen3.c
@@ -18,12 +18,13 @@
void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
unsigned int ctrl_num)
{
- unsigned int i;
+ unsigned int i, bus_width;
volatile ccsr_ddr_t *ddr;
u32 temp_sdram_cfg;
+ u32 total_gb_size_per_controller;
+ int timeout, timeout_save;
#ifdef CONFIG_SYS_FSL_ERRATUM_DDR111_DDR134
volatile ccsr_local_ecm_t *ecm = (void *)CONFIG_SYS_MPC85xx_ECM_ADDR;
- u32 total_gb_size_per_controller;
unsigned int csn_bnds_backup = 0, cs_sa, cs_ea, *csn_bnds_t;
int csn = -1;
#endif
@@ -52,8 +53,8 @@
return;
}
- out_be32(&ddr->eor, regs->ddr_eor);
-
+ if (regs->ddr_eor)
+ 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++) {
@@ -275,9 +276,46 @@
out_be32(&ddr->sdram_cfg, temp_sdram_cfg | SDRAM_CFG_MEM_EN);
asm volatile("sync;isync");
+ total_gb_size_per_controller = 0;
+ for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
+ if (!(regs->cs[i].config & 0x80000000))
+ continue;
+ total_gb_size_per_controller += 1 << (
+ ((regs->cs[i].config >> 14) & 0x3) + 2 +
+ ((regs->cs[i].config >> 8) & 0x7) + 12 +
+ ((regs->cs[i].config >> 0) & 0x7) + 8 +
+ 3 - ((regs->ddr_sdram_cfg >> 19) & 0x3) -
+ 26); /* minus 26 (count of 64M) */
+ }
+ if (fsl_ddr_get_intl3r() & 0x80000000) /* 3-way interleaving */
+ total_gb_size_per_controller *= 3;
+ else if (regs->cs[0].config & 0x20000000) /* 2-way interleaving */
+ total_gb_size_per_controller <<= 1;
+ /*
+ * total memory / bus width = transactions needed
+ * transactions needed / data rate = seconds
+ * to add plenty of buffer, double the time
+ * For example, 2GB on 666MT/s 64-bit bus takes about 402ms
+ * Let's wait for 800ms
+ */
+ bus_width = 3 - ((ddr->sdram_cfg & SDRAM_CFG_DBW_MASK)
+ >> SDRAM_CFG_DBW_SHIFT);
+ timeout = ((total_gb_size_per_controller << (6 - bus_width)) * 100 /
+ (get_ddr_freq(0) >> 20)) << 1;
+ timeout_save = timeout;
+ total_gb_size_per_controller >>= 4; /* shift down to gb size */
+ debug("total %d GB\n", total_gb_size_per_controller);
+ debug("Need to wait up to %d * 10ms\n", timeout);
+
/* Poll DDR_SDRAM_CFG_2[D_INIT] bit until auto-data init is done. */
- while (in_be32(&ddr->sdram_cfg_2) & SDRAM_CFG2_D_INIT)
+ while ((in_be32(&ddr->sdram_cfg_2) & SDRAM_CFG2_D_INIT) &&
+ (timeout >= 0)) {
udelay(10000); /* throttle polling rate */
+ timeout--;
+ }
+
+ if (timeout <= 0)
+ printf("Waiting for D_INIT timeout. Memory may not work.\n");
#ifdef CONFIG_SYS_FSL_ERRATUM_DDR111_DDR134
/* continue this workaround */
@@ -335,23 +373,9 @@
while (in_be32(&ddr->debug[1]) & 0x400)
udelay(10000); /* throttle polling rate */
- /* 7. Wait for 400ms/GB */
- total_gb_size_per_controller = 0;
- for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
- if (i == csn) {
- total_gb_size_per_controller +=
- ((csn_bnds_backup & 0xFFFF) >> 6)
- - (csn_bnds_backup >> 22) + 1;
- } else {
- total_gb_size_per_controller +=
- ((regs->cs[i].bnds & 0xFFFF) >> 6)
- - (regs->cs[i].bnds >> 22) + 1;
- }
- }
- if (in_be32(&ddr->sdram_cfg) & 0x80000)
- total_gb_size_per_controller <<= 1;
- debug("Wait for %d ms\n", total_gb_size_per_controller * 400);
- udelay(total_gb_size_per_controller * 400000);
+ /* 7. Wait for state machine 2nd run, roughly 400ms/GB */
+ debug("Wait for %d * 10ms\n", timeout_save);
+ udelay(timeout_save * 10000);
/* 8. Set sdram_cfg_2[dinit] if options requires */
setbits_be32(&ddr->sdram_cfg_2,
@@ -359,8 +383,16 @@
debug("Setting sdram_cfg_2 to 0x%08x\n", in_be32(&ddr->sdram_cfg_2));
/* 9. Poll until dinit is cleared */
- while (in_be32(&ddr->sdram_cfg_2) & SDRAM_CFG2_D_INIT)
- udelay(10000);
+ timeout = timeout_save;
+ debug("Need to wait up to %d * 10ms\n", timeout);
+ while ((in_be32(&ddr->sdram_cfg_2) & SDRAM_CFG2_D_INIT) &&
+ (timeout >= 0)) {
+ udelay(10000); /* throttle polling rate */
+ timeout--;
+ }
+
+ if (timeout <= 0)
+ printf("Waiting for D_INIT timeout. Memory may not work.\n");
/* 10. Clear EEBACR[3] */
clrbits_be32(&ecm->eebacr, 10000000);
diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/main.c b/arch/powerpc/cpu/mpc8xxx/ddr/main.c
index b47268c..2885906 100644
--- a/arch/powerpc/cpu/mpc8xxx/ddr/main.c
+++ b/arch/powerpc/cpu/mpc8xxx/ddr/main.c
@@ -526,6 +526,17 @@
#endif
total_memory = fsl_ddr_compute(&info, STEP_GET_SPD, 0);
+ /* setup 3-way interleaving before enabling DDRC */
+ switch (info.memctl_opts[0].memctl_interleaving_mode) {
+ case FSL_DDR_3WAY_1KB_INTERLEAVING:
+ case FSL_DDR_3WAY_4KB_INTERLEAVING:
+ case FSL_DDR_3WAY_8KB_INTERLEAVING:
+ fsl_ddr_set_intl3r(info.memctl_opts[0].memctl_interleaving_mode);
+ break;
+ default:
+ break;
+ }
+
/* Program configuration registers. */
for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
debug("Programming controller %u\n", i);
@@ -561,7 +572,6 @@
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);
}
diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/util.c b/arch/powerpc/cpu/mpc8xxx/ddr/util.c
index b439cc9..afc5fae 100644
--- a/arch/powerpc/cpu/mpc8xxx/ddr/util.c
+++ b/arch/powerpc/cpu/mpc8xxx/ddr/util.c
@@ -142,13 +142,13 @@
#if CONFIG_NUM_DDR_CONTROLLERS >= 2
if (!(sdram_cfg & SDRAM_CFG_MEM_EN)) {
- ddr = (void *)CONFIG_SYS_MPC85xx_DDR2_ADDR;
+ ddr = (void __iomem *)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;
+ ddr = (void __iomem *)CONFIG_SYS_MPC85xx_DDR3_ADDR;
sdram_cfg = in_be32(&ddr->sdram_cfg);
}
#endif
diff --git a/arch/powerpc/include/asm/fsl_ddr_sdram.h b/arch/powerpc/include/asm/fsl_ddr_sdram.h
index bb79335..640d329 100644
--- a/arch/powerpc/include/asm/fsl_ddr_sdram.h
+++ b/arch/powerpc/include/asm/fsl_ddr_sdram.h
@@ -98,6 +98,7 @@
#define SDRAM_CFG_SDRAM_TYPE_SHIFT 24
#define SDRAM_CFG_DYN_PWR 0x00200000
#define SDRAM_CFG_DBW_MASK 0x00180000
+#define SDRAM_CFG_DBW_SHIFT 19
#define SDRAM_CFG_32_BE 0x00080000
#define SDRAM_CFG_16_BE 0x00100000
#define SDRAM_CFG_8_BE 0x00040000
@@ -330,6 +331,7 @@
extern int fsl_use_spd(void);
extern void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
unsigned int ctrl_num);
+u32 fsl_ddr_get_intl3r(void);
/*
* The 85xx boards have a common prototype for fixed_sdram so put the