Commit e1fd16b6 authored by York Sun's avatar York Sun Committed by Kumar Gala

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: default avatarYork Sun <yorksun@freescale.com>
Signed-off-by: default avatarKumar Gala <galak@kernel.crashing.org>
parent d2a9568c
......@@ -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);
......
This diff is collapsed.
......@@ -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
*
......
......@@ -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 */
......
......@@ -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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment