Annotation of sys/arch/macppc/dev/wdc_obio.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: wdc_obio.c,v 1.26 2006/06/19 22:42:33 miod Exp $ */
! 2: /* $NetBSD: wdc_obio.c,v 1.15 2001/07/25 20:26:33 bouyer Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 1998 The NetBSD Foundation, Inc.
! 6: * All rights reserved.
! 7: *
! 8: * This code is derived from software contributed to The NetBSD Foundation
! 9: * by Charles M. Hannum and by Onno van der Linden.
! 10: *
! 11: * Redistribution and use in source and binary forms, with or without
! 12: * modification, are permitted provided that the following conditions
! 13: * are met:
! 14: * 1. Redistributions of source code must retain the above copyright
! 15: * notice, this list of conditions and the following disclaimer.
! 16: * 2. Redistributions in binary form must reproduce the above copyright
! 17: * notice, this list of conditions and the following disclaimer in the
! 18: * documentation and/or other materials provided with the distribution.
! 19: * 3. All advertising materials mentioning features or use of this software
! 20: * must display the following acknowledgement:
! 21: * This product includes software developed by the NetBSD
! 22: * Foundation, Inc. and its contributors.
! 23: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 24: * contributors may be used to endorse or promote products derived
! 25: * from this software without specific prior written permission.
! 26: *
! 27: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 28: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 29: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 30: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 31: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 32: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 33: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 34: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 35: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 36: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 37: * POSSIBILITY OF SUCH DAMAGE.
! 38: */
! 39:
! 40: #include <sys/param.h>
! 41: #include <sys/systm.h>
! 42: #include <sys/device.h>
! 43: #include <sys/malloc.h>
! 44:
! 45: #include <uvm/uvm_extern.h>
! 46:
! 47: #include <machine/bus.h>
! 48: #include <machine/autoconf.h>
! 49:
! 50: #include <dev/ofw/openfirm.h>
! 51: #include <dev/ata/atavar.h>
! 52: #include <dev/ata/atareg.h>
! 53: #include <dev/ic/wdcvar.h>
! 54:
! 55: #include <macppc/dev/dbdma.h>
! 56:
! 57: #define WDC_REG_NPORTS 8
! 58: #define WDC_AUXREG_OFFSET 0x16
! 59: #define WDC_DEFAULT_PIO_IRQ 13 /* XXX */
! 60: #define WDC_DEFAULT_DMA_IRQ 2 /* XXX */
! 61:
! 62: #define WDC_OPTIONS_DMA 0x01
! 63:
! 64: #define WDC_DMALIST_MAX 32
! 65:
! 66: struct wdc_obio_softc {
! 67: struct wdc_softc sc_wdcdev;
! 68: struct channel_softc *wdc_chanptr;
! 69: struct channel_softc wdc_channel;
! 70:
! 71: bus_dma_tag_t sc_dmat;
! 72: bus_dmamap_t sc_dmamap;
! 73: dbdma_regmap_t *sc_dmareg;
! 74: dbdma_command_t *sc_dmacmd;
! 75: dbdma_t sc_dbdma;
! 76:
! 77: void *sc_ih;
! 78: int sc_use_dma;
! 79: bus_size_t sc_cmdsize;
! 80: size_t sc_dmasize;
! 81: };
! 82:
! 83: u_int8_t wdc_obio_read_reg(struct channel_softc *, enum wdc_regs);
! 84: void wdc_obio_write_reg(struct channel_softc *, enum wdc_regs, u_int8_t);
! 85:
! 86: struct channel_softc_vtbl wdc_obio_vtbl = {
! 87: wdc_obio_read_reg,
! 88: wdc_obio_write_reg,
! 89: wdc_default_lba48_write_reg,
! 90: wdc_default_read_raw_multi_2,
! 91: wdc_default_write_raw_multi_2,
! 92: wdc_default_read_raw_multi_4,
! 93: wdc_default_write_raw_multi_4
! 94: };
! 95:
! 96: int wdc_obio_probe(struct device *, void *, void *);
! 97: void wdc_obio_attach(struct device *, struct device *, void *);
! 98: int wdc_obio_detach(struct device *, int);
! 99:
! 100: struct cfattach wdc_obio_ca = {
! 101: sizeof(struct wdc_obio_softc), wdc_obio_probe, wdc_obio_attach,
! 102: wdc_obio_detach, wdcactivate
! 103: };
! 104:
! 105: int wdc_obio_dma_init(void *, int, int, void *, size_t, int);
! 106: void wdc_obio_dma_start(void *, int, int);
! 107: int wdc_obio_dma_finish(void *, int, int, int);
! 108: void wdc_obio_adjust_timing(struct channel_softc *);
! 109: void wdc_obio_ata4_adjust_timing(struct channel_softc *);
! 110: void wdc_obio_ata6_adjust_timing(struct channel_softc *);
! 111:
! 112: int
! 113: wdc_obio_probe(struct device *parent, void *match, void *aux)
! 114: {
! 115: struct confargs *ca = aux;
! 116: char compat[32];
! 117:
! 118: if (ca->ca_nreg < 8)
! 119: return 0;
! 120:
! 121: /* XXX should not use name */
! 122: if (strcmp(ca->ca_name, "ATA") == 0 ||
! 123: strncmp(ca->ca_name, "ata", 3) == 0 ||
! 124: strcmp(ca->ca_name, "ide") == 0)
! 125: return 1;
! 126:
! 127: bzero(compat, sizeof(compat));
! 128: OF_getprop(ca->ca_node, "compatible", compat, sizeof(compat));
! 129: if (strcmp(compat, "heathrow-ata") == 0 ||
! 130: strcmp(compat, "keylargo-ata") == 0)
! 131: return 1;
! 132:
! 133: return 0;
! 134: }
! 135:
! 136: void
! 137: wdc_obio_attach(struct device *parent, struct device *self, void *aux)
! 138: {
! 139: struct wdc_obio_softc *sc = (void *)self;
! 140: struct confargs *ca = aux;
! 141: struct channel_softc *chp = &sc->wdc_channel;
! 142: int intr, error;
! 143: bus_addr_t cmdbase;
! 144:
! 145: sc->sc_use_dma = 0;
! 146: if (ca->ca_nreg >= 16)
! 147: sc->sc_use_dma = 1; /* Enable dma */
! 148:
! 149: sc->sc_dmat = ca->ca_dmat;
! 150: if ((error = bus_dmamap_create(sc->sc_dmat,
! 151: WDC_DMALIST_MAX * DBDMA_COUNT_MAX, WDC_DMALIST_MAX,
! 152: DBDMA_COUNT_MAX, NBPG, BUS_DMA_NOWAIT, &sc->sc_dmamap)) != 0) {
! 153: printf(": cannot create dma map, error = %d\n", error);
! 154: return;
! 155: }
! 156:
! 157: if (ca->ca_nintr >= 4 && ca->ca_nreg >= 8) {
! 158: intr = ca->ca_intr[0];
! 159: printf(" irq %d", intr);
! 160: } else if (ca->ca_nintr == -1) {
! 161: intr = WDC_DEFAULT_PIO_IRQ;
! 162: printf(" irq property not found; using %d", intr);
! 163: } else {
! 164: printf(": couldn't get irq property\n");
! 165: return;
! 166: }
! 167:
! 168: if (sc->sc_use_dma)
! 169: printf(": DMA");
! 170:
! 171: printf("\n");
! 172:
! 173: chp->cmd_iot = chp->ctl_iot = ca->ca_iot;
! 174: chp->_vtbl = &wdc_obio_vtbl;
! 175:
! 176: cmdbase = ca->ca_reg[0];
! 177: sc->sc_cmdsize = ca->ca_reg[1];
! 178:
! 179: if (bus_space_map(chp->cmd_iot, cmdbase, sc->sc_cmdsize, 0,
! 180: &chp->cmd_ioh) || bus_space_subregion(chp->cmd_iot, chp->cmd_ioh,
! 181: /* WDC_AUXREG_OFFSET<<4 */ 0x160, 1, &chp->ctl_ioh)) {
! 182: printf("%s: couldn't map registers\n",
! 183: sc->sc_wdcdev.sc_dev.dv_xname);
! 184: return;
! 185: }
! 186: chp->data32iot = chp->cmd_iot;
! 187: chp->data32ioh = chp->cmd_ioh;
! 188:
! 189: sc->sc_ih = mac_intr_establish(parent, intr, IST_LEVEL, IPL_BIO,
! 190: wdcintr, chp, sc->sc_wdcdev.sc_dev.dv_xname);
! 191:
! 192: sc->sc_wdcdev.set_modes = wdc_obio_adjust_timing;
! 193: if (sc->sc_use_dma) {
! 194: sc->sc_dbdma = dbdma_alloc(sc->sc_dmat, WDC_DMALIST_MAX + 1);
! 195: sc->sc_dmacmd = sc->sc_dbdma->d_addr;
! 196:
! 197: sc->sc_dmareg = mapiodev(ca->ca_baseaddr + ca->ca_reg[2],
! 198: sc->sc_dmasize = ca->ca_reg[3]);
! 199:
! 200: sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA;
! 201: sc->sc_wdcdev.DMA_cap = 2;
! 202: if (strcmp(ca->ca_name, "ata-4") == 0) {
! 203: sc->sc_wdcdev.cap |= WDC_CAPABILITY_UDMA |
! 204: WDC_CAPABILITY_MODE;
! 205: sc->sc_wdcdev.UDMA_cap = 4;
! 206: sc->sc_wdcdev.set_modes = wdc_obio_ata4_adjust_timing;
! 207: }
! 208: if (strcmp(ca->ca_name, "ata-6") == 0) {
! 209: sc->sc_wdcdev.cap |= WDC_CAPABILITY_UDMA |
! 210: WDC_CAPABILITY_MODE;
! 211: sc->sc_wdcdev.UDMA_cap = 5;
! 212: sc->sc_wdcdev.set_modes = wdc_obio_ata6_adjust_timing;
! 213: }
! 214: }
! 215: sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA16;
! 216: sc->sc_wdcdev.PIO_cap = 4;
! 217: sc->wdc_chanptr = chp;
! 218: sc->sc_wdcdev.channels = &sc->wdc_chanptr;
! 219: sc->sc_wdcdev.nchannels = 1;
! 220: sc->sc_wdcdev.dma_arg = sc;
! 221: sc->sc_wdcdev.dma_init = wdc_obio_dma_init;
! 222: sc->sc_wdcdev.dma_start = wdc_obio_dma_start;
! 223: sc->sc_wdcdev.dma_finish = wdc_obio_dma_finish;
! 224: chp->channel = 0;
! 225: chp->wdc = &sc->sc_wdcdev;
! 226:
! 227: chp->ch_queue = malloc(sizeof(struct channel_queue), M_DEVBUF,
! 228: M_NOWAIT);
! 229: if (chp->ch_queue == NULL) {
! 230: printf("%s: can't allocate memory for command queue",
! 231: sc->sc_wdcdev.sc_dev.dv_xname);
! 232: return;
! 233: }
! 234:
! 235: wdcattach(chp);
! 236: sc->sc_wdcdev.set_modes(chp);
! 237: wdc_print_current_modes(chp);
! 238: }
! 239:
! 240: int
! 241: wdc_obio_detach(struct device *self, int flags)
! 242: {
! 243: struct wdc_obio_softc *sc = (struct wdc_obio_softc *)self;
! 244: struct channel_softc *chp = &sc->wdc_channel;
! 245: int error;
! 246:
! 247: if ((error = wdcdetach(chp, flags)) != 0)
! 248: return (error);
! 249:
! 250: free(chp->ch_queue, M_DEVBUF);
! 251:
! 252: if (sc->sc_use_dma) {
! 253: unmapiodev((void *)sc->sc_dmareg, sc->sc_dmasize);
! 254: dbdma_free(sc->sc_dbdma);
! 255: }
! 256: mac_intr_disestablish(NULL, sc->sc_ih);
! 257:
! 258: bus_space_unmap(chp->cmd_iot, chp->cmd_ioh, sc->sc_cmdsize);
! 259: bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmamap);
! 260:
! 261: return (0);
! 262: }
! 263:
! 264: /* Multiword DMA transfer timings */
! 265: struct ide_timings {
! 266: int cycle; /* minimum cycle time [ns] */
! 267: int active; /* minimum command active time [ns] */
! 268: };
! 269:
! 270: static const struct ide_timings pio_timing[] = {
! 271: { 600, 165 }, /* Mode 0 */
! 272: { 383, 125 }, /* 1 */
! 273: { 240, 100 }, /* 2 */
! 274: { 180, 80 }, /* 3 */
! 275: { 120, 70 } /* 4 */
! 276: };
! 277:
! 278: static const struct ide_timings dma_timing[] = {
! 279: { 480, 215 }, /* Mode 0 */
! 280: { 150, 80 }, /* Mode 1 */
! 281: { 120, 70 }, /* Mode 2 */
! 282: };
! 283:
! 284: static const struct ide_timings udma_timing[] = {
! 285: {114, 0}, /* Mode 0 */
! 286: { 75, 0}, /* Mode 1 */
! 287: { 55, 0}, /* Mode 2 */
! 288: { 45, 100}, /* Mode 3 */
! 289: { 25, 100} /* Mode 4 */
! 290: };
! 291:
! 292: /* these number _guessed_ from linux driver. */
! 293: static u_int32_t kauai_pio_timing[] = {
! 294: /*600*/ 0x08000a92, /* Mode 0 */
! 295: /*360*/ 0x08000492, /* Mode 1 */
! 296: /*240*/ 0x0800038b, /* Mode 2 */
! 297: /*180*/ 0x05000249, /* Mode 3 */
! 298: /*120*/ 0x04000148 /* Mode 4 */
! 299:
! 300: };
! 301: static u_int32_t kauai_dma_timing[] = {
! 302: /*480*/ 0x00618000, /* Mode 0 */
! 303: /*360*/ 0x00492000, /* Mode 1 */
! 304: /*240*/ 0x00149000 /* Mode 2 */ /* fw value */
! 305: };
! 306: static u_int32_t kauai_udma_timing[] = {
! 307: /*120*/ 0x000070c0, /* Mode 0 */
! 308: /* 90*/ 0x00005d80, /* Mode 1 */
! 309: /* 60*/ 0x00004a60, /* Mode 2 */
! 310: /* 45*/ 0x00003a50, /* Mode 3 */
! 311: /* 30*/ 0x00002a30, /* Mode 4 */
! 312: /* 20*/ 0x00002921 /* Mode 5 */
! 313: };
! 314:
! 315: #define TIME_TO_TICK(time) howmany((time), 30)
! 316: #define PIO_REC_OFFSET 4
! 317: #define PIO_REC_MIN 1
! 318: #define PIO_ACT_MIN 1
! 319: #define DMA_REC_OFFSET 1
! 320: #define DMA_REC_MIN 1
! 321: #define DMA_ACT_MIN 1
! 322:
! 323: #define ATA4_TIME_TO_TICK(time) howmany((time) * 1000, 7500)
! 324:
! 325: #define CONFIG_REG (0x200) /* IDE access timing register */
! 326: #define KAUAI_ULTRA_CONFIG (0x210) /* secondary config register (kauai)*/
! 327:
! 328: #define KAUAI_PIO_MASK 0xff000fff
! 329: #define KAUAI_DMA_MASK 0x00fff000
! 330: #define KAUAI_UDMA_MASK 0x0000ffff
! 331: #define KAUAI_UDMA_EN 0x00000001
! 332:
! 333: void
! 334: wdc_obio_adjust_timing(struct channel_softc *chp)
! 335: {
! 336: struct ata_drive_datas *drvp;
! 337: u_int conf;
! 338: int drive;
! 339: int piomode = -1, dmamode = -1;
! 340: int min_cycle, min_active;
! 341: int cycle_tick, act_tick, inact_tick, half_tick;
! 342:
! 343: for (drive = 0; drive < 2; drive++) {
! 344: drvp = &chp->ch_drive[drive];
! 345: if ((drvp->drive_flags & DRIVE) == 0)
! 346: continue;
! 347: if (piomode == -1 || piomode > drvp->PIO_mode)
! 348: piomode = drvp->PIO_mode;
! 349: if (drvp->drive_flags & DRIVE_DMA)
! 350: if (dmamode == -1 || dmamode > drvp->DMA_mode)
! 351: dmamode = drvp->DMA_mode;
! 352: }
! 353: if (piomode == -1)
! 354: return; /* No drive */
! 355: for (drive = 0; drive < 2; drive++) {
! 356: drvp = &chp->ch_drive[drive];
! 357: if (drvp->drive_flags & DRIVE) {
! 358: drvp->PIO_mode = piomode;
! 359: if (drvp->drive_flags & DRIVE_DMA)
! 360: drvp->DMA_mode = dmamode;
! 361: }
! 362: }
! 363: min_cycle = pio_timing[piomode].cycle;
! 364: min_active = pio_timing[piomode].active;
! 365:
! 366: cycle_tick = TIME_TO_TICK(min_cycle);
! 367: act_tick = TIME_TO_TICK(min_active);
! 368: if (act_tick < PIO_ACT_MIN)
! 369: act_tick = PIO_ACT_MIN;
! 370: inact_tick = cycle_tick - act_tick - PIO_REC_OFFSET;
! 371: if (inact_tick < PIO_REC_MIN)
! 372: inact_tick = PIO_REC_MIN;
! 373: /* mask: 0x000007ff */
! 374: conf = (inact_tick << 5) | act_tick;
! 375: if (dmamode != -1) {
! 376: /* there are active DMA mode */
! 377:
! 378: min_cycle = dma_timing[dmamode].cycle;
! 379: min_active = dma_timing[dmamode].active;
! 380: cycle_tick = TIME_TO_TICK(min_cycle);
! 381: act_tick = TIME_TO_TICK(min_active);
! 382: inact_tick = cycle_tick - act_tick - DMA_REC_OFFSET;
! 383: if (inact_tick < DMA_REC_MIN)
! 384: inact_tick = DMA_REC_MIN;
! 385: half_tick = 0; /* XXX */
! 386: /* mask: 0xfffff800 */
! 387: conf |=
! 388: (half_tick << 21) |
! 389: (inact_tick << 16) | (act_tick << 11);
! 390: }
! 391: bus_space_write_4(chp->cmd_iot, chp->cmd_ioh, CONFIG_REG, conf);
! 392: #if 0
! 393: printf("conf = 0x%x, cyc = %d (%d ns), act = %d (%d ns), inact = %d\n",
! 394: conf, cycle_tick, min_cycle, act_tick, min_active, inact_tick);
! 395: #endif
! 396: }
! 397:
! 398: void
! 399: wdc_obio_ata4_adjust_timing(struct channel_softc *chp)
! 400: {
! 401: struct ata_drive_datas *drvp;
! 402: u_int conf;
! 403: int drive;
! 404: int piomode = -1, dmamode = -1;
! 405: int min_cycle, min_active;
! 406: int cycle_tick, act_tick, inact_tick;
! 407: int udmamode = -1;
! 408:
! 409: for (drive = 0; drive < 2; drive++) {
! 410: drvp = &chp->ch_drive[drive];
! 411: if ((drvp->drive_flags & DRIVE) == 0)
! 412: continue;
! 413: if (piomode == -1 || piomode > drvp->PIO_mode)
! 414: piomode = drvp->PIO_mode;
! 415: if (drvp->drive_flags & DRIVE_DMA)
! 416: if (dmamode == -1 || dmamode > drvp->DMA_mode)
! 417: dmamode = drvp->DMA_mode;
! 418: if (drvp->drive_flags & DRIVE_UDMA) {
! 419: if (udmamode == -1 || udmamode > drvp->UDMA_mode)
! 420: udmamode = drvp->UDMA_mode;
! 421: } else
! 422: udmamode = -2;
! 423: }
! 424: if (piomode == -1)
! 425: return; /* No drive */
! 426: for (drive = 0; drive < 2; drive++) {
! 427: drvp = &chp->ch_drive[drive];
! 428: if (drvp->drive_flags & DRIVE) {
! 429: drvp->PIO_mode = piomode;
! 430: if (drvp->drive_flags & DRIVE_DMA)
! 431: drvp->DMA_mode = dmamode;
! 432: if (drvp->drive_flags & DRIVE_UDMA) {
! 433: if (udmamode == -2)
! 434: drvp->drive_flags &= ~DRIVE_UDMA;
! 435: else
! 436: drvp->UDMA_mode = udmamode;
! 437: }
! 438: }
! 439: }
! 440:
! 441: if (udmamode == -2)
! 442: udmamode = -1;
! 443:
! 444: min_cycle = pio_timing[piomode].cycle;
! 445: min_active = pio_timing[piomode].active;
! 446:
! 447: cycle_tick = ATA4_TIME_TO_TICK(min_cycle);
! 448: act_tick = ATA4_TIME_TO_TICK(min_active);
! 449: inact_tick = cycle_tick - act_tick;
! 450: /* mask: 0x000003ff */
! 451: conf = (inact_tick << 5) | act_tick;
! 452: if (dmamode != -1) {
! 453: /* there are active DMA mode */
! 454:
! 455: min_cycle = dma_timing[dmamode].cycle;
! 456: min_active = dma_timing[dmamode].active;
! 457: cycle_tick = ATA4_TIME_TO_TICK(min_cycle);
! 458: act_tick = ATA4_TIME_TO_TICK(min_active);
! 459: inact_tick = cycle_tick - act_tick;
! 460: /* mask: 0x001ffc00 */
! 461: conf |= (act_tick << 10) | (inact_tick << 15);
! 462: }
! 463: if (udmamode != -1) {
! 464: min_cycle = udma_timing[udmamode].cycle;
! 465: min_active = udma_timing[udmamode].active;
! 466: act_tick = ATA4_TIME_TO_TICK(min_active);
! 467: cycle_tick = ATA4_TIME_TO_TICK(min_cycle);
! 468: /* mask: 0x1ff00000 */
! 469: conf |= (cycle_tick << 21) | (act_tick << 25) | 0x100000;
! 470: }
! 471:
! 472: bus_space_write_4(chp->cmd_iot, chp->cmd_ioh, CONFIG_REG, conf);
! 473: #if 0
! 474: printf("ata4 conf = 0x%x, cyc = %d (%d ns), act = %d (%d ns), inact = %d\n",
! 475: conf, cycle_tick, min_cycle, act_tick, min_active, inact_tick);
! 476: #endif
! 477: }
! 478:
! 479: void
! 480: wdc_obio_ata6_adjust_timing(struct channel_softc *chp)
! 481: {
! 482: struct ata_drive_datas *drvp;
! 483: u_int conf, conf1;
! 484: int drive;
! 485: int piomode = -1, dmamode = -1;
! 486: int udmamode = -1;
! 487:
! 488: for (drive = 0; drive < 2; drive++) {
! 489: drvp = &chp->ch_drive[drive];
! 490: if ((drvp->drive_flags & DRIVE) == 0)
! 491: continue;
! 492: if (piomode == -1 || piomode > drvp->PIO_mode)
! 493: piomode = drvp->PIO_mode;
! 494: if (drvp->drive_flags & DRIVE_DMA) {
! 495: if (dmamode == -1 || dmamode > drvp->DMA_mode)
! 496: dmamode = drvp->DMA_mode;
! 497: }
! 498: if (drvp->drive_flags & DRIVE_UDMA) {
! 499: if (udmamode == -1 || udmamode > drvp->UDMA_mode)
! 500: udmamode = drvp->UDMA_mode;
! 501: } else
! 502: udmamode = -2;
! 503: }
! 504: if (piomode == -1)
! 505: return; /* No drive */
! 506: for (drive = 0; drive < 2; drive++) {
! 507: drvp = &chp->ch_drive[drive];
! 508: if (drvp->drive_flags & DRIVE) {
! 509: drvp->PIO_mode = piomode;
! 510: if (drvp->drive_flags & DRIVE_DMA)
! 511: drvp->DMA_mode = dmamode;
! 512: if (drvp->drive_flags & DRIVE_UDMA) {
! 513: if (udmamode == -2)
! 514: drvp->drive_flags &= ~DRIVE_UDMA;
! 515: else
! 516: drvp->UDMA_mode = udmamode;
! 517: }
! 518: }
! 519: }
! 520:
! 521: if (udmamode == -2)
! 522: udmamode = -1;
! 523:
! 524: conf = bus_space_read_4(chp->cmd_iot, chp->cmd_ioh, CONFIG_REG);
! 525: conf1 = bus_space_read_4(chp->cmd_iot, chp->cmd_ioh,
! 526: KAUAI_ULTRA_CONFIG);
! 527:
! 528: conf = (conf & ~KAUAI_PIO_MASK) | kauai_pio_timing[piomode];
! 529:
! 530: if (dmamode != -1)
! 531: conf = (conf & ~KAUAI_DMA_MASK) | kauai_dma_timing[dmamode];
! 532: if (udmamode != -1)
! 533: conf1 = (conf1 & ~KAUAI_UDMA_MASK) |
! 534: kauai_udma_timing[udmamode] | KAUAI_UDMA_EN;
! 535: else
! 536: conf1 = conf1 & ~KAUAI_UDMA_EN;
! 537:
! 538: bus_space_write_4(chp->cmd_iot, chp->cmd_ioh, CONFIG_REG, conf);
! 539: bus_space_write_4(chp->cmd_iot, chp->cmd_ioh, KAUAI_ULTRA_CONFIG,
! 540: conf1);
! 541: }
! 542:
! 543: int
! 544: wdc_obio_dma_init(void *v, int channel, int drive, void *databuf,
! 545: size_t datalen, int flags)
! 546: {
! 547: struct wdc_obio_softc *sc = v;
! 548: dbdma_command_t *cmdp;
! 549: u_int cmd;
! 550: int i, error;
! 551:
! 552: if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap, databuf,
! 553: datalen, NULL, BUS_DMA_NOWAIT)) != 0)
! 554: return (error);
! 555:
! 556: cmdp = sc->sc_dmacmd;
! 557: cmd = (flags & WDC_DMA_READ) ? DBDMA_CMD_IN_MORE : DBDMA_CMD_OUT_MORE;
! 558:
! 559: for (i = 0; i < sc->sc_dmamap->dm_nsegs; i++, cmdp++) {
! 560: if (i + 1 == sc->sc_dmamap->dm_nsegs)
! 561: cmd = (flags & WDC_DMA_READ) ? DBDMA_CMD_IN_LAST :
! 562: DBDMA_CMD_OUT_LAST;
! 563:
! 564: DBDMA_BUILD(cmdp, cmd, 0, sc->sc_dmamap->dm_segs[i].ds_len,
! 565: sc->sc_dmamap->dm_segs[i].ds_addr,
! 566: DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
! 567: }
! 568:
! 569: DBDMA_BUILD(cmdp, DBDMA_CMD_STOP, 0, 0, 0,
! 570: DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
! 571:
! 572: return 0;
! 573: }
! 574:
! 575: void
! 576: wdc_obio_dma_start(void *v, int channel, int drive)
! 577: {
! 578: struct wdc_obio_softc *sc = v;
! 579:
! 580: dbdma_start(sc->sc_dmareg, sc->sc_dbdma);
! 581: }
! 582:
! 583: int
! 584: wdc_obio_dma_finish(void *v, int channel, int drive, int force)
! 585: {
! 586: struct wdc_obio_softc *sc = v;
! 587:
! 588: dbdma_stop(sc->sc_dmareg);
! 589: bus_dmamap_unload(sc->sc_dmat, sc->sc_dmamap);
! 590: return 0;
! 591: }
! 592:
! 593: /* read register code
! 594: * this allows the registers to be spaced by 0x10, instead of 0x1.
! 595: * mac hardware (obio) requires this.
! 596: */
! 597:
! 598: u_int8_t
! 599: wdc_obio_read_reg(struct channel_softc *chp, enum wdc_regs reg)
! 600: {
! 601: #ifdef DIAGNOSTIC
! 602: if (reg & _WDC_WRONLY) {
! 603: printf ("wdc_obio_read_reg: reading from a write-only register %d\n", reg);
! 604: }
! 605: #endif
! 606:
! 607: if (reg & _WDC_AUX)
! 608: return (bus_space_read_1(chp->ctl_iot, chp->ctl_ioh,
! 609: (reg & _WDC_REGMASK) << 4));
! 610: else
! 611: return (bus_space_read_1(chp->cmd_iot, chp->cmd_ioh,
! 612: (reg & _WDC_REGMASK) << 4));
! 613: }
! 614:
! 615:
! 616: void
! 617: wdc_obio_write_reg(struct channel_softc *chp, enum wdc_regs reg, u_int8_t val)
! 618: {
! 619: #ifdef DIAGNOSTIC
! 620: if (reg & _WDC_RDONLY) {
! 621: printf ("wdc_obio_write_reg: writing to a read-only register %d\n", reg);
! 622: }
! 623: #endif
! 624:
! 625: if (reg & _WDC_AUX)
! 626: bus_space_write_1(chp->ctl_iot, chp->ctl_ioh,
! 627: (reg & _WDC_REGMASK) << 4, val);
! 628: else
! 629: bus_space_write_1(chp->cmd_iot, chp->cmd_ioh,
! 630: (reg & _WDC_REGMASK) << 4, val);
! 631: }
CVSweb