Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:00

0001 /*
0002  * Copyright (c) 2015, Freescale Semiconductor, Inc.
0003  * Copyright 2016-2022 NXP
0004  * All rights reserved.
0005  *
0006  * SPDX-License-Identifier: BSD-3-Clause
0007  */
0008 
0009 #include "fsl_lpspi_edma.h"
0010 
0011 /***********************************************************************************************************************
0012  * Definitions
0013  ***********************************************************************************************************************/
0014 
0015 /* Component ID definition, used by tools. */
0016 #ifndef FSL_COMPONENT_ID
0017 #define FSL_COMPONENT_ID "platform.drivers.lpspi_edma"
0018 #endif
0019 
0020 /*!
0021  * @brief Structure definition for dspi_master_edma_private_handle_t. The structure is private.
0022  */
0023 typedef struct _lpspi_master_edma_private_handle
0024 {
0025     LPSPI_Type *base;                   /*!< LPSPI peripheral base address. */
0026     lpspi_master_edma_handle_t *handle; /*!< lpspi_master_edma_handle_t handle */
0027 } lpspi_master_edma_private_handle_t;
0028 
0029 /*!
0030  * @brief Structure definition for dspi_slave_edma_private_handle_t. The structure is private.
0031  */
0032 typedef struct _lpspi_slave_edma_private_handle
0033 {
0034     LPSPI_Type *base;                  /*!< LPSPI peripheral base address. */
0035     lpspi_slave_edma_handle_t *handle; /*!< lpspi_slave_edma_handle_t handle */
0036 } lpspi_slave_edma_private_handle_t;
0037 
0038 /***********************************************************************************************************************
0039  * Prototypes
0040  ***********************************************************************************************************************/
0041 
0042 /*!
0043  * @brief EDMA_LpspiMasterCallback after the LPSPI master transfer completed by using EDMA.
0044  * This is not a public API.
0045  */
0046 static void EDMA_LpspiMasterCallback(edma_handle_t *edmaHandle,
0047                                      void *g_lpspiEdmaPrivateHandle,
0048                                      bool transferDone,
0049                                      uint32_t tcds);
0050 
0051 /*!
0052  * @brief EDMA_LpspiSlaveCallback after the LPSPI slave transfer completed by using EDMA.
0053  * This is not a public API.
0054  */
0055 static void EDMA_LpspiSlaveCallback(edma_handle_t *edmaHandle,
0056                                     void *g_lpspiEdmaPrivateHandle,
0057                                     bool transferDone,
0058                                     uint32_t tcds);
0059 
0060 static void LPSPI_SeparateEdmaReadData(uint8_t *rxData, uint32_t readData, uint32_t bytesEachRead, bool isByteSwap);
0061 
0062 /***********************************************************************************************************************
0063  * Variables
0064  ***********************************************************************************************************************/
0065 /*! @brief Pointers to lpspi bases for each instance. */
0066 static LPSPI_Type *const s_lpspiBases[] = LPSPI_BASE_PTRS;
0067 
0068 /*! @brief Pointers to lpspi edma handles for each instance. */
0069 static lpspi_master_edma_private_handle_t s_lpspiMasterEdmaPrivateHandle[ARRAY_SIZE(s_lpspiBases)];
0070 static lpspi_slave_edma_private_handle_t s_lpspiSlaveEdmaPrivateHandle[ARRAY_SIZE(s_lpspiBases)];
0071 
0072 /***********************************************************************************************************************
0073  * Code
0074  ***********************************************************************************************************************/
0075 static void LPSPI_SeparateEdmaReadData(uint8_t *rxData, uint32_t readData, uint32_t bytesEachRead, bool isByteSwap)
0076 {
0077     assert(rxData != NULL);
0078 
0079     switch (bytesEachRead)
0080     {
0081         case 1:
0082             if (!isByteSwap)
0083             {
0084                 *rxData = (uint8_t)readData;
0085                 ++rxData;
0086             }
0087             else
0088             {
0089                 *rxData = (uint8_t)(readData >> 24);
0090                 ++rxData;
0091             }
0092             break;
0093 
0094         case 2:
0095             if (!isByteSwap)
0096             {
0097                 *rxData = (uint8_t)readData;
0098                 ++rxData;
0099                 *rxData = (uint8_t)(readData >> 8);
0100                 ++rxData;
0101             }
0102             else
0103             {
0104                 *rxData = (uint8_t)(readData >> 16);
0105                 ++rxData;
0106                 *rxData = (uint8_t)(readData >> 24);
0107                 ++rxData;
0108             }
0109             break;
0110 
0111         case 4:
0112 
0113             *rxData = (uint8_t)readData;
0114             ++rxData;
0115             *rxData = (uint8_t)(readData >> 8);
0116             ++rxData;
0117             *rxData = (uint8_t)(readData >> 16);
0118             ++rxData;
0119             *rxData = (uint8_t)(readData >> 24);
0120             ++rxData;
0121 
0122             break;
0123 
0124         default:
0125             assert(false);
0126             break;
0127     }
0128 }
0129 
0130 /*!
0131  * brief Initializes the LPSPI master eDMA handle.
0132  *
0133  * This function initializes the LPSPI eDMA handle which can be used for other LPSPI transactional APIs.  Usually, for a
0134  * specified LPSPI instance, call this API once to get the initialized handle.
0135  *
0136  * Note that the LPSPI eDMA has a separated (Rx and Rx as two sources) or shared (Rx  and Tx are the same source) DMA
0137  * request source.
0138  * (1) For a separated DMA request source, enable and set the Rx DMAMUX source for edmaRxRegToRxDataHandle and
0139  * Tx DMAMUX source for edmaIntermediaryToTxRegHandle.
0140  * (2) For a shared DMA request source, enable and set the Rx/Rx DMAMUX source for edmaRxRegToRxDataHandle.
0141  *
0142  * param base LPSPI peripheral base address.
0143  * param handle LPSPI handle pointer to lpspi_master_edma_handle_t.
0144  * param callback LPSPI callback.
0145  * param userData callback function parameter.
0146  * param edmaRxRegToRxDataHandle edmaRxRegToRxDataHandle pointer to edma_handle_t.
0147  * param edmaTxDataToTxRegHandle edmaTxDataToTxRegHandle pointer to edma_handle_t.
0148  */
0149 void LPSPI_MasterTransferCreateHandleEDMA(LPSPI_Type *base,
0150                                           lpspi_master_edma_handle_t *handle,
0151                                           lpspi_master_edma_transfer_callback_t callback,
0152                                           void *userData,
0153                                           edma_handle_t *edmaRxRegToRxDataHandle,
0154                                           edma_handle_t *edmaTxDataToTxRegHandle)
0155 {
0156     assert(handle != NULL);
0157     assert(edmaRxRegToRxDataHandle != NULL);
0158     assert(edmaTxDataToTxRegHandle != NULL);
0159 
0160     /* Zero the handle. */
0161     (void)memset(handle, 0, sizeof(*handle));
0162 
0163     uint32_t instance = LPSPI_GetInstance(base);
0164 
0165     s_lpspiMasterEdmaPrivateHandle[instance].base   = base;
0166     s_lpspiMasterEdmaPrivateHandle[instance].handle = handle;
0167 
0168     handle->callback = callback;
0169     handle->userData = userData;
0170 
0171     handle->edmaRxRegToRxDataHandle = edmaRxRegToRxDataHandle;
0172     handle->edmaTxDataToTxRegHandle = edmaTxDataToTxRegHandle;
0173 }
0174 
0175 static void LPSPI_PrepareTransferEDMA(LPSPI_Type *base)
0176 {
0177     /* Flush FIFO, clear status, disable all the inerrupts and DMA requests. */
0178     LPSPI_FlushFifo(base, true, true);
0179     LPSPI_ClearStatusFlags(base, (uint32_t)kLPSPI_AllStatusFlag);
0180     LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_AllInterruptEnable);
0181     LPSPI_DisableDMA(base, (uint32_t)kLPSPI_RxDmaEnable | (uint32_t)kLPSPI_TxDmaEnable);
0182 }
0183 
0184 /*!
0185  * brief LPSPI master transfer data using eDMA.
0186  *
0187  * This function transfers data using eDMA. This is a non-blocking function, which returns right away. When all data
0188  * is transferred, the callback function is called.
0189  *
0190  * Note:
0191  * The transfer data size should be an integer multiple of bytesPerFrame if bytesPerFrame is less than or equal to 4.
0192  * For bytesPerFrame greater than 4:
0193  * The transfer data size should be equal to bytesPerFrame if the bytesPerFrame is not an integer multiple of 4.
0194  * Otherwise, the transfer data size can be an integer multiple of bytesPerFrame.
0195  *
0196  * param base LPSPI peripheral base address.
0197  * param handle pointer to lpspi_master_edma_handle_t structure which stores the transfer state.
0198  * param transfer pointer to lpspi_transfer_t structure.
0199  * return status of status_t.
0200  */
0201 status_t LPSPI_MasterTransferEDMA(LPSPI_Type *base, lpspi_master_edma_handle_t *handle, lpspi_transfer_t *transfer)
0202 {
0203     assert(handle != NULL);
0204     assert(transfer != NULL);
0205 
0206     /* Check that we're not busy.*/
0207     if (handle->state == (uint8_t)kLPSPI_Busy)
0208     {
0209         return kStatus_LPSPI_Busy;
0210     }
0211 
0212     /* Disable module before configuration */
0213     LPSPI_Enable(base, false);
0214     /* Check arguements */
0215     if (!LPSPI_CheckTransferArgument(base, transfer, true))
0216     {
0217         return kStatus_InvalidArgument;
0218     }
0219 
0220     LPSPI_PrepareTransferEDMA(base);
0221 
0222     /* Variables */
0223     bool isThereExtraTxBytes = false;
0224     bool isByteSwap          = ((transfer->configFlags & (uint32_t)kLPSPI_MasterByteSwap) != 0U);
0225     bool isPcsContinuous     = ((transfer->configFlags & (uint32_t)kLPSPI_MasterPcsContinuous) != 0U);
0226     uint32_t instance        = LPSPI_GetInstance(base);
0227     uint8_t dummyData        = g_lpspiDummyData[instance];
0228     uint8_t bytesLastWrite   = 0;
0229     /*Used for byte swap*/
0230     uint32_t addrOffset    = 0;
0231     uint32_t rxAddr        = LPSPI_GetRxRegisterAddress(base);
0232     uint32_t txAddr        = LPSPI_GetTxRegisterAddress(base);
0233     uint32_t whichPcs      = (transfer->configFlags & LPSPI_MASTER_PCS_MASK) >> LPSPI_MASTER_PCS_SHIFT;
0234     uint32_t bytesPerFrame = ((base->TCR & LPSPI_TCR_FRAMESZ_MASK) >> LPSPI_TCR_FRAMESZ_SHIFT) / 8U + 1U;
0235     edma_transfer_config_t transferConfigRx = {0};
0236     edma_transfer_config_t transferConfigTx = {0};
0237     edma_tcd_t *softwareTCD_pcsContinuous   = (edma_tcd_t *)((uint32_t)(&handle->lpspiSoftwareTCD[2]) & (~0x1FU));
0238     edma_tcd_t *softwareTCD_extraBytes      = (edma_tcd_t *)((uint32_t)(&handle->lpspiSoftwareTCD[1]) & (~0x1FU));
0239 
0240     handle->state                  = (uint8_t)kLPSPI_Busy;
0241     handle->txData                 = transfer->txData;
0242     handle->rxData                 = transfer->rxData;
0243     handle->txRemainingByteCount   = transfer->dataSize;
0244     handle->rxRemainingByteCount   = transfer->dataSize;
0245     handle->totalByteCount         = transfer->dataSize;
0246     handle->writeRegRemainingTimes = (transfer->dataSize / bytesPerFrame) * ((bytesPerFrame + 3U) / 4U);
0247     handle->readRegRemainingTimes  = handle->writeRegRemainingTimes;
0248     handle->txBuffIfNull =
0249         ((uint32_t)dummyData) | ((uint32_t)dummyData << 8) | ((uint32_t)dummyData << 16) | ((uint32_t)dummyData << 24);
0250     /*The TX and RX FIFO sizes are always the same*/
0251     handle->fifoSize            = LPSPI_GetRxFifoSize(base);
0252     handle->isPcsContinuous     = isPcsContinuous;
0253     handle->isByteSwap          = isByteSwap;
0254     handle->isThereExtraRxBytes = false;
0255 
0256     /*Because DMA is fast enough , so set the RX and TX watermarks to 0 .*/
0257     LPSPI_SetFifoWatermarks(base, 0U, 0U);
0258 
0259     /* Transfers will stall when transmit FIFO is empty or receive FIFO is full. */
0260     base->CFGR1 &= (~LPSPI_CFGR1_NOSTALL_MASK);
0261 
0262     /* Enable module for following configuration of TCR to take effect. */
0263     LPSPI_Enable(base, true);
0264 
0265     /* For DMA transfer , we'd better not masked the transmit data and receive data in TCR since the transfer flow is
0266      * hard to controlled by software. */
0267     base->TCR = (base->TCR & ~(LPSPI_TCR_CONT_MASK | LPSPI_TCR_CONTC_MASK | LPSPI_TCR_BYSW_MASK | LPSPI_TCR_PCS_MASK)) |
0268                 LPSPI_TCR_CONT(isPcsContinuous) | LPSPI_TCR_BYSW(isByteSwap) | LPSPI_TCR_PCS(whichPcs);
0269 
0270     /*Calculate the bytes for write/read the TX/RX register each time*/
0271     if (bytesPerFrame <= 4U)
0272     {
0273         handle->bytesEachWrite = (uint8_t)bytesPerFrame;
0274         handle->bytesEachRead  = (uint8_t)bytesPerFrame;
0275 
0276         handle->bytesLastRead = (uint8_t)bytesPerFrame;
0277     }
0278     else
0279     {
0280         handle->bytesEachWrite = 4U;
0281         handle->bytesEachRead  = 4U;
0282 
0283         handle->bytesLastRead = 4U;
0284 
0285         if ((transfer->dataSize % 4U) != 0U)
0286         {
0287             bytesLastWrite        = (uint8_t)(transfer->dataSize % 4U);
0288             handle->bytesLastRead = bytesLastWrite;
0289 
0290             isThereExtraTxBytes = true;
0291 
0292             --handle->writeRegRemainingTimes;
0293 
0294             --handle->readRegRemainingTimes;
0295             handle->isThereExtraRxBytes = true;
0296         }
0297     }
0298 
0299     EDMA_SetCallback(handle->edmaRxRegToRxDataHandle, EDMA_LpspiMasterCallback,
0300                      &s_lpspiMasterEdmaPrivateHandle[instance]);
0301 
0302     /* Configure rx EDMA transfer */
0303     EDMA_ResetChannel(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel);
0304 
0305     if (handle->rxData != NULL)
0306     {
0307         transferConfigRx.destAddr   = (uint32_t) & (handle->rxData[0]);
0308         transferConfigRx.destOffset = 1;
0309     }
0310     else
0311     {
0312         transferConfigRx.destAddr   = (uint32_t) & (handle->rxBuffIfNull);
0313         transferConfigRx.destOffset = 0;
0314     }
0315     transferConfigRx.destTransferSize = kEDMA_TransferSize1Bytes;
0316 
0317     addrOffset = 0;
0318     switch (handle->bytesEachRead)
0319     {
0320         case (1U):
0321             transferConfigRx.srcTransferSize = kEDMA_TransferSize1Bytes;
0322             transferConfigRx.minorLoopBytes  = 1;
0323             if (handle->isByteSwap)
0324             {
0325                 addrOffset = 3;
0326             }
0327             break;
0328 
0329         case (2U):
0330             transferConfigRx.srcTransferSize = kEDMA_TransferSize2Bytes;
0331             transferConfigRx.minorLoopBytes  = 2;
0332             if (handle->isByteSwap)
0333             {
0334                 addrOffset = 2;
0335             }
0336             break;
0337 
0338         case (4U):
0339             transferConfigRx.srcTransferSize = kEDMA_TransferSize4Bytes;
0340             transferConfigRx.minorLoopBytes  = 4;
0341             break;
0342 
0343         default:
0344             transferConfigRx.srcTransferSize = kEDMA_TransferSize1Bytes;
0345             transferConfigRx.minorLoopBytes  = 1;
0346             assert(false);
0347             break;
0348     }
0349 
0350     transferConfigRx.srcAddr   = (uint32_t)rxAddr + addrOffset;
0351     transferConfigRx.srcOffset = 0;
0352 
0353     transferConfigRx.majorLoopCounts = handle->readRegRemainingTimes;
0354 
0355     /* Store the initially configured eDMA minor byte transfer count into the LPSPI handle */
0356     handle->nbytes = (uint8_t)transferConfigRx.minorLoopBytes;
0357 
0358     EDMA_SetTransferConfig(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel,
0359                            &transferConfigRx, NULL);
0360     EDMA_EnableChannelInterrupts(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel,
0361                                  (uint32_t)kEDMA_MajorInterruptEnable);
0362 
0363     /* Configure tx EDMA transfer */
0364     EDMA_ResetChannel(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel);
0365 
0366     if (isThereExtraTxBytes)
0367     {
0368         if (handle->txData != NULL)
0369         {
0370             transferConfigTx.srcAddr   = (uint32_t) & (transfer->txData[transfer->dataSize - bytesLastWrite]);
0371             transferConfigTx.srcOffset = 1;
0372         }
0373         else
0374         {
0375             transferConfigTx.srcAddr   = (uint32_t)(&handle->txBuffIfNull);
0376             transferConfigTx.srcOffset = 0;
0377         }
0378 
0379         transferConfigTx.destOffset = 0;
0380 
0381         transferConfigTx.srcTransferSize = kEDMA_TransferSize1Bytes;
0382 
0383         addrOffset = 0;
0384         switch (bytesLastWrite)
0385         {
0386             case (1U):
0387                 transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes;
0388                 transferConfigTx.minorLoopBytes   = 1;
0389                 if (handle->isByteSwap)
0390                 {
0391                     addrOffset = 3;
0392                 }
0393                 break;
0394 
0395             case (2U):
0396                 transferConfigTx.destTransferSize = kEDMA_TransferSize2Bytes;
0397                 transferConfigTx.minorLoopBytes   = 2;
0398                 if (handle->isByteSwap)
0399                 {
0400                     addrOffset = 2;
0401                 }
0402                 break;
0403 
0404             default:
0405                 transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes;
0406                 transferConfigTx.minorLoopBytes   = 1;
0407                 assert(false);
0408                 break;
0409         }
0410 
0411         transferConfigTx.destAddr        = (uint32_t)txAddr + addrOffset;
0412         transferConfigTx.majorLoopCounts = 1;
0413 
0414         EDMA_TcdReset(softwareTCD_extraBytes);
0415 
0416         if (handle->isPcsContinuous)
0417         {
0418             EDMA_TcdSetTransferConfig(softwareTCD_extraBytes, &transferConfigTx, softwareTCD_pcsContinuous);
0419         }
0420         else
0421         {
0422             EDMA_TcdSetTransferConfig(softwareTCD_extraBytes, &transferConfigTx, NULL);
0423         }
0424     }
0425 
0426     if (handle->isPcsContinuous)
0427     {
0428         handle->transmitCommand = base->TCR & ~(LPSPI_TCR_CONTC_MASK | LPSPI_TCR_CONT_MASK);
0429 
0430         transferConfigTx.srcAddr   = (uint32_t) & (handle->transmitCommand);
0431         transferConfigTx.srcOffset = 0;
0432 
0433         transferConfigTx.destAddr   = (uint32_t) & (base->TCR);
0434         transferConfigTx.destOffset = 0;
0435 
0436         transferConfigTx.srcTransferSize  = kEDMA_TransferSize4Bytes;
0437         transferConfigTx.destTransferSize = kEDMA_TransferSize4Bytes;
0438         transferConfigTx.minorLoopBytes   = 4;
0439         transferConfigTx.majorLoopCounts  = 1;
0440 
0441         EDMA_TcdReset(softwareTCD_pcsContinuous);
0442         EDMA_TcdSetTransferConfig(softwareTCD_pcsContinuous, &transferConfigTx, NULL);
0443     }
0444 
0445     if (handle->txData != NULL)
0446     {
0447         transferConfigTx.srcAddr   = (uint32_t)(handle->txData);
0448         transferConfigTx.srcOffset = 1;
0449     }
0450     else
0451     {
0452         transferConfigTx.srcAddr   = (uint32_t)(&handle->txBuffIfNull);
0453         transferConfigTx.srcOffset = 0;
0454     }
0455 
0456     transferConfigTx.destOffset = 0;
0457 
0458     transferConfigTx.srcTransferSize = kEDMA_TransferSize1Bytes;
0459 
0460     addrOffset = 0U;
0461     switch (handle->bytesEachRead)
0462     {
0463         case (1U):
0464             transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes;
0465             transferConfigTx.minorLoopBytes   = 1;
0466             if (handle->isByteSwap)
0467             {
0468                 addrOffset = 3;
0469             }
0470             break;
0471 
0472         case (2U):
0473             transferConfigTx.destTransferSize = kEDMA_TransferSize2Bytes;
0474             transferConfigTx.minorLoopBytes   = 2;
0475 
0476             if (handle->isByteSwap)
0477             {
0478                 addrOffset = 2;
0479             }
0480             break;
0481 
0482         case (4U):
0483             transferConfigTx.destTransferSize = kEDMA_TransferSize4Bytes;
0484             transferConfigTx.minorLoopBytes   = 4;
0485             break;
0486 
0487         default:
0488             transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes;
0489             transferConfigTx.minorLoopBytes   = 1;
0490             assert(false);
0491             break;
0492     }
0493 
0494     transferConfigTx.destAddr = (uint32_t)txAddr + addrOffset;
0495 
0496     transferConfigTx.majorLoopCounts = handle->writeRegRemainingTimes;
0497 
0498     if (isThereExtraTxBytes)
0499     {
0500         EDMA_SetTransferConfig(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel,
0501                                &transferConfigTx, softwareTCD_extraBytes);
0502     }
0503     else if (handle->isPcsContinuous)
0504     {
0505         EDMA_SetTransferConfig(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel,
0506                                &transferConfigTx, softwareTCD_pcsContinuous);
0507     }
0508     else
0509     {
0510         EDMA_SetTransferConfig(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel,
0511                                &transferConfigTx, NULL);
0512     }
0513 
0514     EDMA_StartTransfer(handle->edmaTxDataToTxRegHandle);
0515     EDMA_StartTransfer(handle->edmaRxRegToRxDataHandle);
0516     LPSPI_EnableDMA(base, (uint32_t)kLPSPI_RxDmaEnable | (uint32_t)kLPSPI_TxDmaEnable);
0517 
0518     return kStatus_Success;
0519 }
0520 
0521 static void EDMA_LpspiMasterCallback(edma_handle_t *edmaHandle,
0522                                      void *g_lpspiEdmaPrivateHandle,
0523                                      bool transferDone,
0524                                      uint32_t tcds)
0525 {
0526     assert(edmaHandle != NULL);
0527     assert(g_lpspiEdmaPrivateHandle != NULL);
0528 
0529     uint32_t readData;
0530 
0531     lpspi_master_edma_private_handle_t *lpspiEdmaPrivateHandle;
0532 
0533     lpspiEdmaPrivateHandle = (lpspi_master_edma_private_handle_t *)g_lpspiEdmaPrivateHandle;
0534 
0535     size_t rxRemainingByteCount = lpspiEdmaPrivateHandle->handle->rxRemainingByteCount;
0536     uint8_t bytesLastRead       = lpspiEdmaPrivateHandle->handle->bytesLastRead;
0537     bool isByteSwap             = lpspiEdmaPrivateHandle->handle->isByteSwap;
0538 
0539     LPSPI_DisableDMA(lpspiEdmaPrivateHandle->base, (uint32_t)kLPSPI_TxDmaEnable | (uint32_t)kLPSPI_RxDmaEnable);
0540 
0541     if (lpspiEdmaPrivateHandle->handle->isThereExtraRxBytes)
0542     {
0543         while (LPSPI_GetRxFifoCount(lpspiEdmaPrivateHandle->base) == 0U)
0544         {
0545         }
0546         readData = LPSPI_ReadData(lpspiEdmaPrivateHandle->base);
0547 
0548         if (lpspiEdmaPrivateHandle->handle->rxData != NULL)
0549         {
0550             LPSPI_SeparateEdmaReadData(&(lpspiEdmaPrivateHandle->handle->rxData[rxRemainingByteCount - bytesLastRead]),
0551                                        readData, bytesLastRead, isByteSwap);
0552         }
0553     }
0554 
0555     lpspiEdmaPrivateHandle->handle->state = (uint8_t)kLPSPI_Idle;
0556 
0557     if (lpspiEdmaPrivateHandle->handle->callback != NULL)
0558     {
0559         lpspiEdmaPrivateHandle->handle->callback(lpspiEdmaPrivateHandle->base, lpspiEdmaPrivateHandle->handle,
0560                                                  kStatus_Success, lpspiEdmaPrivateHandle->handle->userData);
0561     }
0562 }
0563 
0564 /*!
0565  * brief LPSPI master aborts a transfer which is using eDMA.
0566  *
0567  * This function aborts a transfer which is using eDMA.
0568  *
0569  * param base LPSPI peripheral base address.
0570  * param handle pointer to lpspi_master_edma_handle_t structure which stores the transfer state.
0571  */
0572 void LPSPI_MasterTransferAbortEDMA(LPSPI_Type *base, lpspi_master_edma_handle_t *handle)
0573 {
0574     assert(handle != NULL);
0575 
0576     LPSPI_DisableDMA(base, (uint32_t)kLPSPI_RxDmaEnable | (uint32_t)kLPSPI_TxDmaEnable);
0577 
0578     EDMA_AbortTransfer(handle->edmaRxRegToRxDataHandle);
0579     EDMA_AbortTransfer(handle->edmaTxDataToTxRegHandle);
0580 
0581     handle->state = (uint8_t)kLPSPI_Idle;
0582 }
0583 
0584 /*!
0585  * brief Gets the master eDMA transfer remaining bytes.
0586  *
0587  * This function gets the master eDMA transfer remaining bytes.
0588  *
0589  * param base LPSPI peripheral base address.
0590  * param handle pointer to lpspi_master_edma_handle_t structure which stores the transfer state.
0591  * param count Number of bytes transferred so far by the EDMA transaction.
0592  * return status of status_t.
0593  */
0594 status_t LPSPI_MasterTransferGetCountEDMA(LPSPI_Type *base, lpspi_master_edma_handle_t *handle, size_t *count)
0595 {
0596     assert(handle != NULL);
0597 
0598     if (NULL == count)
0599     {
0600         return kStatus_InvalidArgument;
0601     }
0602 
0603     /* Catch when there is not an active transfer. */
0604     if (handle->state != (uint8_t)kLPSPI_Busy)
0605     {
0606         *count = 0;
0607         return kStatus_NoTransferInProgress;
0608     }
0609 
0610     size_t remainingByte;
0611 
0612     remainingByte =
0613         (uint32_t)handle->nbytes * EDMA_GetRemainingMajorLoopCount(handle->edmaRxRegToRxDataHandle->base,
0614                                                                    handle->edmaRxRegToRxDataHandle->channel);
0615 
0616     *count = handle->totalByteCount - remainingByte;
0617 
0618     return kStatus_Success;
0619 }
0620 
0621 /*!
0622  * brief Initializes the LPSPI slave eDMA handle.
0623  *
0624  * This function initializes the LPSPI eDMA handle which can be used for other LPSPI transactional APIs.  Usually, for a
0625  * specified LPSPI instance, call this API once to get the initialized handle.
0626  *
0627  * Note that LPSPI eDMA has a separated (Rx and Tx as two sources) or shared (Rx  and Tx as the same source) DMA request
0628  * source.
0629  *
0630  * (1) For a separated DMA request source, enable and set the Rx DMAMUX source for edmaRxRegToRxDataHandle and
0631  * Tx DMAMUX source for edmaTxDataToTxRegHandle.
0632  * (2) For a shared DMA request source, enable and set the Rx/Rx DMAMUX source for edmaRxRegToRxDataHandle .
0633  *
0634  * param base LPSPI peripheral base address.
0635  * param handle LPSPI handle pointer to lpspi_slave_edma_handle_t.
0636  * param callback LPSPI callback.
0637  * param userData callback function parameter.
0638  * param edmaRxRegToRxDataHandle edmaRxRegToRxDataHandle pointer to edma_handle_t.
0639  * param edmaTxDataToTxRegHandle edmaTxDataToTxRegHandle pointer to edma_handle_t.
0640  */
0641 void LPSPI_SlaveTransferCreateHandleEDMA(LPSPI_Type *base,
0642                                          lpspi_slave_edma_handle_t *handle,
0643                                          lpspi_slave_edma_transfer_callback_t callback,
0644                                          void *userData,
0645                                          edma_handle_t *edmaRxRegToRxDataHandle,
0646                                          edma_handle_t *edmaTxDataToTxRegHandle)
0647 {
0648     assert(handle != NULL);
0649     assert(edmaRxRegToRxDataHandle != NULL);
0650     assert(edmaTxDataToTxRegHandle != NULL);
0651 
0652     /* Zero the handle. */
0653     (void)memset(handle, 0, sizeof(*handle));
0654 
0655     uint32_t instance = LPSPI_GetInstance(base);
0656 
0657     s_lpspiSlaveEdmaPrivateHandle[instance].base   = base;
0658     s_lpspiSlaveEdmaPrivateHandle[instance].handle = handle;
0659 
0660     handle->callback = callback;
0661     handle->userData = userData;
0662 
0663     handle->edmaRxRegToRxDataHandle = edmaRxRegToRxDataHandle;
0664     handle->edmaTxDataToTxRegHandle = edmaTxDataToTxRegHandle;
0665 }
0666 
0667 /*!
0668  * brief LPSPI slave transfers data using eDMA.
0669  *
0670  * This function transfers data using eDMA. This is a non-blocking function, which return right away. When all data
0671  * is transferred, the callback function is called.
0672  *
0673  * Note:
0674  * The transfer data size should be an integer multiple of bytesPerFrame if bytesPerFrame is less than or equal to 4.
0675  * For bytesPerFrame greater than 4:
0676  * The transfer data size should be equal to bytesPerFrame if the bytesPerFrame is not an integer multiple of 4.
0677  * Otherwise, the transfer data size can be an integer multiple of bytesPerFrame.
0678  *
0679  * param base LPSPI peripheral base address.
0680  * param handle pointer to lpspi_slave_edma_handle_t structure which stores the transfer state.
0681  * param transfer pointer to lpspi_transfer_t structure.
0682  * return status of status_t.
0683  */
0684 status_t LPSPI_SlaveTransferEDMA(LPSPI_Type *base, lpspi_slave_edma_handle_t *handle, lpspi_transfer_t *transfer)
0685 {
0686     assert(handle != NULL);
0687     assert(transfer != NULL);
0688 
0689     /* Check that we're not busy.*/
0690     if (handle->state == (uint8_t)kLPSPI_Busy)
0691     {
0692         return kStatus_LPSPI_Busy;
0693     }
0694     /* Disable module before configuration. */
0695     LPSPI_Enable(base, false);
0696     /* Check arguements, also dma transfer can not support 3 bytes */
0697     if (!LPSPI_CheckTransferArgument(base, transfer, true))
0698     {
0699         return kStatus_InvalidArgument;
0700     }
0701 
0702     LPSPI_PrepareTransferEDMA(base);
0703 
0704     /* Variables */
0705     bool isThereExtraTxBytes = false;
0706     bool isByteSwap          = ((transfer->configFlags & (uint32_t)kLPSPI_MasterByteSwap) != 0U);
0707     uint8_t bytesLastWrite   = 0;
0708     uint8_t dummyData        = g_lpspiDummyData[LPSPI_GetInstance(base)];
0709     uint32_t mask            = (uint32_t)kLPSPI_RxDmaEnable;
0710 
0711     /* Used for byte swap */
0712     uint32_t addrOffset    = 0;
0713     uint32_t instance      = LPSPI_GetInstance(base);
0714     uint32_t rxAddr        = LPSPI_GetRxRegisterAddress(base);
0715     uint32_t txAddr        = LPSPI_GetTxRegisterAddress(base);
0716     uint32_t whichPcs      = (transfer->configFlags & LPSPI_MASTER_PCS_MASK) >> LPSPI_MASTER_PCS_SHIFT;
0717     uint32_t bytesPerFrame = ((base->TCR & LPSPI_TCR_FRAMESZ_MASK) >> LPSPI_TCR_FRAMESZ_SHIFT) / 8U + 1U;
0718     edma_transfer_config_t transferConfigRx = {0};
0719     edma_transfer_config_t transferConfigTx = {0};
0720     edma_tcd_t *softwareTCD_extraBytes      = (edma_tcd_t *)((uint32_t)(&handle->lpspiSoftwareTCD[1]) & (~0x1FU));
0721 
0722     /* Assign the original value for members of transfer handle. */
0723     handle->state                  = (uint8_t)kLPSPI_Busy;
0724     handle->txData                 = transfer->txData;
0725     handle->rxData                 = transfer->rxData;
0726     handle->txRemainingByteCount   = transfer->dataSize;
0727     handle->rxRemainingByteCount   = transfer->dataSize;
0728     handle->totalByteCount         = transfer->dataSize;
0729     handle->writeRegRemainingTimes = (transfer->dataSize / bytesPerFrame) * ((bytesPerFrame + 3U) / 4U);
0730     handle->readRegRemainingTimes  = handle->writeRegRemainingTimes;
0731     handle->txBuffIfNull =
0732         ((uint32_t)dummyData) | ((uint32_t)dummyData << 8) | ((uint32_t)dummyData << 16) | ((uint32_t)dummyData << 24);
0733     /*The TX and RX FIFO sizes are always the same*/
0734     handle->fifoSize            = LPSPI_GetRxFifoSize(base);
0735     handle->isByteSwap          = isByteSwap;
0736     handle->isThereExtraRxBytes = false;
0737 
0738     /* Because DMA is fast enough, set the RX and TX watermarks to 0. */
0739     LPSPI_SetFifoWatermarks(base, 0U, 0U);
0740 
0741     /* Transfers will stall when transmit FIFO is empty or receive FIFO is full. */
0742     base->CFGR1 &= (~LPSPI_CFGR1_NOSTALL_MASK);
0743 
0744     /* Enable module for following configuration of TCR to take effect. */
0745     LPSPI_Enable(base, true);
0746 
0747     /* For DMA transfer, mask the transmit data if the tx data is null, for rx the receive data should not be masked at
0748        any time since we use rx dma transfer finish cllback to indicate transfer finish. */
0749     base->TCR =
0750         (base->TCR & ~(LPSPI_TCR_CONT_MASK | LPSPI_TCR_CONTC_MASK | LPSPI_TCR_BYSW_MASK | LPSPI_TCR_TXMSK_MASK)) |
0751         LPSPI_TCR_TXMSK(transfer->txData == NULL) | LPSPI_TCR_BYSW(isByteSwap) | LPSPI_TCR_PCS(whichPcs);
0752 
0753     /*Calculate the bytes for write/read the TX/RX register each time*/
0754     if (bytesPerFrame <= 4U)
0755     {
0756         handle->bytesEachWrite = (uint8_t)bytesPerFrame;
0757         handle->bytesEachRead  = (uint8_t)bytesPerFrame;
0758 
0759         handle->bytesLastRead = (uint8_t)bytesPerFrame;
0760     }
0761     else
0762     {
0763         handle->bytesEachWrite = 4U;
0764         handle->bytesEachRead  = 4U;
0765 
0766         handle->bytesLastRead = 4U;
0767 
0768         if ((transfer->dataSize % 4U) != 0U)
0769         {
0770             bytesLastWrite        = (uint8_t)(transfer->dataSize % 4U);
0771             handle->bytesLastRead = bytesLastWrite;
0772 
0773             isThereExtraTxBytes = true;
0774             --handle->writeRegRemainingTimes;
0775 
0776             handle->isThereExtraRxBytes = true;
0777             --handle->readRegRemainingTimes;
0778         }
0779     }
0780 
0781     EDMA_SetCallback(handle->edmaRxRegToRxDataHandle, EDMA_LpspiSlaveCallback,
0782                      &s_lpspiSlaveEdmaPrivateHandle[instance]);
0783 
0784     /*Rx*/
0785     if (handle->readRegRemainingTimes > 0U)
0786     {
0787         EDMA_ResetChannel(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel);
0788 
0789         if (handle->rxData != NULL)
0790         {
0791             transferConfigRx.destAddr   = (uint32_t) & (handle->rxData[0]);
0792             transferConfigRx.destOffset = 1;
0793         }
0794         else
0795         {
0796             transferConfigRx.destAddr   = (uint32_t) & (handle->rxBuffIfNull);
0797             transferConfigRx.destOffset = 0;
0798         }
0799         transferConfigRx.destTransferSize = kEDMA_TransferSize1Bytes;
0800 
0801         addrOffset = 0;
0802         switch (handle->bytesEachRead)
0803         {
0804             case (1U):
0805                 transferConfigRx.srcTransferSize = kEDMA_TransferSize1Bytes;
0806                 transferConfigRx.minorLoopBytes  = 1;
0807                 if (handle->isByteSwap)
0808                 {
0809                     addrOffset = 3;
0810                 }
0811                 break;
0812 
0813             case (2U):
0814                 transferConfigRx.srcTransferSize = kEDMA_TransferSize2Bytes;
0815                 transferConfigRx.minorLoopBytes  = 2;
0816                 if (handle->isByteSwap)
0817                 {
0818                     addrOffset = 2;
0819                 }
0820                 break;
0821 
0822             case (4U):
0823                 transferConfigRx.srcTransferSize = kEDMA_TransferSize4Bytes;
0824                 transferConfigRx.minorLoopBytes  = 4;
0825                 break;
0826 
0827             default:
0828                 transferConfigRx.srcTransferSize = kEDMA_TransferSize1Bytes;
0829                 transferConfigRx.minorLoopBytes  = 1;
0830                 assert(false);
0831                 break;
0832         }
0833 
0834         transferConfigRx.srcAddr   = (uint32_t)rxAddr + addrOffset;
0835         transferConfigRx.srcOffset = 0;
0836 
0837         transferConfigRx.majorLoopCounts = handle->readRegRemainingTimes;
0838 
0839         /* Store the initially configured eDMA minor byte transfer count into the DSPI handle */
0840         handle->nbytes = (uint8_t)transferConfigRx.minorLoopBytes;
0841 
0842         EDMA_SetTransferConfig(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel,
0843                                &transferConfigRx, NULL);
0844         EDMA_EnableChannelInterrupts(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel,
0845                                      (uint32_t)kEDMA_MajorInterruptEnable);
0846         EDMA_StartTransfer(handle->edmaRxRegToRxDataHandle);
0847     }
0848 
0849     /*Tx*/
0850     if (handle->txData != NULL)
0851     {
0852         EDMA_ResetChannel(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel);
0853         if (isThereExtraTxBytes)
0854         {
0855             transferConfigTx.srcAddr         = (uint32_t) & (transfer->txData[transfer->dataSize - bytesLastWrite]);
0856             transferConfigTx.srcOffset       = 1;
0857             transferConfigTx.destOffset      = 0;
0858             transferConfigTx.srcTransferSize = kEDMA_TransferSize1Bytes;
0859             addrOffset                       = 0;
0860             switch (bytesLastWrite)
0861             {
0862                 case (1U):
0863                     transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes;
0864                     transferConfigTx.minorLoopBytes   = 1;
0865                     if (handle->isByteSwap)
0866                     {
0867                         addrOffset = 3;
0868                     }
0869                     break;
0870 
0871                 case (2U):
0872                     transferConfigTx.destTransferSize = kEDMA_TransferSize2Bytes;
0873                     transferConfigTx.minorLoopBytes   = 2;
0874                     if (handle->isByteSwap)
0875                     {
0876                         addrOffset = 2;
0877                     }
0878                     break;
0879 
0880                 default:
0881                     transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes;
0882                     transferConfigTx.minorLoopBytes   = 1;
0883                     assert(false);
0884                     break;
0885             }
0886 
0887             transferConfigTx.destAddr        = (uint32_t)txAddr + addrOffset;
0888             transferConfigTx.majorLoopCounts = 1;
0889 
0890             EDMA_TcdReset(softwareTCD_extraBytes);
0891             EDMA_TcdSetTransferConfig(softwareTCD_extraBytes, &transferConfigTx, NULL);
0892         }
0893 
0894         transferConfigTx.srcAddr         = (uint32_t)(handle->txData);
0895         transferConfigTx.srcOffset       = 1;
0896         transferConfigTx.destOffset      = 0;
0897         transferConfigTx.srcTransferSize = kEDMA_TransferSize1Bytes;
0898         addrOffset                       = 0;
0899         switch (handle->bytesEachRead)
0900         {
0901             case (1U):
0902                 transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes;
0903                 transferConfigTx.minorLoopBytes   = 1;
0904                 if (handle->isByteSwap)
0905                 {
0906                     addrOffset = 3;
0907                 }
0908                 break;
0909 
0910             case (2U):
0911                 transferConfigTx.destTransferSize = kEDMA_TransferSize2Bytes;
0912                 transferConfigTx.minorLoopBytes   = 2;
0913 
0914                 if (handle->isByteSwap)
0915                 {
0916                     addrOffset = 2;
0917                 }
0918                 break;
0919 
0920             case (4U):
0921                 transferConfigTx.destTransferSize = kEDMA_TransferSize4Bytes;
0922                 transferConfigTx.minorLoopBytes   = 4;
0923                 break;
0924 
0925             default:
0926                 transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes;
0927                 transferConfigTx.minorLoopBytes   = 1;
0928                 assert(false);
0929                 break;
0930         }
0931 
0932         transferConfigTx.destAddr        = (uint32_t)txAddr + addrOffset;
0933         transferConfigTx.majorLoopCounts = handle->writeRegRemainingTimes;
0934 
0935         if (isThereExtraTxBytes)
0936         {
0937             EDMA_SetTransferConfig(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel,
0938                                    &transferConfigTx, softwareTCD_extraBytes);
0939         }
0940         else
0941         {
0942             EDMA_SetTransferConfig(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel,
0943                                    &transferConfigTx, NULL);
0944         }
0945         EDMA_StartTransfer(handle->edmaTxDataToTxRegHandle);
0946         mask |= (uint32_t)kLPSPI_TxDmaEnable;
0947     }
0948 
0949     LPSPI_EnableDMA(base, mask);
0950 
0951     return kStatus_Success;
0952 }
0953 
0954 static void EDMA_LpspiSlaveCallback(edma_handle_t *edmaHandle,
0955                                     void *g_lpspiEdmaPrivateHandle,
0956                                     bool transferDone,
0957                                     uint32_t tcds)
0958 {
0959     assert(edmaHandle != NULL);
0960     assert(g_lpspiEdmaPrivateHandle != NULL);
0961 
0962     uint32_t readData;
0963 
0964     lpspi_slave_edma_private_handle_t *lpspiEdmaPrivateHandle;
0965 
0966     lpspiEdmaPrivateHandle = (lpspi_slave_edma_private_handle_t *)g_lpspiEdmaPrivateHandle;
0967 
0968     size_t rxRemainingByteCount = lpspiEdmaPrivateHandle->handle->rxRemainingByteCount;
0969     uint8_t bytesLastRead       = lpspiEdmaPrivateHandle->handle->bytesLastRead;
0970     bool isByteSwap             = lpspiEdmaPrivateHandle->handle->isByteSwap;
0971 
0972     LPSPI_DisableDMA(lpspiEdmaPrivateHandle->base, (uint32_t)kLPSPI_TxDmaEnable | (uint32_t)kLPSPI_RxDmaEnable);
0973 
0974     if (lpspiEdmaPrivateHandle->handle->isThereExtraRxBytes)
0975     {
0976         while (LPSPI_GetRxFifoCount(lpspiEdmaPrivateHandle->base) == 0U)
0977         {
0978         }
0979         readData = LPSPI_ReadData(lpspiEdmaPrivateHandle->base);
0980 
0981         if (lpspiEdmaPrivateHandle->handle->rxData != NULL)
0982         {
0983             LPSPI_SeparateEdmaReadData(&(lpspiEdmaPrivateHandle->handle->rxData[rxRemainingByteCount - bytesLastRead]),
0984                                        readData, bytesLastRead, isByteSwap);
0985         }
0986     }
0987 
0988     lpspiEdmaPrivateHandle->handle->state = (uint8_t)kLPSPI_Idle;
0989 
0990     if (lpspiEdmaPrivateHandle->handle->callback != NULL)
0991     {
0992         lpspiEdmaPrivateHandle->handle->callback(lpspiEdmaPrivateHandle->base, lpspiEdmaPrivateHandle->handle,
0993                                                  kStatus_Success, lpspiEdmaPrivateHandle->handle->userData);
0994     }
0995 }
0996 
0997 /*!
0998  * brief LPSPI slave aborts a transfer which is using eDMA.
0999  *
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  */
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  */
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 }