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 
octeontx_cfg_addr(struct octeontx_pci * pcie,int bus_offs,int shift_offs,pci_dev_t bdf,uint offset)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 
readl_size(uintptr_t addr,enum pci_size_t size)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 
writel_size(uintptr_t addr,enum pci_size_t size,ulong valuep)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 
octeontx_bdf_invalid(pci_dev_t bdf)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 
octeontx_ecam_read_config(const struct udevice * bus,pci_dev_t bdf,uint offset,ulong * valuep,enum pci_size_t size)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 
octeontx_ecam_write_config(struct udevice * bus,pci_dev_t bdf,uint offset,ulong value,enum pci_size_t size)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 
octeontx_pem_read_config(const struct udevice * bus,pci_dev_t bdf,uint offset,ulong * valuep,enum pci_size_t size)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 
octeontx_pem_write_config(struct udevice * bus,pci_dev_t bdf,uint offset,ulong value,enum pci_size_t 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)
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 
octeontx2_pem_read_config(const struct udevice * bus,pci_dev_t bdf,uint offset,ulong * valuep,enum pci_size_t size)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 
octeontx2_pem_write_config(struct udevice * bus,pci_dev_t bdf,uint offset,ulong value,enum pci_size_t size)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 
pci_octeontx_read_config(const struct udevice * bus,pci_dev_t bdf,uint offset,ulong * valuep,enum pci_size_t size)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 
pci_octeontx_write_config(struct udevice * bus,pci_dev_t bdf,uint offset,ulong value,enum pci_size_t size)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 
pci_octeontx_of_to_plat(struct udevice * dev)315 static int pci_octeontx_of_to_plat(struct udevice *dev)
316 {
317 	return 0;
318 }
319 
pci_octeontx_probe(struct udevice * dev)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 };
366