Home | History | Annotate | Line # | Download | only in isa
isadma.c revision 1.10.44.1
      1  1.10.44.1      yamt /*	$NetBSD: isadma.c,v 1.10.44.1 2009/05/04 08:10:37 yamt Exp $	*/
      2        1.1      soda /*	$OpenBSD: isadma.c,v 1.2 1996/11/23 21:45:34 kstailey Exp $	*/
      3        1.2      soda /*	NetBSD: isadma.c,v 1.19 1996/04/29 20:03:26 christos Exp 	*/
      4        1.7     lukem 
      5        1.7     lukem #include <sys/cdefs.h>
      6  1.10.44.1      yamt __KERNEL_RCSID(0, "$NetBSD: isadma.c,v 1.10.44.1 2009/05/04 08:10:37 yamt Exp $");
      7        1.1      soda 
      8        1.1      soda #include <sys/param.h>
      9        1.1      soda #include <sys/systm.h>
     10        1.1      soda #include <sys/device.h>
     11        1.1      soda #include <sys/file.h>
     12        1.1      soda #include <sys/buf.h>
     13        1.1      soda #include <sys/syslog.h>
     14        1.1      soda #include <sys/malloc.h>
     15        1.1      soda #include <sys/uio.h>
     16        1.1      soda 
     17        1.4       mrg #include <uvm/uvm_extern.h>
     18        1.1      soda 
     19        1.1      soda #include <machine/pio.h>
     20        1.1      soda 
     21        1.1      soda #include <dev/isa/isareg.h>
     22        1.1      soda #include <dev/isa/isavar.h>
     23        1.1      soda #include <dev/isa/isadmavar.h>
     24        1.1      soda #include <arch/arc/isa/isadmareg.h> /*XXX*/
     25        1.1      soda 
     26        1.1      soda struct dma_info {
     27        1.1      soda 	int flags;
     28        1.1      soda 	int active;
     29       1.10  christos 	void *addr;
     30        1.3      soda 	bus_size_t nbytes;
     31        1.1      soda 	struct isadma_seg phys[1];
     32        1.1      soda };
     33        1.1      soda 
     34        1.1      soda static struct isadma_softc *isadma_sc;	/*XXX ugly */
     35        1.1      soda static struct dma_info dma_info[8];
     36        1.8   tsutsui static uint8_t dma_finished;
     37        1.1      soda 
     38        1.1      soda /* high byte of address is stored in this port for i-th dma channel */
     39        1.1      soda static int dmapageport[2][4] = {
     40        1.1      soda 	{0x87, 0x83, 0x81, 0x82},
     41        1.1      soda 	{0x8f, 0x8b, 0x89, 0x8a}
     42        1.1      soda };
     43        1.1      soda 
     44        1.8   tsutsui static uint8_t dmamode[4] = {
     45        1.1      soda 	DMA37MD_READ | DMA37MD_SINGLE,
     46        1.1      soda 	DMA37MD_WRITE | DMA37MD_SINGLE,
     47        1.1      soda 	DMA37MD_READ | DMA37MD_LOOP,
     48        1.1      soda 	DMA37MD_WRITE | DMA37MD_LOOP
     49        1.1      soda };
     50        1.1      soda 
     51  1.10.44.1      yamt static int isadmamatch(device_t, cfdata_t, void *);
     52  1.10.44.1      yamt static void isadmaattach(device_t, device_t, void *);
     53        1.1      soda 
     54        1.1      soda struct isadma_softc {
     55  1.10.44.1      yamt 	device_t sc_dev;
     56        1.2      soda 	bus_space_tag_t sc_iot;
     57        1.2      soda 	bus_space_handle_t sc_ioh1;
     58        1.2      soda 	bus_space_handle_t sc_ioh2;
     59        1.1      soda }
     60        1.1      soda 
     61  1.10.44.1      yamt CFATTACH_DECL_NEW(isadma, sizeof(struct isadma_softc),
     62        1.6   thorpej     isadmamatch, isadmaattach, NULL, NULL);
     63        1.1      soda 
     64        1.1      soda struct cfdriver isadma_cd = {
     65        1.1      soda 	NULL, "isadma", DV_DULL, 1
     66        1.1      soda };
     67        1.1      soda 
     68  1.10.44.1      yamt static int
     69  1.10.44.1      yamt isadmamatch(device_t parent, cfdata_t cf, void *aux)
     70        1.1      soda {
     71        1.1      soda 	struct isa_attach_args *ia = aux;
     72        1.1      soda 
     73        1.1      soda 	/* Sure we exist */
     74        1.1      soda 	ia->ia_iosize = 0;
     75        1.8   tsutsui 	return 1;
     76        1.1      soda }
     77        1.1      soda 
     78  1.10.44.1      yamt static void
     79  1.10.44.1      yamt isadmaattach(device_t parent, device_t self, void *aux)
     80        1.1      soda {
     81  1.10.44.1      yamt 	struct isadma_softc *sc = device_private(self);
     82        1.1      soda 	struct isa_attach_args *ia = aux;
     83        1.2      soda 	bus_space_tag_t iot;
     84        1.2      soda 	bus_space_handle_t ioh;
     85        1.1      soda 
     86  1.10.44.1      yamt 	sc->sc_dev = self;
     87  1.10.44.1      yamt 
     88  1.10.44.1      yamt 	aprint_normal("\n");
     89        1.1      soda 
     90        1.2      soda 	iot = sc->sc_iot = ia->ia_iot;
     91        1.2      soda 	if (bus_space_map(iot, IO_DMA1, DMA_NREGS, 0, &ioh))
     92  1.10.44.1      yamt 		panic("%s: couldn't map I/O ports", __func__);
     93        1.1      soda 	sc->sc_ioh1 = ioh;
     94        1.2      soda 	if (bus_space_map(iot, IO_DMA2, DMA_NREGS*2, 0, &ioh))
     95  1.10.44.1      yamt 		panic("%s: couldn't map I/O ports", __func__);
     96        1.1      soda 	sc->sc_ioh2 = ioh;
     97        1.1      soda 	isadma_sc = sc;
     98        1.1      soda }
     99        1.1      soda 
    100        1.1      soda /*
    101        1.1      soda  * isadma_cascade(): program 8237 DMA controller channel to accept
    102        1.1      soda  * external dma control by a board.
    103        1.1      soda  */
    104        1.1      soda void
    105        1.8   tsutsui isadma_cascade(int chan)
    106        1.1      soda {
    107        1.1      soda 	struct isadma_softc *sc = isadma_sc;
    108        1.2      soda 	bus_space_tag_t iot = sc->sc_iot;
    109        1.1      soda 
    110        1.1      soda #ifdef ISADMA_DEBUG
    111        1.1      soda 	if (chan < 0 || chan > 7)
    112  1.10.44.1      yamt 		panic("%s: impossible request", __func__);
    113        1.1      soda #endif
    114        1.1      soda 
    115        1.1      soda 	/* set dma channel mode, and set dma channel mode */
    116        1.1      soda 	if ((chan & 4) == 0) {
    117        1.8   tsutsui 		bus_space_write_1(iot, sc->sc_ioh1, DMA1_MODE,
    118        1.8   tsutsui 		    chan | DMA37MD_CASCADE);
    119        1.2      soda 		bus_space_write_1(iot, sc->sc_ioh1, DMA1_SMSK, chan);
    120        1.1      soda 	} else {
    121        1.1      soda 		chan &= 3;
    122        1.1      soda 
    123        1.8   tsutsui 		bus_space_write_1(iot, sc->sc_ioh2, DMA2_MODE,
    124        1.8   tsutsui 		    chan | DMA37MD_CASCADE);
    125        1.2      soda 		bus_space_write_1(iot, sc->sc_ioh2, DMA2_SMSK, chan);
    126        1.1      soda 	}
    127        1.1      soda }
    128        1.1      soda 
    129        1.1      soda /*
    130        1.1      soda  * isadma_start(): program 8237 DMA controller channel, avoid page alignment
    131        1.1      soda  * problems by using a bounce buffer.
    132        1.1      soda  */
    133        1.1      soda void
    134       1.10  christos isadma_start(void *addr, bus_size_t nbytes, int chan, int flags)
    135        1.1      soda {
    136        1.1      soda 	struct dma_info *di;
    137        1.1      soda 	int waport;
    138        1.1      soda 	int mflags;
    139        1.1      soda 	struct isadma_softc *sc = isadma_sc;
    140        1.2      soda 	bus_space_tag_t iot = sc->sc_iot;
    141        1.2      soda 	bus_space_handle_t ioh;
    142        1.1      soda 
    143        1.1      soda #ifdef ISADMA_DEBUG
    144        1.1      soda 	if (chan < 0 || chan > 7 ||
    145        1.1      soda 	    (((flags & DMAMODE_READ) != 0) + ((flags & DMAMODE_WRITE) != 0) +
    146        1.1      soda 	    ((flags & DMAMODE_LOOP) != 0) != 1) ||
    147        1.1      soda 	    ((chan & 4) ? (nbytes >= (1<<17) || nbytes & 1 || (u_int)addr & 1) :
    148        1.1      soda 	    (nbytes >= (1<<16))))
    149  1.10.44.1      yamt 		panic("%s: impossible request", __func__);
    150        1.1      soda #endif
    151        1.1      soda 
    152        1.1      soda 	di = dma_info+chan;
    153        1.1      soda 	if (di->active) {
    154  1.10.44.1      yamt 		log(LOG_ERR,"%s: old request active on %d\n", __func__, chan);
    155        1.1      soda 		isadma_abort(chan);
    156        1.1      soda 	}
    157        1.1      soda 
    158        1.1      soda 	di->flags = flags;
    159        1.1      soda 	di->active = 1;
    160        1.1      soda 	di->addr = addr;
    161        1.1      soda 	di->nbytes = nbytes;
    162        1.1      soda 
    163        1.1      soda 	mflags = ISADMA_MAP_WAITOK | ISADMA_MAP_BOUNCE | ISADMA_MAP_CONTIG;
    164        1.1      soda 	mflags |= (chan & 4) ? ISADMA_MAP_16BIT : ISADMA_MAP_8BIT;
    165        1.1      soda 
    166        1.1      soda 	if (isadma_map(addr, nbytes, di->phys, mflags) != 1)
    167  1.10.44.1      yamt 		panic("%s: cannot map", __func__);
    168        1.1      soda 
    169        1.1      soda 	/* XXX Will this do what we want with DMAMODE_LOOP?  */
    170        1.1      soda 	if ((flags & DMAMODE_READ) == 0)
    171        1.1      soda 		isadma_copytobuf(addr, nbytes, 1, di->phys);
    172        1.1      soda 
    173        1.1      soda 	dma_finished &= ~(1 << chan);
    174        1.1      soda 
    175        1.1      soda 	if ((chan & 4) == 0) {
    176        1.1      soda 		ioh = sc->sc_ioh1;
    177        1.1      soda 		/*
    178        1.1      soda 		 * Program one of DMA channels 0..3.  These are
    179        1.1      soda 		 * byte mode channels.
    180        1.1      soda 		 */
    181        1.1      soda 		/* set dma channel mode, and reset address ff */
    182        1.2      soda 		bus_space_write_1(iot, ioh, DMA1_MODE, chan | dmamode[flags]);
    183        1.2      soda 		bus_space_write_1(iot, ioh, DMA1_FFC, 0);
    184        1.1      soda 
    185        1.1      soda 		/* send start address */
    186        1.1      soda 		waport = DMA1_CHN(chan);
    187        1.1      soda 		outb(dmapageport[0][chan], di->phys[0].addr>>16);
    188        1.1      soda 		outb(waport, di->phys[0].addr);
    189        1.1      soda 		outb(waport, di->phys[0].addr>>8);
    190        1.1      soda 
    191        1.1      soda 		/* send count */
    192        1.1      soda 		outb(waport + 1, --nbytes);
    193        1.1      soda 		outb(waport + 1, nbytes>>8);
    194        1.1      soda 
    195        1.1      soda 		/* unmask channel */
    196        1.2      soda 		bus_space_write_1(iot, ioh, DMA1_SMSK, chan | DMA37SM_CLEAR);
    197        1.1      soda 	} else {
    198        1.1      soda 		ioh = sc->sc_ioh2;
    199        1.1      soda 		/*
    200        1.1      soda 		 * Program one of DMA channels 4..7.  These are
    201        1.1      soda 		 * word mode channels.
    202        1.1      soda 		 */
    203        1.1      soda 		/* set dma channel mode, and reset address ff */
    204        1.8   tsutsui 		bus_space_write_1(iot, ioh, DMA2_MODE,
    205        1.8   tsutsui 		    (chan & 3) | dmamode[flags]);
    206        1.2      soda 		bus_space_write_1(iot, ioh, DMA2_FFC, 0);
    207        1.1      soda 
    208        1.1      soda 		/* send start address */
    209        1.1      soda 		waport = DMA2_CHN(chan & 3);
    210  1.10.44.1      yamt 		outb(dmapageport[1][chan], di->phys[0].addr >> 16);
    211  1.10.44.1      yamt 		outb(waport, di->phys[0].addr >> 1);
    212  1.10.44.1      yamt 		outb(waport, di->phys[0].addr >> 9);
    213        1.1      soda 
    214        1.1      soda 		/* send count */
    215        1.1      soda 		nbytes >>= 1;
    216        1.1      soda 		outb(waport + 2, --nbytes);
    217        1.1      soda 		outb(waport + 2, nbytes>>8);
    218        1.1      soda 
    219        1.1      soda 		/* unmask channel */
    220        1.8   tsutsui 		bus_space_write_1(iot, ioh, DMA2_SMSK,
    221        1.8   tsutsui 		    (chan & 3) | DMA37SM_CLEAR);
    222        1.1      soda 	}
    223        1.1      soda }
    224        1.1      soda 
    225        1.1      soda void
    226        1.8   tsutsui isadma_abort(int chan)
    227        1.1      soda {
    228        1.1      soda 	struct dma_info *di;
    229        1.1      soda 	struct isadma_softc *sc = isadma_sc;
    230        1.2      soda 	bus_space_tag_t iot = sc->sc_iot;
    231        1.1      soda 
    232        1.1      soda #ifdef ISADMA_DEBUG
    233        1.1      soda 	if (chan < 0 || chan > 7)
    234  1.10.44.1      yamt 		panic("%s: impossible request", __func__);
    235        1.1      soda #endif
    236        1.1      soda 
    237        1.1      soda 	di = dma_info+chan;
    238        1.1      soda 	if (! di->active) {
    239  1.10.44.1      yamt 		log(LOG_ERR,"%s: no request active on %d\n", __func__, chan);
    240        1.1      soda 		return;
    241        1.1      soda 	}
    242        1.1      soda 
    243        1.1      soda 	/* mask channel */
    244        1.1      soda 	if ((chan & 4) == 0)
    245        1.8   tsutsui 		bus_space_write_1(iot, sc->sc_ioh1, DMA1_SMSK,
    246        1.8   tsutsui 		    DMA37SM_SET | chan);
    247        1.1      soda 	else
    248        1.8   tsutsui 		bus_space_write_1(iot, sc->sc_ioh2, DMA2_SMSK,
    249        1.8   tsutsui 		    DMA37SM_SET | (chan & 3));
    250        1.1      soda 
    251        1.1      soda 	isadma_unmap(di->addr, di->nbytes, 1, di->phys);
    252        1.1      soda 	di->active = 0;
    253        1.1      soda }
    254        1.1      soda 
    255        1.1      soda int
    256        1.8   tsutsui isadma_finished(int chan)
    257        1.1      soda {
    258        1.1      soda 	struct isadma_softc *sc = isadma_sc;
    259        1.2      soda 	bus_space_tag_t iot = sc->sc_iot;
    260        1.1      soda 
    261        1.1      soda #ifdef ISADMA_DEBUG
    262        1.1      soda 	if (chan < 0 || chan > 7)
    263  1.10.44.1      yamt 		panic("%s: impossible request", __func__);
    264        1.1      soda #endif
    265        1.1      soda 
    266        1.1      soda 	/* check that the terminal count was reached */
    267        1.1      soda 	if ((chan & 4) == 0)
    268        1.8   tsutsui 		dma_finished |=
    269        1.8   tsutsui 		    bus_space_read_1(iot, sc->sc_ioh1, DMA1_SR) & 0x0f;
    270        1.1      soda 	else
    271        1.8   tsutsui 		dma_finished |=
    272        1.8   tsutsui 		    (bus_space_read_1(iot, sc->sc_ioh2, DMA2_SR) & 0x0f) << 4;
    273        1.1      soda 
    274        1.8   tsutsui 	return (dma_finished & (1 << chan)) != 0;
    275        1.1      soda }
    276        1.1      soda 
    277        1.1      soda void
    278        1.8   tsutsui isadma_done(int chan)
    279        1.1      soda {
    280        1.1      soda 	struct dma_info *di;
    281        1.1      soda 	u_char tc;
    282        1.1      soda 	struct isadma_softc *sc = isadma_sc;
    283        1.2      soda 	bus_space_tag_t iot = sc->sc_iot;
    284        1.1      soda 
    285        1.1      soda #ifdef DIAGNOSTIC
    286        1.1      soda 	if (chan < 0 || chan > 7)
    287  1.10.44.1      yamt 		panic("%s: impossible request", __func__);
    288        1.1      soda #endif
    289        1.1      soda 
    290        1.1      soda 	di = dma_info+chan;
    291        1.1      soda 	if (! di->active) {
    292  1.10.44.1      yamt 		log(LOG_ERR,"%s: no request active on %d\n", __func__, chan);
    293        1.1      soda 		return;
    294        1.1      soda 	}
    295        1.1      soda 
    296        1.1      soda 	/* check that the terminal count was reached */
    297        1.1      soda 	if ((chan & 4) == 0)
    298        1.2      soda 		tc = bus_space_read_1(iot, sc->sc_ioh1, DMA1_SR) & (1 << chan);
    299        1.1      soda 	else
    300        1.8   tsutsui 		tc = bus_space_read_1(iot, sc->sc_ioh2, DMA2_SR) &
    301        1.8   tsutsui 		    (1 << (chan & 3));
    302        1.1      soda 	if (tc == 0)
    303        1.1      soda 		/* XXX probably should panic or something */
    304        1.1      soda 		log(LOG_ERR, "dma channel %d not finished\n", chan);
    305        1.1      soda 
    306        1.1      soda 	/* mask channel */
    307        1.1      soda 	if ((chan & 4) == 0)
    308        1.8   tsutsui 		bus_space_write_1(iot, sc->sc_ioh1, DMA1_SMSK,
    309        1.8   tsutsui 		    DMA37SM_SET | chan);
    310        1.1      soda 	else
    311        1.8   tsutsui 		bus_space_write_1(iot, sc->sc_ioh2, DMA2_SMSK,
    312        1.8   tsutsui 		    DMA37SM_SET | (chan & 3));
    313        1.1      soda 
    314        1.1      soda 	/* XXX Will this do what we want with DMAMODE_LOOP?  */
    315        1.1      soda 	if (di->flags & DMAMODE_READ)
    316        1.1      soda 		isadma_copyfrombuf(di->addr, di->nbytes, 1, di->phys);
    317        1.1      soda 
    318        1.1      soda 	isadma_unmap(di->addr, di->nbytes, 1, di->phys);
    319        1.1      soda 	di->active = 0;
    320        1.1      soda }
    321