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