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:
Patrick Rudolph 2016-01-10 14:22:34 +01:00 committed by Martin Roth
parent 441be59ae0
commit 7e513d1d04
1 changed files with 38 additions and 67 deletions

View File

@ -1224,28 +1224,16 @@ 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("");
} }
} }
@ -1319,11 +1307,9 @@ 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,
FOR_ALL_POPULATED_CHANNELS write_mrreg(ctrl, channel, rank, 0,
make_mr0(ctrl, rank)); make_mr0(ctrl, rank));
} }
@ -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;
FOR_ALL_CHANNELS {
write_mrreg(ctrl, channel, rank, 3, 0); 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 {
FOR_ALL_POPULATED_RANKS {
// MR2 // MR2
printram("MR2 rank %d...", rank); dram_mr2(ctrl, slotrank, channel);
dram_mr2(ctrl, rank);
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));
} }
} }