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