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:
parent
40d93494c3
commit
7c2e5396a3
|
@ -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
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in New Issue