1 /*
2  * Copyright (c) 2015, 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_lpspi_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.lpspi_edma"
18 #endif
19 
20 /*!
21  * @brief Structure definition for dspi_master_edma_private_handle_t. The structure is private.
22  */
23 typedef struct _lpspi_master_edma_private_handle
24 {
25     LPSPI_Type *base;                   /*!< LPSPI peripheral base address. */
26     lpspi_master_edma_handle_t *handle; /*!< lpspi_master_edma_handle_t handle */
27 } lpspi_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 _lpspi_slave_edma_private_handle
33 {
34     LPSPI_Type *base;                  /*!< LPSPI peripheral base address. */
35     lpspi_slave_edma_handle_t *handle; /*!< lpspi_slave_edma_handle_t handle */
36 } lpspi_slave_edma_private_handle_t;
37 
38 /***********************************************************************************************************************
39  * Prototypes
40  ***********************************************************************************************************************/
41 
42 /*!
43  * @brief EDMA_LpspiMasterCallback after the LPSPI master transfer completed by using EDMA.
44  * This is not a public API.
45  */
46 static void EDMA_LpspiMasterCallback(edma_handle_t *edmaHandle,
47                                      void *g_lpspiEdmaPrivateHandle,
48                                      bool transferDone,
49                                      uint32_t tcds);
50 
51 /*!
52  * @brief EDMA_LpspiSlaveCallback after the LPSPI slave transfer completed by using EDMA.
53  * This is not a public API.
54  */
55 static void EDMA_LpspiSlaveCallback(edma_handle_t *edmaHandle,
56                                     void *g_lpspiEdmaPrivateHandle,
57                                     bool transferDone,
58                                     uint32_t tcds);
59 
60 static void LPSPI_SeparateEdmaReadData(uint8_t *rxData, uint32_t readData, uint32_t bytesEachRead, bool isByteSwap);
61 
62 /***********************************************************************************************************************
63  * Variables
64  ***********************************************************************************************************************/
65 /*! @brief Pointers to lpspi bases for each instance. */
66 static LPSPI_Type *const s_lpspiBases[] = LPSPI_BASE_PTRS;
67 
68 /*! @brief Pointers to lpspi edma handles for each instance. */
69 static lpspi_master_edma_private_handle_t s_lpspiMasterEdmaPrivateHandle[ARRAY_SIZE(s_lpspiBases)];
70 static lpspi_slave_edma_private_handle_t s_lpspiSlaveEdmaPrivateHandle[ARRAY_SIZE(s_lpspiBases)];
71 
72 /***********************************************************************************************************************
73  * Code
74  ***********************************************************************************************************************/
LPSPI_SeparateEdmaReadData(uint8_t * rxData,uint32_t readData,uint32_t bytesEachRead,bool isByteSwap)75 static void LPSPI_SeparateEdmaReadData(uint8_t *rxData, uint32_t readData, uint32_t bytesEachRead, bool isByteSwap)
76 {
77     assert(rxData != NULL);
78 
79     switch (bytesEachRead)
80     {
81         case 1:
82             if (!isByteSwap)
83             {
84                 *rxData = (uint8_t)readData;
85                 ++rxData;
86             }
87             else
88             {
89                 *rxData = (uint8_t)(readData >> 24);
90                 ++rxData;
91             }
92             break;
93 
94         case 2:
95             if (!isByteSwap)
96             {
97                 *rxData = (uint8_t)readData;
98                 ++rxData;
99                 *rxData = (uint8_t)(readData >> 8);
100                 ++rxData;
101             }
102             else
103             {
104                 *rxData = (uint8_t)(readData >> 16);
105                 ++rxData;
106                 *rxData = (uint8_t)(readData >> 24);
107                 ++rxData;
108             }
109             break;
110 
111         case 4:
112 
113             *rxData = (uint8_t)readData;
114             ++rxData;
115             *rxData = (uint8_t)(readData >> 8);
116             ++rxData;
117             *rxData = (uint8_t)(readData >> 16);
118             ++rxData;
119             *rxData = (uint8_t)(readData >> 24);
120             ++rxData;
121 
122             break;
123 
124         default:
125             assert(false);
126             break;
127     }
128 }
129 
130 /*!
131  * brief Initializes the LPSPI master eDMA handle.
132  *
133  * This function initializes the LPSPI eDMA handle which can be used for other LPSPI transactional APIs.  Usually, for a
134  * specified LPSPI instance, call this API once to get the initialized handle.
135  *
136  * Note that the LPSPI eDMA has a separated (Rx and Rx as two sources) or shared (Rx  and Tx are the same source) DMA
137  * request source.
138  * (1) For a separated DMA request source, enable and set the Rx DMAMUX source for edmaRxRegToRxDataHandle and
139  * Tx DMAMUX source for edmaIntermediaryToTxRegHandle.
140  * (2) For a shared DMA request source, enable and set the Rx/Rx DMAMUX source for edmaRxRegToRxDataHandle.
141  *
142  * param base LPSPI peripheral base address.
143  * param handle LPSPI handle pointer to lpspi_master_edma_handle_t.
144  * param callback LPSPI callback.
145  * param userData callback function parameter.
146  * param edmaRxRegToRxDataHandle edmaRxRegToRxDataHandle pointer to edma_handle_t.
147  * param edmaTxDataToTxRegHandle edmaTxDataToTxRegHandle pointer to edma_handle_t.
148  */
LPSPI_MasterTransferCreateHandleEDMA(LPSPI_Type * base,lpspi_master_edma_handle_t * handle,lpspi_master_edma_transfer_callback_t callback,void * userData,edma_handle_t * edmaRxRegToRxDataHandle,edma_handle_t * edmaTxDataToTxRegHandle)149 void LPSPI_MasterTransferCreateHandleEDMA(LPSPI_Type *base,
150                                           lpspi_master_edma_handle_t *handle,
151                                           lpspi_master_edma_transfer_callback_t callback,
152                                           void *userData,
153                                           edma_handle_t *edmaRxRegToRxDataHandle,
154                                           edma_handle_t *edmaTxDataToTxRegHandle)
155 {
156     assert(handle != NULL);
157     assert(edmaRxRegToRxDataHandle != NULL);
158     assert(edmaTxDataToTxRegHandle != NULL);
159 
160     /* Zero the handle. */
161     (void)memset(handle, 0, sizeof(*handle));
162 
163     uint32_t instance = LPSPI_GetInstance(base);
164 
165     s_lpspiMasterEdmaPrivateHandle[instance].base   = base;
166     s_lpspiMasterEdmaPrivateHandle[instance].handle = handle;
167 
168     handle->callback = callback;
169     handle->userData = userData;
170 
171     handle->edmaRxRegToRxDataHandle = edmaRxRegToRxDataHandle;
172     handle->edmaTxDataToTxRegHandle = edmaTxDataToTxRegHandle;
173 }
174 
LPSPI_PrepareTransferEDMA(LPSPI_Type * base)175 static void LPSPI_PrepareTransferEDMA(LPSPI_Type *base)
176 {
177     /* Flush FIFO, clear status, disable all the inerrupts and DMA requests. */
178     LPSPI_FlushFifo(base, true, true);
179     LPSPI_ClearStatusFlags(base, (uint32_t)kLPSPI_AllStatusFlag);
180     LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_AllInterruptEnable);
181     LPSPI_DisableDMA(base, (uint32_t)kLPSPI_RxDmaEnable | (uint32_t)kLPSPI_TxDmaEnable);
182 }
183 
184 /*!
185  * brief LPSPI master transfer data using eDMA.
186  *
187  * This function transfers data using eDMA. This is a non-blocking function, which returns right away. When all data
188  * is transferred, the callback function is called.
189  *
190  * Note:
191  * The transfer data size should be an integer multiple of bytesPerFrame if bytesPerFrame is less than or equal to 4.
192  * For bytesPerFrame greater than 4:
193  * The transfer data size should be equal to bytesPerFrame if the bytesPerFrame is not an integer multiple of 4.
194  * Otherwise, the transfer data size can be an integer multiple of bytesPerFrame.
195  *
196  * param base LPSPI peripheral base address.
197  * param handle pointer to lpspi_master_edma_handle_t structure which stores the transfer state.
198  * param transfer pointer to lpspi_transfer_t structure.
199  * return status of status_t.
200  */
LPSPI_MasterTransferEDMA(LPSPI_Type * base,lpspi_master_edma_handle_t * handle,lpspi_transfer_t * transfer)201 status_t LPSPI_MasterTransferEDMA(LPSPI_Type *base, lpspi_master_edma_handle_t *handle, lpspi_transfer_t *transfer)
202 {
203     assert(handle != NULL);
204     assert(transfer != NULL);
205 
206     /* Check that we're not busy.*/
207     if (handle->state == (uint8_t)kLPSPI_Busy)
208     {
209         return kStatus_LPSPI_Busy;
210     }
211 
212     /* Disable module before configuration */
213     LPSPI_Enable(base, false);
214     /* Check arguements */
215     if (!LPSPI_CheckTransferArgument(base, transfer, true))
216     {
217         return kStatus_InvalidArgument;
218     }
219 
220     LPSPI_PrepareTransferEDMA(base);
221 
222     /* Variables */
223     bool isThereExtraTxBytes = false;
224     bool isByteSwap          = ((transfer->configFlags & (uint32_t)kLPSPI_MasterByteSwap) != 0U);
225     bool isPcsContinuous     = ((transfer->configFlags & (uint32_t)kLPSPI_MasterPcsContinuous) != 0U);
226     uint32_t instance        = LPSPI_GetInstance(base);
227     uint8_t dummyData        = g_lpspiDummyData[instance];
228     uint8_t bytesLastWrite   = 0;
229     /*Used for byte swap*/
230     uint32_t addrOffset    = 0;
231     uint32_t rxAddr        = LPSPI_GetRxRegisterAddress(base);
232     uint32_t txAddr        = LPSPI_GetTxRegisterAddress(base);
233     uint32_t whichPcs      = (transfer->configFlags & LPSPI_MASTER_PCS_MASK) >> LPSPI_MASTER_PCS_SHIFT;
234     uint32_t bytesPerFrame = ((base->TCR & LPSPI_TCR_FRAMESZ_MASK) >> LPSPI_TCR_FRAMESZ_SHIFT) / 8U + 1U;
235     edma_transfer_config_t transferConfigRx;
236     edma_transfer_config_t transferConfigTx;
237     edma_tcd_t *softwareTCD_pcsContinuous = (edma_tcd_t *)((uint32_t)(&handle->lpspiSoftwareTCD[2]) & (~0x1FU));
238     edma_tcd_t *softwareTCD_extraBytes    = (edma_tcd_t *)((uint32_t)(&handle->lpspiSoftwareTCD[1]) & (~0x1FU));
239 
240     handle->state                  = (uint8_t)kLPSPI_Busy;
241     handle->txData                 = transfer->txData;
242     handle->rxData                 = transfer->rxData;
243     handle->txRemainingByteCount   = transfer->dataSize;
244     handle->rxRemainingByteCount   = transfer->dataSize;
245     handle->totalByteCount         = transfer->dataSize;
246     handle->writeRegRemainingTimes = (transfer->dataSize / bytesPerFrame) * ((bytesPerFrame + 3U) / 4U);
247     handle->readRegRemainingTimes  = handle->writeRegRemainingTimes;
248     handle->txBuffIfNull =
249         ((uint32_t)dummyData) | ((uint32_t)dummyData << 8) | ((uint32_t)dummyData << 16) | ((uint32_t)dummyData << 24);
250     /*The TX and RX FIFO sizes are always the same*/
251     handle->fifoSize            = LPSPI_GetRxFifoSize(base);
252     handle->isPcsContinuous     = isPcsContinuous;
253     handle->isByteSwap          = isByteSwap;
254     handle->isThereExtraRxBytes = false;
255 
256     /*Because DMA is fast enough , so set the RX and TX watermarks to 0 .*/
257     LPSPI_SetFifoWatermarks(base, 0U, 0U);
258 
259     /* Transfers will stall when transmit FIFO is empty or receive FIFO is full. */
260     base->CFGR1 &= (~LPSPI_CFGR1_NOSTALL_MASK);
261 
262     /* Enable module for following configuration of TCR to take effect. */
263     LPSPI_Enable(base, true);
264 
265     /* For DMA transfer , we'd better not masked the transmit data and receive data in TCR since the transfer flow is
266      * hard to controlled by software. */
267     base->TCR = (base->TCR & ~(LPSPI_TCR_CONT_MASK | LPSPI_TCR_CONTC_MASK | LPSPI_TCR_BYSW_MASK | LPSPI_TCR_PCS_MASK)) |
268                 LPSPI_TCR_CONT(isPcsContinuous) | LPSPI_TCR_BYSW(isByteSwap) | LPSPI_TCR_PCS(whichPcs);
269 
270     /*Calculate the bytes for write/read the TX/RX register each time*/
271     if (bytesPerFrame <= 4U)
272     {
273         handle->bytesEachWrite = (uint8_t)bytesPerFrame;
274         handle->bytesEachRead  = (uint8_t)bytesPerFrame;
275 
276         handle->bytesLastRead = (uint8_t)bytesPerFrame;
277     }
278     else
279     {
280         handle->bytesEachWrite = 4U;
281         handle->bytesEachRead  = 4U;
282 
283         handle->bytesLastRead = 4U;
284 
285         if ((transfer->dataSize % 4U) != 0U)
286         {
287             bytesLastWrite        = (uint8_t)(transfer->dataSize % 4U);
288             handle->bytesLastRead = bytesLastWrite;
289 
290             isThereExtraTxBytes = true;
291 
292             --handle->writeRegRemainingTimes;
293 
294             --handle->readRegRemainingTimes;
295             handle->isThereExtraRxBytes = true;
296         }
297     }
298 
299     EDMA_SetCallback(handle->edmaRxRegToRxDataHandle, EDMA_LpspiMasterCallback,
300                      &s_lpspiMasterEdmaPrivateHandle[instance]);
301 
302     /* Configure rx EDMA transfer */
303     EDMA_ResetChannel(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel);
304 
305     if (handle->rxData != NULL)
306     {
307         transferConfigRx.destAddr   = (uint32_t) & (handle->rxData[0]);
308         transferConfigRx.destOffset = 1;
309     }
310     else
311     {
312         transferConfigRx.destAddr   = (uint32_t) & (handle->rxBuffIfNull);
313         transferConfigRx.destOffset = 0;
314     }
315     transferConfigRx.destTransferSize = kEDMA_TransferSize1Bytes;
316 
317     addrOffset = 0;
318     switch (handle->bytesEachRead)
319     {
320         case (1U):
321             transferConfigRx.srcTransferSize = kEDMA_TransferSize1Bytes;
322             transferConfigRx.minorLoopBytes  = 1;
323             if (handle->isByteSwap)
324             {
325                 addrOffset = 3;
326             }
327             break;
328 
329         case (2U):
330             transferConfigRx.srcTransferSize = kEDMA_TransferSize2Bytes;
331             transferConfigRx.minorLoopBytes  = 2;
332             if (handle->isByteSwap)
333             {
334                 addrOffset = 2;
335             }
336             break;
337 
338         case (4U):
339             transferConfigRx.srcTransferSize = kEDMA_TransferSize4Bytes;
340             transferConfigRx.minorLoopBytes  = 4;
341             break;
342 
343         default:
344             transferConfigRx.srcTransferSize = kEDMA_TransferSize1Bytes;
345             transferConfigRx.minorLoopBytes  = 1;
346             assert(false);
347             break;
348     }
349 
350     transferConfigRx.srcAddr   = (uint32_t)rxAddr + addrOffset;
351     transferConfigRx.srcOffset = 0;
352 
353     transferConfigRx.majorLoopCounts = handle->readRegRemainingTimes;
354 
355     /* Store the initially configured eDMA minor byte transfer count into the LPSPI handle */
356     handle->nbytes = (uint8_t)transferConfigRx.minorLoopBytes;
357 
358     EDMA_SetTransferConfig(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel,
359                            &transferConfigRx, NULL);
360     EDMA_EnableChannelInterrupts(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel,
361                                  (uint32_t)kEDMA_MajorInterruptEnable);
362 
363     /* Configure tx EDMA transfer */
364     EDMA_ResetChannel(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel);
365 
366     if (isThereExtraTxBytes)
367     {
368         if (handle->txData != NULL)
369         {
370             transferConfigTx.srcAddr   = (uint32_t) & (transfer->txData[transfer->dataSize - bytesLastWrite]);
371             transferConfigTx.srcOffset = 1;
372         }
373         else
374         {
375             transferConfigTx.srcAddr   = (uint32_t)(&handle->txBuffIfNull);
376             transferConfigTx.srcOffset = 0;
377         }
378 
379         transferConfigTx.destOffset = 0;
380 
381         transferConfigTx.srcTransferSize = kEDMA_TransferSize1Bytes;
382 
383         addrOffset = 0;
384         switch (bytesLastWrite)
385         {
386             case (1U):
387                 transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes;
388                 transferConfigTx.minorLoopBytes   = 1;
389                 if (handle->isByteSwap)
390                 {
391                     addrOffset = 3;
392                 }
393                 break;
394 
395             case (2U):
396                 transferConfigTx.destTransferSize = kEDMA_TransferSize2Bytes;
397                 transferConfigTx.minorLoopBytes   = 2;
398                 if (handle->isByteSwap)
399                 {
400                     addrOffset = 2;
401                 }
402                 break;
403 
404             default:
405                 transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes;
406                 transferConfigTx.minorLoopBytes   = 1;
407                 assert(false);
408                 break;
409         }
410 
411         transferConfigTx.destAddr        = (uint32_t)txAddr + addrOffset;
412         transferConfigTx.majorLoopCounts = 1;
413 
414         EDMA_TcdReset(softwareTCD_extraBytes);
415 
416         if (handle->isPcsContinuous)
417         {
418             EDMA_TcdSetTransferConfig(softwareTCD_extraBytes, &transferConfigTx, softwareTCD_pcsContinuous);
419         }
420         else
421         {
422             EDMA_TcdSetTransferConfig(softwareTCD_extraBytes, &transferConfigTx, NULL);
423         }
424     }
425 
426     if (handle->isPcsContinuous)
427     {
428         handle->transmitCommand = base->TCR & ~(LPSPI_TCR_CONTC_MASK | LPSPI_TCR_CONT_MASK);
429 
430         transferConfigTx.srcAddr   = (uint32_t) & (handle->transmitCommand);
431         transferConfigTx.srcOffset = 0;
432 
433         transferConfigTx.destAddr   = (uint32_t) & (base->TCR);
434         transferConfigTx.destOffset = 0;
435 
436         transferConfigTx.srcTransferSize  = kEDMA_TransferSize4Bytes;
437         transferConfigTx.destTransferSize = kEDMA_TransferSize4Bytes;
438         transferConfigTx.minorLoopBytes   = 4;
439         transferConfigTx.majorLoopCounts  = 1;
440 
441         EDMA_TcdReset(softwareTCD_pcsContinuous);
442         EDMA_TcdSetTransferConfig(softwareTCD_pcsContinuous, &transferConfigTx, NULL);
443     }
444 
445     if (handle->txData != NULL)
446     {
447         transferConfigTx.srcAddr   = (uint32_t)(handle->txData);
448         transferConfigTx.srcOffset = 1;
449     }
450     else
451     {
452         transferConfigTx.srcAddr   = (uint32_t)(&handle->txBuffIfNull);
453         transferConfigTx.srcOffset = 0;
454     }
455 
456     transferConfigTx.destOffset = 0;
457 
458     transferConfigTx.srcTransferSize = kEDMA_TransferSize1Bytes;
459 
460     addrOffset = 0U;
461     switch (handle->bytesEachRead)
462     {
463         case (1U):
464             transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes;
465             transferConfigTx.minorLoopBytes   = 1;
466             if (handle->isByteSwap)
467             {
468                 addrOffset = 3;
469             }
470             break;
471 
472         case (2U):
473             transferConfigTx.destTransferSize = kEDMA_TransferSize2Bytes;
474             transferConfigTx.minorLoopBytes   = 2;
475 
476             if (handle->isByteSwap)
477             {
478                 addrOffset = 2;
479             }
480             break;
481 
482         case (4U):
483             transferConfigTx.destTransferSize = kEDMA_TransferSize4Bytes;
484             transferConfigTx.minorLoopBytes   = 4;
485             break;
486 
487         default:
488             transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes;
489             transferConfigTx.minorLoopBytes   = 1;
490             assert(false);
491             break;
492     }
493 
494     transferConfigTx.destAddr = (uint32_t)txAddr + addrOffset;
495 
496     transferConfigTx.majorLoopCounts = handle->writeRegRemainingTimes;
497 
498     if (isThereExtraTxBytes)
499     {
500         EDMA_SetTransferConfig(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel,
501                                &transferConfigTx, softwareTCD_extraBytes);
502     }
503     else if (handle->isPcsContinuous)
504     {
505         EDMA_SetTransferConfig(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel,
506                                &transferConfigTx, softwareTCD_pcsContinuous);
507     }
508     else
509     {
510         EDMA_SetTransferConfig(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel,
511                                &transferConfigTx, NULL);
512     }
513 
514     EDMA_StartTransfer(handle->edmaTxDataToTxRegHandle);
515     EDMA_StartTransfer(handle->edmaRxRegToRxDataHandle);
516     LPSPI_EnableDMA(base, (uint32_t)kLPSPI_RxDmaEnable | (uint32_t)kLPSPI_TxDmaEnable);
517 
518     return kStatus_Success;
519 }
520 
EDMA_LpspiMasterCallback(edma_handle_t * edmaHandle,void * g_lpspiEdmaPrivateHandle,bool transferDone,uint32_t tcds)521 static void EDMA_LpspiMasterCallback(edma_handle_t *edmaHandle,
522                                      void *g_lpspiEdmaPrivateHandle,
523                                      bool transferDone,
524                                      uint32_t tcds)
525 {
526     assert(edmaHandle != NULL);
527     assert(g_lpspiEdmaPrivateHandle != NULL);
528 
529     uint32_t readData;
530 
531     lpspi_master_edma_private_handle_t *lpspiEdmaPrivateHandle;
532 
533     lpspiEdmaPrivateHandle = (lpspi_master_edma_private_handle_t *)g_lpspiEdmaPrivateHandle;
534 
535     size_t rxRemainingByteCount = lpspiEdmaPrivateHandle->handle->rxRemainingByteCount;
536     uint8_t bytesLastRead       = lpspiEdmaPrivateHandle->handle->bytesLastRead;
537     bool isByteSwap             = lpspiEdmaPrivateHandle->handle->isByteSwap;
538 
539     LPSPI_DisableDMA(lpspiEdmaPrivateHandle->base, (uint32_t)kLPSPI_TxDmaEnable | (uint32_t)kLPSPI_RxDmaEnable);
540 
541     if (lpspiEdmaPrivateHandle->handle->isThereExtraRxBytes)
542     {
543         while (LPSPI_GetRxFifoCount(lpspiEdmaPrivateHandle->base) == 0U)
544         {
545         }
546         readData = LPSPI_ReadData(lpspiEdmaPrivateHandle->base);
547 
548         if (lpspiEdmaPrivateHandle->handle->rxData != NULL)
549         {
550             LPSPI_SeparateEdmaReadData(&(lpspiEdmaPrivateHandle->handle->rxData[rxRemainingByteCount - bytesLastRead]),
551                                        readData, bytesLastRead, isByteSwap);
552         }
553     }
554 
555     lpspiEdmaPrivateHandle->handle->state = (uint8_t)kLPSPI_Idle;
556 
557     if (lpspiEdmaPrivateHandle->handle->callback != NULL)
558     {
559         lpspiEdmaPrivateHandle->handle->callback(lpspiEdmaPrivateHandle->base, lpspiEdmaPrivateHandle->handle,
560                                                  kStatus_Success, lpspiEdmaPrivateHandle->handle->userData);
561     }
562 }
563 
564 /*!
565  * brief LPSPI master aborts a transfer which is using eDMA.
566  *
567  * This function aborts a transfer which is using eDMA.
568  *
569  * param base LPSPI peripheral base address.
570  * param handle pointer to lpspi_master_edma_handle_t structure which stores the transfer state.
571  */
LPSPI_MasterTransferAbortEDMA(LPSPI_Type * base,lpspi_master_edma_handle_t * handle)572 void LPSPI_MasterTransferAbortEDMA(LPSPI_Type *base, lpspi_master_edma_handle_t *handle)
573 {
574     assert(handle != NULL);
575 
576     LPSPI_DisableDMA(base, (uint32_t)kLPSPI_RxDmaEnable | (uint32_t)kLPSPI_TxDmaEnable);
577 
578     EDMA_AbortTransfer(handle->edmaRxRegToRxDataHandle);
579     EDMA_AbortTransfer(handle->edmaTxDataToTxRegHandle);
580 
581     handle->state = (uint8_t)kLPSPI_Idle;
582 }
583 
584 /*!
585  * brief Gets the master eDMA transfer remaining bytes.
586  *
587  * This function gets the master eDMA transfer remaining bytes.
588  *
589  * param base LPSPI peripheral base address.
590  * param handle pointer to lpspi_master_edma_handle_t structure which stores the transfer state.
591  * param count Number of bytes transferred so far by the EDMA transaction.
592  * return status of status_t.
593  */
LPSPI_MasterTransferGetCountEDMA(LPSPI_Type * base,lpspi_master_edma_handle_t * handle,size_t * count)594 status_t LPSPI_MasterTransferGetCountEDMA(LPSPI_Type *base, lpspi_master_edma_handle_t *handle, size_t *count)
595 {
596     assert(handle != NULL);
597 
598     if (NULL == count)
599     {
600         return kStatus_InvalidArgument;
601     }
602 
603     /* Catch when there is not an active transfer. */
604     if (handle->state != (uint8_t)kLPSPI_Busy)
605     {
606         *count = 0;
607         return kStatus_NoTransferInProgress;
608     }
609 
610     size_t remainingByte;
611 
612     remainingByte =
613         (uint32_t)handle->nbytes * EDMA_GetRemainingMajorLoopCount(handle->edmaRxRegToRxDataHandle->base,
614                                                                    handle->edmaRxRegToRxDataHandle->channel);
615 
616     *count = handle->totalByteCount - remainingByte;
617 
618     return kStatus_Success;
619 }
620 
621 /*!
622  * brief Initializes the LPSPI slave eDMA handle.
623  *
624  * This function initializes the LPSPI eDMA handle which can be used for other LPSPI transactional APIs.  Usually, for a
625  * specified LPSPI instance, call this API once to get the initialized handle.
626  *
627  * Note that LPSPI eDMA has a separated (Rx and Tx as two sources) or shared (Rx  and Tx as the same source) DMA request
628  * source.
629  *
630  * (1) For a separated DMA request source, enable and set the Rx DMAMUX source for edmaRxRegToRxDataHandle and
631  * Tx DMAMUX source for edmaTxDataToTxRegHandle.
632  * (2) For a shared DMA request source, enable and set the Rx/Rx DMAMUX source for edmaRxRegToRxDataHandle .
633  *
634  * param base LPSPI peripheral base address.
635  * param handle LPSPI handle pointer to lpspi_slave_edma_handle_t.
636  * param callback LPSPI callback.
637  * param userData callback function parameter.
638  * param edmaRxRegToRxDataHandle edmaRxRegToRxDataHandle pointer to edma_handle_t.
639  * param edmaTxDataToTxRegHandle edmaTxDataToTxRegHandle pointer to edma_handle_t.
640  */
LPSPI_SlaveTransferCreateHandleEDMA(LPSPI_Type * base,lpspi_slave_edma_handle_t * handle,lpspi_slave_edma_transfer_callback_t callback,void * userData,edma_handle_t * edmaRxRegToRxDataHandle,edma_handle_t * edmaTxDataToTxRegHandle)641 void LPSPI_SlaveTransferCreateHandleEDMA(LPSPI_Type *base,
642                                          lpspi_slave_edma_handle_t *handle,
643                                          lpspi_slave_edma_transfer_callback_t callback,
644                                          void *userData,
645                                          edma_handle_t *edmaRxRegToRxDataHandle,
646                                          edma_handle_t *edmaTxDataToTxRegHandle)
647 {
648     assert(handle != NULL);
649     assert(edmaRxRegToRxDataHandle != NULL);
650     assert(edmaTxDataToTxRegHandle != NULL);
651 
652     /* Zero the handle. */
653     (void)memset(handle, 0, sizeof(*handle));
654 
655     uint32_t instance = LPSPI_GetInstance(base);
656 
657     s_lpspiSlaveEdmaPrivateHandle[instance].base   = base;
658     s_lpspiSlaveEdmaPrivateHandle[instance].handle = handle;
659 
660     handle->callback = callback;
661     handle->userData = userData;
662 
663     handle->edmaRxRegToRxDataHandle = edmaRxRegToRxDataHandle;
664     handle->edmaTxDataToTxRegHandle = edmaTxDataToTxRegHandle;
665 }
666 
667 /*!
668  * brief LPSPI slave transfers data using eDMA.
669  *
670  * This function transfers data using eDMA. This is a non-blocking function, which return right away. When all data
671  * is transferred, the callback function is called.
672  *
673  * Note:
674  * The transfer data size should be an integer multiple of bytesPerFrame if bytesPerFrame is less than or equal to 4.
675  * For bytesPerFrame greater than 4:
676  * The transfer data size should be equal to bytesPerFrame if the bytesPerFrame is not an integer multiple of 4.
677  * Otherwise, the transfer data size can be an integer multiple of bytesPerFrame.
678  *
679  * param base LPSPI peripheral base address.
680  * param handle pointer to lpspi_slave_edma_handle_t structure which stores the transfer state.
681  * param transfer pointer to lpspi_transfer_t structure.
682  * return status of status_t.
683  */
LPSPI_SlaveTransferEDMA(LPSPI_Type * base,lpspi_slave_edma_handle_t * handle,lpspi_transfer_t * transfer)684 status_t LPSPI_SlaveTransferEDMA(LPSPI_Type *base, lpspi_slave_edma_handle_t *handle, lpspi_transfer_t *transfer)
685 {
686     assert(handle != NULL);
687     assert(transfer != NULL);
688 
689     /* Check that we're not busy.*/
690     if (handle->state == (uint8_t)kLPSPI_Busy)
691     {
692         return kStatus_LPSPI_Busy;
693     }
694     /* Disable module before configuration. */
695     LPSPI_Enable(base, false);
696     /* Check arguements, also dma transfer can not support 3 bytes */
697     if (!LPSPI_CheckTransferArgument(base, transfer, true))
698     {
699         return kStatus_InvalidArgument;
700     }
701 
702     LPSPI_PrepareTransferEDMA(base);
703 
704     /* Variables */
705     bool isThereExtraTxBytes = false;
706     bool isByteSwap          = ((transfer->configFlags & (uint32_t)kLPSPI_MasterByteSwap) != 0U);
707     uint8_t bytesLastWrite   = 0;
708     uint8_t dummyData        = g_lpspiDummyData[LPSPI_GetInstance(base)];
709     uint32_t mask            = (uint32_t)kLPSPI_RxDmaEnable;
710 
711     /* Used for byte swap */
712     uint32_t addrOffset    = 0;
713     uint32_t instance      = LPSPI_GetInstance(base);
714     uint32_t rxAddr        = LPSPI_GetRxRegisterAddress(base);
715     uint32_t txAddr        = LPSPI_GetTxRegisterAddress(base);
716     uint32_t whichPcs      = (transfer->configFlags & LPSPI_MASTER_PCS_MASK) >> LPSPI_MASTER_PCS_SHIFT;
717     uint32_t bytesPerFrame = ((base->TCR & LPSPI_TCR_FRAMESZ_MASK) >> LPSPI_TCR_FRAMESZ_SHIFT) / 8U + 1U;
718     edma_transfer_config_t transferConfigRx;
719     edma_transfer_config_t transferConfigTx;
720     edma_tcd_t *softwareTCD_extraBytes = (edma_tcd_t *)((uint32_t)(&handle->lpspiSoftwareTCD[1]) & (~0x1FU));
721 
722     /* Assign the original value for members of transfer handle. */
723     handle->state                  = (uint8_t)kLPSPI_Busy;
724     handle->txData                 = transfer->txData;
725     handle->rxData                 = transfer->rxData;
726     handle->txRemainingByteCount   = transfer->dataSize;
727     handle->rxRemainingByteCount   = transfer->dataSize;
728     handle->totalByteCount         = transfer->dataSize;
729     handle->writeRegRemainingTimes = (transfer->dataSize / bytesPerFrame) * ((bytesPerFrame + 3U) / 4U);
730     handle->readRegRemainingTimes  = handle->writeRegRemainingTimes;
731     handle->txBuffIfNull =
732         ((uint32_t)dummyData) | ((uint32_t)dummyData << 8) | ((uint32_t)dummyData << 16) | ((uint32_t)dummyData << 24);
733     /*The TX and RX FIFO sizes are always the same*/
734     handle->fifoSize            = LPSPI_GetRxFifoSize(base);
735     handle->isByteSwap          = isByteSwap;
736     handle->isThereExtraRxBytes = false;
737 
738     /* Because DMA is fast enough, set the RX and TX watermarks to 0. */
739     LPSPI_SetFifoWatermarks(base, 0U, 0U);
740 
741     /* Transfers will stall when transmit FIFO is empty or receive FIFO is full. */
742     base->CFGR1 &= (~LPSPI_CFGR1_NOSTALL_MASK);
743 
744     /* Enable module for following configuration of TCR to take effect. */
745     LPSPI_Enable(base, true);
746 
747     /* For DMA transfer, mask the transmit data if the tx data is null, for rx the receive data should not be masked at
748        any time since we use rx dma transfer finish cllback to indicate transfer finish. */
749     base->TCR =
750         (base->TCR & ~(LPSPI_TCR_CONT_MASK | LPSPI_TCR_CONTC_MASK | LPSPI_TCR_BYSW_MASK | LPSPI_TCR_TXMSK_MASK)) |
751         LPSPI_TCR_TXMSK(transfer->txData == NULL) | LPSPI_TCR_BYSW(isByteSwap) | LPSPI_TCR_PCS(whichPcs);
752 
753     /*Calculate the bytes for write/read the TX/RX register each time*/
754     if (bytesPerFrame <= 4U)
755     {
756         handle->bytesEachWrite = (uint8_t)bytesPerFrame;
757         handle->bytesEachRead  = (uint8_t)bytesPerFrame;
758 
759         handle->bytesLastRead = (uint8_t)bytesPerFrame;
760     }
761     else
762     {
763         handle->bytesEachWrite = 4U;
764         handle->bytesEachRead  = 4U;
765 
766         handle->bytesLastRead = 4U;
767 
768         if ((transfer->dataSize % 4U) != 0U)
769         {
770             bytesLastWrite        = (uint8_t)(transfer->dataSize % 4U);
771             handle->bytesLastRead = bytesLastWrite;
772 
773             isThereExtraTxBytes = true;
774             --handle->writeRegRemainingTimes;
775 
776             handle->isThereExtraRxBytes = true;
777             --handle->readRegRemainingTimes;
778         }
779     }
780 
781     EDMA_SetCallback(handle->edmaRxRegToRxDataHandle, EDMA_LpspiSlaveCallback,
782                      &s_lpspiSlaveEdmaPrivateHandle[instance]);
783 
784     /*Rx*/
785     if (handle->readRegRemainingTimes > 0U)
786     {
787         EDMA_ResetChannel(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel);
788 
789         if (handle->rxData != NULL)
790         {
791             transferConfigRx.destAddr   = (uint32_t) & (handle->rxData[0]);
792             transferConfigRx.destOffset = 1;
793         }
794         else
795         {
796             transferConfigRx.destAddr   = (uint32_t) & (handle->rxBuffIfNull);
797             transferConfigRx.destOffset = 0;
798         }
799         transferConfigRx.destTransferSize = kEDMA_TransferSize1Bytes;
800 
801         addrOffset = 0;
802         switch (handle->bytesEachRead)
803         {
804             case (1U):
805                 transferConfigRx.srcTransferSize = kEDMA_TransferSize1Bytes;
806                 transferConfigRx.minorLoopBytes  = 1;
807                 if (handle->isByteSwap)
808                 {
809                     addrOffset = 3;
810                 }
811                 break;
812 
813             case (2U):
814                 transferConfigRx.srcTransferSize = kEDMA_TransferSize2Bytes;
815                 transferConfigRx.minorLoopBytes  = 2;
816                 if (handle->isByteSwap)
817                 {
818                     addrOffset = 2;
819                 }
820                 break;
821 
822             case (4U):
823                 transferConfigRx.srcTransferSize = kEDMA_TransferSize4Bytes;
824                 transferConfigRx.minorLoopBytes  = 4;
825                 break;
826 
827             default:
828                 transferConfigRx.srcTransferSize = kEDMA_TransferSize1Bytes;
829                 transferConfigRx.minorLoopBytes  = 1;
830                 assert(false);
831                 break;
832         }
833 
834         transferConfigRx.srcAddr   = (uint32_t)rxAddr + addrOffset;
835         transferConfigRx.srcOffset = 0;
836 
837         transferConfigRx.majorLoopCounts = handle->readRegRemainingTimes;
838 
839         /* Store the initially configured eDMA minor byte transfer count into the DSPI handle */
840         handle->nbytes = (uint8_t)transferConfigRx.minorLoopBytes;
841 
842         EDMA_SetTransferConfig(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel,
843                                &transferConfigRx, NULL);
844         EDMA_EnableChannelInterrupts(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel,
845                                      (uint32_t)kEDMA_MajorInterruptEnable);
846         EDMA_StartTransfer(handle->edmaRxRegToRxDataHandle);
847     }
848 
849     /*Tx*/
850     if (handle->txData != NULL)
851     {
852         EDMA_ResetChannel(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel);
853         if (isThereExtraTxBytes)
854         {
855             transferConfigTx.srcAddr         = (uint32_t) & (transfer->txData[transfer->dataSize - bytesLastWrite]);
856             transferConfigTx.srcOffset       = 1;
857             transferConfigTx.destOffset      = 0;
858             transferConfigTx.srcTransferSize = kEDMA_TransferSize1Bytes;
859             addrOffset                       = 0;
860             switch (bytesLastWrite)
861             {
862                 case (1U):
863                     transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes;
864                     transferConfigTx.minorLoopBytes   = 1;
865                     if (handle->isByteSwap)
866                     {
867                         addrOffset = 3;
868                     }
869                     break;
870 
871                 case (2U):
872                     transferConfigTx.destTransferSize = kEDMA_TransferSize2Bytes;
873                     transferConfigTx.minorLoopBytes   = 2;
874                     if (handle->isByteSwap)
875                     {
876                         addrOffset = 2;
877                     }
878                     break;
879 
880                 default:
881                     transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes;
882                     transferConfigTx.minorLoopBytes   = 1;
883                     assert(false);
884                     break;
885             }
886 
887             transferConfigTx.destAddr        = (uint32_t)txAddr + addrOffset;
888             transferConfigTx.majorLoopCounts = 1;
889 
890             EDMA_TcdReset(softwareTCD_extraBytes);
891             EDMA_TcdSetTransferConfig(softwareTCD_extraBytes, &transferConfigTx, NULL);
892         }
893 
894         transferConfigTx.srcAddr         = (uint32_t)(handle->txData);
895         transferConfigTx.srcOffset       = 1;
896         transferConfigTx.destOffset      = 0;
897         transferConfigTx.srcTransferSize = kEDMA_TransferSize1Bytes;
898         addrOffset                       = 0;
899         switch (handle->bytesEachRead)
900         {
901             case (1U):
902                 transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes;
903                 transferConfigTx.minorLoopBytes   = 1;
904                 if (handle->isByteSwap)
905                 {
906                     addrOffset = 3;
907                 }
908                 break;
909 
910             case (2U):
911                 transferConfigTx.destTransferSize = kEDMA_TransferSize2Bytes;
912                 transferConfigTx.minorLoopBytes   = 2;
913 
914                 if (handle->isByteSwap)
915                 {
916                     addrOffset = 2;
917                 }
918                 break;
919 
920             case (4U):
921                 transferConfigTx.destTransferSize = kEDMA_TransferSize4Bytes;
922                 transferConfigTx.minorLoopBytes   = 4;
923                 break;
924 
925             default:
926                 transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes;
927                 transferConfigTx.minorLoopBytes   = 1;
928                 assert(false);
929                 break;
930         }
931 
932         transferConfigTx.destAddr        = (uint32_t)txAddr + addrOffset;
933         transferConfigTx.majorLoopCounts = handle->writeRegRemainingTimes;
934 
935         if (isThereExtraTxBytes)
936         {
937             EDMA_SetTransferConfig(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel,
938                                    &transferConfigTx, softwareTCD_extraBytes);
939         }
940         else
941         {
942             EDMA_SetTransferConfig(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel,
943                                    &transferConfigTx, NULL);
944         }
945         EDMA_StartTransfer(handle->edmaTxDataToTxRegHandle);
946         mask |= (uint32_t)kLPSPI_TxDmaEnable;
947     }
948 
949     LPSPI_EnableDMA(base, mask);
950 
951     return kStatus_Success;
952 }
953 
EDMA_LpspiSlaveCallback(edma_handle_t * edmaHandle,void * g_lpspiEdmaPrivateHandle,bool transferDone,uint32_t tcds)954 static void EDMA_LpspiSlaveCallback(edma_handle_t *edmaHandle,
955                                     void *g_lpspiEdmaPrivateHandle,
956                                     bool transferDone,
957                                     uint32_t tcds)
958 {
959     assert(edmaHandle != NULL);
960     assert(g_lpspiEdmaPrivateHandle != NULL);
961 
962     uint32_t readData;
963 
964     lpspi_slave_edma_private_handle_t *lpspiEdmaPrivateHandle;
965 
966     lpspiEdmaPrivateHandle = (lpspi_slave_edma_private_handle_t *)g_lpspiEdmaPrivateHandle;
967 
968     size_t rxRemainingByteCount = lpspiEdmaPrivateHandle->handle->rxRemainingByteCount;
969     uint8_t bytesLastRead       = lpspiEdmaPrivateHandle->handle->bytesLastRead;
970     bool isByteSwap             = lpspiEdmaPrivateHandle->handle->isByteSwap;
971 
972     LPSPI_DisableDMA(lpspiEdmaPrivateHandle->base, (uint32_t)kLPSPI_TxDmaEnable | (uint32_t)kLPSPI_RxDmaEnable);
973 
974     if (lpspiEdmaPrivateHandle->handle->isThereExtraRxBytes)
975     {
976         while (LPSPI_GetRxFifoCount(lpspiEdmaPrivateHandle->base) == 0U)
977         {
978         }
979         readData = LPSPI_ReadData(lpspiEdmaPrivateHandle->base);
980 
981         if (lpspiEdmaPrivateHandle->handle->rxData != NULL)
982         {
983             LPSPI_SeparateEdmaReadData(&(lpspiEdmaPrivateHandle->handle->rxData[rxRemainingByteCount - bytesLastRead]),
984                                        readData, bytesLastRead, isByteSwap);
985         }
986     }
987 
988     lpspiEdmaPrivateHandle->handle->state = (uint8_t)kLPSPI_Idle;
989 
990     if (lpspiEdmaPrivateHandle->handle->callback != NULL)
991     {
992         lpspiEdmaPrivateHandle->handle->callback(lpspiEdmaPrivateHandle->base, lpspiEdmaPrivateHandle->handle,
993                                                  kStatus_Success, lpspiEdmaPrivateHandle->handle->userData);
994     }
995 }
996 
997 /*!
998  * brief LPSPI slave aborts a transfer which is using eDMA.
999  *
1000  * This function aborts a transfer which is using eDMA.
1001  *
1002  * param base LPSPI peripheral base address.
1003  * param handle pointer to lpspi_slave_edma_handle_t structure which stores the transfer state.
1004  */
LPSPI_SlaveTransferAbortEDMA(LPSPI_Type * base,lpspi_slave_edma_handle_t * handle)1005 void LPSPI_SlaveTransferAbortEDMA(LPSPI_Type *base, lpspi_slave_edma_handle_t *handle)
1006 {
1007     assert(handle != NULL);
1008 
1009     LPSPI_DisableDMA(base, (uint32_t)kLPSPI_RxDmaEnable | (uint32_t)kLPSPI_TxDmaEnable);
1010 
1011     EDMA_AbortTransfer(handle->edmaRxRegToRxDataHandle);
1012     EDMA_AbortTransfer(handle->edmaTxDataToTxRegHandle);
1013 
1014     handle->state = (uint8_t)kLPSPI_Idle;
1015 }
1016 
1017 /*!
1018  * brief Gets the slave eDMA transfer remaining bytes.
1019  *
1020  * This function gets the slave eDMA transfer remaining bytes.
1021  *
1022  * param base LPSPI peripheral base address.
1023  * param handle pointer to lpspi_slave_edma_handle_t structure which stores the transfer state.
1024  * param count Number of bytes transferred so far by the eDMA transaction.
1025  * return status of status_t.
1026  */
LPSPI_SlaveTransferGetCountEDMA(LPSPI_Type * base,lpspi_slave_edma_handle_t * handle,size_t * count)1027 status_t LPSPI_SlaveTransferGetCountEDMA(LPSPI_Type *base, lpspi_slave_edma_handle_t *handle, size_t *count)
1028 {
1029     assert(handle != NULL);
1030 
1031     if (NULL == count)
1032     {
1033         return kStatus_InvalidArgument;
1034     }
1035 
1036     /* Catch when there is not an active transfer. */
1037     if (handle->state != (uint8_t)kLPSPI_Busy)
1038     {
1039         *count = 0;
1040         return kStatus_NoTransferInProgress;
1041     }
1042 
1043     size_t remainingByte;
1044 
1045     remainingByte =
1046         (uint32_t)handle->nbytes * EDMA_GetRemainingMajorLoopCount(handle->edmaRxRegToRxDataHandle->base,
1047                                                                    handle->edmaRxRegToRxDataHandle->channel);
1048 
1049     *count = handle->totalByteCount - remainingByte;
1050 
1051     return kStatus_Success;
1052 }
1053