xref: /openbsd-src/sys/arch/arm/simplebus/simplebus.c (revision 94673892b7b28179327a9d4cb100f53993b0bd92)
1*94673892Sjsg /* $OpenBSD: simplebus.c,v 1.20 2023/09/22 01:10:43 jsg Exp $ */
279645871Spatrick /*
379645871Spatrick  * Copyright (c) 2016 Patrick Wildt <patrick@blueri.se>
479645871Spatrick  *
579645871Spatrick  * Permission to use, copy, modify, and distribute this software for any
679645871Spatrick  * purpose with or without fee is hereby granted, provided that the above
779645871Spatrick  * copyright notice and this permission notice appear in all copies.
879645871Spatrick  *
979645871Spatrick  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1079645871Spatrick  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1179645871Spatrick  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1279645871Spatrick  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1379645871Spatrick  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1479645871Spatrick  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1579645871Spatrick  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1679645871Spatrick  */
1779645871Spatrick 
1879645871Spatrick #include <sys/param.h>
1979645871Spatrick #include <sys/systm.h>
2079645871Spatrick #include <sys/kernel.h>
2179645871Spatrick #include <sys/device.h>
22442e1276Skettenis #include <sys/malloc.h>
2379645871Spatrick 
2479645871Spatrick #include <dev/ofw/openfirm.h>
25ac7c670eSpatrick #include <dev/ofw/fdt.h>
26eb366b01Sjsg #include <dev/ofw/ofw_clock.h>
27eb366b01Sjsg #include <dev/ofw/ofw_power.h>
2879645871Spatrick 
29*94673892Sjsg #include <machine/fdt.h>
30*94673892Sjsg #include <machine/simplebusvar.h>
3179645871Spatrick 
3279645871Spatrick int simplebus_match(struct device *, void *, void *);
3379645871Spatrick void simplebus_attach(struct device *, struct device *, void *);
3479645871Spatrick 
3579645871Spatrick void simplebus_attach_node(struct device *, int);
36ed541e3aSpatrick int simplebus_bs_map(void *, uint64_t, bus_size_t, int, bus_space_handle_t *);
3737084e1eSkettenis int simplebus_dmamap_load_buffer(bus_dma_tag_t, bus_dmamap_t, void *,
3837084e1eSkettenis     bus_size_t, struct proc *, int, paddr_t *, int *, int);
394c89fce1Skettenis int simplebus_dmamap_load_raw(bus_dma_tag_t, bus_dmamap_t,
404c89fce1Skettenis     bus_dma_segment_t *, int, bus_size_t, int);
4179645871Spatrick 
42e3ee5e84Smpi const struct cfattach simplebus_ca = {
43fc955b36Skettenis 	sizeof(struct simplebus_softc), simplebus_match, simplebus_attach
4479645871Spatrick };
4579645871Spatrick 
4679645871Spatrick struct cfdriver simplebus_cd = {
4779645871Spatrick 	NULL, "simplebus", DV_DULL
4879645871Spatrick };
4979645871Spatrick 
5079645871Spatrick /*
5179645871Spatrick  * Simplebus is a generic bus with no special casings.
5279645871Spatrick  */
5379645871Spatrick int
simplebus_match(struct device * parent,void * cfdata,void * aux)5479645871Spatrick simplebus_match(struct device *parent, void *cfdata, void *aux)
5579645871Spatrick {
5679645871Spatrick 	struct fdt_attach_args *fa = (struct fdt_attach_args *)aux;
5779645871Spatrick 
5879645871Spatrick 	if (fa->fa_node == 0)
5979645871Spatrick 		return (0);
6079645871Spatrick 
61eb366b01Sjsg 	return (OF_is_compatible(fa->fa_node, "simple-bus") ||
62eb366b01Sjsg 	    OF_is_compatible(fa->fa_node, "simple-pm-bus"));
6379645871Spatrick }
6479645871Spatrick 
6579645871Spatrick void
simplebus_attach(struct device * parent,struct device * self,void * aux)6679645871Spatrick simplebus_attach(struct device *parent, struct device *self, void *aux)
6779645871Spatrick {
6879645871Spatrick 	struct simplebus_softc *sc = (struct simplebus_softc *)self;
6979645871Spatrick 	struct fdt_attach_args *fa = (struct fdt_attach_args *)aux;
70c5eaa1e6Skettenis 	char name[32];
7179645871Spatrick 	int node;
7279645871Spatrick 
7379645871Spatrick 	sc->sc_node = fa->fa_node;
7479645871Spatrick 	sc->sc_iot = fa->fa_iot;
7579645871Spatrick 	sc->sc_dmat = fa->fa_dmat;
765586125eSpatrick 	sc->sc_acells = OF_getpropint(sc->sc_node, "#address-cells",
775586125eSpatrick 	    fa->fa_acells);
785586125eSpatrick 	sc->sc_scells = OF_getpropint(sc->sc_node, "#size-cells",
795586125eSpatrick 	    fa->fa_scells);
8039d0e1dcSpatrick 	sc->sc_pacells = fa->fa_acells;
8139d0e1dcSpatrick 	sc->sc_pscells = fa->fa_scells;
8279645871Spatrick 
83c5eaa1e6Skettenis 	if (OF_getprop(sc->sc_node, "name", name, sizeof(name)) > 0) {
84c5eaa1e6Skettenis 		name[sizeof(name) - 1] = 0;
85c5eaa1e6Skettenis 		printf(": \"%s\"", name);
86c5eaa1e6Skettenis 	}
87c5eaa1e6Skettenis 
8879645871Spatrick 	printf("\n");
8979645871Spatrick 
9039d0e1dcSpatrick 	memcpy(&sc->sc_bus, sc->sc_iot, sizeof(sc->sc_bus));
9139d0e1dcSpatrick 	sc->sc_bus.bs_cookie = sc;
9239d0e1dcSpatrick 	sc->sc_bus.bs_map = simplebus_bs_map;
9339d0e1dcSpatrick 
9439d0e1dcSpatrick 	sc->sc_rangeslen = OF_getproplen(sc->sc_node, "ranges");
9537084e1eSkettenis 	if (sc->sc_rangeslen > 0 &&
9637084e1eSkettenis 	    (sc->sc_rangeslen % sizeof(uint32_t)) == 0) {
9739d0e1dcSpatrick 		sc->sc_ranges = malloc(sc->sc_rangeslen, M_TEMP, M_WAITOK);
9839d0e1dcSpatrick 		OF_getpropintarray(sc->sc_node, "ranges", sc->sc_ranges,
9939d0e1dcSpatrick 		    sc->sc_rangeslen);
10039d0e1dcSpatrick 	}
10139d0e1dcSpatrick 
10237084e1eSkettenis 	memcpy(&sc->sc_dma, sc->sc_dmat, sizeof(sc->sc_dma));
10337084e1eSkettenis 	sc->sc_dma._dmamap_load_buffer = simplebus_dmamap_load_buffer;
1044c89fce1Skettenis 	sc->sc_dma._dmamap_load_raw = simplebus_dmamap_load_raw;
10537084e1eSkettenis 	sc->sc_dma._cookie = sc;
10637084e1eSkettenis 
10737084e1eSkettenis 	sc->sc_dmarangeslen = OF_getproplen(sc->sc_node, "dma-ranges");
10837084e1eSkettenis 	if (sc->sc_dmarangeslen > 0 &&
10937084e1eSkettenis 	    (sc->sc_dmarangeslen % sizeof(uint32_t)) == 0) {
11037084e1eSkettenis 		sc->sc_dmaranges = malloc(sc->sc_dmarangeslen,
11137084e1eSkettenis 		    M_TEMP, M_WAITOK);
11237084e1eSkettenis 		OF_getpropintarray(sc->sc_node, "dma-ranges",
11337084e1eSkettenis 		    sc->sc_dmaranges, sc->sc_dmarangeslen);
11437084e1eSkettenis 	}
11537084e1eSkettenis 
116eb366b01Sjsg 	if (OF_is_compatible(sc->sc_node, "simple-pm-bus")) {
117eb366b01Sjsg 		power_domain_enable(sc->sc_node);
118eb366b01Sjsg 		clock_enable_all(sc->sc_node);
119eb366b01Sjsg 	}
120eb366b01Sjsg 
12179645871Spatrick 	/* Scan the whole tree. */
122abc4f2a0Skettenis 	sc->sc_early = 1;
123abc4f2a0Skettenis 	for (node = OF_child(sc->sc_node); node; node = OF_peer(node))
124abc4f2a0Skettenis 		simplebus_attach_node(self, node);
125abc4f2a0Skettenis 
126abc4f2a0Skettenis 	sc->sc_early = 0;
127abc4f2a0Skettenis 	for (node = OF_child(sc->sc_node); node; node = OF_peer(node))
12879645871Spatrick 		simplebus_attach_node(self, node);
12979645871Spatrick }
130abc4f2a0Skettenis 
131abc4f2a0Skettenis int
simplebus_submatch(struct device * self,void * match,void * aux)132abc4f2a0Skettenis simplebus_submatch(struct device *self, void *match, void *aux)
133abc4f2a0Skettenis {
134abc4f2a0Skettenis 	struct simplebus_softc	*sc = (struct simplebus_softc *)self;
135abc4f2a0Skettenis 	struct cfdata *cf = match;
136abc4f2a0Skettenis 
137abc4f2a0Skettenis 	if (cf->cf_loc[0] == sc->sc_early)
138abc4f2a0Skettenis 		return (*cf->cf_attach->ca_match)(self, match, aux);
139abc4f2a0Skettenis 	return 0;
14079645871Spatrick }
14179645871Spatrick 
142ad434fd9Sjsg int
simplebus_print(void * aux,const char * pnp)143ad434fd9Sjsg simplebus_print(void *aux, const char *pnp)
144ad434fd9Sjsg {
145ad434fd9Sjsg 	struct fdt_attach_args *fa = aux;
146ad434fd9Sjsg 	char name[32];
147ad434fd9Sjsg 
148ad434fd9Sjsg 	if (!pnp)
149ad434fd9Sjsg 		return (QUIET);
150ad434fd9Sjsg 
151ad434fd9Sjsg 	if (OF_getprop(fa->fa_node, "name", name, sizeof(name)) > 0) {
152ad434fd9Sjsg 		name[sizeof(name) - 1] = 0;
153ad434fd9Sjsg 		printf("\"%s\"", name);
154ad434fd9Sjsg 	} else
155ad434fd9Sjsg 		printf("node %u", fa->fa_node);
156ad434fd9Sjsg 
157ad434fd9Sjsg 	printf(" at %s", pnp);
158ad434fd9Sjsg 
159ad434fd9Sjsg 	return (UNCONF);
160ad434fd9Sjsg }
161ad434fd9Sjsg 
16279645871Spatrick /*
16379645871Spatrick  * Look for a driver that wants to be attached to this node.
16479645871Spatrick  */
16579645871Spatrick void
simplebus_attach_node(struct device * self,int node)16679645871Spatrick simplebus_attach_node(struct device *self, int node)
16779645871Spatrick {
16879645871Spatrick 	struct simplebus_softc	*sc = (struct simplebus_softc *)self;
16979645871Spatrick 	struct fdt_attach_args	 fa;
17088a615dbSkettenis 	char			 buf[32];
171ac7c670eSpatrick 	int			 i, len, line;
172ac7c670eSpatrick 	uint32_t		*cell, *reg;
1732a1245a1Skettenis 	struct device		*child;
17479645871Spatrick 
17588a615dbSkettenis 	if (OF_getproplen(node, "compatible") <= 0)
17679645871Spatrick 		return;
17779645871Spatrick 
17888a615dbSkettenis 	if (OF_getprop(node, "status", buf, sizeof(buf)) > 0 &&
17988a615dbSkettenis 	    strcmp(buf, "disabled") == 0)
18079645871Spatrick 		return;
18179645871Spatrick 
1822a1245a1Skettenis 	/* Skip if already attached early. */
1832a1245a1Skettenis 	for (i = 0; i < nitems(sc->sc_early_nodes); i++) {
1842a1245a1Skettenis 		if (sc->sc_early_nodes[i] == node)
1852a1245a1Skettenis 			return;
1862a1245a1Skettenis 		if (sc->sc_early_nodes[i] == 0)
1872a1245a1Skettenis 			break;
1882a1245a1Skettenis 	}
1892a1245a1Skettenis 
19079645871Spatrick 	memset(&fa, 0, sizeof(fa));
19179645871Spatrick 	fa.fa_name = "";
19279645871Spatrick 	fa.fa_node = node;
19339d0e1dcSpatrick 	fa.fa_iot = &sc->sc_bus;
19437084e1eSkettenis 	fa.fa_dmat = &sc->sc_dma;
1955586125eSpatrick 	fa.fa_acells = sc->sc_acells;
1965586125eSpatrick 	fa.fa_scells = sc->sc_scells;
19779645871Spatrick 
198442e1276Skettenis 	len = OF_getproplen(node, "reg");
199ac7c670eSpatrick 	line = (sc->sc_acells + sc->sc_scells) * sizeof(uint32_t);
200ac7c670eSpatrick 	if (len > 0 && line > 0 && (len % line) == 0) {
201ac7c670eSpatrick 		reg = malloc(len, M_TEMP, M_WAITOK);
202ac7c670eSpatrick 		OF_getpropintarray(node, "reg", reg, len);
203442e1276Skettenis 
204ac7c670eSpatrick 		fa.fa_reg = malloc((len / line) * sizeof(struct fdt_reg),
205ac7c670eSpatrick 		    M_DEVBUF, M_WAITOK | M_ZERO);
206ac7c670eSpatrick 		fa.fa_nreg = (len / line);
207ac7c670eSpatrick 
208ac7c670eSpatrick 		for (i = 0, cell = reg; i < len / line; i++) {
209ac7c670eSpatrick 			if (sc->sc_acells >= 1)
210ac7c670eSpatrick 				fa.fa_reg[i].addr = cell[0];
211ac7c670eSpatrick 			if (sc->sc_acells == 2) {
212ac7c670eSpatrick 				fa.fa_reg[i].addr <<= 32;
213ac7c670eSpatrick 				fa.fa_reg[i].addr |= cell[1];
214ac7c670eSpatrick 			}
215ac7c670eSpatrick 			cell += sc->sc_acells;
216ac7c670eSpatrick 			if (sc->sc_scells >= 1)
217ac7c670eSpatrick 				fa.fa_reg[i].size = cell[0];
218ac7c670eSpatrick 			if (sc->sc_scells == 2) {
219ac7c670eSpatrick 				fa.fa_reg[i].size <<= 32;
220ac7c670eSpatrick 				fa.fa_reg[i].size |= cell[1];
221ac7c670eSpatrick 			}
222ac7c670eSpatrick 			cell += sc->sc_scells;
223ac7c670eSpatrick 		}
224ac7c670eSpatrick 
225ac7c670eSpatrick 		free(reg, M_TEMP, len);
226442e1276Skettenis 	}
227442e1276Skettenis 
228442e1276Skettenis 	len = OF_getproplen(node, "interrupts");
229442e1276Skettenis 	if (len > 0 && (len % sizeof(uint32_t)) == 0) {
230442e1276Skettenis 		fa.fa_intr = malloc(len, M_DEVBUF, M_WAITOK);
231442e1276Skettenis 		fa.fa_nintr = len / sizeof(uint32_t);
232442e1276Skettenis 
233f501cbd5Skettenis 		OF_getpropintarray(node, "interrupts", fa.fa_intr, len);
234442e1276Skettenis 	}
235442e1276Skettenis 
2362a1245a1Skettenis 	child = config_found_sm(self, &fa, sc->sc_early ? NULL :
2372a1245a1Skettenis 	    simplebus_print, simplebus_submatch);
2382a1245a1Skettenis 
2392a1245a1Skettenis 	/* Record nodes that we attach early. */
2402a1245a1Skettenis 	if (child && sc->sc_early) {
2412a1245a1Skettenis 		for (i = 0; i < nitems(sc->sc_early_nodes); i++) {
2422a1245a1Skettenis 			if (sc->sc_early_nodes[i] != 0)
2432a1245a1Skettenis 				continue;
2442a1245a1Skettenis 			sc->sc_early_nodes[i] = node;
2452a1245a1Skettenis 			break;
2462a1245a1Skettenis 		}
2472a1245a1Skettenis 	}
248442e1276Skettenis 
249ac7c670eSpatrick 	free(fa.fa_reg, M_DEVBUF, fa.fa_nreg * sizeof(struct fdt_reg));
250442e1276Skettenis 	free(fa.fa_intr, M_DEVBUF, fa.fa_nintr * sizeof(uint32_t));
25179645871Spatrick }
25239d0e1dcSpatrick 
25339d0e1dcSpatrick /*
25439d0e1dcSpatrick  * Translate memory address if needed.
25539d0e1dcSpatrick  */
25639d0e1dcSpatrick int
simplebus_bs_map(void * t,uint64_t bpa,bus_size_t size,int flag,bus_space_handle_t * bshp)257ed541e3aSpatrick simplebus_bs_map(void *t, uint64_t bpa, bus_size_t size,
25839d0e1dcSpatrick     int flag, bus_space_handle_t *bshp)
25939d0e1dcSpatrick {
26039d0e1dcSpatrick 	struct simplebus_softc *sc = (struct simplebus_softc *)t;
26139d0e1dcSpatrick 	uint64_t addr, rfrom, rto, rsize;
26239d0e1dcSpatrick 	uint32_t *range;
26339d0e1dcSpatrick 	int parent, rlen, rone;
26439d0e1dcSpatrick 
26539d0e1dcSpatrick 	addr = bpa;
26639d0e1dcSpatrick 	parent = OF_parent(sc->sc_node);
26739d0e1dcSpatrick 	if (parent == 0)
26839d0e1dcSpatrick 		return bus_space_map(sc->sc_iot, addr, size, flag, bshp);
26939d0e1dcSpatrick 
27039d0e1dcSpatrick 	if (sc->sc_rangeslen < 0)
27139d0e1dcSpatrick 		return EINVAL;
27239d0e1dcSpatrick 	if (sc->sc_rangeslen == 0)
27339d0e1dcSpatrick 		return bus_space_map(sc->sc_iot, addr, size, flag, bshp);
27439d0e1dcSpatrick 
27539d0e1dcSpatrick 	rlen = sc->sc_rangeslen / sizeof(uint32_t);
27639d0e1dcSpatrick 	rone = sc->sc_pacells + sc->sc_acells + sc->sc_scells;
27739d0e1dcSpatrick 
27839d0e1dcSpatrick 	/* For each range. */
27939d0e1dcSpatrick 	for (range = sc->sc_ranges; rlen >= rone; rlen -= rone, range += rone) {
28039d0e1dcSpatrick 		/* Extract from and size, so we can see if we fit. */
28139d0e1dcSpatrick 		rfrom = range[0];
28239d0e1dcSpatrick 		if (sc->sc_acells == 2)
28339d0e1dcSpatrick 			rfrom = (rfrom << 32) + range[1];
28439d0e1dcSpatrick 		rsize = range[sc->sc_acells + sc->sc_pacells];
28539d0e1dcSpatrick 		if (sc->sc_scells == 2)
28639d0e1dcSpatrick 			rsize = (rsize << 32) +
28739d0e1dcSpatrick 			    range[sc->sc_acells + sc->sc_pacells + 1];
28839d0e1dcSpatrick 
28939d0e1dcSpatrick 		/* Try next, if we're not in the range. */
29039d0e1dcSpatrick 		if (addr < rfrom || (addr + size) > (rfrom + rsize))
29139d0e1dcSpatrick 			continue;
29239d0e1dcSpatrick 
29339d0e1dcSpatrick 		/* All good, extract to address and translate. */
29439d0e1dcSpatrick 		rto = range[sc->sc_acells];
29539d0e1dcSpatrick 		if (sc->sc_pacells == 2)
29639d0e1dcSpatrick 			rto = (rto << 32) + range[sc->sc_acells + 1];
29739d0e1dcSpatrick 
29839d0e1dcSpatrick 		addr -= rfrom;
29939d0e1dcSpatrick 		addr += rto;
30039d0e1dcSpatrick 
30139d0e1dcSpatrick 		return bus_space_map(sc->sc_iot, addr, size, flag, bshp);
30239d0e1dcSpatrick 	}
30339d0e1dcSpatrick 
30439d0e1dcSpatrick 	return ESRCH;
30539d0e1dcSpatrick }
30637084e1eSkettenis 
30737084e1eSkettenis 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)30837084e1eSkettenis simplebus_dmamap_load_buffer(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
30937084e1eSkettenis     bus_size_t buflen, struct proc *p, int flags, paddr_t *lastaddrp,
31037084e1eSkettenis     int *segp, int first)
31137084e1eSkettenis {
31237084e1eSkettenis 	struct simplebus_softc *sc = t->_cookie;
31337084e1eSkettenis 	int rlen, rone, seg;
31437084e1eSkettenis 	int firstseg = *segp;
31537084e1eSkettenis 	int error;
31637084e1eSkettenis 
31737084e1eSkettenis 	error = sc->sc_dmat->_dmamap_load_buffer(sc->sc_dmat, map, buf, buflen,
31837084e1eSkettenis 	    p, flags, lastaddrp, segp, first);
31937084e1eSkettenis 	if (error)
32037084e1eSkettenis 		return error;
32137084e1eSkettenis 
32237084e1eSkettenis 	if (sc->sc_dmaranges == NULL)
32337084e1eSkettenis 		return 0;
32437084e1eSkettenis 
32537084e1eSkettenis 	rlen = sc->sc_dmarangeslen / sizeof(uint32_t);
32637084e1eSkettenis 	rone = sc->sc_pacells + sc->sc_acells + sc->sc_scells;
32737084e1eSkettenis 
32837084e1eSkettenis 	/* For each segment. */
32937084e1eSkettenis 	for (seg = firstseg; seg <= *segp; seg++) {
33037084e1eSkettenis 		uint64_t addr, size, rfrom, rto, rsize;
33137084e1eSkettenis 		uint32_t *range;
33237084e1eSkettenis 
33337084e1eSkettenis 		addr = map->dm_segs[seg].ds_addr;
33437084e1eSkettenis 		size = map->dm_segs[seg].ds_len;
33537084e1eSkettenis 
33637084e1eSkettenis 		/* For each range. */
33737084e1eSkettenis 		for (range = sc->sc_dmaranges; rlen >= rone;
33837084e1eSkettenis 		     rlen -= rone, range += rone) {
33937084e1eSkettenis 			/* Extract from and size, so we can see if we fit. */
34037084e1eSkettenis 			rfrom = range[sc->sc_acells];
34137084e1eSkettenis 			if (sc->sc_pacells == 2)
34237084e1eSkettenis 				rfrom = (rfrom << 32) + range[sc->sc_acells + 1];
34337084e1eSkettenis 
34437084e1eSkettenis 			rsize = range[sc->sc_acells + sc->sc_pacells];
34537084e1eSkettenis 			if (sc->sc_scells == 2)
34637084e1eSkettenis 				rsize = (rsize << 32) +
34737084e1eSkettenis 				    range[sc->sc_acells + sc->sc_pacells + 1];
34837084e1eSkettenis 
34937084e1eSkettenis 			/* Try next, if we're not in the range. */
35037084e1eSkettenis 			if (addr < rfrom || (addr + size) > (rfrom + rsize))
35137084e1eSkettenis 				continue;
35237084e1eSkettenis 
35337084e1eSkettenis 			/* All good, extract to address and translate. */
35437084e1eSkettenis 			rto = range[0];
35537084e1eSkettenis 			if (sc->sc_acells == 2)
35637084e1eSkettenis 				rto = (rto << 32) + range[1];
35737084e1eSkettenis 
35837084e1eSkettenis 			map->dm_segs[seg].ds_addr -= rfrom;
35937084e1eSkettenis 			map->dm_segs[seg].ds_addr += rto;
36037084e1eSkettenis 			break;
36137084e1eSkettenis 		}
36237084e1eSkettenis 	}
36337084e1eSkettenis 
36437084e1eSkettenis 	return 0;
36537084e1eSkettenis }
3664c89fce1Skettenis 
3674c89fce1Skettenis 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)3684c89fce1Skettenis simplebus_dmamap_load_raw(bus_dma_tag_t t, bus_dmamap_t map,
3694c89fce1Skettenis     bus_dma_segment_t *segs, int nsegs, bus_size_t size, int flags)
3704c89fce1Skettenis {
3714c89fce1Skettenis 	struct simplebus_softc *sc = t->_cookie;
3724c89fce1Skettenis 	int rlen, rone, seg;
3734c89fce1Skettenis 	int error;
3744c89fce1Skettenis 
3754c89fce1Skettenis 	error = sc->sc_dmat->_dmamap_load_raw(sc->sc_dmat, map,
3764c89fce1Skettenis 	     segs, nsegs, size, flags);
3774c89fce1Skettenis 	if (error)
3784c89fce1Skettenis 		return error;
3794c89fce1Skettenis 
3804c89fce1Skettenis 	if (sc->sc_dmaranges == NULL)
3814c89fce1Skettenis 		return 0;
3824c89fce1Skettenis 
3834c89fce1Skettenis 	rlen = sc->sc_dmarangeslen / sizeof(uint32_t);
3844c89fce1Skettenis 	rone = sc->sc_pacells + sc->sc_acells + sc->sc_scells;
3854c89fce1Skettenis 
3864c89fce1Skettenis 	/* For each segment. */
3874c89fce1Skettenis 	for (seg = 0; seg < map->dm_nsegs; seg++) {
3884c89fce1Skettenis 		uint64_t addr, size, rfrom, rto, rsize;
3894c89fce1Skettenis 		uint32_t *range;
3904c89fce1Skettenis 
3914c89fce1Skettenis 		addr = map->dm_segs[seg].ds_addr;
3924c89fce1Skettenis 		size = map->dm_segs[seg].ds_len;
3934c89fce1Skettenis 
3944c89fce1Skettenis 		/* For each range. */
3954c89fce1Skettenis 		for (range = sc->sc_dmaranges; rlen >= rone;
3964c89fce1Skettenis 		     rlen -= rone, range += rone) {
3974c89fce1Skettenis 			/* Extract from and size, so we can see if we fit. */
3984c89fce1Skettenis 			rfrom = range[sc->sc_acells];
3994c89fce1Skettenis 			if (sc->sc_pacells == 2)
4004c89fce1Skettenis 				rfrom = (rfrom << 32) + range[sc->sc_acells + 1];
4014c89fce1Skettenis 
4024c89fce1Skettenis 			rsize = range[sc->sc_acells + sc->sc_pacells];
4034c89fce1Skettenis 			if (sc->sc_scells == 2)
4044c89fce1Skettenis 				rsize = (rsize << 32) +
4054c89fce1Skettenis 				    range[sc->sc_acells + sc->sc_pacells + 1];
4064c89fce1Skettenis 
4074c89fce1Skettenis 			/* Try next, if we're not in the range. */
4084c89fce1Skettenis 			if (addr < rfrom || (addr + size) > (rfrom + rsize))
4094c89fce1Skettenis 				continue;
4104c89fce1Skettenis 
4114c89fce1Skettenis 			/* All good, extract to address and translate. */
4124c89fce1Skettenis 			rto = range[0];
4134c89fce1Skettenis 			if (sc->sc_acells == 2)
4144c89fce1Skettenis 				rto = (rto << 32) + range[1];
4154c89fce1Skettenis 
4164c89fce1Skettenis 			map->dm_segs[seg].ds_addr -= rfrom;
4174c89fce1Skettenis 			map->dm_segs[seg].ds_addr += rto;
4184c89fce1Skettenis 			break;
4194c89fce1Skettenis 		}
4204c89fce1Skettenis 	}
4214c89fce1Skettenis 
4224c89fce1Skettenis 	return 0;
4234c89fce1Skettenis }
424