fsl_sai_edma.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. /*
  2. * The Clear BSD License
  3. * Copyright (c) 2015, Freescale Semiconductor, Inc.
  4. * Copyright 2016-2017 NXP
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without modification,
  8. * are permitted (subject to the limitations in the disclaimer below) provided
  9. * that the following conditions are met:
  10. *
  11. * o Redistributions of source code must retain the above copyright notice, this list
  12. * of conditions and the following disclaimer.
  13. *
  14. * o Redistributions in binary form must reproduce the above copyright notice, this
  15. * list of conditions and the following disclaimer in the documentation and/or
  16. * other materials provided with the distribution.
  17. *
  18. * o Neither the name of the copyright holder nor the names of its
  19. * contributors may be used to endorse or promote products derived from this
  20. * software without specific prior written permission.
  21. *
  22. * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE.
  23. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  24. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  25. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  26. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
  27. * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  28. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  29. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  30. * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  31. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  32. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  33. */
  34. #include "fsl_sai_edma.h"
  35. /*******************************************************************************
  36. * Definitations
  37. ******************************************************************************/
  38. /* Used for 32byte aligned */
  39. #define STCD_ADDR(address) (edma_tcd_t *)(((uint32_t)address + 32) & ~0x1FU)
  40. /*<! Structure definition for uart_edma_private_handle_t. The structure is private. */
  41. typedef struct _sai_edma_private_handle
  42. {
  43. I2S_Type *base;
  44. sai_edma_handle_t *handle;
  45. } sai_edma_private_handle_t;
  46. enum _sai_edma_transfer_state
  47. {
  48. kSAI_Busy = 0x0U, /*!< SAI is busy */
  49. kSAI_Idle, /*!< Transfer is done. */
  50. };
  51. /*<! Private handle only used for internally. */
  52. static sai_edma_private_handle_t s_edmaPrivateHandle[FSL_FEATURE_SOC_I2S_COUNT][2];
  53. /*******************************************************************************
  54. * Prototypes
  55. ******************************************************************************/
  56. /*!
  57. * @brief Get the instance number for SAI.
  58. *
  59. * @param base SAI base pointer.
  60. */
  61. extern uint32_t SAI_GetInstance(I2S_Type *base);
  62. /*!
  63. * @brief SAI EDMA callback for send.
  64. *
  65. * @param handle pointer to sai_edma_handle_t structure which stores the transfer state.
  66. * @param userData Parameter for user callback.
  67. * @param done If the DMA transfer finished.
  68. * @param tcds The TCD index.
  69. */
  70. static void SAI_TxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds);
  71. /*!
  72. * @brief SAI EDMA callback for receive.
  73. *
  74. * @param handle pointer to sai_edma_handle_t structure which stores the transfer state.
  75. * @param userData Parameter for user callback.
  76. * @param done If the DMA transfer finished.
  77. * @param tcds The TCD index.
  78. */
  79. static void SAI_RxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds);
  80. /*******************************************************************************
  81. * Code
  82. ******************************************************************************/
  83. static void SAI_TxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds)
  84. {
  85. sai_edma_private_handle_t *privHandle = (sai_edma_private_handle_t *)userData;
  86. sai_edma_handle_t *saiHandle = privHandle->handle;
  87. /* If finished a blcok, call the callback function */
  88. memset(&saiHandle->saiQueue[saiHandle->queueDriver], 0, sizeof(sai_transfer_t));
  89. saiHandle->queueDriver = (saiHandle->queueDriver + 1) % SAI_XFER_QUEUE_SIZE;
  90. if (saiHandle->callback)
  91. {
  92. (saiHandle->callback)(privHandle->base, saiHandle, kStatus_SAI_TxIdle, saiHandle->userData);
  93. }
  94. /* If all data finished, just stop the transfer */
  95. if (saiHandle->saiQueue[saiHandle->queueDriver].data == NULL)
  96. {
  97. /* Disable DMA enable bit */
  98. SAI_TxEnableDMA(privHandle->base, kSAI_FIFORequestDMAEnable, false);
  99. EDMA_AbortTransfer(handle);
  100. }
  101. }
  102. static void SAI_RxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds)
  103. {
  104. sai_edma_private_handle_t *privHandle = (sai_edma_private_handle_t *)userData;
  105. sai_edma_handle_t *saiHandle = privHandle->handle;
  106. /* If finished a blcok, call the callback function */
  107. memset(&saiHandle->saiQueue[saiHandle->queueDriver], 0, sizeof(sai_transfer_t));
  108. saiHandle->queueDriver = (saiHandle->queueDriver + 1) % SAI_XFER_QUEUE_SIZE;
  109. if (saiHandle->callback)
  110. {
  111. (saiHandle->callback)(privHandle->base, saiHandle, kStatus_SAI_RxIdle, saiHandle->userData);
  112. }
  113. /* If all data finished, just stop the transfer */
  114. if (saiHandle->saiQueue[saiHandle->queueDriver].data == NULL)
  115. {
  116. /* Disable DMA enable bit */
  117. SAI_RxEnableDMA(privHandle->base, kSAI_FIFORequestDMAEnable, false);
  118. EDMA_AbortTransfer(handle);
  119. }
  120. }
  121. void SAI_TransferTxCreateHandleEDMA(
  122. I2S_Type *base, sai_edma_handle_t *handle, sai_edma_callback_t callback, void *userData, edma_handle_t *dmaHandle)
  123. {
  124. assert(handle && dmaHandle);
  125. uint32_t instance = SAI_GetInstance(base);
  126. /* Zero the handle */
  127. memset(handle, 0, sizeof(*handle));
  128. /* Set sai base to handle */
  129. handle->dmaHandle = dmaHandle;
  130. handle->callback = callback;
  131. handle->userData = userData;
  132. /* Set SAI state to idle */
  133. handle->state = kSAI_Idle;
  134. s_edmaPrivateHandle[instance][0].base = base;
  135. s_edmaPrivateHandle[instance][0].handle = handle;
  136. /* Need to use scatter gather */
  137. EDMA_InstallTCDMemory(dmaHandle, STCD_ADDR(handle->tcd), SAI_XFER_QUEUE_SIZE);
  138. /* Install callback for Tx dma channel */
  139. EDMA_SetCallback(dmaHandle, SAI_TxEDMACallback, &s_edmaPrivateHandle[instance][0]);
  140. }
  141. void SAI_TransferRxCreateHandleEDMA(
  142. I2S_Type *base, sai_edma_handle_t *handle, sai_edma_callback_t callback, void *userData, edma_handle_t *dmaHandle)
  143. {
  144. assert(handle && dmaHandle);
  145. uint32_t instance = SAI_GetInstance(base);
  146. /* Zero the handle */
  147. memset(handle, 0, sizeof(*handle));
  148. /* Set sai base to handle */
  149. handle->dmaHandle = dmaHandle;
  150. handle->callback = callback;
  151. handle->userData = userData;
  152. /* Set SAI state to idle */
  153. handle->state = kSAI_Idle;
  154. s_edmaPrivateHandle[instance][1].base = base;
  155. s_edmaPrivateHandle[instance][1].handle = handle;
  156. /* Need to use scatter gather */
  157. EDMA_InstallTCDMemory(dmaHandle, STCD_ADDR(handle->tcd), SAI_XFER_QUEUE_SIZE);
  158. /* Install callback for Tx dma channel */
  159. EDMA_SetCallback(dmaHandle, SAI_RxEDMACallback, &s_edmaPrivateHandle[instance][1]);
  160. }
  161. void SAI_TransferTxSetFormatEDMA(I2S_Type *base,
  162. sai_edma_handle_t *handle,
  163. sai_transfer_format_t *format,
  164. uint32_t mclkSourceClockHz,
  165. uint32_t bclkSourceClockHz)
  166. {
  167. assert(handle && format);
  168. /* Configure the audio format to SAI registers */
  169. SAI_TxSetFormat(base, format, mclkSourceClockHz, bclkSourceClockHz);
  170. /* Get the tranfer size from format, this should be used in EDMA configuration */
  171. if (format->bitWidth == 24U)
  172. {
  173. handle->bytesPerFrame = 4U;
  174. }
  175. else
  176. {
  177. handle->bytesPerFrame = format->bitWidth / 8U;
  178. }
  179. /* Update the data channel SAI used */
  180. handle->channel = format->channel;
  181. /* Clear the channel enable bits unitl do a send/receive */
  182. base->TCR3 &= ~I2S_TCR3_TCE_MASK;
  183. #if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
  184. handle->count = FSL_FEATURE_SAI_FIFO_COUNT - format->watermark;
  185. #else
  186. handle->count = 1U;
  187. #endif /* FSL_FEATURE_SAI_FIFO_COUNT */
  188. }
  189. void SAI_TransferRxSetFormatEDMA(I2S_Type *base,
  190. sai_edma_handle_t *handle,
  191. sai_transfer_format_t *format,
  192. uint32_t mclkSourceClockHz,
  193. uint32_t bclkSourceClockHz)
  194. {
  195. assert(handle && format);
  196. /* Configure the audio format to SAI registers */
  197. SAI_RxSetFormat(base, format, mclkSourceClockHz, bclkSourceClockHz);
  198. /* Get the tranfer size from format, this should be used in EDMA configuration */
  199. if (format->bitWidth == 24U)
  200. {
  201. handle->bytesPerFrame = 4U;
  202. }
  203. else
  204. {
  205. handle->bytesPerFrame = format->bitWidth / 8U;
  206. }
  207. /* Update the data channel SAI used */
  208. handle->channel = format->channel;
  209. /* Clear the channel enable bits unitl do a send/receive */
  210. base->RCR3 &= ~I2S_RCR3_RCE_MASK;
  211. #if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
  212. handle->count = format->watermark;
  213. #else
  214. handle->count = 1U;
  215. #endif /* FSL_FEATURE_SAI_FIFO_COUNT */
  216. }
  217. status_t SAI_TransferSendEDMA(I2S_Type *base, sai_edma_handle_t *handle, sai_transfer_t *xfer)
  218. {
  219. assert(handle && xfer);
  220. edma_transfer_config_t config = {0};
  221. uint32_t destAddr = SAI_TxGetDataRegisterAddress(base, handle->channel);
  222. /* Check if input parameter invalid */
  223. if ((xfer->data == NULL) || (xfer->dataSize == 0U))
  224. {
  225. return kStatus_InvalidArgument;
  226. }
  227. if (handle->saiQueue[handle->queueUser].data)
  228. {
  229. return kStatus_SAI_QueueFull;
  230. }
  231. /* Change the state of handle */
  232. handle->state = kSAI_Busy;
  233. /* Update the queue state */
  234. handle->transferSize[handle->queueUser] = xfer->dataSize;
  235. handle->saiQueue[handle->queueUser].data = xfer->data;
  236. handle->saiQueue[handle->queueUser].dataSize = xfer->dataSize;
  237. handle->queueUser = (handle->queueUser + 1) % SAI_XFER_QUEUE_SIZE;
  238. /* Prepare edma configure */
  239. EDMA_PrepareTransfer(&config, xfer->data, handle->bytesPerFrame, (void *)destAddr, handle->bytesPerFrame,
  240. handle->count * handle->bytesPerFrame, xfer->dataSize, kEDMA_MemoryToPeripheral);
  241. /* Store the initially configured eDMA minor byte transfer count into the SAI handle */
  242. handle->nbytes = handle->count * handle->bytesPerFrame;
  243. EDMA_SubmitTransfer(handle->dmaHandle, &config);
  244. /* Start DMA transfer */
  245. EDMA_StartTransfer(handle->dmaHandle);
  246. /* Enable DMA enable bit */
  247. SAI_TxEnableDMA(base, kSAI_FIFORequestDMAEnable, true);
  248. /* Enable SAI Tx clock */
  249. SAI_TxEnable(base, true);
  250. /* Enable the channel FIFO */
  251. base->TCR3 |= I2S_TCR3_TCE(1U << handle->channel);
  252. return kStatus_Success;
  253. }
  254. status_t SAI_TransferReceiveEDMA(I2S_Type *base, sai_edma_handle_t *handle, sai_transfer_t *xfer)
  255. {
  256. assert(handle && xfer);
  257. edma_transfer_config_t config = {0};
  258. uint32_t srcAddr = SAI_RxGetDataRegisterAddress(base, handle->channel);
  259. /* Check if input parameter invalid */
  260. if ((xfer->data == NULL) || (xfer->dataSize == 0U))
  261. {
  262. return kStatus_InvalidArgument;
  263. }
  264. if (handle->saiQueue[handle->queueUser].data)
  265. {
  266. return kStatus_SAI_QueueFull;
  267. }
  268. /* Change the state of handle */
  269. handle->state = kSAI_Busy;
  270. /* Update queue state */
  271. handle->transferSize[handle->queueUser] = xfer->dataSize;
  272. handle->saiQueue[handle->queueUser].data = xfer->data;
  273. handle->saiQueue[handle->queueUser].dataSize = xfer->dataSize;
  274. handle->queueUser = (handle->queueUser + 1) % SAI_XFER_QUEUE_SIZE;
  275. /* Prepare edma configure */
  276. EDMA_PrepareTransfer(&config, (void *)srcAddr, handle->bytesPerFrame, xfer->data, handle->bytesPerFrame,
  277. handle->count * handle->bytesPerFrame, xfer->dataSize, kEDMA_PeripheralToMemory);
  278. /* Store the initially configured eDMA minor byte transfer count into the SAI handle */
  279. handle->nbytes = handle->count * handle->bytesPerFrame;
  280. EDMA_SubmitTransfer(handle->dmaHandle, &config);
  281. /* Start DMA transfer */
  282. EDMA_StartTransfer(handle->dmaHandle);
  283. /* Enable DMA enable bit */
  284. SAI_RxEnableDMA(base, kSAI_FIFORequestDMAEnable, true);
  285. /* Enable the channel FIFO */
  286. base->RCR3 |= I2S_RCR3_RCE(1U << handle->channel);
  287. /* Enable SAI Rx clock */
  288. SAI_RxEnable(base, true);
  289. return kStatus_Success;
  290. }
  291. void SAI_TransferAbortSendEDMA(I2S_Type *base, sai_edma_handle_t *handle)
  292. {
  293. assert(handle);
  294. /* Disable dma */
  295. EDMA_AbortTransfer(handle->dmaHandle);
  296. /* Disable the channel FIFO */
  297. base->TCR3 &= ~I2S_TCR3_TCE_MASK;
  298. /* Disable DMA enable bit */
  299. SAI_TxEnableDMA(base, kSAI_FIFORequestDMAEnable, false);
  300. /* Disable Tx */
  301. SAI_TxEnable(base, false);
  302. /* Reset the FIFO pointer, at the same time clear all error flags if set */
  303. base->TCSR |= (I2S_TCSR_FR_MASK | I2S_TCSR_SR_MASK);
  304. base->TCSR &= ~I2S_TCSR_SR_MASK;
  305. /* Handle the queue index */
  306. memset(&handle->saiQueue[handle->queueDriver], 0, sizeof(sai_transfer_t));
  307. handle->queueDriver = (handle->queueDriver + 1) % SAI_XFER_QUEUE_SIZE;
  308. /* Set the handle state */
  309. handle->state = kSAI_Idle;
  310. }
  311. void SAI_TransferAbortReceiveEDMA(I2S_Type *base, sai_edma_handle_t *handle)
  312. {
  313. assert(handle);
  314. /* Disable dma */
  315. EDMA_AbortTransfer(handle->dmaHandle);
  316. /* Disable the channel FIFO */
  317. base->RCR3 &= ~I2S_RCR3_RCE_MASK;
  318. /* Disable DMA enable bit */
  319. SAI_RxEnableDMA(base, kSAI_FIFORequestDMAEnable, false);
  320. /* Disable Rx */
  321. SAI_RxEnable(base, false);
  322. /* Reset the FIFO pointer, at the same time clear all error flags if set */
  323. base->RCSR |= (I2S_RCSR_FR_MASK | I2S_RCSR_SR_MASK);
  324. base->RCSR &= ~I2S_RCSR_SR_MASK;
  325. /* Handle the queue index */
  326. memset(&handle->saiQueue[handle->queueDriver], 0, sizeof(sai_transfer_t));
  327. handle->queueDriver = (handle->queueDriver + 1) % SAI_XFER_QUEUE_SIZE;
  328. /* Set the handle state */
  329. handle->state = kSAI_Idle;
  330. }
  331. void SAI_TransferTerminateSendEDMA(I2S_Type *base, sai_edma_handle_t *handle)
  332. {
  333. assert(handle);
  334. /* Abort the current transfer */
  335. SAI_TransferAbortSendEDMA(base, handle);
  336. /* Clear all the internal information */
  337. memset(handle->tcd, 0U, sizeof(handle->tcd));
  338. memset(handle->saiQueue, 0U, sizeof(handle->saiQueue));
  339. memset(handle->transferSize, 0U, sizeof(handle->transferSize));
  340. handle->queueUser = 0U;
  341. handle->queueDriver = 0U;
  342. }
  343. void SAI_TransferTerminateReceiveEDMA(I2S_Type *base, sai_edma_handle_t *handle)
  344. {
  345. assert(handle);
  346. /* Abort the current transfer */
  347. SAI_TransferAbortReceiveEDMA(base, handle);
  348. /* Clear all the internal information */
  349. memset(handle->tcd, 0U, sizeof(handle->tcd));
  350. memset(handle->saiQueue, 0U, sizeof(handle->saiQueue));
  351. memset(handle->transferSize, 0U, sizeof(handle->transferSize));
  352. handle->queueUser = 0U;
  353. handle->queueDriver = 0U;
  354. }
  355. status_t SAI_TransferGetSendCountEDMA(I2S_Type *base, sai_edma_handle_t *handle, size_t *count)
  356. {
  357. assert(handle);
  358. status_t status = kStatus_Success;
  359. if (handle->state != kSAI_Busy)
  360. {
  361. status = kStatus_NoTransferInProgress;
  362. }
  363. else
  364. {
  365. *count = (handle->transferSize[handle->queueDriver] -
  366. (uint32_t)handle->nbytes *
  367. EDMA_GetRemainingMajorLoopCount(handle->dmaHandle->base, handle->dmaHandle->channel));
  368. }
  369. return status;
  370. }
  371. status_t SAI_TransferGetReceiveCountEDMA(I2S_Type *base, sai_edma_handle_t *handle, size_t *count)
  372. {
  373. assert(handle);
  374. status_t status = kStatus_Success;
  375. if (handle->state != kSAI_Busy)
  376. {
  377. status = kStatus_NoTransferInProgress;
  378. }
  379. else
  380. {
  381. *count = (handle->transferSize[handle->queueDriver] -
  382. (uint32_t)handle->nbytes *
  383. EDMA_GetRemainingMajorLoopCount(handle->dmaHandle->base, handle->dmaHandle->channel));
  384. }
  385. return status;
  386. }