summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTobias Diedrich <ranma+coreboot@tdiedrich.de>2017-12-07 22:40:20 +0100
committerPatrick Georgi <pgeorgi@google.com>2019-05-29 20:02:40 +0000
commit87c4f11c64713c8a90d7a6ffe997da891c9758d4 (patch)
treea411d9dc00a717ebc2227bccfe93bc3fce60f0d3
parent1bffc4bda3b66ba2c91163ec396c54e51d2f056b (diff)
intel/sandybridge: Make timC training more robust.
When using native raminit with https://review.coreboot.org/#/c/22683/ I've found that timC training usually fails unless the ram is overspecced (i.e. DDR3L-1600 rated for 1.35V works most of the time with native raminit as DDR3-1333 @1.5V). Looking at the training data I've found that during timC training it is reading register values in the 0-4000 range and checking for runs of 0, but with the failing training the values don't go all the way down to 0. The solution for me has been to do a thresholing pre-pass, after which both the DDR3-1333 @1.5V and the DDR3L-1600 @1.35V work fine for me. Tested: - Intel NUC DCP847SKE - RAM slots with 2x4GB Kingston KVR1333D3S9/4G (DDR3-1333 1.5V), boots fine with native raminit @1.5V - RAM slots with 2x4GB Kingston KVR16LS11/4G (DDR3L-1600 1.35V), boots fine with native raminit @1.35V - Casual use with these settings - Tested on Lenovo T520 with Crucial HyperX DDR3-1833. - Memtest86+ stable. Change-Id: I9986616e86560c4980ccd8e3e549af53caa15c71 Signed-off-by: Tobias Diedrich <ranma+coreboot@tdiedrich.de> Signed-off-by: Patrick Rudolph <siro@das-labor.org> Reviewed-on: https://review.coreboot.org/c/coreboot/+/22776 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
-rw-r--r--src/northbridge/intel/sandybridge/raminit_common.c39
1 files changed, 34 insertions, 5 deletions
diff --git a/src/northbridge/intel/sandybridge/raminit_common.c b/src/northbridge/intel/sandybridge/raminit_common.c
index 5347c5c493..53f28c6cd6 100644
--- a/src/northbridge/intel/sandybridge/raminit_common.c
+++ b/src/northbridge/intel/sandybridge/raminit_common.c
@@ -1524,6 +1524,24 @@ static void test_timC(ramctr_timing * ctrl, int channel, int slotrank)
wait_428c(channel);
}
+static void timC_threshold_process(int *data, const int count)
+{
+ int min = data[0];
+ int max = min;
+ int i;
+ for (i = 1; i < count; i++) {
+ if (min > data[i])
+ min = data[i];
+ if (max < data[i])
+ max = data[i];
+ }
+ int threshold = min/2 + max/2;
+ for (i = 0; i < count; i++)
+ data[i] = data[i] > threshold;
+ printram("threshold=%d min=%d max=%d\n",
+ threshold, min, max);
+}
+
static int discover_timC(ramctr_timing *ctrl, int channel, int slotrank)
{
int timC;
@@ -1554,14 +1572,25 @@ static int discover_timC(ramctr_timing *ctrl, int channel, int slotrank)
}
}
FOR_ALL_LANES {
- struct run rn =
- get_longest_zero_run(statistics[lane], MAX_TIMC + 1);
- ctrl->timings[channel][slotrank].lanes[lane].timC = rn.middle;
- if (rn.all) {
+ struct run rn = get_longest_zero_run(
+ statistics[lane], ARRAY_SIZE(statistics[lane]));
+ if (rn.all || rn.length < 8) {
printk(BIOS_EMERG, "timC discovery failed: %d, %d, %d\n",
channel, slotrank, lane);
- return MAKE_ERR;
+ /* With command training not happend yet, the lane can
+ * be erroneous. Take the avarage as reference and try
+ * again to find a run.
+ */
+ timC_threshold_process(statistics[lane],
+ ARRAY_SIZE(statistics[lane]));
+ rn = get_longest_zero_run(statistics[lane],
+ ARRAY_SIZE(statistics[lane]));
+ if (rn.all || rn.length < 8) {
+ printk(BIOS_EMERG, "timC recovery failed\n");
+ return MAKE_ERR;
+ }
}
+ ctrl->timings[channel][slotrank].lanes[lane].timC = rn.middle;
printram("timC: %d, %d, %d: 0x%02x-0x%02x-0x%02x\n",
channel, slotrank, lane, rn.start, rn.middle, rn.end);
}