1 /*
2  * Copyright (c) 2015, Freescale Semiconductor, Inc.
3  * Copyright 2016-2022 NXP
4  * All rights reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include "fsl_dspi_edma.h"
10 
11 /***********************************************************************************************************************
12  * Definitions
13  ***********************************************************************************************************************/
14 
15 /* Component ID definition, used by tools. */
16 #ifndef FSL_COMPONENT_ID
17 #define FSL_COMPONENT_ID "platform.drivers.dspi_edma"
18 #endif
19 
20 /*!
21  * @brief Structure definition for dspi_master_edma_private_handle_t. The structure is private.
22  */
23 typedef struct _dspi_master_edma_private_handle
24 {
25     SPI_Type *base;                    /*!< DSPI peripheral base address. */
26     dspi_master_edma_handle_t *handle; /*!< dspi_master_edma_handle_t handle */
27 } dspi_master_edma_private_handle_t;
28 
29 /*!
30  * @brief Structure definition for dspi_slave_edma_private_handle_t. The structure is private.
31  */
32 typedef struct _dspi_slave_edma_private_handle
33 {
34     SPI_Type *base;                   /*!< DSPI peripheral base address. */
35     dspi_slave_edma_handle_t *handle; /*!< dspi_master_edma_handle_t handle */
36 } dspi_slave_edma_private_handle_t;
37 
38 /***********************************************************************************************************************
39  * Prototypes
40  ***********************************************************************************************************************/
41 /*!
42  * @brief EDMA_DspiMasterCallback after the DSPI master transfer completed by using EDMA.
43  * This is not a public API.
44  */
45 static void EDMA_DspiMasterCallback(edma_handle_t *edmaHandle,
46                                     void *g_dspiEdmaPrivateHandle,
47                                     bool transferDone,
48                                     uint32_t tcds);
49 
50 /*!
51  * @brief EDMA_DspiSlaveCallback after the DSPI slave transfer completed by using EDMA.
52  * This is not a public API.
53  */
54 static void EDMA_DspiSlaveCallback(edma_handle_t *edmaHandle,
55                                    void *g_dspiEdmaPrivateHandle,
56                                    bool transferDone,
57                                    uint32_t tcds);
58 
59 /***********************************************************************************************************************
60  * Variables
61  ***********************************************************************************************************************/
62 
63 /*! @brief Pointers to dspi edma handles for each instance. */
64 static dspi_master_edma_private_handle_t s_dspiMasterEdmaPrivateHandle[FSL_FEATURE_SOC_DSPI_COUNT];
65 static dspi_slave_edma_private_handle_t s_dspiSlaveEdmaPrivateHandle[FSL_FEATURE_SOC_DSPI_COUNT];
66 
67 /***********************************************************************************************************************
68  * Code
69  ***********************************************************************************************************************/
70 
71 /*!
72  * brief Initializes the DSPI master eDMA handle.
73  *
74  * This function initializes the DSPI eDMA handle which can be used for other DSPI transactional APIs.  Usually, for a
75  * specified DSPI instance, call this API once to get the initialized handle.
76  *
77  * Note that DSPI eDMA has separated (RX and TX as two sources) or shared (RX  and TX are the same source) DMA request
78  * source.
79  * (1) For the separated DMA request source, enable and set the RX DMAMUX source for edmaRxRegToRxDataHandle and
80  * TX DMAMUX source for edmaIntermediaryToTxRegHandle.
81  * (2) For the shared DMA request source, enable and set the RX/RX DMAMUX source for the edmaRxRegToRxDataHandle.
82  *
83  * param base DSPI peripheral base address.
84  * param handle DSPI handle pointer to dspi_master_edma_handle_t.
85  * param callback DSPI callback.
86  * param userData A callback function parameter.
87  * param edmaRxRegToRxDataHandle edmaRxRegToRxDataHandle pointer to edma_handle_t.
88  * param edmaTxDataToIntermediaryHandle edmaTxDataToIntermediaryHandle pointer to edma_handle_t.
89  * param edmaIntermediaryToTxRegHandle edmaIntermediaryToTxRegHandle pointer to edma_handle_t.
90  */
DSPI_MasterTransferCreateHandleEDMA(SPI_Type * base,dspi_master_edma_handle_t * handle,dspi_master_edma_transfer_callback_t callback,void * userData,edma_handle_t * edmaRxRegToRxDataHandle,edma_handle_t * edmaTxDataToIntermediaryHandle,edma_handle_t * edmaIntermediaryToTxRegHandle)91 void DSPI_MasterTransferCreateHandleEDMA(SPI_Type *base,
92                                          dspi_master_edma_handle_t *handle,
93                                          dspi_master_edma_transfer_callback_t callback,
94                                          void *userData,
95                                          edma_handle_t *edmaRxRegToRxDataHandle,
96                                          edma_handle_t *edmaTxDataToIntermediaryHandle,
97                                          edma_handle_t *edmaIntermediaryToTxRegHandle)
98 {
99     assert(NULL != handle);
100     assert(NULL != edmaRxRegToRxDataHandle);
101 #if (!(defined(FSL_FEATURE_DSPI_HAS_GASKET) && FSL_FEATURE_DSPI_HAS_GASKET))
102     assert(NULL != edmaTxDataToIntermediaryHandle);
103 #endif
104     assert(NULL != edmaIntermediaryToTxRegHandle);
105 
106     /* Zero the handle. */
107     (void)memset(handle, 0, sizeof(*handle));
108 
109     uint32_t instance = DSPI_GetInstance(base);
110 
111     s_dspiMasterEdmaPrivateHandle[instance].base   = base;
112     s_dspiMasterEdmaPrivateHandle[instance].handle = handle;
113 
114     handle->callback = callback;
115     handle->userData = userData;
116 
117     handle->edmaRxRegToRxDataHandle        = edmaRxRegToRxDataHandle;
118     handle->edmaTxDataToIntermediaryHandle = edmaTxDataToIntermediaryHandle;
119     handle->edmaIntermediaryToTxRegHandle  = edmaIntermediaryToTxRegHandle;
120 }
121 
122 /*!
123  * brief DSPI master transfer data using eDMA.
124  *
125  * This function transfers data using eDMA. This is a non-blocking function, which returns right away. When all data
126  * is transferred, the callback function is called.
127  *
128  * note The max transfer size of each transfer depends on whether the instance's Tx/Rx shares the same DMA request. If
129  * FSL_FEATURE_DSPI_HAS_SEPARATE_DMA_RX_TX_REQn(x) is true, then the max transfer size is 32767 datawidth of data,
130  * otherwise is 511.
131  *
132  * param base DSPI peripheral base address.
133  * param handle A pointer to the dspi_master_edma_handle_t structure which stores the transfer state.
134  * param transfer A pointer to the dspi_transfer_t structure.
135  * return status of status_t.
136  */
DSPI_MasterTransferEDMA(SPI_Type * base,dspi_master_edma_handle_t * handle,dspi_transfer_t * transfer)137 status_t DSPI_MasterTransferEDMA(SPI_Type *base, dspi_master_edma_handle_t *handle, dspi_transfer_t *transfer)
138 {
139     assert(NULL != handle);
140     assert(NULL != transfer);
141 
142     /* If the transfer count is zero, then return immediately.*/
143     if (transfer->dataSize == 0U)
144     {
145         return kStatus_InvalidArgument;
146     }
147 
148     /* If both send buffer and receive buffer is null */
149     if ((NULL == (transfer->txData)) && (NULL == (transfer->rxData)))
150     {
151         return kStatus_InvalidArgument;
152     }
153 
154     /* Check that we're not busy.*/
155     if (handle->state == (uint8_t)kDSPI_Busy)
156     {
157         return kStatus_DSPI_Busy;
158     }
159 
160     handle->state = (uint8_t)kDSPI_Busy;
161 
162     uint32_t instance                = DSPI_GetInstance(base);
163     uint16_t wordToSend              = 0;
164     uint8_t dummyData                = DSPI_GetDummyDataInstance(base);
165     uint8_t dataAlreadyFed           = 0;
166     uint8_t dataFedMax               = 2;
167     uint32_t tmpMCR                  = 0;
168     size_t tmpRemainingSendByteCount = 0;
169 
170     uint32_t rxAddr = DSPI_GetRxRegisterAddress(base);
171     uint32_t txAddr = DSPI_MasterGetTxRegisterAddress(base);
172 
173     edma_tcd_t *softwareTCD = (edma_tcd_t *)((uint32_t)(&handle->dspiSoftwareTCD[1]) & (~0x1FU));
174 
175     edma_transfer_config_t transferConfigA = {0};
176     edma_transfer_config_t transferConfigB = {0};
177 
178     handle->txBuffIfNull = ((uint32_t)dummyData << 8U) | dummyData;
179 
180     dspi_command_data_config_t commandStruct;
181     DSPI_StopTransfer(base);
182     DSPI_FlushFifo(base, true, true);
183     DSPI_ClearStatusFlags(base, (uint32_t)kDSPI_AllStatusFlag);
184 
185     commandStruct.whichPcs =
186         (uint8_t)((uint32_t)1U << ((transfer->configFlags & DSPI_MASTER_PCS_MASK) >> DSPI_MASTER_PCS_SHIFT));
187     commandStruct.isEndOfQueue       = false;
188     commandStruct.clearTransferCount = false;
189     commandStruct.whichCtar = (uint8_t)((transfer->configFlags & DSPI_MASTER_CTAR_MASK) >> DSPI_MASTER_CTAR_SHIFT);
190     commandStruct.isPcsContinuous =
191         (0U != (transfer->configFlags & (uint32_t)kDSPI_MasterPcsContinuous)) ? true : false;
192     handle->command = DSPI_MasterGetFormattedCommand(&(commandStruct));
193 
194     commandStruct.isEndOfQueue = true;
195     commandStruct.isPcsContinuous =
196         (0U != (transfer->configFlags & (uint32_t)kDSPI_MasterActiveAfterTransfer)) ? true : false;
197     handle->lastCommand = DSPI_MasterGetFormattedCommand(&(commandStruct));
198 
199     handle->bitsPerFrame = ((base->CTAR[commandStruct.whichCtar] & SPI_CTAR_FMSZ_MASK) >> SPI_CTAR_FMSZ_SHIFT) + 1U;
200 
201     tmpMCR = base->MCR;
202     if ((0U != (tmpMCR & SPI_MCR_DIS_RXF_MASK)) || (0U != (tmpMCR & SPI_MCR_DIS_TXF_MASK)))
203     {
204         handle->fifoSize = 1U;
205     }
206     else
207     {
208         handle->fifoSize = (uint8_t)FSL_FEATURE_DSPI_FIFO_SIZEn(base);
209     }
210     handle->txData                    = transfer->txData;
211     handle->rxData                    = transfer->rxData;
212     handle->remainingSendByteCount    = transfer->dataSize;
213     handle->remainingReceiveByteCount = transfer->dataSize;
214     handle->totalByteCount            = transfer->dataSize;
215 
216     /* If using a shared RX/TX DMA request, then this limits the amount of data we can transfer
217      * due to the linked channel. The max bytes is 511 if 8-bit/frame or 1022 if 16-bit/frame
218      */
219     if (transfer->dataSize > DSPI_EDMA_MAX_TRANSFER_SIZE(base, (handle->bitsPerFrame)))
220     {
221         handle->state = (uint8_t)kDSPI_Idle;
222         return kStatus_DSPI_OutOfRange;
223     }
224 
225     /*The data size should be even if the bitsPerFrame is greater than 8 (that is 2 bytes per frame in dspi) */
226     if ((0U != (transfer->dataSize & 0x1U)) && (handle->bitsPerFrame > 8U))
227     {
228         handle->state = (uint8_t)kDSPI_Idle;
229         return kStatus_InvalidArgument;
230     }
231 
232     DSPI_DisableDMA(base, (uint32_t)kDSPI_RxDmaEnable | (uint32_t)kDSPI_TxDmaEnable);
233 
234     EDMA_SetCallback(handle->edmaRxRegToRxDataHandle, EDMA_DspiMasterCallback,
235                      &s_dspiMasterEdmaPrivateHandle[instance]);
236 
237     /*
238     (1)For DSPI instances with shared RX/TX DMA requests: Rx DMA request -> channel_A -> channel_B-> channel_C.
239     channel_A minor link to channel_B , channel_B minor link to channel_C.
240 
241     Already pushed 1 or 2 data in SPI_PUSHR , then start the DMA tansfer.
242     channel_A:SPI_POPR to rxData,
243     channel_B:next txData to handle->command (low 16 bits),
244     channel_C:handle->command (32 bits) to SPI_PUSHR, and use the scatter/gather to transfer the last data
245     (handle->lastCommand to SPI_PUSHR).
246 
247     (2)For DSPI instances with separate RX and TX DMA requests:
248     Rx DMA request -> channel_A
249     Tx DMA request -> channel_C -> channel_B .
250     channel_C major link to channel_B.
251     So need prepare the first data in "intermediary"  before the DMA
252     transfer and then channel_B is used to prepare the next data to "intermediary"
253 
254     channel_A:SPI_POPR to rxData,
255     channel_C: handle->command (32 bits) to SPI_PUSHR,
256     channel_B: next txData to handle->command (low 16 bits), and use the scatter/gather to prepare the last data
257     (handle->lastCommand to handle->Command).
258     */
259 
260     /*If dspi has separate dma request , prepare the first data in "intermediary" .
261     else (dspi has shared dma request) , send first 2 data if there is fifo or send first 1 data if there is no fifo*/
262     if (1 == FSL_FEATURE_DSPI_HAS_SEPARATE_DMA_RX_TX_REQn(base))
263     {
264         /* For DSPI instances with separate RX/TX DMA requests, we'll use the TX DMA request to
265          * trigger the TX DMA channel and RX DMA request to trigger the RX DMA channel
266          */
267 
268         /*Prepare the firt data*/
269         if (handle->bitsPerFrame > 8U)
270         {
271             /* If it's the last word */
272             if (handle->remainingSendByteCount <= 2U)
273             {
274                 if (NULL != handle->txData)
275                 {
276                     wordToSend = *(handle->txData);
277                     ++handle->txData; /* increment to next data byte */
278                     wordToSend |= (uint16_t)(*(handle->txData)) << 8U;
279                 }
280                 else
281                 {
282                     wordToSend = (((uint16_t)dummyData << 8U) | (uint16_t)dummyData);
283                 }
284                 handle->lastCommand = (handle->lastCommand & 0xffff0000U) | wordToSend;
285                 handle->command     = handle->lastCommand;
286             }
287             else /* For all words except the last word , frame > 8bits */
288             {
289                 if (NULL != handle->txData)
290                 {
291                     wordToSend = *(handle->txData);
292                     ++handle->txData; /* increment to next data byte */
293                     wordToSend |= (uint16_t)(*(handle->txData)) << 8U;
294                     ++handle->txData; /* increment to next data byte */
295                 }
296                 else
297                 {
298                     wordToSend = (((uint16_t)dummyData << 8U) | (uint16_t)dummyData);
299                 }
300                 handle->command = (handle->command & 0xffff0000U) | wordToSend;
301             }
302         }
303         else /* Optimized for bits/frame less than or equal to one byte. */
304         {
305             if (NULL != handle->txData)
306             {
307                 wordToSend = *(handle->txData);
308                 ++handle->txData; /* increment to next data word*/
309             }
310             else
311             {
312                 wordToSend = dummyData;
313             }
314 
315             if (handle->remainingSendByteCount == 1U)
316             {
317                 handle->lastCommand = (handle->lastCommand & 0xffff0000U) | wordToSend;
318                 handle->command     = handle->lastCommand;
319             }
320             else
321             {
322                 handle->command = (handle->command & 0xffff0000U) | wordToSend;
323             }
324         }
325     }
326 
327     else /*dspi has shared dma request*/
328     {
329         /* For DSPI instances with shared RX/TX DMA requests, we'll use the RX DMA request to
330          * trigger ongoing transfers and will link to the TX DMA channel from the RX DMA channel.
331          */
332 
333         /* If bits/frame is greater than one byte */
334         if (handle->bitsPerFrame > 8U)
335         {
336             while ((uint32_t)kDSPI_TxFifoFillRequestFlag ==
337                    (DSPI_GetStatusFlags(base) & (uint32_t)kDSPI_TxFifoFillRequestFlag))
338             {
339                 if (handle->remainingSendByteCount <= 2U)
340                 {
341                     if (NULL != handle->txData)
342                     {
343                         wordToSend = *(handle->txData);
344                         ++handle->txData;
345                         wordToSend |= (uint16_t)(*(handle->txData)) << 8U;
346                     }
347                     else
348                     {
349                         wordToSend = (((uint16_t)dummyData << 8U) | (uint16_t)dummyData);
350                     }
351                     handle->remainingSendByteCount = 0;
352                     base->PUSHR                    = (handle->lastCommand & 0xffff0000U) | wordToSend;
353                 }
354                 /* For all words except the last word */
355                 else
356                 {
357                     if (NULL != handle->txData)
358                     {
359                         wordToSend = *(handle->txData);
360                         ++handle->txData;
361                         wordToSend |= (uint16_t)(*(handle->txData)) << 8U;
362                         ++handle->txData;
363                     }
364                     else
365                     {
366                         wordToSend = (((uint16_t)dummyData << 8U) | (uint16_t)dummyData);
367                     }
368                     handle->remainingSendByteCount -= 2U;
369                     base->PUSHR = (handle->command & 0xffff0000U) | wordToSend;
370                 }
371 
372                 /* Try to clear the TFFF; if the TX FIFO is full this will clear */
373                 DSPI_ClearStatusFlags(base, (uint32_t)kDSPI_TxFifoFillRequestFlag);
374 
375                 dataAlreadyFed += 2U;
376 
377                 /* exit loop if send count is zero, else update local variables for next loop */
378                 if ((handle->remainingSendByteCount == 0U) || (dataAlreadyFed == (dataFedMax * 2U)))
379                 {
380                     break;
381                 }
382             } /* End of TX FIFO fill while loop */
383         }
384         else /* Optimized for bits/frame less than or equal to one byte. */
385         {
386             while ((uint32_t)kDSPI_TxFifoFillRequestFlag ==
387                    (DSPI_GetStatusFlags(base) & (uint32_t)kDSPI_TxFifoFillRequestFlag))
388             {
389                 if (NULL != handle->txData)
390                 {
391                     wordToSend = *(handle->txData);
392                     ++handle->txData;
393                 }
394                 else
395                 {
396                     wordToSend = dummyData;
397                 }
398 
399                 if (handle->remainingSendByteCount == 1U)
400                 {
401                     base->PUSHR = (handle->lastCommand & 0xffff0000U) | wordToSend;
402                 }
403                 else
404                 {
405                     base->PUSHR = (handle->command & 0xffff0000U) | wordToSend;
406                 }
407 
408                 /* Try to clear the TFFF; if the TX FIFO is full this will clear */
409                 DSPI_ClearStatusFlags(base, (uint32_t)kDSPI_TxFifoFillRequestFlag);
410 
411                 --handle->remainingSendByteCount;
412 
413                 dataAlreadyFed++;
414 
415                 /* exit loop if send count is zero, else update local variables for next loop */
416                 if ((handle->remainingSendByteCount == 0U) || (dataAlreadyFed == dataFedMax))
417                 {
418                     break;
419                 }
420             } /* End of TX FIFO fill while loop */
421         }
422     }
423 
424     /***channel_A *** used for carry the data from Rx_Data_Register(POPR) to User_Receive_Buffer(rxData)*/
425     EDMA_ResetChannel(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel);
426 
427     transferConfigA.srcAddr   = (uint32_t)rxAddr;
428     transferConfigA.srcOffset = 0;
429 
430     if (NULL != handle->rxData)
431     {
432         transferConfigA.destAddr   = (uint32_t) & (handle->rxData[0]);
433         transferConfigA.destOffset = 1;
434     }
435     else
436     {
437         transferConfigA.destAddr   = (uint32_t) & (handle->rxBuffIfNull);
438         transferConfigA.destOffset = 0;
439     }
440 
441     transferConfigA.destTransferSize = kEDMA_TransferSize1Bytes;
442 
443     if (handle->bitsPerFrame <= 8U)
444     {
445         transferConfigA.srcTransferSize = kEDMA_TransferSize1Bytes;
446         transferConfigA.minorLoopBytes  = 1;
447         transferConfigA.majorLoopCounts = handle->remainingReceiveByteCount;
448     }
449     else
450     {
451         transferConfigA.srcTransferSize = kEDMA_TransferSize2Bytes;
452         transferConfigA.minorLoopBytes  = 2;
453         transferConfigA.majorLoopCounts = handle->remainingReceiveByteCount / 2U;
454     }
455 
456     /* Store the initially configured eDMA minor byte transfer count into the DSPI handle */
457     handle->nbytes = (uint8_t)(transferConfigA.minorLoopBytes);
458 
459     EDMA_SetTransferConfig(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel,
460                            (const edma_transfer_config_t *)(uint32_t)&transferConfigA, NULL);
461     EDMA_EnableChannelInterrupts(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel,
462                                  (uint32_t)kEDMA_MajorInterruptEnable);
463 
464     if (handle->remainingSendByteCount == 0U)
465     {
466         EDMA_StartTransfer(handle->edmaRxRegToRxDataHandle);
467         DSPI_EnableDMA(base, (uint32_t)kDSPI_RxDmaEnable);
468         DSPI_StartTransfer(base);
469         return kStatus_Success;
470     }
471 
472     tmpRemainingSendByteCount = handle->remainingSendByteCount;
473     /*Calculate the last data : handle->lastCommand*/
474     if (((tmpRemainingSendByteCount > 0U) && (1U != (uint8_t)FSL_FEATURE_DSPI_HAS_SEPARATE_DMA_RX_TX_REQn(base))) ||
475         ((((tmpRemainingSendByteCount > 1U) && (handle->bitsPerFrame <= 8U)) ||
476           ((tmpRemainingSendByteCount > 2U) && (handle->bitsPerFrame > 8U))) &&
477          (1U == (uint8_t)FSL_FEATURE_DSPI_HAS_SEPARATE_DMA_RX_TX_REQn(base))))
478     {
479         if (NULL != handle->txData)
480         {
481             uint32_t bufferIndex = 0;
482 
483             if (1 == FSL_FEATURE_DSPI_HAS_SEPARATE_DMA_RX_TX_REQn(base))
484             {
485                 if (handle->bitsPerFrame <= 8U)
486                 {
487                     bufferIndex = handle->remainingSendByteCount - 1U;
488                 }
489                 else
490                 {
491                     bufferIndex = handle->remainingSendByteCount - 2U;
492                 }
493             }
494             else
495             {
496                 bufferIndex = handle->remainingSendByteCount;
497             }
498 
499             uint32_t tmpLastCommand = handle->lastCommand;
500             const uint8_t *tmpTxData      = handle->txData;
501 
502             if (handle->bitsPerFrame <= 8U)
503             {
504                 tmpLastCommand = (tmpLastCommand & 0xffff0000U) | tmpTxData[bufferIndex - 1U];
505             }
506             else
507             {
508                 tmpLastCommand = (tmpLastCommand & 0xffff0000U) | ((uint32_t)tmpTxData[bufferIndex - 1U] << 8U) |
509                                  tmpTxData[bufferIndex - 2U];
510             }
511 
512             handle->lastCommand = tmpLastCommand;
513         }
514         else
515         {
516             if (handle->bitsPerFrame <= 8U)
517             {
518                 wordToSend = dummyData;
519             }
520             else
521             {
522                 wordToSend = (((uint16_t)dummyData << 8U) | (uint16_t)dummyData);
523             }
524             handle->lastCommand = (handle->lastCommand & 0xffff0000U) | wordToSend;
525         }
526     }
527 
528 /* The feature of GASKET is that the SPI supports 8-bit or 16-bit writes to the PUSH TX FIFO,
529  * allowing a single write to the command word followed by multiple writes to the transmit word.
530  * The TX FIFO will save the last command word written, and convert a 8-bit/16-bit write to the
531  * transmit word into a 32-bit write that pushes both the command word and transmit word into
532  * the TX FIFO (PUSH TX FIFO Register In Master Mode)
533  * So, if this feature is supported, we can use use one channel to carry the receive data from
534  * receive regsiter to user data buffer, use the other channel to carry the data from user data buffer
535  * to transmit register,and use the scatter/gather function to prepare the last data.
536  * That is to say, if GASKET feature is supported, we can use only two channels for tansferring data.
537  */
538 #if defined(FSL_FEATURE_DSPI_HAS_GASKET) && FSL_FEATURE_DSPI_HAS_GASKET
539     /*  For DSPI instances with separate RX and TX DMA requests: use the scatter/gather to prepare the last data
540      * (handle->lastCommand) to PUSHR register.
541      */
542 
543     EDMA_ResetChannel(handle->edmaIntermediaryToTxRegHandle->base, handle->edmaIntermediaryToTxRegHandle->channel);
544 
545     if ((1 == FSL_FEATURE_DSPI_HAS_SEPARATE_DMA_RX_TX_REQn(base)) ||
546         ((handle->remainingSendByteCount > 0) && (1 != FSL_FEATURE_DSPI_HAS_SEPARATE_DMA_RX_TX_REQn(base))))
547     {
548         transferConfigB.srcAddr          = (uint32_t) & (handle->lastCommand);
549         transferConfigB.destAddr         = (uint32_t)txAddr;
550         transferConfigB.srcTransferSize  = kEDMA_TransferSize4Bytes;
551         transferConfigB.destTransferSize = kEDMA_TransferSize4Bytes;
552         transferConfigB.srcOffset        = 0;
553         transferConfigB.destOffset       = 0;
554         transferConfigB.minorLoopBytes   = 4;
555         transferConfigB.majorLoopCounts  = 1;
556 
557         EDMA_TcdReset(softwareTCD);
558         EDMA_TcdSetTransferConfig(softwareTCD, &transferConfigB, NULL);
559     }
560 
561     /*User_Send_Buffer(txData) to PUSHR register. */
562     if (((handle->remainingSendByteCount > 2U) && (handle->bitsPerFrame <= 8U)) ||
563         ((handle->remainingSendByteCount > 4U) && (handle->bitsPerFrame > 8U)))
564     {
565         if (handle->txData)
566         {
567             if (1 == FSL_FEATURE_DSPI_HAS_SEPARATE_DMA_RX_TX_REQn(base))
568             {
569                 /* For DSPI with separate RX and TX DMA requests, one frame data has been carry
570                  * to handle->command, so need to reduce the pointer of txData.
571                  */
572                 transferConfigB.srcAddr =
573                     (uint32_t)((uint8_t *)(handle->txData) - ((handle->bitsPerFrame <= 8U) ? (1U) : (2U)));
574                 transferConfigB.srcOffset = 1;
575             }
576             else
577             {
578                 /* For DSPI with shared RX and TX DMA requests, one or two frame data have been carry
579                  * to PUSHR register, so no need to change the pointer of txData.
580                  */
581                 transferConfigB.srcAddr   = (uint32_t)((uint8_t *)(handle->txData));
582                 transferConfigB.srcOffset = 1;
583             }
584         }
585         else
586         {
587             transferConfigB.srcAddr   = (uint32_t)(&handle->txBuffIfNull);
588             transferConfigB.srcOffset = 0;
589         }
590 
591         transferConfigB.destAddr   = (uint32_t)txAddr;
592         transferConfigB.destOffset = 0;
593 
594         transferConfigB.srcTransferSize = kEDMA_TransferSize1Bytes;
595 
596         if (handle->bitsPerFrame <= 8U)
597         {
598             transferConfigB.destTransferSize = kEDMA_TransferSize1Bytes;
599             transferConfigB.minorLoopBytes   = 1;
600 
601             transferConfigB.majorLoopCounts = handle->remainingSendByteCount - 1U;
602         }
603         else
604         {
605             transferConfigB.destTransferSize = kEDMA_TransferSize2Bytes;
606             transferConfigB.minorLoopBytes   = 2;
607             transferConfigB.majorLoopCounts  = (handle->remainingSendByteCount / 2U) - 1U;
608         }
609 
610         EDMA_SetTransferConfig(handle->edmaIntermediaryToTxRegHandle->base,
611                                handle->edmaIntermediaryToTxRegHandle->channel, &transferConfigB, softwareTCD);
612     }
613     /* If only one word to transmit, only carry the lastcommand. */
614     else
615     {
616         EDMA_SetTransferConfig(handle->edmaIntermediaryToTxRegHandle->base,
617                                handle->edmaIntermediaryToTxRegHandle->channel, &transferConfigB, NULL);
618     }
619 
620     /*Start the EDMA channel_A , channel_C. */
621     EDMA_StartTransfer(handle->edmaRxRegToRxDataHandle);
622     EDMA_StartTransfer(handle->edmaIntermediaryToTxRegHandle);
623 
624     /* Set the channel link.
625      * For DSPI instances with shared TX and RX DMA requests, setup channel minor link, first receive data from the
626      * receive register, and then carry transmit data to PUSHER register.
627      * For DSPI instance with separate TX and RX DMA requests, there is no need to set up channel link.
628      */
629     if (1 != FSL_FEATURE_DSPI_HAS_SEPARATE_DMA_RX_TX_REQn(base))
630     {
631         /*Set channel priority*/
632         uint8_t channelPriorityLow  = handle->edmaRxRegToRxDataHandle->channel;
633         uint8_t channelPriorityHigh = handle->edmaIntermediaryToTxRegHandle->channel;
634         uint8_t t                   = 0;
635 
636         if (channelPriorityLow > channelPriorityHigh)
637         {
638             t                   = channelPriorityLow;
639             channelPriorityLow  = channelPriorityHigh;
640             channelPriorityHigh = t;
641         }
642 
643         edma_channel_Preemption_config_t preemption_config_t;
644         preemption_config_t.enableChannelPreemption = true;
645         preemption_config_t.enablePreemptAbility    = true;
646         preemption_config_t.channelPriority         = channelPriorityLow;
647 
648         EDMA_SetChannelPreemptionConfig(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel,
649                                         &preemption_config_t);
650 
651         preemption_config_t.channelPriority = channelPriorityHigh;
652         EDMA_SetChannelPreemptionConfig(handle->edmaIntermediaryToTxRegHandle->base,
653                                         handle->edmaIntermediaryToTxRegHandle->channel, &preemption_config_t);
654         /*if there is Rx DMA request , carry the 32bits data (handle->command) to user data first , then link to
655           channelC to carry the next data to PUSHER register.(txData to PUSHER) */
656         if (handle->remainingSendByteCount > 0U)
657         {
658             EDMA_SetChannelLink(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel,
659                                 kEDMA_MinorLink, handle->edmaIntermediaryToTxRegHandle->channel);
660         }
661     }
662 
663     DSPI_EnableDMA(base, kDSPI_RxDmaEnable | kDSPI_TxDmaEnable);
664 
665     /* Setup control info to PUSHER register. */
666     *((uint16_t *)&(base->PUSHR) + 1) = (handle->command >> 16U);
667 #else
668 
669     /***channel_B *** used for carry the data from User_Send_Buffer to "intermediary" because the SPIx_PUSHR should
670     write the 32bits at once time . Then use channel_C to carry the "intermediary" to SPIx_PUSHR. Note that the
671     SPIx_PUSHR upper 16 bits are the "command" and the low 16bits are data */
672 
673     EDMA_ResetChannel(handle->edmaTxDataToIntermediaryHandle->base, handle->edmaTxDataToIntermediaryHandle->channel);
674 
675     /*For DSPI instances with separate RX and TX DMA requests: use the scatter/gather to prepare the last data
676      * (handle->lastCommand) to handle->Command*/
677     if (1 == FSL_FEATURE_DSPI_HAS_SEPARATE_DMA_RX_TX_REQn(base))
678     {
679         transferConfigB.srcAddr          = (uint32_t) & (handle->lastCommand);
680         transferConfigB.destAddr         = (uint32_t) & (handle->command);
681         transferConfigB.srcTransferSize  = kEDMA_TransferSize4Bytes;
682         transferConfigB.destTransferSize = kEDMA_TransferSize4Bytes;
683         transferConfigB.srcOffset        = 0;
684         transferConfigB.destOffset       = 0;
685         transferConfigB.minorLoopBytes   = 4;
686         transferConfigB.majorLoopCounts  = 1;
687 
688         EDMA_TcdReset(softwareTCD);
689         EDMA_TcdSetTransferConfig(softwareTCD, (const edma_transfer_config_t *)(uint32_t)&transferConfigB, NULL);
690     }
691 
692     tmpRemainingSendByteCount = handle->remainingSendByteCount;
693     /*User_Send_Buffer(txData) to intermediary(handle->command)*/
694     if (((((tmpRemainingSendByteCount > 2U) && (handle->bitsPerFrame <= 8U)) ||
695           ((tmpRemainingSendByteCount > 4U) && (handle->bitsPerFrame > 8U))) &&
696          (1 == FSL_FEATURE_DSPI_HAS_SEPARATE_DMA_RX_TX_REQn(base))) ||
697         (1 != FSL_FEATURE_DSPI_HAS_SEPARATE_DMA_RX_TX_REQn(base)))
698     {
699         if (NULL != handle->txData)
700         {
701             transferConfigB.srcAddr   = (uint32_t)(handle->txData);
702             transferConfigB.srcOffset = 1;
703         }
704         else
705         {
706             transferConfigB.srcAddr   = (uint32_t)(&handle->txBuffIfNull);
707             transferConfigB.srcOffset = 0;
708         }
709 
710         transferConfigB.destAddr   = (uint32_t)(&handle->command);
711         transferConfigB.destOffset = 0;
712 
713         transferConfigB.srcTransferSize = kEDMA_TransferSize1Bytes;
714 
715         if (handle->bitsPerFrame <= 8U)
716         {
717             transferConfigB.destTransferSize = kEDMA_TransferSize1Bytes;
718             transferConfigB.minorLoopBytes   = 1;
719 
720             if (1 == FSL_FEATURE_DSPI_HAS_SEPARATE_DMA_RX_TX_REQn(base))
721             {
722                 transferConfigB.majorLoopCounts = handle->remainingSendByteCount - 2U;
723             }
724             else
725             {
726                 /*Only enable channel_B minorlink to channel_C , so need to add one count due to the last time is
727                 majorlink , the majorlink would not trigger the channel_C*/
728                 transferConfigB.majorLoopCounts = handle->remainingSendByteCount + 1U;
729             }
730         }
731         else
732         {
733             transferConfigB.destTransferSize = kEDMA_TransferSize2Bytes;
734             transferConfigB.minorLoopBytes   = 2;
735             if (1 == FSL_FEATURE_DSPI_HAS_SEPARATE_DMA_RX_TX_REQn(base))
736             {
737                 transferConfigB.majorLoopCounts = handle->remainingSendByteCount / 2U - 2U;
738             }
739             else
740             {
741                 /*Only enable channel_B minorlink to channel_C , so need to add one count due to the last time is
742                  * majorlink*/
743                 transferConfigB.majorLoopCounts = handle->remainingSendByteCount / 2U + 1U;
744             }
745         }
746 
747         if (1 == FSL_FEATURE_DSPI_HAS_SEPARATE_DMA_RX_TX_REQn(base))
748         {
749             EDMA_SetTransferConfig(handle->edmaTxDataToIntermediaryHandle->base,
750                                    handle->edmaTxDataToIntermediaryHandle->channel,
751                                    (const edma_transfer_config_t *)(uint32_t)&transferConfigB, softwareTCD);
752             EDMA_EnableAutoStopRequest(handle->edmaIntermediaryToTxRegHandle->base,
753                                        handle->edmaIntermediaryToTxRegHandle->channel, false);
754         }
755         else
756         {
757             EDMA_SetTransferConfig(handle->edmaTxDataToIntermediaryHandle->base,
758                                    handle->edmaTxDataToIntermediaryHandle->channel,
759                                    (const edma_transfer_config_t *)(uint32_t)&transferConfigB, NULL);
760         }
761     }
762     else
763     {
764         EDMA_SetTransferConfig(handle->edmaTxDataToIntermediaryHandle->base,
765                                handle->edmaTxDataToIntermediaryHandle->channel,
766                                (const edma_transfer_config_t *)(uint32_t)&transferConfigB, NULL);
767     }
768 
769     /***channel_C ***carry the "intermediary" to SPIx_PUSHR. used the edma Scatter Gather function on channel_C to
770     handle the last data */
771 
772     edma_transfer_config_t transferConfigC = {0};
773 
774     EDMA_ResetChannel(handle->edmaIntermediaryToTxRegHandle->base, handle->edmaIntermediaryToTxRegHandle->channel);
775 
776     tmpRemainingSendByteCount = handle->remainingSendByteCount;
777     /*For DSPI instances with shared RX/TX DMA requests: use the scatter/gather to prepare the last data
778      * (handle->lastCommand) to SPI_PUSHR*/
779     if (((1 != FSL_FEATURE_DSPI_HAS_SEPARATE_DMA_RX_TX_REQn(base)) && (tmpRemainingSendByteCount > 0U)))
780     {
781         transferConfigC.srcAddr          = (uint32_t) & (handle->lastCommand);
782         transferConfigC.destAddr         = (uint32_t)txAddr;
783         transferConfigC.srcTransferSize  = kEDMA_TransferSize4Bytes;
784         transferConfigC.destTransferSize = kEDMA_TransferSize4Bytes;
785         transferConfigC.srcOffset        = 0;
786         transferConfigC.destOffset       = 0;
787         transferConfigC.minorLoopBytes   = 4;
788         transferConfigC.majorLoopCounts  = 1;
789 
790         EDMA_TcdReset(softwareTCD);
791         EDMA_TcdSetTransferConfig(softwareTCD, (const edma_transfer_config_t *)(uint32_t)&transferConfigC, NULL);
792     }
793 
794     tmpRemainingSendByteCount = handle->remainingSendByteCount;
795     if (((tmpRemainingSendByteCount > 1U) && (handle->bitsPerFrame <= 8U)) ||
796         ((tmpRemainingSendByteCount > 2U) && (handle->bitsPerFrame > 8U)) ||
797         (1 == FSL_FEATURE_DSPI_HAS_SEPARATE_DMA_RX_TX_REQn(base)))
798     {
799         transferConfigC.srcAddr  = (uint32_t)(&(handle->command));
800         transferConfigC.destAddr = (uint32_t)txAddr;
801 
802         transferConfigC.srcTransferSize  = kEDMA_TransferSize4Bytes;
803         transferConfigC.destTransferSize = kEDMA_TransferSize4Bytes;
804         transferConfigC.srcOffset        = 0;
805         transferConfigC.destOffset       = 0;
806         transferConfigC.minorLoopBytes   = 4;
807         if (1 != FSL_FEATURE_DSPI_HAS_SEPARATE_DMA_RX_TX_REQn(base))
808         {
809             if (handle->bitsPerFrame <= 8U)
810             {
811                 transferConfigC.majorLoopCounts = handle->remainingSendByteCount - 1U;
812             }
813             else
814             {
815                 transferConfigC.majorLoopCounts = (handle->remainingSendByteCount / 2U) - 1U;
816             }
817 
818             EDMA_SetTransferConfig(handle->edmaIntermediaryToTxRegHandle->base,
819                                    handle->edmaIntermediaryToTxRegHandle->channel,
820                                    (const edma_transfer_config_t *)(uint32_t)&transferConfigC, softwareTCD);
821         }
822         else
823         {
824             transferConfigC.majorLoopCounts = 1;
825 
826             EDMA_SetTransferConfig(handle->edmaIntermediaryToTxRegHandle->base,
827                                    handle->edmaIntermediaryToTxRegHandle->channel,
828                                    (const edma_transfer_config_t *)(uint32_t)&transferConfigC, NULL);
829         }
830 
831         EDMA_EnableAutoStopRequest(handle->edmaIntermediaryToTxRegHandle->base,
832                                    handle->edmaIntermediaryToTxRegHandle->channel, false);
833     }
834     else
835     {
836         EDMA_SetTransferConfig(handle->edmaIntermediaryToTxRegHandle->base,
837                                handle->edmaIntermediaryToTxRegHandle->channel,
838                                (const edma_transfer_config_t *)(uint32_t)&transferConfigC, NULL);
839     }
840 
841     /*Start the EDMA channel_A , channel_B , channel_C transfer*/
842     EDMA_StartTransfer(handle->edmaRxRegToRxDataHandle);
843     EDMA_StartTransfer(handle->edmaTxDataToIntermediaryHandle);
844     EDMA_StartTransfer(handle->edmaIntermediaryToTxRegHandle);
845 
846     /*Set channel priority*/
847     uint8_t channelPriorityLow  = handle->edmaRxRegToRxDataHandle->channel;
848     uint8_t channelPriorityMid  = handle->edmaTxDataToIntermediaryHandle->channel;
849     uint8_t channelPriorityHigh = handle->edmaIntermediaryToTxRegHandle->channel;
850     uint8_t t                   = 0;
851     if (channelPriorityLow > channelPriorityMid)
852     {
853         t                  = channelPriorityLow;
854         channelPriorityLow = channelPriorityMid;
855         channelPriorityMid = t;
856     }
857 
858     if (channelPriorityLow > channelPriorityHigh)
859     {
860         t                   = channelPriorityLow;
861         channelPriorityLow  = channelPriorityHigh;
862         channelPriorityHigh = t;
863     }
864 
865     if (channelPriorityMid > channelPriorityHigh)
866     {
867         t                   = channelPriorityMid;
868         channelPriorityMid  = channelPriorityHigh;
869         channelPriorityHigh = t;
870     }
871     edma_channel_Preemption_config_t preemption_config_t;
872     preemption_config_t.enableChannelPreemption = true;
873     preemption_config_t.enablePreemptAbility    = true;
874     preemption_config_t.channelPriority         = channelPriorityLow;
875 
876     if (1 != FSL_FEATURE_DSPI_HAS_SEPARATE_DMA_RX_TX_REQn(base))
877     {
878         EDMA_SetChannelPreemptionConfig(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel,
879                                         (const edma_channel_Preemption_config_t *)(uint32_t)&preemption_config_t);
880 
881         preemption_config_t.channelPriority = channelPriorityMid;
882         EDMA_SetChannelPreemptionConfig(handle->edmaTxDataToIntermediaryHandle->base,
883                                         handle->edmaTxDataToIntermediaryHandle->channel,
884                                         (const edma_channel_Preemption_config_t *)(uint32_t)&preemption_config_t);
885 
886         preemption_config_t.channelPriority = channelPriorityHigh;
887         EDMA_SetChannelPreemptionConfig(handle->edmaIntermediaryToTxRegHandle->base,
888                                         handle->edmaIntermediaryToTxRegHandle->channel,
889                                         (const edma_channel_Preemption_config_t *)(uint32_t)&preemption_config_t);
890     }
891     else
892     {
893         EDMA_SetChannelPreemptionConfig(handle->edmaIntermediaryToTxRegHandle->base,
894                                         handle->edmaIntermediaryToTxRegHandle->channel,
895                                         (const edma_channel_Preemption_config_t *)(uint32_t)&preemption_config_t);
896 
897         preemption_config_t.channelPriority = channelPriorityMid;
898         EDMA_SetChannelPreemptionConfig(handle->edmaTxDataToIntermediaryHandle->base,
899                                         handle->edmaTxDataToIntermediaryHandle->channel,
900                                         (const edma_channel_Preemption_config_t *)(uint32_t)&preemption_config_t);
901 
902         preemption_config_t.channelPriority = channelPriorityHigh;
903         EDMA_SetChannelPreemptionConfig(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel,
904                                         (const edma_channel_Preemption_config_t *)(uint32_t)&preemption_config_t);
905     }
906 
907     /*Set the channel link.*/
908     if (1 == FSL_FEATURE_DSPI_HAS_SEPARATE_DMA_RX_TX_REQn(base))
909     {
910         /*if there is Tx DMA request , carry the 32bits data (handle->command) to PUSHR first , then link to channelB
911         to prepare the next 32bits data (txData to handle->command) */
912         if (handle->remainingSendByteCount > 1U)
913         {
914             EDMA_SetChannelLink(handle->edmaIntermediaryToTxRegHandle->base,
915                                 handle->edmaIntermediaryToTxRegHandle->channel, kEDMA_MajorLink,
916                                 handle->edmaTxDataToIntermediaryHandle->channel);
917         }
918 
919         DSPI_EnableDMA(base, (uint32_t)kDSPI_RxDmaEnable | (uint32_t)kDSPI_TxDmaEnable);
920     }
921     else
922     {
923         if (handle->remainingSendByteCount > 0U)
924         {
925             EDMA_SetChannelLink(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel,
926                                 kEDMA_MinorLink, handle->edmaTxDataToIntermediaryHandle->channel);
927 
928             EDMA_SetChannelLink(handle->edmaTxDataToIntermediaryHandle->base,
929                                 handle->edmaTxDataToIntermediaryHandle->channel, kEDMA_MinorLink,
930                                 handle->edmaIntermediaryToTxRegHandle->channel);
931         }
932 
933         DSPI_EnableDMA(base, (uint32_t)kDSPI_RxDmaEnable);
934     }
935 #endif
936     DSPI_StartTransfer(base);
937 
938     return kStatus_Success;
939 }
940 
941 /*!
942  * brief Transfers a block of data using a eDMA method.
943  *
944  * This function transfers data using eDNA, the transfer mechanism is half-duplex. This is a non-blocking function,
945  * which returns right away. When all data is transferred, the callback function is called.
946  *
947  * param base DSPI base pointer
948  * param handle A pointer to the dspi_master_edma_handle_t structure which stores the transfer state.
949  * param transfer A pointer to the dspi_half_duplex_transfer_t structure.
950  * return status of status_t.
951  */
DSPI_MasterHalfDuplexTransferEDMA(SPI_Type * base,dspi_master_edma_handle_t * handle,dspi_half_duplex_transfer_t * xfer)952 status_t DSPI_MasterHalfDuplexTransferEDMA(SPI_Type *base,
953                                            dspi_master_edma_handle_t *handle,
954                                            dspi_half_duplex_transfer_t *xfer)
955 {
956     assert(NULL != xfer);
957     assert(NULL != handle);
958     dspi_transfer_t tempXfer = {0};
959     status_t status;
960 
961     if (true == xfer->isTransmitFirst)
962     {
963         tempXfer.txData   = xfer->txData;
964         tempXfer.rxData   = NULL;
965         tempXfer.dataSize = xfer->txDataSize;
966     }
967     else
968     {
969         tempXfer.txData   = NULL;
970         tempXfer.rxData   = xfer->rxData;
971         tempXfer.dataSize = xfer->rxDataSize;
972     }
973     /* If the pcs pin keep assert between transmit and receive. */
974     if (true == xfer->isPcsAssertInTransfer)
975     {
976         tempXfer.configFlags = (xfer->configFlags) | (uint32_t)kDSPI_MasterActiveAfterTransfer;
977     }
978     else
979     {
980         tempXfer.configFlags = (xfer->configFlags) & (~(uint32_t)kDSPI_MasterActiveAfterTransfer);
981     }
982 
983     status = DSPI_MasterTransferBlocking(base, &tempXfer);
984     if (status != kStatus_Success)
985     {
986         return status;
987     }
988 
989     if (true == xfer->isTransmitFirst)
990     {
991         tempXfer.txData   = NULL;
992         tempXfer.rxData   = xfer->rxData;
993         tempXfer.dataSize = xfer->rxDataSize;
994     }
995     else
996     {
997         tempXfer.txData   = xfer->txData;
998         tempXfer.rxData   = NULL;
999         tempXfer.dataSize = xfer->txDataSize;
1000     }
1001     tempXfer.configFlags = xfer->configFlags;
1002 
1003     status = DSPI_MasterTransferEDMA(base, handle, &tempXfer);
1004 
1005     return status;
1006 }
EDMA_DspiMasterCallback(edma_handle_t * edmaHandle,void * g_dspiEdmaPrivateHandle,bool transferDone,uint32_t tcds)1007 static void EDMA_DspiMasterCallback(edma_handle_t *edmaHandle,
1008                                     void *g_dspiEdmaPrivateHandle,
1009                                     bool transferDone,
1010                                     uint32_t tcds)
1011 {
1012     assert(NULL != edmaHandle);
1013     assert(NULL != g_dspiEdmaPrivateHandle);
1014 
1015     dspi_master_edma_private_handle_t *dspiEdmaPrivateHandle;
1016 
1017     dspiEdmaPrivateHandle = (dspi_master_edma_private_handle_t *)g_dspiEdmaPrivateHandle;
1018 
1019     DSPI_DisableDMA((dspiEdmaPrivateHandle->base), (uint32_t)kDSPI_RxDmaEnable | (uint32_t)kDSPI_TxDmaEnable);
1020 
1021     dspiEdmaPrivateHandle->handle->state = (uint8_t)kDSPI_Idle;
1022 
1023     if (NULL != dspiEdmaPrivateHandle->handle->callback)
1024     {
1025         dspiEdmaPrivateHandle->handle->callback(dspiEdmaPrivateHandle->base, dspiEdmaPrivateHandle->handle,
1026                                                 kStatus_Success, dspiEdmaPrivateHandle->handle->userData);
1027     }
1028 }
1029 
1030 /*!
1031  * brief DSPI master aborts a transfer which is using eDMA.
1032  *
1033  * This function aborts a transfer which is using eDMA.
1034  *
1035  * param base DSPI peripheral base address.
1036  * param handle A pointer to the dspi_master_edma_handle_t structure which stores the transfer state.
1037  */
DSPI_MasterTransferAbortEDMA(SPI_Type * base,dspi_master_edma_handle_t * handle)1038 void DSPI_MasterTransferAbortEDMA(SPI_Type *base, dspi_master_edma_handle_t *handle)
1039 {
1040     assert(NULL != handle);
1041 
1042     DSPI_StopTransfer(base);
1043 
1044     DSPI_DisableDMA(base, (uint32_t)kDSPI_RxDmaEnable | (uint32_t)kDSPI_TxDmaEnable);
1045 
1046     EDMA_AbortTransfer(handle->edmaRxRegToRxDataHandle);
1047     EDMA_AbortTransfer(handle->edmaTxDataToIntermediaryHandle);
1048     EDMA_AbortTransfer(handle->edmaIntermediaryToTxRegHandle);
1049 
1050     handle->state = (uint8_t)kDSPI_Idle;
1051 }
1052 
1053 /*!
1054  * brief Gets the master eDMA transfer count.
1055  *
1056  * This function gets the master eDMA transfer count.
1057  *
1058  * param base DSPI peripheral base address.
1059  * param handle A pointer to the dspi_master_edma_handle_t structure which stores the transfer state.
1060  * param count A number of bytes transferred by the non-blocking transaction.
1061  * return status of status_t.
1062  */
DSPI_MasterTransferGetCountEDMA(SPI_Type * base,dspi_master_edma_handle_t * handle,size_t * count)1063 status_t DSPI_MasterTransferGetCountEDMA(SPI_Type *base, dspi_master_edma_handle_t *handle, size_t *count)
1064 {
1065     assert(NULL != handle);
1066 
1067     if (NULL == count)
1068     {
1069         return kStatus_InvalidArgument;
1070     }
1071 
1072     /* Catch when there is not an active transfer. */
1073     if (handle->state != (uint8_t)kDSPI_Busy)
1074     {
1075         *count = 0;
1076         return kStatus_NoTransferInProgress;
1077     }
1078 
1079     size_t bytes;
1080 
1081     bytes = (uint32_t)handle->nbytes * EDMA_GetRemainingMajorLoopCount(handle->edmaRxRegToRxDataHandle->base,
1082                                                                        handle->edmaRxRegToRxDataHandle->channel);
1083 
1084     *count = handle->totalByteCount - bytes;
1085 
1086     return kStatus_Success;
1087 }
1088 
1089 /*!
1090  * brief Initializes the DSPI slave eDMA handle.
1091  *
1092  * This function initializes the DSPI eDMA handle which can be used for other DSPI transactional APIs.  Usually, for a
1093  * specified DSPI instance, call this API once to get the initialized handle.
1094  *
1095  * Note that DSPI eDMA has separated (RN and TX in 2 sources) or shared (RX  and TX are the same source) DMA request
1096  * source.
1097  * (1)For the separated DMA request source, enable and set the RX DMAMUX source for edmaRxRegToRxDataHandle and
1098  * TX DMAMUX source for edmaTxDataToTxRegHandle.
1099  * (2)For the shared DMA request source,  enable and set the RX/RX DMAMUX source for the edmaRxRegToRxDataHandle.
1100  *
1101  * param base DSPI peripheral base address.
1102  * param handle DSPI handle pointer to dspi_slave_edma_handle_t.
1103  * param callback DSPI callback.
1104  * param userData A callback function parameter.
1105  * param edmaRxRegToRxDataHandle edmaRxRegToRxDataHandle pointer to edma_handle_t.
1106  * param edmaTxDataToTxRegHandle edmaTxDataToTxRegHandle pointer to edma_handle_t.
1107  */
DSPI_SlaveTransferCreateHandleEDMA(SPI_Type * base,dspi_slave_edma_handle_t * handle,dspi_slave_edma_transfer_callback_t callback,void * userData,edma_handle_t * edmaRxRegToRxDataHandle,edma_handle_t * edmaTxDataToTxRegHandle)1108 void DSPI_SlaveTransferCreateHandleEDMA(SPI_Type *base,
1109                                         dspi_slave_edma_handle_t *handle,
1110                                         dspi_slave_edma_transfer_callback_t callback,
1111                                         void *userData,
1112                                         edma_handle_t *edmaRxRegToRxDataHandle,
1113                                         edma_handle_t *edmaTxDataToTxRegHandle)
1114 {
1115     assert(NULL != handle);
1116     assert(NULL != edmaRxRegToRxDataHandle);
1117     assert(NULL != edmaTxDataToTxRegHandle);
1118 
1119     /* Zero the handle. */
1120     (void)memset(handle, 0, sizeof(*handle));
1121 
1122     uint32_t instance = DSPI_GetInstance(base);
1123 
1124     s_dspiSlaveEdmaPrivateHandle[instance].base   = base;
1125     s_dspiSlaveEdmaPrivateHandle[instance].handle = handle;
1126 
1127     handle->callback = callback;
1128     handle->userData = userData;
1129 
1130     handle->edmaRxRegToRxDataHandle = edmaRxRegToRxDataHandle;
1131     handle->edmaTxDataToTxRegHandle = edmaTxDataToTxRegHandle;
1132 }
1133 
1134 /*!
1135  * brief DSPI slave transfer data using eDMA.
1136  *
1137  * This function transfers data using eDMA. This is a non-blocking function, which returns right away. When all data
1138  * is transferred, the callback function is called.
1139  * Note that the slave eDMA transfer doesn't support transfer_size is 1 when the bitsPerFrame is greater
1140  * than eight.
1141  *
1142  * note The max transfer size of each transfer depends on whether the instance's Tx/Rx shares the same DMA request. If
1143  * FSL_FEATURE_DSPI_HAS_SEPARATE_DMA_RX_TX_REQn(x) is true, then the max transfer size is 32767 datawidth of data,
1144  * otherwise is 511.
1145  *
1146  * param base DSPI peripheral base address.
1147  * param handle A pointer to the dspi_slave_edma_handle_t structure which stores the transfer state.
1148  * param transfer A pointer to the dspi_transfer_t structure.
1149  * return status of status_t.
1150  */
DSPI_SlaveTransferEDMA(SPI_Type * base,dspi_slave_edma_handle_t * handle,dspi_transfer_t * transfer)1151 status_t DSPI_SlaveTransferEDMA(SPI_Type *base, dspi_slave_edma_handle_t *handle, dspi_transfer_t *transfer)
1152 {
1153     assert(NULL != handle);
1154     assert(NULL != transfer);
1155 
1156     /* If send/receive length is zero */
1157     if (transfer->dataSize == 0U)
1158     {
1159         return kStatus_InvalidArgument;
1160     }
1161 
1162     /* If both send buffer and receive buffer is null */
1163     if ((NULL == (transfer->txData)) && (NULL == (transfer->rxData)))
1164     {
1165         return kStatus_InvalidArgument;
1166     }
1167 
1168     /* Check that we're not busy.*/
1169     if (handle->state == (uint8_t)kDSPI_Busy)
1170     {
1171         return kStatus_DSPI_Busy;
1172     }
1173 
1174     handle->state = (uint8_t)kDSPI_Busy;
1175 
1176     uint32_t instance = DSPI_GetInstance(base);
1177     uint8_t whichCtar = (uint8_t)((transfer->configFlags & DSPI_SLAVE_CTAR_MASK) >> DSPI_SLAVE_CTAR_SHIFT);
1178     handle->bitsPerFrame =
1179         (((base->CTAR_SLAVE[whichCtar]) & SPI_CTAR_SLAVE_FMSZ_MASK) >> SPI_CTAR_SLAVE_FMSZ_SHIFT) + 1U;
1180 
1181     /* If using a shared RX/TX DMA request, then this limits the amount of data we can transfer
1182      * due to the linked channel. The max bytes is 511 if 8-bit/frame or 1022 if 16-bit/frame
1183      */
1184     if (transfer->dataSize > DSPI_EDMA_MAX_TRANSFER_SIZE(base, (handle->bitsPerFrame)))
1185     {
1186         handle->state = (uint8_t)kDSPI_Idle;
1187         return kStatus_DSPI_OutOfRange;
1188     }
1189 
1190     /*The data size should be even if the bitsPerFrame is greater than 8 (that is 2 bytes per frame in dspi) */
1191     if ((0U != (transfer->dataSize & 0x1U)) && (handle->bitsPerFrame > 8U))
1192     {
1193         handle->state = (uint8_t)kDSPI_Idle;
1194         return kStatus_InvalidArgument;
1195     }
1196 
1197     EDMA_SetCallback(handle->edmaRxRegToRxDataHandle, EDMA_DspiSlaveCallback, &s_dspiSlaveEdmaPrivateHandle[instance]);
1198 
1199     /* Store transfer information */
1200     handle->txData                    = transfer->txData;
1201     handle->rxData                    = transfer->rxData;
1202     handle->remainingSendByteCount    = transfer->dataSize;
1203     handle->remainingReceiveByteCount = transfer->dataSize;
1204     handle->totalByteCount            = transfer->dataSize;
1205 
1206     uint32_t wordToSend    = 0;
1207     uint8_t dummyData      = DSPI_GetDummyDataInstance(base);
1208     uint8_t dataAlreadyFed = 0;
1209     uint8_t dataFedMax     = 2;
1210 
1211     uint32_t rxAddr = DSPI_GetRxRegisterAddress(base);
1212     uint32_t txAddr = DSPI_SlaveGetTxRegisterAddress(base);
1213 
1214     edma_transfer_config_t transferConfigA = {0};
1215     edma_transfer_config_t transferConfigC = {0};
1216 
1217     DSPI_StopTransfer(base);
1218 
1219     DSPI_FlushFifo(base, true, true);
1220     DSPI_ClearStatusFlags(base, (uint32_t)kDSPI_AllStatusFlag);
1221 
1222     DSPI_DisableDMA(base, (uint32_t)kDSPI_RxDmaEnable | (uint32_t)kDSPI_TxDmaEnable);
1223 
1224     DSPI_StartTransfer(base);
1225 
1226     /*if dspi has separate dma request , need not prepare data first .
1227     else (dspi has shared dma request) , send first 2 data into fifo if there is fifo or send first 1 data to
1228     slaveGetTxRegister if there is no fifo*/
1229     if (1 != FSL_FEATURE_DSPI_HAS_SEPARATE_DMA_RX_TX_REQn(base))
1230     {
1231         /* For DSPI instances with shared RX/TX DMA requests, we'll use the RX DMA request to
1232          * trigger ongoing transfers and will link to the TX DMA channel from the RX DMA channel.
1233          */
1234         /* If bits/frame is greater than one byte */
1235         if (handle->bitsPerFrame > 8U)
1236         {
1237             while ((uint32_t)kDSPI_TxFifoFillRequestFlag ==
1238                    (DSPI_GetStatusFlags(base) & (uint32_t)kDSPI_TxFifoFillRequestFlag))
1239             {
1240                 if (NULL != handle->txData)
1241                 {
1242                     wordToSend = *(handle->txData);
1243                     ++handle->txData; /* Increment to next data byte */
1244 
1245                     wordToSend |= (unsigned)(*(handle->txData)) << 8U;
1246                     ++handle->txData; /* Increment to next data byte */
1247                 }
1248                 else
1249                 {
1250                     wordToSend = ((uint32_t)dummyData << 8U) | dummyData;
1251                 }
1252                 handle->remainingSendByteCount -= 2U; /* decrement remainingSendByteCount by 2 */
1253                 base->PUSHR_SLAVE = wordToSend;
1254 
1255                 /* Try to clear the TFFF; if the TX FIFO is full this will clear */
1256                 DSPI_ClearStatusFlags(base, (uint32_t)kDSPI_TxFifoFillRequestFlag);
1257 
1258                 dataAlreadyFed += 2U;
1259 
1260                 /* Exit loop if send count is zero, else update local variables for next loop */
1261                 if ((handle->remainingSendByteCount == 0U) || (dataAlreadyFed == (dataFedMax * 2U)))
1262                 {
1263                     break;
1264                 }
1265             } /* End of TX FIFO fill while loop */
1266         }
1267         else /* Optimized for bits/frame less than or equal to one byte. */
1268         {
1269             while ((uint32_t)kDSPI_TxFifoFillRequestFlag ==
1270                    (DSPI_GetStatusFlags(base) & (uint32_t)kDSPI_TxFifoFillRequestFlag))
1271             {
1272                 if (NULL != handle->txData)
1273                 {
1274                     wordToSend = *(handle->txData);
1275                     /* Increment to next data word*/
1276                     ++handle->txData;
1277                 }
1278                 else
1279                 {
1280                     wordToSend = dummyData;
1281                 }
1282 
1283                 base->PUSHR_SLAVE = wordToSend;
1284 
1285                 /* Try to clear the TFFF; if the TX FIFO is full this will clear */
1286                 DSPI_ClearStatusFlags(base, (uint32_t)kDSPI_TxFifoFillRequestFlag);
1287                 /* Decrement remainingSendByteCount*/
1288                 --handle->remainingSendByteCount;
1289 
1290                 dataAlreadyFed++;
1291 
1292                 /* Exit loop if send count is zero, else update local variables for next loop */
1293                 if ((handle->remainingSendByteCount == 0U) || (dataAlreadyFed == dataFedMax))
1294                 {
1295                     break;
1296                 }
1297             } /* End of TX FIFO fill while loop */
1298         }
1299     }
1300 
1301     /***channel_A *** used for carry the data from Rx_Data_Register(POPR) to User_Receive_Buffer*/
1302     if (handle->remainingReceiveByteCount > 0U)
1303     {
1304         EDMA_ResetChannel(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel);
1305 
1306         transferConfigA.srcAddr   = (uint32_t)rxAddr;
1307         transferConfigA.srcOffset = 0;
1308 
1309         if (NULL != handle->rxData)
1310         {
1311             transferConfigA.destAddr   = (uint32_t) & (handle->rxData[0]);
1312             transferConfigA.destOffset = 1;
1313         }
1314         else
1315         {
1316             transferConfigA.destAddr   = (uint32_t) & (handle->rxBuffIfNull);
1317             transferConfigA.destOffset = 0;
1318         }
1319 
1320         transferConfigA.destTransferSize = kEDMA_TransferSize1Bytes;
1321 
1322         if (handle->bitsPerFrame <= 8U)
1323         {
1324             transferConfigA.srcTransferSize = kEDMA_TransferSize1Bytes;
1325             transferConfigA.minorLoopBytes  = 1;
1326             transferConfigA.majorLoopCounts = handle->remainingReceiveByteCount;
1327         }
1328         else
1329         {
1330             transferConfigA.srcTransferSize = kEDMA_TransferSize2Bytes;
1331             transferConfigA.minorLoopBytes  = 2;
1332             transferConfigA.majorLoopCounts = handle->remainingReceiveByteCount / 2U;
1333         }
1334 
1335         /* Store the initially configured eDMA minor byte transfer count into the DSPI handle */
1336         handle->nbytes = (uint8_t)(transferConfigA.minorLoopBytes);
1337 
1338         EDMA_SetTransferConfig(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel,
1339                                (const edma_transfer_config_t *)(uint32_t)&transferConfigA, NULL);
1340         EDMA_EnableChannelInterrupts(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel,
1341                                      (uint32_t)kEDMA_MajorInterruptEnable);
1342     }
1343 
1344     if (handle->remainingSendByteCount > 0U)
1345     {
1346         /***channel_C *** used for carry the data from User_Send_Buffer to Tx_Data_Register(PUSHR_SLAVE)*/
1347         EDMA_ResetChannel(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel);
1348 
1349         transferConfigC.destAddr   = (uint32_t)txAddr;
1350         transferConfigC.destOffset = 0;
1351 
1352         if (NULL != handle->txData)
1353         {
1354             transferConfigC.srcAddr   = (uint32_t)(&(handle->txData[0]));
1355             transferConfigC.srcOffset = 1;
1356         }
1357         else
1358         {
1359             transferConfigC.srcAddr   = (uint32_t)(&handle->txBuffIfNull);
1360             transferConfigC.srcOffset = 0;
1361             if (handle->bitsPerFrame <= 8U)
1362             {
1363                 handle->txBuffIfNull = dummyData;
1364             }
1365             else
1366             {
1367                 handle->txBuffIfNull = ((uint32_t)dummyData << 8U) | dummyData;
1368             }
1369         }
1370 
1371         transferConfigC.srcTransferSize = kEDMA_TransferSize1Bytes;
1372 
1373         if (handle->bitsPerFrame <= 8U)
1374         {
1375             transferConfigC.destTransferSize = kEDMA_TransferSize1Bytes;
1376             transferConfigC.minorLoopBytes   = 1;
1377             transferConfigC.majorLoopCounts  = handle->remainingSendByteCount;
1378         }
1379         else
1380         {
1381             transferConfigC.destTransferSize = kEDMA_TransferSize2Bytes;
1382             transferConfigC.minorLoopBytes   = 2;
1383             transferConfigC.majorLoopCounts  = handle->remainingSendByteCount / 2U;
1384         }
1385 
1386         EDMA_SetTransferConfig(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel,
1387                                (const edma_transfer_config_t *)(uint32_t)&transferConfigC, NULL);
1388 
1389         EDMA_StartTransfer(handle->edmaTxDataToTxRegHandle);
1390     }
1391 
1392     EDMA_StartTransfer(handle->edmaRxRegToRxDataHandle);
1393 
1394     /*Set channel priority*/
1395     uint8_t channelPriorityLow  = handle->edmaRxRegToRxDataHandle->channel;
1396     uint8_t channelPriorityHigh = handle->edmaTxDataToTxRegHandle->channel;
1397     uint8_t t                   = 0;
1398 
1399     if (channelPriorityLow > channelPriorityHigh)
1400     {
1401         t                   = channelPriorityLow;
1402         channelPriorityLow  = channelPriorityHigh;
1403         channelPriorityHigh = t;
1404     }
1405 
1406     edma_channel_Preemption_config_t preemption_config_t;
1407     preemption_config_t.enableChannelPreemption = true;
1408     preemption_config_t.enablePreemptAbility    = true;
1409     preemption_config_t.channelPriority         = channelPriorityLow;
1410 
1411     if (1 != FSL_FEATURE_DSPI_HAS_SEPARATE_DMA_RX_TX_REQn(base))
1412     {
1413         EDMA_SetChannelPreemptionConfig(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel,
1414                                         (const edma_channel_Preemption_config_t *)(uint32_t)&preemption_config_t);
1415 
1416         preemption_config_t.channelPriority = channelPriorityHigh;
1417         EDMA_SetChannelPreemptionConfig(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel,
1418                                         (const edma_channel_Preemption_config_t *)(uint32_t)&preemption_config_t);
1419     }
1420     else
1421     {
1422         EDMA_SetChannelPreemptionConfig(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel,
1423                                         (const edma_channel_Preemption_config_t *)(uint32_t)&preemption_config_t);
1424 
1425         preemption_config_t.channelPriority = channelPriorityHigh;
1426         EDMA_SetChannelPreemptionConfig(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel,
1427                                         (const edma_channel_Preemption_config_t *)(uint32_t)&preemption_config_t);
1428     }
1429 
1430     /*Set the channel link.
1431     For DSPI instances with shared RX/TX DMA requests: Rx DMA request -> channel_A -> channel_C.
1432     For DSPI instances with separate RX and TX DMA requests:
1433     Rx DMA request -> channel_A
1434     Tx DMA request -> channel_C */
1435     if (1 != FSL_FEATURE_DSPI_HAS_SEPARATE_DMA_RX_TX_REQn(base))
1436     {
1437         if (handle->remainingSendByteCount > 0U)
1438         {
1439             EDMA_SetChannelLink(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel,
1440                                 kEDMA_MinorLink, handle->edmaTxDataToTxRegHandle->channel);
1441         }
1442         DSPI_EnableDMA(base, (uint32_t)kDSPI_RxDmaEnable);
1443     }
1444     else
1445     {
1446         DSPI_EnableDMA(base, (uint32_t)kDSPI_RxDmaEnable | (uint32_t)kDSPI_TxDmaEnable);
1447     }
1448 
1449     return kStatus_Success;
1450 }
1451 
EDMA_DspiSlaveCallback(edma_handle_t * edmaHandle,void * g_dspiEdmaPrivateHandle,bool transferDone,uint32_t tcds)1452 static void EDMA_DspiSlaveCallback(edma_handle_t *edmaHandle,
1453                                    void *g_dspiEdmaPrivateHandle,
1454                                    bool transferDone,
1455                                    uint32_t tcds)
1456 {
1457     assert(NULL != edmaHandle);
1458     assert(NULL != g_dspiEdmaPrivateHandle);
1459 
1460     dspi_slave_edma_private_handle_t *dspiEdmaPrivateHandle;
1461 
1462     dspiEdmaPrivateHandle = (dspi_slave_edma_private_handle_t *)g_dspiEdmaPrivateHandle;
1463 
1464     DSPI_DisableDMA((dspiEdmaPrivateHandle->base), (uint32_t)kDSPI_RxDmaEnable | (uint32_t)kDSPI_TxDmaEnable);
1465 
1466     dspiEdmaPrivateHandle->handle->state = (uint8_t)kDSPI_Idle;
1467 
1468     if (NULL != dspiEdmaPrivateHandle->handle->callback)
1469     {
1470         dspiEdmaPrivateHandle->handle->callback(dspiEdmaPrivateHandle->base, dspiEdmaPrivateHandle->handle,
1471                                                 kStatus_Success, dspiEdmaPrivateHandle->handle->userData);
1472     }
1473 }
1474 
1475 /*!
1476  * brief DSPI slave aborts a transfer which is using eDMA.
1477  *
1478  * This function aborts a transfer which is using eDMA.
1479  *
1480  * param base DSPI peripheral base address.
1481  * param handle A pointer to the dspi_slave_edma_handle_t structure which stores the transfer state.
1482  */
DSPI_SlaveTransferAbortEDMA(SPI_Type * base,dspi_slave_edma_handle_t * handle)1483 void DSPI_SlaveTransferAbortEDMA(SPI_Type *base, dspi_slave_edma_handle_t *handle)
1484 {
1485     assert(NULL != handle);
1486 
1487     DSPI_StopTransfer(base);
1488 
1489     DSPI_DisableDMA(base, (uint32_t)kDSPI_RxDmaEnable | (uint32_t)kDSPI_TxDmaEnable);
1490 
1491     EDMA_AbortTransfer(handle->edmaRxRegToRxDataHandle);
1492     EDMA_AbortTransfer(handle->edmaTxDataToTxRegHandle);
1493 
1494     handle->state = (uint8_t)kDSPI_Idle;
1495 }
1496 
1497 /*!
1498  * brief Gets the slave eDMA transfer count.
1499  *
1500  * This function gets the slave eDMA transfer count.
1501  *
1502  * param base DSPI peripheral base address.
1503  * param handle A pointer to the dspi_slave_edma_handle_t structure which stores the transfer state.
1504  * param count A number of bytes transferred so far by the non-blocking transaction.
1505  * return status of status_t.
1506  */
DSPI_SlaveTransferGetCountEDMA(SPI_Type * base,dspi_slave_edma_handle_t * handle,size_t * count)1507 status_t DSPI_SlaveTransferGetCountEDMA(SPI_Type *base, dspi_slave_edma_handle_t *handle, size_t *count)
1508 {
1509     assert(NULL != handle);
1510 
1511     if (NULL == count)
1512     {
1513         return kStatus_InvalidArgument;
1514     }
1515 
1516     /* Catch when there is not an active transfer. */
1517     if (handle->state != (uint8_t)kDSPI_Busy)
1518     {
1519         *count = 0;
1520         return kStatus_NoTransferInProgress;
1521     }
1522 
1523     size_t bytes;
1524 
1525     bytes = (uint32_t)handle->nbytes * EDMA_GetRemainingMajorLoopCount(handle->edmaRxRegToRxDataHandle->base,
1526                                                                        handle->edmaRxRegToRxDataHandle->channel);
1527 
1528     *count = handle->totalByteCount - bytes;
1529 
1530     return kStatus_Success;
1531 }
1532