From 3153432b836912e926ec05038b8cc76fcdc9e069 Mon Sep 17 00:00:00 2001 From: Kapil Porwal Date: Thu, 12 Dec 2024 11:37:26 +0000 Subject: [PATCH] soc/intel/alderlake: Add function to force disable memory channels Add a function `mem_init_override_channel_mask` to disable memory channels based on given bitmap where each bit represents a memory channel. A set bit will disable corresponding memory channel. Variants can override this bitmap by selecting `ENFORCE_MEM_CHANNEL_DISABLE` and implementing `mb_get_channel_disable_mask` to return the bitmap. BUG=b:379311559 TEST=Make sure that channel mask is applied correctly. Lotso without any channel mask: ``` lotso-rev0 ~ # dmidecode -t 17 | grep -E "(Locator: C|Size)" Size: 2 GB Locator: Channel-0-DIMM-0 Size: 2 GB Locator: Channel-1-DIMM-0 Size: 2 GB Locator: Channel-2-DIMM-0 Size: 2 GB Locator: Channel-3-DIMM-0 Size: 2 GB Locator: Channel-0-DIMM-0 Size: 2 GB Locator: Channel-1-DIMM-0 Size: 2 GB Locator: Channel-2-DIMM-0 Size: 2 GB Locator: Channel-3-DIMM-0 lotso-rev0 ~ # dmidecode -t 17 | grep Size | wc -l 8 ``` Lotso with channel 2 & 3 masked: ``` lotso-rev0 ~ # dmidecode -t 17 | grep -E "(Locator: C|Size)" Size: 2 GB Locator: Channel-0-DIMM-0 Size: 2 GB Locator: Channel-1-DIMM-0 Size: 2 GB Locator: Channel-0-DIMM-0 Size: 2 GB Locator: Channel-1-DIMM-0 lotso-rev0 ~ # dmidecode -t 17 | grep Size | wc -l 4 ``` Change-Id: Ibfeca4509cb3d88bc1bac2ac2d480e665d895bc5 Signed-off-by: Kapil Porwal Reviewed-on: https://review.coreboot.org/c/coreboot/+/85529 Reviewed-by: Subrata Banik Tested-by: build bot (Jenkins) Reviewed-by: Dinesh Gehlot Reviewed-by: Jayvik Desai --- src/soc/intel/alderlake/Kconfig | 8 +++++ src/soc/intel/alderlake/include/soc/meminit.h | 12 +++++++ src/soc/intel/alderlake/meminit.c | 34 +++++++++++++++++++ 3 files changed, 54 insertions(+) diff --git a/src/soc/intel/alderlake/Kconfig b/src/soc/intel/alderlake/Kconfig index f6e918204b..15f347f755 100644 --- a/src/soc/intel/alderlake/Kconfig +++ b/src/soc/intel/alderlake/Kconfig @@ -441,6 +441,14 @@ config MRC_CHANNEL_WIDTH int default 16 +config ENFORCE_MEM_CHANNEL_DISABLE + bool + default n + help + Select this option to disable certain memory channels on demand. If + selected, A function named mb_get_channel_disable_mask() must be + implemented to return the bit map of memory channels to disable. + config ALDERLAKE_ENABLE_SOC_WORKAROUND bool default y diff --git a/src/soc/intel/alderlake/include/soc/meminit.h b/src/soc/intel/alderlake/include/soc/meminit.h index 1d9eaf9414..97fb77cf81 100644 --- a/src/soc/intel/alderlake/include/soc/meminit.h +++ b/src/soc/intel/alderlake/include/soc/meminit.h @@ -116,4 +116,16 @@ struct mb_cfg { void memcfg_init(FSPM_UPD *memupd, const struct mb_cfg *mb_cfg, const struct mem_spd *spd_info, bool half_populated); +/* + * This function is expected to return a bitmap of memory channels to + * disable. A set bit will disable corresponding memory channel. + * Variants can override this bitmap by selecting + * `ENFORCE_MEM_CHANNEL_DISABLE` and implementing this function. + */ +#if CONFIG(ENFORCE_MEM_CHANNEL_DISABLE) +uint8_t mb_get_channel_disable_mask(void); +#else +static inline uint8_t mb_get_channel_disable_mask(void) { return 0; } +#endif + #endif /* _SOC_ALDERLAKE_MEMINIT_H_ */ diff --git a/src/soc/intel/alderlake/meminit.c b/src/soc/intel/alderlake/meminit.c index 35c32527b2..6b3143eadd 100644 --- a/src/soc/intel/alderlake/meminit.c +++ b/src/soc/intel/alderlake/meminit.c @@ -233,6 +233,39 @@ static void ddr5_fill_dimm_module_info(FSP_M_CONFIG *mem_cfg, const struct mb_cf mem_init_dqs_upds(mem_cfg, NULL, mb_cfg, true); } +/* + * A memory channel will be disabled if corresponding bit in + * ch_disable_mask is set. + */ +static void mem_init_override_channel_mask(FSP_M_CONFIG *mem_cfg) +{ + uint8_t *disable_channel_upds[MRC_CHANNELS] = { + &mem_cfg->DisableMc0Ch0, + &mem_cfg->DisableMc0Ch1, + &mem_cfg->DisableMc0Ch2, + &mem_cfg->DisableMc0Ch3, + &mem_cfg->DisableMc1Ch0, + &mem_cfg->DisableMc1Ch1, + &mem_cfg->DisableMc1Ch2, + &mem_cfg->DisableMc1Ch3, + }; + + uint8_t ch_disable_mask = mb_get_channel_disable_mask(); + if (ch_disable_mask == 0) + return; + + /* Mc0Ch0 cannot be disabled */ + if (ch_disable_mask & BIT(0)) { + printk(BIOS_ERR, "Cannot disable the first memory channel (Mc0Ch0).\n"); + return; + } + + for (size_t ch = 0; ch < MRC_CHANNELS; ch++) { + if (ch_disable_mask & BIT(ch)) + *disable_channel_upds[ch] = 1; + } +} + void memcfg_init(FSPM_UPD *memupd, const struct mb_cfg *mb_cfg, const struct mem_spd *spd_info, bool half_populated) { @@ -283,6 +316,7 @@ void memcfg_init(FSPM_UPD *memupd, const struct mb_cfg *mb_cfg, mem_populate_channel_data(memupd, &soc_mem_cfg[mb_cfg->type], spd_info, half_populated, &data); mem_init_spd_upds(mem_cfg, &data); + mem_init_override_channel_mask(mem_cfg); mem_init_dq_upds(mem_cfg, &data, mb_cfg, dq_dqs_auto_detect); mem_init_dqs_upds(mem_cfg, &data, mb_cfg, dq_dqs_auto_detect); }