diff options
Diffstat (limited to 'src/soc/intel')
7 files changed, 417 insertions, 0 deletions
diff --git a/src/soc/intel/common/block/include/intelblocks/systemagent_server.h b/src/soc/intel/common/block/include/intelblocks/systemagent_server.h new file mode 100644 index 0000000000..7623282698 --- /dev/null +++ b/src/soc/intel/common/block/include/intelblocks/systemagent_server.h @@ -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 diff --git a/src/soc/intel/common/block/systemagent-server/Kconfig b/src/soc/intel/common/block/systemagent-server/Kconfig new file mode 100644 index 0000000000..2f84b632c8 --- /dev/null +++ b/src/soc/intel/common/block/systemagent-server/Kconfig @@ -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 diff --git a/src/soc/intel/common/block/systemagent-server/Makefile.mk b/src/soc/intel/common/block/systemagent-server/Makefile.mk new file mode 100644 index 0000000000..497c687653 --- /dev/null +++ b/src/soc/intel/common/block/systemagent-server/Makefile.mk @@ -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 diff --git a/src/soc/intel/common/block/systemagent-server/common.c b/src/soc/intel/common/block/systemagent-server/common.c new file mode 100644 index 0000000000..a564f3be1d --- /dev/null +++ b/src/soc/intel/common/block/systemagent-server/common.c @@ -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; +} diff --git a/src/soc/intel/common/block/systemagent-server/memmap.c b/src/soc/intel/common/block/systemagent-server/memmap.c new file mode 100644 index 0000000000..6fc14a05ae --- /dev/null +++ b/src/soc/intel/common/block/systemagent-server/memmap.c @@ -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!"); +} diff --git a/src/soc/intel/common/block/systemagent-server/systemagent.c b/src/soc/intel/common/block/systemagent-server/systemagent.c new file mode 100644 index 0000000000..e0c9d4d2cb --- /dev/null +++ b/src/soc/intel/common/block/systemagent-server/systemagent.c @@ -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 +}; diff --git a/src/soc/intel/common/block/systemagent-server/systemagent_early.c b/src/soc/intel/common/block/systemagent-server/systemagent_early.c new file mode 100644 index 0000000000..5cbadfc4ee --- /dev/null +++ b/src/soc/intel/common/block/systemagent-server/systemagent_early.c @@ -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(); +} |