2 * linux/arch/arm/mach-rpc/dma.c
4 * Copyright (C) 1998 Russell King
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
10 * DMA functions specific to RiscPC architecture
12 #include <linux/slab.h>
13 #include <linux/mman.h>
14 #include <linux/init.h>
15 #include <linux/interrupt.h>
16 #include <linux/dma-mapping.h>
23 #include <asm/hardware.h>
24 #include <asm/uaccess.h>
26 #include <asm/mach/dma.h>
27 #include <asm/hardware/iomd.h>
38 #define TRANSFER_SIZE 2
41 #define ENDA (IOMD_IO0ENDA - IOMD_IO0CURA)
42 #define CURB (IOMD_IO0CURB - IOMD_IO0CURA)
43 #define ENDB (IOMD_IO0ENDB - IOMD_IO0CURA)
44 #define CR (IOMD_IO0CR - IOMD_IO0CURA)
45 #define ST (IOMD_IO0ST - IOMD_IO0CURA)
47 static void iomd_get_next_sg(struct scatterlist
*sg
, dma_t
*dma
)
49 unsigned long end
, offset
, flags
= 0;
52 sg
->dma_address
= dma
->sg
->dma_address
;
53 offset
= sg
->dma_address
& ~PAGE_MASK
;
55 end
= offset
+ dma
->sg
->length
;
60 if (offset
+ TRANSFER_SIZE
>= end
)
63 sg
->length
= end
- TRANSFER_SIZE
;
65 dma
->sg
->length
-= end
- offset
;
66 dma
->sg
->dma_address
+= end
- offset
;
68 if (dma
->sg
->length
== 0) {
69 if (dma
->sgcount
> 1) {
78 flags
= DMA_END_S
| DMA_END_L
;
86 static irqreturn_t
iomd_dma_handle(int irq
, void *dev_id
, struct pt_regs
*regs
)
88 dma_t
*dma
= (dma_t
*)dev_id
;
89 unsigned long base
= dma
->dma_base
;
94 status
= iomd_readb(base
+ ST
);
95 if (!(status
& DMA_ST_INT
))
98 if ((dma
->state
^ status
) & DMA_ST_AB
)
99 iomd_get_next_sg(&dma
->cur_sg
, dma
);
101 switch (status
& (DMA_ST_OFL
| DMA_ST_AB
)) {
102 case DMA_ST_OFL
: /* OIA */
103 case DMA_ST_AB
: /* .IB */
104 iomd_writel(dma
->cur_sg
.dma_address
, base
+ CURA
);
105 iomd_writel(dma
->cur_sg
.length
, base
+ ENDA
);
106 dma
->state
= DMA_ST_AB
;
109 case DMA_ST_OFL
| DMA_ST_AB
: /* OIB */
111 iomd_writel(dma
->cur_sg
.dma_address
, base
+ CURB
);
112 iomd_writel(dma
->cur_sg
.length
, base
+ ENDB
);
117 if (status
& DMA_ST_OFL
&&
118 dma
->cur_sg
.length
== (DMA_END_S
|DMA_END_L
))
122 dma
->state
= ~DMA_ST_AB
;
128 static int iomd_request_dma(dmach_t channel
, dma_t
*dma
)
130 return request_irq(dma
->dma_irq
, iomd_dma_handle
,
131 SA_INTERRUPT
, dma
->device_id
, dma
);
134 static void iomd_free_dma(dmach_t channel
, dma_t
*dma
)
136 free_irq(dma
->dma_irq
, dma
);
139 static void iomd_enable_dma(dmach_t channel
, dma_t
*dma
)
141 unsigned long dma_base
= dma
->dma_base
;
142 unsigned int ctrl
= TRANSFER_SIZE
| DMA_CR_E
;
148 * Cope with ISA-style drivers which expect cache
154 dma
->buf
.length
= dma
->count
;
155 dma
->buf
.dma_address
= dma_map_single(NULL
,
156 dma
->addr
, dma
->count
,
157 dma
->dma_mode
== DMA_MODE_READ
?
158 DMA_FROM_DEVICE
: DMA_TO_DEVICE
);
161 iomd_writeb(DMA_CR_C
, dma_base
+ CR
);
162 dma
->state
= DMA_ST_AB
;
165 if (dma
->dma_mode
== DMA_MODE_READ
)
168 iomd_writeb(ctrl
, dma_base
+ CR
);
169 enable_irq(dma
->dma_irq
);
172 static void iomd_disable_dma(dmach_t channel
, dma_t
*dma
)
174 unsigned long dma_base
= dma
->dma_base
;
177 local_irq_save(flags
);
178 if (dma
->state
!= ~DMA_ST_AB
)
179 disable_irq(dma
->dma_irq
);
180 iomd_writeb(0, dma_base
+ CR
);
181 local_irq_restore(flags
);
184 static int iomd_set_dma_speed(dmach_t channel
, dma_t
*dma
, int cycle
)
190 else if (cycle
<= 250)
192 else if (cycle
< 438)
197 tcr
= iomd_readb(IOMD_DMATCR
);
202 tcr
= (tcr
& ~0x03) | speed
;
206 tcr
= (tcr
& ~0x0c) | (speed
<< 2);
210 tcr
= (tcr
& ~0x30) | (speed
<< 4);
214 tcr
= (tcr
& ~0xc0) | (speed
<< 6);
221 iomd_writeb(tcr
, IOMD_DMATCR
);
226 static struct dma_ops iomd_dma_ops
= {
228 .request
= iomd_request_dma
,
229 .free
= iomd_free_dma
,
230 .enable
= iomd_enable_dma
,
231 .disable
= iomd_disable_dma
,
232 .setspeed
= iomd_set_dma_speed
,
235 static struct fiq_handler fh
= {
239 static void floppy_enable_dma(dmach_t channel
, dma_t
*dma
)
241 void *fiqhandler_start
;
242 unsigned int fiqhandler_length
;
248 if (dma
->dma_mode
== DMA_MODE_READ
) {
249 extern unsigned char floppy_fiqin_start
, floppy_fiqin_end
;
250 fiqhandler_start
= &floppy_fiqin_start
;
251 fiqhandler_length
= &floppy_fiqin_end
- &floppy_fiqin_start
;
253 extern unsigned char floppy_fiqout_start
, floppy_fiqout_end
;
254 fiqhandler_start
= &floppy_fiqout_start
;
255 fiqhandler_length
= &floppy_fiqout_end
- &floppy_fiqout_start
;
258 regs
.ARM_r9
= dma
->count
;
259 regs
.ARM_r10
= (unsigned long)dma
->addr
;
260 regs
.ARM_fp
= (unsigned long)FLOPPYDMA_BASE
;
262 if (claim_fiq(&fh
)) {
263 printk("floppydma: couldn't claim FIQ.\n");
267 set_fiq_handler(fiqhandler_start
, fiqhandler_length
);
269 enable_fiq(dma
->dma_irq
);
272 static void floppy_disable_dma(dmach_t channel
, dma_t
*dma
)
274 disable_fiq(dma
->dma_irq
);
278 static int floppy_get_residue(dmach_t channel
, dma_t
*dma
)
285 static struct dma_ops floppy_dma_ops
= {
287 .enable
= floppy_enable_dma
,
288 .disable
= floppy_disable_dma
,
289 .residue
= floppy_get_residue
,
293 * This is virtual DMA - we don't need anything here.
295 static void sound_enable_disable_dma(dmach_t channel
, dma_t
*dma
)
299 static struct dma_ops sound_dma_ops
= {
301 .enable
= sound_enable_disable_dma
,
302 .disable
= sound_enable_disable_dma
,
305 void __init
arch_dma_init(dma_t
*dma
)
307 iomd_writeb(0, IOMD_IO0CR
);
308 iomd_writeb(0, IOMD_IO1CR
);
309 iomd_writeb(0, IOMD_IO2CR
);
310 iomd_writeb(0, IOMD_IO3CR
);
312 iomd_writeb(0xa0, IOMD_DMATCR
);
314 dma
[DMA_0
].dma_base
= IOMD_IO0CURA
;
315 dma
[DMA_0
].dma_irq
= IRQ_DMA0
;
316 dma
[DMA_0
].d_ops
= &iomd_dma_ops
;
317 dma
[DMA_1
].dma_base
= IOMD_IO1CURA
;
318 dma
[DMA_1
].dma_irq
= IRQ_DMA1
;
319 dma
[DMA_1
].d_ops
= &iomd_dma_ops
;
320 dma
[DMA_2
].dma_base
= IOMD_IO2CURA
;
321 dma
[DMA_2
].dma_irq
= IRQ_DMA2
;
322 dma
[DMA_2
].d_ops
= &iomd_dma_ops
;
323 dma
[DMA_3
].dma_base
= IOMD_IO3CURA
;
324 dma
[DMA_3
].dma_irq
= IRQ_DMA3
;
325 dma
[DMA_3
].d_ops
= &iomd_dma_ops
;
326 dma
[DMA_S0
].dma_base
= IOMD_SD0CURA
;
327 dma
[DMA_S0
].dma_irq
= IRQ_DMAS0
;
328 dma
[DMA_S0
].d_ops
= &iomd_dma_ops
;
329 dma
[DMA_S1
].dma_base
= IOMD_SD1CURA
;
330 dma
[DMA_S1
].dma_irq
= IRQ_DMAS1
;
331 dma
[DMA_S1
].d_ops
= &iomd_dma_ops
;
332 dma
[DMA_VIRTUAL_FLOPPY
].dma_irq
= FIQ_FLOPPYDATA
;
333 dma
[DMA_VIRTUAL_FLOPPY
].d_ops
= &floppy_dma_ops
;
334 dma
[DMA_VIRTUAL_SOUND
].d_ops
= &sound_dma_ops
;
337 * Setup DMA channels 2,3 to be for podules
338 * and channels 0,1 for internal devices
340 iomd_writeb(DMA_EXT_IO3
|DMA_EXT_IO2
, IOMD_DMAEXT
);