[BACK]Return to pxa2x0_dmac.c CVS log [TXT][DIR] Up to [local] / sys / arch / arm / xscale

Annotation of sys/arch/arm/xscale/pxa2x0_dmac.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: pxa2x0_dmac.c,v 1.3 2006/04/04 11:37:05 pascoe Exp $  */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 2005 Christopher Pascoe <pascoe@openbsd.org>
        !             5:  *
        !             6:  * Permission to use, copy, modify, and distribute this software for any
        !             7:  * purpose with or without fee is hereby granted, provided that the above
        !             8:  * copyright notice and this permission notice appear in all copies.
        !             9:  *
        !            10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
        !            11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
        !            13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            14:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
        !            15:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
        !            16:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            17:  */
        !            18:
        !            19: /*
        !            20:  * DMA Controller Handler for the Intel PXA2X0 processor.
        !            21:  */
        !            22: #include <sys/cdefs.h>
        !            23:
        !            24: #include <sys/param.h>
        !            25: #include <sys/systm.h>
        !            26: #include <sys/malloc.h>
        !            27: #include <sys/evcount.h>
        !            28: #include <uvm/uvm_extern.h>
        !            29:
        !            30: #include <machine/bus.h>
        !            31: #include <machine/intr.h>
        !            32: #include <machine/lock.h>
        !            33:
        !            34: #include <arm/xscale/pxa2x0reg.h>
        !            35: #include <arm/xscale/pxa2x0var.h>
        !            36: #include <arm/xscale/pxa2x0_dmac.h>
        !            37:
        !            38: typedef void (*pxadmac_intrhandler)(void *);
        !            39:
        !            40: struct pxadmac_softc {
        !            41:        struct device sc_dev;
        !            42:        bus_space_tag_t sc_bust;
        !            43:        bus_space_handle_t sc_bush;
        !            44:        void *sc_ih;
        !            45:        int sc_nchan;
        !            46:        int sc_npri;
        !            47:        pxadmac_intrhandler sc_intrhandlers[DMAC_N_CHANNELS_PXA27X];
        !            48:        void *sc_intrargs[DMAC_N_CHANNELS_PXA27X];
        !            49: };
        !            50:
        !            51: int pxadmac_intr(void *);
        !            52:
        !            53: /*
        !            54:  * DMAC autoconf glue
        !            55:  */
        !            56: int    pxadmac_match(struct device *, void *, void *);
        !            57: void   pxadmac_attach(struct device *, struct device *, void *);
        !            58:
        !            59: struct cfattach pxadmac_ca = {
        !            60:        sizeof(struct pxadmac_softc), pxadmac_match, pxadmac_attach
        !            61: };
        !            62:
        !            63: struct cfdriver pxadmac_cd = {
        !            64:        NULL, "pxadmac", DV_DULL
        !            65: };
        !            66:
        !            67: static struct pxadmac_softc *pxadmac_softc = NULL;
        !            68:
        !            69: int
        !            70: pxadmac_match(struct device *parent, void *cf, void *aux)
        !            71: {
        !            72:        struct pxaip_attach_args *pxa = aux;
        !            73:
        !            74:        if (pxadmac_softc != NULL || pxa->pxa_addr != PXA2X0_DMAC_BASE)
        !            75:                return (0);
        !            76:
        !            77:        return (1);
        !            78: }
        !            79:
        !            80: void
        !            81: pxadmac_attach(struct device *parent, struct device *self, void *args)
        !            82: {
        !            83:        struct pxadmac_softc *sc = (struct pxadmac_softc *)self;
        !            84:        struct pxaip_attach_args *pxa = args;
        !            85:        bus_size_t bus_size;
        !            86:
        !            87:        sc->sc_bust = pxa->pxa_iot;
        !            88:
        !            89:        printf(": DMA Controller\n");
        !            90:
        !            91:        if ((cputype & ~CPU_ID_XSCALE_COREREV_MASK) == CPU_ID_PXA27X) {
        !            92:                sc->sc_nchan = DMAC_N_CHANNELS_PXA27X;
        !            93:                sc->sc_npri = DMAC_N_PRIORITIES_PXA27X;
        !            94:                bus_size = PXA27X_DMAC_SIZE;
        !            95:        } else  {
        !            96:                sc->sc_nchan = DMAC_N_CHANNELS;
        !            97:                sc->sc_npri = DMAC_N_PRIORITIES;
        !            98:                bus_size = PXA2X0_DMAC_SIZE;
        !            99:        }
        !           100:
        !           101:        if (bus_space_map(sc->sc_bust, pxa->pxa_addr, bus_size, 0,
        !           102:            &sc->sc_bush)) {
        !           103:                printf("%s: Can't map registers!\n", sc->sc_dev.dv_xname);
        !           104:                return;
        !           105:        }
        !           106:
        !           107:        sc->sc_ih = pxa2x0_intr_establish(pxa->pxa_intr, IPL_BIO,
        !           108:            pxadmac_intr, sc, "pxadmac");
        !           109:        if (sc->sc_ih == NULL) {
        !           110:                printf(": unable to establish interrupt\n");
        !           111:                bus_space_unmap(sc->sc_bust, sc->sc_bush, bus_size);
        !           112:                return;
        !           113:        }
        !           114:
        !           115:        pxadmac_softc = sc;
        !           116: }
        !           117:
        !           118: /* Perform non-descriptor based DMA to a FIFO */
        !           119: int
        !           120: pxa2x0_dma_to_fifo(int periph, int chan, bus_addr_t fifo_addr, int width,
        !           121:     int burstsize, bus_addr_t src_addr, int length, void (*intr)(void *),
        !           122:     void *intrarg)
        !           123: {
        !           124:        struct pxadmac_softc *sc = pxadmac_softc;
        !           125:        uint32_t cmd;
        !           126:
        !           127:        if (periph < 0 || periph > 63 || periph == 23) {
        !           128:                printf("pxa2x0_dma_to_fifo: bogus peripheral %d", periph);
        !           129:                return EINVAL;
        !           130:        }
        !           131:
        !           132:        if (chan < 0 || chan >= sc->sc_nchan) {
        !           133:                printf("pxa2x0_dma_to_fifo: bogus dma channel %d", chan);
        !           134:                return EINVAL;
        !           135:        }
        !           136:
        !           137:        if (length < 0 || length > DCMD_LENGTH_MASK) {
        !           138:                printf("pxa2x0_dma_to_fifo: bogus length %d", length);
        !           139:                return EINVAL;
        !           140:        }
        !           141:
        !           142:        cmd = (length & DCMD_LENGTH_MASK) | DCMD_INCSRCADDR | DCMD_FLOWTRG
        !           143:            | DCMD_ENDIRQEN;
        !           144:
        !           145:        switch (width) {
        !           146:        case 1:
        !           147:                cmd |= DCMD_WIDTH_1;
        !           148:                break;
        !           149:        case 4:
        !           150:                cmd |= DCMD_WIDTH_4;
        !           151:                break;
        !           152:        default:
        !           153:                printf("pxa2x0_dma_to_fifo: bogus width %d", width);
        !           154:                return EINVAL;
        !           155:        }
        !           156:
        !           157:        switch (burstsize) {
        !           158:        case 8:
        !           159:                cmd |= DCMD_SIZE_8;
        !           160:                break;
        !           161:        case 16:
        !           162:                cmd |= DCMD_SIZE_16;
        !           163:                break;
        !           164:        case 32:
        !           165:                cmd |= DCMD_SIZE_32;
        !           166:                break;
        !           167:        default:
        !           168:                printf("pxa2x0_dma_to_fifo: bogus burstsize %d", burstsize);
        !           169:                return EINVAL;
        !           170:        }
        !           171:
        !           172:        /* XXX: abort anything already in progress, hopefully nothing. */
        !           173:        bus_space_write_4(sc->sc_bust, sc->sc_bush, DMAC_DCSR(chan),
        !           174:            DCSR_NODESCFETCH);
        !           175:
        !           176:        /* Save handler for interrupt-on-completion. */
        !           177:        sc->sc_intrhandlers[chan] = intr;
        !           178:        sc->sc_intrargs[chan] = intrarg;
        !           179:
        !           180:        /* Map peripheral to channel for flow control setup. */
        !           181:        bus_space_write_4(sc->sc_bust, sc->sc_bush, DMAC_DRCMR(periph),
        !           182:            chan | DRCMR_MAPVLD);
        !           183:
        !           184:        /* Setup transfer addresses. */
        !           185:        bus_space_write_4(sc->sc_bust, sc->sc_bush, DMAC_DDADR(chan),
        !           186:            DDADR_STOP);
        !           187:        bus_space_write_4(sc->sc_bust, sc->sc_bush, DMAC_DSADR(chan),
        !           188:            src_addr);
        !           189:        bus_space_write_4(sc->sc_bust, sc->sc_bush, DMAC_DTADR(chan),
        !           190:            fifo_addr);
        !           191:        bus_space_write_4(sc->sc_bust, sc->sc_bush, DMAC_DCMD(chan),
        !           192:            cmd);
        !           193:
        !           194:        /* Start the transfer. */
        !           195:        bus_space_write_4(sc->sc_bust, sc->sc_bush, DMAC_DCSR(chan),
        !           196:            DCSR_RUN | DCSR_NODESCFETCH);
        !           197:
        !           198:        return 0;
        !           199: }
        !           200:
        !           201: /* Perform non-descriptor based DMA from a FIFO */
        !           202: int
        !           203: pxa2x0_dma_from_fifo(int periph, int chan, bus_addr_t fifo_addr, int width,
        !           204:     int burstsize, bus_addr_t trg_addr, int length, void (*intr)(void *),
        !           205:     void *intrarg)
        !           206: {
        !           207:        struct pxadmac_softc *sc = pxadmac_softc;
        !           208:        uint32_t cmd;
        !           209:
        !           210:        if (periph < 0 || periph > 63 || periph == 23) {
        !           211:                printf("pxa2x0_dma_from_fifo: bogus peripheral %d", periph);
        !           212:                return EINVAL;
        !           213:        }
        !           214:
        !           215:        if (chan < 0 || chan >= sc->sc_nchan) {
        !           216:                printf("pxa2x0_dma_from_fifo: bogus dma channel %d", chan);
        !           217:                return EINVAL;
        !           218:        }
        !           219:
        !           220:        if (length < 0 || length > DCMD_LENGTH_MASK) {
        !           221:                printf("pxa2x0_dma_from_fifo: bogus length %d", length);
        !           222:                return EINVAL;
        !           223:        }
        !           224:
        !           225:        cmd = (length & DCMD_LENGTH_MASK) | DCMD_INCTRGADDR | DCMD_FLOWSRC
        !           226:            | DCMD_ENDIRQEN;
        !           227:
        !           228:        switch (width) {
        !           229:        case 1:
        !           230:                cmd |= DCMD_WIDTH_1;
        !           231:                break;
        !           232:        case 4:
        !           233:                cmd |= DCMD_WIDTH_4;
        !           234:                break;
        !           235:        default:
        !           236:                printf("pxa2x0_dma_from_fifo: bogus width %d", width);
        !           237:                return EINVAL;
        !           238:        }
        !           239:
        !           240:        switch (burstsize) {
        !           241:        case 8:
        !           242:                cmd |= DCMD_SIZE_8;
        !           243:                break;
        !           244:        case 16:
        !           245:                cmd |= DCMD_SIZE_16;
        !           246:                break;
        !           247:        case 32:
        !           248:                cmd |= DCMD_SIZE_32;
        !           249:                break;
        !           250:        default:
        !           251:                printf("pxa2x0_dma_from_fifo: bogus burstsize %d", burstsize);
        !           252:                return EINVAL;
        !           253:        }
        !           254:
        !           255:        /* XXX: abort anything already in progress, hopefully nothing. */
        !           256:        bus_space_write_4(sc->sc_bust, sc->sc_bush, DMAC_DCSR(chan),
        !           257:            DCSR_NODESCFETCH);
        !           258:
        !           259:        /* Save handler for interrupt-on-completion. */
        !           260:        sc->sc_intrhandlers[chan] = intr;
        !           261:        sc->sc_intrargs[chan] = intrarg;
        !           262:
        !           263:        /* Map peripheral to channel for flow control setup. */
        !           264:        bus_space_write_4(sc->sc_bust, sc->sc_bush, DMAC_DRCMR(periph),
        !           265:            chan | DRCMR_MAPVLD);
        !           266:
        !           267:        /* Setup transfer addresses. */
        !           268:        bus_space_write_4(sc->sc_bust, sc->sc_bush, DMAC_DDADR(chan),
        !           269:            DDADR_STOP);
        !           270:        bus_space_write_4(sc->sc_bust, sc->sc_bush, DMAC_DSADR(chan),
        !           271:            fifo_addr);
        !           272:        bus_space_write_4(sc->sc_bust, sc->sc_bush, DMAC_DTADR(chan),
        !           273:            trg_addr);
        !           274:        bus_space_write_4(sc->sc_bust, sc->sc_bush, DMAC_DCMD(chan),
        !           275:            cmd);
        !           276:
        !           277:        /* Start the transfer. */
        !           278:        bus_space_write_4(sc->sc_bust, sc->sc_bush, DMAC_DCSR(chan),
        !           279:            DCSR_RUN | DCSR_NODESCFETCH);
        !           280:
        !           281:        return 0;
        !           282: }
        !           283:
        !           284: int
        !           285: pxadmac_intr(void *v)
        !           286: {
        !           287:        struct pxadmac_softc *sc = v;
        !           288:        u_int32_t dint, dcsr;
        !           289:        int chan;
        !           290:
        !           291:        /* Interrupt for us? */
        !           292:        dint = bus_space_read_4(sc->sc_bust, sc->sc_bush, DMAC_DINT);
        !           293:        if (!dint)
        !           294:                return 0;
        !           295:
        !           296:        /* Process individual channels and run handlers. */
        !           297:        /* XXX: this does not respect priority order for channels. */
        !           298:        for (chan = 0; dint != 0 && chan < 32; chan++) {
        !           299:                /* Don't ack channels that weren't ready at call time. */
        !           300:                if ((dint & (1 << chan)) == 0)
        !           301:                        continue;
        !           302:                dint &= ~(1 << chan);
        !           303:
        !           304:                /* Acknowledge individual channel interrupt. */
        !           305:                dcsr = bus_space_read_4(sc->sc_bust, sc->sc_bush,
        !           306:                    DMAC_DCSR(chan));
        !           307:                bus_space_write_4(sc->sc_bust, sc->sc_bush, DMAC_DCSR(chan),
        !           308:                    dcsr & 0x7C80021F);
        !           309:
        !           310:                /* Call the registered handler. */
        !           311:                if (sc->sc_intrhandlers[chan])
        !           312:                        sc->sc_intrhandlers[chan](sc->sc_intrargs[chan]);
        !           313:        }
        !           314:
        !           315:        return 1;
        !           316: }

CVSweb