[coreboot-gerrit] Patch set updated for coreboot: nb/intel/x4x: Fix raminit on reset path

Arthur Heymans (arthur@aheymans.xyz) gerrit at coreboot.org
Thu Jan 5 00:45:02 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/18009

-gerrit

commit 9c7a330ed66dd1356d40c86d1b50c1a4bfd67090
Author: Arthur Heymans <arthur at aheymans.xyz>
Date:   Wed Nov 30 18:40:38 2016 +0100

    nb/intel/x4x: Fix raminit on reset path
    
    Previously the raminit failed on hot reset and to work around this
    issue it unconditionally did a cold reset.
    
    This has the following issues:
    * it's slow;
    * when the OS issues a hot reset some disk drives expect their 5V
      power supply to remain on, which gets cut off by a cold reset,
      causing data corruption.
    
    To fix this some steps in raminit must be ommited on the reset path.
    This includes searching for receive enable.
    To achieve this it stores receive enable results in nvram (which is
    also needed when implementing S3 suspend/resume from S3).
    
    Change-Id: I6601dd90aebd071a0de7cec070487b0f9845bc30
    Signed-off-by: Arthur Heymans <arthur at aheymans.xyz>
---
 src/mainboard/gigabyte/ga-g41m-es2l/cmos.layout |   1 +
 src/mainboard/gigabyte/ga-g41m-es2l/romstage.c  |   7 +-
 src/northbridge/intel/x4x/raminit_ddr2.c        | 135 ++++++++++++++++++++----
 src/northbridge/intel/x4x/x4x.h                 |   7 +-
 4 files changed, 125 insertions(+), 25 deletions(-)

diff --git a/src/mainboard/gigabyte/ga-g41m-es2l/cmos.layout b/src/mainboard/gigabyte/ga-g41m-es2l/cmos.layout
index 3138479..946d1a1 100644
--- a/src/mainboard/gigabyte/ga-g41m-es2l/cmos.layout
+++ b/src/mainboard/gigabyte/ga-g41m-es2l/cmos.layout
@@ -68,6 +68,7 @@ entries
 # coreboot config options: check sums
 984         16       h       0        check_sum
 
+1024        256       r       0        recv_enable_results
 # -----------------------------------------------------------------
 
 enumerations
diff --git a/src/mainboard/gigabyte/ga-g41m-es2l/romstage.c b/src/mainboard/gigabyte/ga-g41m-es2l/romstage.c
index 2503db9..2302842 100644
--- a/src/mainboard/gigabyte/ga-g41m-es2l/romstage.c
+++ b/src/mainboard/gigabyte/ga-g41m-es2l/romstage.c
@@ -29,6 +29,7 @@
 #include <lib.h>
 #include <arch/stages.h>
 #include <cbmem.h>
+#include <northbridge/intel/x4x/iomap.h>
 
 #define SERIAL_DEV PNP_DEV(0x2e, IT8718F_SP1)
 #define GPIO_DEV PNP_DEV(0x2e, IT8718F_GPIO)
@@ -136,6 +137,7 @@ void mainboard_romstage_entry(unsigned long bist)
 {
 	//                          ch0      ch1
 	const u8 spd_addrmap[4] = { 0x50, 0, 0x52, 0 };
+	u8 boot_path = 0;
 
 	/* Disable watchdog timer */
 	RCBA32(0x3410) = RCBA32(0x3410) | 0x20;
@@ -155,8 +157,11 @@ void mainboard_romstage_entry(unsigned long bist)
 
 	x4x_early_init();
 
+	if (MCHBAR32(PMSTS_MCHBAR) & PMSTS_WARM_RESET)
+		boot_path = BOOT_PATH_RESET;
+
 	printk(BIOS_DEBUG, "Initializing memory\n");
-	sdram_initialize(0, spd_addrmap);
+	sdram_initialize(boot_path, spd_addrmap);
 	quick_ram_check();
 	cbmem_initialize_empty();
 	printk(BIOS_DEBUG, "Memory initialized\n");
diff --git a/src/northbridge/intel/x4x/raminit_ddr2.c b/src/northbridge/intel/x4x/raminit_ddr2.c
index b3ee34a..ef21cb8 100644
--- a/src/northbridge/intel/x4x/raminit_ddr2.c
+++ b/src/northbridge/intel/x4x/raminit_ddr2.c
@@ -20,6 +20,9 @@
 #include <console/console.h>
 #include <commonlib/helpers.h>
 #include <delay.h>
+#include <pc80/mc146818rtc.h>
+/* only needed for RCBA32() so it's ok to only include ICH7 function */
+#include <southbridge/intel/i82801gx/i82801gx.h>
 #include "iomap.h"
 #include "x4x.h"
 
@@ -258,10 +261,13 @@ static void checkreset_ddr2(struct sysinfo *s)
 {
 	u8 pmcon2;
 	u8 reset = 0;
+	u32 pmir;
 
+	pmir = pci_read_config32(PCI_DEV(0, 0x1f, 0), 0xac);
 	pmcon2 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa2);
-	if (!(pmcon2 & 0x80)) {
-		pmcon2 |= 0x80;
+
+	if (pmcon2 & 0x80) {
+		pmcon2 &= ~0x80;
 		pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa2, pmcon2);
 		reset = 1;
 
@@ -273,10 +279,16 @@ static void checkreset_ddr2(struct sysinfo *s)
 	}
 	if (reset) {
 		printk(BIOS_DEBUG, "Reset...\n");
+		/* Do a global reset. only useful on ICH10 */
+		pmir |= (1 << 20);
+		pci_write_config32(PCI_DEV(0, 0x1f, 0), 0xac, pmir);
 		outb(0xe, 0xcf9);
 		asm ("hlt");
 	}
-	pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa2, pmcon2 | 0x80);
+	pmir &= ~(1 << 20);
+	pmcon2 |= 0x80;
+	pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa2, pmcon2);
+	pci_write_config32(PCI_DEV(0, 0x1f, 0), 0xac, pmir);
 }
 
 static void setioclk_ddr2(struct sysinfo *s)
@@ -1486,6 +1498,76 @@ static void rcven_ddr2(struct sysinfo *s)
 	printk(BIOS_DEBUG, "End rcven\n");
 }
 
+static void sdram_save_receive_enable(void)
+{
+	int i = 0, j;
+	u32 reg32;
+	u16 reg16;
+	u8 values[32];
+	u8 lane, ch;
+
+	FOR_EACH_CHANNEL(ch) {
+		for (lane = 0; lane < 8; lane++)
+			values[i++] = MCHBAR8(0x400*ch + 0x560 + (lane*4));
+		reg32 = MCHBAR32(0x400*ch + 0x248);
+		for (j = 0; j < 4; j++)
+			values[i++] = (reg32 >> (j * 8)) & 0xff;
+		reg16 = MCHBAR16(0x400*ch + 0x5fa);
+		for (j = 0; j < 2; j++)
+			values[i++] = (reg16 >> (j * 8)) & 0xff;
+		reg16 = MCHBAR16(0x400*ch + 0x58c);
+		for (j = 0; j < 2; j++)
+			values[i++] = (reg16 >> (j * 8)) & 0xff;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(values); i++)
+		cmos_write(values[i], 128 + i);
+}
+
+static void sdram_recover_receive_enable(void)
+{
+	u8 i, j;
+	u32 reg32 = 0;
+	u16 reg16 = 0;
+	u8 values[32];
+	u8 ch, lane;
+
+	for (i = 0; i < ARRAY_SIZE(values); i++)
+		values[i] = cmos_read(128 + i);
+
+	i = 0;
+	FOR_EACH_CHANNEL(ch) {
+		for (lane = 0; lane < 8; lane++)
+			MCHBAR8(0x400*ch + 0x560 + (lane*4)) = values[i++];
+		for (j = 0; j < 4; j++)
+			reg32 |= (values[i++] << (j * 8));
+		MCHBAR32(0x400*ch + 0x248) = reg32;
+		reg32 = 0;
+		for (j = 0; j < 2; j++)
+			reg16 |= (values[i++] << (j * 8));
+		MCHBAR16(0x400*ch + 0x5fa) = reg16;
+		reg16 = 0;
+		for (j = 0; j < 2; j++)
+			reg16 |= (values[i++] << (j * 8));
+		MCHBAR16(0x400*ch + 0x58c) = reg16;
+		reg16 = 0;
+	}
+}
+
+static void sdram_program_receive_enable(struct sysinfo *s)
+{
+	/* enable upper CMOS */
+	RCBA32(0x3400) = (1 << 2);
+
+	/* Program Receive Enable Timings */
+	if (s->boot_path == BOOT_PATH_RESET) {
+		sdram_recover_receive_enable();
+	} else {
+		rcven_ddr2(s);
+		sdram_save_receive_enable();
+	}
+}
+
 static void dradrb_ddr2(struct sysinfo *s)
 {
 	u8 map, i, ch, r, rankpop0, rankpop1;
@@ -1860,22 +1942,24 @@ void raminit_ddr2(struct sysinfo *s)
 	checkreset_ddr2(s);
 
 	// Clear self refresh
-	MCHBAR32(0xf14) = MCHBAR32(0xf14) | 0x3;
+	if (s->boot_path != BOOT_PATH_RESET) {
+		MCHBAR32(PMSTS_MCHBAR) = MCHBAR32(PMSTS_MCHBAR)
+			| PMSTS_BOTH_SELFREFRESH;
 
-	// Clear host clk gate reg
-	MCHBAR32(0x1c) = MCHBAR32(0x1c) | 0xffffffff;
+		// Clear host clk gate reg
+		MCHBAR32(0x1c) = MCHBAR32(0x1c) | 0xffffffff;
 
-	// Select DDR2
-	MCHBAR8(0x1a8) = MCHBAR8(0x1a8) & ~0x4;
+		// Select DDR2
+		MCHBAR8(0x1a8) = MCHBAR8(0x1a8) & ~0x4;
 
-	// Set freq
-	MCHBAR32(0xc00) = (MCHBAR32(0xc00) & ~0x70) |
-		(s->selected_timings.mem_clk << 4) | (1 << 10);
+		// Set freq
+		MCHBAR32(0xc00) = (MCHBAR32(0xc00) & ~0x70) |
+			(s->selected_timings.mem_clk << 4) | (1 << 10);
 
-	// Overwrite freq if chipset rejects it
-	s->selected_timings.mem_clk = (MCHBAR8(0xc00) & 0x70) >> 4;
-	if (s->selected_timings.mem_clk > (s->max_fsb + 3)) {
-		die("Error: DDR is faster than FSB, halt\n");
+		// Overwrite freq if chipset rejects it
+		s->selected_timings.mem_clk = (MCHBAR8(0xc00) & 0x70) >> 4;
+		if (s->selected_timings.mem_clk > (s->max_fsb + 3))
+			die("Error: DDR is faster than FSB, halt\n");
 	}
 
 	udelay(250000);
@@ -1885,8 +1969,10 @@ void raminit_ddr2(struct sysinfo *s)
 	printk(BIOS_DEBUG, "Done clk crossing\n");
 
 	// DDR2 IO
-	setioclk_ddr2(s);
-	printk(BIOS_DEBUG, "Done I/O clk\n");
+	if (s->boot_path != BOOT_PATH_RESET) {
+		setioclk_ddr2(s);
+		printk(BIOS_DEBUG, "Done I/O clk\n");
+	}
 
 	// Grant to launch
 	launch_ddr2(s);
@@ -1900,16 +1986,21 @@ void raminit_ddr2(struct sysinfo *s)
 	dll_ddr2(s);
 
 	// RCOMP
-	rcomp_ddr2(s);
-	printk(BIOS_DEBUG, "RCOMP\n");
+	if (s->boot_path != BOOT_PATH_RESET) {
+		rcomp_ddr2(s);
+		printk(BIOS_DEBUG, "RCOMP\n");
+	}
 
 	// ODT
 	odt_ddr2(s);
 	printk(BIOS_DEBUG, "Done ODT\n");
 
 	// RCOMP update
-	while ((MCHBAR8(0x130) & 1) != 0 );
-	printk(BIOS_DEBUG, "Done RCOMP update\n");
+	if (s->boot_path != BOOT_PATH_RESET) {
+		while ((MCHBAR8(0x130) & 1) != 0)
+			;
+		printk(BIOS_DEBUG, "Done RCOMP update\n");
+	}
 
 	// Set defaults
 	MCHBAR32(0x260) = (MCHBAR32(0x260) & ~1) | 0xf00000;
@@ -1989,7 +2080,7 @@ void raminit_ddr2(struct sysinfo *s)
 	}
 
 	// Receive enable
-	rcven_ddr2(s);
+	sdram_program_receive_enable(s);
 	printk(BIOS_DEBUG, "Done rcven\n");
 
 	// Finish rcven
diff --git a/src/northbridge/intel/x4x/x4x.h b/src/northbridge/intel/x4x/x4x.h
index 7ca634f..1823b8c 100644
--- a/src/northbridge/intel/x4x/x4x.h
+++ b/src/northbridge/intel/x4x/x4x.h
@@ -87,8 +87,8 @@
 #define MCHBAR32(x) *((volatile u32 *)(DEFAULT_MCHBAR + x))
 
 #define PMSTS_MCHBAR		0x0f14	/* Self refresh channel status */
-#define PMSTS_WARM_RESET	(1 << 1)
-#define PMSTS_BOTH_SELFREFRESH	(1 << 0)
+#define PMSTS_WARM_RESET	(1 << 8)
+#define PMSTS_BOTH_SELFREFRESH	(3 << 0)
 
 #define CLKCFG_MCHBAR		0x0c00
 #define CLKCFG_FSBCLK_SHIFT	0
@@ -290,6 +290,9 @@ struct sysinfo {
 	struct dimminfo	dimms[4];
 	u8		spd_map[4];
 };
+#define BOOT_PATH_NORMAL	0
+#define BOOT_PATH_RESET		1
+#define BOOT_PATH_RESUME	2
 
 enum ddr2_signals {
 	CLKSET0 = 0,



More information about the coreboot-gerrit mailing list