diff options
-rw-r--r-- | src/northbridge/intel/x4x/Kconfig | 1 | ||||
-rw-r--r-- | src/northbridge/intel/x4x/early_init.c | 9 | ||||
-rw-r--r-- | src/northbridge/intel/x4x/raminit.c | 126 | ||||
-rw-r--r-- | src/northbridge/intel/x4x/raminit_ddr2.c | 95 | ||||
-rw-r--r-- | src/northbridge/intel/x4x/rcven.c | 7 | ||||
-rw-r--r-- | src/northbridge/intel/x4x/x4x.h | 14 |
6 files changed, 158 insertions, 94 deletions
diff --git a/src/northbridge/intel/x4x/Kconfig b/src/northbridge/intel/x4x/Kconfig index 9239637360..d9dbdc9d46 100644 --- a/src/northbridge/intel/x4x/Kconfig +++ b/src/northbridge/intel/x4x/Kconfig @@ -28,6 +28,7 @@ config NORTHBRIDGE_SPECIFIC_OPTIONS # dummy select RELOCATABLE_RAMSTAGE select HAVE_LINEAR_FRAMEBUFFER if MAINBOARD_DO_NATIVE_VGA_INIT select HAVE_VGA_TEXT_FRAMEBUFFER if MAINBOARD_DO_NATIVE_VGA_INIT + select CACHE_MRC_SETTINGS config CBFS_SIZE hex diff --git a/src/northbridge/intel/x4x/early_init.c b/src/northbridge/intel/x4x/early_init.c index fbdbcb4496..ab4864b880 100644 --- a/src/northbridge/intel/x4x/early_init.c +++ b/src/northbridge/intel/x4x/early_init.c @@ -242,15 +242,6 @@ static void init_dmi(void) static void x4x_prepare_resume(int s3resume) { - int cbmem_recovered; - - cbmem_recovered = !cbmem_recovery(s3resume); - if (!cbmem_recovered && s3resume) { - /* Failed S3 resume, reset to come up cleanly */ - outb(0x6, 0xcf9); - halt(); - } - romstage_handoff_init(s3resume); } 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(); + } } diff --git a/src/northbridge/intel/x4x/raminit_ddr2.c b/src/northbridge/intel/x4x/raminit_ddr2.c index 022cbaa0b4..336f77ec7d 100644 --- a/src/northbridge/intel/x4x/raminit_ddr2.c +++ b/src/northbridge/intel/x4x/raminit_ddr2.c @@ -1045,77 +1045,46 @@ static void jedec_ddr2(struct sysinfo *s) printk(BIOS_DEBUG, "MRS done\n"); } -static void sdram_save_receive_enable(void) +static void sdram_recover_receive_enable(const struct sysinfo *s) { - int i = 0; - u16 reg16; - u8 values[18]; - u8 lane, ch; - - FOR_EACH_CHANNEL(ch) { - lane = 0; - while (lane < 8) { - values[i] = (MCHBAR8(0x400*ch + 0x560 + lane++ * 4) & 0xf); - values[i++] |= (MCHBAR8(0x400*ch + 0x560 + lane++ * 4) & 0xf) << 4; - } - values[i++] = (MCHBAR32(0x400*ch + 0x248) >> 16) & 0xf; - reg16 = MCHBAR16(0x400*ch + 0x5fa); - values[i++] = reg16 & 0xff; - values[i++] = (reg16 >> 8) & 0xff; - reg16 = MCHBAR16(0x400*ch + 0x58c); - values[i++] = reg16 & 0xff; - values[i++] = (reg16 >> 8) & 0xff; - } - - for (i = 0; i < ARRAY_SIZE(values); i++) - cmos_write(values[i], 128 + i); -} - -static void sdram_recover_receive_enable(void) -{ - u8 i; u32 reg32; - u16 reg16; - u8 values[18]; - u8 ch, lane; + u16 medium, coarse_offset; + u8 pi_tap; + int lane, channel; + + FOR_EACH_POPULATED_CHANNEL(s->dimms, channel) { + medium = 0; + coarse_offset = 0; + reg32 = MCHBAR32(0x400 * channel + 0x248); + reg32 &= ~0xf0000; + reg32 |= s->rcven_t[channel].min_common_coarse << 16; + MCHBAR32(0x400 * channel + 0x248) = reg32; - for (i = 0; i < ARRAY_SIZE(values); i++) - values[i] = cmos_read(128 + i); - - i = 0; - FOR_EACH_CHANNEL(ch) { - lane = 0; - while (lane < 8) { - MCHBAR8(0x400*ch + 0x560 + lane++ * 4) = 0x70 | - (values[i] & 0xf); - MCHBAR8(0x400*ch + 0x560 + lane++ * 4) = 0x70 | - ((values[i++] >> 4) & 0xf); + for (lane = 0; lane < 8; lane++) { + medium |= s->rcven_t[channel].medium[lane] + << (lane * 2); + coarse_offset |= + (s->rcven_t[channel].coarse_offset[lane] & 0x3) + << (lane * 2); + + pi_tap = MCHBAR8(0x400 * channel + 0x560 + lane * 4); + pi_tap &= ~0x7f; + pi_tap |= s->rcven_t[channel].tap[lane]; + pi_tap |= s->rcven_t[channel].pi[lane] << 4; + MCHBAR8(0x400 * channel + 0x560 + lane * 4) = pi_tap; } - reg32 = (MCHBAR32(0x400*ch + 0x248) & ~0xf0000) - | ((values[i++] & 0xf) << 16); - MCHBAR32(0x400*ch + 0x248) = reg32; - reg16 = values[i++]; - reg16 |= values[i++] << 8; - MCHBAR16(0x400*ch + 0x5fa) = reg16; - reg16 = values[i++]; - reg16 |= values[i++] << 8; - MCHBAR16(0x400*ch + 0x58c) = reg16; + MCHBAR16(0x400 * channel + 0x58c) = medium; + MCHBAR16(0x400 * channel + 0x5fa) = coarse_offset; } } -static void sdram_program_receive_enable(struct sysinfo *s) +static void sdram_program_receive_enable(struct sysinfo *s, int fast_boot) { - /* enable upper CMOS */ - RCBA32(0x3400) = (1 << 2); - /* Program Receive Enable Timings */ - if ((s->boot_path == BOOT_PATH_WARM_RESET) - || (s->boot_path == BOOT_PATH_RESUME)) { - sdram_recover_receive_enable(); - } else { + if (fast_boot) + sdram_recover_receive_enable(s); + else rcven(s); - sdram_save_receive_enable(); - } } static void dradrb_ddr2(struct sysinfo *s) @@ -1470,7 +1439,7 @@ static void power_ddr2(struct sysinfo *s) MCHBAR8(0x561 + (lane << 2)) = MCHBAR8(0x561 + (lane << 2)) & ~(1 << 3); } -void raminit_ddr2(struct sysinfo *s) +void raminit_ddr2(struct sysinfo *s, int fast_boot) { u8 ch; u8 r, bank; @@ -1613,7 +1582,7 @@ void raminit_ddr2(struct sysinfo *s) } // Receive enable - sdram_program_receive_enable(s); + sdram_program_receive_enable(s, fast_boot); printk(BIOS_DEBUG, "Done rcven\n"); // Finish rcven diff --git a/src/northbridge/intel/x4x/rcven.c b/src/northbridge/intel/x4x/rcven.c index cc45aa9331..30ec4be2ee 100644 --- a/src/northbridge/intel/x4x/rcven.c +++ b/src/northbridge/intel/x4x/rcven.c @@ -304,7 +304,7 @@ static int calibrate_receive_enable(u8 channel, u8 lane, return 0; } -void rcven(const struct sysinfo *s) +void rcven(struct sysinfo *s) { int i; u8 channel, lane, reg8; @@ -354,6 +354,7 @@ void rcven(const struct sysinfo *s) mincoarse = timing[lane].coarse; } printk(BIOS_DEBUG, "Found min coarse value = %d\n", mincoarse); + s->rcven_t[channel].min_common_coarse = mincoarse; printk(BIOS_DEBUG, "Receive enable, final timings:\n"); /* Normalise coarse */ for (lane = 0; lane < 8; lane++) { @@ -365,6 +366,10 @@ void rcven(const struct sysinfo *s) "medium: %d; tap: %d\n", channel, lane, reg8, timing[lane].medium, timing[lane].tap); + s->rcven_t[channel].coarse_offset[lane] = reg8; + s->rcven_t[channel].medium[lane] = timing[lane].medium; + s->rcven_t[channel].tap[lane] = timing[lane].tap; + s->rcven_t[channel].pi[lane] = timing[lane].pi; MCHBAR16(0x400 * channel + 0x5fa) = (MCHBAR16(0x400 * channel + 0x5fa) & ~(3 << (lane * 2))) | (reg8 << (lane * 2)); diff --git a/src/northbridge/intel/x4x/x4x.h b/src/northbridge/intel/x4x/x4x.h index cbb1853fab..70c6525bba 100644 --- a/src/northbridge/intel/x4x/x4x.h +++ b/src/northbridge/intel/x4x/x4x.h @@ -279,6 +279,15 @@ struct dimminfo { unsigned int ranks; unsigned int rows; unsigned int cols; + u16 spd_crc; +}; + +struct rcven_timings { + u8 min_common_coarse; + u8 coarse_offset[8]; + u8 medium[8]; + u8 tap[8]; + u8 pi[8]; }; /* The setup is up to two DIMMs per channel */ @@ -293,6 +302,7 @@ struct sysinfo { struct timings selected_timings; struct dimminfo dimms[4]; u8 spd_map[4]; + struct rcven_timings rcven_t[TOTAL_CHANNELS]; }; #define BOOT_PATH_NORMAL 0 #define BOOT_PATH_WARM_RESET 1 @@ -331,8 +341,8 @@ u32 decode_igd_memory_size(u32 gms); u32 decode_igd_gtt_size(u32 gsm); u8 decode_pciebar(u32 *const base, u32 *const len); void sdram_initialize(int boot_path, const u8 *spd_map); -void raminit_ddr2(struct sysinfo *); -void rcven(const struct sysinfo *); +void raminit_ddr2(struct sysinfo *s, int fast_boot); +void rcven(struct sysinfo *s); u32 fsb2mhz(u32 speed); u32 ddr2mhz(u32 speed); |