summaryrefslogtreecommitdiffstats
path: root/arch/powerpc/cpu/mpc8xxx/ddr
diff options
context:
space:
mode:
authorYork Sun <yorksun@freescale.com>2011-01-10 12:03:00 +0000
committerKumar Gala <galak@kernel.crashing.org>2011-01-19 22:58:23 -0600
commite1fd16b6f5e80d932c73f5a36141adfb35126e83 (patch)
tree7a1bda7894afa9187f50936172aff0529324d7b1 /arch/powerpc/cpu/mpc8xxx/ddr
parentd2a9568c57f0aa02f097911d3811e002a1eec1b8 (diff)
downloadblackbird-obmc-uboot-e1fd16b6f5e80d932c73f5a36141adfb35126e83.tar.gz
blackbird-obmc-uboot-e1fd16b6f5e80d932c73f5a36141adfb35126e83.zip
mpc85xx: Enable unique mode registers and dynamic ODT for DDR3
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>
Diffstat (limited to 'arch/powerpc/cpu/mpc8xxx/ddr')
-rw-r--r--arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c252
-rw-r--r--arch/powerpc/cpu/mpc8xxx/ddr/options.c308
2 files changed, 506 insertions, 54 deletions
diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c b/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c
index 8fdafdb906..2271071ad2 100644
--- a/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c
+++ b/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c
@@ -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
@@ -18,7 +18,28 @@
#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);
}
diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/options.c b/arch/powerpc/cpu/mpc8xxx/ddr/options.c
index 55dff43947..6ccc3b0c70 100644
--- a/arch/powerpc/cpu/mpc8xxx/ddr/options.c
+++ b/arch/powerpc/cpu/mpc8xxx/ddr/options.c
@@ -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
*
OpenPOWER on IntegriCloud