[coreboot-gerrit] Change in coreboot[master]: nb/intel/x4x: Use SPI flash to cache raminit results

Arthur Heymans (Code Review) gerrit at coreboot.org
Mon Sep 25 12:53:22 CEST 2017


Arthur Heymans has uploaded this change for review. ( https://review.coreboot.org/21677


Change subject: nb/intel/x4x: Use SPI flash to cache raminit results
......................................................................

nb/intel/x4x: Use SPI flash to cache raminit results

Stores information obtained from decoding dimms and receive enable
results for future use.

Depreciates using rtc nvram to store receive enable settings.

A notable change is that receive enable results are always reused, not
just on a resume from S3.

TODO: With dimms with a working SPD chip with invalid content this
patch will result in normal boot each time except on resume from S3.

TESTED on Intel DG43GT with W25Q128.V.

Change-Id: I042dc5c52615d40781d9ef7ecd657ad0bf3ed08f
Signed-off-by: Arthur Heymans <arthur at aheymans.xyz>
---
M src/northbridge/intel/x4x/Kconfig
M src/northbridge/intel/x4x/Makefile.inc
M src/northbridge/intel/x4x/early_init.c
M src/northbridge/intel/x4x/raminit.c
M src/northbridge/intel/x4x/raminit_ddr2.c
M src/northbridge/intel/x4x/rcven.c
M src/northbridge/intel/x4x/x4x.h
7 files changed, 153 insertions(+), 87 deletions(-)



  git pull ssh://review.coreboot.org:29418/coreboot refs/changes/77/21677/1

diff --git a/src/northbridge/intel/x4x/Kconfig b/src/northbridge/intel/x4x/Kconfig
index 9239637..23c20b5 100644
--- a/src/northbridge/intel/x4x/Kconfig
+++ b/src/northbridge/intel/x4x/Kconfig
@@ -28,6 +28,7 @@
 	select RELOCATABLE_RAMSTAGE
 	select HAVE_LINEAR_FRAMEBUFFER if MAINBOARD_DO_NATIVE_VGA_INIT
 	select HAVE_VGA_TEXT_FRAMEBUFFER if MAINBOARD_DO_NATIVE_VGA_INIT
+	select NORTHBRIDGE_INTEL_COMMON_MRC_CACHE
 
 config CBFS_SIZE
 	hex
@@ -45,4 +46,8 @@
 	hex
 	default 0xe0000000
 
+config MRC_CACHE_SIZE
+	hex
+	default 0x10000
+
 endif
diff --git a/src/northbridge/intel/x4x/Makefile.inc b/src/northbridge/intel/x4x/Makefile.inc
index 5c64ca7..7661ec3 100644
--- a/src/northbridge/intel/x4x/Makefile.inc
+++ b/src/northbridge/intel/x4x/Makefile.inc
@@ -27,4 +27,15 @@
 ramstage-y += gma.c
 ramstage-y += northbridge.c
 
+$(obj)/mrc.cache: $(obj)/config.h
+	dd if=/dev/zero count=1 \
+	bs=$(shell printf "%d" $(CONFIG_MRC_CACHE_SIZE) ) | \
+	tr '\000' '\377' > $@
+
+cbfs-files-y += mrc.cache
+mrc.cache-file := $(obj)/mrc.cache
+mrc.cache-align := 0x10000
+mrc.cache-type := mrc_cache
+
+
 endif
diff --git a/src/northbridge/intel/x4x/early_init.c b/src/northbridge/intel/x4x/early_init.c
index 27fe916..f463840 100644
--- a/src/northbridge/intel/x4x/early_init.c
+++ b/src/northbridge/intel/x4x/early_init.c
@@ -235,15 +235,6 @@
 
 static void x4x_prepare_resume(int s3resume)
 {
-	int cbmem_recovered;
-
-	cbmem_recovered = !cbmem_recovery(s3resume);
-	if (!cbmem_recovered && s3resume) {
-		/* Failed S3 resume, reset to come up cleanly */
-		outb(0x6, 0xcf9);
-		halt();
-	}
-
 	romstage_handoff_init(s3resume);
 }
 
diff --git a/src/northbridge/intel/x4x/raminit.c b/src/northbridge/intel/x4x/raminit.c
index d5298f6..ac8b576 100644
--- a/src/northbridge/intel/x4x/raminit.c
+++ b/src/northbridge/intel/x4x/raminit.c
@@ -33,10 +33,38 @@
 #include <spd.h>
 #include <string.h>
 #include <device/dram/ddr2.h>
+#include <northbridge/intel/common/mrc_cache.h>
 
 static inline int spd_read_byte(unsigned int device, unsigned int address)
 {
 	return smbus_read_byte(device, address);
+}
+
+static int verify_spds(const u8 *spd_map, struct sysinfo *ctrl_cached)
+{
+	int i;
+	int checksum;
+
+	for (i = 0; i < TOTAL_DIMMS; i++) {
+		checksum = 0;
+		if (!(spd_map[i]))
+			continue;
+		if (ctrl_cached->spd_type == DDR2) {
+			checksum = spd_read_byte(spd_map[i], 63);
+		} else { /* DDR3 */
+			checksum = spd_read_byte(spd_map[i], 126);
+			checksum |= spd_read_byte(spd_map[i], 127) << 8;
+		}
+		if (checksum < 0 && ctrl_cached->dimms[i].card_type
+				== RAW_CARD_UNPOPULATED)
+			continue;
+		if (checksum > 0 && ctrl_cached->dimms[i].card_type
+			== RAW_CARD_UNPOPULATED)
+			return CB_ERR;
+		if ((checksum & 0xffff) != ctrl_cached->dimms[i].checksum)
+			return CB_ERR;
+	}
+	return CB_SUCCESS;
 }
 
 struct abs_timings {
@@ -190,6 +218,7 @@
 				MAX(saved_timings->min_tCLK_cas[i],
 					decoded_dimm.cycle_time[i]);
 	}
+	s->dimms[dimm_idx].checksum = decoded_dimm.checksum;
 	return CB_SUCCESS;
 }
 
@@ -380,8 +409,10 @@
  */
 void sdram_initialize(int boot_path, const u8 *spd_map)
 {
-	struct sysinfo s;
+	struct sysinfo s, *ctrl_cached;
 	u8 reg8;
+	int fast_boot, cbmem_was_inited;
+	struct mrc_data_container *mrc_cache;
 
 	printk(BIOS_DEBUG, "Setting up RAM controller.\n");
 
@@ -389,28 +420,60 @@
 
 	memset(&s, 0, sizeof(struct sysinfo));
 
-	s.boot_path = boot_path;
-	s.spd_map[0] = spd_map[0];
-	s.spd_map[1] = spd_map[1];
-	s.spd_map[2] = spd_map[2];
-	s.spd_map[3] = spd_map[3];
+	mrc_cache = find_current_mrc_cache();
+	if (!mrc_cache || (mrc_cache->mrc_data_size < sizeof(s))) {
+		if (boot_path == BOOT_PATH_RESUME) {
+			/* Failed S3 resume, reset to come up cleanly */
+			outb(0x6, 0xcf9);
+			halt();
+		}
+		ctrl_cached = NULL;
+	} else {
+		ctrl_cached = (struct sysinfo *)mrc_cache->mrc_data;
+	}
 
-	checkreset_ddr2(s.boot_path);
+	/* verify MRC cache for fast boot */
+	if (boot_path != BOOT_PATH_RESUME  && ctrl_cached) {
+		/* check SPD checksum to make sure the DIMMs haven't been
+		 * replaced */
+		fast_boot = verify_spds(spd_map, ctrl_cached) == CB_SUCCESS;
+		if (!fast_boot)
+			printk(BIOS_DEBUG, "SPD checksums don't match,"
+				" dimm's have been replaced\n");
+	} else {
+		fast_boot = boot_path == BOOT_PATH_RESUME;
+	}
 
-	/* Detect dimms per channel */
-	reg8 = pci_read_config8(PCI_DEV(0, 0, 0), 0xe9);
-	printk(BIOS_DEBUG, "Dimms per channel: %d\n", (reg8 & 0x10) ? 1 : 2);
+	if (fast_boot) {
+		printk(BIOS_DEBUG, "Using cached raminit settings\n");
+		memcpy(&s, ctrl_cached, sizeof(s));
+		s.boot_path = boot_path;
+		mchinfo_ddr2(&s);
+		print_selected_timings(&s);
+	} else {
+		s.boot_path = boot_path;
+		s.spd_map[0] = spd_map[0];
+		s.spd_map[1] = spd_map[1];
+		s.spd_map[2] = spd_map[2];
+		s.spd_map[3] = spd_map[3];
+		checkreset_ddr2(s.boot_path);
 
-	mchinfo_ddr2(&s);
+		/* Detect dimms per channel */
+		reg8 = pci_read_config8(PCI_DEV(0, 0, 0), 0xe9);
+		printk(BIOS_DEBUG, "Dimms per channel: %d\n",
+			(reg8 & 0x10) ? 1 : 2);
 
-	find_fsb_speed(&s);
-	decode_spd_select_timings(&s);
-	print_selected_timings(&s);
-	find_dimm_config(&s);
+		mchinfo_ddr2(&s);
+
+		find_fsb_speed(&s);
+		decode_spd_select_timings(&s);
+		print_selected_timings(&s);
+		find_dimm_config(&s);
+	}
 
 	switch (s.spd_type) {
 	case DDR2:
-		raminit_ddr2(&s);
+		raminit_ddr2(&s, fast_boot);
 		break;
 	case DDR3:
 		// FIXME Add: raminit_ddr3(&s);
@@ -426,4 +489,13 @@
 	reg8 = pci_read_config8(PCI_DEV(0, 0, 0), 0xf4);
 	pci_write_config8(PCI_DEV(0, 0, 0), 0xf4, reg8 | 1);
 	printk(BIOS_DEBUG, "RAM initialization finished.\n");
+
+	cbmem_was_inited = !cbmem_recovery(s.boot_path == BOOT_PATH_RESUME);
+	if (!fast_boot)
+		store_current_mrc_cache(&s, sizeof(s));
+	if (s.boot_path == BOOT_PATH_RESUME && !cbmem_was_inited) {
+		/* Failed S3 resume, reset to come up cleanly */
+		outb(0x6, 0xcf9);
+		halt();
+	}
 }
diff --git a/src/northbridge/intel/x4x/raminit_ddr2.c b/src/northbridge/intel/x4x/raminit_ddr2.c
index 079dcde..b9f11ab 100644
--- a/src/northbridge/intel/x4x/raminit_ddr2.c
+++ b/src/northbridge/intel/x4x/raminit_ddr2.c
@@ -1048,77 +1048,49 @@
 	printk(BIOS_DEBUG, "MRS done\n");
 }
 
-static void sdram_save_receive_enable(void)
+static void sdram_recover_receive_enable(struct sysinfo *s)
 {
-	int i = 0;
-	u16 reg16;
-	u8 values[18];
-	u8 lane, ch;
-
-	FOR_EACH_CHANNEL(ch) {
-		lane = 0;
-		while (lane < 8) {
-			values[i] = (MCHBAR8(0x400*ch + 0x560 + lane++ * 4) & 0xf);
-			values[i++] |= (MCHBAR8(0x400*ch + 0x560 + lane++ * 4) & 0xf) << 4;
-		}
-		values[i++] = (MCHBAR32(0x400*ch + 0x248) >> 16) & 0xf;
-		reg16 = MCHBAR16(0x400*ch + 0x5fa);
-		values[i++] = reg16 & 0xff;
-		values[i++] = (reg16 >> 8) & 0xff;
-		reg16 = MCHBAR16(0x400*ch + 0x58c);
-		values[i++] = reg16 & 0xff;
-		values[i++] = (reg16 >> 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;
 	u32 reg32;
-	u16 reg16;
-	u8 values[18];
-	u8 ch, lane;
+	u16 medium, coarse_offset;
+	u8 pitap;
+	int lane, channel;
 
-	for (i = 0; i < ARRAY_SIZE(values); i++)
-		values[i] = cmos_read(128 + i);
+	FOR_EACH_POPULATED_CHANNEL(s->dimms, channel) {
+		medium = 0;
+		coarse_offset = 0;
+		reg32 = MCHBAR32(0x400 * channel + 0x248);
+		reg32 &= ~0xf0000;
+		reg32 |= s->rcven_t[channel].min_common_coarse << 16;
+		MCHBAR32(0x400 * channel + 0x248) = reg32;
 
-	i = 0;
-	FOR_EACH_CHANNEL(ch) {
-		lane = 0;
-		while (lane < 8) {
-			MCHBAR8(0x400*ch + 0x560 + lane++ * 4) = 0x70 |
-				(values[i] & 0xf);
-			MCHBAR8(0x400*ch + 0x560 + lane++ * 4) = 0x70 |
-				((values[i++] >> 4) & 0xf);
+		for (lane = 0; lane < 8; lane++) {
+			medium |= s->rcven_t[channel].medium[lane]
+				<< (lane * 2);
+			coarse_offset |=
+				(s->rcven_t[channel].coarse_offset[lane] & 0x3)
+				<< (lane * 2);
+
+			pitap = MCHBAR8(0x400 * channel + 0x560 + lane * 4);
+			pitap &= ~0x7f;
+			pitap |= s->rcven_t[channel].tap[lane];
+			pitap |= s->rcven_t[channel].pi[lane];
+			MCHBAR8(0x400 * channel + 0x560 + lane * 4) = pitap;
 		}
-		reg32 = (MCHBAR32(0x400*ch + 0x248) & ~0xf0000)
-		  | ((values[i++] & 0xf) << 16);
-		MCHBAR32(0x400*ch + 0x248) = reg32;
-		reg16 = values[i++];
-		reg16 |= values[i++] << 8;
-		MCHBAR16(0x400*ch + 0x5fa) = reg16;
-		reg16 = values[i++];
-		reg16 |= values[i++] << 8;
-		MCHBAR16(0x400*ch + 0x58c) = reg16;
+		MCHBAR16(0x400 * channel + 0x58c) = medium;
+		MCHBAR16(0x400 * channel + 0x5fa) = coarse_offset;
 	}
 }
 
-static void sdram_program_receive_enable(struct sysinfo *s)
+static void sdram_program_receive_enable(struct sysinfo *s, int fast_boot)
 {
 	/* enable upper CMOS */
 	RCBA32(0x3400) = (1 << 2);
 
 	/* Program Receive Enable Timings */
-	if ((s->boot_path == BOOT_PATH_WARM_RESET)
-		|| (s->boot_path == BOOT_PATH_RESUME)) {
-		sdram_recover_receive_enable();
-	} else {
+	if (fast_boot)
+		sdram_recover_receive_enable(s);
+	else
 		rcven(s);
-		sdram_save_receive_enable();
-	}
 }
 
 static void dradrb_ddr2(struct sysinfo *s)
@@ -1473,7 +1445,7 @@
 		MCHBAR8(0x561 + (lane << 2)) = MCHBAR8(0x561 + (lane << 2)) & ~(1 << 3);
 }
 
-void raminit_ddr2(struct sysinfo *s)
+void raminit_ddr2(struct sysinfo *s, int fast_boot)
 {
 	u8 ch;
 	u8 r, bank;
@@ -1616,7 +1588,7 @@
 	}
 
 	// Receive enable
-	sdram_program_receive_enable(s);
+	sdram_program_receive_enable(s, fast_boot);
 	printk(BIOS_DEBUG, "Done rcven\n");
 
 	// Finish rcven
diff --git a/src/northbridge/intel/x4x/rcven.c b/src/northbridge/intel/x4x/rcven.c
index 23f8d52..7ad1e0a 100644
--- a/src/northbridge/intel/x4x/rcven.c
+++ b/src/northbridge/intel/x4x/rcven.c
@@ -304,7 +304,7 @@
 	return 0;
 }
 
-void rcven(const struct sysinfo *s)
+void rcven(struct sysinfo *s)
 {
 	int i;
 	u8 channel, lane, reg8;
@@ -354,6 +354,7 @@
 				mincoarse = timing[lane].coarse;
 		}
 		printk(BIOS_DEBUG, "Found min coarse value = %d\n", mincoarse);
+		s->rcven_t[channel].min_common_coarse = mincoarse;
 		printk(BIOS_DEBUG, "Receive enable, final timings:\n");
 		/* Normalise coarse */
 		for (lane = 0; lane < 8; lane++) {
@@ -365,6 +366,10 @@
 				"medium: %d; tap: %d\n",
 				channel, lane, reg8, timing[lane].medium,
 				timing[lane].tap);
+			s->rcven_t[channel].coarse_offset[lane] = reg8;
+			s->rcven_t[channel].medium[lane] = timing[lane].medium;
+			s->rcven_t[channel].tap[lane] = timing[lane].tap;
+			s->rcven_t[channel].pi[lane] = timing[lane].pi;
 			MCHBAR16(0x400 * channel + 0x5fa) &=
 				~(3 << (lane * 2)) | (reg8 << (lane * 2));
 		}
diff --git a/src/northbridge/intel/x4x/x4x.h b/src/northbridge/intel/x4x/x4x.h
index e4147a1..2fffe8b 100644
--- a/src/northbridge/intel/x4x/x4x.h
+++ b/src/northbridge/intel/x4x/x4x.h
@@ -276,6 +276,15 @@
 	unsigned int	ranks;
 	unsigned int	rows;
 	unsigned int	cols;
+	u16             checksum;
+};
+
+struct rcven_timings {
+	u8 min_common_coarse;
+	u8 coarse_offset[8];
+	u8 medium[8];
+	u8 tap[8];
+	u8 pi[8];
 };
 
 /* The setup is up to two DIMMs per channel */
@@ -290,6 +299,7 @@
 	struct timings	selected_timings;
 	struct dimminfo	dimms[4];
 	u8		spd_map[4];
+	struct rcven_timings rcven_t[TOTAL_CHANNELS];
 };
 #define BOOT_PATH_NORMAL	0
 #define BOOT_PATH_WARM_RESET	1
@@ -328,8 +338,8 @@
 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(const struct sysinfo *);
+void raminit_ddr2(struct sysinfo *s, int fast_boot);
+void rcven(struct sysinfo *s);
 u32 fsb2mhz(u32 speed);
 u32 ddr2mhz(u32 speed);
 

-- 
To view, visit https://review.coreboot.org/21677
To unsubscribe, visit https://review.coreboot.org/settings

Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: I042dc5c52615d40781d9ef7ecd657ad0bf3ed08f
Gerrit-Change-Number: 21677
Gerrit-PatchSet: 1
Gerrit-Owner: Arthur Heymans <arthur at aheymans.xyz>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.coreboot.org/pipermail/coreboot-gerrit/attachments/20170925/1f1dc2d0/attachment-0001.html>


More information about the coreboot-gerrit mailing list