summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Rudolph <siro@das-labor.org>2016-03-13 11:07:45 +0100
committerMartin Roth <martinroth@google.com>2016-04-10 18:15:40 +0200
commit56abd4d878e226c1c4499fdc28901711e2f2a95c (patch)
tree15918925a3401decc9a517e0b6793441a460aa79
parentb2f9a10c189a267e834167e224b5d4be4c1f3269 (diff)
nb/intel/sandybridge/raminit: always use mrccache
Always use MRC cache if possible. Added a CRC16 array to make sure the DIMMs haven't been replaced. In case one of the CRC's doesn't match, start normal RAM training. Use new fallback in case of broken mrc cache. Test system: * Gigabyte GA-B75M-D3H * Intel Pentium CPU G2130 Test result: The system boots a lot faster using the MRC cache. On swapping DIMMs the CRC16 doesn't match and normal ram training is started. Change-Id: Ib48fe8380446846df17d37b22968f7d4fd6b9b13 Signed-off-by: Patrick Rudolph <siro@das-labor.org> Reviewed-on: https://review.coreboot.org/14172 Reviewed-by: Aaron Durbin <adurbin@chromium.org> Tested-by: build bot (Jenkins) Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net>
-rw-r--r--src/northbridge/intel/sandybridge/raminit.c102
1 files changed, 77 insertions, 25 deletions
diff --git a/src/northbridge/intel/sandybridge/raminit.c b/src/northbridge/intel/sandybridge/raminit.c
index 48ec5b50b9..042898dfb6 100644
--- a/src/northbridge/intel/sandybridge/raminit.c
+++ b/src/northbridge/intel/sandybridge/raminit.c
@@ -135,6 +135,7 @@ struct ram_rank_timings {
struct ramctr_timing_st;
typedef struct ramctr_timing_st {
+ u16 spd_crc[NUM_CHANNELS][NUM_SLOTS];
int mobile;
u16 cas_supported;
@@ -324,6 +325,24 @@ static void report_memory_config(void)
}
}
+/*
+ * Return CRC16 match for all SPDs.
+ */
+static int verify_crc16_spds_ddr3(spd_raw_data *spd, ramctr_timing *ctrl)
+{
+ int channel, slot, spd_slot;
+ int match = 1;
+
+ FOR_ALL_CHANNELS {
+ for (slot = 0; slot < NUM_SLOTS; slot++) {
+ spd_slot = 2 * channel + slot;
+ match &= ctrl->spd_crc[channel][slot] ==
+ spd_ddr3_calc_crc(spd[spd_slot], sizeof(spd_raw_data));
+ }
+ }
+ return match;
+}
+
void read_spd(spd_raw_data * spd, u8 addr)
{
int j;
@@ -376,6 +395,10 @@ static void dram_find_spds_ddr3(spd_raw_data *spd, ramctr_timing *ctrl)
spd_decode_ddr3(&dimm->dimm[channel][slot], spd[spd_slot]);
}
+ /* fill in CRC16 for MRC cache */
+ ctrl->spd_crc[channel][slot] =
+ spd_ddr3_calc_crc(spd[spd_slot], sizeof(spd_raw_data));
+
if (dimm->dimm[channel][slot].dram_type != SPD_MEMORY_TYPE_SDRAM_DDR3) {
// set dimm invalid
dimm->dimm[channel][slot].ranks = 0;
@@ -4014,12 +4037,14 @@ static void restore_timings(ramctr_timing * ctrl)
write32(DEFAULT_MCHBAR + 0x4ea8, 0);
}
-static int try_init_dram_ddr3(ramctr_timing *ctrl, int s3resume,
+static int try_init_dram_ddr3(ramctr_timing *ctrl, int fast_boot,
int me_uma_size)
{
int err;
- if (!s3resume) {
+ printk(BIOS_DEBUG, "Starting RAM training (%d).\n", fast_boot);
+
+ if (!fast_boot) {
/* Find fastest common supported parameters */
dram_find_common_params(ctrl);
@@ -4029,7 +4054,7 @@ static int try_init_dram_ddr3(ramctr_timing *ctrl, int s3resume,
/* Set MCU frequency */
dram_freq(ctrl);
- if (!s3resume) {
+ if (!fast_boot) {
/* Calculate timings */
dram_timing(ctrl);
}
@@ -4072,7 +4097,7 @@ static int try_init_dram_ddr3(ramctr_timing *ctrl, int s3resume,
udelay(1);
- if (s3resume) {
+ if (fast_boot) {
restore_timings(ctrl);
} else {
/* Do jedec ddr3 reset sequence */
@@ -4123,11 +4148,9 @@ static int try_init_dram_ddr3(ramctr_timing *ctrl, int s3resume,
write_controller_mr(ctrl);
- if (!s3resume) {
- err = channel_test(ctrl);
- if (err)
- return err;
- }
+ err = channel_test(ctrl);
+ if (err)
+ return err;
return 0;
}
@@ -4138,6 +4161,9 @@ void init_dram_ddr3(spd_raw_data *spds, int mobile, int min_tck,
int me_uma_size;
int cbmem_was_inited;
ramctr_timing ctrl;
+ int fast_boot;
+ struct mrc_data_container *mrc_cache;
+ ramctr_timing *ctrl_cached;
int err;
MCHBAR32(0x5f00) |= 1;
@@ -4171,28 +4197,54 @@ void init_dram_ddr3(spd_raw_data *spds, int mobile, int min_tck,
early_pch_init_native();
early_thermal_init();
- ctrl.mobile = mobile;
- ctrl.tCK = min_tck;
-
- /* FIXME: for non-S3 we should be able to use timing caching with
- proper verification. Right now we use timings only for S3 case.
- */
- if (s3resume) {
- struct mrc_data_container *mrc_cache;
-
- mrc_cache = find_current_mrc_cache();
- if (!mrc_cache || (mrc_cache->mrc_data_size < sizeof(ctrl))) {
+ /* try to find timings in MRC cache */
+ mrc_cache = find_current_mrc_cache();
+ if (!mrc_cache || (mrc_cache->mrc_data_size < sizeof(ctrl))) {
+ if (s3resume) {
/* Failed S3 resume, reset to come up cleanly */
outb(0x6, 0xcf9);
halt();
}
- memcpy(&ctrl, mrc_cache->mrc_data, sizeof(ctrl));
+ ctrl_cached = NULL;
} else {
+ ctrl_cached = (ramctr_timing *)mrc_cache->mrc_data;
+ }
+
+ /* verify MRC cache for fast boot */
+ if (ctrl_cached) {
+ /* check SPD CRC16 to make sure the DIMMs haven't been replaced */
+ fast_boot = verify_crc16_spds_ddr3(spds, ctrl_cached);
+ if (!fast_boot)
+ printk(BIOS_DEBUG, "Stored timings CRC16 mismatch.\n");
+ if (!fast_boot && s3resume) {
+ /* Failed S3 resume, reset to come up cleanly */
+ outb(0x6, 0xcf9);
+ halt();
+ }
+ } else
+ fast_boot = 0;
+
+ if (fast_boot) {
+ printk(BIOS_DEBUG, "Trying stored timings.\n");
+ memcpy(&ctrl, ctrl_cached, sizeof(ctrl));
+
+ err = try_init_dram_ddr3(&ctrl, fast_boot, me_uma_size);
+ if (err) {
+ /* no need to erase bad mrc cache here, it gets overritten on
+ * successful boot. */
+ printk(BIOS_ERR, "Stored timings are invalid !\n");
+ fast_boot = 0;
+ }
+ }
+ if (!fast_boot) {
+ ctrl.mobile = mobile;
+ ctrl.tCK = min_tck;
+
/* Get DDR3 SPD data */
dram_find_spds_ddr3(spds, &ctrl);
- }
- err = try_init_dram_ddr3(&ctrl, s3resume, me_uma_size);
+ err = try_init_dram_ddr3(&ctrl, fast_boot, me_uma_size);
+ }
if (err)
die("raminit failed");
@@ -4208,7 +4260,7 @@ void init_dram_ddr3(spd_raw_data *spds, int mobile, int min_tck,
/* Zone config */
dram_zones(&ctrl, 0);
- if (!s3resume)
+ if (!fast_boot)
quick_ram_check();
intel_early_me_status();
@@ -4218,7 +4270,7 @@ void init_dram_ddr3(spd_raw_data *spds, int mobile, int min_tck,
report_memory_config();
cbmem_was_inited = !cbmem_recovery(s3resume);
- if (!s3resume)
+ if (!fast_boot)
save_timings(&ctrl);
if (s3resume && !cbmem_was_inited) {
/* Failed S3 resume, reset to come up cleanly */