1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2018 Marvell International Ltd.
5 * https://spdx.org/licenses
14 #include <asm/global_data.h>
18 #include <linux/ioport.h>
20 DECLARE_GLOBAL_DATA_PTR;
23 * This driver supports multiple types of operations / host bridges / busses:
25 * OTX_ECAM: Octeon TX & TX2 ECAM (Enhanced Configuration Access Mechanism)
26 * Used to access the internal on-chip devices which are connected
28 * OTX_PEM: Octeon TX PEM (PCI Express MAC)
29 * Used to access the external (off-chip) PCI devices
30 * OTX2_PEM: Octeon TX2 PEM (PCI Express MAC)
31 * Used to access the external (off-chip) PCI devices
40 * struct octeontx_pci - Driver private data
41 * @type: Device type matched via compatible (e.g. OTX_ECAM etc)
42 * @cfg: Config resource
52 static uintptr_t octeontx_cfg_addr(struct octeontx_pci *pcie,
53 int bus_offs, int shift_offs,
54 pci_dev_t bdf, uint offset)
59 bus = PCI_BUS(bdf) + bus_offs;
63 address = (bus << (20 + shift_offs)) |
64 (dev << (15 + shift_offs)) |
65 (func << (12 + shift_offs)) | offset;
66 address += pcie->cfg.start;
71 static ulong readl_size(uintptr_t addr, enum pci_size_t size)
86 printf("Invalid size\n");
93 static void writel_size(uintptr_t addr, enum pci_size_t size, ulong valuep)
100 writew(valuep, addr);
103 writel(valuep, addr);
106 printf("Invalid size\n");
110 static bool octeontx_bdf_invalid(pci_dev_t bdf)
112 if (PCI_BUS(bdf) == 1 && PCI_DEV(bdf) > 0)
118 static int octeontx_ecam_read_config(const struct udevice *bus, pci_dev_t bdf,
119 uint offset, ulong *valuep,
120 enum pci_size_t size)
122 struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
123 struct pci_controller *hose = dev_get_uclass_priv(bus);
126 address = octeontx_cfg_addr(pcie, pcie->bus.start - hose->first_busno,
128 *valuep = readl_size(address, size);
130 debug("%02x.%02x.%02x: u%d %x -> %lx\n",
131 PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), size, offset, *valuep);
136 static int octeontx_ecam_write_config(struct udevice *bus, pci_dev_t bdf,
137 uint offset, ulong value,
138 enum pci_size_t size)
140 struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
141 struct pci_controller *hose = dev_get_uclass_priv(bus);
144 address = octeontx_cfg_addr(pcie, pcie->bus.start - hose->first_busno,
146 writel_size(address, size, value);
148 debug("%02x.%02x.%02x: u%d %x <- %lx\n",
149 PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), size, offset, value);
154 static int octeontx_pem_read_config(const struct udevice *bus, pci_dev_t bdf,
155 uint offset, ulong *valuep,
156 enum pci_size_t size)
158 struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
159 struct pci_controller *hose = dev_get_uclass_priv(bus);
162 u8 pri_bus = pcie->bus.start + 1 - hose->first_busno;
163 u32 bus_offs = (pri_bus << 16) | (pri_bus << 8) | (pri_bus << 0);
165 address = octeontx_cfg_addr(pcie, 1 - hose->first_busno, 4,
168 *valuep = pci_conv_32_to_size(~0UL, offset, size);
170 if (octeontx_bdf_invalid(bdf))
173 *valuep = readl_size(address + offset, size);
175 hdrtype = readb(address + PCI_HEADER_TYPE);
176 if (hdrtype == PCI_HEADER_TYPE_BRIDGE &&
177 offset >= PCI_PRIMARY_BUS &&
178 offset <= PCI_SUBORDINATE_BUS &&
179 *valuep != pci_conv_32_to_size(~0UL, offset, size))
180 *valuep -= pci_conv_32_to_size(bus_offs, offset, size);
185 static int octeontx_pem_write_config(struct udevice *bus, pci_dev_t bdf,
186 uint offset, ulong value,
187 enum pci_size_t size)
189 struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
190 struct pci_controller *hose = dev_get_uclass_priv(bus);
193 u8 pri_bus = pcie->bus.start + 1 - hose->first_busno;
194 u32 bus_offs = (pri_bus << 16) | (pri_bus << 8) | (pri_bus << 0);
196 address = octeontx_cfg_addr(pcie, 1 - hose->first_busno, 4, bdf, 0);
198 hdrtype = readb(address + PCI_HEADER_TYPE);
199 if (hdrtype == PCI_HEADER_TYPE_BRIDGE &&
200 offset >= PCI_PRIMARY_BUS &&
201 offset <= PCI_SUBORDINATE_BUS &&
202 value != pci_conv_32_to_size(~0UL, offset, size))
203 value += pci_conv_32_to_size(bus_offs, offset, size);
205 if (octeontx_bdf_invalid(bdf))
208 writel_size(address + offset, size, value);
210 debug("%02x.%02x.%02x: u%d %x (%lx) <- %lx\n",
211 PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), size, offset,
217 static int octeontx2_pem_read_config(const struct udevice *bus, pci_dev_t bdf,
218 uint offset, ulong *valuep,
219 enum pci_size_t size)
221 struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
222 struct pci_controller *hose = dev_get_uclass_priv(bus);
225 address = octeontx_cfg_addr(pcie, 1 - hose->first_busno, 0,
228 *valuep = pci_conv_32_to_size(~0UL, offset, size);
230 if (octeontx_bdf_invalid(bdf))
233 *valuep = readl_size(address + offset, size);
235 debug("%02x.%02x.%02x: u%d %x (%lx) -> %lx\n",
236 PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), size, offset,
242 static int octeontx2_pem_write_config(struct udevice *bus, pci_dev_t bdf,
243 uint offset, ulong value,
244 enum pci_size_t size)
246 struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
247 struct pci_controller *hose = dev_get_uclass_priv(bus);
250 address = octeontx_cfg_addr(pcie, 1 - hose->first_busno, 0,
253 if (octeontx_bdf_invalid(bdf))
256 writel_size(address + offset, size, value);
258 debug("%02x.%02x.%02x: u%d %x (%lx) <- %lx\n",
259 PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), size, offset,
265 int pci_octeontx_read_config(const struct udevice *bus, pci_dev_t bdf,
266 uint offset, ulong *valuep,
267 enum pci_size_t size)
269 struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
272 switch (pcie->type) {
274 ret = octeontx_ecam_read_config(bus, bdf, offset, valuep,
278 ret = octeontx_pem_read_config(bus, bdf, offset, valuep,
282 ret = octeontx2_pem_read_config(bus, bdf, offset, valuep,
290 int pci_octeontx_write_config(struct udevice *bus, pci_dev_t bdf,
291 uint offset, ulong value,
292 enum pci_size_t size)
294 struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
297 switch (pcie->type) {
299 ret = octeontx_ecam_write_config(bus, bdf, offset, value,
303 ret = octeontx_pem_write_config(bus, bdf, offset, value,
307 ret = octeontx2_pem_write_config(bus, bdf, offset, value,
315 static int pci_octeontx_of_to_plat(struct udevice *dev)
320 static int pci_octeontx_probe(struct udevice *dev)
322 struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(dev);
325 pcie->type = dev_get_driver_data(dev);
327 err = dev_read_resource(dev, 0, &pcie->cfg);
329 debug("Error reading resource: %s\n", fdt_strerror(err));
333 err = dev_read_pci_bus_range(dev, &pcie->bus);
335 debug("Error reading resource: %s\n", fdt_strerror(err));
342 static const struct dm_pci_ops pci_octeontx_ops = {
343 .read_config = pci_octeontx_read_config,
344 .write_config = pci_octeontx_write_config,
347 static const struct udevice_id pci_octeontx_ids[] = {
348 { .compatible = "cavium,pci-host-thunder-ecam", .data = OTX_ECAM },
349 { .compatible = "cavium,pci-host-octeontx-ecam", .data = OTX_ECAM },
350 { .compatible = "pci-host-ecam-generic", .data = OTX_ECAM },
351 { .compatible = "cavium,pci-host-thunder-pem", .data = OTX_PEM },
352 { .compatible = "marvell,pci-host-octeontx2-pem", .data = OTX2_PEM },
356 U_BOOT_DRIVER(pci_octeontx) = {
357 .name = "pci_octeontx",
359 .of_match = pci_octeontx_ids,
360 .ops = &pci_octeontx_ops,
361 .of_to_plat = pci_octeontx_of_to_plat,
362 .probe = pci_octeontx_probe,
363 .priv_auto = sizeof(struct octeontx_pci),
364 .flags = DM_FLAG_PRE_RELOC,