1184299Snwhitehorn/*- 2184299Snwhitehorn * Copyright (c) 2006 Michael Lorenz 3184299Snwhitehorn * Copyright 2008 by Nathan Whitehorn 4184299Snwhitehorn * All rights reserved. 5184299Snwhitehorn * 6184299Snwhitehorn * Redistribution and use in source and binary forms, with or without 7184299Snwhitehorn * modification, are permitted provided that the following conditions 8184299Snwhitehorn * are met: 9184299Snwhitehorn * 1. Redistributions of source code must retain the above copyright 10184299Snwhitehorn * notice, this list of conditions and the following disclaimer. 11184299Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright 12184299Snwhitehorn * notice, this list of conditions and the following disclaimer in the 13184299Snwhitehorn * documentation and/or other materials provided with the distribution. 14184299Snwhitehorn * 3. The name of the author may not be used to endorse or promote products 15184299Snwhitehorn * derived from this software without specific prior written permission. 16184299Snwhitehorn * 17184299Snwhitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18184299Snwhitehorn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19184299Snwhitehorn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20184299Snwhitehorn * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21184299Snwhitehorn * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 22184299Snwhitehorn * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23184299Snwhitehorn * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 24184299Snwhitehorn * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25184299Snwhitehorn * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26184299Snwhitehorn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27184299Snwhitehorn * SUCH DAMAGE. 28184299Snwhitehorn * 29184299Snwhitehorn */ 30184299Snwhitehorn 31184299Snwhitehorn#include <sys/cdefs.h> 32184299Snwhitehorn__FBSDID("$FreeBSD$"); 33184299Snwhitehorn 34184299Snwhitehorn#include <sys/param.h> 35184299Snwhitehorn#include <sys/systm.h> 36184299Snwhitehorn#include <sys/module.h> 37184299Snwhitehorn#include <sys/bus.h> 38184299Snwhitehorn#include <sys/conf.h> 39184299Snwhitehorn#include <sys/kernel.h> 40205506Snwhitehorn#include <sys/clock.h> 41212054Snwhitehorn#include <sys/reboot.h> 42184299Snwhitehorn 43184299Snwhitehorn#include <dev/ofw/ofw_bus.h> 44184299Snwhitehorn#include <dev/ofw/openfirm.h> 45184299Snwhitehorn 46184299Snwhitehorn#include <machine/bus.h> 47184299Snwhitehorn#include <machine/intr_machdep.h> 48184299Snwhitehorn#include <machine/md_var.h> 49184299Snwhitehorn#include <machine/pio.h> 50184299Snwhitehorn#include <machine/resource.h> 51184299Snwhitehorn 52184299Snwhitehorn#include <vm/vm.h> 53184299Snwhitehorn#include <vm/pmap.h> 54184299Snwhitehorn 55184299Snwhitehorn#include <sys/rman.h> 56184299Snwhitehorn 57184299Snwhitehorn#include <dev/adb/adb.h> 58184299Snwhitehorn 59205506Snwhitehorn#include "clock_if.h" 60184299Snwhitehorn#include "cudavar.h" 61184299Snwhitehorn#include "viareg.h" 62184299Snwhitehorn 63184299Snwhitehorn/* 64184299Snwhitehorn * MacIO interface 65184299Snwhitehorn */ 66184299Snwhitehornstatic int cuda_probe(device_t); 67184299Snwhitehornstatic int cuda_attach(device_t); 68184299Snwhitehornstatic int cuda_detach(device_t); 69184299Snwhitehorn 70185724Snwhitehornstatic u_int cuda_adb_send(device_t dev, u_char command_byte, int len, 71184299Snwhitehorn u_char *data, u_char poll); 72185724Snwhitehornstatic u_int cuda_adb_autopoll(device_t dev, uint16_t mask); 73194027Savgstatic u_int cuda_poll(device_t dev); 74185724Snwhitehornstatic void cuda_send_inbound(struct cuda_softc *sc); 75185724Snwhitehornstatic void cuda_send_outbound(struct cuda_softc *sc); 76212054Snwhitehornstatic void cuda_shutdown(void *xsc, int howto); 77184299Snwhitehorn 78205506Snwhitehorn/* 79205506Snwhitehorn * Clock interface 80205506Snwhitehorn */ 81205506Snwhitehornstatic int cuda_gettime(device_t dev, struct timespec *ts); 82205506Snwhitehornstatic int cuda_settime(device_t dev, struct timespec *ts); 83205506Snwhitehorn 84184299Snwhitehornstatic device_method_t cuda_methods[] = { 85184299Snwhitehorn /* Device interface */ 86184299Snwhitehorn DEVMETHOD(device_probe, cuda_probe), 87184299Snwhitehorn DEVMETHOD(device_attach, cuda_attach), 88184299Snwhitehorn DEVMETHOD(device_detach, cuda_detach), 89184299Snwhitehorn DEVMETHOD(device_shutdown, bus_generic_shutdown), 90184299Snwhitehorn DEVMETHOD(device_suspend, bus_generic_suspend), 91184299Snwhitehorn DEVMETHOD(device_resume, bus_generic_resume), 92184299Snwhitehorn 93184299Snwhitehorn /* ADB bus interface */ 94184299Snwhitehorn DEVMETHOD(adb_hb_send_raw_packet, cuda_adb_send), 95184299Snwhitehorn DEVMETHOD(adb_hb_controller_poll, cuda_poll), 96184299Snwhitehorn DEVMETHOD(adb_hb_set_autopoll_mask, cuda_adb_autopoll), 97184299Snwhitehorn 98205506Snwhitehorn /* Clock interface */ 99205506Snwhitehorn DEVMETHOD(clock_gettime, cuda_gettime), 100205506Snwhitehorn DEVMETHOD(clock_settime, cuda_settime), 101205506Snwhitehorn 102227843Smarius DEVMETHOD_END 103184299Snwhitehorn}; 104184299Snwhitehorn 105184299Snwhitehornstatic driver_t cuda_driver = { 106184299Snwhitehorn "cuda", 107184299Snwhitehorn cuda_methods, 108184299Snwhitehorn sizeof(struct cuda_softc), 109184299Snwhitehorn}; 110184299Snwhitehorn 111184299Snwhitehornstatic devclass_t cuda_devclass; 112184299Snwhitehorn 113184299SnwhitehornDRIVER_MODULE(cuda, macio, cuda_driver, cuda_devclass, 0, 0); 114184299SnwhitehornDRIVER_MODULE(adb, cuda, adb_driver, adb_devclass, 0, 0); 115184299Snwhitehorn 116184299Snwhitehornstatic void cuda_intr(void *arg); 117184299Snwhitehornstatic uint8_t cuda_read_reg(struct cuda_softc *sc, u_int offset); 118184299Snwhitehornstatic void cuda_write_reg(struct cuda_softc *sc, u_int offset, uint8_t value); 119184299Snwhitehornstatic void cuda_idle(struct cuda_softc *); 120184299Snwhitehornstatic void cuda_tip(struct cuda_softc *); 121184299Snwhitehornstatic void cuda_clear_tip(struct cuda_softc *); 122184299Snwhitehornstatic void cuda_in(struct cuda_softc *); 123184299Snwhitehornstatic void cuda_out(struct cuda_softc *); 124184299Snwhitehornstatic void cuda_toggle_ack(struct cuda_softc *); 125184299Snwhitehornstatic void cuda_ack_off(struct cuda_softc *); 126184299Snwhitehornstatic int cuda_intr_state(struct cuda_softc *); 127184299Snwhitehorn 128184299Snwhitehornstatic int 129184299Snwhitehorncuda_probe(device_t dev) 130184299Snwhitehorn{ 131184299Snwhitehorn const char *type = ofw_bus_get_type(dev); 132184299Snwhitehorn 133184299Snwhitehorn if (strcmp(type, "via-cuda") != 0) 134184299Snwhitehorn return (ENXIO); 135184299Snwhitehorn 136184299Snwhitehorn device_set_desc(dev, CUDA_DEVSTR); 137184299Snwhitehorn return (0); 138184299Snwhitehorn} 139184299Snwhitehorn 140184299Snwhitehornstatic int 141184299Snwhitehorncuda_attach(device_t dev) 142184299Snwhitehorn{ 143184299Snwhitehorn struct cuda_softc *sc; 144184299Snwhitehorn 145184299Snwhitehorn volatile int i; 146184299Snwhitehorn uint8_t reg; 147184299Snwhitehorn phandle_t node,child; 148184299Snwhitehorn 149184299Snwhitehorn sc = device_get_softc(dev); 150184299Snwhitehorn sc->sc_dev = dev; 151184299Snwhitehorn 152184299Snwhitehorn sc->sc_memrid = 0; 153184299Snwhitehorn sc->sc_memr = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 154184299Snwhitehorn &sc->sc_memrid, RF_ACTIVE); 155184299Snwhitehorn 156184299Snwhitehorn if (sc->sc_memr == NULL) { 157184299Snwhitehorn device_printf(dev, "Could not alloc mem resource!\n"); 158184299Snwhitehorn return (ENXIO); 159184299Snwhitehorn } 160184299Snwhitehorn 161184299Snwhitehorn sc->sc_irqrid = 0; 162184299Snwhitehorn sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irqrid, 163184299Snwhitehorn RF_ACTIVE); 164184299Snwhitehorn if (sc->sc_irq == NULL) { 165184299Snwhitehorn device_printf(dev, "could not allocate interrupt\n"); 166184299Snwhitehorn return (ENXIO); 167184299Snwhitehorn } 168184299Snwhitehorn 169184299Snwhitehorn if (bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_MISC | INTR_MPSAFE 170184299Snwhitehorn | INTR_ENTROPY, NULL, cuda_intr, dev, &sc->sc_ih) != 0) { 171184299Snwhitehorn device_printf(dev, "could not setup interrupt\n"); 172184299Snwhitehorn bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqrid, 173184299Snwhitehorn sc->sc_irq); 174184299Snwhitehorn return (ENXIO); 175184299Snwhitehorn } 176184299Snwhitehorn 177184299Snwhitehorn mtx_init(&sc->sc_mutex,"cuda",NULL,MTX_DEF | MTX_RECURSE); 178184299Snwhitehorn 179184299Snwhitehorn sc->sc_sent = 0; 180184299Snwhitehorn sc->sc_received = 0; 181184299Snwhitehorn sc->sc_waiting = 0; 182184299Snwhitehorn sc->sc_polling = 0; 183184299Snwhitehorn sc->sc_state = CUDA_NOTREADY; 184184299Snwhitehorn sc->sc_autopoll = 0; 185205506Snwhitehorn sc->sc_rtc = -1; 186184299Snwhitehorn 187185724Snwhitehorn STAILQ_INIT(&sc->sc_inq); 188185724Snwhitehorn STAILQ_INIT(&sc->sc_outq); 189186046Snwhitehorn STAILQ_INIT(&sc->sc_freeq); 190185724Snwhitehorn 191186046Snwhitehorn for (i = 0; i < CUDA_MAXPACKETS; i++) 192186046Snwhitehorn STAILQ_INSERT_TAIL(&sc->sc_freeq, &sc->sc_pkts[i], pkt_q); 193186046Snwhitehorn 194184299Snwhitehorn /* Init CUDA */ 195184299Snwhitehorn 196184299Snwhitehorn reg = cuda_read_reg(sc, vDirB); 197184299Snwhitehorn reg |= 0x30; /* register B bits 4 and 5: outputs */ 198184299Snwhitehorn cuda_write_reg(sc, vDirB, reg); 199184299Snwhitehorn 200184299Snwhitehorn reg = cuda_read_reg(sc, vDirB); 201184299Snwhitehorn reg &= 0xf7; /* register B bit 3: input */ 202184299Snwhitehorn cuda_write_reg(sc, vDirB, reg); 203184299Snwhitehorn 204184299Snwhitehorn reg = cuda_read_reg(sc, vACR); 205184299Snwhitehorn reg &= ~vSR_OUT; /* make sure SR is set to IN */ 206184299Snwhitehorn cuda_write_reg(sc, vACR, reg); 207184299Snwhitehorn 208184299Snwhitehorn cuda_write_reg(sc, vACR, (cuda_read_reg(sc, vACR) | 0x0c) & ~0x10); 209184299Snwhitehorn 210184299Snwhitehorn sc->sc_state = CUDA_IDLE; /* used by all types of hardware */ 211184299Snwhitehorn 212184299Snwhitehorn cuda_write_reg(sc, vIER, 0x84); /* make sure VIA interrupts are on */ 213184299Snwhitehorn 214184299Snwhitehorn cuda_idle(sc); /* reset ADB */ 215184299Snwhitehorn 216184299Snwhitehorn /* Reset CUDA */ 217184299Snwhitehorn 218184299Snwhitehorn i = cuda_read_reg(sc, vSR); /* clear interrupt */ 219184299Snwhitehorn cuda_write_reg(sc, vIER, 0x04); /* no interrupts while clearing */ 220184299Snwhitehorn cuda_idle(sc); /* reset state to idle */ 221184299Snwhitehorn DELAY(150); 222184299Snwhitehorn cuda_tip(sc); /* signal start of frame */ 223184299Snwhitehorn DELAY(150); 224184299Snwhitehorn cuda_toggle_ack(sc); 225184299Snwhitehorn DELAY(150); 226184299Snwhitehorn cuda_clear_tip(sc); 227184299Snwhitehorn DELAY(150); 228184299Snwhitehorn cuda_idle(sc); /* back to idle state */ 229184299Snwhitehorn i = cuda_read_reg(sc, vSR); /* clear interrupt */ 230184299Snwhitehorn cuda_write_reg(sc, vIER, 0x84); /* ints ok now */ 231184299Snwhitehorn 232184299Snwhitehorn /* Initialize child buses (ADB) */ 233184299Snwhitehorn node = ofw_bus_get_node(dev); 234184299Snwhitehorn 235184299Snwhitehorn for (child = OF_child(node); child != 0; child = OF_peer(child)) { 236184299Snwhitehorn char name[32]; 237184299Snwhitehorn 238184299Snwhitehorn memset(name, 0, sizeof(name)); 239184299Snwhitehorn OF_getprop(child, "name", name, sizeof(name)); 240184299Snwhitehorn 241184299Snwhitehorn if (bootverbose) 242184299Snwhitehorn device_printf(dev, "CUDA child <%s>\n",name); 243184299Snwhitehorn 244184299Snwhitehorn if (strncmp(name, "adb", 4) == 0) { 245184299Snwhitehorn sc->adb_bus = device_add_child(dev,"adb",-1); 246184299Snwhitehorn } 247184299Snwhitehorn } 248184299Snwhitehorn 249205506Snwhitehorn clock_register(dev, 1000); 250212054Snwhitehorn EVENTHANDLER_REGISTER(shutdown_final, cuda_shutdown, sc, 251212054Snwhitehorn SHUTDOWN_PRI_LAST); 252205506Snwhitehorn 253184299Snwhitehorn return (bus_generic_attach(dev)); 254184299Snwhitehorn} 255184299Snwhitehorn 256184299Snwhitehornstatic int cuda_detach(device_t dev) { 257184299Snwhitehorn struct cuda_softc *sc; 258184299Snwhitehorn 259184299Snwhitehorn sc = device_get_softc(dev); 260184299Snwhitehorn 261184299Snwhitehorn bus_teardown_intr(dev, sc->sc_irq, sc->sc_ih); 262184299Snwhitehorn bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqrid, sc->sc_irq); 263184299Snwhitehorn bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_memrid, sc->sc_memr); 264184299Snwhitehorn mtx_destroy(&sc->sc_mutex); 265184299Snwhitehorn 266184299Snwhitehorn return (bus_generic_detach(dev)); 267184299Snwhitehorn} 268184299Snwhitehorn 269184299Snwhitehornstatic uint8_t 270184299Snwhitehorncuda_read_reg(struct cuda_softc *sc, u_int offset) { 271184299Snwhitehorn return (bus_read_1(sc->sc_memr, offset)); 272184299Snwhitehorn} 273184299Snwhitehorn 274184299Snwhitehornstatic void 275184299Snwhitehorncuda_write_reg(struct cuda_softc *sc, u_int offset, uint8_t value) { 276184299Snwhitehorn bus_write_1(sc->sc_memr, offset, value); 277184299Snwhitehorn} 278184299Snwhitehorn 279184299Snwhitehornstatic void 280184299Snwhitehorncuda_idle(struct cuda_softc *sc) 281184299Snwhitehorn{ 282184299Snwhitehorn uint8_t reg; 283184299Snwhitehorn 284184299Snwhitehorn reg = cuda_read_reg(sc, vBufB); 285184299Snwhitehorn reg |= (vPB4 | vPB5); 286184299Snwhitehorn cuda_write_reg(sc, vBufB, reg); 287184299Snwhitehorn} 288184299Snwhitehorn 289184299Snwhitehornstatic void 290184299Snwhitehorncuda_tip(struct cuda_softc *sc) 291184299Snwhitehorn{ 292184299Snwhitehorn uint8_t reg; 293184299Snwhitehorn 294184299Snwhitehorn reg = cuda_read_reg(sc, vBufB); 295184299Snwhitehorn reg &= ~vPB5; 296184299Snwhitehorn cuda_write_reg(sc, vBufB, reg); 297184299Snwhitehorn} 298184299Snwhitehorn 299184299Snwhitehornstatic void 300184299Snwhitehorncuda_clear_tip(struct cuda_softc *sc) 301184299Snwhitehorn{ 302184299Snwhitehorn uint8_t reg; 303184299Snwhitehorn 304184299Snwhitehorn reg = cuda_read_reg(sc, vBufB); 305184299Snwhitehorn reg |= vPB5; 306184299Snwhitehorn cuda_write_reg(sc, vBufB, reg); 307184299Snwhitehorn} 308184299Snwhitehorn 309184299Snwhitehornstatic void 310184299Snwhitehorncuda_in(struct cuda_softc *sc) 311184299Snwhitehorn{ 312184299Snwhitehorn uint8_t reg; 313184299Snwhitehorn 314184299Snwhitehorn reg = cuda_read_reg(sc, vACR); 315184299Snwhitehorn reg &= ~vSR_OUT; 316184299Snwhitehorn cuda_write_reg(sc, vACR, reg); 317184299Snwhitehorn} 318184299Snwhitehorn 319184299Snwhitehornstatic void 320184299Snwhitehorncuda_out(struct cuda_softc *sc) 321184299Snwhitehorn{ 322184299Snwhitehorn uint8_t reg; 323184299Snwhitehorn 324184299Snwhitehorn reg = cuda_read_reg(sc, vACR); 325184299Snwhitehorn reg |= vSR_OUT; 326184299Snwhitehorn cuda_write_reg(sc, vACR, reg); 327184299Snwhitehorn} 328184299Snwhitehorn 329184299Snwhitehornstatic void 330184299Snwhitehorncuda_toggle_ack(struct cuda_softc *sc) 331184299Snwhitehorn{ 332184299Snwhitehorn uint8_t reg; 333184299Snwhitehorn 334184299Snwhitehorn reg = cuda_read_reg(sc, vBufB); 335184299Snwhitehorn reg ^= vPB4; 336184299Snwhitehorn cuda_write_reg(sc, vBufB, reg); 337184299Snwhitehorn} 338184299Snwhitehorn 339184299Snwhitehornstatic void 340184299Snwhitehorncuda_ack_off(struct cuda_softc *sc) 341184299Snwhitehorn{ 342184299Snwhitehorn uint8_t reg; 343184299Snwhitehorn 344184299Snwhitehorn reg = cuda_read_reg(sc, vBufB); 345184299Snwhitehorn reg |= vPB4; 346184299Snwhitehorn cuda_write_reg(sc, vBufB, reg); 347184299Snwhitehorn} 348184299Snwhitehorn 349184299Snwhitehornstatic int 350184299Snwhitehorncuda_intr_state(struct cuda_softc *sc) 351184299Snwhitehorn{ 352184299Snwhitehorn return ((cuda_read_reg(sc, vBufB) & vPB3) == 0); 353184299Snwhitehorn} 354184299Snwhitehorn 355184299Snwhitehornstatic int 356184299Snwhitehorncuda_send(void *cookie, int poll, int length, uint8_t *msg) 357184299Snwhitehorn{ 358184299Snwhitehorn struct cuda_softc *sc = cookie; 359184299Snwhitehorn device_t dev = sc->sc_dev; 360185724Snwhitehorn struct cuda_packet *pkt; 361184299Snwhitehorn 362184299Snwhitehorn if (sc->sc_state == CUDA_NOTREADY) 363185724Snwhitehorn return (-1); 364184299Snwhitehorn 365184299Snwhitehorn mtx_lock(&sc->sc_mutex); 366184299Snwhitehorn 367186046Snwhitehorn pkt = STAILQ_FIRST(&sc->sc_freeq); 368186046Snwhitehorn if (pkt == NULL) { 369186046Snwhitehorn mtx_unlock(&sc->sc_mutex); 370186046Snwhitehorn return (-1); 371186046Snwhitehorn } 372186046Snwhitehorn 373185724Snwhitehorn pkt->len = length - 1; 374185724Snwhitehorn pkt->type = msg[0]; 375185724Snwhitehorn memcpy(pkt->data, &msg[1], pkt->len); 376185724Snwhitehorn 377186046Snwhitehorn STAILQ_REMOVE_HEAD(&sc->sc_freeq, pkt_q); 378185724Snwhitehorn STAILQ_INSERT_TAIL(&sc->sc_outq, pkt, pkt_q); 379185724Snwhitehorn 380185724Snwhitehorn /* 381185724Snwhitehorn * If we already are sending a packet, we should bail now that this 382185724Snwhitehorn * one has been added to the queue. 383185724Snwhitehorn */ 384185724Snwhitehorn 385185724Snwhitehorn if (sc->sc_waiting) { 386185724Snwhitehorn mtx_unlock(&sc->sc_mutex); 387185724Snwhitehorn return (0); 388184299Snwhitehorn } 389184299Snwhitehorn 390185724Snwhitehorn cuda_send_outbound(sc); 391185724Snwhitehorn mtx_unlock(&sc->sc_mutex); 392185724Snwhitehorn 393185724Snwhitehorn if (sc->sc_polling || poll || cold) 394185724Snwhitehorn cuda_poll(dev); 395185724Snwhitehorn 396185724Snwhitehorn return (0); 397185724Snwhitehorn} 398185724Snwhitehorn 399185724Snwhitehornstatic void 400185724Snwhitehorncuda_send_outbound(struct cuda_softc *sc) 401185724Snwhitehorn{ 402185724Snwhitehorn struct cuda_packet *pkt; 403185724Snwhitehorn 404185724Snwhitehorn mtx_assert(&sc->sc_mutex, MA_OWNED); 405185724Snwhitehorn 406185724Snwhitehorn pkt = STAILQ_FIRST(&sc->sc_outq); 407185724Snwhitehorn if (pkt == NULL) 408185724Snwhitehorn return; 409185724Snwhitehorn 410185724Snwhitehorn sc->sc_out_length = pkt->len + 1; 411185724Snwhitehorn memcpy(sc->sc_out, &pkt->type, pkt->len + 1); 412184299Snwhitehorn sc->sc_sent = 0; 413184299Snwhitehorn 414185724Snwhitehorn STAILQ_REMOVE_HEAD(&sc->sc_outq, pkt_q); 415186046Snwhitehorn STAILQ_INSERT_TAIL(&sc->sc_freeq, pkt, pkt_q); 416185724Snwhitehorn 417185724Snwhitehorn sc->sc_waiting = 1; 418185724Snwhitehorn 419185724Snwhitehorn cuda_poll(sc->sc_dev); 420185724Snwhitehorn 421185724Snwhitehorn DELAY(150); 422185724Snwhitehorn 423185724Snwhitehorn if (sc->sc_state == CUDA_IDLE && !cuda_intr_state(sc)) { 424184299Snwhitehorn sc->sc_state = CUDA_OUT; 425184299Snwhitehorn cuda_out(sc); 426184299Snwhitehorn cuda_write_reg(sc, vSR, sc->sc_out[0]); 427184299Snwhitehorn cuda_ack_off(sc); 428184299Snwhitehorn cuda_tip(sc); 429184299Snwhitehorn } 430185724Snwhitehorn} 431184299Snwhitehorn 432185724Snwhitehornstatic void 433185724Snwhitehorncuda_send_inbound(struct cuda_softc *sc) 434185724Snwhitehorn{ 435185724Snwhitehorn device_t dev; 436185724Snwhitehorn struct cuda_packet *pkt; 437185724Snwhitehorn 438185724Snwhitehorn dev = sc->sc_dev; 439185724Snwhitehorn 440185724Snwhitehorn mtx_lock(&sc->sc_mutex); 441185724Snwhitehorn 442185724Snwhitehorn while ((pkt = STAILQ_FIRST(&sc->sc_inq)) != NULL) { 443185724Snwhitehorn STAILQ_REMOVE_HEAD(&sc->sc_inq, pkt_q); 444185724Snwhitehorn 445185724Snwhitehorn mtx_unlock(&sc->sc_mutex); 446185724Snwhitehorn 447185724Snwhitehorn /* check if we have a handler for this message */ 448185724Snwhitehorn switch (pkt->type) { 449185724Snwhitehorn case CUDA_ADB: 450185724Snwhitehorn if (pkt->len > 2) { 451185724Snwhitehorn adb_receive_raw_packet(sc->adb_bus, 452185724Snwhitehorn pkt->data[0],pkt->data[1], 453185724Snwhitehorn pkt->len - 2,&pkt->data[2]); 454185724Snwhitehorn } else { 455185724Snwhitehorn adb_receive_raw_packet(sc->adb_bus, 456185724Snwhitehorn pkt->data[0],pkt->data[1],0,NULL); 457185724Snwhitehorn } 458185724Snwhitehorn break; 459185724Snwhitehorn case CUDA_PSEUDO: 460185724Snwhitehorn mtx_lock(&sc->sc_mutex); 461205506Snwhitehorn switch (pkt->data[1]) { 462205506Snwhitehorn case CMD_AUTOPOLL: 463185724Snwhitehorn sc->sc_autopoll = 1; 464205506Snwhitehorn break; 465205506Snwhitehorn case CMD_READ_RTC: 466205506Snwhitehorn memcpy(&sc->sc_rtc, &pkt->data[2], 467205506Snwhitehorn sizeof(sc->sc_rtc)); 468205506Snwhitehorn wakeup(&sc->sc_rtc); 469205506Snwhitehorn break; 470205506Snwhitehorn case CMD_WRITE_RTC: 471205506Snwhitehorn break; 472205506Snwhitehorn } 473185724Snwhitehorn mtx_unlock(&sc->sc_mutex); 474185724Snwhitehorn break; 475185724Snwhitehorn case CUDA_ERROR: 476185724Snwhitehorn /* 477185724Snwhitehorn * CUDA will throw errors if we miss a race between 478185724Snwhitehorn * sending and receiving packets. This is already 479185724Snwhitehorn * handled when we abort packet output to handle 480185724Snwhitehorn * this packet in cuda_intr(). Thus, we ignore 481185724Snwhitehorn * these messages. 482185724Snwhitehorn */ 483185724Snwhitehorn break; 484185724Snwhitehorn default: 485185724Snwhitehorn device_printf(dev,"unknown CUDA command %d\n", 486185724Snwhitehorn pkt->type); 487185724Snwhitehorn break; 488185724Snwhitehorn } 489185724Snwhitehorn 490186046Snwhitehorn mtx_lock(&sc->sc_mutex); 491185724Snwhitehorn 492186046Snwhitehorn STAILQ_INSERT_TAIL(&sc->sc_freeq, pkt, pkt_q); 493184299Snwhitehorn } 494184299Snwhitehorn 495185724Snwhitehorn mtx_unlock(&sc->sc_mutex); 496184299Snwhitehorn} 497184299Snwhitehorn 498194027Savgstatic u_int 499184299Snwhitehorncuda_poll(device_t dev) 500184299Snwhitehorn{ 501184299Snwhitehorn struct cuda_softc *sc = device_get_softc(dev); 502184299Snwhitehorn 503184473Snwhitehorn if (sc->sc_state == CUDA_IDLE && !cuda_intr_state(sc) && 504184473Snwhitehorn !sc->sc_waiting) 505194027Savg return (0); 506184473Snwhitehorn 507185724Snwhitehorn cuda_intr(dev); 508194027Savg return (0); 509184299Snwhitehorn} 510184299Snwhitehorn 511184299Snwhitehornstatic void 512184299Snwhitehorncuda_intr(void *arg) 513184299Snwhitehorn{ 514184299Snwhitehorn device_t dev; 515184299Snwhitehorn struct cuda_softc *sc; 516184299Snwhitehorn 517185724Snwhitehorn int i, ending, restart_send, process_inbound; 518184299Snwhitehorn uint8_t reg; 519184299Snwhitehorn 520184299Snwhitehorn dev = (device_t)arg; 521184299Snwhitehorn sc = device_get_softc(dev); 522184299Snwhitehorn 523184299Snwhitehorn mtx_lock(&sc->sc_mutex); 524184299Snwhitehorn 525184299Snwhitehorn restart_send = 0; 526185724Snwhitehorn process_inbound = 0; 527184299Snwhitehorn reg = cuda_read_reg(sc, vIFR); 528185724Snwhitehorn if ((reg & vSR_INT) != vSR_INT) { 529185724Snwhitehorn mtx_unlock(&sc->sc_mutex); 530185724Snwhitehorn return; 531185724Snwhitehorn } 532185724Snwhitehorn 533184299Snwhitehorn cuda_write_reg(sc, vIFR, 0x7f); /* Clear interrupt */ 534184299Snwhitehorn 535184299Snwhitehornswitch_start: 536184299Snwhitehorn switch (sc->sc_state) { 537184299Snwhitehorn case CUDA_IDLE: 538184299Snwhitehorn /* 539184299Snwhitehorn * This is an unexpected packet, so grab the first (dummy) 540184299Snwhitehorn * byte, set up the proper vars, and tell the chip we are 541184299Snwhitehorn * starting to receive the packet by setting the TIP bit. 542184299Snwhitehorn */ 543184299Snwhitehorn sc->sc_in[1] = cuda_read_reg(sc, vSR); 544184299Snwhitehorn 545184299Snwhitehorn if (cuda_intr_state(sc) == 0) { 546184299Snwhitehorn /* must have been a fake start */ 547184299Snwhitehorn 548184299Snwhitehorn if (sc->sc_waiting) { 549184299Snwhitehorn /* start over */ 550184299Snwhitehorn DELAY(150); 551184299Snwhitehorn sc->sc_state = CUDA_OUT; 552184299Snwhitehorn sc->sc_sent = 0; 553184299Snwhitehorn cuda_out(sc); 554184299Snwhitehorn cuda_write_reg(sc, vSR, sc->sc_out[1]); 555184299Snwhitehorn cuda_ack_off(sc); 556184299Snwhitehorn cuda_tip(sc); 557184299Snwhitehorn } 558184299Snwhitehorn break; 559184299Snwhitehorn } 560184299Snwhitehorn 561184299Snwhitehorn cuda_in(sc); 562184299Snwhitehorn cuda_tip(sc); 563184299Snwhitehorn 564184299Snwhitehorn sc->sc_received = 1; 565184299Snwhitehorn sc->sc_state = CUDA_IN; 566184299Snwhitehorn break; 567184299Snwhitehorn 568184299Snwhitehorn case CUDA_IN: 569184299Snwhitehorn sc->sc_in[sc->sc_received] = cuda_read_reg(sc, vSR); 570184299Snwhitehorn ending = 0; 571184299Snwhitehorn 572184299Snwhitehorn if (sc->sc_received > 255) { 573184299Snwhitehorn /* bitch only once */ 574184299Snwhitehorn if (sc->sc_received == 256) { 575184299Snwhitehorn device_printf(dev,"input overflow\n"); 576184299Snwhitehorn ending = 1; 577184299Snwhitehorn } 578184299Snwhitehorn } else 579184299Snwhitehorn sc->sc_received++; 580184299Snwhitehorn 581184299Snwhitehorn /* intr off means this is the last byte (end of frame) */ 582184299Snwhitehorn if (cuda_intr_state(sc) == 0) { 583184299Snwhitehorn ending = 1; 584184299Snwhitehorn } else { 585184299Snwhitehorn cuda_toggle_ack(sc); 586184299Snwhitehorn } 587184299Snwhitehorn 588184299Snwhitehorn if (ending == 1) { /* end of message? */ 589185724Snwhitehorn struct cuda_packet *pkt; 590184299Snwhitehorn 591184299Snwhitehorn /* reset vars and signal the end of this frame */ 592184299Snwhitehorn cuda_idle(sc); 593184299Snwhitehorn 594185724Snwhitehorn /* Queue up the packet */ 595186046Snwhitehorn pkt = STAILQ_FIRST(&sc->sc_freeq); 596186046Snwhitehorn if (pkt != NULL) { 597186046Snwhitehorn /* If we have a free packet, process it */ 598184299Snwhitehorn 599186046Snwhitehorn pkt->len = sc->sc_received - 2; 600186046Snwhitehorn pkt->type = sc->sc_in[1]; 601186046Snwhitehorn memcpy(pkt->data, &sc->sc_in[2], pkt->len); 602184299Snwhitehorn 603186046Snwhitehorn STAILQ_REMOVE_HEAD(&sc->sc_freeq, pkt_q); 604186046Snwhitehorn STAILQ_INSERT_TAIL(&sc->sc_inq, pkt, pkt_q); 605185724Snwhitehorn 606186046Snwhitehorn process_inbound = 1; 607186046Snwhitehorn } 608186046Snwhitehorn 609184299Snwhitehorn sc->sc_state = CUDA_IDLE; 610184299Snwhitehorn sc->sc_received = 0; 611184299Snwhitehorn 612184299Snwhitehorn /* 613184299Snwhitehorn * If there is something waiting to be sent out, 614184299Snwhitehorn * set everything up and send the first byte. 615184299Snwhitehorn */ 616184299Snwhitehorn if (sc->sc_waiting == 1) { 617184299Snwhitehorn DELAY(1500); /* required */ 618184299Snwhitehorn sc->sc_sent = 0; 619184299Snwhitehorn sc->sc_state = CUDA_OUT; 620184299Snwhitehorn 621184299Snwhitehorn /* 622184299Snwhitehorn * If the interrupt is on, we were too slow 623184299Snwhitehorn * and the chip has already started to send 624184299Snwhitehorn * something to us, so back out of the write 625184299Snwhitehorn * and start a read cycle. 626184299Snwhitehorn */ 627184299Snwhitehorn if (cuda_intr_state(sc)) { 628184299Snwhitehorn cuda_in(sc); 629184299Snwhitehorn cuda_idle(sc); 630184299Snwhitehorn sc->sc_sent = 0; 631184299Snwhitehorn sc->sc_state = CUDA_IDLE; 632184299Snwhitehorn sc->sc_received = 0; 633184299Snwhitehorn DELAY(150); 634184299Snwhitehorn goto switch_start; 635184299Snwhitehorn } 636185724Snwhitehorn 637184299Snwhitehorn /* 638184299Snwhitehorn * If we got here, it's ok to start sending 639184299Snwhitehorn * so load the first byte and tell the chip 640184299Snwhitehorn * we want to send. 641184299Snwhitehorn */ 642184299Snwhitehorn cuda_out(sc); 643184299Snwhitehorn cuda_write_reg(sc, vSR, 644184299Snwhitehorn sc->sc_out[sc->sc_sent]); 645184299Snwhitehorn cuda_ack_off(sc); 646184299Snwhitehorn cuda_tip(sc); 647184299Snwhitehorn } 648184299Snwhitehorn } 649184299Snwhitehorn break; 650184299Snwhitehorn 651184299Snwhitehorn case CUDA_OUT: 652184299Snwhitehorn i = cuda_read_reg(sc, vSR); /* reset SR-intr in IFR */ 653184299Snwhitehorn 654184299Snwhitehorn sc->sc_sent++; 655184299Snwhitehorn if (cuda_intr_state(sc)) { /* ADB intr low during write */ 656184299Snwhitehorn cuda_in(sc); /* make sure SR is set to IN */ 657184299Snwhitehorn cuda_idle(sc); 658184299Snwhitehorn sc->sc_sent = 0; /* must start all over */ 659184299Snwhitehorn sc->sc_state = CUDA_IDLE; /* new state */ 660184299Snwhitehorn sc->sc_received = 0; 661184299Snwhitehorn sc->sc_waiting = 1; /* must retry when done with 662184299Snwhitehorn * read */ 663184299Snwhitehorn DELAY(150); 664184299Snwhitehorn goto switch_start; /* process next state right 665184299Snwhitehorn * now */ 666184299Snwhitehorn break; 667184299Snwhitehorn } 668184299Snwhitehorn if (sc->sc_out_length == sc->sc_sent) { /* check for done */ 669184299Snwhitehorn sc->sc_waiting = 0; /* done writing */ 670184299Snwhitehorn sc->sc_state = CUDA_IDLE; /* signal bus is idle */ 671184299Snwhitehorn cuda_in(sc); 672184299Snwhitehorn cuda_idle(sc); 673184299Snwhitehorn } else { 674184299Snwhitehorn /* send next byte */ 675184299Snwhitehorn cuda_write_reg(sc, vSR, sc->sc_out[sc->sc_sent]); 676184299Snwhitehorn cuda_toggle_ack(sc); /* signal byte ready to 677184299Snwhitehorn * shift */ 678184299Snwhitehorn } 679184299Snwhitehorn break; 680184299Snwhitehorn 681184299Snwhitehorn case CUDA_NOTREADY: 682184299Snwhitehorn break; 683184299Snwhitehorn 684184299Snwhitehorn default: 685184299Snwhitehorn break; 686184299Snwhitehorn } 687184299Snwhitehorn 688184299Snwhitehorn mtx_unlock(&sc->sc_mutex); 689185724Snwhitehorn 690185724Snwhitehorn if (process_inbound) 691185724Snwhitehorn cuda_send_inbound(sc); 692185724Snwhitehorn 693185724Snwhitehorn mtx_lock(&sc->sc_mutex); 694185724Snwhitehorn /* If we have another packet waiting, set it up */ 695185724Snwhitehorn if (!sc->sc_waiting && sc->sc_state == CUDA_IDLE) 696185724Snwhitehorn cuda_send_outbound(sc); 697185724Snwhitehorn 698185724Snwhitehorn mtx_unlock(&sc->sc_mutex); 699185724Snwhitehorn 700184299Snwhitehorn} 701184299Snwhitehorn 702184299Snwhitehornstatic u_int 703185724Snwhitehorncuda_adb_send(device_t dev, u_char command_byte, int len, u_char *data, 704185724Snwhitehorn u_char poll) 705184299Snwhitehorn{ 706184299Snwhitehorn struct cuda_softc *sc = device_get_softc(dev); 707185724Snwhitehorn uint8_t packet[16]; 708184299Snwhitehorn int i; 709184299Snwhitehorn 710184299Snwhitehorn /* construct an ADB command packet and send it */ 711184299Snwhitehorn packet[0] = CUDA_ADB; 712184299Snwhitehorn packet[1] = command_byte; 713184299Snwhitehorn for (i = 0; i < len; i++) 714184299Snwhitehorn packet[i + 2] = data[i]; 715184299Snwhitehorn 716184299Snwhitehorn cuda_send(sc, poll, len + 2, packet); 717184299Snwhitehorn 718185724Snwhitehorn return (0); 719184299Snwhitehorn} 720184299Snwhitehorn 721184299Snwhitehornstatic u_int 722184299Snwhitehorncuda_adb_autopoll(device_t dev, uint16_t mask) { 723184299Snwhitehorn struct cuda_softc *sc = device_get_softc(dev); 724184299Snwhitehorn 725184299Snwhitehorn uint8_t cmd[] = {CUDA_PSEUDO, CMD_AUTOPOLL, mask != 0}; 726184299Snwhitehorn 727184299Snwhitehorn mtx_lock(&sc->sc_mutex); 728184473Snwhitehorn 729184299Snwhitehorn if (cmd[2] == sc->sc_autopoll) { 730184299Snwhitehorn mtx_unlock(&sc->sc_mutex); 731185724Snwhitehorn return (0); 732184299Snwhitehorn } 733184299Snwhitehorn 734184299Snwhitehorn sc->sc_autopoll = -1; 735185724Snwhitehorn cuda_send(sc, 1, 3, cmd); 736184299Snwhitehorn 737184299Snwhitehorn mtx_unlock(&sc->sc_mutex); 738185724Snwhitehorn 739185724Snwhitehorn return (0); 740184299Snwhitehorn} 741184299Snwhitehorn 742212054Snwhitehornstatic void 743212054Snwhitehorncuda_shutdown(void *xsc, int howto) 744212054Snwhitehorn{ 745212054Snwhitehorn struct cuda_softc *sc = xsc; 746212054Snwhitehorn uint8_t cmd[] = {CUDA_PSEUDO, 0}; 747212054Snwhitehorn 748212054Snwhitehorn cmd[1] = (howto & RB_HALT) ? CMD_POWEROFF : CMD_RESET; 749212054Snwhitehorn cuda_poll(sc->sc_dev); 750212054Snwhitehorn cuda_send(sc, 1, 2, cmd); 751212054Snwhitehorn 752212054Snwhitehorn while (1) 753212054Snwhitehorn cuda_poll(sc->sc_dev); 754212054Snwhitehorn} 755212054Snwhitehorn 756205506Snwhitehorn#define DIFF19041970 2082844800 757205506Snwhitehorn 758205506Snwhitehornstatic int 759205506Snwhitehorncuda_gettime(device_t dev, struct timespec *ts) 760205506Snwhitehorn{ 761205506Snwhitehorn struct cuda_softc *sc = device_get_softc(dev); 762205506Snwhitehorn uint8_t cmd[] = {CUDA_PSEUDO, CMD_READ_RTC}; 763205506Snwhitehorn 764205506Snwhitehorn mtx_lock(&sc->sc_mutex); 765205506Snwhitehorn sc->sc_rtc = -1; 766205506Snwhitehorn cuda_send(sc, 1, 2, cmd); 767205506Snwhitehorn if (sc->sc_rtc == -1) 768205506Snwhitehorn mtx_sleep(&sc->sc_rtc, &sc->sc_mutex, 0, "rtc", 100); 769205506Snwhitehorn 770205506Snwhitehorn ts->tv_sec = sc->sc_rtc - DIFF19041970; 771205506Snwhitehorn ts->tv_nsec = 0; 772205506Snwhitehorn mtx_unlock(&sc->sc_mutex); 773205506Snwhitehorn 774205506Snwhitehorn return (0); 775205506Snwhitehorn} 776205506Snwhitehorn 777205506Snwhitehornstatic int 778205506Snwhitehorncuda_settime(device_t dev, struct timespec *ts) 779205506Snwhitehorn{ 780205506Snwhitehorn struct cuda_softc *sc = device_get_softc(dev); 781205506Snwhitehorn uint8_t cmd[] = {CUDA_PSEUDO, CMD_WRITE_RTC, 0, 0, 0, 0}; 782205506Snwhitehorn uint32_t sec; 783205506Snwhitehorn 784205506Snwhitehorn sec = ts->tv_sec + DIFF19041970; 785205506Snwhitehorn memcpy(&cmd[2], &sec, sizeof(sec)); 786205506Snwhitehorn 787205506Snwhitehorn mtx_lock(&sc->sc_mutex); 788205506Snwhitehorn cuda_send(sc, 0, 6, cmd); 789205506Snwhitehorn mtx_unlock(&sc->sc_mutex); 790205506Snwhitehorn 791205506Snwhitehorn return (0); 792205506Snwhitehorn} 793205506Snwhitehorn 794