[BACK]Return to mca_machdep.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / arch / i386 / mca

Annotation of src/sys/arch/i386/mca/mca_machdep.c, Revision 1.13

1.13    ! jdolecek    1: /*     $NetBSD: mca_machdep.c,v 1.12 2001/12/02 17:02:33 jdolecek Exp $        */
1.1       jdolecek    2:
1.3       jdolecek    3: /*-
1.12      jdolecek    4:  * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
1.3       jdolecek    5:  * Copyright (c) 1996-1999 Scott D. Telford.
                      6:  * All rights reserved.
                      7:  *
                      8:  * This code is derived from software contributed to The NetBSD Foundation
1.12      jdolecek    9:  * by Scott Telford <s.telford@ed.ac.uk> and Jaromir Dolecek
                     10:  * <jdolecek@NetBSD.org>.
1.1       jdolecek   11:  *
                     12:  * Redistribution and use in source and binary forms, with or without
                     13:  * modification, are permitted provided that the following conditions
                     14:  * are met:
                     15:  * 1. Redistributions of source code must retain the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer.
                     17:  * 2. Redistributions in binary form must reproduce the above copyright
                     18:  *    notice, this list of conditions and the following disclaimer in the
                     19:  *    documentation and/or other materials provided with the distribution.
1.3       jdolecek   20:  * 3. All advertising materials mentioning features or use of this software
                     21:  *    must display the following acknowledgement:
                     22:  *     This product includes software developed by the NetBSD
                     23:  *     Foundation, Inc. and its contributors.
                     24:  * 4. Neither the name of The NetBSD Foundation nor the names of its
                     25:  *    contributors may be used to endorse or promote products derived
                     26:  *    from this software without specific prior written permission.
1.1       jdolecek   27:  *
1.3       jdolecek   28:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     29:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     30:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     31:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     32:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     33:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     34:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     35:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     36:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     37:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     38:  * POSSIBILITY OF SUCH DAMAGE.
1.1       jdolecek   39:  */
                     40:
                     41: /*
                     42:  * Machine-specific functions for MCA autoconfiguration.
                     43:  */
1.10      lukem      44:
                     45: #include <sys/cdefs.h>
1.13    ! jdolecek   46: __KERNEL_RCSID(0, "$NetBSD: mca_machdep.c,v 1.12 2001/12/02 17:02:33 jdolecek Exp $");
1.1       jdolecek   47:
                     48: #include <sys/types.h>
                     49: #include <sys/param.h>
1.11      jdolecek   50: #include <sys/device.h>
                     51: #include <sys/malloc.h>
1.1       jdolecek   52: #include <sys/systm.h>
                     53: #include <sys/syslog.h>
1.11      jdolecek   54: #include <sys/time.h>
                     55: #include <sys/kernel.h>
1.1       jdolecek   56:
                     57: #include <machine/bioscall.h>
                     58: #include <machine/psl.h>
                     59:
                     60: #define _I386_BUS_DMA_PRIVATE
                     61: #include <machine/bus.h>
                     62:
                     63: #include <i386/isa/icu.h>
                     64: #include <dev/isa/isavar.h>
                     65: #include <dev/isa/isareg.h>
                     66: #include <dev/mca/mcavar.h>
                     67: #include <dev/mca/mcareg.h>
                     68:
                     69: #include "isa.h"
                     70: #include "opt_mcaverbose.h"
                     71:
1.7       jdolecek   72: /* System Configuration Block - this info is returned by the BIOS call */
                     73: struct bios_config {
                     74:        u_int16_t       count;
                     75:        u_int8_t        model;
                     76:        u_int8_t        submodel;
                     77:        u_int8_t        bios_rev;
                     78:        u_int8_t        feature1;
                     79: #define FEATURE_MCAISA 0x01    /* Machine contains both MCA and ISA bus */
                     80: #define FEATURE_MCABUS 0x02    /* Machine has MCA bus instead of ISA   */
                     81: #define FEATURE_EBDA   0x04    /* Extended BIOS data area allocated    */
                     82: #define FEATURE_WAITEV 0x08    /* Wait for external event is supported */
                     83: #define FEATURE_KBDINT 0x10    /* Keyboard intercept called by Int 09h */
                     84: #define FEATURE_RTC    0x20    /* Real-time clock present              */
                     85: #define FEATURE_IC2    0x40    /* Second interrupt chip present        */
                     86: #define FEATURE_DMA3   0x80    /* DMA channel 3 used by hard disk BIOS */
1.11      jdolecek   87:        u_int8_t        feature2;
                     88:        u_int8_t        pad[9];
1.7       jdolecek   89: } __attribute__ ((packed));
                     90:
1.11      jdolecek   91: /*
                     92:  * Used to encode DMA channel into ISA DMA cookie. We use upper 4 bits of
                     93:  * ISA DMA cookie id_flags, it's unused.
                     94:  */
                     95: struct i386_isa_dma_cookie {
                     96:        int id_flags;
                     97:        /* We don't care about rest */
                     98: };
                     99:
                    100: /* ISA DMA stuff - see i386/isa/isa_machdep.c */
                    101: int    _isa_bus_dmamap_create __P((bus_dma_tag_t, bus_size_t, int,
                    102:            bus_size_t, bus_size_t, int, bus_dmamap_t *));
                    103: void   _isa_bus_dmamap_destroy __P((bus_dma_tag_t, bus_dmamap_t));
                    104: int    _isa_bus_dmamap_load __P((bus_dma_tag_t, bus_dmamap_t, void *,
                    105:            bus_size_t, struct proc *, int));
                    106: void   _isa_bus_dmamap_unload __P((bus_dma_tag_t, bus_dmamap_t));
                    107: void   _isa_bus_dmamap_sync __P((bus_dma_tag_t, bus_dmamap_t,
                    108:            bus_addr_t, bus_size_t, int));
                    109:
                    110: int    _isa_bus_dmamem_alloc __P((bus_dma_tag_t, bus_size_t, bus_size_t,
                    111:            bus_size_t, bus_dma_segment_t *, int, int *, int));
                    112:
                    113: static void    _mca_bus_dmamap_sync __P((bus_dma_tag_t, bus_dmamap_t,
                    114:                    bus_addr_t, bus_size_t, int));
                    115: static int     _mca_bus_dmamap_load_mbuf __P((bus_dma_tag_t, bus_dmamap_t,
                    116:                    struct mbuf *, int));
                    117: static int     _mca_bus_dmamap_load_uio __P((bus_dma_tag_t, bus_dmamap_t,
                    118:                    struct uio *, int));
                    119: static int     _mca_bus_dmamap_load_raw __P((bus_dma_tag_t, bus_dmamap_t,
                    120:                    bus_dma_segment_t *, int, bus_size_t, int));
                    121:
                    122: /*
                    123:  * For now, we use MCA DMA to 0-16M always. Some IBM PS/2 have 32bit MCA bus,
                    124:  * but majority of them have 24bit only.
                    125:  */
                    126: #define        MCA_DMA_BOUNCE_THRESHOLD        (16 * 1024 * 1024)
1.7       jdolecek  127:
1.1       jdolecek  128: struct i386_bus_dma_tag mca_bus_dma_tag = {
1.11      jdolecek  129:        MCA_DMA_BOUNCE_THRESHOLD,               /* _bounce_thresh */
                    130:        _isa_bus_dmamap_create,
                    131:        _isa_bus_dmamap_destroy,
                    132:        _isa_bus_dmamap_load,
                    133:        _mca_bus_dmamap_load_mbuf,
                    134:        _mca_bus_dmamap_load_uio,
                    135:        _mca_bus_dmamap_load_raw,
                    136:        _isa_bus_dmamap_unload,
                    137:        _mca_bus_dmamap_sync,
                    138:        _isa_bus_dmamem_alloc,
1.1       jdolecek  139:        _bus_dmamem_free,
                    140:        _bus_dmamem_map,
                    141:        _bus_dmamem_unmap,
                    142:        _bus_dmamem_mmap,
                    143: };
                    144:
1.11      jdolecek  145: /* Updated in mca_busprobe() if appropriate. */
                    146: int MCA_system = 0;
                    147:
                    148: /* Used to kick MCA DMA controller */
                    149: #define DMA_CMD                0x18            /* command the controller */
                    150: #define DMA_EXEC       0x1A            /* tell controller how to do things */
                    151: static bus_space_handle_t dmaiot, dmacmdh, dmaexech;
1.1       jdolecek  152:
1.11      jdolecek  153: /*
                    154:  * MCA DMA controller commands. The exact sense of individual bits
                    155:  * are from Tymm Twillman <tymm@computer.org>, who worked on Linux MCA DMA
                    156:  * support.
                    157:  */
                    158: #define DMACMD_SET_IO          0x00    /* set port (16bit) for i/o transfer */
                    159: #define DMACMD_SET_ADDR                0x20    /* set addr (24bit) for i/o transfer */
                    160: #define DMACMD_GET_ADDR                0x30    /* get addr (24bit) for i/o transfer */
                    161: #define        DMACMD_SET_CNT          0x40    /* set memory size for DMA (16b) */
                    162: #define DMACMD_GET_CNT         0x50    /* get count of remaining bytes in DMA*/
                    163: #define DMACMD_GET_STATUS      0x60    /* ?? */
                    164: #define DMACMD_SET_MODE                0x70    /* set DMA mode */
                    165: # define DMACMD_MODE_XFER      0x04    /* do transfer, read by default */
                    166: # define DMACMD_MODE_READ      0x08    /* read transfer */
                    167: # define DMACMD_MODE_WRITE     0x00    /* write transfer */
                    168: # define DMACMD_MODE_IOPORT    0x01    /* DMA from/to IO register */
                    169: # define DMACMD_MODE_16BIT     0x40    /* 16bit transfers (default 8bit) */
                    170: #define DMACMD_SET_ARBUS       0x80    /* ?? */
                    171: #define DMACMD_MASK            0x90    /* command mask */
                    172: #define DMACMD_RESET_MASK      0xA0    /* reset */
                    173: #define DMACMD_MASTER_CLEAR    0xD0    /* ?? */
                    174:
                    175: /*
                    176:  * Map the MCA DMA controller registers.
                    177:  */
1.1       jdolecek  178: void
                    179: mca_attach_hook(parent, self, mba)
                    180:        struct device *parent, *self;
                    181:        struct mcabus_attach_args *mba;
                    182: {
1.11      jdolecek  183:        dmaiot = mba->mba_iot;
                    184:
                    185:        if (bus_space_map(dmaiot, DMA_CMD, 1, 0, &dmacmdh)
                    186:            || bus_space_map(dmaiot, DMA_EXEC, 1, 0, &dmaexech))
                    187:                panic("%s: couldn't map DMA registers",
                    188:                        mba->mba_busname);
1.1       jdolecek  189: }
                    190:
                    191: /*
                    192:  * Read value of MCA POS register "reg" in slot "slot".
                    193:  */
                    194:
                    195: int
                    196: mca_conf_read(mc, slot, reg)
                    197:        mca_chipset_tag_t mc;
                    198:        int slot, reg;
                    199: {
                    200:        int     data;
                    201:
                    202:        slot &= 7;      /* slot must be in range 0-7 */
                    203:        outb(MCA_MB_SETUP_REG, 0xff); /* ensure m/board setup is disabled */
                    204:        outb(MCA_ADAP_SETUP_REG, slot | MCA_ADAP_SET);
                    205:        data = inb(MCA_POS_REG(reg));
                    206:        outb(MCA_ADAP_SETUP_REG, 0);
                    207:        return data;
                    208: }
                    209:
                    210:
                    211: /*
                    212:  * Write "data" to MCA POS register "reg" in slot "slot".
                    213:  */
                    214:
                    215: void
                    216: mca_conf_write(mc, slot, reg, data)
                    217:        mca_chipset_tag_t mc;
                    218:        int slot, reg, data;
                    219: {
                    220:        slot&=7;        /* slot must be in range 0-7 */
                    221:        outb(MCA_MB_SETUP_REG, 0xff); /* ensure m/board setup is disabled */
                    222:        outb(MCA_ADAP_SETUP_REG, slot | MCA_ADAP_SET);
                    223:        outb(MCA_POS_REG(reg), data);
                    224:        outb(MCA_ADAP_SETUP_REG, 0);
                    225: }
                    226:
                    227: #if NISA <= 0
                    228: #error mca_intr_(dis)establish: needs ISA to be configured into kernel
                    229: #endif
1.2       cgd       230:
1.4       jdolecek  231: #if 0
1.2       cgd       232: const struct evcnt *
                    233: mca_intr_establish(mca_chipset_tag_t mc, mca_intr_handle_t ih)
                    234: {
                    235:
                    236:        /* XXX for now, no evcnt parent reported */
                    237:        return NULL;
                    238: }
1.4       jdolecek  239: #endif
1.1       jdolecek  240:
                    241: void *
                    242: mca_intr_establish(mc, ih, level, func, arg)
                    243:        mca_chipset_tag_t mc;
                    244:        mca_intr_handle_t ih;
                    245:        int level, (*func) __P((void *));
                    246:        void *arg;
                    247: {
                    248:        if (ih == 0 || ih >= ICU_LEN || ih == 2)
                    249:                panic("mca_intr_establish: bogus handle 0x%x\n", ih);
                    250:
                    251:        /* MCA interrupts are always level-triggered */
                    252:        return isa_intr_establish(NULL, ih, IST_LEVEL, level, func, arg);
                    253: }
                    254:
                    255: void
                    256: mca_intr_disestablish(mc, cookie)
                    257:        mca_chipset_tag_t mc;
                    258:        void *cookie;
                    259: {
                    260:        return isa_intr_disestablish(NULL, cookie);
                    261: }
                    262:
                    263:
                    264: /*
                    265:  * Handle a NMI.
                    266:  * return true to panic system, false to ignore.
                    267:  */
                    268: int
                    269: mca_nmi()
                    270: {
                    271:        /*
                    272:        * PS/2 MCA devices can generate NMIs - we can find out which
                    273:        * slot generated it from the POS registers.
                    274:        */
                    275:
                    276:        int     slot, mcanmi=0;
                    277:
                    278:        /* if there is no MCA bus, call isa_nmi() */
                    279:        if (!MCA_system)
                    280:                goto out;
                    281:
                    282:        /* ensure motherboard setup is disabled */
                    283:        outb(MCA_MB_SETUP_REG, 0xff);
                    284:
                    285:        /* find if an MCA slot has the CHCK bit asserted (low) in POS 5 */
1.11      jdolecek  286:        for(slot=0; slot<MCA_MAX_SLOTS; slot++) {
1.1       jdolecek  287:                outb(MCA_ADAP_SETUP_REG, slot | MCA_ADAP_SET);
1.11      jdolecek  288:                if ((inb(MCA_POS_REG(5)) & MCA_POS5_CHCK) == 0) {
1.1       jdolecek  289:                        mcanmi = 1;
                    290:                        /* find if CHCK status is available in POS 6/7 */
                    291:                        if((inb(MCA_POS_REG(5)) & MCA_POS5_CHCK_STAT) == 0)
                    292:                                log(LOG_CRIT, "MCA NMI: slot %d, POS6=0x%02x, POS7=0x%02x\n",
                    293:                                        slot+1, inb(MCA_POS_REG(6)),
                    294:                                                inb(MCA_POS_REG(7)));
                    295:                        else
                    296:                                log(LOG_CRIT, "MCA NMI: slot %d\n", slot+1);
                    297:                }
                    298:        }
                    299:        outb(MCA_ADAP_SETUP_REG, 0);
                    300:
                    301:    out:
                    302:        if (!mcanmi) {
                    303:                /* no CHCK bits asserted, assume ISA NMI */
                    304:                return (isa_nmi());
                    305:        } else
                    306:                return(0);
                    307: }
                    308:
1.7       jdolecek  309: /*
                    310:  * We can obtain the information about MCA bus presence via
                    311:  * GET CONFIGURATION BIOS call - int 0x15, function 0xc0.
                    312:  * The call returns a pointer to memory place with the configuration block
                    313:  * in es:bx (on AT-compatible, e.g. all we care about, computers).
                    314:  *
                    315:  * Configuration block contains block length (2 bytes), model
                    316:  * number (1 byte), submodel number (1 byte), BIOS revision
                    317:  * (1 byte) and up to 5 feature bytes. We only care about
                    318:  * first feature byte.
                    319:  */
1.1       jdolecek  320: void
                    321: mca_busprobe()
                    322: {
                    323:        struct bioscallregs regs;
1.7       jdolecek  324:        struct bios_config *scp;
1.1       jdolecek  325:        paddr_t             paddr;
1.7       jdolecek  326:        char buf[50];
1.1       jdolecek  327:
                    328:        memset(&regs, 0, sizeof(regs));
1.7       jdolecek  329:        regs.AH = 0xc0;
1.1       jdolecek  330:        bioscall(0x15, &regs);
                    331:
1.7       jdolecek  332:        if ((regs.EFLAGS & PSL_C) || regs.AH != 0) {
                    333: #ifdef DEBUG
                    334:                printf("BIOS CFG: Not supported. Not AT-compatible?\n");
1.1       jdolecek  335: #endif
                    336:                return;
                    337:        }
1.7       jdolecek  338:
1.1       jdolecek  339:        paddr = (regs.ES << 4) + regs.BX;
1.7       jdolecek  340:        scp = (struct bios_config *)ISA_HOLE_VADDR(paddr);
1.1       jdolecek  341:
1.7       jdolecek  342: #if 1 /* MCAVERBOSE */
1.11      jdolecek  343:        bitmask_snprintf(((scp->feature2 & 1)<< 8) | scp->feature1,
1.3       jdolecek  344:                "\20"
1.9       jdolecek  345:                "\01MCA+ISA"
                    346:                "\02MCA"
1.3       jdolecek  347:                "\03EBDA"
                    348:                "\04WAITEV"
                    349:                "\05KBDINT"
                    350:                "\06RTC"
1.5       jdolecek  351:                "\07IC2"
1.11      jdolecek  352:                "\010DMA3B"
                    353:                "\011DMA32\n",
1.3       jdolecek  354:                buf, sizeof(buf));
1.9       jdolecek  355:
1.11      jdolecek  356:        printf("BIOS CFG: Model-SubM-Rev: %02x-%02x-%02x, 0x%s\n",
1.9       jdolecek  357:                scp->model, scp->submodel, scp->bios_rev, buf);
1.1       jdolecek  358: #endif
                    359:
1.7       jdolecek  360:        MCA_system = (scp->feature1 & FEATURE_MCABUS) ? 1 : 0;
1.6       jdolecek  361: }
                    362:
                    363: #define PORT_DISKLED   0x92
                    364: #define DISKLED_ON     0x40
                    365:
                    366: /*
                    367:  * Light disk busy LED on IBM PS/2.
                    368:  */
                    369: void
                    370: mca_disk_busy(void)
                    371: {
                    372:        outb(PORT_DISKLED, inb(PORT_DISKLED) | DISKLED_ON);
                    373: }
                    374:
                    375: /*
                    376:  * Turn off disk LED on IBM PS/2.
                    377:  */
                    378: void
                    379: mca_disk_unbusy(void)
                    380: {
                    381:        outb(PORT_DISKLED, inb(PORT_DISKLED) & ~DISKLED_ON);
1.11      jdolecek  382: }
                    383:
                    384: /*
                    385:  * -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
                    386:  * MCA DMA specific stuff. We use ISA routines for bulk of the work,
                    387:  * since MCA shares much of the charasteristics with it. We just hook
                    388:  * the DMA channel initialization and kick MCA DMA controller appropriately.
                    389:  * -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
                    390:  */
                    391:
                    392: /*
                    393:  * Like _mca_bus_dmamap_load(), but for mbufs.
                    394:  */
                    395: static int
                    396: _mca_bus_dmamap_load_mbuf(t, map, m0, flags)
                    397:        bus_dma_tag_t t;
                    398:        bus_dmamap_t map;
                    399:        struct mbuf *m0;
                    400:        int flags;
                    401: {
                    402:
                    403:        panic("_mca_bus_dmamap_load_mbuf: not implemented");
                    404: }
                    405:
                    406: /*
                    407:  * Like _mca_bus_dmamap_load(), but for uios.
                    408:  */
                    409: static int
                    410: _mca_bus_dmamap_load_uio(t, map, uio, flags)
                    411:        bus_dma_tag_t t;
                    412:        bus_dmamap_t map;
                    413:        struct uio *uio;
                    414:        int flags;
                    415: {
                    416:
                    417:        panic("_mca_bus_dmamap_load_uio: not implemented");
                    418: }
                    419:
                    420: /*
                    421:  * Like _mca_bus_dmamap_load(), but for raw memory allocated with
                    422:  * bus_dmamem_alloc().
                    423:  */
                    424: static int
                    425: _mca_bus_dmamap_load_raw(t, map, segs, nsegs, size, flags)
                    426:        bus_dma_tag_t t;
                    427:        bus_dmamap_t map;
                    428:        bus_dma_segment_t *segs;
                    429:        int nsegs;
                    430:        bus_size_t size;
                    431:        int flags;
                    432: {
                    433:
                    434:        panic("_mca_bus_dmamap_load_raw: not implemented");
                    435: }
                    436:
                    437: /*
                    438:  * Synchronize a MCA DMA map.
                    439:  */
                    440: static void
                    441: _mca_bus_dmamap_sync(t, map, offset, len, ops)
                    442:        bus_dma_tag_t t;
                    443:        bus_dmamap_t map;
                    444:        bus_addr_t offset;
                    445:        bus_size_t len;
                    446:        int ops;
                    447: {
                    448:        struct i386_isa_dma_cookie *cookie;
                    449:        bus_addr_t phys;
                    450:        bus_size_t cnt;
                    451:        int dmach, mode;
                    452:
                    453:        _isa_bus_dmamap_sync(t, map, offset, len, ops);
                    454:
                    455:        /*
                    456:         * Don't do anything if not using the DMA controller.
                    457:         */
1.12      jdolecek  458:        if ((map->_dm_flags & _MCABUS_DMA_USEDMACTRL) == 0)
1.11      jdolecek  459:                return;
                    460:
                    461:        /*
                    462:         * Don't do anything if not PRE* operation, allow only
                    463:         * one of PREREAD and PREWRITE.
                    464:         */
                    465:        if (ops != BUS_DMASYNC_PREREAD && ops != BUS_DMASYNC_PREWRITE)
                    466:                return;
                    467:
                    468:        cookie = (struct i386_isa_dma_cookie *)map->_dm_cookie;
                    469:        dmach = (cookie->id_flags & 0xf0) >> 4;
                    470:
                    471:        phys = map->dm_segs[0].ds_addr;
                    472:        cnt = map->dm_segs[0].ds_len;
                    473:
                    474:        mode = DMACMD_MODE_XFER;
                    475:        mode |= (ops == BUS_DMASYNC_PREREAD)
                    476:                        ? DMACMD_MODE_READ : DMACMD_MODE_WRITE;
1.12      jdolecek  477:        if (map->_dm_flags & MCABUS_DMA_IOPORT)
                    478:                mode |= DMACMD_MODE_IOPORT;
1.11      jdolecek  479:
1.13    ! jdolecek  480:        /* Use 16bit DMA if requested */
1.12      jdolecek  481:        if (map->_dm_flags & MCABUS_DMA_16BIT) {
                    482: #ifdef DIAGNOSTIC
                    483:                if ((cnt % 2) != 0) {
                    484:                        panic("_mca_bus_dmamap_sync: 16bit DMA and cnt %lu odd",
                    485:                                cnt);
                    486:                }
                    487: #endif
1.11      jdolecek  488:                mode |= DMACMD_MODE_16BIT;
                    489:                cnt /= 2;
                    490:        }
                    491:
                    492:        /*
                    493:         * Initialize the MCA DMA controller appropriately. The exact
                    494:         * sequence to setup the controller is taken from Minix.
                    495:         */
                    496:
                    497:        /* Disable access to dma channel. */
1.12      jdolecek  498:        bus_space_write_1(dmaiot, dmacmdh, 0, DMACMD_MASK | dmach);
                    499:
                    500:        /* Set the transfer mode. */
                    501:        bus_space_write_1(dmaiot, dmacmdh, 0, DMACMD_SET_MODE | dmach);
                    502:        bus_space_write_1(dmaiot, dmaexech, 0, mode);
1.11      jdolecek  503:
                    504:        /* Set the address byte pointer. */
1.12      jdolecek  505:        bus_space_write_1(dmaiot, dmacmdh, 0, DMACMD_SET_ADDR | dmach);
1.11      jdolecek  506:        /* address bits 0..7   */
                    507:        bus_space_write_1(dmaiot, dmaexech, 0, (phys >> 0) & 0xff);
                    508:        /* address bits 8..15  */
                    509:        bus_space_write_1(dmaiot, dmaexech, 0, (phys >> 8) & 0xff);
                    510:        /* address bits 16..23  */
                    511:        bus_space_write_1(dmaiot, dmaexech, 0, (phys >> 16) & 0xff);
                    512:
                    513:        /* Set the count byte pointer */
1.12      jdolecek  514:        bus_space_write_1(dmaiot, dmacmdh, 0, DMACMD_SET_CNT | dmach);
1.11      jdolecek  515:        /* count bits 0..7     */
                    516:        bus_space_write_1(dmaiot, dmaexech, 0, ((cnt - 1) >> 0) & 0xff);
                    517:        /* count bits 8..15    */
                    518:        bus_space_write_1(dmaiot, dmaexech, 0, ((cnt - 1) >> 8) & 0xff);
                    519:
                    520:        /* Enable access to dma channel. */
1.12      jdolecek  521:        bus_space_write_1(dmaiot, dmacmdh, 0, DMACMD_RESET_MASK | dmach);
1.11      jdolecek  522: }
                    523:
                    524: /*
                    525:  * Allocate a dma map, and set up dma channel.
                    526:  */
                    527: int
                    528: mca_dmamap_create(t, size, flags, dmamp, dmach)
                    529:        bus_dma_tag_t t;
                    530:        bus_size_t size;
                    531:        int flags;
                    532:        bus_dmamap_t *dmamp;
                    533:        int dmach;
                    534: {
                    535:        int error;
                    536:        struct i386_isa_dma_cookie *cookie;
                    537:
                    538: #ifdef DEBUG
                    539:        /* Sanity check */
                    540:        if (dmach < 0 || dmach >= 16) {
                    541:                printf("mcadma_create: invalid DMA channel %d\n",
                    542:                        dmach);
                    543:                return (EINVAL);
                    544:        }
                    545:
                    546:        if (size > 65536) {
                    547:                panic("mca_dmamap_create: dmamap sz %ld > 65536",
                    548:                        (long) size)
                    549:        }
                    550: #endif
                    551:
                    552:        /*
                    553:         * MCA DMA transfer can be maximum 65536 bytes long and must
                    554:         * be in one chunk. No specific boundary constraints are present.
                    555:         */
                    556:        if ((error = bus_dmamap_create(t, size, 1, 65536, 0, flags, dmamp)))
                    557:                return (error);
                    558:
                    559:        /* Encode DMA channel */
                    560:        cookie = (struct i386_isa_dma_cookie *) (*dmamp)->_dm_cookie;
                    561:        cookie->id_flags &= 0x0f;
                    562:        cookie->id_flags |= dmach << 4;
                    563:
1.12      jdolecek  564:        /* Mark the dmamap as using DMA controller. Some devices
                    565:         * drive DMA themselves, and don't need the MCA DMA controller.
                    566:         * To distinguish the two, use a flag for dmamaps which use the DMA
                    567:         * controller.
                    568:         */
                    569:        (*dmamp)->_dm_flags |= _MCABUS_DMA_USEDMACTRL;
1.11      jdolecek  570:
                    571:        return (0);
1.12      jdolecek  572: }
                    573:
                    574: /*
                    575:  * Set I/O port for DMA. Implemented separately from _mca_bus_dmamap_sync()
                    576:  * so that it's available for one-shot setup.
                    577:  */
                    578: void
                    579: mca_dma_set_ioport(dma, port)
                    580:        int dma;
                    581:        u_int16_t port;
                    582: {
                    583:        /* Disable access to dma channel. */
                    584:        bus_space_write_1(dmaiot, dmacmdh, 0, DMACMD_MASK | dma);
                    585:
                    586:        /* Set I/O port to use for DMA */
1.13    ! jdolecek  587:        bus_space_write_1(dmaiot, dmacmdh, 0, DMACMD_SET_IO | dma);
1.12      jdolecek  588:        bus_space_write_1(dmaiot, dmaexech, 0, port & 0xff);
1.13    ! jdolecek  589:        bus_space_write_1(dmaiot, dmaexech, 0, (port >> 8) & 0xff);
1.12      jdolecek  590:
                    591:        /* Enable access to dma channel. */
                    592:        bus_space_write_1(dmaiot, dmacmdh, 0, DMACMD_RESET_MASK | dma);
1.1       jdolecek  593: }

CVSweb <webmaster@jp.NetBSD.org>