summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJohnny Lin <johnny_lin@wiwynn.com>2020-09-28 22:38:31 +0800
committerAngel Pons <th3fanbus@gmail.com>2020-10-08 12:09:26 +0000
commit7581352759ed3553f42b5356aaaa9759ec1c43b9 (patch)
tree97d0128b663efb5130f3b774b0c28ad3be48fd54 /src
parentb734ae2e8a1b9d7bca23f97b2da08c7817b8972a (diff)
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>
Diffstat (limited to 'src')
-rw-r--r--src/soc/intel/xeon_sp/cpx/Makefile.inc2
-rw-r--r--src/soc/intel/xeon_sp/cpx/ddr.c84
-rw-r--r--src/soc/intel/xeon_sp/cpx/include/soc/ddr.h51
-rw-r--r--src/soc/intel/xeon_sp/cpx/romstage.c90
-rw-r--r--src/soc/intel/xeon_sp/include/soc/romstage.h2
-rw-r--r--src/soc/intel/xeon_sp/romstage.c3
6 files changed, 229 insertions, 3 deletions
diff --git a/src/soc/intel/xeon_sp/cpx/Makefile.inc b/src/soc/intel/xeon_sp/cpx/Makefile.inc
index b1fcd0481f..79a83b5416 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/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
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 0000000000..0fa36ab6c9
--- /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 0000000000..61a5ebe338
--- /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 a198c993f3..6f47a30234 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 @@ 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;
diff --git a/src/soc/intel/xeon_sp/include/soc/romstage.h b/src/soc/intel/xeon_sp/include/soc/romstage.h
index aa46067bbb..90689afc7f 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 a4853c064e..f3e32fd9ca 100644
--- a/src/soc/intel/xeon_sp/romstage.c
+++ b/src/soc/intel/xeon_sp/romstage.c
@@ -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) { }