123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481 |
- /*
- * The Clear BSD License
- * Copyright (c) 2016, Freescale Semiconductor, Inc.
- * Copyright 2016-2017 NXP
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted (subject to the limitations in the disclaimer below) provided
- * that the following conditions are met:
- *
- * o Redistributions of source code must retain the above copyright notice, this list
- * of conditions and the following disclaimer.
- *
- * o Redistributions in binary form must reproduce the above copyright notice, this
- * list of conditions and the following disclaimer in the documentation and/or
- * other materials provided with the distribution.
- *
- * o Neither the name of the copyright holder nor the names of its
- * contributors may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE.
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- #include "fsl_dma.h"
- /*******************************************************************************
- * Definitions
- ******************************************************************************/
- /* Component ID definition, used by tools. */
- #ifndef FSL_COMPONENT_ID
- #define FSL_COMPONENT_ID "platform.drivers.lpc_dma"
- #endif
- /*******************************************************************************
- * Prototypes
- ******************************************************************************/
- /*!
- * @brief Get instance number for DMA.
- *
- * @param base DMA peripheral base address.
- */
- static uint32_t DMA_GetInstance(DMA_Type *base);
- /*!
- * @brief Get virtual channel number.
- *
- * @param base DMA peripheral base address.
- */
- static uint32_t DMA_GetVirtualStartChannel(DMA_Type *base);
- /*******************************************************************************
- * Variables
- ******************************************************************************/
- /*! @brief Array to map DMA instance number to base pointer. */
- static DMA_Type *const s_dmaBases[] = DMA_BASE_PTRS;
- #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
- /*! @brief Array to map DMA instance number to clock name. */
- static const clock_ip_name_t s_dmaClockName[] = DMA_CLOCKS;
- #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
- /*! @brief Array to map DMA instance number to IRQ number. */
- static const IRQn_Type s_dmaIRQNumber[] = DMA_IRQS;
- /*! @brief Pointers to transfer handle for each DMA channel. */
- static dma_handle_t *s_DMAHandle[FSL_FEATURE_DMA_ALL_CHANNELS];
- /*! @brief Static table of descriptors */
- #if defined(__ICCARM__)
- #pragma data_alignment = FSL_FEATURE_DMA_DESCRIPTOR_ALIGN_SIZE
- static dma_descriptor_t s_dma_descriptor_table[FSL_FEATURE_SOC_DMA_COUNT][FSL_FEATURE_DMA_MAX_CHANNELS] = {0};
- #elif defined(__CC_ARM)
- __attribute__((aligned(FSL_FEATURE_DMA_DESCRIPTOR_ALIGN_SIZE)))
- static dma_descriptor_t s_dma_descriptor_table[FSL_FEATURE_SOC_DMA_COUNT][FSL_FEATURE_DMA_MAX_CHANNELS] = {0};
- #elif defined(__GNUC__)
- __attribute__((aligned(FSL_FEATURE_DMA_DESCRIPTOR_ALIGN_SIZE)))
- static dma_descriptor_t s_dma_descriptor_table[FSL_FEATURE_SOC_DMA_COUNT][FSL_FEATURE_DMA_MAX_CHANNELS] = {0};
- #endif
- /*******************************************************************************
- * Code
- ******************************************************************************/
- static uint32_t DMA_GetInstance(DMA_Type *base)
- {
- int32_t instance;
- /* Find the instance index from base address mappings. */
- for (instance = 0; instance < ARRAY_SIZE(s_dmaBases); instance++)
- {
- if (s_dmaBases[instance] == base)
- {
- break;
- }
- }
- assert(instance < ARRAY_SIZE(s_dmaBases));
- return instance;
- }
- static uint32_t DMA_GetVirtualStartChannel(DMA_Type *base)
- {
- uint32_t startChannel = 0, instance = 0;
- uint32_t i = 0;
- instance = DMA_GetInstance(base);
- /* Compute start channel */
- for (i = 0; i < instance; i++)
- {
- startChannel += FSL_FEATURE_DMA_NUMBER_OF_CHANNELSn(s_dmaBases[i]);
- }
- return startChannel;
- }
- void DMA_Init(DMA_Type *base)
- {
- #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
- /* enable dma clock gate */
- CLOCK_EnableClock(s_dmaClockName[DMA_GetInstance(base)]);
- #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
- /* set descriptor table */
- base->SRAMBASE = (uint32_t)s_dma_descriptor_table;
- /* enable dma peripheral */
- base->CTRL |= DMA_CTRL_ENABLE_MASK;
- }
- void DMA_Deinit(DMA_Type *base)
- {
- #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
- CLOCK_DisableClock(s_dmaClockName[DMA_GetInstance(base)]);
- #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
- /* Disable DMA peripheral */
- base->CTRL &= ~(DMA_CTRL_ENABLE_MASK);
- }
- void DMA_ConfigureChannelTrigger(DMA_Type *base, uint32_t channel, dma_channel_trigger_t *trigger)
- {
- assert((channel < FSL_FEATURE_DMA_NUMBER_OF_CHANNELSn(base)) && (NULL != trigger));
- uint32_t tmp = (DMA_CHANNEL_CFG_HWTRIGEN_MASK | DMA_CHANNEL_CFG_TRIGPOL_MASK | DMA_CHANNEL_CFG_TRIGTYPE_MASK |
- DMA_CHANNEL_CFG_TRIGBURST_MASK | DMA_CHANNEL_CFG_BURSTPOWER_MASK |
- DMA_CHANNEL_CFG_SRCBURSTWRAP_MASK | DMA_CHANNEL_CFG_DSTBURSTWRAP_MASK);
- tmp = base->CHANNEL[channel].CFG & (~tmp);
- tmp |= (uint32_t)(trigger->type) | (uint32_t)(trigger->burst) | (uint32_t)(trigger->wrap);
- base->CHANNEL[channel].CFG = tmp;
- }
- /*!
- * @brief Gets the remaining bytes of the current DMA descriptor transfer.
- *
- * @param base DMA peripheral base address.
- * @param channel DMA channel number.
- * @return The number of bytes which have not been transferred yet.
- */
- uint32_t DMA_GetRemainingBytes(DMA_Type *base, uint32_t channel)
- {
- assert(channel < FSL_FEATURE_DMA_NUMBER_OF_CHANNELSn(base));
- /* NOTE: when descriptors are chained, ACTIVE bit is set for whole chain. It makes
- * impossible to distinguish between:
- * - transfer finishes (represented by value '0x3FF')
- * - and remaining 1024 bytes to transfer (value 0x3FF)
- * for all descriptor in chain, except the last one.
- * If you decide to use this function, please use 1023 transfers as maximal value */
- /* Channel not active (transfer finished) and value is 0x3FF - nothing to transfer */
- if ((!DMA_ChannelIsActive(base, channel)) &&
- (0x3FF == ((base->CHANNEL[channel].XFERCFG & DMA_CHANNEL_XFERCFG_XFERCOUNT_MASK) >>
- DMA_CHANNEL_XFERCFG_XFERCOUNT_SHIFT)))
- {
- return 0;
- }
- return ((base->CHANNEL[channel].XFERCFG & DMA_CHANNEL_XFERCFG_XFERCOUNT_MASK) >>
- DMA_CHANNEL_XFERCFG_XFERCOUNT_SHIFT) +
- 1;
- }
- static void DMA_SetupDescriptor(
- dma_descriptor_t *desc, uint32_t xfercfg, void *srcEndAddr, void *dstEndAddr, void *nextDesc)
- {
- desc->xfercfg = xfercfg;
- desc->srcEndAddr = srcEndAddr;
- desc->dstEndAddr = dstEndAddr;
- desc->linkToNextDesc = nextDesc;
- }
- /* Verify and convert dma_xfercfg_t to XFERCFG register */
- static void DMA_SetupXferCFG(dma_xfercfg_t *xfercfg, uint32_t *xfercfg_addr)
- {
- assert(xfercfg != NULL);
- /* check source increment */
- assert((xfercfg->srcInc == 0) || (xfercfg->srcInc == 1) || (xfercfg->srcInc == 2) || (xfercfg->srcInc == 4));
- /* check destination increment */
- assert((xfercfg->dstInc == 0) || (xfercfg->dstInc == 1) || (xfercfg->dstInc == 2) || (xfercfg->dstInc == 4));
- /* check data width */
- assert((xfercfg->byteWidth == 1) || (xfercfg->byteWidth == 2) || (xfercfg->byteWidth == 4));
- /* check transfer count */
- assert(xfercfg->transferCount <= DMA_MAX_TRANSFER_COUNT);
- uint32_t xfer = 0, tmp;
- /* set valid flag - descriptor is ready now */
- xfer |= DMA_CHANNEL_XFERCFG_CFGVALID(xfercfg->valid ? 1 : 0);
- /* set reload - allow link to next descriptor */
- xfer |= DMA_CHANNEL_XFERCFG_RELOAD(xfercfg->reload ? 1 : 0);
- /* set swtrig flag - start transfer */
- xfer |= DMA_CHANNEL_XFERCFG_SWTRIG(xfercfg->swtrig ? 1 : 0);
- /* set transfer count */
- xfer |= DMA_CHANNEL_XFERCFG_CLRTRIG(xfercfg->clrtrig ? 1 : 0);
- /* set INTA */
- xfer |= DMA_CHANNEL_XFERCFG_SETINTA(xfercfg->intA ? 1 : 0);
- /* set INTB */
- xfer |= DMA_CHANNEL_XFERCFG_SETINTB(xfercfg->intB ? 1 : 0);
- /* set data width */
- tmp = xfercfg->byteWidth == 4 ? 2 : xfercfg->byteWidth - 1;
- xfer |= DMA_CHANNEL_XFERCFG_WIDTH(tmp);
- /* set source increment value */
- tmp = xfercfg->srcInc == 4 ? 3 : xfercfg->srcInc;
- xfer |= DMA_CHANNEL_XFERCFG_SRCINC(tmp);
- /* set destination increment value */
- tmp = xfercfg->dstInc == 4 ? 3 : xfercfg->dstInc;
- xfer |= DMA_CHANNEL_XFERCFG_DSTINC(tmp);
- /* set transfer count */
- xfer |= DMA_CHANNEL_XFERCFG_XFERCOUNT(xfercfg->transferCount - 1);
- /* store xferCFG */
- *xfercfg_addr = xfer;
- }
- void DMA_CreateDescriptor(dma_descriptor_t *desc, dma_xfercfg_t *xfercfg, void *srcAddr, void *dstAddr, void *nextDesc)
- {
- uint32_t xfercfg_reg = 0;
- assert((NULL != desc) && (0 == (uint32_t)desc % 16) && (NULL != xfercfg));
- assert((NULL != srcAddr) && (0 == (uint32_t)srcAddr % xfercfg->byteWidth));
- assert((NULL != dstAddr) && (0 == (uint32_t)dstAddr % xfercfg->byteWidth));
- assert((NULL == nextDesc) || (0 == (uint32_t)nextDesc % 16));
- /* Setup channel configuration */
- DMA_SetupXferCFG(xfercfg, &xfercfg_reg);
- /* Set descriptor structure */
- DMA_SetupDescriptor(
- desc, xfercfg_reg, (uint8_t *)srcAddr + (xfercfg->srcInc * xfercfg->byteWidth * (xfercfg->transferCount - 1)),
- (uint8_t *)dstAddr + (xfercfg->dstInc * xfercfg->byteWidth * (xfercfg->transferCount - 1)), nextDesc);
- }
- void DMA_AbortTransfer(dma_handle_t *handle)
- {
- assert(NULL != handle);
- DMA_DisableChannel(handle->base, handle->channel);
- while (DMA_COMMON_CONST_REG_GET(handle->base, handle->channel, BUSY) & (1U << DMA_CHANNEL_INDEX(handle->channel)))
- {
- }
- DMA_COMMON_REG_GET(handle->base, handle->channel, ABORT) |= 1U << DMA_CHANNEL_INDEX(handle->channel);
- DMA_EnableChannel(handle->base, handle->channel);
- }
- void DMA_CreateHandle(dma_handle_t *handle, DMA_Type *base, uint32_t channel)
- {
- assert((NULL != handle) && (channel < FSL_FEATURE_DMA_NUMBER_OF_CHANNELSn(base)));
- int32_t dmaInstance;
- uint32_t startChannel = 0;
- /* base address is invalid DMA instance */
- dmaInstance = DMA_GetInstance(base);
- startChannel = DMA_GetVirtualStartChannel(base);
- memset(handle, 0, sizeof(*handle));
- handle->base = base;
- handle->channel = channel;
- s_DMAHandle[startChannel + channel] = handle;
- /* Enable NVIC interrupt */
- EnableIRQ(s_dmaIRQNumber[dmaInstance]);
- }
- void DMA_SetCallback(dma_handle_t *handle, dma_callback callback, void *userData)
- {
- assert(handle != NULL);
- handle->callback = callback;
- handle->userData = userData;
- }
- void DMA_PrepareTransfer(dma_transfer_config_t *config,
- void *srcAddr,
- void *dstAddr,
- uint32_t byteWidth,
- uint32_t transferBytes,
- dma_transfer_type_t type,
- void *nextDesc)
- {
- uint32_t xfer_count;
- assert((NULL != config) && (NULL != srcAddr) && (NULL != dstAddr));
- assert((byteWidth == 1) || (byteWidth == 2) || (byteWidth == 4));
- /* check max */
- xfer_count = transferBytes / byteWidth;
- assert((xfer_count <= DMA_MAX_TRANSFER_COUNT) && (0 == transferBytes % byteWidth));
- memset(config, 0, sizeof(*config));
- switch (type)
- {
- case kDMA_MemoryToMemory:
- config->xfercfg.srcInc = 1;
- config->xfercfg.dstInc = 1;
- config->isPeriph = false;
- break;
- case kDMA_PeripheralToMemory:
- /* Peripheral register - source doesn't increment */
- config->xfercfg.srcInc = 0;
- config->xfercfg.dstInc = 1;
- config->isPeriph = true;
- break;
- case kDMA_MemoryToPeripheral:
- /* Peripheral register - destination doesn't increment */
- config->xfercfg.srcInc = 1;
- config->xfercfg.dstInc = 0;
- config->isPeriph = true;
- break;
- case kDMA_StaticToStatic:
- config->xfercfg.srcInc = 0;
- config->xfercfg.dstInc = 0;
- config->isPeriph = true;
- break;
- default:
- return;
- }
- config->dstAddr = (uint8_t *)dstAddr;
- config->srcAddr = (uint8_t *)srcAddr;
- config->nextDesc = (uint8_t *)nextDesc;
- config->xfercfg.transferCount = xfer_count;
- config->xfercfg.byteWidth = byteWidth;
- config->xfercfg.intA = true;
- config->xfercfg.reload = nextDesc != NULL;
- config->xfercfg.valid = true;
- }
- status_t DMA_SubmitTransfer(dma_handle_t *handle, dma_transfer_config_t *config)
- {
- assert((NULL != handle) && (NULL != config));
- uint32_t instance = DMA_GetInstance(handle->base);
- /* Previous transfer has not finished */
- if (DMA_ChannelIsActive(handle->base, handle->channel))
- {
- return kStatus_DMA_Busy;
- }
- /* enable/disable peripheral request */
- if (config->isPeriph)
- {
- DMA_EnableChannelPeriphRq(handle->base, handle->channel);
- }
- else
- {
- DMA_DisableChannelPeriphRq(handle->base, handle->channel);
- }
- DMA_CreateDescriptor(&(s_dma_descriptor_table[instance][handle->channel]), &config->xfercfg, config->srcAddr,
- config->dstAddr, config->nextDesc);
- return kStatus_Success;
- }
- void DMA_StartTransfer(dma_handle_t *handle)
- {
- assert(NULL != handle);
- uint32_t instance = DMA_GetInstance(handle->base);
- /* Enable channel interrupt */
- DMA_EnableChannelInterrupts(handle->base, handle->channel);
- /* If HW trigger is enabled - disable SW trigger */
- if (handle->base->CHANNEL[handle->channel].CFG & DMA_CHANNEL_CFG_HWTRIGEN_MASK)
- {
- s_dma_descriptor_table[instance][handle->channel].xfercfg &= ~(DMA_CHANNEL_XFERCFG_SWTRIG_MASK);
- }
- /* Otherwise enable SW trigger */
- else
- {
- s_dma_descriptor_table[instance][handle->channel].xfercfg |= DMA_CHANNEL_XFERCFG_SWTRIG_MASK;
- }
- /* Set channel XFERCFG register according first channel descriptor. */
- handle->base->CHANNEL[handle->channel].XFERCFG = s_dma_descriptor_table[instance][handle->channel].xfercfg;
- /* At this moment, the channel ACTIVE bit is set and application cannot modify
- * or start another transfer using this channel. Channel ACTIVE bit is cleared by
- * 'AbortTransfer' function or when the transfer finishes */
- }
- void DMA_IRQHandle(DMA_Type *base)
- {
- dma_handle_t *handle;
- int32_t channel_index;
- uint32_t startChannel = DMA_GetVirtualStartChannel(base);
- uint32_t i = 0;
- /* Find channels that have completed transfer */
- for (i = 0; i < FSL_FEATURE_DMA_NUMBER_OF_CHANNELSn(base); i++)
- {
- handle = s_DMAHandle[i + startChannel];
- /* Handle is not present */
- if (NULL == handle)
- {
- continue;
- }
- channel_index = DMA_CHANNEL_INDEX(handle->channel);
- /* Channel uses INTA flag */
- if (DMA_COMMON_REG_GET(handle->base, handle->channel, INTA) & (1U << channel_index))
- {
- /* Clear INTA flag */
- DMA_COMMON_REG_SET(handle->base, handle->channel, INTA, (1U << channel_index));
- if (handle->callback)
- {
- (handle->callback)(handle, handle->userData, true, kDMA_IntA);
- }
- }
- /* Channel uses INTB flag */
- if (DMA_COMMON_REG_GET(handle->base, handle->channel, INTB) & (1U << channel_index))
- {
- /* Clear INTB flag */
- DMA_COMMON_REG_SET(handle->base, handle->channel, INTB, (1U << channel_index));
- if (handle->callback)
- {
- (handle->callback)(handle, handle->userData, true, kDMA_IntB);
- }
- }
- /* Error flag */
- if (DMA_COMMON_REG_GET(handle->base, handle->channel, ERRINT) & (1U << channel_index))
- {
- /* Clear error flag */
- DMA_COMMON_REG_SET(handle->base, handle->channel, ERRINT, (1U << channel_index));
- if (handle->callback)
- {
- (handle->callback)(handle, handle->userData, false, kDMA_IntError);
- }
- }
- }
- }
- void DMA0_DriverIRQHandler(void)
- {
- DMA_IRQHandle(DMA0);
- /* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping
- exception return operation might vector to incorrect interrupt */
- #if defined __CORTEX_M && (__CORTEX_M == 4U)
- __DSB();
- #endif
- }
- #if defined(DMA1)
- void DMA1_DriverIRQHandler(void)
- {
- DMA_IRQHandle(DMA1);
- /* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping
- exception return operation might vector to incorrect interrupt */
- #if defined __CORTEX_M && (__CORTEX_M == 4U)
- __DSB();
- #endif
- }
- #endif
|