[coreboot-gerrit] Change in coreboot[master]: [WIP]nb/intel/sandybridge/raminit: Add ECC support

Patrick Rudolph (Code Review) gerrit at coreboot.org
Sat Oct 28 18:25:59 CEST 2017


Patrick Rudolph has uploaded this change for review. ( https://review.coreboot.org/22215


Change subject: [WIP]nb/intel/sandybridge/raminit: Add ECC support
......................................................................

[WIP]nb/intel/sandybridge/raminit: Add ECC support

Add ECC support for IvyBridge.

Change-Id: I1206746332c9939a78b67e7b48d3098bdef8a2ed
Signed-off-by: Patrick Rudolph <siro at das-labor.org>
---
M src/northbridge/intel/sandybridge/Kconfig
M src/northbridge/intel/sandybridge/raminit.c
M src/northbridge/intel/sandybridge/raminit_common.c
M src/northbridge/intel/sandybridge/raminit_common.h
M src/northbridge/intel/sandybridge/raminit_ivy.c
5 files changed, 73 insertions(+), 3 deletions(-)



  git pull ssh://review.coreboot.org:29418/coreboot refs/changes/15/22215/1

diff --git a/src/northbridge/intel/sandybridge/Kconfig b/src/northbridge/intel/sandybridge/Kconfig
index c7e6e46..97042b2 100644
--- a/src/northbridge/intel/sandybridge/Kconfig
+++ b/src/northbridge/intel/sandybridge/Kconfig
@@ -117,6 +117,12 @@
 	  Run extended memtest over all usable memory below 4GiB.
 	  This will delay raminit training by several microseconds.
 
+config RAMINIT_ENABLE_ECC
+	bool "Enable ECC if supported"
+	default y
+	help
+	  Enable ECC if supported by both, host and RAM.
+
 endif # USE_NATIVE_RAMINIT
 
 if !USE_NATIVE_RAMINIT
diff --git a/src/northbridge/intel/sandybridge/raminit.c b/src/northbridge/intel/sandybridge/raminit.c
index 8e8c457..cd5c9f0 100644
--- a/src/northbridge/intel/sandybridge/raminit.c
+++ b/src/northbridge/intel/sandybridge/raminit.c
@@ -35,7 +35,6 @@
 #include "raminit_common.h"
 #include "sandybridge.h"
 
-/* FIXME: no ECC support.  */
 /* FIXME: no support for 3-channel chipsets.  */
 
 static const char *ecc_decoder[] = {
@@ -195,6 +194,7 @@
 {
 	int dimms = 0, dimms_on_channel;
 	int channel, slot, spd_slot;
+	size_t supports_ecc = 1;
 	dimm_info *dimm = &ctrl->info;
 
 	memset (ctrl->rankmap, 0, sizeof(ctrl->rankmap));
@@ -259,6 +259,9 @@
 			ctrl->rank_mirror[channel][slot * 2 + 1] = dimm->dimm[channel][slot].flags.pins_mirrored;
 			ctrl->channel_size_mb[channel] += dimm->dimm[channel][slot].size_mb;
 
+			if (!dimm->dimm[channel][slot]->flags.is_ecc)
+				supports_ecc = 0;
+
 			ctrl->auto_self_refresh &= dimm->dimm[channel][slot].flags.asr;
 			ctrl->extended_temperature_range &= dimm->dimm[channel][slot].flags.ext_temp_refresh;
 
@@ -282,6 +285,17 @@
 			ctrl->ref_card_offset[channel] = 0;
 	}
 
+	if (ctrl->ecc_supported) {
+		if (ctrl->ecc_forced && !supports_ecc)
+			die("ECC mode forced but non ECC DIMM installed !");
+		ctrl->ecc_enabled = ctrl->ecc_forced ||
+				IS_ENALBED(CONFIG_RAMINIT_ENABLE_ECC);
+		printk(BIOS_DEBUG, "ECC mode %s\n",
+				ctrl->ecc_enabled  ? "on" : "off");
+	}
+
+	ctrl->lanes = ctrl->ecc_enabled ? 9 : 8;
+
 	if (!dimms)
 		die("No DIMMs were found");
 }
diff --git a/src/northbridge/intel/sandybridge/raminit_common.c b/src/northbridge/intel/sandybridge/raminit_common.c
index 00bb513..8569d7e 100644
--- a/src/northbridge/intel/sandybridge/raminit_common.c
+++ b/src/northbridge/intel/sandybridge/raminit_common.c
@@ -328,6 +328,9 @@
 		reg |= 1 << 21; /* rank interleave */
 		reg |= 1 << 22; /* enhanced interleave */
 
+		if (ctrl->ecc_enabled)
+			reg |= 3 << 24;
+
 		if ((dimmA && (dimmA->ranks > 0))
 		    || (dimmB && (dimmB->ranks > 0))) {
 			ctrl->mad_dimm[channel] = reg;
@@ -343,6 +346,8 @@
 	FOR_ALL_CHANNELS {
 		MCHBAR32(0x5004 + channel * 4) = ctrl->mad_dimm[channel];
 	}
+
+	udelay(10);
 }
 
 void dram_zones(ramctr_timing * ctrl, int training)
@@ -3118,6 +3123,45 @@
 	return 0;
 }
 
+void channel_scrub(ramctr_timing *ctrl)
+{
+	int channel, slotrank, lane, bank, row;
+	int rowsize;
+
+	FOR_ALL_POPULATED_CHANNELS FOR_ALL_POPULATED_RANKS {
+		rowsize = 1 << ctrl->info.dimm[channel][slotrank>>1].row_bits;
+		for (bank = 0; bank < 8; bank++) {
+			for (row = 0; row < rowsize; row += 16) {
+
+		wait_428c(channel);
+		/* DRAM command ACT */
+		write32(DEFAULT_MCHBAR + 0x4220 + (channel << 10), 0x0001f006);
+		write32(DEFAULT_MCHBAR + 0x4230 + (channel << 10),
+			(max((ctrl->tFAW >> 2) + 1, ctrl->tRRD) << 10)
+			| 1 | (ctrl->tRCD << 16));
+		write32(DEFAULT_MCHBAR + 0x4200 + (channel << 10),
+			row | 0x00060000 | (slotrank << 24));
+		write32(DEFAULT_MCHBAR + 0x4210 + (channel << 10), 0x00000241);
+		/* DRAM command WR */
+		write32(DEFAULT_MCHBAR + 0x4224 + (channel << 10), 0x0001f201);
+		write32(DEFAULT_MCHBAR + 0x4234 + (channel << 10), 0x08281081);
+		write32(DEFAULT_MCHBAR + 0x4204 + (channel << 10),
+			row | (slotrank << 24));
+		write32(DEFAULT_MCHBAR + 0x4214 + (channel << 10), 0x00000242);
+		/* DRAM command PRE */
+		write32(DEFAULT_MCHBAR + 0x4228 + (channel << 10), 0x0001f002);
+		write32(DEFAULT_MCHBAR + 0x4238 + (channel << 10), 0x00280c01);
+		write32(DEFAULT_MCHBAR + 0x4208 + (channel << 10),
+			0x00060400 | (slotrank << 24));
+		write32(DEFAULT_MCHBAR + 0x4218 + (channel << 10), 0x00000240);
+
+		write32(DEFAULT_MCHBAR + 0x4284 + (channel << 10), 0x00080001);
+		wait_428c(channel);
+		}
+		}
+	}
+}
+
 void set_scrambling_seed(ramctr_timing * ctrl)
 {
 	int channel;
diff --git a/src/northbridge/intel/sandybridge/raminit_common.h b/src/northbridge/intel/sandybridge/raminit_common.h
index cd8310d..dc485d6 100644
--- a/src/northbridge/intel/sandybridge/raminit_common.h
+++ b/src/northbridge/intel/sandybridge/raminit_common.h
@@ -36,7 +36,7 @@
 #define NUM_CHANNELS 2
 #define NUM_SLOTRANKS 4
 #define NUM_SLOTS 2
-#define NUM_LANES 8
+#define NUM_LANES 9
 
 /* FIXME: Vendor BIOS uses 64 but our algorithms are less
    performant and even 1 seems to be enough in practice.  */
@@ -121,6 +121,8 @@
 
 	int ecc_supported;
 	int ecc_forced;
+	int ecc_enabled;
+	int lanes;	/* active lanes: 8 or 9 */
 	int edge_offset[3];
 	int timC_offset[3];
 
@@ -136,7 +138,7 @@
 
 #define SOUTHBRIDGE PCI_DEV(0, 0x1f, 0)
 #define NORTHBRIDGE PCI_DEV(0, 0x0, 0)
-#define FOR_ALL_LANES for (lane = 0; lane < NUM_LANES; lane++)
+#define FOR_ALL_LANES for (lane = 0; lane < ctrl->lanes; lane++)
 #define FOR_ALL_CHANNELS for (channel = 0; channel < NUM_CHANNELS; channel++)
 #define FOR_ALL_POPULATED_RANKS for (slotrank = 0; slotrank < NUM_SLOTRANKS; slotrank++) if (ctrl->rankmap[channel] & (1 << slotrank))
 #define FOR_ALL_POPULATED_CHANNELS for (channel = 0; channel < NUM_CHANNELS; channel++) if (ctrl->rankmap[channel])
@@ -181,6 +183,7 @@
 void set_42a0(ramctr_timing * ctrl);
 void final_registers(ramctr_timing * ctrl);
 void restore_timings(ramctr_timing * ctrl);
+void channel_scrub(ramctr_timing *ctrl);
 
 int try_init_dram_ddr3_sandy(ramctr_timing *ctrl, int fast_boot,
 		int s3_resume, int me_uma_size);
diff --git a/src/northbridge/intel/sandybridge/raminit_ivy.c b/src/northbridge/intel/sandybridge/raminit_ivy.c
index 675ac71..5d375b9 100644
--- a/src/northbridge/intel/sandybridge/raminit_ivy.c
+++ b/src/northbridge/intel/sandybridge/raminit_ivy.c
@@ -747,6 +747,9 @@
 		err = channel_test(ctrl);
 		if (err)
 			return err;
+
+		if (ctrl->ecc_enabled)
+			channel_scrub(ctrl);
 	}
 
 	return 0;

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

Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: I1206746332c9939a78b67e7b48d3098bdef8a2ed
Gerrit-Change-Number: 22215
Gerrit-PatchSet: 1
Gerrit-Owner: Patrick Rudolph <siro at das-labor.org>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.coreboot.org/pipermail/coreboot-gerrit/attachments/20171028/6f7c46cd/attachment.html>


More information about the coreboot-gerrit mailing list