drivers/intel/fsp2_0: Implement API to retrieve DIMM info

This patch extracts the implementation responsible for retrieving DIMM
information from the FSP HOBs and centralizes it within the common FSP
driver code.

This ensures that each SoC layer does not duplicate the logic for
parsing memory-related data. The primary goal is to rely on the
common FSP driver code for retrieving memory information.

The only SoC-specific implementation that remains is limited to
handling dependencies related to FSP UPD or header differences across
SoC generations.

TEST=Able to build and boot google/kinmen. Verify the memory related
information is proper as part of the SMBIOS table.

Change-Id: Ic3741a248bb1fe9420c784d51fbf459a30f8c42f
Signed-off-by: Subrata Banik <subratabanik@google.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/89494
Reviewed-by: Kapil Porwal <kapilporwal@google.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
Subrata Banik 2025-10-09 16:28:08 +05:30
commit 23419df34c
4 changed files with 162 additions and 0 deletions

View file

@ -493,4 +493,11 @@ config USE_COREBOOT_FOR_BMP_RENDERING
Platforms can choose to override this Kconfig option based on their
specific graphics requirements and FSP capabilities.
config FSP_DIMM_INFO
bool
default n
help
Select this option to retrieve DIMM (Memory) related information by relying on
the Intel FSP. coreboot relies on this information to prepare SMBIOS table 17.
endif

View file

@ -17,6 +17,7 @@ romstage-$(CONFIG_MMA) += mma_core.c
romstage-y += cbmem.c
romstage-$(CONFIG_ENABLE_FSP_ERROR_INFO) += fsp_error_info_hob.c
romstage-$(CONFIG_CACHE_MRC_SETTINGS) += save_mrc_data.c
romstage-$(CONFIG_FSP_DIMM_INFO) += fsp_dimm_info.c
ramstage-y += debug.c
ramstage-$(CONFIG_FSP_USES_CB_DEBUG_EVENT_HANDLER) += fsp_debug_event.c

View file

@ -0,0 +1,139 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include <cbmem.h>
#include <console/console.h>
#include <fsp/api.h>
#include <fsp/util.h>
#include <memory_info.h>
#include <soc/intel/common/smbios.h>
#include <string.h>
/*
* Processes a single DIMM slot, checks for presence, fills in the
* dimm_info structure, and prepares for SMBIOS table creation.
*
* @param src_dimm: Source DIMM info from FSP HOB.
* @param dest_dimm: Destination DIMM info in CBMEM.
* @param channel_info: Channel info from FSP HOB.
* @param meminfo_hob: Overall memory info HOB.
* @param node: Memory controller node index.
* @param dram_part_num_ptr: Pointer to the current DRAM part number string.
* @param dram_part_num_len_ptr: Pointer to the current DRAM part number length.
* @return 1 if a DIMM was processed (index incremented), 0 otherwise.
*/
static int fsp_process_dimm_slot(const DIMM_INFO *src_dimm,
struct dimm_info *dest_dimm,
const CHANNEL_INFO *channel_info,
const MEMORY_INFO_DATA_HOB *meminfo_hob,
int node,
const char **dram_part_num_ptr,
size_t *dram_part_num_len_ptr)
{
const char *dram_part_num = *dram_part_num_ptr;
size_t dram_part_num_len = *dram_part_num_len_ptr;
const uint8_t *serial_num;
uint8_t mem_profile_number;
struct dimm_fill_args fill_args;
if (src_dimm->Status != DIMM_PRESENT)
return 0;
/* If there is no DRAM part number overridden by
* mainboard then use original one. */
if (!dram_part_num) {
dram_part_num_len = sizeof(src_dimm->ModulePartNum);
dram_part_num = (const char *)&src_dimm->ModulePartNum[0];
}
mem_profile_number = meminfo_hob->MemoryProfile;
serial_num = src_dimm->SpdSave + SPD_SAVE_OFFSET_SERIAL;
platform_fill_dimm_info_args(src_dimm, meminfo_hob, &fill_args);
/* Populate the DIMM information */
dimm_info_fill(dest_dimm,
src_dimm->DimmCapacity,
meminfo_hob->MemoryType,
meminfo_hob->ConfiguredMemoryClockSpeed,
src_dimm->RankInDimm,
channel_info->ChannelId,
src_dimm->DimmId,
dram_part_num,
dram_part_num_len,
serial_num,
fill_args.data_width,
meminfo_hob->VddVoltage[mem_profile_number],
meminfo_hob->EccSupport,
fill_args.mfg_id_arg,
src_dimm->SpdModuleType,
node,
meminfo_hob->MaximumMemoryClockSpeed);
/* Update the pointers in case the DRAM part number was set here */
*dram_part_num_ptr = dram_part_num;
*dram_part_num_len_ptr = dram_part_num_len;
return 1;
}
void fsp_save_dimm_info(void)
{
int node, channel, dimm_max;
size_t hob_size;
const CONTROLLER_INFO *ctrlr_info;
const CHANNEL_INFO *channel_info;
struct memory_info *mem_info;
const MEMORY_INFO_DATA_HOB *meminfo_hob;
const uint8_t smbios_memory_info_guid[] = {
0xd4, 0x71, 0x20, 0x9b, 0x54, 0xb0, 0x0c, 0x4e,
0x8d, 0x09, 0x11, 0xcf, 0x8b, 0x9f, 0x03, 0x23
};
const char *dram_part_num = NULL;
size_t dram_part_num_len = 0;
/* Locate the memory info HOB, presence validated by raminit */
meminfo_hob = fsp_find_extension_hob_by_guid(smbios_memory_info_guid, &hob_size);
if (!meminfo_hob || hob_size == 0) {
printk(BIOS_ERR, "SMBIOS MEMORY_INFO_DATA_HOB not found\n");
return;
}
/* Allocate CBMEM area for DIMM information... */
mem_info = cbmem_add(CBMEM_ID_MEMINFO, sizeof(*mem_info));
if (!mem_info) {
printk(BIOS_ERR, "CBMEM entry for DIMM info missing\n");
return;
}
memset(mem_info, 0, sizeof(*mem_info));
/* Allow mainboard to override DRAM part number. */
dram_part_num = mainboard_get_dram_part_num();
if (dram_part_num)
dram_part_num_len = strlen(dram_part_num);
/* Save available DIMM information */
size_t dimm = 0;
dimm_max = ARRAY_SIZE(mem_info->dimm);
for (node = 0; node < MAX_NODE; node++) {
ctrlr_info = &meminfo_hob->Controller[node];
for (channel = 0; channel < MAX_CH && dimm < dimm_max; channel++) {
channel_info = &ctrlr_info->ChannelInfo[channel];
if (channel_info->Status != CHANNEL_PRESENT)
continue;
for (size_t index = 0; index < MAX_DIMM && dimm < dimm_max; index++)
dimm += fsp_process_dimm_slot(&channel_info->DimmInfo[index],
&mem_info->dimm[dimm],
channel_info, meminfo_hob,
node, &dram_part_num,
&dram_part_num_len);
}
}
mem_info->dimm_cnt = dimm;
if (mem_info->dimm_cnt == 0)
printk(BIOS_ERR, "No DIMMs found\n");
else
printk(BIOS_DEBUG, "%d DIMMs found\n", mem_info->dimm_cnt);
}

View file

@ -50,6 +50,21 @@ void platform_fsp_silicon_init_params_cb(FSPS_UPD *supd);
/* Callbacks for SoC/Mainboard specific overrides */
void platform_fsp_memory_multi_phase_init_cb(uint32_t phase_index);
void platform_fsp_silicon_multi_phase_init_cb(uint32_t phase_index);
#if CONFIG(FSP_DIMM_INFO)
struct dimm_fill_args {
uint16_t data_width;
uint16_t mfg_id_arg;
};
/* Retrieve DIMM Information by relying on the FSP */
void fsp_save_dimm_info(void);
/* Callbacks for SoC/Mainboard specific overrides */
void platform_fill_dimm_info_args(const DIMM_INFO *src_dimm,
const MEMORY_INFO_DATA_HOB *meminfo_hob,
struct dimm_fill_args *args);
#endif
/*
* Displays an early shutdown notification to the user.
*