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