Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * | |
3 | * BRIEF MODULE DESCRIPTION | |
4 | * The Descriptor Based DMA channel manager that first appeared | |
5 | * on the Au1550. I started with dma.c, but I think all that is | |
6 | * left is this initial comment :-) | |
7 | * | |
8 | * Copyright 2004 Embedded Edge, LLC | |
9 | * dan@embeddededge.com | |
10 | * | |
11 | * This program is free software; you can redistribute it and/or modify it | |
12 | * under the terms of the GNU General Public License as published by the | |
13 | * Free Software Foundation; either version 2 of the License, or (at your | |
14 | * option) any later version. | |
15 | * | |
16 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | |
17 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
18 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | |
19 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
21 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |
22 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | |
23 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
26 | * | |
27 | * You should have received a copy of the GNU General Public License along | |
28 | * with this program; if not, write to the Free Software Foundation, Inc., | |
29 | * 675 Mass Ave, Cambridge, MA 02139, USA. | |
30 | * | |
31 | */ | |
e3ad1c23 | 32 | |
1da177e4 LT |
33 | #include <linux/config.h> |
34 | #include <linux/kernel.h> | |
35 | #include <linux/errno.h> | |
36 | #include <linux/sched.h> | |
37 | #include <linux/slab.h> | |
38 | #include <linux/spinlock.h> | |
39 | #include <linux/string.h> | |
40 | #include <linux/delay.h> | |
41 | #include <linux/interrupt.h> | |
42 | #include <asm/mach-au1x00/au1000.h> | |
43 | #include <asm/mach-au1x00/au1xxx_dbdma.h> | |
44 | #include <asm/system.h> | |
45 | ||
e3ad1c23 PP |
46 | /* #include <linux/module.h> */ |
47 | ||
1da177e4 LT |
48 | #if defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200) |
49 | ||
50 | /* | |
51 | * The Descriptor Based DMA supports up to 16 channels. | |
52 | * | |
53 | * There are 32 devices defined. We keep an internal structure | |
54 | * of devices using these channels, along with additional | |
55 | * information. | |
56 | * | |
57 | * We allocate the descriptors and allow access to them through various | |
58 | * functions. The drivers allocate the data buffers and assign them | |
59 | * to the descriptors. | |
60 | */ | |
e3ad1c23 | 61 | static spinlock_t au1xxx_dbdma_spin_lock = SPIN_LOCK_UNLOCKED; |
1da177e4 LT |
62 | |
63 | /* I couldn't find a macro that did this...... | |
64 | */ | |
65 | #define ALIGN_ADDR(x, a) ((((u32)(x)) + (a-1)) & ~(a-1)) | |
66 | ||
e3ad1c23 PP |
67 | static dbdma_global_t *dbdma_gptr = (dbdma_global_t *)DDMA_GLOBAL_BASE; |
68 | static int dbdma_initialized=0; | |
1da177e4 LT |
69 | static void au1xxx_dbdma_init(void); |
70 | ||
1da177e4 LT |
71 | static dbdev_tab_t dbdev_tab[] = { |
72 | #ifdef CONFIG_SOC_AU1550 | |
73 | /* UARTS */ | |
74 | { DSCR_CMD0_UART0_TX, DEV_FLAGS_OUT, 0, 8, 0x11100004, 0, 0 }, | |
75 | { DSCR_CMD0_UART0_RX, DEV_FLAGS_IN, 0, 8, 0x11100000, 0, 0 }, | |
76 | { DSCR_CMD0_UART3_TX, DEV_FLAGS_OUT, 0, 8, 0x11400004, 0, 0 }, | |
77 | { DSCR_CMD0_UART3_RX, DEV_FLAGS_IN, 0, 8, 0x11400000, 0, 0 }, | |
78 | ||
79 | /* EXT DMA */ | |
80 | { DSCR_CMD0_DMA_REQ0, 0, 0, 0, 0x00000000, 0, 0 }, | |
81 | { DSCR_CMD0_DMA_REQ1, 0, 0, 0, 0x00000000, 0, 0 }, | |
82 | { DSCR_CMD0_DMA_REQ2, 0, 0, 0, 0x00000000, 0, 0 }, | |
83 | { DSCR_CMD0_DMA_REQ3, 0, 0, 0, 0x00000000, 0, 0 }, | |
84 | ||
85 | /* USB DEV */ | |
86 | { DSCR_CMD0_USBDEV_RX0, DEV_FLAGS_IN, 4, 8, 0x10200000, 0, 0 }, | |
87 | { DSCR_CMD0_USBDEV_TX0, DEV_FLAGS_OUT, 4, 8, 0x10200004, 0, 0 }, | |
88 | { DSCR_CMD0_USBDEV_TX1, DEV_FLAGS_OUT, 4, 8, 0x10200008, 0, 0 }, | |
89 | { DSCR_CMD0_USBDEV_TX2, DEV_FLAGS_OUT, 4, 8, 0x1020000c, 0, 0 }, | |
90 | { DSCR_CMD0_USBDEV_RX3, DEV_FLAGS_IN, 4, 8, 0x10200010, 0, 0 }, | |
91 | { DSCR_CMD0_USBDEV_RX4, DEV_FLAGS_IN, 4, 8, 0x10200014, 0, 0 }, | |
92 | ||
93 | /* PSC 0 */ | |
94 | { DSCR_CMD0_PSC0_TX, DEV_FLAGS_OUT, 0, 0, 0x11a0001c, 0, 0 }, | |
95 | { DSCR_CMD0_PSC0_RX, DEV_FLAGS_IN, 0, 0, 0x11a0001c, 0, 0 }, | |
96 | ||
97 | /* PSC 1 */ | |
98 | { DSCR_CMD0_PSC1_TX, DEV_FLAGS_OUT, 0, 0, 0x11b0001c, 0, 0 }, | |
99 | { DSCR_CMD0_PSC1_RX, DEV_FLAGS_IN, 0, 0, 0x11b0001c, 0, 0 }, | |
100 | ||
101 | /* PSC 2 */ | |
102 | { DSCR_CMD0_PSC2_TX, DEV_FLAGS_OUT, 0, 0, 0x10a0001c, 0, 0 }, | |
103 | { DSCR_CMD0_PSC2_RX, DEV_FLAGS_IN, 0, 0, 0x10a0001c, 0, 0 }, | |
104 | ||
105 | /* PSC 3 */ | |
106 | { DSCR_CMD0_PSC3_TX, DEV_FLAGS_OUT, 0, 0, 0x10b0001c, 0, 0 }, | |
107 | { DSCR_CMD0_PSC3_RX, DEV_FLAGS_IN, 0, 0, 0x10b0001c, 0, 0 }, | |
108 | ||
109 | { DSCR_CMD0_PCI_WRITE, 0, 0, 0, 0x00000000, 0, 0 }, /* PCI */ | |
110 | { DSCR_CMD0_NAND_FLASH, 0, 0, 0, 0x00000000, 0, 0 }, /* NAND */ | |
111 | ||
112 | /* MAC 0 */ | |
113 | { DSCR_CMD0_MAC0_RX, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 }, | |
114 | { DSCR_CMD0_MAC0_TX, DEV_FLAGS_OUT, 0, 0, 0x00000000, 0, 0 }, | |
115 | ||
116 | /* MAC 1 */ | |
117 | { DSCR_CMD0_MAC1_RX, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 }, | |
118 | { DSCR_CMD0_MAC1_TX, DEV_FLAGS_OUT, 0, 0, 0x00000000, 0, 0 }, | |
119 | ||
120 | #endif /* CONFIG_SOC_AU1550 */ | |
121 | ||
122 | #ifdef CONFIG_SOC_AU1200 | |
123 | { DSCR_CMD0_UART0_TX, DEV_FLAGS_OUT, 0, 8, 0x11100004, 0, 0 }, | |
124 | { DSCR_CMD0_UART0_RX, DEV_FLAGS_IN, 0, 8, 0x11100000, 0, 0 }, | |
125 | { DSCR_CMD0_UART1_TX, DEV_FLAGS_OUT, 0, 8, 0x11200004, 0, 0 }, | |
126 | { DSCR_CMD0_UART1_RX, DEV_FLAGS_IN, 0, 8, 0x11200000, 0, 0 }, | |
127 | ||
128 | { DSCR_CMD0_DMA_REQ0, 0, 0, 0, 0x00000000, 0, 0 }, | |
129 | { DSCR_CMD0_DMA_REQ1, 0, 0, 0, 0x00000000, 0, 0 }, | |
130 | ||
131 | { DSCR_CMD0_MAE_BE, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, | |
132 | { DSCR_CMD0_MAE_FE, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, | |
133 | { DSCR_CMD0_MAE_BOTH, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, | |
134 | { DSCR_CMD0_LCD, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, | |
135 | ||
e3ad1c23 PP |
136 | { DSCR_CMD0_SDMS_TX0, DEV_FLAGS_OUT, 4, 8, 0x10600000, 0, 0 }, |
137 | { DSCR_CMD0_SDMS_RX0, DEV_FLAGS_IN, 4, 8, 0x10600004, 0, 0 }, | |
138 | { DSCR_CMD0_SDMS_TX1, DEV_FLAGS_OUT, 4, 8, 0x10680000, 0, 0 }, | |
139 | { DSCR_CMD0_SDMS_RX1, DEV_FLAGS_IN, 4, 8, 0x10680004, 0, 0 }, | |
1da177e4 | 140 | |
e3ad1c23 PP |
141 | { DSCR_CMD0_AES_RX, DEV_FLAGS_IN , 4, 32, 0x10300008, 0, 0 }, |
142 | { DSCR_CMD0_AES_TX, DEV_FLAGS_OUT, 4, 32, 0x10300004, 0, 0 }, | |
1da177e4 LT |
143 | |
144 | { DSCR_CMD0_PSC0_TX, DEV_FLAGS_OUT, 0, 0, 0x11a0001c, 0, 0 }, | |
145 | { DSCR_CMD0_PSC0_RX, DEV_FLAGS_IN, 0, 0, 0x11a0001c, 0, 0 }, | |
146 | { DSCR_CMD0_PSC0_SYNC, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, | |
147 | ||
148 | { DSCR_CMD0_PSC1_TX, DEV_FLAGS_OUT, 0, 0, 0x11b0001c, 0, 0 }, | |
149 | { DSCR_CMD0_PSC1_RX, DEV_FLAGS_IN, 0, 0, 0x11b0001c, 0, 0 }, | |
150 | { DSCR_CMD0_PSC1_SYNC, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, | |
151 | ||
e3ad1c23 PP |
152 | { DSCR_CMD0_CIM_RXA, DEV_FLAGS_IN, 0, 32, 0x14004020, 0, 0 }, |
153 | { DSCR_CMD0_CIM_RXB, DEV_FLAGS_IN, 0, 32, 0x14004040, 0, 0 }, | |
154 | { DSCR_CMD0_CIM_RXC, DEV_FLAGS_IN, 0, 32, 0x14004060, 0, 0 }, | |
1da177e4 LT |
155 | { DSCR_CMD0_CIM_SYNC, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, |
156 | ||
157 | { DSCR_CMD0_NAND_FLASH, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 }, | |
158 | ||
159 | #endif // CONFIG_SOC_AU1200 | |
160 | ||
161 | { DSCR_CMD0_THROTTLE, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, | |
162 | { DSCR_CMD0_ALWAYS, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, | |
e3ad1c23 PP |
163 | |
164 | /* Provide 16 user definable device types */ | |
165 | { 0, 0, 0, 0, 0, 0, 0 }, | |
166 | { 0, 0, 0, 0, 0, 0, 0 }, | |
167 | { 0, 0, 0, 0, 0, 0, 0 }, | |
168 | { 0, 0, 0, 0, 0, 0, 0 }, | |
169 | { 0, 0, 0, 0, 0, 0, 0 }, | |
170 | { 0, 0, 0, 0, 0, 0, 0 }, | |
171 | { 0, 0, 0, 0, 0, 0, 0 }, | |
172 | { 0, 0, 0, 0, 0, 0, 0 }, | |
173 | { 0, 0, 0, 0, 0, 0, 0 }, | |
174 | { 0, 0, 0, 0, 0, 0, 0 }, | |
175 | { 0, 0, 0, 0, 0, 0, 0 }, | |
176 | { 0, 0, 0, 0, 0, 0, 0 }, | |
177 | { 0, 0, 0, 0, 0, 0, 0 }, | |
178 | { 0, 0, 0, 0, 0, 0, 0 }, | |
179 | { 0, 0, 0, 0, 0, 0, 0 }, | |
180 | { 0, 0, 0, 0, 0, 0, 0 }, | |
1da177e4 LT |
181 | }; |
182 | ||
183 | #define DBDEV_TAB_SIZE (sizeof(dbdev_tab) / sizeof(dbdev_tab_t)) | |
184 | ||
185 | static chan_tab_t *chan_tab_ptr[NUM_DBDMA_CHANS]; | |
186 | ||
187 | static dbdev_tab_t * | |
188 | find_dbdev_id (u32 id) | |
189 | { | |
190 | int i; | |
191 | dbdev_tab_t *p; | |
192 | for (i = 0; i < DBDEV_TAB_SIZE; ++i) { | |
193 | p = &dbdev_tab[i]; | |
194 | if (p->dev_id == id) | |
195 | return p; | |
196 | } | |
197 | return NULL; | |
198 | } | |
199 | ||
e3ad1c23 PP |
200 | u32 |
201 | au1xxx_ddma_add_device(dbdev_tab_t *dev) | |
202 | { | |
203 | u32 ret = 0; | |
204 | dbdev_tab_t *p=NULL; | |
205 | static u16 new_id=0x1000; | |
206 | ||
207 | p = find_dbdev_id(0); | |
208 | if ( NULL != p ) | |
209 | { | |
210 | memcpy(p, dev, sizeof(dbdev_tab_t)); | |
211 | p->dev_id = DSCR_DEV2CUSTOM_ID(new_id,dev->dev_id); | |
212 | ret = p->dev_id; | |
213 | new_id++; | |
214 | #if 0 | |
215 | printk("add_device: id:%x flags:%x padd:%x\n", | |
216 | p->dev_id, p->dev_flags, p->dev_physaddr ); | |
217 | #endif | |
218 | } | |
219 | ||
220 | return ret; | |
221 | } | |
222 | EXPORT_SYMBOL(au1xxx_ddma_add_device); | |
223 | ||
1da177e4 LT |
224 | /* Allocate a channel and return a non-zero descriptor if successful. |
225 | */ | |
226 | u32 | |
227 | au1xxx_dbdma_chan_alloc(u32 srcid, u32 destid, | |
228 | void (*callback)(int, void *, struct pt_regs *), void *callparam) | |
229 | { | |
230 | unsigned long flags; | |
231 | u32 used, chan, rv; | |
232 | u32 dcp; | |
233 | int i; | |
234 | dbdev_tab_t *stp, *dtp; | |
235 | chan_tab_t *ctp; | |
e3ad1c23 | 236 | au1x_dma_chan_t *cp; |
1da177e4 LT |
237 | |
238 | /* We do the intialization on the first channel allocation. | |
239 | * We have to wait because of the interrupt handler initialization | |
240 | * which can't be done successfully during board set up. | |
241 | */ | |
242 | if (!dbdma_initialized) | |
243 | au1xxx_dbdma_init(); | |
244 | dbdma_initialized = 1; | |
245 | ||
1da177e4 LT |
246 | if ((stp = find_dbdev_id(srcid)) == NULL) return 0; |
247 | if ((dtp = find_dbdev_id(destid)) == NULL) return 0; | |
248 | ||
249 | used = 0; | |
250 | rv = 0; | |
251 | ||
252 | /* Check to see if we can get both channels. | |
253 | */ | |
254 | spin_lock_irqsave(&au1xxx_dbdma_spin_lock, flags); | |
255 | if (!(stp->dev_flags & DEV_FLAGS_INUSE) || | |
256 | (stp->dev_flags & DEV_FLAGS_ANYUSE)) { | |
257 | /* Got source */ | |
258 | stp->dev_flags |= DEV_FLAGS_INUSE; | |
259 | if (!(dtp->dev_flags & DEV_FLAGS_INUSE) || | |
260 | (dtp->dev_flags & DEV_FLAGS_ANYUSE)) { | |
261 | /* Got destination */ | |
262 | dtp->dev_flags |= DEV_FLAGS_INUSE; | |
263 | } | |
264 | else { | |
265 | /* Can't get dest. Release src. | |
266 | */ | |
267 | stp->dev_flags &= ~DEV_FLAGS_INUSE; | |
268 | used++; | |
269 | } | |
270 | } | |
271 | else { | |
272 | used++; | |
273 | } | |
274 | spin_unlock_irqrestore(&au1xxx_dbdma_spin_lock, flags); | |
275 | ||
276 | if (!used) { | |
277 | /* Let's see if we can allocate a channel for it. | |
278 | */ | |
279 | ctp = NULL; | |
280 | chan = 0; | |
281 | spin_lock_irqsave(&au1xxx_dbdma_spin_lock, flags); | |
282 | for (i=0; i<NUM_DBDMA_CHANS; i++) { | |
283 | if (chan_tab_ptr[i] == NULL) { | |
284 | /* If kmalloc fails, it is caught below same | |
285 | * as a channel not available. | |
286 | */ | |
e3ad1c23 PP |
287 | ctp = (chan_tab_t *) |
288 | kmalloc(sizeof(chan_tab_t), GFP_KERNEL); | |
1da177e4 | 289 | chan_tab_ptr[i] = ctp; |
1da177e4 LT |
290 | break; |
291 | } | |
292 | } | |
293 | spin_unlock_irqrestore(&au1xxx_dbdma_spin_lock, flags); | |
294 | ||
295 | if (ctp != NULL) { | |
296 | memset(ctp, 0, sizeof(chan_tab_t)); | |
e3ad1c23 | 297 | ctp->chan_index = chan = i; |
1da177e4 LT |
298 | dcp = DDMA_CHANNEL_BASE; |
299 | dcp += (0x0100 * chan); | |
300 | ctp->chan_ptr = (au1x_dma_chan_t *)dcp; | |
e3ad1c23 | 301 | cp = (au1x_dma_chan_t *)dcp; |
1da177e4 LT |
302 | ctp->chan_src = stp; |
303 | ctp->chan_dest = dtp; | |
304 | ctp->chan_callback = callback; | |
305 | ctp->chan_callparam = callparam; | |
306 | ||
307 | /* Initialize channel configuration. | |
308 | */ | |
309 | i = 0; | |
310 | if (stp->dev_intlevel) | |
311 | i |= DDMA_CFG_SED; | |
312 | if (stp->dev_intpolarity) | |
313 | i |= DDMA_CFG_SP; | |
314 | if (dtp->dev_intlevel) | |
315 | i |= DDMA_CFG_DED; | |
316 | if (dtp->dev_intpolarity) | |
317 | i |= DDMA_CFG_DP; | |
e3ad1c23 PP |
318 | if ((stp->dev_flags & DEV_FLAGS_SYNC) || |
319 | (dtp->dev_flags & DEV_FLAGS_SYNC)) | |
320 | i |= DDMA_CFG_SYNC; | |
1da177e4 LT |
321 | cp->ddma_cfg = i; |
322 | au_sync(); | |
323 | ||
324 | /* Return a non-zero value that can be used to | |
325 | * find the channel information in subsequent | |
326 | * operations. | |
327 | */ | |
328 | rv = (u32)(&chan_tab_ptr[chan]); | |
329 | } | |
330 | else { | |
e3ad1c23 | 331 | /* Release devices */ |
1da177e4 LT |
332 | stp->dev_flags &= ~DEV_FLAGS_INUSE; |
333 | dtp->dev_flags &= ~DEV_FLAGS_INUSE; | |
334 | } | |
335 | } | |
336 | return rv; | |
337 | } | |
e3ad1c23 | 338 | EXPORT_SYMBOL(au1xxx_dbdma_chan_alloc); |
1da177e4 LT |
339 | |
340 | /* Set the device width if source or destination is a FIFO. | |
341 | * Should be 8, 16, or 32 bits. | |
342 | */ | |
343 | u32 | |
344 | au1xxx_dbdma_set_devwidth(u32 chanid, int bits) | |
345 | { | |
346 | u32 rv; | |
347 | chan_tab_t *ctp; | |
348 | dbdev_tab_t *stp, *dtp; | |
349 | ||
350 | ctp = *((chan_tab_t **)chanid); | |
351 | stp = ctp->chan_src; | |
352 | dtp = ctp->chan_dest; | |
353 | rv = 0; | |
354 | ||
355 | if (stp->dev_flags & DEV_FLAGS_IN) { /* Source in fifo */ | |
356 | rv = stp->dev_devwidth; | |
357 | stp->dev_devwidth = bits; | |
358 | } | |
359 | if (dtp->dev_flags & DEV_FLAGS_OUT) { /* Destination out fifo */ | |
360 | rv = dtp->dev_devwidth; | |
361 | dtp->dev_devwidth = bits; | |
362 | } | |
363 | ||
364 | return rv; | |
365 | } | |
e3ad1c23 | 366 | EXPORT_SYMBOL(au1xxx_dbdma_set_devwidth); |
1da177e4 LT |
367 | |
368 | /* Allocate a descriptor ring, initializing as much as possible. | |
369 | */ | |
370 | u32 | |
371 | au1xxx_dbdma_ring_alloc(u32 chanid, int entries) | |
372 | { | |
373 | int i; | |
374 | u32 desc_base, srcid, destid; | |
375 | u32 cmd0, cmd1, src1, dest1; | |
376 | u32 src0, dest0; | |
377 | chan_tab_t *ctp; | |
378 | dbdev_tab_t *stp, *dtp; | |
379 | au1x_ddma_desc_t *dp; | |
380 | ||
381 | /* I guess we could check this to be within the | |
382 | * range of the table...... | |
383 | */ | |
384 | ctp = *((chan_tab_t **)chanid); | |
385 | stp = ctp->chan_src; | |
386 | dtp = ctp->chan_dest; | |
387 | ||
388 | /* The descriptors must be 32-byte aligned. There is a | |
389 | * possibility the allocation will give us such an address, | |
390 | * and if we try that first we are likely to not waste larger | |
391 | * slabs of memory. | |
392 | */ | |
e3ad1c23 PP |
393 | desc_base = (u32)kmalloc(entries * sizeof(au1x_ddma_desc_t), |
394 | GFP_KERNEL|GFP_DMA); | |
1da177e4 LT |
395 | if (desc_base == 0) |
396 | return 0; | |
397 | ||
398 | if (desc_base & 0x1f) { | |
399 | /* Lost....do it again, allocate extra, and round | |
400 | * the address base. | |
401 | */ | |
402 | kfree((const void *)desc_base); | |
403 | i = entries * sizeof(au1x_ddma_desc_t); | |
404 | i += (sizeof(au1x_ddma_desc_t) - 1); | |
e3ad1c23 | 405 | if ((desc_base = (u32)kmalloc(i, GFP_KERNEL|GFP_DMA)) == 0) |
1da177e4 LT |
406 | return 0; |
407 | ||
408 | desc_base = ALIGN_ADDR(desc_base, sizeof(au1x_ddma_desc_t)); | |
409 | } | |
410 | dp = (au1x_ddma_desc_t *)desc_base; | |
411 | ||
412 | /* Keep track of the base descriptor. | |
413 | */ | |
414 | ctp->chan_desc_base = dp; | |
415 | ||
416 | /* Initialize the rings with as much information as we know. | |
417 | */ | |
418 | srcid = stp->dev_id; | |
419 | destid = dtp->dev_id; | |
420 | ||
421 | cmd0 = cmd1 = src1 = dest1 = 0; | |
422 | src0 = dest0 = 0; | |
423 | ||
424 | cmd0 |= DSCR_CMD0_SID(srcid); | |
425 | cmd0 |= DSCR_CMD0_DID(destid); | |
426 | cmd0 |= DSCR_CMD0_IE | DSCR_CMD0_CV; | |
427 | cmd0 |= DSCR_CMD0_ST(DSCR_CMD0_ST_CURRENT); | |
428 | ||
429 | switch (stp->dev_devwidth) { | |
430 | case 8: | |
431 | cmd0 |= DSCR_CMD0_SW(DSCR_CMD0_BYTE); | |
432 | break; | |
433 | case 16: | |
434 | cmd0 |= DSCR_CMD0_SW(DSCR_CMD0_HALFWORD); | |
435 | break; | |
436 | case 32: | |
437 | default: | |
438 | cmd0 |= DSCR_CMD0_SW(DSCR_CMD0_WORD); | |
439 | break; | |
440 | } | |
441 | ||
442 | switch (dtp->dev_devwidth) { | |
443 | case 8: | |
444 | cmd0 |= DSCR_CMD0_DW(DSCR_CMD0_BYTE); | |
445 | break; | |
446 | case 16: | |
447 | cmd0 |= DSCR_CMD0_DW(DSCR_CMD0_HALFWORD); | |
448 | break; | |
449 | case 32: | |
450 | default: | |
451 | cmd0 |= DSCR_CMD0_DW(DSCR_CMD0_WORD); | |
452 | break; | |
453 | } | |
454 | ||
455 | /* If the device is marked as an in/out FIFO, ensure it is | |
456 | * set non-coherent. | |
457 | */ | |
458 | if (stp->dev_flags & DEV_FLAGS_IN) | |
459 | cmd0 |= DSCR_CMD0_SN; /* Source in fifo */ | |
460 | if (dtp->dev_flags & DEV_FLAGS_OUT) | |
461 | cmd0 |= DSCR_CMD0_DN; /* Destination out fifo */ | |
462 | ||
463 | /* Set up source1. For now, assume no stride and increment. | |
464 | * A channel attribute update can change this later. | |
465 | */ | |
466 | switch (stp->dev_tsize) { | |
467 | case 1: | |
468 | src1 |= DSCR_SRC1_STS(DSCR_xTS_SIZE1); | |
469 | break; | |
470 | case 2: | |
471 | src1 |= DSCR_SRC1_STS(DSCR_xTS_SIZE2); | |
472 | break; | |
473 | case 4: | |
474 | src1 |= DSCR_SRC1_STS(DSCR_xTS_SIZE4); | |
475 | break; | |
476 | case 8: | |
477 | default: | |
478 | src1 |= DSCR_SRC1_STS(DSCR_xTS_SIZE8); | |
479 | break; | |
480 | } | |
481 | ||
482 | /* If source input is fifo, set static address. | |
483 | */ | |
484 | if (stp->dev_flags & DEV_FLAGS_IN) { | |
e3ad1c23 PP |
485 | if ( stp->dev_flags & DEV_FLAGS_BURSTABLE ) |
486 | src1 |= DSCR_SRC1_SAM(DSCR_xAM_BURST); | |
487 | else | |
1da177e4 | 488 | src1 |= DSCR_SRC1_SAM(DSCR_xAM_STATIC); |
e3ad1c23 | 489 | |
1da177e4 | 490 | } |
e3ad1c23 PP |
491 | if (stp->dev_physaddr) |
492 | src0 = stp->dev_physaddr; | |
1da177e4 LT |
493 | |
494 | /* Set up dest1. For now, assume no stride and increment. | |
495 | * A channel attribute update can change this later. | |
496 | */ | |
497 | switch (dtp->dev_tsize) { | |
498 | case 1: | |
499 | dest1 |= DSCR_DEST1_DTS(DSCR_xTS_SIZE1); | |
500 | break; | |
501 | case 2: | |
502 | dest1 |= DSCR_DEST1_DTS(DSCR_xTS_SIZE2); | |
503 | break; | |
504 | case 4: | |
505 | dest1 |= DSCR_DEST1_DTS(DSCR_xTS_SIZE4); | |
506 | break; | |
507 | case 8: | |
508 | default: | |
509 | dest1 |= DSCR_DEST1_DTS(DSCR_xTS_SIZE8); | |
510 | break; | |
511 | } | |
512 | ||
513 | /* If destination output is fifo, set static address. | |
514 | */ | |
515 | if (dtp->dev_flags & DEV_FLAGS_OUT) { | |
e3ad1c23 PP |
516 | if ( dtp->dev_flags & DEV_FLAGS_BURSTABLE ) |
517 | dest1 |= DSCR_DEST1_DAM(DSCR_xAM_BURST); | |
518 | else | |
1da177e4 LT |
519 | dest1 |= DSCR_DEST1_DAM(DSCR_xAM_STATIC); |
520 | } | |
e3ad1c23 PP |
521 | if (dtp->dev_physaddr) |
522 | dest0 = dtp->dev_physaddr; | |
1da177e4 | 523 | |
e3ad1c23 PP |
524 | #if 0 |
525 | printk("did:%x sid:%x cmd0:%x cmd1:%x source0:%x source1:%x dest0:%x dest1:%x\n", | |
526 | dtp->dev_id, stp->dev_id, cmd0, cmd1, src0, src1, dest0, dest1 ); | |
527 | #endif | |
1da177e4 LT |
528 | for (i=0; i<entries; i++) { |
529 | dp->dscr_cmd0 = cmd0; | |
530 | dp->dscr_cmd1 = cmd1; | |
531 | dp->dscr_source0 = src0; | |
532 | dp->dscr_source1 = src1; | |
533 | dp->dscr_dest0 = dest0; | |
534 | dp->dscr_dest1 = dest1; | |
535 | dp->dscr_stat = 0; | |
e3ad1c23 | 536 | dp->sw_context = dp->sw_status = 0; |
1da177e4 LT |
537 | dp->dscr_nxtptr = DSCR_NXTPTR(virt_to_phys(dp + 1)); |
538 | dp++; | |
539 | } | |
540 | ||
541 | /* Make last descrptor point to the first. | |
542 | */ | |
543 | dp--; | |
544 | dp->dscr_nxtptr = DSCR_NXTPTR(virt_to_phys(ctp->chan_desc_base)); | |
545 | ctp->get_ptr = ctp->put_ptr = ctp->cur_ptr = ctp->chan_desc_base; | |
546 | ||
547 | return (u32)(ctp->chan_desc_base); | |
548 | } | |
e3ad1c23 | 549 | EXPORT_SYMBOL(au1xxx_dbdma_ring_alloc); |
1da177e4 LT |
550 | |
551 | /* Put a source buffer into the DMA ring. | |
552 | * This updates the source pointer and byte count. Normally used | |
553 | * for memory to fifo transfers. | |
554 | */ | |
555 | u32 | |
e3ad1c23 | 556 | _au1xxx_dbdma_put_source(u32 chanid, void *buf, int nbytes, u32 flags) |
1da177e4 LT |
557 | { |
558 | chan_tab_t *ctp; | |
559 | au1x_ddma_desc_t *dp; | |
560 | ||
561 | /* I guess we could check this to be within the | |
562 | * range of the table...... | |
563 | */ | |
564 | ctp = *((chan_tab_t **)chanid); | |
565 | ||
566 | /* We should have multiple callers for a particular channel, | |
567 | * an interrupt doesn't affect this pointer nor the descriptor, | |
568 | * so no locking should be needed. | |
569 | */ | |
570 | dp = ctp->put_ptr; | |
571 | ||
572 | /* If the descriptor is valid, we are way ahead of the DMA | |
573 | * engine, so just return an error condition. | |
574 | */ | |
575 | if (dp->dscr_cmd0 & DSCR_CMD0_V) { | |
576 | return 0; | |
577 | } | |
578 | ||
579 | /* Load up buffer address and byte count. | |
580 | */ | |
581 | dp->dscr_source0 = virt_to_phys(buf); | |
582 | dp->dscr_cmd1 = nbytes; | |
e3ad1c23 PP |
583 | /* Check flags */ |
584 | if (flags & DDMA_FLAGS_IE) | |
585 | dp->dscr_cmd0 |= DSCR_CMD0_IE; | |
586 | if (flags & DDMA_FLAGS_NOIE) | |
587 | dp->dscr_cmd0 &= ~DSCR_CMD0_IE; | |
1da177e4 LT |
588 | /* Get next descriptor pointer. |
589 | */ | |
590 | ctp->put_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr)); | |
591 | ||
e3ad1c23 PP |
592 | /* |
593 | * There is an errata on the Au1200/Au1550 parts that could result | |
594 | * in "stale" data being DMA'd. It has to do with the snoop logic on | |
595 | * the dache eviction buffer. NONCOHERENT_IO is on by default for | |
596 | * these parts. If it is fixedin the future, these dma_cache_inv will | |
597 | * just be nothing more than empty macros. See io.h. | |
598 | * */ | |
599 | dma_cache_wback_inv(buf,nbytes); | |
600 | dp->dscr_cmd0 |= DSCR_CMD0_V; /* Let it rip */ | |
601 | au_sync(); | |
602 | dma_cache_wback_inv(dp, sizeof(dp)); | |
603 | ctp->chan_ptr->ddma_dbell = 0; | |
604 | ||
1da177e4 LT |
605 | /* return something not zero. |
606 | */ | |
607 | return nbytes; | |
608 | } | |
e3ad1c23 | 609 | EXPORT_SYMBOL(_au1xxx_dbdma_put_source); |
1da177e4 LT |
610 | |
611 | /* Put a destination buffer into the DMA ring. | |
612 | * This updates the destination pointer and byte count. Normally used | |
613 | * to place an empty buffer into the ring for fifo to memory transfers. | |
614 | */ | |
615 | u32 | |
e3ad1c23 | 616 | _au1xxx_dbdma_put_dest(u32 chanid, void *buf, int nbytes, u32 flags) |
1da177e4 LT |
617 | { |
618 | chan_tab_t *ctp; | |
619 | au1x_ddma_desc_t *dp; | |
620 | ||
621 | /* I guess we could check this to be within the | |
622 | * range of the table...... | |
623 | */ | |
624 | ctp = *((chan_tab_t **)chanid); | |
625 | ||
626 | /* We should have multiple callers for a particular channel, | |
627 | * an interrupt doesn't affect this pointer nor the descriptor, | |
628 | * so no locking should be needed. | |
629 | */ | |
630 | dp = ctp->put_ptr; | |
631 | ||
632 | /* If the descriptor is valid, we are way ahead of the DMA | |
633 | * engine, so just return an error condition. | |
634 | */ | |
635 | if (dp->dscr_cmd0 & DSCR_CMD0_V) | |
636 | return 0; | |
637 | ||
e3ad1c23 PP |
638 | /* Load up buffer address and byte count */ |
639 | ||
640 | /* Check flags */ | |
641 | if (flags & DDMA_FLAGS_IE) | |
642 | dp->dscr_cmd0 |= DSCR_CMD0_IE; | |
643 | if (flags & DDMA_FLAGS_NOIE) | |
644 | dp->dscr_cmd0 &= ~DSCR_CMD0_IE; | |
645 | ||
1da177e4 LT |
646 | dp->dscr_dest0 = virt_to_phys(buf); |
647 | dp->dscr_cmd1 = nbytes; | |
e3ad1c23 PP |
648 | #if 0 |
649 | printk("cmd0:%x cmd1:%x source0:%x source1:%x dest0:%x dest1:%x\n", | |
650 | dp->dscr_cmd0, dp->dscr_cmd1, dp->dscr_source0, | |
651 | dp->dscr_source1, dp->dscr_dest0, dp->dscr_dest1 ); | |
652 | #endif | |
653 | /* | |
654 | * There is an errata on the Au1200/Au1550 parts that could result in | |
655 | * "stale" data being DMA'd. It has to do with the snoop logic on the | |
656 | * dache eviction buffer. NONCOHERENT_IO is on by default for these | |
657 | * parts. If it is fixedin the future, these dma_cache_inv will just | |
658 | * be nothing more than empty macros. See io.h. | |
659 | * */ | |
660 | dma_cache_inv(buf,nbytes); | |
1da177e4 | 661 | dp->dscr_cmd0 |= DSCR_CMD0_V; /* Let it rip */ |
e3ad1c23 PP |
662 | au_sync(); |
663 | dma_cache_wback_inv(dp, sizeof(dp)); | |
664 | ctp->chan_ptr->ddma_dbell = 0; | |
1da177e4 LT |
665 | |
666 | /* Get next descriptor pointer. | |
667 | */ | |
668 | ctp->put_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr)); | |
669 | ||
670 | /* return something not zero. | |
671 | */ | |
672 | return nbytes; | |
673 | } | |
e3ad1c23 | 674 | EXPORT_SYMBOL(_au1xxx_dbdma_put_dest); |
1da177e4 LT |
675 | |
676 | /* Get a destination buffer into the DMA ring. | |
677 | * Normally used to get a full buffer from the ring during fifo | |
678 | * to memory transfers. This does not set the valid bit, you will | |
679 | * have to put another destination buffer to keep the DMA going. | |
680 | */ | |
681 | u32 | |
682 | au1xxx_dbdma_get_dest(u32 chanid, void **buf, int *nbytes) | |
683 | { | |
684 | chan_tab_t *ctp; | |
685 | au1x_ddma_desc_t *dp; | |
686 | u32 rv; | |
687 | ||
688 | /* I guess we could check this to be within the | |
689 | * range of the table...... | |
690 | */ | |
691 | ctp = *((chan_tab_t **)chanid); | |
692 | ||
693 | /* We should have multiple callers for a particular channel, | |
694 | * an interrupt doesn't affect this pointer nor the descriptor, | |
695 | * so no locking should be needed. | |
696 | */ | |
697 | dp = ctp->get_ptr; | |
698 | ||
699 | /* If the descriptor is valid, we are way ahead of the DMA | |
700 | * engine, so just return an error condition. | |
701 | */ | |
702 | if (dp->dscr_cmd0 & DSCR_CMD0_V) | |
703 | return 0; | |
704 | ||
705 | /* Return buffer address and byte count. | |
706 | */ | |
707 | *buf = (void *)(phys_to_virt(dp->dscr_dest0)); | |
708 | *nbytes = dp->dscr_cmd1; | |
709 | rv = dp->dscr_stat; | |
710 | ||
711 | /* Get next descriptor pointer. | |
712 | */ | |
713 | ctp->get_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr)); | |
714 | ||
715 | /* return something not zero. | |
716 | */ | |
717 | return rv; | |
718 | } | |
719 | ||
720 | void | |
721 | au1xxx_dbdma_stop(u32 chanid) | |
722 | { | |
723 | chan_tab_t *ctp; | |
e3ad1c23 | 724 | au1x_dma_chan_t *cp; |
1da177e4 LT |
725 | int halt_timeout = 0; |
726 | ||
727 | ctp = *((chan_tab_t **)chanid); | |
728 | ||
729 | cp = ctp->chan_ptr; | |
730 | cp->ddma_cfg &= ~DDMA_CFG_EN; /* Disable channel */ | |
731 | au_sync(); | |
732 | while (!(cp->ddma_stat & DDMA_STAT_H)) { | |
733 | udelay(1); | |
734 | halt_timeout++; | |
735 | if (halt_timeout > 100) { | |
736 | printk("warning: DMA channel won't halt\n"); | |
737 | break; | |
738 | } | |
739 | } | |
740 | /* clear current desc valid and doorbell */ | |
741 | cp->ddma_stat |= (DDMA_STAT_DB | DDMA_STAT_V); | |
742 | au_sync(); | |
743 | } | |
e3ad1c23 | 744 | EXPORT_SYMBOL(au1xxx_dbdma_stop); |
1da177e4 LT |
745 | |
746 | /* Start using the current descriptor pointer. If the dbdma encounters | |
747 | * a not valid descriptor, it will stop. In this case, we can just | |
748 | * continue by adding a buffer to the list and starting again. | |
749 | */ | |
750 | void | |
751 | au1xxx_dbdma_start(u32 chanid) | |
752 | { | |
753 | chan_tab_t *ctp; | |
e3ad1c23 | 754 | au1x_dma_chan_t *cp; |
1da177e4 LT |
755 | |
756 | ctp = *((chan_tab_t **)chanid); | |
1da177e4 LT |
757 | cp = ctp->chan_ptr; |
758 | cp->ddma_desptr = virt_to_phys(ctp->cur_ptr); | |
759 | cp->ddma_cfg |= DDMA_CFG_EN; /* Enable channel */ | |
760 | au_sync(); | |
e3ad1c23 | 761 | cp->ddma_dbell = 0; |
1da177e4 LT |
762 | au_sync(); |
763 | } | |
e3ad1c23 | 764 | EXPORT_SYMBOL(au1xxx_dbdma_start); |
1da177e4 LT |
765 | |
766 | void | |
767 | au1xxx_dbdma_reset(u32 chanid) | |
768 | { | |
769 | chan_tab_t *ctp; | |
770 | au1x_ddma_desc_t *dp; | |
771 | ||
772 | au1xxx_dbdma_stop(chanid); | |
773 | ||
774 | ctp = *((chan_tab_t **)chanid); | |
775 | ctp->get_ptr = ctp->put_ptr = ctp->cur_ptr = ctp->chan_desc_base; | |
776 | ||
777 | /* Run through the descriptors and reset the valid indicator. | |
778 | */ | |
779 | dp = ctp->chan_desc_base; | |
780 | ||
781 | do { | |
782 | dp->dscr_cmd0 &= ~DSCR_CMD0_V; | |
e3ad1c23 PP |
783 | /* reset our SW status -- this is used to determine |
784 | * if a descriptor is in use by upper level SW. Since | |
785 | * posting can reset 'V' bit. | |
786 | */ | |
787 | dp->sw_status = 0; | |
1da177e4 LT |
788 | dp = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr)); |
789 | } while (dp != ctp->chan_desc_base); | |
790 | } | |
e3ad1c23 | 791 | EXPORT_SYMBOL(au1xxx_dbdma_reset); |
1da177e4 LT |
792 | |
793 | u32 | |
794 | au1xxx_get_dma_residue(u32 chanid) | |
795 | { | |
796 | chan_tab_t *ctp; | |
e3ad1c23 | 797 | au1x_dma_chan_t *cp; |
1da177e4 LT |
798 | u32 rv; |
799 | ||
800 | ctp = *((chan_tab_t **)chanid); | |
801 | cp = ctp->chan_ptr; | |
802 | ||
803 | /* This is only valid if the channel is stopped. | |
804 | */ | |
805 | rv = cp->ddma_bytecnt; | |
806 | au_sync(); | |
807 | ||
808 | return rv; | |
809 | } | |
810 | ||
811 | void | |
812 | au1xxx_dbdma_chan_free(u32 chanid) | |
813 | { | |
814 | chan_tab_t *ctp; | |
815 | dbdev_tab_t *stp, *dtp; | |
816 | ||
817 | ctp = *((chan_tab_t **)chanid); | |
818 | stp = ctp->chan_src; | |
819 | dtp = ctp->chan_dest; | |
820 | ||
821 | au1xxx_dbdma_stop(chanid); | |
822 | ||
823 | if (ctp->chan_desc_base != NULL) | |
824 | kfree(ctp->chan_desc_base); | |
825 | ||
826 | stp->dev_flags &= ~DEV_FLAGS_INUSE; | |
827 | dtp->dev_flags &= ~DEV_FLAGS_INUSE; | |
828 | chan_tab_ptr[ctp->chan_index] = NULL; | |
829 | ||
830 | kfree(ctp); | |
831 | } | |
e3ad1c23 | 832 | EXPORT_SYMBOL(au1xxx_dbdma_chan_free); |
1da177e4 | 833 | |
e3ad1c23 | 834 | static void |
1da177e4 LT |
835 | dbdma_interrupt(int irq, void *dev_id, struct pt_regs *regs) |
836 | { | |
e3ad1c23 | 837 | u32 intstat, flags; |
1da177e4 LT |
838 | u32 chan_index; |
839 | chan_tab_t *ctp; | |
840 | au1x_ddma_desc_t *dp; | |
e3ad1c23 | 841 | au1x_dma_chan_t *cp; |
1da177e4 LT |
842 | |
843 | intstat = dbdma_gptr->ddma_intstat; | |
844 | au_sync(); | |
845 | chan_index = au_ffs(intstat) - 1; | |
846 | ||
847 | ctp = chan_tab_ptr[chan_index]; | |
848 | cp = ctp->chan_ptr; | |
849 | dp = ctp->cur_ptr; | |
850 | ||
851 | /* Reset interrupt. | |
852 | */ | |
853 | cp->ddma_irq = 0; | |
854 | au_sync(); | |
855 | ||
856 | if (ctp->chan_callback) | |
857 | (ctp->chan_callback)(irq, ctp->chan_callparam, regs); | |
858 | ||
859 | ctp->cur_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr)); | |
1da177e4 LT |
860 | } |
861 | ||
e3ad1c23 | 862 | static void au1xxx_dbdma_init(void) |
1da177e4 | 863 | { |
e3ad1c23 PP |
864 | int irq_nr; |
865 | ||
1da177e4 LT |
866 | dbdma_gptr->ddma_config = 0; |
867 | dbdma_gptr->ddma_throttle = 0; | |
868 | dbdma_gptr->ddma_inten = 0xffff; | |
869 | au_sync(); | |
870 | ||
e3ad1c23 PP |
871 | #if defined(CONFIG_SOC_AU1550) |
872 | irq_nr = AU1550_DDMA_INT; | |
873 | #elif defined(CONFIG_SOC_AU1200) | |
874 | irq_nr = AU1200_DDMA_INT; | |
875 | #else | |
876 | #error Unknown Au1x00 SOC | |
877 | #endif | |
878 | ||
879 | if (request_irq(irq_nr, dbdma_interrupt, SA_INTERRUPT, | |
1da177e4 LT |
880 | "Au1xxx dbdma", (void *)dbdma_gptr)) |
881 | printk("Can't get 1550 dbdma irq"); | |
882 | } | |
883 | ||
884 | void | |
885 | au1xxx_dbdma_dump(u32 chanid) | |
886 | { | |
887 | chan_tab_t *ctp; | |
888 | au1x_ddma_desc_t *dp; | |
889 | dbdev_tab_t *stp, *dtp; | |
e3ad1c23 PP |
890 | au1x_dma_chan_t *cp; |
891 | u32 i = 0; | |
1da177e4 LT |
892 | |
893 | ctp = *((chan_tab_t **)chanid); | |
894 | stp = ctp->chan_src; | |
895 | dtp = ctp->chan_dest; | |
896 | cp = ctp->chan_ptr; | |
897 | ||
898 | printk("Chan %x, stp %x (dev %d) dtp %x (dev %d) \n", | |
899 | (u32)ctp, (u32)stp, stp - dbdev_tab, (u32)dtp, dtp - dbdev_tab); | |
900 | printk("desc base %x, get %x, put %x, cur %x\n", | |
901 | (u32)(ctp->chan_desc_base), (u32)(ctp->get_ptr), | |
902 | (u32)(ctp->put_ptr), (u32)(ctp->cur_ptr)); | |
903 | ||
904 | printk("dbdma chan %x\n", (u32)cp); | |
905 | printk("cfg %08x, desptr %08x, statptr %08x\n", | |
906 | cp->ddma_cfg, cp->ddma_desptr, cp->ddma_statptr); | |
907 | printk("dbell %08x, irq %08x, stat %08x, bytecnt %08x\n", | |
908 | cp->ddma_dbell, cp->ddma_irq, cp->ddma_stat, cp->ddma_bytecnt); | |
909 | ||
910 | ||
911 | /* Run through the descriptors | |
912 | */ | |
913 | dp = ctp->chan_desc_base; | |
914 | ||
915 | do { | |
e3ad1c23 PP |
916 | printk("Dp[%d]= %08x, cmd0 %08x, cmd1 %08x\n", |
917 | i++, (u32)dp, dp->dscr_cmd0, dp->dscr_cmd1); | |
918 | printk("src0 %08x, src1 %08x, dest0 %08x, dest1 %08x\n", | |
919 | dp->dscr_source0, dp->dscr_source1, dp->dscr_dest0, dp->dscr_dest1); | |
920 | printk("stat %08x, nxtptr %08x\n", | |
921 | dp->dscr_stat, dp->dscr_nxtptr); | |
1da177e4 LT |
922 | dp = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr)); |
923 | } while (dp != ctp->chan_desc_base); | |
924 | } | |
925 | ||
e3ad1c23 PP |
926 | /* Put a descriptor into the DMA ring. |
927 | * This updates the source/destination pointers and byte count. | |
928 | */ | |
929 | u32 | |
930 | au1xxx_dbdma_put_dscr(u32 chanid, au1x_ddma_desc_t *dscr ) | |
931 | { | |
932 | chan_tab_t *ctp; | |
933 | au1x_ddma_desc_t *dp; | |
934 | u32 nbytes=0; | |
935 | ||
936 | /* I guess we could check this to be within the | |
937 | * range of the table...... | |
938 | */ | |
939 | ctp = *((chan_tab_t **)chanid); | |
940 | ||
941 | /* We should have multiple callers for a particular channel, | |
942 | * an interrupt doesn't affect this pointer nor the descriptor, | |
943 | * so no locking should be needed. | |
944 | */ | |
945 | dp = ctp->put_ptr; | |
946 | ||
947 | /* If the descriptor is valid, we are way ahead of the DMA | |
948 | * engine, so just return an error condition. | |
949 | */ | |
950 | if (dp->dscr_cmd0 & DSCR_CMD0_V) | |
951 | return 0; | |
952 | ||
953 | /* Load up buffer addresses and byte count. | |
954 | */ | |
955 | dp->dscr_dest0 = dscr->dscr_dest0; | |
956 | dp->dscr_source0 = dscr->dscr_source0; | |
957 | dp->dscr_dest1 = dscr->dscr_dest1; | |
958 | dp->dscr_source1 = dscr->dscr_source1; | |
959 | dp->dscr_cmd1 = dscr->dscr_cmd1; | |
960 | nbytes = dscr->dscr_cmd1; | |
961 | /* Allow the caller to specifiy if an interrupt is generated */ | |
962 | dp->dscr_cmd0 &= ~DSCR_CMD0_IE; | |
963 | dp->dscr_cmd0 |= dscr->dscr_cmd0 | DSCR_CMD0_V; | |
964 | ctp->chan_ptr->ddma_dbell = 0; | |
965 | ||
966 | /* Get next descriptor pointer. | |
967 | */ | |
968 | ctp->put_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr)); | |
969 | ||
970 | /* return something not zero. | |
971 | */ | |
972 | return nbytes; | |
973 | } | |
974 | ||
1da177e4 LT |
975 | #endif /* defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200) */ |
976 |