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