Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
dmac.h
Go to the documentation of this file.
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 <[email protected]>
10  * Authors: Fabian Godehardt <[email protected]>
11  * Oskar Schirmer <[email protected]>
12  * Daniel Gloeckner <[email protected]>
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 {
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)
182 }
183 
184 static inline void s6dmac_set_terminal_count(u32 dmac, int chan, u32 n)
185 {
187  n |= readl(DMA_CHNL(dmac, chan) + S6_DMA_TERMCNTNB)
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))
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);
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);
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) {
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  static const 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 */