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 <patrick.rudolph@9elements.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/41334
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net>
Reviewed-by: Christian Walter <christian.walter@9elements.com>
Reviewed-by: Philipp Deppenwiese <zaolin.daisuki@gmail.com>
This commit is contained in:
Patrick Rudolph 2020-05-12 16:04:47 +02:00 committed by Patrick Rudolph
parent 78e8db1eeb
commit bf72dcbd2f
9 changed files with 99 additions and 4 deletions

View file

@ -88,3 +88,9 @@ int soc_get_uncore_prmmr_base_and_mask(uint64_t *prmrr_base,
return 0; 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;
}

View file

@ -73,3 +73,17 @@ void soc_systemagent_init(struct device *dev)
soc_config = &config->power_limits_config; soc_config = &config->power_limits_config;
set_power_limits(MOBILE_SKU_PL1_TIME_SEC, soc_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;
}
}

View file

@ -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 /* SoC specific APIs to get UNCORE PRMRR base and mask values
* returns 0, if able to get base and mask values; otherwise returns -1 */ * 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); 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 */ #endif /* SOC_INTEL_COMMON_BLOCK_SA_H */

View file

@ -41,6 +41,11 @@ __weak unsigned long sa_write_acpi_tables(const struct device *dev,
return current; 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 * Add all known fixed MMIO ranges that hang off the host bridge/memory
* controller device. * controller device.
@ -258,11 +263,27 @@ static void systemagent_read_resources(struct device *dev)
} }
#if CONFIG(GENERATE_SMBIOS_TABLES) #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, static int sa_smbios_write_type_16(struct device *dev, int *handle,
unsigned long *current) unsigned long *current)
{ {
struct smbios_type16 *t = (struct smbios_type16 *)*current; struct smbios_type16 *t = (struct smbios_type16 *)*current;
int len = sizeof(struct smbios_type16); int len = sizeof(struct smbios_type16);
const uint32_t capida = pci_read_config32(dev, CAPID0_A);
struct memory_info *meminfo; struct memory_info *meminfo;
meminfo = cbmem_find(CBMEM_ID_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->length = len - 2;
t->location = MEMORY_ARRAY_LOCATION_SYSTEM_BOARD; t->location = MEMORY_ARRAY_LOCATION_SYSTEM_BOARD;
t->use = MEMORY_ARRAY_USE_SYSTEM; t->use = MEMORY_ARRAY_USE_SYSTEM;
/* TBD, meminfo hob have information about ECC */ t->memory_error_correction = sa_supports_ecc(capida) ? MEMORY_ARRAY_ECC_SINGLE_BIT :
t->memory_error_correction = MEMORY_ARRAY_ECC_NONE; MEMORY_ARRAY_ECC_NONE;
/* no error information handle available */ /* no error information handle available */
t->memory_error_information_handle = 0xFFFE; t->memory_error_information_handle = 0xFFFE;
t->maximum_capacity = 32 * (GiB / KiB); /* 32GB as default */ t->maximum_capacity = soc_systemagent_max_chan_capacity_mib(CAPID_DDRSZ(capida)) *
t->number_of_memory_devices = meminfo->dimm_cnt; sa_number_of_channels(capida) * (MiB / KiB);
t->number_of_memory_devices = sa_slots_per_channel(capida) *
sa_number_of_channels(capida);
*current += len; *current += len;
*handle += 1; *handle += 1;

View file

@ -17,6 +17,11 @@
#define DPR_EPM (1 << 2) #define DPR_EPM (1 << 2)
#define DPR_PRS (1 << 1) #define DPR_PRS (1 << 1)
#define DPR_SIZE_MASK 0xff0 #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_64MB 2
#define PCIEXBAR_LENGTH_128MB 1 #define PCIEXBAR_LENGTH_128MB 1

View file

@ -15,6 +15,7 @@
#define D_LCK (1 << 4) #define D_LCK (1 << 4)
#define G_SMRAME (1 << 3) #define G_SMRAME (1 << 3)
#define C_BASE_SEG ((0 << 2) | (1 << 1) | (0 << 0)) #define C_BASE_SEG ((0 << 2) | (1 << 1) | (0 << 0))
#define CAPID0_A 0xe4
#define BIOS_RESET_CPL 0x5da8 #define BIOS_RESET_CPL 0x5da8
#define EDRAMBAR 0x5408 #define EDRAMBAR 0x5408

View file

@ -52,3 +52,17 @@ void soc_systemagent_init(struct device *dev)
/* Enable BIOS Reset CPL */ /* Enable BIOS Reset CPL */
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;
}
}

View file

@ -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; *prmrr_mask = (uint64_t) msr.hi << 32 | msr.lo;
return 0; 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;
}
}

View file

@ -67,3 +67,17 @@ void soc_systemagent_init(struct device *dev)
soc_config = &config->power_limits_config; soc_config = &config->power_limits_config;
set_power_limits(MOBILE_SKU_PL1_TIME_SEC, soc_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;
}
}