intel/sandybridge/raminit: fix ODT setting
Count DIMMs on current memory channel instead of all memory channels. The current code is only able to correctly handle the following memory configurations: One DIMM installed in either channel. Four DIMMs installed, two in each channel. Two DIMMs installed, both in the same channel. For systems that have any other configuration the DRAM On-Die-Termination setting is wrong. For example: Two DIMMs installed, one in each channel. Test system: * Gigabyte GA-B75M-D3H (Intel Pentium CPU G2130) Change-Id: I0e8e1a47a2c33a326926c6aac1ec4d8ffaf57bb6 Signed-off-by: Patrick Rudolph <siro@das-labor.org> Reviewed-on: https://review.coreboot.org/12892 Tested-by: build bot (Jenkins) Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net> Reviewed-by: Martin Roth <martinroth@google.com> Reviewed-by: Philipp Deppenwiese <zaolin.daisuki@googlemail.com>
This commit is contained in:
parent
441be59ae0
commit
7e513d1d04
|
@ -1224,32 +1224,20 @@ static void dram_jedecreset(ramctr_timing * ctrl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static odtmap get_ODT(ramctr_timing * ctrl, u8 rank)
|
static odtmap get_ODT(ramctr_timing *ctrl, u8 rank, int channel)
|
||||||
{
|
{
|
||||||
/* Get ODT based on rankmap: */
|
/* Get ODT based on rankmap: */
|
||||||
int dimms_per_ch = 0;
|
int dimms_per_ch = (ctrl->rankmap[channel] & 1)
|
||||||
int channel;
|
+ ((ctrl->rankmap[channel] >> 2) & 1);
|
||||||
|
|
||||||
FOR_ALL_CHANNELS {
|
|
||||||
dimms_per_ch = max ((ctrl->rankmap[channel] & 1)
|
|
||||||
+ ((ctrl->rankmap[channel] >> 2) & 1),
|
|
||||||
dimms_per_ch);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dimms_per_ch == 1) {
|
if (dimms_per_ch == 1) {
|
||||||
return (const odtmap){60, 60};
|
return (const odtmap){60, 60};
|
||||||
} else if (dimms_per_ch == 2) {
|
|
||||||
return (const odtmap){120, 30};
|
|
||||||
} else {
|
} else {
|
||||||
printk(BIOS_DEBUG,
|
return (const odtmap){120, 30};
|
||||||
"Huh, no dimms? m0 = %d m1 = %d dpc = %d\n",
|
|
||||||
ctrl->rankmap[0],
|
|
||||||
ctrl->rankmap[1], dimms_per_ch);
|
|
||||||
die("");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void write_mrreg(ramctr_timing * ctrl, int channel, int slotrank,
|
static void write_mrreg(ramctr_timing *ctrl, int channel, int slotrank,
|
||||||
int reg, u32 val)
|
int reg, u32 val)
|
||||||
{
|
{
|
||||||
wait_428c(channel);
|
wait_428c(channel);
|
||||||
|
@ -1319,12 +1307,10 @@ static u32 make_mr0(ramctr_timing * ctrl, u8 rank)
|
||||||
return mr0reg;
|
return mr0reg;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dram_mr0(ramctr_timing * ctrl, u8 rank)
|
static void dram_mr0(ramctr_timing *ctrl, u8 rank, int channel)
|
||||||
{
|
{
|
||||||
int channel;
|
write_mrreg(ctrl, channel, rank, 0,
|
||||||
|
make_mr0(ctrl, rank));
|
||||||
FOR_ALL_POPULATED_CHANNELS write_mrreg(ctrl, channel, rank, 0,
|
|
||||||
make_mr0(ctrl, rank));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 encode_odt(u32 odt)
|
static u32 encode_odt(u32 odt)
|
||||||
|
@ -1342,12 +1328,12 @@ static u32 encode_odt(u32 odt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 make_mr1(ramctr_timing * ctrl, u8 rank)
|
static u32 make_mr1(ramctr_timing *ctrl, u8 rank, int channel)
|
||||||
{
|
{
|
||||||
odtmap odt;
|
odtmap odt;
|
||||||
u32 mr1reg;
|
u32 mr1reg;
|
||||||
|
|
||||||
odt = get_ODT(ctrl, rank);
|
odt = get_ODT(ctrl, rank, channel);
|
||||||
mr1reg = 0x2;
|
mr1reg = 0x2;
|
||||||
|
|
||||||
mr1reg |= encode_odt(odt.rttnom);
|
mr1reg |= encode_odt(odt.rttnom);
|
||||||
|
@ -1355,28 +1341,24 @@ static u32 make_mr1(ramctr_timing * ctrl, u8 rank)
|
||||||
return mr1reg;
|
return mr1reg;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dram_mr1(ramctr_timing * ctrl, u8 rank)
|
static void dram_mr1(ramctr_timing *ctrl, u8 rank, int channel)
|
||||||
{
|
{
|
||||||
u16 mr1reg;
|
u16 mr1reg;
|
||||||
int channel;
|
|
||||||
|
|
||||||
mr1reg = make_mr1(ctrl, rank);
|
mr1reg = make_mr1(ctrl, rank, channel);
|
||||||
|
|
||||||
FOR_ALL_CHANNELS {
|
write_mrreg(ctrl, channel, rank, 1, mr1reg);
|
||||||
write_mrreg(ctrl, channel, rank, 1, mr1reg);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dram_mr2(ramctr_timing * ctrl, u8 rank)
|
static void dram_mr2(ramctr_timing *ctrl, u8 rank, int channel)
|
||||||
{
|
{
|
||||||
u16 pasr, cwl, mr2reg;
|
u16 pasr, cwl, mr2reg;
|
||||||
odtmap odt;
|
odtmap odt;
|
||||||
int channel;
|
|
||||||
int srt;
|
int srt;
|
||||||
|
|
||||||
pasr = 0;
|
pasr = 0;
|
||||||
cwl = ctrl->CWL - 5;
|
cwl = ctrl->CWL - 5;
|
||||||
odt = get_ODT(ctrl, rank);
|
odt = get_ODT(ctrl, rank, channel);
|
||||||
|
|
||||||
srt = ctrl->extended_temperature_range && !ctrl->auto_self_refresh;
|
srt = ctrl->extended_temperature_range && !ctrl->auto_self_refresh;
|
||||||
|
|
||||||
|
@ -1387,46 +1369,34 @@ static void dram_mr2(ramctr_timing * ctrl, u8 rank)
|
||||||
mr2reg = (mr2reg & ~0x80) | (srt << 7);
|
mr2reg = (mr2reg & ~0x80) | (srt << 7);
|
||||||
mr2reg |= (odt.rttwr / 60) << 9;
|
mr2reg |= (odt.rttwr / 60) << 9;
|
||||||
|
|
||||||
FOR_ALL_CHANNELS {
|
write_mrreg(ctrl, channel, rank, 2, mr2reg);
|
||||||
write_mrreg(ctrl, channel, rank, 2, mr2reg);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dram_mr3(ramctr_timing * ctrl, u8 rank)
|
static void dram_mr3(ramctr_timing *ctrl, u8 rank, int channel)
|
||||||
{
|
{
|
||||||
int channel;
|
write_mrreg(ctrl, channel, rank, 3, 0);
|
||||||
|
|
||||||
FOR_ALL_CHANNELS {
|
|
||||||
write_mrreg(ctrl, channel, rank, 3, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dram_mrscommands(ramctr_timing * ctrl)
|
static void dram_mrscommands(ramctr_timing * ctrl)
|
||||||
{
|
{
|
||||||
u8 rank;
|
u8 slotrank;
|
||||||
u32 reg, addr;
|
u32 reg, addr;
|
||||||
int channel;
|
int channel;
|
||||||
|
|
||||||
for (rank = 0; rank < 4; rank++) {
|
FOR_ALL_POPULATED_CHANNELS {
|
||||||
// MR2
|
FOR_ALL_POPULATED_RANKS {
|
||||||
printram("MR2 rank %d...", rank);
|
// MR2
|
||||||
dram_mr2(ctrl, rank);
|
dram_mr2(ctrl, slotrank, channel);
|
||||||
printram("done\n");
|
|
||||||
|
|
||||||
// MR3
|
// MR3
|
||||||
printram("MR3 rank %d...", rank);
|
dram_mr3(ctrl, slotrank, channel);
|
||||||
dram_mr3(ctrl, rank);
|
|
||||||
printram("done\n");
|
|
||||||
|
|
||||||
// MR1
|
// MR1
|
||||||
printram("MR1 rank %d...", rank);
|
dram_mr1(ctrl, slotrank, channel);
|
||||||
dram_mr1(ctrl, rank);
|
|
||||||
printram("done\n");
|
|
||||||
|
|
||||||
// MR0
|
// MR0
|
||||||
printram("MR0 rank %d...", rank);
|
dram_mr0(ctrl, slotrank, channel);
|
||||||
dram_mr0(ctrl, rank);
|
}
|
||||||
printram("done\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* DRAM command NOP */
|
/* DRAM command NOP */
|
||||||
|
@ -1461,7 +1431,7 @@ static void dram_mrscommands(ramctr_timing * ctrl)
|
||||||
|
|
||||||
wait_428c(channel);
|
wait_428c(channel);
|
||||||
|
|
||||||
rank = (ctrl->rankmap[channel] & 1) ? 0 : 2;
|
slotrank = (ctrl->rankmap[channel] & 1) ? 0 : 2;
|
||||||
|
|
||||||
// Drain
|
// Drain
|
||||||
wait_428c(channel);
|
wait_428c(channel);
|
||||||
|
@ -1470,7 +1440,7 @@ static void dram_mrscommands(ramctr_timing * ctrl)
|
||||||
write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x0f003);
|
write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x0f003);
|
||||||
write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, 0x659001);
|
write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, 0x659001);
|
||||||
write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel,
|
write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel,
|
||||||
(rank << 24) | 0x60000);
|
(slotrank << 24) | 0x60000);
|
||||||
write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0x3e0);
|
write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0x3e0);
|
||||||
write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0x1);
|
write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0x1);
|
||||||
|
|
||||||
|
@ -2308,7 +2278,7 @@ static void test_timB(ramctr_timing * ctrl, int channel, int slotrank)
|
||||||
{
|
{
|
||||||
/* enable DQs on this slotrank */
|
/* enable DQs on this slotrank */
|
||||||
write_mrreg(ctrl, channel, slotrank, 1,
|
write_mrreg(ctrl, channel, slotrank, 1,
|
||||||
0x80 | make_mr1(ctrl, slotrank));
|
0x80 | make_mr1(ctrl, slotrank, channel));
|
||||||
|
|
||||||
wait_428c(channel);
|
wait_428c(channel);
|
||||||
/* DRAM command NOP */
|
/* DRAM command NOP */
|
||||||
|
@ -2332,7 +2302,7 @@ static void test_timB(ramctr_timing * ctrl, int channel, int slotrank)
|
||||||
|
|
||||||
/* disable DQs on this slotrank */
|
/* disable DQs on this slotrank */
|
||||||
write_mrreg(ctrl, channel, slotrank, 1,
|
write_mrreg(ctrl, channel, slotrank, 1,
|
||||||
0x1080 | make_mr1(ctrl, slotrank));
|
0x1080 | make_mr1(ctrl, slotrank, channel));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void discover_timB(ramctr_timing * ctrl, int channel, int slotrank)
|
static void discover_timB(ramctr_timing * ctrl, int channel, int slotrank)
|
||||||
|
@ -2564,7 +2534,7 @@ static void write_training(ramctr_timing * ctrl)
|
||||||
FOR_ALL_CHANNELS
|
FOR_ALL_CHANNELS
|
||||||
FOR_ALL_POPULATED_RANKS
|
FOR_ALL_POPULATED_RANKS
|
||||||
write_mrreg(ctrl, channel, slotrank, 1,
|
write_mrreg(ctrl, channel, slotrank, 1,
|
||||||
make_mr1(ctrl, slotrank) | 0x1080);
|
make_mr1(ctrl, slotrank, channel) | 0x1080);
|
||||||
|
|
||||||
write32(DEFAULT_MCHBAR + 0x3400, 0x108052);
|
write32(DEFAULT_MCHBAR + 0x3400, 0x108052);
|
||||||
|
|
||||||
|
@ -2577,7 +2547,7 @@ static void write_training(ramctr_timing * ctrl)
|
||||||
/* disable write leveling on all ranks */
|
/* disable write leveling on all ranks */
|
||||||
FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS
|
FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS
|
||||||
write_mrreg(ctrl, channel,
|
write_mrreg(ctrl, channel,
|
||||||
slotrank, 1, make_mr1(ctrl, slotrank));
|
slotrank, 1, make_mr1(ctrl, slotrank, channel));
|
||||||
|
|
||||||
write32(DEFAULT_MCHBAR + 0x3400, 0);
|
write32(DEFAULT_MCHBAR + 0x3400, 0);
|
||||||
|
|
||||||
|
@ -3503,7 +3473,8 @@ static void write_controller_mr(ramctr_timing * ctrl)
|
||||||
write32(DEFAULT_MCHBAR + 0x0004 + (channel << 8) +
|
write32(DEFAULT_MCHBAR + 0x0004 + (channel << 8) +
|
||||||
lane_registers[slotrank], make_mr0(ctrl, slotrank));
|
lane_registers[slotrank], make_mr0(ctrl, slotrank));
|
||||||
write32(DEFAULT_MCHBAR + 0x0008 + (channel << 8) +
|
write32(DEFAULT_MCHBAR + 0x0008 + (channel << 8) +
|
||||||
lane_registers[slotrank], make_mr1(ctrl, slotrank));
|
lane_registers[slotrank],
|
||||||
|
make_mr1(ctrl, slotrank, channel));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue