[coreboot-gerrit] Patch set updated for coreboot: nb/intel/x4x/raminit: Refactor receive enable calibration

Arthur Heymans (arthur@aheymans.xyz) gerrit at coreboot.org
Fri Mar 10 11:01:23 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/18692

-gerrit

commit fae61e5f36cf057787b43254c573a36c1fee26f8
Author: Arthur Heymans <arthur at aheymans.xyz>
Date:   Tue Mar 7 20:48:14 2017 +0100

    nb/intel/x4x/raminit: Refactor receive enable calibration
    
    Moves receive enable calibration to a separate file to lighten
    raminit.c a bit.
    
    Receive enable calibration is quite similar to gm45 so it reuses some
    of it function names.
    
    TESTED on ga-g41m-es2l
    
    Change-Id: I0c970455e609d3ce96a262cbf110336a2079da4d
    Signed-off-by: Arthur Heymans <arthur at aheymans.xyz>
---
 src/northbridge/intel/x4x/Makefile.inc   |   1 +
 src/northbridge/intel/x4x/raminit_ddr2.c | 278 +--------------------------
 src/northbridge/intel/x4x/rcven.c        | 316 +++++++++++++++++++++++++++++++
 src/northbridge/intel/x4x/x4x.h          |   1 +
 4 files changed, 319 insertions(+), 277 deletions(-)

diff --git a/src/northbridge/intel/x4x/Makefile.inc b/src/northbridge/intel/x4x/Makefile.inc
index 34d9b0f..5c64ca7 100644
--- a/src/northbridge/intel/x4x/Makefile.inc
+++ b/src/northbridge/intel/x4x/Makefile.inc
@@ -20,6 +20,7 @@ romstage-y += early_init.c
 romstage-y += raminit.c
 romstage-y += raminit_ddr2.c
 romstage-y += ram_calc.c
+romstage-y += rcven.c
 
 ramstage-y += acpi.c
 ramstage-y += ram_calc.c
diff --git a/src/northbridge/intel/x4x/raminit_ddr2.c b/src/northbridge/intel/x4x/raminit_ddr2.c
index 9c414e2..40903ba 100644
--- a/src/northbridge/intel/x4x/raminit_ddr2.c
+++ b/src/northbridge/intel/x4x/raminit_ddr2.c
@@ -30,11 +30,6 @@
 
 #define ME_UMA_SIZEMB 0
 
-static inline void barrier(void)
-{
-	asm volatile("mfence":::);
-}
-
 static u32 fsb2mhz(u32 speed)
 {
 	return (speed * 267) + 800;
@@ -1233,277 +1228,6 @@ static void jedec_ddr2(struct sysinfo *s)
 	printk(BIOS_DEBUG, "MRS done\n");
 }
 
-static u8 sampledqs(u16 mchloc, u32 addr, u8 hilow, u8 repeat)
-{
-	u8 dqsmatch = 1;
-	volatile u32 strobe;
-
-	while (repeat-- > 0) {
-		MCHBAR8(0x5d8) = MCHBAR8(0x5d8) & ~0x2;
-		udelay(2);
-		MCHBAR8(0x5d8) = MCHBAR8(0x5d8) | 0x2;
-		udelay(2);
-		MCHBAR8(0x9d8) = MCHBAR8(0x9d8) & ~0x2;
-		udelay(2);
-		MCHBAR8(0x9d8) = MCHBAR8(0x9d8) | 0x2;
-		udelay(2);
-		barrier();
-		strobe = read32((u32 *)addr);
-		barrier();
-		if (((MCHBAR32(mchloc) & 0x40) >> 6) != hilow) {
-			dqsmatch = 0;
-		}
-	}
-	return dqsmatch;
-}
-
-static void rcven_ddr2(struct sysinfo *s)
-{
-	u8 i, reg8, ch, lane;
-	u32 addr;
-	u8 tap = 0;
-	u8 savecc, savemedium, savetap, coarsecommon, medium;
-	u8 lanecoarse[8] = {0};
-	u8 mincoarse = 0xff;
-	u8 pitap[2][8];
-	u16 coarsectrl[2];
-	u16 coarsedelay[2];
-	u16 mediumphase[2];
-	u16 readdelay[2];
-	u16 mchbar;
-	MCHBAR8(0x5d8) = MCHBAR8(0x5d8) & ~0xc;
-	MCHBAR8(0x9d8) = MCHBAR8(0x9d8) & ~0xc;
-	MCHBAR8(0x5dc) = MCHBAR8(0x5dc) & ~0x80;
-
-	FOR_EACH_POPULATED_CHANNEL(s->dimms, ch) {
-		addr = (ch << 29);
-		for (i = 0; !RANK_IS_POPULATED(s->dimms, ch, i); i++) {
-			addr += 128*1024*1024;
-		}
-		for (lane = 0; lane < 8; lane++) {
-			printk(BIOS_DEBUG, "Channel %d, Lane %d addr=0x%08x\n", ch, lane, addr);
-			coarsecommon = (s->selected_timings.CAS - 1);
-			switch (lane) {
-				case 0: case 1: medium = 0; break;
-				case 2: case 3: medium = 1; break;
-				case 4: case 5: medium = 2; break;
-				case 6: case 7: medium = 3; break;
-				default: medium = 0; break;
-			}
-			mchbar = 0x400*ch + 0x561 + (lane << 2);
-			tap = 0;
-			MCHBAR32(0x400*ch + 0x248) = (MCHBAR32(0x400*ch + 0x248) & ~0xf0000) |
-				(coarsecommon << 16);
-			MCHBAR16(0x400*ch + 0x58c) = (MCHBAR16(0x400*ch + 0x58c) & ~(3 << (lane*2))) |
-				(medium << (lane*2));
-			MCHBAR8(0x400*ch + 0x560 + lane*4) = MCHBAR8(0x400*ch + 0x560 + lane*4) & ~0xf;
-			MCHBAR8(0x400*ch + 0x560 + lane*4) = MCHBAR8(0x400*ch + 0x560 + lane*4) & ~0x70;
-			savecc = coarsecommon;
-			savemedium = medium;
-			savetap = 0;
-
-			MCHBAR16(0x400*ch + 0x588) = (MCHBAR16(0x400*ch + 0x588) & ~(3 << (lane*2))) |
-				(1 << (lane*2));
-
-			printk(BIOS_DEBUG, "rcven 0.1 coarse=%d\n", coarsecommon);
-			while (sampledqs(mchbar, addr, 1, 1) == 1) {
-				if (medium < 3) {
-					medium++;
-					MCHBAR16(0x400*ch + 0x58c) = (MCHBAR16(0x400*ch + 0x58c) &
-						~(3 << (lane*2))) | (medium << (lane*2));
-				} else {
-					medium = 0;
-					coarsecommon++;
-					MCHBAR32(0x400*ch + 0x248) = (MCHBAR32(0x400*ch + 0x248) &
-						~0xf0000) | (coarsecommon << 16);
-					MCHBAR16(0x400*ch + 0x58c) = (MCHBAR16(0x400*ch + 0x58c) &
-						~(3 << (lane*2))) | (medium << (lane*2));
-				}
-				if (coarsecommon > 16) {
-					die("Coarse > 16: DQS tuning failed, halt\n");
-					break;
-				}
-			}
-			printk(BIOS_DEBUG, "  GOT IT (high -> low transition) coarse=%d medium=%d\n", coarsecommon, medium);
-
-			savemedium = medium;
-			savecc = coarsecommon;
-			if (medium < 3) {
-				medium++;
-				MCHBAR16(0x400*ch + 0x58c) = (MCHBAR16(0x400*ch + 0x58c) &
-					~(3 << (lane*2))) | (medium << (lane*2));
-			} else {
-				medium = 0;
-				coarsecommon++;
-
-				MCHBAR32(0x400*ch + 0x248) = (MCHBAR32(0x400*ch + 0x248) & ~0xf0000) |
-					(coarsecommon << 16);
-				MCHBAR16(0x400*ch + 0x58c) = (MCHBAR16(0x400*ch + 0x58c) & ~(3 << (lane*2))) |
-					(medium << (lane*2));
-			}
-
-			printk(BIOS_DEBUG, "rcven 0.2\n");
-			while (sampledqs(mchbar, addr, 0, 1) == 1) {
-				savemedium = medium;
-				savecc = coarsecommon;
-				if (medium < 3) {
-					medium++;
-					MCHBAR16(0x400*ch + 0x58c) = (MCHBAR16(0x400*ch + 0x58c) &
-						~(3 << (lane*2))) | (medium << (lane*2));
-				} else {
-					medium = 0;
-					coarsecommon++;
-					MCHBAR32(0x400*ch + 0x248) = (MCHBAR32(0x400*ch + 0x248) &
-						~0xf0000) | (coarsecommon << 16);
-					MCHBAR16(0x400*ch + 0x58c) = (MCHBAR16(0x400*ch + 0x58c) &
-						~(3 << (lane*2))) | (medium << (lane*2));
-				}
-				if (coarsecommon > 16) {
-					die("Coarse DQS tuning 2 failed, halt\n");
-					break;
-				}
-			}
-			printk(BIOS_DEBUG, "  GOT IT (low -> high transition) coarse=%d medium=%d\n", coarsecommon, medium);
-
-
-			coarsecommon = savecc;
-			medium = savemedium;
-			MCHBAR32(0x400*ch + 0x248) = (MCHBAR32(0x400*ch + 0x248) &
-				~0xf0000) | (coarsecommon << 16);
-			MCHBAR16(0x400*ch + 0x58c) = (MCHBAR16(0x400*ch + 0x58c) &
-				~(3 << (lane*2))) | (medium << (lane*2));
-
-			printk(BIOS_DEBUG, "rcven 0.3\n");
-			tap = 0;
-			while (sampledqs(mchbar, addr, 1, 1) == 0) {
-				savetap = tap;
-				tap++;
-				if (tap > 14) {
-					break;
-				}
-				MCHBAR8(0x400*ch + 0x560 + (lane*4)) =
-					(MCHBAR8(0x400*ch + 0x560 + (lane*4)) & ~0xf) | tap;
-			}
-
-			tap = savetap;
-			MCHBAR8(0x400*ch + 0x560 + (lane*4)) =
-				(MCHBAR8(0x400*ch + 0x560 + (lane*4)) & ~0xf) | tap;
-			MCHBAR8(0x400*ch + 0x560 + (lane*4)) =
-				(MCHBAR8(0x400*ch + 0x560 + (lane*4)) & ~0x70) | 0x30;
-			if (medium < 3) {
-				medium++;
-				MCHBAR16(0x400*ch + 0x58c) = (MCHBAR16(0x400*ch + 0x58c) &
-					~(3 << (lane*2))) | (medium << (lane*2));
-			} else {
-				medium = 0;
-				coarsecommon++;
-				MCHBAR32(0x400*ch + 0x248) = (MCHBAR32(0x400*ch + 0x248) &
-					~0xf0000) | (coarsecommon << 16);
-				MCHBAR16(0x400*ch + 0x58c) = (MCHBAR16(0x400*ch + 0x58c) &
-					~(3 << (lane*2))) | (medium << (lane*2));
-			}
-			if (sampledqs(mchbar, addr, 1, 1) == 0) {
-				die("Not at DQS high, doh\n");
-			}
-
-			printk(BIOS_DEBUG, "rcven 0.4\n");
-			while (sampledqs(mchbar, addr, 1, 1) == 1) {
-				coarsecommon--;
-				MCHBAR32(0x400*ch + 0x248) = (MCHBAR32(0x400*ch + 0x248) &
-					~0xf0000) | (coarsecommon << 16);
-				if (coarsecommon == 0) {
-					die("Couldn't find DQS-high 0 indicator, halt\n");
-					break;
-				}
-			}
-			printk(BIOS_DEBUG, "  GOT IT (high -> low transition) coarse=%d medium=%d\n", coarsecommon, medium);
-
-			printk(BIOS_DEBUG, "rcven 0.5\n");
-			while (sampledqs(mchbar, addr, 0, 1) == 1) {
-				savemedium = medium;
-				savecc = coarsecommon;
-				if (medium < 3) {
-					medium++;
-					MCHBAR16(0x400*ch + 0x58c) = (MCHBAR16(0x400*ch + 0x58c) &
-						~(3 << (lane*2))) | (medium << (lane*2));
-				} else {
-					medium = 0;
-					coarsecommon++;
-					MCHBAR32(0x400*ch + 0x248) = (MCHBAR32(0x400*ch + 0x248) &
-						~0xf0000) | (coarsecommon << 16);
-					MCHBAR16(0x400*ch + 0x58c) = (MCHBAR16(0x400*ch + 0x58c) &
-						~(3 << (lane*2))) | (medium << (lane*2));
-				}
-				if (coarsecommon > 16) {
-					die("Coarse DQS tuning 5 failed, halt\n");
-					break;
-				}
-			}
-			printk(BIOS_DEBUG, "  GOT IT (low -> high transition) coarse=%d medium=%d\n", coarsecommon, medium);
-
-			printk(BIOS_DEBUG, "rcven 0.6\n");
-			coarsecommon = savecc;
-			medium = savemedium;
-			MCHBAR32(0x400*ch + 0x248) = (MCHBAR32(0x400*ch + 0x248) &
-				~0xf0000) | (coarsecommon << 16);
-			MCHBAR16(0x400*ch + 0x58c) = (MCHBAR16(0x400*ch + 0x58c) &
-				~(3 << (lane*2))) | (medium << (lane*2));
-			while (sampledqs(mchbar, addr, 1, 1) == 0) {
-				savetap = tap;
-				tap++;
-				if (tap > 14) {
-					break;
-				}
-				MCHBAR8(0x400*ch + 0x560 + lane*4) =
-					(MCHBAR8(0x400*ch + 0x560 + lane*4) & ~0xf) | tap;
-			}
-			tap = savetap;
-			MCHBAR8(0x400*ch + 0x560 + lane*4) =
-				(MCHBAR8(0x400*ch + 0x560 + lane*4) & ~0xf) | tap;
-			MCHBAR8(0x400*ch + 0x560 + lane*4) =
-				(MCHBAR8(0x400*ch + 0x560 + lane*4) & ~0x70) | 0x70;
-
-			pitap[ch][lane] = 0x70 | tap;
-
-			MCHBAR16(0x400*ch + 0x588) = MCHBAR16(0x400*ch + 0x588) & ~(3 << (lane*2));
-			lanecoarse[lane] = coarsecommon;
-			printk(BIOS_DEBUG, "rcven 0.7\n");
-		} // END EACH LANE
-
-		// Find minimum coarse value
-		for (lane = 0; lane < 8; lane++) {
-			if (mincoarse > lanecoarse[lane]) {
-				mincoarse = lanecoarse[lane];
-			}
-		}
-
-		printk(BIOS_DEBUG, "Found min coarse value = %d\n", mincoarse);
-
-		for (lane = 0; lane < 8; lane++) {
-			reg8 = (lanecoarse[lane] == 0) ? 0 : lanecoarse[lane] - mincoarse;
-			MCHBAR16(0x400*ch + 0x5fa) = (MCHBAR16(0x400*ch + 0x5fa) & ~(3 << (lane*2))) |
-				(reg8 << (lane*2));
-		}
-		MCHBAR32(0x400*ch + 0x248) = (MCHBAR32(0x400*ch + 0x248) & ~0xf0000) | (mincoarse << 16);
-		coarsectrl[ch] = mincoarse;
-		coarsedelay[ch] = MCHBAR16(0x400*ch + 0x5fa);
-		mediumphase[ch] = MCHBAR16(0x400*ch + 0x58c);
-		readdelay[ch] = MCHBAR16(0x400*ch + 0x588);
-	} // END EACH POPULATED CHANNEL
-
-	FOR_EACH_CHANNEL(ch) {
-		for (lane = 0; lane < 8; lane++) {
-			MCHBAR8(0x400*ch + 0x560 + (lane*4)) =
-				(MCHBAR8(0x400*ch + 0x560 + (lane*4)) & ~0xf) | pitap[ch][lane];
-		}
-		MCHBAR32(0x400*ch + 0x248) = (MCHBAR32(0x400*ch + 0x248) & ~0xf0000) |
-			(coarsectrl[ch] << 16);
-		MCHBAR16(0x400*ch + 0x5fa) = coarsedelay[ch];
-		MCHBAR16(0x400*ch + 0x58c) = mediumphase[ch];
-	}
-	printk(BIOS_DEBUG, "End rcven\n");
-}
-
 static void sdram_save_receive_enable(void)
 {
 	int i = 0;
@@ -1572,7 +1296,7 @@ static void sdram_program_receive_enable(struct sysinfo *s)
 		|| (s->boot_path == BOOT_PATH_RESUME)) {
 		sdram_recover_receive_enable();
 	} else {
-		rcven_ddr2(s);
+		rcven(s);
 		sdram_save_receive_enable();
 	}
 }
diff --git a/src/northbridge/intel/x4x/rcven.c b/src/northbridge/intel/x4x/rcven.c
new file mode 100644
index 0000000..f449b7d
--- /dev/null
+++ b/src/northbridge/intel/x4x/rcven.c
@@ -0,0 +1,316 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2015 Damien Zammit <damien at zamaudio.com>
+ * Copyright (C) 2017 Arthur Heymans <arthur at aheymans.xyz>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <arch/io.h>
+#include <console/console.h>
+#include <delay.h>
+#include "iomap.h"
+#include "x4x.h"
+
+#define MAX_COARSE 16
+#define DQS_HIGH 1
+#define DQS_LOW 0
+#define MATCH 1
+#define NOT_MATCH 0
+
+typedef struct {
+	u8 medium;
+	u8 coarse;
+	u8 pi;
+	u8 tap;
+} rec_timing_t;
+
+static inline void barrier(void)
+{
+	asm volatile("mfence":::);
+}
+
+static u8 sampledqs(u16 mchloc, u32 addr, u8 hilow)
+{
+	u8 dqsmatch = MATCH;
+	volatile u32 strobe;
+
+	MCHBAR8(0x5d8) = MCHBAR8(0x5d8) & ~0x2;
+	udelay(2);
+	MCHBAR8(0x5d8) = MCHBAR8(0x5d8) | 0x2;
+	udelay(2);
+	MCHBAR8(0x9d8) = MCHBAR8(0x9d8) & ~0x2;
+	udelay(2);
+	MCHBAR8(0x9d8) = MCHBAR8(0x9d8) | 0x2;
+	udelay(2);
+	barrier();
+	strobe = read32((u32 *)addr);
+	barrier();
+	if (((MCHBAR32(mchloc) & 0x40) >> 6) != hilow)
+		dqsmatch = NOT_MATCH;
+	return dqsmatch;
+}
+
+static void program_timing(rec_timing_t *timing, u8 channel, u8 lane)
+{
+	u32 reg32;
+	u16 reg16;
+	u8 reg8;
+
+	printk(BIOS_DEBUG, "      Programming timings:"
+		"Coarse: %d, Medium: %d, TAP: %d, PI: %d\n",
+		timing->coarse, timing->medium, timing->tap, timing->pi);
+
+	reg32 = MCHBAR32(0x400 * channel + 0x248);
+	reg32 &= ~0xf0000;
+	reg32 |= timing->coarse << 16;
+	MCHBAR32(0x400 * channel + 0x248) = reg32;
+
+	reg16 = MCHBAR16(0x400 * channel + 0x58c);
+	reg16 &= ~(3 << (lane * 2));
+	reg16 |= (timing->medium << (lane * 2));
+	MCHBAR16(0x400 * channel + 0x58c) = reg16;
+
+	reg8 = MCHBAR8(0x400 * channel + 0x560 + lane * 4);
+	reg8 &= ~0xf;
+	reg8 |= timing->tap;
+	MCHBAR8(0x400 * channel + 0x560 + lane * 4) = reg8;
+
+	reg8 = MCHBAR8(0x400 * channel + 0x560 + lane * 4);
+	reg8 &= ~0x70;
+	reg8 |= (timing->pi & 7) << 4;
+	MCHBAR8(0x400 * channel + 0x560 + lane * 4) = reg8;
+}
+
+static void increase_medium(rec_timing_t *timing)
+{
+	if (timing->medium < 3) {
+		timing->medium++;
+	} else {
+		timing->medium = 0;
+		timing->coarse++;
+	}
+}
+
+static void decrease_medium(rec_timing_t *timing)
+{
+	if (timing->medium == 0) {
+		timing->medium = 3;
+		timing->coarse--;
+	} else {
+		timing->medium--;
+	}
+}
+
+static int decr_coarse_low(u32 mchbar, u8 channel, u8 lane, u32 addr,
+			rec_timing_t *timing)
+{
+	printk(BIOS_DEBUG, "  Decreasing coarse until high to low transition is found\n");
+	while (sampledqs(mchbar, addr, DQS_HIGH) == MATCH) {
+		timing->coarse--;
+		program_timing(timing, channel, lane);
+		if (timing->coarse == 0) {
+			printk(BIOS_DEBUG, "Couldn't find DQS-high 0 indicator, halt\n");
+			return -1;
+		}
+	}
+	printk(BIOS_DEBUG, "    high -> low transition at coarse=%d medium=%d\n",
+		timing->coarse, timing->medium);
+	return 0;
+}
+
+static void fine_search_dqs_high(u32 mchbar, u8 channel, u8 lane, u32 addr,
+				rec_timing_t *timing)
+{
+	printk(BIOS_DEBUG, "  Increasing TAP until high to low transition is found\n");
+	while (sampledqs(mchbar, addr, DQS_HIGH) == NOT_MATCH) {
+		timing->tap++;
+		if (timing->tap > 14)
+			return;
+		program_timing(timing, channel, lane);
+	}
+}
+
+static int find_dqs_low(u32 mchbar, u8 channel, u8 lane, u32 addr,
+			rec_timing_t *timing)
+{
+	/* Look for DQS low, using quarter steps. */
+	printk(BIOS_DEBUG, "  Increasing medium until DQS LOW is found\n");
+	while (sampledqs(mchbar, addr, DQS_HIGH) == MATCH) {
+		increase_medium(timing);
+		program_timing(timing, channel, lane);
+		if (timing->coarse > MAX_COARSE) {
+			printk(BIOS_DEBUG, "Coarse > 16: DQS tuning failed, halt\n");
+			return -1;
+		}
+	}
+	printk(BIOS_DEBUG, "    high -> low transition at coarse=%d medium=%d\n",
+		timing->coarse, timing->medium);
+	return 0;
+}
+static int find_dqs_high(u32 mchbar, u8 channel, u8 lane, u32 addr,
+				rec_timing_t *timing)
+{
+	/* Look for DQS low, using quarter steps. */
+	printk(BIOS_DEBUG, "  Increasing medium until DQS HIGH is found\n");
+	while (sampledqs(mchbar, addr, DQS_LOW) == MATCH) {
+		increase_medium(timing);
+		program_timing(timing, channel, lane);
+		if (timing->coarse > MAX_COARSE) {
+			printk(BIOS_DEBUG, "Coarse > 16: DQS tuning failed, halt\n");
+			return -1;
+		}
+	}
+	printk(BIOS_DEBUG, "    low -> high transition at coarse=%d medium=%d\n",
+		timing->coarse, timing->medium);
+	return 0;
+}
+
+static int find_dqs_edge_lowhigh(u32 mchbar, u8 channel, u8 lane, u32 addr,
+				rec_timing_t *timing)
+{
+	/* Coarsely look for DQS high. */
+	if (find_dqs_high(mchbar, channel, lane, addr, timing))
+		return -1;
+
+	/* Go back and perform finer search. */
+	decrease_medium(timing);
+	program_timing(timing, channel, lane);
+	fine_search_dqs_high(mchbar, channel, lane, addr, timing);
+
+	/* Go back on fine search */
+	if (timing->tap)
+		timing->tap--;
+	program_timing(timing, channel, lane);
+	return 0;
+
+}
+
+static int find_preamble(u32 mchbar, u8 channel, u8 lane, u32 addr,
+			rec_timing_t *timing)
+{
+	/* Add a quarter step */
+	increase_medium(timing);
+	program_timing(timing, channel, lane);
+	/* Verify we are at high */
+	if (sampledqs(mchbar, addr, DQS_HIGH) == NOT_MATCH) {
+		printk(BIOS_DEBUG, "Not at DQS high, doh\n");
+		return -1;
+	}
+
+	/* Decrease coarse until LOW is found */
+	if (decr_coarse_low(mchbar, channel, lane, addr, timing))
+		return -1;
+	return 0;
+}
+
+static int calibrate_receive_enable(u8 channel, u8 lane,
+				u32 addr, rec_timing_t *timing)
+{
+	u32 mchbar = 0x400 * channel + 0x561 + (lane << 2);
+
+	program_timing(timing, channel, lane);
+	/* Set receive enable bit */
+	MCHBAR16(0x400 * channel + 0x588) = (MCHBAR16(0x400 * channel + 0x588)
+				& ~(3 << (lane * 2))) |	(1 << (lane * 2));
+
+	if (find_dqs_low(mchbar, channel, lane, addr, timing))
+		return -1;
+
+	/* Advance beyond previous high to low transition. */
+	increase_medium(timing);
+	program_timing(timing, channel, lane);
+
+	if (find_dqs_edge_lowhigh(mchbar, channel, lane, addr, timing))
+		return -1;
+	timing->pi = 3;
+	program_timing(timing, channel, lane);
+
+	if (find_preamble(mchbar, channel, lane, addr, timing))
+		return -1;
+
+	if (find_dqs_edge_lowhigh(mchbar, channel, lane, addr, timing))
+		return -1;
+	timing->pi = 7;
+	program_timing(timing, channel, lane);
+
+	/* Unset receive enable bit */
+	MCHBAR16(0x400 * channel + 0x588) = MCHBAR16(0x400 * channel + 0x588) &
+		~(3 << (lane * 2));
+	return 0;
+}
+
+void rcven(struct sysinfo *s)
+{
+	int i;
+	u8 channel, lane, reg8;
+	u32 addr;
+	rec_timing_t timing[8];
+	u8 mincoarse;
+
+	MCHBAR8(0x5d8) = MCHBAR8(0x5d8) & ~0xc;
+	MCHBAR8(0x9d8) = MCHBAR8(0x9d8) & ~0xc;
+	MCHBAR8(0x5dc) = MCHBAR8(0x5dc) & ~0x80;
+	FOR_EACH_POPULATED_CHANNEL(s->dimms, channel) {
+		addr = (channel << 29);
+		mincoarse = 0xff;
+		for (i = 0; !RANK_IS_POPULATED(s->dimms, channel, i); i++)
+			addr += 128 * 1024 * 1024;
+		for (lane = 0; lane < 8; lane++) {
+			printk(BIOS_DEBUG, "Channel %d, Lane %d addr=0x%08x\n",
+				channel, lane, addr);
+			timing[lane].coarse = (s->selected_timings.CAS - 1);
+			switch (lane) {
+			default:
+			case 0:
+			case 1:
+				timing[lane].medium = 0;
+				break;
+			case 2:
+			case 3:
+				timing[lane].medium = 1;
+				break;
+			case 4:
+			case 5:
+				timing[lane].medium = 2;
+				break;
+			case 6:
+			case 7:
+				timing[lane].medium = 3;
+				break;
+			}
+			timing[lane].tap = 0;
+			timing[lane].pi = 0;
+
+			if (calibrate_receive_enable(channel, lane, addr, &timing[lane]))
+				die("Receive enable calibration failed\n");
+			if (mincoarse > timing[lane].coarse)
+				mincoarse = timing[lane].coarse;
+		}
+		printk(BIOS_DEBUG, "Found min coarse value = %d\n", mincoarse);
+		printk(BIOS_DEBUG, "Receive enable, final timings:\n");
+		/* Normalise coarse */
+		for (lane = 0; lane < 8; lane++) {
+			if (timing[lane].coarse == 0)
+				reg8 = 0;
+			else
+				reg8 = timing[lane].coarse - mincoarse;
+			printk(BIOS_DEBUG, "ch %d lane %d: coarse offset: %d; medium: %d; tap: %d\n",
+				channel, lane, reg8, timing[lane].medium, timing[lane].tap);
+			MCHBAR16(0x400 * channel + 0x5fa) &=
+				~(3 << (lane * 2)) | (reg8 << (lane * 2));			
+		}
+		/* simply use timing[0] to program to program mincoarse */
+		timing[0].coarse = mincoarse;
+		program_timing(&timing[0], channel, 0);
+	}
+}
diff --git a/src/northbridge/intel/x4x/x4x.h b/src/northbridge/intel/x4x/x4x.h
index faae775..57ff2d5 100644
--- a/src/northbridge/intel/x4x/x4x.h
+++ b/src/northbridge/intel/x4x/x4x.h
@@ -328,6 +328,7 @@ u32 decode_igd_gtt_size(u32 gsm);
 u8 decode_pciebar(u32 *const base, u32 *const len);
 void sdram_initialize(int boot_path, const u8 *spd_map);
 void raminit_ddr2(struct sysinfo *);
+void rcven(struct sysinfo *s);
 
 struct acpi_rsdp;
 #ifndef __SIMPLE_DEVICE__



More information about the coreboot-gerrit mailing list