xref: /openbsd-src/sys/arch/powerpc64/dev/mainbus.c (revision 130ea1eca9fa3e4fe9bd0c779b913a2bb61dee85)
1*130ea1ecSderaadt /* $OpenBSD: mainbus.c,v 1.7 2024/08/18 15:50:49 deraadt Exp $ */
28c07258aSkettenis /*
38c07258aSkettenis  * Copyright (c) 2016 Patrick Wildt <patrick@blueri.se>
48c07258aSkettenis  * Copyright (c) 2017 Mark Kettenis <kettenis@openbsd.org>
58c07258aSkettenis  *
68c07258aSkettenis  * Permission to use, copy, modify, and distribute this software for any
78c07258aSkettenis  * purpose with or without fee is hereby granted, provided that the above
88c07258aSkettenis  * copyright notice and this permission notice appear in all copies.
98c07258aSkettenis  *
108c07258aSkettenis  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
118c07258aSkettenis  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
128c07258aSkettenis  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
138c07258aSkettenis  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
148c07258aSkettenis  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
158c07258aSkettenis  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
168c07258aSkettenis  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
178c07258aSkettenis  */
188c07258aSkettenis 
198c07258aSkettenis #include <sys/param.h>
208c07258aSkettenis #include <sys/systm.h>
218c07258aSkettenis #include <sys/kernel.h>
228c07258aSkettenis #include <sys/device.h>
238c07258aSkettenis #include <sys/malloc.h>
248c07258aSkettenis 
258c07258aSkettenis #include <machine/cpufunc.h>
268c07258aSkettenis #include <machine/fdt.h>
278c07258aSkettenis #include <dev/ofw/openfirm.h>
288c07258aSkettenis #include <dev/ofw/fdt.h>
298c07258aSkettenis #include <dev/ofw/ofw_thermal.h>
308c07258aSkettenis 
318c07258aSkettenis int mainbus_match(struct device *, void *, void *);
328c07258aSkettenis void mainbus_attach(struct device *, struct device *, void *);
338c07258aSkettenis 
348c07258aSkettenis void mainbus_attach_node(struct device *, int, cfmatch_t);
358c07258aSkettenis int mainbus_match_status(struct device *, void *, void *);
368c07258aSkettenis void mainbus_attach_cpus(struct device *, cfmatch_t);
378c07258aSkettenis int mainbus_match_primary(struct device *, void *, void *);
388c07258aSkettenis int mainbus_match_secondary(struct device *, void *, void *);
398c07258aSkettenis 
408c07258aSkettenis struct mainbus_softc {
418c07258aSkettenis 	struct device		 sc_dev;
428c07258aSkettenis 	int			 sc_node;
438c07258aSkettenis 	bus_space_tag_t		 sc_iot;
448c07258aSkettenis 	bus_dma_tag_t		 sc_dmat;
458c07258aSkettenis 	int			 sc_acells;
468c07258aSkettenis 	int			 sc_scells;
478c07258aSkettenis 	int			*sc_ranges;
488c07258aSkettenis 	int			 sc_rangeslen;
498c07258aSkettenis 	int			 sc_early;
508c07258aSkettenis 	int			 sc_early_nodes[64];
518c07258aSkettenis };
528c07258aSkettenis 
53471aeecfSnaddy const struct cfattach mainbus_ca = {
54*130ea1ecSderaadt 	sizeof(struct mainbus_softc), mainbus_match, mainbus_attach
558c07258aSkettenis };
568c07258aSkettenis 
578c07258aSkettenis struct cfdriver mainbus_cd = {
588c07258aSkettenis 	NULL, "mainbus", DV_DULL
598c07258aSkettenis };
608c07258aSkettenis 
61352f7f3bSkettenis struct bus_space mainbus_bus_space = {
62352f7f3bSkettenis 	._space_read_1 =	generic_space_read_1,
63352f7f3bSkettenis 	._space_write_1 =	generic_space_write_1,
64352f7f3bSkettenis 	._space_read_2 =	generic_space_read_2,
65352f7f3bSkettenis 	._space_write_2 =	generic_space_write_2,
66352f7f3bSkettenis 	._space_read_4 =	generic_space_read_4,
67352f7f3bSkettenis 	._space_write_4 =	generic_space_write_4,
68352f7f3bSkettenis 	._space_read_8 =	generic_space_read_8,
69352f7f3bSkettenis 	._space_write_8 =	generic_space_write_8,
70352f7f3bSkettenis 	._space_read_raw_2 =	generic_space_read_raw_2,
71352f7f3bSkettenis 	._space_write_raw_2 =	generic_space_write_raw_2,
72352f7f3bSkettenis 	._space_read_raw_4 =	generic_space_read_raw_4,
73352f7f3bSkettenis 	._space_write_raw_4 =	generic_space_write_raw_4,
74352f7f3bSkettenis 	._space_read_raw_8 =	generic_space_read_raw_8,
75352f7f3bSkettenis 	._space_write_raw_8 =	generic_space_write_raw_8,
76352f7f3bSkettenis 	._space_map =		generic_space_map,
77352f7f3bSkettenis 	._space_unmap =		generic_space_unmap,
78352f7f3bSkettenis 	._space_subregion =	generic_space_region,
79352f7f3bSkettenis 	._space_vaddr =		generic_space_vaddr,
80352f7f3bSkettenis 	._space_mmap =		generic_space_mmap
81352f7f3bSkettenis };
82352f7f3bSkettenis 
838c07258aSkettenis struct machine_bus_dma_tag mainbus_dma_tag = {
848c07258aSkettenis 	NULL,
858c07258aSkettenis 	0,
868c07258aSkettenis 	_dmamap_create,
878c07258aSkettenis 	_dmamap_destroy,
888c07258aSkettenis 	_dmamap_load,
898c07258aSkettenis 	_dmamap_load_mbuf,
908c07258aSkettenis 	_dmamap_load_uio,
918c07258aSkettenis 	_dmamap_load_raw,
928c07258aSkettenis 	_dmamap_load_buffer,
938c07258aSkettenis 	_dmamap_unload,
948c07258aSkettenis 	_dmamap_sync,
958c07258aSkettenis 	_dmamem_alloc,
968c07258aSkettenis 	_dmamem_free,
978c07258aSkettenis 	_dmamem_map,
988c07258aSkettenis 	_dmamem_unmap,
998c07258aSkettenis 	_dmamem_mmap,
1008c07258aSkettenis };
1018c07258aSkettenis 
1028c07258aSkettenis /*
1038c07258aSkettenis  * Mainbus takes care of FDT and non-FDT machines, so we
1048c07258aSkettenis  * always attach.
1058c07258aSkettenis  */
1068c07258aSkettenis int
1078c07258aSkettenis mainbus_match(struct device *parent, void *cfdata, void *aux)
1088c07258aSkettenis {
1098c07258aSkettenis 	return (1);
1108c07258aSkettenis }
1118c07258aSkettenis 
1128c07258aSkettenis void
1138c07258aSkettenis mainbus_attach(struct device *parent, struct device *self, void *aux)
1148c07258aSkettenis {
1158c07258aSkettenis 	struct mainbus_softc *sc = (struct mainbus_softc *)self;
1168c07258aSkettenis 	char prop[128];
1178c07258aSkettenis 	int node, len;
1188c07258aSkettenis 
1198c07258aSkettenis 	sc->sc_node = OF_peer(0);
120352f7f3bSkettenis 	sc->sc_iot = &mainbus_bus_space;
121184c283eSkettenis 	sc->sc_dmat = &mainbus_dma_tag;
1228c07258aSkettenis 	sc->sc_acells = OF_getpropint(OF_peer(0), "#address-cells", 1);
1238c07258aSkettenis 	sc->sc_scells = OF_getpropint(OF_peer(0), "#size-cells", 1);
1248c07258aSkettenis 
1258c07258aSkettenis 	len = OF_getprop(sc->sc_node, "model", prop, sizeof(prop));
1268c07258aSkettenis 	if (len > 0) {
1278c07258aSkettenis 		printf(": %s\n", prop);
1288c07258aSkettenis 		hw_prod = malloc(len, M_DEVBUF, M_NOWAIT);
1298c07258aSkettenis 		if (hw_prod)
1308c07258aSkettenis 			strlcpy(hw_prod, prop, len);
1318c07258aSkettenis 	} else
1328c07258aSkettenis 		printf(": unknown model\n");
1338c07258aSkettenis 
1348c07258aSkettenis 	len = OF_getprop(sc->sc_node, "serial-number", prop, sizeof(prop));
1358c07258aSkettenis 	if (len > 0) {
1368c07258aSkettenis 		hw_serial = malloc(len, M_DEVBUF, M_NOWAIT);
1378c07258aSkettenis 		if (hw_serial)
1388c07258aSkettenis 			strlcpy(hw_serial, prop, len);
1398c07258aSkettenis 	}
1408c07258aSkettenis 
1418c07258aSkettenis 	/* Attach primary CPU first. */
1428c07258aSkettenis 	mainbus_attach_cpus(self, mainbus_match_primary);
1438c07258aSkettenis 
144612a5197Skettenis 	/* Attach secondary CPUs. */
145612a5197Skettenis 	mainbus_attach_cpus(self, mainbus_match_secondary);
146612a5197Skettenis 
1478c07258aSkettenis 	sc->sc_rangeslen = OF_getproplen(OF_peer(0), "ranges");
1488c07258aSkettenis 	if (sc->sc_rangeslen > 0 && !(sc->sc_rangeslen % sizeof(uint32_t))) {
1498c07258aSkettenis 		sc->sc_ranges = malloc(sc->sc_rangeslen, M_TEMP, M_WAITOK);
1508c07258aSkettenis 		OF_getpropintarray(OF_peer(0), "ranges", sc->sc_ranges,
1518c07258aSkettenis 		    sc->sc_rangeslen);
1528c07258aSkettenis 	}
1538c07258aSkettenis 
1548c07258aSkettenis 	/* Scan the whole tree. */
1558c07258aSkettenis 	sc->sc_early = 1;
1568c07258aSkettenis 	for (node = OF_child(sc->sc_node); node != 0; node = OF_peer(node))
1578c07258aSkettenis 		mainbus_attach_node(self, node, NULL);
1588c07258aSkettenis 
1598c07258aSkettenis 	sc->sc_early = 0;
1608c07258aSkettenis 	for (node = OF_child(sc->sc_node); node != 0; node = OF_peer(node))
1618c07258aSkettenis 		mainbus_attach_node(self, node, NULL);
1628c07258aSkettenis }
1638c07258aSkettenis 
1648c07258aSkettenis int
1658c07258aSkettenis mainbus_print(void *aux, const char *pnp)
1668c07258aSkettenis {
1678c07258aSkettenis 	struct fdt_attach_args *fa = aux;
1688c07258aSkettenis 	char buf[32];
1698c07258aSkettenis 
1708c07258aSkettenis 	if (!pnp)
1718c07258aSkettenis 		return (QUIET);
1728c07258aSkettenis 
1738c07258aSkettenis 	if (OF_getprop(fa->fa_node, "status", buf, sizeof(buf)) > 0 &&
1748c07258aSkettenis 	    strcmp(buf, "disabled") == 0)
1758c07258aSkettenis 		return (QUIET);
1768c07258aSkettenis 
1778c07258aSkettenis 	if (OF_getprop(fa->fa_node, "name", buf, sizeof(buf)) > 0) {
1788c07258aSkettenis 		buf[sizeof(buf) - 1] = 0;
1798c07258aSkettenis 		if (strcmp(buf, "aliases") == 0 ||
1808c07258aSkettenis 		    strcmp(buf, "chosen") == 0 ||
1818c07258aSkettenis 		    strcmp(buf, "cpus") == 0 ||
1828c07258aSkettenis 		    strcmp(buf, "memory") == 0 ||
1838c07258aSkettenis 		    strcmp(buf, "reserved-memory") == 0 ||
1848c07258aSkettenis 		    strcmp(buf, "thermal-zones") == 0 ||
1858c07258aSkettenis 		    strncmp(buf, "__", 2) == 0)
1868c07258aSkettenis 			return (QUIET);
1878c07258aSkettenis 		printf("\"%s\"", buf);
1888c07258aSkettenis 	} else
1898c07258aSkettenis 		printf("node %u", fa->fa_node);
1908c07258aSkettenis 
1918c07258aSkettenis 	printf(" at %s", pnp);
1928c07258aSkettenis 
1938c07258aSkettenis 	return (UNCONF);
1948c07258aSkettenis }
1958c07258aSkettenis 
1968c07258aSkettenis /*
1978c07258aSkettenis  * Look for a driver that wants to be attached to this node.
1988c07258aSkettenis  */
1998c07258aSkettenis void
2008c07258aSkettenis mainbus_attach_node(struct device *self, int node, cfmatch_t submatch)
2018c07258aSkettenis {
2028c07258aSkettenis 	struct mainbus_softc	*sc = (struct mainbus_softc *)self;
2038c07258aSkettenis 	struct fdt_attach_args	 fa;
2048c07258aSkettenis 	int			 i, len, line;
2058c07258aSkettenis 	uint32_t		*cell, *reg;
2068c07258aSkettenis 	struct device		*child;
2078c07258aSkettenis 	cfprint_t		 print = NULL;
2088c07258aSkettenis 
2098c07258aSkettenis 	/* Skip if already attached early. */
2108c07258aSkettenis 	for (i = 0; i < nitems(sc->sc_early_nodes); i++) {
2118c07258aSkettenis 		if (sc->sc_early_nodes[i] == node)
2128c07258aSkettenis 			return;
2138c07258aSkettenis 		if (sc->sc_early_nodes[i] == 0)
2148c07258aSkettenis 			break;
2158c07258aSkettenis 	}
2168c07258aSkettenis 
2178c07258aSkettenis 	memset(&fa, 0, sizeof(fa));
2188c07258aSkettenis 	fa.fa_name = "";
2198c07258aSkettenis 	fa.fa_node = node;
2208c07258aSkettenis 	fa.fa_iot = sc->sc_iot;
2218c07258aSkettenis 	fa.fa_dmat = sc->sc_dmat;
2228c07258aSkettenis 	fa.fa_acells = sc->sc_acells;
2238c07258aSkettenis 	fa.fa_scells = sc->sc_scells;
2248c07258aSkettenis 
2258c07258aSkettenis 	len = OF_getproplen(node, "reg");
2268c07258aSkettenis 	line = (sc->sc_acells + sc->sc_scells) * sizeof(uint32_t);
2278c07258aSkettenis 	if (len > 0 && (len % line) == 0) {
2288c07258aSkettenis 		reg = malloc(len, M_TEMP, M_WAITOK);
2298c07258aSkettenis 		OF_getpropintarray(node, "reg", reg, len);
2308c07258aSkettenis 
2318c07258aSkettenis 		fa.fa_reg = malloc((len / line) * sizeof(struct fdt_reg),
2328c07258aSkettenis 		    M_DEVBUF, M_WAITOK);
2338c07258aSkettenis 		fa.fa_nreg = (len / line);
2348c07258aSkettenis 
2358c07258aSkettenis 		for (i = 0, cell = reg; i < len / line; i++) {
2368c07258aSkettenis 			if (sc->sc_acells >= 1)
2378c07258aSkettenis 				fa.fa_reg[i].addr = cell[0];
2388c07258aSkettenis 			if (sc->sc_acells == 2) {
2398c07258aSkettenis 				fa.fa_reg[i].addr <<= 32;
2408c07258aSkettenis 				fa.fa_reg[i].addr |= cell[1];
2418c07258aSkettenis 			}
2428c07258aSkettenis 			cell += sc->sc_acells;
2438c07258aSkettenis 			if (sc->sc_scells >= 1)
2448c07258aSkettenis 				fa.fa_reg[i].size = cell[0];
2458c07258aSkettenis 			if (sc->sc_scells == 2) {
2468c07258aSkettenis 				fa.fa_reg[i].size <<= 32;
2478c07258aSkettenis 				fa.fa_reg[i].size |= cell[1];
2488c07258aSkettenis 			}
2498c07258aSkettenis 			cell += sc->sc_scells;
2508c07258aSkettenis 		}
2518c07258aSkettenis 
2528c07258aSkettenis 		free(reg, M_TEMP, len);
2538c07258aSkettenis 	}
2548c07258aSkettenis 
2558c07258aSkettenis 	len = OF_getproplen(node, "interrupts");
2568c07258aSkettenis 	if (len > 0 && (len % sizeof(uint32_t)) == 0) {
2578c07258aSkettenis 		fa.fa_intr = malloc(len, M_DEVBUF, M_WAITOK);
2588c07258aSkettenis 		fa.fa_nintr = len / sizeof(uint32_t);
2598c07258aSkettenis 
2608c07258aSkettenis 		OF_getpropintarray(node, "interrupts", fa.fa_intr, len);
2618c07258aSkettenis 	}
2628c07258aSkettenis 
2638c07258aSkettenis #ifdef notyet
2648c07258aSkettenis 	if (OF_getproplen(node, "dma-coherent") >= 0) {
2658c07258aSkettenis 		fa.fa_dmat = malloc(sizeof(*sc->sc_dmat),
2668c07258aSkettenis 		    M_DEVBUF, M_WAITOK | M_ZERO);
2678c07258aSkettenis 		memcpy(fa.fa_dmat, sc->sc_dmat, sizeof(*sc->sc_dmat));
2688c07258aSkettenis 		fa.fa_dmat->_flags |= BUS_DMA_COHERENT;
2698c07258aSkettenis 	}
2708c07258aSkettenis #endif
2718c07258aSkettenis 
2728c07258aSkettenis 	if (submatch == NULL && sc->sc_early == 0)
2738c07258aSkettenis 		print = mainbus_print;
2748c07258aSkettenis 	if (submatch == NULL)
2758c07258aSkettenis 		submatch = mainbus_match_status;
2768c07258aSkettenis 
2778c07258aSkettenis 	child = config_found_sm(self, &fa, print, submatch);
2788c07258aSkettenis 
2798c07258aSkettenis 	/* Record nodes that we attach early. */
2808c07258aSkettenis 	if (child && sc->sc_early) {
2818c07258aSkettenis 		for (i = 0; i < nitems(sc->sc_early_nodes); i++) {
2828c07258aSkettenis 			if (sc->sc_early_nodes[i] != 0)
2838c07258aSkettenis 				continue;
2848c07258aSkettenis 			sc->sc_early_nodes[i] = node;
2858c07258aSkettenis 			break;
2868c07258aSkettenis 		}
2878c07258aSkettenis 	}
2888c07258aSkettenis 
2898c07258aSkettenis 	free(fa.fa_reg, M_DEVBUF, fa.fa_nreg * sizeof(struct fdt_reg));
2908c07258aSkettenis 	free(fa.fa_intr, M_DEVBUF, fa.fa_nintr * sizeof(uint32_t));
2918c07258aSkettenis }
2928c07258aSkettenis 
2938c07258aSkettenis int
2948c07258aSkettenis mainbus_match_status(struct device *parent, void *match, void *aux)
2958c07258aSkettenis {
2968c07258aSkettenis 	struct mainbus_softc *sc = (struct mainbus_softc *)parent;
2978c07258aSkettenis 	struct fdt_attach_args *fa = aux;
2988c07258aSkettenis 	struct cfdata *cf = match;
2998c07258aSkettenis 	char buf[32];
3008c07258aSkettenis 
3018c07258aSkettenis 	if (OF_getprop(fa->fa_node, "status", buf, sizeof(buf)) > 0 &&
3028c07258aSkettenis 	    strcmp(buf, "disabled") == 0)
3038c07258aSkettenis 		return 0;
3048c07258aSkettenis 
3058c07258aSkettenis 	if (cf->cf_loc[0] == sc->sc_early)
3068c07258aSkettenis 		return (*cf->cf_attach->ca_match)(parent, match, aux);
3078c07258aSkettenis 
3088c07258aSkettenis 	return 0;
3098c07258aSkettenis }
3108c07258aSkettenis 
3118c07258aSkettenis void
3128c07258aSkettenis mainbus_attach_cpus(struct device *self, cfmatch_t match)
3138c07258aSkettenis {
3148c07258aSkettenis 	struct mainbus_softc *sc = (struct mainbus_softc *)self;
3158c07258aSkettenis 	int node = OF_finddevice("/cpus");
3168c07258aSkettenis 	int acells, scells;
3178c07258aSkettenis 	char buf[32];
3188c07258aSkettenis 
3198c07258aSkettenis 	if (node == 0)
3208c07258aSkettenis 		return;
3218c07258aSkettenis 
3228c07258aSkettenis 	acells = sc->sc_acells;
3238c07258aSkettenis 	scells = sc->sc_scells;
3248c07258aSkettenis 	sc->sc_acells = OF_getpropint(node, "#address-cells", 1);
3258c07258aSkettenis 	sc->sc_scells = OF_getpropint(node, "#size-cells", 0);
3268c07258aSkettenis 
3278c07258aSkettenis 	ncpusfound = 0;
3288c07258aSkettenis 	for (node = OF_child(node); node != 0; node = OF_peer(node)) {
3298c07258aSkettenis 		if (OF_getprop(node, "device_type", buf, sizeof(buf)) > 0 &&
3308c07258aSkettenis 		    strcmp(buf, "cpu") == 0)
3318c07258aSkettenis 			ncpusfound++;
3328c07258aSkettenis 
3338c07258aSkettenis 		mainbus_attach_node(self, node, match);
3348c07258aSkettenis 	}
3358c07258aSkettenis 
3368c07258aSkettenis 	sc->sc_acells = acells;
3378c07258aSkettenis 	sc->sc_scells = scells;
3388c07258aSkettenis }
3398c07258aSkettenis 
3408c07258aSkettenis int
3418c07258aSkettenis mainbus_match_primary(struct device *parent, void *match, void *aux)
3428c07258aSkettenis {
3438c07258aSkettenis 	struct fdt_attach_args *fa = aux;
3448c07258aSkettenis 	struct cfdata *cf = match;
3458c07258aSkettenis 
3468c07258aSkettenis 	if (fa->fa_nreg < 1 || fa->fa_reg[0].addr != mfpir())
3478c07258aSkettenis 		return 0;
3488c07258aSkettenis 
3498c07258aSkettenis 	return (*cf->cf_attach->ca_match)(parent, match, aux);
3508c07258aSkettenis }
3518c07258aSkettenis 
3528c07258aSkettenis int
3538c07258aSkettenis mainbus_match_secondary(struct device *parent, void *match, void *aux)
3548c07258aSkettenis {
3558c07258aSkettenis 	struct fdt_attach_args *fa = aux;
3568c07258aSkettenis 	struct cfdata *cf = match;
3578c07258aSkettenis 
3588c07258aSkettenis 	if (fa->fa_nreg < 1 || fa->fa_reg[0].addr == mfpir())
3598c07258aSkettenis 		return 0;
3608c07258aSkettenis 
3618c07258aSkettenis 	return (*cf->cf_attach->ca_match)(parent, match, aux);
3628c07258aSkettenis }
363