Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:22:59

0001 /*
0002  * Copyright (c) 2016, Freescale Semiconductor, Inc.
0003  * Copyright 2016-2020 NXP
0004  * All rights reserved.
0005  *
0006  * SPDX-License-Identifier: BSD-3-Clause
0007  */
0008 
0009 #include "fsl_flexspi_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.flexspi_edma"
0018 #endif
0019 
0020 /*<! Structure definition for flexspi_edma_private_handle_t. The structure is private. */
0021 typedef struct _flexspi_edma_private_handle
0022 {
0023     FLEXSPI_Type *base;
0024     flexspi_edma_handle_t *handle;
0025 } flexspi_edma_private_handle_t;
0026 
0027 /* FLEXSPI EDMA transfer handle, _flexspi_edma_tansfer_states. */
0028 enum
0029 {
0030     kFLEXSPI_Idle, /* FLEXSPI Bus idle. */
0031     kFLEXSPI_Busy  /* FLEXSPI Bus busy. */
0032 };
0033 
0034 /*******************************************************************************
0035  * Variables
0036  ******************************************************************************/
0037 
0038 /*! @brief Pointers to flexspi bases for each instance. */
0039 static FLEXSPI_Type *const s_flexspiBases[] = FLEXSPI_BASE_PTRS;
0040 
0041 /*<! Private handle only used for internally. */
0042 static flexspi_edma_private_handle_t s_edmaPrivateHandle[ARRAY_SIZE(s_flexspiBases)];
0043 
0044 /*******************************************************************************
0045  * Prototypes
0046  ******************************************************************************/
0047 
0048 /*!
0049  * @brief FLEXSPI EDMA transfer finished callback function.
0050  *
0051  * This function is called when FLEXSPI EDMA transfer finished. It disables the FLEXSPI
0052  * TX/RX EDMA request and sends status to FLEXSPI callback.
0053  *
0054  * @param handle The EDMA handle.
0055  * @param param Callback function parameter.
0056  */
0057 static void FLEXSPI_TransferEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds);
0058 
0059 /*******************************************************************************
0060  * Code
0061  ******************************************************************************/
0062 static uint8_t FLEXSPI_CalculatePower(uint8_t value)
0063 {
0064     uint8_t power = 0;
0065     while (value >> 1 != 0U)
0066     {
0067         power++;
0068         value = value >> 1;
0069     }
0070 
0071     return power;
0072 }
0073 static void FLEXSPI_TransferEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds)
0074 {
0075     flexspi_edma_private_handle_t *flexspiPrivateHandle = (flexspi_edma_private_handle_t *)param;
0076 
0077     /* Avoid warning for unused parameters. */
0078     handle = handle;
0079     tcds   = tcds;
0080 
0081     if (transferDone)
0082     {
0083         /* Wait for bus idle. */
0084         while (!FLEXSPI_GetBusIdleStatus(flexspiPrivateHandle->base))
0085         {
0086         }
0087         /* Disable transfer. */
0088         FLEXSPI_TransferAbortEDMA(flexspiPrivateHandle->base, flexspiPrivateHandle->handle);
0089 
0090         if (flexspiPrivateHandle->handle->completionCallback != NULL)
0091         {
0092             flexspiPrivateHandle->handle->completionCallback(flexspiPrivateHandle->base, flexspiPrivateHandle->handle,
0093                                                              kStatus_Success, flexspiPrivateHandle->handle->userData);
0094         }
0095     }
0096 }
0097 
0098 /*!
0099  * brief Initializes the FLEXSPI handle for transfer which is used in transactional functions and set the callback.
0100  *
0101  * param base FLEXSPI peripheral base address
0102  * param handle Pointer to flexspi_edma_handle_t structure
0103  * param callback FLEXSPI callback, NULL means no callback.
0104  * param userData User callback function data.
0105  * param txDmaHandle User requested DMA handle for TX DMA transfer.
0106  * param rxDmaHandle User requested DMA handle for RX DMA transfer.
0107  */
0108 void FLEXSPI_TransferCreateHandleEDMA(FLEXSPI_Type *base,
0109                                       flexspi_edma_handle_t *handle,
0110                                       flexspi_edma_callback_t callback,
0111                                       void *userData,
0112                                       edma_handle_t *txDmaHandle,
0113                                       edma_handle_t *rxDmaHandle)
0114 {
0115     assert(handle);
0116 
0117     uint32_t instance = FLEXSPI_GetInstance(base);
0118 
0119     s_edmaPrivateHandle[instance].base   = base;
0120     s_edmaPrivateHandle[instance].handle = handle;
0121 
0122     (void)memset(handle, 0, sizeof(*handle));
0123 
0124     handle->state       = kFLEXSPI_Idle;
0125     handle->txDmaHandle = txDmaHandle;
0126     handle->rxDmaHandle = rxDmaHandle;
0127     handle->nsize       = kFLEXPSI_EDMAnSize1Bytes;
0128 
0129     handle->completionCallback = callback;
0130     handle->userData           = userData;
0131 }
0132 
0133 /*!
0134  * brief Update FLEXSPI EDMA transfer source data transfer size(SSIZE) and destination data transfer size(DSIZE).
0135  *
0136  * param base FLEXSPI peripheral base address
0137  * param handle Pointer to flexspi_edma_handle_t structure
0138  * param nsize FLEXSPI DMA transfer data transfer size(SSIZE/DSIZE), by default the size is
0139  * kFLEXPSI_EDMAnSize1Bytes(one byte).
0140  * see flexspi_edma_transfer_nsize_t               .
0141  */
0142 void FLEXSPI_TransferUpdateSizeEDMA(FLEXSPI_Type *base,
0143                                     flexspi_edma_handle_t *handle,
0144                                     flexspi_edma_transfer_nsize_t nsize)
0145 {
0146     handle->nsize = nsize;
0147 }
0148 
0149 /*!
0150  * brief Transfers FLEXSPI data using an eDMA non-blocking method.
0151  *
0152  * This function writes/receives data to/from the FLEXSPI transmit/receive FIFO. This function is non-blocking.
0153  * param base FLEXSPI peripheral base address.
0154  * param handle Pointer to flexspi_edma_handle_t structure
0155  * param xfer FLEXSPI transfer structure.
0156  * retval kStatus_FLEXSPI_Busy     FLEXSPI is busy transfer.
0157  * retval kStatus_InvalidArgument  The watermark configuration is invalid, the watermark should be power of
0158                                     2 to do successfully EDMA transfer.
0159  * retval kStatus_Success          FLEXSPI successfully start edma transfer.
0160  */
0161 status_t FLEXSPI_TransferEDMA(FLEXSPI_Type *base, flexspi_edma_handle_t *handle, flexspi_transfer_t *xfer)
0162 {
0163     uint32_t configValue = 0;
0164     status_t result      = kStatus_Success;
0165     edma_transfer_config_t xferConfig;
0166     uint32_t instance = FLEXSPI_GetInstance(base);
0167     uint8_t power     = 0;
0168 
0169     assert(handle);
0170     assert(xfer);
0171 
0172     /* Check if the FLEXSPI bus is idle - if not return busy status. */
0173     if (handle->state != (uint32_t)kFLEXSPI_Idle)
0174     {
0175         result = kStatus_FLEXSPI_Busy;
0176     }
0177     else
0178     {
0179         handle->transferSize = xfer->dataSize;
0180         handle->state        = kFLEXSPI_Busy;
0181 
0182         /* Clear sequence pointer before sending data to external devices. */
0183         base->FLSHCR2[xfer->port] |= FLEXSPI_FLSHCR2_CLRINSTRPTR_MASK;
0184 
0185         /* Clear former pending status before start this transfer. */
0186         base->INTR |= FLEXSPI_INTR_AHBCMDERR_MASK | FLEXSPI_INTR_IPCMDERR_MASK | FLEXSPI_INTR_AHBCMDGE_MASK |
0187                       FLEXSPI_INTR_IPCMDGE_MASK;
0188 
0189         /* Configure base address. */
0190         base->IPCR0 = xfer->deviceAddress;
0191 
0192         /* Reset fifos. */
0193         base->IPTXFCR |= FLEXSPI_IPTXFCR_CLRIPTXF_MASK;
0194         base->IPRXFCR |= FLEXSPI_IPRXFCR_CLRIPRXF_MASK;
0195 
0196         /* Configure data size. */
0197         if ((xfer->cmdType == kFLEXSPI_Read) || (xfer->cmdType == kFLEXSPI_Write))
0198         {
0199             configValue = FLEXSPI_IPCR1_IDATSZ(xfer->dataSize);
0200         }
0201 
0202         /* Configure sequence ID. */
0203         configValue |= FLEXSPI_IPCR1_ISEQID(xfer->seqIndex) | FLEXSPI_IPCR1_ISEQNUM((uint32_t)xfer->SeqNumber - 1U);
0204         base->IPCR1 = configValue;
0205     }
0206 
0207     if ((xfer->cmdType == kFLEXSPI_Write) || (xfer->cmdType == kFLEXSPI_Config))
0208     {
0209         handle->count = (uint8_t)((base->IPTXFCR & FLEXSPI_IPTXFCR_TXWMRK_MASK) >> FLEXSPI_IPTXFCR_TXWMRK_SHIFT) + 1U;
0210 
0211         if (xfer->dataSize < 8U * (uint32_t)handle->count)
0212         {
0213             handle->nbytes = (uint8_t)xfer->dataSize;
0214         }
0215         else
0216         {
0217             /* Check the handle->count is power of 2 */
0218             if (((handle->count) & (handle->count - 1U)) != 0U)
0219             {
0220                 return kStatus_InvalidArgument;
0221             }
0222             /* Store the initially configured eDMA minor byte transfer count into the FLEXSPI handle */
0223             handle->nbytes = (8U * handle->count);
0224         }
0225 
0226         power = FLEXSPI_CalculatePower(8U * handle->count);
0227 
0228         /* Prepare transfer. */
0229         EDMA_PrepareTransfer(&xferConfig, xfer->data, (uint32_t)handle->nsize,
0230                              (void *)(uint32_t *)FLEXSPI_GetTxFifoAddress(base), (uint32_t)handle->nsize,
0231                              (uint32_t)handle->nbytes, xfer->dataSize, kEDMA_MemoryToMemory);
0232 
0233         /* Submit transfer. */
0234         (void)EDMA_SubmitTransfer(handle->txDmaHandle, &xferConfig);
0235         EDMA_SetModulo(handle->txDmaHandle->base, handle->txDmaHandle->channel, kEDMA_ModuloDisable,
0236                        (edma_modulo_t)power);
0237         EDMA_SetCallback(handle->txDmaHandle, FLEXSPI_TransferEDMACallback,
0238                          &s_edmaPrivateHandle[FLEXSPI_GetInstance(base)]);
0239         EDMA_StartTransfer(handle->txDmaHandle);
0240 
0241         /* Enable FLEXSPI TX EDMA. */
0242         FLEXSPI_EnableTxDMA(base, true);
0243 
0244         /* Start Transfer. */
0245         base->IPCMD |= FLEXSPI_IPCMD_TRG_MASK;
0246     }
0247     else if (xfer->cmdType == kFLEXSPI_Read)
0248     {
0249         handle->count = (uint8_t)((base->IPRXFCR & FLEXSPI_IPRXFCR_RXWMRK_MASK) >> FLEXSPI_IPRXFCR_RXWMRK_SHIFT) + 1U;
0250 
0251         if (xfer->dataSize < 8U * (uint32_t)handle->count)
0252         {
0253             handle->nbytes = (uint8_t)xfer->dataSize;
0254         }
0255         else
0256         {
0257             /* Check the handle->count is power of 2 */
0258             if (((handle->count) & (handle->count - 1U)) != 0U)
0259             {
0260                 return kStatus_InvalidArgument;
0261             }
0262             /* Store the initially configured eDMA minor byte transfer count into the FLEXSPI handle */
0263             handle->nbytes = (8U * handle->count);
0264         }
0265 
0266         power = FLEXSPI_CalculatePower(8U * handle->count);
0267 
0268         /* Prepare transfer. */
0269         EDMA_PrepareTransfer(&xferConfig, (void *)(uint32_t *)FLEXSPI_GetRxFifoAddress(base), (uint32_t)handle->nsize,
0270                              xfer->data, (uint32_t)handle->nsize, (uint32_t)handle->nbytes, xfer->dataSize,
0271                              kEDMA_MemoryToMemory);
0272 
0273         /* Submit transfer. */
0274         (void)EDMA_SubmitTransfer(handle->rxDmaHandle, &xferConfig);
0275         EDMA_SetModulo(handle->txDmaHandle->base, handle->txDmaHandle->channel, (edma_modulo_t)power,
0276                        kEDMA_ModuloDisable);
0277         EDMA_SetCallback(handle->rxDmaHandle, FLEXSPI_TransferEDMACallback, &s_edmaPrivateHandle[instance]);
0278         EDMA_StartTransfer(handle->rxDmaHandle);
0279 
0280         /* Enable FLEXSPI RX EDMA. */
0281         FLEXSPI_EnableRxDMA(base, true);
0282 
0283         /* Start Transfer. */
0284         base->IPCMD |= FLEXSPI_IPCMD_TRG_MASK;
0285     }
0286     else
0287     {
0288         /* Start Transfer. */
0289         base->IPCMD |= FLEXSPI_IPCMD_TRG_MASK;
0290         /* Wait for bus idle. */
0291         while (!FLEXSPI_GetBusIdleStatus(base))
0292         {
0293         }
0294         result = FLEXSPI_CheckAndClearError(base, base->INTR);
0295 
0296         handle->state = kFLEXSPI_Idle;
0297 
0298         if (handle->completionCallback != NULL)
0299         {
0300             handle->completionCallback(base, handle, result, handle->userData);
0301         }
0302     }
0303 
0304     return result;
0305 }
0306 
0307 /*!
0308  * brief Aborts the transfer data using eDMA.
0309  *
0310  * This function aborts the transfer data using eDMA.
0311  *
0312  * param base FLEXSPI peripheral base address.
0313  * param handle Pointer to flexspi_edma_handle_t structure
0314  */
0315 void FLEXSPI_TransferAbortEDMA(FLEXSPI_Type *base, flexspi_edma_handle_t *handle)
0316 {
0317     assert(handle);
0318 
0319     if ((base->IPTXFCR & FLEXSPI_IPTXFCR_TXDMAEN_MASK) != 0x00U)
0320     {
0321         FLEXSPI_EnableTxDMA(base, false);
0322         EDMA_AbortTransfer(handle->txDmaHandle);
0323     }
0324 
0325     if ((base->IPRXFCR & FLEXSPI_IPRXFCR_RXDMAEN_MASK) != 0x00U)
0326     {
0327         FLEXSPI_EnableRxDMA(base, false);
0328         EDMA_AbortTransfer(handle->rxDmaHandle);
0329     }
0330 
0331     handle->state = kFLEXSPI_Idle;
0332 }
0333 
0334 status_t FLEXSPI_TransferGetTransferCountEDMA(FLEXSPI_Type *base, flexspi_edma_handle_t *handle, size_t *count)
0335 {
0336     assert(handle);
0337     assert(count);
0338 
0339     status_t result = kStatus_Success;
0340 
0341     if (handle->state != (uint32_t)kFLEXSPI_Busy)
0342     {
0343         result = kStatus_NoTransferInProgress;
0344     }
0345     else
0346     {
0347         if ((base->IPRXFCR & FLEXSPI_IPRXFCR_RXDMAEN_MASK) != 0x00U)
0348         {
0349             *count = (handle->transferSize -
0350                       (uint32_t)handle->nbytes *
0351                           EDMA_GetRemainingMajorLoopCount(handle->rxDmaHandle->base, handle->rxDmaHandle->channel));
0352         }
0353         else if ((base->IPTXFCR & FLEXSPI_IPTXFCR_TXDMAEN_MASK) != 0x00U)
0354         {
0355             *count = (handle->transferSize -
0356                       (uint32_t)handle->nbytes *
0357                           EDMA_GetRemainingMajorLoopCount(handle->txDmaHandle->base, handle->txDmaHandle->channel));
0358         }
0359         else
0360         {
0361             ; /* Intentional empty for MISRA C-2012 rule 15.7. */
0362         }
0363     }
0364 
0365     return result;
0366 }