Tim Wawrzynczak has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/48860 )
Change subject: soc/intel/alderlake: Refactor meminit code ......................................................................
soc/intel/alderlake: Refactor meminit code
Align ADL's memory initialization code with TGL; this allows mainboards to e.g. more easily align the CPU<->DRAM DQ pin mapping between the data structure and the schematic.
BUG=b:172978729 TEST=abuild intel/adlrvp
Signed-off-by: Tim Wawrzynczak twawrzynczak@chromium.org Change-Id: I2b75e856f1f2aa34bb7a91913147faf3037e7cfb --- M src/mainboard/intel/adlrvp/include/baseboard/variants.h M src/mainboard/intel/adlrvp/memory.c M src/mainboard/intel/adlrvp/romstage_fsp_params.c M src/soc/intel/alderlake/include/soc/meminit.h M src/soc/intel/alderlake/meminit.c 5 files changed, 501 insertions(+), 269 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/60/48860/1
diff --git a/src/mainboard/intel/adlrvp/include/baseboard/variants.h b/src/mainboard/intel/adlrvp/include/baseboard/variants.h index 9cb8640..9efa67e 100644 --- a/src/mainboard/intel/adlrvp/include/baseboard/variants.h +++ b/src/mainboard/intel/adlrvp/include/baseboard/variants.h @@ -29,5 +29,5 @@ void variant_configure_early_gpio_pads(void);
size_t variant_memory_sku(void); -const struct mb_cfg *variant_memory_params(void); +const struct adl_mem_config *variant_memory_params(void); #endif /*__BASEBOARD_VARIANTS_H__ */ diff --git a/src/mainboard/intel/adlrvp/memory.c b/src/mainboard/intel/adlrvp/memory.c index 80ec14a..2cfcac4 100644 --- a/src/mainboard/intel/adlrvp/memory.c +++ b/src/mainboard/intel/adlrvp/memory.c @@ -5,7 +5,7 @@ #include <baseboard/variants.h> #include <soc/romstage.h>
-static const struct mb_cfg ddr4_mem_config = { +static const struct ddr_mem_config ddr4_params = { /* Baseboard uses only 100ohm Rcomp resistors */ .rcomp_resistor = {100, 100, 100},
@@ -15,64 +15,97 @@ .dq_pins_interleaved = false,
.ect = true, /* Early Command Training */ - - .UserBd = BOARD_TYPE_MOBILE, +}; +static const struct adl_mem_config ddr4_mem_config = { + .mem_type = MEMTYPE_DDR4, + .ddr_cfg = &ddr4_params, };
-static const struct mb_cfg lpddr4_mem_config = { +static const struct lpx_common_mem_config lpddr4_params = { /* DQ byte map */ .dq_map = { - { 0, 2, 3, 1, 6, 7, 5, 4, 10, 8, 11, 9, 14, 12, 13, 15 }, - { 12, 8, 14, 10, 11, 13, 15, 9, 5, 0, 7, 3, 6, 2, 1, 4 }, - { 3, 0, 2, 1, 6, 5, 4, 7, 12, 13, 14, 15, 10, 9, 8, 11 }, - { 2, 6, 7, 1, 3, 4, 0, 5, 9, 13, 8, 15, 14, 11, 12, 10 }, - { 3, 0, 1, 2, 7, 4, 6, 5, 10, 8, 11, 9, 14, 13, 12, 15 }, - { 10, 12, 14, 8, 9, 13, 15, 11, 3, 7, 6, 2, 0, 4, 5, 1 }, - { 12, 15, 14, 13, 9, 10, 11, 8, 7, 4, 6, 5, 0, 1, 3, 2 }, - { 0, 2, 4, 3, 1, 6, 7, 5, 13, 9, 10, 11, 8, 12, 14, 15 }, + [0] = { { 0, 2, 3, 1, 6, 7, 5, 4 }, + { 10, 8, 11, 9, 14, 12, 13, 15 }, }, + [1] = { { 12, 8, 14, 10, 11, 13, 15, 9 }, + { 5, 0, 7, 3, 6, 2, 1, 4 }, }, + [2] = { { 3, 0, 2, 1, 6, 5, 4, 7 }, + { 12, 13, 14, 15, 10, 9, 8, 11 }, }, + [3] = { { 2, 6, 7, 1, 3, 4, 0, 5 }, + { 9, 13, 8, 15, 14, 11, 12, 10 }, }, + [4] = { { 3, 0, 1, 2, 7, 4, 6, 5 }, + { 10, 8, 11, 9, 14, 13, 12, 15 }, }, + [5] = { { 10, 12, 14, 8, 9, 13, 15, 11 }, + { 3, 7, 6, 2, 0, 4, 5, 1 }, }, + [6] = { { 12, 15, 14, 13, 9, 10, 11, 8 }, + { 7, 4, 6, 5, 0, 1, 3, 2 }, }, + [7] = { { 0, 2, 4, 3, 1, 6, 7, 5 }, + { 13, 9, 10, 11, 8, 12, 14, 15 }, }, },
/* DQS CPU<>DRAM map */ .dqs_map = { - { 0, 1 }, { 1, 0 }, { 0, 1 }, { 0, 1 }, { 0, 1 }, { 1, 0 }, { 1, 0 }, { 0, 1 } + [0] = { 0, 1 }, + [1] = { 1, 0 }, + [2] = { 0, 1 }, + [3] = { 0, 1 }, + [4] = { 0, 1 }, + [5] = { 1, 0 }, + [6] = { 1, 0 }, + [7] = { 0, 1 }, },
- .dq_pins_interleaved = false, - .ect = true, /* Early Command Training */ - - .UserBd = BOARD_TYPE_MOBILE, +}; +static const struct adl_mem_config lpddr4_mem_config = { + .mem_type = MEMTYPE_LP4X, + .lp4x_cfg = &lpddr4_params, };
-static const struct mb_cfg lp5_mem_config = { - +static const struct lpx_common_mem_config lpddr5_params = { /* DQ byte map */ .dq_map = { - { 3, 2, 1, 0, 5, 4, 6, 7, 15, 14, 12, 13, 8, 9, 10, 11 }, - { 0, 2, 3, 1, 5, 7, 4, 6, 14, 13, 15, 12, 8, 9, 11, 10 }, - { 1, 2, 0, 3, 4, 6, 5, 7, 15, 13, 12, 14, 9, 10, 8, 11 }, - { 2, 1, 3, 0, 7, 4, 5, 6, 13, 12, 15, 14, 9, 11, 8, 10 }, - { 1, 2, 3, 0, 6, 4, 5, 7, 15, 13, 14, 12, 10, 9, 8, 11 }, - { 1, 0, 3, 2, 6, 7, 4, 5, 14, 12, 15, 13, 8, 9, 10, 11 }, - { 0, 2, 1, 3, 4, 7, 5, 6, 12, 13, 15, 14, 9, 11, 10, 8 }, - { 3, 2, 1, 0, 5, 4, 6, 7, 13, 15, 11, 12, 10, 9, 14, 8 }, + [0] = { { 3, 2, 1, 0, 5, 4, 6, 7 }, + { 15, 14, 12, 13, 8, 9, 10, 11 }, }, + [1] = { { 0, 2, 3, 1, 5, 7, 4, 6 }, + { 14, 13, 15, 12, 8, 9, 11, 10 }, }, + [2] = { { 1, 2, 0, 3, 4, 6, 5, 7 }, + { 15, 13, 12, 14, 9, 10, 8, 11 }, }, + [3] = { { 2, 1, 3, 0, 7, 4, 5, 6 }, + { 13, 12, 15, 14, 9, 11, 8, 10 }, }, + [4] = { { 1, 2, 3, 0, 6, 4, 5, 7 }, + { 15, 13, 14, 12, 10, 9, 8, 11 }, }, + [5] = { { 1, 0, 3, 2, 6, 7, 4, 5 }, + { 14, 12, 15, 13, 8, 9, 10, 11 }, }, + [6] = { { 0, 2, 1, 3, 4, 7, 5, 6 }, + { 12, 13, 15, 14, 9, 11, 10, 8 }, }, + [7] = { { 3, 2, 1, 0, 5, 4, 6, 7 }, + { 13, 15, 11, 12, 10, 9, 14, 8 }, }, },
/* DQS CPU<>DRAM map */ .dqs_map = { - { 0, 1 }, { 0, 1 }, { 0, 1 }, { 0, 1 }, { 0, 1 }, { 0, 1 }, { 0, 1 }, { 0, 1 } + [0] = { 0, 1 }, + [1] = { 0, 1 }, + [2] = { 0, 1 }, + [3] = { 0, 1 }, + [4] = { 0, 1 }, + [5] = { 0, 1 }, + [6] = { 0, 1 }, + [7] = { 0, 1 }, },
- .dq_pins_interleaved = false, - .ect = false, /* Early Command Training */ - +}; +static const struct lp5x_mem_config lpddr5_config = { + .lpx_config = &lpddr5_params, .lp5_ccc_config = 0xff, - - .UserBd = BOARD_TYPE_MOBILE, +}; +static const struct adl_mem_config lpddr5_mem_config = { + .mem_type = MEMTYPE_LP5X, + .lp5x_cfg = &lpddr5_config, };
-static const struct mb_cfg ddr5_mem_config = { +static const struct ddr_mem_config ddr5_params = { /* Baseboard uses only 100ohm Rcomp resistors */ .rcomp_resistor = {100, 100, 100},
@@ -82,11 +115,13 @@ .dq_pins_interleaved = false,
.ect = true, /* Early Command Training */ - - .UserBd = BOARD_TYPE_MOBILE, +}; +static const struct adl_mem_config ddr5_mem_config = { + .mem_type = MEMTYPE_DDR5, + .ddr_cfg = &ddr5_params, };
-const struct mb_cfg *variant_memory_params(void) +const struct adl_mem_config *variant_memory_params(void) { int board_id = get_board_id();
@@ -100,7 +135,7 @@ case ADL_P_DDR5: return &ddr5_mem_config; case ADL_P_LP5: - return &lp5_mem_config; + return &lpddr5_mem_config; default: die("unsupported board id : 0x%x\n", board_id); } diff --git a/src/mainboard/intel/adlrvp/romstage_fsp_params.c b/src/mainboard/intel/adlrvp/romstage_fsp_params.c index 2f03cb4..da7103f 100644 --- a/src/mainboard/intel/adlrvp/romstage_fsp_params.c +++ b/src/mainboard/intel/adlrvp/romstage_fsp_params.c @@ -27,30 +27,29 @@
void mainboard_memory_init_params(FSPM_UPD *mupd) { - const struct mb_cfg *mem_config = variant_memory_params(); + const struct adl_mem_config *mem_config = variant_memory_params(); int board_id = get_board_id(); const bool half_populated = false;
const struct spd_info lp4_lp5_spd_info = { - .read_type = READ_SPD_CBFS, - .spd_spec.spd_index = get_spd_index(), + .topology = MEMORY_DOWN, + .md_spd_loc = SPD_CBFS, + .cbfs_index = get_spd_index(), };
const struct spd_info ddr4_ddr5_spd_info = { - .read_type = READ_SMBUS, - .spd_spec = { - .spd_smbus_address = { - [0] = 0xa0, - [1] = 0xa2, - [8] = 0xa4, - [9] = 0xa6, - }, + .topology = SODIMM, + .smbus_info = { + [0] = { .addr_dimm0 = 0xa0, .addr_dimm1 = 0xa2, }, + [1] = { .addr_dimm0 = 0xa4, .addr_dimm1 = 0xa6, }, }, };
switch (board_id) { case ADL_P_DDR4_1: case ADL_P_DDR4_2: + memcfg_init(&mupd->FspmConfig, mem_config, &ddr4_ddr5_spd_info, half_populated); + break; case ADL_P_DDR5: memcfg_init(&mupd->FspmConfig, mem_config, &ddr4_ddr5_spd_info, half_populated); break; diff --git a/src/soc/intel/alderlake/include/soc/meminit.h b/src/soc/intel/alderlake/include/soc/meminit.h index 36d0750..1e70d5c 100644 --- a/src/soc/intel/alderlake/include/soc/meminit.h +++ b/src/soc/intel/alderlake/include/soc/meminit.h @@ -7,65 +7,65 @@ #include <stdint.h> #include <fsp/soc_binding.h>
-#define BYTES_PER_CHANNEL 2 -#define BITS_PER_BYTE 8 -#define DQS_PER_CHANNEL 2 +#define BITS_PER_BYTE 8
-/* 64-bit Channel identification */ -enum { - DDR_CH0, - DDR_CH1, - DDR_CH2, - DDR_CH3, - DDR_CH4, - DDR_CH5, - DDR_CH6, - DDR_CH7, - DDR_NUM_CHANNELS -}; -/* Number of memory DIMM slots available on Alderlake board */ -#define NUM_DIMM_SLOT 16 +/* True for both LP4X and LP5X */ +#define LPX_CHANNELS 8 +#define LPX_BYTES_PER_CHANNEL 2
-struct spd_by_pointer { - size_t spd_data_len; - uintptr_t spd_data_ptr; +/* True for both DDR4 and DDR5 */ +#define DDR_CHANNELS 2 +#define DDR_BYTES_PER_CHANNEL 8 + +enum mem_topology { + MEMORY_DOWN, /* SPD sourced from CBFS or in-memory pointer */ + SODIMM, /* DDR4 supports reading SPD over SMBus */ + MIXED, /* DDR4 supports CH0 as SODIMM and CH1 as Memory Down */ };
-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. */ +enum ddr_memtype { + MEMTYPE_DDR4, + MEMTYPE_LP4X, + MEMTYPE_DDR5, + MEMTYPE_LP5X, +}; + +/* Memory-down SPD location */ +enum md_spd_loc { + SPD_MEMPTR, + SPD_CBFS, };
struct spd_info { - 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[NUM_DIMM_SLOT]; - - /* 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; -}; - -/* Board-specific memory configuration information */ -struct mb_cfg { - /* DQ mapping */ - uint8_t dq_map[DDR_NUM_CHANNELS][BYTES_PER_CHANNEL * BITS_PER_BYTE]; + enum mem_topology topology; + enum md_spd_loc md_spd_loc; + union { + /* Used for SPD_CBFS */ + uint8_t cbfs_index; + /* Used for SPD_MEMPTR */ + struct { + uintptr_t data_ptr; + size_t data_len; + }; + };
/* - * DQS CPU<>DRAM map. Each array entry represents a - * mapping of a dq bit on the CPU to the bit it's connected to on - * the memory part. The array index represents the dqs bit number - * on the memory part, and the values in the array represent which - * pin on the CPU that DRAM pin connects to. + * SPD info for SODIMM topology. + * Leave addr_dimmN as 0 for any DIMMs that are not populated. */ - uint8_t dqs_map[DDR_NUM_CHANNELS][DQS_PER_CHANNEL]; + struct { + /* SMBus address for DIMM0 within the channel. */ + uint8_t addr_dimm0; + /* SMBus address for DIMM1 within the channel. */ + uint8_t addr_dimm1; + } smbus_info[DDR_CHANNELS]; +};
+struct ddr_mem_config { + uint8_t dq_map[DDR_CHANNELS][DDR_BYTES_PER_CHANNEL][BITS_PER_BYTE]; + uint8_t dqs_map[DDR_CHANNELS][DDR_BYTES_PER_CHANNEL]; + uint8_t dq_pins_interleaved; + uint8_t ect; /* * Rcomp resistor values. These values represent the resistance in * ohms of the three rcomp resistors attached to the DDR_COMP_0, @@ -75,36 +75,29 @@
/* Rcomp target values. */ uint16_t rcomp_targets[5]; +};
- /* - * Dqs Pins Interleaved Setting. Enable/Disable Control - * TRUE = enable, FALSE = disable - */ - bool dq_pins_interleaved; +struct lpx_common_mem_config { + uint8_t dq_map[LPX_CHANNELS][LPX_BYTES_PER_CHANNEL][BITS_PER_BYTE]; + uint8_t dqs_map[LPX_CHANNELS][LPX_BYTES_PER_CHANNEL]; + uint8_t ect; +};
- /* - * Early Command Training Enable/Disable Control - * TRUE = enable, FALSE = disable - */ - bool ect; - - /* Board type */ - uint8_t UserBd; - - /* - * Command pins mapping for Controller Channel (ccc) - * lp5_ccc_config: Bitmask where bits [3:0] are Controller 0 Channel [3:0] and - * bits [7:4] are Controller 1 Channel [3:0] - * Bit value: 0 = ccc pin mapping is ascending, 1 = ccc pin mapping is descending. - */ +struct lp5x_mem_config { + const struct lpx_common_mem_config *lpx_config; uint8_t lp5_ccc_config; };
-/* - * Initialize default memory configurations for Alder Lake. - */ +struct adl_mem_config { + enum ddr_memtype mem_type; + union { + const struct ddr_mem_config *ddr_cfg; + const struct lpx_common_mem_config *lp4x_cfg; + const struct lp5x_mem_config *lp5x_cfg; + }; +};
-void memcfg_init(FSP_M_CONFIG *mem_cfg, const struct mb_cfg *board_cfg, - const struct spd_info *spd_info, bool half_populated); +void memcfg_init(FSP_M_CONFIG *mem_cfg, const struct adl_mem_config *board_cfg, + const struct spd_info *info, bool half_populated);
#endif /* _SOC_ALDERLAKE_MEMINIT_H_ */ diff --git a/src/soc/intel/alderlake/meminit.c b/src/soc/intel/alderlake/meminit.c index 8473ad8..d93469f 100644 --- a/src/soc/intel/alderlake/meminit.c +++ b/src/soc/intel/alderlake/meminit.c @@ -7,6 +7,14 @@ #include <spd_bin.h> #include <string.h>
+/* + * Translate DDR4/5 channel to FSP UPD index for the channel. + * Channel 0 -> Index 0 + * Channel 1 -> Index 4 + * All others indexes are unused. + */ +#define DDR_FSP_UPD_CHANNEL_IDX(x) ((x) * 4) + enum dimm_enable_options { ENABLE_BOTH_DIMMS = 0, DISABLE_DIMM0 = 1, @@ -14,172 +22,369 @@ DISABLE_BOTH_DIMMS = 3 };
-static void spd_read_from_cbfs(const struct spd_info *spd_info, - uintptr_t *spd_data_ptr, size_t *spd_data_len) +static enum dimm_enable_options get_dimm_cfg(uintptr_t dimm0, uintptr_t dimm1) +{ + if (dimm0 && dimm1) + return ENABLE_BOTH_DIMMS; + if (!dimm0 && !dimm1) + return DISABLE_BOTH_DIMMS; + if (!dimm1) + return DISABLE_DIMM1; + if (!dimm0) + die("Disabling only dimm0 is not supported!\n"); + + return DISABLE_BOTH_DIMMS; +} + +static void init_spd_upds(FSP_M_CONFIG *mem_cfg, int channel, uintptr_t spd_dimm0, + uintptr_t spd_dimm1) +{ + const enum dimm_enable_options dimm_cfg = get_dimm_cfg(spd_dimm0, spd_dimm1); + switch (channel) { + case 0: + mem_cfg->DisableDimmMc0Ch0 = (uint8_t)dimm_cfg; + mem_cfg->MemorySpdPtr00 = spd_dimm0; + mem_cfg->MemorySpdPtr01 = spd_dimm1; + break; + case 1: + mem_cfg->DisableDimmMc0Ch1 = (uint8_t)dimm_cfg; + mem_cfg->MemorySpdPtr02 = spd_dimm0; + mem_cfg->MemorySpdPtr03 = spd_dimm1; + break; + case 2: + mem_cfg->DisableDimmMc0Ch2 = (uint8_t)dimm_cfg; + mem_cfg->MemorySpdPtr04 = spd_dimm0; + mem_cfg->MemorySpdPtr05 = spd_dimm1; + break; + case 3: + mem_cfg->DisableDimmMc0Ch3 = (uint8_t)dimm_cfg; + mem_cfg->MemorySpdPtr06 = spd_dimm0; + mem_cfg->MemorySpdPtr07 = spd_dimm1; + break; + case 4: + mem_cfg->DisableDimmMc1Ch0 = (uint8_t)dimm_cfg; + mem_cfg->MemorySpdPtr08 = spd_dimm0; + mem_cfg->MemorySpdPtr09 = spd_dimm1; + break; + case 5: + mem_cfg->DisableDimmMc1Ch1 = (uint8_t)dimm_cfg; + mem_cfg->MemorySpdPtr10 = spd_dimm0; + mem_cfg->MemorySpdPtr11 = spd_dimm1; + break; + case 6: + mem_cfg->DisableDimmMc1Ch2 = (uint8_t)dimm_cfg; + mem_cfg->MemorySpdPtr12 = spd_dimm0; + mem_cfg->MemorySpdPtr13 = spd_dimm1; + break; + case 7: + mem_cfg->DisableDimmMc1Ch3 = (uint8_t)dimm_cfg; + mem_cfg->MemorySpdPtr14 = spd_dimm0; + mem_cfg->MemorySpdPtr15 = spd_dimm1; + break; + default: + die("Invalid channel %d\n", channel); + break; + } +} + +static void init_spd_upds_empty(FSP_M_CONFIG *mem_cfg, int channel) +{ + init_spd_upds(mem_cfg, channel, 0, 0); +} + +static void init_spd_upds_dimm0(FSP_M_CONFIG *mem_cfg, int channel, uintptr_t spd_dimm0) +{ + init_spd_upds(mem_cfg, channel, spd_dimm0, 0); +} + +static void init_dq_upds(FSP_M_CONFIG *mem_cfg, int byte_pair, const uint8_t *dq_byte0, + const uint8_t *dq_byte1) +{ + uint8_t *dq_upd; + + switch (byte_pair) { + case 0: + dq_upd = mem_cfg->DqMapCpu2DramCh0; + break; + case 1: + dq_upd = mem_cfg->DqMapCpu2DramCh1; + break; + case 2: + dq_upd = mem_cfg->DqMapCpu2DramCh2; + break; + case 3: + dq_upd = mem_cfg->DqMapCpu2DramCh3; + break; + case 4: + dq_upd = mem_cfg->DqMapCpu2DramCh4; + break; + case 5: + dq_upd = mem_cfg->DqMapCpu2DramCh5; + break; + case 6: + dq_upd = mem_cfg->DqMapCpu2DramCh6; + break; + case 7: + dq_upd = mem_cfg->DqMapCpu2DramCh7; + break; + default: + die("Invalid byte_pair: %d\n", byte_pair); + } + + if (dq_byte0 && dq_byte1) { + memcpy(dq_upd, dq_byte0, BITS_PER_BYTE); + memcpy(dq_upd + BITS_PER_BYTE, dq_byte1, BITS_PER_BYTE); + } else { + memset(dq_upd, 0, BITS_PER_BYTE * 2); + } +} + +static void init_dq_upds_empty(FSP_M_CONFIG *mem_cfg, int byte_pair) +{ + init_dq_upds(mem_cfg, byte_pair, NULL, NULL); +} + +static void init_dqs_upds(FSP_M_CONFIG *mem_cfg, int byte_pair, uint8_t dqs_byte0, + uint8_t dqs_byte1) +{ + uint8_t *dqs_upd; + + switch (byte_pair) { + case 0: + dqs_upd = mem_cfg->DqsMapCpu2DramCh0; + break; + case 1: + dqs_upd = mem_cfg->DqsMapCpu2DramCh1; + break; + case 2: + dqs_upd = mem_cfg->DqsMapCpu2DramCh2; + break; + case 3: + dqs_upd = mem_cfg->DqsMapCpu2DramCh3; + break; + case 4: + dqs_upd = mem_cfg->DqsMapCpu2DramCh4; + break; + case 5: + dqs_upd = mem_cfg->DqsMapCpu2DramCh5; + break; + case 6: + dqs_upd = mem_cfg->DqsMapCpu2DramCh6; + break; + case 7: + dqs_upd = mem_cfg->DqsMapCpu2DramCh7; + break; + default: + die("Invalid byte pair %d\n", byte_pair); + } + + dqs_upd[0] = dqs_byte0; + dqs_upd[1] = dqs_byte1; +} + +static void init_dqs_upds_empty(FSP_M_CONFIG *mem_cfg, int byte_pair) +{ + init_dqs_upds(mem_cfg, byte_pair, 0, 0); +} + +static void read_spd_from_cbfs(uint8_t index, uintptr_t *data, size_t *len) { struct region_device spd_rdev; - size_t spd_index = spd_info->spd_spec.spd_index;
- printk(BIOS_DEBUG, "SPD INDEX = %lu\n", spd_index); - if (get_spd_cbfs_rdev(&spd_rdev, spd_index) < 0) + printk(BIOS_DEBUG, "SPD index = %u\n", index); + if (get_spd_cbfs_rdev(&spd_rdev, index) < 0) die("spd.bin not found or incorrect index\n");
- *spd_data_len = region_device_sz(&spd_rdev); - /* 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); + *len = region_device_sz(&spd_rdev); + *data = (uintptr_t)rdev_mmap_full(&spd_rdev); }
-static void get_spd_data(const struct spd_info *spd_info, - uintptr_t *spd_data_ptr, size_t *spd_data_len) +static void read_md_spd(const struct spd_info *info, uintptr_t *data, size_t *len) { - if (spd_info->read_type == READ_SPD_MEMPTR) { - *spd_data_ptr = spd_info->spd_spec.spd_data_ptr_info.spd_data_ptr; - *spd_data_len = spd_info->spd_spec.spd_data_ptr_info.spd_data_len; - return; + switch (info->md_spd_loc) { + case SPD_MEMPTR: + *data = info->data_ptr; + *len = info->data_len; + break; + case SPD_CBFS: + read_spd_from_cbfs(info->cbfs_index, data, len); + break; + default: + die("Invalid location (%d) for Memory-down SPD\n", info->md_spd_loc); }
- if (spd_info->read_type == READ_SPD_CBFS) { - spd_read_from_cbfs(spd_info, spd_data_ptr, spd_data_len); - return; + print_spd_info((uint8_t *) *data); +} + +static void read_sodimm_spd(const struct spd_info *info, struct spd_block *blk) +{ + size_t i; + + blk->addr_map[0] = info->smbus_info[0].addr_dimm0; + blk->addr_map[1] = info->smbus_info[0].addr_dimm1; + blk->addr_map[2] = info->smbus_info[1].addr_dimm0; + blk->addr_map[3] = info->smbus_info[1].addr_dimm1; + + get_spd_smbus(blk); + + for (i = 0; i < ARRAY_SIZE(blk->addr_map); i++) { + if (blk->spd_array[i] != NULL) + print_spd_info((uint8_t *)blk->spd_array[i]); } }
-static void meminit_dq_dqs_map(FSP_M_CONFIG *mem_cfg, - const struct mb_cfg *board_cfg, - bool half_populated) +static void ddr_get_spd(int channel, const uintptr_t *spd_md_data, + const struct spd_block *spd_sodimm_blk, + const struct spd_info *info, + const bool half_populated, uintptr_t *spd_dimm0, + uintptr_t *spd_dimm1) { - memcpy(&mem_cfg->RcompResistor, &board_cfg->rcomp_resistor, - sizeof(mem_cfg->RcompResistor)); - - memcpy(&mem_cfg->RcompTarget, &board_cfg->rcomp_targets, - sizeof(mem_cfg->RcompTarget)); - - memcpy(&mem_cfg->DqMapCpu2DramCh0, &board_cfg->dq_map[DDR_CH0], - sizeof(board_cfg->dq_map[DDR_CH0])); - memcpy(&mem_cfg->DqsMapCpu2DramCh0, &board_cfg->dqs_map[DDR_CH0], - sizeof(board_cfg->dqs_map[DDR_CH0])); - - memcpy(&mem_cfg->DqMapCpu2DramCh1, &board_cfg->dq_map[DDR_CH1], - sizeof(board_cfg->dq_map[DDR_CH1])); - memcpy(&mem_cfg->DqsMapCpu2DramCh1, &board_cfg->dqs_map[DDR_CH1], - sizeof(board_cfg->dqs_map[DDR_CH1])); - - memcpy(&mem_cfg->DqMapCpu2DramCh2, &board_cfg->dq_map[DDR_CH2], - sizeof(board_cfg->dq_map[DDR_CH2])); - memcpy(&mem_cfg->DqsMapCpu2DramCh2, &board_cfg->dqs_map[DDR_CH2], - sizeof(board_cfg->dqs_map[DDR_CH2])); - - memcpy(&mem_cfg->DqMapCpu2DramCh3, &board_cfg->dq_map[DDR_CH3], - sizeof(board_cfg->dq_map[DDR_CH3])); - memcpy(&mem_cfg->DqsMapCpu2DramCh3, &board_cfg->dqs_map[DDR_CH3], - sizeof(board_cfg->dqs_map[DDR_CH3])); - - if (half_populated) - return; - - memcpy(&mem_cfg->DqMapCpu2DramCh4, &board_cfg->dq_map[DDR_CH4], - sizeof(board_cfg->dq_map[DDR_CH4])); - memcpy(&mem_cfg->DqsMapCpu2DramCh4, &board_cfg->dqs_map[DDR_CH4], - sizeof(board_cfg->dqs_map[DDR_CH4])); - - memcpy(&mem_cfg->DqMapCpu2DramCh5, &board_cfg->dq_map[DDR_CH5], - sizeof(board_cfg->dq_map[DDR_CH5])); - memcpy(&mem_cfg->DqsMapCpu2DramCh5, &board_cfg->dqs_map[DDR_CH5], - sizeof(board_cfg->dqs_map[DDR_CH5])); - - memcpy(&mem_cfg->DqMapCpu2DramCh6, &board_cfg->dq_map[DDR_CH6], - sizeof(board_cfg->dq_map[DDR_CH6])); - memcpy(&mem_cfg->DqsMapCpu2DramCh6, &board_cfg->dqs_map[DDR_CH6], - sizeof(board_cfg->dqs_map[DDR_CH6])); - - memcpy(&mem_cfg->DqMapCpu2DramCh7, &board_cfg->dq_map[DDR_CH7], - sizeof(board_cfg->dq_map[DDR_CH7])); - memcpy(&mem_cfg->DqsMapCpu2DramCh7, &board_cfg->dqs_map[DDR_CH7], - sizeof(board_cfg->dqs_map[DDR_CH7])); -} - -static void meminit_channels(FSP_M_CONFIG *mem_cfg, - const struct mb_cfg *board_cfg, - uintptr_t spd_data_ptr, - bool half_populated) -{ - uint8_t dimm_cfg = DISABLE_DIMM1; /* Use only DIMM0 */ - - /* Channel 0 */ - mem_cfg->DisableDimmMc0Ch0 = dimm_cfg; - mem_cfg->MemorySpdPtr00 = spd_data_ptr; - mem_cfg->MemorySpdPtr01 = 0; - - /* Channel 1 */ - mem_cfg->DisableDimmMc0Ch1 = dimm_cfg; - mem_cfg->MemorySpdPtr02 = spd_data_ptr; - mem_cfg->MemorySpdPtr03 = 0; - - /* Channel 2 */ - mem_cfg->DisableDimmMc0Ch2 = dimm_cfg; - mem_cfg->MemorySpdPtr04 = spd_data_ptr; - mem_cfg->MemorySpdPtr05 = 0; - - /* Channel 3 */ - mem_cfg->DisableDimmMc0Ch3 = dimm_cfg; - mem_cfg->MemorySpdPtr06 = spd_data_ptr; - mem_cfg->MemorySpdPtr07 = 0; - - if (half_populated) { - printk(BIOS_INFO, "%s: DRAM half-populated\n", __func__); - dimm_cfg = DISABLE_BOTH_DIMMS; - spd_data_ptr = 0; - } - - /* Channel 4 */ - mem_cfg->DisableDimmMc1Ch0 = dimm_cfg; - mem_cfg->MemorySpdPtr08 = spd_data_ptr; - mem_cfg->MemorySpdPtr09 = 0; - - /* Channel 5 */ - mem_cfg->DisableDimmMc1Ch1 = dimm_cfg; - mem_cfg->MemorySpdPtr10 = spd_data_ptr; - mem_cfg->MemorySpdPtr11 = 0; - - /* Channel 6 */ - mem_cfg->DisableDimmMc1Ch2 = dimm_cfg; - mem_cfg->MemorySpdPtr12 = spd_data_ptr; - mem_cfg->MemorySpdPtr13 = 0; - - /* Channel 7 */ - mem_cfg->DisableDimmMc1Ch3 = dimm_cfg; - mem_cfg->MemorySpdPtr14 = spd_data_ptr; - mem_cfg->MemorySpdPtr15 = 0; - - meminit_dq_dqs_map(mem_cfg, board_cfg, half_populated); -} - -/* Initialize onboard memory configurations for lpddr4x */ -void memcfg_init(FSP_M_CONFIG *mem_cfg, - const struct mb_cfg *board_cfg, - const struct spd_info *spd_info, - bool half_populated) -{ - if (spd_info->read_type == READ_SMBUS) { - for (int i = 0; i < NUM_DIMM_SLOT; i++) - mem_cfg->SpdAddressTable[i] = spd_info->spd_spec.spd_smbus_address[i]; - meminit_dq_dqs_map(mem_cfg, board_cfg, half_populated); + if (channel == 0) { + switch (info->topology) { + case MEMORY_DOWN: + *spd_dimm0 = 0; + *spd_dimm1 = *spd_md_data; + break; + case SODIMM: + case MIXED: /* For a mixed topology, channel 0 can only be SODIMM */ + *spd_dimm0 = (uintptr_t)spd_sodimm_blk->spd_array[0]; + *spd_dimm1 = (uintptr_t)spd_sodimm_blk->spd_array[1]; + break; + default: + die("Invalid memory topology on channel 0 (%d)\n", info->topology); + } + } else if (channel == 1) { + if (half_populated) { + *spd_dimm0 = *spd_dimm1 = 0; + } else { + switch (info->topology) { + case MEMORY_DOWN: + case MIXED: /* For a mixed topology, channel 1 can only be memory-down */ + *spd_dimm0 = *spd_md_data; + *spd_dimm1 = 0; + break; + case SODIMM: + *spd_dimm0 = (uintptr_t)spd_sodimm_blk->spd_array[2]; + *spd_dimm0 = (uintptr_t)spd_sodimm_blk->spd_array[3]; + break; + default: + die("Invalid memory topology on channel 1 (%d)\n", info->topology); + } + } } else { - size_t spd_data_len = 0; - uintptr_t spd_data_ptr = 0; + die("Invalid channel %d\n", channel); + } +}
- memset(&mem_cfg->SpdAddressTable, 0, sizeof(mem_cfg->SpdAddressTable)); - get_spd_data(spd_info, &spd_data_ptr, &spd_data_len); +/* If memory is half-populated, then upper half of the channels are required to be empty. */ +static bool lpx_channel_unpopulated(int channel, bool half_populated) +{ + return (half_populated && (channel >= (LPX_CHANNELS / 2))); +}
- mem_cfg->MemorySpdDataLen = spd_data_len; - meminit_channels(mem_cfg, board_cfg, spd_data_ptr, half_populated); +static void meminit_lpx(FSP_M_CONFIG *mem_cfg, const struct lpx_common_mem_config *board_cfg, + const struct spd_info *info, bool half_populated) +{ + size_t i; + size_t spd_len; + uintptr_t spd_data; + + if (info->topology != MEMORY_DOWN) + die("LPX only supports memory down topology\n"); + + /* LP4X does not support interleaving DQ pins */ + mem_cfg->DqPinsInterleaved = 0; + mem_cfg->ECT = board_cfg->ect; + + read_md_spd(info, &spd_data, &spd_len); + mem_cfg->MemorySpdDataLen = spd_len; + + for (i = 0; i < LPX_CHANNELS; ++i) { + if (lpx_channel_unpopulated(i, half_populated)) { + init_spd_upds_empty(mem_cfg, i); + init_dq_upds_empty(mem_cfg, i); + init_dqs_upds_empty(mem_cfg, i); + } else { + init_spd_upds_dimm0(mem_cfg, i, spd_data); + init_dq_upds(mem_cfg, i, board_cfg->dq_map[i][0], + board_cfg->dq_map[i][1]); + init_dqs_upds(mem_cfg, i, board_cfg->dqs_map[i][0], + board_cfg->dqs_map[i][1]); + } + } +} + +static void meminit_ddr(FSP_M_CONFIG *mem_cfg, const struct ddr_mem_config *board_cfg, + const struct spd_info *info, bool half_populated) +{ + uintptr_t spd_md_data; + size_t spd_md_len; + uintptr_t spd_dimm0 = 0; + uintptr_t spd_dimm1 = 0; + struct spd_block spd_sodimm_blk; + size_t i, b; + size_t index = 0; + + mem_cfg->ECT = board_cfg->ect; + mem_cfg->DqPinsInterleaved = board_cfg->dq_pins_interleaved; + + if (info->topology == MEMORY_DOWN || info->topology == MIXED) { + read_md_spd(info, &spd_md_data, &spd_md_len); + mem_cfg->MemorySpdDataLen = spd_md_len; }
- mem_cfg->Lp5CccConfig = board_cfg->lp5_ccc_config; - mem_cfg->ECT = board_cfg->ect; - mem_cfg->UserBd = board_cfg->UserBd; - mem_cfg->DqPinsInterleaved = board_cfg->dq_pins_interleaved; + if (info->topology == SODIMM || info->topology == MIXED) { + read_sodimm_spd(info, &spd_sodimm_blk); + if (info->topology == MIXED && + spd_md_len != spd_sodimm_blk.len) + die("Mixed topology SPDs don't match lengths\n"); + else + mem_cfg->MemorySpdDataLen = spd_sodimm_blk.len; + } + + /* Init SPD UPDs */ + for (i = 0; i < DDR_CHANNELS; ++i) { + ddr_get_spd(i, &spd_md_data, &spd_sodimm_blk, info, half_populated, &spd_dimm0, + &spd_dimm1); + init_spd_upds(mem_cfg, DDR_FSP_UPD_CHANNEL_IDX(i), spd_dimm0, spd_dimm1); + } + + /* Init DQ & DQS mapping UPDs */ + for (i = 0; i < DDR_CHANNELS; ++i) { + for (b = 0; b < DDR_BYTES_PER_CHANNEL; b += 2) { + if (half_populated && i == 1) { + init_dq_upds_empty(mem_cfg, index); + init_dqs_upds_empty(mem_cfg, index); + } else { + init_dq_upds(mem_cfg, index, board_cfg->dq_map[i][b], + board_cfg->dq_map[i][b + 1]); + init_dqs_upds(mem_cfg, index, board_cfg->dqs_map[i][b], + board_cfg->dqs_map[i][b + 1]); + } + ++index; + } + } +} + +void memcfg_init(FSP_M_CONFIG *mem_cfg, const struct adl_mem_config *board_cfg, + const struct spd_info *info, bool half_populated) +{ + switch (board_cfg->mem_type) { + case MEMTYPE_DDR4: + case MEMTYPE_DDR5: /* intentional fallthrough */ + meminit_ddr(mem_cfg, board_cfg->ddr_cfg, info, half_populated); + break; + case MEMTYPE_LP4X: + meminit_lpx(mem_cfg, board_cfg->lp4x_cfg, info, half_populated); + break; + case MEMTYPE_LP5X: + meminit_lpx(mem_cfg, board_cfg->lp5x_cfg->lpx_config, info, half_populated); + mem_cfg->Lp5CccConfig = board_cfg->lp5x_cfg->lp5_ccc_config; + break; + default: + die("Unsupported memory type (%d)\n", board_cfg->mem_type); + } }