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/resource.h> 46 #include <machine/vmparam.h> 47 48 #include <dev/ofw/ofw_bus.h> 49 #include <dev/ofw/ofw_bus_subr.h> 50 #include <dev/ofw/openfirm.h> 51 52 #include <powerpc/powermac/macgpiovar.h> 53 54 /* 55 * Macgpio softc 56 */ 57 struct macgpio_softc { 58 phandle_t sc_node; 59 struct resource *sc_gpios; 60 int sc_gpios_rid; 61 uint32_t sc_saved_gpio_levels[2]; 62 uint32_t sc_saved_gpios[GPIO_COUNT]; 63 uint32_t sc_saved_extint_gpios[GPIO_EXTINT_COUNT]; 64 }; 65 66 static MALLOC_DEFINE(M_MACGPIO, "macgpio", "macgpio device information"); 67 68 static int macgpio_probe(device_t); 69 static int macgpio_attach(device_t); 70 static int macgpio_print_child(device_t dev, device_t child); 71 static void macgpio_probe_nomatch(device_t, device_t); 72 static struct resource *macgpio_alloc_resource(device_t, device_t, int, int *, 73 rman_res_t, rman_res_t, rman_res_t, u_int); 74 static int macgpio_activate_resource(device_t, device_t, int, int, 75 struct resource *); 76 static int macgpio_deactivate_resource(device_t, device_t, int, int, 77 struct resource *); 78 static ofw_bus_get_devinfo_t macgpio_get_devinfo; 79 static int macgpio_suspend(device_t dev); 80 static int macgpio_resume(device_t dev); 81 82 /* 83 * Bus interface definition 84 */ 85 static device_method_t macgpio_methods[] = { 86 /* Device interface */ 87 DEVMETHOD(device_probe, macgpio_probe), 88 DEVMETHOD(device_attach, macgpio_attach), 89 DEVMETHOD(device_detach, bus_generic_detach), 90 DEVMETHOD(device_shutdown, bus_generic_shutdown), 91 DEVMETHOD(device_suspend, macgpio_suspend), 92 DEVMETHOD(device_resume, macgpio_resume), 93 94 /* Bus interface */ 95 DEVMETHOD(bus_print_child, macgpio_print_child), 96 DEVMETHOD(bus_probe_nomatch, macgpio_probe_nomatch), 97 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 98 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 99 100 DEVMETHOD(bus_alloc_resource, macgpio_alloc_resource), 101 DEVMETHOD(bus_activate_resource, macgpio_activate_resource), 102 DEVMETHOD(bus_deactivate_resource, macgpio_deactivate_resource), 103 DEVMETHOD(bus_release_resource, bus_generic_release_resource), 104 105 DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str), 106 107 /* ofw_bus interface */ 108 DEVMETHOD(ofw_bus_get_devinfo, macgpio_get_devinfo), 109 DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), 110 DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), 111 DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), 112 DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), 113 DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), 114 115 { 0, 0 } 116 }; 117 118 static driver_t macgpio_pci_driver = { 119 "macgpio", 120 macgpio_methods, 121 sizeof(struct macgpio_softc) 122 }; 123 124 devclass_t macgpio_devclass; 125 126 DRIVER_MODULE(macgpio, macio, macgpio_pci_driver, macgpio_devclass, 0, 0); 127 128 struct macgpio_devinfo { 129 struct ofw_bus_devinfo mdi_obdinfo; 130 struct resource_list mdi_resources; 131 132 int gpio_num; 133 }; 134 135 static int 136 macgpio_probe(device_t dev) 137 { 138 const char *name; 139 140 name = ofw_bus_get_name(dev); 141 if (name && strcmp(name, "gpio") == 0) { 142 device_set_desc(dev, "MacIO GPIO Controller"); 143 return (0); 144 } 145 146 return (ENXIO); 147 } 148 149 /* 150 * Scan Open Firmware child nodes, and attach these as children 151 * of the macgpio bus 152 */ 153 static int 154 macgpio_attach(device_t dev) 155 { 156 struct macgpio_softc *sc; 157 struct macgpio_devinfo *dinfo; 158 phandle_t root, child, iparent; 159 device_t cdev; 160 uint32_t irq; 161 162 sc = device_get_softc(dev); 163 root = sc->sc_node = ofw_bus_get_node(dev); 164 165 sc->sc_gpios = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 166 &sc->sc_gpios_rid, RF_ACTIVE); 167 168 /* 169 * Iterate through the sub-devices 170 */ 171 for (child = OF_child(root); child != 0; child = OF_peer(child)) { 172 dinfo = malloc(sizeof(*dinfo), M_MACGPIO, M_WAITOK | M_ZERO); 173 if (ofw_bus_gen_setup_devinfo(&dinfo->mdi_obdinfo, child) != 174 0) { 175 free(dinfo, M_MACGPIO); 176 continue; 177 } 178 179 if (OF_getencprop(child, "reg", &dinfo->gpio_num, 180 sizeof(dinfo->gpio_num)) != sizeof(dinfo->gpio_num)) { 181 /* 182 * Some early GPIO controllers don't provide GPIO 183 * numbers for GPIOs designed only to provide 184 * interrupt resources. We should still allow these 185 * to attach, but with caution. 186 */ 187 188 dinfo->gpio_num = -1; 189 } 190 191 resource_list_init(&dinfo->mdi_resources); 192 193 if (OF_getencprop(child, "interrupts", &irq, sizeof(irq)) == 194 sizeof(irq)) { 195 OF_searchencprop(child, "interrupt-parent", &iparent, 196 sizeof(iparent)); 197 resource_list_add(&dinfo->mdi_resources, SYS_RES_IRQ, 198 0, MAP_IRQ(iparent, irq), MAP_IRQ(iparent, irq), 199 1); 200 } 201 202 /* Fix messed-up offsets */ 203 if (dinfo->gpio_num > 0x50) 204 dinfo->gpio_num -= 0x50; 205 206 cdev = device_add_child(dev, NULL, -1); 207 if (cdev == NULL) { 208 device_printf(dev, "<%s>: device_add_child failed\n", 209 dinfo->mdi_obdinfo.obd_name); 210 ofw_bus_gen_destroy_devinfo(&dinfo->mdi_obdinfo); 211 free(dinfo, M_MACGPIO); 212 continue; 213 } 214 device_set_ivars(cdev, dinfo); 215 } 216 217 return (bus_generic_attach(dev)); 218 } 219 220 221 static int 222 macgpio_print_child(device_t dev, device_t child) 223 { 224 struct macgpio_devinfo *dinfo; 225 int retval = 0; 226 227 dinfo = device_get_ivars(child); 228 229 retval += bus_print_child_header(dev, child); 230 231 if (dinfo->gpio_num >= GPIO_BASE) 232 printf(" gpio %d", dinfo->gpio_num - GPIO_BASE); 233 else if (dinfo->gpio_num >= GPIO_EXTINT_BASE) 234 printf(" extint-gpio %d", dinfo->gpio_num - GPIO_EXTINT_BASE); 235 else if (dinfo->gpio_num >= 0) 236 printf(" addr 0x%02x", dinfo->gpio_num); /* should not happen */ 237 238 resource_list_print_type(&dinfo->mdi_resources, "irq", SYS_RES_IRQ, 239 "%jd"); 240 retval += bus_print_child_footer(dev, child); 241 242 return (retval); 243 } 244 245 246 static void 247 macgpio_probe_nomatch(device_t dev, device_t child) 248 { 249 struct macgpio_devinfo *dinfo; 250 const char *type; 251 252 if (bootverbose) { 253 dinfo = device_get_ivars(child); 254 255 if ((type = ofw_bus_get_type(child)) == NULL) 256 type = "(unknown)"; 257 device_printf(dev, "<%s, %s>", type, ofw_bus_get_name(child)); 258 if (dinfo->gpio_num >= 0) 259 printf(" gpio %d",dinfo->gpio_num); 260 resource_list_print_type(&dinfo->mdi_resources, "irq", 261 SYS_RES_IRQ, "%jd"); 262 printf(" (no driver attached)\n"); 263 } 264 } 265 266 267 static struct resource * 268 macgpio_alloc_resource(device_t bus, device_t child, int type, int *rid, 269 rman_res_t start, rman_res_t end, rman_res_t count, 270 u_int flags) 271 { 272 struct macgpio_devinfo *dinfo; 273 274 dinfo = device_get_ivars(child); 275 276 if (type != SYS_RES_IRQ) 277 return (NULL); 278 279 return (resource_list_alloc(&dinfo->mdi_resources, bus, child, type, 280 rid, start, end, count, flags)); 281 } 282 283 static int 284 macgpio_activate_resource(device_t bus, device_t child, int type, int rid, 285 struct resource *res) 286 { 287 struct macgpio_softc *sc; 288 struct macgpio_devinfo *dinfo; 289 u_char val; 290 291 sc = device_get_softc(bus); 292 dinfo = device_get_ivars(child); 293 294 if (type != SYS_RES_IRQ) 295 return ENXIO; 296 297 if (dinfo->gpio_num >= 0) { 298 val = bus_read_1(sc->sc_gpios,dinfo->gpio_num); 299 val |= 0x80; 300 bus_write_1(sc->sc_gpios,dinfo->gpio_num,val); 301 } 302 303 return (bus_activate_resource(bus, type, rid, res)); 304 } 305 306 307 static int 308 macgpio_deactivate_resource(device_t bus, device_t child, int type, int rid, 309 struct resource *res) 310 { 311 struct macgpio_softc *sc; 312 struct macgpio_devinfo *dinfo; 313 u_char val; 314 315 sc = device_get_softc(bus); 316 dinfo = device_get_ivars(child); 317 318 if (type != SYS_RES_IRQ) 319 return ENXIO; 320 321 if (dinfo->gpio_num >= 0) { 322 val = bus_read_1(sc->sc_gpios,dinfo->gpio_num); 323 val &= ~0x80; 324 bus_write_1(sc->sc_gpios,dinfo->gpio_num,val); 325 } 326 327 return (bus_deactivate_resource(bus, type, rid, res)); 328 } 329 330 uint8_t 331 macgpio_read(device_t dev) 332 { 333 struct macgpio_softc *sc; 334 struct macgpio_devinfo *dinfo; 335 336 sc = device_get_softc(device_get_parent(dev)); 337 dinfo = device_get_ivars(dev); 338 339 if (dinfo->gpio_num < 0) 340 return (0); 341 342 return (bus_read_1(sc->sc_gpios,dinfo->gpio_num)); 343 } 344 345 void 346 macgpio_write(device_t dev, uint8_t val) 347 { 348 struct macgpio_softc *sc; 349 struct macgpio_devinfo *dinfo; 350 351 sc = device_get_softc(device_get_parent(dev)); 352 dinfo = device_get_ivars(dev); 353 354 if (dinfo->gpio_num < 0) 355 return; 356 357 bus_write_1(sc->sc_gpios,dinfo->gpio_num,val); 358 } 359 360 static const struct ofw_bus_devinfo * 361 macgpio_get_devinfo(device_t dev, device_t child) 362 { 363 struct macgpio_devinfo *dinfo; 364 365 dinfo = device_get_ivars(child); 366 return (&dinfo->mdi_obdinfo); 367 } 368 369 static int 370 macgpio_suspend(device_t dev) 371 { 372 struct macgpio_softc *sc; 373 int i; 374 375 sc = device_get_softc(dev); 376 sc->sc_saved_gpio_levels[0] = bus_read_4(sc->sc_gpios, GPIO_LEVELS_0); 377 sc->sc_saved_gpio_levels[1] = bus_read_4(sc->sc_gpios, GPIO_LEVELS_1); 378 379 for (i = 0; i < GPIO_COUNT; i++) 380 sc->sc_saved_gpios[i] = bus_read_1(sc->sc_gpios, GPIO_BASE + i); 381 for (i = 0; i < GPIO_EXTINT_COUNT; i++) 382 sc->sc_saved_extint_gpios[i] = bus_read_1(sc->sc_gpios, GPIO_EXTINT_BASE + i); 383 384 return (0); 385 } 386 387 static int 388 macgpio_resume(device_t dev) 389 { 390 struct macgpio_softc *sc; 391 int i; 392 393 sc = device_get_softc(dev); 394 bus_write_4(sc->sc_gpios, GPIO_LEVELS_0, sc->sc_saved_gpio_levels[0]); 395 bus_write_4(sc->sc_gpios, GPIO_LEVELS_1, sc->sc_saved_gpio_levels[1]); 396 397 for (i = 0; i < GPIO_COUNT; i++) 398 bus_write_1(sc->sc_gpios, GPIO_BASE + i, sc->sc_saved_gpios[i]); 399 for (i = 0; i < GPIO_EXTINT_COUNT; i++) 400 bus_write_1(sc->sc_gpios, GPIO_EXTINT_BASE + i, sc->sc_saved_extint_gpios[i]); 401 402 return (0); 403 } 404