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