From bf72dcbd2f1b0138a329f0c9adac33c387e8cd9f Mon Sep 17 00:00:00 2001 From: Patrick Rudolph Date: Tue, 12 May 2020 16:04:47 +0200 Subject: soc/intel/common: Improve Type16 SMBIOS tables Use CAPID0_A to provide information closer to reality. * Correctly advertise ECC support, max DIMM count and max capacity * CAPID0_A hasn't changed since SNB, but most EDS mark the bits as reserved even though they are still used by FSP. * Assume the same bits for Tiger Lake as for Ice Lake * Assume the same bits for Skylake as for Coffee Lake * Add CAPID0_A to Icelake headers The lastest complete documentation can be found in Document: 341078-002. Change-Id: I0d8fbb512fccbd99a6cfdacadc496d8266ae4cc7 Signed-off-by: Patrick Rudolph Reviewed-on: https://review.coreboot.org/c/coreboot/+/41334 Tested-by: build bot (Jenkins) Reviewed-by: Paul Menzel Reviewed-by: Christian Walter Reviewed-by: Philipp Deppenwiese --- src/soc/intel/apollolake/systemagent.c | 6 +++++ src/soc/intel/cannonlake/systemagent.c | 14 ++++++++++ .../common/block/include/intelblocks/systemagent.h | 4 +++ .../intel/common/block/systemagent/systemagent.c | 31 +++++++++++++++++++--- .../common/block/systemagent/systemagent_def.h | 5 ++++ src/soc/intel/icelake/include/soc/systemagent.h | 1 + src/soc/intel/icelake/systemagent.c | 14 ++++++++++ src/soc/intel/skylake/systemagent.c | 14 ++++++++++ src/soc/intel/tigerlake/systemagent.c | 14 ++++++++++ 9 files changed, 99 insertions(+), 4 deletions(-) diff --git a/src/soc/intel/apollolake/systemagent.c b/src/soc/intel/apollolake/systemagent.c index 258376a999..e05a470d50 100644 --- a/src/soc/intel/apollolake/systemagent.c +++ b/src/soc/intel/apollolake/systemagent.c @@ -88,3 +88,9 @@ int soc_get_uncore_prmmr_base_and_mask(uint64_t *prmrr_base, return 0; } + +uint32_t soc_systemagent_max_chan_capacity_mib(u8 capid0_a_ddrsz) +{ + /* Max 4GiB per rank, 2 ranks per channel. Intel Document: 332092-002 */ + return 8192; +} diff --git a/src/soc/intel/cannonlake/systemagent.c b/src/soc/intel/cannonlake/systemagent.c index c225651649..d57b3e9219 100644 --- a/src/soc/intel/cannonlake/systemagent.c +++ b/src/soc/intel/cannonlake/systemagent.c @@ -73,3 +73,17 @@ void soc_systemagent_init(struct device *dev) soc_config = &config->power_limits_config; set_power_limits(MOBILE_SKU_PL1_TIME_SEC, soc_config); } + +uint32_t soc_systemagent_max_chan_capacity_mib(u8 capid0_a_ddrsz) +{ + switch (capid0_a_ddrsz) { + case 1: + return 8192; + case 2: + return 4096; + case 3: + return 2048; + default: + return 32768; + } +} diff --git a/src/soc/intel/common/block/include/intelblocks/systemagent.h b/src/soc/intel/common/block/include/intelblocks/systemagent.h index 30c892ba13..ae7211697e 100644 --- a/src/soc/intel/common/block/include/intelblocks/systemagent.h +++ b/src/soc/intel/common/block/include/intelblocks/systemagent.h @@ -90,4 +90,8 @@ void soc_add_fixed_mmio_resources(struct device *dev, int *resource_cnt); /* SoC specific APIs to get UNCORE PRMRR base and mask values * returns 0, if able to get base and mask values; otherwise returns -1 */ int soc_get_uncore_prmmr_base_and_mask(uint64_t *base, uint64_t *mask); + +/* Returns the maximum supported capacity of a channel as encoded by DDRSZ in MiB */ +uint32_t soc_systemagent_max_chan_capacity_mib(u8 capid0_a_ddrsz); + #endif /* SOC_INTEL_COMMON_BLOCK_SA_H */ diff --git a/src/soc/intel/common/block/systemagent/systemagent.c b/src/soc/intel/common/block/systemagent/systemagent.c index 269236ba32..d25e1aa46c 100644 --- a/src/soc/intel/common/block/systemagent/systemagent.c +++ b/src/soc/intel/common/block/systemagent/systemagent.c @@ -41,6 +41,11 @@ __weak unsigned long sa_write_acpi_tables(const struct device *dev, return current; } +__weak uint32_t soc_systemagent_max_chan_capacity_mib(u8 capid0_a_ddrsz) +{ + return 32768; /* 32 GiB per channel */ +} + /* * Add all known fixed MMIO ranges that hang off the host bridge/memory * controller device. @@ -258,11 +263,27 @@ static void systemagent_read_resources(struct device *dev) } #if CONFIG(GENERATE_SMBIOS_TABLES) +static bool sa_supports_ecc(const uint32_t capida) +{ + return !(capida & CAPID_ECCDIS); +} + +static size_t sa_slots_per_channel(const uint32_t capida) +{ + return !(capida & CAPID_DDPCD) + 1; +} + +static size_t sa_number_of_channels(const uint32_t capida) +{ + return !(capida & CAPID_PDCD) + 1; +} + static int sa_smbios_write_type_16(struct device *dev, int *handle, unsigned long *current) { struct smbios_type16 *t = (struct smbios_type16 *)*current; int len = sizeof(struct smbios_type16); + const uint32_t capida = pci_read_config32(dev, CAPID0_A); struct memory_info *meminfo; meminfo = cbmem_find(CBMEM_ID_MEMINFO); @@ -275,12 +296,14 @@ static int sa_smbios_write_type_16(struct device *dev, int *handle, t->length = len - 2; t->location = MEMORY_ARRAY_LOCATION_SYSTEM_BOARD; t->use = MEMORY_ARRAY_USE_SYSTEM; - /* TBD, meminfo hob have information about ECC */ - t->memory_error_correction = MEMORY_ARRAY_ECC_NONE; + t->memory_error_correction = sa_supports_ecc(capida) ? MEMORY_ARRAY_ECC_SINGLE_BIT : + MEMORY_ARRAY_ECC_NONE; /* no error information handle available */ t->memory_error_information_handle = 0xFFFE; - t->maximum_capacity = 32 * (GiB / KiB); /* 32GB as default */ - t->number_of_memory_devices = meminfo->dimm_cnt; + t->maximum_capacity = soc_systemagent_max_chan_capacity_mib(CAPID_DDRSZ(capida)) * + sa_number_of_channels(capida) * (MiB / KiB); + t->number_of_memory_devices = sa_slots_per_channel(capida) * + sa_number_of_channels(capida); *current += len; *handle += 1; diff --git a/src/soc/intel/common/block/systemagent/systemagent_def.h b/src/soc/intel/common/block/systemagent/systemagent_def.h index a652dfd9a2..a7823c347c 100644 --- a/src/soc/intel/common/block/systemagent/systemagent_def.h +++ b/src/soc/intel/common/block/systemagent/systemagent_def.h @@ -17,6 +17,11 @@ #define DPR_EPM (1 << 2) #define DPR_PRS (1 << 1) #define DPR_SIZE_MASK 0xff0 +/* CAPID0_A */ +#define CAPID_ECCDIS (1 << 25) +#define CAPID_DDPCD (1 << 14) +#define CAPID_PDCD (1 << 12) +#define CAPID_DDRSZ(x) (((x) >> 19) & 0x3) #define PCIEXBAR_LENGTH_64MB 2 #define PCIEXBAR_LENGTH_128MB 1 diff --git a/src/soc/intel/icelake/include/soc/systemagent.h b/src/soc/intel/icelake/include/soc/systemagent.h index 297ee5d56c..90465a248b 100644 --- a/src/soc/intel/icelake/include/soc/systemagent.h +++ b/src/soc/intel/icelake/include/soc/systemagent.h @@ -15,6 +15,7 @@ #define D_LCK (1 << 4) #define G_SMRAME (1 << 3) #define C_BASE_SEG ((0 << 2) | (1 << 1) | (0 << 0)) +#define CAPID0_A 0xe4 #define BIOS_RESET_CPL 0x5da8 #define EDRAMBAR 0x5408 diff --git a/src/soc/intel/icelake/systemagent.c b/src/soc/intel/icelake/systemagent.c index ac96d81adf..c9fe0a97eb 100644 --- a/src/soc/intel/icelake/systemagent.c +++ b/src/soc/intel/icelake/systemagent.c @@ -52,3 +52,17 @@ void soc_systemagent_init(struct device *dev) /* Enable BIOS Reset CPL */ enable_bios_reset_cpl(); } + +uint32_t soc_systemagent_max_chan_capacity_mib(u8 capid0_a_ddrsz) +{ + switch (capid0_a_ddrsz) { + case 1: + return 8192; + case 2: + return 4096; + case 3: + return 2048; + default: + return 65536; + } +} diff --git a/src/soc/intel/skylake/systemagent.c b/src/soc/intel/skylake/systemagent.c index 8e58bf6669..f28bd257fe 100644 --- a/src/soc/intel/skylake/systemagent.c +++ b/src/soc/intel/skylake/systemagent.c @@ -87,3 +87,17 @@ int soc_get_uncore_prmmr_base_and_mask(uint64_t *prmrr_base, *prmrr_mask = (uint64_t) msr.hi << 32 | msr.lo; return 0; } + +uint32_t soc_systemagent_max_chan_capacity_mib(u8 capid0_a_ddrsz) +{ + switch (capid0_a_ddrsz) { + case 1: + return 8192; + case 2: + return 4096; + case 3: + return 2048; + default: + return 32768; + } +} diff --git a/src/soc/intel/tigerlake/systemagent.c b/src/soc/intel/tigerlake/systemagent.c index 8c0a42a71a..08d1ef387c 100644 --- a/src/soc/intel/tigerlake/systemagent.c +++ b/src/soc/intel/tigerlake/systemagent.c @@ -67,3 +67,17 @@ void soc_systemagent_init(struct device *dev) soc_config = &config->power_limits_config; set_power_limits(MOBILE_SKU_PL1_TIME_SEC, soc_config); } + +uint32_t soc_systemagent_max_chan_capacity_mib(u8 capid0_a_ddrsz) +{ + switch (capid0_a_ddrsz) { + case 1: + return 8192; + case 2: + return 4096; + case 3: + return 2048; + default: + return 65536; + } +} -- cgit v1.2.3