diff options
author | Philip Chen <philipchen@google.com> | 2019-04-29 10:18:24 -0700 |
---|---|---|
committer | Patrick Georgi <pgeorgi@google.com> | 2019-05-15 17:47:13 +0000 |
commit | 0d4200fef396fb0d1fbf28b4ced475fbf59b5b85 (patch) | |
tree | 4cfd6a29afa5062c4bb125320657e7b54f6f002c /src/soc | |
parent | 72f6fbb1bc64a68dab121231b186c803e9836ad7 (diff) | |
download | coreboot-0d4200fef396fb0d1fbf28b4ced475fbf59b5b85.tar.xz |
soc/intel/cannonlake: Support different SPD read type for each slot
Also clean up cannonlake_memcfg_init.
The major changes include:
(1) Add enum 'mem_info_read_type' to spd_info.
(2) Add per-dimm-slot spd_info to cnl_mb_cfg.
(3) Setup memory config for each slot independently.
(4) Squash meminit_memcfg_spd().
BUG=chromium:960581, b:124990009
BRANCH=none
TEST=boot hatch, hatch_whl, and kohaku
Change-Id: I686a85996858204c20fd05ef24787a0487817c34
Signed-off-by: Philip Chen <philipchen@google.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/32513
Reviewed-by: Paul Fagerburg <pfagerburg@chromium.org>
Reviewed-by: Furquan Shaikh <furquan@google.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Diffstat (limited to 'src/soc')
-rw-r--r-- | src/soc/intel/cannonlake/cnl_memcfg_init.c | 111 | ||||
-rw-r--r-- | src/soc/intel/cannonlake/include/soc/cnl_memcfg_init.h | 38 |
2 files changed, 83 insertions, 66 deletions
diff --git a/src/soc/intel/cannonlake/cnl_memcfg_init.c b/src/soc/intel/cannonlake/cnl_memcfg_init.c index db001b82ae..4ebd9978ae 100644 --- a/src/soc/intel/cannonlake/cnl_memcfg_init.c +++ b/src/soc/intel/cannonlake/cnl_memcfg_init.c @@ -20,7 +20,7 @@ #include <string.h> static void meminit_memcfg(FSP_M_CONFIG *mem_cfg, - const struct cnl_mb_cfg *board_cfg) + const struct cnl_mb_cfg *board_cfg) { /* * DqByteMapChx expects 12 bytes of data, but the last 6 bytes @@ -29,47 +29,58 @@ static void meminit_memcfg(FSP_M_CONFIG *mem_cfg, */ memset(&mem_cfg->DqByteMapCh0, 0, sizeof(mem_cfg->DqByteMapCh0)); memcpy(&mem_cfg->DqByteMapCh0, &board_cfg->dq_map[DDR_CH0], - sizeof(board_cfg->dq_map[DDR_CH0])); + sizeof(board_cfg->dq_map[DDR_CH0])); memset(&mem_cfg->DqByteMapCh1, 0, sizeof(mem_cfg->DqByteMapCh1)); memcpy(&mem_cfg->DqByteMapCh1, &board_cfg->dq_map[DDR_CH1], - sizeof(board_cfg->dq_map[DDR_CH1])); + sizeof(board_cfg->dq_map[DDR_CH1])); memcpy(&mem_cfg->DqsMapCpu2DramCh0, &board_cfg->dqs_map[DDR_CH0], - sizeof(board_cfg->dqs_map[DDR_CH0])); + sizeof(board_cfg->dqs_map[DDR_CH0])); memcpy(&mem_cfg->DqsMapCpu2DramCh1, &board_cfg->dqs_map[DDR_CH1], - sizeof(board_cfg->dqs_map[DDR_CH1])); + sizeof(board_cfg->dqs_map[DDR_CH1])); memcpy(&mem_cfg->RcompResistor, &board_cfg->rcomp_resistor, - sizeof(mem_cfg->RcompResistor)); + sizeof(mem_cfg->RcompResistor)); /* Early cannonlake requires rcomp targets to be 0 */ memcpy(&mem_cfg->RcompTarget, &board_cfg->rcomp_targets, - sizeof(mem_cfg->RcompTarget)); + sizeof(mem_cfg->RcompTarget)); } -static void meminit_memcfg_spd(FSP_M_CONFIG *mem_cfg, - const struct cnl_mb_cfg *cnl_cfg, - size_t spd_data_len, uintptr_t spd_data_ptr) +/* + * Initialize default memory settings using spd data contained in a buffer. + */ +static void meminit_spd_data(FSP_M_CONFIG *mem_cfg, uint8_t mem_slot, + size_t spd_data_len, uintptr_t spd_data_ptr) { + static size_t last_set_spd_data_len = 0; + + assert(spd_data_ptr != 0 && spd_data_len != 0); + + if (last_set_spd_data_len != 0 && + last_set_spd_data_len != spd_data_len) + die("spd data length disparity among slots"); + mem_cfg->MemorySpdDataLen = spd_data_len; + last_set_spd_data_len = spd_data_len; - if (cnl_cfg->channel_empty[0] == 0) + switch (mem_slot) { + case 0: mem_cfg->MemorySpdPtr00 = spd_data_ptr; - - if (cnl_cfg->channel_empty[1] == 0) + break; + case 1: + mem_cfg->MemorySpdPtr01 = spd_data_ptr; + break; + case 2: mem_cfg->MemorySpdPtr10 = spd_data_ptr; -} - -/* - * Initialize default memory settings using spd data contained in a buffer. - */ -static void meminit_spd_data(FSP_M_CONFIG *mem_cfg, - const struct cnl_mb_cfg *cnl_cfg, - size_t spd_data_len, uintptr_t spd_data_ptr) -{ - assert(spd_data_ptr && spd_data_len); - meminit_memcfg_spd(mem_cfg, cnl_cfg, spd_data_len, spd_data_ptr); + break; + case 3: + mem_cfg->MemorySpdPtr11 = spd_data_ptr; + break; + default: + die("nonexistent memory slot"); + } } /* @@ -78,13 +89,13 @@ static void meminit_spd_data(FSP_M_CONFIG *mem_cfg, * in spd/Makefile.inc. */ static void meminit_cbfs_spd_index(FSP_M_CONFIG *mem_cfg, - const struct cnl_mb_cfg *cnl_cfg, - int spd_index) + int spd_index, uint8_t mem_slot) { size_t spd_data_len; uintptr_t spd_data_ptr; struct region_device spd_rdev; + assert(mem_slot < NUM_DIMM_SLOT); printk(BIOS_DEBUG, "SPD INDEX = %d\n", spd_index); if (get_spd_cbfs_rdev(&spd_rdev, spd_index) < 0) die("spd.bin not found or incorrect index\n"); @@ -92,40 +103,42 @@ static void meminit_cbfs_spd_index(FSP_M_CONFIG *mem_cfg, /* Memory leak is ok since we have memory mapped boot media */ assert(CONFIG(BOOT_DEVICE_MEMORY_MAPPED)); spd_data_ptr = (uintptr_t)rdev_mmap_full(&spd_rdev); - meminit_spd_data(mem_cfg, cnl_cfg, spd_data_len, spd_data_ptr); + meminit_spd_data(mem_cfg, mem_slot, spd_data_len, spd_data_ptr); } /* Initialize onboard memory configurations for CannonLake */ void cannonlake_memcfg_init(FSP_M_CONFIG *mem_cfg, - const struct cnl_mb_cfg *cnl_cfg, - const struct spd_info *spd) + const struct cnl_mb_cfg *cnl_cfg) { - bool OnModuleSpd = false; + const struct spd_info *spdi; + /* Early Command Training Enabled */ mem_cfg->ECT = cnl_cfg->ect; mem_cfg->DqPinsInterleaved = cnl_cfg->dq_pins_interleaved; mem_cfg->CaVrefConfig = cnl_cfg->vref_ca_config; - /* Spd pointer will only be used if all smbus slave address of memory - * sockets on the platform is empty */ - for (int i = 0; i < ARRAY_SIZE(mem_cfg->SpdAddressTable); i++) { - if (spd->spd_smbus_address[i] != 0) { - mem_cfg->SpdAddressTable[i] = spd->spd_smbus_address[i]; - OnModuleSpd = true; + for (int i = 0; i < NUM_DIMM_SLOT; i++) { + spdi = &(cnl_cfg->spd[i]); + switch (spdi->read_type) { + case NOT_EXISTING: + break; + case READ_SMBUS: + mem_cfg->SpdAddressTable[i] = + spdi->spd_spec.spd_smbus_address; + break; + case READ_SPD_CBFS: + meminit_cbfs_spd_index(mem_cfg, + spdi->spd_spec.spd_index, i); + break; + case READ_SPD_MEMPTR: + meminit_spd_data(mem_cfg, i, + spdi->spd_spec.spd_data_ptr_info.spd_data_len, + spdi->spd_spec.spd_data_ptr_info.spd_data_ptr); + break; + default: + die("no valid way to read mem info"); } - } - if (!OnModuleSpd) { - if (spd->spd_by_index) { - meminit_cbfs_spd_index(mem_cfg, cnl_cfg, - spd->spd_spec.spd_index); - } else { - meminit_spd_data(mem_cfg, cnl_cfg, - spd->spd_spec.spd_data_ptr_info.spd_data_len, - spd->spd_spec.spd_data_ptr_info.spd_data_ptr); - } + meminit_memcfg(mem_cfg, cnl_cfg); } - - meminit_memcfg(mem_cfg, cnl_cfg); - } diff --git a/src/soc/intel/cannonlake/include/soc/cnl_memcfg_init.h b/src/soc/intel/cannonlake/include/soc/cnl_memcfg_init.h index e602a33f78..d5f6c39f24 100644 --- a/src/soc/intel/cannonlake/include/soc/cnl_memcfg_init.h +++ b/src/soc/intel/cannonlake/include/soc/cnl_memcfg_init.h @@ -23,6 +23,9 @@ /* Number of dq bits controlled per dqs */ #define DQ_BITS_PER_DQS 8 +/* Number of memory DIMM slots available on Cannonlake board */ +#define NUM_DIMM_SLOT 4 + /* * Number of memory packages, where a "package" represents a 64-bit solution. */ @@ -40,17 +43,32 @@ struct spd_by_pointer { uintptr_t spd_data_ptr; }; +enum mem_info_read_type { + NOT_EXISTING, /* No memory in this slot */ + READ_SMBUS, /* Read on-module spd by SMBUS. */ + READ_SPD_CBFS, /* Find spd file in CBFS. */ + READ_SPD_MEMPTR /* Find spd data from pointer. */ +}; + struct spd_info { - bool spd_by_index; + enum mem_info_read_type read_type; union spd_data_by { + /* To read on-module spd when read_type is READ_SMBUS. */ + uint8_t spd_smbus_address; + + /* To identify spd file when read_type is READ_SPD_CBFS. */ int spd_index; + + /* To find spd data when read_type is READ_SPD_MEMPTR. */ struct spd_by_pointer spd_data_ptr_info; } spd_spec; - uint8_t spd_smbus_address[4]; }; /* Board-specific memory dq mapping information */ struct cnl_mb_cfg { + /* Parameters required to access SPD for CH0D0/CH0D1/CH1D0/CH1D1. */ + struct spd_info spd[NUM_DIMM_SLOT]; + /* * For each channel, there are 6 sets of DQ byte mappings, * where each set has a package 0 and a package 1 value (package 0 @@ -107,26 +125,12 @@ struct cnl_mb_cfg { /* Early Command Training Enabled */ uint8_t ect; - - /* - * Flags to indicate which channels are populated. We - * currently support single or dual channel configurations. - * Set 1 to indicate that the channel is not populated Set 0 - * to indicate that the channel is populated. For example, - * dual channel memory configuration would have both - * channel_empty[0] = 0 and channel_empty[1] = 0. Note that - * this flag is only used for soldered down DRAM where we get - * SPD data from CBFS. We need the value 0 to default to - * populated in order to support existing boards. - */ - uint8_t channel_empty[2]; }; /* * Initialize default memory configurations for CannonLake. */ void cannonlake_memcfg_init(FSP_M_CONFIG *mem_cfg, - const struct cnl_mb_cfg *cnl_cfg, - const struct spd_info *spd); + const struct cnl_mb_cfg *cnl_cfg); #endif /* _SOC_CANNONLAKE_MEMCFG_INIT_H_ */ |