xref: /aosp_15_r20/external/coreboot/src/device/pci_early.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <device/pci.h>
4 #include <device/pci_ops.h>
5 #include <delay.h>
6 
pci_s_assert_secondary_reset(pci_devfn_t p2p_bridge)7 void pci_s_assert_secondary_reset(pci_devfn_t p2p_bridge)
8 {
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);
13 }
14 
pci_s_deassert_secondary_reset(pci_devfn_t p2p_bridge)15 void pci_s_deassert_secondary_reset(pci_devfn_t p2p_bridge)
16 {
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);
21 }
22 
pci_s_bridge_set_secondary(pci_devfn_t p2p_bridge,u8 secondary)23 void pci_s_bridge_set_secondary(pci_devfn_t p2p_bridge, u8 secondary)
24 {
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);
31 }
32 
pci_s_bridge_set_mmio(pci_devfn_t p2p_bridge,u32 base,u32 size)33 static void pci_s_bridge_set_mmio(pci_devfn_t p2p_bridge, u32 base, u32 size)
34 {
35 	u16 reg16;
36 
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);
42 
43 	if (!size)
44 		return;
45 
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));
49 
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);
53 }
54 
pci_s_early_mmio_window(pci_devfn_t p2p_bridge,u32 mmio_base,u32 mmio_size)55 static void pci_s_early_mmio_window(pci_devfn_t p2p_bridge, u32 mmio_base, u32 mmio_size)
56 {
57 	int timeout, ret = -1;
58 
59 	/* Secondary bus number is mostly irrelevant as we disable
60 	 * configuration transactions right after the probe.
61 	 */
62 	u8 secondary = 15;
63 	u8 dev = 0;
64 
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);
70 
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);
77 	}
78 
79 	if (timeout != 0)
80 		ret = pci_early_device_probe(secondary, dev, mmio_base);
81 
82 	/* Disable MMIO window if we found no suitable device. */
83 	if (ret)
84 		pci_s_bridge_set_mmio(p2p_bridge, 0, 0);
85 
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.
89 	 */
90 	pci_s_bridge_set_secondary(p2p_bridge, 0);
91 }
92 
pci_early_bridge_init(void)93 void pci_early_bridge_init(void)
94 {
95 	/* No PCI-to-PCI bridges are enabled yet, so the one we try to
96 	 * configure must have its primary on bus 0.
97 	 */
98 	pci_devfn_t p2p_bridge = PCI_DEV(0, CONFIG_EARLY_PCI_BRIDGE_DEVICE,
99 		CONFIG_EARLY_PCI_BRIDGE_FUNCTION);
100 
101 	pci_s_early_mmio_window(p2p_bridge, CONFIG_EARLY_PCI_MMIO_BASE, 0x4000);
102 }
103 
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.
107  */
pci_locate_device(unsigned int pci_id,pci_devfn_t dev)108 pci_devfn_t pci_locate_device(unsigned int pci_id, pci_devfn_t dev)
109 {
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;
115 	}
116 	return PCI_DEV_INVALID;
117 }
118 
pci_locate_device_on_bus(unsigned int pci_id,unsigned int bus)119 pci_devfn_t pci_locate_device_on_bus(unsigned int pci_id, unsigned int bus)
120 {
121 	pci_devfn_t dev, last;
122 
123 	dev = PCI_DEV(bus, 0, 0);
124 	last = PCI_DEV(bus, 31, 7);
125 
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;
131 	}
132 	return PCI_DEV_INVALID;
133 }
134