diff options
Diffstat (limited to 'bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_mculcd_edma.c')
-rw-r--r-- | bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_mculcd_edma.c | 564 |
1 files changed, 564 insertions, 0 deletions
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_mculcd_edma.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_mculcd_edma.c new file mode 100644 index 0000000000..458ad8e72b --- /dev/null +++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_mculcd_edma.c @@ -0,0 +1,564 @@ +/* + * Copyright (c) 2016, Freescale Semiconductor, Inc. + * Copyright 2016-2019 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_flexio_mculcd_edma.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/* Component ID definition, used by tools. */ +#ifndef FSL_COMPONENT_ID +#define FSL_COMPONENT_ID "platform.drivers.flexio_mculcd_edma" +#endif + +#define EDMA_MAX_MAJOR_COUNT (DMA_CITER_ELINKNO_CITER_MASK >> DMA_CITER_ELINKNO_CITER_SHIFT) + +enum +{ + kFLEXIO_MCULCD_StateIdle, /*!< No transfer in progress. */ + kFLEXIO_MCULCD_StateReadArray, /*!< Reading array in progress. */ + kFLEXIO_MCULCD_StateWriteArray, /*!< Writing array in progress. */ + kFLEXIO_MCULCD_StateWriteSameValue, /*!< Writing the same value in progress. + */ +}; + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/*! + * @brief EDMA callback function for FLEXIO MCULCD TX. + * + * For details, see @ref edma_callback. + */ +static void FLEXIO_MCULCD_TxEDMACallback(edma_handle_t *DmaHandle, void *param, bool transferDone, uint32_t tcds); + +/*! + * @brief EDMA callback function for FLEXIO MCULCD RX. + * + * For details, see @ref edma_callback. + */ +static void FLEXIO_MCULCD_RxEDMACallback(edma_handle_t *DmaHandle, void *param, bool transferDone, uint32_t tcds); + +/*! + * @brief Set EDMA config for FLEXIO MCULCD transfer. + * + * @param base pointer to FLEXIO_MCULCD_Type structure. + * @param handle pointer to flexio_mculcd_edma_handle_t structure to store the + * transfer state. + */ +static void FLEXIO_MCULCD_EDMAConfig(FLEXIO_MCULCD_Type *base, flexio_mculcd_edma_handle_t *handle); + +/*! + * @brief Convert the FlexIO shifter number to eDMA modulo. + * + * @param shifterNum The FlexIO shifter number. + * @param modulo The modulo number. + * @retval Get the modulo successfully. + * @retval Could not get the modulo for the shifter number. + */ +static bool FLEXIO_MCULCD_GetEDMAModulo(uint8_t shifterNum, edma_modulo_t *modulo); + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ + +static void FLEXIO_MCULCD_TxEDMACallback(edma_handle_t *DmaHandle, void *param, bool transferDone, uint32_t tcds) +{ + tcds = tcds; + flexio_mculcd_edma_handle_t *flexioLcdMcuHandle = (flexio_mculcd_edma_handle_t *)param; + FLEXIO_MCULCD_Type *flexioLcdMcuBase = flexioLcdMcuHandle->base; + + if (transferDone) + { + if (flexioLcdMcuHandle->remainingCount >= flexioLcdMcuHandle->minorLoopBytes) + { + FLEXIO_MCULCD_EDMAConfig(flexioLcdMcuBase, flexioLcdMcuHandle); + EDMA_StartTransfer(flexioLcdMcuHandle->txDmaHandle); + } + else + { + FLEXIO_MCULCD_EnableTxDMA(flexioLcdMcuBase, false); + + /* Now the data are in shifter, wait for the data send out from the shifter. */ + FLEXIO_MCULCD_WaitTransmitComplete(); + + /* Disable the TX shifter and the timer. */ + FLEXIO_MCULCD_ClearMultiBeatsWriteConfig(flexioLcdMcuBase); + + /* Send the remaining data. */ + if (0U != flexioLcdMcuHandle->remainingCount) + { + if ((uint32_t)kFLEXIO_MCULCD_StateWriteSameValue == flexioLcdMcuHandle->state) + { + FLEXIO_MCULCD_WriteSameValueBlocking(flexioLcdMcuBase, flexioLcdMcuHandle->dataAddrOrSameValue, + flexioLcdMcuHandle->remainingCount); + } + else + { + FLEXIO_MCULCD_WriteDataArrayBlocking(flexioLcdMcuBase, + (uint8_t *)flexioLcdMcuHandle->dataAddrOrSameValue, + flexioLcdMcuHandle->remainingCount); + } + } + + /* De-assert nCS. */ + FLEXIO_MCULCD_StopTransfer(flexioLcdMcuBase); + + /* Change the state. */ + flexioLcdMcuHandle->state = (uint32_t)kFLEXIO_MCULCD_StateIdle; + flexioLcdMcuHandle->dataCount = 0; + flexioLcdMcuHandle->remainingCount = 0; + + /* Callback to inform upper layer. */ + if (NULL != flexioLcdMcuHandle->completionCallback) + { + flexioLcdMcuHandle->completionCallback(flexioLcdMcuBase, flexioLcdMcuHandle, kStatus_FLEXIO_MCULCD_Idle, + flexioLcdMcuHandle->userData); + } + } + } +} + +static void FLEXIO_MCULCD_RxEDMACallback(edma_handle_t *DmaHandle, void *param, bool transferDone, uint32_t tcds) +{ + tcds = tcds; + uint32_t i; + uint32_t rxBufAddr; + flexio_mculcd_edma_handle_t *flexioLcdMcuHandle = (flexio_mculcd_edma_handle_t *)param; + FLEXIO_MCULCD_Type *flexioLcdMcuBase = flexioLcdMcuHandle->base; + FLEXIO_Type *flexioBase = flexioLcdMcuBase->flexioBase; + + if (transferDone) + { + if (flexioLcdMcuHandle->remainingCount >= (2U * flexioLcdMcuHandle->minorLoopBytes)) + { + FLEXIO_MCULCD_EDMAConfig(flexioLcdMcuBase, flexioLcdMcuHandle); + EDMA_StartTransfer(flexioLcdMcuHandle->rxDmaHandle); + } + else + { + FLEXIO_MCULCD_EnableRxDMA(flexioLcdMcuBase, false); + + /* Wait the data saved to the shifter buffer. */ + while (0U == ((1UL << flexioLcdMcuBase->rxShifterEndIndex) & FLEXIO_GetShifterStatusFlags(flexioBase))) + { + } + + /* Disable the RX shifter and the timer. */ + FLEXIO_MCULCD_ClearMultiBeatsReadConfig(flexioLcdMcuBase); + + rxBufAddr = FLEXIO_MCULCD_GetRxDataRegisterAddress(flexioLcdMcuBase); + +/* Read out the data. */ +#if (defined(__CORTEX_M) && (__CORTEX_M == 0)) + /* Cortex M0 and M0+ only support aligned access. */ + for (i = 0; i < flexioLcdMcuHandle->rxShifterNum * 4; i++) + { + ((uint8_t *)(flexioLcdMcuHandle->dataAddrOrSameValue))[i] = ((volatile uint8_t *)rxBufAddr)[i]; + } +#else + for (i = 0; i < flexioLcdMcuHandle->rxShifterNum; i++) + { + ((uint32_t *)(flexioLcdMcuHandle->dataAddrOrSameValue))[i] = ((volatile uint32_t *)rxBufAddr)[i]; + } +#endif + flexioLcdMcuHandle->remainingCount -= flexioLcdMcuHandle->minorLoopBytes; + + if (0U != flexioLcdMcuHandle->remainingCount) + { + FLEXIO_MCULCD_ReadDataArrayBlocking( + flexioLcdMcuBase, + (uint8_t *)(flexioLcdMcuHandle->dataAddrOrSameValue + flexioLcdMcuHandle->minorLoopBytes), + flexioLcdMcuHandle->remainingCount); + } + + /* De-assert nCS. */ + FLEXIO_MCULCD_StopTransfer(flexioLcdMcuBase); + + /* Change the state. */ + flexioLcdMcuHandle->state = (uint32_t)kFLEXIO_MCULCD_StateIdle; + flexioLcdMcuHandle->dataCount = 0; + flexioLcdMcuHandle->remainingCount = 0; + + /* Callback to inform upper layer. */ + if (NULL != flexioLcdMcuHandle->completionCallback) + { + flexioLcdMcuHandle->completionCallback(flexioLcdMcuBase, flexioLcdMcuHandle, kStatus_FLEXIO_MCULCD_Idle, + flexioLcdMcuHandle->userData); + } + } + } +} + +static void FLEXIO_MCULCD_EDMAConfig(FLEXIO_MCULCD_Type *base, flexio_mculcd_edma_handle_t *handle) +{ + edma_transfer_config_t xferConfig = {0}; + edma_transfer_size_t transferSize = kEDMA_TransferSize1Bytes; + int16_t offset; + uint32_t majorLoopCounts; + uint32_t transferCount; + +#if (8 == FLEXIO_MCULCD_DATA_BUS_WIDTH) + transferSize = kEDMA_TransferSize1Bytes; + offset = 1; +#else + transferSize = kEDMA_TransferSize2Bytes; + offset = 2; +#endif + + majorLoopCounts = handle->remainingCount / handle->minorLoopBytes; + + /* For reading, the last minor loop data is not tranfered by DMA. */ + if ((uint32_t)kFLEXIO_MCULCD_StateReadArray == handle->state) + { + majorLoopCounts--; + } + + if (majorLoopCounts > EDMA_MAX_MAJOR_COUNT) + { + majorLoopCounts = EDMA_MAX_MAJOR_COUNT; + } + + transferCount = majorLoopCounts * handle->minorLoopBytes; + + if ((uint32_t)kFLEXIO_MCULCD_StateReadArray == handle->state) + { + xferConfig.srcAddr = FLEXIO_MCULCD_GetRxDataRegisterAddress(base); + xferConfig.destAddr = handle->dataAddrOrSameValue; + xferConfig.srcTransferSize = kEDMA_TransferSize4Bytes; + xferConfig.destTransferSize = transferSize; + xferConfig.srcOffset = 4; + xferConfig.destOffset = offset; + xferConfig.minorLoopBytes = handle->minorLoopBytes; + xferConfig.majorLoopCounts = majorLoopCounts; + handle->remainingCount -= transferCount; + handle->dataAddrOrSameValue += transferCount; + (void)EDMA_SubmitTransfer(handle->rxDmaHandle, &xferConfig); + EDMA_SetModulo(handle->rxDmaHandle->base, handle->rxDmaHandle->channel, handle->rxEdmaModulo, + kEDMA_ModuloDisable); + } + else + { + if ((uint32_t)kFLEXIO_MCULCD_StateWriteArray == handle->state) + { + xferConfig.srcAddr = handle->dataAddrOrSameValue; + xferConfig.srcOffset = offset; + handle->dataAddrOrSameValue += transferCount; + } + else + { + xferConfig.srcAddr = (uint32_t)(&(handle->dataAddrOrSameValue)); + xferConfig.srcOffset = 0; + } + xferConfig.destAddr = FLEXIO_MCULCD_GetTxDataRegisterAddress(base); + xferConfig.srcTransferSize = transferSize; + xferConfig.destTransferSize = kEDMA_TransferSize4Bytes; + xferConfig.destOffset = 4; + xferConfig.minorLoopBytes = handle->minorLoopBytes; + xferConfig.majorLoopCounts = majorLoopCounts; + handle->remainingCount -= transferCount; + (void)EDMA_SubmitTransfer(handle->txDmaHandle, &xferConfig); + EDMA_SetModulo(handle->txDmaHandle->base, handle->txDmaHandle->channel, kEDMA_ModuloDisable, + handle->txEdmaModulo); + } +} + +static bool FLEXIO_MCULCD_GetEDMAModulo(uint8_t shifterNum, edma_modulo_t *modulo) +{ + bool ret = true; + + switch (shifterNum) + { + case 1U: + *modulo = kEDMA_Modulo4bytes; + break; + case 2U: + *modulo = kEDMA_Modulo8bytes; + break; + case 4U: + *modulo = kEDMA_Modulo16bytes; + break; + case 8U: + *modulo = kEDMA_Modulo32bytes; + break; + default: + ret = false; + break; + } + + return ret; +} + +/*! + * brief Initializes the FLEXO MCULCD master eDMA handle. + * + * This function initializes the FLEXO MCULCD master eDMA handle which can be + * used for other FLEXO MCULCD transactional APIs. For a specified FLEXO MCULCD + * instance, call this API once to get the initialized handle. + * + * param base Pointer to FLEXIO_MCULCD_Type structure. + * param handle Pointer to flexio_mculcd_edma_handle_t structure to store the + * transfer state. + * param callback MCULCD transfer complete callback, NULL means no callback. + * param userData callback function parameter. + * param txDmaHandle User requested eDMA handle for FlexIO MCULCD eDMA TX, + * the DMA request source of this handle should be the first of TX shifters. + * param rxDmaHandle User requested eDMA handle for FlexIO MCULCD eDMA RX, + * the DMA request source of this handle should be the last of RX shifters. + * retval kStatus_Success Successfully create the handle. + */ +status_t FLEXIO_MCULCD_TransferCreateHandleEDMA(FLEXIO_MCULCD_Type *base, + flexio_mculcd_edma_handle_t *handle, + flexio_mculcd_edma_transfer_callback_t callback, + void *userData, + edma_handle_t *txDmaHandle, + edma_handle_t *rxDmaHandle) +{ + assert(NULL != handle); + + /* Zero the handle. */ + (void)memset(handle, 0, sizeof(*handle)); + + /* Initialize the state. */ + handle->state = (uint32_t)kFLEXIO_MCULCD_StateIdle; + + /* Register callback and userData. */ + handle->completionCallback = callback; + handle->userData = userData; + + handle->base = base; + handle->txShifterNum = base->txShifterEndIndex - base->txShifterStartIndex + 1U; + handle->rxShifterNum = base->rxShifterEndIndex - base->rxShifterStartIndex + 1U; + + if (NULL != rxDmaHandle) + { + if (!FLEXIO_MCULCD_GetEDMAModulo(handle->rxShifterNum, &handle->rxEdmaModulo)) + { + return kStatus_InvalidArgument; + } + + handle->rxDmaHandle = rxDmaHandle; + EDMA_SetCallback(rxDmaHandle, FLEXIO_MCULCD_RxEDMACallback, handle); + } + + if (NULL != txDmaHandle) + { + if (!FLEXIO_MCULCD_GetEDMAModulo(handle->txShifterNum, &handle->txEdmaModulo)) + { + return kStatus_InvalidArgument; + } + + handle->txDmaHandle = txDmaHandle; + EDMA_SetCallback(txDmaHandle, FLEXIO_MCULCD_TxEDMACallback, handle); + } + + return kStatus_Success; +} + +/*! + * brief Performs a non-blocking FlexIO MCULCD transfer using eDMA. + * + * This function returns immediately after transfer initiates. To check whether + * the transfer is completed, user could: + * 1. Use the transfer completed callback; + * 2. Polling function ref FLEXIO_MCULCD_GetTransferCountEDMA + * + * param base pointer to FLEXIO_MCULCD_Type structure. + * param handle pointer to flexio_mculcd_edma_handle_t structure to store the + * transfer state. + * param xfer Pointer to FlexIO MCULCD transfer structure. + * retval kStatus_Success Successfully start a transfer. + * retval kStatus_InvalidArgument Input argument is invalid. + * retval kStatus_FLEXIO_MCULCD_Busy FlexIO MCULCD is not idle, it is running another + * transfer. + */ +status_t FLEXIO_MCULCD_TransferEDMA(FLEXIO_MCULCD_Type *base, + flexio_mculcd_edma_handle_t *handle, + flexio_mculcd_transfer_t *xfer) +{ + assert(NULL != handle); + assert(NULL != xfer); + + /* + * The data transfer mechanism: + * + * Read: + * Assume the data length is Lr = (n1 * minorLoopBytes + n2), where + * n2 < minorLoopBytes. + * If (n1 <= 1), then all data are sent using blocking method. + * If (n1 > 1), then the beginning ((n1-1) * minorLoopBytes) are read + * using DMA, the left (minorLoopBytes + n2) are read using blocking method. + * + * Write: + * Assume the data length is Lw = (n1 * minorLoopBytes + n2), where + * n2 < minorLoopBytes. + * If (n1 = 0), then all data are sent using blocking method. + * If (n1 >= 1), then the beginning (n1 * minorLoopBytes) are sent + * using DMA, the left n2 are sent using blocking method. + */ + + /* Check if the device is busy. */ + if ((uint32_t)kFLEXIO_MCULCD_StateIdle != handle->state) + { + return kStatus_FLEXIO_MCULCD_Busy; + } + + /* Set the state in handle. */ + if (kFLEXIO_MCULCD_ReadArray == xfer->mode) + { + handle->state = (uint32_t)kFLEXIO_MCULCD_StateReadArray; + handle->minorLoopBytes = handle->rxShifterNum * 4UL; + } + else + { + handle->minorLoopBytes = handle->txShifterNum * 4UL; + + if (kFLEXIO_MCULCD_WriteArray == xfer->mode) + { + handle->state = (uint32_t)kFLEXIO_MCULCD_StateWriteArray; + } + else + { + handle->state = (uint32_t)kFLEXIO_MCULCD_StateWriteSameValue; + } + } + + /* + * For TX, if data is less than one minor loop, then use polling method. + * For RX, if data is less than two minor loop, then use polling method. + */ + if ((xfer->dataSize < handle->minorLoopBytes) || + ((kFLEXIO_MCULCD_ReadArray == xfer->mode) && (xfer->dataSize < 2U * (handle->minorLoopBytes)))) + { + FLEXIO_MCULCD_TransferBlocking(base, xfer); + + handle->state = (uint32_t)kFLEXIO_MCULCD_StateIdle; + + /* Callback to inform upper layer. */ + if (NULL != handle->completionCallback) + { + handle->completionCallback(base, handle, kStatus_FLEXIO_MCULCD_Idle, handle->userData); + } + } + else + { + handle->dataCount = xfer->dataSize; + handle->remainingCount = xfer->dataSize; + handle->dataAddrOrSameValue = xfer->dataAddrOrSameValue; + + /* Setup DMA to transfer data. */ + /* Assert the nCS. */ + FLEXIO_MCULCD_StartTransfer(base); + /* Send the command. */ + FLEXIO_MCULCD_WriteCommandBlocking(base, xfer->command); + + /* Setup the DMA configuration. */ + FLEXIO_MCULCD_EDMAConfig(base, handle); + + /* Start the transfer. */ + if (kFLEXIO_MCULCD_ReadArray == xfer->mode) + { + /* For 6800, assert the RDWR pin. */ + if (kFLEXIO_MCULCD_6800 == base->busType) + { + base->setRDWRPin(true); + } + FLEXIO_MCULCD_SetMultiBeatsReadConfig(base); + FLEXIO_MCULCD_EnableRxDMA(base, true); + EDMA_StartTransfer(handle->rxDmaHandle); + } + else + { + /* For 6800, de-assert the RDWR pin. */ + if (kFLEXIO_MCULCD_6800 == base->busType) + { + base->setRDWRPin(false); + } + FLEXIO_MCULCD_SetMultiBeatsWriteConfig(base); + FLEXIO_MCULCD_EnableTxDMA(base, true); + EDMA_StartTransfer(handle->txDmaHandle); + } + } + + return kStatus_Success; +} + +/*! + * brief Aborts a FlexIO MCULCD transfer using eDMA. + * + * param base pointer to FLEXIO_MCULCD_Type structure. + * param handle FlexIO MCULCD eDMA handle pointer. + */ +void FLEXIO_MCULCD_TransferAbortEDMA(FLEXIO_MCULCD_Type *base, flexio_mculcd_edma_handle_t *handle) +{ + assert(NULL != handle); + + /* Disable dma. */ + if (NULL != handle->txDmaHandle) + { + EDMA_AbortTransfer(handle->txDmaHandle); + } + if (NULL != handle->rxDmaHandle) + { + EDMA_AbortTransfer(handle->rxDmaHandle); + } + + /* Disable DMA enable bit. */ + FLEXIO_MCULCD_EnableTxDMA(handle->base, false); + FLEXIO_MCULCD_EnableRxDMA(handle->base, false); + + /* Set the handle state. */ + handle->state = (uint32_t)kFLEXIO_MCULCD_StateIdle; + handle->dataCount = 0; +} + +/*! + * brief Gets the remaining bytes for FlexIO MCULCD eDMA transfer. + * + * param base pointer to FLEXIO_MCULCD_Type structure. + * param handle FlexIO MCULCD eDMA handle pointer. + * param count Number of count transferred so far by the eDMA transaction. + * retval kStatus_Success Get the transferred count Successfully. + * retval kStatus_NoTransferInProgress No transfer in process. + */ +status_t FLEXIO_MCULCD_TransferGetCountEDMA(FLEXIO_MCULCD_Type *base, + flexio_mculcd_edma_handle_t *handle, + size_t *count) +{ + assert(NULL != handle); + assert(NULL != count); + uint32_t state = handle->state; + + if ((uint32_t)kFLEXIO_MCULCD_StateIdle == state) + { + return kStatus_NoTransferInProgress; + } + else + { + *count = handle->dataCount - handle->remainingCount; + + if ((uint32_t)kFLEXIO_MCULCD_StateReadArray == state) + { + *count -= handle->minorLoopBytes * + EDMA_GetRemainingMajorLoopCount(handle->rxDmaHandle->base, handle->rxDmaHandle->channel); + } + else + { + *count -= handle->minorLoopBytes * + EDMA_GetRemainingMajorLoopCount(handle->txDmaHandle->base, handle->txDmaHandle->channel); + } + } + + return kStatus_Success; +} |