[coreboot-gerrit] Patch set updated for coreboot: nb/intel/x4x: Refactor dram freq and cas selection

Arthur Heymans (arthur@aheymans.xyz) gerrit at coreboot.org
Tue Jan 24 15:03:28 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 a1afec0addeadc877b32048c93ed244a4492e1be
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
    
    The code did not check for tAC and for tCLK potentially selected
    the wrong spd offset for minimum cycle time.
    
    Adds some debugging output for freq and cas selection.
    
    The code is also written to be easily extendable for officially
    unsported dram frequencies like 533MHz and 400MHz which some vendor
    bios seem to support.
    
    Change-Id: Ie0d8326af50d3125bf35918ba645a6df27dd2ee4
    Signed-off-by: Arthur Heymans <arthur at aheymans.xyz>
---
 src/northbridge/intel/x4x/raminit.c | 111 ++++++++++++++++++++++--------------
 1 file changed, 68 insertions(+), 43 deletions(-)

diff --git a/src/northbridge/intel/x4x/raminit.c b/src/northbridge/intel/x4x/raminit.c
index 86f63f1..d604783 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,29 @@ static void sdram_detect_ram_speed(struct sysinfo *s)
 {
 	u8 i;
 	u8 commoncas = 0;
+	u8 highest_commoncas;
 	u8 currcas;
 	u8 currfreq;
 	u8 maxfreq;
 	u8 freq = 0;
+	u8 highest_supported_cas[TOTAL_DIMMS];
+	u8 idx;
+	u8 tclk, tclk_target;
+	u8 tac, tac_target;
+
+	const u8 ddr2_speeds_table[] = {
+		0x50, 0x60, /* DDR2 400: tCLK = 5.0ns  tAC = 0.6ns  */
+		0x3d, 0x50, /* DDR2 533: tCLK = 3.75ns tAC = 0.5ns  */
+		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,57 +234,73 @@ 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;
-
+		/* Only CAS 5 and 6 are supported */
+		commoncas = SPD_CAS_LATENCY_DDR2_6 | SPD_CAS_LATENCY_DDR2_5;
 		FOR_EACH_POPULATED_DIMM(s->dimms, i) {
+			if (s->dimms[i].cas_latencies & SPD_CAS_LATENCY_DDR2_7) {
+				highest_supported_cas[i] = 7;
+			} else if (s->dimms[i].cas_latencies & SPD_CAS_LATENCY_DDR2_6) {
+				highest_supported_cas[i] = 6;
+			} else if (s->dimms[i].cas_latencies & SPD_CAS_LATENCY_DDR2_5) {
+				highest_supported_cas[i] = 5;
+			} /* Don't check for lower CAS since not supported */
 			commoncas &= s->dimms[i].cas_latencies;
 		}
-		if (commoncas == 0) {
+		if (commoncas == 0)
 			die("No common CAS among dimms\n");
-		}
+		else if (commoncas & SPD_CAS_LATENCY_DDR2_6)
+			highest_commoncas = 6;
+		else
+			highest_commoncas = 5;
+
+		/*
+		 * FIXME: datasheets say only 667MHz and 800MHz are supported
+		 * but vendor bios also supports 533MHz and possibly 400MHz
+		 */
+		/* Test from higher to lower frequency, from lower to higher CAS latency */
+		for (currfreq = MEM_CLOCK_800MHz; currfreq >= MEM_CLOCK_667MHz; currfreq--) {
+			printk(BIOS_DEBUG, "Trying DDR2: ");
+			switch (currfreq) {
+			case MEM_CLOCK_400MHz:
+				printk(BIOS_DEBUG, "%dMHz\n", 400);
+			case MEM_CLOCK_533MHz:
+				printk(BIOS_DEBUG, "%dMHz\n", 533);
+			case MEM_CLOCK_667MHz:
+				printk(BIOS_DEBUG, "%dMHz\n", 667);
+			case MEM_CLOCK_800MHz:
+				printk(BIOS_DEBUG, "%dMHz\n", 800);
+			}
 
-		// 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) {
+			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
+					idx = highest_supported_cas[i] - 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\n");
 						found = 0;
+						break; /* No need to check other dimms for these timings */
 					}
 				}
-				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) {
+					s->selected_timings.mem_clk = currfreq;
+					s->selected_timings.CAS = currcas;
+					return;
 				}
 			}
 		}
-
 		if (!found)
 			die("No valid CAS/frequencies detected\n");
 
-		s->selected_timings.mem_clk = currfreq;
-		s->selected_timings.CAS = currcas;
-
 	} else { // DDR3
 		// Limit frequency for MCH
 		maxfreq = (s->max_ddr2_mhz == 800) ? MEM_CLOCK_800MHz : MEM_CLOCK_667MHz;



More information about the coreboot-gerrit mailing list