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;
|
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)
|
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 */
|
/* 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;
|
int i;
|
||||||
uint32_t value;
|
uint32_t value;
|
||||||
|
|
||||||
static const uint8_t latency_indicies[] = { 25, 23, 9 };
|
|
||||||
|
|
||||||
static const uint16_t min_cycle_times[] = { // use full speed to compare
|
static const uint16_t min_cycle_times[] = { // use full speed to compare
|
||||||
[NBCAP_MEMCLK_NOLIMIT] = 0x250, /*2.5ns */
|
[NBCAP_MEMCLK_NOLIMIT] = 0x250, /*2.5ns */
|
||||||
[NBCAP_MEMCLK_333MHZ] = 0x300, /* 3.0ns */
|
[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.
|
* by both the memory controller and the dimms.
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < DIMM_SOCKETS; i++) {
|
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];
|
u32 spd_device = ctrl->channel0[i];
|
||||||
|
|
||||||
printk_raminit("1.1 dimm_mask: %08x\n", meminfo->dimm_mask);
|
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("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 */
|
switch (find_optimum_spd_latency(spd_device, &min_latency, &min_cycle_time)) {
|
||||||
for (index = 0; index < 3; index++, latency++) {
|
case -1:
|
||||||
int value;
|
goto hw_error;
|
||||||
if ((latency < 3) || (latency > 6) ||
|
break;
|
||||||
(!(latencies & (1 << latency)))) {
|
case 1:
|
||||||
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){
|
|
||||||
continue;
|
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
|
/* Make a second pass through the dimms and disable
|
||||||
* any that cannot support the selected memclk and cas latency.
|
* any that cannot support the selected memclk and cas latency.
|
||||||
|
|
Loading…
Reference in New Issue