wii_bus.c revision 296373
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: releng/10.3/sys/powerpc/wii/wii_bus.c 249973 2013-04-27 06:54:49Z 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#include <machine/platformvar.h> 48 49#include <powerpc/wii/wii_picreg.h> 50#include <powerpc/wii/wii_fbreg.h> 51#include <powerpc/wii/wii_exireg.h> 52#include <powerpc/wii/wii_ipcreg.h> 53#include <powerpc/wii/wii_gpioreg.h> 54 55#define WIIBUS_CSR_ADDR 0x0d800100 56#define WIIBUS_CSR_LEN 0x300 57#define WIIBUS_CSR_RESET 0x94 58 59struct wiibus_softc { 60 device_t sc_dev; 61 struct rman sc_rman; 62 bus_space_tag_t sc_tag; 63 bus_space_handle_t sc_handle; 64}; 65 66static struct wiibus_softc *wiibus_sc = NULL; 67 68static uint32_t wiibus_csr_read(struct wiibus_softc *, uint16_t); 69static void wiibus_csr_write(struct wiibus_softc *, uint16_t, uint32_t); 70static void wiibus_identify(driver_t *, device_t); 71static int wiibus_probe(device_t); 72static int wiibus_attach(device_t); 73static int wiibus_print_child(device_t, device_t); 74static struct resource * 75 wiibus_alloc_resource(device_t, device_t, int, int *, 76 unsigned long, unsigned long, unsigned long, 77 unsigned int); 78static int wiibus_activate_resource(device_t, device_t, int, int, 79 struct resource *); 80 void wiibus_reset_system(void); 81 82static device_method_t wiibus_methods[] = { 83 /* Device interface */ 84 DEVMETHOD(device_identify, wiibus_identify), 85 DEVMETHOD(device_probe, wiibus_probe), 86 DEVMETHOD(device_attach, wiibus_attach), 87 88 /* Bus interface */ 89 DEVMETHOD(bus_add_child, bus_generic_add_child), 90 DEVMETHOD(bus_print_child, wiibus_print_child), 91 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 92 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 93 DEVMETHOD(bus_alloc_resource, wiibus_alloc_resource), 94 DEVMETHOD(bus_activate_resource,wiibus_activate_resource), 95 96 DEVMETHOD_END 97}; 98 99static MALLOC_DEFINE(M_WIIBUS, "wiibus", "Nintendo Wii system bus"); 100 101struct wiibus_devinfo { 102 struct resource_list di_resources; 103 uint8_t di_init; 104}; 105 106static driver_t wiibus_driver = { 107 "wiibus", 108 wiibus_methods, 109 sizeof(struct wiibus_softc) 110}; 111 112static devclass_t wiibus_devclass; 113 114DRIVER_MODULE(wiibus, nexus, wiibus_driver, wiibus_devclass, 0, 0); 115 116static uint32_t 117wiibus_csr_read(struct wiibus_softc *sc, uint16_t reg) 118{ 119 120 return (bus_space_read_4(sc->sc_tag, sc->sc_handle, reg)); 121} 122 123static void 124wiibus_csr_write(struct wiibus_softc *sc, uint16_t reg, 125 uint32_t val) 126{ 127 128 bus_space_write_4(sc->sc_tag, sc->sc_handle, reg, val); 129} 130 131static void 132wiibus_identify(driver_t *driver, device_t parent) 133{ 134 135 if (strcmp(installed_platform(), "wii") != 0) 136 return; 137 138 if (device_find_child(parent, "wiibus", -1) == NULL) 139 BUS_ADD_CHILD(parent, 0, "wiibus", 0); 140} 141 142 143static int 144wiibus_probe(device_t dev) 145{ 146 147 device_set_desc(dev, "Nintendo Wii System Bus"); 148 149 return (BUS_PROBE_NOWILDCARD); 150} 151 152static void 153wiibus_init_device_resources(struct rman *rm, struct wiibus_devinfo *dinfo, 154 unsigned int rid, uintptr_t addr, size_t len, unsigned int irq) 155 156{ 157 158 if (!dinfo->di_init) { 159 resource_list_init(&dinfo->di_resources); 160 dinfo->di_init++; 161 } 162 if (addr) { 163 rman_manage_region(rm, addr, addr + len - 1); 164 resource_list_add(&dinfo->di_resources, SYS_RES_MEMORY, rid, 165 addr, addr + len, len); 166 } 167 if (irq) 168 resource_list_add(&dinfo->di_resources, SYS_RES_IRQ, rid, 169 irq, irq, 1); 170} 171 172static int 173wiibus_attach(device_t self) 174{ 175 struct wiibus_softc *sc; 176 struct wiibus_devinfo *dinfo; 177 device_t cdev; 178 179 sc = device_get_softc(self); 180 sc->sc_rman.rm_type = RMAN_ARRAY; 181 sc->sc_rman.rm_descr = "Wii Bus Memory Mapped I/O"; 182 rman_init(&sc->sc_rman); 183 KASSERT(wiibus_sc == NULL, ("wiibus_sc already initialised")); 184 wiibus_sc = sc; 185 186 /* Nintendo PIC */ 187 dinfo = malloc(sizeof(*dinfo), M_WIIBUS, M_WAITOK | M_ZERO); 188 wiibus_init_device_resources(&sc->sc_rman, dinfo, 0, WIIPIC_REG_ADDR, 189 WIIPIC_REG_LEN, 1); 190 cdev = BUS_ADD_CHILD(self, 0, "wiipic", 0); 191 device_set_ivars(cdev, dinfo); 192 193 /* Framebuffer */ 194 dinfo = malloc(sizeof(*dinfo), M_WIIBUS, M_WAITOK | M_ZERO); 195 wiibus_init_device_resources(&sc->sc_rman, dinfo, 0, WIIFB_REG_ADDR, 196 WIIFB_REG_LEN, 8); 197 wiibus_init_device_resources(&sc->sc_rman, dinfo, 1, WIIFB_FB_ADDR, 198 WIIFB_FB_LEN, 0); 199 cdev = BUS_ADD_CHILD(self, 0, "wiifb", 0); 200 device_set_ivars(cdev, dinfo); 201 202 /* External Interface Bus */ 203 dinfo = malloc(sizeof(*dinfo), M_WIIBUS, M_WAITOK | M_ZERO); 204 wiibus_init_device_resources(&sc->sc_rman, dinfo, 0, WIIEXI_REG_ADDR, 205 WIIEXI_REG_LEN, 4); 206 cdev = BUS_ADD_CHILD(self, 0, "wiiexi", 0); 207 device_set_ivars(cdev, dinfo); 208 209 /* Nintendo IOS IPC */ 210 dinfo = malloc(sizeof(*dinfo), M_WIIBUS, M_WAITOK | M_ZERO); 211 wiibus_init_device_resources(&sc->sc_rman, dinfo, 0, WIIIPC_REG_ADDR, 212 WIIIPC_REG_LEN, 14); 213 wiibus_init_device_resources(&sc->sc_rman, dinfo, 1, WIIIPC_IOH_ADDR, 214 WIIIPC_IOH_LEN, 0); 215 cdev = BUS_ADD_CHILD(self, 0, "wiiipc", 0); 216 device_set_ivars(cdev, dinfo); 217 218 /* GPIO */ 219 dinfo = malloc(sizeof(*dinfo), M_WIIBUS, M_WAITOK | M_ZERO); 220 wiibus_init_device_resources(&sc->sc_rman, dinfo, 0, WIIGPIO_REG_ADDR, 221 WIIGPIO_REG_LEN, 0); 222 cdev = BUS_ADD_CHILD(self, 0, "wiigpio", 0); 223 device_set_ivars(cdev, dinfo); 224 225 /* The control registers */ 226 sc->sc_tag = &bs_be_tag; 227 sc->sc_handle = (bus_space_handle_t)pmap_mapdev(WIIBUS_CSR_ADDR, 228 WIIBUS_CSR_LEN); 229 230 return (bus_generic_attach(self)); 231} 232 233static int 234wiibus_print_child(device_t dev, device_t child) 235{ 236 struct wiibus_devinfo *dinfo = device_get_ivars(child); 237 int retval = 0; 238 239 retval += bus_print_child_header(dev, child); 240 retval += resource_list_print_type(&dinfo->di_resources, "mem", 241 SYS_RES_MEMORY, "%#lx"); 242 retval += resource_list_print_type(&dinfo->di_resources, "irq", 243 SYS_RES_IRQ, "%ld"); 244 retval += bus_print_child_footer(dev, child); 245 246 return (retval); 247} 248 249static struct resource * 250wiibus_alloc_resource(device_t bus, device_t child, int type, 251 int *rid, unsigned long start, unsigned long end, 252 unsigned long count, unsigned int flags) 253{ 254 struct wiibus_softc *sc; 255 struct wiibus_devinfo *dinfo; 256 struct resource_list_entry *rle; 257 struct resource *rv; 258 int needactivate; 259 260 sc = device_get_softc(bus); 261 dinfo = device_get_ivars(child); 262 needactivate = flags & RF_ACTIVE; 263 flags &= ~RF_ACTIVE; 264 265 switch (type) { 266 case SYS_RES_MEMORY: 267 rle = resource_list_find(&dinfo->di_resources, SYS_RES_MEMORY, 268 *rid); 269 if (rle == NULL) { 270 device_printf(bus, "no res entry for %s memory 0x%x\n", 271 device_get_nameunit(child), *rid); 272 return (NULL); 273 } 274 rv = rman_reserve_resource(&sc->sc_rman, rle->start, rle->end, 275 rle->count, flags, child); 276 if (rv == NULL) { 277 device_printf(bus, 278 "failed to reserve resource for %s\n", 279 device_get_nameunit(child)); 280 return (NULL); 281 } 282 rman_set_rid(rv, *rid); 283 break; 284 case SYS_RES_IRQ: 285 return (resource_list_alloc(&dinfo->di_resources, bus, child, 286 type, rid, start, end, count, flags)); 287 default: 288 device_printf(bus, "unknown resource request from %s\n", 289 device_get_nameunit(child)); 290 return (NULL); 291 } 292 293 if (needactivate) { 294 if (bus_activate_resource(child, type, *rid, rv) != 0) { 295 device_printf(bus, 296 "failed to activate resource for %s\n", 297 device_get_nameunit(child)); 298 return (NULL); 299 } 300 } 301 302 return (rv); 303} 304 305static int 306wiibus_activate_resource(device_t bus, device_t child, int type, int rid, 307 struct resource *res) 308{ 309 void *p; 310 311 switch (type) { 312 case SYS_RES_MEMORY: 313 p = pmap_mapdev(rman_get_start(res), rman_get_size(res)); 314 if (p == NULL) 315 return (ENOMEM); 316 rman_set_virtual(res, p); 317 rman_set_bustag(res, &bs_be_tag); 318 rman_set_bushandle(res, (unsigned long)p); 319 break; 320 case SYS_RES_IRQ: 321 return (bus_activate_resource(bus, type, rid, res)); 322 default: 323 device_printf(bus, 324 "unknown activate resource request from %s\n", 325 device_get_nameunit(child)); 326 return (ENXIO); 327 } 328 329 return (rman_activate_resource(res)); 330} 331 332void 333wiibus_reset_system(void) 334{ 335 uint32_t r; 336 337 r = wiibus_csr_read(wiibus_sc, WIIBUS_CSR_RESET); 338 r &= ~1; 339 wiibus_csr_write(wiibus_sc, WIIBUS_CSR_RESET, r); 340} 341