aboutsummaryrefslogtreecommitdiff
path: root/src/soc/intel/skylake/chip_fsp20.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/soc/intel/skylake/chip_fsp20.c')
-rw-r--r--src/soc/intel/skylake/chip_fsp20.c127
1 files changed, 127 insertions, 0 deletions
diff --git a/src/soc/intel/skylake/chip_fsp20.c b/src/soc/intel/skylake/chip_fsp20.c
index bc78586019..0ba70e08ab 100644
--- a/src/soc/intel/skylake/chip_fsp20.c
+++ b/src/soc/intel/skylake/chip_fsp20.c
@@ -19,12 +19,14 @@
#include <device/pci.h>
#include <fsp/api.h>
#include <arch/acpi.h>
+#include <arch/io.h>
#include <chip.h>
#include <compiler.h>
#include <bootstate.h>
#include <console/console.h>
#include <device/device.h>
#include <device/pci.h>
+#include <device/pci_ids.h>
#include <fsp/api.h>
#include <fsp/util.h>
#include <intelblocks/xdci.h>
@@ -39,10 +41,135 @@
#include <soc/systemagent.h>
#include <string.h>
+struct pcie_entry {
+ unsigned int devfn;
+ unsigned int func_count;
+};
+
+/*
+ * According to table 2-2 in doc#546717:
+ * PCI bus[function] ID
+ * D28:[F0 - F7] 0xA110 - 0xA117
+ * D29:[F0 - F7] 0xA118 - 0xA11F
+ * D27:[F0 - F3] 0xA167 - 0xA16A
+ */
+static const struct pcie_entry pcie_table_skl_pch_h[] = {
+ {PCH_DEVFN_PCIE1, 8},
+ {PCH_DEVFN_PCIE9, 8},
+ {PCH_DEVFN_PCIE17, 4},
+};
+
+/*
+ * According to table 2-2 in doc#564464:
+ * PCI bus[function] ID
+ * D28:[F0 - F7] 0xA290 - 0xA297
+ * D29:[F0 - F7] 0xA298 - 0xA29F
+ * D27:[F0 - F7] 0xA2E7 - 0xA2EE
+ */
+static const struct pcie_entry pcie_table_kbl_pch_h[] = {
+ {PCH_DEVFN_PCIE1, 8},
+ {PCH_DEVFN_PCIE9, 8},
+ {PCH_DEVFN_PCIE17, 8},
+};
+
+/*
+ * According to table 2-2 in doc#567995/545659:
+ * PCI bus[function] ID
+ * D28:[F0 - F7] 0x9D10 - 0x9D17
+ * D29:[F0 - F3] 0x9D18 - 0x9D1B
+ */
+static const struct pcie_entry pcie_table_skl_pch_lp[] = {
+ {PCH_DEVFN_PCIE1, 8},
+ {PCH_DEVFN_PCIE9, 4},
+};
+
+/*
+ * If the PCIe root port at function 0 is disabled,
+ * the PCIe root ports might be coalesced after FSP silicon init.
+ * The below function will swap the devfn of the first enabled device
+ * in devicetree and function 0 resides a pci device
+ * so that it won't confuse coreboot.
+ */
+static void pcie_update_device_tree(const struct pcie_entry *pcie_rp_group,
+ size_t pci_groups)
+{
+ struct device *func0;
+ unsigned int devfn, devfn0;
+ int i, group;
+ unsigned int inc = PCI_DEVFN(0, 1);
+
+ for (group = 0; group < pci_groups; group++) {
+ devfn0 = pcie_rp_group[group].devfn;
+ func0 = dev_find_slot(0, devfn0);
+ if (func0 == NULL)
+ continue;
+
+ /* No more functions if function 0 is disabled. */
+ if (pci_read_config32(func0, PCI_VENDOR_ID) == 0xffffffff)
+ continue;
+
+ devfn = devfn0 + inc;
+
+ /*
+ * Increase function by 1.
+ * Then find first enabled device to replace func0
+ * as that port was move to func0.
+ */
+ for (i = 1; i < pcie_rp_group[group].func_count;
+ i++, devfn += inc) {
+ struct device *dev = dev_find_slot(0, devfn);
+ if (dev == NULL || !dev->enabled)
+ continue;
+
+ /*
+ * Found the first enabled device in
+ * a given dev number.
+ */
+ printk(BIOS_INFO, "PCI func %d was swapped"
+ " to func 0.\n", i);
+ func0->path.pci.devfn = dev->path.pci.devfn;
+ dev->path.pci.devfn = devfn0;
+ break;
+ }
+ }
+}
+
+static void pcie_override_devicetree_after_silicon_init(void)
+{
+ uint16_t id, id_mask;
+
+ id = pci_read_config16(PCH_DEV_PCIE1, PCI_DEVICE_ID);
+ /*
+ * We may read an ID other than func 0 after FSP-S.
+ * Strip out 4 least significant bits.
+ */
+ id_mask = id & ~0xf;
+ printk(BIOS_INFO, "Override DT after FSP-S, PCH is ");
+ if (id_mask == (PCI_DEVICE_ID_INTEL_SPT_LP_PCIE_RP1 & ~0xf)) {
+ printk(BIOS_INFO, "KBL/SKL PCH-LP SKU\n");
+ pcie_update_device_tree(&pcie_table_skl_pch_lp[0],
+ ARRAY_SIZE(pcie_table_skl_pch_lp));
+ } else if (id_mask == (PCI_DEVICE_ID_INTEL_KBP_H_PCIE_RP1 & ~0xf)) {
+ printk(BIOS_INFO, "KBL PCH-H SKU\n");
+ pcie_update_device_tree(&pcie_table_kbl_pch_h[0],
+ ARRAY_SIZE(pcie_table_kbl_pch_h));
+ } else if (id_mask == (PCI_DEVICE_ID_INTEL_SPT_H_PCIE_RP1 & ~0xf)) {
+ printk(BIOS_INFO, "SKL PCH-H SKU\n");
+ pcie_update_device_tree(&pcie_table_skl_pch_h[0],
+ ARRAY_SIZE(pcie_table_skl_pch_h));
+ } else {
+ printk(BIOS_ERR, "[BUG] PCIE Root Port id 0x%x"
+ " is not found\n", id);
+ return;
+ }
+}
+
void soc_init_pre_device(void *chip_info)
{
/* Perform silicon specific init. */
fsp_silicon_init(romstage_handoff_is_resume());
+ /* swap enabled PCI ports in device tree if needed */
+ pcie_override_devicetree_after_silicon_init();
}
void soc_fsp_load(void)