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 <siro@das-labor.org> Signed-off-by: Jonathan A. Kollasch <jakllsch@kollasch.net> Reviewed-on: https://review.coreboot.org/c/coreboot/+/22215 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Angel Pons <th3fanbus@gmail.com>
This commit is contained in:
parent
05d4bf7ea7
commit
dd662870dd
@ -100,6 +100,12 @@ config DCACHE_RAM_MRC_VAR_SIZE
|
|||||||
hex
|
hex
|
||||||
default 0x0
|
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
|
endif # USE_NATIVE_RAMINIT
|
||||||
|
|
||||||
if !USE_NATIVE_RAMINIT
|
if !USE_NATIVE_RAMINIT
|
||||||
|
@ -102,6 +102,7 @@ static void dram_find_spds_ddr3(spd_raw_data *spd, ramctr_timing *ctrl)
|
|||||||
{
|
{
|
||||||
int dimms = 0, ch_dimms;
|
int dimms = 0, ch_dimms;
|
||||||
int channel, slot, spd_slot;
|
int channel, slot, spd_slot;
|
||||||
|
bool can_use_ecc = ctrl->ecc_supported;
|
||||||
dimm_info *dimm = &ctrl->info;
|
dimm_info *dimm = &ctrl->info;
|
||||||
|
|
||||||
memset (ctrl->rankmap, 0, sizeof(ctrl->rankmap));
|
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;
|
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->auto_self_refresh &= dimm->dimm[channel][slot].flags.asr;
|
||||||
|
|
||||||
ctrl->extended_temperature_range &=
|
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)
|
if (!dimms)
|
||||||
die("No DIMMs were found");
|
die("No DIMMs were found");
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
#include "raminit_tables.h"
|
#include "raminit_tables.h"
|
||||||
#include "sandybridge.h"
|
#include "sandybridge.h"
|
||||||
|
|
||||||
/* FIXME: no ECC support */
|
|
||||||
/* FIXME: no support for 3-channel chipsets */
|
/* FIXME: no support for 3-channel chipsets */
|
||||||
|
|
||||||
/* length: [1..4] */
|
/* 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;
|
int channel;
|
||||||
|
u32 ecc;
|
||||||
|
|
||||||
|
if (ctrl->ecc_enabled)
|
||||||
|
ecc = training ? (1 << 24) : (3 << 24);
|
||||||
|
else
|
||||||
|
ecc = 0;
|
||||||
|
|
||||||
FOR_ALL_CHANNELS {
|
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)
|
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;
|
lanes_ok |= 1 << lane;
|
||||||
}
|
}
|
||||||
ctr++;
|
ctr++;
|
||||||
if (lanes_ok == ((1 << NUM_LANES) - 1))
|
if (lanes_ok == ((1 << ctrl->lanes) - 1))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctrl->timings[channel][slotrank] = saved_rt;
|
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)
|
static void fill_pattern5(ramctr_timing *ctrl, int channel, int patno)
|
||||||
@ -3006,6 +3014,46 @@ int channel_test(ramctr_timing *ctrl)
|
|||||||
return 0;
|
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)
|
void set_scrambling_seed(ramctr_timing *ctrl)
|
||||||
{
|
{
|
||||||
int channel;
|
int channel;
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
#define NUM_CHANNELS 2
|
#define NUM_CHANNELS 2
|
||||||
#define NUM_SLOTRANKS 4
|
#define NUM_SLOTRANKS 4
|
||||||
#define NUM_SLOTS 2
|
#define NUM_SLOTS 2
|
||||||
#define NUM_LANES 8
|
#define NUM_LANES 9
|
||||||
|
|
||||||
#define NO_RANKSEL (~(1 << 16))
|
#define NO_RANKSEL (~(1 << 16))
|
||||||
#define IOSAV_MRS (0x1f000)
|
#define IOSAV_MRS (0x1f000)
|
||||||
@ -43,7 +43,7 @@
|
|||||||
/*
|
/*
|
||||||
* WARNING: Do not forget to increase MRC_CACHE_VERSION when the saved data is changed!
|
* 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 {
|
typedef struct odtmap_st {
|
||||||
u16 rttwr;
|
u16 rttwr;
|
||||||
@ -134,6 +134,8 @@ typedef struct ramctr_timing_st {
|
|||||||
|
|
||||||
bool ecc_supported;
|
bool ecc_supported;
|
||||||
bool ecc_forced;
|
bool ecc_forced;
|
||||||
|
bool ecc_enabled;
|
||||||
|
int lanes; /* active lanes: 8 or 9 */
|
||||||
int edge_offset[3];
|
int edge_offset[3];
|
||||||
int timC_offset[3];
|
int timC_offset[3];
|
||||||
|
|
||||||
@ -149,7 +151,7 @@ typedef struct ramctr_timing_st {
|
|||||||
|
|
||||||
#define SOUTHBRIDGE PCI_DEV(0, 0x1f, 0)
|
#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_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_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])
|
#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_xover(ramctr_timing *ctrl);
|
||||||
void dram_timing_regs(ramctr_timing *ctrl);
|
void dram_timing_regs(ramctr_timing *ctrl);
|
||||||
void dram_dimm_mapping(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);
|
void dram_zones(ramctr_timing *ctrl, int training);
|
||||||
unsigned int get_mem_min_tck(void);
|
unsigned int get_mem_min_tck(void);
|
||||||
void dram_memorymap(ramctr_timing *ctrl, int me_uma_size);
|
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);
|
void restore_timings(ramctr_timing *ctrl);
|
||||||
int try_init_dram_ddr3(ramctr_timing *ctrl, int fast_boot, int s3resume, int me_uma_size);
|
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_cap(void);
|
||||||
bool get_host_ecc_forced(void);
|
bool get_host_ecc_forced(void);
|
||||||
|
|
||||||
|
@ -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);
|
MCHBAR32(MC_INIT_STATE_G) &= ~(1 << 5);
|
||||||
|
|
||||||
/* Set MAD-DIMM registers */
|
/* Set MAD-DIMM registers */
|
||||||
dram_dimm_set_mapping(ctrl);
|
dram_dimm_set_mapping(ctrl, 1);
|
||||||
printk(BIOS_DEBUG, "Done dimm mapping\n");
|
printk(BIOS_DEBUG, "Done dimm mapping\n");
|
||||||
|
|
||||||
/* Zone config */
|
/* 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);
|
err = channel_test(ctrl);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
if (ctrl->ecc_enabled)
|
||||||
|
channel_scrub(ctrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Set MAD-DIMM registers */
|
||||||
|
dram_dimm_set_mapping(ctrl, 0);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user