nb/intel/x4x: Fix CAS latency detection and max memory detection

Now hardcode maximum memory frequency capability to 800MHz, as
all chipsets in x4x family support PC2-6400 according to the datasheet.
CAS latency detection also relies on this, and has been cleaned up.

Ram initialization does not work with FSB 1333MHz / DDR2 800MHz combination,
so disable this combination for now, and reduce to 667MHz instead.
Still don't know why this is the case, but FSB1333/667 works.

These changes should now allow existing configurations to continue working,
while providing support for previously unworking configurations, due to
previous buggy CAS latency detection code.

TESTED: on GA-G41M-ES2L
CPU: E5200 @ 2.50GHz (FSB 800MHz)

2x 1GB 667MHz hynix	worked @ 667
1x 2GB 800Mhz ARAM	worked @ 800
1x 1GB 667Mhz StarRam	worked @ 667
2x 2GB 800Mhz (generic)	worked @ 800

Change-Id: I1ddd7827ee6fe3d4162ba0546f738a8f9decdf93
Signed-off-by: Damien Zammit <damien@zamaudio.com>
Reviewed-on: https://review.coreboot.org/15818
Tested-by: build bot (Jenkins)
Reviewed-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
This commit is contained in:
Damien Zammit 2016-07-24 03:28:42 +10:00 committed by Kyösti Mälkki
parent 40d93494c3
commit 7c2e5396a3
2 changed files with 47 additions and 98 deletions

View File

@ -111,10 +111,9 @@ static void sdram_read_spds(struct sysinfo *s)
s->dimms[i].chip_capacity = s->dimms[i].banks; s->dimms[i].chip_capacity = s->dimms[i].banks;
s->dimms[i].rows = s->dimms[i].spd_data[3];// - 12; s->dimms[i].rows = s->dimms[i].spd_data[3];// - 12;
s->dimms[i].cols = s->dimms[i].spd_data[4];// - 9; s->dimms[i].cols = s->dimms[i].spd_data[4];// - 9;
s->dimms[i].cas_latencies = 0x70; // 6,5,4 CL s->dimms[i].cas_latencies = s->dimms[i].spd_data[18];
s->dimms[i].cas_latencies &= s->dimms[i].spd_data[18];
if (s->dimms[i].cas_latencies == 0) if (s->dimms[i].cas_latencies == 0)
s->dimms[i].cas_latencies = 0x70; s->dimms[i].cas_latencies = 0x60; // 6,5 CL
s->dimms[i].tAAmin = s->dimms[i].spd_data[26]; s->dimms[i].tAAmin = s->dimms[i].spd_data[26];
s->dimms[i].tCKmin = s->dimms[i].spd_data[25]; s->dimms[i].tCKmin = s->dimms[i].spd_data[25];
s->dimms[i].width = (s->dimms[i].spd_data[13] >> 3) - 1; s->dimms[i].width = (s->dimms[i].spd_data[13] >> 3) - 1;
@ -248,13 +247,6 @@ static void sdram_read_spds(struct sysinfo *s)
} }
} }
static u8 lsbpos(u8 val) //Forward
{
u8 i;
for (i = 0; (i < 8) && ((val & (1 << i)) == 0); i++);
return i;
}
static u8 msbpos(u8 val) //Reverse static u8 msbpos(u8 val) //Reverse
{ {
u8 i; u8 i;
@ -264,8 +256,6 @@ static u8 msbpos(u8 val) //Reverse
static void mchinfo_ddr2(struct sysinfo *s) static void mchinfo_ddr2(struct sysinfo *s)
{ {
u8 capablefreq, maxfreq;
const u32 eax = cpuid_ext(0x04, 0).eax; const u32 eax = cpuid_ext(0x04, 0).eax;
s->cores = ((eax >> 26) & 0x3f) + 1; s->cores = ((eax >> 26) & 0x3f) + 1;
printk(BIOS_WARNING, "%d CPU cores\n", s->cores); printk(BIOS_WARNING, "%d CPU cores\n", s->cores);
@ -284,19 +274,7 @@ static void mchinfo_ddr2(struct sysinfo *s)
printk(BIOS_WARNING, "AMT enabled\n"); printk(BIOS_WARNING, "AMT enabled\n");
} }
maxfreq = MEM_CLOCK_800MHz; s->max_ddr2_mhz = 800; // All chipsets in x4x support up to 800MHz DDR2
capablefreq = (u8)((pci_read_config16(PCI_DEV(0, 0, 0), 0xea) >> 4) & 0x3f);
capablefreq &= 0x7;
if (capablefreq)
maxfreq = capablefreq + 1;
if (maxfreq > MEM_CLOCK_800MHz)
maxfreq = MEM_CLOCK_800MHz;
if (maxfreq < MEM_CLOCK_667MHz)
maxfreq = MEM_CLOCK_667MHz;
s->max_ddr2_mhz = (maxfreq == MEM_CLOCK_800MHz) ? 800 : 667;
printk(BIOS_WARNING, "Capable of DDR2 of %d MHz or lower\n", s->max_ddr2_mhz); printk(BIOS_WARNING, "Capable of DDR2 of %d MHz or lower\n", s->max_ddr2_mhz);
if (!(capid & (1<<(48-32)))) { if (!(capid & (1<<(48-32)))) {
@ -308,12 +286,15 @@ static void sdram_detect_ram_speed(struct sysinfo *s)
{ {
u8 i; u8 i;
u8 commoncas = 0; u8 commoncas = 0;
u8 cas; u8 currcas;
u8 lowcas; u8 currfreq;
u8 highcas;
u8 maxfreq; u8 maxfreq;
u8 freq = 0; u8 freq = 0;
// spdidx,cycletime @CAS 5 6
u8 idx800[7][2] = {{0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {23,0x30}, {9,0x25}};
int found = 0;
// Find max FSB speed // Find max FSB speed
switch (MCHBAR32(0xc00) & 0x7) { switch (MCHBAR32(0xc00) & 0x7) {
case 0x0: case 0x0:
@ -334,11 +315,13 @@ static void sdram_detect_ram_speed(struct sysinfo *s)
// Max RAM speed // Max RAM speed
if (s->spd_type == DDR2) { if (s->spd_type == DDR2) {
// Choose max memory frequency for MCH as previously detected // FIXME: Limit memory speed to 667MHz if FSB is 1333MHz
freq = (s->max_ddr2_mhz == 800) ? MEM_CLOCK_800MHz : MEM_CLOCK_667MHz; maxfreq = (s->max_fsb == FSB_CLOCK_1333MHz)
? MEM_CLOCK_667MHz : MEM_CLOCK_800MHz;
// Choose common CAS latency from {6,5}, 4 does not work
commoncas = 0x60;
// Detect a common CAS latency (Choose from 6,5,4 CL)
commoncas = 0x70;
FOR_EACH_POPULATED_DIMM(s->dimms, i) { FOR_EACH_POPULATED_DIMM(s->dimms, i) {
commoncas &= s->dimms[i].cas_latencies; commoncas &= s->dimms[i].cas_latencies;
} }
@ -346,74 +329,41 @@ static void sdram_detect_ram_speed(struct sysinfo *s)
die("No common CAS among dimms\n"); die("No common CAS among dimms\n");
} }
// Start with fastest common CAS // Working from fastest to slowest,
cas = 0; // fast->slow 5@800 6@800 5@667
highcas = msbpos(commoncas); found = 0;
lowcas = lsbpos(commoncas); for (currcas = 5; currcas <= msbpos(commoncas); currcas++) {
currfreq = maxfreq;
while (cas == 0 && highcas >= lowcas) { if (currfreq == MEM_CLOCK_800MHz) {
FOR_EACH_POPULATED_DIMM(s->dimms, i) { found = 1;
switch (freq) {
case MEM_CLOCK_800MHz:
if ((s->dimms[i].spd_data[9] > 0x25) ||
(s->dimms[i].spd_data[10] > 0x40)) {
// CAS too fast, lower it
highcas--;
break;
} else {
cas = highcas;
}
break;
case MEM_CLOCK_667MHz:
default:
if ((s->dimms[i].spd_data[9] > 0x30) ||
(s->dimms[i].spd_data[10] > 0x45)) {
// CAS too fast, lower it
highcas--;
break;
} else {
cas = highcas;
}
break;
}
}
}
if (highcas < lowcas) {
// Timings not supported by MCH, lower the frequency
freq--;
cas = 0;
highcas = msbpos(commoncas);
lowcas = lsbpos(commoncas);
while (cas == 0 && highcas >= lowcas) {
FOR_EACH_POPULATED_DIMM(s->dimms, i) { FOR_EACH_POPULATED_DIMM(s->dimms, i) {
switch (freq) { if (s->dimms[i].spd_data[idx800[currcas][0]] > idx800[currcas][1]) {
case MEM_CLOCK_800MHz: // this is too fast
if ((s->dimms[i].spd_data[23] > 0x25) || found = 0;
(s->dimms[i].spd_data[24] > 0x40)) {
// CAS too fast, lower it
highcas--;
break;
} else {
cas = highcas;
}
break;
case MEM_CLOCK_667MHz:
default:
if ((s->dimms[i].spd_data[23] > 0x30) ||
(s->dimms[i].spd_data[24] > 0x45)) {
// CAS too fast, lower it
highcas--;
break;
} else {
cas = highcas;
}
break;
} }
} }
if (found)
break;
}
}
if (!found) {
currcas = 5;
currfreq = MEM_CLOCK_667MHz;
found = 1;
FOR_EACH_POPULATED_DIMM(s->dimms, i) {
if (s->dimms[i].spd_data[9] > 0x30) {
// this is too fast
found = 0;
}
} }
} }
s->selected_timings.mem_clk = freq;
s->selected_timings.CAS = cas; if (!found)
die("No valid CAS/frequencies detected\n");
s->selected_timings.mem_clk = currfreq;
s->selected_timings.CAS = currcas;
} else { // DDR3 } else { // DDR3
// Limit frequency for MCH // Limit frequency for MCH

View File

@ -293,11 +293,10 @@ static void launch_ddr2(struct sysinfo *s)
if (s->selected_timings.CAS == 5) { if (s->selected_timings.CAS == 5) {
launch2 = 0x00220201; launch2 = 0x00220201;
} else if ((s->selected_timings.mem_clk == MEM_CLOCK_800MHz) && } else if (s->selected_timings.CAS == 6) {
(s->selected_timings.CAS == 6)) {
launch2 = 0x00230302; launch2 = 0x00230302;
} else { } else {
die("Unsupported CAS & Frequency combination detected\n"); die("Unsupported CAS\n");
} }
FOR_EACH_POPULATED_CHANNEL(s->dimms, i) { FOR_EACH_POPULATED_CHANNEL(s->dimms, i) {