Merge branch 'upstream-fixes' into upstream
[linux-2.6/mini2440.git] / arch / arm / mach-s3c2410 / dma.c
blob094cc52745c52e0adaa85a5d87bc947486f480c5
1 /* linux/arch/arm/mach-bast/dma.c
3 * (c) 2003-2005 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
6 * S3C2410 DMA core
8 * http://www.simtec.co.uk/products/EB2410ITX/
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.
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
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.
30 * The re-write is pretty much complete, and should be good enough for any
31 * possible DMA function
35 #ifdef CONFIG_S3C2410_DMA_DEBUG
36 #define DEBUG
37 #endif
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>
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>
55 #include <asm/mach/dma.h>
56 #include <asm/arch/map.h>
58 /* io map for dma */
59 static void __iomem *dma_base;
60 static kmem_cache_t *dma_kmem;
62 /* dma channel state information */
63 s3c2410_dma_chan_t s3c2410_chans[S3C2410_DMA_CHANNELS];
65 /* debugging functions */
67 #define BUF_MAGIC (0xcafebabe)
69 #define dmawarn(fmt...) printk(KERN_DEBUG fmt)
71 #define dma_regaddr(chan, reg) ((chan)->regs + (reg))
73 #if 1
74 #define dma_wrreg(chan, reg, val) writel((val), (chan)->regs + (reg))
75 #else
76 static inline void
77 dma_wrreg(s3c2410_dma_chan_t *chan, int reg, unsigned long val)
79 pr_debug("writing %08x to register %08x\n",(unsigned int)val,reg);
80 writel(val, dma_regaddr(chan, reg));
83 #endif
85 #define dma_rdreg(chan, reg) readl((chan)->regs + (reg))
87 /* captured register state for debug */
89 struct s3c2410_dma_regstate {
90 unsigned long dcsrc;
91 unsigned long disrc;
92 unsigned long dstat;
93 unsigned long dcon;
94 unsigned long dmsktrig;
97 #ifdef CONFIG_S3C2410_DMA_DEBUG
99 /* dmadbg_showregs
101 * simple debug routine to print the current state of the dma registers
104 static void
105 dmadbg_capture(s3c2410_dma_chan_t *chan, struct s3c2410_dma_regstate *regs)
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);
114 static void
115 dmadbg_showregs(const char *fname, int line, s3c2410_dma_chan_t *chan,
116 struct s3c2410_dma_regstate *regs)
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);
124 static void
125 dmadbg_showchan(const char *fname, int line, s3c2410_dma_chan_t *chan)
127 struct s3c2410_dma_regstate state;
129 dmadbg_capture(chan, &state);
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);
135 dmadbg_showregs(fname, line, chan, &state);
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 */
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)
152 /* s3c2410_dma_stats_timeout
154 * Update DMA stats from timeout info
157 static void
158 s3c2410_dma_stats_timeout(s3c2410_dma_stats_t *stats, int val)
160 if (stats == NULL)
161 return;
163 if (val > stats->timeout_longest)
164 stats->timeout_longest = val;
165 if (val < stats->timeout_shortest)
166 stats->timeout_shortest = val;
168 stats->timeout_avg += val;
171 /* s3c2410_dma_waitforload
173 * wait for the DMA engine to load a buffer, and update the state accordingly
176 static int
177 s3c2410_dma_waitforload(s3c2410_dma_chan_t *chan, int line)
179 int timeout = chan->load_timeout;
180 int took;
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;
187 if (chan->stats != NULL)
188 chan->stats->loads++;
190 while (--timeout > 0) {
191 if ((dma_rdreg(chan, S3C2410_DMA_DSTAT) << (32-20)) != 0) {
192 took = chan->load_timeout - timeout;
194 s3c2410_dma_stats_timeout(chan->stats, took);
196 switch (chan->load_state) {
197 case S3C2410_DMALOAD_1LOADED:
198 chan->load_state = S3C2410_DMALOAD_1RUNNING;
199 break;
201 default:
202 printk(KERN_ERR "dma%d: unknown load_state in s3c2410_dma_waitforload() %d\n", chan->number, chan->load_state);
205 return 1;
209 if (chan->stats != NULL) {
210 chan->stats->timeout_failed++;
213 return 0;
218 /* s3c2410_dma_loadbuffer
220 * load a buffer, and update the channel state
223 static inline int
224 s3c2410_dma_loadbuffer(s3c2410_dma_chan_t *chan,
225 s3c2410_dma_buf_t *buf)
227 unsigned long reload;
229 pr_debug("s3c2410_chan_loadbuffer: loading buff %p (0x%08lx,0x%06x)\n",
230 buf, (unsigned long)buf->data, buf->size);
232 if (buf == NULL) {
233 dmawarn("buffer is NULL\n");
234 return -EINVAL;
237 /* check the state of the channel before we do anything */
239 if (chan->load_state == S3C2410_DMALOAD_1LOADED) {
240 dmawarn("load_state is S3C2410_DMALOAD_1LOADED\n");
243 if (chan->load_state == S3C2410_DMALOAD_1LOADED_1RUNNING) {
244 dmawarn("state is S3C2410_DMALOAD_1LOADED_1RUNNING\n");
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...
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;
260 writel(buf->data, chan->addr_reg);
262 dma_wrreg(chan, S3C2410_DMA_DCON,
263 chan->dcon | reload | (buf->size/chan->xfer_unit));
265 chan->next = buf->next;
267 /* update the state of the channel */
269 switch (chan->load_state) {
270 case S3C2410_DMALOAD_NONE:
271 chan->load_state = S3C2410_DMALOAD_1LOADED;
272 break;
274 case S3C2410_DMALOAD_1RUNNING:
275 chan->load_state = S3C2410_DMALOAD_1LOADED_1RUNNING;
276 break;
278 default:
279 dmawarn("dmaload: unknown state %d in loadbuffer\n",
280 chan->load_state);
281 break;
284 return 0;
287 /* s3c2410_dma_call_op
289 * small routine to call the op routine with the given op if it has been
290 * registered
293 static void
294 s3c2410_dma_call_op(s3c2410_dma_chan_t *chan, s3c2410_chan_op_t op)
296 if (chan->op_fn != NULL) {
297 (chan->op_fn)(chan, op);
301 /* s3c2410_dma_buffdone
303 * small wrapper to check if callback routine needs to be called, and
304 * if so, call it
307 static inline void
308 s3c2410_dma_buffdone(s3c2410_dma_chan_t *chan, s3c2410_dma_buf_t *buf,
309 s3c2410_dma_buffresult_t result)
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);
314 if (chan->callback_fn != NULL) {
315 (chan->callback_fn)(chan, buf->id, buf->size, result);
319 /* s3c2410_dma_start
321 * start a dma channel going
324 static int s3c2410_dma_start(s3c2410_dma_chan_t *chan)
326 unsigned long tmp;
327 unsigned long flags;
329 pr_debug("s3c2410_start_dma: channel=%d\n", chan->number);
331 local_irq_save(flags);
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;
339 chan->state = S3C2410_DMA_RUNNING;
341 /* check wether there is anything to load, and if not, see
342 * if we can find anything to load
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;
354 s3c2410_dma_loadbuffer(chan, chan->next);
357 dbg_showchan(chan);
359 /* enable the channel */
361 if (!chan->irq_enabled) {
362 enable_irq(chan->irq);
363 chan->irq_enabled = 1;
366 /* start the channel going */
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);
373 pr_debug("wrote %08lx to DMASKTRIG\n", tmp);
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
383 s3c2410_dma_call_op(chan, S3C2410_DMAOP_START);
385 dbg_showchan(chan);
387 local_irq_restore(flags);
388 return 0;
391 /* s3c2410_dma_canload
393 * work out if we can queue another buffer into the DMA engine
396 static int
397 s3c2410_dma_canload(s3c2410_dma_chan_t *chan)
399 if (chan->load_state == S3C2410_DMALOAD_NONE ||
400 chan->load_state == S3C2410_DMALOAD_1RUNNING)
401 return 1;
403 return 0;
407 /* s3c2410_dma_enqueue
409 * queue an given buffer for dma transfer.
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
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.
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.
424 int s3c2410_dma_enqueue(unsigned int channel, void *id,
425 dma_addr_t data, int size)
427 s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
428 s3c2410_dma_buf_t *buf;
429 unsigned long flags;
431 check_channel(channel);
433 pr_debug("%s: id=%p, data=%08x, size=%d\n",
434 __FUNCTION__, id, (unsigned int)data, size);
436 buf = kmem_cache_alloc(dma_kmem, GFP_ATOMIC);
437 if (buf == NULL) {
438 pr_debug("%s: out of memory (%ld alloc)\n",
439 __FUNCTION__, sizeof(*buf));
440 return -ENOMEM;
443 pr_debug("%s: new buffer %p\n", __FUNCTION__, buf);
445 //dbg_showchan(chan);
447 buf->next = NULL;
448 buf->data = buf->ptr = data;
449 buf->size = size;
450 buf->id = id;
451 buf->magic = BUF_MAGIC;
453 local_irq_save(flags);
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);
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);
467 if (chan->end == NULL)
468 pr_debug("dma%d: %s: %p not empty, and chan->end==NULL?\n",
469 chan->number, __FUNCTION__, chan);
471 chan->end->next = buf;
472 chan->end = buf;
475 /* if necessary, update the next buffer field */
476 if (chan->next == NULL)
477 chan->next = buf;
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;
492 while (s3c2410_dma_canload(chan) && chan->next != NULL) {
493 s3c2410_dma_loadbuffer(chan, chan->next);
495 } else if (chan->state == S3C2410_DMA_IDLE) {
496 if (chan->flags & S3C2410_DMAF_AUTOSTART) {
497 s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_START);
501 local_irq_restore(flags);
502 return 0;
505 EXPORT_SYMBOL(s3c2410_dma_enqueue);
507 static inline void
508 s3c2410_dma_freebuf(s3c2410_dma_buf_t *buf)
510 int magicok = (buf->magic == BUF_MAGIC);
512 buf->magic = -1;
514 if (magicok) {
515 kmem_cache_free(dma_kmem, buf);
516 } else {
517 printk("s3c2410_dma_freebuf: buff %p with bad magic\n", buf);
521 /* s3c2410_dma_lastxfer
523 * called when the system is out of buffers, to ensure that the channel
524 * is prepared for shutdown.
527 static inline void
528 s3c2410_dma_lastxfer(s3c2410_dma_chan_t *chan)
530 pr_debug("dma%d: s3c2410_dma_lastxfer: load_state %d\n",
531 chan->number, chan->load_state);
533 switch (chan->load_state) {
534 case S3C2410_DMALOAD_NONE:
535 break;
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;
544 break;
546 default:
547 pr_debug("dma%d: lastxfer: unhandled load_state %d with no next",
548 chan->number, chan->load_state);
549 return;
553 /* hopefully this'll shut the damned thing up after the transfer... */
554 dma_wrreg(chan, S3C2410_DMA_DCON, chan->dcon | S3C2410_DCON_NORELOAD);
558 #define dmadbg2(x...)
560 static irqreturn_t
561 s3c2410_dma_irq(int irq, void *devpw, struct pt_regs *regs)
563 s3c2410_dma_chan_t *chan = (s3c2410_dma_chan_t *)devpw;
564 s3c2410_dma_buf_t *buf;
566 buf = chan->curr;
568 dbg_showchan(chan);
570 /* modify the channel state */
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 */
578 chan->load_state = S3C2410_DMALOAD_NONE;
579 break;
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.
587 chan->load_state = S3C2410_DMALOAD_NONE;
588 break;
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
597 chan->load_state = S3C2410_DMALOAD_1LOADED;
598 break;
600 case S3C2410_DMALOAD_NONE:
601 printk(KERN_ERR "dma%d: IRQ with no loaded buffer?\n",
602 chan->number);
603 break;
605 default:
606 printk(KERN_ERR "dma%d: IRQ in invalid load_state %d\n",
607 chan->number, chan->load_state);
608 break;
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 */
616 chan->curr = buf->next;
617 buf->next = NULL;
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;
625 s3c2410_dma_buffdone(chan, buf, S3C2410_RES_OK);
627 /* free resouces */
628 s3c2410_dma_freebuf(buf);
629 } else {
632 if (chan->next != NULL) {
633 unsigned long flags;
635 switch (chan->load_state) {
636 case S3C2410_DMALOAD_1RUNNING:
637 /* don't need to do anything for this state */
638 break;
640 case S3C2410_DMALOAD_NONE:
641 /* can load buffer immediately */
642 break;
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;
652 break;
654 case S3C2410_DMALOAD_1LOADED_1RUNNING:
655 goto no_load;
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;
663 local_irq_save(flags);
664 s3c2410_dma_loadbuffer(chan, chan->next);
665 local_irq_restore(flags);
666 } else {
667 s3c2410_dma_lastxfer(chan);
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);
677 no_load:
678 return IRQ_HANDLED;
683 /* s3c2410_request_dma
685 * get control of an dma channel
688 int s3c2410_dma_request(unsigned int channel, s3c2410_dma_client_t *client,
689 void *dev)
691 s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
692 unsigned long flags;
693 int err;
695 pr_debug("dma%d: s3c2410_request_dma: client=%s, dev=%p\n",
696 channel, client->name, dev);
698 check_channel(channel);
700 local_irq_save(flags);
702 dbg_showchan(chan);
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);
714 chan->client = client;
715 chan->in_use = 1;
717 if (!chan->irq_claimed) {
718 pr_debug("dma%d: %s : requesting irq %d\n",
719 channel, __FUNCTION__, chan->irq);
721 err = request_irq(chan->irq, s3c2410_dma_irq, IRQF_DISABLED,
722 client->name, (void *)chan);
724 if (err) {
725 chan->in_use = 0;
726 local_irq_restore(flags);
728 printk(KERN_ERR "%s: cannot get IRQ %d for DMA %d\n",
729 client->name, chan->irq, chan->number);
730 return err;
733 chan->irq_claimed = 1;
734 chan->irq_enabled = 1;
737 local_irq_restore(flags);
739 /* need to setup */
741 pr_debug("%s: channel initialised, %p\n", __FUNCTION__, chan);
743 return 0;
746 EXPORT_SYMBOL(s3c2410_dma_request);
748 /* s3c2410_dma_free
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.
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.
759 int s3c2410_dma_free(dmach_t channel, s3c2410_dma_client_t *client)
761 s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
762 unsigned long flags;
764 check_channel(channel);
766 local_irq_save(flags);
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);
774 /* sort out stopping and freeing the channel */
776 if (chan->state != S3C2410_DMA_IDLE) {
777 pr_debug("%s: need to stop dma channel %p\n",
778 __FUNCTION__, chan);
780 /* possibly flush the channel */
781 s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STOP);
784 chan->client = NULL;
785 chan->in_use = 0;
787 if (chan->irq_claimed)
788 free_irq(chan->irq, (void *)chan);
789 chan->irq_claimed = 0;
791 local_irq_restore(flags);
793 return 0;
796 EXPORT_SYMBOL(s3c2410_dma_free);
798 static int s3c2410_dma_dostop(s3c2410_dma_chan_t *chan)
800 unsigned long tmp;
801 unsigned long flags;
803 pr_debug("%s:\n", __FUNCTION__);
805 dbg_showchan(chan);
807 local_irq_save(flags);
809 s3c2410_dma_call_op(chan, S3C2410_DMAOP_STOP);
811 tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
812 tmp |= S3C2410_DMASKTRIG_STOP;
813 dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp);
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
822 chan->state = S3C2410_DMA_IDLE;
823 chan->load_state = S3C2410_DMALOAD_NONE;
825 local_irq_restore(flags);
827 return 0;
830 /* s3c2410_dma_flush
832 * stop the channel, and remove all current and pending transfers
835 static int s3c2410_dma_flush(s3c2410_dma_chan_t *chan)
837 s3c2410_dma_buf_t *buf, *next;
838 unsigned long flags;
840 pr_debug("%s:\n", __FUNCTION__);
842 local_irq_save(flags);
844 if (chan->state != S3C2410_DMA_IDLE) {
845 pr_debug("%s: stopping channel...\n", __FUNCTION__ );
846 s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_STOP);
849 buf = chan->curr;
850 if (buf == NULL)
851 buf = chan->next;
853 chan->curr = chan->next = chan->end = NULL;
855 if (buf != NULL) {
856 for ( ; buf != NULL; buf = next) {
857 next = buf->next;
859 pr_debug("%s: free buffer %p, next %p\n",
860 __FUNCTION__, buf, buf->next);
862 s3c2410_dma_buffdone(chan, buf, S3C2410_RES_ABORT);
863 s3c2410_dma_freebuf(buf);
867 local_irq_restore(flags);
869 return 0;
874 s3c2410_dma_ctrl(dmach_t channel, s3c2410_chan_op_t op)
876 s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
878 check_channel(channel);
880 switch (op) {
881 case S3C2410_DMAOP_START:
882 return s3c2410_dma_start(chan);
884 case S3C2410_DMAOP_STOP:
885 return s3c2410_dma_dostop(chan);
887 case S3C2410_DMAOP_PAUSE:
888 return -ENOENT;
890 case S3C2410_DMAOP_RESUME:
891 return -ENOENT;
893 case S3C2410_DMAOP_FLUSH:
894 return s3c2410_dma_flush(chan);
896 case S3C2410_DMAOP_TIMEOUT:
897 return 0;
901 return -ENOENT; /* unknown, don't bother */
904 EXPORT_SYMBOL(s3c2410_dma_ctrl);
906 /* DMA configuration for each channel
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
914 /* s3c2410_dma_config
916 * xfersize: size of unit in bytes (1,2,4)
917 * dcon: base value of the DCONx register
920 int s3c2410_dma_config(dmach_t channel,
921 int xferunit,
922 int dcon)
924 s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
926 pr_debug("%s: chan=%d, xfer_unit=%d, dcon=%08x\n",
927 __FUNCTION__, channel, xferunit, dcon);
929 check_channel(channel);
931 switch (xferunit) {
932 case 1:
933 dcon |= S3C2410_DCON_BYTE;
934 break;
936 case 2:
937 dcon |= S3C2410_DCON_HALFWORD;
938 break;
940 case 4:
941 dcon |= S3C2410_DCON_WORD;
942 break;
944 default:
945 pr_debug("%s: bad transfer size %d\n", __FUNCTION__, xferunit);
946 return -EINVAL;
949 dcon |= S3C2410_DCON_HWTRIG;
950 dcon |= S3C2410_DCON_INTREQ;
952 pr_debug("%s: dcon now %08x\n", __FUNCTION__, dcon);
954 chan->dcon = dcon;
955 chan->xfer_unit = xferunit;
957 return 0;
960 EXPORT_SYMBOL(s3c2410_dma_config);
962 int s3c2410_dma_setflags(dmach_t channel, unsigned int flags)
964 s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
966 check_channel(channel);
968 pr_debug("%s: chan=%p, flags=%08x\n", __FUNCTION__, chan, flags);
970 chan->flags = flags;
972 return 0;
975 EXPORT_SYMBOL(s3c2410_dma_setflags);
978 /* do we need to protect the settings of the fields from
979 * irq?
982 int s3c2410_dma_set_opfn(dmach_t channel, s3c2410_dma_opfn_t rtn)
984 s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
986 check_channel(channel);
988 pr_debug("%s: chan=%p, op rtn=%p\n", __FUNCTION__, chan, rtn);
990 chan->op_fn = rtn;
992 return 0;
995 EXPORT_SYMBOL(s3c2410_dma_set_opfn);
997 int s3c2410_dma_set_buffdone_fn(dmach_t channel, s3c2410_dma_cbfn_t rtn)
999 s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
1001 check_channel(channel);
1003 pr_debug("%s: chan=%p, callback rtn=%p\n", __FUNCTION__, chan, rtn);
1005 chan->callback_fn = rtn;
1007 return 0;
1010 EXPORT_SYMBOL(s3c2410_dma_set_buffdone_fn);
1012 /* s3c2410_dma_devconfig
1014 * configure the dma source/destination hardware type and address
1016 * source: S3C2410_DMASRC_HW: source is hardware
1017 * S3C2410_DMASRC_MEM: source is memory
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
1023 * devaddr: physical address of the source
1026 int s3c2410_dma_devconfig(int channel,
1027 s3c2410_dmasrc_t source,
1028 int hwcfg,
1029 unsigned long devaddr)
1031 s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
1033 check_channel(channel);
1035 pr_debug("%s: source=%d, hwcfg=%08x, devaddr=%08lx\n",
1036 __FUNCTION__, (int)source, hwcfg, devaddr);
1038 chan->source = source;
1039 chan->dev_addr = devaddr;
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));
1050 chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DIDST);
1051 return 0;
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);
1061 chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DISRC);
1062 return 0;
1065 printk(KERN_ERR "dma%d: invalid source type (%d)\n", channel, source);
1066 return -EINVAL;
1069 EXPORT_SYMBOL(s3c2410_dma_devconfig);
1071 /* s3c2410_dma_getposition
1073 * returns the current transfer points for the dma source and destination
1076 int s3c2410_dma_getposition(dmach_t channel, dma_addr_t *src, dma_addr_t *dst)
1078 s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
1080 check_channel(channel);
1082 if (src != NULL)
1083 *src = dma_rdreg(chan, S3C2410_DMA_DCSRC);
1085 if (dst != NULL)
1086 *dst = dma_rdreg(chan, S3C2410_DMA_DCDST);
1088 return 0;
1091 EXPORT_SYMBOL(s3c2410_dma_getposition);
1094 /* system device class */
1096 #ifdef CONFIG_PM
1098 static int s3c2410_dma_suspend(struct sys_device *dev, pm_message_t state)
1100 s3c2410_dma_chan_t *cp = container_of(dev, s3c2410_dma_chan_t, dev);
1102 printk(KERN_DEBUG "suspending dma channel %d\n", cp->number);
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.
1111 printk(KERN_INFO "dma: stopping channel %d due to suspend\n",
1112 cp->number);
1114 s3c2410_dma_dostop(cp);
1117 return 0;
1120 static int s3c2410_dma_resume(struct sys_device *dev)
1122 return 0;
1125 #else
1126 #define s3c2410_dma_suspend NULL
1127 #define s3c2410_dma_resume NULL
1128 #endif /* CONFIG_PM */
1130 static struct sysdev_class dma_sysclass = {
1131 set_kset_name("s3c24xx-dma"),
1132 .suspend = s3c2410_dma_suspend,
1133 .resume = s3c2410_dma_resume,
1136 /* kmem cache implementation */
1138 static void s3c2410_dma_cache_ctor(void *p, kmem_cache_t *c, unsigned long f)
1140 memset(p, 0, sizeof(s3c2410_dma_buf_t));
1144 /* initialisation code */
1146 static int __init s3c2410_init_dma(void)
1148 s3c2410_dma_chan_t *cp;
1149 int channel;
1150 int ret;
1152 printk("S3C2410 DMA Driver, (c) 2003-2004 Simtec Electronics\n");
1154 dma_base = ioremap(S3C24XX_PA_DMA, 0x200);
1155 if (dma_base == NULL) {
1156 printk(KERN_ERR "dma failed to remap register block\n");
1157 return -ENOMEM;
1160 ret = sysdev_class_register(&dma_sysclass);
1161 if (ret != 0) {
1162 printk(KERN_ERR "dma sysclass registration failed\n");
1163 goto err;
1166 dma_kmem = kmem_cache_create("dma_desc", sizeof(s3c2410_dma_buf_t), 0,
1167 SLAB_HWCACHE_ALIGN,
1168 s3c2410_dma_cache_ctor, NULL);
1170 if (dma_kmem == NULL) {
1171 printk(KERN_ERR "dma failed to make kmem cache\n");
1172 ret = -ENOMEM;
1173 goto err;
1176 for (channel = 0; channel < S3C2410_DMA_CHANNELS; channel++) {
1177 cp = &s3c2410_chans[channel];
1179 memset(cp, 0, sizeof(s3c2410_dma_chan_t));
1181 /* dma channel irqs are in order.. */
1182 cp->number = channel;
1183 cp->irq = channel + IRQ_DMA0;
1184 cp->regs = dma_base + (channel*0x40);
1186 /* point current stats somewhere */
1187 cp->stats = &cp->stats_store;
1188 cp->stats_store.timeout_shortest = LONG_MAX;
1190 /* basic channel configuration */
1192 cp->load_timeout = 1<<18;
1194 /* register system device */
1196 cp->dev.cls = &dma_sysclass;
1197 cp->dev.id = channel;
1198 ret = sysdev_register(&cp->dev);
1200 printk("DMA channel %d at %p, irq %d\n",
1201 cp->number, cp->regs, cp->irq);
1204 return 0;
1206 err:
1207 kmem_cache_destroy(dma_kmem);
1208 iounmap(dma_base);
1209 dma_base = NULL;
1210 return ret;
1213 __initcall(s3c2410_init_dma);