123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470 |
- /*
- * Copyright 2019-2020 NXP
- * All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
- #include "fsl_asrc_edma.h"
- /* Component ID definition, used by tools. */
- #ifndef FSL_COMPONENT_ID
- #define FSL_COMPONENT_ID "platform.drivers.asrc_edma"
- #endif
- /*******************************************************************************
- * Definitations
- ******************************************************************************/
- /* Used for 32byte aligned */
- #define STCD_ADDR(address) (edma_tcd_t *)(((uint32_t)(address) + 32U) & ~0x1FU)
- /*<! Structure definition for uart_edma_private_handle_t. The structure is private. */
- typedef struct _asrc_edma_private_handle
- {
- ASRC_Type *base;
- asrc_edma_handle_t *handle;
- } asrc_edma_private_handle_t;
- /*<! Private handle only used for internally. */
- static asrc_edma_private_handle_t s_edmaPrivateHandle[FSL_FEATURE_SOC_ASRC_COUNT][FSL_ASRC_CHANNEL_PAIR_COUNT];
- /*******************************************************************************
- * Prototypes
- ******************************************************************************/
- /*!
- * @brief ASRC EDMA callback for input.
- *
- * @param handle pointer to asrc_edma_handle_t structure which stores the transfer state.
- * @param userData Parameter for user callback.
- * @param done If the DMA transfer finished.
- * @param tcds The TCD index.
- */
- static void ASRC_InEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds);
- /*!
- * @brief ASRC EDMA callback for output.
- *
- * @param handle pointer to asrc_edma_handle_t structure which stores the transfer state.
- * @param userData Parameter for user callback.
- * @param done If the DMA transfer finished.
- * @param tcds The TCD index.
- */
- static void ASRC_OutEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds);
- /*******************************************************************************
- * Code
- ******************************************************************************/
- static void ASRC_InEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds)
- {
- asrc_edma_private_handle_t *privHandle = (asrc_edma_private_handle_t *)userData;
- asrc_edma_handle_t *asrcHandle = privHandle->handle;
- asrc_in_edma_handle_t *asrcInHandle = &(privHandle->handle->in);
- status_t inStatus = kStatus_ASRCInIdle;
- /* If finished a block, call the callback function */
- asrcInHandle->asrcQueue[asrcInHandle->queueDriver] = NULL;
- asrcInHandle->queueDriver = (asrcInHandle->queueDriver + 1U) % ASRC_XFER_QUEUE_SIZE;
- /* If all data finished, just stop the transfer */
- if (asrcInHandle->asrcQueue[asrcInHandle->queueDriver] == NULL)
- {
- EDMA_AbortTransfer(asrcInHandle->inDmaHandle);
- inStatus = kStatus_ASRCInQueueIdle;
- }
- if (asrcHandle->callback != NULL)
- {
- (asrcHandle->callback)(privHandle->base, asrcHandle, inStatus, asrcHandle->userData);
- }
- }
- static void ASRC_OutEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds)
- {
- asrc_edma_private_handle_t *privHandle = (asrc_edma_private_handle_t *)userData;
- asrc_edma_handle_t *asrcHandle = privHandle->handle;
- asrc_out_edma_handle_t *asrcOutHandle = &(privHandle->handle->out);
- uint32_t queueDriverIndex = asrcOutHandle->queueDriver;
- status_t callbackStatus = kStatus_ASRCOutIdle;
- /* If finished a block, call the callback function */
- asrcOutHandle->asrcQueue[queueDriverIndex] = NULL;
- asrcOutHandle->queueDriver = (uint8_t)((queueDriverIndex + 1U) % ASRC_XFER_OUT_QUEUE_SIZE);
- /* If all data finished, just stop the transfer */
- if (asrcOutHandle->asrcQueue[asrcOutHandle->queueDriver] == NULL)
- {
- EDMA_AbortTransfer(asrcOutHandle->outDmaHandle);
- callbackStatus = kStatus_ASRCOutQueueIdle;
- }
- if (asrcHandle->callback != NULL)
- {
- (asrcHandle->callback)(privHandle->base, asrcHandle, callbackStatus, asrcHandle->userData);
- }
- }
- /*!
- * brief Initializes the ASRC IN eDMA handle.
- *
- * This function initializes the ASRC DMA handle, which can be used for other ASRC transactional APIs.
- * Usually, for a specified ASRC channel pair, call this API once to get the initialized handle.
- *
- * param base ASRC base pointer.
- * param channelPair ASRC channel pair
- * param handle ASRC eDMA handle pointer.
- * param callback Pointer to user callback function.
- * param txDmaHandle ASRC send edma handle pointer.
- * param periphConfig peripheral configuration.
- * param userData User parameter passed to the callback function.
- */
- void ASRC_TransferInCreateHandleEDMA(ASRC_Type *base,
- asrc_edma_handle_t *handle,
- asrc_channel_pair_t channelPair,
- asrc_edma_callback_t callback,
- edma_handle_t *inDmaHandle,
- const asrc_p2p_edma_config_t *periphConfig,
- void *userData)
- {
- assert((handle != NULL) && (inDmaHandle != NULL));
- uint32_t instance = ASRC_GetInstance(base);
- /* Zero the handle */
- (void)memset(&handle->in, 0, sizeof(asrc_in_edma_handle_t));
- handle->in.inDmaHandle = inDmaHandle;
- handle->callback = callback;
- handle->userData = userData;
- /* Set ASRC state to idle */
- handle->in.state = kStatus_ASRCIdle;
- handle->channelPair = channelPair;
- handle->in.peripheralConfig = periphConfig;
- s_edmaPrivateHandle[instance][channelPair].base = base;
- s_edmaPrivateHandle[instance][channelPair].handle = handle;
- /* Need to use scatter gather */
- EDMA_InstallTCDMemory(inDmaHandle, (edma_tcd_t *)(STCD_ADDR(handle->in.tcd)), ASRC_XFER_OUT_QUEUE_SIZE);
- /* Install callback for Tx dma channel */
- EDMA_SetCallback(inDmaHandle, ASRC_InEDMACallback, &s_edmaPrivateHandle[instance][channelPair]);
- }
- /*!
- * brief Initializes the ASRC OUT eDMA handle.
- *
- * This function initializes the ASRC DMA handle, which can be used for other ASRC transactional APIs.
- * Usually, for a specified ASRC channel pair, call this API once to get the initialized handle.
- *
- * param base ASRC base pointer.
- * param channelPair ASRC channel pair
- * param handle ASRC eDMA handle pointer.
- * param callback Pointer to user callback function.
- * param txDmaHandle ASRC send edma handle pointer.
- * param periphConfig peripheral configuration.
- * param userData User parameter passed to the callback function.
- */
- void ASRC_TransferOutCreateHandleEDMA(ASRC_Type *base,
- asrc_edma_handle_t *handle,
- asrc_channel_pair_t channelPair,
- asrc_edma_callback_t callback,
- edma_handle_t *outDmaHandle,
- const asrc_p2p_edma_config_t *periphConfig,
- void *userData)
- {
- assert((handle != NULL) && (NULL != outDmaHandle));
- uint32_t instance = ASRC_GetInstance(base);
- /* Zero the handle */
- (void)memset(&handle->out, 0, sizeof(asrc_out_edma_handle_t));
- handle->out.outDmaHandle = outDmaHandle;
- handle->callback = callback;
- handle->userData = userData;
- /* Set ASRC state to idle */
- handle->out.state = kStatus_ASRCIdle;
- handle->channelPair = channelPair;
- handle->out.peripheralConfig = periphConfig;
- s_edmaPrivateHandle[instance][channelPair].base = base;
- s_edmaPrivateHandle[instance][channelPair].handle = handle;
- /* Need to use scatter gather */
- EDMA_InstallTCDMemory(outDmaHandle, (edma_tcd_t *)(STCD_ADDR(handle->out.tcd)), ASRC_XFER_OUT_QUEUE_SIZE);
- /* Install callback for Tx dma channel */
- EDMA_SetCallback(outDmaHandle, ASRC_OutEDMACallback, &s_edmaPrivateHandle[instance][channelPair]);
- }
- /*!
- * brief Configures the ASRC channel pair.
- *
- * param base ASRC base pointer.
- * param handle ASRC eDMA handle pointer.
- * param asrcConfig asrc configurations.
- * param periphConfig peripheral configuration.
- * param inputSampleRate ASRC input sample rate.
- * param outputSampleRate ASRC output sample rate.
- */
- status_t ASRC_TransferSetChannelPairConfigEDMA(ASRC_Type *base,
- asrc_edma_handle_t *handle,
- asrc_channel_pair_config_t *asrcConfig,
- uint32_t inSampleRate,
- uint32_t outSampleRate)
- {
- assert((handle != NULL) && (NULL != asrcConfig));
- /* Configure the audio format to ASRC registers */
- if (ASRC_SetChannelPairConfig(base, handle->channelPair, asrcConfig, inSampleRate, outSampleRate) !=
- kStatus_Success)
- {
- return kStatus_ASRCChannelPairConfigureFailed;
- }
- handle->in.fifoThreshold = (asrcConfig->inFifoThreshold) * (uint32_t)asrcConfig->audioDataChannels;
- handle->out.fifoThreshold = (asrcConfig->outFifoThreshold) * (uint32_t)asrcConfig->audioDataChannels;
- (void)ASRC_MapSamplesWidth(base, handle->channelPair, &handle->in.sampleWidth, &handle->out.sampleWidth);
- return kStatus_Success;
- }
- /*!
- * brief Get output sample buffer size can be transferred by edma.
- *
- * note This API is depends on the ASRC output configuration, should be called after the
- * ASRC_TransferSetChannelPairConfigEDMA.
- *
- * param base asrc base pointer.
- * param handle ASRC channel pair edma handle.
- * param inSampleRate input sample rate.
- * param outSampleRate output sample rate.
- * param inSamples input sampleS size.
- * retval output buffer size in byte.
- */
- uint32_t ASRC_GetOutSamplesSizeEDMA(
- ASRC_Type *base, asrc_edma_handle_t *handle, uint32_t inSampleRate, uint32_t outSampleRate, uint32_t inSamplesize)
- {
- uint32_t outputSize = ASRC_GetOutSamplesSize(base, handle->channelPair, inSampleRate, outSampleRate, inSamplesize);
- return outputSize - outputSize % handle->out.fifoThreshold;
- }
- static status_t ASRC_TransferOutSubmitEDMA(ASRC_Type *base,
- asrc_edma_handle_t *handle,
- uint32_t *outDataAddr,
- uint32_t outDataSize)
- {
- assert(outDataAddr != NULL);
- assert(outDataSize != 0U);
- uint32_t outAddr = ASRC_GetOutputDataRegisterAddress(base, handle->channelPair);
- edma_transfer_config_t config = {0};
- edma_transfer_type_t type = kEDMA_PeripheralToMemory;
- if (handle->out.asrcQueue[handle->out.queueUser] != NULL)
- {
- return kStatus_ASRCQueueFull;
- }
- if (handle->out.peripheralConfig != NULL)
- {
- type = kEDMA_PeripheralToPeripheral;
- }
- if (handle->out.asrcQueue[handle->out.queueUser] != NULL)
- {
- return kStatus_ASRCQueueFull;
- }
- handle->out.asrcQueue[handle->out.queueUser] = outDataAddr;
- handle->out.transferSize[handle->out.queueUser] = outDataSize;
- handle->out.queueUser = (handle->out.queueUser + 1U) % ASRC_XFER_OUT_QUEUE_SIZE;
- /* Prepare ASRC output edma configuration */
- EDMA_PrepareTransfer(&config, (uint32_t *)outAddr, handle->out.sampleWidth, outDataAddr, handle->out.sampleWidth,
- handle->out.fifoThreshold * handle->out.sampleWidth, outDataSize, type);
- if (handle->out.state != (uint32_t)kStatus_ASRCBusy)
- {
- (void)EDMA_SubmitTransfer(handle->out.outDmaHandle, &config);
- EDMA_StartTransfer(handle->out.outDmaHandle);
- if ((handle->out.peripheralConfig != NULL) && (handle->out.peripheralConfig->startPeripheral != NULL))
- {
- handle->out.peripheralConfig->startPeripheral(true);
- }
- }
- return kStatus_Success;
- }
- static status_t ASRC_TransferInSubmitEDMA(ASRC_Type *base,
- asrc_edma_handle_t *handle,
- uint32_t *inDataAddr,
- uint32_t inDataSize)
- {
- assert(inDataAddr != NULL);
- assert(inDataSize != 0U);
- uint32_t inAddr = ASRC_GetInputDataRegisterAddress(base, handle->channelPair);
- edma_transfer_config_t config = {0};
- if (handle->in.asrcQueue[handle->in.queueUser] != NULL)
- {
- return kStatus_ASRCQueueFull;
- }
- /* Add into queue */
- handle->in.asrcQueue[handle->in.queueUser] = inDataAddr;
- handle->in.transferSize[handle->in.queueUser] = inDataSize;
- handle->in.queueUser = (handle->in.queueUser + 1U) % ASRC_XFER_IN_QUEUE_SIZE;
- /* Prepare ASRC input edma configuration */
- EDMA_PrepareTransfer(&config, (uint32_t *)inDataAddr, handle->in.sampleWidth, (uint32_t *)inAddr,
- handle->in.sampleWidth, handle->in.fifoThreshold * handle->in.sampleWidth, inDataSize,
- handle->in.peripheralConfig == NULL ? kEDMA_MemoryToPeripheral : kEDMA_PeripheralToPeripheral);
- if (handle->in.state != (uint32_t)kStatus_ASRCBusy)
- {
- (void)EDMA_SubmitTransfer(handle->in.inDmaHandle, &config);
- EDMA_StartTransfer(handle->in.inDmaHandle);
- /* start peripheral */
- if ((handle->in.peripheralConfig != NULL) && (handle->in.peripheralConfig->startPeripheral != NULL))
- {
- handle->in.peripheralConfig->startPeripheral(true);
- }
- }
- return kStatus_Success;
- }
- /*!
- * brief Performs a non-blocking ASRC convert using EDMA.
- *
- * note This interface returns immediately after the transfer initiates.
- * param base ASRC base pointer.
- * param handle ASRC eDMA handle pointer.
- * param xfer Pointer to the DMA transfer structure.
- * retval kStatus_Success Start a ASRC eDMA send successfully.
- * retval kStatus_InvalidArgument The input argument is invalid.
- * retval kStatus_ASRCQueueFull ASRC EDMA driver queue is full.
- */
- status_t ASRC_TransferEDMA(ASRC_Type *base, asrc_edma_handle_t *handle, asrc_transfer_t *xfer)
- {
- assert(handle != NULL);
- if (ASRC_TransferOutSubmitEDMA(base, handle, xfer->outData, xfer->outDataSize) != kStatus_Success)
- {
- return kStatus_ASRCQueueFull;
- }
- if (ASRC_TransferInSubmitEDMA(base, handle, xfer->inData, xfer->inDataSize) != kStatus_Success)
- {
- return kStatus_ASRCQueueFull;
- }
- return kStatus_Success;
- }
- /*!
- * brief Aborts a ASRC IN transfer using eDMA.
- *
- * This function only aborts the current transfer slots, the other transfer slots' information still kept
- * in the handler. If users want to terminate all transfer slots, just call ASRC_TransferTerminalP2PEDMA.
- *
- * param base ASRC base pointer.
- * param handle ASRC eDMA handle pointer.
- */
- void ASRC_TransferInAbortEDMA(ASRC_Type *base, asrc_edma_handle_t *handle)
- {
- assert(handle != NULL);
- /* Disable dma */
- EDMA_AbortTransfer(handle->in.inDmaHandle);
- /* Handle the queue index */
- handle->in.asrcQueue[handle->in.queueDriver] = NULL;
- handle->in.queueDriver = (handle->in.queueDriver + 1U) % ASRC_XFER_QUEUE_SIZE;
- /* Set the handle state */
- handle->in.state = kStatus_ASRCIdle;
- }
- /*!
- * brief Aborts a ASRC OUT transfer using eDMA.
- *
- * This function only aborts the current transfer slots, the other transfer slots' information still kept
- * in the handler. If users want to terminate all transfer slots, just call ASRC_TransferTerminalP2PEDMA.
- *
- * param base ASRC base pointer.
- * param handle ASRC eDMA handle pointer.
- */
- void ASRC_TransferOutAbortEDMA(ASRC_Type *base, asrc_edma_handle_t *handle)
- {
- assert(handle != NULL);
- /* Disable dma */
- EDMA_AbortTransfer(handle->out.outDmaHandle);
- /* Handle the queue index */
- handle->out.asrcQueue[handle->out.queueDriver] = NULL;
- handle->out.queueDriver = (handle->out.queueDriver + 1U) % ASRC_XFER_QUEUE_SIZE;
- /* Set the handle state */
- handle->out.state = kStatus_ASRCIdle;
- }
- /*!
- * brief Terminate In ASRC Convert.
- *
- * This function will clear all transfer slots buffered in the asrc queue. If users only want to abort the
- * current transfer slot, please call ASRC_TransferAbortPP2PEDMA.
- *
- * param base ASRC base pointer.
- * param handle ASRC eDMA handle pointer.
- */
- void ASRC_TransferInTerminalEDMA(ASRC_Type *base, asrc_edma_handle_t *handle)
- {
- assert(handle != NULL);
- /* Abort the current transfer */
- ASRC_TransferInAbortEDMA(base, handle);
- /* stop peripheral */
- if ((handle->in.peripheralConfig != NULL) && (handle->in.peripheralConfig->startPeripheral != NULL))
- {
- handle->in.peripheralConfig->startPeripheral(false);
- }
- /* Clear all the internal information */
- (void)memset(handle->in.tcd, 0, sizeof(handle->in.tcd));
- (void)memset(handle->in.asrcQueue, 0, sizeof(handle->in.asrcQueue));
- (void)memset(handle->in.transferSize, 0, sizeof(handle->in.transferSize));
- handle->in.queueUser = 0U;
- handle->in.queueDriver = 0U;
- }
- /*!
- * brief Terminate Out ASRC Convert.
- *
- * This function will clear all transfer slots buffered in the asrc queue. If users only want to abort the
- * current transfer slot, please call ASRC_TransferAbortPP2PEDMA.
- *
- * param base ASRC base pointer.
- * param handle ASRC eDMA handle pointer.
- */
- void ASRC_TransferOutTerminalEDMA(ASRC_Type *base, asrc_edma_handle_t *handle)
- {
- assert(handle != NULL);
- /* Abort the current transfer */
- ASRC_TransferOutAbortEDMA(base, handle);
- if ((handle->out.peripheralConfig != NULL) && (handle->out.peripheralConfig->startPeripheral != NULL))
- {
- handle->out.peripheralConfig->startPeripheral(false);
- }
- (void)memset(handle->out.tcd, 0, sizeof(handle->out.tcd));
- (void)memset(handle->out.asrcQueue, 0, sizeof(handle->out.asrcQueue));
- (void)memset(handle->out.transferSize, 0, sizeof(handle->out.transferSize));
- handle->out.queueUser = 0U;
- handle->out.queueDriver = 0U;
- }
|