Hi Ward,
I wanted to calculate the optimal timing for any setup with mixed DIMMs where the timing parameters may be compatible but not identical. This patch is a step in the right direction (hopefully). I think Marc already reviewed parts of it last year, but I couldn't find the conversation anymore.
Warning: The spec is horribly backwards in some places, and the code sort of inherits this. I spent a few days figuring out why the old code even worked, and then I noticed it wasn't as bad as it originally looked.
Feel free to comment, fix, apply, rip to shreds.
Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net
Index: LinuxBIOSv2-asus_m2a-vm/src/northbridge/amd/amdk8/raminit_f.c =================================================================== --- LinuxBIOSv2-asus_m2a-vm/src/northbridge/amd/amdk8/raminit_f.c (Revision 4614) +++ LinuxBIOSv2-asus_m2a-vm/src/northbridge/amd/amdk8/raminit_f.c (Arbeitskopie) @@ -39,7 +39,7 @@ #error This file needs CONFIG_USE_PRINTK_IN_CAR #endif
-#define RAM_TIMING_DEBUG 0 +#define RAM_TIMING_DEBUG 1
#if RAM_TIMING_DEBUG == 1 #define printk_raminit printk_debug @@ -1499,7 +1499,8 @@ } if (value0 != value1) { printk_raminit("SPD values differ between channel 0/1 for byte %i\n", addr); - goto single_channel; + printk_raminit("Ignoring the differences for now!\n", addr); + //goto single_channel; } } } @@ -1786,6 +1787,51 @@ return 0; }
+int check_spd_latency_available(u32 spd_device, unsigned min_cycle_time, unsigned min_latency) +{ + int latencies; + int latency; + int index; + int value; + + latencies = spd_read_byte(spd_device, SPD_CAS_LAT); + if (latencies < 0) + return -1; + if (latencies == 0) + return 1; + + /* Compute the lowest cas latency supported */ + latency = log2(latencies) -2; + + /* Walk through searching for the selected latency */ + for (index = 0; index < 3; index++, latency++) { + if (!(latencies & (1 << latency))) { + continue; + } + if (latency == min_latency) + break; + } + /* If I can't find the latency or my index is bad error */ + if ((latency != min_latency) || (index >= 3)) { + return -2; + } + + /* Read the min_cycle_time for this latency */ + value = spd_read_byte(spd_device, latency_indicies[index]); + if (value < 0) + return -1; + + value = convert_to_linear(value); + /* All is good if the selected clock speed + * is what I need or slower. + */ + if (value <= min_cycle_time) + return 1; + + /* That didn't work out... */ + return -2; +} + static struct spd_set_memclk_result spd_set_memclk(const struct mem_controller *ctrl, struct mem_info *meminfo) { /* Compute the minimum cycle time for these dimms */ @@ -1856,10 +1902,6 @@ printk_raminit("3 min_latency: %08x\n", min_latency);
for (i = 0; (i < DIMM_SOCKETS); i++) { - int latencies; - int latency; - int index; - int value; u32 spd_device = ctrl->channel0[i];
if (!(meminfo->dimm_mask & (1 << i))) { @@ -1870,42 +1912,17 @@ } }
- latencies = spd_read_byte(spd_device, SPD_CAS_LAT); - if (latencies < 0) goto hw_error; - if (latencies == 0) { + switch (check_spd_latency_available(spd_device, min_cycle_time, min_latency)) { + case -2: + /* We have an error, disable the dimm */ + meminfo->dimm_mask = disable_dimm(ctrl, i, meminfo); + break; + case -1: + goto hw_error; + break; + case 1: continue; } - - /* Compute the lowest cas latency supported */ - latency = log2(latencies) -2; - - /* Walk through searching for the selected latency */ - for (index = 0; index < 3; index++, latency++) { - if (!(latencies & (1 << latency))) { - continue; - } - if (latency == min_latency) - break; - } - /* If I can't find the latency or my index is bad error */ - if ((latency != min_latency) || (index >= 3)) { - goto dimm_err; - } - - /* Read the min_cycle_time for this latency */ - value = spd_read_byte(spd_device, latency_indicies[index]); - if (value < 0) goto hw_error; - - value = convert_to_linear(value); - /* All is good if the selected clock speed - * is what I need or slower. - */ - if (value <= min_cycle_time) { - continue; - } - /* Otherwise I have an error, disable the dimm */ - dimm_err: - meminfo->dimm_mask = disable_dimm(ctrl, i, meminfo); }
printk_raminit("4 min_cycle_time: %08x\n", min_cycle_time);