dma.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. /* *****************************************************************************
  2. * Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved.
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included
  12. * in all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  15. * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  16. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  17. * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
  18. * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19. * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20. * OTHER DEALINGS IN THE SOFTWARE.
  21. *
  22. * Except as contained in this notice, the name of Maxim Integrated
  23. * Products, Inc. shall not be used except as stated in the Maxim Integrated
  24. * Products, Inc. Branding Policy.
  25. *
  26. * The mere transfer of this software does not imply any licenses
  27. * of trade secrets, proprietary technology, copyrights, patents,
  28. * trademarks, maskwork rights, or any other form of intellectual
  29. * property whatsoever. Maxim Integrated Products, Inc. retains all
  30. * ownership rights.
  31. *
  32. * $Date: 2019-07-01 11:06:19 -0500 (Mon, 01 Jul 2019) $
  33. * $Revision: 44383 $
  34. *
  35. **************************************************************************** */
  36. #include <stddef.h>
  37. #include <stdint.h>
  38. #include "mxc_config.h"
  39. #include "mxc_assert.h"
  40. #include "mxc_lock.h"
  41. #include "mxc_sys.h"
  42. #include "dma.h"
  43. /*
  44. * Structure type
  45. */
  46. typedef struct {
  47. unsigned int valid; /* Flag to invalidate this resource */
  48. unsigned int instance; /* Hardware instance of this DMA controller */
  49. unsigned int id; /* Channel ID, which matches the index into the underlying hardware */
  50. mxc_dma_ch_regs_t *regs; /* Pointer to the registers for this channel */
  51. void (*cb)(int, int); /* Pointer to a callback function type */
  52. } dma_channel_t;
  53. #define CHECK_HANDLE(x) ((x >= 0) && (x < MXC_DMA_CHANNELS) && (dma_resource[x].valid))
  54. /* DMA driver must be initialized once before use, and may not be initialized again without shutdown, as it is a shared resource */
  55. static unsigned int dma_initialized = 0;
  56. static dma_channel_t dma_resource[MXC_DMA_CHANNELS];
  57. static uint32_t dma_lock;
  58. /* Initialize DMA to known state */
  59. int DMA_Init(void)
  60. {
  61. int i;
  62. if (dma_initialized) {
  63. return E_BAD_STATE;
  64. }
  65. /* Initialize any system-level DMA settings */
  66. SYS_DMA_Init();
  67. /* Initialize mutex */
  68. mxc_free_lock(&dma_lock);
  69. if (mxc_get_lock(&dma_lock, 1) != E_NO_ERROR) {
  70. return E_BUSY;
  71. }
  72. /* Ensure all channels are disabled at start, clear flags, init handles */
  73. MXC_DMA->cn = 0;
  74. for (i = 0; i < MXC_DMA_CHANNELS; i++) {
  75. dma_resource[i].valid = 0;
  76. dma_resource[i].instance = 0;
  77. dma_resource[i].id = i;
  78. dma_resource[i].regs = (mxc_dma_ch_regs_t *)&MXC_DMA->ch[i];
  79. dma_resource[i].regs->cfg = 0;
  80. dma_resource[i].regs->st = dma_resource[i].regs->st;
  81. dma_resource[i].cb = NULL;
  82. }
  83. dma_initialized++;
  84. mxc_free_lock(&dma_lock);
  85. return E_NO_ERROR;
  86. }
  87. /* Shut down DMA in an orderly manner, informing clients that their requests did not complete */
  88. int DMA_Shutdown(void)
  89. {
  90. int i;
  91. if (!dma_initialized) {
  92. /* Never initialized, so shutdown is not appropriate */
  93. return E_BUSY;
  94. }
  95. if (mxc_get_lock(&dma_lock, 1) != E_NO_ERROR) {
  96. return E_BUSY;
  97. }
  98. /* Prevent any new resource allocation by this API */
  99. dma_initialized = 0;
  100. /* Disable interrupts, preventing future callbacks */
  101. MXC_DMA->cn = 0;
  102. /* For each channel:
  103. * - invalidate the handles held by clients
  104. * - stop any transfer in progress
  105. */
  106. for (i = 0; i < MXC_DMA_CHANNELS; i++) {
  107. dma_resource[i].regs->cfg = 0;
  108. if (dma_resource[i].valid) {
  109. dma_resource[i].valid = 0;
  110. if (dma_resource[i].cb != NULL) {
  111. dma_resource[i].cb(i, E_SHUTDOWN);
  112. }
  113. }
  114. }
  115. /* Disable any system-level DMA settings */
  116. SYS_DMA_Shutdown();
  117. mxc_free_lock(&dma_lock);
  118. return E_NO_ERROR;
  119. }
  120. /* Request DMA channel */
  121. /* Once "owned", this channel may be used directly via the DMA_GetCHRegs(ch) pointer, or */
  122. /* configured via the API functions */
  123. int DMA_AcquireChannel(void)
  124. {
  125. int i, channel;
  126. /* Check for initialization */
  127. if (!dma_initialized) {
  128. return E_BAD_STATE;
  129. }
  130. /* If DMA is locked return busy */
  131. if (mxc_get_lock(&dma_lock, 1) != E_NO_ERROR) {
  132. return E_BUSY;
  133. }
  134. /* Default is no channel available */
  135. channel = E_NONE_AVAIL;
  136. if (dma_initialized) {
  137. for (i = 0; i < MXC_DMA_CHANNELS; i++) {
  138. if (!dma_resource[i].valid) {
  139. /* Found one */
  140. channel = i;
  141. dma_resource[i].valid = 1;
  142. dma_resource[i].regs->cfg = 0;
  143. dma_resource[i].regs->cnt_rld = 0; /* Used by DMA_Start() to conditionally set RLDEN */
  144. break;
  145. }
  146. }
  147. }
  148. mxc_free_lock(&dma_lock);
  149. return channel;
  150. }
  151. /* Release DMA channel */
  152. /* Callbacks will not be called */
  153. int DMA_ReleaseChannel(int ch)
  154. {
  155. if (CHECK_HANDLE(ch)) {
  156. if (mxc_get_lock(&dma_lock, 1) != E_NO_ERROR) {
  157. return E_BUSY;
  158. }
  159. dma_resource[ch].valid = 0;
  160. dma_resource[ch].regs->cfg = 0;
  161. dma_resource[ch].regs->st = dma_resource[ch].regs->st;
  162. mxc_free_lock(&dma_lock);
  163. } else {
  164. return E_BAD_PARAM;
  165. }
  166. return E_NO_ERROR;
  167. }
  168. /* Channel configuration */
  169. int DMA_ConfigChannel(int ch,
  170. dma_priority_t prio,
  171. dma_reqsel_t reqsel, unsigned int reqwait_en,
  172. dma_timeout_t tosel, dma_prescale_t pssel,
  173. dma_width_t srcwd, unsigned int srcinc_en,
  174. dma_width_t dstwd, unsigned int dstinc_en,
  175. unsigned int burst_size, unsigned int chdis_inten,
  176. unsigned int ctz_inten)
  177. {
  178. if (CHECK_HANDLE(ch) && (burst_size > 0)) {
  179. /* Designed to be safe, not speedy. Should not be called often */
  180. dma_resource[ch].regs->cfg =
  181. ((reqwait_en ? MXC_F_DMA_CFG_REQWAIT : 0) |
  182. (srcinc_en ? MXC_F_DMA_CFG_SRCINC : 0) |
  183. (dstinc_en ? MXC_F_DMA_CFG_DSTINC : 0) |
  184. (chdis_inten ? MXC_F_DMA_CFG_CHDIEN : 0) |
  185. (ctz_inten ? MXC_F_DMA_CFG_CTZIEN : 0) |
  186. prio |reqsel | tosel | pssel |
  187. (srcwd << MXC_F_DMA_CFG_SRCWD_POS) |
  188. (dstwd << MXC_F_DMA_CFG_DSTWD_POS) |
  189. (((burst_size - 1) << MXC_F_DMA_CFG_BRST_POS) & MXC_F_DMA_CFG_BRST));
  190. } else {
  191. return E_BAD_PARAM;
  192. }
  193. return E_NO_ERROR;
  194. }
  195. /*
  196. * DMA request selects for peripherals will override either src_addr or dst_addr.
  197. * In these cases, the overridden address is a don't care and may be 0.
  198. */
  199. int DMA_SetSrcDstCnt(int ch,
  200. void *src_addr,
  201. void *dst_addr,
  202. unsigned int count)
  203. {
  204. if (CHECK_HANDLE(ch)) {
  205. dma_resource[ch].regs->src = (unsigned int)src_addr;
  206. dma_resource[ch].regs->dst = (unsigned int)dst_addr;
  207. dma_resource[ch].regs->cnt = count;
  208. } else {
  209. return E_BAD_PARAM;
  210. }
  211. return E_NO_ERROR;
  212. }
  213. /* Must set en_reload == 1 to have any effect */
  214. int DMA_SetReload(int ch,
  215. void *src_addr_reload,
  216. void *dst_addr_reload,
  217. unsigned int count_reload)
  218. {
  219. if (CHECK_HANDLE(ch)) {
  220. dma_resource[ch].regs->src_rld = (unsigned int)src_addr_reload;
  221. dma_resource[ch].regs->dst_rld = (unsigned int)dst_addr_reload;
  222. if (dma_resource[ch].regs->cfg & MXC_F_DMA_CFG_CHEN) {
  223. /* If channel is already running, set RLDEN to enable next reload */
  224. dma_resource[ch].regs->cnt_rld = MXC_F_DMA_CNT_RLD_RLDEN | count_reload;
  225. } else {
  226. /* Otherwise, this is the initial setup, so DMA_Start() will handle setting that bit */
  227. dma_resource[ch].regs->cnt_rld = count_reload;
  228. }
  229. } else {
  230. return E_BAD_PARAM;
  231. }
  232. return E_NO_ERROR;
  233. }
  234. int DMA_SetCallback(int ch, void (*callback)(int, int))
  235. {
  236. if (CHECK_HANDLE(ch)) {
  237. /* Callback for interrupt handler, no checking is done, as NULL is valid for (none) */
  238. dma_resource[ch].cb = callback;
  239. } else {
  240. return E_BAD_PARAM;
  241. }
  242. return E_NO_ERROR;
  243. }
  244. /* Interrupt enable/disable */
  245. int DMA_EnableInterrupt(int ch)
  246. {
  247. if (CHECK_HANDLE(ch)) {
  248. MXC_DMA->cn |= (1 << ch);
  249. } else {
  250. return E_BAD_PARAM;
  251. }
  252. return E_NO_ERROR;
  253. }
  254. int DMA_DisableInterrupt(int ch)
  255. {
  256. if (CHECK_HANDLE(ch)) {
  257. MXC_DMA->cn &= ~(1 << ch);
  258. } else {
  259. return E_BAD_PARAM;
  260. }
  261. return E_NO_ERROR;
  262. }
  263. /* Channel interrupt flags */
  264. int DMA_GetFlags(int ch, unsigned int *fl)
  265. {
  266. if (CHECK_HANDLE(ch) && fl) {
  267. *fl = dma_resource[ch].regs->st;
  268. } else {
  269. return E_BAD_PARAM;
  270. }
  271. return E_NO_ERROR;
  272. }
  273. int DMA_ClearFlags(int ch)
  274. {
  275. if (CHECK_HANDLE(ch)) {
  276. dma_resource[ch].regs->st = dma_resource[ch].regs->st;
  277. } else {
  278. return E_BAD_PARAM;
  279. }
  280. return E_NO_ERROR;
  281. }
  282. /* Start channel */
  283. int DMA_Start(int ch)
  284. {
  285. if (CHECK_HANDLE(ch)) {
  286. DMA_ClearFlags(ch);
  287. if (dma_resource[ch].regs->cnt_rld) {
  288. dma_resource[ch].regs->cfg |= (MXC_F_DMA_CFG_CHEN | MXC_F_DMA_CFG_RLDEN);
  289. } else {
  290. dma_resource[ch].regs->cfg |= MXC_F_DMA_CFG_CHEN;
  291. }
  292. } else {
  293. return E_BAD_PARAM;
  294. }
  295. return E_NO_ERROR;
  296. }
  297. /* Stop channel */
  298. int DMA_Stop(int ch)
  299. {
  300. if (CHECK_HANDLE(ch)) {
  301. dma_resource[ch].regs->cfg &= ~MXC_F_DMA_CFG_CHEN;
  302. } else {
  303. return E_BAD_PARAM;
  304. }
  305. return E_NO_ERROR;
  306. }
  307. /* Get pointer to registers, for advanced users */
  308. mxc_dma_ch_regs_t *DMA_GetCHRegs(int ch)
  309. {
  310. if (CHECK_HANDLE(ch)) {
  311. return dma_resource[ch].regs;
  312. } else {
  313. return NULL;
  314. }
  315. }
  316. /* */
  317. void DMA_Handler(int ch)
  318. {
  319. /* Do callback, if enabled */
  320. if (dma_resource[ch].cb != NULL) {
  321. dma_resource[ch].cb(ch, E_NO_ERROR);
  322. }
  323. DMA_ClearFlags(ch);
  324. }