1 /*- 2 * Copyright 2008 by Nathan Whitehorn. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 18 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 20 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 21 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 * 25 * $FreeBSD$ 26 */ 27 28 /* 29 * Driver for MacIO GPIO controller 30 */ 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/kernel.h> 35 #include <sys/malloc.h> 36 #include <sys/module.h> 37 #include <sys/bus.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/intr_machdep.h> 45 #include <machine/pmap.h> 46 #include <machine/resource.h> 47 #include <machine/vmparam.h> 48 49 #include <dev/ofw/ofw_bus.h> 50 #include <dev/ofw/ofw_bus_subr.h> 51 #include <dev/ofw/openfirm.h> 52 53 #include <powerpc/powermac/macgpiovar.h> 54 55 /* 56 * Macgpio softc 57 */ 58 struct macgpio_softc { 59 phandle_t sc_node; 60 struct resource *sc_gpios; 61 int sc_gpios_rid; 62 uint32_t sc_saved_gpio_levels[2]; 63 uint32_t sc_saved_gpios[GPIO_COUNT]; 64 uint32_t sc_saved_extint_gpios[GPIO_EXTINT_COUNT]; 65 }; 66 67 static MALLOC_DEFINE(M_MACGPIO, "macgpio", "macgpio device information"); 68 69 static int macgpio_probe(device_t); 70 static int macgpio_attach(device_t); 71 static int macgpio_print_child(device_t dev, device_t child); 72 static void macgpio_probe_nomatch(device_t, device_t); 73 static struct resource *macgpio_alloc_resource(device_t, device_t, int, int *, 74 rman_res_t, rman_res_t, rman_res_t, u_int); 75 static int macgpio_activate_resource(device_t, device_t, int, int, 76 struct resource *); 77 static int macgpio_deactivate_resource(device_t, device_t, int, int, 78 struct resource *); 79 static ofw_bus_get_devinfo_t macgpio_get_devinfo; 80 static int macgpio_suspend(device_t dev); 81 static int macgpio_resume(device_t dev); 82 83 /* 84 * Bus interface definition 85 */ 86 static device_method_t macgpio_methods[] = { 87 /* Device interface */ 88 DEVMETHOD(device_probe, macgpio_probe), 89 DEVMETHOD(device_attach, macgpio_attach), 90 DEVMETHOD(device_detach, bus_generic_detach), 91 DEVMETHOD(device_shutdown, bus_generic_shutdown), 92 DEVMETHOD(device_suspend, macgpio_suspend), 93 DEVMETHOD(device_resume, macgpio_resume), 94 95 /* Bus interface */ 96 DEVMETHOD(bus_print_child, macgpio_print_child), 97 DEVMETHOD(bus_probe_nomatch, macgpio_probe_nomatch), 98 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 99 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 100 101 DEVMETHOD(bus_alloc_resource, macgpio_alloc_resource), 102 DEVMETHOD(bus_activate_resource, macgpio_activate_resource), 103 DEVMETHOD(bus_deactivate_resource, macgpio_deactivate_resource), 104 DEVMETHOD(bus_release_resource, bus_generic_release_resource), 105 106 DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str), 107 108 /* ofw_bus interface */ 109 DEVMETHOD(ofw_bus_get_devinfo, macgpio_get_devinfo), 110 DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), 111 DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), 112 DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), 113 DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), 114 DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), 115 116 { 0, 0 } 117 }; 118 119 static driver_t macgpio_pci_driver = { 120 "macgpio", 121 macgpio_methods, 122 sizeof(struct macgpio_softc) 123 }; 124 125 devclass_t macgpio_devclass; 126 127 DRIVER_MODULE(macgpio, macio, macgpio_pci_driver, macgpio_devclass, 0, 0); 128 129 struct macgpio_devinfo { 130 struct ofw_bus_devinfo mdi_obdinfo; 131 struct resource_list mdi_resources; 132 133 int gpio_num; 134 }; 135 136 static int 137 macgpio_probe(device_t dev) 138 { 139 const char *name; 140 141 name = ofw_bus_get_name(dev); 142 if (name && strcmp(name, "gpio") == 0) { 143 device_set_desc(dev, "MacIO GPIO Controller"); 144 return (0); 145 } 146 147 return (ENXIO); 148 } 149 150 /* 151 * Scan Open Firmware child nodes, and attach these as children 152 * of the macgpio bus 153 */ 154 static int 155 macgpio_attach(device_t dev) 156 { 157 struct macgpio_softc *sc; 158 struct macgpio_devinfo *dinfo; 159 phandle_t root, child, iparent; 160 device_t cdev; 161 uint32_t irq; 162 163 sc = device_get_softc(dev); 164 root = sc->sc_node = ofw_bus_get_node(dev); 165 166 sc->sc_gpios = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 167 &sc->sc_gpios_rid, RF_ACTIVE); 168 169 /* 170 * Iterate through the sub-devices 171 */ 172 for (child = OF_child(root); child != 0; child = OF_peer(child)) { 173 dinfo = malloc(sizeof(*dinfo), M_MACGPIO, M_WAITOK | M_ZERO); 174 if (ofw_bus_gen_setup_devinfo(&dinfo->mdi_obdinfo, child) != 175 0) { 176 free(dinfo, M_MACGPIO); 177 continue; 178 } 179 180 if (OF_getencprop(child, "reg", &dinfo->gpio_num, 181 sizeof(dinfo->gpio_num)) != sizeof(dinfo->gpio_num)) { 182 /* 183 * Some early GPIO controllers don't provide GPIO 184 * numbers for GPIOs designed only to provide 185 * interrupt resources. We should still allow these 186 * to attach, but with caution. 187 */ 188 189 dinfo->gpio_num = -1; 190 } 191 192 resource_list_init(&dinfo->mdi_resources); 193 194 if (OF_getencprop(child, "interrupts", &irq, sizeof(irq)) == 195 sizeof(irq)) { 196 OF_searchencprop(child, "interrupt-parent", &iparent, 197 sizeof(iparent)); 198 resource_list_add(&dinfo->mdi_resources, SYS_RES_IRQ, 199 0, MAP_IRQ(iparent, irq), MAP_IRQ(iparent, irq), 200 1); 201 } 202 203 /* Fix messed-up offsets */ 204 if (dinfo->gpio_num > 0x50) 205 dinfo->gpio_num -= 0x50; 206 207 cdev = device_add_child(dev, NULL, -1); 208 if (cdev == NULL) { 209 device_printf(dev, "<%s>: device_add_child failed\n", 210 dinfo->mdi_obdinfo.obd_name); 211 ofw_bus_gen_destroy_devinfo(&dinfo->mdi_obdinfo); 212 free(dinfo, M_MACGPIO); 213 continue; 214 } 215 device_set_ivars(cdev, dinfo); 216 } 217 218 return (bus_generic_attach(dev)); 219 } 220 221 222 static int 223 macgpio_print_child(device_t dev, device_t child) 224 { 225 struct macgpio_devinfo *dinfo; 226 int retval = 0; 227 228 dinfo = device_get_ivars(child); 229 230 retval += bus_print_child_header(dev, child); 231 232 if (dinfo->gpio_num >= GPIO_BASE) 233 printf(" gpio %d", dinfo->gpio_num - GPIO_BASE); 234 else if (dinfo->gpio_num >= GPIO_EXTINT_BASE) 235 printf(" extint-gpio %d", dinfo->gpio_num - GPIO_EXTINT_BASE); 236 else if (dinfo->gpio_num >= 0) 237 printf(" addr 0x%02x", dinfo->gpio_num); /* should not happen */ 238 239 resource_list_print_type(&dinfo->mdi_resources, "irq", SYS_RES_IRQ, 240 "%ld"); 241 retval += bus_print_child_footer(dev, child); 242 243 return (retval); 244 } 245 246 247 static void 248 macgpio_probe_nomatch(device_t dev, device_t child) 249 { 250 struct macgpio_devinfo *dinfo; 251 const char *type; 252 253 if (bootverbose) { 254 dinfo = device_get_ivars(child); 255 256 if ((type = ofw_bus_get_type(child)) == NULL) 257 type = "(unknown)"; 258 device_printf(dev, "<%s, %s>", type, ofw_bus_get_name(child)); 259 if (dinfo->gpio_num >= 0) 260 printf(" gpio %d",dinfo->gpio_num); 261 resource_list_print_type(&dinfo->mdi_resources, "irq", 262 SYS_RES_IRQ, "%ld"); 263 printf(" (no driver attached)\n"); 264 } 265 } 266 267 268 static struct resource * 269 macgpio_alloc_resource(device_t bus, device_t child, int type, int *rid, 270 rman_res_t start, rman_res_t end, rman_res_t count, 271 u_int flags) 272 { 273 struct macgpio_devinfo *dinfo; 274 275 dinfo = device_get_ivars(child); 276 277 if (type != SYS_RES_IRQ) 278 return (NULL); 279 280 return (resource_list_alloc(&dinfo->mdi_resources, bus, child, type, 281 rid, start, end, count, flags)); 282 } 283 284 static int 285 macgpio_activate_resource(device_t bus, device_t child, int type, int rid, 286 struct resource *res) 287 { 288 struct macgpio_softc *sc; 289 struct macgpio_devinfo *dinfo; 290 u_char val; 291 292 sc = device_get_softc(bus); 293 dinfo = device_get_ivars(child); 294 295 if (type != SYS_RES_IRQ) 296 return ENXIO; 297 298 if (dinfo->gpio_num >= 0) { 299 val = bus_read_1(sc->sc_gpios,dinfo->gpio_num); 300 val |= 0x80; 301 bus_write_1(sc->sc_gpios,dinfo->gpio_num,val); 302 } 303 304 return (bus_activate_resource(bus, type, rid, res)); 305 } 306 307 308 static int 309 macgpio_deactivate_resource(device_t bus, device_t child, int type, int rid, 310 struct resource *res) 311 { 312 struct macgpio_softc *sc; 313 struct macgpio_devinfo *dinfo; 314 u_char val; 315 316 sc = device_get_softc(bus); 317 dinfo = device_get_ivars(child); 318 319 if (type != SYS_RES_IRQ) 320 return ENXIO; 321 322 if (dinfo->gpio_num >= 0) { 323 val = bus_read_1(sc->sc_gpios,dinfo->gpio_num); 324 val &= ~0x80; 325 bus_write_1(sc->sc_gpios,dinfo->gpio_num,val); 326 } 327 328 return (bus_deactivate_resource(bus, type, rid, res)); 329 } 330 331 uint8_t 332 macgpio_read(device_t dev) 333 { 334 struct macgpio_softc *sc; 335 struct macgpio_devinfo *dinfo; 336 337 sc = device_get_softc(device_get_parent(dev)); 338 dinfo = device_get_ivars(dev); 339 340 if (dinfo->gpio_num < 0) 341 return (0); 342 343 return (bus_read_1(sc->sc_gpios,dinfo->gpio_num)); 344 } 345 346 void 347 macgpio_write(device_t dev, uint8_t val) 348 { 349 struct macgpio_softc *sc; 350 struct macgpio_devinfo *dinfo; 351 352 sc = device_get_softc(device_get_parent(dev)); 353 dinfo = device_get_ivars(dev); 354 355 if (dinfo->gpio_num < 0) 356 return; 357 358 bus_write_1(sc->sc_gpios,dinfo->gpio_num,val); 359 } 360 361 static const struct ofw_bus_devinfo * 362 macgpio_get_devinfo(device_t dev, device_t child) 363 { 364 struct macgpio_devinfo *dinfo; 365 366 dinfo = device_get_ivars(child); 367 return (&dinfo->mdi_obdinfo); 368 } 369 370 static int 371 macgpio_suspend(device_t dev) 372 { 373 struct macgpio_softc *sc; 374 int i; 375 376 sc = device_get_softc(dev); 377 sc->sc_saved_gpio_levels[0] = bus_read_4(sc->sc_gpios, GPIO_LEVELS_0); 378 sc->sc_saved_gpio_levels[1] = bus_read_4(sc->sc_gpios, GPIO_LEVELS_1); 379 380 for (i = 0; i < GPIO_COUNT; i++) 381 sc->sc_saved_gpios[i] = bus_read_1(sc->sc_gpios, GPIO_BASE + i); 382 for (i = 0; i < GPIO_EXTINT_COUNT; i++) 383 sc->sc_saved_extint_gpios[i] = bus_read_1(sc->sc_gpios, GPIO_EXTINT_BASE + i); 384 385 return (0); 386 } 387 388 static int 389 macgpio_resume(device_t dev) 390 { 391 struct macgpio_softc *sc; 392 int i; 393 394 sc = device_get_softc(dev); 395 bus_write_4(sc->sc_gpios, GPIO_LEVELS_0, sc->sc_saved_gpio_levels[0]); 396 bus_write_4(sc->sc_gpios, GPIO_LEVELS_1, sc->sc_saved_gpio_levels[1]); 397 398 for (i = 0; i < GPIO_COUNT; i++) 399 bus_write_1(sc->sc_gpios, GPIO_BASE + i, sc->sc_saved_gpios[i]); 400 for (i = 0; i < GPIO_EXTINT_COUNT; i++) 401 bus_write_1(sc->sc_gpios, GPIO_EXTINT_BASE + i, sc->sc_saved_extint_gpios[i]); 402 403 return (0); 404 } 405