diff options
author | Patrick Rudolph <siro@das-labor.org> | 2016-03-13 11:07:45 +0100 |
---|---|---|
committer | Martin Roth <martinroth@google.com> | 2016-04-10 18:15:40 +0200 |
commit | 56abd4d878e226c1c4499fdc28901711e2f2a95c (patch) | |
tree | 15918925a3401decc9a517e0b6793441a460aa79 | |
parent | b2f9a10c189a267e834167e224b5d4be4c1f3269 (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.c | 102 |
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 */ |