1 /*- 2 * Copyright (c) 2006 Michael Lorenz 3 * Copyright 2008 by Nathan Whitehorn 4 * 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 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 22 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 24 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 */ 30 31 #include <sys/cdefs.h> 32 __FBSDID("$FreeBSD$"); 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/module.h> 37 #include <sys/bus.h> 38 #include <sys/conf.h> 39 #include <sys/kernel.h> 40 41 #include <dev/ofw/ofw_bus.h> 42 #include <dev/ofw/openfirm.h> 43 44 #include <machine/bus.h> 45 #include <machine/intr.h> 46 #include <machine/intr_machdep.h> 47 #include <machine/md_var.h> 48 #include <machine/pio.h> 49 #include <machine/resource.h> 50 51 #include <vm/vm.h> 52 #include <vm/pmap.h> 53 54 #include <sys/rman.h> 55 56 #include <dev/adb/adb.h> 57 58 #include "pmuvar.h" 59 #include "viareg.h" 60 61 /* 62 * MacIO interface 63 */ 64 static int pmu_probe(device_t); 65 static int pmu_attach(device_t); 66 static int pmu_detach(device_t); 67 68 static u_int pmu_adb_send(device_t dev, u_char command_byte, int len, 69 u_char *data, u_char poll); 70 static u_int pmu_adb_autopoll(device_t dev, uint16_t mask); 71 static void pmu_poll(device_t dev); 72 73 static device_method_t pmu_methods[] = { 74 /* Device interface */ 75 DEVMETHOD(device_probe, pmu_probe), 76 DEVMETHOD(device_attach, pmu_attach), 77 DEVMETHOD(device_detach, pmu_detach), 78 DEVMETHOD(device_shutdown, bus_generic_shutdown), 79 DEVMETHOD(device_suspend, bus_generic_suspend), 80 DEVMETHOD(device_resume, bus_generic_resume), 81 82 /* bus interface, for ADB root */ 83 DEVMETHOD(bus_print_child, bus_generic_print_child), 84 DEVMETHOD(bus_driver_added, bus_generic_driver_added), 85 86 /* ADB bus interface */ 87 DEVMETHOD(adb_hb_send_raw_packet, pmu_adb_send), 88 DEVMETHOD(adb_hb_controller_poll, pmu_poll), 89 DEVMETHOD(adb_hb_set_autopoll_mask, pmu_adb_autopoll), 90 91 { 0, 0 }, 92 }; 93 94 static driver_t pmu_driver = { 95 "pmu", 96 pmu_methods, 97 sizeof(struct pmu_softc), 98 }; 99 100 static devclass_t pmu_devclass; 101 102 DRIVER_MODULE(pmu, macio, pmu_driver, pmu_devclass, 0, 0); 103 DRIVER_MODULE(adb, pmu, adb_driver, adb_devclass, 0, 0); 104 105 static int pmuextint_probe(device_t); 106 static int pmuextint_attach(device_t); 107 108 static device_method_t pmuextint_methods[] = { 109 /* Device interface */ 110 DEVMETHOD(device_probe, pmuextint_probe), 111 DEVMETHOD(device_attach, pmuextint_attach), 112 113 {0,0} 114 }; 115 116 static driver_t pmuextint_driver = { 117 "pmuextint", 118 pmuextint_methods, 119 0 120 }; 121 122 static devclass_t pmuextint_devclass; 123 124 DRIVER_MODULE(pmuextint, macgpio, pmuextint_driver, pmuextint_devclass, 0, 0); 125 126 /* Make sure uhid is loaded, as it turns off some of the ADB emulation */ 127 MODULE_DEPEND(pmu, usb, 1, 1, 1); 128 129 static void pmu_intr(void *arg); 130 static void pmu_in(struct pmu_softc *sc); 131 static void pmu_out(struct pmu_softc *sc); 132 static void pmu_ack_on(struct pmu_softc *sc); 133 static void pmu_ack_off(struct pmu_softc *sc); 134 static int pmu_send(void *cookie, int cmd, int length, uint8_t *in_msg, 135 int rlen, uint8_t *out_msg); 136 static uint8_t pmu_read_reg(struct pmu_softc *sc, u_int offset); 137 static void pmu_write_reg(struct pmu_softc *sc, u_int offset, uint8_t value); 138 static int pmu_intr_state(struct pmu_softc *); 139 140 /* these values shows that number of data returned after 'send' cmd is sent */ 141 static signed char pm_send_cmd_type[] = { 142 -1, -1, -1, -1, -1, -1, -1, -1, 143 -1, -1, -1, -1, -1, -1, -1, -1, 144 0x01, 0x01, -1, -1, -1, -1, -1, -1, 145 0x00, 0x00, -1, -1, -1, -1, -1, 0x00, 146 -1, 0x00, 0x02, 0x01, 0x01, -1, -1, -1, 147 0x00, -1, -1, -1, -1, -1, -1, -1, 148 0x04, 0x14, -1, 0x03, -1, -1, -1, -1, 149 0x00, 0x00, 0x02, 0x02, -1, -1, -1, -1, 150 0x01, 0x01, -1, -1, -1, -1, -1, -1, 151 0x00, 0x00, -1, -1, 0x01, -1, -1, -1, 152 0x01, 0x00, 0x02, 0x02, -1, 0x01, 0x03, 0x01, 153 0x00, 0x01, 0x00, 0x00, 0x00, -1, -1, -1, 154 0x02, -1, -1, -1, -1, -1, -1, -1, 155 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -1, -1, 156 0x01, 0x01, 0x01, -1, -1, -1, -1, -1, 157 0x00, 0x00, -1, -1, -1, -1, 0x04, 0x04, 158 0x04, -1, 0x00, -1, -1, -1, -1, -1, 159 0x00, -1, -1, -1, -1, -1, -1, -1, 160 0x01, 0x02, -1, -1, -1, -1, -1, -1, 161 0x00, 0x00, -1, -1, -1, -1, -1, -1, 162 0x02, 0x02, 0x02, 0x04, -1, 0x00, -1, -1, 163 0x01, 0x01, 0x03, 0x02, -1, -1, -1, -1, 164 -1, -1, -1, -1, -1, -1, -1, -1, 165 -1, -1, -1, -1, -1, -1, -1, -1, 166 -1, -1, -1, -1, -1, -1, -1, -1, 167 -1, -1, -1, -1, -1, -1, -1, -1, 168 0x00, -1, -1, -1, -1, -1, -1, -1, 169 0x01, 0x01, -1, -1, 0x00, 0x00, -1, -1, 170 -1, 0x04, 0x00, -1, -1, -1, -1, -1, 171 0x03, -1, 0x00, -1, 0x00, -1, -1, 0x00, 172 -1, -1, -1, -1, -1, -1, -1, -1, 173 -1, -1, -1, -1, -1, -1, -1, -1 174 }; 175 176 /* these values shows that number of data returned after 'receive' cmd is sent */ 177 static signed char pm_receive_cmd_type[] = { 178 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 179 -1, -1, -1, -1, -1, -1, -1, -1, 180 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 181 0x02, 0x02, -1, -1, -1, -1, -1, 0x00, 182 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 183 -1, -1, -1, -1, -1, -1, -1, -1, 184 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 185 0x05, 0x15, -1, 0x02, -1, -1, -1, -1, 186 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 187 0x02, 0x02, -1, -1, -1, -1, -1, -1, 188 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 189 0x02, 0x00, 0x03, 0x03, -1, -1, -1, -1, 190 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 191 0x04, 0x04, 0x03, 0x09, -1, -1, -1, -1, 192 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 193 -1, -1, -1, -1, -1, -1, 0x01, 0x01, 194 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 195 0x06, -1, -1, -1, -1, -1, -1, -1, 196 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 197 0x02, 0x02, -1, -1, -1, -1, -1, -1, 198 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 199 0x02, 0x00, 0x00, 0x00, -1, -1, -1, -1, 200 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 201 -1, -1, -1, -1, -1, -1, -1, -1, 202 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 203 -1, -1, -1, -1, -1, -1, -1, -1, 204 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 205 0x02, 0x02, -1, -1, 0x02, -1, -1, -1, 206 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 207 -1, -1, 0x02, -1, -1, -1, -1, 0x00, 208 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 209 -1, -1, -1, -1, -1, -1, -1, -1, 210 }; 211 212 /* We only have one of each device, so globals are safe */ 213 static device_t pmu = NULL; 214 static device_t pmu_extint = NULL; 215 216 static int 217 pmuextint_probe(device_t dev) 218 { 219 const char *type = ofw_bus_get_type(dev); 220 221 if (strcmp(type, "extint-gpio1") != 0) 222 return (ENXIO); 223 224 device_set_desc(dev, "Apple PMU99 External Interrupt"); 225 return (0); 226 } 227 228 static int 229 pmu_probe(device_t dev) 230 { 231 const char *type = ofw_bus_get_type(dev); 232 233 if (strcmp(type, "via-pmu") != 0) 234 return (ENXIO); 235 236 device_set_desc(dev, "Apple PMU99 Controller"); 237 return (0); 238 } 239 240 241 static int 242 setup_pmu_intr(device_t dev, device_t extint) 243 { 244 struct pmu_softc *sc; 245 sc = device_get_softc(dev); 246 247 sc->sc_irqrid = 0; 248 sc->sc_irq = bus_alloc_resource_any(extint, SYS_RES_IRQ, &sc->sc_irqrid, 249 RF_ACTIVE); 250 if (sc->sc_irq == NULL) { 251 device_printf(dev, "could not allocate interrupt\n"); 252 return (ENXIO); 253 } 254 255 if (bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_MISC | INTR_MPSAFE 256 | INTR_ENTROPY, NULL, pmu_intr, dev, &sc->sc_ih) != 0) { 257 device_printf(dev, "could not setup interrupt\n"); 258 bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqrid, 259 sc->sc_irq); 260 return (ENXIO); 261 } 262 263 return (0); 264 } 265 266 static int 267 pmuextint_attach(device_t dev) 268 { 269 pmu_extint = dev; 270 if (pmu) 271 return (setup_pmu_intr(pmu,dev)); 272 273 return (0); 274 } 275 276 static int 277 pmu_attach(device_t dev) 278 { 279 struct pmu_softc *sc; 280 281 uint8_t reg; 282 uint8_t cmd[2] = {2, 0}; 283 uint8_t resp[16]; 284 phandle_t node,child; 285 286 sc = device_get_softc(dev); 287 sc->sc_dev = dev; 288 289 sc->sc_memrid = 0; 290 sc->sc_memr = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 291 &sc->sc_memrid, RF_ACTIVE); 292 293 mtx_init(&sc->sc_mutex,"pmu",NULL,MTX_DEF | MTX_RECURSE); 294 295 if (sc->sc_memr == NULL) { 296 device_printf(dev, "Could not alloc mem resource!\n"); 297 return (ENXIO); 298 } 299 300 /* 301 * Our interrupt is attached to a GPIO pin. Depending on probe order, 302 * we may not have found it yet. If we haven't, it will find us, and 303 * attach our interrupt then. 304 */ 305 pmu = dev; 306 if (pmu_extint != NULL) { 307 if (setup_pmu_intr(dev,pmu_extint) != 0) 308 return (ENXIO); 309 } 310 311 sc->sc_error = 0; 312 sc->sc_polling = 0; 313 sc->sc_autopoll = 0; 314 315 /* Init PMU */ 316 317 reg = PMU_INT_TICK | PMU_INT_ADB | PMU_INT_PCEJECT | PMU_INT_SNDBRT; 318 reg |= PMU_INT_BATTERY; 319 reg |= PMU_INT_ENVIRONMENT; 320 pmu_send(sc, PMU_SET_IMASK, 1, ®, 16, resp); 321 322 pmu_write_reg(sc, vIER, 0x90); /* make sure VIA interrupts are on */ 323 324 pmu_send(sc, PMU_SYSTEM_READY, 1, cmd, 16, resp); 325 pmu_send(sc, PMU_GET_VERSION, 1, cmd, 16, resp); 326 327 /* Initialize child buses (ADB) */ 328 node = ofw_bus_get_node(dev); 329 330 for (child = OF_child(node); child != 0; child = OF_peer(child)) { 331 char name[32]; 332 333 memset(name, 0, sizeof(name)); 334 OF_getprop(child, "name", name, sizeof(name)); 335 336 if (bootverbose) 337 device_printf(dev, "PMU child <%s>\n",name); 338 339 if (strncmp(name, "adb", 4) == 0) { 340 sc->adb_bus = device_add_child(dev,"adb",-1); 341 } 342 } 343 344 return (bus_generic_attach(dev)); 345 } 346 347 static int 348 pmu_detach(device_t dev) 349 { 350 struct pmu_softc *sc; 351 352 sc = device_get_softc(dev); 353 354 bus_teardown_intr(dev, sc->sc_irq, sc->sc_ih); 355 bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqrid, sc->sc_irq); 356 bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_memrid, sc->sc_memr); 357 mtx_destroy(&sc->sc_mutex); 358 359 return (bus_generic_detach(dev)); 360 } 361 362 static uint8_t 363 pmu_read_reg(struct pmu_softc *sc, u_int offset) 364 { 365 return (bus_read_1(sc->sc_memr, offset)); 366 } 367 368 static void 369 pmu_write_reg(struct pmu_softc *sc, u_int offset, uint8_t value) 370 { 371 bus_write_1(sc->sc_memr, offset, value); 372 } 373 374 static int 375 pmu_send_byte(struct pmu_softc *sc, uint8_t data) 376 { 377 378 pmu_out(sc); 379 pmu_write_reg(sc, vSR, data); 380 pmu_ack_off(sc); 381 /* wait for intr to come up */ 382 /* XXX should add a timeout and bail if it expires */ 383 do {} while (pmu_intr_state(sc) == 0); 384 pmu_ack_on(sc); 385 do {} while (pmu_intr_state(sc)); 386 pmu_ack_on(sc); 387 return 0; 388 } 389 390 static inline int 391 pmu_read_byte(struct pmu_softc *sc, uint8_t *data) 392 { 393 volatile uint8_t scratch; 394 pmu_in(sc); 395 scratch = pmu_read_reg(sc, vSR); 396 pmu_ack_off(sc); 397 /* wait for intr to come up */ 398 do {} while (pmu_intr_state(sc) == 0); 399 pmu_ack_on(sc); 400 do {} while (pmu_intr_state(sc)); 401 *data = pmu_read_reg(sc, vSR); 402 return 0; 403 } 404 405 static int 406 pmu_intr_state(struct pmu_softc *sc) 407 { 408 return ((pmu_read_reg(sc, vBufB) & vPB3) == 0); 409 } 410 411 static int 412 pmu_send(void *cookie, int cmd, int length, uint8_t *in_msg, int rlen, 413 uint8_t *out_msg) 414 { 415 struct pmu_softc *sc = cookie; 416 int i, rcv_len = -1; 417 uint8_t out_len, intreg; 418 419 intreg = pmu_read_reg(sc, vIER); 420 intreg &= 0x10; 421 pmu_write_reg(sc, vIER, intreg); 422 423 /* wait idle */ 424 do {} while (pmu_intr_state(sc)); 425 sc->sc_error = 0; 426 427 /* send command */ 428 pmu_send_byte(sc, cmd); 429 430 /* send length if necessary */ 431 if (pm_send_cmd_type[cmd] < 0) { 432 pmu_send_byte(sc, length); 433 } 434 435 for (i = 0; i < length; i++) { 436 pmu_send_byte(sc, in_msg[i]); 437 } 438 439 /* see if there's data to read */ 440 rcv_len = pm_receive_cmd_type[cmd]; 441 if (rcv_len == 0) 442 goto done; 443 444 /* read command */ 445 if (rcv_len == 1) { 446 pmu_read_byte(sc, out_msg); 447 goto done; 448 } else 449 out_msg[0] = cmd; 450 if (rcv_len < 0) { 451 pmu_read_byte(sc, &out_len); 452 rcv_len = out_len + 1; 453 } 454 for (i = 1; i < min(rcv_len, rlen); i++) 455 pmu_read_byte(sc, &out_msg[i]); 456 457 done: 458 pmu_write_reg(sc, vIER, (intreg == 0) ? 0 : 0x90); 459 460 return rcv_len; 461 } 462 463 464 static void 465 pmu_poll(device_t dev) 466 { 467 pmu_intr(dev); 468 } 469 470 static void 471 pmu_in(struct pmu_softc *sc) 472 { 473 uint8_t reg; 474 475 reg = pmu_read_reg(sc, vACR); 476 reg &= ~vSR_OUT; 477 reg |= 0x0c; 478 pmu_write_reg(sc, vACR, reg); 479 } 480 481 static void 482 pmu_out(struct pmu_softc *sc) 483 { 484 uint8_t reg; 485 486 reg = pmu_read_reg(sc, vACR); 487 reg |= vSR_OUT; 488 reg |= 0x0c; 489 pmu_write_reg(sc, vACR, reg); 490 } 491 492 static void 493 pmu_ack_off(struct pmu_softc *sc) 494 { 495 uint8_t reg; 496 497 reg = pmu_read_reg(sc, vBufB); 498 reg &= ~vPB4; 499 pmu_write_reg(sc, vBufB, reg); 500 } 501 502 static void 503 pmu_ack_on(struct pmu_softc *sc) 504 { 505 uint8_t reg; 506 507 reg = pmu_read_reg(sc, vBufB); 508 reg |= vPB4; 509 pmu_write_reg(sc, vBufB, reg); 510 } 511 512 static void 513 pmu_intr(void *arg) 514 { 515 device_t dev; 516 struct pmu_softc *sc; 517 518 unsigned int len; 519 uint8_t resp[16]; 520 uint8_t junk[16]; 521 522 dev = (device_t)arg; 523 sc = device_get_softc(dev); 524 525 mtx_lock(&sc->sc_mutex); 526 527 pmu_write_reg(sc, vIFR, 0x90); /* Clear 'em */ 528 len = pmu_send(sc, PMU_INT_ACK, 0, NULL, 16, resp); 529 530 mtx_unlock(&sc->sc_mutex); 531 532 if ((len < 1) || (resp[1] == 0)) { 533 return; 534 } 535 536 if (resp[1] & PMU_INT_ADB) { 537 /* 538 * the PMU will turn off autopolling after each command that 539 * it did not issue, so we assume any but TALK R0 is ours and 540 * re-enable autopoll here whenever we receive an ACK for a 541 * non TR0 command. 542 */ 543 mtx_lock(&sc->sc_mutex); 544 545 if ((resp[2] & 0x0f) != (ADB_COMMAND_TALK << 2)) { 546 if (sc->sc_autopoll) { 547 uint8_t cmd[] = {0, PMU_SET_POLL_MASK, 548 (sc->sc_autopoll >> 8) & 0xff, 549 sc->sc_autopoll & 0xff}; 550 551 pmu_send(sc, PMU_ADB_CMD, 4, cmd, 16, junk); 552 } 553 } 554 555 mtx_unlock(&sc->sc_mutex); 556 557 adb_receive_raw_packet(sc->adb_bus,resp[1],resp[2], 558 len - 3,&resp[3]); 559 } 560 } 561 562 static u_int 563 pmu_adb_send(device_t dev, u_char command_byte, int len, u_char *data, 564 u_char poll) 565 { 566 struct pmu_softc *sc = device_get_softc(dev); 567 int i,replen; 568 uint8_t packet[16], resp[16]; 569 570 /* construct an ADB command packet and send it */ 571 572 packet[0] = command_byte; 573 574 packet[1] = 0; 575 packet[2] = len; 576 for (i = 0; i < len; i++) 577 packet[i + 3] = data[i]; 578 579 mtx_lock(&sc->sc_mutex); 580 replen = pmu_send(sc, PMU_ADB_CMD, len + 3, packet, 16, resp); 581 mtx_unlock(&sc->sc_mutex); 582 583 if (poll) 584 pmu_poll(dev); 585 586 return 0; 587 } 588 589 static u_int 590 pmu_adb_autopoll(device_t dev, uint16_t mask) 591 { 592 struct pmu_softc *sc = device_get_softc(dev); 593 594 /* magical incantation to re-enable autopolling */ 595 uint8_t cmd[] = {0, PMU_SET_POLL_MASK, (mask >> 8) & 0xff, mask & 0xff}; 596 uint8_t resp[16]; 597 598 mtx_lock(&sc->sc_mutex); 599 600 if (sc->sc_autopoll == mask) { 601 mtx_unlock(&sc->sc_mutex); 602 return 0; 603 } 604 605 sc->sc_autopoll = mask & 0xffff; 606 607 if (mask) 608 pmu_send(sc, PMU_ADB_CMD, 4, cmd, 16, resp); 609 else 610 pmu_send(sc, PMU_ADB_POLL_OFF, 0, NULL, 16, resp); 611 612 mtx_unlock(&sc->sc_mutex); 613 614 return 0; 615 } 616