diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/soc/intel/xeon_sp/Makefile.mk | 1 | ||||
-rw-r--r-- | src/soc/intel/xeon_sp/pcie_root_port.c | 91 |
2 files changed, 92 insertions, 0 deletions
diff --git a/src/soc/intel/xeon_sp/Makefile.mk b/src/soc/intel/xeon_sp/Makefile.mk index 35b998c850..4f87367c5e 100644 --- a/src/soc/intel/xeon_sp/Makefile.mk +++ b/src/soc/intel/xeon_sp/Makefile.mk @@ -16,6 +16,7 @@ ramstage-y += uncore.c reset.c util.c lpc.c spi.c ramstage.c chip_common.c ramstage-y += memmap.c pch.c lockdown.c finalize.c ramstage-y += numa.c ramstage-y += config.c +ramstage-y += pcie_root_port.c ramstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_PMC) += pmc.c pmutil.c ramstage-$(CONFIG_HAVE_ACPI_TABLES) += uncore_acpi.c acpi.c ramstage-$(CONFIG_SOC_INTEL_HAS_CXL) += uncore_acpi_cxl.c diff --git a/src/soc/intel/xeon_sp/pcie_root_port.c b/src/soc/intel/xeon_sp/pcie_root_port.c new file mode 100644 index 0000000000..fb9abde131 --- /dev/null +++ b/src/soc/intel/xeon_sp/pcie_root_port.c @@ -0,0 +1,91 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include <device/pci.h> +#include <device/pciexp.h> +#include <device/pci_ids.h> +#include <soc/acpi.h> +#include <soc/pci_devs.h> +#include <soc/ramstage.h> + +static const char *pcie_device_get_acpi_name(const struct device *dev) +{ + /* + * dev->name cannot be assigned in this routine with const struct device *, + * instead, it is set up in pcie_device_set_acpi_name ahead of time. + */ + assert(dev->name); + return dev->name; +} + +static void soc_pciexp_scan_bridge(struct device *dev) +{ + if (CONFIG(PCIEXP_HOTPLUG)) { + unsigned int pciexpos = pci_find_capability(dev, PCI_CAP_ID_PCIE); + u16 sltcap = pci_read_config16(dev, pciexpos + PCI_EXP_SLTCAP); + if (sltcap & PCI_EXP_SLTCAP_HPC) { + pciexp_hotplug_scan_bridge(dev); + return; + } + } else + pciexp_scan_bridge(dev); +} + +static void pcie_device_set_acpi_name(struct device *dev, const char *prefix) +{ + assert(prefix != NULL && strlen(prefix) == 2); + if (!prefix || strlen(prefix) != 2) + return; + + char *name = xmalloc(ACPI_NAME_BUFFER_SIZE); + uint8_t slot = PCI_SLOT(dev->path.pci.devfn); + uint8_t func = PCI_FUNC(dev->path.pci.devfn); + snprintf(name, ACPI_NAME_BUFFER_SIZE, "%s%02X", prefix, PCI_DEVFN(slot, func)); + dev->name = name; +} + +static void pcie_root_port_init(struct device *rp) +{ + if (!is_pci_bridge(rp)) + return; + + pcie_device_set_acpi_name(rp, "RP"); + + struct device *dev = NULL; + while ((dev = dev_bus_each_child(rp->downstream, dev))) { + if (!is_pci(dev)) + continue; + pcie_device_set_acpi_name(dev, "DC"); + } + + pci_dev_init(rp); +} + +static const unsigned short pcie_root_port_ids[] = { + /* + * Refer to https://pcisig.com/developers/integrators-list?field_il_comp_product_type_value=All&keys=Intel + */ + 0x352a, + 0x352b, + 0x352c, + 0x352d, + 0x347a, + 0 +}; + +static struct device_operations pcie_root_port_ops = { + .read_resources = pci_bus_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_bus_enable_resources, + .scan_bus = soc_pciexp_scan_bridge, + .reset_bus = pci_bus_reset, + .init = pcie_root_port_init, + .ops_pci = &soc_pci_ops, + .acpi_fill_ssdt = &acpigen_write_pci_root_port, + .acpi_name = &pcie_device_get_acpi_name, +}; + +static const struct pci_driver pcie_root_port_driver __pci_driver = { + .ops = &pcie_root_port_ops, + .vendor = PCI_VID_INTEL, + .devices = pcie_root_port_ids, +}; |