Xeon-SP boards: Factor out OCP VPD `get_cxl_mode()` impl
[coreboot2.git] / src / device / pci_early.c
blob86278f9222ffcbeff61ade550bfbbd60b1cb3a3e
1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <device/pci.h>
4 #include <device/pci_ops.h>
5 #include <delay.h>
7 void pci_s_assert_secondary_reset(pci_devfn_t p2p_bridge)
9 u16 reg16;
10 reg16 = pci_s_read_config16(p2p_bridge, PCI_BRIDGE_CONTROL);
11 reg16 |= PCI_BRIDGE_CTL_BUS_RESET;
12 pci_s_write_config16(p2p_bridge, PCI_BRIDGE_CONTROL, reg16);
15 void pci_s_deassert_secondary_reset(pci_devfn_t p2p_bridge)
17 u16 reg16;
18 reg16 = pci_s_read_config16(p2p_bridge, PCI_BRIDGE_CONTROL);
19 reg16 &= ~PCI_BRIDGE_CTL_BUS_RESET;
20 pci_s_write_config16(p2p_bridge, PCI_BRIDGE_CONTROL, reg16);
23 void pci_s_bridge_set_secondary(pci_devfn_t p2p_bridge, u8 secondary)
25 /* Disable config transaction forwarding. */
26 pci_s_write_config8(p2p_bridge, PCI_SECONDARY_BUS, 0x00);
27 pci_s_write_config8(p2p_bridge, PCI_SUBORDINATE_BUS, 0x00);
28 /* Enable config transaction forwarding. */
29 pci_s_write_config8(p2p_bridge, PCI_SECONDARY_BUS, secondary);
30 pci_s_write_config8(p2p_bridge, PCI_SUBORDINATE_BUS, secondary);
33 static void pci_s_bridge_set_mmio(pci_devfn_t p2p_bridge, u32 base, u32 size)
35 u16 reg16;
37 /* Disable MMIO window behind the bridge. */
38 reg16 = pci_s_read_config16(p2p_bridge, PCI_COMMAND);
39 reg16 &= ~PCI_COMMAND_MEMORY;
40 pci_s_write_config16(p2p_bridge, PCI_COMMAND, reg16);
41 pci_s_write_config32(p2p_bridge, PCI_MEMORY_BASE, 0x10);
43 if (!size)
44 return;
46 /* Enable MMIO window behind the bridge. */
47 pci_s_write_config32(p2p_bridge, PCI_MEMORY_BASE,
48 ((base + size - 1) & 0xfff00000) | ((base >> 16) & 0xfff0));
50 reg16 = pci_s_read_config16(p2p_bridge, PCI_COMMAND);
51 reg16 |= PCI_COMMAND_MEMORY;
52 pci_s_write_config16(p2p_bridge, PCI_COMMAND, reg16);
55 static void pci_s_early_mmio_window(pci_devfn_t p2p_bridge, u32 mmio_base, u32 mmio_size)
57 int timeout, ret = -1;
59 /* Secondary bus number is mostly irrelevant as we disable
60 * configuration transactions right after the probe.
62 u8 secondary = 15;
63 u8 dev = 0;
65 /* Enable configuration and MMIO over bridge. */
66 pci_s_assert_secondary_reset(p2p_bridge);
67 pci_s_deassert_secondary_reset(p2p_bridge);
68 pci_s_bridge_set_secondary(p2p_bridge, secondary);
69 pci_s_bridge_set_mmio(p2p_bridge, mmio_base, mmio_size);
71 for (timeout = 20000; timeout; timeout--) {
72 pci_devfn_t dbg_dev = PCI_DEV(secondary, dev, 0);
73 u32 id = pci_s_read_config32(dbg_dev, PCI_VENDOR_ID);
74 if (id != 0 && id != 0xffffffff && id != 0xffff0001)
75 break;
76 udelay(10);
79 if (timeout != 0)
80 ret = pci_early_device_probe(secondary, dev, mmio_base);
82 /* Disable MMIO window if we found no suitable device. */
83 if (ret)
84 pci_s_bridge_set_mmio(p2p_bridge, 0, 0);
86 /* Resource allocator will reconfigure bridges and secondary bus
87 * number may change. Thus early device cannot reliably use config
88 * transactions from here on, so we may as well disable them.
90 pci_s_bridge_set_secondary(p2p_bridge, 0);
93 void pci_early_bridge_init(void)
95 /* No PCI-to-PCI bridges are enabled yet, so the one we try to
96 * configure must have its primary on bus 0.
98 pci_devfn_t p2p_bridge = PCI_DEV(0, CONFIG_EARLY_PCI_BRIDGE_DEVICE,
99 CONFIG_EARLY_PCI_BRIDGE_FUNCTION);
101 pci_s_early_mmio_window(p2p_bridge, CONFIG_EARLY_PCI_MMIO_BASE, 0x4000);
104 /* FIXME: A lot of issues using the following, please avoid.
105 * Assumes 256 PCI buses, scans them all even when PCI bridges are still
106 * disabled. Probes all functions even if 0 is not present.
108 pci_devfn_t pci_locate_device(unsigned int pci_id, pci_devfn_t dev)
110 for (; dev <= PCI_DEV(255, 31, 7); dev += PCI_DEV(0, 0, 1)) {
111 unsigned int id;
112 id = pci_s_read_config32(dev, 0);
113 if (id == pci_id)
114 return dev;
116 return PCI_DEV_INVALID;
119 pci_devfn_t pci_locate_device_on_bus(unsigned int pci_id, unsigned int bus)
121 pci_devfn_t dev, last;
123 dev = PCI_DEV(bus, 0, 0);
124 last = PCI_DEV(bus, 31, 7);
126 for (; dev <= last; dev += PCI_DEV(0, 0, 1)) {
127 unsigned int id;
128 id = pci_s_read_config32(dev, 0);
129 if (id == pci_id)
130 return dev;
132 return PCI_DEV_INVALID;