xtensa: s6000 dma engine support
[pandora-kernel.git] / arch / xtensa / variants / s6000 / include / variant / dmac.h
1 /*
2  * include/asm-xtensa/variant-s6000/dmac.h
3  *
4  * This file is subject to the terms and conditions of the GNU General Public
5  * License.  See the file "COPYING" in the main directory of this archive
6  * for more details.
7  *
8  * Copyright (C) 2006 Tensilica Inc.
9  * Copyright (C) 2008 Emlix GmbH <info@emlix.com>
10  * Authors:     Fabian Godehardt <fg@emlix.com>
11  *              Oskar Schirmer <os@emlix.com>
12  *              Daniel Gloeckner <dg@emlix.com>
13  */
14
15 #ifndef __ASM_XTENSA_S6000_DMAC_H
16 #define __ASM_XTENSA_S6000_DMAC_H
17 #include <linux/io.h>
18 #include <variant/hardware.h>
19
20 /* DMA global */
21
22 #define S6_DMA_INTSTAT0         0x000
23 #define S6_DMA_INTSTAT1         0x004
24 #define S6_DMA_INTENABLE0       0x008
25 #define S6_DMA_INTENABLE1       0x00C
26 #define S6_DMA_INTRAW0          0x010
27 #define S6_DMA_INTRAW1          0x014
28 #define S6_DMA_INTCLEAR0        0x018
29 #define S6_DMA_INTCLEAR1        0x01C
30 #define S6_DMA_INTSET0          0x020
31 #define S6_DMA_INTSET1          0x024
32 #define S6_DMA_INT0_UNDER               0
33 #define S6_DMA_INT0_OVER                16
34 #define S6_DMA_INT1_CHANNEL             0
35 #define S6_DMA_INT1_MASTER              16
36 #define S6_DMA_INT1_MASTER_MASK                 7
37 #define S6_DMA_TERMCNTIRQSTAT   0x028
38 #define S6_DMA_TERMCNTIRQCLR    0x02C
39 #define S6_DMA_TERMCNTIRQSET    0x030
40 #define S6_DMA_PENDCNTIRQSTAT   0x034
41 #define S6_DMA_PENDCNTIRQCLR    0x038
42 #define S6_DMA_PENDCNTIRQSET    0x03C
43 #define S6_DMA_LOWWMRKIRQSTAT   0x040
44 #define S6_DMA_LOWWMRKIRQCLR    0x044
45 #define S6_DMA_LOWWMRKIRQSET    0x048
46 #define S6_DMA_MASTERERRINFO    0x04C
47 #define S6_DMA_MASTERERR_CHAN(n)        (4*(n))
48 #define S6_DMA_MASTERERR_CHAN_MASK              0xF
49 #define S6_DMA_DESCRFIFO0       0x050
50 #define S6_DMA_DESCRFIFO1       0x054
51 #define S6_DMA_DESCRFIFO2       0x058
52 #define S6_DMA_DESCRFIFO2_AUTODISABLE   24
53 #define S6_DMA_DESCRFIFO3       0x05C
54 #define S6_DMA_MASTER0START     0x060
55 #define S6_DMA_MASTER0END       0x064
56 #define S6_DMA_MASTER1START     0x068
57 #define S6_DMA_MASTER1END       0x06C
58 #define S6_DMA_NEXTFREE         0x070
59 #define S6_DMA_NEXTFREE_CHAN            0
60 #define S6_DMA_NEXTFREE_CHAN_MASK       0x1F
61 #define S6_DMA_NEXTFREE_ENA             16
62 #define S6_DMA_NEXTFREE_ENA_MASK        ((1 << 16) - 1)
63 #define S6_DMA_DPORTCTRLGRP(p)  ((p) * 4 + 0x074)
64 #define S6_DMA_DPORTCTRLGRP_FRAMEREP    0
65 #define S6_DMA_DPORTCTRLGRP_NRCHANS     1
66 #define S6_DMA_DPORTCTRLGRP_NRCHANS_1           0
67 #define S6_DMA_DPORTCTRLGRP_NRCHANS_3           1
68 #define S6_DMA_DPORTCTRLGRP_NRCHANS_4           2
69 #define S6_DMA_DPORTCTRLGRP_NRCHANS_2           3
70 #define S6_DMA_DPORTCTRLGRP_ENA         31
71
72
73 /* DMA per channel */
74
75 #define DMA_CHNL(dmac, n)       ((dmac) + 0x1000 + (n) * 0x100)
76 #define DMA_INDEX_CHNL(addr)    (((addr) >> 8) & 0xF)
77 #define DMA_MASK_DMAC(addr)     ((addr) & 0xFFFF0000)
78 #define S6_DMA_CHNCTRL          0x000
79 #define S6_DMA_CHNCTRL_ENABLE           0
80 #define S6_DMA_CHNCTRL_PAUSE            1
81 #define S6_DMA_CHNCTRL_PRIO             2
82 #define S6_DMA_CHNCTRL_PRIO_MASK                3
83 #define S6_DMA_CHNCTRL_PERIPHXFER       4
84 #define S6_DMA_CHNCTRL_PERIPHENA        5
85 #define S6_DMA_CHNCTRL_SRCINC           6
86 #define S6_DMA_CHNCTRL_DSTINC           7
87 #define S6_DMA_CHNCTRL_BURSTLOG         8
88 #define S6_DMA_CHNCTRL_BURSTLOG_MASK            7
89 #define S6_DMA_CHNCTRL_DESCFIFODEPTH    12
90 #define S6_DMA_CHNCTRL_DESCFIFODEPTH_MASK       0x1F
91 #define S6_DMA_CHNCTRL_DESCFIFOFULL     17
92 #define S6_DMA_CHNCTRL_BWCONSEL         18
93 #define S6_DMA_CHNCTRL_BWCONENA         19
94 #define S6_DMA_CHNCTRL_PENDGCNTSTAT     20
95 #define S6_DMA_CHNCTRL_PENDGCNTSTAT_MASK        0x3F
96 #define S6_DMA_CHNCTRL_LOWWMARK         26
97 #define S6_DMA_CHNCTRL_LOWWMARK_MASK            0xF
98 #define S6_DMA_CHNCTRL_TSTAMP           30
99 #define S6_DMA_TERMCNTNB        0x004
100 #define S6_DMA_TERMCNTNB_MASK                   0xFFFF
101 #define S6_DMA_TERMCNTTMO       0x008
102 #define S6_DMA_TERMCNTSTAT      0x00C
103 #define S6_DMA_TERMCNTSTAT_MASK         0xFF
104 #define S6_DMA_CMONCHUNK        0x010
105 #define S6_DMA_SRCSKIP          0x014
106 #define S6_DMA_DSTSKIP          0x018
107 #define S6_DMA_CUR_SRC          0x024
108 #define S6_DMA_CUR_DST          0x028
109 #define S6_DMA_TIMESTAMP        0x030
110
111 /* DMA channel lists */
112
113 #define S6_DPDMA_CHAN(stream, channel)  (4 * (stream) + (channel))
114 #define S6_DPDMA_NB     16
115
116 #define S6_HIFDMA_GMACTX        0
117 #define S6_HIFDMA_GMACRX        1
118 #define S6_HIFDMA_I2S0          2
119 #define S6_HIFDMA_I2S1          3
120 #define S6_HIFDMA_EGIB          4
121 #define S6_HIFDMA_PCITX         5
122 #define S6_HIFDMA_PCIRX         6
123 #define S6_HIFDMA_NB    7
124
125 #define S6_NIDMA_NB     4
126
127 #define S6_LMSDMA_NB    12
128
129 /* controller access */
130
131 #define S6_DMAC_NB      4
132 #define S6_DMAC_INDEX(dmac)     (((unsigned)(dmac) >> 18) % S6_DMAC_NB)
133
134 struct s6dmac_ctrl {
135         u32 dmac;
136         spinlock_t lock;
137         u8 chan_nb;
138 };
139
140 extern struct s6dmac_ctrl s6dmac_ctrl[S6_DMAC_NB];
141
142
143 /* DMA control, per channel */
144
145 static inline int s6dmac_fifo_full(u32 dmac, int chan)
146 {
147         return (readl(DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL)
148                 & (1 << S6_DMA_CHNCTRL_DESCFIFOFULL)) && 1;
149 }
150
151 static inline int s6dmac_termcnt_irq(u32 dmac, int chan)
152 {
153         u32 m = 1 << chan;
154         int r = (readl(dmac + S6_DMA_TERMCNTIRQSTAT) & m) && 1;
155         if (r)
156                 writel(m, dmac + S6_DMA_TERMCNTIRQCLR);
157         return r;
158 }
159
160 static inline int s6dmac_pendcnt_irq(u32 dmac, int chan)
161 {
162         u32 m = 1 << chan;
163         int r = (readl(dmac + S6_DMA_PENDCNTIRQSTAT) & m) && 1;
164         if (r)
165                 writel(m, dmac + S6_DMA_PENDCNTIRQCLR);
166         return r;
167 }
168
169 static inline int s6dmac_lowwmark_irq(u32 dmac, int chan)
170 {
171         int r = (readl(dmac + S6_DMA_LOWWMRKIRQSTAT) & (1 << chan)) ? 1 : 0;
172         if (r)
173                 writel(1 << chan, dmac + S6_DMA_LOWWMRKIRQCLR);
174         return r;
175 }
176
177 static inline u32 s6dmac_pending_count(u32 dmac, int chan)
178 {
179         return (readl(DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL)
180                         >> S6_DMA_CHNCTRL_PENDGCNTSTAT)
181                 & S6_DMA_CHNCTRL_PENDGCNTSTAT_MASK;
182 }
183
184 static inline void s6dmac_set_terminal_count(u32 dmac, int chan, u32 n)
185 {
186         n &= S6_DMA_TERMCNTNB_MASK;
187         n |= readl(DMA_CHNL(dmac, chan) + S6_DMA_TERMCNTNB)
188               & ~S6_DMA_TERMCNTNB_MASK;
189         writel(n, DMA_CHNL(dmac, chan) + S6_DMA_TERMCNTNB);
190 }
191
192 static inline u32 s6dmac_get_terminal_count(u32 dmac, int chan)
193 {
194         return (readl(DMA_CHNL(dmac, chan) + S6_DMA_TERMCNTNB))
195                 & S6_DMA_TERMCNTNB_MASK;
196 }
197
198 static inline u32 s6dmac_timestamp(u32 dmac, int chan)
199 {
200         return readl(DMA_CHNL(dmac, chan) + S6_DMA_TIMESTAMP);
201 }
202
203 static inline u32 s6dmac_cur_src(u32 dmac, int chan)
204 {
205         return readl(DMA_CHNL(dmac, chan) + S6_DMA_CUR_SRC);
206 }
207
208 static inline u32 s6dmac_cur_dst(u32 dmac, int chan)
209 {
210         return readl(DMA_CHNL(dmac, chan) + S6_DMA_CUR_DST);
211 }
212
213 static inline void s6dmac_disable_chan(u32 dmac, int chan)
214 {
215         u32 ctrl;
216         writel(readl(DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL)
217                 & ~(1 << S6_DMA_CHNCTRL_ENABLE),
218                 DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL);
219         do
220                 ctrl = readl(DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL);
221         while (ctrl & (1 << S6_DMA_CHNCTRL_ENABLE));
222 }
223
224 static inline void s6dmac_set_stride_skip(u32 dmac, int chan,
225         int comchunk,           /* 0: disable scatter/gather */
226         int srcskip, int dstskip)
227 {
228         writel(comchunk, DMA_CHNL(dmac, chan) + S6_DMA_CMONCHUNK);
229         writel(srcskip, DMA_CHNL(dmac, chan) + S6_DMA_SRCSKIP);
230         writel(dstskip, DMA_CHNL(dmac, chan) + S6_DMA_DSTSKIP);
231 }
232
233 static inline void s6dmac_enable_chan(u32 dmac, int chan,
234         int prio,               /* 0 (highest) .. 3 (lowest) */
235         int periphxfer,         /* <0: disable p.req.line, 0..1: mode */
236         int srcinc, int dstinc, /* 0: dont increment src/dst address */
237         int comchunk,           /* 0: disable scatter/gather */
238         int srcskip, int dstskip,
239         int burstsize,          /* 4 for I2S, 7 for everything else */
240         int bandwidthconserve,  /* <0: disable, 0..1: select */
241         int lowwmark,           /* 0..15 */
242         int timestamp,          /* 0: disable timestamp */
243         int enable)             /* 0: disable for now */
244 {
245         writel(1, DMA_CHNL(dmac, chan) + S6_DMA_TERMCNTNB);
246         writel(0, DMA_CHNL(dmac, chan) + S6_DMA_TERMCNTTMO);
247         writel(lowwmark << S6_DMA_CHNCTRL_LOWWMARK,
248                 DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL);
249         s6dmac_set_stride_skip(dmac, chan, comchunk, srcskip, dstskip);
250         writel(((enable ? 1 : 0) << S6_DMA_CHNCTRL_ENABLE) |
251                 (prio << S6_DMA_CHNCTRL_PRIO) |
252                 (((periphxfer > 0) ? 1 : 0) << S6_DMA_CHNCTRL_PERIPHXFER) |
253                 (((periphxfer < 0) ? 0 : 1) << S6_DMA_CHNCTRL_PERIPHENA) |
254                 ((srcinc ? 1 : 0) << S6_DMA_CHNCTRL_SRCINC) |
255                 ((dstinc ? 1 : 0) << S6_DMA_CHNCTRL_DSTINC) |
256                 (burstsize << S6_DMA_CHNCTRL_BURSTLOG) |
257                 (((bandwidthconserve > 0) ? 1 : 0) << S6_DMA_CHNCTRL_BWCONSEL) |
258                 (((bandwidthconserve < 0) ? 0 : 1) << S6_DMA_CHNCTRL_BWCONENA) |
259                 (lowwmark << S6_DMA_CHNCTRL_LOWWMARK) |
260                 ((timestamp ? 1 : 0) << S6_DMA_CHNCTRL_TSTAMP),
261                 DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL);
262 }
263
264
265 /* DMA control, per engine */
266
267 static inline unsigned _dmac_addr_index(u32 dmac)
268 {
269         unsigned i = S6_DMAC_INDEX(dmac);
270         if (s6dmac_ctrl[i].dmac != dmac)
271                 BUG();
272         return i;
273 }
274
275 static inline void _s6dmac_disable_error_irqs(u32 dmac, u32 mask)
276 {
277         writel(mask, dmac + S6_DMA_TERMCNTIRQCLR);
278         writel(mask, dmac + S6_DMA_PENDCNTIRQCLR);
279         writel(mask, dmac + S6_DMA_LOWWMRKIRQCLR);
280         writel(readl(dmac + S6_DMA_INTENABLE0)
281                 & ~((mask << S6_DMA_INT0_UNDER) | (mask << S6_DMA_INT0_OVER)),
282                 dmac + S6_DMA_INTENABLE0);
283         writel(readl(dmac + S6_DMA_INTENABLE1) & ~(mask << S6_DMA_INT1_CHANNEL),
284                 dmac + S6_DMA_INTENABLE1);
285         writel((mask << S6_DMA_INT0_UNDER) | (mask << S6_DMA_INT0_OVER),
286                 dmac + S6_DMA_INTCLEAR0);
287         writel(mask << S6_DMA_INT1_CHANNEL, dmac + S6_DMA_INTCLEAR1);
288 }
289
290 /*
291  * request channel from specified engine
292  * with chan<0, accept any channel
293  * further parameters see s6dmac_enable_chan
294  * returns < 0 upon error, channel nb otherwise
295  */
296 static inline int s6dmac_request_chan(u32 dmac, int chan,
297         int prio,
298         int periphxfer,
299         int srcinc, int dstinc,
300         int comchunk,
301         int srcskip, int dstskip,
302         int burstsize,
303         int bandwidthconserve,
304         int lowwmark,
305         int timestamp,
306         int enable)
307 {
308         int r = chan;
309         unsigned long flags;
310         spinlock_t *spinl = &s6dmac_ctrl[_dmac_addr_index(dmac)].lock;
311         spin_lock_irqsave(spinl, flags);
312         if (r < 0) {
313                 r = (readl(dmac + S6_DMA_NEXTFREE) >> S6_DMA_NEXTFREE_CHAN)
314                         & S6_DMA_NEXTFREE_CHAN_MASK;
315         }
316         if (r >= s6dmac_ctrl[_dmac_addr_index(dmac)].chan_nb) {
317                 if (chan < 0)
318                         r = -EBUSY;
319                 else
320                         r = -ENXIO;
321         } else if (((readl(dmac + S6_DMA_NEXTFREE) >> S6_DMA_NEXTFREE_ENA)
322                         >> r) & 1) {
323                 r = -EBUSY;
324         } else {
325                 s6dmac_enable_chan(dmac, r, prio, periphxfer,
326                         srcinc, dstinc, comchunk, srcskip, dstskip, burstsize,
327                         bandwidthconserve, lowwmark, timestamp, enable);
328         }
329         spin_unlock_irqrestore(spinl, flags);
330         return r;
331 }
332
333 static inline void s6dmac_put_fifo(u32 dmac, int chan,
334         u32 src, u32 dst, u32 size)
335 {
336         unsigned long flags;
337         spinlock_t *spinl = &s6dmac_ctrl[_dmac_addr_index(dmac)].lock;
338         spin_lock_irqsave(spinl, flags);
339         writel(src, dmac + S6_DMA_DESCRFIFO0);
340         writel(dst, dmac + S6_DMA_DESCRFIFO1);
341         writel(size, dmac + S6_DMA_DESCRFIFO2);
342         writel(chan, dmac + S6_DMA_DESCRFIFO3);
343         spin_unlock_irqrestore(spinl, flags);
344 }
345
346 static inline u32 s6dmac_channel_enabled(u32 dmac, int chan)
347 {
348         return readl(DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL) &
349                         (1 << S6_DMA_CHNCTRL_ENABLE);
350 }
351
352 /*
353  * group 1-4 data port channels
354  * with port=0..3, nrch=1-4 channels,
355  * frrep=0/1 (dis- or enable frame repeat)
356  */
357 static inline void s6dmac_dp_setup_group(u32 dmac, int port,
358                         int nrch, int frrep)
359 {
360         const static u8 mask[4] = {0, 3, 1, 2};
361         BUG_ON(dmac != S6_REG_DPDMA);
362         if ((port < 0) || (port > 3) || (nrch < 1) || (nrch > 4))
363                 return;
364         writel((mask[nrch - 1] << S6_DMA_DPORTCTRLGRP_NRCHANS)
365                 | ((frrep ? 1 : 0) << S6_DMA_DPORTCTRLGRP_FRAMEREP),
366                 dmac + S6_DMA_DPORTCTRLGRP(port));
367 }
368
369 static inline void s6dmac_dp_switch_group(u32 dmac, int port, int enable)
370 {
371         u32 tmp;
372         BUG_ON(dmac != S6_REG_DPDMA);
373         tmp = readl(dmac + S6_DMA_DPORTCTRLGRP(port));
374         if (enable)
375                 tmp |= (1 << S6_DMA_DPORTCTRLGRP_ENA);
376         else
377                 tmp &= ~(1 << S6_DMA_DPORTCTRLGRP_ENA);
378         writel(tmp, dmac + S6_DMA_DPORTCTRLGRP(port));
379 }
380
381 extern void s6dmac_put_fifo_cache(u32 dmac, int chan,
382         u32 src, u32 dst, u32 size);
383 extern void s6dmac_disable_error_irqs(u32 dmac, u32 mask);
384 extern u32 s6dmac_int_sources(u32 dmac, u32 channel);
385 extern void s6dmac_release_chan(u32 dmac, int chan);
386
387 #endif /* __ASM_XTENSA_S6000_DMAC_H */