wii_bus.c revision 239478
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 239478 2012-08-21 06:31:26Z adrian $"); 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 if (strcmp(installed_platform(), "wii") != 0) 108 return; 109 110 if (device_find_child(parent, "wiibus", -1) == NULL) 111 BUS_ADD_CHILD(parent, 0, "wiibus", 0); 112} 113 114 115static int 116wiibus_probe(device_t dev) 117{ 118 /* Do not attach to any OF nodes that may be present */ 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 if (!dinfo->di_init) { 131 resource_list_init(&dinfo->di_resources); 132 dinfo->di_init++; 133 } 134 if (addr) { 135 rman_manage_region(rm, addr, addr + len - 1); 136 resource_list_add(&dinfo->di_resources, SYS_RES_MEMORY, rid, 137 addr, addr + len, len); 138 } 139 if (irq) 140 resource_list_add(&dinfo->di_resources, SYS_RES_IRQ, rid, 141 irq, irq, 1); 142} 143 144static int 145wiibus_attach(device_t self) 146{ 147 struct wiibus_softc *sc; 148 struct wiibus_devinfo *dinfo; 149 device_t cdev; 150 151 sc = device_get_softc(self); 152 sc->sc_rman.rm_type = RMAN_ARRAY; 153 sc->sc_rman.rm_descr = "Wii Bus Memory Mapped I/O"; 154 rman_init(&sc->sc_rman); 155 156 /* Nintendo PIC */ 157 dinfo = malloc(sizeof(*dinfo), M_WIIBUS, M_WAITOK | M_ZERO); 158 wiibus_init_device_resources(&sc->sc_rman, dinfo, 0, WIIPIC_REG_ADDR, 159 WIIPIC_REG_LEN, 0); 160 cdev = BUS_ADD_CHILD(self, 0, "wiipic", 0); 161 device_set_ivars(cdev, dinfo); 162 163 /* Framebuffer */ 164 dinfo = malloc(sizeof(*dinfo), M_WIIBUS, M_WAITOK | M_ZERO); 165 wiibus_init_device_resources(&sc->sc_rman, dinfo, 0, WIIFB_REG_ADDR, 166 WIIFB_REG_LEN, 8); 167 wiibus_init_device_resources(&sc->sc_rman, dinfo, 1, WIIFB_FB_ADDR, 168 WIIFB_FB_LEN, 0); 169 cdev = BUS_ADD_CHILD(self, 0, "wiifb", 0); 170 device_set_ivars(cdev, dinfo); 171 172 /* External Interface Bus */ 173 dinfo = malloc(sizeof(*dinfo), M_WIIBUS, M_WAITOK | M_ZERO); 174 wiibus_init_device_resources(&sc->sc_rman, dinfo, 0, WIIEXI_REG_ADDR, 175 WIIEXI_REG_LEN, 4); 176 cdev = BUS_ADD_CHILD(self, 0, "wiiexi", 0); 177 device_set_ivars(cdev, dinfo); 178 179 /* Nintendo IOS IPC */ 180 dinfo = malloc(sizeof(*dinfo), M_WIIBUS, M_WAITOK | M_ZERO); 181 wiibus_init_device_resources(&sc->sc_rman, dinfo, 0, WIIIPC_REG_ADDR, 182 WIIIPC_REG_LEN, 14); 183 wiibus_init_device_resources(&sc->sc_rman, dinfo, 1, WIIIPC_IOH_ADDR, 184 WIIIPC_IOH_LEN, 0); 185 cdev = BUS_ADD_CHILD(self, 0, "wiiipc", 0); 186 device_set_ivars(cdev, dinfo); 187 188 /* GPIO */ 189 dinfo = malloc(sizeof(*dinfo), M_WIIBUS, M_WAITOK | M_ZERO); 190 wiibus_init_device_resources(&sc->sc_rman, dinfo, 0, WIIGPIO_REG_ADDR, 191 WIIGPIO_REG_LEN, 0); 192 cdev = BUS_ADD_CHILD(self, 0, "wiigpio", 0); 193 device_set_ivars(cdev, dinfo); 194 195 return (bus_generic_attach(self)); 196} 197 198static int 199wiibus_print_child(device_t dev, device_t child) 200{ 201 struct wiibus_devinfo *dinfo = device_get_ivars(child); 202 int retval = 0; 203 204 retval += bus_print_child_header(dev, child); 205 retval += resource_list_print_type(&dinfo->di_resources, "mem", 206 SYS_RES_MEMORY, "%#lx"); 207 retval += resource_list_print_type(&dinfo->di_resources, "irq", 208 SYS_RES_IRQ, "%ld"); 209 retval += bus_print_child_footer(dev, child); 210 211 return (retval); 212} 213 214static struct resource * 215wiibus_alloc_resource(device_t bus, device_t child, int type, 216 int *rid, unsigned long start, unsigned long end, 217 unsigned long count, unsigned int flags) 218{ 219 struct wiibus_softc *sc; 220 struct wiibus_devinfo *dinfo; 221 struct resource_list_entry *rle; 222 struct resource *rv; 223 int needactivate; 224 225 sc = device_get_softc(bus); 226 dinfo = device_get_ivars(child); 227 needactivate = flags & RF_ACTIVE; 228 flags &= ~RF_ACTIVE; 229 230 switch (type) { 231 case SYS_RES_MEMORY: 232 rle = resource_list_find(&dinfo->di_resources, SYS_RES_MEMORY, 233 *rid); 234 if (rle == NULL) { 235 device_printf(bus, "no res entry for %s memory 0x%x\n", 236 device_get_nameunit(child), *rid); 237 return (NULL); 238 } 239 rv = rman_reserve_resource(&sc->sc_rman, rle->start, rle->end, 240 rle->count, flags, child); 241 if (rv == NULL) { 242 device_printf(bus, 243 "failed to reserve resource for %s\n", 244 device_get_nameunit(child)); 245 return (NULL); 246 } 247 rman_set_rid(rv, *rid); 248 break; 249 /* XXX IRQ */ 250 default: 251 device_printf(bus, "unknown resource request from %s\n", 252 device_get_nameunit(child)); 253 return (NULL); 254 } 255 256 if (needactivate) { 257 if (bus_activate_resource(child, type, *rid, rv) != 0) { 258 device_printf(bus, 259 "failed to activate resource for %s\n", 260 device_get_nameunit(child)); 261 return (NULL); 262 } 263 } 264 265 return (rv); 266} 267 268static int 269wiibus_activate_resource(device_t bus, device_t child, int type, int rid, 270 struct resource *res) 271{ 272 void *p; 273 274 switch (type) { 275 case SYS_RES_MEMORY: 276 p = pmap_mapdev(rman_get_start(res), rman_get_size(res)); 277 if (p == NULL) 278 return (ENOMEM); 279 rman_set_virtual(res, p); 280 rman_set_bustag(res, &bs_be_tag); 281 rman_set_bushandle(res, (unsigned long)p); 282 break; 283 /* XXX IRQ */ 284 default: 285 device_printf(bus, 286 "unknown activate resource request from %s\n", 287 device_get_nameunit(child)); 288 return (ENXIO); 289 } 290 291 return (rman_activate_resource(res)); 292} 293 294