xref: /openbsd/sys/dev/fdt/bcm2711_pcie.c (revision 2ee472d0)
1*2ee472d0Spatrick /*	$OpenBSD: bcm2711_pcie.c,v 1.13 2024/03/27 15:15:00 patrick Exp $	*/
2e40d0fbfSkettenis /*
3e40d0fbfSkettenis  * Copyright (c) 2020 Mark Kettenis <kettenis@openbsd.org>
4e40d0fbfSkettenis  *
5e40d0fbfSkettenis  * Permission to use, copy, modify, and distribute this software for any
6e40d0fbfSkettenis  * purpose with or without fee is hereby granted, provided that the above
7e40d0fbfSkettenis  * copyright notice and this permission notice appear in all copies.
8e40d0fbfSkettenis  *
9e40d0fbfSkettenis  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10e40d0fbfSkettenis  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11e40d0fbfSkettenis  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12e40d0fbfSkettenis  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13e40d0fbfSkettenis  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14e40d0fbfSkettenis  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15e40d0fbfSkettenis  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16e40d0fbfSkettenis  */
17e40d0fbfSkettenis 
18e40d0fbfSkettenis #include <sys/param.h>
19e40d0fbfSkettenis #include <sys/systm.h>
20e40d0fbfSkettenis #include <sys/device.h>
21e40d0fbfSkettenis #include <sys/extent.h>
22e40d0fbfSkettenis #include <sys/malloc.h>
23e40d0fbfSkettenis 
24e40d0fbfSkettenis #include <machine/intr.h>
25e40d0fbfSkettenis #include <machine/bus.h>
26e40d0fbfSkettenis #include <machine/fdt.h>
27*2ee472d0Spatrick #include <machine/simplebusvar.h>
28e40d0fbfSkettenis 
29e40d0fbfSkettenis #include <dev/pci/pcidevs.h>
30e40d0fbfSkettenis #include <dev/pci/pcireg.h>
31e40d0fbfSkettenis #include <dev/pci/pcivar.h>
326f7ca46aSkettenis #include <dev/pci/ppbreg.h>
33e40d0fbfSkettenis 
34e40d0fbfSkettenis #include <dev/ofw/openfirm.h>
35e40d0fbfSkettenis #include <dev/ofw/fdt.h>
36e40d0fbfSkettenis 
376f7ca46aSkettenis #define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO		0x400c
386f7ca46aSkettenis #define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_HI		0x4010
396f7ca46aSkettenis #define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT	0x4070
406f7ca46aSkettenis #define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI		0x4080
416f7ca46aSkettenis #define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI		0x4084
42e40d0fbfSkettenis #define PCIE_EXT_CFG_DATA				0x8000
43e40d0fbfSkettenis #define PCIE_EXT_CFG_INDEX				0x9000
44054189b2Skettenis #define PCIE_RGR1_SW_INIT_1				0x9210
45054189b2Skettenis #define  PCIE_RGR1_SW_INIT_1_PERST_MASK			(1 << 0)
46054189b2Skettenis #define  PCIE_RGR1_SW_INIT_1_INIT_MASK			(1 << 1)
47e40d0fbfSkettenis 
48e40d0fbfSkettenis #define HREAD4(sc, reg)							\
49e40d0fbfSkettenis 	(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
50e40d0fbfSkettenis #define HWRITE4(sc, reg, val)						\
51e40d0fbfSkettenis 	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
52e40d0fbfSkettenis 
53e40d0fbfSkettenis struct bcmpcie_range {
54e40d0fbfSkettenis 	uint32_t		flags;
55e40d0fbfSkettenis 	uint64_t		pci_base;
56e40d0fbfSkettenis 	uint64_t		phys_base;
57e40d0fbfSkettenis 	uint64_t		size;
58e40d0fbfSkettenis };
59e40d0fbfSkettenis 
60e40d0fbfSkettenis struct bcmpcie_softc {
61*2ee472d0Spatrick 	struct simplebus_softc	sc_sbus;
62e40d0fbfSkettenis 	bus_space_tag_t		sc_iot;
63e40d0fbfSkettenis 	bus_space_handle_t	sc_ioh;
64b943319fSkettenis 	bus_dma_tag_t		sc_dmat;
65e40d0fbfSkettenis 
66e40d0fbfSkettenis 	int			sc_node;
67e40d0fbfSkettenis 	int			sc_acells;
68e40d0fbfSkettenis 	int			sc_scells;
69e40d0fbfSkettenis 	int			sc_pacells;
70e40d0fbfSkettenis 	int			sc_pscells;
71e40d0fbfSkettenis 	struct bcmpcie_range	*sc_ranges;
72e40d0fbfSkettenis 	int			sc_nranges;
73b943319fSkettenis 	struct bcmpcie_range	*sc_dmaranges;
74b943319fSkettenis 	int			sc_ndmaranges;
75e40d0fbfSkettenis 
76e40d0fbfSkettenis 	struct bus_space	sc_bus_iot;
77e40d0fbfSkettenis 	struct bus_space	sc_bus_memt;
78e40d0fbfSkettenis 
79b943319fSkettenis 	struct machine_bus_dma_tag sc_dma;
80b943319fSkettenis 
812b0be198Skettenis 	struct machine_pci_chipset sc_pc;
82e40d0fbfSkettenis 	int			sc_bus;
83e40d0fbfSkettenis };
84e40d0fbfSkettenis 
85e40d0fbfSkettenis int bcmpcie_match(struct device *, void *, void *);
86e40d0fbfSkettenis void bcmpcie_attach(struct device *, struct device *, void *);
87e40d0fbfSkettenis 
88471aeecfSnaddy const struct cfattach bcmpcie_ca = {
89e40d0fbfSkettenis 	sizeof (struct bcmpcie_softc), bcmpcie_match, bcmpcie_attach
90e40d0fbfSkettenis };
91e40d0fbfSkettenis 
92e40d0fbfSkettenis struct cfdriver bcmpcie_cd = {
93e40d0fbfSkettenis 	NULL, "bcmpcie", DV_DULL
94e40d0fbfSkettenis };
95e40d0fbfSkettenis 
96e40d0fbfSkettenis int
bcmpcie_match(struct device * parent,void * match,void * aux)97e40d0fbfSkettenis bcmpcie_match(struct device *parent, void *match, void *aux)
98e40d0fbfSkettenis {
99e40d0fbfSkettenis 	struct fdt_attach_args *faa = aux;
100e40d0fbfSkettenis 
101*2ee472d0Spatrick 	return OF_is_compatible(faa->fa_node, "brcm,bcm2711-pcie") ||
102*2ee472d0Spatrick 	    OF_is_compatible(faa->fa_node, "brcm,bcm2712-pcie");
103e40d0fbfSkettenis }
104e40d0fbfSkettenis 
105*2ee472d0Spatrick int	bcmpcie_submatch(struct device *, void *, void *);
106e40d0fbfSkettenis void	bcmpcie_attach_hook(struct device *, struct device *,
107e40d0fbfSkettenis 	    struct pcibus_attach_args *);
108e40d0fbfSkettenis int	bcmpcie_bus_maxdevs(void *, int);
109e40d0fbfSkettenis pcitag_t bcmpcie_make_tag(void *, int, int, int);
110e40d0fbfSkettenis void	bcmpcie_decompose_tag(void *, pcitag_t, int *, int *, int *);
111e40d0fbfSkettenis int	bcmpcie_conf_size(void *, pcitag_t);
112e40d0fbfSkettenis pcireg_t bcmpcie_conf_read(void *, pcitag_t, int);
113e40d0fbfSkettenis void	bcmpcie_conf_write(void *, pcitag_t, int, pcireg_t);
114619b146dSpatrick int	bcmpcie_probe_device_hook(void *, struct pci_attach_args *);
115e40d0fbfSkettenis 
116e40d0fbfSkettenis int	bcmpcie_intr_map(struct pci_attach_args *, pci_intr_handle_t *);
117e40d0fbfSkettenis const char *bcmpcie_intr_string(void *, pci_intr_handle_t);
118e40d0fbfSkettenis void	*bcmpcie_intr_establish(void *, pci_intr_handle_t, int,
119d67371fdSpatrick 	    struct cpu_info *, int (*)(void *), void *, char *);
120e40d0fbfSkettenis void	bcmpcie_intr_disestablish(void *, void *);
121e40d0fbfSkettenis 
122e40d0fbfSkettenis int	bcmpcie_bs_iomap(bus_space_tag_t, bus_addr_t, bus_size_t, int,
123e40d0fbfSkettenis 	    bus_space_handle_t *);
124e40d0fbfSkettenis int	bcmpcie_bs_memmap(bus_space_tag_t, bus_addr_t, bus_size_t, int,
125e40d0fbfSkettenis 	    bus_space_handle_t *);
126b943319fSkettenis int	bcmpcie_dmamap_load_buffer(bus_dma_tag_t, bus_dmamap_t, void *,
127b943319fSkettenis 	    bus_size_t, struct proc *, int, paddr_t *, int *, int);
128eb76c742Skettenis int	bcmpcie_dmamap_load_raw(bus_dma_tag_t, bus_dmamap_t,
129eb76c742Skettenis 	    bus_dma_segment_t *, int, bus_size_t, int);
130e40d0fbfSkettenis 
131e40d0fbfSkettenis void
bcmpcie_attach(struct device * parent,struct device * self,void * aux)132e40d0fbfSkettenis bcmpcie_attach(struct device *parent, struct device *self, void *aux)
133e40d0fbfSkettenis {
134e40d0fbfSkettenis 	struct bcmpcie_softc *sc = (struct bcmpcie_softc *)self;
135e40d0fbfSkettenis 	struct fdt_attach_args *faa = aux;
136e40d0fbfSkettenis 	struct pcibus_attach_args pba;
137e40d0fbfSkettenis 	uint32_t *ranges;
138e40d0fbfSkettenis 	int i, j, nranges, rangeslen;
139054189b2Skettenis 	uint32_t reg;
140e40d0fbfSkettenis 
141148b84e4Skettenis 	if (faa->fa_nreg < 1) {
142e40d0fbfSkettenis 		printf(": no registers\n");
143e40d0fbfSkettenis 		return;
144e40d0fbfSkettenis 	}
145e40d0fbfSkettenis 
146e40d0fbfSkettenis 	sc->sc_iot = faa->fa_iot;
147e40d0fbfSkettenis 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
148e40d0fbfSkettenis 	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
149e40d0fbfSkettenis 		printf(": can't map registers\n");
150e40d0fbfSkettenis 		return;
151e40d0fbfSkettenis 	}
152e40d0fbfSkettenis 
153054189b2Skettenis 	reg = HREAD4(sc, PCIE_RGR1_SW_INIT_1);
154054189b2Skettenis 	if (reg & PCIE_RGR1_SW_INIT_1_INIT_MASK) {
155054189b2Skettenis 		printf(": disabled\n");
156054189b2Skettenis 		return;
157054189b2Skettenis 	}
158054189b2Skettenis 
159e40d0fbfSkettenis 	sc->sc_node = faa->fa_node;
160b943319fSkettenis 	sc->sc_dmat = faa->fa_dmat;
161e40d0fbfSkettenis 
162e40d0fbfSkettenis 	sc->sc_acells = OF_getpropint(sc->sc_node, "#address-cells",
163e40d0fbfSkettenis 	    faa->fa_acells);
164e40d0fbfSkettenis 	sc->sc_scells = OF_getpropint(sc->sc_node, "#size-cells",
165e40d0fbfSkettenis 	    faa->fa_scells);
166e40d0fbfSkettenis 	sc->sc_pacells = faa->fa_acells;
167e40d0fbfSkettenis 	sc->sc_pscells = faa->fa_scells;
168e40d0fbfSkettenis 
169b943319fSkettenis 	/* Memory and IO space translations. */
170e40d0fbfSkettenis 	rangeslen = OF_getproplen(sc->sc_node, "ranges");
171e40d0fbfSkettenis 	if (rangeslen <= 0 || (rangeslen % sizeof(uint32_t)) ||
172e40d0fbfSkettenis 	     (rangeslen / sizeof(uint32_t)) % (sc->sc_acells +
173e40d0fbfSkettenis 	     sc->sc_pacells + sc->sc_scells)) {
174e40d0fbfSkettenis 		printf(": invalid ranges property\n");
175e40d0fbfSkettenis 		return;
176e40d0fbfSkettenis 	}
177e40d0fbfSkettenis 
178e40d0fbfSkettenis 	ranges = malloc(rangeslen, M_TEMP, M_WAITOK);
179e40d0fbfSkettenis 	OF_getpropintarray(sc->sc_node, "ranges", ranges,
180e40d0fbfSkettenis 	    rangeslen);
181e40d0fbfSkettenis 
182e40d0fbfSkettenis 	nranges = (rangeslen / sizeof(uint32_t)) /
183e40d0fbfSkettenis 	    (sc->sc_acells + sc->sc_pacells + sc->sc_scells);
184e40d0fbfSkettenis 	sc->sc_ranges = mallocarray(nranges,
185b943319fSkettenis 	    sizeof(struct bcmpcie_range), M_DEVBUF, M_WAITOK);
186e40d0fbfSkettenis 	sc->sc_nranges = nranges;
187e40d0fbfSkettenis 
188e40d0fbfSkettenis 	for (i = 0, j = 0; i < sc->sc_nranges; i++) {
189e40d0fbfSkettenis 		sc->sc_ranges[i].flags = ranges[j++];
190e40d0fbfSkettenis 		sc->sc_ranges[i].pci_base = ranges[j++];
191e40d0fbfSkettenis 		if (sc->sc_acells - 1 == 2) {
192e40d0fbfSkettenis 			sc->sc_ranges[i].pci_base <<= 32;
193e40d0fbfSkettenis 			sc->sc_ranges[i].pci_base |= ranges[j++];
194e40d0fbfSkettenis 		}
195e40d0fbfSkettenis 		sc->sc_ranges[i].phys_base = ranges[j++];
196e40d0fbfSkettenis 		if (sc->sc_pacells == 2) {
197e40d0fbfSkettenis 			sc->sc_ranges[i].phys_base <<= 32;
198e40d0fbfSkettenis 			sc->sc_ranges[i].phys_base |= ranges[j++];
199e40d0fbfSkettenis 		}
200e40d0fbfSkettenis 		sc->sc_ranges[i].size = ranges[j++];
201e40d0fbfSkettenis 		if (sc->sc_scells == 2) {
202e40d0fbfSkettenis 			sc->sc_ranges[i].size <<= 32;
203e40d0fbfSkettenis 			sc->sc_ranges[i].size |= ranges[j++];
204e40d0fbfSkettenis 		}
205e40d0fbfSkettenis 	}
206e40d0fbfSkettenis 
207e40d0fbfSkettenis 	free(ranges, M_TEMP, rangeslen);
208e40d0fbfSkettenis 
209b943319fSkettenis 	/* DMA translations */
210b943319fSkettenis 	rangeslen = OF_getproplen(sc->sc_node, "dma-ranges");
211b943319fSkettenis 	if (rangeslen > 0) {
212b943319fSkettenis 		if ((rangeslen % sizeof(uint32_t)) ||
213b943319fSkettenis 		     (rangeslen / sizeof(uint32_t)) % (sc->sc_acells +
214b943319fSkettenis 		     sc->sc_pacells + sc->sc_scells)) {
215b943319fSkettenis 			printf(": invalid dma-ranges property\n");
216b943319fSkettenis 			free(sc->sc_ranges, M_DEVBUF,
217b943319fSkettenis 			    sc->sc_nranges * sizeof(struct bcmpcie_range));
218b943319fSkettenis 			return;
219b943319fSkettenis 		}
220b943319fSkettenis 
221b943319fSkettenis 		ranges = malloc(rangeslen, M_TEMP, M_WAITOK);
222b943319fSkettenis 		OF_getpropintarray(sc->sc_node, "dma-ranges", ranges,
223b943319fSkettenis 		    rangeslen);
224b943319fSkettenis 
225b943319fSkettenis 		nranges = (rangeslen / sizeof(uint32_t)) /
226b943319fSkettenis 		    (sc->sc_acells + sc->sc_pacells + sc->sc_scells);
227b943319fSkettenis 		sc->sc_dmaranges = mallocarray(nranges,
228b943319fSkettenis 		    sizeof(struct bcmpcie_range), M_DEVBUF, M_WAITOK);
229b943319fSkettenis 		sc->sc_ndmaranges = nranges;
230b943319fSkettenis 
231b943319fSkettenis 		for (i = 0, j = 0; i < sc->sc_ndmaranges; i++) {
232b943319fSkettenis 			sc->sc_dmaranges[i].flags = ranges[j++];
233b943319fSkettenis 			sc->sc_dmaranges[i].pci_base = ranges[j++];
234b943319fSkettenis 			if (sc->sc_acells - 1 == 2) {
235b943319fSkettenis 				sc->sc_dmaranges[i].pci_base <<= 32;
236b943319fSkettenis 				sc->sc_dmaranges[i].pci_base |= ranges[j++];
237b943319fSkettenis 			}
238b943319fSkettenis 			sc->sc_dmaranges[i].phys_base = ranges[j++];
239b943319fSkettenis 			if (sc->sc_pacells == 2) {
240b943319fSkettenis 				sc->sc_dmaranges[i].phys_base <<= 32;
241b943319fSkettenis 				sc->sc_dmaranges[i].phys_base |= ranges[j++];
242b943319fSkettenis 			}
243b943319fSkettenis 			sc->sc_dmaranges[i].size = ranges[j++];
244b943319fSkettenis 			if (sc->sc_scells == 2) {
245b943319fSkettenis 				sc->sc_dmaranges[i].size <<= 32;
246b943319fSkettenis 				sc->sc_dmaranges[i].size |= ranges[j++];
247b943319fSkettenis 			}
248b943319fSkettenis 		}
249b943319fSkettenis 
250b943319fSkettenis 		free(ranges, M_TEMP, rangeslen);
251b943319fSkettenis 	}
252b943319fSkettenis 
2536f7ca46aSkettenis 	/*
2546f7ca46aSkettenis 	 * Reprogram the outbound window to match the configuration in
2556f7ca46aSkettenis 	 * the device tree.  This is necessary since the EDK2-based
2566f7ca46aSkettenis 	 * UEFI firmware reprograms the window.
2576f7ca46aSkettenis 	 */
2586f7ca46aSkettenis 	for (i = 0; i < sc->sc_nranges; i++) {
2596f7ca46aSkettenis 		if ((sc->sc_ranges[i].flags & 0x03000000) == 0x02000000) {
2606f7ca46aSkettenis 			uint64_t cpu_base = sc->sc_ranges[i].phys_base;
2616f7ca46aSkettenis 			uint64_t cpu_limit = sc->sc_ranges[i].phys_base +
2626f7ca46aSkettenis 			    sc->sc_ranges[i].size - 1;
2636f7ca46aSkettenis 
2646f7ca46aSkettenis 			HWRITE4(sc, PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO,
2656f7ca46aSkettenis 			    sc->sc_ranges[i].pci_base);
2666f7ca46aSkettenis 			HWRITE4(sc, PCIE_MISC_CPU_2_PCIE_MEM_WIN0_HI,
2676f7ca46aSkettenis 			    sc->sc_ranges[i].pci_base >> 32);
2686f7ca46aSkettenis 			HWRITE4(sc, PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT,
2696f7ca46aSkettenis 			    (cpu_base & PPB_MEM_MASK) >> PPB_MEM_SHIFT |
2706f7ca46aSkettenis 			    (cpu_limit & PPB_MEM_MASK));
2716f7ca46aSkettenis 			HWRITE4(sc, PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI,
2726f7ca46aSkettenis 			    cpu_base >> 32);
2736f7ca46aSkettenis 			HWRITE4(sc, PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI,
2746f7ca46aSkettenis 			    cpu_limit >> 32);
2756f7ca46aSkettenis 		}
2766f7ca46aSkettenis 	}
2776f7ca46aSkettenis 
278e40d0fbfSkettenis 	memcpy(&sc->sc_bus_iot, sc->sc_iot, sizeof(sc->sc_bus_iot));
279e40d0fbfSkettenis 	sc->sc_bus_iot.bus_private = sc;
280e40d0fbfSkettenis 	sc->sc_bus_iot._space_map = bcmpcie_bs_iomap;
281e40d0fbfSkettenis 	memcpy(&sc->sc_bus_memt, sc->sc_iot, sizeof(sc->sc_bus_memt));
282e40d0fbfSkettenis 	sc->sc_bus_memt.bus_private = sc;
283e40d0fbfSkettenis 	sc->sc_bus_memt._space_map = bcmpcie_bs_memmap;
284e40d0fbfSkettenis 
285b943319fSkettenis 	memcpy(&sc->sc_dma, sc->sc_dmat, sizeof(sc->sc_dma));
286b943319fSkettenis 	sc->sc_dma._dmamap_load_buffer = bcmpcie_dmamap_load_buffer;
287eb76c742Skettenis 	sc->sc_dma._dmamap_load_raw = bcmpcie_dmamap_load_raw;
288b943319fSkettenis 	sc->sc_dma._cookie = sc;
289b943319fSkettenis 
290e40d0fbfSkettenis 	sc->sc_pc.pc_conf_v = sc;
291e40d0fbfSkettenis 	sc->sc_pc.pc_attach_hook = bcmpcie_attach_hook;
292e40d0fbfSkettenis 	sc->sc_pc.pc_bus_maxdevs = bcmpcie_bus_maxdevs;
293e40d0fbfSkettenis 	sc->sc_pc.pc_make_tag = bcmpcie_make_tag;
294e40d0fbfSkettenis 	sc->sc_pc.pc_decompose_tag = bcmpcie_decompose_tag;
295e40d0fbfSkettenis 	sc->sc_pc.pc_conf_size = bcmpcie_conf_size;
296e40d0fbfSkettenis 	sc->sc_pc.pc_conf_read = bcmpcie_conf_read;
297e40d0fbfSkettenis 	sc->sc_pc.pc_conf_write = bcmpcie_conf_write;
298619b146dSpatrick 	sc->sc_pc.pc_probe_device_hook = bcmpcie_probe_device_hook;
299e40d0fbfSkettenis 
300e40d0fbfSkettenis 	sc->sc_pc.pc_intr_v = sc;
301e40d0fbfSkettenis 	sc->sc_pc.pc_intr_map = bcmpcie_intr_map;
302e40d0fbfSkettenis 	sc->sc_pc.pc_intr_map_msi = _pci_intr_map_msi;
30356d02c00Skettenis 	sc->sc_pc.pc_intr_map_msivec = _pci_intr_map_msivec;
304e40d0fbfSkettenis 	sc->sc_pc.pc_intr_map_msix = _pci_intr_map_msix;
305e40d0fbfSkettenis 	sc->sc_pc.pc_intr_string = bcmpcie_intr_string;
306e40d0fbfSkettenis 	sc->sc_pc.pc_intr_establish = bcmpcie_intr_establish;
307e40d0fbfSkettenis 	sc->sc_pc.pc_intr_disestablish = bcmpcie_intr_disestablish;
308e40d0fbfSkettenis 
309e40d0fbfSkettenis 	memset(&pba, 0, sizeof(pba));
310e40d0fbfSkettenis 	pba.pba_busname = "pci";
311e40d0fbfSkettenis 	pba.pba_iot = &sc->sc_bus_iot;
312e40d0fbfSkettenis 	pba.pba_memt = &sc->sc_bus_memt;
313b943319fSkettenis 	pba.pba_dmat = &sc->sc_dma;
314e40d0fbfSkettenis 	pba.pba_pc = &sc->sc_pc;
315e40d0fbfSkettenis 	pba.pba_domain = pci_ndomains++;
316e40d0fbfSkettenis 	pba.pba_bus = 0;
317e40d0fbfSkettenis 
318*2ee472d0Spatrick 	/* Attach device tree nodes enumerating PCIe bus */
319*2ee472d0Spatrick 	simplebus_attach(parent, &sc->sc_sbus.sc_dev, faa);
320*2ee472d0Spatrick 
321*2ee472d0Spatrick 	config_found_sm(self, &pba, NULL, bcmpcie_submatch);
322*2ee472d0Spatrick }
323*2ee472d0Spatrick 
324*2ee472d0Spatrick int
bcmpcie_submatch(struct device * self,void * match,void * aux)325*2ee472d0Spatrick bcmpcie_submatch(struct device *self, void *match, void *aux)
326*2ee472d0Spatrick {
327*2ee472d0Spatrick 	struct cfdata *cf = match;
328*2ee472d0Spatrick 	struct pcibus_attach_args *pba = aux;
329*2ee472d0Spatrick 
330*2ee472d0Spatrick 	if (strcmp(pba->pba_busname, cf->cf_driver->cd_name) != 0)
331*2ee472d0Spatrick 		return 0;
332*2ee472d0Spatrick 
333*2ee472d0Spatrick 	return (*cf->cf_attach->ca_match)(self, match, aux);
334e40d0fbfSkettenis }
335e40d0fbfSkettenis 
336e40d0fbfSkettenis void
bcmpcie_attach_hook(struct device * parent,struct device * self,struct pcibus_attach_args * pba)337e40d0fbfSkettenis bcmpcie_attach_hook(struct device *parent, struct device *self,
338e40d0fbfSkettenis     struct pcibus_attach_args *pba)
339e40d0fbfSkettenis {
340e40d0fbfSkettenis }
341e40d0fbfSkettenis 
342e40d0fbfSkettenis int
bcmpcie_bus_maxdevs(void * v,int bus)343e40d0fbfSkettenis bcmpcie_bus_maxdevs(void *v, int bus)
344e40d0fbfSkettenis {
345e40d0fbfSkettenis 	struct bcmpcie_softc *sc = v;
346e40d0fbfSkettenis 
347e40d0fbfSkettenis 	if (bus == sc->sc_bus || bus == sc->sc_bus + 1)
348e40d0fbfSkettenis 		return 1;
349e40d0fbfSkettenis 	return 32;
350e40d0fbfSkettenis }
351e40d0fbfSkettenis 
352e40d0fbfSkettenis pcitag_t
bcmpcie_make_tag(void * v,int bus,int device,int function)353e40d0fbfSkettenis bcmpcie_make_tag(void *v, int bus, int device, int function)
354e40d0fbfSkettenis {
355e40d0fbfSkettenis 	/* Return ECAM address. */
356e40d0fbfSkettenis 	return ((bus << 20) | (device << 15) | (function << 12));
357e40d0fbfSkettenis }
358e40d0fbfSkettenis 
359e40d0fbfSkettenis void
bcmpcie_decompose_tag(void * v,pcitag_t tag,int * bp,int * dp,int * fp)360e40d0fbfSkettenis bcmpcie_decompose_tag(void *v, pcitag_t tag, int *bp, int *dp, int *fp)
361e40d0fbfSkettenis {
362e40d0fbfSkettenis 	if (bp != NULL)
363e40d0fbfSkettenis 		*bp = (tag >> 20) & 0xff;
364e40d0fbfSkettenis 	if (dp != NULL)
365e40d0fbfSkettenis 		*dp = (tag >> 15) & 0x1f;
366e40d0fbfSkettenis 	if (fp != NULL)
367e40d0fbfSkettenis 		*fp = (tag >> 12) & 0x7;
368e40d0fbfSkettenis }
369e40d0fbfSkettenis 
370e40d0fbfSkettenis int
bcmpcie_conf_size(void * v,pcitag_t tag)371e40d0fbfSkettenis bcmpcie_conf_size(void *v, pcitag_t tag)
372e40d0fbfSkettenis {
373e40d0fbfSkettenis 	return PCIE_CONFIG_SPACE_SIZE;
374e40d0fbfSkettenis }
375e40d0fbfSkettenis 
376e40d0fbfSkettenis pcireg_t
bcmpcie_conf_read(void * v,pcitag_t tag,int reg)377e40d0fbfSkettenis bcmpcie_conf_read(void *v, pcitag_t tag, int reg)
378e40d0fbfSkettenis {
379e40d0fbfSkettenis 	struct bcmpcie_softc *sc = v;
380e40d0fbfSkettenis 	int bus, dev, fn;
381e40d0fbfSkettenis 
382e40d0fbfSkettenis 	bcmpcie_decompose_tag(sc, tag, &bus, &dev, &fn);
383e40d0fbfSkettenis 	if (bus == 0) {
384e40d0fbfSkettenis 		KASSERT(dev == 0);
385e40d0fbfSkettenis 		return HREAD4(sc, tag | reg);
386e40d0fbfSkettenis 	}
387e40d0fbfSkettenis 
388e40d0fbfSkettenis 	HWRITE4(sc, PCIE_EXT_CFG_INDEX, tag);
389e40d0fbfSkettenis 	return HREAD4(sc, PCIE_EXT_CFG_DATA + reg);
390e40d0fbfSkettenis }
391e40d0fbfSkettenis 
392e40d0fbfSkettenis void
bcmpcie_conf_write(void * v,pcitag_t tag,int reg,pcireg_t data)393e40d0fbfSkettenis bcmpcie_conf_write(void *v, pcitag_t tag, int reg, pcireg_t data)
394e40d0fbfSkettenis {
395e40d0fbfSkettenis 	struct bcmpcie_softc *sc = v;
396e40d0fbfSkettenis 	int bus, dev, fn;
397e40d0fbfSkettenis 
398e40d0fbfSkettenis 	bcmpcie_decompose_tag(sc, tag, &bus, &dev, &fn);
399e40d0fbfSkettenis 	if (bus == 0) {
400e40d0fbfSkettenis 		KASSERT(dev == 0);
401e40d0fbfSkettenis 		HWRITE4(sc, tag | reg, data);
402e40d0fbfSkettenis 		return;
403e40d0fbfSkettenis 	}
404e40d0fbfSkettenis 
405e40d0fbfSkettenis 	HWRITE4(sc, PCIE_EXT_CFG_INDEX, tag);
406e40d0fbfSkettenis 	HWRITE4(sc, PCIE_EXT_CFG_DATA + reg, data);
407e40d0fbfSkettenis }
408e40d0fbfSkettenis 
409e40d0fbfSkettenis int
bcmpcie_probe_device_hook(void * v,struct pci_attach_args * pa)410619b146dSpatrick bcmpcie_probe_device_hook(void *v, struct pci_attach_args *pa)
411619b146dSpatrick {
412619b146dSpatrick 	return 0;
413619b146dSpatrick }
414619b146dSpatrick 
415619b146dSpatrick int
bcmpcie_intr_map(struct pci_attach_args * pa,pci_intr_handle_t * ihp)416e40d0fbfSkettenis bcmpcie_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
417e40d0fbfSkettenis {
418e40d0fbfSkettenis 	int pin = pa->pa_rawintrpin;
419e40d0fbfSkettenis 
420e40d0fbfSkettenis 	if (pin == 0 || pin > PCI_INTERRUPT_PIN_MAX)
421e40d0fbfSkettenis 		return -1;
422e40d0fbfSkettenis 
423e40d0fbfSkettenis 	if (pa->pa_tag == 0)
424e40d0fbfSkettenis 		return -1;
425e40d0fbfSkettenis 
426e40d0fbfSkettenis 	ihp->ih_pc = pa->pa_pc;
427e40d0fbfSkettenis 	ihp->ih_tag = pa->pa_intrtag;
428e40d0fbfSkettenis 	ihp->ih_intrpin = pa->pa_intrpin;
429e40d0fbfSkettenis 	ihp->ih_type = PCI_INTX;
430e40d0fbfSkettenis 
431e40d0fbfSkettenis 	return 0;
432e40d0fbfSkettenis }
433e40d0fbfSkettenis 
434e40d0fbfSkettenis const char *
bcmpcie_intr_string(void * v,pci_intr_handle_t ih)435e40d0fbfSkettenis bcmpcie_intr_string(void *v, pci_intr_handle_t ih)
436e40d0fbfSkettenis {
437e40d0fbfSkettenis 	switch (ih.ih_type) {
438e40d0fbfSkettenis 	case PCI_MSI:
439e40d0fbfSkettenis 		return "msi";
440e40d0fbfSkettenis 	case PCI_MSIX:
441e40d0fbfSkettenis 		return "msix";
442e40d0fbfSkettenis 	}
443e40d0fbfSkettenis 
444e40d0fbfSkettenis 	return "intx";
445e40d0fbfSkettenis }
446e40d0fbfSkettenis 
447e40d0fbfSkettenis void *
bcmpcie_intr_establish(void * v,pci_intr_handle_t ih,int level,struct cpu_info * ci,int (* func)(void *),void * arg,char * name)448e40d0fbfSkettenis bcmpcie_intr_establish(void *v, pci_intr_handle_t ih, int level,
449d67371fdSpatrick     struct cpu_info *ci, int (*func)(void *), void *arg, char *name)
450e40d0fbfSkettenis {
451e40d0fbfSkettenis 	struct bcmpcie_softc *sc = v;
452e40d0fbfSkettenis 	int bus, dev, fn;
453e40d0fbfSkettenis 	uint32_t reg[4];
454e40d0fbfSkettenis 
455e40d0fbfSkettenis 	KASSERT(ih.ih_type == PCI_INTX);
456e40d0fbfSkettenis 	bcmpcie_decompose_tag(sc, ih.ih_tag, &bus, &dev, &fn);
457e40d0fbfSkettenis 
458e40d0fbfSkettenis 	reg[0] = bus << 16 | dev << 11 | fn << 8;
459e40d0fbfSkettenis 	reg[1] = reg[2] = 0;
460e40d0fbfSkettenis 	reg[3] = ih.ih_intrpin;
461e40d0fbfSkettenis 
462d67371fdSpatrick 	return fdt_intr_establish_imap_cpu(sc->sc_node, reg, sizeof(reg),
463d67371fdSpatrick 	    level, ci, func, arg, name);
464e40d0fbfSkettenis }
465e40d0fbfSkettenis 
466e40d0fbfSkettenis void
bcmpcie_intr_disestablish(void * v,void * cookie)467e40d0fbfSkettenis bcmpcie_intr_disestablish(void *v, void *cookie)
468e40d0fbfSkettenis {
469e40d0fbfSkettenis }
470e40d0fbfSkettenis 
471e40d0fbfSkettenis int
bcmpcie_bs_iomap(bus_space_tag_t t,bus_addr_t addr,bus_size_t size,int flags,bus_space_handle_t * bshp)472e40d0fbfSkettenis bcmpcie_bs_iomap(bus_space_tag_t t, bus_addr_t addr, bus_size_t size,
473e40d0fbfSkettenis     int flags, bus_space_handle_t *bshp)
474e40d0fbfSkettenis {
475e40d0fbfSkettenis 	struct bcmpcie_softc *sc = t->bus_private;
476e40d0fbfSkettenis 	int i;
477e40d0fbfSkettenis 
478e40d0fbfSkettenis 	for (i = 0; i < sc->sc_nranges; i++) {
479e40d0fbfSkettenis 		uint64_t pci_start = sc->sc_ranges[i].pci_base;
480e40d0fbfSkettenis 		uint64_t pci_end = pci_start + sc->sc_ranges[i].size;
481e40d0fbfSkettenis 		uint64_t phys_start = sc->sc_ranges[i].phys_base;
482e40d0fbfSkettenis 
483e40d0fbfSkettenis 		if ((sc->sc_ranges[i].flags & 0x03000000) == 0x01000000 &&
484e40d0fbfSkettenis 		    addr >= pci_start && addr + size <= pci_end) {
485e40d0fbfSkettenis 			return bus_space_map(sc->sc_iot,
486e40d0fbfSkettenis 			    addr - pci_start + phys_start, size, flags, bshp);
487e40d0fbfSkettenis 		}
488e40d0fbfSkettenis 	}
489e40d0fbfSkettenis 
490e40d0fbfSkettenis 	return ENXIO;
491e40d0fbfSkettenis }
492e40d0fbfSkettenis 
493e40d0fbfSkettenis int
bcmpcie_bs_memmap(bus_space_tag_t t,bus_addr_t addr,bus_size_t size,int flags,bus_space_handle_t * bshp)494e40d0fbfSkettenis bcmpcie_bs_memmap(bus_space_tag_t t, bus_addr_t addr, bus_size_t size,
495e40d0fbfSkettenis     int flags, bus_space_handle_t *bshp)
496e40d0fbfSkettenis {
497e40d0fbfSkettenis 	struct bcmpcie_softc *sc = t->bus_private;
498e40d0fbfSkettenis 	int i;
499e40d0fbfSkettenis 
500e40d0fbfSkettenis 	for (i = 0; i < sc->sc_nranges; i++) {
501e40d0fbfSkettenis 		uint64_t pci_start = sc->sc_ranges[i].pci_base;
502e40d0fbfSkettenis 		uint64_t pci_end = pci_start + sc->sc_ranges[i].size;
503e40d0fbfSkettenis 		uint64_t phys_start = sc->sc_ranges[i].phys_base;
504e40d0fbfSkettenis 
505e40d0fbfSkettenis 		if ((sc->sc_ranges[i].flags & 0x03000000) == 0x02000000 &&
506e40d0fbfSkettenis 		    addr >= pci_start && addr + size <= pci_end) {
507e40d0fbfSkettenis 			return bus_space_map(sc->sc_iot,
508e40d0fbfSkettenis 			    addr - pci_start + phys_start, size, flags, bshp);
509e40d0fbfSkettenis 		}
510e40d0fbfSkettenis 	}
511e40d0fbfSkettenis 
512e40d0fbfSkettenis 	return ENXIO;
513e40d0fbfSkettenis }
514b943319fSkettenis 
515b943319fSkettenis int
bcmpcie_dmamap_load_buffer(bus_dma_tag_t t,bus_dmamap_t map,void * buf,bus_size_t buflen,struct proc * p,int flags,paddr_t * lastaddrp,int * segp,int first)516b943319fSkettenis bcmpcie_dmamap_load_buffer(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
517b943319fSkettenis     bus_size_t buflen, struct proc *p, int flags, paddr_t *lastaddrp,
518b943319fSkettenis     int *segp, int first)
519b943319fSkettenis {
520b943319fSkettenis 	struct bcmpcie_softc *sc = t->_cookie;
521b943319fSkettenis 	int seg, firstseg = *segp;
522b943319fSkettenis 	int error;
523b943319fSkettenis 
524b943319fSkettenis 	error = sc->sc_dmat->_dmamap_load_buffer(sc->sc_dmat, map, buf, buflen,
525b943319fSkettenis 	    p, flags, lastaddrp, segp, first);
526b943319fSkettenis 	if (error)
527b943319fSkettenis 		return error;
528b943319fSkettenis 
529b943319fSkettenis 	if (sc->sc_dmaranges == NULL)
530b943319fSkettenis 		return 0;
531b943319fSkettenis 
532b943319fSkettenis 	/* For each segment. */
533b943319fSkettenis 	for (seg = firstseg; seg <= *segp; seg++) {
534b943319fSkettenis 		uint64_t addr = map->dm_segs[seg].ds_addr;
535b943319fSkettenis 		uint64_t size = map->dm_segs[seg].ds_len;
536b943319fSkettenis 		int i;
537b943319fSkettenis 
538b943319fSkettenis 		/* For each range. */
539b943319fSkettenis 		for (i = 0; i < sc->sc_ndmaranges; i++) {
540b943319fSkettenis 			uint64_t pci_start = sc->sc_dmaranges[i].pci_base;
541b943319fSkettenis 			uint64_t phys_start = sc->sc_dmaranges[i].phys_base;
542b943319fSkettenis 			uint64_t phys_end = phys_start +
543b943319fSkettenis 			    sc->sc_dmaranges[i].size;
544b943319fSkettenis 
545b943319fSkettenis 			if (addr >= phys_start && addr + size <= phys_end) {
546b943319fSkettenis 				map->dm_segs[seg].ds_addr -= phys_start;
547b943319fSkettenis 				map->dm_segs[seg].ds_addr += pci_start;
548b943319fSkettenis 				break;
549b943319fSkettenis 			}
550b943319fSkettenis 		}
551b943319fSkettenis 
552b943319fSkettenis 		if (i == sc->sc_ndmaranges)
553b943319fSkettenis 			return EINVAL;
554b943319fSkettenis 	}
555b943319fSkettenis 
556b943319fSkettenis 	return 0;
557b943319fSkettenis }
558eb76c742Skettenis 
559eb76c742Skettenis int
bcmpcie_dmamap_load_raw(bus_dma_tag_t t,bus_dmamap_t map,bus_dma_segment_t * segs,int nsegs,bus_size_t size,int flags)560eb76c742Skettenis bcmpcie_dmamap_load_raw(bus_dma_tag_t t, bus_dmamap_t map,
561eb76c742Skettenis     bus_dma_segment_t *segs, int nsegs, bus_size_t size, int flags)
562eb76c742Skettenis {
563eb76c742Skettenis 	struct bcmpcie_softc *sc = t->_cookie;
564eb76c742Skettenis 	int seg, error;
565eb76c742Skettenis 
566eb76c742Skettenis 	error = sc->sc_dmat->_dmamap_load_raw(sc->sc_dmat, map,
567eb76c742Skettenis 	     segs, nsegs, size, flags);
568eb76c742Skettenis 	if (error)
569eb76c742Skettenis 		return error;
570eb76c742Skettenis 
571a8a0f531Skettenis 	if (sc->sc_dmaranges == NULL)
572a8a0f531Skettenis 		return 0;
573a8a0f531Skettenis 
574eb76c742Skettenis 	/* For each segment. */
575eb76c742Skettenis 	for (seg = 0; seg < map->dm_nsegs; seg++) {
576eb76c742Skettenis 		uint64_t addr = map->dm_segs[seg].ds_addr;
577eb76c742Skettenis 		uint64_t size = map->dm_segs[seg].ds_len;
578eb76c742Skettenis 		int i;
579eb76c742Skettenis 
580eb76c742Skettenis 		/* For each range. */
581eb76c742Skettenis 		for (i = 0; i < sc->sc_ndmaranges; i++) {
582eb76c742Skettenis 			uint64_t pci_start = sc->sc_dmaranges[i].pci_base;
583eb76c742Skettenis 			uint64_t phys_start = sc->sc_dmaranges[i].phys_base;
584eb76c742Skettenis 			uint64_t phys_end = phys_start +
585eb76c742Skettenis 			    sc->sc_dmaranges[i].size;
586eb76c742Skettenis 
587eb76c742Skettenis 			if (addr >= phys_start && addr + size <= phys_end) {
588eb76c742Skettenis 				map->dm_segs[seg].ds_addr -= phys_start;
589eb76c742Skettenis 				map->dm_segs[seg].ds_addr += pci_start;
590eb76c742Skettenis 				break;
591eb76c742Skettenis 			}
592eb76c742Skettenis 		}
593eb76c742Skettenis 
594eb76c742Skettenis 		if (i == sc->sc_ndmaranges)
595eb76c742Skettenis 			return EINVAL;
596eb76c742Skettenis 	}
597eb76c742Skettenis 
598eb76c742Skettenis 	return 0;
599eb76c742Skettenis }
600