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

<div style="display:none"> Gerrit-Project: coreboot </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>
<div style="display:none"> Gerrit-Change-Id: I1206746332c9939a78b67e7b48d3098bdef8a2ed </div>
<div style="display:none"> Gerrit-Change-Number: 22215 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Patrick Rudolph <siro@das-labor.org> </div>