1 /*
2  * Copyright 2019-2022 NXP
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include "fsl_flexspi_dma.h"
9 
10 /*******************************************************************************
11  * Definitions
12  ******************************************************************************/
13 
14 /* Component ID definition, used by tools. */
15 #ifndef FSL_COMPONENT_ID
16 #define FSL_COMPONENT_ID "platform.drivers.flexspi_dma"
17 #endif
18 
19 /*<! Structure definition for flexspi_dma_private_handle_t. The structure is private. */
20 typedef struct _flexspi_dma_private_handle
21 {
22     FLEXSPI_Type *base;
23     flexspi_dma_handle_t *handle;
24 } flexspi_dma_private_handle_t;
25 
26 /* FLEXSPI DMA transfer handle, _flexspi_dma_tansfer_states. */
27 enum
28 {
29     kFLEXSPI_Idle, /* FLEXSPI Bus idle. */
30     kFLEXSPI_Busy  /* FLEXSPI Bus busy. */
31 };
32 
33 /*******************************************************************************
34  * Variables
35  ******************************************************************************/
36 
37 /*! @brief Pointers to flexspi bases for each instance. */
38 static FLEXSPI_Type *const s_flexspiBases[] = FLEXSPI_BASE_PTRS;
39 
40 /*<! Private handle only used for internally. */
41 static flexspi_dma_private_handle_t s_dmaPrivateHandle[ARRAY_SIZE(s_flexspiBases)];
42 
43 #if defined(FSL_FEATURE_FLEXSPI_DMA_MULTIPLE_DES) && FSL_FEATURE_FLEXSPI_DMA_MULTIPLE_DES
44 /*<! Private DMA descriptor array used for internally to fix FLEXSPI+DMA ERRATA.
45 FLEXSPI.1: Using FLEXSPI register interface, TX buffer fill / RX buffer drain by DMA
46 with a single DMA descriptor cannot be performed. The link array consumes about
47 2K RAM consumption support FLEXSPI TX watermark starting from 8 bytes.*/
48 #define FLEXSPI_DMA_DES_COUNT 128U
49 #else
50 /*<! Private DMA descriptor array to support transfer size not multiple of watermark level byts.
51 The link array consumes 16 bytes consumption.*/
52 #define FLEXSPI_DMA_DES_COUNT 1U
53 #endif
54 
55 #if defined(FSL_FEATURE_DMA_DESCRIPTOR_ALIGN_SIZEn)
56 #define FSL_FEATURE_DMA_DESCRIPTOR_ALIGN_SIZE                                            \
57     ((FSL_FEATURE_DMA0_DESCRIPTOR_ALIGN_SIZE > FSL_FEATURE_DMA1_DESCRIPTOR_ALIGN_SIZE) ? \
58          FSL_FEATURE_DMA0_DESCRIPTOR_ALIGN_SIZE :                                        \
59          FSL_FEATURE_DMA1_DESCRIPTOR_ALIGN_SIZE)
60 #endif
61 #if defined(__ICCARM__)
62 #pragma data_alignment = FSL_FEATURE_DMA_DESCRIPTOR_ALIGN_SIZE
63 static dma_descriptor_t s_flexspiDes[FLEXSPI_DMA_DES_COUNT];
64 #elif defined(__CC_ARM) || defined(__ARMCC_VERSION)
65 __attribute__((
66     aligned(FSL_FEATURE_DMA_DESCRIPTOR_ALIGN_SIZE))) static dma_descriptor_t s_flexspiDes[FLEXSPI_DMA_DES_COUNT];
67 #elif defined(__GNUC__)
68 __attribute__((
69     aligned(FSL_FEATURE_DMA_DESCRIPTOR_ALIGN_SIZE))) static dma_descriptor_t s_flexspiDes[FLEXSPI_DMA_DES_COUNT];
70 #endif
71 /*******************************************************************************
72  * Prototypes
73  ******************************************************************************/
74 
75 /*!
76  * @brief FLEXSPI DMA transfer finished callback function.
77  *
78  * This function is called when FLEXSPI DMA transfer finished. It disables the FLEXSPI
79  * TX/RX DMA request and sends status to FLEXSPI callback.
80  *
81  * @param handle The DMA handle.
82  * @param param Callback function parameter.
83  */
84 static void FLEXSPI_TransferDMACallback(dma_handle_t *handle, void *param, bool transferDone, uint32_t tcds);
85 
86 /*!
87  * @brief FLEXSPI Write DMA data.
88  *
89  * This function is called in FLEXSPI DMA transfer. It configures Write DMA and prepare DMA data transfer.
90  *
91  * @param base FLEXSPI peripheral base address.
92  * @param handle The DMA handle.
93  * @param data pointer to data buffer which stores the transmit data
94  * @param dataSize size for transmit data buffer .
95  */
96 static status_t FLEXSPI_WriteDataDMA(FLEXSPI_Type *base, flexspi_dma_handle_t *handle, uint32_t *data, size_t dataSize);
97 
98 /*!
99  * @brief FLEXSPI Read DMA data.
100  *
101  * This function is called in FLEXSPI DMA transfer. It configures Read DMA and prepare DMA data transfer.
102  *
103  * @param base FLEXSPI peripheral base address.
104  * @param handle The DMA handle.
105  * @param data pointer to data buffer which stores the receive data
106  * @param dataSize size for receive data buffer .
107  */
108 static status_t FLEXSPI_ReadDataDMA(FLEXSPI_Type *base, flexspi_dma_handle_t *handle, uint32_t *data, size_t dataSize);
109 /*******************************************************************************
110  * Code
111  ******************************************************************************/
112 #if !(defined(FSL_FEATURE_FLEXSPI_DMA_MULTIPLE_DES) && FSL_FEATURE_FLEXSPI_DMA_MULTIPLE_DES)
FLEXSPI_CalculatePower(uint8_t value)113 static uint8_t FLEXSPI_CalculatePower(uint8_t value)
114 {
115     uint8_t power = 0;
116     while (value >> 1 != 0U)
117     {
118         power++;
119         value = value >> 1;
120     }
121 
122     return power;
123 }
124 #endif
125 
FLEXSPI_TransferDMACallback(dma_handle_t * handle,void * param,bool transferDone,uint32_t tcds)126 static void FLEXSPI_TransferDMACallback(dma_handle_t *handle, void *param, bool transferDone, uint32_t tcds)
127 {
128     flexspi_dma_private_handle_t *flexspiPrivateHandle = (flexspi_dma_private_handle_t *)param;
129 
130     /* Avoid warning for unused parameters. */
131     handle = handle;
132     tcds   = tcds;
133 
134     if (transferDone)
135     {
136         /* Wait for bus idle. */
137         while (!FLEXSPI_GetBusIdleStatus(flexspiPrivateHandle->base))
138         {
139         }
140         /* Disable transfer. */
141         FLEXSPI_TransferAbortDMA(flexspiPrivateHandle->base, flexspiPrivateHandle->handle);
142 
143         if (flexspiPrivateHandle->handle->completionCallback != NULL)
144         {
145             flexspiPrivateHandle->handle->completionCallback(flexspiPrivateHandle->base, flexspiPrivateHandle->handle,
146                                                              kStatus_Success, flexspiPrivateHandle->handle->userData);
147         }
148     }
149 }
150 
FLEXSPI_WriteDataDMA(FLEXSPI_Type * base,flexspi_dma_handle_t * handle,uint32_t * data,size_t dataSize)151 static status_t FLEXSPI_WriteDataDMA(FLEXSPI_Type *base, flexspi_dma_handle_t *handle, uint32_t *data, size_t dataSize)
152 {
153     void *txFifoBase = (void *)(uint32_t *)FLEXSPI_GetTxFifoAddress(base);
154     void *nextDesc   = NULL;
155     dma_channel_trigger_t dmaTxTriggerConfig;
156     dma_channel_config_t txChannelConfig;
157     uint32_t bytesPerDes;
158     uint8_t desCount;
159     uint8_t remains;
160     uint8_t srcInc;
161     uint8_t dstInc;
162 
163     /* Source address interleave size */
164     srcInc = kDMA_AddressInterleave1xWidth;
165     /* Destination address interleave size */
166     dstInc = kDMA_AddressInterleave1xWidth;
167 
168     /* Check the xfer->data start address follows the alignment */
169     if (((uint32_t)data & ((uint32_t)handle->nsize - 1U)) != 0U)
170     {
171         return kStatus_InvalidArgument;
172     }
173 
174     handle->count =
175         8U * ((uint8_t)(((base->IPTXFCR & FLEXSPI_IPTXFCR_TXWMRK_MASK) >> FLEXSPI_IPTXFCR_TXWMRK_SHIFT) + 1U));
176 
177     /* Check the handle->count is power of 2 */
178     if (((handle->count) & (handle->count - 1U)) != 0U)
179     {
180         return kStatus_InvalidArgument;
181     }
182 
183 #if defined(FSL_FEATURE_FLEXSPI_DMA_MULTIPLE_DES) && FSL_FEATURE_FLEXSPI_DMA_MULTIPLE_DES
184     if (dataSize < handle->count)
185     {
186         handle->nsize  = kFLEXPSI_DMAnSize1Bytes;
187         handle->nbytes = (uint8_t)dataSize;
188     }
189     else
190     {
191         /* Store the initially configured dma minor byte transfer count into the FLEXSPI handle */
192         handle->nbytes = handle->count;
193     }
194 
195     handle->transferSize     = dataSize;
196     dmaTxTriggerConfig.burst = kDMA_SingleTransfer;
197     dmaTxTriggerConfig.type  = kDMA_HighLevelTrigger;
198     dmaTxTriggerConfig.wrap  = kDMA_NoWrap;
199 
200     /* Configure linked descriptors to start FLEXSPI Tx DMA transfer to provide software workaround for
201     ERRATA FLEXSPI.1: Using FLEXSPI register interface, TX buffer fill / RX buffer drain by DMA with a
202     single DMA descriptor cannot be performed. */
203     desCount    = (uint8_t)(dataSize / (uint32_t)handle->nbytes);
204     bytesPerDes = handle->nbytes;
205     remains     = (uint8_t)(dataSize - (uint32_t)desCount * (uint32_t)handle->nbytes);
206     if (remains > 0U)
207     {
208         uint8_t width = (uint8_t)kFLEXPSI_DMAnSize1Bytes;
209         DMA_SetupDescriptor(&s_flexspiDes[desCount - 1U],
210                             DMA_CHANNEL_XFER(false, true, true, false, width, srcInc, dstInc, remains),
211                             (void *)(uint64_t *)((uint32_t)data + desCount * bytesPerDes), txFifoBase, NULL);
212         nextDesc = &s_flexspiDes[desCount - 1U];
213     }
214 
215     remains = (uint8_t)bytesPerDes;
216 #else
217     uint32_t dmaTriggerBurst;
218     dmaTxTriggerConfig.type = kDMA_RisingEdgeTrigger;
219     bytesPerDes             = dataSize;
220 
221     if (dataSize < handle->count)
222     {
223         handle->nsize           = kFLEXPSI_DMAnSize1Bytes;
224         handle->nbytes          = (uint8_t)(dataSize / (uint32_t)handle->nsize);
225         dmaTxTriggerConfig.wrap = kDMA_NoWrap;
226 
227         /* Check the handle->nbytes is power of 2 */
228         if (((handle->nbytes) & (handle->nbytes - 1U)) != 0U)
229         {
230             handle->nbytes = 2U * ((handle->nbytes) & (handle->nbytes - 1U));
231         }
232 
233         desCount = 1U;
234     }
235     else
236     {
237         dmaTxTriggerConfig.wrap = kDMA_DstWrap;
238         remains                 = (uint8_t)(dataSize % (uint32_t)handle->count);
239         if (remains == 0U)
240         {
241             desCount = 1U;
242         }
243         else
244         {
245             desCount    = 2U;
246             bytesPerDes = dataSize - remains;
247             if ((remains & 3U) == 0U)
248             {
249                 handle->nsize = kFLEXPSI_DMAnSize4Bytes;
250             }
251             else if ((remains & 1U) == 0U)
252             {
253                 handle->nsize = kFLEXPSI_DMAnSize2Bytes;
254             }
255             else
256             {
257                 handle->nsize = kFLEXPSI_DMAnSize1Bytes;
258             }
259         }
260         /* Store the initially configured dma minor byte transfer count into the FLEXSPI handle */
261         handle->nbytes = handle->count / (uint8_t)handle->nsize;
262 
263         /* Check if dataSize exceeds the maximum transfer count supported by the driver. */
264         if ((dataSize - handle->count + 1U) / ((uint32_t)handle->nsize) > 1024U)
265         {
266             return kStatus_InvalidArgument;
267         }
268     }
269 
270     /* xfer->dataSize needs to be larger than 1 due to hardware limitation */
271     if (dataSize / (uint8_t)handle->nsize == 1U)
272     {
273         return kStatus_InvalidArgument;
274     }
275 
276     dmaTriggerBurst = DMA_CHANNEL_CFG_TRIGBURST(1) | DMA_CHANNEL_CFG_BURSTPOWER(FLEXSPI_CalculatePower(handle->nbytes));
277     dmaTxTriggerConfig.burst = (dma_trigger_burst_t)dmaTriggerBurst;
278     handle->transferSize     = dataSize;
279 #endif
280 
281     for (uint8_t i = desCount - 1U; i > 0U; i--)
282     {
283         DMA_SetupDescriptor(&s_flexspiDes[i - 1U],
284                             DMA_CHANNEL_XFER((nextDesc == NULL) ? false : true, true, (nextDesc == NULL) ? true : false,
285                                              false, (uint8_t)handle->nsize, srcInc, dstInc, remains),
286                             (void *)(uint64_t *)((uint32_t)data + i * bytesPerDes), txFifoBase, nextDesc);
287         nextDesc = &s_flexspiDes[i - 1U];
288     }
289 
290     DMA_PrepareChannelTransfer(
291         &txChannelConfig, (void *)data, txFifoBase,
292         DMA_CHANNEL_XFER((nextDesc == NULL) ? false : true, true, (nextDesc == NULL) ? true : false, false,
293                          (uint8_t)handle->nsize, srcInc, dstInc, bytesPerDes),
294         kDMA_MemoryToMemory, &dmaTxTriggerConfig, nextDesc);
295 
296     (void)DMA_SubmitChannelTransfer(handle->txDmaHandle, &txChannelConfig);
297 
298     DMA_SetCallback(handle->txDmaHandle, FLEXSPI_TransferDMACallback, &s_dmaPrivateHandle[FLEXSPI_GetInstance(base)]);
299     DMA_StartTransfer(handle->txDmaHandle);
300 
301     /* Enable FLEXSPI TX DMA. */
302     FLEXSPI_EnableTxDMA(base, true);
303 
304     /* Start Transfer. */
305     base->IPCMD |= FLEXSPI_IPCMD_TRG_MASK;
306 
307     return kStatus_Success;
308 }
309 
FLEXSPI_ReadDataDMA(FLEXSPI_Type * base,flexspi_dma_handle_t * handle,uint32_t * data,size_t dataSize)310 static status_t FLEXSPI_ReadDataDMA(FLEXSPI_Type *base, flexspi_dma_handle_t *handle, uint32_t *data, size_t dataSize)
311 {
312     dma_channel_trigger_t dmaRxTriggerConfig;
313     void *rxFifoBase = (void *)(uint32_t *)FLEXSPI_GetRxFifoAddress(base);
314     void *nextDesc   = NULL;
315     dma_channel_config_t rxChannelConfig;
316     uint32_t bytesPerDes;
317     uint8_t remains;
318     uint8_t desCount;
319     uint8_t srcInc;
320     uint8_t dstInc;
321 
322     /* Source address interleave size */
323     srcInc = kDMA_AddressInterleave1xWidth;
324     /* Destination address interleave size */
325     dstInc = kDMA_AddressInterleave1xWidth;
326 
327     handle->count =
328         8U * (uint8_t)(((base->IPRXFCR & FLEXSPI_IPRXFCR_RXWMRK_MASK) >> FLEXSPI_IPRXFCR_RXWMRK_SHIFT) + 1U);
329 
330     /* Check the watermark is power of 2U */
331     if ((handle->count & (handle->count - 1U)) != 0U)
332     {
333         return kStatus_InvalidArgument;
334     }
335 
336 #if defined(FSL_FEATURE_FLEXSPI_DMA_MULTIPLE_DES) && FSL_FEATURE_FLEXSPI_DMA_MULTIPLE_DES
337     if (dataSize < handle->count)
338     {
339         handle->nsize  = kFLEXPSI_DMAnSize1Bytes;
340         handle->nbytes = (uint8_t)dataSize;
341     }
342     else
343     {
344         /* Store the initially configured dma minor byte transfer count into the FLEXSPI handle */
345         handle->nbytes = handle->count;
346     }
347 
348     dmaRxTriggerConfig.burst = kDMA_SingleTransfer;
349     dmaRxTriggerConfig.type  = kDMA_HighLevelTrigger;
350     dmaRxTriggerConfig.wrap  = kDMA_NoWrap;
351 
352     /* Configure linked descriptors to start FLEXSPI Tx DMA transfer to provide software workaround for
353     ERRATA FLEXSPI.1: Using FLEXSPI register interface, TX buffer fill / RX buffer drain by DMA with a
354     single DMA descriptor cannot be performed. */
355     desCount    = (uint8_t)(dataSize / (uint32_t)handle->nbytes);
356     bytesPerDes = handle->nbytes;
357     remains     = (uint8_t)(dataSize - (uint32_t)desCount * (uint32_t)handle->nbytes);
358 
359     if (remains > 0U)
360     {
361         uint8_t width = (uint8_t)kFLEXPSI_DMAnSize1Bytes;
362         DMA_SetupDescriptor(&s_flexspiDes[desCount - 1U],
363                             DMA_CHANNEL_XFER(false, true, true, false, width, srcInc, dstInc, remains), rxFifoBase,
364                             (void *)(uint64_t *)((uint32_t)data + desCount * bytesPerDes), NULL);
365         nextDesc = &s_flexspiDes[desCount - 1U];
366     }
367     remains = (uint8_t)bytesPerDes;
368 
369 #else
370     uint32_t dmaTriggerBurst;
371     dmaRxTriggerConfig.type = kDMA_RisingEdgeTrigger;
372     bytesPerDes             = dataSize;
373 
374     if (dataSize < handle->count)
375     {
376         handle->nsize           = kFLEXPSI_DMAnSize1Bytes;
377         handle->nbytes          = (uint8_t)(dataSize / (uint32_t)handle->nsize);
378         dmaRxTriggerConfig.wrap = kDMA_NoWrap;
379         /* Check the handle->nbytes is power of 2 */
380         if (((handle->nbytes) & (handle->nbytes - 1U)) != 0U)
381         {
382             handle->nbytes = 2U * ((handle->nbytes) & (handle->nbytes - 1U));
383         }
384         desCount = 1U;
385     }
386     else
387     {
388         dmaRxTriggerConfig.wrap = kDMA_SrcWrap;
389         remains                 = (uint8_t)(dataSize % (uint32_t)handle->count);
390         if (remains == 0U)
391         {
392             desCount = 1U;
393         }
394         else
395         {
396             desCount    = 2U;
397             bytesPerDes = dataSize - remains;
398             if ((remains & 3U) == 0U)
399             {
400                 handle->nsize = kFLEXPSI_DMAnSize4Bytes;
401             }
402             else if ((remains & 1U) == 0U)
403             {
404                 handle->nsize = kFLEXPSI_DMAnSize2Bytes;
405             }
406             else
407             {
408                 handle->nsize = kFLEXPSI_DMAnSize1Bytes;
409             }
410         }
411         /* Store the initially configured dma minor byte transfer count into the FLEXSPI handle */
412         handle->nbytes = handle->count / (uint8_t)handle->nsize;
413 
414         /* Check dataSize exceeds the maximum transfer count supported by the driver. */
415         if ((dataSize - handle->count + 1U) / ((uint32_t)handle->nsize) > 1024U)
416         {
417             return kStatus_InvalidArgument;
418         }
419     }
420 
421     dmaTriggerBurst =
422         DMA_CHANNEL_CFG_TRIGBURST(1U) | DMA_CHANNEL_CFG_BURSTPOWER(FLEXSPI_CalculatePower(handle->nbytes));
423     dmaRxTriggerConfig.burst = (dma_trigger_burst_t)(dmaTriggerBurst);
424 #endif
425 
426     for (uint8_t i = desCount - 1U; i > 0U; i--)
427     {
428         DMA_SetupDescriptor(&s_flexspiDes[i - 1U],
429                             DMA_CHANNEL_XFER((nextDesc == NULL) ? false : true, true, (nextDesc == NULL) ? true : false,
430                                              false, (uint8_t)handle->nsize, srcInc, dstInc, remains),
431                             rxFifoBase, (void *)(uint64_t *)((uint32_t)data + i * bytesPerDes), nextDesc);
432         nextDesc = &s_flexspiDes[i - 1U];
433     }
434 
435     DMA_PrepareChannelTransfer(
436         &rxChannelConfig, rxFifoBase, (void *)data,
437         DMA_CHANNEL_XFER((nextDesc == NULL) ? false : true, true, (nextDesc == NULL) ? true : false, false,
438                          (uint8_t)handle->nsize, srcInc, dstInc, bytesPerDes),
439         kDMA_MemoryToMemory, &dmaRxTriggerConfig, nextDesc);
440 
441     (void)DMA_SubmitChannelTransfer(handle->rxDmaHandle, &rxChannelConfig);
442 
443     DMA_SetCallback(handle->rxDmaHandle, FLEXSPI_TransferDMACallback, &s_dmaPrivateHandle[FLEXSPI_GetInstance(base)]);
444     DMA_StartTransfer(handle->rxDmaHandle);
445 
446     /* Enable FLEXSPI RX DMA. */
447     FLEXSPI_EnableRxDMA(base, true);
448 
449     /* Start Transfer. */
450     base->IPCMD |= FLEXSPI_IPCMD_TRG_MASK;
451 
452     return kStatus_Success;
453 }
454 
455 /*!
456  * brief Initializes the FLEXSPI handle for transfer which is used in transactional functions and set the callback.
457  *
458  * param base FLEXSPI peripheral base address
459  * param handle Pointer to flexspi_dma_handle_t structure
460  * param callback FLEXSPI callback, NULL means no callback.
461  * param userData User callback function data.
462  * param txDmaHandle User requested DMA handle for TX DMA transfer.
463  * param rxDmaHandle User requested DMA handle for RX DMA transfer.
464  */
FLEXSPI_TransferCreateHandleDMA(FLEXSPI_Type * base,flexspi_dma_handle_t * handle,flexspi_dma_callback_t callback,void * userData,dma_handle_t * txDmaHandle,dma_handle_t * rxDmaHandle)465 void FLEXSPI_TransferCreateHandleDMA(FLEXSPI_Type *base,
466                                      flexspi_dma_handle_t *handle,
467                                      flexspi_dma_callback_t callback,
468                                      void *userData,
469                                      dma_handle_t *txDmaHandle,
470                                      dma_handle_t *rxDmaHandle)
471 {
472     assert(handle);
473 
474     uint32_t instance = FLEXSPI_GetInstance(base);
475 
476     s_dmaPrivateHandle[instance].base   = base;
477     s_dmaPrivateHandle[instance].handle = handle;
478 
479     (void)memset(handle, 0, sizeof(*handle));
480 
481     handle->state       = kFLEXSPI_Idle;
482     handle->txDmaHandle = txDmaHandle;
483     handle->rxDmaHandle = rxDmaHandle;
484     handle->nsize       = kFLEXPSI_DMAnSize4Bytes;
485 
486     handle->completionCallback = callback;
487     handle->userData           = userData;
488 }
489 
490 /*!
491  * brief Update FLEXSPI DMA transfer source data transfer size(SSIZE) and destination data transfer size(DSIZE).
492  *
493  * param base FLEXSPI peripheral base address
494  * param handle Pointer to flexspi_dma_handle_t structure
495  * param nsize FLEXSPI DMA transfer data transfer size(SSIZE/DSIZE), by default the size is
496  * kFLEXPSI_DMAnSize1Bytes(one byte).
497  * see flexspi_dma_transfer_nsize_t               .
498  */
FLEXSPI_TransferUpdateSizeDMA(FLEXSPI_Type * base,flexspi_dma_handle_t * handle,flexspi_dma_transfer_nsize_t nsize)499 void FLEXSPI_TransferUpdateSizeDMA(FLEXSPI_Type *base, flexspi_dma_handle_t *handle, flexspi_dma_transfer_nsize_t nsize)
500 {
501     handle->nsize = nsize;
502 }
503 
504 /*!
505  * brief Transfers FLEXSPI data using an dma non-blocking method.
506  *
507  * This function writes/receives data to/from the FLEXSPI transmit/receive FIFO. This function is non-blocking.
508  * param base FLEXSPI peripheral base address.
509  * param handle Pointer to flexspi_dma_handle_t structure
510  * param xfer FLEXSPI transfer structure.
511  * retval kStatus_FLEXSPI_Busy     FLEXSPI is busy transfer.
512  * retval kStatus_InvalidArgument  The watermark configuration is invalid, the watermark should be power of
513                                     2 to do successfully DMA transfer.
514  * retval kStatus_Success          FLEXSPI successfully start dma transfer.
515  */
FLEXSPI_TransferDMA(FLEXSPI_Type * base,flexspi_dma_handle_t * handle,flexspi_transfer_t * xfer)516 status_t FLEXSPI_TransferDMA(FLEXSPI_Type *base, flexspi_dma_handle_t *handle, flexspi_transfer_t *xfer)
517 {
518     uint32_t configValue = 0;
519     status_t result      = kStatus_Success;
520 
521     assert(handle);
522     assert(xfer);
523 
524     /* Check if the FLEXSPI bus is idle - if not return busy status. */
525     if (handle->state != (uint32_t)kFLEXSPI_Idle)
526     {
527         result = kStatus_FLEXSPI_Busy;
528     }
529     else
530     {
531         handle->transferSize = xfer->dataSize;
532 
533         /* Clear sequence pointer before sending data to external devices. */
534         base->FLSHCR2[xfer->port] |= FLEXSPI_FLSHCR2_CLRINSTRPTR_MASK;
535 
536         /* Clear former pending status before start this transfer. */
537         base->INTR |= FLEXSPI_INTR_AHBCMDERR_MASK | FLEXSPI_INTR_IPCMDERR_MASK | FLEXSPI_INTR_AHBCMDGE_MASK |
538                       FLEXSPI_INTR_IPCMDGE_MASK;
539 
540         /* Configure base address. */
541         base->IPCR0 = xfer->deviceAddress;
542 
543         /* Reset fifos. */
544         base->IPTXFCR |= FLEXSPI_IPTXFCR_CLRIPTXF_MASK;
545         base->IPRXFCR |= FLEXSPI_IPRXFCR_CLRIPRXF_MASK;
546 
547         /* Configure data size. */
548         if ((xfer->cmdType == kFLEXSPI_Read) || (xfer->cmdType == kFLEXSPI_Write))
549         {
550             configValue = FLEXSPI_IPCR1_IDATSZ(xfer->dataSize);
551         }
552 
553         /* Configure sequence ID. */
554         configValue |= FLEXSPI_IPCR1_ISEQID(xfer->seqIndex) | FLEXSPI_IPCR1_ISEQNUM((uint32_t)xfer->SeqNumber - 1U);
555         base->IPCR1 = configValue;
556 
557         if ((xfer->cmdType == kFLEXSPI_Write) || (xfer->cmdType == kFLEXSPI_Config))
558         {
559             handle->state = kFLEXSPI_Busy;
560             result        = FLEXSPI_WriteDataDMA(base, handle, xfer->data, xfer->dataSize);
561         }
562         else if (xfer->cmdType == kFLEXSPI_Read)
563         {
564             handle->state = kFLEXSPI_Busy;
565             result        = FLEXSPI_ReadDataDMA(base, handle, xfer->data, xfer->dataSize);
566         }
567         else
568         {
569             /* Start Transfer. */
570             base->IPCMD |= FLEXSPI_IPCMD_TRG_MASK;
571             /* Wait for bus idle. */
572             while (!FLEXSPI_GetBusIdleStatus(base))
573             {
574             }
575             result = FLEXSPI_CheckAndClearError(base, base->INTR);
576 
577             handle->state = kFLEXSPI_Idle;
578 
579             if (handle->completionCallback != NULL)
580             {
581                 handle->completionCallback(base, handle, result, handle->userData);
582             }
583         }
584     }
585 
586     return result;
587 }
588 
589 /*!
590  * brief Aborts the transfer data using dma.
591  *
592  * This function aborts the transfer data using dma.
593  *
594  * param base FLEXSPI peripheral base address.
595  * param handle Pointer to flexspi_dma_handle_t structure
596  */
FLEXSPI_TransferAbortDMA(FLEXSPI_Type * base,flexspi_dma_handle_t * handle)597 void FLEXSPI_TransferAbortDMA(FLEXSPI_Type *base, flexspi_dma_handle_t *handle)
598 {
599     assert(handle != NULL);
600 
601     if ((base->IPTXFCR & FLEXSPI_IPTXFCR_TXDMAEN_MASK) != 0x00U)
602     {
603         FLEXSPI_EnableTxDMA(base, false);
604         DMA_AbortTransfer(handle->txDmaHandle);
605     }
606 
607     if ((base->IPRXFCR & FLEXSPI_IPRXFCR_RXDMAEN_MASK) != 0x00U)
608     {
609         FLEXSPI_EnableRxDMA(base, false);
610         DMA_AbortTransfer(handle->rxDmaHandle);
611     }
612 
613     handle->state = kFLEXSPI_Idle;
614 }
615 
FLEXSPI_TransferGetTransferCountDMA(FLEXSPI_Type * base,flexspi_dma_handle_t * handle,size_t * count)616 status_t FLEXSPI_TransferGetTransferCountDMA(FLEXSPI_Type *base, flexspi_dma_handle_t *handle, size_t *count)
617 {
618     assert(handle);
619     assert(count);
620 
621     status_t result = kStatus_Success;
622 
623     if (handle->state != (uint32_t)kFLEXSPI_Busy)
624     {
625         result = kStatus_NoTransferInProgress;
626     }
627     else
628     {
629         if ((base->IPRXFCR & FLEXSPI_IPRXFCR_RXDMAEN_MASK) != 0x00U)
630         {
631             *count =
632                 (handle->transferSize - DMA_GetRemainingBytes(handle->rxDmaHandle->base, handle->rxDmaHandle->channel));
633         }
634         else if ((base->IPTXFCR & FLEXSPI_IPTXFCR_TXDMAEN_MASK) != 0x00U)
635         {
636             *count =
637                 (handle->transferSize - DMA_GetRemainingBytes(handle->txDmaHandle->base, handle->txDmaHandle->channel));
638         }
639         else
640         {
641             ; /* Intentional empty for MISRA C-2012 rule 15.7. */
642         }
643     }
644 
645     return result;
646 }
647