1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright 2008 by Nathan Whitehorn. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 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, 20 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 22 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 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, 75 struct resource *); 76 static int macgpio_deactivate_resource(device_t, device_t, 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, ofw_bus_gen_child_pnpinfo), 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 { 0, 0 } 115 }; 116 117 static driver_t macgpio_pci_driver = { 118 "macgpio", 119 macgpio_methods, 120 sizeof(struct macgpio_softc) 121 }; 122 123 EARLY_DRIVER_MODULE(macgpio, macio, macgpio_pci_driver, 0, 0, BUS_PASS_BUS); 124 125 struct macgpio_devinfo { 126 struct ofw_bus_devinfo mdi_obdinfo; 127 struct resource_list mdi_resources; 128 129 int gpio_num; 130 }; 131 132 static int 133 macgpio_probe(device_t dev) 134 { 135 const char *name; 136 137 name = ofw_bus_get_name(dev); 138 if (name && strcmp(name, "gpio") == 0) { 139 device_set_desc(dev, "MacIO GPIO Controller"); 140 return (0); 141 } 142 143 return (ENXIO); 144 } 145 146 /* 147 * Scan Open Firmware child nodes, and attach these as children 148 * of the macgpio bus 149 */ 150 static int 151 macgpio_attach(device_t dev) 152 { 153 struct macgpio_softc *sc; 154 struct macgpio_devinfo *dinfo; 155 phandle_t root, child, iparent; 156 device_t cdev; 157 uint32_t irq[2]; 158 159 sc = device_get_softc(dev); 160 root = sc->sc_node = ofw_bus_get_node(dev); 161 162 sc->sc_gpios = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 163 &sc->sc_gpios_rid, RF_ACTIVE); 164 165 /* 166 * Iterate through the sub-devices 167 */ 168 for (child = OF_child(root); child != 0; child = OF_peer(child)) { 169 dinfo = malloc(sizeof(*dinfo), M_MACGPIO, M_WAITOK | M_ZERO); 170 if (ofw_bus_gen_setup_devinfo(&dinfo->mdi_obdinfo, child) != 171 0) { 172 free(dinfo, M_MACGPIO); 173 continue; 174 } 175 176 if (OF_getencprop(child, "reg", &dinfo->gpio_num, 177 sizeof(dinfo->gpio_num)) != sizeof(dinfo->gpio_num)) { 178 /* 179 * Some early GPIO controllers don't provide GPIO 180 * numbers for GPIOs designed only to provide 181 * interrupt resources. We should still allow these 182 * to attach, but with caution. 183 */ 184 185 dinfo->gpio_num = -1; 186 } 187 188 resource_list_init(&dinfo->mdi_resources); 189 190 if (OF_getencprop(child, "interrupts", irq, sizeof(irq)) == 191 sizeof(irq)) { 192 OF_searchencprop(child, "interrupt-parent", &iparent, 193 sizeof(iparent)); 194 resource_list_add(&dinfo->mdi_resources, SYS_RES_IRQ, 195 0, MAP_IRQ(iparent, irq[0]), 196 MAP_IRQ(iparent, irq[0]), 1); 197 } 198 199 /* Fix messed-up offsets */ 200 if (dinfo->gpio_num > 0x50) 201 dinfo->gpio_num -= 0x50; 202 203 cdev = device_add_child(dev, NULL, DEVICE_UNIT_ANY); 204 if (cdev == NULL) { 205 device_printf(dev, "<%s>: device_add_child failed\n", 206 dinfo->mdi_obdinfo.obd_name); 207 ofw_bus_gen_destroy_devinfo(&dinfo->mdi_obdinfo); 208 free(dinfo, M_MACGPIO); 209 continue; 210 } 211 device_set_ivars(cdev, dinfo); 212 } 213 214 return (bus_generic_attach(dev)); 215 } 216 217 static int 218 macgpio_print_child(device_t dev, device_t child) 219 { 220 struct macgpio_devinfo *dinfo; 221 int retval = 0; 222 223 dinfo = device_get_ivars(child); 224 225 retval += bus_print_child_header(dev, child); 226 227 if (dinfo->gpio_num >= GPIO_BASE) 228 printf(" gpio %d", dinfo->gpio_num - GPIO_BASE); 229 else if (dinfo->gpio_num >= GPIO_EXTINT_BASE) 230 printf(" extint-gpio %d", dinfo->gpio_num - GPIO_EXTINT_BASE); 231 else if (dinfo->gpio_num >= 0) 232 printf(" addr 0x%02x", dinfo->gpio_num); /* should not happen */ 233 234 resource_list_print_type(&dinfo->mdi_resources, "irq", SYS_RES_IRQ, 235 "%jd"); 236 retval += bus_print_child_footer(dev, child); 237 238 return (retval); 239 } 240 241 static void 242 macgpio_probe_nomatch(device_t dev, device_t child) 243 { 244 struct macgpio_devinfo *dinfo; 245 const char *type; 246 247 if (bootverbose) { 248 dinfo = device_get_ivars(child); 249 250 if ((type = ofw_bus_get_type(child)) == NULL) 251 type = "(unknown)"; 252 device_printf(dev, "<%s, %s>", type, ofw_bus_get_name(child)); 253 if (dinfo->gpio_num >= 0) 254 printf(" gpio %d",dinfo->gpio_num); 255 resource_list_print_type(&dinfo->mdi_resources, "irq", 256 SYS_RES_IRQ, "%jd"); 257 printf(" (no driver attached)\n"); 258 } 259 } 260 261 static struct resource * 262 macgpio_alloc_resource(device_t bus, device_t child, int type, int *rid, 263 rman_res_t start, rman_res_t end, rman_res_t count, 264 u_int flags) 265 { 266 struct macgpio_devinfo *dinfo; 267 268 dinfo = device_get_ivars(child); 269 270 if (type != SYS_RES_IRQ) 271 return (NULL); 272 273 return (resource_list_alloc(&dinfo->mdi_resources, bus, child, type, 274 rid, start, end, count, flags)); 275 } 276 277 static int 278 macgpio_activate_resource(device_t bus, device_t child, struct resource *res) 279 { 280 struct macgpio_softc *sc; 281 struct macgpio_devinfo *dinfo; 282 u_char val; 283 284 sc = device_get_softc(bus); 285 dinfo = device_get_ivars(child); 286 287 if (rman_get_type(res) != SYS_RES_IRQ) 288 return ENXIO; 289 290 if (dinfo->gpio_num >= 0) { 291 val = bus_read_1(sc->sc_gpios,dinfo->gpio_num); 292 val |= 0x80; 293 bus_write_1(sc->sc_gpios,dinfo->gpio_num,val); 294 } 295 296 return (bus_generic_activate_resource(bus, child, res)); 297 } 298 299 static int 300 macgpio_deactivate_resource(device_t bus, device_t child, struct resource *res) 301 { 302 struct macgpio_softc *sc; 303 struct macgpio_devinfo *dinfo; 304 u_char val; 305 306 sc = device_get_softc(bus); 307 dinfo = device_get_ivars(child); 308 309 if (rman_get_type(res) != SYS_RES_IRQ) 310 return ENXIO; 311 312 if (dinfo->gpio_num >= 0) { 313 val = bus_read_1(sc->sc_gpios,dinfo->gpio_num); 314 val &= ~0x80; 315 bus_write_1(sc->sc_gpios,dinfo->gpio_num,val); 316 } 317 318 return (bus_generic_deactivate_resource(bus, child, res)); 319 } 320 321 uint8_t 322 macgpio_read(device_t dev) 323 { 324 struct macgpio_softc *sc; 325 struct macgpio_devinfo *dinfo; 326 327 sc = device_get_softc(device_get_parent(dev)); 328 dinfo = device_get_ivars(dev); 329 330 if (dinfo->gpio_num < 0) 331 return (0); 332 333 return (bus_read_1(sc->sc_gpios,dinfo->gpio_num)); 334 } 335 336 void 337 macgpio_write(device_t dev, uint8_t val) 338 { 339 struct macgpio_softc *sc; 340 struct macgpio_devinfo *dinfo; 341 342 sc = device_get_softc(device_get_parent(dev)); 343 dinfo = device_get_ivars(dev); 344 345 if (dinfo->gpio_num < 0) 346 return; 347 348 bus_write_1(sc->sc_gpios,dinfo->gpio_num,val); 349 } 350 351 static const struct ofw_bus_devinfo * 352 macgpio_get_devinfo(device_t dev, device_t child) 353 { 354 struct macgpio_devinfo *dinfo; 355 356 dinfo = device_get_ivars(child); 357 return (&dinfo->mdi_obdinfo); 358 } 359 360 static int 361 macgpio_suspend(device_t dev) 362 { 363 struct macgpio_softc *sc; 364 int i; 365 366 sc = device_get_softc(dev); 367 sc->sc_saved_gpio_levels[0] = bus_read_4(sc->sc_gpios, GPIO_LEVELS_0); 368 sc->sc_saved_gpio_levels[1] = bus_read_4(sc->sc_gpios, GPIO_LEVELS_1); 369 370 for (i = 0; i < GPIO_COUNT; i++) 371 sc->sc_saved_gpios[i] = bus_read_1(sc->sc_gpios, GPIO_BASE + i); 372 for (i = 0; i < GPIO_EXTINT_COUNT; i++) 373 sc->sc_saved_extint_gpios[i] = bus_read_1(sc->sc_gpios, GPIO_EXTINT_BASE + i); 374 375 return (0); 376 } 377 378 static int 379 macgpio_resume(device_t dev) 380 { 381 struct macgpio_softc *sc; 382 int i; 383 384 sc = device_get_softc(dev); 385 bus_write_4(sc->sc_gpios, GPIO_LEVELS_0, sc->sc_saved_gpio_levels[0]); 386 bus_write_4(sc->sc_gpios, GPIO_LEVELS_1, sc->sc_saved_gpio_levels[1]); 387 388 for (i = 0; i < GPIO_COUNT; i++) 389 bus_write_1(sc->sc_gpios, GPIO_BASE + i, sc->sc_saved_gpios[i]); 390 for (i = 0; i < GPIO_EXTINT_COUNT; i++) 391 bus_write_1(sc->sc_gpios, GPIO_EXTINT_BASE + i, sc->sc_saved_extint_gpios[i]); 392 393 return (0); 394 } 395