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>
This commit is contained in:
Johnny Lin
2020-09-28 22:38:31 +08:00
committed by Angel Pons
parent b734ae2e8a
commit 7581352759
6 changed files with 229 additions and 3 deletions

View File

@@ -8,7 +8,7 @@ subdirs-y += ../../../../cpu/x86/mtrr
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

View File

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

View File

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

View File

@@ -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 @@ void __weak mainboard_memory_init_params(FSPM_UPD *mupd)
/* 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;

View File

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

View File

@@ -41,7 +41,7 @@ asmlinkage void car_stage_entry(void)
/* 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 mainboard_rtc_failed(void)
{
}
__weak void save_dimm_info(void) { }