fsl/ddr: Add erratum_a009942_check_cpo and clean related erratum
authorShengzhou Liu <Shengzhou.Liu@nxp.com>
Mon, 21 Nov 2016 03:36:48 +0000 (11:36 +0800)
committerYork Sun <york.sun@nxp.com>
Mon, 5 Dec 2016 16:31:45 +0000 (08:31 -0800)
- 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>
arch/arm/cpu/armv8/fsl-layerscape/cpu.c
arch/powerpc/cpu/mpc85xx/cpu_init.c
arch/powerpc/include/asm/config_mpc85xx.h
board/freescale/ls1021aqds/ls1021aqds.c
drivers/ddr/fsl/ctrl_regs.c
drivers/ddr/fsl/fsl_ddr_gen4.c
drivers/ddr/fsl/mpc85xx_ddr_gen3.c
include/fsl_ddr.h
include/fsl_ddr_sdram.h

index d6ee54642d214cb1445adab7965e09f6110c12b5..ffbbd729d461da29f4395cfd25d144d3cf8248b8 100644 (file)
@@ -26,6 +26,9 @@
 #ifdef CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT
 #include <asm/armv8/sec_firmware.h>
 #endif
+#ifdef CONFIG_SYS_FSL_DDR
+#include <fsl_ddr.h>
+#endif
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -403,7 +406,9 @@ int arch_early_init_r(void)
 #ifdef CONFIG_SYS_FSL_ERRATUM_A009635
        erratum_a009635();
 #endif
-
+#if defined(CONFIG_SYS_FSL_ERRATUM_A009942) && defined(CONFIG_SYS_FSL_DDR)
+       erratum_a009942_check_cpo();
+#endif
 #ifdef CONFIG_MP
 #if defined(CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT) && defined(CONFIG_ARMV8_PSCI)
        /* Check the psci version to determine if the psci is supported */
index c2402a8bda2bfdd32b95171a16d919ecfacfa653..d1b6699a6a1d96981c7788f358141f90e80d0c05 100644 (file)
@@ -45,7 +45,9 @@
 #include <nand.h>
 #include <errno.h>
 #endif
-
+#ifndef CONFIG_ARCH_QEMU_E500
+#include <fsl_ddr.h>
+#endif
 #include "../../../../drivers/block/fsl_sata.h"
 #ifdef CONFIG_U_QE
 #include <fsl_qe.h>
@@ -947,6 +949,10 @@ int cpu_init_r(void)
 
 #endif /* CONFIG_SYS_FSL_USB_DUAL_PHY_ENABLE */
 
+#ifdef CONFIG_SYS_FSL_ERRATUM_A009942
+       erratum_a009942_check_cpo();
+#endif
+
 #ifdef CONFIG_FMAN_ENET
        fman_enet_init();
 #endif
index 4877b759815658777a8611b6c8af56aced16d58f..603d6aeadc315db7428f8361529efaf3c92e0c6e 100644 (file)
 #define CONFIG_SYS_FSL_USB_DUAL_PHY_ENABLE
 #define CONFIG_SYS_FSL_USB_INTERNAL_UTMI_PHY
 #define CONFIG_SYS_FSL_ERRATUM_A004468
-#define CONFIG_SYS_FSL_ERRATUM_A_004934
 #define CONFIG_SYS_FSL_ERRATUM_A005871
 #define CONFIG_SYS_FSL_ERRATUM_A006379
 #define CONFIG_SYS_FSL_ERRATUM_A007186
 #define CONFIG_SYS_FSL_TBCLK_DIV       16
 #define CONFIG_SYS_FSL_PCIE_COMPAT     "fsl,qoriq-pcie-v2.4"
 #define CONFIG_SYS_FSL_USB1_PHY_ENABLE
-#define CONFIG_SYS_FSL_ERRATUM_A_004934
 #define CONFIG_SYS_FSL_ERRATUM_A005871
 #define CONFIG_SYS_FSL_ERRATUM_A006379
 #define CONFIG_SYS_FSL_ERRATUM_A007186
index 4eb38a73c901050761cced88c6498e4b2260d88e..79078d237b44731ecf8b49efe4459c10fa002df8 100644 (file)
@@ -22,7 +22,7 @@
 #include <spl.h>
 #include <fsl_devdis.h>
 #include <fsl_validate.h>
-
+#include <fsl_ddr.h>
 #include "../common/sleep.h"
 #include "../common/qixis.h"
 #include "ls1021aqds_qixis.h"
@@ -433,7 +433,9 @@ int board_init(void)
 #ifdef CONFIG_SYS_FSL_ERRATUM_A010315
        erratum_a010315();
 #endif
-
+#ifdef CONFIG_SYS_FSL_ERRATUM_A009942
+       erratum_a009942_check_cpo();
+#endif
        major = get_soc_major_rev();
        if (major == SOC_MAJOR_VER_1_0) {
                /* Set CCI-400 control override register to
index 32b09679e2ec4fa9a24ad88ab03ddf9c4cb59fe8..f7e87b8ee9d2532bca6ae971f3ead304b99d09ba 100644 (file)
@@ -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
index 30f60e0fe1aa38067416b42d597a7c99aca6de1d..dadcb3abc39b81450b54a3c11e1046aa53c63589 100644 (file)
@@ -63,9 +63,6 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
 #endif
 #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:
@@ -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)) {
index 653b7f0c770c965f0e31f84271c478d441413d06..1bfb9d4097ced8f0bb1f604649a1773b554fe0e0 100644 (file)
@@ -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);
index 3351acdd7aed4b9715f83b2f3b9d8e78aeee3d86..0c3be0e2e02a8336754b7b62af759251b1633047 100644 (file)
@@ -138,4 +138,6 @@ int fsl_ddr_get_dimm_params(dimm_params_t *pdimm,
 void update_spd_address(unsigned int ctrl_num,
                        unsigned int slot,
                        unsigned int *addr);
+
+void erratum_a009942_check_cpo(void);
 #endif
index 36bd9d7c934a7a299a147a5c0c0d29bb15d8aa60..1404c5793607089c519c8d8f6dfe0fc9ef18fe57 100644 (file)
@@ -374,7 +374,8 @@ typedef struct memctl_options_s {
        unsigned int additive_latency_override_value;
 
        unsigned int clk_adjust;                /* */
-       unsigned int cpo_override;
+       unsigned int cpo_override;              /* override timing_cfg_2[CPO]*/
+       unsigned int cpo_sample;                /* optimize debug_29[24:31] */
        unsigned int write_data_delay;          /* DQS adjust */
 
        unsigned int cswl_override;