summaryrefslogtreecommitdiff
path: root/src/soc
diff options
context:
space:
mode:
Diffstat (limited to 'src/soc')
-rw-r--r--src/soc/intel/common/block/include/intelblocks/systemagent_server.h76
-rw-r--r--src/soc/intel/common/block/systemagent-server/Kconfig24
-rw-r--r--src/soc/intel/common/block/systemagent-server/Makefile.mk9
-rw-r--r--src/soc/intel/common/block/systemagent-server/common.c55
-rw-r--r--src/soc/intel/common/block/systemagent-server/memmap.c27
-rw-r--r--src/soc/intel/common/block/systemagent-server/systemagent.c197
-rw-r--r--src/soc/intel/common/block/systemagent-server/systemagent_early.c29
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();
+}