soc/intel/common/systemagent_server: Add server platform system agent
Intel server processors have a different system agent design, it has some differences with client platform such as (1) no BDSM and BGSM registers; (2) different alignment size and bit fields in TOLUD, TOUUD and TSEG registers. Thus this patch adds a new common block for server platform system agent. Change-Id: If32c2a6524c9d55ce7f9c3dd203bcf85cab76c2c Signed-off-by: Yuchi Chen <yuchi.chen@intel.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/83318 Reviewed-by: Shuo Liu <shuo.liu@intel.com> Reviewed-by: Angel Pons <th3fanbus@gmail.com> Reviewed-by: Lean Sheng Tan <sheng.tan@9elements.com> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
parent
7101c166fa
commit
239f7f7408
7 changed files with 417 additions and 0 deletions
|
|
@ -0,0 +1,76 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
#ifndef SOC_INTEL_COMMON_BLOCK_SA_SERVER_H
|
||||
#define SOC_INTEL_COMMON_BLOCK_SA_SERVER_H
|
||||
|
||||
#include <device/device.h>
|
||||
#include <device/pci_type.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
enum sa_server_reg {
|
||||
MMCFG_BASE_REG,
|
||||
MMCFG_LIMIT_REG,
|
||||
TSEG_BASE_REG,
|
||||
TSEG_LIMIT_REG,
|
||||
TOCM_REG,
|
||||
TOUUD_REG,
|
||||
TOLUD_REG,
|
||||
MMIO_L_REG,
|
||||
VT_BAR_REG,
|
||||
DPR_REG,
|
||||
NUM_MAP_ENTRIES, /* Must be last. */
|
||||
};
|
||||
|
||||
/**
|
||||
* SoC implementation to convert register index to SoC-specific register PCIe configuration
|
||||
* space offset.
|
||||
*/
|
||||
uint32_t sa_server_soc_reg_to_pci_offset(enum sa_server_reg reg);
|
||||
|
||||
struct sa_server_mem_map_descriptor {
|
||||
uint32_t reg_offset; /* PCI configuration space offset. */
|
||||
bool is_64_bit; /* If register is 64 bit. */
|
||||
bool is_limit; /* If lower bits should be treated as 1s or 0s but always read as 0s. */
|
||||
uint32_t alignment; /* Alignment of the address in register. Probing as PCI BAR if 0. */
|
||||
};
|
||||
|
||||
uint64_t sa_server_read_map_entry(pci_devfn_t dev,
|
||||
const struct sa_server_mem_map_descriptor *entry);
|
||||
|
||||
struct sa_server_mmio_descriptor {
|
||||
uint64_t base;
|
||||
uint64_t size;
|
||||
bool (*get_resource)(struct device *dev, uint64_t *base, uint64_t *size);
|
||||
const char *description; /* Name of the register. */
|
||||
};
|
||||
|
||||
uintptr_t sa_server_get_tseg_base(void);
|
||||
|
||||
size_t sa_server_get_tseg_size(void);
|
||||
|
||||
uint64_t sa_server_get_touud(void);
|
||||
|
||||
uintptr_t sa_server_get_tolud(void);
|
||||
|
||||
/*
|
||||
* API to determine whether system agent is on PCH domain or accelerators domains.
|
||||
*/
|
||||
bool sa_server_is_on_pch_domain(const struct device *dev);
|
||||
|
||||
/*
|
||||
* API to add MMIO resources based on `struct sa_mmio_descriptor` provided by SoC.
|
||||
*/
|
||||
void sa_server_add_mmio_resources(
|
||||
struct device *dev, int *resource_cnt,
|
||||
const struct sa_server_mmio_descriptor *sa_server_fixed_resources, size_t count);
|
||||
|
||||
/**
|
||||
* SoC call to provide all known fixed memory ranges for system agent.
|
||||
*
|
||||
* SoC function should provide fixed resource ranges in form of
|
||||
* `struct sa_server_mmio_descriptor` along with resource count.
|
||||
*/
|
||||
void sa_server_soc_add_fixed_mmio_resources(struct device *dev, int *resource_cnt);
|
||||
|
||||
#endif // SOC_INTEL_COMMON_BLOCK_SA_SERVER_H
|
||||
24
src/soc/intel/common/block/systemagent-server/Kconfig
Normal file
24
src/soc/intel/common/block/systemagent-server/Kconfig
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
## SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
config SOC_INTEL_COMMON_BLOCK_SA_SERVER
|
||||
bool
|
||||
help
|
||||
Intel Server Processor common System Agent support
|
||||
|
||||
if SOC_INTEL_COMMON_BLOCK_SA_SERVER
|
||||
|
||||
config TOUUD_LIMIT
|
||||
bool
|
||||
default y
|
||||
help
|
||||
Specify if the lower bits in top of upper usable DRAM register should be
|
||||
treated as 1s.
|
||||
|
||||
config TOLUD_LIMIT
|
||||
bool
|
||||
default y
|
||||
help
|
||||
Specify if the lower bits in top of lower usable DRAM register should be
|
||||
treated as 1s.
|
||||
|
||||
endif
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
## SPDX-License-Identifier: GPL-2.0-only
|
||||
romstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_SA_SERVER) += common.c
|
||||
romstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_SA_SERVER) += memmap.c
|
||||
romstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_SA_SERVER) += systemagent_early.c
|
||||
|
||||
ramstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_SA_SERVER) += common.c
|
||||
ramstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_SA_SERVER) += memmap.c
|
||||
ramstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_SA_SERVER) += systemagent.c
|
||||
ramstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_SA_SERVER) += systemagent_early.c
|
||||
55
src/soc/intel/common/block/systemagent-server/common.c
Normal file
55
src/soc/intel/common/block/systemagent-server/common.c
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
#define __SIMPLE_DEVICE__
|
||||
|
||||
#include <device/pci_ops.h>
|
||||
#include <intelblocks/systemagent_server.h>
|
||||
|
||||
static uint32_t pci_moving_config32(pci_devfn_t dev, unsigned int reg)
|
||||
{
|
||||
uint32_t value, ones, zeroes;
|
||||
|
||||
value = pci_read_config32(dev, reg);
|
||||
|
||||
pci_write_config32(dev, reg, 0xffffffff);
|
||||
ones = pci_read_config32(dev, reg);
|
||||
|
||||
pci_write_config32(dev, reg, 0x00000000);
|
||||
zeroes = pci_read_config32(dev, reg);
|
||||
|
||||
pci_write_config32(dev, reg, value);
|
||||
|
||||
return ones ^ zeroes;
|
||||
}
|
||||
|
||||
uint64_t sa_server_read_map_entry(pci_devfn_t dev,
|
||||
const struct sa_server_mem_map_descriptor *entry)
|
||||
{
|
||||
uint64_t value = 0;
|
||||
uint32_t alignment = entry->alignment;
|
||||
|
||||
if (entry->is_64_bit) {
|
||||
value = pci_s_read_config32(dev, entry->reg_offset + 4);
|
||||
value <<= 32;
|
||||
}
|
||||
|
||||
value |= pci_s_read_config32(dev, entry->reg_offset);
|
||||
|
||||
/**
|
||||
* Probe the alignment if not provided, promising the lower bits are read only, otherwise
|
||||
* SoC should give a initial value.
|
||||
*/
|
||||
if (!alignment)
|
||||
alignment = ~pci_moving_config32(dev, entry->reg_offset) + 1;
|
||||
|
||||
/**
|
||||
* If register stores the limit address, where lower bits are read as 0s but treated as 1s,
|
||||
* restore the lower bits and align it up.
|
||||
*/
|
||||
if (entry->is_limit)
|
||||
value = ALIGN_UP(value + alignment - 1, alignment);
|
||||
else
|
||||
value = ALIGN_DOWN(value, alignment);
|
||||
|
||||
return value;
|
||||
}
|
||||
27
src/soc/intel/common/block/systemagent-server/memmap.c
Normal file
27
src/soc/intel/common/block/systemagent-server/memmap.c
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
#include <arch/romstage.h>
|
||||
#include <console/console.h>
|
||||
#include <cpu/x86/smm.h>
|
||||
#include <intelblocks/systemagent_server.h>
|
||||
|
||||
void smm_region(uintptr_t *start, size_t *size)
|
||||
{
|
||||
*start = sa_server_get_tseg_base();
|
||||
*size = sa_server_get_tseg_size();
|
||||
}
|
||||
|
||||
void fill_postcar_frame(struct postcar_frame *pcf)
|
||||
{
|
||||
/*
|
||||
* `postcar_mtrr_setup()` will be skipped if using FSP to tear down CAR.
|
||||
*/
|
||||
if (!CONFIG(NO_FSP_TEMP_RAM_EXIT))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Add MTRR for ramstage, TSEG and extended BIOS region if exiting CAR without FSP is supporated.
|
||||
*/
|
||||
_Static_assert(!CONFIG(NO_FSP_TEMP_RAM_EXIT),
|
||||
"NO_FSP_TEMP_RAM_EXIT is not supportted currently!");
|
||||
}
|
||||
197
src/soc/intel/common/block/systemagent-server/systemagent.c
Normal file
197
src/soc/intel/common/block/systemagent-server/systemagent.c
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
#include <arch/vga.h>
|
||||
#include <commonlib/bsd/helpers.h>
|
||||
#include <device/pci.h>
|
||||
#include <device/pci_ids.h>
|
||||
#include <device/pci_type.h>
|
||||
#include <fsp/util.h>
|
||||
#include <intelblocks/acpi.h>
|
||||
#include <intelblocks/systemagent_server.h>
|
||||
#include <security/intel/txt/txt_register.h>
|
||||
#include <soc/pci_devs.h>
|
||||
#include <soc/systemagent.h>
|
||||
|
||||
__weak void sa_server_soc_add_fixed_mmio_resources(struct device *dev, int *resource_cnt)
|
||||
{
|
||||
}
|
||||
|
||||
__weak unsigned long sa_write_acpi_tables(const struct device *dev, unsigned long current,
|
||||
struct acpi_rsdp *rsdp)
|
||||
{
|
||||
return current;
|
||||
}
|
||||
|
||||
uint64_t sa_server_get_touud(void)
|
||||
{
|
||||
struct sa_server_mem_map_descriptor touud_descriptor = {
|
||||
.reg_offset = sa_server_soc_reg_to_pci_offset(TOUUD_REG),
|
||||
.is_64_bit = true,
|
||||
.is_limit = CONFIG(TOUUD_LIMIT),
|
||||
};
|
||||
|
||||
return sa_server_read_map_entry(PCI_BDF(SA_DEV_ROOT), &touud_descriptor);
|
||||
}
|
||||
|
||||
uintptr_t sa_server_get_tolud(void)
|
||||
{
|
||||
struct sa_server_mem_map_descriptor tolud_descriptor = {
|
||||
.reg_offset = sa_server_soc_reg_to_pci_offset(TOLUD_REG),
|
||||
.is_limit = CONFIG(TOLUD_LIMIT),
|
||||
};
|
||||
|
||||
return sa_server_read_map_entry(PCI_BDF(SA_DEV_ROOT), &tolud_descriptor);
|
||||
}
|
||||
|
||||
bool sa_server_is_on_pch_domain(const struct device *dev)
|
||||
{
|
||||
return is_dev_on_domain0(dev);
|
||||
}
|
||||
|
||||
void sa_server_add_mmio_resources(struct device *dev, int *resource_cnt,
|
||||
const struct sa_server_mmio_descriptor *mmio_descriptors,
|
||||
size_t count)
|
||||
{
|
||||
int index = *resource_cnt;
|
||||
uint64_t base, size;
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
base = mmio_descriptors[i].base;
|
||||
size = mmio_descriptors[i].size;
|
||||
|
||||
/**
|
||||
* Prefer to using `base` and `size` to retrieving them from `get_resource()` since
|
||||
* some MMIO resources may not stored in any registers and registers may hold an
|
||||
* incorrect value.
|
||||
*/
|
||||
if (!size)
|
||||
if (!mmio_descriptors[i].get_resource ||
|
||||
!mmio_descriptors[i].get_resource(dev, &base, &size))
|
||||
continue;
|
||||
|
||||
printk(BIOS_DEBUG,
|
||||
"SA MMIO resource: %-8s -> base = 0x%08llx, size = 0x%08llx\n",
|
||||
mmio_descriptors[i].description, base, size);
|
||||
|
||||
mmio_range(dev, index++, base, size);
|
||||
}
|
||||
|
||||
*resource_cnt = index;
|
||||
}
|
||||
|
||||
/*
|
||||
* Host Memory Map:
|
||||
* +--------------------------+
|
||||
* | MMIOH |
|
||||
* | (relocatable) |
|
||||
* +--------------------------+ TOUUD
|
||||
* | High DRAM |
|
||||
* +--------------------------+ 4GB (0x1_0000_0000)
|
||||
* | Firmware |
|
||||
* +--------------------------+ 0xFF00_0000
|
||||
* | Reserved |
|
||||
* +--------------------------+ 0xFEF0_0000
|
||||
* | Local xAPIC |
|
||||
* +--------------------------+ 0xFEE0_0000
|
||||
* | HPET, Intel TXT, TPM |
|
||||
* +--------------------------+ 0xFED0_0000
|
||||
* | I/O xAPIC |
|
||||
* +--------------------------+ 0xFEC0_0000
|
||||
* | Reserved |
|
||||
* +--------------------------+ MMIOL
|
||||
* | MMIOL |
|
||||
* | (relocatable) |
|
||||
* +--------------------------+
|
||||
* | PCIe MMCFG |
|
||||
* | (relocatable) |
|
||||
* +--------------------------+ TOLUD
|
||||
* | MESEG (relocatable) |
|
||||
* +--------------------------+
|
||||
* | TSEG (relocatable) |
|
||||
* +--------------------------+
|
||||
* | DMA Protected Range |
|
||||
* | (relocatable) |
|
||||
* +--------------------------+ DPR base, 1M aligned
|
||||
* | Unused memory (possible) |
|
||||
* +--------------------------+ cbmem_top
|
||||
* | FSP Bootloader TOLUM |
|
||||
* +--------------------------+
|
||||
* | FSP Reserved |
|
||||
* +--------------------------+ top_of_ram
|
||||
* | Low DRAM |
|
||||
* | Legacy ISA hole |
|
||||
* +--------------------------+ 0x10_0000 (1MB)
|
||||
* | C, D, E, F segments |
|
||||
* +--------------------------+ 0xC_0000
|
||||
* | VGA (TSEG, MESEG) |
|
||||
* +--------------------------+ 0xA_0000
|
||||
* | DOS Range |
|
||||
* +--------------------------+ 0
|
||||
*/
|
||||
static void sa_server_add_dram_resources(struct device *dev, int *resource_cnt)
|
||||
{
|
||||
int index = *resource_cnt;
|
||||
|
||||
/* 0 - > 0xa0000 */
|
||||
ram_from_to(dev, index++, 0, 0xa0000);
|
||||
|
||||
/* 0xa0000 - > 0xc0000 */
|
||||
mmio_range(dev, index++, VGA_MMIO_BASE, VGA_MMIO_SIZE);
|
||||
|
||||
/* 0xc0000 - > 1MB */
|
||||
reserved_ram_from_to(dev, index++, 0xc0000, 1 * MiB);
|
||||
|
||||
/* 1MB -> top_of_ram (FSP reserved base) */
|
||||
struct range_entry fsp_mem;
|
||||
fsp_find_reserved_memory(&fsp_mem);
|
||||
uint32_t top_of_ram = range_entry_base(&fsp_mem);
|
||||
ram_from_to(dev, index++, 1 * MiB, top_of_ram);
|
||||
|
||||
/* top_of_ram -> cbmem_top, including FSP reserved and bootloader TOLUM. */
|
||||
ram_from_to(dev, index++, top_of_ram, cbmem_top());
|
||||
|
||||
/* Mark cbmem_top to TOLUD as reserved, SoC should provide more details for this ranges. */
|
||||
reserved_ram_from_to(dev, index++, cbmem_top(), sa_server_get_tolud());
|
||||
|
||||
/* 4GB -> TOUUD */
|
||||
upper_ram_end(dev, index++, sa_server_get_touud());
|
||||
|
||||
*resource_cnt = index;
|
||||
}
|
||||
|
||||
static void sa_server_read_resources(struct device *dev)
|
||||
{
|
||||
int index = 0;
|
||||
|
||||
pci_dev_read_resources(dev);
|
||||
|
||||
/*
|
||||
* Only add DRAM resource when calling from PCH domain.
|
||||
*/
|
||||
if (sa_server_is_on_pch_domain(dev))
|
||||
sa_server_add_dram_resources(dev, &index);
|
||||
|
||||
/* Add all SoC fixed MMIO resources. */
|
||||
sa_server_soc_add_fixed_mmio_resources(dev, &index);
|
||||
}
|
||||
|
||||
struct device_operations systemagent_server_ops = {
|
||||
.read_resources = sa_server_read_resources,
|
||||
.set_resources = pci_dev_set_resources,
|
||||
.enable_resources = pci_dev_enable_resources,
|
||||
.ops_pci = &pci_dev_ops_pci,
|
||||
#if CONFIG(HAVE_ACPI_TABLES)
|
||||
.write_acpi_tables = sa_write_acpi_tables,
|
||||
#endif
|
||||
};
|
||||
|
||||
static const unsigned short systemagent_server_ids[] = {
|
||||
PCI_DID_INTEL_SNR_ID,
|
||||
0
|
||||
};
|
||||
|
||||
static const struct pci_driver systemagent_server_driver __pci_driver = {
|
||||
.ops = &systemagent_server_ops,
|
||||
.vendor = PCI_VID_INTEL,
|
||||
.devices = systemagent_server_ids
|
||||
};
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
#define __SIMPLE_DEVICE__
|
||||
|
||||
#include <commonlib/bsd/helpers.h>
|
||||
#include <device/pci_ops.h>
|
||||
#include <intelblocks/systemagent_server.h>
|
||||
#include <soc/pci_devs.h>
|
||||
#include <soc/systemagent.h>
|
||||
|
||||
uintptr_t sa_server_get_tseg_base(void)
|
||||
{
|
||||
struct sa_server_mem_map_descriptor tseg_descriptor = {
|
||||
.reg_offset = sa_server_soc_reg_to_pci_offset(TSEG_BASE_REG),
|
||||
};
|
||||
|
||||
return sa_server_read_map_entry(SA_DEV_ROOT, &tseg_descriptor);
|
||||
}
|
||||
|
||||
size_t sa_server_get_tseg_size(void)
|
||||
{
|
||||
struct sa_server_mem_map_descriptor tseg_descriptor = {
|
||||
.reg_offset = sa_server_soc_reg_to_pci_offset(TSEG_LIMIT_REG),
|
||||
.is_limit = true,
|
||||
};
|
||||
|
||||
return sa_server_read_map_entry(SA_DEV_ROOT, &tseg_descriptor) -
|
||||
sa_server_get_tseg_base();
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue