summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Rudolph <siro@das-labor.org>2016-03-26 12:16:29 +0100
committerMartin Roth <martinroth@google.com>2016-05-04 19:58:46 +0200
commit2ccb74b6e97381ce2b2f8520076204f7737ade4c (patch)
tree3cae8b87576b4a21bab443b8e04083eeba6edc7c
parent1e302cbd09bb304309476113c149c2c0d09a2a86 (diff)
nb/intel/sandybridge/raminit: add additional fallbacks
Add the following fallbacks: * Try decreasing clock frequency. In case of DDR1600 the next possible value of DDR1333 is being used. * Try decreasing clock frequency. In case of DDR1333 the next possible value of DDR1066 is being used. * Disable failing channel. The system may be able to boot with a single channel enabled. The fallbacks are untested. Change-Id: I3be7034ad25312b3ebf47a54f335a3893f8d7cc1 Signed-off-by: Patrick Rudolph <siro@das-labor.org> Reviewed-on: https://review.coreboot.org/14173 Tested-by: build bot (Jenkins) Reviewed-by: Martin Roth <martinroth@google.com>
-rw-r--r--src/northbridge/intel/sandybridge/raminit.c44
1 files changed, 44 insertions, 0 deletions
diff --git a/src/northbridge/intel/sandybridge/raminit.c b/src/northbridge/intel/sandybridge/raminit.c
index 3c606e17c2..0c191b2abd 100644
--- a/src/northbridge/intel/sandybridge/raminit.c
+++ b/src/northbridge/intel/sandybridge/raminit.c
@@ -201,6 +201,7 @@ typedef struct ramctr_timing_st {
#define MAX_TIMA 127
#define MAKE_ERR ((channel<<16)|(slotrank<<8)|1)
+#define GET_ERR_CHANNEL(x) (x>>16)
static void program_timings(ramctr_timing * ctrl, int channel);
@@ -241,6 +242,18 @@ static void toggle_io_reset(void) {
}
/*
+ * Disable a channel in ramctr_timing.
+ */
+static void disable_channel(ramctr_timing *ctrl, int channel) {
+ ctrl->rankmap[channel] = 0;
+ memset(&ctrl->rank_mirror[channel][0], 0, sizeof(ctrl->rank_mirror[0]));
+ ctrl->channel_size_mb[channel] = 0;
+ ctrl->cmd_stretch[channel] = 0;
+ ctrl->mad_dimm[channel] = 0;
+ memset(&ctrl->timings[channel][0], 0, sizeof(ctrl->timings[0]));
+}
+
+/*
* Fill cbmem with information for SMBIOS type 17.
*/
static void fill_smbios17(ramctr_timing *ctrl)
@@ -4252,6 +4265,37 @@ void init_dram_ddr3(spd_raw_data *spds, int mobile, int min_tck,
err = try_init_dram_ddr3(&ctrl, fast_boot, s3resume, me_uma_size);
}
+
+ if (err && (ctrl.tCK < TCK_400MHZ)) {
+ /* fallback: lower clock frequency */
+ printk(BIOS_ERR, "RAM training failed, trying fallback.\n");
+ printram("Decreasing clock frequency.\n");
+ ctrl.tCK++;
+ err = try_init_dram_ddr3(&ctrl, fast_boot, s3resume, me_uma_size);
+ }
+
+ if (err && (ctrl.tCK < TCK_400MHZ)) {
+ /* fallback: lower clock frequency */
+ printk(BIOS_ERR, "RAM training failed, trying fallback.\n");
+ printram("Decreasing clock frequency.\n");
+ ctrl.tCK++;
+ err = try_init_dram_ddr3(&ctrl, fast_boot, s3resume, me_uma_size);
+ }
+
+ if (err) {
+ /* fallback: disable failing channel */
+ printk(BIOS_ERR, "RAM training failed, trying fallback.\n");
+ printram("Disable failing channel.\n");
+
+ /* Reset DDR3 frequency */
+ dram_find_spds_ddr3(spds, &ctrl);
+
+ /* disable failing channel */
+ disable_channel(&ctrl, GET_ERR_CHANNEL(err));
+
+ err = try_init_dram_ddr3(&ctrl, fast_boot, s3resume, me_uma_size);
+ }
+
if (err)
die("raminit failed");