aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-rpc/dma.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-rpc/dma.c')
-rw-r--r--arch/arm/mach-rpc/dma.c213
1 files changed, 131 insertions, 82 deletions
diff --git a/arch/arm/mach-rpc/dma.c b/arch/arm/mach-rpc/dma.c
index 7958a30f8932..c47d974d52bd 100644
--- a/arch/arm/mach-rpc/dma.c
+++ b/arch/arm/mach-rpc/dma.c
@@ -26,6 +26,16 @@
26#include <asm/mach/dma.h> 26#include <asm/mach/dma.h>
27#include <asm/hardware/iomd.h> 27#include <asm/hardware/iomd.h>
28 28
29struct iomd_dma {
30 struct dma_struct dma;
31 unsigned int state;
32 unsigned long base; /* Controller base address */
33 int irq; /* Controller IRQ */
34 struct scatterlist cur_sg; /* Current controller buffer */
35 dma_addr_t dma_addr;
36 unsigned int dma_len;
37};
38
29#if 0 39#if 0
30typedef enum { 40typedef enum {
31 dma_size_8 = 1, 41 dma_size_8 = 1,
@@ -44,15 +54,15 @@ typedef enum {
44#define CR (IOMD_IO0CR - IOMD_IO0CURA) 54#define CR (IOMD_IO0CR - IOMD_IO0CURA)
45#define ST (IOMD_IO0ST - IOMD_IO0CURA) 55#define ST (IOMD_IO0ST - IOMD_IO0CURA)
46 56
47static void iomd_get_next_sg(struct scatterlist *sg, dma_t *dma) 57static void iomd_get_next_sg(struct scatterlist *sg, struct iomd_dma *idma)
48{ 58{
49 unsigned long end, offset, flags = 0; 59 unsigned long end, offset, flags = 0;
50 60
51 if (dma->sg) { 61 if (idma->dma.sg) {
52 sg->dma_address = dma->sg->dma_address; 62 sg->dma_address = idma->dma_addr;
53 offset = sg->dma_address & ~PAGE_MASK; 63 offset = sg->dma_address & ~PAGE_MASK;
54 64
55 end = offset + dma->sg->length; 65 end = offset + idma->dma_len;
56 66
57 if (end > PAGE_SIZE) 67 if (end > PAGE_SIZE)
58 end = PAGE_SIZE; 68 end = PAGE_SIZE;
@@ -62,15 +72,17 @@ static void iomd_get_next_sg(struct scatterlist *sg, dma_t *dma)
62 72
63 sg->length = end - TRANSFER_SIZE; 73 sg->length = end - TRANSFER_SIZE;
64 74
65 dma->sg->length -= end - offset; 75 idma->dma_len -= end - offset;
66 dma->sg->dma_address += end - offset; 76 idma->dma_addr += end - offset;
67 77
68 if (dma->sg->length == 0) { 78 if (idma->dma_len == 0) {
69 if (dma->sgcount > 1) { 79 if (idma->dma.sgcount > 1) {
70 dma->sg++; 80 idma->dma.sg = sg_next(idma->dma.sg);
71 dma->sgcount--; 81 idma->dma_addr = idma->dma.sg->dma_address;
82 idma->dma_len = idma->dma.sg->length;
83 idma->dma.sgcount--;
72 } else { 84 } else {
73 dma->sg = NULL; 85 idma->dma.sg = NULL;
74 flags |= DMA_END_S; 86 flags |= DMA_END_S;
75 } 87 }
76 } 88 }
@@ -85,8 +97,8 @@ static void iomd_get_next_sg(struct scatterlist *sg, dma_t *dma)
85 97
86static irqreturn_t iomd_dma_handle(int irq, void *dev_id) 98static irqreturn_t iomd_dma_handle(int irq, void *dev_id)
87{ 99{
88 dma_t *dma = (dma_t *)dev_id; 100 struct iomd_dma *idma = dev_id;
89 unsigned long base = dma->dma_base; 101 unsigned long base = idma->base;
90 102
91 do { 103 do {
92 unsigned int status; 104 unsigned int status;
@@ -95,93 +107,99 @@ static irqreturn_t iomd_dma_handle(int irq, void *dev_id)
95 if (!(status & DMA_ST_INT)) 107 if (!(status & DMA_ST_INT))
96 return IRQ_HANDLED; 108 return IRQ_HANDLED;
97 109
98 if ((dma->state ^ status) & DMA_ST_AB) 110 if ((idma->state ^ status) & DMA_ST_AB)
99 iomd_get_next_sg(&dma->cur_sg, dma); 111 iomd_get_next_sg(&idma->cur_sg, idma);
100 112
101 switch (status & (DMA_ST_OFL | DMA_ST_AB)) { 113 switch (status & (DMA_ST_OFL | DMA_ST_AB)) {
102 case DMA_ST_OFL: /* OIA */ 114 case DMA_ST_OFL: /* OIA */
103 case DMA_ST_AB: /* .IB */ 115 case DMA_ST_AB: /* .IB */
104 iomd_writel(dma->cur_sg.dma_address, base + CURA); 116 iomd_writel(idma->cur_sg.dma_address, base + CURA);
105 iomd_writel(dma->cur_sg.length, base + ENDA); 117 iomd_writel(idma->cur_sg.length, base + ENDA);
106 dma->state = DMA_ST_AB; 118 idma->state = DMA_ST_AB;
107 break; 119 break;
108 120
109 case DMA_ST_OFL | DMA_ST_AB: /* OIB */ 121 case DMA_ST_OFL | DMA_ST_AB: /* OIB */
110 case 0: /* .IA */ 122 case 0: /* .IA */
111 iomd_writel(dma->cur_sg.dma_address, base + CURB); 123 iomd_writel(idma->cur_sg.dma_address, base + CURB);
112 iomd_writel(dma->cur_sg.length, base + ENDB); 124 iomd_writel(idma->cur_sg.length, base + ENDB);
113 dma->state = 0; 125 idma->state = 0;
114 break; 126 break;
115 } 127 }
116 128
117 if (status & DMA_ST_OFL && 129 if (status & DMA_ST_OFL &&
118 dma->cur_sg.length == (DMA_END_S|DMA_END_L)) 130 idma->cur_sg.length == (DMA_END_S|DMA_END_L))
119 break; 131 break;
120 } while (1); 132 } while (1);
121 133
122 dma->state = ~DMA_ST_AB; 134 idma->state = ~DMA_ST_AB;
123 disable_irq(irq); 135 disable_irq(irq);
124 136
125 return IRQ_HANDLED; 137 return IRQ_HANDLED;
126} 138}
127 139
128static int iomd_request_dma(dmach_t channel, dma_t *dma) 140static int iomd_request_dma(unsigned int chan, dma_t *dma)
129{ 141{
130 return request_irq(dma->dma_irq, iomd_dma_handle, 142 struct iomd_dma *idma = container_of(dma, struct iomd_dma, dma);
131 IRQF_DISABLED, dma->device_id, dma); 143
144 return request_irq(idma->irq, iomd_dma_handle,
145 IRQF_DISABLED, idma->dma.device_id, idma);
132} 146}
133 147
134static void iomd_free_dma(dmach_t channel, dma_t *dma) 148static void iomd_free_dma(unsigned int chan, dma_t *dma)
135{ 149{
136 free_irq(dma->dma_irq, dma); 150 struct iomd_dma *idma = container_of(dma, struct iomd_dma, dma);
151
152 free_irq(idma->irq, idma);
137} 153}
138 154
139static void iomd_enable_dma(dmach_t channel, dma_t *dma) 155static void iomd_enable_dma(unsigned int chan, dma_t *dma)
140{ 156{
141 unsigned long dma_base = dma->dma_base; 157 struct iomd_dma *idma = container_of(dma, struct iomd_dma, dma);
158 unsigned long dma_base = idma->base;
142 unsigned int ctrl = TRANSFER_SIZE | DMA_CR_E; 159 unsigned int ctrl = TRANSFER_SIZE | DMA_CR_E;
143 160
144 if (dma->invalid) { 161 if (idma->dma.invalid) {
145 dma->invalid = 0; 162 idma->dma.invalid = 0;
146 163
147 /* 164 /*
148 * Cope with ISA-style drivers which expect cache 165 * Cope with ISA-style drivers which expect cache
149 * coherence. 166 * coherence.
150 */ 167 */
151 if (!dma->sg) { 168 if (!idma->dma.sg) {
152 dma->sg = &dma->buf; 169 idma->dma.sg = &idma->dma.buf;
153 dma->sgcount = 1; 170 idma->dma.sgcount = 1;
154 dma->buf.length = dma->count; 171 idma->dma.buf.length = idma->dma.count;
155 dma->buf.dma_address = dma_map_single(NULL, 172 idma->dma.buf.dma_address = dma_map_single(NULL,
156 dma->addr, dma->count, 173 idma->dma.addr, idma->dma.count,
157 dma->dma_mode == DMA_MODE_READ ? 174 idma->dma.dma_mode == DMA_MODE_READ ?
158 DMA_FROM_DEVICE : DMA_TO_DEVICE); 175 DMA_FROM_DEVICE : DMA_TO_DEVICE);
159 } 176 }
160 177
161 iomd_writeb(DMA_CR_C, dma_base + CR); 178 iomd_writeb(DMA_CR_C, dma_base + CR);
162 dma->state = DMA_ST_AB; 179 idma->state = DMA_ST_AB;
163 } 180 }
164 181
165 if (dma->dma_mode == DMA_MODE_READ) 182 if (idma->dma.dma_mode == DMA_MODE_READ)
166 ctrl |= DMA_CR_D; 183 ctrl |= DMA_CR_D;
167 184
168 iomd_writeb(ctrl, dma_base + CR); 185 iomd_writeb(ctrl, dma_base + CR);
169 enable_irq(dma->dma_irq); 186 enable_irq(idma->irq);
170} 187}
171 188
172static void iomd_disable_dma(dmach_t channel, dma_t *dma) 189static void iomd_disable_dma(unsigned int chan, dma_t *dma)
173{ 190{
174 unsigned long dma_base = dma->dma_base; 191 struct iomd_dma *idma = container_of(dma, struct iomd_dma, dma);
192 unsigned long dma_base = idma->base;
175 unsigned long flags; 193 unsigned long flags;
176 194
177 local_irq_save(flags); 195 local_irq_save(flags);
178 if (dma->state != ~DMA_ST_AB) 196 if (idma->state != ~DMA_ST_AB)
179 disable_irq(dma->dma_irq); 197 disable_irq(idma->irq);
180 iomd_writeb(0, dma_base + CR); 198 iomd_writeb(0, dma_base + CR);
181 local_irq_restore(flags); 199 local_irq_restore(flags);
182} 200}
183 201
184static int iomd_set_dma_speed(dmach_t channel, dma_t *dma, int cycle) 202static int iomd_set_dma_speed(unsigned int chan, dma_t *dma, int cycle)
185{ 203{
186 int tcr, speed; 204 int tcr, speed;
187 205
@@ -197,7 +215,7 @@ static int iomd_set_dma_speed(dmach_t channel, dma_t *dma, int cycle)
197 tcr = iomd_readb(IOMD_DMATCR); 215 tcr = iomd_readb(IOMD_DMATCR);
198 speed &= 3; 216 speed &= 3;
199 217
200 switch (channel) { 218 switch (chan) {
201 case DMA_0: 219 case DMA_0:
202 tcr = (tcr & ~0x03) | speed; 220 tcr = (tcr & ~0x03) | speed;
203 break; 221 break;
@@ -236,16 +254,22 @@ static struct fiq_handler fh = {
236 .name = "floppydma" 254 .name = "floppydma"
237}; 255};
238 256
239static void floppy_enable_dma(dmach_t channel, dma_t *dma) 257struct floppy_dma {
258 struct dma_struct dma;
259 unsigned int fiq;
260};
261
262static void floppy_enable_dma(unsigned int chan, dma_t *dma)
240{ 263{
264 struct floppy_dma *fdma = container_of(dma, struct floppy_dma, dma);
241 void *fiqhandler_start; 265 void *fiqhandler_start;
242 unsigned int fiqhandler_length; 266 unsigned int fiqhandler_length;
243 struct pt_regs regs; 267 struct pt_regs regs;
244 268
245 if (dma->sg) 269 if (fdma->dma.sg)
246 BUG(); 270 BUG();
247 271
248 if (dma->dma_mode == DMA_MODE_READ) { 272 if (fdma->dma.dma_mode == DMA_MODE_READ) {
249 extern unsigned char floppy_fiqin_start, floppy_fiqin_end; 273 extern unsigned char floppy_fiqin_start, floppy_fiqin_end;
250 fiqhandler_start = &floppy_fiqin_start; 274 fiqhandler_start = &floppy_fiqin_start;
251 fiqhandler_length = &floppy_fiqin_end - &floppy_fiqin_start; 275 fiqhandler_length = &floppy_fiqin_end - &floppy_fiqin_start;
@@ -255,8 +279,8 @@ static void floppy_enable_dma(dmach_t channel, dma_t *dma)
255 fiqhandler_length = &floppy_fiqout_end - &floppy_fiqout_start; 279 fiqhandler_length = &floppy_fiqout_end - &floppy_fiqout_start;
256 } 280 }
257 281
258 regs.ARM_r9 = dma->count; 282 regs.ARM_r9 = fdma->dma.count;
259 regs.ARM_r10 = (unsigned long)dma->addr; 283 regs.ARM_r10 = (unsigned long)fdma->dma.addr;
260 regs.ARM_fp = (unsigned long)FLOPPYDMA_BASE; 284 regs.ARM_fp = (unsigned long)FLOPPYDMA_BASE;
261 285
262 if (claim_fiq(&fh)) { 286 if (claim_fiq(&fh)) {
@@ -266,16 +290,17 @@ static void floppy_enable_dma(dmach_t channel, dma_t *dma)
266 290
267 set_fiq_handler(fiqhandler_start, fiqhandler_length); 291 set_fiq_handler(fiqhandler_start, fiqhandler_length);
268 set_fiq_regs(&regs); 292 set_fiq_regs(&regs);
269 enable_fiq(dma->dma_irq); 293 enable_fiq(fdma->fiq);
270} 294}
271 295
272static void floppy_disable_dma(dmach_t channel, dma_t *dma) 296static void floppy_disable_dma(unsigned int chan, dma_t *dma)
273{ 297{
274 disable_fiq(dma->dma_irq); 298 struct floppy_dma *fdma = container_of(dma, struct floppy_dma, dma);
299 disable_fiq(fdma->fiq);
275 release_fiq(&fh); 300 release_fiq(&fh);
276} 301}
277 302
278static int floppy_get_residue(dmach_t channel, dma_t *dma) 303static int floppy_get_residue(unsigned int chan, dma_t *dma)
279{ 304{
280 struct pt_regs regs; 305 struct pt_regs regs;
281 get_fiq_regs(&regs); 306 get_fiq_regs(&regs);
@@ -292,7 +317,7 @@ static struct dma_ops floppy_dma_ops = {
292/* 317/*
293 * This is virtual DMA - we don't need anything here. 318 * This is virtual DMA - we don't need anything here.
294 */ 319 */
295static void sound_enable_disable_dma(dmach_t channel, dma_t *dma) 320static void sound_enable_disable_dma(unsigned int chan, dma_t *dma)
296{ 321{
297} 322}
298 323
@@ -302,8 +327,24 @@ static struct dma_ops sound_dma_ops = {
302 .disable = sound_enable_disable_dma, 327 .disable = sound_enable_disable_dma,
303}; 328};
304 329
305void __init arch_dma_init(dma_t *dma) 330static struct iomd_dma iomd_dma[6];
331
332static struct floppy_dma floppy_dma = {
333 .dma = {
334 .d_ops = &floppy_dma_ops,
335 },
336 .fiq = FIQ_FLOPPYDATA,
337};
338
339static dma_t sound_dma = {
340 .d_ops = &sound_dma_ops,
341};
342
343static int __init rpc_dma_init(void)
306{ 344{
345 unsigned int i;
346 int ret;
347
307 iomd_writeb(0, IOMD_IO0CR); 348 iomd_writeb(0, IOMD_IO0CR);
308 iomd_writeb(0, IOMD_IO1CR); 349 iomd_writeb(0, IOMD_IO1CR);
309 iomd_writeb(0, IOMD_IO2CR); 350 iomd_writeb(0, IOMD_IO2CR);
@@ -311,31 +352,39 @@ void __init arch_dma_init(dma_t *dma)
311 352
312 iomd_writeb(0xa0, IOMD_DMATCR); 353 iomd_writeb(0xa0, IOMD_DMATCR);
313 354
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;
335
336 /* 355 /*
337 * Setup DMA channels 2,3 to be for podules 356 * Setup DMA channels 2,3 to be for podules
338 * and channels 0,1 for internal devices 357 * and channels 0,1 for internal devices
339 */ 358 */
340 iomd_writeb(DMA_EXT_IO3|DMA_EXT_IO2, IOMD_DMAEXT); 359 iomd_writeb(DMA_EXT_IO3|DMA_EXT_IO2, IOMD_DMAEXT);
360
361 iomd_dma[DMA_0].base = IOMD_IO0CURA;
362 iomd_dma[DMA_0].irq = IRQ_DMA0;
363 iomd_dma[DMA_1].base = IOMD_IO1CURA;
364 iomd_dma[DMA_1].irq = IRQ_DMA1;
365 iomd_dma[DMA_2].base = IOMD_IO2CURA;
366 iomd_dma[DMA_2].irq = IRQ_DMA2;
367 iomd_dma[DMA_3].base = IOMD_IO3CURA;
368 iomd_dma[DMA_3].irq = IRQ_DMA3;
369 iomd_dma[DMA_S0].base = IOMD_SD0CURA;
370 iomd_dma[DMA_S0].irq = IRQ_DMAS0;
371 iomd_dma[DMA_S1].base = IOMD_SD1CURA;
372 iomd_dma[DMA_S1].irq = IRQ_DMAS1;
373
374 for (i = DMA_0; i <= DMA_S1; i++) {
375 iomd_dma[i].dma.d_ops = &iomd_dma_ops;
376
377 ret = isa_dma_add(i, &iomd_dma[i].dma);
378 if (ret)
379 printk("IOMDDMA%u: unable to register: %d\n", i, ret);
380 }
381
382 ret = isa_dma_add(DMA_VIRTUAL_FLOPPY, &floppy_dma.dma);
383 if (ret)
384 printk("IOMDFLOPPY: unable to register: %d\n", ret);
385 ret = isa_dma_add(DMA_VIRTUAL_SOUND, &sound_dma);
386 if (ret)
387 printk("IOMDSOUND: unable to register: %d\n", ret);
388 return 0;
341} 389}
390core_initcall(rpc_dma_init);