Angel Pons has submitted this change. ( https://review.coreboot.org/c/coreboot/+/45798 )
Change subject: soc/intel/xeon_sp/cpx: Add save_dimm_info for SMBIOS type 17 ......................................................................
soc/intel/xeon_sp/cpx: Add save_dimm_info for SMBIOS type 17
For now only implement for one socket and some of the fields are hard-coded for DDR4 including memory device type, data width and ECC support.
Change-Id: I3cb72d18027d972140828970206834ff55b72022 Signed-off-by: Johnny Lin johnny_lin@wiwynn.com Reviewed-on: https://review.coreboot.org/c/coreboot/+/45798 Tested-by: build bot (Jenkins) no-reply@coreboot.org Reviewed-by: Jonathan Zhang jonzhang@fb.com Reviewed-by: Angel Pons th3fanbus@gmail.com --- M src/soc/intel/xeon_sp/cpx/Makefile.inc A src/soc/intel/xeon_sp/cpx/ddr.c A src/soc/intel/xeon_sp/cpx/include/soc/ddr.h M src/soc/intel/xeon_sp/cpx/romstage.c M src/soc/intel/xeon_sp/include/soc/romstage.h M src/soc/intel/xeon_sp/romstage.c 6 files changed, 229 insertions(+), 3 deletions(-)
Approvals: build bot (Jenkins): Verified Angel Pons: Looks good to me, approved Jonathan Zhang: Looks good to me, but someone else must approve
diff --git a/src/soc/intel/xeon_sp/cpx/Makefile.inc b/src/soc/intel/xeon_sp/cpx/Makefile.inc index b1fcd04..79a83b5 100644 --- a/src/soc/intel/xeon_sp/cpx/Makefile.inc +++ b/src/soc/intel/xeon_sp/cpx/Makefile.inc @@ -8,7 +8,7 @@ subdirs-y += ../../../../cpu/x86/tsc subdirs-y += ../../../../cpu/intel/microcode
-romstage-y += romstage.c +romstage-y += romstage.c ddr.c romstage-$(CONFIG_DISPLAY_UPD_DATA) += upd_display.c romstage-$(CONFIG_DISPLAY_HOBS) += hob_display.c
diff --git a/src/soc/intel/xeon_sp/cpx/ddr.c b/src/soc/intel/xeon_sp/cpx/ddr.c new file mode 100644 index 0000000..0fa36ab --- /dev/null +++ b/src/soc/intel/xeon_sp/cpx/ddr.c @@ -0,0 +1,84 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include <soc/ddr.h> + +uint32_t get_ddr_voltage(uint8_t DdrVoltage) +{ + /* SPD Byte 11: Module Nominal Voltage, currently DDR4 only supports 1.2V. + Either Bit 0 or Bit 1 is set, return 1.2V */ + if (DdrVoltage & 0x3) + return 1200; + return 0; +} + +uint16_t get_max_memory_speed(uint32_t commonTck) +{ + if (commonTck <= DDR_8400_TCK_MIN) + return 8400; + else if (commonTck <= DDR_6400_TCK_MIN) + return 6400; + else if (commonTck <= DDR_6000_TCK_MIN) + return 6000; + else if (commonTck <= DDR_5600_TCK_MIN) + return 5600; + else if (commonTck <= DDR_5200_TCK_MIN) + return 5200; + else if (commonTck <= DDR_4800_TCK_MIN) + return 4800; + else if (commonTck <= DDR_4400_TCK_MIN) + return 4400; + else if (commonTck <= DDR_4266_TCK_MIN) + return 4266; + else if (commonTck <= DDR_4200_TCK_MIN) + return 4200; + else if (commonTck <= DDR_4000_TCK_MIN) + return 4000; + else if (commonTck <= DDR_3800_TCK_MIN) + return 3800; + else if (commonTck <= DDR_3733_TCK_MIN) + return 3733; + else if (commonTck <= DDR_3600_TCK_MIN) + return 3600; + else if (commonTck <= DDR_3466_TCK_MIN) + return 3466; + else if (commonTck <= DDR_3400_TCK_MIN) + return 3400; + else if (commonTck <= DDR_3200_TCK_MIN) + return 3200; + else if (commonTck <= DDR_3000_TCK_MIN) + return 3000; + else if (commonTck <= DDR_2933_TCK_MIN) + return 2933; + else if (commonTck <= DDR_2800_TCK_MIN) + return 2800; + else if (commonTck <= DDR_2666_TCK_MIN) + return 2666; + else if (commonTck <= DDR_2600_TCK_MIN) + return 2600; + else if (commonTck <= DDR_2400_TCK_MIN) + return 2400; + else if (commonTck <= DDR_2200_TCK_MIN) + return 2200; + else if (commonTck <= DDR_2133_TCK_MIN) + return 2133; + else if (commonTck <= DDR_2000_TCK_MIN) + return 2000; + else if (commonTck <= DDR_1866_TCK_MIN) + return 1866; + else if (commonTck <= DDR_1800_TCK_MIN) + return 1800; + else if (commonTck <= DDR_1600_TCK_MIN) + return 1600; + else if (commonTck <= DDR_1400_TCK_MIN) + return 1400; + else if (commonTck <= DDR_1333_TCK_MIN) + return 1333; + else if (commonTck <= DDR_1200_TCK_MIN) + return 1200; + else if (commonTck <= DDR_1066_TCK_MIN) + return 1066; + else if (commonTck <= DDR_1000_TCK_MIN) + return 1000; + else + return 800; +} diff --git a/src/soc/intel/xeon_sp/cpx/include/soc/ddr.h b/src/soc/intel/xeon_sp/cpx/include/soc/ddr.h new file mode 100644 index 0000000..61a5ebe --- /dev/null +++ b/src/soc/intel/xeon_sp/cpx/include/soc/ddr.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef _CPX_DDR_H_ +#define _CPX_DDR_H_ + +#include <stdint.h> + +/* DDR_*_TCK_MIN are in picoseconds */ +#define DDR_800_TCK_MIN 2500 +#define DDR_1000_TCK_MIN 2000 +#define DDR_1066_TCK_MIN 1875 +#define DDR_1200_TCK_MIN 1667 +#define DDR_1333_TCK_MIN 1500 +#define DDR_1400_TCK_MIN 1429 +#define DDR_1600_TCK_MIN 1250 +#define DDR_1800_TCK_MIN 1110 +#define DDR_1866_TCK_MIN 1071 +#define DDR_2000_TCK_MIN 1000 +#define DDR_2133_TCK_MIN 938 +#define DDR_2200_TCK_MIN 909 +#define DDR_2400_TCK_MIN 833 +#define DDR_2600_TCK_MIN 769 +#define DDR_2666_TCK_MIN 750 +#define DDR_2800_TCK_MIN 714 +#define DDR_2933_TCK_MIN 682 +#define DDR_3000_TCK_MIN 667 +#define DDR_3200_TCK_MIN 625 +#define DDR_3400_TCK_MIN 589 +#define DDR_3466_TCK_MIN 577 +#define DDR_3600_TCK_MIN 556 +#define DDR_3733_TCK_MIN 536 +#define DDR_3800_TCK_MIN 527 +#define DDR_4000_TCK_MIN 500 +#define DDR_4200_TCK_MIN 477 +#define DDR_4266_TCK_MIN 469 +#define DDR_4400_TCK_MIN 455 +#define DDR_4800_TCK_MIN 417 +#define DDR_5200_TCK_MIN 385 +#define DDR_5600_TCK_MIN 358 +#define DDR_6000_TCK_MIN 334 +#define DDR_6400_TCK_MIN 313 +#define DDR_6800_TCK_MIN 295 +#define DDR_7200_TCK_MIN 278 +#define DDR_7600_TCK_MIN 264 +#define DDR_8000_TCK_MIN 250 +#define DDR_8400_TCK_MIN 239 + +uint16_t get_max_memory_speed(uint32_t commonTck); +uint32_t get_ddr_voltage(uint8_t DdrVoltage); + +#endif /* _CPX_DDR_H_ */ diff --git a/src/soc/intel/xeon_sp/cpx/romstage.c b/src/soc/intel/xeon_sp/cpx/romstage.c index a198c99..6f47a30 100644 --- a/src/soc/intel/xeon_sp/cpx/romstage.c +++ b/src/soc/intel/xeon_sp/cpx/romstage.c @@ -1,9 +1,19 @@ /* SPDX-License-Identifier: GPL-2.0-only */
+#include <assert.h> #include <arch/romstage.h> +#include <console/console.h> +#include <cbmem.h> #include <fsp/api.h> +#include <fsp/util.h> +#include <hob_iiouds.h> +#include <hob_memmap.h> +#include <soc/ddr.h> #include <soc/romstage.h> #include <soc/pci_devs.h> +#include <soc/intel/common/smbios.h> +#include <string.h> + #include "chip.h"
void __weak mainboard_memory_init_params(FSPM_UPD *mupd) @@ -11,6 +21,86 @@ /* Default weak implementation */ }
+static const struct SystemMemoryMapHob *get_system_memory_map(void) +{ + size_t hob_size; + const uint8_t mem_hob_guid[16] = FSP_SYSTEM_MEMORYMAP_HOB_GUID; + const struct SystemMemoryMapHob **memmap_addr; + + memmap_addr = (const struct SystemMemoryMapHob **) + fsp_find_extension_hob_by_guid(mem_hob_guid, &hob_size); + /* hob_size is the size of the 8-byte address not the hob data */ + assert(memmap_addr != NULL && hob_size != 0); + /* assert the pointer to the hob is not NULL */ + assert(*memmap_addr != NULL); + + return *memmap_addr; +} + +/* Save the DIMM information for SMBIOS table 17 */ +void save_dimm_info(void) +{ + struct dimm_info *dest_dimm; + struct memory_info *mem_info; + const struct SystemMemoryMapHob *hob; + MEMMAP_DIMM_DEVICE_INFO_STRUCT src_dimm; + int dimm_max, index = 0; + uint32_t vdd_voltage; + + hob = get_system_memory_map(); + assert(hob != NULL); + + /* + * Allocate CBMEM area for DIMM information used to populate SMBIOS + * table 17 + */ + mem_info = cbmem_add(CBMEM_ID_MEMINFO, sizeof(*mem_info)); + if (mem_info == NULL) { + printk(BIOS_ERR, "CBMEM entry for DIMM info missing\n"); + return; + } + memset(mem_info, 0, sizeof(*mem_info)); + dimm_max = ARRAY_SIZE(mem_info->dimm); + vdd_voltage = get_ddr_voltage(hob->DdrVoltage); + /* For now only implement for one socket and hard-coded for DDR4 */ + for (int ch = 0; ch < MAX_CH; ch++) { + for (int dimm = 0; dimm < MAX_IMC; dimm++) { + src_dimm = hob->Socket[0].ChannelInfo[ch].DimmInfo[dimm]; + if (src_dimm.Present) { + if (index >= dimm_max) { + printk(BIOS_WARNING, "Too many DIMMs info for %s.\n", + __func__); + return; + } + dest_dimm = &mem_info->dimm[index]; + dest_dimm->max_speed_mts = + get_max_memory_speed(src_dimm.commonTck); + dest_dimm->configured_speed_mts = hob->memFreq; + dimm_info_fill(dest_dimm, + src_dimm.DimmSize << 6, + 0x1a, /* hard-coded memory device type as DDR4 */ + hob->memFreq, /* replaced by configured_speed_mts */ + src_dimm.NumRanks, + ch, /* for mainboard locator string override */ + dimm, /* for mainboard locator string override */ + (const char *)&src_dimm.PartNumber[0], + sizeof(src_dimm.PartNumber), + (const uint8_t *)&src_dimm.serialNumber[0], + 64, /* hard-coded for DDR4 data width */ + vdd_voltage, + true, /* hard-coded as ECC supported */ + src_dimm.VendorID, + src_dimm.actKeyByte2); + index++; + } + } + } + + /* Save available DIMM information */ + mem_info->dimm_cnt = index; + printk(BIOS_DEBUG, "%d DIMMs found\n", mem_info->dimm_cnt); +} + void platform_fsp_memory_init_params_cb(FSPM_UPD *mupd, uint32_t version) { FSPM_CONFIG *m_cfg = &mupd->FspmConfig; diff --git a/src/soc/intel/xeon_sp/include/soc/romstage.h b/src/soc/intel/xeon_sp/include/soc/romstage.h index aa46067..90689af 100644 --- a/src/soc/intel/xeon_sp/include/soc/romstage.h +++ b/src/soc/intel/xeon_sp/include/soc/romstage.h @@ -8,5 +8,5 @@ /* These functions are weak and can be overridden by a mainboard functions. */ void mainboard_memory_init_params(FSPM_UPD * mupd); void mainboard_rtc_failed(void); - +void save_dimm_info(void); #endif /* _SOC_ROMSTAGE_H_ */ diff --git a/src/soc/intel/xeon_sp/romstage.c b/src/soc/intel/xeon_sp/romstage.c index a4853c0..f3e32fd 100644 --- a/src/soc/intel/xeon_sp/romstage.c +++ b/src/soc/intel/xeon_sp/romstage.c @@ -41,7 +41,7 @@
/* Cache the memory-mapped boot media. */ postcar_frame_add_romcache(&pcf, MTRR_TYPE_WRPROT); - + save_dimm_info(); run_postcar_phase(&pcf); }
@@ -54,3 +54,4 @@ {
} +__weak void save_dimm_info(void) { }