[U-Boot] [Patch v3 6/7] mpc85xx: Implement workaround for erratum DDR-A003

York Sun
2011-01-10T22:03:01Z

Erratum DDR-A003 requires workaround to correctly set RCW10 for registered DIMM.
Also adding polling after enabling DDR controller to ensure completion.

Signed-off-by: York Sun <yorksun@freescale.com>
---
arch/powerpc/cpu/mpc85xx/cmd_errata.c | 4 ++
arch/powerpc/cpu/mpc85xx/ddr-gen3.c | 81 +++++++++++++++++++++++++++++-
arch/powerpc/include/asm/fsl_ddr_sdram.h | 19 +++++++
include/configs/P4080DS.h | 1 +
4 files changed, 104 insertions(+), 1 deletions(-)

diff --git a/arch/powerpc/cpu/mpc85xx/cmd_errata.c b/arch/powerpc/cpu/mpc85xx/cmd_errata.c
index d73f3d7..7d9a074 100644
--- a/arch/powerpc/cpu/mpc85xx/cmd_errata.c
+++ b/arch/powerpc/cpu/mpc85xx/cmd_errata.c
@@ -47,6 +47,10 @@ static int do_errata(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
#if defined(CONFIG_SYS_P4080_ERRATUM_CPU22)
puts("Work-around for Erratum CPU22 enabled\n");
#endif
+#ifdef CONFIG_SYS_FSL_ERRATUM_DDR_A003
+ puts("Work-around for Erratum DDR-A003 enabled\n");
+#endif
+
return 0;
}

diff --git a/arch/powerpc/cpu/mpc85xx/ddr-gen3.c b/arch/powerpc/cpu/mpc85xx/ddr-gen3.c
index 5f1848f..1e15111 100644
--- a/arch/powerpc/cpu/mpc85xx/ddr-gen3.c
+++ b/arch/powerpc/cpu/mpc85xx/ddr-gen3.c
@@ -97,6 +97,82 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
temp_sdram_cfg = regs->ddr_sdram_cfg;
temp_sdram_cfg &= ~(SDRAM_CFG_MEM_EN);
out_be32(&ddr->sdram_cfg, temp_sdram_cfg);
+#ifdef CONFIG_SYS_FSL_ERRATUM_DDR_A003
+ if (regs->ddr_sdram_rcw_2 & 0x00f00000) {
+ out_be32(&ddr->timing_cfg_2, regs->timing_cfg_2 & 0xf07fffff);
+ out_be32(&ddr->debug[2], 0x00000400);
+ out_be32(&ddr->ddr_zq_cntl, regs->ddr_zq_cntl & 0x7fffffff);
+ out_be32(&ddr->ddr_wrlvl_cntl, regs->ddr_wrlvl_cntl & 0x7fffffff);
+ out_be32(&ddr->sdram_cfg_2, regs->ddr_sdram_cfg_2 & 0xffffffeb);
+ out_be32(&ddr->mtcr, 0);
+ out_be32(&ddr->debug[12], 0x00000015);
+ out_be32(&ddr->debug[21], 0x24000000);
+ out_be32(&ddr->sdram_interval, regs->ddr_sdram_interval & 0xffff);
+ out_be32(&ddr->sdram_cfg, temp_sdram_cfg | SDRAM_CFG_BI | SDRAM_CFG_MEM_EN);
+
+ asm volatile("sync;isync");
+ while (!(in_be32(&ddr->debug[1]) & 0x2))
+ ;
+
+ switch (regs->ddr_sdram_rcw_2 & 0x00f00000) {
+ case 0x00000000:
+ out_be32(&ddr->sdram_md_cntl,
+ MD_CNTL_MD_EN |
+ MD_CNTL_CS_SEL_CS0_CS1 |
+ 0x04000000 |
+ MD_CNTL_WRCW |
+ MD_CNTL_MD_VALUE(0x02));
+ break;
+ case 0x00100000:
+ out_be32(&ddr->sdram_md_cntl,
+ MD_CNTL_MD_EN |
+ MD_CNTL_CS_SEL_CS0_CS1 |
+ 0x04000000 |
+ MD_CNTL_WRCW |
+ MD_CNTL_MD_VALUE(0x0a));
+ break;
+ case 0x00200000:
+ out_be32(&ddr->sdram_md_cntl,
+ MD_CNTL_MD_EN |
+ MD_CNTL_CS_SEL_CS0_CS1 |
+ 0x04000000 |
+ MD_CNTL_WRCW |
+ MD_CNTL_MD_VALUE(0x12));
+ break;
+ case 0x00300000:
+ out_be32(&ddr->sdram_md_cntl,
+ MD_CNTL_MD_EN |
+ MD_CNTL_CS_SEL_CS0_CS1 |
+ 0x04000000 |
+ MD_CNTL_WRCW |
+ MD_CNTL_MD_VALUE(0x1a));
+ break;
+ default:
+ out_be32(&ddr->sdram_md_cntl,
+ MD_CNTL_MD_EN |
+ MD_CNTL_CS_SEL_CS0_CS1 |
+ 0x04000000 |
+ MD_CNTL_WRCW |
+ MD_CNTL_MD_VALUE(0x02));
+ printf("Unsupported RC10\n");
+ break;
+ }
+
+ while (in_be32(&ddr->sdram_md_cntl) & 0x80000000)
+ ;
+ udelay(6);
+ out_be32(&ddr->sdram_cfg, temp_sdram_cfg);
+ out_be32(&ddr->timing_cfg_2, regs->timing_cfg_2);
+ out_be32(&ddr->debug[2], 0x0);
+ out_be32(&ddr->ddr_zq_cntl, regs->ddr_zq_cntl);
+ out_be32(&ddr->ddr_wrlvl_cntl, regs->ddr_wrlvl_cntl);
+ out_be32(&ddr->sdram_cfg_2, regs->ddr_sdram_cfg_2);
+ out_be32(&ddr->debug[12], 0x0);
+ out_be32(&ddr->debug[21], 0x0);
+ out_be32(&ddr->sdram_interval, regs->ddr_sdram_interval);
+
+ }
+#endif
/*
* For 8572 DDR1 erratum - DDR controller may enter illegal state
* when operatiing in 32-bit bus mode with 4-beat bursts,
@@ -120,8 +196,11 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
asm volatile("sync;isync");

/* Let the controller go */
- temp_sdram_cfg = in_be32(&ddr->sdram_cfg);
+ temp_sdram_cfg = in_be32(&ddr->sdram_cfg) & ~SDRAM_CFG_BI;
out_be32(&ddr->sdram_cfg, temp_sdram_cfg | SDRAM_CFG_MEM_EN);
+ asm volatile("sync;isync");
+ while (!(in_be32(&ddr->debug[1]) & 0x2))
+ ;

/* Poll DDR_SDRAM_CFG_2[D_INIT] bit until auto-data init is done. */
while (in_be32(&ddr->sdram_cfg_2) & 0x10) {
diff --git a/arch/powerpc/include/asm/fsl_ddr_sdram.h b/arch/powerpc/include/asm/fsl_ddr_sdram.h
index 8c35c14..96e308b 100644
--- a/arch/powerpc/include/asm/fsl_ddr_sdram.h
+++ b/arch/powerpc/include/asm/fsl_ddr_sdram.h
@@ -101,6 +101,25 @@ typedef ddr3_spd_eeprom_t generic_spd_eeprom_t;
#define WR_DATA_DELAY_SHIFT 10
#endif

+/* DDR_MD_CNTL */
+#define MD_CNTL_MD_EN 0x80000000
+#define MD_CNTL_CS_SEL_CS0 0x00000000
+#define MD_CNTL_CS_SEL_CS1 0x10000000
+#define MD_CNTL_CS_SEL_CS2 0x20000000
+#define MD_CNTL_CS_SEL_CS3 0x30000000
+#define MD_CNTL_CS_SEL_CS0_CS1 0x40000000
+#define MD_CNTL_CS_SEL_CS2_CS3 0x50000000
+#define MD_CNTL_MD_SEL_MR 0x00000000
+#define MD_CNTL_MD_SEL_EMR 0x01000000
+#define MD_CNTL_MD_SEL_EMR2 0x02000000
+#define MD_CNTL_MD_SEL_EMR3 0x03000000
+#define MD_CNTL_SET_REF 0x00800000
+#define MD_CNTL_SET_PRE 0x00400000
+#define MD_CNTL_CKE_CNTL_LOW 0x00100000
+#define MD_CNTL_CKE_CNTL_HIGH 0x00200000
+#define MD_CNTL_WRCW 0x00080000
+#define MD_CNTL_MD_VALUE(x) (x & 0x0000FFFF)
+
/* Record of register values computed */
typedef struct fsl_ddr_cfg_regs_s {
struct {
diff --git a/include/configs/P4080DS.h b/include/configs/P4080DS.h
index 21b48e9..f502ee6 100644
--- a/include/configs/P4080DS.h
+++ b/include/configs/P4080DS.h
@@ -37,5 +37,6 @@

#define CONFIG_SYS_P4080_ERRATUM_CPU22
#define CONFIG_SYS_P4080_ERRATUM_SERDES8
+#define CONFIG_SYS_FSL_ERRATUM_DDR_A003

#include "corenet_ds.h"
--
1.7.0.4