xref: /openbsd/sys/dev/fdt/bcm2711_pcie.c (revision 09467b48)
1 /*	$OpenBSD: bcm2711_pcie.c,v 1.3 2020/07/14 15:42:19 patrick Exp $	*/
2 /*
3  * Copyright (c) 2020 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/fdt.h>
34 
35 #define PCIE_EXT_CFG_DATA	0x8000
36 #define PCIE_EXT_CFG_INDEX	0x9000
37 
38 #define HREAD4(sc, reg)							\
39 	(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
40 #define HWRITE4(sc, reg, val)						\
41 	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
42 
43 struct bcmpcie_range {
44 	uint32_t		flags;
45 	uint64_t		pci_base;
46 	uint64_t		phys_base;
47 	uint64_t		size;
48 };
49 
50 struct bcmpcie_softc {
51 	struct device		sc_dev;
52 	bus_space_tag_t		sc_iot;
53 	bus_space_handle_t	sc_ioh;
54 
55 	int			sc_node;
56 	int			sc_acells;
57 	int			sc_scells;
58 	int			sc_pacells;
59 	int			sc_pscells;
60 	struct bcmpcie_range	*sc_ranges;
61 	int			sc_nranges;
62 
63 	struct bus_space	sc_bus_iot;
64 	struct bus_space	sc_bus_memt;
65 
66 	struct arm64_pci_chipset sc_pc;
67 	int			sc_bus;
68 };
69 
70 int bcmpcie_match(struct device *, void *, void *);
71 void bcmpcie_attach(struct device *, struct device *, void *);
72 
73 struct cfattach bcmpcie_ca = {
74 	sizeof (struct bcmpcie_softc), bcmpcie_match, bcmpcie_attach
75 };
76 
77 struct cfdriver bcmpcie_cd = {
78 	NULL, "bcmpcie", DV_DULL
79 };
80 
81 int
82 bcmpcie_match(struct device *parent, void *match, void *aux)
83 {
84 	struct fdt_attach_args *faa = aux;
85 
86 	return OF_is_compatible(faa->fa_node, "brcm,bcm2711-pcie");
87 }
88 
89 void	bcmpcie_attach_hook(struct device *, struct device *,
90 	    struct pcibus_attach_args *);
91 int	bcmpcie_bus_maxdevs(void *, int);
92 pcitag_t bcmpcie_make_tag(void *, int, int, int);
93 void	bcmpcie_decompose_tag(void *, pcitag_t, int *, int *, int *);
94 int	bcmpcie_conf_size(void *, pcitag_t);
95 pcireg_t bcmpcie_conf_read(void *, pcitag_t, int);
96 void	bcmpcie_conf_write(void *, pcitag_t, int, pcireg_t);
97 
98 int	bcmpcie_intr_map(struct pci_attach_args *, pci_intr_handle_t *);
99 const char *bcmpcie_intr_string(void *, pci_intr_handle_t);
100 void	*bcmpcie_intr_establish(void *, pci_intr_handle_t, int,
101 	    struct cpu_info *, int (*)(void *), void *, char *);
102 void	bcmpcie_intr_disestablish(void *, void *);
103 
104 int	bcmpcie_bs_iomap(bus_space_tag_t, bus_addr_t, bus_size_t, int,
105 	    bus_space_handle_t *);
106 int	bcmpcie_bs_memmap(bus_space_tag_t, bus_addr_t, bus_size_t, int,
107 	    bus_space_handle_t *);
108 
109 void
110 bcmpcie_attach(struct device *parent, struct device *self, void *aux)
111 {
112 	struct bcmpcie_softc *sc = (struct bcmpcie_softc *)self;
113 	struct fdt_attach_args *faa = aux;
114 	struct pcibus_attach_args pba;
115 	uint32_t *ranges;
116 	int i, j, nranges, rangeslen;
117 
118 	if (faa->fa_nreg < 1) {
119 		printf(": no registers\n");
120 		return;
121 	}
122 
123 	sc->sc_iot = faa->fa_iot;
124 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
125 	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
126 		printf(": can't map registers\n");
127 		return;
128 	}
129 
130 	sc->sc_node = faa->fa_node;
131 
132 	sc->sc_acells = OF_getpropint(sc->sc_node, "#address-cells",
133 	    faa->fa_acells);
134 	sc->sc_scells = OF_getpropint(sc->sc_node, "#size-cells",
135 	    faa->fa_scells);
136 	sc->sc_pacells = faa->fa_acells;
137 	sc->sc_pscells = faa->fa_scells;
138 
139 	rangeslen = OF_getproplen(sc->sc_node, "ranges");
140 	if (rangeslen <= 0 || (rangeslen % sizeof(uint32_t)) ||
141 	     (rangeslen / sizeof(uint32_t)) % (sc->sc_acells +
142 	     sc->sc_pacells + sc->sc_scells)) {
143 		printf(": invalid ranges property\n");
144 		return;
145 	}
146 
147 	ranges = malloc(rangeslen, M_TEMP, M_WAITOK);
148 	OF_getpropintarray(sc->sc_node, "ranges", ranges,
149 	    rangeslen);
150 
151 	nranges = (rangeslen / sizeof(uint32_t)) /
152 	    (sc->sc_acells + sc->sc_pacells + sc->sc_scells);
153 	sc->sc_ranges = mallocarray(nranges,
154 	    sizeof(struct bcmpcie_range), M_TEMP, M_WAITOK);
155 	sc->sc_nranges = nranges;
156 
157 	for (i = 0, j = 0; i < sc->sc_nranges; i++) {
158 		sc->sc_ranges[i].flags = ranges[j++];
159 		sc->sc_ranges[i].pci_base = ranges[j++];
160 		if (sc->sc_acells - 1 == 2) {
161 			sc->sc_ranges[i].pci_base <<= 32;
162 			sc->sc_ranges[i].pci_base |= ranges[j++];
163 		}
164 		sc->sc_ranges[i].phys_base = ranges[j++];
165 		if (sc->sc_pacells == 2) {
166 			sc->sc_ranges[i].phys_base <<= 32;
167 			sc->sc_ranges[i].phys_base |= ranges[j++];
168 		}
169 		sc->sc_ranges[i].size = ranges[j++];
170 		if (sc->sc_scells == 2) {
171 			sc->sc_ranges[i].size <<= 32;
172 			sc->sc_ranges[i].size |= ranges[j++];
173 		}
174 	}
175 
176 	free(ranges, M_TEMP, rangeslen);
177 
178 	printf("\n");
179 
180 	memcpy(&sc->sc_bus_iot, sc->sc_iot, sizeof(sc->sc_bus_iot));
181 	sc->sc_bus_iot.bus_private = sc;
182 	sc->sc_bus_iot._space_map = bcmpcie_bs_iomap;
183 	memcpy(&sc->sc_bus_memt, sc->sc_iot, sizeof(sc->sc_bus_memt));
184 	sc->sc_bus_memt.bus_private = sc;
185 	sc->sc_bus_memt._space_map = bcmpcie_bs_memmap;
186 
187 	sc->sc_pc.pc_conf_v = sc;
188 	sc->sc_pc.pc_attach_hook = bcmpcie_attach_hook;
189 	sc->sc_pc.pc_bus_maxdevs = bcmpcie_bus_maxdevs;
190 	sc->sc_pc.pc_make_tag = bcmpcie_make_tag;
191 	sc->sc_pc.pc_decompose_tag = bcmpcie_decompose_tag;
192 	sc->sc_pc.pc_conf_size = bcmpcie_conf_size;
193 	sc->sc_pc.pc_conf_read = bcmpcie_conf_read;
194 	sc->sc_pc.pc_conf_write = bcmpcie_conf_write;
195 
196 	sc->sc_pc.pc_intr_v = sc;
197 	sc->sc_pc.pc_intr_map = bcmpcie_intr_map;
198 	sc->sc_pc.pc_intr_map_msi = _pci_intr_map_msi;
199 	sc->sc_pc.pc_intr_map_msix = _pci_intr_map_msix;
200 	sc->sc_pc.pc_intr_string = bcmpcie_intr_string;
201 	sc->sc_pc.pc_intr_establish = bcmpcie_intr_establish;
202 	sc->sc_pc.pc_intr_disestablish = bcmpcie_intr_disestablish;
203 
204 	memset(&pba, 0, sizeof(pba));
205 	pba.pba_busname = "pci";
206 	pba.pba_iot = &sc->sc_bus_iot;
207 	pba.pba_memt = &sc->sc_bus_memt;
208 	pba.pba_dmat = faa->fa_dmat;
209 	pba.pba_pc = &sc->sc_pc;
210 	pba.pba_domain = pci_ndomains++;
211 	pba.pba_bus = 0;
212 
213 	config_found(self, &pba, NULL);
214 }
215 
216 void
217 bcmpcie_attach_hook(struct device *parent, struct device *self,
218     struct pcibus_attach_args *pba)
219 {
220 }
221 
222 int
223 bcmpcie_bus_maxdevs(void *v, int bus)
224 {
225 	struct bcmpcie_softc *sc = v;
226 
227 	if (bus == sc->sc_bus || bus == sc->sc_bus + 1)
228 		return 1;
229 	return 32;
230 }
231 
232 pcitag_t
233 bcmpcie_make_tag(void *v, int bus, int device, int function)
234 {
235 	/* Return ECAM address. */
236 	return ((bus << 20) | (device << 15) | (function << 12));
237 }
238 
239 void
240 bcmpcie_decompose_tag(void *v, pcitag_t tag, int *bp, int *dp, int *fp)
241 {
242 	if (bp != NULL)
243 		*bp = (tag >> 20) & 0xff;
244 	if (dp != NULL)
245 		*dp = (tag >> 15) & 0x1f;
246 	if (fp != NULL)
247 		*fp = (tag >> 12) & 0x7;
248 }
249 
250 int
251 bcmpcie_conf_size(void *v, pcitag_t tag)
252 {
253 	return PCIE_CONFIG_SPACE_SIZE;
254 }
255 
256 pcireg_t
257 bcmpcie_conf_read(void *v, pcitag_t tag, int reg)
258 {
259 	struct bcmpcie_softc *sc = v;
260 	int bus, dev, fn;
261 
262 	bcmpcie_decompose_tag(sc, tag, &bus, &dev, &fn);
263 	if (bus == 0) {
264 		KASSERT(dev == 0);
265 		return HREAD4(sc, tag | reg);
266 	}
267 
268 	HWRITE4(sc, PCIE_EXT_CFG_INDEX, tag);
269 	return HREAD4(sc, PCIE_EXT_CFG_DATA + reg);
270 }
271 
272 void
273 bcmpcie_conf_write(void *v, pcitag_t tag, int reg, pcireg_t data)
274 {
275 	struct bcmpcie_softc *sc = v;
276 	int bus, dev, fn;
277 
278 	bcmpcie_decompose_tag(sc, tag, &bus, &dev, &fn);
279 	if (bus == 0) {
280 		KASSERT(dev == 0);
281 		HWRITE4(sc, tag | reg, data);
282 		return;
283 	}
284 
285 	HWRITE4(sc, PCIE_EXT_CFG_INDEX, tag);
286 	HWRITE4(sc, PCIE_EXT_CFG_DATA + reg, data);
287 }
288 
289 int
290 bcmpcie_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
291 {
292 	int pin = pa->pa_rawintrpin;
293 
294 	if (pin == 0 || pin > PCI_INTERRUPT_PIN_MAX)
295 		return -1;
296 
297 	if (pa->pa_tag == 0)
298 		return -1;
299 
300 	ihp->ih_pc = pa->pa_pc;
301 	ihp->ih_tag = pa->pa_intrtag;
302 	ihp->ih_intrpin = pa->pa_intrpin;
303 	ihp->ih_type = PCI_INTX;
304 
305 	return 0;
306 }
307 
308 const char *
309 bcmpcie_intr_string(void *v, pci_intr_handle_t ih)
310 {
311 	switch (ih.ih_type) {
312 	case PCI_MSI:
313 		return "msi";
314 	case PCI_MSIX:
315 		return "msix";
316 	}
317 
318 	return "intx";
319 }
320 
321 void *
322 bcmpcie_intr_establish(void *v, pci_intr_handle_t ih, int level,
323     struct cpu_info *ci, int (*func)(void *), void *arg, char *name)
324 {
325 	struct bcmpcie_softc *sc = v;
326 	int bus, dev, fn;
327 	uint32_t reg[4];
328 
329 	KASSERT(ih.ih_type == PCI_INTX);
330 	bcmpcie_decompose_tag(sc, ih.ih_tag, &bus, &dev, &fn);
331 
332 	reg[0] = bus << 16 | dev << 11 | fn << 8;
333 	reg[1] = reg[2] = 0;
334 	reg[3] = ih.ih_intrpin;
335 
336 	return fdt_intr_establish_imap_cpu(sc->sc_node, reg, sizeof(reg),
337 	    level, ci, func, arg, name);
338 }
339 
340 void
341 bcmpcie_intr_disestablish(void *v, void *cookie)
342 {
343 }
344 
345 int
346 bcmpcie_bs_iomap(bus_space_tag_t t, bus_addr_t addr, bus_size_t size,
347     int flags, bus_space_handle_t *bshp)
348 {
349 	struct bcmpcie_softc *sc = t->bus_private;
350 	int i;
351 
352 	for (i = 0; i < sc->sc_nranges; i++) {
353 		uint64_t pci_start = sc->sc_ranges[i].pci_base;
354 		uint64_t pci_end = pci_start + sc->sc_ranges[i].size;
355 		uint64_t phys_start = sc->sc_ranges[i].phys_base;
356 
357 		if ((sc->sc_ranges[i].flags & 0x03000000) == 0x01000000 &&
358 		    addr >= pci_start && addr + size <= pci_end) {
359 			return bus_space_map(sc->sc_iot,
360 			    addr - pci_start + phys_start, size, flags, bshp);
361 		}
362 	}
363 
364 	return ENXIO;
365 }
366 
367 int
368 bcmpcie_bs_memmap(bus_space_tag_t t, bus_addr_t addr, bus_size_t size,
369     int flags, bus_space_handle_t *bshp)
370 {
371 	struct bcmpcie_softc *sc = t->bus_private;
372 	int i;
373 
374 	for (i = 0; i < sc->sc_nranges; i++) {
375 		uint64_t pci_start = sc->sc_ranges[i].pci_base;
376 		uint64_t pci_end = pci_start + sc->sc_ranges[i].size;
377 		uint64_t phys_start = sc->sc_ranges[i].phys_base;
378 
379 		if ((sc->sc_ranges[i].flags & 0x03000000) == 0x02000000 &&
380 		    addr >= pci_start && addr + size <= pci_end) {
381 			return bus_space_map(sc->sc_iot,
382 			    addr - pci_start + phys_start, size, flags, bshp);
383 		}
384 	}
385 
386 	return ENXIO;
387 }
388