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