1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2018 Marvell International Ltd.
5 * https://spdx.org/licenses
17 #include <linux/ioport.h>
19 DECLARE_GLOBAL_DATA_PTR;
22 * This driver supports multiple types of operations / host bridges / busses:
24 * OTX_ECAM: Octeon TX & TX2 ECAM (Enhanced Configuration Access Mechanism)
25 * Used to access the internal on-chip devices which are connected
27 * OTX_PEM: Octeon TX PEM (PCI Express MAC)
28 * Used to access the external (off-chip) PCI devices
29 * OTX2_PEM: Octeon TX2 PEM (PCI Express MAC)
30 * Used to access the external (off-chip) PCI devices
39 * struct octeontx_pci - Driver private data
40 * @type: Device type matched via compatible (e.g. OTX_ECAM etc)
41 * @cfg: Config resource
51 static uintptr_t octeontx_cfg_addr(struct octeontx_pci *pcie,
52 int bus_offs, int shift_offs,
53 pci_dev_t bdf, uint offset)
58 bus = PCI_BUS(bdf) + bus_offs;
62 address = (bus << (20 + shift_offs)) |
63 (dev << (15 + shift_offs)) |
64 (func << (12 + shift_offs)) | offset;
65 address += pcie->cfg.start;
70 static ulong readl_size(uintptr_t addr, enum pci_size_t size)
85 printf("Invalid size\n");
92 static void writel_size(uintptr_t addr, enum pci_size_t size, ulong valuep)
102 writel(valuep, addr);
105 printf("Invalid size\n");
109 static bool octeontx_bdf_invalid(pci_dev_t bdf)
111 if (PCI_BUS(bdf) == 1 && PCI_DEV(bdf) > 0)
117 static int octeontx_ecam_read_config(const struct udevice *bus, pci_dev_t bdf,
118 uint offset, ulong *valuep,
119 enum pci_size_t size)
121 struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
122 struct pci_controller *hose = dev_get_uclass_priv(bus);
125 address = octeontx_cfg_addr(pcie, pcie->bus.start - hose->first_busno,
127 *valuep = readl_size(address, size);
129 debug("%02x.%02x.%02x: u%d %x -> %lx\n",
130 PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), size, offset, *valuep);
135 static int octeontx_ecam_write_config(struct udevice *bus, pci_dev_t bdf,
136 uint offset, ulong value,
137 enum pci_size_t size)
139 struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
140 struct pci_controller *hose = dev_get_uclass_priv(bus);
143 address = octeontx_cfg_addr(pcie, pcie->bus.start - hose->first_busno,
145 writel_size(address, size, value);
147 debug("%02x.%02x.%02x: u%d %x <- %lx\n",
148 PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), size, offset, value);
153 static int octeontx_pem_read_config(const struct udevice *bus, pci_dev_t bdf,
154 uint offset, ulong *valuep,
155 enum pci_size_t size)
157 struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
158 struct pci_controller *hose = dev_get_uclass_priv(bus);
161 u8 pri_bus = pcie->bus.start + 1 - hose->first_busno;
162 u32 bus_offs = (pri_bus << 16) | (pri_bus << 8) | (pri_bus << 0);
164 address = octeontx_cfg_addr(pcie, 1 - hose->first_busno, 4,
167 *valuep = pci_conv_32_to_size(~0UL, offset, size);
169 if (octeontx_bdf_invalid(bdf))
172 *valuep = readl_size(address + offset, size);
174 hdrtype = readb(address + PCI_HEADER_TYPE);
175 if (hdrtype == PCI_HEADER_TYPE_BRIDGE &&
176 offset >= PCI_PRIMARY_BUS &&
177 offset <= PCI_SUBORDINATE_BUS &&
178 *valuep != pci_conv_32_to_size(~0UL, offset, size))
179 *valuep -= pci_conv_32_to_size(bus_offs, offset, size);
184 static int octeontx_pem_write_config(struct udevice *bus, pci_dev_t bdf,
185 uint offset, ulong value,
186 enum pci_size_t size)
188 struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
189 struct pci_controller *hose = dev_get_uclass_priv(bus);
192 u8 pri_bus = pcie->bus.start + 1 - hose->first_busno;
193 u32 bus_offs = (pri_bus << 16) | (pri_bus << 8) | (pri_bus << 0);
195 address = octeontx_cfg_addr(pcie, 1 - hose->first_busno, 4, bdf, 0);
197 hdrtype = readb(address + PCI_HEADER_TYPE);
198 if (hdrtype == PCI_HEADER_TYPE_BRIDGE &&
199 offset >= PCI_PRIMARY_BUS &&
200 offset <= PCI_SUBORDINATE_BUS &&
201 value != pci_conv_32_to_size(~0UL, offset, size))
202 value += pci_conv_32_to_size(bus_offs, offset, size);
204 if (octeontx_bdf_invalid(bdf))
207 writel_size(address + offset, size, value);
209 debug("%02x.%02x.%02x: u%d %x (%lx) <- %lx\n",
210 PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), size, offset,
216 static int octeontx2_pem_read_config(const struct udevice *bus, pci_dev_t bdf,
217 uint offset, ulong *valuep,
218 enum pci_size_t size)
220 struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
221 struct pci_controller *hose = dev_get_uclass_priv(bus);
224 address = octeontx_cfg_addr(pcie, 1 - hose->first_busno, 0,
227 *valuep = pci_conv_32_to_size(~0UL, offset, size);
229 if (octeontx_bdf_invalid(bdf))
232 *valuep = readl_size(address + offset, size);
234 debug("%02x.%02x.%02x: u%d %x (%lx) -> %lx\n",
235 PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), size, offset,
241 static int octeontx2_pem_write_config(struct udevice *bus, pci_dev_t bdf,
242 uint offset, ulong value,
243 enum pci_size_t size)
245 struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
246 struct pci_controller *hose = dev_get_uclass_priv(bus);
249 address = octeontx_cfg_addr(pcie, 1 - hose->first_busno, 0,
252 if (octeontx_bdf_invalid(bdf))
255 writel_size(address + offset, size, value);
257 debug("%02x.%02x.%02x: u%d %x (%lx) <- %lx\n",
258 PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), size, offset,
264 int pci_octeontx_read_config(const struct udevice *bus, pci_dev_t bdf,
265 uint offset, ulong *valuep,
266 enum pci_size_t size)
268 struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
271 switch (pcie->type) {
273 ret = octeontx_ecam_read_config(bus, bdf, offset, valuep,
277 ret = octeontx_pem_read_config(bus, bdf, offset, valuep,
281 ret = octeontx2_pem_read_config(bus, bdf, offset, valuep,
289 int pci_octeontx_write_config(struct udevice *bus, pci_dev_t bdf,
290 uint offset, ulong value,
291 enum pci_size_t size)
293 struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
296 switch (pcie->type) {
298 ret = octeontx_ecam_write_config(bus, bdf, offset, value,
302 ret = octeontx_pem_write_config(bus, bdf, offset, value,
306 ret = octeontx2_pem_write_config(bus, bdf, offset, value,
314 static int pci_octeontx_of_to_plat(struct udevice *dev)
319 static int pci_octeontx_probe(struct udevice *dev)
321 struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(dev);
324 pcie->type = dev_get_driver_data(dev);
326 err = dev_read_resource(dev, 0, &pcie->cfg);
328 debug("Error reading resource: %s\n", fdt_strerror(err));
332 err = dev_read_pci_bus_range(dev, &pcie->bus);
334 debug("Error reading resource: %s\n", fdt_strerror(err));
341 static const struct dm_pci_ops pci_octeontx_ops = {
342 .read_config = pci_octeontx_read_config,
343 .write_config = pci_octeontx_write_config,
346 static const struct udevice_id pci_octeontx_ids[] = {
347 { .compatible = "cavium,pci-host-thunder-ecam", .data = OTX_ECAM },
348 { .compatible = "cavium,pci-host-octeontx-ecam", .data = OTX_ECAM },
349 { .compatible = "pci-host-ecam-generic", .data = OTX_ECAM },
350 { .compatible = "cavium,pci-host-thunder-pem", .data = OTX_PEM },
351 { .compatible = "marvell,pci-host-octeontx2-pem", .data = OTX2_PEM },
355 U_BOOT_DRIVER(pci_octeontx) = {
356 .name = "pci_octeontx",
358 .of_match = pci_octeontx_ids,
359 .ops = &pci_octeontx_ops,
360 .of_to_plat = pci_octeontx_of_to_plat,
361 .probe = pci_octeontx_probe,
362 .priv_auto = sizeof(struct octeontx_pci),
363 .flags = DM_FLAG_PRE_RELOC,