summaryrefslogtreecommitdiff
path: root/drivers/ddr
diff options
context:
space:
mode:
authorShengzhou Liu <Shengzhou.Liu@nxp.com>2016-11-21 11:36:48 +0800
committerYork Sun <york.sun@nxp.com>2016-12-05 08:31:45 -0800
commit02fb2761576be8096ebf1b3f961a2cdb21b422ae (patch)
tree70cd556e7498ef63f2d51519958cfc2994c73950 /drivers/ddr
parent5a17b8b5dab8973089b7400d05f8503d56f29370 (diff)
fsl/ddr: Add erratum_a009942_check_cpo and clean related erratum
- add additional function erratum_a009942_check_cpo to check if the board needs tuning CPO calibration for optimal setting. - move ERRATUM_A009942(with revision to check cpo_sample option) from fsl_ddr_gen4.c to ctrl_regs.c for reuse on all DDR4/DDR3 parts. - move ERRATUM_A008378 from fsl_ddr_gen4.c to ctrl_regs.c - remove obsolete ERRATUM_A004934 which is replaced with ERRATUM_A009942. Signed-off-by: Shengzhou Liu <Shengzhou.Liu@nxp.com> [YS: Replaced CONFIG_QEMU_E500 with CONFIG_ARCH_QEMU_E500] Reviewed-by: York Sun <york.sun@nxp.com>
Diffstat (limited to 'drivers/ddr')
-rw-r--r--drivers/ddr/fsl/ctrl_regs.c136
-rw-r--r--drivers/ddr/fsl/fsl_ddr_gen4.c26
-rw-r--r--drivers/ddr/fsl/mpc85xx_ddr_gen3.c3
3 files changed, 134 insertions, 31 deletions
diff --git a/drivers/ddr/fsl/ctrl_regs.c b/drivers/ddr/fsl/ctrl_regs.c
index 32b09679e2..f7e87b8ee9 100644
--- a/drivers/ddr/fsl/ctrl_regs.c
+++ b/drivers/ddr/fsl/ctrl_regs.c
@@ -5,14 +5,14 @@
*/
/*
- * Generic driver for Freescale DDR/DDR2/DDR3 memory controller.
+ * Generic driver for Freescale DDR/DDR2/DDR3/DDR4 memory controller.
* Based on code from spd_sdram.c
* Author: James Yang [at freescale.com]
*/
#include <common.h>
#include <fsl_ddr_sdram.h>
-
+#include <fsl_errata.h>
#include <fsl_ddr.h>
#include <fsl_immap.h>
#include <asm/io.h>
@@ -2306,6 +2306,38 @@ compute_fsl_memctl_config_regs(const unsigned int ctrl_num,
unsigned int ip_rev = 0;
unsigned int unq_mrs_en = 0;
int cs_en = 1;
+#ifdef CONFIG_SYS_FSL_ERRATUM_A009942
+ unsigned int ddr_freq;
+#endif
+#if (defined(CONFIG_SYS_FSL_ERRATUM_A008378) && \
+ defined(CONFIG_SYS_FSL_DDRC_GEN4)) || \
+ defined(CONFIG_SYS_FSL_ERRATUM_A009942)
+ struct ccsr_ddr __iomem *ddrc;
+
+ switch (ctrl_num) {
+ case 0:
+ ddrc = (void *)CONFIG_SYS_FSL_DDR_ADDR;
+ break;
+#if defined(CONFIG_SYS_FSL_DDR2_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 1)
+ case 1:
+ ddrc = (void *)CONFIG_SYS_FSL_DDR2_ADDR;
+ break;
+#endif
+#if defined(CONFIG_SYS_FSL_DDR3_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 2)
+ case 2:
+ ddrc = (void *)CONFIG_SYS_FSL_DDR3_ADDR;
+ break;
+#endif
+#if defined(CONFIG_SYS_FSL_DDR4_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 3)
+ case 3:
+ ddrc = (void *)CONFIG_SYS_FSL_DDR4_ADDR;
+ break;
+#endif
+ default:
+ printf("%s unexpected ctrl_num = %u\n", __func__, ctrl_num);
+ return 1;
+ }
+#endif
memset(ddr, 0, sizeof(fsl_ddr_cfg_regs_t));
@@ -2526,5 +2558,105 @@ compute_fsl_memctl_config_regs(const unsigned int ctrl_num,
ddr->debug[2] |= 0x00000200; /* set bit 22 */
#endif
+#if defined(CONFIG_SYS_FSL_ERRATUM_A008378) && defined(CONFIG_SYS_FSL_DDRC_GEN4)
+ /* Erratum applies when accumulated ECC is used, or DBI is enabled */
+#define IS_ACC_ECC_EN(v) ((v) & 0x4)
+#define IS_DBI(v) ((((v) >> 12) & 0x3) == 0x2)
+ if (has_erratum_a008378()) {
+ if (IS_ACC_ECC_EN(ddr->ddr_sdram_cfg) ||
+ IS_DBI(ddr->ddr_sdram_cfg_3)) {
+ ddr->debug[28] = ddr_in32(&ddrc->debug[28]);
+ ddr->debug[28] |= (0x9 << 20);
+ }
+ }
+#endif
+
+#ifdef CONFIG_SYS_FSL_ERRATUM_A009942
+ ddr_freq = get_ddr_freq(ctrl_num) / 1000000;
+ ddr->debug[28] |= ddr_in32(&ddrc->debug[28]);
+ ddr->debug[28] &= 0xff0fff00;
+ if (ddr_freq <= 1333)
+ ddr->debug[28] |= 0x0080006a;
+ else if (ddr_freq <= 1600)
+ ddr->debug[28] |= 0x0070006f;
+ else if (ddr_freq <= 1867)
+ ddr->debug[28] |= 0x00700076;
+ else if (ddr_freq <= 2133)
+ ddr->debug[28] |= 0x0060007b;
+ if (popts->cpo_sample)
+ ddr->debug[28] = (ddr->debug[28] & 0xffffff00) |
+ popts->cpo_sample;
+#endif
+
return check_fsl_memctl_config_regs(ddr);
}
+
+#ifdef CONFIG_SYS_FSL_ERRATUM_A009942
+/*
+ * This additional workaround of A009942 checks the condition to determine if
+ * the CPO value set by the existing A009942 workaround needs to be updated.
+ * If need, print a warning to prompt user reconfigure DDR debug_29[24:31] with
+ * expected optimal value, the optimal value is highly board dependent.
+ */
+void erratum_a009942_check_cpo(void)
+{
+ struct ccsr_ddr __iomem *ddr =
+ (struct ccsr_ddr __iomem *)(CONFIG_SYS_FSL_DDR_ADDR);
+ u32 cpo, cpo_e, cpo_o, cpo_target, cpo_optimal;
+ u32 cpo_min = ddr_in32(&ddr->debug[9]) >> 24;
+ u32 cpo_max = cpo_min;
+ u32 sdram_cfg, i, tmp, lanes, ddr_type;
+ bool update_cpo = false, has_ecc = false;
+
+ sdram_cfg = ddr_in32(&ddr->sdram_cfg);
+ if (sdram_cfg & SDRAM_CFG_32_BE)
+ lanes = 4;
+ else if (sdram_cfg & SDRAM_CFG_16_BE)
+ lanes = 2;
+ else
+ lanes = 8;
+
+ if (sdram_cfg & SDRAM_CFG_ECC_EN)
+ has_ecc = true;
+
+ /* determine the maximum and minimum CPO values */
+ for (i = 9; i < 9 + lanes / 2; i++) {
+ cpo = ddr_in32(&ddr->debug[i]);
+ cpo_e = cpo >> 24;
+ cpo_o = (cpo >> 8) & 0xff;
+ tmp = min(cpo_e, cpo_o);
+ if (tmp < cpo_min)
+ cpo_min = tmp;
+ tmp = max(cpo_e, cpo_o);
+ if (tmp > cpo_max)
+ cpo_max = tmp;
+ }
+
+ if (has_ecc) {
+ cpo = ddr_in32(&ddr->debug[13]);
+ cpo = cpo >> 24;
+ if (cpo < cpo_min)
+ cpo_min = cpo;
+ if (cpo > cpo_max)
+ cpo_max = cpo;
+ }
+
+ cpo_target = ddr_in32(&ddr->debug[28]) & 0xff;
+ cpo_optimal = ((cpo_max + cpo_min) >> 1) + 0x27;
+ debug("cpo_optimal = 0x%x, cpo_target = 0x%x\n", cpo_optimal,
+ cpo_target);
+ debug("cpo_max = 0x%x, cpo_min = 0x%x\n", cpo_max, cpo_min);
+
+ ddr_type = (sdram_cfg & SDRAM_CFG_SDRAM_TYPE_MASK) >>
+ SDRAM_CFG_SDRAM_TYPE_SHIFT;
+ if (ddr_type == SDRAM_TYPE_DDR4)
+ update_cpo = (cpo_min + 0x3b) < cpo_target ? true : false;
+ else if (ddr_type == SDRAM_TYPE_DDR3)
+ update_cpo = (cpo_min + 0x3f) < cpo_target ? true : false;
+
+ if (update_cpo) {
+ printf("WARN: pls set popts->cpo_sample = 0x%x ", cpo_optimal);
+ printf("in <board>/ddr.c to optimize cpo\n");
+ }
+}
+#endif
diff --git a/drivers/ddr/fsl/fsl_ddr_gen4.c b/drivers/ddr/fsl/fsl_ddr_gen4.c
index 30f60e0fe1..dadcb3abc3 100644
--- a/drivers/ddr/fsl/fsl_ddr_gen4.c
+++ b/drivers/ddr/fsl/fsl_ddr_gen4.c
@@ -64,9 +64,6 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
#ifdef CONFIG_FSL_DDR_BIST
char buffer[CONFIG_SYS_CBSIZE];
#endif
-#if defined(CONFIG_SYS_FSL_ERRATUM_A009942)
- u32 ddr_freq;
-#endif
switch (ctrl_num) {
case 0:
ddr = (void *)CONFIG_SYS_FSL_DDR_ADDR;
@@ -223,16 +220,6 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
ddr_out32(&ddr->debug[i], regs->debug[i]);
}
}
-#ifdef CONFIG_SYS_FSL_ERRATUM_A008378
- /* Erratum applies when accumulated ECC is used, or DBI is enabled */
-#define IS_ACC_ECC_EN(v) ((v) & 0x4)
-#define IS_DBI(v) ((((v) >> 12) & 0x3) == 0x2)
- if (has_erratum_a008378()) {
- if (IS_ACC_ECC_EN(regs->ddr_sdram_cfg) ||
- IS_DBI(regs->ddr_sdram_cfg_3))
- ddr_setbits32(&ddr->debug[28], 0x9 << 20);
- }
-#endif
#ifdef CONFIG_SYS_FSL_ERRATUM_A008511
/* Part 1 of 2 */
@@ -270,19 +257,6 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
ddr_out32(&ddr->debug[25], temp32);
#endif
-#ifdef CONFIG_SYS_FSL_ERRATUM_A009942
- ddr_freq = get_ddr_freq(ctrl_num) / 1000000;
- temp32 = ddr_in32(&ddr->debug[28]);
- if (ddr_freq <= 1333)
- ddr_out32(&ddr->debug[28], temp32 | 0x0080006a);
- else if (ddr_freq <= 1600)
- ddr_out32(&ddr->debug[28], temp32 | 0x0070006f);
- else if (ddr_freq <= 1867)
- ddr_out32(&ddr->debug[28], temp32 | 0x00700076);
- else if (ddr_freq <= 2133)
- ddr_out32(&ddr->debug[28], temp32 | 0x0060007b);
-#endif
-
#ifdef CONFIG_SYS_FSL_ERRATUM_A010165
temp32 = get_ddr_freq(ctrl_num) / 1000000;
if ((temp32 > 1900) && (temp32 < 2300)) {
diff --git a/drivers/ddr/fsl/mpc85xx_ddr_gen3.c b/drivers/ddr/fsl/mpc85xx_ddr_gen3.c
index 653b7f0c77..1bfb9d4097 100644
--- a/drivers/ddr/fsl/mpc85xx_ddr_gen3.c
+++ b/drivers/ddr/fsl/mpc85xx_ddr_gen3.c
@@ -174,9 +174,6 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
out_be32(&ddr->debug[i], regs->debug[i]);
}
}
-#ifdef CONFIG_SYS_FSL_ERRATUM_A_004934
- out_be32(&ddr->debug[28], 0x30003000);
-#endif
#ifdef CONFIG_SYS_FSL_ERRATUM_DDR_A003474
out_be32(&ddr->debug[12], 0x00000015);