Patrick Rudolph has uploaded this change for review.

View Change

soc/intel/common: Better advertisment of 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 CoffeeLake

The lastest complete documentation can be found in Document: 341078-002.

Change-Id: I0d8fbb512fccbd99a6cfdacadc496d8266ae4cc7
Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
---
M src/soc/intel/apollolake/systemagent.c
M src/soc/intel/cannonlake/systemagent.c
M src/soc/intel/common/block/include/intelblocks/systemagent.h
M src/soc/intel/common/block/systemagent/systemagent.c
M src/soc/intel/common/block/systemagent/systemagent_def.h
M src/soc/intel/icelake/systemagent.c
M src/soc/intel/skylake/systemagent.c
M src/soc/intel/tigerlake/systemagent.c
8 files changed, 98 insertions(+), 4 deletions(-)

git pull ssh://review.coreboot.org:29418/coreboot refs/changes/34/41334/1
diff --git a/src/soc/intel/apollolake/systemagent.c b/src/soc/intel/apollolake/systemagent.c
index cc3639c..32113e6 100644
--- a/src/soc/intel/apollolake/systemagent.c
+++ b/src/soc/intel/apollolake/systemagent.c
@@ -89,3 +89,9 @@

return 0;
}
+
+uint32_t soc_systemagent_max_chan_capacity(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 1ab365e..f917f66 100644
--- a/src/soc/intel/cannonlake/systemagent.c
+++ b/src/soc/intel/cannonlake/systemagent.c
@@ -68,3 +68,17 @@
mdelay(1);
set_power_limits(28);
}
+
+uint32_t soc_systemagent_max_chan_capacity(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 c6aa4b4..394f27a 100644
--- a/src/soc/intel/common/block/include/intelblocks/systemagent.h
+++ b/src/soc/intel/common/block/include/intelblocks/systemagent.h
@@ -91,4 +91,8 @@
/* 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(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 d0e171d..7cba085 100644
--- a/src/soc/intel/common/block/systemagent/systemagent.c
+++ b/src/soc/intel/common/block/systemagent/systemagent.c
@@ -41,6 +41,11 @@
return current;
}

+__weak uint32_t soc_systemagent_max_chan_capacity(u8 capid0_a_ddrsz)
+{
+ return 32768; /* 32 GiB per channel */
+}
+
/*
* This function will get above 4GB mmio enable config specific to soc.
*
@@ -274,11 +279,27 @@
}

#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);
@@ -291,12 +312,14 @@
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(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 03f4de4..2fc86b0 100644
--- a/src/soc/intel/common/block/systemagent/systemagent_def.h
+++ b/src/soc/intel/common/block/systemagent/systemagent_def.h
@@ -18,6 +18,11 @@
#define DPR_EPM (1 << 2)
#define DPR_PRS (1 << 1)
#define DPR_SIZE_MASK 0xff0
+#define CAPID0_A 0xe4
+#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/systemagent.c b/src/soc/intel/icelake/systemagent.c
index c07fd0a..0f4ff58 100644
--- a/src/soc/intel/icelake/systemagent.c
+++ b/src/soc/intel/icelake/systemagent.c
@@ -53,3 +53,17 @@
/* Enable BIOS Reset CPL */
enable_bios_reset_cpl();
}
+
+uint32_t soc_systemagent_max_chan_capacity(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 9a4c4de..d8142ee 100644
--- a/src/soc/intel/skylake/systemagent.c
+++ b/src/soc/intel/skylake/systemagent.c
@@ -82,3 +82,17 @@
*prmrr_mask = (uint64_t) msr.hi << 32 | msr.lo;
return 0;
}
+
+uint32_t soc_systemagent_max_chan_capacity(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 8859386..42afd75 100644
--- a/src/soc/intel/tigerlake/systemagent.c
+++ b/src/soc/intel/tigerlake/systemagent.c
@@ -67,3 +67,17 @@
/* Enable BIOS Reset CPL */
enable_bios_reset_cpl();
}
+
+uint32_t soc_systemagent_max_chan_capacity(u8 capid0_a_ddrsz)
+{
+ switch (capid0_a_ddrsz) {
+ case 1:
+ return 8192;
+ case 2:
+ return 4096;
+ case 3:
+ return 2048;
+ default:
+ return 65536;
+ }
+}

To view, visit change 41334. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Change-Id: I0d8fbb512fccbd99a6cfdacadc496d8266ae4cc7
Gerrit-Change-Number: 41334
Gerrit-PatchSet: 1
Gerrit-Owner: Patrick Rudolph <patrick.rudolph@9elements.com>
Gerrit-MessageType: newchange