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 bus_attach_children(dev); 215 return (0); 216 } 217 218 static int 219 macgpio_print_child(device_t dev, device_t child) 220 { 221 struct macgpio_devinfo *dinfo; 222 int retval = 0; 223 224 dinfo = device_get_ivars(child); 225 226 retval += bus_print_child_header(dev, child); 227 228 if (dinfo->gpio_num >= GPIO_BASE) 229 printf(" gpio %d", dinfo->gpio_num - GPIO_BASE); 230 else if (dinfo->gpio_num >= GPIO_EXTINT_BASE) 231 printf(" extint-gpio %d", dinfo->gpio_num - GPIO_EXTINT_BASE); 232 else if (dinfo->gpio_num >= 0) 233 printf(" addr 0x%02x", dinfo->gpio_num); /* should not happen */ 234 235 resource_list_print_type(&dinfo->mdi_resources, "irq", SYS_RES_IRQ, 236 "%jd"); 237 retval += bus_print_child_footer(dev, child); 238 239 return (retval); 240 } 241 242 static void 243 macgpio_probe_nomatch(device_t dev, device_t child) 244 { 245 struct macgpio_devinfo *dinfo; 246 const char *type; 247 248 if (bootverbose) { 249 dinfo = device_get_ivars(child); 250 251 if ((type = ofw_bus_get_type(child)) == NULL) 252 type = "(unknown)"; 253 device_printf(dev, "<%s, %s>", type, ofw_bus_get_name(child)); 254 if (dinfo->gpio_num >= 0) 255 printf(" gpio %d",dinfo->gpio_num); 256 resource_list_print_type(&dinfo->mdi_resources, "irq", 257 SYS_RES_IRQ, "%jd"); 258 printf(" (no driver attached)\n"); 259 } 260 } 261 262 static struct resource * 263 macgpio_alloc_resource(device_t bus, device_t child, int type, int *rid, 264 rman_res_t start, rman_res_t end, rman_res_t count, 265 u_int flags) 266 { 267 struct macgpio_devinfo *dinfo; 268 269 dinfo = device_get_ivars(child); 270 271 if (type != SYS_RES_IRQ) 272 return (NULL); 273 274 return (resource_list_alloc(&dinfo->mdi_resources, bus, child, type, 275 rid, start, end, count, flags)); 276 } 277 278 static int 279 macgpio_activate_resource(device_t bus, device_t child, struct resource *res) 280 { 281 struct macgpio_softc *sc; 282 struct macgpio_devinfo *dinfo; 283 u_char val; 284 285 sc = device_get_softc(bus); 286 dinfo = device_get_ivars(child); 287 288 if (rman_get_type(res) != SYS_RES_IRQ) 289 return ENXIO; 290 291 if (dinfo->gpio_num >= 0) { 292 val = bus_read_1(sc->sc_gpios,dinfo->gpio_num); 293 val |= 0x80; 294 bus_write_1(sc->sc_gpios,dinfo->gpio_num,val); 295 } 296 297 return (bus_generic_activate_resource(bus, child, res)); 298 } 299 300 static int 301 macgpio_deactivate_resource(device_t bus, device_t child, struct resource *res) 302 { 303 struct macgpio_softc *sc; 304 struct macgpio_devinfo *dinfo; 305 u_char val; 306 307 sc = device_get_softc(bus); 308 dinfo = device_get_ivars(child); 309 310 if (rman_get_type(res) != SYS_RES_IRQ) 311 return ENXIO; 312 313 if (dinfo->gpio_num >= 0) { 314 val = bus_read_1(sc->sc_gpios,dinfo->gpio_num); 315 val &= ~0x80; 316 bus_write_1(sc->sc_gpios,dinfo->gpio_num,val); 317 } 318 319 return (bus_generic_deactivate_resource(bus, child, res)); 320 } 321 322 uint8_t 323 macgpio_read(device_t dev) 324 { 325 struct macgpio_softc *sc; 326 struct macgpio_devinfo *dinfo; 327 328 sc = device_get_softc(device_get_parent(dev)); 329 dinfo = device_get_ivars(dev); 330 331 if (dinfo->gpio_num < 0) 332 return (0); 333 334 return (bus_read_1(sc->sc_gpios,dinfo->gpio_num)); 335 } 336 337 void 338 macgpio_write(device_t dev, uint8_t val) 339 { 340 struct macgpio_softc *sc; 341 struct macgpio_devinfo *dinfo; 342 343 sc = device_get_softc(device_get_parent(dev)); 344 dinfo = device_get_ivars(dev); 345 346 if (dinfo->gpio_num < 0) 347 return; 348 349 bus_write_1(sc->sc_gpios,dinfo->gpio_num,val); 350 } 351 352 static const struct ofw_bus_devinfo * 353 macgpio_get_devinfo(device_t dev, device_t child) 354 { 355 struct macgpio_devinfo *dinfo; 356 357 dinfo = device_get_ivars(child); 358 return (&dinfo->mdi_obdinfo); 359 } 360 361 static int 362 macgpio_suspend(device_t dev) 363 { 364 struct macgpio_softc *sc; 365 int i; 366 367 sc = device_get_softc(dev); 368 sc->sc_saved_gpio_levels[0] = bus_read_4(sc->sc_gpios, GPIO_LEVELS_0); 369 sc->sc_saved_gpio_levels[1] = bus_read_4(sc->sc_gpios, GPIO_LEVELS_1); 370 371 for (i = 0; i < GPIO_COUNT; i++) 372 sc->sc_saved_gpios[i] = bus_read_1(sc->sc_gpios, GPIO_BASE + i); 373 for (i = 0; i < GPIO_EXTINT_COUNT; i++) 374 sc->sc_saved_extint_gpios[i] = bus_read_1(sc->sc_gpios, GPIO_EXTINT_BASE + i); 375 376 return (0); 377 } 378 379 static int 380 macgpio_resume(device_t dev) 381 { 382 struct macgpio_softc *sc; 383 int i; 384 385 sc = device_get_softc(dev); 386 bus_write_4(sc->sc_gpios, GPIO_LEVELS_0, sc->sc_saved_gpio_levels[0]); 387 bus_write_4(sc->sc_gpios, GPIO_LEVELS_1, sc->sc_saved_gpio_levels[1]); 388 389 for (i = 0; i < GPIO_COUNT; i++) 390 bus_write_1(sc->sc_gpios, GPIO_BASE + i, sc->sc_saved_gpios[i]); 391 for (i = 0; i < GPIO_EXTINT_COUNT; i++) 392 bus_write_1(sc->sc_gpios, GPIO_EXTINT_BASE + i, sc->sc_saved_extint_gpios[i]); 393 394 return (0); 395 } 396