[coreboot-gerrit] New patch to review for coreboot: nb/intel/x4x: Refactor dram freq and cas selection
Arthur Heymans (arthur@aheymans.xyz)
gerrit at coreboot.org
Tue Jan 17 00:19:29 CET 2017
Arthur Heymans (arthur at aheymans.xyz) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/18156
-gerrit
commit 46d4eb6b1aed7b63fc20c71c79c69190505b24f8
Author: Arthur Heymans <arthur at aheymans.xyz>
Date: Mon Jan 16 23:32:02 2017 +0100
nb/intel/x4x: Refactor dram freq and cas selection
Inspired by i945 code.
The code incorrectly accounts for highest CAS with respect to
SPD_MIN_CYCLE_TIME_AT_CAS_MAX (and max_cas - 1, etc...) and did not
check tAC.
Adds some debugging output for freq and cas selection.
Change-Id: Ie0d8326af50d3125bf35918ba645a6df27dd2ee4
Signed-off-by: Arthur Heymans <arthur at aheymans.xyz>
---
src/northbridge/intel/x4x/raminit.c | 97 +++++++++++++++++++++----------------
1 file changed, 56 insertions(+), 41 deletions(-)
diff --git a/src/northbridge/intel/x4x/raminit.c b/src/northbridge/intel/x4x/raminit.c
index 86f63f1..6e5488e 100644
--- a/src/northbridge/intel/x4x/raminit.c
+++ b/src/northbridge/intel/x4x/raminit.c
@@ -160,13 +160,6 @@ static void sdram_read_spds(struct sysinfo *s)
}
}
-static u8 msbpos(u8 val) //Reverse
-{
- u8 i;
- for (i = 7; (i >= 0) && ((val & (1 << i)) == 0); i--);
- return i;
-}
-
static void mchinfo_ddr2(struct sysinfo *s)
{
const u32 eax = cpuid_ext(0x04, 0).eax;
@@ -199,13 +192,28 @@ static void sdram_detect_ram_speed(struct sysinfo *s)
{
u8 i;
u8 commoncas = 0;
+ u8 highest_commoncas;
u8 currcas;
u8 currfreq;
- u8 maxfreq;
+ u8 maxfreq, minfreq;
u8 freq = 0;
+ u8 highest_supported_cas = 0;
+ u8 currcas_mask;
+ u8 idx;
+ u8 tclk, tclk_target;
+ u8 tac, tac_target;
+
+ const u8 ddr2_speeds_table[] = {
+ 0x30, 0x45, /* DDR2 667: tCLK = 3.0ns tAC = 0.45ns */
+ 0x25, 0x40, /* DDR2 800: tCLK = 2.5ns tAC = 0.40ns */
+ };
+
+ const u8 spd_lookup_table[] = {
+ SPD_MIN_CYCLE_TIME_AT_CAS_MAX, SPD_ACCESS_TIME_FROM_CLOCK,
+ SPD_SDRAM_CYCLE_TIME_2ND, SPD_ACCESS_TIME_FROM_CLOCK_2ND,
+ SPD_SDRAM_CYCLE_TIME_3RD, SPD_ACCESS_TIME_FROM_CLOCK_3RD,
+ };
- // 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
@@ -225,55 +233,62 @@ static void sdram_detect_ram_speed(struct sysinfo *s)
break;
}
- // Max RAM speed
- if (s->spd_type == DDR2) {
-
- maxfreq = MEM_CLOCK_800MHz;
-
- // Choose common CAS latency from {6,5}, 4 does not work
- commoncas = 0x60;
+ maxfreq = MEM_CLOCK_800MHz;
+ minfreq = MEM_CLOCK_667MHz;
+ if (s->spd_type == DDR2) {
+ /*
+ * Only CAS 5 and 6 are supported
+ * Do a quick check if dimms have supported CAS in common
+ */
+ commoncas = SPD_CAS_LATENCY_DDR2_6 | SPD_CAS_LATENCY_DDR2_5;
FOR_EACH_POPULATED_DIMM(s->dimms, i) {
commoncas &= s->dimms[i].cas_latencies;
}
if (commoncas == 0) {
die("No common CAS among dimms\n");
}
-
- // Working from fastest to slowest,
- // fast->slow 5 at 800 6 at 800 5 at 667
- found = 0;
- for (currcas = 5; currcas <= msbpos(commoncas); currcas++) {
- currfreq = maxfreq;
- if (currfreq == MEM_CLOCK_800MHz) {
+ if (commoncas & SPD_CAS_LATENCY_DDR2_6)
+ highest_commoncas = 6;
+ else /* commoncas & SPD_CAS_LATENCY_DDR2_5 */
+ highest_commoncas = 5;
+
+ for (currfreq = maxfreq - minfreq; currfreq >= 0; currfreq--) {
+ printk(BIOS_DEBUG, "Trying DDR2: %dMHz\n", currfreq ? 800 : 667);
+ for (currcas = 5; currcas <= highest_commoncas; currcas++) {
+ printk(BIOS_DEBUG, " Trying CAS: %d\n", currcas);
found = 1;
FOR_EACH_POPULATED_DIMM(s->dimms, i) {
- if (s->dimms[i].spd_data[idx800[currcas][0]] > idx800[currcas][1]) {
- // this is too fast
- found = 0;
+ currcas_mask = s->dimms[i].cas_latencies;
+ if (currcas_mask & SPD_CAS_LATENCY_DDR2_7) {
+ highest_supported_cas = 7;
+ } else if (currcas_mask & SPD_CAS_LATENCY_DDR2_6) {
+ highest_supported_cas = 6;
+ } else if (currcas_mask & SPD_CAS_LATENCY_DDR2_5) {
+ highest_supported_cas = 5;
+ }
+
+ idx = highest_supported_cas - currcas;
+ printk(BIOS_DEBUG, " dimm: %d, idx: %d\n", i, idx);
+ tclk = s->dimms[i].spd_data[spd_lookup_table[2*idx]];
+ tclk_target = ddr2_speeds_table[2 * currfreq];
+ tac = s->dimms[i].spd_data[spd_lookup_table[2*idx + 1]];
+ tac_target = ddr2_speeds_table[2 * currfreq + 1];
+ printk(BIOS_DEBUG, " tCLK: 0x%x , tCLK_target: 0x%x\n", tclk, tclk_target);
+ printk(BIOS_DEBUG, " tAC: 0x%x , tAC_target: 0x%x\n", tac, tac_target);
+ if ((tclk > tclk_target) && (tac > tac_target)) {
+ printk(BIOS_DEBUG, " Timing too fast");
+ found &= 0;
}
}
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;
- }
- }
- }
-
if (!found)
die("No valid CAS/frequencies detected\n");
- s->selected_timings.mem_clk = currfreq;
+ s->selected_timings.mem_clk = currfreq + minfreq;
s->selected_timings.CAS = currcas;
} else { // DDR3
More information about the coreboot-gerrit
mailing list