xref: /openbsd/sys/arch/sparc64/dev/upa.c (revision eb7eaf8d)
1 /*	$OpenBSD: upa.c,v 1.11 2021/10/24 17:05:04 mpi Exp $	*/
2 
3 /*
4  * Copyright (c) 2002 Jason L. Wright (jason@thought.net)
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  *
28  * Effort sponsored in part by the Defense Advanced Research Projects
29  * Agency (DARPA) and Air Force Research Laboratory, Air Force
30  * Materiel Command, USAF, under agreement number F30602-01-2-0537.
31  *
32  */
33 
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/kernel.h>
37 #include <sys/device.h>
38 #include <sys/conf.h>
39 #include <sys/timeout.h>
40 #include <sys/malloc.h>
41 
42 #define _SPARC_BUS_DMA_PRIVATE
43 #include <machine/bus.h>
44 #include <machine/autoconf.h>
45 #include <machine/openfirm.h>
46 
47 struct upa_range {
48 	u_int64_t	ur_space;
49 	u_int64_t	ur_addr;
50 	u_int64_t	ur_len;
51 };
52 
53 struct upa_softc {
54 	struct device		sc_dev;
55 	bus_space_tag_t		sc_bt;
56 	bus_space_handle_t	sc_reg[3];
57 	struct upa_range	*sc_range;
58 	int			sc_node;
59 	int			sc_nrange;
60 	bus_space_tag_t		sc_cbt;
61 };
62 
63 int	upa_match(struct device *, void *, void *);
64 void	upa_attach(struct device *, struct device *, void *);
65 
66 const struct cfattach upa_ca = {
67 	sizeof(struct upa_softc), upa_match, upa_attach
68 };
69 
70 struct cfdriver upa_cd = {
71 	NULL, "upa", DV_DULL
72 };
73 
74 int upa_print(void *, const char *);
75 bus_space_tag_t upa_alloc_bus_tag(struct upa_softc *);
76 int upa_bus_map(bus_space_tag_t, bus_space_tag_t, bus_addr_t,
77     bus_size_t, int, bus_space_handle_t *);
78 paddr_t upa_bus_mmap(bus_space_tag_t, bus_space_tag_t,
79     bus_addr_t, off_t, int, int);
80 
81 int
upa_match(struct device * parent,void * match,void * aux)82 upa_match(struct device *parent, void *match, void *aux)
83 {
84 	struct mainbus_attach_args *ma = aux;
85 
86 	if (strcmp(ma->ma_name, "upa") == 0)
87 		return (1);
88 
89 	return (0);
90 }
91 
92 void
upa_attach(struct device * parent,struct device * self,void * aux)93 upa_attach(struct device *parent, struct device *self, void *aux)
94 {
95 	struct upa_softc *sc = (void *)self;
96 	struct mainbus_attach_args *ma = aux;
97 	int i, node;
98 
99 	sc->sc_bt = ma->ma_bustag;
100 	sc->sc_node = ma->ma_node;
101 
102 	for (i = 0; i < 3; i++) {
103 		if (i >= ma->ma_nreg) {
104 			printf(": no register %d\n", i);
105 			return;
106 		}
107 		if (bus_space_map(sc->sc_bt, ma->ma_reg[i].ur_paddr,
108 		    ma->ma_reg[i].ur_len, 0, &sc->sc_reg[i])) {
109 			printf(": failed to map reg%d\n", i);
110 			return;
111 		}
112 	}
113 
114 	if (getprop(sc->sc_node, "ranges", sizeof(struct upa_range),
115 	    &sc->sc_nrange, (void **)&sc->sc_range))
116 		panic("upa: can't get ranges");
117 
118 	printf("\n");
119 
120 	sc->sc_cbt = upa_alloc_bus_tag(sc);
121 
122 	for (node = OF_child(sc->sc_node); node; node = OF_peer(node)) {
123 		char buf[32];
124 		struct mainbus_attach_args map;
125 
126 		bzero(&map, sizeof(map));
127 		if (OF_getprop(node, "device_type", buf, sizeof(buf)) <= 0)
128 			continue;
129 		if (getprop(node, "reg", sizeof(*map.ma_reg),
130 		    &map.ma_nreg, (void **)&map.ma_reg) != 0)
131 			continue;
132 		if (OF_getprop(node, "name", buf, sizeof(buf)) <= 0)
133 			continue;
134 		map.ma_node = node;
135 		map.ma_name = buf;
136 		map.ma_bustag = sc->sc_cbt;
137 		map.ma_dmatag = ma->ma_dmatag;
138 		config_found(&sc->sc_dev, &map, upa_print);
139 	}
140 }
141 
142 int
upa_print(void * args,const char * name)143 upa_print(void *args, const char *name)
144 {
145 	struct mainbus_attach_args *ma = args;
146 
147 	if (name)
148 		printf("\"%s\" at %s", ma->ma_name, name);
149 	return (UNCONF);
150 }
151 
152 bus_space_tag_t
upa_alloc_bus_tag(struct upa_softc * sc)153 upa_alloc_bus_tag(struct upa_softc *sc)
154 {
155 	struct sparc_bus_space_tag *bt;
156 
157 	bt = malloc(sizeof(*bt), M_DEVBUF, M_NOWAIT | M_ZERO);
158 	if (bt == NULL)
159 		panic("upa: couldn't alloc bus tag");
160 
161 	strlcpy(bt->name, sc->sc_dev.dv_xname, sizeof(bt->name));
162 	bt->cookie = sc;
163 	bt->parent = sc->sc_bt;
164 	bt->asi = bt->parent->asi;
165 	bt->sasi = bt->parent->sasi;
166 	bt->sparc_bus_map = upa_bus_map;
167 	bt->sparc_bus_mmap = upa_bus_mmap;
168 	/* XXX bt->sparc_intr_establish = upa_intr_establish; */
169 	return (bt);
170 }
171 
172 int
upa_bus_map(bus_space_tag_t t,bus_space_tag_t t0,bus_addr_t offset,bus_size_t size,int flags,bus_space_handle_t * hp)173 upa_bus_map(bus_space_tag_t t, bus_space_tag_t t0, bus_addr_t offset,
174     bus_size_t size, int flags, bus_space_handle_t *hp)
175 {
176 	struct upa_softc *sc = t->cookie;
177 	int i;
178 
179 	if (t->parent == 0 || t->parent->sparc_bus_map == 0) {
180 		printf("\n__upa_bus_map: invalid parent");
181 		return (EINVAL);
182 	}
183 
184 	t = t->parent;
185 
186         if (flags & BUS_SPACE_MAP_PROMADDRESS) {
187 		return ((*t->sparc_bus_map)
188 		    (t, t0, offset, size, flags, hp));
189 	}
190 
191 	for (i = 0; i < sc->sc_nrange; i++) {
192 		if (offset < sc->sc_range[i].ur_space)
193 			continue;
194 		if (offset >= (sc->sc_range[i].ur_space +
195 		    sc->sc_range[i].ur_space))
196 			continue;
197 		break;
198 	}
199 	if (i == sc->sc_nrange)
200 		return (EINVAL);
201 
202 	offset -= sc->sc_range[i].ur_space;
203 	offset += sc->sc_range[i].ur_addr;
204 
205 	return ((*t->sparc_bus_map)(t, t0, offset, size, flags, hp));
206 }
207 
208 paddr_t
upa_bus_mmap(bus_space_tag_t t,bus_space_tag_t t0,bus_addr_t paddr,off_t off,int prot,int flags)209 upa_bus_mmap(bus_space_tag_t t, bus_space_tag_t t0, bus_addr_t paddr,
210     off_t off, int prot, int flags)
211 {
212 	struct upa_softc *sc = t->cookie;
213 	int i;
214 
215 	if (t->parent == 0 || t->parent->sparc_bus_map == 0) {
216 		printf("\n__upa_bus_map: invalid parent");
217 		return (EINVAL);
218 	}
219 
220 	t = t->parent;
221 
222         if (flags & BUS_SPACE_MAP_PROMADDRESS)
223 		return ((*t->sparc_bus_mmap)(t, t0, paddr, off, prot, flags));
224 
225 	for (i = 0; i < sc->sc_nrange; i++) {
226 		if (paddr + off < sc->sc_range[i].ur_space)
227 			continue;
228 		if (paddr + off >= (sc->sc_range[i].ur_space +
229 		    sc->sc_range[i].ur_space))
230 			continue;
231 		break;
232 	}
233 	if (i == sc->sc_nrange)
234 		return (EINVAL);
235 
236 	paddr -= sc->sc_range[i].ur_space;
237 	paddr += sc->sc_range[i].ur_addr;
238 
239 	return ((*t->sparc_bus_mmap)(t, t0, paddr, off, prot, flags));
240 }
241