]> Git Repo - J-u-boot.git/blob - drivers/pci/pci_octeontx.c
Merge patch series "Add TI K3 PCIe Controller support for J7200"
[J-u-boot.git] / drivers / pci / pci_octeontx.c
1 // SPDX-License-Identifier:    GPL-2.0
2 /*
3  * Copyright (C) 2018 Marvell International Ltd.
4  *
5  * https://spdx.org/licenses
6  */
7
8 #include <dm.h>
9 #include <errno.h>
10 #include <fdtdec.h>
11 #include <log.h>
12 #include <malloc.h>
13 #include <pci.h>
14 #include <asm/global_data.h>
15
16 #include <asm/io.h>
17
18 #include <linux/ioport.h>
19
20 DECLARE_GLOBAL_DATA_PTR;
21
22 /*
23  * This driver supports multiple types of operations / host bridges / busses:
24  *
25  * OTX_ECAM: Octeon TX & TX2 ECAM (Enhanced Configuration Access Mechanism)
26  *           Used to access the internal on-chip devices which are connected
27  *           to internal buses
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
32  */
33 enum {
34         OTX_ECAM,
35         OTX_PEM,
36         OTX2_PEM,
37 };
38
39 /**
40  * struct octeontx_pci - Driver private data
41  * @type:       Device type matched via compatible (e.g. OTX_ECAM etc)
42  * @cfg:        Config resource
43  * @bus:        Bus resource
44  */
45 struct octeontx_pci {
46         unsigned int type;
47
48         struct resource cfg;
49         struct resource bus;
50 };
51
52 static ulong readl_size(uintptr_t addr, enum pci_size_t size)
53 {
54         ulong val;
55
56         switch (size) {
57         case PCI_SIZE_8:
58                 val = readb(addr);
59                 break;
60         case PCI_SIZE_16:
61                 val = readw(addr);
62                 break;
63         case PCI_SIZE_32:
64                 val = readl(addr);
65                 break;
66         default:
67                 printf("Invalid size\n");
68                 return -EINVAL;
69         };
70
71         return val;
72 }
73
74 static void writel_size(uintptr_t addr, enum pci_size_t size, ulong valuep)
75 {
76         switch (size) {
77         case PCI_SIZE_8:
78                 writeb(valuep, addr);
79                 break;
80         case PCI_SIZE_16:
81                 writew(valuep, addr);
82                 break;
83         case PCI_SIZE_32:
84                 writel(valuep, addr);
85                 break;
86         default:
87                 printf("Invalid size\n");
88         };
89 }
90
91 static bool octeontx_bdf_invalid(pci_dev_t bdf)
92 {
93         if (PCI_BUS(bdf) == 1 && PCI_DEV(bdf) > 0)
94                 return true;
95
96         return false;
97 }
98
99 static int octeontx_ecam_read_config(const struct udevice *bus, pci_dev_t bdf,
100                                      uint offset, ulong *valuep,
101                                      enum pci_size_t size)
102 {
103         struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
104         struct pci_controller *hose = dev_get_uclass_priv(bus);
105         uintptr_t address;
106
107         address = PCIE_ECAM_OFFSET(PCI_BUS(bdf) + pcie->bus.start - hose->first_busno,
108                                    PCI_DEV(bdf), PCI_FUNC(bdf), offset);
109         *valuep = readl_size(pcie->cfg.start + address, size);
110
111         debug("%02x.%02x.%02x: u%d %x -> %lx\n",
112               PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), size, offset, *valuep);
113
114         return 0;
115 }
116
117 static int octeontx_ecam_write_config(struct udevice *bus, pci_dev_t bdf,
118                                       uint offset, ulong value,
119                                       enum pci_size_t size)
120 {
121         struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
122         struct pci_controller *hose = dev_get_uclass_priv(bus);
123         uintptr_t address;
124
125         address = PCIE_ECAM_OFFSET(PCI_BUS(bdf) + pcie->bus.start - hose->first_busno,
126                                    PCI_DEV(bdf), PCI_FUNC(bdf), offset);
127         writel_size(pcie->cfg.start + address, size, value);
128
129         debug("%02x.%02x.%02x: u%d %x <- %lx\n",
130               PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), size, offset, value);
131
132         return 0;
133 }
134
135 static int octeontx_pem_read_config(const struct udevice *bus, pci_dev_t bdf,
136                                     uint offset, ulong *valuep,
137                                     enum pci_size_t size)
138 {
139         struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
140         struct pci_controller *hose = dev_get_uclass_priv(bus);
141         uintptr_t address;
142         u8 hdrtype;
143         u8 pri_bus = pcie->bus.start + 1 - hose->first_busno;
144         u32 bus_offs = (pri_bus << 16) | (pri_bus << 8) | (pri_bus << 0);
145
146         *valuep = pci_conv_32_to_size(~0UL, offset, size);
147
148         if (octeontx_bdf_invalid(bdf))
149                 return -EPERM;
150
151         address = PCIE_ECAM_OFFSET(PCI_BUS(bdf) + 1 - hose->first_busno,
152                                    PCI_DEV(bdf), PCI_FUNC(bdf), 0) << 4;
153         *valuep = readl_size(pcie->cfg.start + address + offset, size);
154
155         hdrtype = readb(pcie->cfg.start + address + PCI_HEADER_TYPE);
156         if (hdrtype == PCI_HEADER_TYPE_BRIDGE &&
157             offset >= PCI_PRIMARY_BUS &&
158             offset <= PCI_SUBORDINATE_BUS &&
159             *valuep != pci_conv_32_to_size(~0UL, offset, size))
160                 *valuep -= pci_conv_32_to_size(bus_offs, offset, size);
161
162         return 0;
163 }
164
165 static int octeontx_pem_write_config(struct udevice *bus, pci_dev_t bdf,
166                                      uint offset, ulong value,
167                                      enum pci_size_t size)
168 {
169         struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
170         struct pci_controller *hose = dev_get_uclass_priv(bus);
171         uintptr_t address;
172         u8 hdrtype;
173         u8 pri_bus = pcie->bus.start + 1 - hose->first_busno;
174         u32 bus_offs = (pri_bus << 16) | (pri_bus << 8) | (pri_bus << 0);
175
176         address = PCIE_ECAM_OFFSET(PCI_BUS(bdf) + 1 - hose->first_busno,
177                                    PCI_DEV(bdf), PCI_FUNC(bdf), 0) << 4;
178
179         hdrtype = readb(pcie->cfg.start + address + PCI_HEADER_TYPE);
180         if (hdrtype == PCI_HEADER_TYPE_BRIDGE &&
181             offset >= PCI_PRIMARY_BUS &&
182             offset <= PCI_SUBORDINATE_BUS &&
183             value != pci_conv_32_to_size(~0UL, offset, size))
184                 value +=  pci_conv_32_to_size(bus_offs, offset, size);
185
186         if (octeontx_bdf_invalid(bdf))
187                 return -EPERM;
188
189         writel_size(pcie->cfg.start + address + offset, size, value);
190
191         debug("%02x.%02x.%02x: u%d %x (%lx) <- %lx\n",
192               PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), size, offset,
193               address, value);
194
195         return 0;
196 }
197
198 static int octeontx2_pem_read_config(const struct udevice *bus, pci_dev_t bdf,
199                                      uint offset, ulong *valuep,
200                                      enum pci_size_t size)
201 {
202         struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
203         struct pci_controller *hose = dev_get_uclass_priv(bus);
204         uintptr_t address;
205
206         *valuep = pci_conv_32_to_size(~0UL, offset, size);
207
208         if (octeontx_bdf_invalid(bdf))
209                 return -EPERM;
210
211         address = PCIE_ECAM_OFFSET(PCI_BUS(bdf) + 1 - hose->first_busno,
212                                    PCI_DEV(bdf), PCI_FUNC(bdf), offset);
213         *valuep = readl_size(pcie->cfg.start + address, size);
214
215         debug("%02x.%02x.%02x: u%d %x (%lx) -> %lx\n",
216               PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), size, offset,
217               address, *valuep);
218
219         return 0;
220 }
221
222 static int octeontx2_pem_write_config(struct udevice *bus, pci_dev_t bdf,
223                                       uint offset, ulong value,
224                                       enum pci_size_t size)
225 {
226         struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
227         struct pci_controller *hose = dev_get_uclass_priv(bus);
228         uintptr_t address;
229
230         if (octeontx_bdf_invalid(bdf))
231                 return -EPERM;
232
233         address = PCIE_ECAM_OFFSET(PCI_BUS(bdf) + 1 - hose->first_busno,
234                                    PCI_DEV(bdf), PCI_FUNC(bdf), offset);
235         writel_size(pcie->cfg.start + address, size, value);
236
237         debug("%02x.%02x.%02x: u%d %x (%lx) <- %lx\n",
238               PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), size, offset,
239               address, value);
240
241         return 0;
242 }
243
244 int pci_octeontx_read_config(const struct udevice *bus, pci_dev_t bdf,
245                              uint offset, ulong *valuep,
246                              enum pci_size_t size)
247 {
248         struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
249         int ret = -EIO;
250
251         switch (pcie->type) {
252         case OTX_ECAM:
253                 ret = octeontx_ecam_read_config(bus, bdf, offset, valuep,
254                                                 size);
255                 break;
256         case OTX_PEM:
257                 ret = octeontx_pem_read_config(bus, bdf, offset, valuep,
258                                                size);
259                 break;
260         case OTX2_PEM:
261                 ret = octeontx2_pem_read_config(bus, bdf, offset, valuep,
262                                                 size);
263                 break;
264         }
265
266         return ret;
267 }
268
269 int pci_octeontx_write_config(struct udevice *bus, pci_dev_t bdf,
270                               uint offset, ulong value,
271                               enum pci_size_t size)
272 {
273         struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
274         int ret = -EIO;
275
276         switch (pcie->type) {
277         case OTX_ECAM:
278                 ret = octeontx_ecam_write_config(bus, bdf, offset, value,
279                                                  size);
280                 break;
281         case OTX_PEM:
282                 ret = octeontx_pem_write_config(bus, bdf, offset, value,
283                                                 size);
284                 break;
285         case OTX2_PEM:
286                 ret = octeontx2_pem_write_config(bus, bdf, offset, value,
287                                                  size);
288                 break;
289         }
290
291         return ret;
292 }
293
294 static int pci_octeontx_of_to_plat(struct udevice *dev)
295 {
296         return 0;
297 }
298
299 static int pci_octeontx_probe(struct udevice *dev)
300 {
301         struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(dev);
302         int err;
303
304         pcie->type = dev_get_driver_data(dev);
305
306         err = dev_read_resource(dev, 0, &pcie->cfg);
307         if (err) {
308                 debug("Error reading resource: %s\n", fdt_strerror(err));
309                 return err;
310         }
311
312         err = dev_read_pci_bus_range(dev, &pcie->bus);
313         if (err) {
314                 debug("Error reading resource: %s\n", fdt_strerror(err));
315                 return err;
316         }
317
318         return 0;
319 }
320
321 static const struct dm_pci_ops pci_octeontx_ops = {
322         .read_config    = pci_octeontx_read_config,
323         .write_config   = pci_octeontx_write_config,
324 };
325
326 static const struct udevice_id pci_octeontx_ids[] = {
327         { .compatible = "cavium,pci-host-thunder-ecam", .data = OTX_ECAM },
328         { .compatible = "cavium,pci-host-octeontx-ecam", .data = OTX_ECAM },
329         { .compatible = "pci-host-ecam-generic", .data = OTX_ECAM },
330         { .compatible = "cavium,pci-host-thunder-pem", .data = OTX_PEM },
331         { .compatible = "marvell,pci-host-octeontx2-pem", .data = OTX2_PEM },
332         { }
333 };
334
335 U_BOOT_DRIVER(pci_octeontx) = {
336         .name   = "pci_octeontx",
337         .id     = UCLASS_PCI,
338         .of_match = pci_octeontx_ids,
339         .ops    = &pci_octeontx_ops,
340         .of_to_plat = pci_octeontx_of_to_plat,
341         .probe  = pci_octeontx_probe,
342         .priv_auto      = sizeof(struct octeontx_pci),
343         .flags = DM_FLAG_PRE_RELOC,
344 };
This page took 0.043877 seconds and 4 git commands to generate.