From dd662870dd9da0be937c593b0b62f3b5c8030cf7 Mon Sep 17 00:00:00 2001 From: Patrick Rudolph Date: Sat, 28 Oct 2017 18:20:11 +0200 Subject: nb/intel/sandybridge/raminit: Add ECC support Add ECC support for native raminit on SandyBridge/IvyBridge. Change-Id: I1206746332c9939a78b67e7b48d3098bdef8a2ed Depends-On: I5b7599746195cfa996a48320404a8dbe6820483a Signed-off-by: Patrick Rudolph Signed-off-by: Jonathan A. Kollasch Reviewed-on: https://review.coreboot.org/c/coreboot/+/22215 Tested-by: build bot (Jenkins) Reviewed-by: Angel Pons --- src/northbridge/intel/sandybridge/Kconfig | 6 +++ src/northbridge/intel/sandybridge/raminit.c | 12 +++++ src/northbridge/intel/sandybridge/raminit_common.c | 58 ++++++++++++++++++++-- src/northbridge/intel/sandybridge/raminit_common.h | 11 ++-- src/northbridge/intel/sandybridge/raminit_native.c | 8 ++- 5 files changed, 85 insertions(+), 10 deletions(-) diff --git a/src/northbridge/intel/sandybridge/Kconfig b/src/northbridge/intel/sandybridge/Kconfig index 29a6db7fb3..6b7520f27d 100644 --- a/src/northbridge/intel/sandybridge/Kconfig +++ b/src/northbridge/intel/sandybridge/Kconfig @@ -100,6 +100,12 @@ config DCACHE_RAM_MRC_VAR_SIZE hex default 0x0 +config RAMINIT_ENABLE_ECC + bool "Enable ECC if supported" + default y + help + Enable ECC if supported by both, host and RAM. + endif # USE_NATIVE_RAMINIT if !USE_NATIVE_RAMINIT diff --git a/src/northbridge/intel/sandybridge/raminit.c b/src/northbridge/intel/sandybridge/raminit.c index a938a49172..e138756d9b 100644 --- a/src/northbridge/intel/sandybridge/raminit.c +++ b/src/northbridge/intel/sandybridge/raminit.c @@ -102,6 +102,7 @@ static void dram_find_spds_ddr3(spd_raw_data *spd, ramctr_timing *ctrl) { int dimms = 0, ch_dimms; int channel, slot, spd_slot; + bool can_use_ecc = ctrl->ecc_supported; dimm_info *dimm = &ctrl->info; memset (ctrl->rankmap, 0, sizeof(ctrl->rankmap)); @@ -173,6 +174,9 @@ static void dram_find_spds_ddr3(spd_raw_data *spd, ramctr_timing *ctrl) ctrl->channel_size_mb[channel] += dimm->dimm[channel][slot].size_mb; + if (!dimm->dimm[channel][slot].flags.is_ecc) + can_use_ecc = false; + ctrl->auto_self_refresh &= dimm->dimm[channel][slot].flags.asr; ctrl->extended_temperature_range &= @@ -204,6 +208,14 @@ static void dram_find_spds_ddr3(spd_raw_data *spd, ramctr_timing *ctrl) } } + if (ctrl->ecc_forced || CONFIG(RAMINIT_ENABLE_ECC)) + ctrl->ecc_enabled = can_use_ecc; + if (ctrl->ecc_forced && !ctrl->ecc_enabled) + die("ECC mode forced but non-ECC DIMM installed!"); + printk(BIOS_DEBUG, "ECC is %s\n", ctrl->ecc_enabled ? "enabled" : "disabled"); + + ctrl->lanes = ctrl->ecc_enabled ? 9 : 8; + if (!dimms) die("No DIMMs were found"); } diff --git a/src/northbridge/intel/sandybridge/raminit_common.c b/src/northbridge/intel/sandybridge/raminit_common.c index 9642a55b31..51f33629f1 100644 --- a/src/northbridge/intel/sandybridge/raminit_common.c +++ b/src/northbridge/intel/sandybridge/raminit_common.c @@ -16,7 +16,6 @@ #include "raminit_tables.h" #include "sandybridge.h" -/* FIXME: no ECC support */ /* FIXME: no support for 3-channel chipsets */ /* length: [1..4] */ @@ -309,12 +308,21 @@ void dram_dimm_mapping(ramctr_timing *ctrl) } } -void dram_dimm_set_mapping(ramctr_timing *ctrl) +void dram_dimm_set_mapping(ramctr_timing *ctrl, int training) { int channel; + u32 ecc; + + if (ctrl->ecc_enabled) + ecc = training ? (1 << 24) : (3 << 24); + else + ecc = 0; + FOR_ALL_CHANNELS { - MCHBAR32(MAD_DIMM(channel)) = ctrl->mad_dimm[channel]; + MCHBAR32(MAD_DIMM(channel)) = ctrl->mad_dimm[channel] | ecc; } + + //udelay(10); /* TODO: Might be needed for ECC configurations; so far works without. */ } void dram_zones(ramctr_timing *ctrl, int training) @@ -2120,13 +2128,13 @@ static int test_320c(ramctr_timing *ctrl, int channel, int slotrank) lanes_ok |= 1 << lane; } ctr++; - if (lanes_ok == ((1 << NUM_LANES) - 1)) + if (lanes_ok == ((1 << ctrl->lanes) - 1)) break; } ctrl->timings[channel][slotrank] = saved_rt; - return lanes_ok != ((1 << NUM_LANES) - 1); + return lanes_ok != ((1 << ctrl->lanes) - 1); } static void fill_pattern5(ramctr_timing *ctrl, int channel, int patno) @@ -3006,6 +3014,46 @@ int channel_test(ramctr_timing *ctrl) return 0; } +void channel_scrub(ramctr_timing *ctrl) +{ + int channel, slotrank, row, rowsize; + + FOR_ALL_POPULATED_CHANNELS FOR_ALL_POPULATED_RANKS { + rowsize = 1 << ctrl->info.dimm[channel][slotrank >> 1].row_bits; + for (row = 0; row < rowsize; row += 16) { + + wait_for_iosav(channel); + + /* DRAM command ACT */ + MCHBAR32(IOSAV_n_SP_CMD_CTRL_ch(channel, 0)) = IOSAV_ACT; + MCHBAR32(IOSAV_n_SUBSEQ_CTRL_ch(channel, 0)) = + (MAX((ctrl->tFAW >> 2) + 1, ctrl->tRRD) << 10) + | 1 | (ctrl->tRCD << 16); + MCHBAR32(IOSAV_n_SP_CMD_ADDR_ch(channel, 0)) = + row | 0x00060000 | (slotrank << 24); + MCHBAR32(IOSAV_n_ADDR_UPDATE_ch(channel, 0)) = 0x00000241; + + /* DRAM command WR */ + MCHBAR32(IOSAV_n_SP_CMD_CTRL_ch(channel, 1)) = IOSAV_WR; + MCHBAR32(IOSAV_n_SUBSEQ_CTRL_ch(channel, 1)) = 0x08281081; + MCHBAR32(IOSAV_n_SP_CMD_ADDR_ch(channel, 1)) = row | (slotrank << 24); + MCHBAR32(IOSAV_n_ADDR_UPDATE_ch(channel, 1)) = 0x00000242; + + /* DRAM command PRE */ + MCHBAR32(IOSAV_n_SP_CMD_CTRL_ch(channel, 2)) = IOSAV_PRE; + MCHBAR32(IOSAV_n_SUBSEQ_CTRL_ch(channel, 2)) = 0x00280c01; + MCHBAR32(IOSAV_n_SP_CMD_ADDR_ch(channel, 2)) = + 0x00060400 | (slotrank << 24); + MCHBAR32(IOSAV_n_ADDR_UPDATE_ch(channel, 2)) = 0x00000240; + + /* execute command queue */ + MCHBAR32(IOSAV_SEQ_CTL_ch(channel)) = IOSAV_RUN_ONCE(3); + + wait_for_iosav(channel); + } + } +} + void set_scrambling_seed(ramctr_timing *ctrl) { int channel; diff --git a/src/northbridge/intel/sandybridge/raminit_common.h b/src/northbridge/intel/sandybridge/raminit_common.h index ea3d66687e..93541b50fd 100644 --- a/src/northbridge/intel/sandybridge/raminit_common.h +++ b/src/northbridge/intel/sandybridge/raminit_common.h @@ -24,7 +24,7 @@ #define NUM_CHANNELS 2 #define NUM_SLOTRANKS 4 #define NUM_SLOTS 2 -#define NUM_LANES 8 +#define NUM_LANES 9 #define NO_RANKSEL (~(1 << 16)) #define IOSAV_MRS (0x1f000) @@ -43,7 +43,7 @@ /* * WARNING: Do not forget to increase MRC_CACHE_VERSION when the saved data is changed! */ -#define MRC_CACHE_VERSION 4 +#define MRC_CACHE_VERSION 5 typedef struct odtmap_st { u16 rttwr; @@ -134,6 +134,8 @@ typedef struct ramctr_timing_st { bool ecc_supported; bool ecc_forced; + bool ecc_enabled; + int lanes; /* active lanes: 8 or 9 */ int edge_offset[3]; int timC_offset[3]; @@ -149,7 +151,7 @@ typedef struct ramctr_timing_st { #define SOUTHBRIDGE PCI_DEV(0, 0x1f, 0) -#define FOR_ALL_LANES for (lane = 0; lane < NUM_LANES; lane++) +#define FOR_ALL_LANES for (lane = 0; lane < ctrl->lanes; lane++) #define FOR_ALL_CHANNELS for (channel = 0; channel < NUM_CHANNELS; channel++) #define FOR_ALL_POPULATED_RANKS for (slotrank = 0; slotrank < NUM_SLOTRANKS; slotrank++) if (ctrl->rankmap[channel] & (1 << slotrank)) #define FOR_ALL_POPULATED_CHANNELS for (channel = 0; channel < NUM_CHANNELS; channel++) if (ctrl->rankmap[channel]) @@ -170,7 +172,7 @@ void dram_find_common_params(ramctr_timing *ctrl); void dram_xover(ramctr_timing *ctrl); void dram_timing_regs(ramctr_timing *ctrl); void dram_dimm_mapping(ramctr_timing *ctrl); -void dram_dimm_set_mapping(ramctr_timing *ctrl); +void dram_dimm_set_mapping(ramctr_timing *ctrl, int training); void dram_zones(ramctr_timing *ctrl, int training); unsigned int get_mem_min_tck(void); void dram_memorymap(ramctr_timing *ctrl, int me_uma_size); @@ -193,6 +195,7 @@ void final_registers(ramctr_timing *ctrl); void restore_timings(ramctr_timing *ctrl); int try_init_dram_ddr3(ramctr_timing *ctrl, int fast_boot, int s3resume, int me_uma_size); +void channel_scrub(ramctr_timing *ctrl); bool get_host_ecc_cap(void); bool get_host_ecc_forced(void); diff --git a/src/northbridge/intel/sandybridge/raminit_native.c b/src/northbridge/intel/sandybridge/raminit_native.c index d27914a184..99c1a4c4ff 100644 --- a/src/northbridge/intel/sandybridge/raminit_native.c +++ b/src/northbridge/intel/sandybridge/raminit_native.c @@ -537,7 +537,7 @@ int try_init_dram_ddr3(ramctr_timing *ctrl, int fast_boot, int s3resume, int me_ MCHBAR32(MC_INIT_STATE_G) &= ~(1 << 5); /* Set MAD-DIMM registers */ - dram_dimm_set_mapping(ctrl); + dram_dimm_set_mapping(ctrl, 1); printk(BIOS_DEBUG, "Done dimm mapping\n"); /* Zone config */ @@ -608,7 +608,13 @@ int try_init_dram_ddr3(ramctr_timing *ctrl, int fast_boot, int s3resume, int me_ err = channel_test(ctrl); if (err) return err; + + if (ctrl->ecc_enabled) + channel_scrub(ctrl); } + /* Set MAD-DIMM registers */ + dram_dimm_set_mapping(ctrl, 0); + return 0; } -- cgit v1.2.3