[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