1 /*
2  * Copyright (c) 2016, Freescale Semiconductor, Inc.
3  * Copyright 2016-2020 NXP
4  * All rights reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include "fsl_spi_dma.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.flexcomm_spi_dma"
18 #endif
19 
20 /*<! Structure definition for spi_dma_private_handle_t. The structure is private. */
21 typedef struct _spi_dma_private_handle
22 {
23     SPI_Type *base;
24     spi_dma_handle_t *handle;
25 } spi_dma_private_handle_t;
26 
27 /*! @brief SPI transfer state, which is used for SPI transactiaonl APIs' internal state. */
28 enum _spi_dma_states_t
29 {
30     kSPI_Idle = 0x0, /*!< SPI is idle state */
31     kSPI_Busy        /*!< SPI is busy tranferring data. */
32 };
33 
34 typedef struct _spi_dma_txdummy
35 {
36     uint32_t lastWord;
37     uint32_t word;
38 } spi_dma_txdummy_t;
39 
40 static spi_dma_private_handle_t s_dmaPrivateHandle[FSL_FEATURE_SOC_SPI_COUNT];
41 /*******************************************************************************
42  * Prototypes
43  ******************************************************************************/
44 
45 /*!
46  * @brief DMA callback function for SPI send transfer.
47  *
48  * @param handle DMA handle pointer.
49  * @param userData User data for DMA callback function.
50  */
51 static void SPI_TxDMACallback(dma_handle_t *handle, void *userData, bool transferDone, uint32_t intmode);
52 
53 /*!
54  * @brief DMA callback function for SPI receive transfer.
55  *
56  * @param handle DMA handle pointer.
57  * @param userData User data for DMA callback function.
58  */
59 static void SPI_RxDMACallback(dma_handle_t *handle, void *userData, bool transferDone, uint32_t intmode);
60 
61 /*******************************************************************************
62  * Variables
63  ******************************************************************************/
64 #if defined(__ICCARM__)
65 #pragma data_alignment                                        = 4
66 static spi_dma_txdummy_t s_txDummy[FSL_FEATURE_SOC_SPI_COUNT] = {0};
67 #elif defined(__CC_ARM) || defined(__ARMCC_VERSION)
68 __attribute__((aligned(4))) static spi_dma_txdummy_t s_txDummy[FSL_FEATURE_SOC_SPI_COUNT] = {0};
69 #elif defined(__GNUC__)
70 __attribute__((aligned(4))) static spi_dma_txdummy_t s_txDummy[FSL_FEATURE_SOC_SPI_COUNT] = {0};
71 #endif
72 
73 #if defined(__ICCARM__)
74 #pragma data_alignment = 4
75 static uint16_t s_rxDummy;
76 static uint32_t s_txLastWord[FSL_FEATURE_SOC_SPI_COUNT];
77 #elif defined(__CC_ARM) || defined(__ARMCC_VERSION)
78 __attribute__((aligned(4))) static uint16_t s_rxDummy;
79 __attribute__((aligned(4))) static uint32_t s_txLastWord[FSL_FEATURE_SOC_SPI_COUNT];
80 #elif defined(__GNUC__)
81 __attribute__((aligned(4))) static uint16_t s_rxDummy;
82 __attribute__((aligned(4))) static uint32_t s_txLastWord[FSL_FEATURE_SOC_SPI_COUNT];
83 #endif
84 
85 #if defined(__ICCARM__)
86 #pragma data_alignment                                                    = 16
87 static dma_descriptor_t s_spi_descriptor_table[FSL_FEATURE_SOC_SPI_COUNT] = {0};
88 #elif defined(__CC_ARM) || defined(__ARMCC_VERSION)
89 __attribute__((aligned(16))) static dma_descriptor_t s_spi_descriptor_table[FSL_FEATURE_SOC_SPI_COUNT] = {0};
90 #elif defined(__GNUC__)
91 __attribute__((aligned(16))) static dma_descriptor_t s_spi_descriptor_table[FSL_FEATURE_SOC_SPI_COUNT] = {0};
92 #endif
93 
94 /*******************************************************************************
95  * Code
96  ******************************************************************************/
97 
XferToFifoWR(spi_transfer_t * xfer,uint32_t * fifowr)98 static void XferToFifoWR(spi_transfer_t *xfer, uint32_t *fifowr)
99 {
100     *fifowr |= ((xfer->configFlags & (uint32_t)kSPI_FrameDelay) != 0U) ? (uint32_t)kSPI_FrameDelay : 0U;
101     *fifowr |= ((xfer->configFlags & (uint32_t)kSPI_FrameAssert) != 0U) ? (uint32_t)kSPI_FrameAssert : 0U;
102 }
103 
SpiConfigToFifoWR(spi_config_t * config,uint32_t * fifowr)104 static void SpiConfigToFifoWR(spi_config_t *config, uint32_t *fifowr)
105 {
106     *fifowr |= ((uint32_t)SPI_DEASSERT_ALL & (~(uint32_t)SPI_DEASSERTNUM_SSEL((uint32_t)config->sselNum)));
107     /* set width of data - range asserted at entry */
108     *fifowr |= SPI_FIFOWR_LEN(config->dataWidth);
109 }
110 
PrepareTxLastWord(spi_transfer_t * xfer,uint32_t * txLastWord,spi_config_t * config)111 static void PrepareTxLastWord(spi_transfer_t *xfer, uint32_t *txLastWord, spi_config_t *config)
112 {
113     if (config->dataWidth > kSPI_Data8Bits)
114     {
115         *txLastWord = (((uint32_t)xfer->txData[xfer->dataSize - 1U] << 8U) | (xfer->txData[xfer->dataSize - 2U]));
116     }
117     else
118     {
119         *txLastWord = xfer->txData[xfer->dataSize - 1U];
120     }
121     XferToFifoWR(xfer, txLastWord);
122     SpiConfigToFifoWR(config, txLastWord);
123 }
124 
SPI_SetupDummy(SPI_Type * base,spi_dma_txdummy_t * dummy,spi_transfer_t * xfer,spi_config_t * spi_config_p)125 static void SPI_SetupDummy(SPI_Type *base, spi_dma_txdummy_t *dummy, spi_transfer_t *xfer, spi_config_t *spi_config_p)
126 {
127     uint32_t instance  = SPI_GetInstance(base);
128     uint32_t dummydata = (uint32_t)s_dummyData[instance];
129     dummydata |= (uint32_t)s_dummyData[instance] << 8U;
130 
131     dummy->word     = dummydata;
132     dummy->lastWord = dummydata;
133 
134     XferToFifoWR(xfer, &dummy->word);
135     XferToFifoWR(xfer, &dummy->lastWord);
136     SpiConfigToFifoWR(spi_config_p, &dummy->word);
137     SpiConfigToFifoWR(spi_config_p, &dummy->lastWord);
138     /* Clear the end of transfer bit for continue word transfer. */
139     dummy->word &= (~(uint32_t)kSPI_FrameAssert);
140 }
141 
142 /*!
143  * brief Initialize the SPI master DMA handle.
144  *
145  * This function initializes the SPI master DMA handle which can be used for other SPI master transactional APIs.
146  * Usually, for a specified SPI instance, user need only call this API once to get the initialized handle.
147  *
148  * param base SPI peripheral base address.
149  * param handle SPI handle pointer.
150  * param callback User callback function called at the end of a transfer.
151  * param userData User data for callback.
152  * param txHandle DMA handle pointer for SPI Tx, the handle shall be static allocated by users.
153  * param rxHandle DMA handle pointer for SPI Rx, the handle shall be static allocated by users.
154  */
SPI_MasterTransferCreateHandleDMA(SPI_Type * base,spi_dma_handle_t * handle,spi_dma_callback_t callback,void * userData,dma_handle_t * txHandle,dma_handle_t * rxHandle)155 status_t SPI_MasterTransferCreateHandleDMA(SPI_Type *base,
156                                            spi_dma_handle_t *handle,
157                                            spi_dma_callback_t callback,
158                                            void *userData,
159                                            dma_handle_t *txHandle,
160                                            dma_handle_t *rxHandle)
161 {
162     uint32_t instance;
163 
164     /* check 'base' */
165     assert(!(NULL == base));
166     if (NULL == base)
167     {
168         return kStatus_InvalidArgument;
169     }
170     /* check 'handle' */
171     assert(!(NULL == handle));
172     if (NULL == handle)
173     {
174         return kStatus_InvalidArgument;
175     }
176 
177     instance = SPI_GetInstance(base);
178 
179     (void)memset(handle, 0, sizeof(*handle));
180     /* Set spi base to handle */
181     handle->txHandle           = txHandle;
182     handle->rxHandle           = rxHandle;
183     handle->callback           = callback;
184     handle->userData           = userData;
185     handle->instance           = instance;
186     handle->dataBytesEveryTime = DMA_MAX_TRANSFER_COUNT;
187 
188     /* Set SPI state to idle */
189     handle->state = (uint8_t)kSPI_Idle;
190 
191     /* Set handle to global state */
192     s_dmaPrivateHandle[instance].base   = base;
193     s_dmaPrivateHandle[instance].handle = handle;
194 
195     /* Install callback for Tx dma channel */
196     DMA_SetCallback(handle->txHandle, SPI_TxDMACallback, &s_dmaPrivateHandle[instance]);
197     DMA_SetCallback(handle->rxHandle, SPI_RxDMACallback, &s_dmaPrivateHandle[instance]);
198 
199     return kStatus_Success;
200 }
201 
202 /*!
203  * brief Perform a non-blocking SPI transfer using DMA.
204  *
205  * note This interface returned immediately after transfer initiates, users should call
206  * SPI_GetTransferStatus to poll the transfer status to check whether SPI transfer finished.
207  *
208  * param base SPI peripheral base address.
209  * param handle SPI DMA handle pointer.
210  * param xfer Pointer to dma transfer structure.
211  * retval kStatus_Success Successfully start a transfer.
212  * retval kStatus_InvalidArgument Input argument is invalid.
213  * retval kStatus_SPI_Busy SPI is not idle, is running another transfer.
214  */
SPI_MasterTransferDMA(SPI_Type * base,spi_dma_handle_t * handle,spi_transfer_t * xfer)215 status_t SPI_MasterTransferDMA(SPI_Type *base, spi_dma_handle_t *handle, spi_transfer_t *xfer)
216 {
217     assert(!((NULL == handle) || (NULL == xfer)));
218 
219     uint32_t instance;
220     status_t result = kStatus_Success;
221     spi_config_t *spi_config_p;
222     uint32_t address;
223     void *nextDesc                   = NULL;
224     uint32_t firstTimeSize           = 0;
225     dma_transfer_config_t xferConfig = {0};
226     spi_config_p                     = (spi_config_t *)SPI_GetConfig(base);
227     bool firstTimeIntFlag            = false;
228     bool lastTimeIntFlag             = false;
229     uint8_t bytesPerFrame =
230         (uint8_t)((spi_config_p->dataWidth > kSPI_Data8Bits) ? (sizeof(uint16_t)) : (sizeof(uint8_t)));
231     handle->bytesPerFrame = bytesPerFrame;
232     uint8_t lastwordBytes = 0U;
233 
234     if ((xfer->configFlags & (uint32_t)kSPI_FrameAssert) != 0U)
235     {
236         handle->lastwordBytes = bytesPerFrame;
237         lastwordBytes         = bytesPerFrame;
238     }
239     else
240     {
241         handle->lastwordBytes = 0U;
242         lastwordBytes         = 0U;
243     }
244 
245     if ((NULL == handle) || (NULL == xfer))
246     {
247         return kStatus_InvalidArgument;
248     }
249 
250     /* Byte size is zero. */
251     if (xfer->dataSize == 0U)
252     {
253         return kStatus_InvalidArgument;
254     }
255     /* cannot get instance from base address */
256     instance = SPI_GetInstance(base);
257 
258     /* Check if the device is busy */
259     if (handle->state == (uint8_t)kSPI_Busy)
260     {
261         return kStatus_SPI_Busy;
262     }
263     else
264     {
265         /* Set the dma unit by dataSize */
266         if (xfer->dataSize <= bytesPerFrame)
267         {
268             nextDesc         = NULL;
269             firstTimeSize    = xfer->dataSize;
270             firstTimeIntFlag = false;
271             lastTimeIntFlag  = true;
272         }
273         else if (xfer->dataSize - lastwordBytes <= handle->dataBytesEveryTime)
274         {
275             firstTimeSize = xfer->dataSize - lastwordBytes;
276             if (lastwordBytes != 0U)
277             {
278                 firstTimeIntFlag = false;
279                 lastTimeIntFlag  = false;
280                 nextDesc         = &s_spi_descriptor_table[instance];
281             }
282             else
283             {
284                 nextDesc         = NULL;
285                 firstTimeIntFlag = true;
286             }
287         }
288         else
289         {
290             firstTimeSize    = handle->dataBytesEveryTime;
291             nextDesc         = NULL;
292             firstTimeIntFlag = true;
293             lastTimeIntFlag  = false;
294         }
295 
296         /* Clear FIFOs before transfer. */
297         base->FIFOCFG |= SPI_FIFOCFG_EMPTYTX_MASK | SPI_FIFOCFG_EMPTYRX_MASK;
298         base->FIFOSTAT |= SPI_FIFOSTAT_TXERR_MASK | SPI_FIFOSTAT_RXERR_MASK;
299 
300         handle->state        = (uint8_t)kSPI_Busy;
301         handle->transferSize = xfer->dataSize;
302 
303         /* receive */
304         SPI_EnableRxDMA(base, true);
305         address = (uint32_t)&base->FIFORD;
306         if (xfer->rxData != NULL)
307         {
308             handle->rxEndData = xfer->rxData + xfer->dataSize;
309             DMA_PrepareTransfer(&xferConfig, (uint32_t *)address, xfer->rxData, bytesPerFrame, firstTimeSize,
310                                 kDMA_PeripheralToMemory, NULL);
311             handle->rxNextData = xfer->rxData + firstTimeSize;
312         }
313         else
314         {
315             DMA_PrepareTransfer(&xferConfig, (uint32_t *)address, &s_rxDummy,
316                                 ((spi_config_p->dataWidth > kSPI_Data8Bits) ? (sizeof(uint16_t)) : (sizeof(uint8_t))),
317                                 xfer->dataSize, kDMA_StaticToStatic, NULL);
318         }
319         (void)DMA_SubmitTransfer(handle->rxHandle, &xferConfig);
320         handle->rxInProgress = true;
321         DMA_StartTransfer(handle->rxHandle);
322 
323         /* transmit */
324         SPI_EnableTxDMA(base, true);
325         address = (uint32_t)&base->FIFOWR;
326         if (xfer->txData != NULL)
327         {
328             handle->txEndData  = xfer->txData + xfer->dataSize;
329             handle->txNextData = xfer->txData + firstTimeSize;
330             if ((xfer->configFlags & (uint32_t)kSPI_FrameAssert) != 0U)
331             {
332                 PrepareTxLastWord(xfer, &s_txLastWord[instance], spi_config_p);
333             }
334             /* If end of tranfer function is enabled and data transfer frame is bigger then 1, use dma
335              * descriptor to send the last data.
336              */
337             if (((xfer->configFlags & (uint32_t)kSPI_FrameAssert) != 0U) &&
338                 ((spi_config_p->dataWidth > kSPI_Data8Bits) ? (xfer->dataSize > 2U) : (xfer->dataSize > 1U)))
339             {
340                 dma_xfercfg_t tmp_xfercfg;
341                 tmp_xfercfg.valid         = true;
342                 tmp_xfercfg.swtrig        = true;
343                 tmp_xfercfg.intA          = false;
344                 tmp_xfercfg.byteWidth     = 4U;
345                 tmp_xfercfg.srcInc        = 0;
346                 tmp_xfercfg.dstInc        = 0;
347                 tmp_xfercfg.transferCount = 1U;
348                 tmp_xfercfg.reload        = false;
349                 tmp_xfercfg.clrtrig       = false;
350                 tmp_xfercfg.intB          = true;
351                 /* Create chained descriptor to transmit last word */
352                 DMA_CreateDescriptor(&s_spi_descriptor_table[instance], &tmp_xfercfg, &s_txLastWord[instance],
353                                      (uint32_t *)address, NULL);
354             }
355             DMA_PrepareTransfer(&xferConfig, (void *)xfer->txData, (uint32_t *)address, bytesPerFrame, firstTimeSize,
356                                 kDMA_MemoryToPeripheral, nextDesc);
357 
358             /* Disable interrupts for first descriptor to avoid calling callback twice. */
359             xferConfig.xfercfg.intA = firstTimeIntFlag;
360             xferConfig.xfercfg.intB = lastTimeIntFlag;
361             result                  = DMA_SubmitTransfer(handle->txHandle, &xferConfig);
362             if (result != kStatus_Success)
363             {
364                 return result;
365             }
366         }
367         else
368         {
369             /* Setup tx dummy data. */
370             SPI_SetupDummy(base, &s_txDummy[instance], xfer, spi_config_p);
371             if (((xfer->configFlags & (uint32_t)kSPI_FrameAssert) != 0U) &&
372                 ((spi_config_p->dataWidth > kSPI_Data8Bits) ? (xfer->dataSize > 2U) : (xfer->dataSize > 1U)))
373             {
374                 dma_xfercfg_t tmp_xfercfg;
375                 tmp_xfercfg.valid         = true;
376                 tmp_xfercfg.swtrig        = true;
377                 tmp_xfercfg.intA          = true;
378                 tmp_xfercfg.byteWidth     = (uint8_t)sizeof(uint32_t);
379                 tmp_xfercfg.srcInc        = 0;
380                 tmp_xfercfg.dstInc        = 0;
381                 tmp_xfercfg.transferCount = 1;
382                 tmp_xfercfg.reload        = false;
383                 tmp_xfercfg.clrtrig       = false;
384                 tmp_xfercfg.intB          = false;
385                 /* Create chained descriptor to transmit last word */
386                 DMA_CreateDescriptor(&s_spi_descriptor_table[instance], &tmp_xfercfg, &s_txDummy[instance].lastWord,
387                                      (uint32_t *)address, NULL);
388                 /* Use common API to setup first descriptor */
389                 DMA_PrepareTransfer(
390                     &xferConfig, &s_txDummy[instance].word, (uint32_t *)address,
391                     ((spi_config_p->dataWidth > kSPI_Data8Bits) ? (sizeof(uint16_t)) : (sizeof(uint8_t))),
392                     ((spi_config_p->dataWidth > kSPI_Data8Bits) ? (xfer->dataSize - 2U) : (xfer->dataSize - 1U)),
393                     kDMA_StaticToStatic, &s_spi_descriptor_table[instance]);
394                 /* Disable interrupts for first descriptor to avoid calling callback twice */
395                 xferConfig.xfercfg.intA = false;
396                 xferConfig.xfercfg.intB = false;
397                 result                  = DMA_SubmitTransfer(handle->txHandle, &xferConfig);
398                 if (result != kStatus_Success)
399                 {
400                     return result;
401                 }
402             }
403             else
404             {
405                 DMA_PrepareTransfer(
406                     &xferConfig, &s_txDummy[instance].word, (uint32_t *)address,
407                     ((spi_config_p->dataWidth > kSPI_Data8Bits) ? (sizeof(uint16_t)) : (sizeof(uint8_t))),
408                     xfer->dataSize, kDMA_StaticToStatic, NULL);
409                 result = DMA_SubmitTransfer(handle->txHandle, &xferConfig);
410                 if (result != kStatus_Success)
411                 {
412                     return result;
413                 }
414             }
415         }
416 
417         handle->txInProgress  = true;
418         uint32_t tmpData      = 0U;
419         uint32_t writeAddress = (uint32_t) & (base->FIFOWR) + 2UL;
420         XferToFifoWR(xfer, &tmpData);
421         SpiConfigToFifoWR(spi_config_p, &tmpData);
422 
423         /* Setup the control info.
424          * Halfword writes to just the control bits (offset 0xE22) doesn't push anything into the FIFO.
425          * And the data access type of control bits must be uint16_t, byte writes or halfword writes to FIFOWR
426          * will push the data and the current control bits into the FIFO.
427          */
428         if (((xfer->configFlags & (uint32_t)kSPI_FrameAssert) != 0U) &&
429             ((spi_config_p->dataWidth > kSPI_Data8Bits) ? (xfer->dataSize == 2U) : (xfer->dataSize == 1U)))
430         {
431             *(uint16_t *)writeAddress = (uint16_t)(tmpData >> 16U);
432         }
433         else
434         {
435             /* Clear the SPI_FIFOWR_EOT_MASK bit when data is not the last. */
436             tmpData &= (~(uint32_t)kSPI_FrameAssert);
437             *(uint16_t *)writeAddress = (uint16_t)(tmpData >> 16U);
438         }
439 
440         DMA_StartTransfer(handle->txHandle);
441     }
442 
443     return result;
444 }
445 
446 /*!
447  * brief Transfers a block of data using a DMA method.
448  *
449  * This function using polling way to do the first half transimission and using DMA way to
450  * do the srcond half transimission, the transfer mechanism is half-duplex.
451  * When do the second half transimission, code will return right away. When all data is transferred,
452  * the callback function is called.
453  *
454  * param base SPI base pointer
455  * param handle A pointer to the spi_master_dma_handle_t structure which stores the transfer state.
456  * param transfer A pointer to the spi_half_duplex_transfer_t structure.
457  * return status of status_t.
458  */
SPI_MasterHalfDuplexTransferDMA(SPI_Type * base,spi_dma_handle_t * handle,spi_half_duplex_transfer_t * xfer)459 status_t SPI_MasterHalfDuplexTransferDMA(SPI_Type *base, spi_dma_handle_t *handle, spi_half_duplex_transfer_t *xfer)
460 {
461     assert((xfer != NULL) && (handle != NULL));
462     spi_transfer_t tempXfer = {0};
463     status_t status;
464 
465     if (xfer->isTransmitFirst)
466     {
467         tempXfer.txData   = xfer->txData;
468         tempXfer.rxData   = NULL;
469         tempXfer.dataSize = xfer->txDataSize;
470     }
471     else
472     {
473         tempXfer.txData   = NULL;
474         tempXfer.rxData   = xfer->rxData;
475         tempXfer.dataSize = xfer->rxDataSize;
476     }
477     /* If the pcs pin keep assert between transmit and receive. */
478     if (xfer->isPcsAssertInTransfer)
479     {
480         tempXfer.configFlags = (xfer->configFlags) & (~(uint32_t)kSPI_FrameAssert);
481     }
482     else
483     {
484         tempXfer.configFlags = (xfer->configFlags) | (uint32_t)kSPI_FrameAssert;
485     }
486 
487     status = SPI_MasterTransferBlocking(base, &tempXfer);
488     if (status != kStatus_Success)
489     {
490         return status;
491     }
492 
493     if (xfer->isTransmitFirst)
494     {
495         tempXfer.txData   = NULL;
496         tempXfer.rxData   = xfer->rxData;
497         tempXfer.dataSize = xfer->rxDataSize;
498     }
499     else
500     {
501         tempXfer.txData   = xfer->txData;
502         tempXfer.rxData   = NULL;
503         tempXfer.dataSize = xfer->txDataSize;
504     }
505     tempXfer.configFlags = xfer->configFlags;
506 
507     status = SPI_MasterTransferDMA(base, handle, &tempXfer);
508 
509     return status;
510 }
511 
SPI_RxDMACallback(dma_handle_t * handle,void * userData,bool transferDone,uint32_t intmode)512 static void SPI_RxDMACallback(dma_handle_t *handle, void *userData, bool transferDone, uint32_t intmode)
513 {
514     spi_dma_private_handle_t *privHandle = (spi_dma_private_handle_t *)userData;
515     spi_dma_handle_t *spiHandle          = privHandle->handle;
516     SPI_Type *base                       = privHandle->base;
517     status_t result                      = kStatus_Success;
518     uint8_t bytesPerFrame                = spiHandle->bytesPerFrame;
519     uint32_t nextDataSize                = 0;
520     uint32_t address                     = (uint32_t)&base->FIFORD;
521 
522     if (spiHandle->rxNextData >= spiHandle->rxEndData)
523     {
524         /* change the state */
525         spiHandle->rxInProgress = false;
526         /* All finished, call the callback */
527         if ((spiHandle->txInProgress == false) && (spiHandle->rxInProgress == false))
528         {
529             spiHandle->state = (uint8_t)kSPI_Idle;
530             if (spiHandle->callback != NULL)
531             {
532                 (spiHandle->callback)(base, spiHandle, kStatus_Success, spiHandle->userData);
533             }
534         }
535     }
536     else
537     {
538         /* need transmit by DMA again */
539         if (spiHandle->rxEndData <= (spiHandle->dataBytesEveryTime + spiHandle->rxNextData))
540         {
541             nextDataSize = (uint32_t)((uint32_t)spiHandle->rxEndData - (uint32_t)spiHandle->rxNextData);
542         }
543         else if (spiHandle->rxEndData > (spiHandle->dataBytesEveryTime + spiHandle->rxNextData))
544         {
545             nextDataSize = spiHandle->dataBytesEveryTime;
546         }
547         else
548         {
549             /* MISRA 15.7*/
550         }
551         dma_transfer_config_t xferConfig = {0};
552         DMA_PrepareTransfer(&xferConfig, (uint32_t *)(address), (uint8_t *)spiHandle->rxNextData, bytesPerFrame,
553                             nextDataSize, kDMA_PeripheralToMemory, NULL);
554         spiHandle->rxNextData = (uint8_t *)(spiHandle->rxNextData + nextDataSize);
555         result                = DMA_SubmitTransfer(spiHandle->rxHandle, &xferConfig);
556         if (result != kStatus_Success)
557         {
558             return;
559         }
560         DMA_StartTransfer(spiHandle->rxHandle);
561     }
562 }
563 
SPI_TxDMACallback(dma_handle_t * handle,void * userData,bool transferDone,uint32_t intmode)564 static void SPI_TxDMACallback(dma_handle_t *handle, void *userData, bool transferDone, uint32_t intmode)
565 {
566     spi_dma_private_handle_t *privHandle = (spi_dma_private_handle_t *)userData;
567     spi_dma_handle_t *spiHandle          = privHandle->handle;
568     SPI_Type *base                       = privHandle->base;
569     status_t result                      = kStatus_Success;
570     uint32_t instance                    = spiHandle->instance;
571     bool thisTimeIntFlag                 = false;
572     uint8_t bytesPerFrame                = spiHandle->bytesPerFrame;
573     void *nextDesc                       = NULL;
574     uint32_t nextDataSize                = 0U;
575     uint8_t lastwordBytes                = spiHandle->lastwordBytes;
576     uint32_t writeAddress                = (uint32_t) & (base->FIFOWR);
577     if (spiHandle->txNextData + lastwordBytes >= spiHandle->txEndData)
578     {
579         spiHandle->txInProgress = false;
580         if ((spiHandle->txInProgress == false) && (spiHandle->rxInProgress == false))
581         {
582             spiHandle->state = (uint8_t)kSPI_Idle;
583             if (spiHandle->callback != NULL)
584             {
585                 (spiHandle->callback)(base, spiHandle, kStatus_Success, spiHandle->userData);
586             }
587         }
588     }
589     else
590     {
591         if ((uint32_t)((uint32_t)(spiHandle->txEndData)) <=
592             (spiHandle->dataBytesEveryTime + lastwordBytes + (uint32_t)spiHandle->txNextData))
593         {
594             if (lastwordBytes != 0U)
595             {
596                 nextDesc        = &s_spi_descriptor_table[instance];
597                 thisTimeIntFlag = false;
598             }
599             else
600             {
601                 thisTimeIntFlag = true;
602             }
603             nextDataSize = (uint32_t)((uint32_t)spiHandle->txEndData - (uint32_t)spiHandle->txNextData - lastwordBytes);
604         }
605         else if ((uint32_t)(spiHandle->txEndData) >
606                  (spiHandle->dataBytesEveryTime + lastwordBytes + (uint32_t)spiHandle->txNextData))
607         {
608             nextDesc        = NULL;
609             nextDataSize    = spiHandle->dataBytesEveryTime;
610             thisTimeIntFlag = true;
611         }
612         else
613         {
614             /* MISRA 15.7*/
615         }
616         dma_transfer_config_t xferConfig = {0};
617         DMA_PrepareTransfer(&xferConfig, (uint8_t *)spiHandle->txNextData, (uint32_t *)(writeAddress), bytesPerFrame,
618                             nextDataSize, kDMA_MemoryToPeripheral, nextDesc);
619         spiHandle->txNextData   = (uint8_t *)(spiHandle->txNextData + nextDataSize);
620         xferConfig.xfercfg.intA = thisTimeIntFlag;
621         xferConfig.xfercfg.intB = false;
622         result                  = DMA_SubmitTransfer(spiHandle->txHandle, &xferConfig);
623         if (result != kStatus_Success)
624         {
625             return;
626         }
627         DMA_StartTransfer(spiHandle->txHandle);
628     }
629 }
630 
631 /*!
632  * brief Abort a SPI transfer using DMA.
633  *
634  * param base SPI peripheral base address.
635  * param handle SPI DMA handle pointer.
636  */
SPI_MasterTransferAbortDMA(SPI_Type * base,spi_dma_handle_t * handle)637 void SPI_MasterTransferAbortDMA(SPI_Type *base, spi_dma_handle_t *handle)
638 {
639     assert(NULL != handle);
640 
641     /* Stop tx transfer first */
642     DMA_AbortTransfer(handle->txHandle);
643     /* Then rx transfer */
644     DMA_AbortTransfer(handle->rxHandle);
645 
646     /* Set the handle state */
647     handle->txInProgress = false;
648     handle->rxInProgress = false;
649     handle->state        = (uint8_t)kSPI_Idle;
650 }
651 
652 /*!
653  * brief Gets the master DMA transfer remaining bytes.
654  *
655  * This function gets the master DMA transfer remaining bytes.
656  *
657  * param base SPI peripheral base address.
658  * param handle A pointer to the spi_dma_handle_t structure which stores the transfer state.
659  * param count A number of bytes transferred by the non-blocking transaction.
660  * return status of status_t.
661  */
SPI_MasterTransferGetCountDMA(SPI_Type * base,spi_dma_handle_t * handle,size_t * count)662 status_t SPI_MasterTransferGetCountDMA(SPI_Type *base, spi_dma_handle_t *handle, size_t *count)
663 {
664     assert(handle != NULL);
665 
666     if (NULL == count)
667     {
668         return kStatus_InvalidArgument;
669     }
670 
671     /* Catch when there is not an active transfer. */
672     if (handle->state != (uint8_t)kSPI_Busy)
673     {
674         *count = 0;
675         return kStatus_NoTransferInProgress;
676     }
677 
678     size_t bytes;
679 
680     bytes = DMA_GetRemainingBytes(handle->rxHandle->base, handle->rxHandle->channel);
681 
682     *count = handle->transferSize - bytes;
683 
684     return kStatus_Success;
685 }
686