1 /* $NetBSD: isadma.c,v 1.10 2007/03/04 05:59:35 christos 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 */
6 __KERNEL_RCSID(0, "$NetBSD: isadma.c,v 1.10 2007/03/04 05:59:35 christos Exp $");
10 #include <sys/device.h>
13 #include <sys/syslog.h>
14 #include <sys/malloc.h>
17 #include <uvm/uvm_extern.h>
19 #include <machine/pio.h>
21 #include <dev/isa/isareg.h>
22 #include <dev/isa/isavar.h>
23 #include <dev/isa/isadmavar.h>
24 #include <arch/arc/isa/isadmareg.h> /*XXX*/
31 struct isadma_seg phys
[1];
34 static struct isadma_softc
*isadma_sc
; /*XXX ugly */
35 static struct dma_info dma_info
[8];
36 static uint8_t dma_finished
;
38 /* high byte of address is stored in this port for i-th dma channel */
39 static int dmapageport
[2][4] = {
40 {0x87, 0x83, 0x81, 0x82},
41 {0x8f, 0x8b, 0x89, 0x8a}
44 static uint8_t dmamode
[4] = {
45 DMA37MD_READ
| DMA37MD_SINGLE
,
46 DMA37MD_WRITE
| DMA37MD_SINGLE
,
47 DMA37MD_READ
| DMA37MD_LOOP
,
48 DMA37MD_WRITE
| DMA37MD_LOOP
51 static int isadmamatch(device_t
, cfdata_t
, void *);
52 static void isadmaattach(device_t
, device_t
, void *);
56 bus_space_tag_t sc_iot
;
57 bus_space_handle_t sc_ioh1
;
58 bus_space_handle_t sc_ioh2
;
61 CFATTACH_DECL_NEW(isadma
, sizeof(struct isadma_softc
),
62 isadmamatch
, isadmaattach
, NULL
, NULL
);
64 struct cfdriver isadma_cd
= {
65 NULL
, "isadma", DV_DULL
, 1
69 isadmamatch(device_t parent
, cfdata_t cf
, void *aux
)
71 struct isa_attach_args
*ia
= aux
;
79 isadmaattach(device_t parent
, device_t self
, void *aux
)
81 struct isadma_softc
*sc
= device_private(self
);
82 struct isa_attach_args
*ia
= aux
;
84 bus_space_handle_t ioh
;
90 iot
= sc
->sc_iot
= ia
->ia_iot
;
91 if (bus_space_map(iot
, IO_DMA1
, DMA_NREGS
, 0, &ioh
))
92 panic("%s: couldn't map I/O ports", __func__
);
94 if (bus_space_map(iot
, IO_DMA2
, DMA_NREGS
*2, 0, &ioh
))
95 panic("%s: couldn't map I/O ports", __func__
);
101 * isadma_cascade(): program 8237 DMA controller channel to accept
102 * external dma control by a board.
105 isadma_cascade(int chan
)
107 struct isadma_softc
*sc
= isadma_sc
;
108 bus_space_tag_t iot
= sc
->sc_iot
;
111 if (chan
< 0 || chan
> 7)
112 panic("%s: impossible request", __func__
);
115 /* set dma channel mode, and set dma channel mode */
116 if ((chan
& 4) == 0) {
117 bus_space_write_1(iot
, sc
->sc_ioh1
, DMA1_MODE
,
118 chan
| DMA37MD_CASCADE
);
119 bus_space_write_1(iot
, sc
->sc_ioh1
, DMA1_SMSK
, chan
);
123 bus_space_write_1(iot
, sc
->sc_ioh2
, DMA2_MODE
,
124 chan
| DMA37MD_CASCADE
);
125 bus_space_write_1(iot
, sc
->sc_ioh2
, DMA2_SMSK
, chan
);
130 * isadma_start(): program 8237 DMA controller channel, avoid page alignment
131 * problems by using a bounce buffer.
134 isadma_start(void *addr
, bus_size_t nbytes
, int chan
, int flags
)
139 struct isadma_softc
*sc
= isadma_sc
;
140 bus_space_tag_t iot
= sc
->sc_iot
;
141 bus_space_handle_t ioh
;
144 if (chan
< 0 || chan
> 7 ||
145 (((flags
& DMAMODE_READ
) != 0) + ((flags
& DMAMODE_WRITE
) != 0) +
146 ((flags
& DMAMODE_LOOP
) != 0) != 1) ||
147 ((chan
& 4) ? (nbytes
>= (1<<17) || nbytes
& 1 || (u_int
)addr
& 1) :
148 (nbytes
>= (1<<16))))
149 panic("%s: impossible request", __func__
);
154 log(LOG_ERR
,"%s: old request active on %d\n", __func__
, chan
);
163 mflags
= ISADMA_MAP_WAITOK
| ISADMA_MAP_BOUNCE
| ISADMA_MAP_CONTIG
;
164 mflags
|= (chan
& 4) ? ISADMA_MAP_16BIT
: ISADMA_MAP_8BIT
;
166 if (isadma_map(addr
, nbytes
, di
->phys
, mflags
) != 1)
167 panic("%s: cannot map", __func__
);
169 /* XXX Will this do what we want with DMAMODE_LOOP? */
170 if ((flags
& DMAMODE_READ
) == 0)
171 isadma_copytobuf(addr
, nbytes
, 1, di
->phys
);
173 dma_finished
&= ~(1 << chan
);
175 if ((chan
& 4) == 0) {
178 * Program one of DMA channels 0..3. These are
179 * byte mode channels.
181 /* set dma channel mode, and reset address ff */
182 bus_space_write_1(iot
, ioh
, DMA1_MODE
, chan
| dmamode
[flags
]);
183 bus_space_write_1(iot
, ioh
, DMA1_FFC
, 0);
185 /* send start address */
186 waport
= DMA1_CHN(chan
);
187 outb(dmapageport
[0][chan
], di
->phys
[0].addr
>>16);
188 outb(waport
, di
->phys
[0].addr
);
189 outb(waport
, di
->phys
[0].addr
>>8);
192 outb(waport
+ 1, --nbytes
);
193 outb(waport
+ 1, nbytes
>>8);
196 bus_space_write_1(iot
, ioh
, DMA1_SMSK
, chan
| DMA37SM_CLEAR
);
200 * Program one of DMA channels 4..7. These are
201 * word mode channels.
203 /* set dma channel mode, and reset address ff */
204 bus_space_write_1(iot
, ioh
, DMA2_MODE
,
205 (chan
& 3) | dmamode
[flags
]);
206 bus_space_write_1(iot
, ioh
, DMA2_FFC
, 0);
208 /* send start address */
209 waport
= DMA2_CHN(chan
& 3);
210 outb(dmapageport
[1][chan
], di
->phys
[0].addr
>> 16);
211 outb(waport
, di
->phys
[0].addr
>> 1);
212 outb(waport
, di
->phys
[0].addr
>> 9);
216 outb(waport
+ 2, --nbytes
);
217 outb(waport
+ 2, nbytes
>>8);
220 bus_space_write_1(iot
, ioh
, DMA2_SMSK
,
221 (chan
& 3) | DMA37SM_CLEAR
);
226 isadma_abort(int chan
)
229 struct isadma_softc
*sc
= isadma_sc
;
230 bus_space_tag_t iot
= sc
->sc_iot
;
233 if (chan
< 0 || chan
> 7)
234 panic("%s: impossible request", __func__
);
239 log(LOG_ERR
,"%s: no request active on %d\n", __func__
, chan
);
245 bus_space_write_1(iot
, sc
->sc_ioh1
, DMA1_SMSK
,
248 bus_space_write_1(iot
, sc
->sc_ioh2
, DMA2_SMSK
,
249 DMA37SM_SET
| (chan
& 3));
251 isadma_unmap(di
->addr
, di
->nbytes
, 1, di
->phys
);
256 isadma_finished(int chan
)
258 struct isadma_softc
*sc
= isadma_sc
;
259 bus_space_tag_t iot
= sc
->sc_iot
;
262 if (chan
< 0 || chan
> 7)
263 panic("%s: impossible request", __func__
);
266 /* check that the terminal count was reached */
269 bus_space_read_1(iot
, sc
->sc_ioh1
, DMA1_SR
) & 0x0f;
272 (bus_space_read_1(iot
, sc
->sc_ioh2
, DMA2_SR
) & 0x0f) << 4;
274 return (dma_finished
& (1 << chan
)) != 0;
278 isadma_done(int chan
)
282 struct isadma_softc
*sc
= isadma_sc
;
283 bus_space_tag_t iot
= sc
->sc_iot
;
286 if (chan
< 0 || chan
> 7)
287 panic("%s: impossible request", __func__
);
292 log(LOG_ERR
,"%s: no request active on %d\n", __func__
, chan
);
296 /* check that the terminal count was reached */
298 tc
= bus_space_read_1(iot
, sc
->sc_ioh1
, DMA1_SR
) & (1 << chan
);
300 tc
= bus_space_read_1(iot
, sc
->sc_ioh2
, DMA2_SR
) &
303 /* XXX probably should panic or something */
304 log(LOG_ERR
, "dma channel %d not finished\n", chan
);
308 bus_space_write_1(iot
, sc
->sc_ioh1
, DMA1_SMSK
,
311 bus_space_write_1(iot
, sc
->sc_ioh2
, DMA2_SMSK
,
312 DMA37SM_SET
| (chan
& 3));
314 /* XXX Will this do what we want with DMAMODE_LOOP? */
315 if (di
->flags
& DMAMODE_READ
)
316 isadma_copyfrombuf(di
->addr
, di
->nbytes
, 1, di
->phys
);
318 isadma_unmap(di
->addr
, di
->nbytes
, 1, di
->phys
);