aboutsummaryrefslogtreecommitdiff
path: root/src/northbridge/intel/x4x/raminit.c
diff options
context:
space:
mode:
authorArthur Heymans <arthur@aheymans.xyz>2017-09-25 09:40:54 +0200
committerPatrick Georgi <pgeorgi@google.com>2018-04-17 10:39:45 +0000
commitadc571a54c484bc5a4bb7785db8eda1be153eed9 (patch)
tree383e4a655a22bdcfa7012cacf01daccc63f219fe /src/northbridge/intel/x4x/raminit.c
parent0cdaad36eb033eec831ad1eecec785ce89950ca7 (diff)
nb/intel/x4x: Use SPI flash to cache raminit results
Stores information obtained from decoding dimms and receive enable results for future use. Depreciates using rtc nvram to store receive enable settings. A notable change is that receive enable results are always reused, not just on a resume from S3. This requires cbmem to be initialized a bit earlier, right after the raminit finished to be able to add the sysinfo struct to cbmem which gets cached to the SPI flash in ramstage. TESTED on Intel DG43GT with W25Q128.V. With 4 ddr2 dimms time in raminit goes from 133,857ms (using i2c block read to fetch SPD) to 21,071ms for cached results. Change-Id: I042dc5c52615d40781d9ef7ecd657ad0bf3ed08f Signed-off-by: Arthur Heymans <arthur@aheymans.xyz> Reviewed-on: https://review.coreboot.org/21677 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Felix Held <felix-coreboot@felixheld.de>
Diffstat (limited to 'src/northbridge/intel/x4x/raminit.c')
-rw-r--r--src/northbridge/intel/x4x/raminit.c126
1 files changed, 107 insertions, 19 deletions
diff --git a/src/northbridge/intel/x4x/raminit.c b/src/northbridge/intel/x4x/raminit.c
index 7bb5f2b48b..37120dfe7c 100644
--- a/src/northbridge/intel/x4x/raminit.c
+++ b/src/northbridge/intel/x4x/raminit.c
@@ -33,12 +33,51 @@
#include <spd.h>
#include <string.h>
#include <device/dram/ddr2.h>
+#include <mrc_cache.h>
+
+#define MRC_CACHE_VERSION 0
static inline int spd_read_byte(unsigned int device, unsigned int address)
{
return smbus_read_byte(device, address);
}
+static enum cb_err verify_spds(const u8 *spd_map,
+ const struct sysinfo *ctrl_cached)
+{
+ int i;
+ u8 raw_spd[256] = {};
+ u16 crc;
+
+ for (i = 0; i < TOTAL_DIMMS; i++) {
+ if (!(spd_map[i]))
+ continue;
+ int len = smbus_read_byte(spd_map[i], 0);
+ if (len < 0 && ctrl_cached->dimms[i].card_type
+ == RAW_CARD_UNPOPULATED)
+ continue;
+ if (len > 0 && ctrl_cached->dimms[i].card_type
+ == RAW_CARD_UNPOPULATED)
+ return CB_ERR;
+
+ if (ctrl_cached->spd_type == DDR2) {
+ i2c_block_read(spd_map[i], 64, 9, &raw_spd[64]);
+ i2c_block_read(spd_map[i], 93, 6, &raw_spd[93]);
+ crc = spd_ddr2_calc_unique_crc(raw_spd, len);
+ } else { /*
+ * DDR3: TODO ddr2.h and ddr3.h
+ * cannot be included directly
+ */
+ crc = 0;
+ // i2c_block_read(spd_map[i], 117, 11, &raw_spd[117]);
+ // crc = spd_ddr3_calc_unique_crc(raw_spd, len);
+ }
+ if (crc != ctrl_cached->dimms[i].spd_crc)
+ return CB_ERR;
+ }
+ return CB_SUCCESS;
+}
+
struct abs_timings {
u32 min_tclk;
u32 min_tRAS;
@@ -192,6 +231,9 @@ static int ddr2_save_dimminfo(u8 dimm_idx, u8 *raw_spd,
MAX(saved_timings->min_tCLK_cas[i],
decoded_dimm.cycle_time[i]);
}
+
+ s->dimms[dimm_idx].spd_crc = spd_ddr2_calc_unique_crc(raw_spd,
+ spd_decode_spd_size_ddr2(raw_spd[0]));
return CB_SUCCESS;
}
@@ -292,10 +334,10 @@ static void decode_spd_select_timings(struct sysinfo *s)
if (s->spd_type == DDR2){
printk(BIOS_DEBUG,
"Reading SPD using i2c block operation.\n");
- if (i2c_block_read(device, 0, 64, raw_spd) != 64) {
+ if (i2c_block_read(device, 0, 128, raw_spd) != 128) {
printk(BIOS_DEBUG, "i2c block operation failed,"
" trying smbus byte operation.\n");
- for (j = 0; j < 64; j++)
+ for (j = 0; j < 128; j++)
raw_spd[j] = spd_read_byte(device, j);
}
if (ddr2_save_dimminfo(i, raw_spd, &saved_timings, s)) {
@@ -385,8 +427,10 @@ static void checkreset_ddr2(int boot_path)
*/
void sdram_initialize(int boot_path, const u8 *spd_map)
{
- struct sysinfo s;
+ struct sysinfo s, *ctrl_cached;
u8 reg8;
+ int fast_boot, cbmem_was_inited, cache_not_found;
+ struct region_device rdev;
printk(BIOS_DEBUG, "Setting up RAM controller.\n");
@@ -394,28 +438,62 @@ void sdram_initialize(int boot_path, const u8 *spd_map)
memset(&s, 0, sizeof(struct sysinfo));
- s.boot_path = boot_path;
- s.spd_map[0] = spd_map[0];
- s.spd_map[1] = spd_map[1];
- s.spd_map[2] = spd_map[2];
- s.spd_map[3] = spd_map[3];
-
- checkreset_ddr2(s.boot_path);
+ cache_not_found = mrc_cache_get_current(MRC_TRAINING_DATA,
+ MRC_CACHE_VERSION, &rdev);
- /* Detect dimms per channel */
- reg8 = pci_read_config8(PCI_DEV(0, 0, 0), 0xe9);
- printk(BIOS_DEBUG, "Dimms per channel: %d\n", (reg8 & 0x10) ? 1 : 2);
+ if (cache_not_found || (region_device_sz(&rdev) < sizeof(s))) {
+ if (boot_path == BOOT_PATH_RESUME) {
+ /* Failed S3 resume, reset to come up cleanly */
+ outb(0x6, 0xcf9);
+ halt();
+ }
+ ctrl_cached = NULL;
+ } else {
+ ctrl_cached = rdev_mmap_full(&rdev);
+ }
- mchinfo_ddr2(&s);
+ /* verify MRC cache for fast boot */
+ if (boot_path != BOOT_PATH_RESUME && ctrl_cached) {
+ /* check SPD checksum to make sure the DIMMs haven't been
+ * replaced */
+ fast_boot = verify_spds(spd_map, ctrl_cached) == CB_SUCCESS;
+ if (!fast_boot)
+ printk(BIOS_DEBUG, "SPD checksums don't match,"
+ " dimm's have been replaced\n");
+ } else {
+ fast_boot = boot_path == BOOT_PATH_RESUME;
+ }
- find_fsb_speed(&s);
- decode_spd_select_timings(&s);
- print_selected_timings(&s);
- find_dimm_config(&s);
+ if (fast_boot) {
+ printk(BIOS_DEBUG, "Using cached raminit settings\n");
+ memcpy(&s, ctrl_cached, sizeof(s));
+ s.boot_path = boot_path;
+ mchinfo_ddr2(&s);
+ print_selected_timings(&s);
+ } else {
+ s.boot_path = boot_path;
+ s.spd_map[0] = spd_map[0];
+ s.spd_map[1] = spd_map[1];
+ s.spd_map[2] = spd_map[2];
+ s.spd_map[3] = spd_map[3];
+ checkreset_ddr2(s.boot_path);
+
+ /* Detect dimms per channel */
+ reg8 = pci_read_config8(PCI_DEV(0, 0, 0), 0xe9);
+ printk(BIOS_DEBUG, "Dimms per channel: %d\n",
+ (reg8 & 0x10) ? 1 : 2);
+
+ mchinfo_ddr2(&s);
+
+ find_fsb_speed(&s);
+ decode_spd_select_timings(&s);
+ print_selected_timings(&s);
+ find_dimm_config(&s);
+ }
switch (s.spd_type) {
case DDR2:
- raminit_ddr2(&s);
+ raminit_ddr2(&s, fast_boot);
break;
case DDR3:
// FIXME Add: raminit_ddr3(&s);
@@ -431,4 +509,14 @@ void sdram_initialize(int boot_path, const u8 *spd_map)
reg8 = pci_read_config8(PCI_DEV(0, 0, 0), 0xf4);
pci_write_config8(PCI_DEV(0, 0, 0), 0xf4, reg8 | 1);
printk(BIOS_DEBUG, "RAM initialization finished.\n");
+
+ cbmem_was_inited = !cbmem_recovery(s.boot_path == BOOT_PATH_RESUME);
+ if (!fast_boot)
+ mrc_cache_stash_data(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
+ &s, sizeof(s));
+ if (s.boot_path == BOOT_PATH_RESUME && !cbmem_was_inited) {
+ /* Failed S3 resume, reset to come up cleanly */
+ outb(0x6, 0xcf9);
+ halt();
+ }
}