dmac.h 11 KB

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