cuda.c revision 184299
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: head/sys/powerpc/powermac/cuda.c 184299 2008-10-26 19:37:38Z nwhitehorn $"); 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 "cudavar.h" 59#include "viareg.h" 60 61/* 62 * MacIO interface 63 */ 64static int cuda_probe(device_t); 65static int cuda_attach(device_t); 66static int cuda_detach(device_t); 67 68static u_int cuda_adb_send(device_t dev, u_char command_byte, int len, 69 u_char *data, u_char poll); 70static u_int cuda_adb_autopoll(device_t dev, uint16_t mask); 71static void cuda_poll(device_t dev); 72 73static device_method_t cuda_methods[] = { 74 /* Device interface */ 75 DEVMETHOD(device_probe, cuda_probe), 76 DEVMETHOD(device_attach, cuda_attach), 77 DEVMETHOD(device_detach, cuda_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, cuda_adb_send), 88 DEVMETHOD(adb_hb_controller_poll, cuda_poll), 89 DEVMETHOD(adb_hb_set_autopoll_mask, cuda_adb_autopoll), 90 91 { 0, 0 }, 92}; 93 94static driver_t cuda_driver = { 95 "cuda", 96 cuda_methods, 97 sizeof(struct cuda_softc), 98}; 99 100static devclass_t cuda_devclass; 101 102DRIVER_MODULE(cuda, macio, cuda_driver, cuda_devclass, 0, 0); 103DRIVER_MODULE(adb, cuda, adb_driver, adb_devclass, 0, 0); 104 105static void cuda_intr(void *arg); 106static uint8_t cuda_read_reg(struct cuda_softc *sc, u_int offset); 107static void cuda_write_reg(struct cuda_softc *sc, u_int offset, uint8_t value); 108static void cuda_idle(struct cuda_softc *); 109static void cuda_tip(struct cuda_softc *); 110static void cuda_clear_tip(struct cuda_softc *); 111static void cuda_in(struct cuda_softc *); 112static void cuda_out(struct cuda_softc *); 113static void cuda_toggle_ack(struct cuda_softc *); 114static void cuda_ack_off(struct cuda_softc *); 115static int cuda_intr_state(struct cuda_softc *); 116 117static int 118cuda_probe(device_t dev) 119{ 120 const char *type = ofw_bus_get_type(dev); 121 122 if (strcmp(type, "via-cuda") != 0) 123 return (ENXIO); 124 125 device_set_desc(dev, CUDA_DEVSTR); 126 return (0); 127} 128 129static int 130cuda_attach(device_t dev) 131{ 132 struct cuda_softc *sc; 133 134 volatile int i; 135 uint8_t reg; 136 phandle_t node,child; 137 138 sc = device_get_softc(dev); 139 sc->sc_dev = dev; 140 141 sc->sc_memrid = 0; 142 sc->sc_memr = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 143 &sc->sc_memrid, RF_ACTIVE); 144 145 if (sc->sc_memr == NULL) { 146 device_printf(dev, "Could not alloc mem resource!\n"); 147 return (ENXIO); 148 } 149 150 sc->sc_irqrid = 0; 151 sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irqrid, 152 RF_ACTIVE); 153 if (sc->sc_irq == NULL) { 154 device_printf(dev, "could not allocate interrupt\n"); 155 return (ENXIO); 156 } 157 158 if (bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_MISC | INTR_MPSAFE 159 | INTR_ENTROPY, NULL, cuda_intr, dev, &sc->sc_ih) != 0) { 160 device_printf(dev, "could not setup interrupt\n"); 161 bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqrid, 162 sc->sc_irq); 163 return (ENXIO); 164 } 165 166 mtx_init(&sc->sc_mutex,"cuda",NULL,MTX_DEF | MTX_RECURSE); 167 168 sc->sc_sent = 0; 169 sc->sc_received = 0; 170 sc->sc_waiting = 0; 171 sc->sc_polling = 0; 172 sc->sc_state = CUDA_NOTREADY; 173 sc->sc_error = 0; 174 sc->sc_autopoll = 0; 175 176 /* Init CUDA */ 177 178 reg = cuda_read_reg(sc, vDirB); 179 reg |= 0x30; /* register B bits 4 and 5: outputs */ 180 cuda_write_reg(sc, vDirB, reg); 181 182 reg = cuda_read_reg(sc, vDirB); 183 reg &= 0xf7; /* register B bit 3: input */ 184 cuda_write_reg(sc, vDirB, reg); 185 186 reg = cuda_read_reg(sc, vACR); 187 reg &= ~vSR_OUT; /* make sure SR is set to IN */ 188 cuda_write_reg(sc, vACR, reg); 189 190 cuda_write_reg(sc, vACR, (cuda_read_reg(sc, vACR) | 0x0c) & ~0x10); 191 192 sc->sc_state = CUDA_IDLE; /* used by all types of hardware */ 193 194 cuda_write_reg(sc, vIER, 0x84); /* make sure VIA interrupts are on */ 195 196 cuda_idle(sc); /* reset ADB */ 197 198 /* Reset CUDA */ 199 200 i = cuda_read_reg(sc, vSR); /* clear interrupt */ 201 cuda_write_reg(sc, vIER, 0x04); /* no interrupts while clearing */ 202 cuda_idle(sc); /* reset state to idle */ 203 DELAY(150); 204 cuda_tip(sc); /* signal start of frame */ 205 DELAY(150); 206 cuda_toggle_ack(sc); 207 DELAY(150); 208 cuda_clear_tip(sc); 209 DELAY(150); 210 cuda_idle(sc); /* back to idle state */ 211 i = cuda_read_reg(sc, vSR); /* clear interrupt */ 212 cuda_write_reg(sc, vIER, 0x84); /* ints ok now */ 213 214 /* Initialize child buses (ADB) */ 215 node = ofw_bus_get_node(dev); 216 217 for (child = OF_child(node); child != 0; child = OF_peer(child)) { 218 char name[32]; 219 220 memset(name, 0, sizeof(name)); 221 OF_getprop(child, "name", name, sizeof(name)); 222 223 if (bootverbose) 224 device_printf(dev, "CUDA child <%s>\n",name); 225 226 if (strncmp(name, "adb", 4) == 0) { 227 sc->adb_bus = device_add_child(dev,"adb",-1); 228 } 229 } 230 231 return (bus_generic_attach(dev)); 232} 233 234static int cuda_detach(device_t dev) { 235 struct cuda_softc *sc; 236 237 sc = device_get_softc(dev); 238 239 bus_teardown_intr(dev, sc->sc_irq, sc->sc_ih); 240 bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqrid, sc->sc_irq); 241 bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_memrid, sc->sc_memr); 242 mtx_destroy(&sc->sc_mutex); 243 244 return (bus_generic_detach(dev)); 245} 246 247static uint8_t 248cuda_read_reg(struct cuda_softc *sc, u_int offset) { 249 return (bus_read_1(sc->sc_memr, offset)); 250} 251 252static void 253cuda_write_reg(struct cuda_softc *sc, u_int offset, uint8_t value) { 254 bus_write_1(sc->sc_memr, offset, value); 255} 256 257static void 258cuda_idle(struct cuda_softc *sc) 259{ 260 uint8_t reg; 261 262 reg = cuda_read_reg(sc, vBufB); 263 reg |= (vPB4 | vPB5); 264 cuda_write_reg(sc, vBufB, reg); 265} 266 267static void 268cuda_tip(struct cuda_softc *sc) 269{ 270 uint8_t reg; 271 272 reg = cuda_read_reg(sc, vBufB); 273 reg &= ~vPB5; 274 cuda_write_reg(sc, vBufB, reg); 275} 276 277static void 278cuda_clear_tip(struct cuda_softc *sc) 279{ 280 uint8_t reg; 281 282 reg = cuda_read_reg(sc, vBufB); 283 reg |= vPB5; 284 cuda_write_reg(sc, vBufB, reg); 285} 286 287static void 288cuda_in(struct cuda_softc *sc) 289{ 290 uint8_t reg; 291 292 reg = cuda_read_reg(sc, vACR); 293 reg &= ~vSR_OUT; 294 cuda_write_reg(sc, vACR, reg); 295} 296 297static void 298cuda_out(struct cuda_softc *sc) 299{ 300 uint8_t reg; 301 302 reg = cuda_read_reg(sc, vACR); 303 reg |= vSR_OUT; 304 cuda_write_reg(sc, vACR, reg); 305} 306 307static void 308cuda_toggle_ack(struct cuda_softc *sc) 309{ 310 uint8_t reg; 311 312 reg = cuda_read_reg(sc, vBufB); 313 reg ^= vPB4; 314 cuda_write_reg(sc, vBufB, reg); 315} 316 317static void 318cuda_ack_off(struct cuda_softc *sc) 319{ 320 uint8_t reg; 321 322 reg = cuda_read_reg(sc, vBufB); 323 reg |= vPB4; 324 cuda_write_reg(sc, vBufB, reg); 325} 326 327static int 328cuda_intr_state(struct cuda_softc *sc) 329{ 330 return ((cuda_read_reg(sc, vBufB) & vPB3) == 0); 331} 332 333static int 334cuda_send(void *cookie, int poll, int length, uint8_t *msg) 335{ 336 struct cuda_softc *sc = cookie; 337 device_t dev = sc->sc_dev; 338 339 if (sc->sc_state == CUDA_NOTREADY) 340 return -1; 341 342 mtx_lock(&sc->sc_mutex); 343 344 if ((sc->sc_state == CUDA_IDLE) /*&& 345 ((cuda_read_reg(sc, vBufB) & vPB3) == vPB3)*/) { 346 /* fine */ 347 } else { 348 if (sc->sc_waiting == 0) { 349 sc->sc_waiting = 1; 350 } else { 351 mtx_unlock(&sc->sc_mutex); 352 return -1; 353 } 354 } 355 356 sc->sc_error = 0; 357 memcpy(sc->sc_out, msg, length); 358 sc->sc_out_length = length; 359 sc->sc_sent = 0; 360 361 if (sc->sc_waiting != 1) { 362 DELAY(150); 363 sc->sc_state = CUDA_OUT; 364 cuda_out(sc); 365 cuda_write_reg(sc, vSR, sc->sc_out[0]); 366 cuda_ack_off(sc); 367 cuda_tip(sc); 368 } 369 sc->sc_waiting = 1; 370 mtx_unlock(&sc->sc_mutex); 371 372 if (sc->sc_polling || poll || cold) { 373 cuda_poll(dev); 374 } 375 376 return 0; 377} 378 379static void 380cuda_poll(device_t dev) 381{ 382 struct cuda_softc *sc = device_get_softc(dev); 383 384 while ((sc->sc_state != CUDA_IDLE) || 385 (cuda_intr_state(sc)) || 386 (sc->sc_waiting == 1)) { 387 if ((cuda_read_reg(sc, vIFR) & vSR_INT) == vSR_INT) 388 cuda_intr(dev); 389 } 390} 391 392static void 393cuda_intr(void *arg) 394{ 395 device_t dev; 396 struct cuda_softc *sc; 397 398 int i, ending, type, restart_send; 399 uint8_t reg; 400 401 dev = (device_t)arg; 402 sc = device_get_softc(dev); 403 404 mtx_lock(&sc->sc_mutex); 405 406 restart_send = 0; 407 reg = cuda_read_reg(sc, vIFR); 408 cuda_write_reg(sc, vIFR, 0x7f); /* Clear interrupt */ 409 410switch_start: 411 switch (sc->sc_state) { 412 case CUDA_IDLE: 413 /* 414 * This is an unexpected packet, so grab the first (dummy) 415 * byte, set up the proper vars, and tell the chip we are 416 * starting to receive the packet by setting the TIP bit. 417 */ 418 sc->sc_in[1] = cuda_read_reg(sc, vSR); 419 420 if (cuda_intr_state(sc) == 0) { 421 /* must have been a fake start */ 422 423 if (sc->sc_waiting) { 424 /* start over */ 425 DELAY(150); 426 sc->sc_state = CUDA_OUT; 427 sc->sc_sent = 0; 428 cuda_out(sc); 429 cuda_write_reg(sc, vSR, sc->sc_out[1]); 430 cuda_ack_off(sc); 431 cuda_tip(sc); 432 } 433 break; 434 } 435 436 cuda_in(sc); 437 cuda_tip(sc); 438 439 sc->sc_received = 1; 440 sc->sc_state = CUDA_IN; 441 break; 442 443 case CUDA_IN: 444 sc->sc_in[sc->sc_received] = cuda_read_reg(sc, vSR); 445 ending = 0; 446 447 if (sc->sc_received > 255) { 448 /* bitch only once */ 449 if (sc->sc_received == 256) { 450 device_printf(dev,"input overflow\n"); 451 ending = 1; 452 } 453 } else 454 sc->sc_received++; 455 456 if (sc->sc_received > 3) { 457 if ((sc->sc_in[3] == CMD_IIC) && 458 (sc->sc_received > (sc->sc_i2c_read_len + 4))) { 459 ending = 1; 460 } 461 } 462 463 /* intr off means this is the last byte (end of frame) */ 464 if (cuda_intr_state(sc) == 0) { 465 ending = 1; 466 } else { 467 cuda_toggle_ack(sc); 468 } 469 470 if (ending == 1) { /* end of message? */ 471 sc->sc_in[0] = sc->sc_received - 1; 472 473 /* reset vars and signal the end of this frame */ 474 cuda_idle(sc); 475 476 /* check if we have a handler for this message */ 477 type = sc->sc_in[1]; 478 479 switch (type) { 480 case CUDA_ADB: 481 if (sc->sc_received > 4) { 482 adb_receive_raw_packet(sc->adb_bus, 483 sc->sc_in[2],sc->sc_in[3], 484 sc->sc_received - 4,&sc->sc_in[4]); 485 } else { 486 adb_receive_raw_packet(sc->adb_bus, 487 sc->sc_in[2],sc->sc_in[3],0,NULL); 488 } 489 break; 490 case CUDA_PSEUDO: 491 if (sc->sc_in[3] == CMD_AUTOPOLL) 492 sc->sc_autopoll = 1; 493 break; 494 case CUDA_ERROR: 495 device_printf(dev,"CUDA Error\n"); 496 sc->sc_error = 1; 497 break; 498 default: 499 device_printf(dev,"unknown CUDA command %d\n", 500 type); 501 break; 502 } 503 504 sc->sc_state = CUDA_IDLE; 505 506 sc->sc_received = 0; 507 508 /* 509 * If there is something waiting to be sent out, 510 * set everything up and send the first byte. 511 */ 512 if (sc->sc_waiting == 1) { 513 DELAY(1500); /* required */ 514 sc->sc_sent = 0; 515 sc->sc_state = CUDA_OUT; 516 517 /* 518 * If the interrupt is on, we were too slow 519 * and the chip has already started to send 520 * something to us, so back out of the write 521 * and start a read cycle. 522 */ 523 if (cuda_intr_state(sc)) { 524 cuda_in(sc); 525 cuda_idle(sc); 526 sc->sc_sent = 0; 527 sc->sc_state = CUDA_IDLE; 528 sc->sc_received = 0; 529 DELAY(150); 530 goto switch_start; 531 } 532 /* 533 * If we got here, it's ok to start sending 534 * so load the first byte and tell the chip 535 * we want to send. 536 */ 537 cuda_out(sc); 538 cuda_write_reg(sc, vSR, 539 sc->sc_out[sc->sc_sent]); 540 cuda_ack_off(sc); 541 cuda_tip(sc); 542 } 543 } 544 break; 545 546 case CUDA_OUT: 547 i = cuda_read_reg(sc, vSR); /* reset SR-intr in IFR */ 548 549 sc->sc_sent++; 550 if (cuda_intr_state(sc)) { /* ADB intr low during write */ 551 cuda_in(sc); /* make sure SR is set to IN */ 552 cuda_idle(sc); 553 sc->sc_sent = 0; /* must start all over */ 554 sc->sc_state = CUDA_IDLE; /* new state */ 555 sc->sc_received = 0; 556 sc->sc_waiting = 1; /* must retry when done with 557 * read */ 558 DELAY(150); 559 goto switch_start; /* process next state right 560 * now */ 561 break; 562 } 563 if (sc->sc_out_length == sc->sc_sent) { /* check for done */ 564 565 sc->sc_waiting = 0; /* done writing */ 566 sc->sc_state = CUDA_IDLE; /* signal bus is idle */ 567 cuda_in(sc); 568 cuda_idle(sc); 569 } else { 570 /* send next byte */ 571 cuda_write_reg(sc, vSR, sc->sc_out[sc->sc_sent]); 572 cuda_toggle_ack(sc); /* signal byte ready to 573 * shift */ 574 } 575 break; 576 577 case CUDA_NOTREADY: 578 break; 579 580 default: 581 break; 582 } 583 584 mtx_unlock(&sc->sc_mutex); 585} 586 587static u_int 588cuda_adb_send(device_t dev, u_char command_byte, int len, u_char *data, u_char poll) 589{ 590 struct cuda_softc *sc = device_get_softc(dev); 591 int i; 592 uint8_t packet[16]; 593 594 /* construct an ADB command packet and send it */ 595 packet[0] = CUDA_ADB; 596 packet[1] = command_byte; 597 for (i = 0; i < len; i++) 598 packet[i + 2] = data[i]; 599 600 if (poll) 601 cuda_poll(dev); 602 603 cuda_send(sc, poll, len + 2, packet); 604 605 if (poll) 606 cuda_poll(dev); 607 608 return 0; 609} 610 611static u_int 612cuda_adb_autopoll(device_t dev, uint16_t mask) { 613 struct cuda_softc *sc = device_get_softc(dev); 614 615 uint8_t cmd[] = {CUDA_PSEUDO, CMD_AUTOPOLL, mask != 0}; 616 617 mtx_lock(&sc->sc_mutex); 618 if (cmd[2] == sc->sc_autopoll) { 619 mtx_unlock(&sc->sc_mutex); 620 return 0; 621 } 622 623 while (sc->sc_state != CUDA_IDLE) 624 mtx_sleep(dev,&sc->sc_mutex,0,"cuda",1); 625 626 sc->sc_autopoll = -1; 627 mtx_unlock(&sc->sc_mutex); 628 629 cuda_send(sc, 0, 3, cmd); 630 631 mtx_lock(&sc->sc_mutex); 632 while(sc->sc_autopoll == -1) { 633 mtx_sleep(dev,&sc->sc_mutex,0,"cuda",100); 634 cuda_poll(dev); 635 } 636 637 mtx_unlock(&sc->sc_mutex); 638 639 return 0; 640} 641 642