mpc85xx: Enable unique mode registers and dynamic ODT for DDR3
authorYork Sun <yorksun@freescale.com>
Mon, 10 Jan 2011 12:03:00 +0000 (12:03 +0000)
committerKumar Gala <galak@kernel.crashing.org>
Thu, 20 Jan 2011 04:58:23 +0000 (22:58 -0600)
Added fsl_ddr_get_version() function to for DDR3 to poll DDRC IP version
(major, minor, errata) to determine if unique mode registers are available.
If true, always use unique mode registers. Dynamic ODT is enabled if needed.
The table is documented in doc/README.fsl-ddr. This function may also need
to be extend for future other platforms if such a feature exists.

Enable address parity and RCW by default for RDIMMs.

Change default output driver impedance from 34 ohm to 40ohm. Make it 34ohm for
quad-rank RDIMMs.

Use a formula to calculate rodt_on for timing_cfg_5.

Signed-off-by: York Sun <yorksun@freescale.com>
Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
arch/powerpc/cpu/mpc85xx/ddr-gen3.c
arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c
arch/powerpc/cpu/mpc8xxx/ddr/options.c
arch/powerpc/include/asm/fsl_ddr_sdram.h
doc/README.fsl-ddr

index 4e768d39ba6371e5ae0a1ff36b940a4702c33d1e..9bc36f3211b0f5dd4430637c3373c52835c496ff 100644 (file)
@@ -66,6 +66,12 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
        out_be32(&ddr->sdram_cfg_2, regs->ddr_sdram_cfg_2);
        out_be32(&ddr->sdram_mode, regs->ddr_sdram_mode);
        out_be32(&ddr->sdram_mode_2, regs->ddr_sdram_mode_2);
+       out_be32(&ddr->sdram_mode_3, regs->ddr_sdram_mode_3);
+       out_be32(&ddr->sdram_mode_4, regs->ddr_sdram_mode_4);
+       out_be32(&ddr->sdram_mode_5, regs->ddr_sdram_mode_5);
+       out_be32(&ddr->sdram_mode_6, regs->ddr_sdram_mode_6);
+       out_be32(&ddr->sdram_mode_7, regs->ddr_sdram_mode_7);
+       out_be32(&ddr->sdram_mode_8, regs->ddr_sdram_mode_8);
        out_be32(&ddr->sdram_md_cntl, regs->ddr_sdram_md_cntl);
        out_be32(&ddr->sdram_interval, regs->ddr_sdram_interval);
        out_be32(&ddr->sdram_data_init, regs->ddr_data_init);
index 8fdafdb906a2c931217119d1f7d1977e186af6b9..2271071ad260aa3e7dcc006a805ce75e62f7ad35 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008-2010 Freescale Semiconductor, Inc.
+ * Copyright 2008-2011 Freescale Semiconductor, Inc.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
 
 #include "ddr.h"
 
-extern unsigned int picos_to_mclk(unsigned int picos);
+#ifdef CONFIG_MPC85xx
+       #define _DDR_ADDR CONFIG_SYS_MPC85xx_DDR_ADDR
+#elif defined(CONFIG_MPC86xx)
+       #define _DDR_ADDR CONFIG_SYS_MPC86xx_DDR_ADDR
+#else
+       #error "Undefined _DDR_ADDR"
+#endif
+
+u32 fsl_ddr_get_version(void)
+{
+       ccsr_ddr_t *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.
  *
@@ -187,7 +208,8 @@ static void set_csn_config_2(int i, fsl_ddr_cfg_regs_t *ddr)
  * 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(fsl_ddr_cfg_regs_t *ddr,
+                               const memctl_options_t *popts)
 {
        unsigned char trwt_mclk = 0;   /* Read-to-write turnaround */
        unsigned char twrt_mclk = 0;   /* Write-to-read turnaround */
@@ -204,7 +226,7 @@ static void set_timing_cfg_0(fsl_ddr_cfg_regs_t *ddr)
        /* Mode register set cycle time (tMRD). */
        unsigned char tmrd_mclk;
 
-#if defined(CONFIG_FSL_DDR3)
+#ifdef CONFIG_FSL_DDR3
        /*
         * (tXARD and tXARDS). Empirical?
         * The DDR3 spec has not tXARD,
@@ -214,13 +236,21 @@ static void set_timing_cfg_0(fsl_ddr_cfg_regs_t *ddr)
         * tAXPD=1, need design to confirm.
         */
        int tXP = max((get_memory_clk_period_ps() * 3), 7500); /* unit=ps */
-       act_pd_exit_mclk = picos_to_mclk(tXP);
-       /* Mode register MR0[A12] is '1' - fast exit */
-       pre_pd_exit_mclk = act_pd_exit_mclk;
-       taxpd_mclk = 1;
        tmrd_mclk = 4;
        /* set the turnaround time */
        trwt_mclk = 1;
+
+       if (popts->dynamic_power == 0) {        /* powerdown is not used */
+               act_pd_exit_mclk = 1;
+               pre_pd_exit_mclk = 1;
+               taxpd_mclk = 1;
+       } else {
+               /* act_pd_exit_mclk = tXARD, see above */
+               act_pd_exit_mclk = picos_to_mclk(tXP);
+               /* Mode register MR0[A12] is '1' - fast exit */
+               pre_pd_exit_mclk = act_pd_exit_mclk;
+               taxpd_mclk = 1;
+       }
 #else /* CONFIG_FSL_DDR2 */
        /*
         * (tXARD and tXARDS). Empirical?
@@ -450,28 +480,34 @@ static void set_timing_cfg_2(fsl_ddr_cfg_regs_t *ddr,
 
 /* DDR SDRAM Register Control Word */
 static void set_ddr_sdram_rcw(fsl_ddr_cfg_regs_t *ddr,
+                              const memctl_options_t *popts,
                               const common_timing_params_t *common_dimm)
 {
        if (common_dimm->all_DIMMs_registered
                && !common_dimm->all_DIMMs_unbuffered) {
-               ddr->ddr_sdram_rcw_1 =
-                       common_dimm->rcw[0] << 28 | \
-                       common_dimm->rcw[1] << 24 | \
-                       common_dimm->rcw[2] << 20 | \
-                       common_dimm->rcw[3] << 16 | \
-                       common_dimm->rcw[4] << 12 | \
-                       common_dimm->rcw[5] << 8 | \
-                       common_dimm->rcw[6] << 4 | \
-                       common_dimm->rcw[7];
-               ddr->ddr_sdram_rcw_2 =
-                       common_dimm->rcw[8] << 28 | \
-                       common_dimm->rcw[9] << 24 | \
-                       common_dimm->rcw[10] << 20 | \
-                       common_dimm->rcw[11] << 16 | \
-                       common_dimm->rcw[12] << 12 | \
-                       common_dimm->rcw[13] << 8 | \
-                       common_dimm->rcw[14] << 4 | \
-                       common_dimm->rcw[15];
+               if (popts->rcw_override) {
+                       ddr->ddr_sdram_rcw_1 = popts->rcw_1;
+                       ddr->ddr_sdram_rcw_2 = popts->rcw_2;
+               } else {
+                       ddr->ddr_sdram_rcw_1 =
+                               common_dimm->rcw[0] << 28 | \
+                               common_dimm->rcw[1] << 24 | \
+                               common_dimm->rcw[2] << 20 | \
+                               common_dimm->rcw[3] << 16 | \
+                               common_dimm->rcw[4] << 12 | \
+                               common_dimm->rcw[5] << 8 | \
+                               common_dimm->rcw[6] << 4 | \
+                               common_dimm->rcw[7];
+                       ddr->ddr_sdram_rcw_2 =
+                               common_dimm->rcw[8] << 28 | \
+                               common_dimm->rcw[9] << 24 | \
+                               common_dimm->rcw[10] << 20 | \
+                               common_dimm->rcw[11] << 16 | \
+                               common_dimm->rcw[12] << 12 | \
+                               common_dimm->rcw[13] << 8 | \
+                               common_dimm->rcw[14] << 4 | \
+                               common_dimm->rcw[15];
+               }
                debug("FSLDDR: ddr_sdram_rcw_1 = 0x%08x\n", ddr->ddr_sdram_rcw_1);
                debug("FSLDDR: ddr_sdram_rcw_2 = 0x%08x\n", ddr->ddr_sdram_rcw_2);
        }
@@ -509,8 +545,14 @@ static void set_ddr_sdram_cfg(fsl_ddr_cfg_regs_t *ddr,
                ecc_en = 0;
        }
 
-       rd_en = (common_dimm->all_DIMMs_registered
-                && !common_dimm->all_DIMMs_unbuffered);
+       if (common_dimm->all_DIMMs_registered
+               && !common_dimm->all_DIMMs_unbuffered) {
+               rd_en = 1;
+               twoT_en = 0;
+       } else {
+               rd_en = 0;
+               twoT_en = popts->twoT_en;
+       }
 
        sdram_type = CONFIG_FSL_SDRAM_TYPE;
 
@@ -530,7 +572,6 @@ static void set_ddr_sdram_cfg(fsl_ddr_cfg_regs_t *ddr,
        }
 
        threeT_en = popts->threeT_en;
-       twoT_en = popts->twoT_en;
        ba_intlv_ctl = popts->ba_intlv_ctl;
        hse = popts->half_strength_driver_enable;
 
@@ -558,7 +599,8 @@ 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,
-                              const memctl_options_t *popts)
+                              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 */
@@ -598,11 +640,17 @@ static void set_ddr_sdram_cfg_2(fsl_ddr_cfg_regs_t *ddr,
        obc_cfg = 0;
 #endif
 
-       ap_en = 0;      /* Make this configurable? */
+       if (popts->registered_dimm_en) {
+               rcw_en = 1;
+               ap_en = popts->ap_en;
+       } else {
+               rcw_en = 0;
+               ap_en = 0;
+       }
 
 #if defined(CONFIG_ECC_INIT_VIA_DDRCONTROLLER)
        /* Use the DDR controller to auto initialize memory. */
-       d_init = 1;
+       d_init = popts->ECC_init_using_memctl;
        ddr->ddr_data_init = CONFIG_MEM_INIT_VALUE;
        debug("DDR: ddr_data_init = 0x%08x\n", ddr->ddr_data_init);
 #else
@@ -613,7 +661,6 @@ static void set_ddr_sdram_cfg_2(fsl_ddr_cfg_regs_t *ddr,
 #if defined(CONFIG_FSL_DDR3)
        md_en = popts->mirrored_dimm;
 #endif
-       rcw_en = popts->registered_dimm_en;
        qd_en = popts->quad_rank_present ? 1 : 0;
        ddr->ddr_sdram_cfg_2 = (0
                | ((frc_sr & 0x1) << 31)
@@ -623,6 +670,7 @@ static void set_ddr_sdram_cfg_2(fsl_ddr_cfg_regs_t *ddr,
                | ((odt_cfg & 0x3) << 21)
                | ((num_pr & 0xf) << 12)
                | (qd_en << 9)
+               | (unq_mrs_en << 8)
                | ((obc_cfg & 0x1) << 6)
                | ((ap_en & 0x1) << 5)
                | ((d_init & 0x1) << 4)
@@ -634,10 +682,12 @@ static void set_ddr_sdram_cfg_2(fsl_ddr_cfg_regs_t *ddr,
 
 /* DDR SDRAM Mode configuration 2 (DDR_SDRAM_MODE_2) */
 static void set_ddr_sdram_mode_2(fsl_ddr_cfg_regs_t *ddr,
-                               const memctl_options_t *popts)
+                               const memctl_options_t *popts,
+                               const unsigned int unq_mrs_en)
 {
        unsigned short esdmode2 = 0;    /* Extended SDRAM mode 2 */
        unsigned short esdmode3 = 0;    /* Extended SDRAM mode 3 */
+       int i;
 
 #if defined(CONFIG_FSL_DDR3)
        unsigned int rtt_wr = 0;        /* Rtt_WR - dynamic ODT off */
@@ -648,7 +698,8 @@ static void set_ddr_sdram_mode_2(fsl_ddr_cfg_regs_t *ddr,
 
        if (popts->rtt_override)
                rtt_wr = popts->rtt_wr_override_value;
-
+       else
+               rtt_wr = popts->cs_local_opts[0].odt_rtt_wr;
        esdmode2 = (0
                | ((rtt_wr & 0x3) << 9)
                | ((srt & 0x1) << 7)
@@ -661,6 +712,46 @@ static void set_ddr_sdram_mode_2(fsl_ddr_cfg_regs_t *ddr,
                                 | ((esdmode3 & 0xFFFF) << 0)
                                 );
        debug("FSLDDR: ddr_sdram_mode_2 = 0x%08x\n", ddr->ddr_sdram_mode_2);
+
+#ifdef CONFIG_FSL_DDR3
+       if (unq_mrs_en) {       /* unique mode registers are supported */
+               for (i = 1; i < 4; 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);
+       }
+#endif
 }
 
 /* DDR SDRAM Interval Configuration (DDR_SDRAM_INTERVAL) */
@@ -689,7 +780,8 @@ static void set_ddr_sdram_mode(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)
+                              unsigned int additive_latency,
+                              const unsigned int unq_mrs_en)
 {
        unsigned short esdmode;         /* Extended SDRAM mode */
        unsigned short sdmode;          /* SDRAM mode */
@@ -700,7 +792,7 @@ static void set_ddr_sdram_mode(fsl_ddr_cfg_regs_t *ddr,
        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 = 1;           /* Output driver impedance, 34ohm */
+       unsigned int dic = 0;           /* Output driver impedance, 40ohm */
        unsigned int dll_en = 0;        /* DLL Enable  0=Enable (Normal),
                                                       1=Disable (Test/Debug) */
 
@@ -717,16 +809,21 @@ static void set_ddr_sdram_mode(fsl_ddr_cfg_regs_t *ddr,
        unsigned int wr_mclk;
 
        const unsigned int mclk_ps = get_memory_clk_period_ps();
+       int i;
 
-       rtt = fsl_ddr_get_rtt();
        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
@@ -812,6 +909,48 @@ static void set_ddr_sdram_mode(fsl_ddr_cfg_regs_t *ddr,
                               );
 
        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 < 4; i++) {
+                       if (popts->rtt_override)
+                               rtt = popts->rtt_override_value;
+                       else
+                               rtt = popts->cs_local_opts[i].odt_rtt_norm;
+
+                       esdmode &= 0xFDBB;      /* clear bit 9,6,2 */
+                       esdmode |= (0
+                               | ((rtt & 0x4) << 7)   /* rtt field is split */
+                               | ((rtt & 0x2) << 5)   /* rtt field is split */
+                               | ((rtt & 0x1) << 2)  /* rtt field is split */
+                               );
+                       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);
+       }
 }
 
 #else /* !CONFIG_FSL_DDR3 */
@@ -821,7 +960,8 @@ static void set_ddr_sdram_mode(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)
+                              unsigned int additive_latency,
+                              const unsigned int unq_mrs_en)
 {
        unsigned short esdmode;         /* Extended SDRAM mode */
        unsigned short sdmode;          /* SDRAM mode */
@@ -1024,7 +1164,7 @@ static void set_timing_cfg_4(fsl_ddr_cfg_regs_t *ddr,
 }
 
 /* DDR SDRAM Timing Configuration 5 (TIMING_CFG_5) */
-static void set_timing_cfg_5(fsl_ddr_cfg_regs_t *ddr)
+static void set_timing_cfg_5(fsl_ddr_cfg_regs_t *ddr, unsigned int cas_latency)
 {
        unsigned int rodt_on = 0;       /* Read to ODT on */
        unsigned int rodt_off = 0;      /* Read to ODT off */
@@ -1032,7 +1172,8 @@ static void set_timing_cfg_5(fsl_ddr_cfg_regs_t *ddr)
        unsigned int wodt_off = 0;      /* Write to ODT off */
 
 #if defined(CONFIG_FSL_DDR3)
-       rodt_on = 2;    /*  2 clocks */
+       /* rodt_on = timing_cfg_1[caslat] - timing_cfg_2[wrlat] + 1 */
+       rodt_on = cas_latency - ((ddr->timing_cfg_2 & 0x00780000) >> 19) + 1;
        rodt_off = 4;   /*  4 clocks */
        wodt_on = 1;    /*  1 clocks */
        wodt_off = 4;   /*  4 clocks */
@@ -1068,6 +1209,7 @@ static void set_ddr_zq_cntl(fsl_ddr_cfg_regs_t *ddr, unsigned int zq_en)
                            | ((zqoper & 0xF) << 16)
                            | ((zqcs & 0xF) << 8)
                            );
+       debug("FSLDDR: zq_cntl = 0x%08x\n", ddr->ddr_zq_cntl);
 }
 
 /* DDR Write Leveling Control (DDR_WRLVL_CNTL) */
@@ -1113,7 +1255,8 @@ static void set_ddr_wrlvl_cntl(fsl_ddr_cfg_regs_t *ddr, unsigned int wrlvl_en,
                /*
                 * Write leveling start time
                 * The value use for the DQS_ADJUST for the first sample
-                * when write leveling is enabled.
+                * when write leveling is enabled. It probably needs to be
+                * overriden per platform.
                 */
                wrlvl_start = 0x8;
                /*
@@ -1135,6 +1278,7 @@ static void set_ddr_wrlvl_cntl(fsl_ddr_cfg_regs_t *ddr, unsigned int wrlvl_en,
                               | ((wrlvl_wlr & 0x7) << 8)
                               | ((wrlvl_start & 0x1F) << 0)
                               );
+       debug("FSLDDR: wrlvl_cntl = 0x%08x\n", ddr->ddr_wrlvl_cntl);
 }
 
 /* DDR Self Refresh Counter (DDR_SR_CNTR) */
@@ -1152,6 +1296,12 @@ static void set_ddr_eor(fsl_ddr_cfg_regs_t *ddr, const memctl_options_t *popts)
        }
 }
 
+static void set_ddr_cdr1(fsl_ddr_cfg_regs_t *ddr, const memctl_options_t *popts)
+{
+       ddr->ddr_cdr1 = popts->ddr_cdr1;
+       debug("FSLDDR: ddr_cdr1 = 0x%08x\n", ddr->ddr_cdr1);
+}
+
 unsigned int
 check_fsl_memctl_config_regs(const fsl_ddr_cfg_regs_t *ddr)
 {
@@ -1185,6 +1335,8 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts,
        unsigned int sr_it;
        unsigned int zq_en;
        unsigned int wrlvl_en;
+       unsigned int ip_rev = 0;
+       unsigned int unq_mrs_en = 0;
        int cs_en = 1;
 
        memset(ddr, 0, sizeof(fsl_ddr_cfg_regs_t));
@@ -1405,7 +1557,7 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts,
        set_ddr_eor(ddr, popts);
 
 #if !defined(CONFIG_FSL_DDR1)
-       set_timing_cfg_0(ddr);
+       set_timing_cfg_0(ddr, popts);
 #endif
 
        set_timing_cfg_3(ddr, common_dimm, cas_latency);
@@ -1413,26 +1565,30 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts,
        set_timing_cfg_2(ddr, popts, common_dimm,
                                cas_latency, additive_latency);
 
+       set_ddr_cdr1(ddr, popts);
        set_ddr_sdram_cfg(ddr, popts, common_dimm);
+       ip_rev = fsl_ddr_get_version();
+       if (ip_rev > 0x40400)
+               unq_mrs_en = 1;
 
-       set_ddr_sdram_cfg_2(ddr, popts);
+       set_ddr_sdram_cfg_2(ddr, popts, unq_mrs_en);
        set_ddr_sdram_mode(ddr, popts, common_dimm,
-                               cas_latency, additive_latency);
-       set_ddr_sdram_mode_2(ddr, popts);
+                               cas_latency, additive_latency, unq_mrs_en);
+       set_ddr_sdram_mode_2(ddr, popts, unq_mrs_en);
        set_ddr_sdram_interval(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);
+       set_timing_cfg_5(ddr, cas_latency);
 
        set_ddr_zq_cntl(ddr, zq_en);
        set_ddr_wrlvl_cntl(ddr, wrlvl_en, popts);
 
        set_ddr_sr_cntr(ddr, sr_it);
 
-       set_ddr_sdram_rcw(ddr, common_dimm);
+       set_ddr_sdram_rcw(ddr, popts, common_dimm);
 
        return check_fsl_memctl_config_regs(ddr);
 }
index 55dff43947b16f538f04719d25f45b6cbe9d6303..6ccc3b0c70ea260a927bab4026bc9c957abebc4a 100644 (file)
@@ -26,6 +26,243 @@ extern void fsl_ddr_board_options(memctl_options_t *popts,
                dimm_params_t *pdimm,
                unsigned int ctrl_num);
 
+typedef struct {
+       unsigned int odt_rd_cfg;
+       unsigned int odt_wr_cfg;
+       unsigned int odt_rtt_norm;
+       unsigned int odt_rtt_wr;
+} dynamic_odt_t;
+
+static const dynamic_odt_t single_Q[4] = {
+       {       /* cs0 */
+               FSL_DDR_ODT_NEVER,
+               FSL_DDR_ODT_CS_AND_OTHER_DIMM,
+               DDR3_RTT_20_OHM,
+               DDR3_RTT_120_OHM
+       },
+       {       /* cs1 */
+               FSL_DDR_ODT_NEVER,
+               FSL_DDR_ODT_NEVER,      /* tied high */
+               DDR3_RTT_OFF,
+               DDR3_RTT_120_OHM
+       },
+       {       /* cs2 */
+               FSL_DDR_ODT_NEVER,
+               FSL_DDR_ODT_CS_AND_OTHER_DIMM,
+               DDR3_RTT_20_OHM,
+               DDR3_RTT_120_OHM
+       },
+       {       /* cs3 */
+               FSL_DDR_ODT_NEVER,
+               FSL_DDR_ODT_NEVER,      /* tied high */
+               DDR3_RTT_OFF,
+               DDR3_RTT_120_OHM
+       }
+};
+
+static const dynamic_odt_t single_D[4] = {
+       {       /* cs0 */
+               FSL_DDR_ODT_NEVER,
+               FSL_DDR_ODT_ALL,
+               DDR3_RTT_40_OHM,
+               DDR3_RTT_OFF
+       },
+       {       /* cs1 */
+               FSL_DDR_ODT_NEVER,
+               FSL_DDR_ODT_NEVER,
+               DDR3_RTT_OFF,
+               DDR3_RTT_OFF
+       },
+       {0, 0, 0, 0},
+       {0, 0, 0, 0}
+};
+
+static const dynamic_odt_t single_S[4] = {
+       {       /* cs0 */
+               FSL_DDR_ODT_NEVER,
+               FSL_DDR_ODT_ALL,
+               DDR3_RTT_40_OHM,
+               DDR3_RTT_OFF
+       },
+       {0, 0, 0, 0},
+       {0, 0, 0, 0},
+       {0, 0, 0, 0},
+};
+
+static const dynamic_odt_t dual_DD[4] = {
+       {       /* cs0 */
+               FSL_DDR_ODT_NEVER,
+               FSL_DDR_ODT_SAME_DIMM,
+               DDR3_RTT_120_OHM,
+               DDR3_RTT_OFF
+       },
+       {       /* cs1 */
+               FSL_DDR_ODT_OTHER_DIMM,
+               FSL_DDR_ODT_OTHER_DIMM,
+               DDR3_RTT_30_OHM,
+               DDR3_RTT_OFF
+       },
+       {       /* cs2 */
+               FSL_DDR_ODT_NEVER,
+               FSL_DDR_ODT_SAME_DIMM,
+               DDR3_RTT_120_OHM,
+               DDR3_RTT_OFF
+       },
+       {       /* cs3 */
+               FSL_DDR_ODT_OTHER_DIMM,
+               FSL_DDR_ODT_OTHER_DIMM,
+               DDR3_RTT_30_OHM,
+               DDR3_RTT_OFF
+       }
+};
+
+static const dynamic_odt_t dual_DS[4] = {
+       {       /* cs0 */
+               FSL_DDR_ODT_NEVER,
+               FSL_DDR_ODT_SAME_DIMM,
+               DDR3_RTT_120_OHM,
+               DDR3_RTT_OFF
+       },
+       {       /* cs1 */
+               FSL_DDR_ODT_OTHER_DIMM,
+               FSL_DDR_ODT_OTHER_DIMM,
+               DDR3_RTT_30_OHM,
+               DDR3_RTT_OFF
+       },
+       {       /* cs2 */
+               FSL_DDR_ODT_OTHER_DIMM,
+               FSL_DDR_ODT_ALL,
+               DDR3_RTT_20_OHM,
+               DDR3_RTT_120_OHM
+       },
+       {0, 0, 0, 0}
+};
+static const dynamic_odt_t dual_SD[4] = {
+       {       /* cs0 */
+               FSL_DDR_ODT_OTHER_DIMM,
+               FSL_DDR_ODT_ALL,
+               DDR3_RTT_20_OHM,
+               DDR3_RTT_120_OHM
+       },
+       {0, 0, 0, 0},
+       {       /* cs2 */
+               FSL_DDR_ODT_NEVER,
+               FSL_DDR_ODT_SAME_DIMM,
+               DDR3_RTT_120_OHM,
+               DDR3_RTT_OFF
+       },
+       {       /* cs3 */
+               FSL_DDR_ODT_OTHER_DIMM,
+               FSL_DDR_ODT_OTHER_DIMM,
+               DDR3_RTT_20_OHM,
+               DDR3_RTT_OFF
+       }
+};
+
+static const dynamic_odt_t dual_SS[4] = {
+       {       /* cs0 */
+               FSL_DDR_ODT_OTHER_DIMM,
+               FSL_DDR_ODT_ALL,
+               DDR3_RTT_30_OHM,
+               DDR3_RTT_120_OHM
+       },
+       {0, 0, 0, 0},
+       {       /* cs2 */
+               FSL_DDR_ODT_OTHER_DIMM,
+               FSL_DDR_ODT_ALL,
+               DDR3_RTT_30_OHM,
+               DDR3_RTT_120_OHM
+       },
+       {0, 0, 0, 0}
+};
+
+static const dynamic_odt_t dual_D0[4] = {
+       {       /* cs0 */
+               FSL_DDR_ODT_NEVER,
+               FSL_DDR_ODT_SAME_DIMM,
+               DDR3_RTT_40_OHM,
+               DDR3_RTT_OFF
+       },
+       {       /* cs1 */
+               FSL_DDR_ODT_NEVER,
+               FSL_DDR_ODT_NEVER,
+               DDR3_RTT_OFF,
+               DDR3_RTT_OFF
+       },
+       {0, 0, 0, 0},
+       {0, 0, 0, 0}
+};
+
+static const dynamic_odt_t dual_0D[4] = {
+       {0, 0, 0, 0},
+       {0, 0, 0, 0},
+       {       /* cs2 */
+               FSL_DDR_ODT_NEVER,
+               FSL_DDR_ODT_SAME_DIMM,
+               DDR3_RTT_40_OHM,
+               DDR3_RTT_OFF
+       },
+       {       /* cs3 */
+               FSL_DDR_ODT_NEVER,
+               FSL_DDR_ODT_NEVER,
+               DDR3_RTT_OFF,
+               DDR3_RTT_OFF
+       }
+};
+
+static const dynamic_odt_t dual_S0[4] = {
+       {       /* cs0 */
+               FSL_DDR_ODT_NEVER,
+               FSL_DDR_ODT_CS,
+               DDR3_RTT_40_OHM,
+               DDR3_RTT_OFF
+       },
+       {0, 0, 0, 0},
+       {0, 0, 0, 0},
+       {0, 0, 0, 0}
+
+};
+
+static const dynamic_odt_t dual_0S[4] = {
+       {0, 0, 0, 0},
+       {0, 0, 0, 0},
+       {       /* cs2 */
+               FSL_DDR_ODT_NEVER,
+               FSL_DDR_ODT_CS,
+               DDR3_RTT_40_OHM,
+               DDR3_RTT_OFF
+       },
+       {0, 0, 0, 0}
+
+};
+
+static const dynamic_odt_t odt_unknown[4] = {
+       {       /* cs0 */
+               FSL_DDR_ODT_NEVER,
+               FSL_DDR_ODT_CS,
+               DDR3_RTT_120_OHM,
+               DDR3_RTT_OFF
+       },
+       {       /* cs1 */
+               FSL_DDR_ODT_NEVER,
+               FSL_DDR_ODT_CS,
+               DDR3_RTT_120_OHM,
+               DDR3_RTT_OFF
+       },
+       {       /* cs2 */
+               FSL_DDR_ODT_NEVER,
+               FSL_DDR_ODT_CS,
+               DDR3_RTT_120_OHM,
+               DDR3_RTT_OFF
+       },
+       {       /* cs3 */
+               FSL_DDR_ODT_NEVER,
+               FSL_DDR_ODT_CS,
+               DDR3_RTT_120_OHM,
+               DDR3_RTT_OFF
+       }
+};
+
 unsigned int populate_memctl_options(int all_DIMMs_registered,
                        memctl_options_t *popts,
                        dimm_params_t *pdimm,
@@ -34,6 +271,7 @@ unsigned int populate_memctl_options(int all_DIMMs_registered,
        unsigned int i;
        char buffer[HWCONFIG_BUFFER_SIZE];
        char *buf = NULL;
+       const dynamic_odt_t *pdodt = odt_unknown;
 
        /*
         * Extract hwconfig from environment since we have not properly setup
@@ -43,15 +281,70 @@ unsigned int populate_memctl_options(int all_DIMMs_registered,
                buf = buffer;
 
        /* Chip select options. */
+       if (CONFIG_DIMM_SLOTS_PER_CTLR == 1) {
+               switch (pdimm[0].n_ranks) {
+               case 1:
+                       pdodt = single_S;
+                       break;
+               case 2:
+                       pdodt = single_D;
+                       break;
+               case 4:
+                       pdodt = single_Q;
+                       break;
+               }
+       } else if (CONFIG_DIMM_SLOTS_PER_CTLR == 2) {
+               switch (pdimm[0].n_ranks) {
+               case 2:
+                       switch (pdimm[1].n_ranks) {
+                       case 2:
+                               pdodt = dual_DD;
+                               break;
+                       case 1:
+                               pdodt = dual_DS;
+                               break;
+                       case 0:
+                               pdodt = dual_D0;
+                               break;
+                       }
+                       break;
+               case 1:
+                       switch (pdimm[1].n_ranks) {
+                       case 2:
+                               pdodt = dual_SD;
+                               break;
+                       case 1:
+                               pdodt = dual_SS;
+                               break;
+                       case 0:
+                               pdodt = dual_S0;
+                               break;
+                       }
+                       break;
+               case 0:
+                       switch (pdimm[1].n_ranks) {
+                       case 2:
+                               pdodt = dual_0D;
+                               break;
+                       case 1:
+                               pdodt = dual_0S;
+                               break;
+                       }
+                       break;
+               }
+       }
 
        /* Pick chip-select local options. */
        for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
-               /* If not DDR2, odt_rd_cfg and odt_wr_cfg need to be 0. */
-
-               /* only for single CS? */
-               popts->cs_local_opts[i].odt_rd_cfg = 0;
-
-               popts->cs_local_opts[i].odt_wr_cfg = 1;
+#if defined(CONFIG_FSL_DDR3)
+               popts->cs_local_opts[i].odt_rd_cfg = pdodt[i].odt_rd_cfg;
+               popts->cs_local_opts[i].odt_wr_cfg = pdodt[i].odt_wr_cfg;
+               popts->cs_local_opts[i].odt_rtt_norm = pdodt[i].odt_rtt_norm;
+               popts->cs_local_opts[i].odt_rtt_wr = pdodt[i].odt_rtt_wr;
+#else
+               popts->cs_local_opts[i].odt_rd_cfg = FSL_DDR_ODT_NEVER;
+               popts->cs_local_opts[i].odt_wr_cfg = FSL_DDR_ODT_CS;
+#endif
                popts->cs_local_opts[i].auto_precharge = 0;
        }
 
@@ -179,6 +472,9 @@ unsigned int populate_memctl_options(int all_DIMMs_registered,
        popts->twoT_en = 0;
        popts->threeT_en = 0;
 
+       /* for RDIMM, address parity enable */
+       popts->ap_en = 1;
+
        /*
         * BSTTOPRE precharge interval
         *
index 04aeb40753e39572a0f953a24306840ad1c9ee75..989c915839ae5acc27a86386c2099a26fda1a8a3 100644 (file)
@@ -24,6 +24,7 @@
 #define DDR_OTF                6       /* on-the-fly BC4 and BL8 */
 #define DDR_BL8                8       /* burst length 8 */
 
+#define DDR3_RTT_OFF           0
 #define DDR3_RTT_60_OHM                1 /* RTT_Nom = RZQ/4 */
 #define DDR3_RTT_120_OHM       2 /* RTT_Nom = RZQ/2 */
 #define DDR3_RTT_40_OHM                3 /* RTT_Nom = RZQ/6 */
@@ -50,6 +51,15 @@ typedef ddr3_spd_eeprom_t generic_spd_eeprom_t;
 #endif
 #endif /* #if defined(CONFIG_FSL_DDR1) */
 
+#define FSL_DDR_ODT_NEVER              0x0
+#define FSL_DDR_ODT_CS                 0x1
+#define FSL_DDR_ODT_ALL_OTHER_CS       0x2
+#define FSL_DDR_ODT_OTHER_DIMM         0x3
+#define FSL_DDR_ODT_ALL                        0x4
+#define FSL_DDR_ODT_SAME_DIMM          0x5
+#define FSL_DDR_ODT_CS_AND_OTHER_DIMM  0x6
+#define FSL_DDR_ODT_OTHER_CS_ONSAMEDIMM        0x7
+
 /* define bank(chip select) interleaving mode */
 #define FSL_DDR_CS0_CS1                        0x40
 #define FSL_DDR_CS2_CS3                        0x20
@@ -106,6 +116,12 @@ typedef struct fsl_ddr_cfg_regs_s {
        unsigned int ddr_sdram_cfg_2;
        unsigned int ddr_sdram_mode;
        unsigned int ddr_sdram_mode_2;
+       unsigned int ddr_sdram_mode_3;
+       unsigned int ddr_sdram_mode_4;
+       unsigned int ddr_sdram_mode_5;
+       unsigned int ddr_sdram_mode_6;
+       unsigned int ddr_sdram_mode_7;
+       unsigned int ddr_sdram_mode_8;
        unsigned int ddr_sdram_md_cntl;
        unsigned int ddr_sdram_interval;
        unsigned int ddr_data_init;
@@ -156,6 +172,8 @@ typedef struct memctl_options_s {
                unsigned int auto_precharge;
                unsigned int odt_rd_cfg;
                unsigned int odt_wr_cfg;
+               unsigned int odt_rtt_norm;
+               unsigned int odt_rtt_wr;
        } cs_local_opts[CONFIG_CHIP_SELECTS_PER_CTRL];
 
        /* Special configurations for chip select */
index 9e3c5390de54255b23852b63bd55ece4a6574de5..a7ba193f3014caf68580eff3403f53bd6bec4198 100644 (file)
@@ -104,4 +104,69 @@ Combination of hwconfig
 Hwconfig can be combined with multiple parameters, for example, on a supported
 platform
 
-hwconfig=fsl_ddr:addr_hash=true,ctlr_intlv=cacheline,bank_intlv=cs0_cs1_cs2_cs3
+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
+be needed, depending on the configuration. The numbers in the following tables are
+in Ohms.
+
+* denotes dynamic ODT
+
+Two slots system
++-----------------------+----------+---------------+-----------------------------+-----------------------------+
+|     Configuration     |          |DRAM controller|           Slot 1            |            Slot 2           |
++-----------+-----------+----------+-------+-------+--------------+--------------+--------------+--------------+
+|           |           |          |       |       |     Rank 1   |     Rank 2   |   Rank 1     |    Rank 2    |
++  Slot 1   |   Slot 2  |Write/Read| Write | Read  |-------+------+-------+------+-------+------+-------+------+
+|           |           |          |       |       | Write | Read | Write | Read | Write | Read | Write | Read |
++-----------+-----------+----------+-------+-------+-------+------+-------+------+-------+------+-------+------+
+|           |           |  Slot 1  |  off  | 75    | 120   | off  | off   | off  | off   | off  | 30    | 30   |
+| Dual Rank | Dual Rank |----------+-------+-------+-------+------+-------+------+-------+------+-------+------+
+|           |           |  Slot 2  |  off  | 75    | off   | off  | 30    | 30   | 120   | off  | off   | off  |
++-----------+-----------+----------+-------+-------+-------+------+-------+------+-------+------+-------+------+
+|           |           |  Slot 1  |  off  | 75    | 120   | off  | off   | off  | 20    | 20   |       |      |
+| Dual Rank |Single Rank|----------+-------+-------+-------+------+-------+------+-------+------+-------+------+
+|           |           |  Slot 2  |  off  | 75    | off   | off  | 20    | 20   | 120  *| off  |       |      |
++-----------+-----------+----------+-------+-------+-------+------+-------+------+-------+------+-------+------+
+|           |           |  Slot 1  |  off  | 75    | 120  *| off  |       |      | off   | off  | 20    | 20   |
+|Single Rank| Dual Rank |----------+-------+-------+-------+------+-------+------+-------+------+-------+------+
+|           |           |  Slot 2  |  off  | 75    | 20    | 20   |       |      | 120   | off  | off   | off  |
++-----------+-----------+----------+-------+-------+-------+------+-------+------+-------+------+-------+------+
+|           |           |  Slot 1  |  off  | 75    | 120  *| off  |       |      | 30    | 30   |       |      |
+|Single Rank|Single Rank|----------+-------+-------+-------+------+-------+------+-------+------+-------+------+
+|           |           |  Slot 2  |  off  | 75    | 30    | 30   |       |      | 120  *| off  |       |      |
++-----------+-----------+----------+-------+-------+-------+------+-------+------+-------+------+-------+------+
+| Dual Rank |   Empty   |  Slot 1  |  off  | 75    | 40    | off  | off   | off  |       |      |       |      |
++-----------+-----------+----------+-------+-------+-------+------+-------+------+-------+------+-------+------+
+|   Empty   | Dual Rank |  Slot 2  |  off  | 75    |       |      |       |      | 40    | off  | off   | off  |
++-----------+-----------+----------+-------+-------+-------+------+-------+------+-------+------+-------+------+
+|Single Rank|   Empty   |  Slot 1  |  off  | 75    | 40    | off  |       |      |       |      |       |      |
++-----------+-----------+----------+-------+-------+-------+------+-------+------+-------+------+-------+------+
+|   Empty   |Single Rank|  Slot 2  |  off  | 75    |       |      |       |      | 40    | off  |       |      |
++-----------+-----------+----------+-------+-------+-------+------+-------+------+-------+------+-------+------+
+
+Single slot system
++-------------+------------+---------------+-----------------------------+-----------------------------+
+|             |            |DRAM controller|     Rank 1   |    Rank 2    |    Rank 3    |    Rank 4    |
+|Configuration| Write/Read |-------+-------+-------+------+-------+------+-------+------+-------+------+
+|             |            | Write | Read  | Write | Read | Write | Read | Write | Read | Write | Read |
++-------------+------------+-------+-------+-------+------+-------+------+-------+------+-------+------+
+|             |   R1       | off   | 75    | 120  *| off  | off   | off  | 20    | 20   | off   | off  |
+|             |------------+-------+-------+-------+------+-------+------+-------+------+-------+------+
+|             |   R2       | off   | 75    | off   | 20   | 120   | off  | 20    | 20   | off   | off  |
+|  Quad Rank  |------------+-------+-------+-------+------+-------+------+-------+------+-------+------+
+|             |   R3       | off   | 75    | 20    | 20   | off   | off  | 120  *| off  | off   | off  |
+|             |------------+-------+-------+-------+------+-------+------+-------+------+-------+------+
+|             |   R4       | off   | 75    | 20    | 20   | off   | off  | off   | 20   | 120   | off  |
++-------------+------------+-------+-------+-------+------+-------+------+-------+------+-------+------+
+|             |   R1       | off   | 75    | 40    | off  | off   | off  |
+|  Dual Rank  |------------+-------+-------+-------+------+-------+------+
+|             |   R2       | off   | 75    | 40    | off  | off   | off  |
++-------------+------------+-------+-------+-------+------+-------+------+
+| Single Rank |   R1       | off   | 75    | 40    | off  |
++-------------+------------+-------+-------+-------+------+
+
+Reference http://www.xrosstalkmag.com/mag_issues/xrosstalk_oct08_final.pdf
+          http://download.micron.com/pdf/technotes/ddr3/tn4108_ddr3_design_guide.pdf