common: Drop asm/global_data.h from common header
[platform/kernel/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 uintptr_t octeontx_cfg_addr(struct octeontx_pci *pcie,
53                                    int bus_offs, int shift_offs,
54                                    pci_dev_t bdf, uint offset)
55 {
56         u32 bus, dev, func;
57         uintptr_t address;
58
59         bus = PCI_BUS(bdf) + bus_offs;
60         dev = PCI_DEV(bdf);
61         func = PCI_FUNC(bdf);
62
63         address = (bus << (20 + shift_offs)) |
64                 (dev << (15 + shift_offs)) |
65                 (func << (12 + shift_offs)) | offset;
66         address += pcie->cfg.start;
67
68         return address;
69 }
70
71 static ulong readl_size(uintptr_t addr, enum pci_size_t size)
72 {
73         ulong val;
74
75         switch (size) {
76         case PCI_SIZE_8:
77                 val = readb(addr);
78                 break;
79         case PCI_SIZE_16:
80                 val = readw(addr);
81                 break;
82         case PCI_SIZE_32:
83                 val = readl(addr);
84                 break;
85         default:
86                 printf("Invalid size\n");
87                 return -EINVAL;
88         };
89
90         return val;
91 }
92
93 static void writel_size(uintptr_t addr, enum pci_size_t size, ulong valuep)
94 {
95         switch (size) {
96         case PCI_SIZE_8:
97                 writeb(valuep, addr);
98                 break;
99         case PCI_SIZE_16:
100                 writew(valuep, addr);
101                 break;
102         case PCI_SIZE_32:
103                 writel(valuep, addr);
104                 break;
105         default:
106                 printf("Invalid size\n");
107         };
108 }
109
110 static bool octeontx_bdf_invalid(pci_dev_t bdf)
111 {
112         if (PCI_BUS(bdf) == 1 && PCI_DEV(bdf) > 0)
113                 return true;
114
115         return false;
116 }
117
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)
121 {
122         struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
123         struct pci_controller *hose = dev_get_uclass_priv(bus);
124         uintptr_t address;
125
126         address = octeontx_cfg_addr(pcie, pcie->bus.start - hose->first_busno,
127                                     0, bdf, offset);
128         *valuep = readl_size(address, size);
129
130         debug("%02x.%02x.%02x: u%d %x -> %lx\n",
131               PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), size, offset, *valuep);
132
133         return 0;
134 }
135
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)
139 {
140         struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
141         struct pci_controller *hose = dev_get_uclass_priv(bus);
142         uintptr_t address;
143
144         address = octeontx_cfg_addr(pcie, pcie->bus.start - hose->first_busno,
145                                     0, bdf, offset);
146         writel_size(address, size, value);
147
148         debug("%02x.%02x.%02x: u%d %x <- %lx\n",
149               PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), size, offset, value);
150
151         return 0;
152 }
153
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)
157 {
158         struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
159         struct pci_controller *hose = dev_get_uclass_priv(bus);
160         uintptr_t address;
161         u8 hdrtype;
162         u8 pri_bus = pcie->bus.start + 1 - hose->first_busno;
163         u32 bus_offs = (pri_bus << 16) | (pri_bus << 8) | (pri_bus << 0);
164
165         address = octeontx_cfg_addr(pcie, 1 - hose->first_busno, 4,
166                                     bdf, 0);
167
168         *valuep = pci_conv_32_to_size(~0UL, offset, size);
169
170         if (octeontx_bdf_invalid(bdf))
171                 return -EPERM;
172
173         *valuep = readl_size(address + offset, size);
174
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);
181
182         return 0;
183 }
184
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)
188 {
189         struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
190         struct pci_controller *hose = dev_get_uclass_priv(bus);
191         uintptr_t address;
192         u8 hdrtype;
193         u8 pri_bus = pcie->bus.start + 1 - hose->first_busno;
194         u32 bus_offs = (pri_bus << 16) | (pri_bus << 8) | (pri_bus << 0);
195
196         address = octeontx_cfg_addr(pcie, 1 - hose->first_busno, 4, bdf, 0);
197
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);
204
205         if (octeontx_bdf_invalid(bdf))
206                 return -EPERM;
207
208         writel_size(address + offset, size, value);
209
210         debug("%02x.%02x.%02x: u%d %x (%lx) <- %lx\n",
211               PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), size, offset,
212               address, value);
213
214         return 0;
215 }
216
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)
220 {
221         struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
222         struct pci_controller *hose = dev_get_uclass_priv(bus);
223         uintptr_t address;
224
225         address = octeontx_cfg_addr(pcie, 1 - hose->first_busno, 0,
226                                     bdf, 0);
227
228         *valuep = pci_conv_32_to_size(~0UL, offset, size);
229
230         if (octeontx_bdf_invalid(bdf))
231                 return -EPERM;
232
233         *valuep = readl_size(address + offset, size);
234
235         debug("%02x.%02x.%02x: u%d %x (%lx) -> %lx\n",
236               PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), size, offset,
237               address, *valuep);
238
239         return 0;
240 }
241
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)
245 {
246         struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
247         struct pci_controller *hose = dev_get_uclass_priv(bus);
248         uintptr_t address;
249
250         address = octeontx_cfg_addr(pcie, 1 - hose->first_busno, 0,
251                                     bdf, 0);
252
253         if (octeontx_bdf_invalid(bdf))
254                 return -EPERM;
255
256         writel_size(address + offset, size, value);
257
258         debug("%02x.%02x.%02x: u%d %x (%lx) <- %lx\n",
259               PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), size, offset,
260               address, value);
261
262         return 0;
263 }
264
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)
268 {
269         struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
270         int ret = -EIO;
271
272         switch (pcie->type) {
273         case OTX_ECAM:
274                 ret = octeontx_ecam_read_config(bus, bdf, offset, valuep,
275                                                 size);
276                 break;
277         case OTX_PEM:
278                 ret = octeontx_pem_read_config(bus, bdf, offset, valuep,
279                                                size);
280                 break;
281         case OTX2_PEM:
282                 ret = octeontx2_pem_read_config(bus, bdf, offset, valuep,
283                                                 size);
284                 break;
285         }
286
287         return ret;
288 }
289
290 int pci_octeontx_write_config(struct udevice *bus, pci_dev_t bdf,
291                               uint offset, ulong value,
292                               enum pci_size_t size)
293 {
294         struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
295         int ret = -EIO;
296
297         switch (pcie->type) {
298         case OTX_ECAM:
299                 ret = octeontx_ecam_write_config(bus, bdf, offset, value,
300                                                  size);
301                 break;
302         case OTX_PEM:
303                 ret = octeontx_pem_write_config(bus, bdf, offset, value,
304                                                 size);
305                 break;
306         case OTX2_PEM:
307                 ret = octeontx2_pem_write_config(bus, bdf, offset, value,
308                                                  size);
309                 break;
310         }
311
312         return ret;
313 }
314
315 static int pci_octeontx_of_to_plat(struct udevice *dev)
316 {
317         return 0;
318 }
319
320 static int pci_octeontx_probe(struct udevice *dev)
321 {
322         struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(dev);
323         int err;
324
325         pcie->type = dev_get_driver_data(dev);
326
327         err = dev_read_resource(dev, 0, &pcie->cfg);
328         if (err) {
329                 debug("Error reading resource: %s\n", fdt_strerror(err));
330                 return err;
331         }
332
333         err = dev_read_pci_bus_range(dev, &pcie->bus);
334         if (err) {
335                 debug("Error reading resource: %s\n", fdt_strerror(err));
336                 return err;
337         }
338
339         return 0;
340 }
341
342 static const struct dm_pci_ops pci_octeontx_ops = {
343         .read_config    = pci_octeontx_read_config,
344         .write_config   = pci_octeontx_write_config,
345 };
346
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 },
353         { }
354 };
355
356 U_BOOT_DRIVER(pci_octeontx) = {
357         .name   = "pci_octeontx",
358         .id     = UCLASS_PCI,
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,
365 };