wii_bus.c revision 249826
1/*-
2 * Copyright (C) 2012 Margarida Gouveia
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer,
10 *    without modification, immediately at the beginning of the file.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26#include <sys/cdefs.h>
27__FBSDID("$FreeBSD: head/sys/powerpc/wii/wii_bus.c 249826 2013-04-24 01:36:35Z rpaulo $");
28
29#include <sys/param.h>
30#include <sys/systm.h>
31#include <sys/kernel.h>
32#include <sys/module.h>
33#include <sys/malloc.h>
34#include <sys/bus.h>
35#include <sys/clock.h>
36#include <sys/cpu.h>
37#include <sys/resource.h>
38#include <sys/rman.h>
39
40#include <vm/vm.h>
41#include <vm/pmap.h>
42
43#include <machine/bus.h>
44#include <machine/platform.h>
45#include <machine/pmap.h>
46#include <machine/resource.h>
47
48#include <powerpc/wii/wii_picreg.h>
49#include <powerpc/wii/wii_fbreg.h>
50#include <powerpc/wii/wii_exireg.h>
51#include <powerpc/wii/wii_ipcreg.h>
52#include <powerpc/wii/wii_gpioreg.h>
53
54static void	wiibus_identify(driver_t *, device_t);
55static int	wiibus_probe(device_t);
56static int	wiibus_attach(device_t);
57static int	wiibus_print_child(device_t, device_t);
58static struct resource *
59		wiibus_alloc_resource(device_t, device_t, int, int *,
60		    unsigned long, unsigned long, unsigned long,
61		    unsigned int);
62static int	wiibus_activate_resource(device_t, device_t, int, int,
63		    struct resource *);
64
65static device_method_t wiibus_methods[] = {
66	/* Device interface */
67	DEVMETHOD(device_identify,	wiibus_identify),
68	DEVMETHOD(device_probe,		wiibus_probe),
69	DEVMETHOD(device_attach,	wiibus_attach),
70
71        /* Bus interface */
72	DEVMETHOD(bus_add_child,	bus_generic_add_child),
73	DEVMETHOD(bus_print_child,	wiibus_print_child),
74	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),
75	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
76	DEVMETHOD(bus_alloc_resource,   wiibus_alloc_resource),
77	DEVMETHOD(bus_activate_resource,wiibus_activate_resource),
78
79	DEVMETHOD_END
80};
81
82struct wiibus_softc {
83	device_t		sc_dev;
84	struct rman		sc_rman;
85};
86
87static MALLOC_DEFINE(M_WIIBUS, "wiibus", "Nintendo Wii system bus");
88
89struct wiibus_devinfo {
90	struct resource_list	di_resources;
91	uint8_t			di_init;
92};
93
94static driver_t wiibus_driver = {
95	"wiibus",
96	wiibus_methods,
97	sizeof(struct wiibus_softc)
98};
99
100static devclass_t wiibus_devclass;
101
102DRIVER_MODULE(wiibus, nexus, wiibus_driver, wiibus_devclass, 0, 0);
103
104static void
105wiibus_identify(driver_t *driver, device_t parent)
106{
107
108	if (strcmp(installed_platform(), "wii") != 0)
109		return;
110
111	if (device_find_child(parent, "wiibus", -1) == NULL)
112		BUS_ADD_CHILD(parent, 0, "wiibus", 0);
113}
114
115
116static int
117wiibus_probe(device_t dev)
118{
119
120	device_set_desc(dev, "Nintendo Wii System Bus");
121
122	return (BUS_PROBE_NOWILDCARD);
123}
124
125static void
126wiibus_init_device_resources(struct rman *rm, struct wiibus_devinfo *dinfo,
127    unsigned int rid, uintptr_t addr, size_t len, unsigned int irq)
128
129{
130
131	if (!dinfo->di_init) {
132		resource_list_init(&dinfo->di_resources);
133		dinfo->di_init++;
134	}
135	if (addr) {
136		rman_manage_region(rm, addr, addr + len - 1);
137		resource_list_add(&dinfo->di_resources, SYS_RES_MEMORY, rid,
138		    addr, addr + len, len);
139	}
140	if (irq)
141		resource_list_add(&dinfo->di_resources, SYS_RES_IRQ, rid,
142		    irq, irq, 1);
143}
144
145static int
146wiibus_attach(device_t self)
147{
148	struct wiibus_softc *sc;
149	struct wiibus_devinfo *dinfo;
150	device_t cdev;
151
152	sc = device_get_softc(self);
153	sc->sc_rman.rm_type = RMAN_ARRAY;
154	sc->sc_rman.rm_descr = "Wii Bus Memory Mapped I/O";
155	rman_init(&sc->sc_rman);
156
157	/* Nintendo PIC */
158	dinfo = malloc(sizeof(*dinfo), M_WIIBUS, M_WAITOK | M_ZERO);
159	wiibus_init_device_resources(&sc->sc_rman, dinfo, 0, WIIPIC_REG_ADDR,
160	    WIIPIC_REG_LEN, 1);
161	cdev = BUS_ADD_CHILD(self, 0, "wiipic", 0);
162	device_set_ivars(cdev, dinfo);
163
164	/* Framebuffer */
165	dinfo = malloc(sizeof(*dinfo), M_WIIBUS, M_WAITOK | M_ZERO);
166	wiibus_init_device_resources(&sc->sc_rman, dinfo, 0, WIIFB_REG_ADDR,
167	    WIIFB_REG_LEN, 8);
168	wiibus_init_device_resources(&sc->sc_rman, dinfo, 1, WIIFB_FB_ADDR,
169	    WIIFB_FB_LEN, 0);
170	cdev = BUS_ADD_CHILD(self, 0, "wiifb", 0);
171	device_set_ivars(cdev, dinfo);
172
173	/* External Interface Bus */
174	dinfo = malloc(sizeof(*dinfo), M_WIIBUS, M_WAITOK | M_ZERO);
175	wiibus_init_device_resources(&sc->sc_rman, dinfo, 0, WIIEXI_REG_ADDR,
176	    WIIEXI_REG_LEN, 4);
177	cdev = BUS_ADD_CHILD(self, 0, "wiiexi", 0);
178	device_set_ivars(cdev, dinfo);
179
180	/* Nintendo IOS IPC */
181	dinfo = malloc(sizeof(*dinfo), M_WIIBUS, M_WAITOK | M_ZERO);
182	wiibus_init_device_resources(&sc->sc_rman, dinfo, 0, WIIIPC_REG_ADDR,
183	    WIIIPC_REG_LEN, 14);
184	wiibus_init_device_resources(&sc->sc_rman, dinfo, 1, WIIIPC_IOH_ADDR,
185	    WIIIPC_IOH_LEN, 0);
186	cdev = BUS_ADD_CHILD(self, 0, "wiiipc", 0);
187	device_set_ivars(cdev, dinfo);
188
189	/* GPIO */
190	dinfo = malloc(sizeof(*dinfo), M_WIIBUS, M_WAITOK | M_ZERO);
191	wiibus_init_device_resources(&sc->sc_rman, dinfo, 0, WIIGPIO_REG_ADDR,
192	    WIIGPIO_REG_LEN, 0);
193	cdev = BUS_ADD_CHILD(self, 0, "wiigpio", 0);
194	device_set_ivars(cdev, dinfo);
195
196	return (bus_generic_attach(self));
197}
198
199static int
200wiibus_print_child(device_t dev, device_t child)
201{
202	struct wiibus_devinfo *dinfo = device_get_ivars(child);
203	int retval = 0;
204
205	retval += bus_print_child_header(dev, child);
206	retval += resource_list_print_type(&dinfo->di_resources, "mem",
207	    SYS_RES_MEMORY, "%#lx");
208	retval += resource_list_print_type(&dinfo->di_resources, "irq",
209	    SYS_RES_IRQ, "%ld");
210	retval += bus_print_child_footer(dev, child);
211
212	return (retval);
213}
214
215static struct resource *
216wiibus_alloc_resource(device_t bus, device_t child, int type,
217    int *rid, unsigned long start, unsigned long end,
218    unsigned long count, unsigned int flags)
219{
220	struct wiibus_softc *sc;
221	struct wiibus_devinfo *dinfo;
222	struct resource_list_entry *rle;
223	struct resource *rv;
224	int needactivate;
225
226	sc = device_get_softc(bus);
227	dinfo = device_get_ivars(child);
228	needactivate = flags & RF_ACTIVE;
229	flags &= ~RF_ACTIVE;
230
231	switch (type) {
232	case SYS_RES_MEMORY:
233		rle = resource_list_find(&dinfo->di_resources, SYS_RES_MEMORY,
234		    *rid);
235		if (rle == NULL) {
236			device_printf(bus, "no res entry for %s memory 0x%x\n",
237			    device_get_nameunit(child), *rid);
238			return (NULL);
239		}
240		rv = rman_reserve_resource(&sc->sc_rman, rle->start, rle->end,
241		    rle->count, flags, child);
242		if (rv == NULL) {
243			device_printf(bus,
244			    "failed to reserve resource for %s\n",
245			    device_get_nameunit(child));
246			return (NULL);
247		}
248		rman_set_rid(rv, *rid);
249		break;
250	case SYS_RES_IRQ:
251		return (resource_list_alloc(&dinfo->di_resources, bus, child,
252		    type, rid, start, end, count, flags));
253	default:
254		device_printf(bus, "unknown resource request from %s\n",
255		    device_get_nameunit(child));
256		return (NULL);
257	}
258
259	if (needactivate) {
260		if (bus_activate_resource(child, type, *rid, rv) != 0) {
261			device_printf(bus,
262			    "failed to activate resource for %s\n",
263			    device_get_nameunit(child));
264			return (NULL);
265		}
266	}
267
268	return (rv);
269}
270
271static int
272wiibus_activate_resource(device_t bus, device_t child, int type, int rid,
273    struct resource *res)
274{
275	void *p;
276
277	switch (type) {
278	case SYS_RES_MEMORY:
279		p = pmap_mapdev(rman_get_start(res), rman_get_size(res));
280		if (p == NULL)
281			return (ENOMEM);
282		rman_set_virtual(res, p);
283		rman_set_bustag(res, &bs_be_tag);
284		rman_set_bushandle(res, (unsigned long)p);
285		break;
286	case SYS_RES_IRQ:
287		return (bus_activate_resource(bus, type, rid, res));
288	default:
289		device_printf(bus,
290		    "unknown activate resource request from %s\n",
291		    device_get_nameunit(child));
292		return (ENXIO);
293	}
294
295	return (rman_activate_resource(res));
296}
297
298