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 <kapilporwal@google.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/85529
Reviewed-by: Subrata Banik <subratabanik@google.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Dinesh Gehlot <digehlot@google.com>
Reviewed-by: Jayvik Desai <jayvik@google.com>
This commit is contained in:
Kapil Porwal 2024-12-12 11:37:26 +00:00 committed by Subrata Banik
commit 3153432b83
3 changed files with 54 additions and 0 deletions

View file

@ -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

View file

@ -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_ */

View file

@ -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);
}