drivers/ddr/fsl: Enable detection of one DDR controller operation for LSCH3
[oweals/u-boot.git] / drivers / ddr / fsl / ctrl_regs.c
index 6bf22cfbd6fe5e01fea70079c724c231aaed35cb..8543679108751b1597137ecc8e859226d71fdb9b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008-2012 Freescale Semiconductor, Inc.
+ * Copyright 2008-2014 Freescale Semiconductor, Inc.
  *
  * SPDX-License-Identifier:    GPL-2.0+
  */
 #include <fsl_immap.h>
 #include <asm/io.h>
 
-#define _DDR_ADDR CONFIG_SYS_FSL_DDR_ADDR
-
-static u32 fsl_ddr_get_version(void)
-{
-       struct ccsr_ddr __iomem *ddr;
-       u32 ver_major_minor_errata;
-
-       ddr = (void *)_DDR_ADDR;
-       ver_major_minor_errata = (in_be32(&ddr->ip_rev1) & 0xFFFF) << 8;
-       ver_major_minor_errata |= (in_be32(&ddr->ip_rev2) & 0xFF00) >> 8;
-
-       return ver_major_minor_errata;
-}
-
-unsigned int picos_to_mclk(unsigned int picos);
-
 /*
  * Determine Rtt value.
  *
@@ -81,6 +65,40 @@ static inline int fsl_ddr_get_rtt(void)
        return rtt;
 }
 
+#ifdef CONFIG_SYS_FSL_DDR4
+/*
+ * compute CAS write latency according to DDR4 spec
+ * CWL = 9 for <= 1600MT/s
+ *       10 for <= 1866MT/s
+ *       11 for <= 2133MT/s
+ *       12 for <= 2400MT/s
+ *       14 for <= 2667MT/s
+ *       16 for <= 2933MT/s
+ *       18 for higher
+ */
+static inline unsigned int compute_cas_write_latency(
+                               const unsigned int ctrl_num)
+{
+       unsigned int cwl;
+       const unsigned int mclk_ps = get_memory_clk_period_ps(ctrl_num);
+       if (mclk_ps >= 1250)
+               cwl = 9;
+       else if (mclk_ps >= 1070)
+               cwl = 10;
+       else if (mclk_ps >= 935)
+               cwl = 11;
+       else if (mclk_ps >= 833)
+               cwl = 12;
+       else if (mclk_ps >= 750)
+               cwl = 14;
+       else if (mclk_ps >= 681)
+               cwl = 16;
+       else
+               cwl = 18;
+
+       return cwl;
+}
+#else
 /*
  * compute the CAS write latency according to DDR3 spec
  * CWL = 5 if tCK >= 2.5ns
@@ -92,10 +110,11 @@ static inline int fsl_ddr_get_rtt(void)
  *       11 if 0.935ns > tCK >= 0.833ns
  *       12 if 0.833ns > tCK >= 0.75ns
  */
-static inline unsigned int compute_cas_write_latency(void)
+static inline unsigned int compute_cas_write_latency(
+                               const unsigned int ctrl_num)
 {
        unsigned int cwl;
-       const unsigned int mclk_ps = get_memory_clk_period_ps();
+       const unsigned int mclk_ps = get_memory_clk_period_ps(ctrl_num);
 
        if (mclk_ps >= 2500)
                cwl = 5;
@@ -119,6 +138,7 @@ static inline unsigned int compute_cas_write_latency(void)
        }
        return cwl;
 }
+#endif
 
 /* Chip Select Configuration (CSn_CONFIG) */
 static void set_csn_config(int dimm_number, int i, fsl_ddr_cfg_regs_t *ddr,
@@ -135,6 +155,11 @@ static void set_csn_config(int dimm_number, int i, fsl_ddr_cfg_regs_t *ddr,
        unsigned int row_bits_cs_n = 0; /* Num of row bits for SDRAM on CSn */
        unsigned int col_bits_cs_n = 0; /* Num of ocl bits for SDRAM on CSn */
        int go_config = 0;
+#ifdef CONFIG_SYS_FSL_DDR4
+       unsigned int bg_bits_cs_n = 0; /* Num of bank group bits */
+#else
+       unsigned int n_banks_per_sdram_device;
+#endif
 
        /* Compute CS_CONFIG only for existing ranks of each DIMM.  */
        switch (i) {
@@ -145,6 +170,7 @@ static void set_csn_config(int dimm_number, int i, fsl_ddr_cfg_regs_t *ddr,
                        if (!popts->memctl_interleaving)
                                break;
                        switch (popts->memctl_interleaving_mode) {
+                       case FSL_DDR_256B_INTERLEAVING:
                        case FSL_DDR_CACHE_LINE_INTERLEAVING:
                        case FSL_DDR_PAGE_INTERLEAVING:
                        case FSL_DDR_BANK_INTERLEAVING:
@@ -177,14 +203,18 @@ static void set_csn_config(int dimm_number, int i, fsl_ddr_cfg_regs_t *ddr,
                break;
        }
        if (go_config) {
-               unsigned int n_banks_per_sdram_device;
                cs_n_en = 1;
                ap_n_en = popts->cs_local_opts[i].auto_precharge;
                odt_rd_cfg = popts->cs_local_opts[i].odt_rd_cfg;
                odt_wr_cfg = popts->cs_local_opts[i].odt_wr_cfg;
+#ifdef CONFIG_SYS_FSL_DDR4
+               ba_bits_cs_n = dimm_params[dimm_number].bank_addr_bits;
+               bg_bits_cs_n = dimm_params[dimm_number].bank_group_bits;
+#else
                n_banks_per_sdram_device
                        = dimm_params[dimm_number].n_banks_per_sdram_device;
                ba_bits_cs_n = __ilog2(n_banks_per_sdram_device) - 2;
+#endif
                row_bits_cs_n = dimm_params[dimm_number].n_row_addr - 12;
                col_bits_cs_n = dimm_params[dimm_number].n_col_addr - 8;
        }
@@ -202,6 +232,9 @@ static void set_csn_config(int dimm_number, int i, fsl_ddr_cfg_regs_t *ddr,
 
                | ((ba_bits_cs_n & 0x3) << 14)
                | ((row_bits_cs_n & 0x7) << 8)
+#ifdef CONFIG_SYS_FSL_DDR4
+               | ((bg_bits_cs_n & 0x3) << 4)
+#endif
                | ((col_bits_cs_n & 0x7) << 0)
                );
        debug("FSLDDR: cs[%d]_config = 0x%08x\n", i,ddr->cs[i].config);
@@ -220,22 +253,30 @@ static void set_csn_config_2(int i, fsl_ddr_cfg_regs_t *ddr)
 /* -3E = 667 CL5, -25 = CL6 800, -25E = CL5 800 */
 
 #if !defined(CONFIG_SYS_FSL_DDR1)
+/*
+ * Check DIMM configuration, return 2 if quad-rank or two dual-rank
+ * Return 1 if other two slots configuration. Return 0 if single slot.
+ */
 static inline int avoid_odt_overlap(const dimm_params_t *dimm_params)
 {
 #if CONFIG_DIMM_SLOTS_PER_CTLR == 1
        if (dimm_params[0].n_ranks == 4)
-               return 1;
+               return 2;
 #endif
 
 #if CONFIG_DIMM_SLOTS_PER_CTLR == 2
        if ((dimm_params[0].n_ranks == 2) &&
                (dimm_params[1].n_ranks == 2))
-               return 1;
+               return 2;
 
 #ifdef CONFIG_FSL_DDR_FIRST_SLOT_QUAD_CAPABLE
        if (dimm_params[0].n_ranks == 4)
-               return 1;
+               return 2;
 #endif
+
+       if ((dimm_params[0].n_ranks != 0) &&
+           (dimm_params[2].n_ranks != 0))
+               return 1;
 #endif
        return 0;
 }
@@ -246,7 +287,8 @@ static inline int avoid_odt_overlap(const dimm_params_t *dimm_params)
  * Avoid writing for DDR I.  The new PQ38 DDR controller
  * dreams up non-zero default values to be backwards compatible.
  */
-static void set_timing_cfg_0(fsl_ddr_cfg_regs_t *ddr,
+static void set_timing_cfg_0(const unsigned int ctrl_num,
+                               fsl_ddr_cfg_regs_t *ddr,
                                const memctl_options_t *popts,
                                const dimm_params_t *dimm_params)
 {
@@ -261,32 +303,84 @@ static void set_timing_cfg_0(fsl_ddr_cfg_regs_t *ddr,
        /* Precharge powerdown exit timing (tXP). */
        unsigned char pre_pd_exit_mclk;
        /* ODT powerdown exit timing (tAXPD). */
-       unsigned char taxpd_mclk;
+       unsigned char taxpd_mclk = 0;
        /* Mode register set cycle time (tMRD). */
        unsigned char tmrd_mclk;
+#if defined(CONFIG_SYS_FSL_DDR4) || defined(CONFIG_SYS_FSL_DDR3)
+       const unsigned int mclk_ps = get_memory_clk_period_ps(ctrl_num);
+#endif
 
-#ifdef CONFIG_SYS_FSL_DDR3
+#ifdef CONFIG_SYS_FSL_DDR4
+       /* tXP=max(4nCK, 6ns) */
+       int txp = max((int)mclk_ps * 4, 6000); /* unit=ps */
+       unsigned int data_rate = get_ddr_freq(ctrl_num);
+
+       /* for faster clock, need more time for data setup */
+       trwt_mclk = (data_rate/1000000 > 1900) ? 3 : 2;
+       twrt_mclk = 1;
+       act_pd_exit_mclk = picos_to_mclk(ctrl_num, txp);
+       pre_pd_exit_mclk = act_pd_exit_mclk;
+       /*
+        * MRS_CYC = max(tMRD, tMOD)
+        * tMRD = 8nCK, tMOD = max(24nCK, 15ns)
+        */
+       tmrd_mclk = max(24U, picos_to_mclk(ctrl_num, 15000));
+#elif defined(CONFIG_SYS_FSL_DDR3)
+       unsigned int data_rate = get_ddr_freq(ctrl_num);
+       int txp;
+       unsigned int ip_rev;
+       int odt_overlap;
        /*
         * (tXARD and tXARDS). Empirical?
         * The DDR3 spec has not tXARD,
         * we use the tXP instead of it.
-        * tXP=max(3nCK, 7.5ns) for DDR3.
+        * tXP=max(3nCK, 7.5ns) for DDR3-800, 1066
+        *     max(3nCK, 6ns) for DDR3-1333, 1600, 1866, 2133
         * spec has not the tAXPD, we use
         * tAXPD=1, need design to confirm.
         */
-       int tXP = max((get_memory_clk_period_ps() * 3), 7500); /* unit=ps */
-       unsigned int data_rate = get_ddr_freq(0);
-       tmrd_mclk = 4;
+       txp = max((int)mclk_ps * 3, (mclk_ps > 1540 ? 7500 : 6000));
+
+       ip_rev = fsl_ddr_get_version(ctrl_num);
+       if (ip_rev >= 0x40700) {
+               /*
+                * MRS_CYC = max(tMRD, tMOD)
+                * tMRD = 4nCK (8nCK for RDIMM)
+                * tMOD = max(12nCK, 15ns)
+                */
+               tmrd_mclk = max((unsigned int)12,
+                               picos_to_mclk(ctrl_num, 15000));
+       } else {
+               /*
+                * MRS_CYC = tMRD
+                * tMRD = 4nCK (8nCK for RDIMM)
+                */
+               if (popts->registered_dimm_en)
+                       tmrd_mclk = 8;
+               else
+                       tmrd_mclk = 4;
+       }
+
        /* set the turnaround time */
 
        /*
-        * for single quad-rank DIMM and two dual-rank DIMMs
+        * for single quad-rank DIMM and two-slot DIMMs
         * to avoid ODT overlap
         */
-       if (avoid_odt_overlap(dimm_params)) {
+       odt_overlap = avoid_odt_overlap(dimm_params);
+       switch (odt_overlap) {
+       case 2:
                twwt_mclk = 2;
                trrt_mclk = 1;
+               break;
+       case 1:
+               twwt_mclk = 1;
+               trrt_mclk = 0;
+               break;
+       default:
+               break;
        }
+
        /* for faster clock, need more time for data setup */
        trwt_mclk = (data_rate/1000000 > 1800) ? 2 : 1;
 
@@ -299,7 +393,7 @@ static void set_timing_cfg_0(fsl_ddr_cfg_regs_t *ddr,
                taxpd_mclk = 1;
        } else {
                /* act_pd_exit_mclk = tXARD, see above */
-               act_pd_exit_mclk = picos_to_mclk(tXP);
+               act_pd_exit_mclk = picos_to_mclk(ctrl_num, txp);
                /* Mode register MR0[A12] is '1' - fast exit */
                pre_pd_exit_mclk = act_pd_exit_mclk;
                taxpd_mclk = 1;
@@ -332,14 +426,15 @@ static void set_timing_cfg_0(fsl_ddr_cfg_regs_t *ddr,
                );
        debug("FSLDDR: timing_cfg_0 = 0x%08x\n", ddr->timing_cfg_0);
 }
-#endif /* defined(CONFIG_SYS_FSL_DDR2) */
+#endif /* !defined(CONFIG_SYS_FSL_DDR1) */
 
 /* DDR SDRAM Timing Configuration 3 (TIMING_CFG_3) */
-static void set_timing_cfg_3(fsl_ddr_cfg_regs_t *ddr,
-                              const memctl_options_t *popts,
-                              const common_timing_params_t *common_dimm,
-                              unsigned int cas_latency,
-                              unsigned int additive_latency)
+static void set_timing_cfg_3(const unsigned int ctrl_num,
+                            fsl_ddr_cfg_regs_t *ddr,
+                            const memctl_options_t *popts,
+                            const common_timing_params_t *common_dimm,
+                            unsigned int cas_latency,
+                            unsigned int additive_latency)
 {
        /* Extended precharge to activate interval (tRP) */
        unsigned int ext_pretoact = 0;
@@ -358,14 +453,18 @@ static void set_timing_cfg_3(fsl_ddr_cfg_regs_t *ddr,
        /* Control Adjust */
        unsigned int cntl_adj = 0;
 
-       ext_pretoact = picos_to_mclk(common_dimm->trp_ps) >> 4;
-       ext_acttopre = picos_to_mclk(common_dimm->tras_ps) >> 4;
-       ext_acttorw = picos_to_mclk(common_dimm->trcd_ps) >> 4;
+       ext_pretoact = picos_to_mclk(ctrl_num, common_dimm->trp_ps) >> 4;
+       ext_acttopre = picos_to_mclk(ctrl_num, common_dimm->tras_ps) >> 4;
+       ext_acttorw = picos_to_mclk(ctrl_num, common_dimm->trcd_ps) >> 4;
        ext_caslat = (2 * cas_latency - 1) >> 4;
        ext_add_lat = additive_latency >> 4;
-       ext_refrec = (picos_to_mclk(common_dimm->trfc_ps) - 8) >> 4;
+#ifdef CONFIG_SYS_FSL_DDR4
+       ext_refrec = (picos_to_mclk(ctrl_num, common_dimm->trfc1_ps) - 8) >> 4;
+#else
+       ext_refrec = (picos_to_mclk(ctrl_num, common_dimm->trfc_ps) - 8) >> 4;
        /* ext_wrrec only deals with 16 clock and above, or 14 with OTF */
-       ext_wrrec = (picos_to_mclk(common_dimm->twr_ps) +
+#endif
+       ext_wrrec = (picos_to_mclk(ctrl_num, common_dimm->twr_ps) +
                (popts->otf_burst_chop_en ? 2 : 0)) >> 4;
 
        ddr->timing_cfg_3 = (0
@@ -382,10 +481,11 @@ static void set_timing_cfg_3(fsl_ddr_cfg_regs_t *ddr,
 }
 
 /* DDR SDRAM Timing Configuration 1 (TIMING_CFG_1) */
-static void set_timing_cfg_1(fsl_ddr_cfg_regs_t *ddr,
-                              const memctl_options_t *popts,
-                              const common_timing_params_t *common_dimm,
-                              unsigned int cas_latency)
+static void set_timing_cfg_1(const unsigned int ctrl_num,
+                            fsl_ddr_cfg_regs_t *ddr,
+                            const memctl_options_t *popts,
+                            const common_timing_params_t *common_dimm,
+                            unsigned int cas_latency)
 {
        /* Precharge-to-activate interval (tRP) */
        unsigned char pretoact_mclk;
@@ -403,13 +503,23 @@ static void set_timing_cfg_1(fsl_ddr_cfg_regs_t *ddr,
        unsigned char acttoact_mclk;
        /* Last write data pair to read command issue interval (tWTR) */
        unsigned char wrtord_mclk;
+#ifdef CONFIG_SYS_FSL_DDR4
+       /* DDR4 supports 10, 12, 14, 16, 18, 20, 24 */
+       static const u8 wrrec_table[] = {
+               10, 10, 10, 10, 10,
+               10, 10, 10, 10, 10,
+               12, 12, 14, 14, 16,
+               16, 18, 18, 20, 20,
+               24, 24, 24, 24};
+#else
        /* DDR_SDRAM_MODE doesn't support 9,11,13,15 */
        static const u8 wrrec_table[] = {
                1, 2, 3, 4, 5, 6, 7, 8, 10, 10, 12, 12, 14, 14, 0, 0};
+#endif
 
-       pretoact_mclk = picos_to_mclk(common_dimm->trp_ps);
-       acttopre_mclk = picos_to_mclk(common_dimm->tras_ps);
-       acttorw_mclk = picos_to_mclk(common_dimm->trcd_ps);
+       pretoact_mclk = picos_to_mclk(ctrl_num, common_dimm->trp_ps);
+       acttopre_mclk = picos_to_mclk(ctrl_num, common_dimm->tras_ps);
+       acttorw_mclk = picos_to_mclk(ctrl_num, common_dimm->trcd_ps);
 
        /*
         * Translate CAS Latency to a DDR controller field value:
@@ -437,20 +547,34 @@ static void set_timing_cfg_1(fsl_ddr_cfg_regs_t *ddr,
         * we need set extend bit for it at
         * TIMING_CFG_3[EXT_CASLAT]
         */
-       caslat_ctrl = 2 * cas_latency - 1;
+       if (fsl_ddr_get_version(ctrl_num) <= 0x40400)
+               caslat_ctrl = 2 * cas_latency - 1;
+       else
+               caslat_ctrl = (cas_latency - 1) << 1;
 #endif
 
-       refrec_ctrl = picos_to_mclk(common_dimm->trfc_ps) - 8;
-       wrrec_mclk = picos_to_mclk(common_dimm->twr_ps);
-
-       if (wrrec_mclk > 16)
-               printf("Error: WRREC doesn't support more than 16 clocks\n");
+#ifdef CONFIG_SYS_FSL_DDR4
+       refrec_ctrl = picos_to_mclk(ctrl_num, common_dimm->trfc1_ps) - 8;
+       wrrec_mclk = picos_to_mclk(ctrl_num, common_dimm->twr_ps);
+       acttoact_mclk = max(picos_to_mclk(ctrl_num, common_dimm->trrds_ps), 4U);
+       wrtord_mclk = max(2U, picos_to_mclk(ctrl_num, 2500));
+       if ((wrrec_mclk < 1) || (wrrec_mclk > 24))
+               printf("Error: WRREC doesn't support %d clocks\n", wrrec_mclk);
        else
                wrrec_mclk = wrrec_table[wrrec_mclk - 1];
+#else
+       refrec_ctrl = picos_to_mclk(ctrl_num, common_dimm->trfc_ps) - 8;
+       wrrec_mclk = picos_to_mclk(ctrl_num, common_dimm->twr_ps);
+       acttoact_mclk = picos_to_mclk(ctrl_num, common_dimm->trrd_ps);
+       wrtord_mclk = picos_to_mclk(ctrl_num, common_dimm->twtr_ps);
+       if ((wrrec_mclk < 1) || (wrrec_mclk > 16))
+               printf("Error: WRREC doesn't support %d clocks\n", wrrec_mclk);
+       else
+               wrrec_mclk = wrrec_table[wrrec_mclk - 1];
+#endif
        if (popts->otf_burst_chop_en)
                wrrec_mclk += 2;
 
-       acttoact_mclk = picos_to_mclk(common_dimm->trrd_ps);
        /*
         * JEDEC has min requirement for tRRD
         */
@@ -458,7 +582,6 @@ static void set_timing_cfg_1(fsl_ddr_cfg_regs_t *ddr,
        if (acttoact_mclk < 4)
                acttoact_mclk = 4;
 #endif
-       wrtord_mclk = picos_to_mclk(common_dimm->twtr_ps);
        /*
         * JEDEC has some min requirements for tWTR
         */
@@ -486,11 +609,12 @@ static void set_timing_cfg_1(fsl_ddr_cfg_regs_t *ddr,
 }
 
 /* DDR SDRAM Timing Configuration 2 (TIMING_CFG_2) */
-static void set_timing_cfg_2(fsl_ddr_cfg_regs_t *ddr,
-                              const memctl_options_t *popts,
-                              const common_timing_params_t *common_dimm,
-                              unsigned int cas_latency,
-                              unsigned int additive_latency)
+static void set_timing_cfg_2(const unsigned int ctrl_num,
+                            fsl_ddr_cfg_regs_t *ddr,
+                            const memctl_options_t *popts,
+                            const common_timing_params_t *common_dimm,
+                            unsigned int cas_latency,
+                            unsigned int additive_latency)
 {
        /* Additive latency */
        unsigned char add_lat_mclk;
@@ -506,6 +630,9 @@ static void set_timing_cfg_2(fsl_ddr_cfg_regs_t *ddr,
        unsigned char cke_pls;
        /* Window for four activates (tFAW) */
        unsigned short four_act;
+#ifdef CONFIG_SYS_FSL_DDR3
+       const unsigned int mclk_ps = get_memory_clk_period_ps(ctrl_num);
+#endif
 
        /* FIXME add check that this must be less than acttorw_mclk */
        add_lat_mclk = additive_latency;
@@ -522,17 +649,21 @@ static void set_timing_cfg_2(fsl_ddr_cfg_regs_t *ddr,
 #elif defined(CONFIG_SYS_FSL_DDR2)
        wr_lat = cas_latency - 1;
 #else
-       wr_lat = compute_cas_write_latency();
+       wr_lat = compute_cas_write_latency(ctrl_num);
 #endif
 
-       rd_to_pre = picos_to_mclk(common_dimm->trtp_ps);
+#ifdef CONFIG_SYS_FSL_DDR4
+       rd_to_pre = picos_to_mclk(ctrl_num, 7500);
+#else
+       rd_to_pre = picos_to_mclk(ctrl_num, common_dimm->trtp_ps);
+#endif
        /*
         * JEDEC has some min requirements for tRTP
         */
 #if defined(CONFIG_SYS_FSL_DDR2)
        if (rd_to_pre  < 2)
                rd_to_pre  = 2;
-#elif defined(CONFIG_SYS_FSL_DDR3)
+#elif defined(CONFIG_SYS_FSL_DDR3) || defined(CONFIG_SYS_FSL_DDR4)
        if (rd_to_pre < 4)
                rd_to_pre = 4;
 #endif
@@ -540,13 +671,28 @@ static void set_timing_cfg_2(fsl_ddr_cfg_regs_t *ddr,
                rd_to_pre += 2; /* according to UM */
 
        wr_data_delay = popts->write_data_delay;
-       cke_pls = picos_to_mclk(popts->tcke_clock_pulse_width_ps);
-       four_act = picos_to_mclk(popts->tfaw_window_four_activates_ps);
+#ifdef CONFIG_SYS_FSL_DDR4
+       cpo = 0;
+       cke_pls = max(3U, picos_to_mclk(ctrl_num, 5000));
+#elif defined(CONFIG_SYS_FSL_DDR3)
+       /*
+        * cke pulse = max(3nCK, 7.5ns) for DDR3-800
+        *             max(3nCK, 5.625ns) for DDR3-1066, 1333
+        *             max(3nCK, 5ns) for DDR3-1600, 1866, 2133
+        */
+       cke_pls = max(3U, picos_to_mclk(ctrl_num, mclk_ps > 1870 ? 7500 :
+                                       (mclk_ps > 1245 ? 5625 : 5000)));
+#else
+       cke_pls = FSL_DDR_MIN_TCKE_PULSE_WIDTH_DDR;
+#endif
+       four_act = picos_to_mclk(ctrl_num,
+                                popts->tfaw_window_four_activates_ps);
 
        ddr->timing_cfg_2 = (0
                | ((add_lat_mclk & 0xf) << 28)
                | ((cpo & 0x1f) << 23)
                | ((wr_lat & 0xf) << 19)
+               | ((wr_lat & 0x10) << 14)
                | ((rd_to_pre & RD_TO_PRE_MASK) << RD_TO_PRE_SHIFT)
                | ((wr_data_delay & WR_DATA_DELAY_MASK) << WR_DATA_DELAY_SHIFT)
                | ((cke_pls & 0x7) << 6)
@@ -610,6 +756,7 @@ static void set_ddr_sdram_cfg(fsl_ddr_cfg_regs_t *ddr,
        unsigned int x32_en = 0;        /* x32 enable */
        unsigned int pchb8 = 0;         /* precharge bit 8 enable */
        unsigned int hse;               /* Global half strength override */
+       unsigned int acc_ecc_en = 0;    /* Accumulated ECC enable */
        unsigned int mem_halt = 0;      /* memory controller halt */
        unsigned int bi = 0;            /* Bypass initialization */
 
@@ -639,7 +786,8 @@ static void set_ddr_sdram_cfg(fsl_ddr_cfg_regs_t *ddr,
         * we must clear it when use the on-the-fly mode,
         * must set it when use the 32-bits bus mode.
         */
-       if (sdram_type == SDRAM_TYPE_DDR3) {
+       if ((sdram_type == SDRAM_TYPE_DDR3) ||
+           (sdram_type == SDRAM_TYPE_DDR4)) {
                if (popts->burst_length == DDR_BL8)
                        eight_be = 1;
                if (popts->burst_length == DDR_OTF)
@@ -652,6 +800,9 @@ static void set_ddr_sdram_cfg(fsl_ddr_cfg_regs_t *ddr,
        ba_intlv_ctl = popts->ba_intlv_ctl;
        hse = popts->half_strength_driver_enable;
 
+       /* set when ddr bus width < 64 */
+       acc_ecc_en = (dbw != 0 && ecc_en == 1) ? 1 : 0;
+
        ddr->ddr_sdram_cfg = (0
                        | ((mem_en & 0x1) << 31)
                        | ((sren & 0x1) << 30)
@@ -668,6 +819,7 @@ static void set_ddr_sdram_cfg(fsl_ddr_cfg_regs_t *ddr,
                        | ((x32_en & 0x1) << 5)
                        | ((pchb8 & 0x1) << 4)
                        | ((hse & 0x1) << 3)
+                       | ((acc_ecc_en & 0x1) << 2)
                        | ((mem_halt & 0x1) << 1)
                        | ((bi & 0x1) << 0)
                        );
@@ -675,14 +827,13 @@ static void set_ddr_sdram_cfg(fsl_ddr_cfg_regs_t *ddr,
 }
 
 /* DDR SDRAM control configuration 2 (DDR_SDRAM_CFG_2) */
-static void set_ddr_sdram_cfg_2(fsl_ddr_cfg_regs_t *ddr,
+static void set_ddr_sdram_cfg_2(const unsigned int ctrl_num,
+                              fsl_ddr_cfg_regs_t *ddr,
                               const memctl_options_t *popts,
                               const unsigned int unq_mrs_en)
 {
        unsigned int frc_sr = 0;        /* Force self refresh */
        unsigned int sr_ie = 0;         /* Self-refresh interrupt enable */
-       unsigned int dll_rst_dis;       /* DLL reset disable */
-       unsigned int dqs_cfg;           /* DQS configuration */
        unsigned int odt_cfg = 0;       /* ODT configuration */
        unsigned int num_pr;            /* Number of posted refreshes */
        unsigned int slow = 0;          /* DDR will be run less than 1250 */
@@ -694,9 +845,12 @@ static void set_ddr_sdram_cfg_2(fsl_ddr_cfg_regs_t *ddr,
        unsigned int md_en = 0;         /* Mirrored DIMM Enable */
        unsigned int qd_en = 0;         /* quad-rank DIMM Enable */
        int i;
+#ifndef CONFIG_SYS_FSL_DDR4
+       unsigned int dll_rst_dis = 1;   /* DLL reset disable */
+       unsigned int dqs_cfg;           /* DQS configuration */
 
-       dll_rst_dis = 1;        /* Make this configurable */
        dqs_cfg = popts->dqs_config;
+#endif
        for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
                if (popts->cs_local_opts[i].odt_rd_cfg
                        || popts->cs_local_opts[i].odt_wr_cfg) {
@@ -704,7 +858,7 @@ static void set_ddr_sdram_cfg_2(fsl_ddr_cfg_regs_t *ddr,
                        break;
                }
        }
-
+       sr_ie = popts->self_refresh_interrupt_en;
        num_pr = 1;     /* Make this configurable */
 
        /*
@@ -714,14 +868,14 @@ static void set_ddr_sdram_cfg_2(fsl_ddr_cfg_regs_t *ddr,
         *        * ({EXT_REFREC || REFREC} + 8 + 2)]}
         *      << DDR_SDRAM_INTERVAL[REFINT]
         */
-#if defined(CONFIG_SYS_FSL_DDR3)
+#if defined(CONFIG_SYS_FSL_DDR3) || defined(CONFIG_SYS_FSL_DDR4)
        obc_cfg = popts->otf_burst_chop_en;
 #else
        obc_cfg = 0;
 #endif
 
 #if (CONFIG_SYS_FSL_DDR_VER >= FSL_DDR_VER_4_7)
-       slow = get_ddr_freq(0) < 1249000000;
+       slow = get_ddr_freq(ctrl_num) < 1249000000;
 #endif
 
        if (popts->registered_dimm_en) {
@@ -743,15 +897,17 @@ static void set_ddr_sdram_cfg_2(fsl_ddr_cfg_regs_t *ddr,
        d_init = 0;
 #endif
 
-#if defined(CONFIG_SYS_FSL_DDR3)
+#if defined(CONFIG_SYS_FSL_DDR3) || defined(CONFIG_SYS_FSL_DDR4)
        md_en = popts->mirrored_dimm;
 #endif
        qd_en = popts->quad_rank_present ? 1 : 0;
        ddr->ddr_sdram_cfg_2 = (0
                | ((frc_sr & 0x1) << 31)
                | ((sr_ie & 0x1) << 30)
+#ifndef CONFIG_SYS_FSL_DDR4
                | ((dll_rst_dis & 0x1) << 29)
                | ((dqs_cfg & 0x3) << 26)
+#endif
                | ((odt_cfg & 0x3) << 21)
                | ((num_pr & 0xf) << 12)
                | ((slow & 1) << 11)
@@ -767,21 +923,109 @@ static void set_ddr_sdram_cfg_2(fsl_ddr_cfg_regs_t *ddr,
        debug("FSLDDR: ddr_sdram_cfg_2 = 0x%08x\n", ddr->ddr_sdram_cfg_2);
 }
 
+#ifdef CONFIG_SYS_FSL_DDR4
 /* DDR SDRAM Mode configuration 2 (DDR_SDRAM_MODE_2) */
-static void set_ddr_sdram_mode_2(fsl_ddr_cfg_regs_t *ddr,
+static void set_ddr_sdram_mode_2(const unsigned int ctrl_num,
+                               fsl_ddr_cfg_regs_t *ddr,
                                const memctl_options_t *popts,
                                const common_timing_params_t *common_dimm,
                                const unsigned int unq_mrs_en)
 {
        unsigned short esdmode2 = 0;    /* Extended SDRAM mode 2 */
        unsigned short esdmode3 = 0;    /* Extended SDRAM mode 3 */
+       int i;
+       unsigned int wr_crc = 0;        /* Disable */
+       unsigned int rtt_wr = 0;        /* Rtt_WR - dynamic ODT off */
+       unsigned int srt = 0;   /* self-refresh temerature, normal range */
+       unsigned int cwl = compute_cas_write_latency(ctrl_num) - 9;
+       unsigned int mpr = 0;   /* serial */
+       unsigned int wc_lat;
+       const unsigned int mclk_ps = get_memory_clk_period_ps(ctrl_num);
 
-#if defined(CONFIG_SYS_FSL_DDR3)
+       if (popts->rtt_override)
+               rtt_wr = popts->rtt_wr_override_value;
+       else
+               rtt_wr = popts->cs_local_opts[0].odt_rtt_wr;
+
+       if (common_dimm->extended_op_srt)
+               srt = common_dimm->extended_op_srt;
+
+       esdmode2 = (0
+               | ((wr_crc & 0x1) << 12)
+               | ((rtt_wr & 0x3) << 9)
+               | ((srt & 0x3) << 6)
+               | ((cwl & 0x7) << 3));
+
+       if (mclk_ps >= 1250)
+               wc_lat = 0;
+       else if (mclk_ps >= 833)
+               wc_lat = 1;
+       else
+               wc_lat = 2;
+
+       esdmode3 = (0
+               | ((mpr & 0x3) << 11)
+               | ((wc_lat & 0x3) << 9));
+
+       ddr->ddr_sdram_mode_2 = (0
+                                | ((esdmode2 & 0xFFFF) << 16)
+                                | ((esdmode3 & 0xFFFF) << 0)
+                                );
+       debug("FSLDDR: ddr_sdram_mode_2 = 0x%08x\n", ddr->ddr_sdram_mode_2);
+
+       if (unq_mrs_en) {       /* unique mode registers are supported */
+               for (i = 1; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
+                       if (popts->rtt_override)
+                               rtt_wr = popts->rtt_wr_override_value;
+                       else
+                               rtt_wr = popts->cs_local_opts[i].odt_rtt_wr;
+
+                       esdmode2 &= 0xF9FF;     /* clear bit 10, 9 */
+                       esdmode2 |= (rtt_wr & 0x3) << 9;
+                       switch (i) {
+                       case 1:
+                               ddr->ddr_sdram_mode_4 = (0
+                                       | ((esdmode2 & 0xFFFF) << 16)
+                                       | ((esdmode3 & 0xFFFF) << 0)
+                                       );
+                               break;
+                       case 2:
+                               ddr->ddr_sdram_mode_6 = (0
+                                       | ((esdmode2 & 0xFFFF) << 16)
+                                       | ((esdmode3 & 0xFFFF) << 0)
+                                       );
+                               break;
+                       case 3:
+                               ddr->ddr_sdram_mode_8 = (0
+                                       | ((esdmode2 & 0xFFFF) << 16)
+                                       | ((esdmode3 & 0xFFFF) << 0)
+                                       );
+                               break;
+                       }
+               }
+               debug("FSLDDR: ddr_sdram_mode_4 = 0x%08x\n",
+                     ddr->ddr_sdram_mode_4);
+               debug("FSLDDR: ddr_sdram_mode_6 = 0x%08x\n",
+                     ddr->ddr_sdram_mode_6);
+               debug("FSLDDR: ddr_sdram_mode_8 = 0x%08x\n",
+                     ddr->ddr_sdram_mode_8);
+       }
+}
+#elif defined(CONFIG_SYS_FSL_DDR3)
+/* DDR SDRAM Mode configuration 2 (DDR_SDRAM_MODE_2) */
+static void set_ddr_sdram_mode_2(const unsigned int ctrl_num,
+                               fsl_ddr_cfg_regs_t *ddr,
+                               const memctl_options_t *popts,
+                               const common_timing_params_t *common_dimm,
+                               const unsigned int unq_mrs_en)
+{
+       unsigned short esdmode2 = 0;    /* Extended SDRAM mode 2 */
+       unsigned short esdmode3 = 0;    /* Extended SDRAM mode 3 */
        int i;
        unsigned int rtt_wr = 0;        /* Rtt_WR - dynamic ODT off */
        unsigned int srt = 0;   /* self-refresh temerature, normal range */
        unsigned int asr = 0;   /* auto self-refresh disable */
-       unsigned int cwl = compute_cas_write_latency() - 5;
+       unsigned int cwl = compute_cas_write_latency(ctrl_num) - 5;
        unsigned int pasr = 0;  /* partial array self refresh disable */
 
        if (popts->rtt_override)
@@ -798,14 +1042,12 @@ static void set_ddr_sdram_mode_2(fsl_ddr_cfg_regs_t *ddr,
                | ((asr & 0x1) << 6)
                | ((cwl & 0x7) << 3)
                | ((pasr & 0x7) << 0));
-#endif
        ddr->ddr_sdram_mode_2 = (0
                                 | ((esdmode2 & 0xFFFF) << 16)
                                 | ((esdmode3 & 0xFFFF) << 0)
                                 );
        debug("FSLDDR: ddr_sdram_mode_2 = 0x%08x\n", ddr->ddr_sdram_mode_2);
 
-#ifdef CONFIG_SYS_FSL_DDR3
        if (unq_mrs_en) {       /* unique mode registers are supported */
                for (i = 1; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
                        if (popts->rtt_override)
@@ -843,18 +1085,156 @@ static void set_ddr_sdram_mode_2(fsl_ddr_cfg_regs_t *ddr,
                debug("FSLDDR: ddr_sdram_mode_8 = 0x%08x\n",
                        ddr->ddr_sdram_mode_8);
        }
+}
+
+#else /* for DDR2 and DDR1 */
+/* DDR SDRAM Mode configuration 2 (DDR_SDRAM_MODE_2) */
+static void set_ddr_sdram_mode_2(const unsigned int ctrl_num,
+                               fsl_ddr_cfg_regs_t *ddr,
+                               const memctl_options_t *popts,
+                               const common_timing_params_t *common_dimm,
+                               const unsigned int unq_mrs_en)
+{
+       unsigned short esdmode2 = 0;    /* Extended SDRAM mode 2 */
+       unsigned short esdmode3 = 0;    /* Extended SDRAM mode 3 */
+
+       ddr->ddr_sdram_mode_2 = (0
+                                | ((esdmode2 & 0xFFFF) << 16)
+                                | ((esdmode3 & 0xFFFF) << 0)
+                                );
+       debug("FSLDDR: ddr_sdram_mode_2 = 0x%08x\n", ddr->ddr_sdram_mode_2);
+}
 #endif
+
+#ifdef CONFIG_SYS_FSL_DDR4
+/* DDR SDRAM Mode configuration 9 (DDR_SDRAM_MODE_9) */
+static void set_ddr_sdram_mode_9(fsl_ddr_cfg_regs_t *ddr,
+                               const memctl_options_t *popts,
+                               const common_timing_params_t *common_dimm,
+                               const unsigned int unq_mrs_en)
+{
+       int i;
+       unsigned short esdmode4 = 0;    /* Extended SDRAM mode 4 */
+       unsigned short esdmode5;        /* Extended SDRAM mode 5 */
+       int rtt_park = 0;
+
+       if (ddr->cs[0].config & SDRAM_CS_CONFIG_EN) {
+               esdmode5 = 0x00000500;  /* Data mask enable, RTT_PARK CS0 */
+               rtt_park = 1;
+       } else {
+               esdmode5 = 0x00000400;  /* Data mask enabled */
+       }
+
+       ddr->ddr_sdram_mode_9 = (0
+                                | ((esdmode4 & 0xffff) << 16)
+                                | ((esdmode5 & 0xffff) << 0)
+                               );
+
+       /* only mode_9 use 0x500, others use 0x400 */
+
+       debug("FSLDDR: ddr_sdram_mode_9) = 0x%08x\n", ddr->ddr_sdram_mode_9);
+       if (unq_mrs_en) {       /* unique mode registers are supported */
+               for (i = 1; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
+                       if (!rtt_park &&
+                           (ddr->cs[i].config & SDRAM_CS_CONFIG_EN)) {
+                               esdmode5 |= 0x00000500; /* RTT_PARK */
+                               rtt_park = 1;
+                       } else {
+                               esdmode5 = 0x00000400;
+                       }
+                       switch (i) {
+                       case 1:
+                               ddr->ddr_sdram_mode_11 = (0
+                                       | ((esdmode4 & 0xFFFF) << 16)
+                                       | ((esdmode5 & 0xFFFF) << 0)
+                                       );
+                               break;
+                       case 2:
+                               ddr->ddr_sdram_mode_13 = (0
+                                       | ((esdmode4 & 0xFFFF) << 16)
+                                       | ((esdmode5 & 0xFFFF) << 0)
+                                       );
+                               break;
+                       case 3:
+                               ddr->ddr_sdram_mode_15 = (0
+                                       | ((esdmode4 & 0xFFFF) << 16)
+                                       | ((esdmode5 & 0xFFFF) << 0)
+                                       );
+                               break;
+                       }
+               }
+               debug("FSLDDR: ddr_sdram_mode_11 = 0x%08x\n",
+                     ddr->ddr_sdram_mode_11);
+               debug("FSLDDR: ddr_sdram_mode_13 = 0x%08x\n",
+                     ddr->ddr_sdram_mode_13);
+               debug("FSLDDR: ddr_sdram_mode_15 = 0x%08x\n",
+                     ddr->ddr_sdram_mode_15);
+       }
 }
 
+/* DDR SDRAM Mode configuration 10 (DDR_SDRAM_MODE_10) */
+static void set_ddr_sdram_mode_10(const unsigned int ctrl_num,
+                               fsl_ddr_cfg_regs_t *ddr,
+                               const memctl_options_t *popts,
+                               const common_timing_params_t *common_dimm,
+                               const unsigned int unq_mrs_en)
+{
+       int i;
+       unsigned short esdmode6 = 0;    /* Extended SDRAM mode 6 */
+       unsigned short esdmode7 = 0;    /* Extended SDRAM mode 7 */
+       unsigned int tccdl_min = picos_to_mclk(ctrl_num, common_dimm->tccdl_ps);
+
+       esdmode6 = ((tccdl_min - 4) & 0x7) << 10;
+
+       ddr->ddr_sdram_mode_10 = (0
+                                | ((esdmode6 & 0xffff) << 16)
+                                | ((esdmode7 & 0xffff) << 0)
+                               );
+       debug("FSLDDR: ddr_sdram_mode_10) = 0x%08x\n", ddr->ddr_sdram_mode_10);
+       if (unq_mrs_en) {       /* unique mode registers are supported */
+               for (i = 1; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
+                       switch (i) {
+                       case 1:
+                               ddr->ddr_sdram_mode_12 = (0
+                                       | ((esdmode6 & 0xFFFF) << 16)
+                                       | ((esdmode7 & 0xFFFF) << 0)
+                                       );
+                               break;
+                       case 2:
+                               ddr->ddr_sdram_mode_14 = (0
+                                       | ((esdmode6 & 0xFFFF) << 16)
+                                       | ((esdmode7 & 0xFFFF) << 0)
+                                       );
+                               break;
+                       case 3:
+                               ddr->ddr_sdram_mode_16 = (0
+                                       | ((esdmode6 & 0xFFFF) << 16)
+                                       | ((esdmode7 & 0xFFFF) << 0)
+                                       );
+                               break;
+                       }
+               }
+               debug("FSLDDR: ddr_sdram_mode_12 = 0x%08x\n",
+                     ddr->ddr_sdram_mode_12);
+               debug("FSLDDR: ddr_sdram_mode_14 = 0x%08x\n",
+                     ddr->ddr_sdram_mode_14);
+               debug("FSLDDR: ddr_sdram_mode_16 = 0x%08x\n",
+                     ddr->ddr_sdram_mode_16);
+       }
+}
+
+#endif
+
 /* DDR SDRAM Interval Configuration (DDR_SDRAM_INTERVAL) */
-static void set_ddr_sdram_interval(fsl_ddr_cfg_regs_t *ddr,
-                              const memctl_options_t *popts,
-                              const common_timing_params_t *common_dimm)
+static void set_ddr_sdram_interval(const unsigned int ctrl_num,
+                               fsl_ddr_cfg_regs_t *ddr,
+                               const memctl_options_t *popts,
+                               const common_timing_params_t *common_dimm)
 {
        unsigned int refint;    /* Refresh interval */
        unsigned int bstopre;   /* Precharge interval */
 
-       refint = picos_to_mclk(common_dimm->refresh_rate_ps);
+       refint = picos_to_mclk(ctrl_num, common_dimm->refresh_rate_ps);
 
        bstopre = popts->bstopre;
 
@@ -866,15 +1246,188 @@ static void set_ddr_sdram_interval(fsl_ddr_cfg_regs_t *ddr,
        debug("FSLDDR: ddr_sdram_interval = 0x%08x\n", ddr->ddr_sdram_interval);
 }
 
-#if defined(CONFIG_SYS_FSL_DDR3)
+#ifdef CONFIG_SYS_FSL_DDR4
+/* DDR SDRAM Mode configuration set (DDR_SDRAM_MODE) */
+static void set_ddr_sdram_mode(const unsigned int ctrl_num,
+                              fsl_ddr_cfg_regs_t *ddr,
+                              const memctl_options_t *popts,
+                              const common_timing_params_t *common_dimm,
+                              unsigned int cas_latency,
+                              unsigned int additive_latency,
+                              const unsigned int unq_mrs_en)
+{
+       int i;
+       unsigned short esdmode;         /* Extended SDRAM mode */
+       unsigned short sdmode;          /* SDRAM mode */
+
+       /* Mode Register - MR1 */
+       unsigned int qoff = 0;          /* Output buffer enable 0=yes, 1=no */
+       unsigned int tdqs_en = 0;       /* TDQS Enable: 0=no, 1=yes */
+       unsigned int rtt;
+       unsigned int wrlvl_en = 0;      /* Write level enable: 0=no, 1=yes */
+       unsigned int al = 0;            /* Posted CAS# additive latency (AL) */
+       unsigned int dic = 0;           /* Output driver impedance, 40ohm */
+       unsigned int dll_en = 1;        /* DLL Enable  1=Enable (Normal),
+                                                      0=Disable (Test/Debug) */
+
+       /* Mode Register - MR0 */
+       unsigned int wr = 0;    /* Write Recovery */
+       unsigned int dll_rst;   /* DLL Reset */
+       unsigned int mode;      /* Normal=0 or Test=1 */
+       unsigned int caslat = 4;/* CAS# latency, default set as 6 cycles */
+       /* BT: Burst Type (0=Nibble Sequential, 1=Interleaved) */
+       unsigned int bt;
+       unsigned int bl;        /* BL: Burst Length */
+
+       unsigned int wr_mclk;
+       /* DDR4 support WR 10, 12, 14, 16, 18, 20, 24 */
+       static const u8 wr_table[] = {
+               0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 6, 6};
+       /* DDR4 support CAS 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 22, 24 */
+       static const u8 cas_latency_table[] = {
+               0, 1, 2, 3, 4, 5, 6, 7, 8, 8,
+               9, 9, 10, 10, 11, 11};
+
+       if (popts->rtt_override)
+               rtt = popts->rtt_override_value;
+       else
+               rtt = popts->cs_local_opts[0].odt_rtt_norm;
+
+       if (additive_latency == (cas_latency - 1))
+               al = 1;
+       if (additive_latency == (cas_latency - 2))
+               al = 2;
+
+       if (popts->quad_rank_present)
+               dic = 1;        /* output driver impedance 240/7 ohm */
+
+       /*
+        * The esdmode value will also be used for writing
+        * MR1 during write leveling for DDR3, although the
+        * bits specifically related to the write leveling
+        * scheme will be handled automatically by the DDR
+        * controller. so we set the wrlvl_en = 0 here.
+        */
+       esdmode = (0
+               | ((qoff & 0x1) << 12)
+               | ((tdqs_en & 0x1) << 11)
+               | ((rtt & 0x7) << 8)
+               | ((wrlvl_en & 0x1) << 7)
+               | ((al & 0x3) << 3)
+               | ((dic & 0x3) << 1)   /* DIC field is split */
+               | ((dll_en & 0x1) << 0)
+               );
+
+       /*
+        * DLL control for precharge PD
+        * 0=slow exit DLL off (tXPDLL)
+        * 1=fast exit DLL on (tXP)
+        */
+
+       wr_mclk = picos_to_mclk(ctrl_num, common_dimm->twr_ps);
+       if (wr_mclk <= 24) {
+               wr = wr_table[wr_mclk - 10];
+       } else {
+               printf("Error: unsupported write recovery for mode register wr_mclk = %d\n",
+                      wr_mclk);
+       }
+
+       dll_rst = 0;    /* dll no reset */
+       mode = 0;       /* normal mode */
+
+       /* look up table to get the cas latency bits */
+       if (cas_latency >= 9 && cas_latency <= 24)
+               caslat = cas_latency_table[cas_latency - 9];
+       else
+               printf("Error: unsupported cas latency for mode register\n");
+
+       bt = 0; /* Nibble sequential */
+
+       switch (popts->burst_length) {
+       case DDR_BL8:
+               bl = 0;
+               break;
+       case DDR_OTF:
+               bl = 1;
+               break;
+       case DDR_BC4:
+               bl = 2;
+               break;
+       default:
+               printf("Error: invalid burst length of %u specified. ",
+                      popts->burst_length);
+               puts("Defaulting to on-the-fly BC4 or BL8 beats.\n");
+               bl = 1;
+               break;
+       }
+
+       sdmode = (0
+                 | ((wr & 0x7) << 9)
+                 | ((dll_rst & 0x1) << 8)
+                 | ((mode & 0x1) << 7)
+                 | (((caslat >> 1) & 0x7) << 4)
+                 | ((bt & 0x1) << 3)
+                 | ((caslat & 1) << 2)
+                 | ((bl & 0x3) << 0)
+                 );
+
+       ddr->ddr_sdram_mode = (0
+                              | ((esdmode & 0xFFFF) << 16)
+                              | ((sdmode & 0xFFFF) << 0)
+                              );
+
+       debug("FSLDDR: ddr_sdram_mode = 0x%08x\n", ddr->ddr_sdram_mode);
+
+       if (unq_mrs_en) {       /* unique mode registers are supported */
+               for (i = 1; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
+                       if (popts->rtt_override)
+                               rtt = popts->rtt_override_value;
+                       else
+                               rtt = popts->cs_local_opts[i].odt_rtt_norm;
+
+                       esdmode &= 0xF8FF;      /* clear bit 10,9,8 for rtt */
+                       esdmode |= (rtt & 0x7) << 8;
+                       switch (i) {
+                       case 1:
+                               ddr->ddr_sdram_mode_3 = (0
+                                      | ((esdmode & 0xFFFF) << 16)
+                                      | ((sdmode & 0xFFFF) << 0)
+                                      );
+                               break;
+                       case 2:
+                               ddr->ddr_sdram_mode_5 = (0
+                                      | ((esdmode & 0xFFFF) << 16)
+                                      | ((sdmode & 0xFFFF) << 0)
+                                      );
+                               break;
+                       case 3:
+                               ddr->ddr_sdram_mode_7 = (0
+                                      | ((esdmode & 0xFFFF) << 16)
+                                      | ((sdmode & 0xFFFF) << 0)
+                                      );
+                               break;
+                       }
+               }
+               debug("FSLDDR: ddr_sdram_mode_3 = 0x%08x\n",
+                     ddr->ddr_sdram_mode_3);
+               debug("FSLDDR: ddr_sdram_mode_5 = 0x%08x\n",
+                     ddr->ddr_sdram_mode_5);
+               debug("FSLDDR: ddr_sdram_mode_5 = 0x%08x\n",
+                     ddr->ddr_sdram_mode_5);
+       }
+}
+
+#elif defined(CONFIG_SYS_FSL_DDR3)
 /* DDR SDRAM Mode configuration set (DDR_SDRAM_MODE) */
-static void set_ddr_sdram_mode(fsl_ddr_cfg_regs_t *ddr,
+static void set_ddr_sdram_mode(const unsigned int ctrl_num,
+                              fsl_ddr_cfg_regs_t *ddr,
                               const memctl_options_t *popts,
                               const common_timing_params_t *common_dimm,
                               unsigned int cas_latency,
                               unsigned int additive_latency,
                               const unsigned int unq_mrs_en)
 {
+       int i;
        unsigned short esdmode;         /* Extended SDRAM mode */
        unsigned short sdmode;          /* SDRAM mode */
 
@@ -906,9 +1459,6 @@ static void set_ddr_sdram_mode(fsl_ddr_cfg_regs_t *ddr,
         */
        static const u8 wr_table[] = {1, 2, 3, 4, 5, 5, 6, 6, 7, 7, 0, 0};
 
-       const unsigned int mclk_ps = get_memory_clk_period_ps();
-       int i;
-
        if (popts->rtt_override)
                rtt = popts->rtt_override_value;
        else
@@ -949,7 +1499,7 @@ static void set_ddr_sdram_mode(fsl_ddr_cfg_regs_t *ddr,
         */
        dll_on = 1;
 
-       wr_mclk = (common_dimm->twr_ps + mclk_ps - 1) / mclk_ps;
+       wr_mclk = picos_to_mclk(ctrl_num, common_dimm->twr_ps);
        if (wr_mclk <= 16) {
                wr = wr_table[wr_mclk - 5];
        } else {
@@ -1065,7 +1615,8 @@ static void set_ddr_sdram_mode(fsl_ddr_cfg_regs_t *ddr,
 #else /* !CONFIG_SYS_FSL_DDR3 */
 
 /* DDR SDRAM Mode configuration set (DDR_SDRAM_MODE) */
-static void set_ddr_sdram_mode(fsl_ddr_cfg_regs_t *ddr,
+static void set_ddr_sdram_mode(const unsigned int ctrl_num,
+                              fsl_ddr_cfg_regs_t *ddr,
                               const memctl_options_t *popts,
                               const common_timing_params_t *common_dimm,
                               unsigned int cas_latency,
@@ -1108,9 +1659,6 @@ static void set_ddr_sdram_mode(fsl_ddr_cfg_regs_t *ddr,
        unsigned int bt;
        unsigned int bl;        /* BL: Burst Length */
 
-#if defined(CONFIG_SYS_FSL_DDR2)
-       const unsigned int mclk_ps = get_memory_clk_period_ps();
-#endif
        dqs_en = !popts->dqs_config;
        rtt = fsl_ddr_get_rtt();
 
@@ -1140,7 +1688,7 @@ static void set_ddr_sdram_mode(fsl_ddr_cfg_regs_t *ddr,
 #if defined(CONFIG_SYS_FSL_DDR1)
        wr = 0;       /* Historical */
 #elif defined(CONFIG_SYS_FSL_DDR2)
-       wr = (common_dimm->twr_ps + mclk_ps - 1) / mclk_ps - 1;
+       wr = picos_to_mclk(ctrl_num, common_dimm->twr_ps);
 #endif
        dll_res = 0;
        mode = 0;
@@ -1218,9 +1766,17 @@ static void set_ddr_sdram_clk_cntl(fsl_ddr_cfg_regs_t *ddr,
                                         const memctl_options_t *popts)
 {
        unsigned int clk_adjust;        /* Clock adjust */
+       unsigned int ss_en = 0;         /* Source synchronous enable */
 
+#if defined(CONFIG_MPC8541) || defined(CONFIG_MPC8555)
+       /* Per FSL Application Note: AN2805 */
+       ss_en = 1;
+#endif
        clk_adjust = popts->clk_adjust;
-       ddr->ddr_sdram_clk_cntl = (clk_adjust & 0xF) << 23;
+       ddr->ddr_sdram_clk_cntl = (0
+                                  | ((ss_en & 0x1) << 31)
+                                  | ((clk_adjust & 0xF) << 23)
+                                  );
        debug("FSLDDR: clk_cntl = 0x%08x\n", ddr->ddr_sdram_clk_cntl);
 }
 
@@ -1254,7 +1810,7 @@ static void set_timing_cfg_4(fsl_ddr_cfg_regs_t *ddr,
        unsigned int wwt = 0; /* Write-to-write turnaround for same CS */
        unsigned int dll_lock = 0; /* DDR SDRAM DLL Lock Time */
 
-#if defined(CONFIG_SYS_FSL_DDR3)
+#if defined(CONFIG_SYS_FSL_DDR3) || defined(CONFIG_SYS_FSL_DDR4)
        if (popts->burst_length == DDR_BL8) {
                /* We set BL/2 for fixed BL8 */
                rrt = 0;        /* BL/2 clocks */
@@ -1264,6 +1820,11 @@ static void set_timing_cfg_4(fsl_ddr_cfg_regs_t *ddr,
                rrt = 2;        /* BL/2 + 2 clocks */
                wwt = 2;        /* BL/2 + 2 clocks */
        }
+#endif
+
+#ifdef CONFIG_SYS_FSL_DDR4
+       dll_lock = 2;   /* tDLLK = 1024 clocks */
+#elif defined(CONFIG_SYS_FSL_DDR3)
        dll_lock = 1;   /* tDLLK = 512 clocks from spec */
 #endif
        ddr->timing_cfg_4 = (0
@@ -1284,9 +1845,12 @@ static void set_timing_cfg_5(fsl_ddr_cfg_regs_t *ddr, unsigned int cas_latency)
        unsigned int wodt_on = 0;       /* Write to ODT on */
        unsigned int wodt_off = 0;      /* Write to ODT off */
 
-#if defined(CONFIG_SYS_FSL_DDR3)
+#if defined(CONFIG_SYS_FSL_DDR3) || defined(CONFIG_SYS_FSL_DDR4)
+       unsigned int wr_lat = ((ddr->timing_cfg_2 & 0x00780000) >> 19) +
+                             ((ddr->timing_cfg_2 & 0x00040000) >> 14);
        /* rodt_on = timing_cfg_1[caslat] - timing_cfg_2[wrlat] + 1 */
-       rodt_on = cas_latency - ((ddr->timing_cfg_2 & 0x00780000) >> 19) + 1;
+       if (cas_latency >= wr_lat)
+               rodt_on = cas_latency - wr_lat + 1;
        rodt_off = 4;   /*  4 clocks */
        wodt_on = 1;    /*  1 clocks */
        wodt_off = 4;   /*  4 clocks */
@@ -1301,6 +1865,184 @@ static void set_timing_cfg_5(fsl_ddr_cfg_regs_t *ddr, unsigned int cas_latency)
        debug("FSLDDR: timing_cfg_5 = 0x%08x\n", ddr->timing_cfg_5);
 }
 
+#ifdef CONFIG_SYS_FSL_DDR4
+static void set_timing_cfg_6(fsl_ddr_cfg_regs_t *ddr)
+{
+       unsigned int hs_caslat = 0;
+       unsigned int hs_wrlat = 0;
+       unsigned int hs_wrrec = 0;
+       unsigned int hs_clkadj = 0;
+       unsigned int hs_wrlvl_start = 0;
+
+       ddr->timing_cfg_6 = (0
+                            | ((hs_caslat & 0x1f) << 24)
+                            | ((hs_wrlat & 0x1f) << 19)
+                            | ((hs_wrrec & 0x1f) << 12)
+                            | ((hs_clkadj & 0x1f) << 6)
+                            | ((hs_wrlvl_start & 0x1f) << 0)
+                           );
+       debug("FSLDDR: timing_cfg_6 = 0x%08x\n", ddr->timing_cfg_6);
+}
+
+static void set_timing_cfg_7(const unsigned int ctrl_num,
+                            fsl_ddr_cfg_regs_t *ddr,
+                            const common_timing_params_t *common_dimm)
+{
+       unsigned int txpr, tcksre, tcksrx;
+       unsigned int cke_rst, cksre, cksrx, par_lat, cs_to_cmd;
+
+       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;
+       cs_to_cmd = 0;
+
+       if (txpr <= 200)
+               cke_rst = 0;
+       else if (txpr <= 256)
+               cke_rst = 1;
+       else if (txpr <= 512)
+               cke_rst = 2;
+       else
+               cke_rst = 3;
+
+       if (tcksre <= 19)
+               cksre = tcksre - 5;
+       else
+               cksre = 15;
+
+       if (tcksrx <= 19)
+               cksrx = tcksrx - 5;
+       else
+               cksrx = 15;
+
+       ddr->timing_cfg_7 = (0
+                            | ((cke_rst & 0x3) << 28)
+                            | ((cksre & 0xf) << 24)
+                            | ((cksrx & 0xf) << 20)
+                            | ((par_lat & 0xf) << 16)
+                            | ((cs_to_cmd & 0xf) << 4)
+                           );
+       debug("FSLDDR: timing_cfg_7 = 0x%08x\n", ddr->timing_cfg_7);
+}
+
+static void set_timing_cfg_8(const unsigned int ctrl_num,
+                            fsl_ddr_cfg_regs_t *ddr,
+                            const memctl_options_t *popts,
+                            const common_timing_params_t *common_dimm,
+                            unsigned int cas_latency)
+{
+       unsigned int rwt_bg, wrt_bg, rrt_bg, wwt_bg;
+       unsigned int acttoact_bg, wrtord_bg, pre_all_rec;
+       unsigned int tccdl = picos_to_mclk(ctrl_num, common_dimm->tccdl_ps);
+       unsigned int wr_lat = ((ddr->timing_cfg_2 & 0x00780000) >> 19) +
+                             ((ddr->timing_cfg_2 & 0x00040000) >> 14);
+
+       rwt_bg = cas_latency + 2 + 4 - wr_lat;
+       if (rwt_bg < tccdl)
+               rwt_bg = tccdl - rwt_bg;
+       else
+               rwt_bg = 0;
+
+       wrt_bg = wr_lat + 4 + 1 - cas_latency;
+       if (wrt_bg < tccdl)
+               wrt_bg = tccdl - wrt_bg;
+       else
+               wrt_bg = 0;
+
+       if (popts->burst_length == DDR_BL8) {
+               rrt_bg = tccdl - 4;
+               wwt_bg = tccdl - 4;
+       } else {
+               rrt_bg = tccdl - 2;
+               wwt_bg = tccdl - 2;
+       }
+
+       acttoact_bg = picos_to_mclk(ctrl_num, common_dimm->trrdl_ps);
+       wrtord_bg = max(4U, picos_to_mclk(ctrl_num, 7500));
+       if (popts->otf_burst_chop_en)
+               wrtord_bg += 2;
+
+       pre_all_rec = 0;
+
+       ddr->timing_cfg_8 = (0
+                            | ((rwt_bg & 0xf) << 28)
+                            | ((wrt_bg & 0xf) << 24)
+                            | ((rrt_bg & 0xf) << 20)
+                            | ((wwt_bg & 0xf) << 16)
+                            | ((acttoact_bg & 0xf) << 12)
+                            | ((wrtord_bg & 0xf) << 8)
+                            | ((pre_all_rec & 0x1f) << 0)
+                           );
+
+       debug("FSLDDR: timing_cfg_8 = 0x%08x\n", ddr->timing_cfg_8);
+}
+
+static void set_timing_cfg_9(fsl_ddr_cfg_regs_t *ddr)
+{
+       ddr->timing_cfg_9 = 0;
+       debug("FSLDDR: timing_cfg_9 = 0x%08x\n", ddr->timing_cfg_9);
+}
+
+/* This function needs to be called after set_ddr_sdram_cfg() is called */
+static void set_ddr_dq_mapping(fsl_ddr_cfg_regs_t *ddr,
+                              const dimm_params_t *dimm_params)
+{
+       unsigned int acc_ecc_en = (ddr->ddr_sdram_cfg >> 2) & 0x1;
+       int i;
+
+       for (i = 0; i < CONFIG_DIMM_SLOTS_PER_CTLR; i++) {
+               if (dimm_params[i].n_ranks)
+                       break;
+       }
+       if (i >= CONFIG_DIMM_SLOTS_PER_CTLR) {
+               puts("DDR error: no DIMM found!\n");
+               return;
+       }
+
+       ddr->dq_map_0 = ((dimm_params[i].dq_mapping[0] & 0x3F) << 26) |
+                       ((dimm_params[i].dq_mapping[1] & 0x3F) << 20) |
+                       ((dimm_params[i].dq_mapping[2] & 0x3F) << 14) |
+                       ((dimm_params[i].dq_mapping[3] & 0x3F) << 8) |
+                       ((dimm_params[i].dq_mapping[4] & 0x3F) << 2);
+
+       ddr->dq_map_1 = ((dimm_params[i].dq_mapping[5] & 0x3F) << 26) |
+                       ((dimm_params[i].dq_mapping[6] & 0x3F) << 20) |
+                       ((dimm_params[i].dq_mapping[7] & 0x3F) << 14) |
+                       ((dimm_params[i].dq_mapping[10] & 0x3F) << 8) |
+                       ((dimm_params[i].dq_mapping[11] & 0x3F) << 2);
+
+       ddr->dq_map_2 = ((dimm_params[i].dq_mapping[12] & 0x3F) << 26) |
+                       ((dimm_params[i].dq_mapping[13] & 0x3F) << 20) |
+                       ((dimm_params[i].dq_mapping[14] & 0x3F) << 14) |
+                       ((dimm_params[i].dq_mapping[15] & 0x3F) << 8) |
+                       ((dimm_params[i].dq_mapping[16] & 0x3F) << 2);
+
+       /* dq_map for ECC[4:7] is set to 0 if accumulated ECC is enabled */
+       ddr->dq_map_3 = ((dimm_params[i].dq_mapping[17] & 0x3F) << 26) |
+                       ((dimm_params[i].dq_mapping[8] & 0x3F) << 20) |
+                       (acc_ecc_en ? 0 :
+                        (dimm_params[i].dq_mapping[9] & 0x3F) << 14) |
+                       dimm_params[i].dq_mapping_ors;
+
+       debug("FSLDDR: dq_map_0 = 0x%08x\n", ddr->dq_map_0);
+       debug("FSLDDR: dq_map_1 = 0x%08x\n", ddr->dq_map_1);
+       debug("FSLDDR: dq_map_2 = 0x%08x\n", ddr->dq_map_2);
+       debug("FSLDDR: dq_map_3 = 0x%08x\n", ddr->dq_map_3);
+}
+static void set_ddr_sdram_cfg_3(fsl_ddr_cfg_regs_t *ddr,
+                              const memctl_options_t *popts)
+{
+       int rd_pre;
+
+       rd_pre = popts->quad_rank_present ? 1 : 0;
+
+       ddr->ddr_sdram_cfg_3 = (rd_pre & 0x1) << 16;
+
+       debug("FSLDDR: ddr_sdram_cfg_3 = 0x%08x\n", ddr->ddr_sdram_cfg_3);
+}
+#endif /* CONFIG_SYS_FSL_DDR4 */
+
 /* DDR ZQ Calibration Control (DDR_ZQ_CNTL) */
 static void set_ddr_zq_cntl(fsl_ddr_cfg_regs_t *ddr, unsigned int zq_en)
 {
@@ -1309,11 +2051,21 @@ static void set_ddr_zq_cntl(fsl_ddr_cfg_regs_t *ddr, unsigned int zq_en)
        unsigned int zqoper = 0;
        /* Normal Operation Short Calibration Time (tZQCS) */
        unsigned int zqcs = 0;
+#ifdef CONFIG_SYS_FSL_DDR4
+       unsigned int zqcs_init;
+#endif
 
        if (zq_en) {
+#ifdef CONFIG_SYS_FSL_DDR4
+               zqinit = 10;    /* 1024 clocks */
+               zqoper = 9;     /* 512 clocks */
+               zqcs = 7;       /* 128 clocks */
+               zqcs_init = 5;  /* 1024 refresh sequences */
+#else
                zqinit = 9;     /* 512 clocks */
                zqoper = 8;     /* 256 clocks */
                zqcs = 6;       /* 64 clocks */
+#endif
        }
 
        ddr->ddr_zq_cntl = (0
@@ -1321,6 +2073,9 @@ static void set_ddr_zq_cntl(fsl_ddr_cfg_regs_t *ddr, unsigned int zq_en)
                            | ((zqinit & 0xF) << 24)
                            | ((zqoper & 0xF) << 16)
                            | ((zqcs & 0xF) << 8)
+#ifdef CONFIG_SYS_FSL_DDR4
+                           | ((zqcs_init & 0xF) << 0)
+#endif
                            );
        debug("FSLDDR: zq_cntl = 0x%08x\n", ddr->ddr_zq_cntl);
 }
@@ -1446,7 +2201,8 @@ check_fsl_memctl_config_regs(const fsl_ddr_cfg_regs_t *ddr)
 }
 
 unsigned int
-compute_fsl_memctl_config_regs(const memctl_options_t *popts,
+compute_fsl_memctl_config_regs(const unsigned int ctrl_num,
+                              const memctl_options_t *popts,
                               fsl_ddr_cfg_regs_t *ddr,
                               const common_timing_params_t *common_dimm,
                               const dimm_params_t *dimm_params,
@@ -1477,7 +2233,7 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts,
         */
        cas_latency = (popts->cas_latency_override)
                ? popts->cas_latency_override_value
-               : common_dimm->lowest_common_SPD_caslat;
+               : common_dimm->lowest_common_spd_caslat;
 
        additive_latency = (popts->additive_latency_override)
                ? popts->additive_latency_override_value
@@ -1618,33 +2374,48 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts,
        set_ddr_eor(ddr, popts);
 
 #if !defined(CONFIG_SYS_FSL_DDR1)
-       set_timing_cfg_0(ddr, popts, dimm_params);
+       set_timing_cfg_0(ctrl_num, ddr, popts, dimm_params);
 #endif
 
-       set_timing_cfg_3(ddr, popts, common_dimm, cas_latency,
+       set_timing_cfg_3(ctrl_num, ddr, popts, common_dimm, cas_latency,
                         additive_latency);
-       set_timing_cfg_1(ddr, popts, common_dimm, cas_latency);
-       set_timing_cfg_2(ddr, popts, common_dimm,
-                               cas_latency, additive_latency);
+       set_timing_cfg_1(ctrl_num, ddr, popts, common_dimm, cas_latency);
+       set_timing_cfg_2(ctrl_num, ddr, popts, common_dimm,
+                        cas_latency, additive_latency);
 
        set_ddr_cdr1(ddr, popts);
        set_ddr_cdr2(ddr, popts);
        set_ddr_sdram_cfg(ddr, popts, common_dimm);
-       ip_rev = fsl_ddr_get_version();
+       ip_rev = fsl_ddr_get_version(ctrl_num);
        if (ip_rev > 0x40400)
                unq_mrs_en = 1;
 
-       set_ddr_sdram_cfg_2(ddr, popts, unq_mrs_en);
-       set_ddr_sdram_mode(ddr, popts, common_dimm,
-                               cas_latency, additive_latency, unq_mrs_en);
-       set_ddr_sdram_mode_2(ddr, popts, common_dimm, unq_mrs_en);
-       set_ddr_sdram_interval(ddr, popts, common_dimm);
+       if ((ip_rev > 0x40700) && (popts->cswl_override != 0))
+               ddr->debug[18] = popts->cswl_override;
+
+       set_ddr_sdram_cfg_2(ctrl_num, ddr, popts, unq_mrs_en);
+       set_ddr_sdram_mode(ctrl_num, ddr, popts, common_dimm,
+                          cas_latency, additive_latency, unq_mrs_en);
+       set_ddr_sdram_mode_2(ctrl_num, ddr, popts, common_dimm, unq_mrs_en);
+#ifdef CONFIG_SYS_FSL_DDR4
+       set_ddr_sdram_mode_9(ddr, popts, common_dimm, unq_mrs_en);
+       set_ddr_sdram_mode_10(ctrl_num, ddr, popts, common_dimm, unq_mrs_en);
+#endif
+       set_ddr_sdram_interval(ctrl_num, ddr, popts, common_dimm);
        set_ddr_data_init(ddr);
        set_ddr_sdram_clk_cntl(ddr, popts);
        set_ddr_init_addr(ddr);
        set_ddr_init_ext_addr(ddr);
        set_timing_cfg_4(ddr, popts);
        set_timing_cfg_5(ddr, cas_latency);
+#ifdef CONFIG_SYS_FSL_DDR4
+       set_ddr_sdram_cfg_3(ddr, popts);
+       set_timing_cfg_6(ddr);
+       set_timing_cfg_7(ctrl_num, ddr, common_dimm);
+       set_timing_cfg_8(ctrl_num, ddr, popts, common_dimm, cas_latency);
+       set_timing_cfg_9(ddr);
+       set_ddr_dq_mapping(ddr, dimm_params);
+#endif
 
        set_ddr_zq_cntl(ddr, zq_en);
        set_ddr_wrlvl_cntl(ddr, wrlvl_en, popts);
@@ -1656,7 +2427,16 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts,
 #ifdef CONFIG_SYS_FSL_DDR_EMU
        /* disble DDR training for emulator */
        ddr->debug[2] = 0x00000400;
-       ddr->debug[4] = 0xff800000;
+       ddr->debug[4] = 0xff800800;
+       ddr->debug[5] = 0x08000800;
+       ddr->debug[6] = 0x08000800;
+       ddr->debug[7] = 0x08000800;
+       ddr->debug[8] = 0x08000800;
+#endif
+#ifdef CONFIG_SYS_FSL_ERRATUM_A004508
+       if ((ip_rev >= 0x40000) && (ip_rev < 0x40400))
+               ddr->debug[2] |= 0x00000200;    /* set bit 22 */
 #endif
+
        return check_fsl_memctl_config_regs(ddr);
 }