blob: 094cc52745c52e0adaa85a5d87bc947486f480c5 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/* linux/arch/arm/mach-bast/dma.c
2 *
3 * (c) 2003-2005 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * S3C2410 DMA core
7 *
8 * http://www.simtec.co.uk/products/EB2410ITX/
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 *
14 * Changelog:
15 * 27-Feb-2005 BJD Added kmem cache for dma descriptors
16 * 18-Nov-2004 BJD Removed error for loading onto stopped channel
17 * 10-Nov-2004 BJD Ensure all external symbols exported for modules
18 * 10-Nov-2004 BJD Use sys_device and sysdev_class for power management
19 * 08-Aug-2004 BJD Apply rmk's suggestions
20 * 21-Jul-2004 BJD Ported to linux 2.6
21 * 12-Jul-2004 BJD Finished re-write and change of API
22 * 06-Jul-2004 BJD Rewrote dma code to try and cope with various problems
23 * 23-May-2003 BJD Created file
24 * 19-Aug-2003 BJD Cleanup, header fix, added URL
25 *
26 * This file is based on the Sangwook Lee/Samsung patches, re-written due
27 * to various ommisions from the code (such as flexible dma configuration)
28 * for use with the BAST system board.
29 *
30 * The re-write is pretty much complete, and should be good enough for any
31 * possible DMA function
32 */
33
Linus Torvalds1da177e2005-04-16 15:20:36 -070034
35#ifdef CONFIG_S3C2410_DMA_DEBUG
36#define DEBUG
37#endif
38
39#include <linux/module.h>
40#include <linux/init.h>
41#include <linux/sched.h>
42#include <linux/spinlock.h>
43#include <linux/interrupt.h>
44#include <linux/sysdev.h>
45#include <linux/slab.h>
46#include <linux/errno.h>
47#include <linux/delay.h>
48
49#include <asm/system.h>
50#include <asm/irq.h>
51#include <asm/hardware.h>
52#include <asm/io.h>
53#include <asm/dma.h>
54
55#include <asm/mach/dma.h>
56#include <asm/arch/map.h>
57
58/* io map for dma */
59static void __iomem *dma_base;
60static kmem_cache_t *dma_kmem;
61
62/* dma channel state information */
63s3c2410_dma_chan_t s3c2410_chans[S3C2410_DMA_CHANNELS];
64
65/* debugging functions */
66
67#define BUF_MAGIC (0xcafebabe)
68
69#define dmawarn(fmt...) printk(KERN_DEBUG fmt)
70
71#define dma_regaddr(chan, reg) ((chan)->regs + (reg))
72
73#if 1
74#define dma_wrreg(chan, reg, val) writel((val), (chan)->regs + (reg))
75#else
76static inline void
77dma_wrreg(s3c2410_dma_chan_t *chan, int reg, unsigned long val)
78{
79 pr_debug("writing %08x to register %08x\n",(unsigned int)val,reg);
80 writel(val, dma_regaddr(chan, reg));
81}
82
83#endif
84
85#define dma_rdreg(chan, reg) readl((chan)->regs + (reg))
86
87/* captured register state for debug */
88
89struct s3c2410_dma_regstate {
90 unsigned long dcsrc;
91 unsigned long disrc;
92 unsigned long dstat;
93 unsigned long dcon;
94 unsigned long dmsktrig;
95};
96
97#ifdef CONFIG_S3C2410_DMA_DEBUG
98
99/* dmadbg_showregs
100 *
101 * simple debug routine to print the current state of the dma registers
102*/
103
104static void
105dmadbg_capture(s3c2410_dma_chan_t *chan, struct s3c2410_dma_regstate *regs)
106{
107 regs->dcsrc = dma_rdreg(chan, S3C2410_DMA_DCSRC);
108 regs->disrc = dma_rdreg(chan, S3C2410_DMA_DISRC);
109 regs->dstat = dma_rdreg(chan, S3C2410_DMA_DSTAT);
110 regs->dcon = dma_rdreg(chan, S3C2410_DMA_DCON);
111 regs->dmsktrig = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
112}
113
114static void
115dmadbg_showregs(const char *fname, int line, s3c2410_dma_chan_t *chan,
116 struct s3c2410_dma_regstate *regs)
117{
118 printk(KERN_DEBUG "dma%d: %s:%d: DCSRC=%08lx, DISRC=%08lx, DSTAT=%08lx DMT=%02lx, DCON=%08lx\n",
119 chan->number, fname, line,
120 regs->dcsrc, regs->disrc, regs->dstat, regs->dmsktrig,
121 regs->dcon);
122}
123
124static void
125dmadbg_showchan(const char *fname, int line, s3c2410_dma_chan_t *chan)
126{
127 struct s3c2410_dma_regstate state;
128
129 dmadbg_capture(chan, &state);
130
131 printk(KERN_DEBUG "dma%d: %s:%d: ls=%d, cur=%p, %p %p\n",
132 chan->number, fname, line, chan->load_state,
133 chan->curr, chan->next, chan->end);
134
135 dmadbg_showregs(fname, line, chan, &state);
136}
137
138#define dbg_showregs(chan) dmadbg_showregs(__FUNCTION__, __LINE__, (chan))
139#define dbg_showchan(chan) dmadbg_showchan(__FUNCTION__, __LINE__, (chan))
140#else
141#define dbg_showregs(chan) do { } while(0)
142#define dbg_showchan(chan) do { } while(0)
143#endif /* CONFIG_S3C2410_DMA_DEBUG */
144
145#define check_channel(chan) \
146 do { if ((chan) >= S3C2410_DMA_CHANNELS) { \
147 printk(KERN_ERR "%s: invalid channel %d\n", __FUNCTION__, (chan)); \
148 return -EINVAL; \
149 } } while(0)
150
151
152/* s3c2410_dma_stats_timeout
153 *
154 * Update DMA stats from timeout info
155*/
156
157static void
158s3c2410_dma_stats_timeout(s3c2410_dma_stats_t *stats, int val)
159{
160 if (stats == NULL)
161 return;
162
163 if (val > stats->timeout_longest)
164 stats->timeout_longest = val;
165 if (val < stats->timeout_shortest)
166 stats->timeout_shortest = val;
167
168 stats->timeout_avg += val;
169}
170
171/* s3c2410_dma_waitforload
172 *
173 * wait for the DMA engine to load a buffer, and update the state accordingly
174*/
175
176static int
177s3c2410_dma_waitforload(s3c2410_dma_chan_t *chan, int line)
178{
179 int timeout = chan->load_timeout;
180 int took;
181
182 if (chan->load_state != S3C2410_DMALOAD_1LOADED) {
183 printk(KERN_ERR "dma%d: s3c2410_dma_waitforload() called in loadstate %d from line %d\n", chan->number, chan->load_state, line);
184 return 0;
185 }
186
187 if (chan->stats != NULL)
188 chan->stats->loads++;
189
190 while (--timeout > 0) {
191 if ((dma_rdreg(chan, S3C2410_DMA_DSTAT) << (32-20)) != 0) {
192 took = chan->load_timeout - timeout;
193
194 s3c2410_dma_stats_timeout(chan->stats, took);
195
196 switch (chan->load_state) {
197 case S3C2410_DMALOAD_1LOADED:
198 chan->load_state = S3C2410_DMALOAD_1RUNNING;
199 break;
200
201 default:
202 printk(KERN_ERR "dma%d: unknown load_state in s3c2410_dma_waitforload() %d\n", chan->number, chan->load_state);
203 }
204
205 return 1;
206 }
207 }
208
209 if (chan->stats != NULL) {
210 chan->stats->timeout_failed++;
211 }
212
213 return 0;
214}
215
216
217
218/* s3c2410_dma_loadbuffer
219 *
220 * load a buffer, and update the channel state
221*/
222
223static inline int
224s3c2410_dma_loadbuffer(s3c2410_dma_chan_t *chan,
225 s3c2410_dma_buf_t *buf)
226{
227 unsigned long reload;
228
229 pr_debug("s3c2410_chan_loadbuffer: loading buff %p (0x%08lx,0x%06x)\n",
230 buf, (unsigned long)buf->data, buf->size);
231
232 if (buf == NULL) {
233 dmawarn("buffer is NULL\n");
234 return -EINVAL;
235 }
236
237 /* check the state of the channel before we do anything */
238
239 if (chan->load_state == S3C2410_DMALOAD_1LOADED) {
240 dmawarn("load_state is S3C2410_DMALOAD_1LOADED\n");
241 }
242
243 if (chan->load_state == S3C2410_DMALOAD_1LOADED_1RUNNING) {
244 dmawarn("state is S3C2410_DMALOAD_1LOADED_1RUNNING\n");
245 }
246
247 /* it would seem sensible if we are the last buffer to not bother
248 * with the auto-reload bit, so that the DMA engine will not try
249 * and load another transfer after this one has finished...
250 */
251 if (chan->load_state == S3C2410_DMALOAD_NONE) {
252 pr_debug("load_state is none, checking for noreload (next=%p)\n",
253 buf->next);
254 reload = (buf->next == NULL) ? S3C2410_DCON_NORELOAD : 0;
255 } else {
256 pr_debug("load_state is %d => autoreload\n", chan->load_state);
257 reload = S3C2410_DCON_AUTORELOAD;
258 }
259
260 writel(buf->data, chan->addr_reg);
261
262 dma_wrreg(chan, S3C2410_DMA_DCON,
263 chan->dcon | reload | (buf->size/chan->xfer_unit));
264
265 chan->next = buf->next;
266
267 /* update the state of the channel */
268
269 switch (chan->load_state) {
270 case S3C2410_DMALOAD_NONE:
271 chan->load_state = S3C2410_DMALOAD_1LOADED;
272 break;
273
274 case S3C2410_DMALOAD_1RUNNING:
275 chan->load_state = S3C2410_DMALOAD_1LOADED_1RUNNING;
276 break;
277
278 default:
279 dmawarn("dmaload: unknown state %d in loadbuffer\n",
280 chan->load_state);
281 break;
282 }
283
284 return 0;
285}
286
287/* s3c2410_dma_call_op
288 *
289 * small routine to call the op routine with the given op if it has been
290 * registered
291*/
292
293static void
294s3c2410_dma_call_op(s3c2410_dma_chan_t *chan, s3c2410_chan_op_t op)
295{
296 if (chan->op_fn != NULL) {
297 (chan->op_fn)(chan, op);
298 }
299}
300
301/* s3c2410_dma_buffdone
302 *
303 * small wrapper to check if callback routine needs to be called, and
304 * if so, call it
305*/
306
307static inline void
308s3c2410_dma_buffdone(s3c2410_dma_chan_t *chan, s3c2410_dma_buf_t *buf,
309 s3c2410_dma_buffresult_t result)
310{
311 pr_debug("callback_fn=%p, buf=%p, id=%p, size=%d, result=%d\n",
312 chan->callback_fn, buf, buf->id, buf->size, result);
313
314 if (chan->callback_fn != NULL) {
315 (chan->callback_fn)(chan, buf->id, buf->size, result);
316 }
317}
318
319/* s3c2410_dma_start
320 *
321 * start a dma channel going
322*/
323
324static int s3c2410_dma_start(s3c2410_dma_chan_t *chan)
325{
326 unsigned long tmp;
327 unsigned long flags;
328
329 pr_debug("s3c2410_start_dma: channel=%d\n", chan->number);
330
331 local_irq_save(flags);
332
333 if (chan->state == S3C2410_DMA_RUNNING) {
334 pr_debug("s3c2410_start_dma: already running (%d)\n", chan->state);
335 local_irq_restore(flags);
336 return 0;
337 }
338
339 chan->state = S3C2410_DMA_RUNNING;
340
341 /* check wether there is anything to load, and if not, see
342 * if we can find anything to load
343 */
344
345 if (chan->load_state == S3C2410_DMALOAD_NONE) {
346 if (chan->next == NULL) {
347 printk(KERN_ERR "dma%d: channel has nothing loaded\n",
348 chan->number);
349 chan->state = S3C2410_DMA_IDLE;
350 local_irq_restore(flags);
351 return -EINVAL;
352 }
353
354 s3c2410_dma_loadbuffer(chan, chan->next);
355 }
356
357 dbg_showchan(chan);
358
359 /* enable the channel */
360
361 if (!chan->irq_enabled) {
362 enable_irq(chan->irq);
363 chan->irq_enabled = 1;
364 }
365
366 /* start the channel going */
367
368 tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
369 tmp &= ~S3C2410_DMASKTRIG_STOP;
370 tmp |= S3C2410_DMASKTRIG_ON;
371 dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp);
372
373 pr_debug("wrote %08lx to DMASKTRIG\n", tmp);
374
375#if 0
376 /* the dma buffer loads should take care of clearing the AUTO
377 * reloading feature */
378 tmp = dma_rdreg(chan, S3C2410_DMA_DCON);
379 tmp &= ~S3C2410_DCON_NORELOAD;
380 dma_wrreg(chan, S3C2410_DMA_DCON, tmp);
381#endif
382
383 s3c2410_dma_call_op(chan, S3C2410_DMAOP_START);
384
385 dbg_showchan(chan);
386
387 local_irq_restore(flags);
388 return 0;
389}
390
391/* s3c2410_dma_canload
392 *
393 * work out if we can queue another buffer into the DMA engine
394*/
395
396static int
397s3c2410_dma_canload(s3c2410_dma_chan_t *chan)
398{
399 if (chan->load_state == S3C2410_DMALOAD_NONE ||
400 chan->load_state == S3C2410_DMALOAD_1RUNNING)
401 return 1;
402
403 return 0;
404}
405
406
407/* s3c2410_dma_enqueue
408 *
409 * queue an given buffer for dma transfer.
410 *
411 * id the device driver's id information for this buffer
412 * data the physical address of the buffer data
413 * size the size of the buffer in bytes
414 *
415 * If the channel is not running, then the flag S3C2410_DMAF_AUTOSTART
416 * is checked, and if set, the channel is started. If this flag isn't set,
417 * then an error will be returned.
418 *
419 * It is possible to queue more than one DMA buffer onto a channel at
420 * once, and the code will deal with the re-loading of the next buffer
421 * when necessary.
422*/
423
424int s3c2410_dma_enqueue(unsigned int channel, void *id,
425 dma_addr_t data, int size)
426{
427 s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
428 s3c2410_dma_buf_t *buf;
429 unsigned long flags;
430
431 check_channel(channel);
432
433 pr_debug("%s: id=%p, data=%08x, size=%d\n",
434 __FUNCTION__, id, (unsigned int)data, size);
435
436 buf = kmem_cache_alloc(dma_kmem, GFP_ATOMIC);
437 if (buf == NULL) {
Lucas Correia Villa Real53776eb2005-07-24 00:15:46 +0100438 pr_debug("%s: out of memory (%ld alloc)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 __FUNCTION__, sizeof(*buf));
440 return -ENOMEM;
441 }
442
443 pr_debug("%s: new buffer %p\n", __FUNCTION__, buf);
444
445 //dbg_showchan(chan);
446
447 buf->next = NULL;
448 buf->data = buf->ptr = data;
449 buf->size = size;
450 buf->id = id;
451 buf->magic = BUF_MAGIC;
452
453 local_irq_save(flags);
454
455 if (chan->curr == NULL) {
456 /* we've got nothing loaded... */
457 pr_debug("%s: buffer %p queued onto empty channel\n",
458 __FUNCTION__, buf);
459
460 chan->curr = buf;
461 chan->end = buf;
462 chan->next = NULL;
463 } else {
464 pr_debug("dma%d: %s: buffer %p queued onto non-empty channel\n",
465 chan->number, __FUNCTION__, buf);
466
467 if (chan->end == NULL)
468 pr_debug("dma%d: %s: %p not empty, and chan->end==NULL?\n",
469 chan->number, __FUNCTION__, chan);
470
471 chan->end->next = buf;
472 chan->end = buf;
473 }
474
475 /* if necessary, update the next buffer field */
476 if (chan->next == NULL)
477 chan->next = buf;
478
479 /* check to see if we can load a buffer */
480 if (chan->state == S3C2410_DMA_RUNNING) {
481 if (chan->load_state == S3C2410_DMALOAD_1LOADED && 1) {
482 if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
483 printk(KERN_ERR "dma%d: loadbuffer:"
484 "timeout loading buffer\n",
485 chan->number);
486 dbg_showchan(chan);
487 local_irq_restore(flags);
488 return -EINVAL;
489 }
490 }
491
492 while (s3c2410_dma_canload(chan) && chan->next != NULL) {
493 s3c2410_dma_loadbuffer(chan, chan->next);
494 }
495 } else if (chan->state == S3C2410_DMA_IDLE) {
496 if (chan->flags & S3C2410_DMAF_AUTOSTART) {
497 s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_START);
498 }
499 }
500
501 local_irq_restore(flags);
502 return 0;
503}
504
505EXPORT_SYMBOL(s3c2410_dma_enqueue);
506
507static inline void
508s3c2410_dma_freebuf(s3c2410_dma_buf_t *buf)
509{
510 int magicok = (buf->magic == BUF_MAGIC);
511
512 buf->magic = -1;
513
514 if (magicok) {
515 kmem_cache_free(dma_kmem, buf);
516 } else {
517 printk("s3c2410_dma_freebuf: buff %p with bad magic\n", buf);
518 }
519}
520
521/* s3c2410_dma_lastxfer
522 *
523 * called when the system is out of buffers, to ensure that the channel
524 * is prepared for shutdown.
525*/
526
527static inline void
528s3c2410_dma_lastxfer(s3c2410_dma_chan_t *chan)
529{
530 pr_debug("dma%d: s3c2410_dma_lastxfer: load_state %d\n",
531 chan->number, chan->load_state);
532
533 switch (chan->load_state) {
534 case S3C2410_DMALOAD_NONE:
535 break;
536
537 case S3C2410_DMALOAD_1LOADED:
538 if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
539 /* flag error? */
540 printk(KERN_ERR "dma%d: timeout waiting for load\n",
541 chan->number);
542 return;
543 }
544 break;
545
546 default:
547 pr_debug("dma%d: lastxfer: unhandled load_state %d with no next",
548 chan->number, chan->load_state);
549 return;
550
551 }
552
553 /* hopefully this'll shut the damned thing up after the transfer... */
554 dma_wrreg(chan, S3C2410_DMA_DCON, chan->dcon | S3C2410_DCON_NORELOAD);
555}
556
557
558#define dmadbg2(x...)
559
560static irqreturn_t
561s3c2410_dma_irq(int irq, void *devpw, struct pt_regs *regs)
562{
563 s3c2410_dma_chan_t *chan = (s3c2410_dma_chan_t *)devpw;
564 s3c2410_dma_buf_t *buf;
565
566 buf = chan->curr;
567
568 dbg_showchan(chan);
569
570 /* modify the channel state */
571
572 switch (chan->load_state) {
573 case S3C2410_DMALOAD_1RUNNING:
574 /* TODO - if we are running only one buffer, we probably
575 * want to reload here, and then worry about the buffer
576 * callback */
577
578 chan->load_state = S3C2410_DMALOAD_NONE;
579 break;
580
581 case S3C2410_DMALOAD_1LOADED:
582 /* iirc, we should go back to NONE loaded here, we
583 * had a buffer, and it was never verified as being
584 * loaded.
585 */
586
587 chan->load_state = S3C2410_DMALOAD_NONE;
588 break;
589
590 case S3C2410_DMALOAD_1LOADED_1RUNNING:
591 /* we'll worry about checking to see if another buffer is
592 * ready after we've called back the owner. This should
593 * ensure we do not wait around too long for the DMA
594 * engine to start the next transfer
595 */
596
597 chan->load_state = S3C2410_DMALOAD_1LOADED;
598 break;
599
600 case S3C2410_DMALOAD_NONE:
601 printk(KERN_ERR "dma%d: IRQ with no loaded buffer?\n",
602 chan->number);
603 break;
604
605 default:
606 printk(KERN_ERR "dma%d: IRQ in invalid load_state %d\n",
607 chan->number, chan->load_state);
608 break;
609 }
610
611 if (buf != NULL) {
612 /* update the chain to make sure that if we load any more
613 * buffers when we call the callback function, things should
614 * work properly */
615
616 chan->curr = buf->next;
617 buf->next = NULL;
618
619 if (buf->magic != BUF_MAGIC) {
620 printk(KERN_ERR "dma%d: %s: buf %p incorrect magic\n",
621 chan->number, __FUNCTION__, buf);
622 return IRQ_HANDLED;
623 }
624
625 s3c2410_dma_buffdone(chan, buf, S3C2410_RES_OK);
626
627 /* free resouces */
628 s3c2410_dma_freebuf(buf);
629 } else {
630 }
631
632 if (chan->next != NULL) {
633 unsigned long flags;
634
635 switch (chan->load_state) {
636 case S3C2410_DMALOAD_1RUNNING:
637 /* don't need to do anything for this state */
638 break;
639
640 case S3C2410_DMALOAD_NONE:
641 /* can load buffer immediately */
642 break;
643
644 case S3C2410_DMALOAD_1LOADED:
645 if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
646 /* flag error? */
647 printk(KERN_ERR "dma%d: timeout waiting for load\n",
648 chan->number);
649 return IRQ_HANDLED;
650 }
651
652 break;
653
654 case S3C2410_DMALOAD_1LOADED_1RUNNING:
655 goto no_load;
656
657 default:
658 printk(KERN_ERR "dma%d: unknown load_state in irq, %d\n",
659 chan->number, chan->load_state);
660 return IRQ_HANDLED;
661 }
662
663 local_irq_save(flags);
664 s3c2410_dma_loadbuffer(chan, chan->next);
665 local_irq_restore(flags);
666 } else {
667 s3c2410_dma_lastxfer(chan);
668
669 /* see if we can stop this channel.. */
670 if (chan->load_state == S3C2410_DMALOAD_NONE) {
671 pr_debug("dma%d: end of transfer, stopping channel (%ld)\n",
672 chan->number, jiffies);
673 s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_STOP);
674 }
675 }
676
677 no_load:
678 return IRQ_HANDLED;
679}
680
681
682
683/* s3c2410_request_dma
684 *
685 * get control of an dma channel
686*/
687
688int s3c2410_dma_request(unsigned int channel, s3c2410_dma_client_t *client,
689 void *dev)
690{
691 s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
692 unsigned long flags;
693 int err;
694
695 pr_debug("dma%d: s3c2410_request_dma: client=%s, dev=%p\n",
696 channel, client->name, dev);
697
698 check_channel(channel);
699
700 local_irq_save(flags);
701
702 dbg_showchan(chan);
703
704 if (chan->in_use) {
705 if (client != chan->client) {
706 printk(KERN_ERR "dma%d: already in use\n", channel);
707 local_irq_restore(flags);
708 return -EBUSY;
709 } else {
710 printk(KERN_ERR "dma%d: client already has channel\n", channel);
711 }
712 }
713
714 chan->client = client;
715 chan->in_use = 1;
716
717 if (!chan->irq_claimed) {
718 pr_debug("dma%d: %s : requesting irq %d\n",
719 channel, __FUNCTION__, chan->irq);
720
Thomas Gleixner52e405e2006-07-03 02:20:05 +0200721 err = request_irq(chan->irq, s3c2410_dma_irq, IRQF_DISABLED,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 client->name, (void *)chan);
723
724 if (err) {
725 chan->in_use = 0;
726 local_irq_restore(flags);
727
728 printk(KERN_ERR "%s: cannot get IRQ %d for DMA %d\n",
729 client->name, chan->irq, chan->number);
730 return err;
731 }
732
733 chan->irq_claimed = 1;
734 chan->irq_enabled = 1;
735 }
736
737 local_irq_restore(flags);
738
739 /* need to setup */
740
741 pr_debug("%s: channel initialised, %p\n", __FUNCTION__, chan);
742
743 return 0;
744}
745
746EXPORT_SYMBOL(s3c2410_dma_request);
747
748/* s3c2410_dma_free
749 *
750 * release the given channel back to the system, will stop and flush
751 * any outstanding transfers, and ensure the channel is ready for the
752 * next claimant.
753 *
754 * Note, although a warning is currently printed if the freeing client
755 * info is not the same as the registrant's client info, the free is still
756 * allowed to go through.
757*/
758
759int s3c2410_dma_free(dmach_t channel, s3c2410_dma_client_t *client)
760{
761 s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
762 unsigned long flags;
763
764 check_channel(channel);
765
766 local_irq_save(flags);
767
768
769 if (chan->client != client) {
770 printk(KERN_WARNING "dma%d: possible free from different client (channel %p, passed %p)\n",
771 channel, chan->client, client);
772 }
773
774 /* sort out stopping and freeing the channel */
775
776 if (chan->state != S3C2410_DMA_IDLE) {
777 pr_debug("%s: need to stop dma channel %p\n",
778 __FUNCTION__, chan);
779
780 /* possibly flush the channel */
781 s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STOP);
782 }
783
784 chan->client = NULL;
785 chan->in_use = 0;
786
Albrecht Dreß105bb262005-06-03 20:52:26 +0100787 if (chan->irq_claimed)
788 free_irq(chan->irq, (void *)chan);
789 chan->irq_claimed = 0;
790
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 local_irq_restore(flags);
792
793 return 0;
794}
795
796EXPORT_SYMBOL(s3c2410_dma_free);
797
798static int s3c2410_dma_dostop(s3c2410_dma_chan_t *chan)
799{
800 unsigned long tmp;
801 unsigned long flags;
802
803 pr_debug("%s:\n", __FUNCTION__);
804
805 dbg_showchan(chan);
806
807 local_irq_save(flags);
808
809 s3c2410_dma_call_op(chan, S3C2410_DMAOP_STOP);
810
811 tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
812 tmp |= S3C2410_DMASKTRIG_STOP;
813 dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp);
814
815#if 0
816 /* should also clear interrupts, according to WinCE BSP */
817 tmp = dma_rdreg(chan, S3C2410_DMA_DCON);
818 tmp |= S3C2410_DCON_NORELOAD;
819 dma_wrreg(chan, S3C2410_DMA_DCON, tmp);
820#endif
821
822 chan->state = S3C2410_DMA_IDLE;
823 chan->load_state = S3C2410_DMALOAD_NONE;
824
825 local_irq_restore(flags);
826
827 return 0;
828}
829
830/* s3c2410_dma_flush
831 *
832 * stop the channel, and remove all current and pending transfers
833*/
834
835static int s3c2410_dma_flush(s3c2410_dma_chan_t *chan)
836{
837 s3c2410_dma_buf_t *buf, *next;
838 unsigned long flags;
839
840 pr_debug("%s:\n", __FUNCTION__);
841
842 local_irq_save(flags);
843
844 if (chan->state != S3C2410_DMA_IDLE) {
845 pr_debug("%s: stopping channel...\n", __FUNCTION__ );
846 s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_STOP);
847 }
848
849 buf = chan->curr;
850 if (buf == NULL)
851 buf = chan->next;
852
853 chan->curr = chan->next = chan->end = NULL;
854
855 if (buf != NULL) {
856 for ( ; buf != NULL; buf = next) {
857 next = buf->next;
858
859 pr_debug("%s: free buffer %p, next %p\n",
860 __FUNCTION__, buf, buf->next);
861
862 s3c2410_dma_buffdone(chan, buf, S3C2410_RES_ABORT);
863 s3c2410_dma_freebuf(buf);
864 }
865 }
866
867 local_irq_restore(flags);
868
869 return 0;
870}
871
872
873int
874s3c2410_dma_ctrl(dmach_t channel, s3c2410_chan_op_t op)
875{
876 s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
877
878 check_channel(channel);
879
880 switch (op) {
881 case S3C2410_DMAOP_START:
882 return s3c2410_dma_start(chan);
883
884 case S3C2410_DMAOP_STOP:
885 return s3c2410_dma_dostop(chan);
886
887 case S3C2410_DMAOP_PAUSE:
888 return -ENOENT;
889
890 case S3C2410_DMAOP_RESUME:
891 return -ENOENT;
892
893 case S3C2410_DMAOP_FLUSH:
894 return s3c2410_dma_flush(chan);
895
896 case S3C2410_DMAOP_TIMEOUT:
897 return 0;
898
899 }
900
901 return -ENOENT; /* unknown, don't bother */
902}
903
904EXPORT_SYMBOL(s3c2410_dma_ctrl);
905
906/* DMA configuration for each channel
907 *
908 * DISRCC -> source of the DMA (AHB,APB)
909 * DISRC -> source address of the DMA
910 * DIDSTC -> destination of the DMA (AHB,APD)
911 * DIDST -> destination address of the DMA
912*/
913
914/* s3c2410_dma_config
915 *
916 * xfersize: size of unit in bytes (1,2,4)
917 * dcon: base value of the DCONx register
918*/
919
920int s3c2410_dma_config(dmach_t channel,
921 int xferunit,
922 int dcon)
923{
924 s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
925
926 pr_debug("%s: chan=%d, xfer_unit=%d, dcon=%08x\n",
927 __FUNCTION__, channel, xferunit, dcon);
928
929 check_channel(channel);
930
931 switch (xferunit) {
932 case 1:
933 dcon |= S3C2410_DCON_BYTE;
934 break;
935
936 case 2:
937 dcon |= S3C2410_DCON_HALFWORD;
938 break;
939
940 case 4:
941 dcon |= S3C2410_DCON_WORD;
942 break;
943
944 default:
945 pr_debug("%s: bad transfer size %d\n", __FUNCTION__, xferunit);
946 return -EINVAL;
947 }
948
949 dcon |= S3C2410_DCON_HWTRIG;
950 dcon |= S3C2410_DCON_INTREQ;
951
952 pr_debug("%s: dcon now %08x\n", __FUNCTION__, dcon);
953
954 chan->dcon = dcon;
955 chan->xfer_unit = xferunit;
956
957 return 0;
958}
959
960EXPORT_SYMBOL(s3c2410_dma_config);
961
962int s3c2410_dma_setflags(dmach_t channel, unsigned int flags)
963{
964 s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
965
966 check_channel(channel);
967
968 pr_debug("%s: chan=%p, flags=%08x\n", __FUNCTION__, chan, flags);
969
970 chan->flags = flags;
971
972 return 0;
973}
974
975EXPORT_SYMBOL(s3c2410_dma_setflags);
976
977
978/* do we need to protect the settings of the fields from
979 * irq?
980*/
981
982int s3c2410_dma_set_opfn(dmach_t channel, s3c2410_dma_opfn_t rtn)
983{
984 s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
985
986 check_channel(channel);
987
988 pr_debug("%s: chan=%p, op rtn=%p\n", __FUNCTION__, chan, rtn);
989
990 chan->op_fn = rtn;
991
992 return 0;
993}
994
995EXPORT_SYMBOL(s3c2410_dma_set_opfn);
996
997int s3c2410_dma_set_buffdone_fn(dmach_t channel, s3c2410_dma_cbfn_t rtn)
998{
999 s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
1000
1001 check_channel(channel);
1002
1003 pr_debug("%s: chan=%p, callback rtn=%p\n", __FUNCTION__, chan, rtn);
1004
1005 chan->callback_fn = rtn;
1006
1007 return 0;
1008}
1009
1010EXPORT_SYMBOL(s3c2410_dma_set_buffdone_fn);
1011
1012/* s3c2410_dma_devconfig
1013 *
1014 * configure the dma source/destination hardware type and address
1015 *
1016 * source: S3C2410_DMASRC_HW: source is hardware
1017 * S3C2410_DMASRC_MEM: source is memory
1018 *
1019 * hwcfg: the value for xxxSTCn register,
1020 * bit 0: 0=increment pointer, 1=leave pointer
1021 * bit 1: 0=soucre is AHB, 1=soucre is APB
1022 *
1023 * devaddr: physical address of the source
1024*/
1025
1026int s3c2410_dma_devconfig(int channel,
1027 s3c2410_dmasrc_t source,
1028 int hwcfg,
1029 unsigned long devaddr)
1030{
1031 s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
1032
1033 check_channel(channel);
1034
1035 pr_debug("%s: source=%d, hwcfg=%08x, devaddr=%08lx\n",
1036 __FUNCTION__, (int)source, hwcfg, devaddr);
1037
1038 chan->source = source;
1039 chan->dev_addr = devaddr;
1040
1041 switch (source) {
1042 case S3C2410_DMASRC_HW:
1043 /* source is hardware */
1044 pr_debug("%s: hw source, devaddr=%08lx, hwcfg=%d\n",
1045 __FUNCTION__, devaddr, hwcfg);
1046 dma_wrreg(chan, S3C2410_DMA_DISRCC, hwcfg & 3);
1047 dma_wrreg(chan, S3C2410_DMA_DISRC, devaddr);
1048 dma_wrreg(chan, S3C2410_DMA_DIDSTC, (0<<1) | (0<<0));
1049
1050 chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DIDST);
1051 return 0;
1052
1053 case S3C2410_DMASRC_MEM:
1054 /* source is memory */
1055 pr_debug( "%s: mem source, devaddr=%08lx, hwcfg=%d\n",
1056 __FUNCTION__, devaddr, hwcfg);
1057 dma_wrreg(chan, S3C2410_DMA_DISRCC, (0<<1) | (0<<0));
1058 dma_wrreg(chan, S3C2410_DMA_DIDST, devaddr);
1059 dma_wrreg(chan, S3C2410_DMA_DIDSTC, hwcfg & 3);
1060
1061 chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DISRC);
1062 return 0;
1063 }
1064
1065 printk(KERN_ERR "dma%d: invalid source type (%d)\n", channel, source);
1066 return -EINVAL;
1067}
1068
1069EXPORT_SYMBOL(s3c2410_dma_devconfig);
1070
1071/* s3c2410_dma_getposition
1072 *
1073 * returns the current transfer points for the dma source and destination
1074*/
1075
1076int s3c2410_dma_getposition(dmach_t channel, dma_addr_t *src, dma_addr_t *dst)
1077{
1078 s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
1079
1080 check_channel(channel);
1081
1082 if (src != NULL)
1083 *src = dma_rdreg(chan, S3C2410_DMA_DCSRC);
1084
1085 if (dst != NULL)
1086 *dst = dma_rdreg(chan, S3C2410_DMA_DCDST);
1087
1088 return 0;
1089}
1090
1091EXPORT_SYMBOL(s3c2410_dma_getposition);
1092
1093
1094/* system device class */
1095
1096#ifdef CONFIG_PM
1097
1098static int s3c2410_dma_suspend(struct sys_device *dev, pm_message_t state)
1099{
1100 s3c2410_dma_chan_t *cp = container_of(dev, s3c2410_dma_chan_t, dev);
1101
1102 printk(KERN_DEBUG "suspending dma channel %d\n", cp->number);
1103
1104 if (dma_rdreg(cp, S3C2410_DMA_DMASKTRIG) & S3C2410_DMASKTRIG_ON) {
1105 /* the dma channel is still working, which is probably
1106 * a bad thing to do over suspend/resume. We stop the
1107 * channel and assume that the client is either going to
1108 * retry after resume, or that it is broken.
1109 */
1110
1111 printk(KERN_INFO "dma: stopping channel %d due to suspend\n",
1112 cp->number);
1113
1114 s3c2410_dma_dostop(cp);
1115 }
1116
1117 return 0;
1118}
1119
1120static int s3c2410_dma_resume(struct sys_device *dev)
1121{
1122 return 0;
1123}
1124
1125#else
1126#define s3c2410_dma_suspend NULL
1127#define s3c2410_dma_resume NULL
1128#endif /* CONFIG_PM */
1129
1130static struct sysdev_class dma_sysclass = {
1131 set_kset_name("s3c24xx-dma"),
1132 .suspend = s3c2410_dma_suspend,
1133 .resume = s3c2410_dma_resume,
1134};
1135
1136/* kmem cache implementation */
1137
1138static void s3c2410_dma_cache_ctor(void *p, kmem_cache_t *c, unsigned long f)
1139{
1140 memset(p, 0, sizeof(s3c2410_dma_buf_t));
1141}
1142
1143
1144/* initialisation code */
1145
1146static int __init s3c2410_init_dma(void)
1147{
1148 s3c2410_dma_chan_t *cp;
1149 int channel;
1150 int ret;
1151
1152 printk("S3C2410 DMA Driver, (c) 2003-2004 Simtec Electronics\n");
1153
Lucas Correia Villa Real0367a8d2006-01-26 15:20:50 +00001154 dma_base = ioremap(S3C24XX_PA_DMA, 0x200);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 if (dma_base == NULL) {
1156 printk(KERN_ERR "dma failed to remap register block\n");
1157 return -ENOMEM;
1158 }
1159
1160 ret = sysdev_class_register(&dma_sysclass);
1161 if (ret != 0) {
1162 printk(KERN_ERR "dma sysclass registration failed\n");
1163 goto err;
1164 }
1165
1166 dma_kmem = kmem_cache_create("dma_desc", sizeof(s3c2410_dma_buf_t), 0,
1167 SLAB_HWCACHE_ALIGN,
1168 s3c2410_dma_cache_ctor, NULL);
1169
1170 if (dma_kmem == NULL) {
1171 printk(KERN_ERR "dma failed to make kmem cache\n");
1172 ret = -ENOMEM;
1173 goto err;
1174 }
1175
1176 for (channel = 0; channel < S3C2410_DMA_CHANNELS; channel++) {
1177 cp = &s3c2410_chans[channel];
1178
1179 memset(cp, 0, sizeof(s3c2410_dma_chan_t));
1180
1181 /* dma channel irqs are in order.. */
1182 cp->number = channel;
1183 cp->irq = channel + IRQ_DMA0;
1184 cp->regs = dma_base + (channel*0x40);
1185
1186 /* point current stats somewhere */
1187 cp->stats = &cp->stats_store;
1188 cp->stats_store.timeout_shortest = LONG_MAX;
1189
1190 /* basic channel configuration */
1191
1192 cp->load_timeout = 1<<18;
1193
1194 /* register system device */
1195
1196 cp->dev.cls = &dma_sysclass;
1197 cp->dev.id = channel;
1198 ret = sysdev_register(&cp->dev);
1199
1200 printk("DMA channel %d at %p, irq %d\n",
1201 cp->number, cp->regs, cp->irq);
1202 }
1203
1204 return 0;
1205
1206 err:
1207 kmem_cache_destroy(dma_kmem);
1208 iounmap(dma_base);
1209 dma_base = NULL;
1210 return ret;
1211}
1212
1213__initcall(s3c2410_init_dma);