fsl_flexspi_edma.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. /*
  2. * Copyright (c) 2016, Freescale Semiconductor, Inc.
  3. * Copyright 2016-2020 NXP
  4. * All rights reserved.
  5. *
  6. * SPDX-License-Identifier: BSD-3-Clause
  7. */
  8. #include "fsl_flexspi_edma.h"
  9. /*******************************************************************************
  10. * Definitions
  11. ******************************************************************************/
  12. /* Component ID definition, used by tools. */
  13. #ifndef FSL_COMPONENT_ID
  14. #define FSL_COMPONENT_ID "platform.drivers.flexspi_edma"
  15. #endif
  16. /*<! Structure definition for flexspi_edma_private_handle_t. The structure is private. */
  17. typedef struct _flexspi_edma_private_handle
  18. {
  19. FLEXSPI_Type *base;
  20. flexspi_edma_handle_t *handle;
  21. } flexspi_edma_private_handle_t;
  22. /* FLEXSPI EDMA transfer handle, _flexspi_edma_tansfer_states. */
  23. enum
  24. {
  25. kFLEXSPI_Idle, /* FLEXSPI Bus idle. */
  26. kFLEXSPI_Busy /* FLEXSPI Bus busy. */
  27. };
  28. /*******************************************************************************
  29. * Variables
  30. ******************************************************************************/
  31. /*! @brief Pointers to flexspi bases for each instance. */
  32. static FLEXSPI_Type *const s_flexspiBases[] = FLEXSPI_BASE_PTRS;
  33. /*<! Private handle only used for internally. */
  34. static flexspi_edma_private_handle_t s_edmaPrivateHandle[ARRAY_SIZE(s_flexspiBases)];
  35. /*******************************************************************************
  36. * Prototypes
  37. ******************************************************************************/
  38. /*!
  39. * @brief FLEXSPI EDMA transfer finished callback function.
  40. *
  41. * This function is called when FLEXSPI EDMA transfer finished. It disables the FLEXSPI
  42. * TX/RX EDMA request and sends status to FLEXSPI callback.
  43. *
  44. * @param handle The EDMA handle.
  45. * @param param Callback function parameter.
  46. */
  47. static void FLEXSPI_TransferEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds);
  48. /*******************************************************************************
  49. * Code
  50. ******************************************************************************/
  51. static uint8_t FLEXSPI_CalculatePower(uint8_t value)
  52. {
  53. uint8_t power = 0;
  54. while (value >> 1 != 0U)
  55. {
  56. power++;
  57. value = value >> 1;
  58. }
  59. return power;
  60. }
  61. static void FLEXSPI_TransferEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds)
  62. {
  63. flexspi_edma_private_handle_t *flexspiPrivateHandle = (flexspi_edma_private_handle_t *)param;
  64. /* Avoid warning for unused parameters. */
  65. handle = handle;
  66. tcds = tcds;
  67. if (transferDone)
  68. {
  69. /* Wait for bus idle. */
  70. while (!FLEXSPI_GetBusIdleStatus(flexspiPrivateHandle->base))
  71. {
  72. }
  73. /* Disable transfer. */
  74. FLEXSPI_TransferAbortEDMA(flexspiPrivateHandle->base, flexspiPrivateHandle->handle);
  75. if (flexspiPrivateHandle->handle->completionCallback != NULL)
  76. {
  77. flexspiPrivateHandle->handle->completionCallback(flexspiPrivateHandle->base, flexspiPrivateHandle->handle,
  78. kStatus_Success, flexspiPrivateHandle->handle->userData);
  79. }
  80. }
  81. }
  82. /*!
  83. * brief Initializes the FLEXSPI handle for transfer which is used in transactional functions and set the callback.
  84. *
  85. * param base FLEXSPI peripheral base address
  86. * param handle Pointer to flexspi_edma_handle_t structure
  87. * param callback FLEXSPI callback, NULL means no callback.
  88. * param userData User callback function data.
  89. * param txDmaHandle User requested DMA handle for TX DMA transfer.
  90. * param rxDmaHandle User requested DMA handle for RX DMA transfer.
  91. */
  92. void FLEXSPI_TransferCreateHandleEDMA(FLEXSPI_Type *base,
  93. flexspi_edma_handle_t *handle,
  94. flexspi_edma_callback_t callback,
  95. void *userData,
  96. edma_handle_t *txDmaHandle,
  97. edma_handle_t *rxDmaHandle)
  98. {
  99. assert(handle);
  100. uint32_t instance = FLEXSPI_GetInstance(base);
  101. s_edmaPrivateHandle[instance].base = base;
  102. s_edmaPrivateHandle[instance].handle = handle;
  103. (void)memset(handle, 0, sizeof(*handle));
  104. handle->state = kFLEXSPI_Idle;
  105. handle->txDmaHandle = txDmaHandle;
  106. handle->rxDmaHandle = rxDmaHandle;
  107. handle->nsize = kFLEXPSI_EDMAnSize1Bytes;
  108. handle->completionCallback = callback;
  109. handle->userData = userData;
  110. }
  111. /*!
  112. * brief Update FLEXSPI EDMA transfer source data transfer size(SSIZE) and destination data transfer size(DSIZE).
  113. *
  114. * param base FLEXSPI peripheral base address
  115. * param handle Pointer to flexspi_edma_handle_t structure
  116. * param nsize FLEXSPI DMA transfer data transfer size(SSIZE/DSIZE), by default the size is
  117. * kFLEXPSI_EDMAnSize1Bytes(one byte).
  118. * see flexspi_edma_transfer_nsize_t .
  119. */
  120. void FLEXSPI_TransferUpdateSizeEDMA(FLEXSPI_Type *base,
  121. flexspi_edma_handle_t *handle,
  122. flexspi_edma_transfer_nsize_t nsize)
  123. {
  124. handle->nsize = nsize;
  125. }
  126. /*!
  127. * brief Transfers FLEXSPI data using an eDMA non-blocking method.
  128. *
  129. * This function writes/receives data to/from the FLEXSPI transmit/receive FIFO. This function is non-blocking.
  130. * param base FLEXSPI peripheral base address.
  131. * param handle Pointer to flexspi_edma_handle_t structure
  132. * param xfer FLEXSPI transfer structure.
  133. * retval kStatus_FLEXSPI_Busy FLEXSPI is busy transfer.
  134. * retval kStatus_InvalidArgument The watermark configuration is invalid, the watermark should be power of
  135. 2 to do successfully EDMA transfer.
  136. * retval kStatus_Success FLEXSPI successfully start edma transfer.
  137. */
  138. status_t FLEXSPI_TransferEDMA(FLEXSPI_Type *base, flexspi_edma_handle_t *handle, flexspi_transfer_t *xfer)
  139. {
  140. uint32_t configValue = 0;
  141. status_t result = kStatus_Success;
  142. edma_transfer_config_t xferConfig;
  143. uint32_t instance = FLEXSPI_GetInstance(base);
  144. uint8_t power = 0;
  145. assert(handle);
  146. assert(xfer);
  147. /* Check if the FLEXSPI bus is idle - if not return busy status. */
  148. if (handle->state != (uint32_t)kFLEXSPI_Idle)
  149. {
  150. result = kStatus_FLEXSPI_Busy;
  151. }
  152. else
  153. {
  154. handle->transferSize = xfer->dataSize;
  155. handle->state = kFLEXSPI_Busy;
  156. /* Clear sequence pointer before sending data to external devices. */
  157. base->FLSHCR2[xfer->port] |= FLEXSPI_FLSHCR2_CLRINSTRPTR_MASK;
  158. /* Clear former pending status before start this transfer. */
  159. base->INTR |= FLEXSPI_INTR_AHBCMDERR_MASK | FLEXSPI_INTR_IPCMDERR_MASK | FLEXSPI_INTR_AHBCMDGE_MASK |
  160. FLEXSPI_INTR_IPCMDGE_MASK;
  161. /* Configure base address. */
  162. base->IPCR0 = xfer->deviceAddress;
  163. /* Reset fifos. */
  164. base->IPTXFCR |= FLEXSPI_IPTXFCR_CLRIPTXF_MASK;
  165. base->IPRXFCR |= FLEXSPI_IPRXFCR_CLRIPRXF_MASK;
  166. /* Configure data size. */
  167. if ((xfer->cmdType == kFLEXSPI_Read) || (xfer->cmdType == kFLEXSPI_Write))
  168. {
  169. configValue = FLEXSPI_IPCR1_IDATSZ(xfer->dataSize);
  170. }
  171. /* Configure sequence ID. */
  172. configValue |= FLEXSPI_IPCR1_ISEQID(xfer->seqIndex) | FLEXSPI_IPCR1_ISEQNUM((uint32_t)xfer->SeqNumber - 1U);
  173. base->IPCR1 = configValue;
  174. }
  175. if ((xfer->cmdType == kFLEXSPI_Write) || (xfer->cmdType == kFLEXSPI_Config))
  176. {
  177. handle->count = (uint8_t)((base->IPTXFCR & FLEXSPI_IPTXFCR_TXWMRK_MASK) >> FLEXSPI_IPTXFCR_TXWMRK_SHIFT) + 1U;
  178. if (xfer->dataSize < 8U * (uint32_t)handle->count)
  179. {
  180. handle->nbytes = (uint8_t)xfer->dataSize;
  181. }
  182. else
  183. {
  184. /* Check the handle->count is power of 2 */
  185. if (((handle->count) & (handle->count - 1U)) != 0U)
  186. {
  187. return kStatus_InvalidArgument;
  188. }
  189. /* Store the initially configured eDMA minor byte transfer count into the FLEXSPI handle */
  190. handle->nbytes = (8U * handle->count);
  191. }
  192. power = FLEXSPI_CalculatePower(8U * handle->count);
  193. /* Prepare transfer. */
  194. EDMA_PrepareTransfer(&xferConfig, xfer->data, (uint32_t)handle->nsize,
  195. (void *)(uint32_t *)FLEXSPI_GetTxFifoAddress(base), (uint32_t)handle->nsize,
  196. (uint32_t)handle->nbytes, xfer->dataSize, kEDMA_MemoryToMemory);
  197. /* Submit transfer. */
  198. (void)EDMA_SubmitTransfer(handle->txDmaHandle, &xferConfig);
  199. handle->txDmaHandle->base->TCD[handle->txDmaHandle->channel].ATTR |= DMA_ATTR_DMOD(power);
  200. EDMA_SetCallback(handle->txDmaHandle, FLEXSPI_TransferEDMACallback,
  201. &s_edmaPrivateHandle[FLEXSPI_GetInstance(base)]);
  202. EDMA_StartTransfer(handle->txDmaHandle);
  203. /* Enable FLEXSPI TX EDMA. */
  204. FLEXSPI_EnableTxDMA(base, true);
  205. /* Start Transfer. */
  206. base->IPCMD |= FLEXSPI_IPCMD_TRG_MASK;
  207. }
  208. else if (xfer->cmdType == kFLEXSPI_Read)
  209. {
  210. handle->count = (uint8_t)((base->IPRXFCR & FLEXSPI_IPRXFCR_RXWMRK_MASK) >> FLEXSPI_IPRXFCR_RXWMRK_SHIFT) + 1U;
  211. if (xfer->dataSize < 8U * (uint32_t)handle->count)
  212. {
  213. handle->nbytes = (uint8_t)xfer->dataSize;
  214. }
  215. else
  216. {
  217. /* Check the handle->count is power of 2 */
  218. if (((handle->count) & (handle->count - 1U)) != 0U)
  219. {
  220. return kStatus_InvalidArgument;
  221. }
  222. /* Store the initially configured eDMA minor byte transfer count into the FLEXSPI handle */
  223. handle->nbytes = (8U * handle->count);
  224. }
  225. power = FLEXSPI_CalculatePower(8U * handle->count);
  226. /* Prepare transfer. */
  227. EDMA_PrepareTransfer(&xferConfig, (void *)(uint32_t *)FLEXSPI_GetRxFifoAddress(base), (uint32_t)handle->nsize,
  228. xfer->data, (uint32_t)handle->nsize, (uint32_t)handle->nbytes, xfer->dataSize,
  229. kEDMA_MemoryToMemory);
  230. /* Submit transfer. */
  231. (void)EDMA_SubmitTransfer(handle->rxDmaHandle, &xferConfig);
  232. handle->rxDmaHandle->base->TCD[handle->rxDmaHandle->channel].ATTR |= DMA_ATTR_SMOD(power);
  233. EDMA_SetCallback(handle->rxDmaHandle, FLEXSPI_TransferEDMACallback, &s_edmaPrivateHandle[instance]);
  234. EDMA_StartTransfer(handle->rxDmaHandle);
  235. /* Enable FLEXSPI RX EDMA. */
  236. FLEXSPI_EnableRxDMA(base, true);
  237. /* Start Transfer. */
  238. base->IPCMD |= FLEXSPI_IPCMD_TRG_MASK;
  239. }
  240. else
  241. {
  242. /* Start Transfer. */
  243. base->IPCMD |= FLEXSPI_IPCMD_TRG_MASK;
  244. /* Wait for bus idle. */
  245. while (!FLEXSPI_GetBusIdleStatus(base))
  246. {
  247. }
  248. result = FLEXSPI_CheckAndClearError(base, base->INTR);
  249. handle->state = kFLEXSPI_Idle;
  250. if (handle->completionCallback != NULL)
  251. {
  252. handle->completionCallback(base, handle, result, handle->userData);
  253. }
  254. }
  255. return result;
  256. }
  257. /*!
  258. * brief Aborts the transfer data using eDMA.
  259. *
  260. * This function aborts the transfer data using eDMA.
  261. *
  262. * param base FLEXSPI peripheral base address.
  263. * param handle Pointer to flexspi_edma_handle_t structure
  264. */
  265. void FLEXSPI_TransferAbortEDMA(FLEXSPI_Type *base, flexspi_edma_handle_t *handle)
  266. {
  267. assert(handle);
  268. if ((base->IPTXFCR & FLEXSPI_IPTXFCR_TXDMAEN_MASK) != 0x00U)
  269. {
  270. FLEXSPI_EnableTxDMA(base, false);
  271. EDMA_AbortTransfer(handle->txDmaHandle);
  272. }
  273. if ((base->IPRXFCR & FLEXSPI_IPRXFCR_RXDMAEN_MASK) != 0x00U)
  274. {
  275. FLEXSPI_EnableRxDMA(base, false);
  276. EDMA_AbortTransfer(handle->rxDmaHandle);
  277. }
  278. handle->state = kFLEXSPI_Idle;
  279. }
  280. status_t FLEXSPI_TransferGetTransferCountEDMA(FLEXSPI_Type *base, flexspi_edma_handle_t *handle, size_t *count)
  281. {
  282. assert(handle);
  283. assert(count);
  284. status_t result = kStatus_Success;
  285. if (handle->state != (uint32_t)kFLEXSPI_Busy)
  286. {
  287. result = kStatus_NoTransferInProgress;
  288. }
  289. else
  290. {
  291. if ((base->IPRXFCR & FLEXSPI_IPRXFCR_RXDMAEN_MASK) != 0x00U)
  292. {
  293. *count = (handle->transferSize -
  294. (uint32_t)handle->nbytes *
  295. EDMA_GetRemainingMajorLoopCount(handle->rxDmaHandle->base, handle->rxDmaHandle->channel));
  296. }
  297. else if ((base->IPTXFCR & FLEXSPI_IPTXFCR_TXDMAEN_MASK) != 0x00U)
  298. {
  299. *count = (handle->transferSize -
  300. (uint32_t)handle->nbytes *
  301. EDMA_GetRemainingMajorLoopCount(handle->txDmaHandle->base, handle->txDmaHandle->channel));
  302. }
  303. else
  304. {
  305. ; /* Intentional empty for MISRA C-2012 rule 15.7. */
  306. }
  307. }
  308. return result;
  309. }