Patrick Rudolph (siro@das-labor.org) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/14082
-gerrit
commit f3c8a14276de9a9d721dabed4e186bf75ab3e88d Author: Patrick Rudolph siro@das-labor.org Date: Sun Mar 13 11:07:45 2016 +0100
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.
Test system: * Gigabyte GA-B75M-D3H * Intel Pentium CPU G2130
Change-Id: I974c5bce70692a706410180c2a512eb071364be0 Signed-off-by: Patrick Rudolph siro@das-labor.org --- src/northbridge/intel/sandybridge/raminit.c | 75 +++++++++++++++++++++-------- 1 file changed, 55 insertions(+), 20 deletions(-)
diff --git a/src/northbridge/intel/sandybridge/raminit.c b/src/northbridge/intel/sandybridge/raminit.c index 0b27fe5..152e881 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; @@ -316,6 +317,23 @@ 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; @@ -368,6 +386,9 @@ static void dram_find_spds_ddr3(spd_raw_data * spd, dimm_info * dimm, 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; @@ -3943,6 +3964,10 @@ void init_dram_ddr3(spd_raw_data * spds, int mobile, int min_tck, { int me_uma_size; int cbmem_was_inited; + int fast_boot; + ramctr_timing ctrl; + struct mrc_data_container *mrc_cache; + ramctr_timing *ctrl_cached; dimm_info info;
MCHBAR32(0x5f00) |= 1; @@ -3971,32 +3996,42 @@ void init_dram_ddr3(spd_raw_data * spds, int mobile, int min_tck, halt(); }
- ramctr_timing ctrl; - memset(&ctrl, 0, sizeof (ctrl));
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; }
- if (!s3resume) { + /* 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"); + } else + fast_boot = 0; + + if (fast_boot) { + printk(BIOS_DEBUG, "Using stored timings. Skipping RAM training.\n"); + memcpy(&ctrl, ctrl_cached, sizeof(ctrl)); + } else { + ctrl.mobile = mobile; + ctrl.tCK = min_tck; + + printk(BIOS_DEBUG, "No valid stored timings found. Starting RAM training.\n"); + /* Get DDR3 SPD data */ dram_find_spds_ddr3(spds, &info, &ctrl);
@@ -4009,7 +4044,7 @@ void init_dram_ddr3(spd_raw_data * spds, int mobile, int min_tck, /* Set MCU frequency */ dram_freq(&ctrl);
- if (!s3resume) { + if (!fast_boot) { /* Calculate timings */ dram_timing(&ctrl); } @@ -4052,7 +4087,7 @@ void init_dram_ddr3(spd_raw_data * spds, int mobile, int min_tck,
udelay(1);
- if (s3resume) { + if (fast_boot) { restore_timings(&ctrl); } else { /* Do jedec ddr3 reset sequence */ @@ -4090,7 +4125,7 @@ void init_dram_ddr3(spd_raw_data * spds, int mobile, int min_tck,
write_controller_mr(&ctrl);
- if (!s3resume) { + if (!fast_boot) { channel_test(&ctrl); }
@@ -4106,7 +4141,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(); @@ -4116,7 +4151,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 */