[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
Mon Jan 30 19:30:21 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 30d24e0c265bef2fe30e79b5a97ba577e8ecb0de
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 | 148 +++++++++++++++++++++++++-----------
 1 file changed, 104 insertions(+), 44 deletions(-)

diff --git a/src/northbridge/intel/x4x/raminit.c b/src/northbridge/intel/x4x/raminit.c
index 86f63f1..a0a7cbd 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;
@@ -195,17 +188,58 @@ static void mchinfo_ddr2(struct sysinfo *s)
 	}
 }
 
+/* Decode tclk to picoseconds */
+static int decode_tclk(u8 spd_data)
+{
+	int high_nibble = (spd_data >> 4) * 1000;
+	int low_nibble;
+	switch (spd_data & 0xf) {
+	case 0xa:
+		low_nibble = 250;
+		break;
+	case 0xb:
+		low_nibble = 330;
+		break;
+	case 0xc:
+		low_nibble = 660;
+		break;
+	case 0xd:
+		low_nibble = 750;
+	default:
+		low_nibble = (spd_data & 0xf) * 100;
+	}
+
+	return high_nibble + low_nibble;
+}
+
 static void sdram_detect_ram_speed(struct sysinfo *s)
 {
-	u8 i;
+	u8 i, j;
 	u8 commoncas = 0;
+	u8 highest_commoncas;
 	u8 currcas;
 	u8 currfreq;
 	u8 maxfreq;
 	u8 freq = 0;
+	u8 high_cas;
+	u8 spd_tclk_lat[TOTAL_DIMMS][8] = { 0 };
+	u8 spd_tac_lat[TOTAL_DIMMS][8] = { 0 };
+	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 +259,83 @@ 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) {
+				high_cas = 7;
+			} else if (s->dimms[i].cas_latencies & SPD_CAS_LATENCY_DDR2_6) {
+				high_cas = 6;
+			} else if (s->dimms[i].cas_latencies & SPD_CAS_LATENCY_DDR2_5) {
+				high_cas = 5;
+			} /* Don't check for lower CAS since not supported */
 			commoncas &= s->dimms[i].cas_latencies;
+			for (j = 0; j < 3; i++) {
+				if (s->dimms[i].cas_latencies & (1 << (high_cas - j))) {
+						spd_tclk_lat[i][high_cas - j] =
+							s->dimms[i].spd_data[spd_lookup_table[2 * j]];
+						spd_tac_lat[i][high_cas - j] =
+							s->dimms[i].spd_data[spd_lookup_table[2 * j + 1]];
+				}
+			}
 		}
-		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
+					tclk = decode_tclk(spd_tclk_lat[i][currcas]);
+					if (tclk == 0) {
+						/* this timing is not supprted */
 						found = 0;
+						break;
+					}
+					tclk_target = ddr2_speeds_table[2 * currfreq];
+					tac = spd_tac_lat[i][currcas];
+					tac_target = ddr2_speeds_table[2 * currfreq + 1];
+					printk(BIOS_DEBUG, "   tCLK: %dps , tCLK_target: %dps\n", tclk, tclk_target);
+					printk(BIOS_DEBUG, "   tAC: 0.%xns , tAC_target: 0.%xns\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