xref: /openbsd-src/sys/arch/arm64/dev/simplebus.c (revision 94673892b7b28179327a9d4cb100f53993b0bd92)
1*94673892Sjsg /* $OpenBSD: simplebus.c,v 1.18 2023/09/22 01:10:43 jsg Exp $ */
2f24071e5Spatrick /*
3f24071e5Spatrick  * Copyright (c) 2016 Patrick Wildt <patrick@blueri.se>
4f24071e5Spatrick  *
5f24071e5Spatrick  * Permission to use, copy, modify, and distribute this software for any
6f24071e5Spatrick  * purpose with or without fee is hereby granted, provided that the above
7f24071e5Spatrick  * copyright notice and this permission notice appear in all copies.
8f24071e5Spatrick  *
9f24071e5Spatrick  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10f24071e5Spatrick  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11f24071e5Spatrick  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12f24071e5Spatrick  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13f24071e5Spatrick  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14f24071e5Spatrick  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15f24071e5Spatrick  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16f24071e5Spatrick  */
17f24071e5Spatrick 
18f24071e5Spatrick #include <sys/param.h>
19f24071e5Spatrick #include <sys/systm.h>
20f24071e5Spatrick #include <sys/kernel.h>
21f24071e5Spatrick #include <sys/device.h>
22f24071e5Spatrick #include <sys/malloc.h>
23f24071e5Spatrick 
241d276ec2Spatrick #include <machine/fdt.h>
25f24071e5Spatrick #include <dev/ofw/openfirm.h>
26f24071e5Spatrick #include <dev/ofw/fdt.h>
271d276ec2Spatrick #include <dev/ofw/ofw_misc.h>
28f24071e5Spatrick 
29*94673892Sjsg #include <machine/fdt.h>
30*94673892Sjsg #include <machine/simplebusvar.h>
31f24071e5Spatrick 
32f24071e5Spatrick int simplebus_match(struct device *, void *, void *);
33f24071e5Spatrick void simplebus_attach(struct device *, struct device *, void *);
34f24071e5Spatrick 
35f24071e5Spatrick void simplebus_attach_node(struct device *, int);
363e99d0b8Skettenis int simplebus_bs_map(bus_space_tag_t, bus_addr_t, bus_size_t, int,
373e99d0b8Skettenis     bus_space_handle_t *);
38d0a66818Skettenis paddr_t simplebus_bs_mmap(bus_space_tag_t, bus_addr_t, off_t, int, int);
393e99d0b8Skettenis int simplebus_dmamap_load_buffer(bus_dma_tag_t, bus_dmamap_t, void *,
403e99d0b8Skettenis     bus_size_t, struct proc *, int, paddr_t *, int *, int);
41d068a9bdSkettenis int simplebus_dmamap_load_raw(bus_dma_tag_t, bus_dmamap_t,
42d068a9bdSkettenis     bus_dma_segment_t *, int, bus_size_t, int);
43f24071e5Spatrick 
449fdf0c62Smpi const struct cfattach simplebus_ca = {
45fc955b36Skettenis 	sizeof(struct simplebus_softc), simplebus_match, simplebus_attach
46f24071e5Spatrick };
47f24071e5Spatrick 
48f24071e5Spatrick struct cfdriver simplebus_cd = {
49f24071e5Spatrick 	NULL, "simplebus", DV_DULL
50f24071e5Spatrick };
51f24071e5Spatrick 
52f24071e5Spatrick /*
53f24071e5Spatrick  * Simplebus is a generic bus with no special casings.
54f24071e5Spatrick  */
55f24071e5Spatrick int
simplebus_match(struct device * parent,void * cfdata,void * aux)56f24071e5Spatrick simplebus_match(struct device *parent, void *cfdata, void *aux)
57f24071e5Spatrick {
58f24071e5Spatrick 	struct fdt_attach_args *fa = (struct fdt_attach_args *)aux;
59f24071e5Spatrick 
60f24071e5Spatrick 	if (fa->fa_node == 0)
61f24071e5Spatrick 		return (0);
62f24071e5Spatrick 
631ffa54ffSpatrick 	/* Qualcomm GENI can mostly be treated as simple-bus. */
641ffa54ffSpatrick 	if (OF_is_compatible(fa->fa_node, "qcom,geni-se-qup"))
651ffa54ffSpatrick 		return (1);
661ffa54ffSpatrick 
67f24071e5Spatrick 	if (!OF_is_compatible(fa->fa_node, "simple-bus"))
68f24071e5Spatrick 		return (0);
69f24071e5Spatrick 
70f24071e5Spatrick 	return (1);
71f24071e5Spatrick }
72f24071e5Spatrick 
73f24071e5Spatrick void
simplebus_attach(struct device * parent,struct device * self,void * aux)74f24071e5Spatrick simplebus_attach(struct device *parent, struct device *self, void *aux)
75f24071e5Spatrick {
76f24071e5Spatrick 	struct simplebus_softc *sc = (struct simplebus_softc *)self;
77f24071e5Spatrick 	struct fdt_attach_args *fa = (struct fdt_attach_args *)aux;
78f24071e5Spatrick 	char name[32];
79f24071e5Spatrick 	int node;
80f24071e5Spatrick 
81f24071e5Spatrick 	sc->sc_node = fa->fa_node;
82f24071e5Spatrick 	sc->sc_iot = fa->fa_iot;
83f24071e5Spatrick 	sc->sc_dmat = fa->fa_dmat;
84f24071e5Spatrick 	sc->sc_acells = OF_getpropint(sc->sc_node, "#address-cells",
85f24071e5Spatrick 	    fa->fa_acells);
86f24071e5Spatrick 	sc->sc_scells = OF_getpropint(sc->sc_node, "#size-cells",
87f24071e5Spatrick 	    fa->fa_scells);
88f24071e5Spatrick 	sc->sc_pacells = fa->fa_acells;
89f24071e5Spatrick 	sc->sc_pscells = fa->fa_scells;
90f24071e5Spatrick 
91f24071e5Spatrick 	if (OF_getprop(sc->sc_node, "name", name, sizeof(name)) > 0) {
92f24071e5Spatrick 		name[sizeof(name) - 1] = 0;
93f24071e5Spatrick 		printf(": \"%s\"", name);
94f24071e5Spatrick 	}
95f24071e5Spatrick 
96f24071e5Spatrick 	printf("\n");
97f24071e5Spatrick 
98f24071e5Spatrick 	memcpy(&sc->sc_bus, sc->sc_iot, sizeof(sc->sc_bus));
99f24071e5Spatrick 	sc->sc_bus.bus_private = sc;
100f24071e5Spatrick 	sc->sc_bus._space_map = simplebus_bs_map;
101d0a66818Skettenis 	sc->sc_bus._space_mmap = simplebus_bs_mmap;
102f24071e5Spatrick 
103f24071e5Spatrick 	sc->sc_rangeslen = OF_getproplen(sc->sc_node, "ranges");
1043e99d0b8Skettenis 	if (sc->sc_rangeslen > 0 &&
1053e99d0b8Skettenis 	    (sc->sc_rangeslen % sizeof(uint32_t)) == 0) {
106f24071e5Spatrick 		sc->sc_ranges = malloc(sc->sc_rangeslen, M_TEMP, M_WAITOK);
107f24071e5Spatrick 		OF_getpropintarray(sc->sc_node, "ranges", sc->sc_ranges,
108f24071e5Spatrick 		    sc->sc_rangeslen);
109f24071e5Spatrick 	}
110f24071e5Spatrick 
1113e99d0b8Skettenis 	memcpy(&sc->sc_dma, sc->sc_dmat, sizeof(sc->sc_dma));
1123e99d0b8Skettenis 	sc->sc_dma._dmamap_load_buffer = simplebus_dmamap_load_buffer;
113d068a9bdSkettenis 	sc->sc_dma._dmamap_load_raw = simplebus_dmamap_load_raw;
1143e99d0b8Skettenis 	sc->sc_dma._cookie = sc;
1153e99d0b8Skettenis 
1163e99d0b8Skettenis 	sc->sc_dmarangeslen = OF_getproplen(sc->sc_node, "dma-ranges");
1173e99d0b8Skettenis 	if (sc->sc_dmarangeslen > 0 &&
1183e99d0b8Skettenis 	    (sc->sc_dmarangeslen % sizeof(uint32_t)) == 0) {
1193e99d0b8Skettenis 		sc->sc_dmaranges = malloc(sc->sc_dmarangeslen,
1203e99d0b8Skettenis 		    M_TEMP, M_WAITOK);
1213e99d0b8Skettenis 		OF_getpropintarray(sc->sc_node, "dma-ranges",
1223e99d0b8Skettenis 		    sc->sc_dmaranges, sc->sc_dmarangeslen);
1233e99d0b8Skettenis 	}
1243e99d0b8Skettenis 
125c46d2c7fSkettenis 	/*
126c46d2c7fSkettenis 	 * The device tree provided by the Raspberry Pi firmware lacks
127c46d2c7fSkettenis 	 * a "dma-ranges" option.  So provide the information until
128c46d2c7fSkettenis 	 * that gets fixed.
129c46d2c7fSkettenis 	 */
130c46d2c7fSkettenis 	if (sc->sc_dmaranges == NULL) {
131c46d2c7fSkettenis 		node = OF_parent(sc->sc_node);
132c46d2c7fSkettenis 		if (OF_is_compatible(node, "brcm,bcm2709")) {
133c46d2c7fSkettenis 			sc->sc_dmarangeslen = 3 * sizeof(uint32_t);
134c46d2c7fSkettenis 			sc->sc_dmaranges = malloc(sc->sc_dmarangeslen,
135c46d2c7fSkettenis 			    M_TEMP, M_WAITOK);
136c46d2c7fSkettenis 			sc->sc_dmaranges[0] = 0xc0000000;
137c46d2c7fSkettenis 			sc->sc_dmaranges[1] = 0x00000000;
138c46d2c7fSkettenis 			sc->sc_dmaranges[2] = 0x3f000000;
139c46d2c7fSkettenis 		}
140c46d2c7fSkettenis 	}
141c46d2c7fSkettenis 
142f24071e5Spatrick 	/* Scan the whole tree. */
143159e7744Skettenis 	for (sc->sc_early = 2; sc->sc_early >= 0; sc->sc_early--) {
144f24071e5Spatrick 		for (node = OF_child(sc->sc_node); node; node = OF_peer(node))
145f24071e5Spatrick 			simplebus_attach_node(self, node);
146159e7744Skettenis 	}
147f24071e5Spatrick }
148f24071e5Spatrick 
149f24071e5Spatrick int
simplebus_submatch(struct device * self,void * match,void * aux)150f24071e5Spatrick simplebus_submatch(struct device *self, void *match, void *aux)
151f24071e5Spatrick {
152f24071e5Spatrick 	struct simplebus_softc	*sc = (struct simplebus_softc *)self;
153f24071e5Spatrick 	struct cfdata *cf = match;
154f24071e5Spatrick 
155f24071e5Spatrick 	if (cf->cf_loc[0] == sc->sc_early)
156f24071e5Spatrick 		return (*cf->cf_attach->ca_match)(self, match, aux);
157f24071e5Spatrick 	return 0;
158f24071e5Spatrick }
159f24071e5Spatrick 
160e3246555Sdlg int
simplebus_print(void * aux,const char * pnp)161e3246555Sdlg simplebus_print(void *aux, const char *pnp)
162e3246555Sdlg {
163e3246555Sdlg 	struct fdt_attach_args *fa = aux;
164e3246555Sdlg 	char name[32];
165e3246555Sdlg 
166e3246555Sdlg 	if (!pnp)
167e3246555Sdlg 		return (QUIET);
168e3246555Sdlg 
169e3246555Sdlg 	if (OF_getprop(fa->fa_node, "name", name, sizeof(name)) > 0) {
170e3246555Sdlg 		name[sizeof(name) - 1] = 0;
171e3246555Sdlg 		printf("\"%s\"", name);
172e3246555Sdlg 	} else
173e3246555Sdlg 		printf("node %u", fa->fa_node);
174e3246555Sdlg 
175e3246555Sdlg 	printf(" at %s", pnp);
176e3246555Sdlg 
177e3246555Sdlg 	return (UNCONF);
178e3246555Sdlg }
179e3246555Sdlg 
180f24071e5Spatrick /*
181f24071e5Spatrick  * Look for a driver that wants to be attached to this node.
182f24071e5Spatrick  */
183f24071e5Spatrick void
simplebus_attach_node(struct device * self,int node)184f24071e5Spatrick simplebus_attach_node(struct device *self, int node)
185f24071e5Spatrick {
186f24071e5Spatrick 	struct simplebus_softc	*sc = (struct simplebus_softc *)self;
187f24071e5Spatrick 	struct fdt_attach_args	 fa;
1883f173131Skettenis 	char			 buf[32];
189f24071e5Spatrick 	int			 i, len, line;
190f24071e5Spatrick 	uint32_t		*cell, *reg;
191d45a5b64Skettenis 	struct device		*child;
192f24071e5Spatrick 
1933f173131Skettenis 	if (OF_getproplen(node, "compatible") <= 0)
194f24071e5Spatrick 		return;
195f24071e5Spatrick 
1963f173131Skettenis 	if (OF_getprop(node, "status", buf, sizeof(buf)) > 0 &&
1973f173131Skettenis 	    strcmp(buf, "disabled") == 0)
198f24071e5Spatrick 		return;
199f24071e5Spatrick 
200d45a5b64Skettenis 	/* Skip if already attached early. */
201d45a5b64Skettenis 	for (i = 0; i < nitems(sc->sc_early_nodes); i++) {
202d45a5b64Skettenis 		if (sc->sc_early_nodes[i] == node)
203d45a5b64Skettenis 			return;
204d45a5b64Skettenis 		if (sc->sc_early_nodes[i] == 0)
205d45a5b64Skettenis 			break;
206d45a5b64Skettenis 	}
207d45a5b64Skettenis 
208f24071e5Spatrick 	memset(&fa, 0, sizeof(fa));
209f24071e5Spatrick 	fa.fa_name = "";
210f24071e5Spatrick 	fa.fa_node = node;
211f24071e5Spatrick 	fa.fa_iot = &sc->sc_bus;
2123e99d0b8Skettenis 	fa.fa_dmat = &sc->sc_dma;
213f24071e5Spatrick 	fa.fa_acells = sc->sc_acells;
214f24071e5Spatrick 	fa.fa_scells = sc->sc_scells;
215f24071e5Spatrick 
216f24071e5Spatrick 	len = OF_getproplen(node, "reg");
217f24071e5Spatrick 	line = (sc->sc_acells + sc->sc_scells) * sizeof(uint32_t);
218f24071e5Spatrick 	if (len > 0 && line > 0 && (len % line) == 0) {
219f24071e5Spatrick 		reg = malloc(len, M_TEMP, M_WAITOK);
220f24071e5Spatrick 		OF_getpropintarray(node, "reg", reg, len);
221f24071e5Spatrick 
222f24071e5Spatrick 		fa.fa_reg = malloc((len / line) * sizeof(struct fdt_reg),
223f24071e5Spatrick 		    M_DEVBUF, M_WAITOK | M_ZERO);
224f24071e5Spatrick 		fa.fa_nreg = (len / line);
225f24071e5Spatrick 
226f24071e5Spatrick 		for (i = 0, cell = reg; i < len / line; i++) {
227f24071e5Spatrick 			if (sc->sc_acells >= 1)
228f24071e5Spatrick 				fa.fa_reg[i].addr = cell[0];
229f24071e5Spatrick 			if (sc->sc_acells == 2) {
230f24071e5Spatrick 				fa.fa_reg[i].addr <<= 32;
231f24071e5Spatrick 				fa.fa_reg[i].addr |= cell[1];
232f24071e5Spatrick 			}
233f24071e5Spatrick 			cell += sc->sc_acells;
234f24071e5Spatrick 			if (sc->sc_scells >= 1)
235f24071e5Spatrick 				fa.fa_reg[i].size = cell[0];
236f24071e5Spatrick 			if (sc->sc_scells == 2) {
237f24071e5Spatrick 				fa.fa_reg[i].size <<= 32;
238f24071e5Spatrick 				fa.fa_reg[i].size |= cell[1];
239f24071e5Spatrick 			}
240f24071e5Spatrick 			cell += sc->sc_scells;
241f24071e5Spatrick 		}
242f24071e5Spatrick 
243f24071e5Spatrick 		free(reg, M_TEMP, len);
244f24071e5Spatrick 	}
245f24071e5Spatrick 
246f24071e5Spatrick 	len = OF_getproplen(node, "interrupts");
247f24071e5Spatrick 	if (len > 0 && (len % sizeof(uint32_t)) == 0) {
248f24071e5Spatrick 		fa.fa_intr = malloc(len, M_DEVBUF, M_WAITOK);
249f24071e5Spatrick 		fa.fa_nintr = len / sizeof(uint32_t);
250f24071e5Spatrick 
251f24071e5Spatrick 		OF_getpropintarray(node, "interrupts", fa.fa_intr, len);
252f24071e5Spatrick 	}
253f24071e5Spatrick 
2542d784deaSpatrick 	if (OF_getproplen(node, "dma-coherent") >= 0) {
2552d784deaSpatrick 		fa.fa_dmat = malloc(sizeof(sc->sc_dma),
2562d784deaSpatrick 		    M_DEVBUF, M_WAITOK | M_ZERO);
2572d784deaSpatrick 		memcpy(fa.fa_dmat, &sc->sc_dma, sizeof(sc->sc_dma));
2582d784deaSpatrick 		fa.fa_dmat->_flags |= BUS_DMA_COHERENT;
2592d784deaSpatrick 	}
2602d784deaSpatrick 
2611d276ec2Spatrick 	fa.fa_dmat = iommu_device_map(fa.fa_node, fa.fa_dmat);
2621d276ec2Spatrick 
263d45a5b64Skettenis 	child = config_found_sm(self, &fa, sc->sc_early ? NULL :
264d45a5b64Skettenis 	    simplebus_print, simplebus_submatch);
265d45a5b64Skettenis 
266d45a5b64Skettenis 	/* Record nodes that we attach early. */
267d45a5b64Skettenis 	if (child && sc->sc_early) {
268d45a5b64Skettenis 		for (i = 0; i < nitems(sc->sc_early_nodes); i++) {
269d45a5b64Skettenis 			if (sc->sc_early_nodes[i] != 0)
270d45a5b64Skettenis 				continue;
271d45a5b64Skettenis 			sc->sc_early_nodes[i] = node;
272d45a5b64Skettenis 			break;
273d45a5b64Skettenis 		}
274d45a5b64Skettenis 	}
275f24071e5Spatrick 
276f24071e5Spatrick 	free(fa.fa_reg, M_DEVBUF, fa.fa_nreg * sizeof(struct fdt_reg));
277f24071e5Spatrick 	free(fa.fa_intr, M_DEVBUF, fa.fa_nintr * sizeof(uint32_t));
278f24071e5Spatrick }
279f24071e5Spatrick 
280f24071e5Spatrick /*
281f24071e5Spatrick  * Translate memory address if needed.
282f24071e5Spatrick  */
283f24071e5Spatrick int
simplebus_bs_map(bus_space_tag_t t,bus_addr_t bpa,bus_size_t size,int flag,bus_space_handle_t * bshp)284f24071e5Spatrick simplebus_bs_map(bus_space_tag_t t, bus_addr_t bpa, bus_size_t size,
285f24071e5Spatrick     int flag, bus_space_handle_t *bshp)
286f24071e5Spatrick {
287535110bcSpatrick 	struct simplebus_softc *sc = t->bus_private;
288f24071e5Spatrick 	uint64_t addr, rfrom, rto, rsize;
289f24071e5Spatrick 	uint32_t *range;
290f24071e5Spatrick 	int parent, rlen, rone;
291f24071e5Spatrick 
292f24071e5Spatrick 	addr = bpa;
293f24071e5Spatrick 	parent = OF_parent(sc->sc_node);
294f24071e5Spatrick 	if (parent == 0)
295f24071e5Spatrick 		return bus_space_map(sc->sc_iot, addr, size, flag, bshp);
296f24071e5Spatrick 
297f24071e5Spatrick 	if (sc->sc_rangeslen < 0)
298f24071e5Spatrick 		return EINVAL;
299f24071e5Spatrick 	if (sc->sc_rangeslen == 0)
300f24071e5Spatrick 		return bus_space_map(sc->sc_iot, addr, size, flag, bshp);
301f24071e5Spatrick 
302f24071e5Spatrick 	rlen = sc->sc_rangeslen / sizeof(uint32_t);
303f24071e5Spatrick 	rone = sc->sc_pacells + sc->sc_acells + sc->sc_scells;
304f24071e5Spatrick 
305f24071e5Spatrick 	/* For each range. */
306f24071e5Spatrick 	for (range = sc->sc_ranges; rlen >= rone; rlen -= rone, range += rone) {
307f24071e5Spatrick 		/* Extract from and size, so we can see if we fit. */
308f24071e5Spatrick 		rfrom = range[0];
309f24071e5Spatrick 		if (sc->sc_acells == 2)
310f24071e5Spatrick 			rfrom = (rfrom << 32) + range[1];
311f24071e5Spatrick 		rsize = range[sc->sc_acells + sc->sc_pacells];
312f24071e5Spatrick 		if (sc->sc_scells == 2)
313f24071e5Spatrick 			rsize = (rsize << 32) +
314f24071e5Spatrick 			    range[sc->sc_acells + sc->sc_pacells + 1];
315f24071e5Spatrick 
316f24071e5Spatrick 		/* Try next, if we're not in the range. */
317f24071e5Spatrick 		if (addr < rfrom || (addr + size) > (rfrom + rsize))
318f24071e5Spatrick 			continue;
319f24071e5Spatrick 
320f24071e5Spatrick 		/* All good, extract to address and translate. */
321f24071e5Spatrick 		rto = range[sc->sc_acells];
322f24071e5Spatrick 		if (sc->sc_pacells == 2)
323f24071e5Spatrick 			rto = (rto << 32) + range[sc->sc_acells + 1];
324f24071e5Spatrick 
325f24071e5Spatrick 		addr -= rfrom;
326f24071e5Spatrick 		addr += rto;
327f24071e5Spatrick 
328f24071e5Spatrick 		return bus_space_map(sc->sc_iot, addr, size, flag, bshp);
329f24071e5Spatrick 	}
330f24071e5Spatrick 
331f24071e5Spatrick 	return ESRCH;
332f24071e5Spatrick }
3333e99d0b8Skettenis 
334d0a66818Skettenis paddr_t
simplebus_bs_mmap(bus_space_tag_t t,bus_addr_t bpa,off_t off,int prot,int flags)335d0a66818Skettenis simplebus_bs_mmap(bus_space_tag_t t, bus_addr_t bpa, off_t off,
336d0a66818Skettenis     int prot, int flags)
337d0a66818Skettenis {
338d0a66818Skettenis 	struct simplebus_softc *sc = t->bus_private;
339d0a66818Skettenis 	uint64_t addr, rfrom, rto, rsize;
340d0a66818Skettenis 	uint32_t *range;
341d0a66818Skettenis 	int parent, rlen, rone;
342d0a66818Skettenis 
343d0a66818Skettenis 	addr = bpa;
344d0a66818Skettenis 	parent = OF_parent(sc->sc_node);
345d0a66818Skettenis 	if (parent == 0)
346d0a66818Skettenis 		return bus_space_mmap(sc->sc_iot, addr, off, prot, flags);
347d0a66818Skettenis 
348d0a66818Skettenis 	if (sc->sc_rangeslen < 0)
349d0a66818Skettenis 		return EINVAL;
350d0a66818Skettenis 	if (sc->sc_rangeslen == 0)
351d0a66818Skettenis 		return bus_space_mmap(sc->sc_iot, addr, off, prot, flags);
352d0a66818Skettenis 
353d0a66818Skettenis 	rlen = sc->sc_rangeslen / sizeof(uint32_t);
354d0a66818Skettenis 	rone = sc->sc_pacells + sc->sc_acells + sc->sc_scells;
355d0a66818Skettenis 
356d0a66818Skettenis 	/* For each range. */
357d0a66818Skettenis 	for (range = sc->sc_ranges; rlen >= rone; rlen -= rone, range += rone) {
358d0a66818Skettenis 		/* Extract from and size, so we can see if we fit. */
359d0a66818Skettenis 		rfrom = range[0];
360d0a66818Skettenis 		if (sc->sc_acells == 2)
361d0a66818Skettenis 			rfrom = (rfrom << 32) + range[1];
362d0a66818Skettenis 		rsize = range[sc->sc_acells + sc->sc_pacells];
363d0a66818Skettenis 		if (sc->sc_scells == 2)
364d0a66818Skettenis 			rsize = (rsize << 32) +
365d0a66818Skettenis 			    range[sc->sc_acells + sc->sc_pacells + 1];
366d0a66818Skettenis 
367d0a66818Skettenis 		/* Try next, if we're not in the range. */
368d0a66818Skettenis 		if (addr < rfrom || addr >= (rfrom + rsize))
369d0a66818Skettenis 			continue;
370d0a66818Skettenis 
371d0a66818Skettenis 		/* All good, extract to address and translate. */
372d0a66818Skettenis 		rto = range[sc->sc_acells];
373d0a66818Skettenis 		if (sc->sc_pacells == 2)
374d0a66818Skettenis 			rto = (rto << 32) + range[sc->sc_acells + 1];
375d0a66818Skettenis 
376d0a66818Skettenis 		addr -= rfrom;
377d0a66818Skettenis 		addr += rto;
378d0a66818Skettenis 
379d0a66818Skettenis 		return bus_space_mmap(sc->sc_iot, addr, off, prot, flags);
380d0a66818Skettenis 	}
381d0a66818Skettenis 
382d0a66818Skettenis 	return -1;
383d0a66818Skettenis }
384d0a66818Skettenis 
3853e99d0b8Skettenis int
simplebus_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)3863e99d0b8Skettenis simplebus_dmamap_load_buffer(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
3873e99d0b8Skettenis     bus_size_t buflen, struct proc *p, int flags, paddr_t *lastaddrp,
3883e99d0b8Skettenis     int *segp, int first)
3893e99d0b8Skettenis {
3903e99d0b8Skettenis 	struct simplebus_softc *sc = t->_cookie;
3913e99d0b8Skettenis 	int rlen, rone, seg;
3923e99d0b8Skettenis 	int firstseg = *segp;
3933e99d0b8Skettenis 	int error;
3943e99d0b8Skettenis 
39535e95590Spatrick 	error = sc->sc_dmat->_dmamap_load_buffer(sc->sc_dmat, map, buf, buflen,
39635e95590Spatrick 	    p, flags, lastaddrp, segp, first);
3973e99d0b8Skettenis 	if (error)
3983e99d0b8Skettenis 		return error;
3993e99d0b8Skettenis 
4003e99d0b8Skettenis 	if (sc->sc_dmaranges == NULL)
4013e99d0b8Skettenis 		return 0;
4023e99d0b8Skettenis 
4033e99d0b8Skettenis 	rlen = sc->sc_dmarangeslen / sizeof(uint32_t);
4043e99d0b8Skettenis 	rone = sc->sc_pacells + sc->sc_acells + sc->sc_scells;
4053e99d0b8Skettenis 
4063e99d0b8Skettenis 	/* For each segment. */
4073e99d0b8Skettenis 	for (seg = firstseg; seg <= *segp; seg++) {
4083e99d0b8Skettenis 		uint64_t addr, size, rfrom, rto, rsize;
4093e99d0b8Skettenis 		uint32_t *range;
4103e99d0b8Skettenis 
4113e99d0b8Skettenis 		addr = map->dm_segs[seg].ds_addr;
4123e99d0b8Skettenis 		size = map->dm_segs[seg].ds_len;
4133e99d0b8Skettenis 
4143e99d0b8Skettenis 		/* For each range. */
4153e99d0b8Skettenis 		for (range = sc->sc_dmaranges; rlen >= rone;
4163e99d0b8Skettenis 		     rlen -= rone, range += rone) {
4173e99d0b8Skettenis 			/* Extract from and size, so we can see if we fit. */
4183e99d0b8Skettenis 			rfrom = range[sc->sc_acells];
4193e99d0b8Skettenis 			if (sc->sc_pacells == 2)
4203e99d0b8Skettenis 				rfrom = (rfrom << 32) + range[sc->sc_acells + 1];
4213e99d0b8Skettenis 
4223e99d0b8Skettenis 			rsize = range[sc->sc_acells + sc->sc_pacells];
4233e99d0b8Skettenis 			if (sc->sc_scells == 2)
4243e99d0b8Skettenis 				rsize = (rsize << 32) +
4253e99d0b8Skettenis 				    range[sc->sc_acells + sc->sc_pacells + 1];
4263e99d0b8Skettenis 
4273e99d0b8Skettenis 			/* Try next, if we're not in the range. */
4283e99d0b8Skettenis 			if (addr < rfrom || (addr + size) > (rfrom + rsize))
4293e99d0b8Skettenis 				continue;
4303e99d0b8Skettenis 
4313e99d0b8Skettenis 			/* All good, extract to address and translate. */
4323e99d0b8Skettenis 			rto = range[0];
433229c19cdSpatrick 			if (sc->sc_acells == 2)
4343e99d0b8Skettenis 				rto = (rto << 32) + range[1];
4353e99d0b8Skettenis 
4363e99d0b8Skettenis 			map->dm_segs[seg].ds_addr -= rfrom;
4373e99d0b8Skettenis 			map->dm_segs[seg].ds_addr += rto;
4383e99d0b8Skettenis 			break;
4393e99d0b8Skettenis 		}
4403e99d0b8Skettenis 	}
4413e99d0b8Skettenis 
4423e99d0b8Skettenis 	return 0;
4433e99d0b8Skettenis }
444d068a9bdSkettenis 
445d068a9bdSkettenis int
simplebus_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)446d068a9bdSkettenis simplebus_dmamap_load_raw(bus_dma_tag_t t, bus_dmamap_t map,
447d068a9bdSkettenis     bus_dma_segment_t *segs, int nsegs, bus_size_t size, int flags)
448d068a9bdSkettenis {
449d068a9bdSkettenis 	struct simplebus_softc *sc = t->_cookie;
450d068a9bdSkettenis 	int rlen, rone, seg;
451d068a9bdSkettenis 	int error;
452d068a9bdSkettenis 
453d068a9bdSkettenis 	error = sc->sc_dmat->_dmamap_load_raw(sc->sc_dmat, map,
454d068a9bdSkettenis 	     segs, nsegs, size, flags);
455d068a9bdSkettenis 	if (error)
456d068a9bdSkettenis 		return error;
457d068a9bdSkettenis 
458d068a9bdSkettenis 	if (sc->sc_dmaranges == NULL)
459d068a9bdSkettenis 		return 0;
460d068a9bdSkettenis 
461d068a9bdSkettenis 	rlen = sc->sc_dmarangeslen / sizeof(uint32_t);
462d068a9bdSkettenis 	rone = sc->sc_pacells + sc->sc_acells + sc->sc_scells;
463d068a9bdSkettenis 
464d068a9bdSkettenis 	/* For each segment. */
465d068a9bdSkettenis 	for (seg = 0; seg < map->dm_nsegs; seg++) {
466d068a9bdSkettenis 		uint64_t addr, size, rfrom, rto, rsize;
467d068a9bdSkettenis 		uint32_t *range;
468d068a9bdSkettenis 
469d068a9bdSkettenis 		addr = map->dm_segs[seg].ds_addr;
470d068a9bdSkettenis 		size = map->dm_segs[seg].ds_len;
471d068a9bdSkettenis 
472d068a9bdSkettenis 		/* For each range. */
473d068a9bdSkettenis 		for (range = sc->sc_dmaranges; rlen >= rone;
474d068a9bdSkettenis 		     rlen -= rone, range += rone) {
475d068a9bdSkettenis 			/* Extract from and size, so we can see if we fit. */
476d068a9bdSkettenis 			rfrom = range[sc->sc_acells];
477d068a9bdSkettenis 			if (sc->sc_pacells == 2)
478d068a9bdSkettenis 				rfrom = (rfrom << 32) + range[sc->sc_acells + 1];
479d068a9bdSkettenis 
480d068a9bdSkettenis 			rsize = range[sc->sc_acells + sc->sc_pacells];
481d068a9bdSkettenis 			if (sc->sc_scells == 2)
482d068a9bdSkettenis 				rsize = (rsize << 32) +
483d068a9bdSkettenis 				    range[sc->sc_acells + sc->sc_pacells + 1];
484d068a9bdSkettenis 
485d068a9bdSkettenis 			/* Try next, if we're not in the range. */
486d068a9bdSkettenis 			if (addr < rfrom || (addr + size) > (rfrom + rsize))
487d068a9bdSkettenis 				continue;
488d068a9bdSkettenis 
489d068a9bdSkettenis 			/* All good, extract to address and translate. */
490d068a9bdSkettenis 			rto = range[0];
491d068a9bdSkettenis 			if (sc->sc_acells == 2)
492d068a9bdSkettenis 				rto = (rto << 32) + range[1];
493d068a9bdSkettenis 
494d068a9bdSkettenis 			map->dm_segs[seg].ds_addr -= rfrom;
495d068a9bdSkettenis 			map->dm_segs[seg].ds_addr += rto;
496d068a9bdSkettenis 			break;
497d068a9bdSkettenis 		}
498d068a9bdSkettenis 	}
499d068a9bdSkettenis 
500d068a9bdSkettenis 	return 0;
501d068a9bdSkettenis }
502