fsl_asrc_edma.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. /*
  2. * Copyright 2019-2020 NXP
  3. * All rights reserved.
  4. *
  5. * SPDX-License-Identifier: BSD-3-Clause
  6. */
  7. #include "fsl_asrc_edma.h"
  8. /* Component ID definition, used by tools. */
  9. #ifndef FSL_COMPONENT_ID
  10. #define FSL_COMPONENT_ID "platform.drivers.asrc_edma"
  11. #endif
  12. /*******************************************************************************
  13. * Definitations
  14. ******************************************************************************/
  15. /* Used for 32byte aligned */
  16. #define STCD_ADDR(address) (edma_tcd_t *)(((uint32_t)(address) + 32U) & ~0x1FU)
  17. /*<! Structure definition for uart_edma_private_handle_t. The structure is private. */
  18. typedef struct _asrc_edma_private_handle
  19. {
  20. ASRC_Type *base;
  21. asrc_edma_handle_t *handle;
  22. } asrc_edma_private_handle_t;
  23. /*<! Private handle only used for internally. */
  24. static asrc_edma_private_handle_t s_edmaPrivateHandle[FSL_FEATURE_SOC_ASRC_COUNT][FSL_ASRC_CHANNEL_PAIR_COUNT];
  25. /*******************************************************************************
  26. * Prototypes
  27. ******************************************************************************/
  28. /*!
  29. * @brief ASRC EDMA callback for input.
  30. *
  31. * @param handle pointer to asrc_edma_handle_t structure which stores the transfer state.
  32. * @param userData Parameter for user callback.
  33. * @param done If the DMA transfer finished.
  34. * @param tcds The TCD index.
  35. */
  36. static void ASRC_InEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds);
  37. /*!
  38. * @brief ASRC EDMA callback for output.
  39. *
  40. * @param handle pointer to asrc_edma_handle_t structure which stores the transfer state.
  41. * @param userData Parameter for user callback.
  42. * @param done If the DMA transfer finished.
  43. * @param tcds The TCD index.
  44. */
  45. static void ASRC_OutEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds);
  46. /*******************************************************************************
  47. * Code
  48. ******************************************************************************/
  49. static void ASRC_InEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds)
  50. {
  51. asrc_edma_private_handle_t *privHandle = (asrc_edma_private_handle_t *)userData;
  52. asrc_edma_handle_t *asrcHandle = privHandle->handle;
  53. asrc_in_edma_handle_t *asrcInHandle = &(privHandle->handle->in);
  54. status_t inStatus = kStatus_ASRCInIdle;
  55. /* If finished a block, call the callback function */
  56. asrcInHandle->asrcQueue[asrcInHandle->queueDriver] = NULL;
  57. asrcInHandle->queueDriver = (asrcInHandle->queueDriver + 1U) % ASRC_XFER_QUEUE_SIZE;
  58. /* If all data finished, just stop the transfer */
  59. if (asrcInHandle->asrcQueue[asrcInHandle->queueDriver] == NULL)
  60. {
  61. EDMA_AbortTransfer(asrcInHandle->inDmaHandle);
  62. inStatus = kStatus_ASRCInQueueIdle;
  63. }
  64. if (asrcHandle->callback != NULL)
  65. {
  66. (asrcHandle->callback)(privHandle->base, asrcHandle, inStatus, asrcHandle->userData);
  67. }
  68. }
  69. static void ASRC_OutEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds)
  70. {
  71. asrc_edma_private_handle_t *privHandle = (asrc_edma_private_handle_t *)userData;
  72. asrc_edma_handle_t *asrcHandle = privHandle->handle;
  73. asrc_out_edma_handle_t *asrcOutHandle = &(privHandle->handle->out);
  74. uint32_t queueDriverIndex = asrcOutHandle->queueDriver;
  75. status_t callbackStatus = kStatus_ASRCOutIdle;
  76. /* If finished a block, call the callback function */
  77. asrcOutHandle->asrcQueue[queueDriverIndex] = NULL;
  78. asrcOutHandle->queueDriver = (uint8_t)((queueDriverIndex + 1U) % ASRC_XFER_OUT_QUEUE_SIZE);
  79. /* If all data finished, just stop the transfer */
  80. if (asrcOutHandle->asrcQueue[asrcOutHandle->queueDriver] == NULL)
  81. {
  82. EDMA_AbortTransfer(asrcOutHandle->outDmaHandle);
  83. callbackStatus = kStatus_ASRCOutQueueIdle;
  84. }
  85. if (asrcHandle->callback != NULL)
  86. {
  87. (asrcHandle->callback)(privHandle->base, asrcHandle, callbackStatus, asrcHandle->userData);
  88. }
  89. }
  90. /*!
  91. * brief Initializes the ASRC IN eDMA handle.
  92. *
  93. * This function initializes the ASRC DMA handle, which can be used for other ASRC transactional APIs.
  94. * Usually, for a specified ASRC channel pair, call this API once to get the initialized handle.
  95. *
  96. * param base ASRC base pointer.
  97. * param channelPair ASRC channel pair
  98. * param handle ASRC eDMA handle pointer.
  99. * param callback Pointer to user callback function.
  100. * param txDmaHandle ASRC send edma handle pointer.
  101. * param periphConfig peripheral configuration.
  102. * param userData User parameter passed to the callback function.
  103. */
  104. void ASRC_TransferInCreateHandleEDMA(ASRC_Type *base,
  105. asrc_edma_handle_t *handle,
  106. asrc_channel_pair_t channelPair,
  107. asrc_edma_callback_t callback,
  108. edma_handle_t *inDmaHandle,
  109. const asrc_p2p_edma_config_t *periphConfig,
  110. void *userData)
  111. {
  112. assert((handle != NULL) && (inDmaHandle != NULL));
  113. uint32_t instance = ASRC_GetInstance(base);
  114. /* Zero the handle */
  115. (void)memset(&handle->in, 0, sizeof(asrc_in_edma_handle_t));
  116. handle->in.inDmaHandle = inDmaHandle;
  117. handle->callback = callback;
  118. handle->userData = userData;
  119. /* Set ASRC state to idle */
  120. handle->in.state = kStatus_ASRCIdle;
  121. handle->channelPair = channelPair;
  122. handle->in.peripheralConfig = periphConfig;
  123. s_edmaPrivateHandle[instance][channelPair].base = base;
  124. s_edmaPrivateHandle[instance][channelPair].handle = handle;
  125. /* Need to use scatter gather */
  126. EDMA_InstallTCDMemory(inDmaHandle, (edma_tcd_t *)(STCD_ADDR(handle->in.tcd)), ASRC_XFER_OUT_QUEUE_SIZE);
  127. /* Install callback for Tx dma channel */
  128. EDMA_SetCallback(inDmaHandle, ASRC_InEDMACallback, &s_edmaPrivateHandle[instance][channelPair]);
  129. }
  130. /*!
  131. * brief Initializes the ASRC OUT eDMA handle.
  132. *
  133. * This function initializes the ASRC DMA handle, which can be used for other ASRC transactional APIs.
  134. * Usually, for a specified ASRC channel pair, call this API once to get the initialized handle.
  135. *
  136. * param base ASRC base pointer.
  137. * param channelPair ASRC channel pair
  138. * param handle ASRC eDMA handle pointer.
  139. * param callback Pointer to user callback function.
  140. * param txDmaHandle ASRC send edma handle pointer.
  141. * param periphConfig peripheral configuration.
  142. * param userData User parameter passed to the callback function.
  143. */
  144. void ASRC_TransferOutCreateHandleEDMA(ASRC_Type *base,
  145. asrc_edma_handle_t *handle,
  146. asrc_channel_pair_t channelPair,
  147. asrc_edma_callback_t callback,
  148. edma_handle_t *outDmaHandle,
  149. const asrc_p2p_edma_config_t *periphConfig,
  150. void *userData)
  151. {
  152. assert((handle != NULL) && (NULL != outDmaHandle));
  153. uint32_t instance = ASRC_GetInstance(base);
  154. /* Zero the handle */
  155. (void)memset(&handle->out, 0, sizeof(asrc_out_edma_handle_t));
  156. handle->out.outDmaHandle = outDmaHandle;
  157. handle->callback = callback;
  158. handle->userData = userData;
  159. /* Set ASRC state to idle */
  160. handle->out.state = kStatus_ASRCIdle;
  161. handle->channelPair = channelPair;
  162. handle->out.peripheralConfig = periphConfig;
  163. s_edmaPrivateHandle[instance][channelPair].base = base;
  164. s_edmaPrivateHandle[instance][channelPair].handle = handle;
  165. /* Need to use scatter gather */
  166. EDMA_InstallTCDMemory(outDmaHandle, (edma_tcd_t *)(STCD_ADDR(handle->out.tcd)), ASRC_XFER_OUT_QUEUE_SIZE);
  167. /* Install callback for Tx dma channel */
  168. EDMA_SetCallback(outDmaHandle, ASRC_OutEDMACallback, &s_edmaPrivateHandle[instance][channelPair]);
  169. }
  170. /*!
  171. * brief Configures the ASRC channel pair.
  172. *
  173. * param base ASRC base pointer.
  174. * param handle ASRC eDMA handle pointer.
  175. * param asrcConfig asrc configurations.
  176. * param periphConfig peripheral configuration.
  177. * param inputSampleRate ASRC input sample rate.
  178. * param outputSampleRate ASRC output sample rate.
  179. */
  180. status_t ASRC_TransferSetChannelPairConfigEDMA(ASRC_Type *base,
  181. asrc_edma_handle_t *handle,
  182. asrc_channel_pair_config_t *asrcConfig,
  183. uint32_t inSampleRate,
  184. uint32_t outSampleRate)
  185. {
  186. assert((handle != NULL) && (NULL != asrcConfig));
  187. /* Configure the audio format to ASRC registers */
  188. if (ASRC_SetChannelPairConfig(base, handle->channelPair, asrcConfig, inSampleRate, outSampleRate) !=
  189. kStatus_Success)
  190. {
  191. return kStatus_ASRCChannelPairConfigureFailed;
  192. }
  193. handle->in.fifoThreshold = (asrcConfig->inFifoThreshold) * (uint32_t)asrcConfig->audioDataChannels;
  194. handle->out.fifoThreshold = (asrcConfig->outFifoThreshold) * (uint32_t)asrcConfig->audioDataChannels;
  195. (void)ASRC_MapSamplesWidth(base, handle->channelPair, &handle->in.sampleWidth, &handle->out.sampleWidth);
  196. return kStatus_Success;
  197. }
  198. /*!
  199. * brief Get output sample buffer size can be transferred by edma.
  200. *
  201. * note This API is depends on the ASRC output configuration, should be called after the
  202. * ASRC_TransferSetChannelPairConfigEDMA.
  203. *
  204. * param base asrc base pointer.
  205. * param handle ASRC channel pair edma handle.
  206. * param inSampleRate input sample rate.
  207. * param outSampleRate output sample rate.
  208. * param inSamples input sampleS size.
  209. * retval output buffer size in byte.
  210. */
  211. uint32_t ASRC_GetOutSamplesSizeEDMA(
  212. ASRC_Type *base, asrc_edma_handle_t *handle, uint32_t inSampleRate, uint32_t outSampleRate, uint32_t inSamplesize)
  213. {
  214. uint32_t outputSize = ASRC_GetOutSamplesSize(base, handle->channelPair, inSampleRate, outSampleRate, inSamplesize);
  215. return outputSize - outputSize % handle->out.fifoThreshold;
  216. }
  217. static status_t ASRC_TransferOutSubmitEDMA(ASRC_Type *base,
  218. asrc_edma_handle_t *handle,
  219. uint32_t *outDataAddr,
  220. uint32_t outDataSize)
  221. {
  222. assert(outDataAddr != NULL);
  223. assert(outDataSize != 0U);
  224. uint32_t outAddr = ASRC_GetOutputDataRegisterAddress(base, handle->channelPair);
  225. edma_transfer_config_t config = {0};
  226. edma_transfer_type_t type = kEDMA_PeripheralToMemory;
  227. if (handle->out.asrcQueue[handle->out.queueUser] != NULL)
  228. {
  229. return kStatus_ASRCQueueFull;
  230. }
  231. if (handle->out.peripheralConfig != NULL)
  232. {
  233. type = kEDMA_PeripheralToPeripheral;
  234. }
  235. if (handle->out.asrcQueue[handle->out.queueUser] != NULL)
  236. {
  237. return kStatus_ASRCQueueFull;
  238. }
  239. handle->out.asrcQueue[handle->out.queueUser] = outDataAddr;
  240. handle->out.transferSize[handle->out.queueUser] = outDataSize;
  241. handle->out.queueUser = (handle->out.queueUser + 1U) % ASRC_XFER_OUT_QUEUE_SIZE;
  242. /* Prepare ASRC output edma configuration */
  243. EDMA_PrepareTransfer(&config, (uint32_t *)outAddr, handle->out.sampleWidth, outDataAddr, handle->out.sampleWidth,
  244. handle->out.fifoThreshold * handle->out.sampleWidth, outDataSize, type);
  245. if (handle->out.state != (uint32_t)kStatus_ASRCBusy)
  246. {
  247. (void)EDMA_SubmitTransfer(handle->out.outDmaHandle, &config);
  248. EDMA_StartTransfer(handle->out.outDmaHandle);
  249. if ((handle->out.peripheralConfig != NULL) && (handle->out.peripheralConfig->startPeripheral != NULL))
  250. {
  251. handle->out.peripheralConfig->startPeripheral(true);
  252. }
  253. }
  254. return kStatus_Success;
  255. }
  256. static status_t ASRC_TransferInSubmitEDMA(ASRC_Type *base,
  257. asrc_edma_handle_t *handle,
  258. uint32_t *inDataAddr,
  259. uint32_t inDataSize)
  260. {
  261. assert(inDataAddr != NULL);
  262. assert(inDataSize != 0U);
  263. uint32_t inAddr = ASRC_GetInputDataRegisterAddress(base, handle->channelPair);
  264. edma_transfer_config_t config = {0};
  265. if (handle->in.asrcQueue[handle->in.queueUser] != NULL)
  266. {
  267. return kStatus_ASRCQueueFull;
  268. }
  269. /* Add into queue */
  270. handle->in.asrcQueue[handle->in.queueUser] = inDataAddr;
  271. handle->in.transferSize[handle->in.queueUser] = inDataSize;
  272. handle->in.queueUser = (handle->in.queueUser + 1U) % ASRC_XFER_IN_QUEUE_SIZE;
  273. /* Prepare ASRC input edma configuration */
  274. EDMA_PrepareTransfer(&config, (uint32_t *)inDataAddr, handle->in.sampleWidth, (uint32_t *)inAddr,
  275. handle->in.sampleWidth, handle->in.fifoThreshold * handle->in.sampleWidth, inDataSize,
  276. handle->in.peripheralConfig == NULL ? kEDMA_MemoryToPeripheral : kEDMA_PeripheralToPeripheral);
  277. if (handle->in.state != (uint32_t)kStatus_ASRCBusy)
  278. {
  279. (void)EDMA_SubmitTransfer(handle->in.inDmaHandle, &config);
  280. EDMA_StartTransfer(handle->in.inDmaHandle);
  281. /* start peripheral */
  282. if ((handle->in.peripheralConfig != NULL) && (handle->in.peripheralConfig->startPeripheral != NULL))
  283. {
  284. handle->in.peripheralConfig->startPeripheral(true);
  285. }
  286. }
  287. return kStatus_Success;
  288. }
  289. /*!
  290. * brief Performs a non-blocking ASRC convert using EDMA.
  291. *
  292. * note This interface returns immediately after the transfer initiates.
  293. * param base ASRC base pointer.
  294. * param handle ASRC eDMA handle pointer.
  295. * param xfer Pointer to the DMA transfer structure.
  296. * retval kStatus_Success Start a ASRC eDMA send successfully.
  297. * retval kStatus_InvalidArgument The input argument is invalid.
  298. * retval kStatus_ASRCQueueFull ASRC EDMA driver queue is full.
  299. */
  300. status_t ASRC_TransferEDMA(ASRC_Type *base, asrc_edma_handle_t *handle, asrc_transfer_t *xfer)
  301. {
  302. assert(handle != NULL);
  303. if (ASRC_TransferOutSubmitEDMA(base, handle, xfer->outData, xfer->outDataSize) != kStatus_Success)
  304. {
  305. return kStatus_ASRCQueueFull;
  306. }
  307. if (ASRC_TransferInSubmitEDMA(base, handle, xfer->inData, xfer->inDataSize) != kStatus_Success)
  308. {
  309. return kStatus_ASRCQueueFull;
  310. }
  311. return kStatus_Success;
  312. }
  313. /*!
  314. * brief Aborts a ASRC IN transfer using eDMA.
  315. *
  316. * This function only aborts the current transfer slots, the other transfer slots' information still kept
  317. * in the handler. If users want to terminate all transfer slots, just call ASRC_TransferTerminalP2PEDMA.
  318. *
  319. * param base ASRC base pointer.
  320. * param handle ASRC eDMA handle pointer.
  321. */
  322. void ASRC_TransferInAbortEDMA(ASRC_Type *base, asrc_edma_handle_t *handle)
  323. {
  324. assert(handle != NULL);
  325. /* Disable dma */
  326. EDMA_AbortTransfer(handle->in.inDmaHandle);
  327. /* Handle the queue index */
  328. handle->in.asrcQueue[handle->in.queueDriver] = NULL;
  329. handle->in.queueDriver = (handle->in.queueDriver + 1U) % ASRC_XFER_QUEUE_SIZE;
  330. /* Set the handle state */
  331. handle->in.state = kStatus_ASRCIdle;
  332. }
  333. /*!
  334. * brief Aborts a ASRC OUT transfer using eDMA.
  335. *
  336. * This function only aborts the current transfer slots, the other transfer slots' information still kept
  337. * in the handler. If users want to terminate all transfer slots, just call ASRC_TransferTerminalP2PEDMA.
  338. *
  339. * param base ASRC base pointer.
  340. * param handle ASRC eDMA handle pointer.
  341. */
  342. void ASRC_TransferOutAbortEDMA(ASRC_Type *base, asrc_edma_handle_t *handle)
  343. {
  344. assert(handle != NULL);
  345. /* Disable dma */
  346. EDMA_AbortTransfer(handle->out.outDmaHandle);
  347. /* Handle the queue index */
  348. handle->out.asrcQueue[handle->out.queueDriver] = NULL;
  349. handle->out.queueDriver = (handle->out.queueDriver + 1U) % ASRC_XFER_QUEUE_SIZE;
  350. /* Set the handle state */
  351. handle->out.state = kStatus_ASRCIdle;
  352. }
  353. /*!
  354. * brief Terminate In ASRC Convert.
  355. *
  356. * This function will clear all transfer slots buffered in the asrc queue. If users only want to abort the
  357. * current transfer slot, please call ASRC_TransferAbortPP2PEDMA.
  358. *
  359. * param base ASRC base pointer.
  360. * param handle ASRC eDMA handle pointer.
  361. */
  362. void ASRC_TransferInTerminalEDMA(ASRC_Type *base, asrc_edma_handle_t *handle)
  363. {
  364. assert(handle != NULL);
  365. /* Abort the current transfer */
  366. ASRC_TransferInAbortEDMA(base, handle);
  367. /* stop peripheral */
  368. if ((handle->in.peripheralConfig != NULL) && (handle->in.peripheralConfig->startPeripheral != NULL))
  369. {
  370. handle->in.peripheralConfig->startPeripheral(false);
  371. }
  372. /* Clear all the internal information */
  373. (void)memset(handle->in.tcd, 0, sizeof(handle->in.tcd));
  374. (void)memset(handle->in.asrcQueue, 0, sizeof(handle->in.asrcQueue));
  375. (void)memset(handle->in.transferSize, 0, sizeof(handle->in.transferSize));
  376. handle->in.queueUser = 0U;
  377. handle->in.queueDriver = 0U;
  378. }
  379. /*!
  380. * brief Terminate Out ASRC Convert.
  381. *
  382. * This function will clear all transfer slots buffered in the asrc queue. If users only want to abort the
  383. * current transfer slot, please call ASRC_TransferAbortPP2PEDMA.
  384. *
  385. * param base ASRC base pointer.
  386. * param handle ASRC eDMA handle pointer.
  387. */
  388. void ASRC_TransferOutTerminalEDMA(ASRC_Type *base, asrc_edma_handle_t *handle)
  389. {
  390. assert(handle != NULL);
  391. /* Abort the current transfer */
  392. ASRC_TransferOutAbortEDMA(base, handle);
  393. if ((handle->out.peripheralConfig != NULL) && (handle->out.peripheralConfig->startPeripheral != NULL))
  394. {
  395. handle->out.peripheralConfig->startPeripheral(false);
  396. }
  397. (void)memset(handle->out.tcd, 0, sizeof(handle->out.tcd));
  398. (void)memset(handle->out.asrcQueue, 0, sizeof(handle->out.asrcQueue));
  399. (void)memset(handle->out.transferSize, 0, sizeof(handle->out.transferSize));
  400. handle->out.queueUser = 0U;
  401. handle->out.queueDriver = 0U;
  402. }