[BACK]Return to wdc_obio.c CVS log [TXT][DIR] Up to [local] / sys / arch / macppc / dev

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