1 /* SPDX-License-Identifier: GPL-2.0-only */
4 * Derived from Cavium's BSD-3 Clause OCTEONTX-SDK-6.2.0.
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>
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
)
24 printk(BIOS_DEBUG
, "PCI: 01:%02x.%x is secure\n", devfn
>> 3,
27 /* disable function */
28 addr
= (void *)ECAM0_RSLX_SDIS
;
29 u64 reg
= read64(&addr
[devfn
]);
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
)
42 printk(BIOS_DEBUG
, "PCI: 01:%02x.%x is insecure\n", devfn
>> 3,
46 addr
= (void *)ECAM0_RSLX_SDIS
;
47 u64 reg
= read64(&addr
[devfn
]);
49 write64(&addr
[devfn
], reg
);
51 addr
= (void *)ECAM0_RSLX_NSDIS
;
52 reg
= read64(&addr
[devfn
]);
54 write64(&addr
[devfn
], reg
);
58 * Hide PCI device on BUS 0 in non secure world.
60 static void disable_device(unsigned int dev
)
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
]);
70 write64(&addr
[dev
], reg
);
72 addr
= (void *)ECAM0_DEVX_NSDIS
;
73 reg
= read64(&addr
[dev
]);
75 write64(&addr
[dev
], reg
);
79 * Show PCI device on BUS 0 in non secure world.
81 static void enable_device(unsigned int dev
)
85 printk(BIOS_DEBUG
, "PCI: 00:%02x.0 is insecure\n", dev
);
88 addr
= (void *)ECAM0_DEVX_SDIS
;
89 u64 reg
= read64(&addr
[dev
]);
91 write64(&addr
[dev
], reg
);
93 addr
= (void *)ECAM0_DEVX_NSDIS
;
94 reg
= read64(&addr
[dev
]);
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
)
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
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
);
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
;
154 printk(BIOS_ERR
, "%s: No entries specified\n", __func__
);
158 const size_t pos
= pci_find_capability(dev
, PCI_CAP_ID_MSIX
);
160 printk(BIOS_ERR
, "%s: Device not MSI-X capable\n",
164 nr_entries
= pci_msix_table_size(dev
);
165 if (nvec
> nr_entries
) {
166 printk(BIOS_ERR
, "%s: Specified to many table entries\n",
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 */
179 if (pci_msix_table_bar(dev
, &offset
, &bar_idx
)) {
180 printk(BIOS_ERR
, "%s: Failed to find MSI-X entry\n",
184 bar
= ecam0_get_bar_val(pcidev_bdf(dev
), bar_idx
);
186 printk(BIOS_ERR
, "%s: Failed to find MSI-X bar\n",
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
);
212 static void ecam0_init(struct device
*dev
)
214 struct soc_cavium_common_pci_config
*config
;
215 struct device
*child
, *child_last
;
219 printk(BIOS_INFO
, "ECAM0: init\n");
220 const struct device
*bridge
= pcidev_on_root(1, 0);
222 printk(BIOS_INFO
, "ECAM0: ERROR: PCI 00:01.0 not found.\n");
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 */
233 for (i
= 0; i
<= PCI_DEVFN(0x1f, 7); i
++) {
234 child
= pcidev_path_behind(bridge
->downstream
, i
);
235 if (!child
|| !child
->enabled
)
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
,
250 /* Program insecure ARI capability on bus 1 */
252 for (i
= 0; i
<= PCI_DEVFN(0x1f, 7); i
++) {
253 child
= pcidev_path_behind(bridge
->downstream
, i
);
256 config
= child
->chip_info
;
257 if (!child
->enabled
|| (config
&& config
->secure
))
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
,
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
)
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
))
293 /* Apply IRQ on PCI devices */
295 for (i
= 0; i
< 4; i
++) {
296 child
= pcidev_path_behind(bridge
->downstream
,
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
,
315 .scan_bus
= pci_host_bridge_scan_bus
,