xref: /openbsd-src/sys/arch/arm64/dev/aplpcie.c (revision f1dd7b858388b4a23f4f67a4957ec5ff656ebbe8)
1 /*	$OpenBSD: aplpcie.c,v 1.1 2021/02/26 11:09:23 kettenis Exp $	*/
2 /*
3  * Copyright (c) 2021 Mark Kettenis <kettenis@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/param.h>
19 #include <sys/systm.h>
20 #include <sys/device.h>
21 #include <sys/extent.h>
22 #include <sys/malloc.h>
23 
24 #include <machine/intr.h>
25 #include <machine/bus.h>
26 #include <machine/fdt.h>
27 
28 #include <dev/pci/pcidevs.h>
29 #include <dev/pci/pcireg.h>
30 #include <dev/pci/pcivar.h>
31 
32 #include <dev/ofw/openfirm.h>
33 #include <dev/ofw/ofw_misc.h>
34 #include <dev/ofw/fdt.h>
35 
36 /*
37  * This driver is based on preliminary device tree bindings and will
38  * almost certainly need changes once the official bindings land in
39  * mainline Linux.  Support for these preliminary bindings will be
40  * dropped as soon as official bindings are available.
41  *
42  * The driver assumes that the hardware has been (almost) completely
43  * initialized by U-Boot.  More code will be needed to support
44  * alternate boot paths.
45  */
46 
47 #define PCIE_MSI_CTRL		0x0124
48 #define  PCIE_MSI_CTRL_ENABLE	(1 << 0)
49 #define  PCIE_MSI_CTRL_32	(5 << 4)
50 #define PCIE_MSI_REMAP		0x0128
51 #define PCIE_MSI_DOORBELL	0x0168
52 
53 #define HREAD4(sc, reg)							\
54 	(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
55 #define HWRITE4(sc, reg, val)						\
56 	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
57 
58 struct aplpcie_range {
59 	uint32_t		flags;
60 	uint64_t		pci_base;
61 	uint64_t		phys_base;
62 	uint64_t		size;
63 };
64 
65 struct aplpcie_softc {
66 	struct device		sc_dev;
67 	bus_space_tag_t		sc_iot;
68 	bus_space_handle_t	sc_ioh;
69 	bus_space_handle_t	sc_port_ioh[3];
70 	bus_dma_tag_t		sc_dmat;
71 
72 	int			sc_node;
73 	int			sc_acells;
74 	int			sc_scells;
75 	int			sc_pacells;
76 	int			sc_pscells;
77 	struct aplpcie_range	*sc_ranges;
78 	int			sc_nranges;
79 
80 	struct bus_space	sc_bus_iot;
81 	struct bus_space	sc_bus_memt;
82 
83 	struct arm64_pci_chipset sc_pc;
84 	struct extent		*sc_busex;
85 	struct extent		*sc_memex;
86 	struct extent		*sc_pmemex;
87 	struct extent		*sc_ioex;
88 	int			sc_bus;
89 
90 	int			sc_msi;
91 	bus_addr_t		sc_msi_doorbell;
92 };
93 
94 int	aplpcie_match(struct device *, void *, void *);
95 void	aplpcie_attach(struct device *, struct device *, void *);
96 
97 struct cfattach	aplpcie_ca = {
98 	sizeof (struct aplpcie_softc), aplpcie_match, aplpcie_attach
99 };
100 
101 struct cfdriver aplpcie_cd = {
102 	NULL, "aplpcie", DV_DULL
103 };
104 
105 int
106 aplpcie_match(struct device *parent, void *match, void *aux)
107 {
108 	struct fdt_attach_args *faa = aux;
109 
110 	return OF_is_compatible(faa->fa_node, "apple,pcie-m1");
111 }
112 
113 void	aplpcie_attach_hook(struct device *, struct device *,
114 	    struct pcibus_attach_args *);
115 int	aplpcie_bus_maxdevs(void *, int);
116 pcitag_t aplpcie_make_tag(void *, int, int, int);
117 void	aplpcie_decompose_tag(void *, pcitag_t, int *, int *, int *);
118 int	aplpcie_conf_size(void *, pcitag_t);
119 pcireg_t aplpcie_conf_read(void *, pcitag_t, int);
120 void	aplpcie_conf_write(void *, pcitag_t, int, pcireg_t);
121 int	aplpcie_probe_device_hook(void *, struct pci_attach_args *);
122 
123 int	aplpcie_intr_map(struct pci_attach_args *, pci_intr_handle_t *);
124 const char *aplpcie_intr_string(void *, pci_intr_handle_t);
125 void	*aplpcie_intr_establish(void *, pci_intr_handle_t, int,
126 	    struct cpu_info *, int (*)(void *), void *, char *);
127 void	aplpcie_intr_disestablish(void *, void *);
128 
129 int	aplpcie_bs_iomap(bus_space_tag_t, bus_addr_t, bus_size_t, int,
130 	    bus_space_handle_t *);
131 int	aplpcie_bs_memmap(bus_space_tag_t, bus_addr_t, bus_size_t, int,
132 	    bus_space_handle_t *);
133 
134 void
135 aplpcie_attach(struct device *parent, struct device *self, void *aux)
136 {
137 	struct aplpcie_softc *sc = (struct aplpcie_softc *)self;
138 	struct fdt_attach_args *faa = aux;
139 	struct pcibus_attach_args pba;
140 	uint32_t *ranges;
141 	int i, j, nranges, rangeslen;
142 	uint32_t bus_range[2];
143 
144 	if (faa->fa_nreg < 6) {
145 		printf(": no registers\n");
146 		return;
147 	}
148 
149 	sc->sc_iot = faa->fa_iot;
150 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
151 	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
152 		printf(": can't map registers\n");
153 		return;
154 	}
155 
156 	for (i = 3; i < 6; i++) {
157 		if (bus_space_map(sc->sc_iot, faa->fa_reg[i].addr,
158 		    faa->fa_reg[i].size, 0, &sc->sc_port_ioh[i - 3])) {
159 			printf(": can't map registers\n");
160 			return;
161 		}
162 	}
163 
164 	sc->sc_dmat = faa->fa_dmat;
165 	sc->sc_node = faa->fa_node;
166 	printf("\n");
167 
168 	sc->sc_msi_doorbell =
169 	    OF_getpropint64(sc->sc_node, "msi-doorbell", 0xffff000ULL);
170 
171 	/*
172 	 * Set things up such that we can share the 32 available MSIs
173 	 * across all ports.
174 	 */
175 	for (i = 0; i < 3; i++) {
176 		bus_space_write_4(sc->sc_iot, sc->sc_port_ioh[i],
177 		    PCIE_MSI_CTRL, PCIE_MSI_CTRL_32 | PCIE_MSI_CTRL_ENABLE);
178 		bus_space_write_4(sc->sc_iot, sc->sc_port_ioh[i],
179 		    PCIE_MSI_REMAP, 0);
180 		bus_space_write_4(sc->sc_iot, sc->sc_port_ioh[i],
181 		    PCIE_MSI_DOORBELL, sc->sc_msi_doorbell);
182 	}
183 	sc->sc_msi = 0;
184 
185 	sc->sc_acells = OF_getpropint(sc->sc_node, "#address-cells",
186 	    faa->fa_acells);
187 	sc->sc_scells = OF_getpropint(sc->sc_node, "#size-cells",
188 	    faa->fa_scells);
189 	sc->sc_pacells = faa->fa_acells;
190 	sc->sc_pscells = faa->fa_scells;
191 
192 	rangeslen = OF_getproplen(sc->sc_node, "ranges");
193 	if (rangeslen <= 0 || (rangeslen % sizeof(uint32_t)) ||
194 	     (rangeslen / sizeof(uint32_t)) % (sc->sc_acells +
195 	     sc->sc_pacells + sc->sc_scells)) {
196 		printf(": invalid ranges property\n");
197 		return;
198 	}
199 
200 	ranges = malloc(rangeslen, M_TEMP, M_WAITOK);
201 	OF_getpropintarray(sc->sc_node, "ranges", ranges,
202 	    rangeslen);
203 
204 	nranges = (rangeslen / sizeof(uint32_t)) /
205 	    (sc->sc_acells + sc->sc_pacells + sc->sc_scells);
206 	sc->sc_ranges = mallocarray(nranges,
207 	    sizeof(struct aplpcie_range), M_TEMP, M_WAITOK);
208 	sc->sc_nranges = nranges;
209 
210 	for (i = 0, j = 0; i < sc->sc_nranges; i++) {
211 		sc->sc_ranges[i].flags = ranges[j++];
212 		sc->sc_ranges[i].pci_base = ranges[j++];
213 		if (sc->sc_acells - 1 == 2) {
214 			sc->sc_ranges[i].pci_base <<= 32;
215 			sc->sc_ranges[i].pci_base |= ranges[j++];
216 		}
217 		sc->sc_ranges[i].phys_base = ranges[j++];
218 		if (sc->sc_pacells == 2) {
219 			sc->sc_ranges[i].phys_base <<= 32;
220 			sc->sc_ranges[i].phys_base |= ranges[j++];
221 		}
222 		sc->sc_ranges[i].size = ranges[j++];
223 		if (sc->sc_scells == 2) {
224 			sc->sc_ranges[i].size <<= 32;
225 			sc->sc_ranges[i].size |= ranges[j++];
226 		}
227 	}
228 
229 	free(ranges, M_TEMP, rangeslen);
230 
231 	/* Create extents for our address spaces. */
232 	sc->sc_busex = extent_create("pcibus", 0, 255,
233 	    M_DEVBUF, NULL, 0, EX_WAITOK | EX_FILLED);
234 	sc->sc_memex = extent_create("pcimem", 0, (u_long)-1,
235 	    M_DEVBUF, NULL, 0, EX_WAITOK | EX_FILLED);
236 	sc->sc_pmemex = extent_create("pcipmem", 0, (u_long)-1,
237 	    M_DEVBUF, NULL, 0, EX_WAITOK | EX_FILLED);
238 	sc->sc_ioex = extent_create("pciio", 0, 0xffffffff,
239 	    M_DEVBUF, NULL, 0, EX_WAITOK | EX_FILLED);
240 	for (i = 0; i < sc->sc_nranges; i++) {
241 		if ((sc->sc_ranges[i].flags & 0x03000000) == 0x01000000) {
242 			extent_free(sc->sc_ioex, sc->sc_ranges[i].pci_base,
243 			    sc->sc_ranges[i].size, EX_WAITOK);
244 		}
245 		if ((sc->sc_ranges[i].flags & 0x03000000) == 0x02000000) {
246 			extent_free(sc->sc_memex, sc->sc_ranges[i].pci_base,
247 			    sc->sc_ranges[i].size, EX_WAITOK);
248 		}
249 		if ((sc->sc_ranges[i].flags & 0x03000000) == 0x03000000) {
250 			extent_free(sc->sc_pmemex, sc->sc_ranges[i].pci_base,
251 			    sc->sc_ranges[i].size, EX_WAITOK);
252 		}
253 	}
254 
255 	/* Set up bus range. */
256 	if (OF_getpropintarray(sc->sc_node, "bus-range", bus_range,
257 	    sizeof(bus_range)) != sizeof(bus_range) ||
258 	    bus_range[0] >= 32 || bus_range[1] >= 32) {
259 		bus_range[0] = 0;
260 		bus_range[1] = 31;
261 	}
262 	sc->sc_bus = bus_range[0];
263 	extent_free(sc->sc_busex, bus_range[0],
264 	    bus_range[1] - bus_range[0] + 1, EX_WAITOK);
265 
266 	memcpy(&sc->sc_bus_iot, sc->sc_iot, sizeof(sc->sc_bus_iot));
267 	sc->sc_bus_iot.bus_private = sc;
268 	sc->sc_bus_iot._space_map = aplpcie_bs_iomap;
269 	memcpy(&sc->sc_bus_memt, sc->sc_iot, sizeof(sc->sc_bus_memt));
270 	sc->sc_bus_memt.bus_private = sc;
271 	sc->sc_bus_memt._space_map = aplpcie_bs_memmap;
272 
273 	sc->sc_pc.pc_conf_v = sc;
274 	sc->sc_pc.pc_attach_hook = aplpcie_attach_hook;
275 	sc->sc_pc.pc_bus_maxdevs = aplpcie_bus_maxdevs;
276 	sc->sc_pc.pc_make_tag = aplpcie_make_tag;
277 	sc->sc_pc.pc_decompose_tag = aplpcie_decompose_tag;
278 	sc->sc_pc.pc_conf_size = aplpcie_conf_size;
279 	sc->sc_pc.pc_conf_read = aplpcie_conf_read;
280 	sc->sc_pc.pc_conf_write = aplpcie_conf_write;
281 	sc->sc_pc.pc_probe_device_hook = aplpcie_probe_device_hook;
282 
283 	sc->sc_pc.pc_intr_v = sc;
284 	sc->sc_pc.pc_intr_map = aplpcie_intr_map;
285 	sc->sc_pc.pc_intr_map_msi = _pci_intr_map_msi;
286 	sc->sc_pc.pc_intr_map_msix = _pci_intr_map_msix;
287 	sc->sc_pc.pc_intr_string = aplpcie_intr_string;
288 	sc->sc_pc.pc_intr_establish = aplpcie_intr_establish;
289 	sc->sc_pc.pc_intr_disestablish = aplpcie_intr_disestablish;
290 
291 	memset(&pba, 0, sizeof(pba));
292 	pba.pba_busname = "pci";
293 	pba.pba_iot = &sc->sc_bus_iot;
294 	pba.pba_memt = &sc->sc_bus_memt;
295 	pba.pba_dmat = sc->sc_dmat;
296 	pba.pba_pc = &sc->sc_pc;
297 	pba.pba_busex = sc->sc_busex;
298 	pba.pba_memex = sc->sc_memex;
299 	pba.pba_pmemex = sc->sc_pmemex;
300 	pba.pba_ioex = sc->sc_ioex;
301 	pba.pba_domain = pci_ndomains++;
302 	pba.pba_bus = sc->sc_bus;
303 	pba.pba_flags |= PCI_FLAGS_MSI_ENABLED;
304 
305 	config_found(self, &pba, NULL);
306 }
307 
308 void
309 aplpcie_attach_hook(struct device *parent, struct device *self,
310     struct pcibus_attach_args *pba)
311 {
312 }
313 
314 int
315 aplpcie_bus_maxdevs(void *v, int bus)
316 {
317 	return 32;
318 }
319 
320 pcitag_t
321 aplpcie_make_tag(void *v, int bus, int device, int function)
322 {
323 	/* Return ECAM address. */
324 	return ((bus << 20) | (device << 15) | (function << 12));
325 }
326 
327 void
328 aplpcie_decompose_tag(void *v, pcitag_t tag, int *bp, int *dp, int *fp)
329 {
330 	if (bp != NULL)
331 		*bp = (tag >> 20) & 0xff;
332 	if (dp != NULL)
333 		*dp = (tag >> 15) & 0x1f;
334 	if (fp != NULL)
335 		*fp = (tag >> 12) & 0x7;
336 }
337 
338 int
339 aplpcie_conf_size(void *v, pcitag_t tag)
340 {
341 	return PCIE_CONFIG_SPACE_SIZE;
342 }
343 
344 pcireg_t
345 aplpcie_conf_read(void *v, pcitag_t tag, int reg)
346 {
347 	struct aplpcie_softc *sc = v;
348 
349 	return HREAD4(sc, tag | reg);
350 }
351 
352 void
353 aplpcie_conf_write(void *v, pcitag_t tag, int reg, pcireg_t data)
354 {
355 	struct aplpcie_softc *sc = v;
356 
357 	HWRITE4(sc, tag | reg, data);
358 }
359 
360 int
361 aplpcie_probe_device_hook(void *v, struct pci_attach_args *pa)
362 {
363 	struct aplpcie_softc *sc = v;
364 	uint16_t rid;
365 
366 	rid = pci_requester_id(pa->pa_pc, pa->pa_tag);
367 	pa->pa_dmat = iommu_device_map_pci(sc->sc_node, rid, pa->pa_dmat);
368 
369 	return 0;
370 }
371 
372 int
373 aplpcie_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
374 {
375 	int pin = pa->pa_rawintrpin;
376 
377 	if (pin == 0 || pin > PCI_INTERRUPT_PIN_MAX)
378 		return -1;
379 
380 	if (pa->pa_tag == 0)
381 		return -1;
382 
383 	ihp->ih_pc = pa->pa_pc;
384 	ihp->ih_tag = pa->pa_intrtag;
385 	ihp->ih_intrpin = pa->pa_intrpin;
386 	ihp->ih_type = PCI_INTX;
387 
388 	return 0;
389 }
390 
391 const char *
392 aplpcie_intr_string(void *v, pci_intr_handle_t ih)
393 {
394 	switch (ih.ih_type) {
395 	case PCI_MSI:
396 		return "msi";
397 	case PCI_MSIX:
398 		return "msix";
399 	}
400 
401 	return "intx";
402 }
403 
404 void *
405 aplpcie_intr_establish(void *v, pci_intr_handle_t ih, int level,
406     struct cpu_info *ci, int (*func)(void *), void *arg, char *name)
407 {
408 	struct aplpcie_softc *sc = v;
409 	void *cookie;
410 
411 	KASSERT(ih.ih_type != PCI_NONE);
412 
413 	if (ih.ih_type != PCI_INTX) {
414 		uint64_t addr, data;
415 
416 		data = sc->sc_msi++;
417 		addr = sc->sc_msi_doorbell;
418 		cookie = fdt_intr_establish_idx_cpu(sc->sc_node, 3 + data,
419 		    level, ci, func, arg, (void *)name);
420 		if (cookie == NULL)
421 			return NULL;
422 
423 		if (ih.ih_type == PCI_MSIX) {
424 			pci_msix_enable(ih.ih_pc, ih.ih_tag,
425 			    &sc->sc_bus_memt, ih.ih_intrpin, addr, data);
426 		} else
427 			pci_msi_enable(ih.ih_pc, ih.ih_tag, addr, data);
428 	} else {
429 		int bus, dev, fn;
430 		uint32_t reg[4];
431 
432 		aplpcie_decompose_tag(sc, ih.ih_tag, &bus, &dev, &fn);
433 
434 		reg[0] = bus << 16 | dev << 11 | fn << 8;
435 		reg[1] = reg[2] = 0;
436 		reg[3] = ih.ih_intrpin;
437 
438 		cookie = fdt_intr_establish_imap_cpu(sc->sc_node, reg,
439 		    sizeof(reg), level, ci, func, arg, name);
440 	}
441 
442 	return cookie;
443 }
444 
445 void
446 aplpcie_intr_disestablish(void *v, void *cookie)
447 {
448 }
449 
450 int
451 aplpcie_bs_iomap(bus_space_tag_t t, bus_addr_t addr, bus_size_t size,
452     int flags, bus_space_handle_t *bshp)
453 {
454 	struct aplpcie_softc *sc = t->bus_private;
455 	int i;
456 
457 	for (i = 0; i < sc->sc_nranges; i++) {
458 		uint64_t pci_start = sc->sc_ranges[i].pci_base;
459 		uint64_t pci_end = pci_start + sc->sc_ranges[i].size;
460 		uint64_t phys_start = sc->sc_ranges[i].phys_base;
461 
462 		if ((sc->sc_ranges[i].flags & 0x03000000) == 0x01000000 &&
463 		    addr >= pci_start && addr + size <= pci_end) {
464 			return bus_space_map(sc->sc_iot,
465 			    addr - pci_start + phys_start, size, flags, bshp);
466 		}
467 	}
468 
469 	return ENXIO;
470 }
471 
472 int
473 aplpcie_bs_memmap(bus_space_tag_t t, bus_addr_t addr, bus_size_t size,
474     int flags, bus_space_handle_t *bshp)
475 {
476 	struct aplpcie_softc *sc = t->bus_private;
477 	int i;
478 
479 	flags |= BUS_SPACE_MAP_POSTED;
480 
481 	for (i = 0; i < sc->sc_nranges; i++) {
482 		uint64_t pci_start = sc->sc_ranges[i].pci_base;
483 		uint64_t pci_end = pci_start + sc->sc_ranges[i].size;
484 		uint64_t phys_start = sc->sc_ranges[i].phys_base;
485 
486 		if ((sc->sc_ranges[i].flags & 0x02000000) == 0x02000000 &&
487 		    addr >= pci_start && addr + size <= pci_end) {
488 			return bus_space_map(sc->sc_iot,
489 			    addr - pci_start + phys_start, size, flags, bshp);
490 		}
491 	}
492 
493 	return ENXIO;
494 }
495