]> git.ipfire.org Git - people/ms/u-boot.git/commitdiff
driver/ddr/fsl: Add address parity support for DDR4 UDIMM/discrete
authorShengzhou Liu <Shengzhou.Liu@nxp.com>
Thu, 10 Mar 2016 09:36:56 +0000 (17:36 +0800)
committerYork Sun <york.sun@nxp.com>
Mon, 21 Mar 2016 19:42:13 +0000 (12:42 -0700)
Add support of address parity for DDR4 UDIMM or discrete memory.
It requires to configurate corresponding MR5[2:0] and
TIMING_CFG_7[PAR_LAT]. Parity can be turned on by hwconfig,
e.g. hwconfig=fsl_ddr:parity=on.

Signed-off-by: Shengzhou Liu <Shengzhou.Liu@nxp.com>
Reviewed-by: York Sun <york.sun@nxp.com>
doc/README.fsl-ddr
drivers/ddr/fsl/ctrl_regs.c
drivers/ddr/fsl/options.c
include/fsl_ddr_sdram.h

index cd71ec8e1698aad0e2e010b276078ccd6584c8bb..cec5d94df4a83fe84b227f9827f167b7918aba9d 100644 (file)
@@ -123,6 +123,14 @@ ECC can be turned on/off by hwconfig.
 Syntax is
 hwconfig=fsl_ddr:ecc=off
 
+
+Memory address parity on/off
+============================
+address parity can be turned on/off by hwconfig.
+Syntax is:
+hwconfig=fsl_ddr:parity=on
+
+
 Memory testing options for mpc85xx
 ==================================
 1. Memory test can be done once U-Boot prompt comes up using mtest, or
@@ -143,6 +151,7 @@ platform
 
 hwconfig=fsl_ddr:addr_hash=true,ctlr_intlv=cacheline,bank_intlv=cs0_cs1_cs2_cs3,ecc=on
 
+
 Table for dynamic ODT for DDR3
 ==============================
 For single-slot system with quad-rank DIMM and dual-slot system, dynamic ODT may
index 0bfcd3413c62a5832b397627a99fed36a6a768e2..9073917914e9630a77d4df47870c248357b0f53d 100644 (file)
@@ -895,11 +895,15 @@ static void set_ddr_sdram_cfg_2(const unsigned int ctrl_num,
        slow = get_ddr_freq(ctrl_num) < 1249000000;
 #endif
 
-       if (popts->registered_dimm_en) {
+       if (popts->registered_dimm_en)
                rcw_en = 1;
-               ap_en = popts->ap_en;
-       } else {
+
+       /* DDR4 can have address parity for UDIMM and discrete */
+       if ((CONFIG_FSL_SDRAM_TYPE != SDRAM_TYPE_DDR4) &&
+           (!popts->registered_dimm_en)) {
                ap_en = 0;
+       } else {
+               ap_en = popts->ap_en;
        }
 
        x4_en = popts->x4_en ? 1 : 0;
@@ -1135,6 +1139,7 @@ static void set_ddr_sdram_mode_9(fsl_ddr_cfg_regs_t *ddr,
        unsigned short esdmode5;        /* Extended SDRAM mode 5 */
        int rtt_park = 0;
        bool four_cs = false;
+       const unsigned int mclk_ps = get_memory_clk_period_ps(0);
 
 #if CONFIG_CHIP_SELECTS_PER_CTRL == 4
        if ((ddr->cs[0].config & SDRAM_CS_CONFIG_EN) &&
@@ -1150,6 +1155,19 @@ static void set_ddr_sdram_mode_9(fsl_ddr_cfg_regs_t *ddr,
                esdmode5 = 0x00000400;  /* Data mask enabled */
        }
 
+       /* set command/address parity latency */
+       if (ddr->ddr_sdram_cfg_2 & SDRAM_CFG2_AP_EN) {
+               if (mclk_ps >= 935) {
+                       /* for DDR4-1600/1866/2133 */
+                       esdmode5 |= DDR_MR5_CA_PARITY_LAT_4_CLK;
+               } else if (mclk_ps >= 833) {
+                       /* for DDR4-2400 */
+                       esdmode5 |= DDR_MR5_CA_PARITY_LAT_5_CLK;
+               } else {
+                       printf("parity: mclk_ps = %d not supported\n", mclk_ps);
+               }
+       }
+
        ddr->ddr_sdram_mode_9 = (0
                                 | ((esdmode4 & 0xffff) << 16)
                                 | ((esdmode5 & 0xffff) << 0)
@@ -1170,6 +1188,20 @@ static void set_ddr_sdram_mode_9(fsl_ddr_cfg_regs_t *ddr,
                        } else {
                                esdmode5 = 0x00000400;
                        }
+
+                       if (ddr->ddr_sdram_cfg_2 & SDRAM_CFG2_AP_EN) {
+                               if (mclk_ps >= 935) {
+                                       /* for DDR4-1600/1866/2133 */
+                                       esdmode5 |= DDR_MR5_CA_PARITY_LAT_4_CLK;
+                               } else if (mclk_ps >= 833) {
+                                       /* for DDR4-2400 */
+                                       esdmode5 |= DDR_MR5_CA_PARITY_LAT_5_CLK;
+                               } else {
+                                       printf("parity: mclk_ps = %d not supported\n",
+                                              mclk_ps);
+                               }
+                       }
+
                        switch (i) {
                        case 1:
                                ddr->ddr_sdram_mode_11 = (0
@@ -1925,12 +1957,25 @@ static void set_timing_cfg_7(const unsigned int ctrl_num,
                             const common_timing_params_t *common_dimm)
 {
        unsigned int txpr, tcksre, tcksrx;
-       unsigned int cke_rst, cksre, cksrx, par_lat, cs_to_cmd;
+       unsigned int cke_rst, cksre, cksrx, par_lat = 0, cs_to_cmd;
+       const unsigned int mclk_ps = get_memory_clk_period_ps(ctrl_num);
 
        txpr = max(5U, picos_to_mclk(ctrl_num, common_dimm->trfc1_ps + 10000));
        tcksre = max(5U, picos_to_mclk(ctrl_num, 10000));
        tcksrx = max(5U, picos_to_mclk(ctrl_num, 10000));
-       par_lat = 0;
+
+       if (ddr->ddr_sdram_cfg_2 & SDRAM_CFG2_AP_EN) {
+               if (mclk_ps >= 935) {
+                       /* parity latency 4 clocks in case of 1600/1866/2133 */
+                       par_lat = 4;
+               } else if (mclk_ps >= 833) {
+                       /* parity latency 5 clocks for DDR4-2400 */
+                       par_lat = 5;
+               } else {
+                       printf("parity: mclk_ps = %d not supported\n", mclk_ps);
+               }
+       }
+
        cs_to_cmd = 0;
 
        if (txpr <= 200)
index 791d6441010ae43e637838248ac47c8e9f80256f..d0075ff1fd2b3fb96e8fee513ceb5b276d529cb3 100644 (file)
@@ -1002,8 +1002,19 @@ unsigned int populate_memctl_options(const common_timing_params_t *common_dimm,
        popts->twot_en = 0;
        popts->threet_en = 0;
 
-       /* for RDIMM, address parity enable */
-       popts->ap_en = 1;
+       /* for RDIMM and DDR4 UDIMM/discrete memory, address parity enable */
+       if (popts->registered_dimm_en)
+               popts->ap_en = 1; /* 0 = disable,  1 = enable */
+       else
+               popts->ap_en = 0; /* disabled for DDR4 UDIMM/discrete default */
+
+       if (hwconfig_sub_f("fsl_ddr", "parity", buf)) {
+               if (hwconfig_subarg_cmp_f("fsl_ddr", "parity", "on", buf)) {
+                       if (popts->registered_dimm_en ||
+                           (CONFIG_FSL_SDRAM_TYPE == SDRAM_TYPE_DDR4))
+                               popts->ap_en = 1;
+               }
+       }
 
        /*
         * BSTTOPRE precharge interval
index 3699c0408a11aeeee2354b471e5a63174f12d924..cf316a4665f4487a9a8d34e0809e9eab98dda345 100644 (file)
@@ -123,6 +123,7 @@ typedef struct ddr4_spd_eeprom_s generic_spd_eeprom_t;
 
 #define SDRAM_CFG2_FRC_SR              0x80000000
 #define SDRAM_CFG2_D_INIT              0x00000010
+#define SDRAM_CFG2_AP_EN               0x00000020
 #define SDRAM_CFG2_ODT_CFG_MASK                0x00600000
 #define SDRAM_CFG2_ODT_NEVER           0
 #define SDRAM_CFG2_ODT_ONLY_WRITE      1
@@ -177,6 +178,14 @@ typedef struct ddr4_spd_eeprom_s generic_spd_eeprom_t;
 #define DDR_CDR2_VREF_TRAIN_EN 0x00000080
 #define DDR_CDR2_VREF_RANGE_2  0x00000040
 
+/* DDR ERR_DISABLE */
+#define DDR_ERR_DISABLE_APED   (1 << 8)  /* Address parity error disable */
+
+/* Mode Registers */
+#define DDR_MR5_CA_PARITY_LAT_4_CLK    0x1 /* for DDR4-1600/1866/2133 */
+#define DDR_MR5_CA_PARITY_LAT_5_CLK    0x2 /* for DDR4-2400 */
+
+
 #if (defined(CONFIG_SYS_FSL_DDR_VER) && \
        (CONFIG_SYS_FSL_DDR_VER >= FSL_DDR_VER_4_7))
 #ifdef CONFIG_SYS_FSL_DDR3L
@@ -343,7 +352,7 @@ typedef struct memctl_options_s {
        /* mirrior DIMMs for DDR3 */
        unsigned int mirrored_dimm;
        unsigned int quad_rank_present;
-       unsigned int ap_en;     /* address parity enable for RDIMM */
+       unsigned int ap_en;     /* address parity enable for RDIMM/DDR4-UDIMM */
        unsigned int x4_en;     /* enable x4 devices */
 
        /* Global Timing Parameters */