Refactor K8 rev F DDR2 CL timing retrieval.
This will allow usage of compatible DIMMS in a dual channel setup instead of requiring the DIMMS to be identical. Code impact is minimal because a large chunk of code has been moved into a separate function with almost no changes. Tested, yields identical results and identical logs. Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net> Acked-by: Peter Stuge <peter@stuge.se> git-svn-id: svn://svn.coreboot.org/coreboot/trunk@3866 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
This commit is contained in:
parent
abcddcd392
commit
1d72e10bb4
|
@ -1702,6 +1702,96 @@ static unsigned convert_to_linear(unsigned value)
|
|||
return value;
|
||||
}
|
||||
|
||||
static const uint8_t latency_indicies[] = { 25, 23, 9 };
|
||||
|
||||
int find_optimum_spd_latency(u32 spd_device, unsigned *min_latency, unsigned *min_cycle_time)
|
||||
{
|
||||
int new_cycle_time, new_latency;
|
||||
int index;
|
||||
int latencies;
|
||||
int latency;
|
||||
|
||||
/* First find the supported CAS latencies
|
||||
* Byte 18 for DDR SDRAM is interpreted:
|
||||
* bit 3 == CAS Latency = 3
|
||||
* bit 4 == CAS Latency = 4
|
||||
* bit 5 == CAS Latency = 5
|
||||
* bit 6 == CAS Latency = 6
|
||||
*/
|
||||
new_cycle_time = 0x500;
|
||||
new_latency = 6;
|
||||
|
||||
latencies = spd_read_byte(spd_device, SPD_CAS_LAT);
|
||||
if (latencies <= 0)
|
||||
return 1;
|
||||
|
||||
printk_raminit("\tlatencies: %08x\n", latencies);
|
||||
/* Compute the lowest cas latency which can be expressed in this
|
||||
* particular SPD EEPROM. You can store at most settings for 3
|
||||
* contiguous CAS latencies, so by taking the highest CAS
|
||||
* latency maked as supported in the SPD and subtracting 2 you
|
||||
* get the lowest expressable CAS latency. That latency is not
|
||||
* necessarily supported, but a (maybe invalid) entry exists
|
||||
* for it.
|
||||
*/
|
||||
latency = log2(latencies) - 2;
|
||||
|
||||
/* Loop through and find a fast clock with a low latency */
|
||||
for (index = 0; index < 3; index++, latency++) {
|
||||
int value;
|
||||
if ((latency < 3) || (latency > 6) ||
|
||||
(!(latencies & (1 << latency)))) {
|
||||
continue;
|
||||
}
|
||||
value = spd_read_byte(spd_device, latency_indicies[index]);
|
||||
if (value < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
printk_raminit("\tindex: %08x\n", index);
|
||||
printk_raminit("\t\tlatency: %08x\n", latency);
|
||||
printk_raminit("\t\tvalue1: %08x\n", value);
|
||||
|
||||
value = convert_to_linear(value);
|
||||
|
||||
printk_raminit("\t\tvalue2: %08x\n", value);
|
||||
|
||||
/* Only increase the latency if we decrease the clock */
|
||||
if (value >= *min_cycle_time ) {
|
||||
if (value < new_cycle_time) {
|
||||
new_cycle_time = value;
|
||||
new_latency = latency;
|
||||
} else if (value == new_cycle_time) {
|
||||
if (new_latency > latency) {
|
||||
new_latency = latency;
|
||||
}
|
||||
}
|
||||
}
|
||||
printk_raminit("\t\tnew_cycle_time: %08x\n", new_cycle_time);
|
||||
printk_raminit("\t\tnew_latency: %08x\n", new_latency);
|
||||
|
||||
}
|
||||
|
||||
if (new_latency > 6){
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Does min_latency need to be increased? */
|
||||
if (new_cycle_time > *min_cycle_time) {
|
||||
*min_cycle_time = new_cycle_time;
|
||||
}
|
||||
|
||||
/* Does min_cycle_time need to be increased? */
|
||||
if (new_latency > *min_latency) {
|
||||
*min_latency = new_latency;
|
||||
}
|
||||
|
||||
printk_raminit("2 min_cycle_time: %08x\n", *min_cycle_time);
|
||||
printk_raminit("2 min_latency: %08x\n", *min_latency);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 */
|
||||
|
@ -1710,8 +1800,6 @@ static struct spd_set_memclk_result spd_set_memclk(const struct mem_controller *
|
|||
int i;
|
||||
uint32_t value;
|
||||
|
||||
static const uint8_t latency_indicies[] = { 25, 23, 9 };
|
||||
|
||||
static const uint16_t min_cycle_times[] = { // use full speed to compare
|
||||
[NBCAP_MEMCLK_NOLIMIT] = 0x250, /*2.5ns */
|
||||
[NBCAP_MEMCLK_333MHZ] = 0x300, /* 3.0ns */
|
||||
|
@ -1735,10 +1823,6 @@ static struct spd_set_memclk_result spd_set_memclk(const struct mem_controller *
|
|||
* by both the memory controller and the dimms.
|
||||
*/
|
||||
for (i = 0; i < DIMM_SOCKETS; i++) {
|
||||
int new_cycle_time, new_latency;
|
||||
int index;
|
||||
int latencies;
|
||||
int latency;
|
||||
u32 spd_device = ctrl->channel0[i];
|
||||
|
||||
printk_raminit("1.1 dimm_mask: %08x\n", meminfo->dimm_mask);
|
||||
|
@ -1750,83 +1834,15 @@ static struct spd_set_memclk_result spd_set_memclk(const struct mem_controller *
|
|||
}
|
||||
}
|
||||
|
||||
/* First find the supported CAS latencies
|
||||
* Byte 18 for DDR SDRAM is interpreted:
|
||||
* bit 3 == CAS Latency = 3
|
||||
* bit 4 == CAS Latency = 4
|
||||
* bit 5 == CAS Latency = 5
|
||||
* bit 6 == CAS Latency = 6
|
||||
*/
|
||||
new_cycle_time = 0x500;
|
||||
new_latency = 6;
|
||||
|
||||
latencies = spd_read_byte(spd_device, SPD_CAS_LAT);
|
||||
if (latencies <= 0) continue;
|
||||
|
||||
printk_raminit("i: %08x\n",i);
|
||||
printk_raminit("\tlatencies: %08x\n", latencies);
|
||||
/* Compute the lowest cas latency which can be expressed in this
|
||||
* particular SPD EEPROM. You can store at most settings for 3
|
||||
* contiguous CAS latencies, so by taking the highest CAS
|
||||
* latency maked as supported in the SPD and subtracting 2 you
|
||||
* get the lowest expressable CAS latency. That latency is not
|
||||
* necessarily supported, but a (maybe invalid) entry exists
|
||||
* for it.
|
||||
*/
|
||||
latency = log2(latencies) - 2;
|
||||
|
||||
/* Loop through and find a fast clock with a low latency */
|
||||
for (index = 0; index < 3; index++, latency++) {
|
||||
int value;
|
||||
if ((latency < 3) || (latency > 6) ||
|
||||
(!(latencies & (1 << latency)))) {
|
||||
continue;
|
||||
}
|
||||
value = spd_read_byte(spd_device, latency_indicies[index]);
|
||||
if (value < 0) {
|
||||
goto hw_error;
|
||||
}
|
||||
|
||||
printk_raminit("\tindex: %08x\n", index);
|
||||
printk_raminit("\t\tlatency: %08x\n", latency);
|
||||
printk_raminit("\t\tvalue1: %08x\n", value);
|
||||
|
||||
value = convert_to_linear(value);
|
||||
|
||||
printk_raminit("\t\tvalue2: %08x\n", value);
|
||||
|
||||
/* Only increase the latency if we decrease the clock */
|
||||
if (value >= min_cycle_time ) {
|
||||
if (value < new_cycle_time) {
|
||||
new_cycle_time = value;
|
||||
new_latency = latency;
|
||||
} else if (value == new_cycle_time) {
|
||||
if (new_latency > latency) {
|
||||
new_latency = latency;
|
||||
}
|
||||
}
|
||||
}
|
||||
printk_raminit("\t\tnew_cycle_time: %08x\n", new_cycle_time);
|
||||
printk_raminit("\t\tnew_latency: %08x\n", new_latency);
|
||||
|
||||
}
|
||||
|
||||
if (new_latency > 6){
|
||||
switch (find_optimum_spd_latency(spd_device, &min_latency, &min_cycle_time)) {
|
||||
case -1:
|
||||
goto hw_error;
|
||||
break;
|
||||
case 1:
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Does min_latency need to be increased? */
|
||||
if (new_cycle_time > min_cycle_time) {
|
||||
min_cycle_time = new_cycle_time;
|
||||
}
|
||||
|
||||
/* Does min_cycle_time need to be increased? */
|
||||
if (new_latency > min_latency) {
|
||||
min_latency = new_latency;
|
||||
}
|
||||
|
||||
printk_raminit("2 min_cycle_time: %08x\n", min_cycle_time);
|
||||
printk_raminit("2 min_latency: %08x\n", min_latency);
|
||||
}
|
||||
}
|
||||
/* Make a second pass through the dimms and disable
|
||||
* any that cannot support the selected memclk and cas latency.
|
||||
|
|
Loading…
Reference in New Issue