drivers/wifi: Remove unnecessary data structure copy
[coreboot2.git] / src / soc / cavium / cn81xx / ecam0.c
blobdb5090f5dfaa36d9004c5e7ca0f9ad2fbda6a9a1
1 /* SPDX-License-Identifier: GPL-2.0-only */
3 /*
4 * Derived from Cavium's BSD-3 Clause OCTEONTX-SDK-6.2.0.
5 */
7 #include <console/console.h>
8 #include <device/mmio.h>
9 #include <device/pci.h>
10 #include <device/pci_ops.h>
11 #include <soc/addressmap.h>
12 #include <soc/cavium/common/pci/chip.h>
13 #include <soc/ecam.h>
15 #define CAVM_PCCPF_XXX_VSEC_CTL 0x108
16 #define CAVM_PCCPF_XXX_VSEC_SCTL 0x10c
19 * Hide PCI device function on BUS 1 in non secure world.
21 static void disable_func(unsigned int devfn)
23 u64 *addr;
24 printk(BIOS_DEBUG, "PCI: 01:%02x.%x is secure\n", devfn >> 3,
25 devfn & 7);
27 /* disable function */
28 addr = (void *)ECAM0_RSLX_SDIS;
29 u64 reg = read64(&addr[devfn]);
30 reg &= ~3;
31 reg |= 2;
32 write64(&addr[devfn], reg);
36 * Show PCI device function on BUS 1 in non secure world.
38 static void enable_func(unsigned int devfn)
40 u64 *addr;
42 printk(BIOS_DEBUG, "PCI: 01:%02x.%x is insecure\n", devfn >> 3,
43 devfn & 7);
45 /* enable function */
46 addr = (void *)ECAM0_RSLX_SDIS;
47 u64 reg = read64(&addr[devfn]);
48 reg &= ~3;
49 write64(&addr[devfn], reg);
51 addr = (void *)ECAM0_RSLX_NSDIS;
52 reg = read64(&addr[devfn]);
53 reg &= ~1;
54 write64(&addr[devfn], reg);
58 * Hide PCI device on BUS 0 in non secure world.
60 static void disable_device(unsigned int dev)
62 u64 *addr;
64 printk(BIOS_DEBUG, "PCI: 00:%02x.0 is secure\n", dev);
66 /* disable function */
67 addr = (void *)ECAM0_DEVX_SDIS;
68 u64 reg = read64(&addr[dev]);
69 reg &= ~3;
70 write64(&addr[dev], reg);
72 addr = (void *)ECAM0_DEVX_NSDIS;
73 reg = read64(&addr[dev]);
74 reg |= 1;
75 write64(&addr[dev], reg);
79 * Show PCI device on BUS 0 in non secure world.
81 static void enable_device(unsigned int dev)
83 u64 *addr;
85 printk(BIOS_DEBUG, "PCI: 00:%02x.0 is insecure\n", dev);
87 /* enable function */
88 addr = (void *)ECAM0_DEVX_SDIS;
89 u64 reg = read64(&addr[dev]);
90 reg &= ~3;
91 write64(&addr[dev], reg);
93 addr = (void *)ECAM0_DEVX_NSDIS;
94 reg = read64(&addr[dev]);
95 reg &= ~1;
96 write64(&addr[dev], reg);
99 static void ecam0_read_resources(struct device *dev)
101 /* There are no dynamic PCI resources on Cavium SoC */
104 static void ecam0_fix_missing_devices(struct bus *link)
106 size_t i;
109 * Cavium thinks it's a good idea to violate the PCI spec.
110 * Disabled multi-function PCI devices might have active functions.
111 * Add devices here manually, as coreboot's PCI allocator won't find
112 * them otherwise...
114 for (i = 0; i <= PCI_DEVFN(0x1f, 7); i++) {
115 struct device_path pci_path;
116 struct device *child;
118 pci_path.type = DEVICE_PATH_PCI;
119 pci_path.pci.devfn = i;
121 child = find_dev_path(link, &pci_path);
122 if (!child)
123 pci_probe_dev(NULL, link, i);
128 * pci_enable_msix - configure device's MSI-X capability structure
129 * @dev: pointer to the pci_dev data structure of MSI-X device function
130 * @entries: pointer to an array of MSI-X entries
131 * @nvec: number of MSI-X irqs requested for allocation by device driver
133 * Setup the MSI-X capability structure of device function with the number
134 * of requested irqs upon its software driver call to request for
135 * MSI-X mode enabled on its hardware device function. A return of zero
136 * indicates the successful configuration of MSI-X capability structure.
137 * A return of < 0 indicates a failure.
138 * Or a return of > 0 indicates that driver request is exceeding the number
139 * of irqs or MSI-X vectors available. Driver should use the returned value to
140 * re-send its request.
142 static size_t ecam0_pci_enable_msix(struct device *dev,
143 struct msix_entry *entries, size_t nvec)
145 struct msix_entry *msixtable;
146 u32 offset;
147 u8 bar_idx;
148 u64 bar;
149 size_t nr_entries;
150 size_t i;
151 u16 control;
153 if (!entries) {
154 printk(BIOS_ERR, "%s: No entries specified\n", __func__);
155 return -1;
158 const size_t pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
159 if (!pos) {
160 printk(BIOS_ERR, "%s: Device not MSI-X capable\n",
161 dev_path(dev));
162 return -1;
164 nr_entries = pci_msix_table_size(dev);
165 if (nvec > nr_entries) {
166 printk(BIOS_ERR, "%s: Specified to many table entries\n",
167 dev_path(dev));
168 return nr_entries;
171 /* Ensure MSI-X is disabled while it is set up */
172 control = pci_read_config16(dev, pos + PCI_MSIX_FLAGS);
173 control &= ~PCI_MSIX_FLAGS_ENABLE;
174 pci_write_config16(dev, pos + PCI_MSIX_FLAGS, control);
176 /* Find MSI-X table region */
177 offset = 0;
178 bar_idx = 0;
179 if (pci_msix_table_bar(dev, &offset, &bar_idx)) {
180 printk(BIOS_ERR, "%s: Failed to find MSI-X entry\n",
181 dev_path(dev));
182 return -1;
184 bar = ecam0_get_bar_val(pcidev_bdf(dev), bar_idx);
185 if (!bar) {
186 printk(BIOS_ERR, "%s: Failed to find MSI-X bar\n",
187 dev_path(dev));
188 return -1;
190 msixtable = (struct msix_entry *)((void *)bar + offset);
193 * Some devices require MSI-X to be enabled before we can touch the
194 * MSI-X registers. We need to mask all the vectors to prevent
195 * interrupts coming in before they're fully set up.
197 control |= PCI_MSIX_FLAGS_MASKALL | PCI_MSIX_FLAGS_ENABLE;
198 pci_write_config16(dev, pos + PCI_MSIX_FLAGS, control);
200 for (i = 0; i < nvec; i++) {
201 write64(&msixtable[i].addr, entries[i].addr);
202 write32(&msixtable[i].data, entries[i].data);
203 write32(&msixtable[i].vec_control, entries[i].vec_control);
206 control &= ~PCI_MSIX_FLAGS_MASKALL;
207 pci_write_config16(dev, pos + PCI_MSIX_FLAGS, control);
209 return 0;
212 static void ecam0_init(struct device *dev)
214 struct soc_cavium_common_pci_config *config;
215 struct device *child, *child_last;
216 size_t i;
217 u32 reg32;
219 printk(BIOS_INFO, "ECAM0: init\n");
220 const struct device *bridge = pcidev_on_root(1, 0);
221 if (!bridge) {
222 printk(BIOS_INFO, "ECAM0: ERROR: PCI 00:01.0 not found.\n");
223 return;
226 * Search for missing devices on BUS 1.
227 * Only required for ARI capability programming.
229 ecam0_fix_missing_devices(bridge->downstream);
231 /* Program secure ARI capability on bus 1 */
232 child_last = NULL;
233 for (i = 0; i <= PCI_DEVFN(0x1f, 7); i++) {
234 child = pcidev_path_behind(bridge->downstream, i);
235 if (!child || !child->enabled)
236 continue;
238 if (child_last) {
239 /* Program ARI capability of the previous device */
240 reg32 = pci_read_config32(child_last,
241 CAVM_PCCPF_XXX_VSEC_SCTL);
242 reg32 &= ~(0xffU << 24);
243 reg32 |= child->path.pci.devfn << 24;
244 pci_write_config32(child_last, CAVM_PCCPF_XXX_VSEC_SCTL,
245 reg32);
247 child_last = child;
250 /* Program insecure ARI capability on bus 1 */
251 child_last = NULL;
252 for (i = 0; i <= PCI_DEVFN(0x1f, 7); i++) {
253 child = pcidev_path_behind(bridge->downstream, i);
254 if (!child)
255 continue;
256 config = child->chip_info;
257 if (!child->enabled || (config && config->secure))
258 continue;
260 if (child_last) {
261 /* Program ARI capability of the previous device */
262 reg32 = pci_read_config32(child_last,
263 CAVM_PCCPF_XXX_VSEC_CTL);
264 reg32 &= ~(0xffU << 24);
265 reg32 |= child->path.pci.devfn << 24;
266 pci_write_config32(child_last, CAVM_PCCPF_XXX_VSEC_CTL,
267 reg32);
269 child_last = child;
272 /* Enable / disable devices on bus 0 */
273 for (i = 0; i <= 0x1f; i++) {
274 child = pcidev_on_root(i, 0);
275 config = child ? child->chip_info : NULL;
276 if (child && child->enabled && config && !config->secure)
277 enable_device(i);
278 else
279 disable_device(i);
282 /* Enable / disable devices and functions on bus 1 */
283 for (i = 0; i <= PCI_DEVFN(0x1f, 7); i++) {
284 child = pcidev_path_behind(bridge->downstream, i);
285 config = child ? child->chip_info : NULL;
286 if (child && child->enabled &&
287 ((config && !config->secure) || !config))
288 enable_func(i);
289 else
290 disable_func(i);
293 /* Apply IRQ on PCI devices */
294 /* UUA */
295 for (i = 0; i < 4; i++) {
296 child = pcidev_path_behind(bridge->downstream,
297 PCI_DEVFN(8, i));
298 if (!child)
299 continue;
301 struct msix_entry entry[2] = {
302 {.addr = CAVM_GICD_SETSPI_NSR, .data = 37 + i},
303 {.addr = CAVM_GICD_CLRSPI_NSR, .data = 37 + i},
306 ecam0_pci_enable_msix(child, entry, 2);
309 printk(BIOS_INFO, "ECAM0: done\n");
312 struct device_operations pci_domain_ops_ecam0 = {
313 .read_resources = ecam0_read_resources,
314 .init = ecam0_init,
315 .scan_bus = pci_host_bridge_scan_bus,