1a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* linux/arch/arm/plat-s3c24xx/dma.c
2a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks *
3e02f866456ec31d20649670e3af048ddc2a3892bBen Dooks * Copyright 2003-2006 Simtec Electronics
4a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks *	Ben Dooks <ben@simtec.co.uk>
5a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks *
6a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * S3C2410 DMA core
7a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks *
8a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * http://armlinux.simtec.co.uk/
9a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks *
10a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * This program is free software; you can redistribute it and/or modify
11a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * it under the terms of the GNU General Public License version 2 as
12a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * published by the Free Software Foundation.
13a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks*/
14a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
15a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
16a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#ifdef CONFIG_S3C2410_DMA_DEBUG
17a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#define DEBUG
18a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#endif
19a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
20a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#include <linux/module.h>
21a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#include <linux/init.h>
22a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#include <linux/sched.h>
23a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#include <linux/spinlock.h>
24a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#include <linux/interrupt.h>
25bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysocki#include <linux/syscore_ops.h>
26a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#include <linux/slab.h>
27a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#include <linux/errno.h>
28fced80c735941fa518ac67c0b61bbe153fb8c050Russell King#include <linux/io.h>
29a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
30a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#include <asm/irq.h>
31a09e64fbc0094e3073dbb09c3b4bfe4ab669244bRussell King#include <mach/hardware.h>
32dcea83adc666061864b82c96e059dffe7268b512Russell King#include <mach/dma.h>
33a09e64fbc0094e3073dbb09c3b4bfe4ab669244bRussell King#include <mach/map.h>
34a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
35992426bfe98e71db1ce767fd66f6c68ed18fcc14Ben Dooks#include <plat/dma-s3c24xx.h>
3644dc94045f6ddbc07db3e0eb3448c2efc13ac2cfBen Dooks#include <plat/regs-dma.h>
37a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
38a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* io map for dma */
39a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksstatic void __iomem *dma_base;
40a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksstatic struct kmem_cache *dma_kmem;
41a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
4248adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooksstatic int dma_channels;
4348adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooks
44a7717435656c874843b1742383cc37540f5ff91eBen Dooksstatic struct s3c24xx_dma_selection dma_sel;
45a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
46a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
47a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* debugging functions */
48a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
49a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#define BUF_MAGIC (0xcafebabe)
50a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
51a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#define dmawarn(fmt...) printk(KERN_DEBUG fmt)
52a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
53a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#define dma_regaddr(chan, reg) ((chan)->regs + (reg))
54a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
55a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#if 1
56a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#define dma_wrreg(chan, reg, val) writel((val), (chan)->regs + (reg))
57a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#else
58a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksstatic inline void
59a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksdma_wrreg(struct s3c2410_dma_chan *chan, int reg, unsigned long val)
60a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{
61a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	pr_debug("writing %08x to register %08x\n",(unsigned int)val,reg);
62a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	writel(val, dma_regaddr(chan, reg));
63a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks}
64a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#endif
65a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
66a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#define dma_rdreg(chan, reg) readl((chan)->regs + (reg))
67a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
68a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* captured register state for debug */
69a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
70a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksstruct s3c2410_dma_regstate {
71a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	unsigned long         dcsrc;
72a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	unsigned long         disrc;
73a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	unsigned long         dstat;
74a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	unsigned long         dcon;
75a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	unsigned long         dmsktrig;
76a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks};
77a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
78a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#ifdef CONFIG_S3C2410_DMA_DEBUG
79a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
80a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* dmadbg_showregs
81a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks *
82a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * simple debug routine to print the current state of the dma registers
83a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks*/
84a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
85a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksstatic void
86a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksdmadbg_capture(struct s3c2410_dma_chan *chan, struct s3c2410_dma_regstate *regs)
87a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{
88a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	regs->dcsrc    = dma_rdreg(chan, S3C2410_DMA_DCSRC);
89a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	regs->disrc    = dma_rdreg(chan, S3C2410_DMA_DISRC);
90a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	regs->dstat    = dma_rdreg(chan, S3C2410_DMA_DSTAT);
91a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	regs->dcon     = dma_rdreg(chan, S3C2410_DMA_DCON);
92a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	regs->dmsktrig = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
93a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks}
94a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
95a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksstatic void
96a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksdmadbg_dumpregs(const char *fname, int line, struct s3c2410_dma_chan *chan,
97a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		 struct s3c2410_dma_regstate *regs)
98a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{
99a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	printk(KERN_DEBUG "dma%d: %s:%d: DCSRC=%08lx, DISRC=%08lx, DSTAT=%08lx DMT=%02lx, DCON=%08lx\n",
100a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	       chan->number, fname, line,
101a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	       regs->dcsrc, regs->disrc, regs->dstat, regs->dmsktrig,
102a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	       regs->dcon);
103a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks}
104a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
105a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksstatic void
106a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksdmadbg_showchan(const char *fname, int line, struct s3c2410_dma_chan *chan)
107a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{
108a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	struct s3c2410_dma_regstate state;
109a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
110a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	dmadbg_capture(chan, &state);
111a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
112a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	printk(KERN_DEBUG "dma%d: %s:%d: ls=%d, cur=%p, %p %p\n",
113a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	       chan->number, fname, line, chan->load_state,
114a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	       chan->curr, chan->next, chan->end);
115a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
116a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	dmadbg_dumpregs(fname, line, chan, &state);
117a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks}
118a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
119a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksstatic void
120a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksdmadbg_showregs(const char *fname, int line, struct s3c2410_dma_chan *chan)
121a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{
122a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	struct s3c2410_dma_regstate state;
123a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
124a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	dmadbg_capture(chan, &state);
125a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	dmadbg_dumpregs(fname, line, chan, &state);
126a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks}
127a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1288e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison#define dbg_showregs(chan) dmadbg_showregs(__func__, __LINE__, (chan))
1298e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison#define dbg_showchan(chan) dmadbg_showchan(__func__, __LINE__, (chan))
130a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#else
131a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#define dbg_showregs(chan) do { } while(0)
132a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#define dbg_showchan(chan) do { } while(0)
133a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#endif /* CONFIG_S3C2410_DMA_DEBUG */
134a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
135a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* s3c2410_dma_stats_timeout
136a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks *
137a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * Update DMA stats from timeout info
138a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks*/
139a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
140a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksstatic void
141a21765a70ec06be175d3997320a83fa66fcc8955Ben Dookss3c2410_dma_stats_timeout(struct s3c2410_dma_stats *stats, int val)
142a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{
143a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	if (stats == NULL)
144a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		return;
145a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
146a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	if (val > stats->timeout_longest)
147a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		stats->timeout_longest = val;
148a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	if (val < stats->timeout_shortest)
149a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		stats->timeout_shortest = val;
150a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
151a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	stats->timeout_avg += val;
152a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks}
153a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
154a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* s3c2410_dma_waitforload
155a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks *
156a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * wait for the DMA engine to load a buffer, and update the state accordingly
157a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks*/
158a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
159a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksstatic int
160a21765a70ec06be175d3997320a83fa66fcc8955Ben Dookss3c2410_dma_waitforload(struct s3c2410_dma_chan *chan, int line)
161a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{
162a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	int timeout = chan->load_timeout;
163a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	int took;
164a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
165a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	if (chan->load_state != S3C2410_DMALOAD_1LOADED) {
166a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		printk(KERN_ERR "dma%d: s3c2410_dma_waitforload() called in loadstate %d from line %d\n", chan->number, chan->load_state, line);
167a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		return 0;
168a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	}
169a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
170a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	if (chan->stats != NULL)
171a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		chan->stats->loads++;
172a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
173a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	while (--timeout > 0) {
174a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		if ((dma_rdreg(chan, S3C2410_DMA_DSTAT) << (32-20)) != 0) {
175a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			took = chan->load_timeout - timeout;
176a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
177a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			s3c2410_dma_stats_timeout(chan->stats, took);
178a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
179a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			switch (chan->load_state) {
180a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			case S3C2410_DMALOAD_1LOADED:
181a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks				chan->load_state = S3C2410_DMALOAD_1RUNNING;
182a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks				break;
183a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
184a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			default:
185a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks				printk(KERN_ERR "dma%d: unknown load_state in s3c2410_dma_waitforload() %d\n", chan->number, chan->load_state);
186a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			}
187a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
188a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			return 1;
189a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		}
190a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	}
191a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
192a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	if (chan->stats != NULL) {
193a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		chan->stats->timeout_failed++;
194a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	}
195a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
196a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	return 0;
197a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks}
198a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
199a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* s3c2410_dma_loadbuffer
200a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks *
201a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * load a buffer, and update the channel state
202a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks*/
203a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
204a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksstatic inline int
205a21765a70ec06be175d3997320a83fa66fcc8955Ben Dookss3c2410_dma_loadbuffer(struct s3c2410_dma_chan *chan,
206a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		       struct s3c2410_dma_buf *buf)
207a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{
208a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	unsigned long reload;
209a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
210a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	if (buf == NULL) {
211a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		dmawarn("buffer is NULL\n");
212a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		return -EINVAL;
213a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	}
214a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
21560e5c1b5ecd99e06d3133a2a20d58d3c2b9968acJulia Lawall	pr_debug("s3c2410_chan_loadbuffer: loading buff %p (0x%08lx,0x%06x)\n",
21660e5c1b5ecd99e06d3133a2a20d58d3c2b9968acJulia Lawall		 buf, (unsigned long)buf->data, buf->size);
21760e5c1b5ecd99e06d3133a2a20d58d3c2b9968acJulia Lawall
218a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	/* check the state of the channel before we do anything */
219a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
220a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	if (chan->load_state == S3C2410_DMALOAD_1LOADED) {
221a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		dmawarn("load_state is S3C2410_DMALOAD_1LOADED\n");
222a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	}
223a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
224a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	if (chan->load_state == S3C2410_DMALOAD_1LOADED_1RUNNING) {
225a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		dmawarn("state is S3C2410_DMALOAD_1LOADED_1RUNNING\n");
226a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	}
227a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
228a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	/* it would seem sensible if we are the last buffer to not bother
229a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	 * with the auto-reload bit, so that the DMA engine will not try
230a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	 * and load another transfer after this one has finished...
231a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	 */
232a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	if (chan->load_state == S3C2410_DMALOAD_NONE) {
233a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		pr_debug("load_state is none, checking for noreload (next=%p)\n",
234a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			 buf->next);
235a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		reload = (buf->next == NULL) ? S3C2410_DCON_NORELOAD : 0;
236a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	} else {
237a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		//pr_debug("load_state is %d => autoreload\n", chan->load_state);
238a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		reload = S3C2410_DCON_AUTORELOAD;
239a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	}
240a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
241a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	if ((buf->data & 0xf0000000) != 0x30000000) {
242a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		dmawarn("dmaload: buffer is %p\n", (void *)buf->data);
243a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	}
244a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
245a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	writel(buf->data, chan->addr_reg);
246a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
247a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	dma_wrreg(chan, S3C2410_DMA_DCON,
248a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		  chan->dcon | reload | (buf->size/chan->xfer_unit));
249a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
250a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	chan->next = buf->next;
251a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
252a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	/* update the state of the channel */
253a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
254a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	switch (chan->load_state) {
255a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	case S3C2410_DMALOAD_NONE:
256a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		chan->load_state = S3C2410_DMALOAD_1LOADED;
257a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		break;
258a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
259a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	case S3C2410_DMALOAD_1RUNNING:
260a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		chan->load_state = S3C2410_DMALOAD_1LOADED_1RUNNING;
261a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		break;
262a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
263a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	default:
264a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		dmawarn("dmaload: unknown state %d in loadbuffer\n",
265a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			chan->load_state);
266a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		break;
267a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	}
268a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
269a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	return 0;
270a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks}
271a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
272a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* s3c2410_dma_call_op
273a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks *
274a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * small routine to call the op routine with the given op if it has been
275a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * registered
276a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks*/
277a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
278a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksstatic void
279a21765a70ec06be175d3997320a83fa66fcc8955Ben Dookss3c2410_dma_call_op(struct s3c2410_dma_chan *chan, enum s3c2410_chan_op op)
280a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{
281a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	if (chan->op_fn != NULL) {
282a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		(chan->op_fn)(chan, op);
283a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	}
284a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks}
285a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
286a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* s3c2410_dma_buffdone
287a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks *
288a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * small wrapper to check if callback routine needs to be called, and
289a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * if so, call it
290a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks*/
291a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
292a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksstatic inline void
293a21765a70ec06be175d3997320a83fa66fcc8955Ben Dookss3c2410_dma_buffdone(struct s3c2410_dma_chan *chan, struct s3c2410_dma_buf *buf,
294a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		     enum s3c2410_dma_buffresult result)
295a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{
296a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#if 0
297a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	pr_debug("callback_fn=%p, buf=%p, id=%p, size=%d, result=%d\n",
298a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		 chan->callback_fn, buf, buf->id, buf->size, result);
299a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#endif
300a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
301a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	if (chan->callback_fn != NULL) {
302a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		(chan->callback_fn)(chan, buf->id, buf->size, result);
303a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	}
304a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks}
305a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
306a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* s3c2410_dma_start
307a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks *
308a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * start a dma channel going
309a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks*/
310a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
311a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksstatic int s3c2410_dma_start(struct s3c2410_dma_chan *chan)
312a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{
313a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	unsigned long tmp;
314a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	unsigned long flags;
315a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
316a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	pr_debug("s3c2410_start_dma: channel=%d\n", chan->number);
317a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
318a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	local_irq_save(flags);
319a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
320a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	if (chan->state == S3C2410_DMA_RUNNING) {
321a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		pr_debug("s3c2410_start_dma: already running (%d)\n", chan->state);
322a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		local_irq_restore(flags);
323a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		return 0;
324a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	}
325a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
326a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	chan->state = S3C2410_DMA_RUNNING;
327a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
328a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	/* check wether there is anything to load, and if not, see
329a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	 * if we can find anything to load
330a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	 */
331a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
332a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	if (chan->load_state == S3C2410_DMALOAD_NONE) {
333a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		if (chan->next == NULL) {
334a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			printk(KERN_ERR "dma%d: channel has nothing loaded\n",
335a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			       chan->number);
336a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			chan->state = S3C2410_DMA_IDLE;
337a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			local_irq_restore(flags);
338a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			return -EINVAL;
339a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		}
340a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
341a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		s3c2410_dma_loadbuffer(chan, chan->next);
342a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	}
343a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
344a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	dbg_showchan(chan);
345a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
346a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	/* enable the channel */
347a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
348a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	if (!chan->irq_enabled) {
349a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		enable_irq(chan->irq);
350a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		chan->irq_enabled = 1;
351a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	}
352a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
353a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	/* start the channel going */
354a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
355a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
356a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	tmp &= ~S3C2410_DMASKTRIG_STOP;
357a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	tmp |= S3C2410_DMASKTRIG_ON;
358a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp);
359a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
360a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	pr_debug("dma%d: %08lx to DMASKTRIG\n", chan->number, tmp);
361a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
362a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#if 0
363a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	/* the dma buffer loads should take care of clearing the AUTO
364a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	 * reloading feature */
365a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	tmp = dma_rdreg(chan, S3C2410_DMA_DCON);
366a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	tmp &= ~S3C2410_DCON_NORELOAD;
367a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	dma_wrreg(chan, S3C2410_DMA_DCON, tmp);
368a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#endif
369a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
370a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	s3c2410_dma_call_op(chan, S3C2410_DMAOP_START);
371a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
372a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	dbg_showchan(chan);
373a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
374a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	/* if we've only loaded one buffer onto the channel, then chec
375a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	 * to see if we have another, and if so, try and load it so when
376a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	 * the first buffer is finished, the new one will be loaded onto
377a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	 * the channel */
378a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
379a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	if (chan->next != NULL) {
380a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		if (chan->load_state == S3C2410_DMALOAD_1LOADED) {
381a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
382a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
383a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks				pr_debug("%s: buff not yet loaded, no more todo\n",
3848e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison					 __func__);
385a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			} else {
386a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks				chan->load_state = S3C2410_DMALOAD_1RUNNING;
387a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks				s3c2410_dma_loadbuffer(chan, chan->next);
388a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			}
389a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
390a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		} else if (chan->load_state == S3C2410_DMALOAD_1RUNNING) {
391a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			s3c2410_dma_loadbuffer(chan, chan->next);
392a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		}
393a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	}
394a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
395a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
396a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	local_irq_restore(flags);
397a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
398a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	return 0;
399a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks}
400a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
401a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* s3c2410_dma_canload
402a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks *
403a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * work out if we can queue another buffer into the DMA engine
404a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks*/
405a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
406a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksstatic int
407a21765a70ec06be175d3997320a83fa66fcc8955Ben Dookss3c2410_dma_canload(struct s3c2410_dma_chan *chan)
408a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{
409a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	if (chan->load_state == S3C2410_DMALOAD_NONE ||
410a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	    chan->load_state == S3C2410_DMALOAD_1RUNNING)
411a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		return 1;
412a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
413a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	return 0;
414a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks}
415a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
416a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* s3c2410_dma_enqueue
417a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks *
418a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * queue an given buffer for dma transfer.
419a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks *
420a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * id         the device driver's id information for this buffer
421a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * data       the physical address of the buffer data
422a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * size       the size of the buffer in bytes
423a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks *
424a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * If the channel is not running, then the flag S3C2410_DMAF_AUTOSTART
425a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * is checked, and if set, the channel is started. If this flag isn't set,
426a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * then an error will be returned.
427a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks *
428a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * It is possible to queue more than one DMA buffer onto a channel at
429a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * once, and the code will deal with the re-loading of the next buffer
430a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * when necessary.
431a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks*/
432a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
433a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksint s3c2410_dma_enqueue(unsigned int channel, void *id,
434a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			dma_addr_t data, int size)
435a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{
43697c1b145231730e62dd71921ec653315a1da3aadBen Dooks	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
437a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	struct s3c2410_dma_buf *buf;
438a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	unsigned long flags;
439a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
440a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	if (chan == NULL)
441a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		return -EINVAL;
442a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
443a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	pr_debug("%s: id=%p, data=%08x, size=%d\n",
4448e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison		 __func__, id, (unsigned int)data, size);
445a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
446a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	buf = kmem_cache_alloc(dma_kmem, GFP_ATOMIC);
447a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	if (buf == NULL) {
448a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		pr_debug("%s: out of memory (%ld alloc)\n",
4498e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison			 __func__, (long)sizeof(*buf));
450a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		return -ENOMEM;
451a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	}
452a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
4538e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison	//pr_debug("%s: new buffer %p\n", __func__, buf);
454a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	//dbg_showchan(chan);
455a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
456a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	buf->next  = NULL;
457a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	buf->data  = buf->ptr = data;
458a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	buf->size  = size;
459a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	buf->id    = id;
460a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	buf->magic = BUF_MAGIC;
461a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
462a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	local_irq_save(flags);
463a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
464a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	if (chan->curr == NULL) {
465a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		/* we've got nothing loaded... */
466a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		pr_debug("%s: buffer %p queued onto empty channel\n",
4678e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison			 __func__, buf);
468a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
469a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		chan->curr = buf;
470a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		chan->end  = buf;
471a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		chan->next = NULL;
472a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	} else {
473a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		pr_debug("dma%d: %s: buffer %p queued onto non-empty channel\n",
4748e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison			 chan->number, __func__, buf);
475a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
476a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		if (chan->end == NULL)
477a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			pr_debug("dma%d: %s: %p not empty, and chan->end==NULL?\n",
4788e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison				 chan->number, __func__, chan);
479a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
480a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		chan->end->next = buf;
481a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		chan->end = buf;
482a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	}
483a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
484a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	/* if necessary, update the next buffer field */
485a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	if (chan->next == NULL)
486a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		chan->next = buf;
487a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
488a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	/* check to see if we can load a buffer */
489a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	if (chan->state == S3C2410_DMA_RUNNING) {
490a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		if (chan->load_state == S3C2410_DMALOAD_1LOADED && 1) {
491a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
492a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks				printk(KERN_ERR "dma%d: loadbuffer:"
493a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks				       "timeout loading buffer\n",
494a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks				       chan->number);
495a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks				dbg_showchan(chan);
496a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks				local_irq_restore(flags);
497a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks				return -EINVAL;
498a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			}
499a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		}
500a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
501a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		while (s3c2410_dma_canload(chan) && chan->next != NULL) {
502a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			s3c2410_dma_loadbuffer(chan, chan->next);
503a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		}
504a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	} else if (chan->state == S3C2410_DMA_IDLE) {
505a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		if (chan->flags & S3C2410_DMAF_AUTOSTART) {
506046c9d321fd5f5ce1c89c9d0f1a519c26a096486Ben Dooks			s3c2410_dma_ctrl(chan->number | DMACH_LOW_LEVEL,
507046c9d321fd5f5ce1c89c9d0f1a519c26a096486Ben Dooks					 S3C2410_DMAOP_START);
508a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		}
509a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	}
510a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
511a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	local_irq_restore(flags);
512a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	return 0;
513a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks}
514a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
515a21765a70ec06be175d3997320a83fa66fcc8955Ben DooksEXPORT_SYMBOL(s3c2410_dma_enqueue);
516a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
517a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksstatic inline void
518a21765a70ec06be175d3997320a83fa66fcc8955Ben Dookss3c2410_dma_freebuf(struct s3c2410_dma_buf *buf)
519a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{
520a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	int magicok = (buf->magic == BUF_MAGIC);
521a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
522a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	buf->magic = -1;
523a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
524a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	if (magicok) {
525a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		kmem_cache_free(dma_kmem, buf);
526a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	} else {
527a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		printk("s3c2410_dma_freebuf: buff %p with bad magic\n", buf);
528a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	}
529a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks}
530a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
531a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* s3c2410_dma_lastxfer
532a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks *
533a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * called when the system is out of buffers, to ensure that the channel
534a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * is prepared for shutdown.
535a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks*/
536a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
537a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksstatic inline void
538a21765a70ec06be175d3997320a83fa66fcc8955Ben Dookss3c2410_dma_lastxfer(struct s3c2410_dma_chan *chan)
539a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{
540a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#if 0
541a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	pr_debug("dma%d: s3c2410_dma_lastxfer: load_state %d\n",
542a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		 chan->number, chan->load_state);
543a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#endif
544a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
545a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	switch (chan->load_state) {
546a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	case S3C2410_DMALOAD_NONE:
547a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		break;
548a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
549a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	case S3C2410_DMALOAD_1LOADED:
550a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
551a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks				/* flag error? */
552a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			printk(KERN_ERR "dma%d: timeout waiting for load (%s)\n",
5538e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison			       chan->number, __func__);
554a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			return;
555a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		}
556a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		break;
557a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
558a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	case S3C2410_DMALOAD_1LOADED_1RUNNING:
55925985edcedea6396277003854657b5f3cb31a628Lucas De Marchi		/* I believe in this case we do not have anything to do
560a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		 * until the next buffer comes along, and we turn off the
561a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		 * reload */
562a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		return;
563a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
564a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	default:
565a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		pr_debug("dma%d: lastxfer: unhandled load_state %d with no next\n",
566a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			 chan->number, chan->load_state);
567a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		return;
568a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
569a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	}
570a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
571a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	/* hopefully this'll shut the damned thing up after the transfer... */
572a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	dma_wrreg(chan, S3C2410_DMA_DCON, chan->dcon | S3C2410_DCON_NORELOAD);
573a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks}
574a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
575a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
576a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#define dmadbg2(x...)
577a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
578a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksstatic irqreturn_t
579a21765a70ec06be175d3997320a83fa66fcc8955Ben Dookss3c2410_dma_irq(int irq, void *devpw)
580a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{
581a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	struct s3c2410_dma_chan *chan = (struct s3c2410_dma_chan *)devpw;
582a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	struct s3c2410_dma_buf  *buf;
583a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
584a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	buf = chan->curr;
585a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
586a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	dbg_showchan(chan);
587a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
588a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	/* modify the channel state */
589a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
590a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	switch (chan->load_state) {
591a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	case S3C2410_DMALOAD_1RUNNING:
592a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		/* TODO - if we are running only one buffer, we probably
593a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		 * want to reload here, and then worry about the buffer
594a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		 * callback */
595a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
596a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		chan->load_state = S3C2410_DMALOAD_NONE;
597a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		break;
598a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
599a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	case S3C2410_DMALOAD_1LOADED:
600a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		/* iirc, we should go back to NONE loaded here, we
601a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		 * had a buffer, and it was never verified as being
602a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		 * loaded.
603a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		 */
604a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
605a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		chan->load_state = S3C2410_DMALOAD_NONE;
606a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		break;
607a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
608a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	case S3C2410_DMALOAD_1LOADED_1RUNNING:
609a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		/* we'll worry about checking to see if another buffer is
610a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		 * ready after we've called back the owner. This should
611a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		 * ensure we do not wait around too long for the DMA
612a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		 * engine to start the next transfer
613a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		 */
614a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
615a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		chan->load_state = S3C2410_DMALOAD_1LOADED;
616a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		break;
617a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
618a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	case S3C2410_DMALOAD_NONE:
619a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		printk(KERN_ERR "dma%d: IRQ with no loaded buffer?\n",
620a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		       chan->number);
621a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		break;
622a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
623a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	default:
624a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		printk(KERN_ERR "dma%d: IRQ in invalid load_state %d\n",
625a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		       chan->number, chan->load_state);
626a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		break;
627a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	}
628a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
629a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	if (buf != NULL) {
630a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		/* update the chain to make sure that if we load any more
631a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		 * buffers when we call the callback function, things should
632a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		 * work properly */
633a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
634a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		chan->curr = buf->next;
635a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		buf->next  = NULL;
636a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
637a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		if (buf->magic != BUF_MAGIC) {
638a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			printk(KERN_ERR "dma%d: %s: buf %p incorrect magic\n",
6398e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison			       chan->number, __func__, buf);
640a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			return IRQ_HANDLED;
641a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		}
642a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
643a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		s3c2410_dma_buffdone(chan, buf, S3C2410_RES_OK);
644a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
645a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		/* free resouces */
646a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		s3c2410_dma_freebuf(buf);
647a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	} else {
648a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	}
649a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
650a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	/* only reload if the channel is still running... our buffer done
651a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	 * routine may have altered the state by requesting the dma channel
652a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	 * to stop or shutdown... */
653a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
654a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	/* todo: check that when the channel is shut-down from inside this
655a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	 * function, we cope with unsetting reload, etc */
656a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
657a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	if (chan->next != NULL && chan->state != S3C2410_DMA_IDLE) {
658a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		unsigned long flags;
659a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
660a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		switch (chan->load_state) {
661a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		case S3C2410_DMALOAD_1RUNNING:
662a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			/* don't need to do anything for this state */
663a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			break;
664a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
665a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		case S3C2410_DMALOAD_NONE:
666a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			/* can load buffer immediately */
667a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			break;
668a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
669a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		case S3C2410_DMALOAD_1LOADED:
670a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
671a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks				/* flag error? */
672a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks				printk(KERN_ERR "dma%d: timeout waiting for load (%s)\n",
6738e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison				       chan->number, __func__);
674a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks				return IRQ_HANDLED;
675a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			}
676a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
677a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			break;
678a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
679a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		case S3C2410_DMALOAD_1LOADED_1RUNNING:
680a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			goto no_load;
681a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
682a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		default:
683a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			printk(KERN_ERR "dma%d: unknown load_state in irq, %d\n",
684a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			       chan->number, chan->load_state);
685a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			return IRQ_HANDLED;
686a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		}
687a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
688a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		local_irq_save(flags);
689a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		s3c2410_dma_loadbuffer(chan, chan->next);
690a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		local_irq_restore(flags);
691a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	} else {
692a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		s3c2410_dma_lastxfer(chan);
693a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
694a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		/* see if we can stop this channel.. */
695a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		if (chan->load_state == S3C2410_DMALOAD_NONE) {
696a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			pr_debug("dma%d: end of transfer, stopping channel (%ld)\n",
697a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks				 chan->number, jiffies);
698a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			s3c2410_dma_ctrl(chan->number | DMACH_LOW_LEVEL,
699a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks					 S3C2410_DMAOP_STOP);
700a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		}
701a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	}
702a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
703a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks no_load:
704a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	return IRQ_HANDLED;
705a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks}
706a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
707a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksstatic struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel);
708a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
709a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* s3c2410_request_dma
710a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks *
711a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * get control of an dma channel
712a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks*/
713a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
714d670ac019f60e4932ba329bb0800bf2929e6d77cSangwook Leeint s3c2410_dma_request(enum dma_ch channel,
715a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			struct s3c2410_dma_client *client,
716a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			void *dev)
717a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{
718a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	struct s3c2410_dma_chan *chan;
719a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	unsigned long flags;
720a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	int err;
721a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
722a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	pr_debug("dma%d: s3c2410_request_dma: client=%s, dev=%p\n",
723a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		 channel, client->name, dev);
724a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
725a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	local_irq_save(flags);
726a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
727a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	chan = s3c2410_dma_map_channel(channel);
728a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	if (chan == NULL) {
729a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		local_irq_restore(flags);
730a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		return -EBUSY;
731a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	}
732a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
733a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	dbg_showchan(chan);
734a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
735a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	chan->client = client;
736a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	chan->in_use = 1;
737a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
738a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	if (!chan->irq_claimed) {
739a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		pr_debug("dma%d: %s : requesting irq %d\n",
7408e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison			 channel, __func__, chan->irq);
741a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
742a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		chan->irq_claimed = 1;
743a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		local_irq_restore(flags);
744a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
745a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		err = request_irq(chan->irq, s3c2410_dma_irq, IRQF_DISABLED,
746a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks				  client->name, (void *)chan);
747a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
748a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		local_irq_save(flags);
749a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
750a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		if (err) {
751a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			chan->in_use = 0;
752a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			chan->irq_claimed = 0;
753a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			local_irq_restore(flags);
754a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
755a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			printk(KERN_ERR "%s: cannot get IRQ %d for DMA %d\n",
756a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			       client->name, chan->irq, chan->number);
757a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			return err;
758a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		}
759a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
760a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		chan->irq_enabled = 1;
761a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	}
762a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
763a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	local_irq_restore(flags);
764a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
765a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	/* need to setup */
766a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
7678e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison	pr_debug("%s: channel initialised, %p\n", __func__, chan);
768a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
769a07c438faf952643f79983fb16a10f111c9df0dfBen Dooks	return chan->number | DMACH_LOW_LEVEL;
770a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks}
771a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
772a21765a70ec06be175d3997320a83fa66fcc8955Ben DooksEXPORT_SYMBOL(s3c2410_dma_request);
773a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
774a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* s3c2410_dma_free
775a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks *
776a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * release the given channel back to the system, will stop and flush
777a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * any outstanding transfers, and ensure the channel is ready for the
778a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * next claimant.
779a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks *
780a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * Note, although a warning is currently printed if the freeing client
781a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * info is not the same as the registrant's client info, the free is still
782a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * allowed to go through.
783a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks*/
784a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
785d670ac019f60e4932ba329bb0800bf2929e6d77cSangwook Leeint s3c2410_dma_free(enum dma_ch channel, struct s3c2410_dma_client *client)
786a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{
78797c1b145231730e62dd71921ec653315a1da3aadBen Dooks	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
788a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	unsigned long flags;
789a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
790a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	if (chan == NULL)
791a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		return -EINVAL;
792a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
793a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	local_irq_save(flags);
794a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
795a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	if (chan->client != client) {
796a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		printk(KERN_WARNING "dma%d: possible free from different client (channel %p, passed %p)\n",
797a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		       channel, chan->client, client);
798a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	}
799a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
800a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	/* sort out stopping and freeing the channel */
801a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
802a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	if (chan->state != S3C2410_DMA_IDLE) {
803a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		pr_debug("%s: need to stop dma channel %p\n",
8048e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison		       __func__, chan);
805a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
806a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		/* possibly flush the channel */
807a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STOP);
808a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	}
809a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
810a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	chan->client = NULL;
811a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	chan->in_use = 0;
812a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
813a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	if (chan->irq_claimed)
814a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		free_irq(chan->irq, (void *)chan);
815a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
816a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	chan->irq_claimed = 0;
817a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
818a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	if (!(channel & DMACH_LOW_LEVEL))
81997c1b145231730e62dd71921ec653315a1da3aadBen Dooks		s3c_dma_chan_map[channel] = NULL;
820a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
821a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	local_irq_restore(flags);
822a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
823a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	return 0;
824a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks}
825a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
826a21765a70ec06be175d3997320a83fa66fcc8955Ben DooksEXPORT_SYMBOL(s3c2410_dma_free);
827a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
828a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksstatic int s3c2410_dma_dostop(struct s3c2410_dma_chan *chan)
829a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{
830a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	unsigned long flags;
831a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	unsigned long tmp;
832a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
8338e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison	pr_debug("%s:\n", __func__);
834a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
835a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	dbg_showchan(chan);
836a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
837a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	local_irq_save(flags);
838a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
839a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	s3c2410_dma_call_op(chan,  S3C2410_DMAOP_STOP);
840a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
841a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
842a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	tmp |= S3C2410_DMASKTRIG_STOP;
843a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	//tmp &= ~S3C2410_DMASKTRIG_ON;
844a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp);
845a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
846a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#if 0
847a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	/* should also clear interrupts, according to WinCE BSP */
848a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	tmp = dma_rdreg(chan, S3C2410_DMA_DCON);
849a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	tmp |= S3C2410_DCON_NORELOAD;
850a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	dma_wrreg(chan, S3C2410_DMA_DCON, tmp);
851a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#endif
852a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
853a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	/* should stop do this, or should we wait for flush? */
854a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	chan->state      = S3C2410_DMA_IDLE;
855a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	chan->load_state = S3C2410_DMALOAD_NONE;
856a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
857a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	local_irq_restore(flags);
858a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
859a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	return 0;
860a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks}
861a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
862a7717435656c874843b1742383cc37540f5ff91eBen Dooksstatic void s3c2410_dma_waitforstop(struct s3c2410_dma_chan *chan)
863a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{
864a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	unsigned long tmp;
865a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	unsigned int timeout = 0x10000;
866a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
867a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	while (timeout-- > 0) {
868a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
869a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
870a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		if (!(tmp & S3C2410_DMASKTRIG_ON))
871a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			return;
872a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	}
873a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
874a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	pr_debug("dma%d: failed to stop?\n", chan->number);
875a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks}
876a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
877a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
878a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* s3c2410_dma_flush
879a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks *
880a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * stop the channel, and remove all current and pending transfers
881a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks*/
882a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
883a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksstatic int s3c2410_dma_flush(struct s3c2410_dma_chan *chan)
884a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{
885a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	struct s3c2410_dma_buf *buf, *next;
886a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	unsigned long flags;
887a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
8888e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison	pr_debug("%s: chan %p (%d)\n", __func__, chan, chan->number);
889a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
890a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	dbg_showchan(chan);
891a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
892a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	local_irq_save(flags);
893a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
894a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	if (chan->state != S3C2410_DMA_IDLE) {
8958e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison		pr_debug("%s: stopping channel...\n", __func__ );
896a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_STOP);
897a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	}
898a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
899a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	buf = chan->curr;
900a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	if (buf == NULL)
901a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		buf = chan->next;
902a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
903a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	chan->curr = chan->next = chan->end = NULL;
904a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
905a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	if (buf != NULL) {
906a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		for ( ; buf != NULL; buf = next) {
907a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			next = buf->next;
908a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
909a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			pr_debug("%s: free buffer %p, next %p\n",
9108e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison			       __func__, buf, buf->next);
911a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
912a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			s3c2410_dma_buffdone(chan, buf, S3C2410_RES_ABORT);
913a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			s3c2410_dma_freebuf(buf);
914a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		}
915a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	}
916a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
917a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	dbg_showregs(chan);
918a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
919a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	s3c2410_dma_waitforstop(chan);
920a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
921a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#if 0
922a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	/* should also clear interrupts, according to WinCE BSP */
923a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	{
924a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		unsigned long tmp;
925a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
926a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		tmp = dma_rdreg(chan, S3C2410_DMA_DCON);
927a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		tmp |= S3C2410_DCON_NORELOAD;
928a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		dma_wrreg(chan, S3C2410_DMA_DCON, tmp);
929a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	}
930a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#endif
931a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
932a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	dbg_showregs(chan);
933a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
934a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	local_irq_restore(flags);
935a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
936a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	return 0;
937a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks}
938a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
939a7717435656c874843b1742383cc37540f5ff91eBen Dooksstatic int s3c2410_dma_started(struct s3c2410_dma_chan *chan)
940a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{
941a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	unsigned long flags;
942a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
943a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	local_irq_save(flags);
944a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
945a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	dbg_showchan(chan);
946a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
947a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	/* if we've only loaded one buffer onto the channel, then chec
948a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	 * to see if we have another, and if so, try and load it so when
949a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	 * the first buffer is finished, the new one will be loaded onto
950a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	 * the channel */
951a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
952a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	if (chan->next != NULL) {
953a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		if (chan->load_state == S3C2410_DMALOAD_1LOADED) {
954a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
955a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
956a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks				pr_debug("%s: buff not yet loaded, no more todo\n",
9578e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison					 __func__);
958a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			} else {
959a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks				chan->load_state = S3C2410_DMALOAD_1RUNNING;
960a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks				s3c2410_dma_loadbuffer(chan, chan->next);
961a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			}
962a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
963a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		} else if (chan->load_state == S3C2410_DMALOAD_1RUNNING) {
964a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			s3c2410_dma_loadbuffer(chan, chan->next);
965a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		}
966a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	}
967a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
968a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
969a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	local_irq_restore(flags);
970a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
971a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	return 0;
972a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
973a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks}
974a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
975a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksint
976d670ac019f60e4932ba329bb0800bf2929e6d77cSangwook Lees3c2410_dma_ctrl(enum dma_ch channel, enum s3c2410_chan_op op)
977a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{
97897c1b145231730e62dd71921ec653315a1da3aadBen Dooks	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
979a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
980a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	if (chan == NULL)
981a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		return -EINVAL;
982a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
983a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	switch (op) {
984a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	case S3C2410_DMAOP_START:
985a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		return s3c2410_dma_start(chan);
986a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
987a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	case S3C2410_DMAOP_STOP:
988a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		return s3c2410_dma_dostop(chan);
989a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
990a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	case S3C2410_DMAOP_PAUSE:
991a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	case S3C2410_DMAOP_RESUME:
992a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		return -ENOENT;
993a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
994a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	case S3C2410_DMAOP_FLUSH:
995a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		return s3c2410_dma_flush(chan);
996a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
997a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	case S3C2410_DMAOP_STARTED:
998a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		return s3c2410_dma_started(chan);
999a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1000a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	case S3C2410_DMAOP_TIMEOUT:
1001a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		return 0;
1002a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1003a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	}
1004a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1005a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	return -ENOENT;      /* unknown, don't bother */
1006a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks}
1007a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1008a21765a70ec06be175d3997320a83fa66fcc8955Ben DooksEXPORT_SYMBOL(s3c2410_dma_ctrl);
1009a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1010a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* DMA configuration for each channel
1011a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks *
1012a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * DISRCC -> source of the DMA (AHB,APB)
1013a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * DISRC  -> source address of the DMA
1014a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * DIDSTC -> destination of the DMA (AHB,APD)
1015a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * DIDST  -> destination address of the DMA
1016a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks*/
1017a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1018a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* s3c2410_dma_config
1019a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks *
1020a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * xfersize:     size of unit in bytes (1,2,4)
1021a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks*/
1022a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1023d670ac019f60e4932ba329bb0800bf2929e6d77cSangwook Leeint s3c2410_dma_config(enum dma_ch channel,
10248970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks		       int xferunit)
1025a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{
102697c1b145231730e62dd71921ec653315a1da3aadBen Dooks	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
10278970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks	unsigned int dcon;
1028a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
10295838e9b8dada491278db48ff9162e25125fa89d6Wolfram Sang	pr_debug("%s: chan=%d, xfer_unit=%d\n", __func__, channel, xferunit);
1030a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1031a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	if (chan == NULL)
1032a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		return -EINVAL;
1033a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
10348970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks	dcon = chan->dcon & dma_sel.dcon_mask;
10355838e9b8dada491278db48ff9162e25125fa89d6Wolfram Sang	pr_debug("%s: dcon is %08x\n", __func__, dcon);
1036a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
10378970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks	switch (chan->req_ch) {
10388970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks	case DMACH_I2S_IN:
10398970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks	case DMACH_I2S_OUT:
10408970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks	case DMACH_PCM_IN:
10418970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks	case DMACH_PCM_OUT:
10428970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks	case DMACH_MIC_IN:
10438970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks	default:
10448970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks		dcon |= S3C2410_DCON_HANDSHAKE;
10458970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks		dcon |= S3C2410_DCON_SYNC_PCLK;
10468970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks		break;
10478970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks
10488970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks	case DMACH_SDI:
10498970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks		/* note, ensure if need HANDSHAKE or not */
10508970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks		dcon |= S3C2410_DCON_SYNC_PCLK;
10518970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks		break;
10528970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks
10538970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks	case DMACH_XD0:
10548970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks	case DMACH_XD1:
10558970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks		dcon |= S3C2410_DCON_HANDSHAKE;
10568970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks		dcon |= S3C2410_DCON_SYNC_HCLK;
10578970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks		break;
10588970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks	}
10598970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks
1060a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	switch (xferunit) {
1061a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	case 1:
1062a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		dcon |= S3C2410_DCON_BYTE;
1063a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		break;
1064a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1065a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	case 2:
1066a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		dcon |= S3C2410_DCON_HALFWORD;
1067a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		break;
1068a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1069a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	case 4:
1070a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		dcon |= S3C2410_DCON_WORD;
1071a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		break;
1072a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1073a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	default:
10748e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison		pr_debug("%s: bad transfer size %d\n", __func__, xferunit);
1075a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		return -EINVAL;
1076a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	}
1077a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1078a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	dcon |= S3C2410_DCON_HWTRIG;
1079a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	dcon |= S3C2410_DCON_INTREQ;
1080a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
10818e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison	pr_debug("%s: dcon now %08x\n", __func__, dcon);
1082a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1083a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	chan->dcon = dcon;
1084a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	chan->xfer_unit = xferunit;
1085a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1086a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	return 0;
1087a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks}
1088a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1089a21765a70ec06be175d3997320a83fa66fcc8955Ben DooksEXPORT_SYMBOL(s3c2410_dma_config);
1090a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1091a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1092a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* s3c2410_dma_devconfig
1093a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks *
1094a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * configure the dma source/destination hardware type and address
1095a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks *
109651ddf31da16b1ab9da861eafedad6d263faf4388Boojin Kim * source:    DMA_FROM_DEVICE: source is hardware
109751ddf31da16b1ab9da861eafedad6d263faf4388Boojin Kim *            DMA_TO_DEVICE: source is memory
1098a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks *
1099a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * devaddr:   physical address of the source
1100a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks*/
1101a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1102d670ac019f60e4932ba329bb0800bf2929e6d77cSangwook Leeint s3c2410_dma_devconfig(enum dma_ch channel,
110351ddf31da16b1ab9da861eafedad6d263faf4388Boojin Kim			  enum dma_data_direction source,
1104a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			  unsigned long devaddr)
1105a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{
110697c1b145231730e62dd71921ec653315a1da3aadBen Dooks	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
11078970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks	unsigned int hwcfg;
1108a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1109a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	if (chan == NULL)
1110a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		return -EINVAL;
1111a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
11128970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks	pr_debug("%s: source=%d, devaddr=%08lx\n",
11138970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks		 __func__, (int)source, devaddr);
1114a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1115a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	chan->source = source;
1116a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	chan->dev_addr = devaddr;
11178970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks
11188970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks	switch (chan->req_ch) {
11198970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks	case DMACH_XD0:
11208970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks	case DMACH_XD1:
11218970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks		hwcfg = 0; /* AHB */
11228970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks		break;
11238970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks
11248970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks	default:
11258970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks		hwcfg = S3C2410_DISRCC_APB;
11268970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks	}
11278970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks
11288970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks	/* always assume our peripheral desintation is a fixed
11298970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks	 * address in memory. */
11308970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks	 hwcfg |= S3C2410_DISRCC_INC;
1131a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1132a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	switch (source) {
113351ddf31da16b1ab9da861eafedad6d263faf4388Boojin Kim	case DMA_FROM_DEVICE:
1134a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		/* source is hardware */
1135a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		pr_debug("%s: hw source, devaddr=%08lx, hwcfg=%d\n",
11368e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison			 __func__, devaddr, hwcfg);
1137a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		dma_wrreg(chan, S3C2410_DMA_DISRCC, hwcfg & 3);
1138a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		dma_wrreg(chan, S3C2410_DMA_DISRC,  devaddr);
1139a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		dma_wrreg(chan, S3C2410_DMA_DIDSTC, (0<<1) | (0<<0));
1140a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1141a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DIDST);
1142c6709e8ef5752314c22c75bc7575f9be390e215bBen Dooks		break;
1143a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
114451ddf31da16b1ab9da861eafedad6d263faf4388Boojin Kim	case DMA_TO_DEVICE:
1145a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		/* source is memory */
11468e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison		pr_debug("%s: mem source, devaddr=%08lx, hwcfg=%d\n",
11478e86f4271aaac7685923b80cf57972be41afbc1dHarvey Harrison			 __func__, devaddr, hwcfg);
1148a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		dma_wrreg(chan, S3C2410_DMA_DISRCC, (0<<1) | (0<<0));
1149a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		dma_wrreg(chan, S3C2410_DMA_DIDST,  devaddr);
1150a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		dma_wrreg(chan, S3C2410_DMA_DIDSTC, hwcfg & 3);
1151a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1152a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DISRC);
1153c6709e8ef5752314c22c75bc7575f9be390e215bBen Dooks		break;
1154c6709e8ef5752314c22c75bc7575f9be390e215bBen Dooks
1155c6709e8ef5752314c22c75bc7575f9be390e215bBen Dooks	default:
1156c6709e8ef5752314c22c75bc7575f9be390e215bBen Dooks		printk(KERN_ERR "dma%d: invalid source type (%d)\n",
1157c6709e8ef5752314c22c75bc7575f9be390e215bBen Dooks		       channel, source);
1158c6709e8ef5752314c22c75bc7575f9be390e215bBen Dooks
1159c6709e8ef5752314c22c75bc7575f9be390e215bBen Dooks		return -EINVAL;
1160a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	}
1161a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1162c6709e8ef5752314c22c75bc7575f9be390e215bBen Dooks	if (dma_sel.direction != NULL)
1163c6709e8ef5752314c22c75bc7575f9be390e215bBen Dooks		(dma_sel.direction)(chan, chan->map, source);
1164c6709e8ef5752314c22c75bc7575f9be390e215bBen Dooks
1165c6709e8ef5752314c22c75bc7575f9be390e215bBen Dooks	return 0;
1166a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks}
1167a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1168a21765a70ec06be175d3997320a83fa66fcc8955Ben DooksEXPORT_SYMBOL(s3c2410_dma_devconfig);
1169a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1170a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* s3c2410_dma_getposition
1171a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks *
1172a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * returns the current transfer points for the dma source and destination
1173a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks*/
1174a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1175d670ac019f60e4932ba329bb0800bf2929e6d77cSangwook Leeint s3c2410_dma_getposition(enum dma_ch channel, dma_addr_t *src, dma_addr_t *dst)
1176a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{
117797c1b145231730e62dd71921ec653315a1da3aadBen Dooks	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
1178a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1179a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	if (chan == NULL)
1180a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		return -EINVAL;
1181a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1182a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	if (src != NULL)
1183a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 		*src = dma_rdreg(chan, S3C2410_DMA_DCSRC);
1184a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1185a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 	if (dst != NULL)
1186a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 		*dst = dma_rdreg(chan, S3C2410_DMA_DCDST);
1187a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1188a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks 	return 0;
1189a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks}
1190a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1191a21765a70ec06be175d3997320a83fa66fcc8955Ben DooksEXPORT_SYMBOL(s3c2410_dma_getposition);
1192a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1193bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysocki/* system core operations */
1194a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1195a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#ifdef CONFIG_PM
1196a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1197e4698188444a639ac9a3cfb3e06006dd1d4e7fccHeiko Stuebnerstatic void s3c2410_dma_suspend_chan(struct s3c2410_dma_chan *cp)
1198a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{
1199a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	printk(KERN_DEBUG "suspending dma channel %d\n", cp->number);
1200a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1201a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	if (dma_rdreg(cp, S3C2410_DMA_DMASKTRIG) & S3C2410_DMASKTRIG_ON) {
1202a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		/* the dma channel is still working, which is probably
1203a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		 * a bad thing to do over suspend/resume. We stop the
1204a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		 * channel and assume that the client is either going to
1205a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		 * retry after resume, or that it is broken.
1206a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		 */
1207a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1208a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		printk(KERN_INFO "dma: stopping channel %d due to suspend\n",
1209a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		       cp->number);
1210a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1211a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		s3c2410_dma_dostop(cp);
1212a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	}
1213bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysocki}
1214bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysocki
1215bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysockistatic int s3c2410_dma_suspend(void)
1216bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysocki{
1217bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysocki	struct s3c2410_dma_chan *cp = s3c2410_chans;
1218bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysocki	int channel;
1219bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysocki
1220bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysocki	for (channel = 0; channel < dma_channels; cp++, channel++)
1221bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysocki		s3c2410_dma_suspend_chan(cp);
1222a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1223a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	return 0;
1224a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks}
1225a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1226bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysockistatic void s3c2410_dma_resume_chan(struct s3c2410_dma_chan *cp)
1227a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{
1228c58f7a1d36709e50398c05df9419386befef2c59Ben Dooks	unsigned int no = cp->number | DMACH_LOW_LEVEL;
1229c58f7a1d36709e50398c05df9419386befef2c59Ben Dooks
1230c58f7a1d36709e50398c05df9419386befef2c59Ben Dooks	/* restore channel's hardware configuration */
1231c58f7a1d36709e50398c05df9419386befef2c59Ben Dooks
1232c58f7a1d36709e50398c05df9419386befef2c59Ben Dooks	if (!cp->in_use)
1233cb26a7b1c18857d14913040b45f3fe51b513f936Wolfram Sang		return;
1234c58f7a1d36709e50398c05df9419386befef2c59Ben Dooks
1235c58f7a1d36709e50398c05df9419386befef2c59Ben Dooks	printk(KERN_INFO "dma%d: restoring configuration\n", cp->number);
1236c58f7a1d36709e50398c05df9419386befef2c59Ben Dooks
12378970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks	s3c2410_dma_config(no, cp->xfer_unit);
12388970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks	s3c2410_dma_devconfig(no, cp->source, cp->dev_addr);
1239c58f7a1d36709e50398c05df9419386befef2c59Ben Dooks
1240c58f7a1d36709e50398c05df9419386befef2c59Ben Dooks	/* re-select the dma source for this channel */
1241c58f7a1d36709e50398c05df9419386befef2c59Ben Dooks
1242c58f7a1d36709e50398c05df9419386befef2c59Ben Dooks	if (cp->map != NULL)
1243c58f7a1d36709e50398c05df9419386befef2c59Ben Dooks		dma_sel.select(cp, cp->map);
1244a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks}
1245a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1246bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysockistatic void s3c2410_dma_resume(void)
1247bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysocki{
1248bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysocki	struct s3c2410_dma_chan *cp = s3c2410_chans + dma_channels - 1;
1249bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysocki	int channel;
1250bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysocki
1251e39d40c65dfd8390b50c03482ae9e289b8a8f351Gusakov Andrey	for (channel = dma_channels - 1; channel >= 0; cp--, channel--)
1252bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysocki		s3c2410_dma_resume_chan(cp);
1253bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysocki}
1254bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysocki
1255a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#else
1256a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#define s3c2410_dma_suspend NULL
1257a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#define s3c2410_dma_resume  NULL
1258a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks#endif /* CONFIG_PM */
1259a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1260bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysockistruct syscore_ops dma_syscore_ops = {
1261a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	.suspend	= s3c2410_dma_suspend,
1262a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	.resume		= s3c2410_dma_resume,
1263a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks};
1264a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1265a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* kmem cache implementation */
1266a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
126751cc50685a4275c6a02653670af9f108a64e01cfAlexey Dobriyanstatic void s3c2410_dma_cache_ctor(void *p)
1268a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{
1269a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	memset(p, 0, sizeof(struct s3c2410_dma_buf));
1270a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks}
1271a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1272a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* initialisation code */
1273a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1274bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysockistatic int __init s3c24xx_dma_syscore_init(void)
127548adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooks{
1276bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysocki	register_syscore_ops(&dma_syscore_ops);
127748adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooks
127848adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooks	return 0;
127948adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooks}
128048adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooks
1281bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675bRafael J. Wysockilate_initcall(s3c24xx_dma_syscore_init);
128248adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooks
128348adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooksint __init s3c24xx_dma_init(unsigned int channels, unsigned int irq,
128448adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooks			    unsigned int stride)
1285a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{
1286a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	struct s3c2410_dma_chan *cp;
1287a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	int channel;
1288a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	int ret;
1289a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1290e02f866456ec31d20649670e3af048ddc2a3892bBen Dooks	printk("S3C24XX DMA Driver, Copyright 2003-2006 Simtec Electronics\n");
1291a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
129248adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooks	dma_channels = channels;
129348adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooks
129448adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooks	dma_base = ioremap(S3C24XX_PA_DMA, stride * channels);
1295a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	if (dma_base == NULL) {
1296a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		printk(KERN_ERR "dma failed to remap register block\n");
1297a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		return -ENOMEM;
1298a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	}
1299a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
130048adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooks	dma_kmem = kmem_cache_create("dma_desc",
130148adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooks				     sizeof(struct s3c2410_dma_buf), 0,
1302a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks				     SLAB_HWCACHE_ALIGN,
130320c2df83d25c6a95affe6157a4c9cac4cf5ffaacPaul Mundt				     s3c2410_dma_cache_ctor);
1304a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1305a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	if (dma_kmem == NULL) {
1306a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		printk(KERN_ERR "dma failed to make kmem cache\n");
1307a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		ret = -ENOMEM;
1308a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		goto err;
1309a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	}
1310a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
131148adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooks	for (channel = 0; channel < channels;  channel++) {
1312a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		cp = &s3c2410_chans[channel];
1313a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1314a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		memset(cp, 0, sizeof(struct s3c2410_dma_chan));
1315a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1316a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		/* dma channel irqs are in order.. */
1317a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		cp->number = channel;
131848adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooks		cp->irq    = channel + irq;
131948adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooks		cp->regs   = dma_base + (channel * stride);
1320a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1321a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		/* point current stats somewhere */
1322a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		cp->stats  = &cp->stats_store;
1323a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		cp->stats_store.timeout_shortest = LONG_MAX;
1324a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1325a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		/* basic channel configuration */
1326a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1327a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		cp->load_timeout = 1<<18;
1328a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1329a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		printk("DMA channel %d at %p, irq %d\n",
1330a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		       cp->number, cp->regs, cp->irq);
1331a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	}
1332a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1333a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	return 0;
1334a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1335a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks err:
1336a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	kmem_cache_destroy(dma_kmem);
1337a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	iounmap(dma_base);
1338a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	dma_base = NULL;
1339a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	return ret;
1340a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks}
1341a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1342f2c10d6c669e5b792c48e86da37ec7fde0a2e302Krzysztof Heltint __init s3c2410_dma_init(void)
134348adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooks{
134448adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooks	return s3c24xx_dma_init(4, IRQ_DMA0, 0x40);
134548adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooks}
1346a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1347a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksstatic inline int is_channel_valid(unsigned int channel)
1348a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{
1349a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	return (channel & DMA_CH_VALID);
1350a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks}
1351a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
13520c6022d453ecebdace0ce15434c7108e158149caBen Dooksstatic struct s3c24xx_dma_order *dma_order;
13530c6022d453ecebdace0ce15434c7108e158149caBen Dooks
13540c6022d453ecebdace0ce15434c7108e158149caBen Dooks
1355a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks/* s3c2410_dma_map_channel()
1356a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks *
1357a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * turn the virtual channel number into a real, and un-used hardware
1358a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks * channel.
1359a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks *
13600c6022d453ecebdace0ce15434c7108e158149caBen Dooks * first, try the dma ordering given to us by either the relevant
13610c6022d453ecebdace0ce15434c7108e158149caBen Dooks * dma code, or the board. Then just find the first usable free
13620c6022d453ecebdace0ce15434c7108e158149caBen Dooks * channel
1363a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks*/
1364a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1365a7717435656c874843b1742383cc37540f5ff91eBen Dooksstatic struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel)
1366a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{
13670c6022d453ecebdace0ce15434c7108e158149caBen Dooks	struct s3c24xx_dma_order_ch *ord = NULL;
1368a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	struct s3c24xx_dma_map *ch_map;
1369a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	struct s3c2410_dma_chan *dmach;
1370a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	int ch;
1371a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1372a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	if (dma_sel.map == NULL || channel > dma_sel.map_size)
1373a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		return NULL;
1374a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1375a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	ch_map = dma_sel.map + channel;
1376a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
13770c6022d453ecebdace0ce15434c7108e158149caBen Dooks	/* first, try the board mapping */
13780c6022d453ecebdace0ce15434c7108e158149caBen Dooks
13790c6022d453ecebdace0ce15434c7108e158149caBen Dooks	if (dma_order) {
13800c6022d453ecebdace0ce15434c7108e158149caBen Dooks		ord = &dma_order->channels[channel];
13810c6022d453ecebdace0ce15434c7108e158149caBen Dooks
138248adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooks		for (ch = 0; ch < dma_channels; ch++) {
1383947a2462792a89b8aa168a1108288e0d0ae36d12Ramax Lo			int tmp;
13840c6022d453ecebdace0ce15434c7108e158149caBen Dooks			if (!is_channel_valid(ord->list[ch]))
13850c6022d453ecebdace0ce15434c7108e158149caBen Dooks				continue;
13860c6022d453ecebdace0ce15434c7108e158149caBen Dooks
1387947a2462792a89b8aa168a1108288e0d0ae36d12Ramax Lo			tmp = ord->list[ch] & ~DMA_CH_VALID;
1388947a2462792a89b8aa168a1108288e0d0ae36d12Ramax Lo			if (s3c2410_chans[tmp].in_use == 0) {
1389947a2462792a89b8aa168a1108288e0d0ae36d12Ramax Lo				ch = tmp;
13900c6022d453ecebdace0ce15434c7108e158149caBen Dooks				goto found;
13910c6022d453ecebdace0ce15434c7108e158149caBen Dooks			}
13920c6022d453ecebdace0ce15434c7108e158149caBen Dooks		}
13930c6022d453ecebdace0ce15434c7108e158149caBen Dooks
13940c6022d453ecebdace0ce15434c7108e158149caBen Dooks		if (ord->flags & DMA_CH_NEVER)
13950c6022d453ecebdace0ce15434c7108e158149caBen Dooks			return NULL;
13960c6022d453ecebdace0ce15434c7108e158149caBen Dooks	}
13970c6022d453ecebdace0ce15434c7108e158149caBen Dooks
13980c6022d453ecebdace0ce15434c7108e158149caBen Dooks	/* second, search the channel map for first free */
13990c6022d453ecebdace0ce15434c7108e158149caBen Dooks
140048adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooks	for (ch = 0; ch < dma_channels; ch++) {
1401a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		if (!is_channel_valid(ch_map->channels[ch]))
1402a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			continue;
1403a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1404a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		if (s3c2410_chans[ch].in_use == 0) {
1405a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			printk("mapped channel %d to %d\n", channel, ch);
1406a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks			break;
1407a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		}
1408a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	}
1409a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
141048adbcf33b6087727a2db0b517c994a7ecfbeb0cBen Dooks	if (ch >= dma_channels)
1411a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		return NULL;
1412a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1413a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	/* update our channel mapping */
1414a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
14150c6022d453ecebdace0ce15434c7108e158149caBen Dooks found:
1416a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	dmach = &s3c2410_chans[ch];
1417c58f7a1d36709e50398c05df9419386befef2c59Ben Dooks	dmach->map = ch_map;
14188970ef47d56fd3db28ee798b9d400caf08abd924Ben Dooks	dmach->req_ch = channel;
141997c1b145231730e62dd71921ec653315a1da3aadBen Dooks	s3c_dma_chan_map[channel] = dmach;
1420a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1421a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	/* select the channel */
1422a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1423a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	(dma_sel.select)(dmach, ch_map);
1424a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1425a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	return dmach;
1426a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks}
1427a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1428a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksstatic int s3c24xx_dma_check_entry(struct s3c24xx_dma_map *map, int ch)
1429a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{
1430a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	return 0;
1431a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks}
1432a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1433a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooksint __init s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel)
1434a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks{
1435a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	struct s3c24xx_dma_map *nmap;
1436a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	size_t map_sz = sizeof(*nmap) * sel->map_size;
1437a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	int ptr;
1438a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
14397803c7aa8ef262a63e91ee0b04470715a7dc2eb0Thomas Meyer	nmap = kmemdup(sel->map, map_sz, GFP_KERNEL);
1440a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	if (nmap == NULL)
1441a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		return -ENOMEM;
1442a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1443a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	memcpy(&dma_sel, sel, sizeof(*sel));
1444a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1445a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	dma_sel.map = nmap;
1446a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1447a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	for (ptr = 0; ptr < sel->map_size; ptr++)
1448a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks		s3c24xx_dma_check_entry(nmap+ptr, ptr);
1449a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks
1450a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks	return 0;
1451a21765a70ec06be175d3997320a83fa66fcc8955Ben Dooks}
14520c6022d453ecebdace0ce15434c7108e158149caBen Dooks
14530c6022d453ecebdace0ce15434c7108e158149caBen Dooksint __init s3c24xx_dma_order_set(struct s3c24xx_dma_order *ord)
14540c6022d453ecebdace0ce15434c7108e158149caBen Dooks{
14550c6022d453ecebdace0ce15434c7108e158149caBen Dooks	struct s3c24xx_dma_order *nord = dma_order;
14560c6022d453ecebdace0ce15434c7108e158149caBen Dooks
14570c6022d453ecebdace0ce15434c7108e158149caBen Dooks	if (nord == NULL)
14580c6022d453ecebdace0ce15434c7108e158149caBen Dooks		nord = kmalloc(sizeof(struct s3c24xx_dma_order), GFP_KERNEL);
14590c6022d453ecebdace0ce15434c7108e158149caBen Dooks
14600c6022d453ecebdace0ce15434c7108e158149caBen Dooks	if (nord == NULL) {
14610c6022d453ecebdace0ce15434c7108e158149caBen Dooks		printk(KERN_ERR "no memory to store dma channel order\n");
14620c6022d453ecebdace0ce15434c7108e158149caBen Dooks		return -ENOMEM;
14630c6022d453ecebdace0ce15434c7108e158149caBen Dooks	}
14640c6022d453ecebdace0ce15434c7108e158149caBen Dooks
14650c6022d453ecebdace0ce15434c7108e158149caBen Dooks	dma_order = nord;
14660c6022d453ecebdace0ce15434c7108e158149caBen Dooks	memcpy(nord, ord, sizeof(struct s3c24xx_dma_order));
14670c6022d453ecebdace0ce15434c7108e158149caBen Dooks	return 0;
14680c6022d453ecebdace0ce15434c7108e158149caBen Dooks}
1469