xref: /openbsd-src/sys/arch/riscv64/dev/mainbus.c (revision 5a38ef86d0b61900239c7913d24a05e7b88a58f0)
1 /*	$OpenBSD: mainbus.c,v 1.8 2021/06/20 16:51:37 deraadt Exp $ */
2 
3 /*
4  * Copyright (c) 2016 Patrick Wildt <patrick@blueri.se>
5  * Copyright (c) 2017 Mark Kettenis <kettenis@openbsd.org>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <sys/param.h>
21 #include <sys/systm.h>
22 #include <sys/device.h>
23 #include <sys/malloc.h>
24 
25 #include <machine/fdt.h>
26 #include <dev/ofw/openfirm.h>
27 #include <dev/ofw/fdt.h>
28 
29 #include <machine/riscv64var.h>
30 #include <riscv64/dev/mainbus.h>
31 
32 int mainbus_match(struct device *, void *, void *);
33 void mainbus_attach(struct device *, struct device *, void *);
34 
35 void mainbus_attach_node(struct device *, int, cfmatch_t);
36 int mainbus_match_status(struct device *, void *, void *);
37 void mainbus_attach_cpus(struct device *, cfmatch_t);
38 int mainbus_match_primary(struct device *, void *, void *);
39 int mainbus_match_secondary(struct device *, void *, void *);
40 void mainbus_attach_efi(struct device *);
41 void mainbus_attach_framebuffer(struct device *);
42 
43 struct mainbus_softc {
44 	struct device		 sc_dev;
45 	int			 sc_node;
46 	bus_space_tag_t		 sc_iot;
47 	bus_dma_tag_t		 sc_dmat;
48 	int			 sc_acells;
49 	int			 sc_scells;
50 	int			*sc_ranges;
51 	int			 sc_rangeslen;
52 	int			 sc_early;
53 	int			 sc_early_nodes[64];
54 };
55 
56 const struct cfattach mainbus_ca = {
57 	sizeof(struct mainbus_softc), mainbus_match, mainbus_attach, NULL,
58 	config_activate_children
59 };
60 
61 struct cfdriver mainbus_cd = {
62 	NULL, "mainbus", DV_DULL
63 };
64 
65 struct machine_bus_dma_tag mainbus_dma_tag = {
66 	NULL,
67 	0,
68 	_dmamap_create,
69 	_dmamap_destroy,
70 	_dmamap_load,
71 	_dmamap_load_mbuf,
72 	_dmamap_load_uio,
73 	_dmamap_load_raw,
74 	_dmamap_load_buffer,
75 	_dmamap_unload,
76 	_dmamap_sync,
77 	_dmamem_alloc,
78 	_dmamem_free,
79 	_dmamem_map,
80 	_dmamem_unmap,
81 	_dmamem_mmap,
82 };
83 
84 /*
85  * Mainbus takes care of FDT and non-FDT machines, so we
86  * always attach.
87  */
88 int
89 mainbus_match(struct device *parent, void *cfdata, void *aux)
90 {
91 	return (1);
92 }
93 
94 void
95 mainbus_attach(struct device *parent, struct device *self, void *aux)
96 {
97 	struct mainbus_softc *sc = (struct mainbus_softc *)self;
98 	char prop[128];
99 	int node, len;
100 
101 	riscv_intr_init_fdt();
102 
103 	sc->sc_node = OF_peer(0);
104 	sc->sc_iot = &riscv64_bs_tag;
105 	sc->sc_dmat = &mainbus_dma_tag;
106 	sc->sc_acells = OF_getpropint(OF_peer(0), "#address-cells", 1);
107 	sc->sc_scells = OF_getpropint(OF_peer(0), "#size-cells", 1);
108 
109 	len = OF_getprop(sc->sc_node, "model", prop, sizeof(prop));
110 	if (len > 0) {
111 		printf(": %s\n", prop);
112 		hw_prod = malloc(len, M_DEVBUF, M_NOWAIT);
113 		if (hw_prod)
114 			strlcpy(hw_prod, prop, len);
115 	} else
116 		printf(": unknown model\n");
117 
118 	len = OF_getprop(sc->sc_node, "serial-number", prop, sizeof(prop));
119 	if (len > 0) {
120 		hw_serial = malloc(len, M_DEVBUF, M_NOWAIT);
121 		if (hw_serial)
122 			strlcpy(hw_serial, prop, len);
123 	}
124 
125 	/* Attach primary CPU first. */
126 	mainbus_attach_cpus(self, mainbus_match_primary);
127 
128 	/* Attach secondary CPUs. */
129 	mainbus_attach_cpus(self, mainbus_match_secondary);
130 
131 	sc->sc_rangeslen = OF_getproplen(OF_peer(0), "ranges");
132 	if (sc->sc_rangeslen > 0 && !(sc->sc_rangeslen % sizeof(uint32_t))) {
133 		sc->sc_ranges = malloc(sc->sc_rangeslen, M_TEMP, M_WAITOK);
134 		OF_getpropintarray(OF_peer(0), "ranges", sc->sc_ranges,
135 		    sc->sc_rangeslen);
136 	}
137 
138 	/* Scan the whole tree. */
139 	sc->sc_early = 1;
140 	for (node = OF_child(sc->sc_node); node != 0; node = OF_peer(node))
141 		mainbus_attach_node(self, node, NULL);
142 
143 	sc->sc_early = 0;
144 	for (node = OF_child(sc->sc_node); node != 0; node = OF_peer(node))
145 		mainbus_attach_node(self, node, NULL);
146 
147 	mainbus_attach_framebuffer(self);
148 }
149 
150 int
151 mainbus_print(void *aux, const char *pnp)
152 {
153 	struct fdt_attach_args *fa = aux;
154 	char buf[32];
155 
156 	if (!pnp)
157 		return (QUIET);
158 
159 	if (OF_getprop(fa->fa_node, "status", buf, sizeof(buf)) > 0 &&
160 	    strcmp(buf, "disabled") == 0)
161 		return (QUIET);
162 
163 	if (OF_getprop(fa->fa_node, "name", buf, sizeof(buf)) > 0) {
164 		buf[sizeof(buf) - 1] = 0;
165 		if (strcmp(buf, "aliases") == 0 ||
166 		    strcmp(buf, "chosen") == 0 ||
167 		    strcmp(buf, "cpus") == 0 ||
168 		    strcmp(buf, "memory") == 0 ||
169 		    strcmp(buf, "reserved-memory") == 0 ||
170 		    strcmp(buf, "thermal-zones") == 0 ||
171 		    strncmp(buf, "__", 2) == 0)
172 			return (QUIET);
173 		printf("\"%s\"", buf);
174 	} else
175 		printf("node %u", fa->fa_node);
176 
177 	printf(" at %s", pnp);
178 
179 	return (UNCONF);
180 }
181 
182 /*
183  * Look for a driver that wants to be attached to this node.
184  */
185 void
186 mainbus_attach_node(struct device *self, int node, cfmatch_t submatch)
187 {
188 	struct mainbus_softc	*sc = (struct mainbus_softc *)self;
189 	struct fdt_attach_args	 fa;
190 	int			 i, len, line;
191 	uint32_t		*cell, *reg;
192 	struct device		*child;
193 	cfprint_t		 print = NULL;
194 
195 	/* Skip if already attached early. */
196 	for (i = 0; i < nitems(sc->sc_early_nodes); i++) {
197 		if (sc->sc_early_nodes[i] == node)
198 			return;
199 		if (sc->sc_early_nodes[i] == 0)
200 			break;
201 	}
202 
203 	memset(&fa, 0, sizeof(fa));
204 	fa.fa_name = "";
205 	fa.fa_node = node;
206 	fa.fa_iot = sc->sc_iot;
207 	fa.fa_dmat = sc->sc_dmat;
208 	fa.fa_acells = sc->sc_acells;
209 	fa.fa_scells = sc->sc_scells;
210 
211 	len = OF_getproplen(node, "reg");
212 	line = (sc->sc_acells + sc->sc_scells) * sizeof(uint32_t);
213 	if (len > 0 && (len % line) == 0) {
214 		reg = malloc(len, M_TEMP, M_WAITOK);
215 		OF_getpropintarray(node, "reg", reg, len);
216 
217 		fa.fa_reg = malloc((len / line) * sizeof(struct fdt_reg),
218 		    M_DEVBUF, M_WAITOK);
219 		fa.fa_nreg = (len / line);
220 
221 		for (i = 0, cell = reg; i < len / line; i++) {
222 			if (sc->sc_acells >= 1)
223 				fa.fa_reg[i].addr = cell[0];
224 			if (sc->sc_acells == 2) {
225 				fa.fa_reg[i].addr <<= 32;
226 				fa.fa_reg[i].addr |= cell[1];
227 			}
228 			cell += sc->sc_acells;
229 			if (sc->sc_scells >= 1)
230 				fa.fa_reg[i].size = cell[0];
231 			if (sc->sc_scells == 2) {
232 				fa.fa_reg[i].size <<= 32;
233 				fa.fa_reg[i].size |= cell[1];
234 			}
235 			cell += sc->sc_scells;
236 		}
237 
238 		free(reg, M_TEMP, len);
239 	}
240 
241 	len = OF_getproplen(node, "interrupts");
242 	if (len > 0 && (len % sizeof(uint32_t)) == 0) {
243 		fa.fa_intr = malloc(len, M_DEVBUF, M_WAITOK);
244 		fa.fa_nintr = len / sizeof(uint32_t);
245 
246 		OF_getpropintarray(node, "interrupts", fa.fa_intr, len);
247 	}
248 
249 	if (submatch == NULL && sc->sc_early == 0)
250 		print = mainbus_print;
251 	if (submatch == NULL)
252 		submatch = mainbus_match_status;
253 
254 	child = config_found_sm(self, &fa, print, submatch);
255 
256 	/* Record nodes that we attach early. */
257 	if (child && sc->sc_early) {
258 		for (i = 0; i < nitems(sc->sc_early_nodes); i++) {
259 			if (sc->sc_early_nodes[i] != 0)
260 				continue;
261 			sc->sc_early_nodes[i] = node;
262 			break;
263 		}
264 	}
265 
266 	free(fa.fa_reg, M_DEVBUF, fa.fa_nreg * sizeof(struct fdt_reg));
267 	free(fa.fa_intr, M_DEVBUF, fa.fa_nintr * sizeof(uint32_t));
268 }
269 
270 int
271 mainbus_match_status(struct device *parent, void *match, void *aux)
272 {
273 	struct mainbus_softc *sc = (struct mainbus_softc *)parent;
274 	struct fdt_attach_args *fa = aux;
275 	struct cfdata *cf = match;
276 	char buf[32];
277 
278 	if (OF_getprop(fa->fa_node, "status", buf, sizeof(buf)) > 0 &&
279 	    strcmp(buf, "disabled") == 0)
280 		return 0;
281 
282 	if (cf->cf_loc[0] == sc->sc_early)
283 		return (*cf->cf_attach->ca_match)(parent, match, aux);
284 
285 	return 0;
286 }
287 
288 void
289 mainbus_attach_cpus(struct device *self, cfmatch_t match)
290 {
291 	struct mainbus_softc *sc = (struct mainbus_softc *)self;
292 	int node = OF_finddevice("/cpus");
293 	int acells, scells;
294 	char buf[32];
295 
296 	if (node == -1)
297 		return;
298 
299 	acells = sc->sc_acells;
300 	scells = sc->sc_scells;
301 	sc->sc_acells = OF_getpropint(node, "#address-cells", 2);
302 	sc->sc_scells = OF_getpropint(node, "#size-cells", 0);
303 
304 	ncpusfound = 0;
305 	for (node = OF_child(node); node != 0; node = OF_peer(node)) {
306 		if (OF_getprop(node, "status", buf, sizeof(buf)) > 0 &&
307 		    strcmp(buf, "disabled") == 0)
308 			continue;
309 
310 		if (OF_getprop(node, "device_type", buf, sizeof(buf)) > 0 &&
311 		    strcmp(buf, "cpu") == 0)
312 			ncpusfound++;
313 
314 		mainbus_attach_node(self, node, match);
315 	}
316 
317 	sc->sc_acells = acells;
318 	sc->sc_scells = scells;
319 }
320 
321 int
322 mainbus_match_primary(struct device *parent, void *match, void *aux)
323 {
324 	struct fdt_attach_args *fa = aux;
325 	struct cfdata *cf = match;
326 
327 	if (fa->fa_nreg < 1 || fa->fa_reg[0].addr != boot_hart)
328 		return 0;
329 
330 	return (*cf->cf_attach->ca_match)(parent, match, aux);
331 }
332 
333 int
334 mainbus_match_secondary(struct device *parent, void *match, void *aux)
335 {
336 	struct fdt_attach_args *fa = aux;
337 	struct cfdata *cf = match;
338 
339 	if (fa->fa_nreg < 1 || fa->fa_reg[0].addr == boot_hart)
340 		return 0;
341 
342 	return (*cf->cf_attach->ca_match)(parent, match, aux);
343 }
344 
345 void
346 mainbus_attach_framebuffer(struct device *self)
347 {
348 	int node = OF_finddevice("/chosen");
349 
350 	if (node == -1)
351 		return;
352 
353 	for (node = OF_child(node); node != 0; node = OF_peer(node))
354 		mainbus_attach_node(self, node, NULL);
355 }
356