blob: d02e8843f223a065d45fae40292b20d6467a3c29 [file] [log] [blame]
Angel Pons5f249e62020-04-04 18:51:01 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Angel Pons5f249e62020-04-04 18:51:01 +02002
Patrick Rudolphd0c67972018-04-17 13:47:55 +02003/*
Patrick Rudolphd0c67972018-04-17 13:47:55 +02004 * Derived from Cavium's BSD-3 Clause OCTEONTX-SDK-6.2.0.
5 */
6
7#include <console/console.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +02008#include <device/mmio.h>
Patrick Rudolphd0c67972018-04-17 13:47:55 +02009#include <device/pci.h>
10#include <device/pci_ops.h>
11#include <soc/addressmap.h>
12#include <soc/cavium/common/pci/chip.h>
Patrick Rudolphb94ecc42019-02-22 12:05:16 +010013#include <soc/ecam.h>
Patrick Rudolphd0c67972018-04-17 13:47:55 +020014
15#define CAVM_PCCPF_XXX_VSEC_CTL 0x108
16#define CAVM_PCCPF_XXX_VSEC_SCTL 0x10c
17
18/*
19 * Hide PCI device function on BUS 1 in non secure world.
20 */
21static void disable_func(unsigned int devfn)
22{
23 u64 *addr;
24 printk(BIOS_DEBUG, "PCI: 01:%02x.%x is secure\n", devfn >> 3,
25 devfn & 7);
26
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);
33}
34
35/*
36 * Show PCI device function on BUS 1 in non secure world.
37 */
38static void enable_func(unsigned int devfn)
39{
40 u64 *addr;
41
42 printk(BIOS_DEBUG, "PCI: 01:%02x.%x is insecure\n", devfn >> 3,
43 devfn & 7);
44
45 /* enable function */
46 addr = (void *)ECAM0_RSLX_SDIS;
47 u64 reg = read64(&addr[devfn]);
48 reg &= ~3;
49 write64(&addr[devfn], reg);
50
51 addr = (void *)ECAM0_RSLX_NSDIS;
52 reg = read64(&addr[devfn]);
53 reg &= ~1;
54 write64(&addr[devfn], reg);
55}
56
57/*
58 * Hide PCI device on BUS 0 in non secure world.
59 */
60static void disable_device(unsigned int dev)
61{
62 u64 *addr;
63
64 printk(BIOS_DEBUG, "PCI: 00:%02x.0 is secure\n", dev);
65
66 /* disable function */
67 addr = (void *)ECAM0_DEVX_SDIS;
68 u64 reg = read64(&addr[dev]);
69 reg &= ~3;
70 write64(&addr[dev], reg);
71
72 addr = (void *)ECAM0_DEVX_NSDIS;
73 reg = read64(&addr[dev]);
74 reg |= 1;
75 write64(&addr[dev], reg);
76}
77
78/*
79 * Show PCI device on BUS 0 in non secure world.
80 */
81static void enable_device(unsigned int dev)
82{
83 u64 *addr;
84
85 printk(BIOS_DEBUG, "PCI: 00:%02x.0 is insecure\n", dev);
86
87 /* enable function */
88 addr = (void *)ECAM0_DEVX_SDIS;
89 u64 reg = read64(&addr[dev]);
90 reg &= ~3;
91 write64(&addr[dev], reg);
92
93 addr = (void *)ECAM0_DEVX_NSDIS;
94 reg = read64(&addr[dev]);
95 reg &= ~1;
96 write64(&addr[dev], reg);
97}
98
99static void ecam0_read_resources(struct device *dev)
100{
101 /* There are no dynamic PCI resources on Cavium SoC */
102}
103
104static void ecam0_fix_missing_devices(struct bus *link)
105{
106 size_t i;
107
108 /**
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...
113 */
114 for (i = 0; i <= PCI_DEVFN(0x1f, 7); i++) {
115 struct device_path pci_path;
116 struct device *child;
117
118 pci_path.type = DEVICE_PATH_PCI;
119 pci_path.pci.devfn = i;
120
121 child = find_dev_path(link, &pci_path);
122 if (!child)
123 pci_probe_dev(NULL, link, i);
124 }
125}
126
127/**
Patrick Rudolphd0c67972018-04-17 13:47:55 +0200128 * 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
132 *
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.
141 **/
142static size_t ecam0_pci_enable_msix(struct device *dev,
143 struct msix_entry *entries, size_t nvec)
144{
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;
152
153 if (!entries) {
154 printk(BIOS_ERR, "%s: No entries specified\n", __func__);
155 return -1;
156 }
157
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;
163 }
164 nr_entries = pci_msix_table_size(dev);
165 if (nvec > nr_entries) {
Julius Wernere9665952022-01-21 17:06:20 -0800166 printk(BIOS_ERR, "%s: Specified to many table entries\n",
Patrick Rudolphd0c67972018-04-17 13:47:55 +0200167 dev_path(dev));
168 return nr_entries;
169 }
170
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);
175
176 /* Find MSI-X table region */
177 offset = 0;
178 bar_idx = 0;
179 if (pci_msix_table_bar(dev, &offset, &bar_idx)) {
Julius Wernere9665952022-01-21 17:06:20 -0800180 printk(BIOS_ERR, "%s: Failed to find MSI-X entry\n",
Patrick Rudolphd0c67972018-04-17 13:47:55 +0200181 dev_path(dev));
182 return -1;
183 }
Patrick Rudolphb94ecc42019-02-22 12:05:16 +0100184 bar = ecam0_get_bar_val(dev, bar_idx);
Patrick Rudolphd0c67972018-04-17 13:47:55 +0200185 if (!bar) {
Julius Wernere9665952022-01-21 17:06:20 -0800186 printk(BIOS_ERR, "%s: Failed to find MSI-X bar\n",
Patrick Rudolphd0c67972018-04-17 13:47:55 +0200187 dev_path(dev));
188 return -1;
189 }
190 msixtable = (struct msix_entry *)((void *)bar + offset);
191
192 /*
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.
196 */
197 control |= PCI_MSIX_FLAGS_MASKALL | PCI_MSIX_FLAGS_ENABLE;
198 pci_write_config16(dev, pos + PCI_MSIX_FLAGS, control);
199
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);
204 }
205
206 control &= ~PCI_MSIX_FLAGS_MASKALL;
207 pci_write_config16(dev, pos + PCI_MSIX_FLAGS, control);
208
209 return 0;
210}
211
212static void ecam0_init(struct device *dev)
213{
214 struct soc_cavium_common_pci_config *config;
215 struct device *child, *child_last;
216 size_t i;
217 u32 reg32;
218
219 printk(BIOS_INFO, "ECAM0: init\n");
Kyösti Mälkki267684f2018-12-29 14:45:28 +0200220 const struct device *bridge = pcidev_on_root(1, 0);
Patrick Rudolphd0c67972018-04-17 13:47:55 +0200221 if (!bridge) {
222 printk(BIOS_INFO, "ECAM0: ERROR: PCI 00:01.0 not found.\n");
223 return;
224 }
225 /**
226 * Search for missing devices on BUS 1.
227 * Only required for ARI capability programming.
228 */
229 ecam0_fix_missing_devices(bridge->link_list);
230
231 /* Program secure ARI capability on bus 1 */
232 child_last = NULL;
233 for (i = 0; i <= PCI_DEVFN(0x1f, 7); i++) {
Kyösti Mälkki267684f2018-12-29 14:45:28 +0200234 child = pcidev_path_behind(bridge->link_list, i);
Patrick Rudolphd0c67972018-04-17 13:47:55 +0200235 if (!child || !child->enabled)
236 continue;
237
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);
246 }
247 child_last = child;
248 }
249
250 /* Program insecure ARI capability on bus 1 */
251 child_last = NULL;
252 for (i = 0; i <= PCI_DEVFN(0x1f, 7); i++) {
Kyösti Mälkki267684f2018-12-29 14:45:28 +0200253 child = pcidev_path_behind(bridge->link_list, i);
Patrick Rudolphd0c67972018-04-17 13:47:55 +0200254 if (!child)
255 continue;
256 config = child->chip_info;
257 if (!child->enabled || (config && config->secure))
258 continue;
259
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);
268 }
269 child_last = child;
270 }
271
272 /* Enable / disable devices on bus 0 */
273 for (i = 0; i <= 0x1f; i++) {
Kyösti Mälkki267684f2018-12-29 14:45:28 +0200274 child = pcidev_on_root(i, 0);
Patrick Rudolphd0c67972018-04-17 13:47:55 +0200275 config = child ? child->chip_info : NULL;
276 if (child && child->enabled && config && !config->secure)
277 enable_device(i);
278 else
279 disable_device(i);
280 }
281
282 /* Enable / disable devices and functions on bus 1 */
283 for (i = 0; i <= PCI_DEVFN(0x1f, 7); i++) {
Kyösti Mälkki267684f2018-12-29 14:45:28 +0200284 child = pcidev_path_behind(bridge->link_list, i);
Patrick Rudolphd0c67972018-04-17 13:47:55 +0200285 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);
291 }
292
293 /* Apply IRQ on PCI devices */
294 /* UUA */
295 for (i = 0; i < 4; i++) {
Kyösti Mälkki267684f2018-12-29 14:45:28 +0200296 child = pcidev_path_behind(bridge->link_list,
Patrick Rudolphd0c67972018-04-17 13:47:55 +0200297 PCI_DEVFN(8, i));
298 if (!child)
299 continue;
300
301 struct msix_entry entry[2] = {
302 {.addr = CAVM_GICD_SETSPI_NSR, .data = 37 + i},
303 {.addr = CAVM_GICD_CLRSPI_NSR, .data = 37 + i},
304 };
305
306 ecam0_pci_enable_msix(child, entry, 2);
307 }
308
309 printk(BIOS_INFO, "ECAM0: done\n");
310}
311
312struct device_operations pci_domain_ops_ecam0 = {
Patrick Rudolphd0c67972018-04-17 13:47:55 +0200313 .read_resources = ecam0_read_resources,
314 .init = ecam0_init,
Arthur Heymans0b0113f2023-08-31 17:09:28 +0200315 .scan_bus = pci_host_bridge_scan_bus,
Patrick Rudolphd0c67972018-04-17 13:47:55 +0200316};