/* * Copyright (c) 2015, Freescale Semiconductor, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted 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 Freescale Semiconductor, Inc. nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * 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 ******************************************************************************/ /******************************************************************************* * Prototypes ******************************************************************************/ /*! * @brief Get instance number for DMA. * * @param base DMA peripheral base address. */ static uint32_t DMA_GetInstance(DMA_Type *base); /******************************************************************************* * Variables ******************************************************************************/ /*! @brief Array to map DMA instance number to base pointer. */ static DMA_Type *const s_dmaBases[] = DMA_BASE_PTRS; /*! @brief Array to map DMA instance number to clock name. */ static const clock_ip_name_t s_dmaClockName[] = DMA_CLOCKS; /*! @brief Array to map DMA instance number to IRQ number. */ static const IRQn_Type s_dmaIRQNumber[] = DMA_CHN_IRQS; /*! @brief Pointers to transfer handle for each DMA channel. */ static dma_handle_t *s_DMAHandle[FSL_FEATURE_DMAMUX_MODULE_CHANNEL * FSL_FEATURE_SOC_DMA_COUNT]; /******************************************************************************* * Code ******************************************************************************/ static uint32_t DMA_GetInstance(DMA_Type *base) { uint32_t instance; /* Find the instance index from base address mappings. */ for (instance = 0; instance < FSL_FEATURE_SOC_DMA_COUNT; instance++) { if (s_dmaBases[instance] == base) { break; } } assert(instance < FSL_FEATURE_SOC_DMA_COUNT); return instance; } void DMA_Init(DMA_Type *base) { CLOCK_EnableClock(s_dmaClockName[DMA_GetInstance(base)]); } void DMA_Deinit(DMA_Type *base) { CLOCK_DisableClock(s_dmaClockName[DMA_GetInstance(base)]); } void DMA_ResetChannel(DMA_Type *base, uint32_t channel) { assert(channel < FSL_FEATURE_DMAMUX_MODULE_CHANNEL); /* clear all status bit */ base->DMA[channel].DSR_BCR |= DMA_DSR_BCR_DONE(true); /* clear all registers */ base->DMA[channel].SAR = 0; base->DMA[channel].DAR = 0; base->DMA[channel].DSR_BCR = 0; /* enable cycle steal and enable auto disable channel request */ base->DMA[channel].DCR = DMA_DCR_D_REQ(true) | DMA_DCR_CS(true); } void DMA_SetTransferConfig(DMA_Type *base, uint32_t channel, const dma_transfer_config_t *config) { assert(channel < FSL_FEATURE_DMAMUX_MODULE_CHANNEL); assert(config != NULL); uint32_t tmpreg; /* Set source address */ base->DMA[channel].SAR = config->srcAddr; /* Set destination address */ base->DMA[channel].DAR = config->destAddr; /* Set transfer bytes */ base->DMA[channel].DSR_BCR = DMA_DSR_BCR_BCR(config->transferSize); /* Set DMA Control Register */ tmpreg = base->DMA[channel].DCR; tmpreg &= ~(DMA_DCR_DSIZE_MASK | DMA_DCR_DINC_MASK | DMA_DCR_SSIZE_MASK | DMA_DCR_SINC_MASK); tmpreg |= (DMA_DCR_DSIZE(config->destSize) | DMA_DCR_DINC(config->enableDestIncrement) | DMA_DCR_SSIZE(config->srcSize) | DMA_DCR_SINC(config->enableSrcIncrement)); base->DMA[channel].DCR = tmpreg; } void DMA_SetChannelLinkConfig(DMA_Type *base, uint32_t channel, const dma_channel_link_config_t *config) { assert(channel < FSL_FEATURE_DMAMUX_MODULE_CHANNEL); assert(config != NULL); uint32_t tmpreg; tmpreg = base->DMA[channel].DCR; tmpreg &= ~(DMA_DCR_LINKCC_MASK | DMA_DCR_LCH1_MASK | DMA_DCR_LCH2_MASK); tmpreg |= (DMA_DCR_LINKCC(config->linkType) | DMA_DCR_LCH1(config->channel1) | DMA_DCR_LCH2(config->channel2)); base->DMA[channel].DCR = tmpreg; } void DMA_SetModulo(DMA_Type *base, uint32_t channel, dma_modulo_t srcModulo, dma_modulo_t destModulo) { assert(channel < FSL_FEATURE_DMAMUX_MODULE_CHANNEL); uint32_t tmpreg; tmpreg = base->DMA[channel].DCR; tmpreg &= ~(DMA_DCR_SMOD_MASK | DMA_DCR_DMOD_MASK); tmpreg |= (DMA_DCR_SMOD(srcModulo) | DMA_DCR_DMOD(destModulo)); base->DMA[channel].DCR = tmpreg; } void DMA_CreateHandle(dma_handle_t *handle, DMA_Type *base, uint32_t channel) { assert(handle != NULL); assert(channel < FSL_FEATURE_DMAMUX_MODULE_CHANNEL); uint32_t dmaInstance; uint32_t channelIndex; handle->base = base; handle->channel = channel; /* Get the DMA instance number */ dmaInstance = DMA_GetInstance(base); channelIndex = (dmaInstance * FSL_FEATURE_DMAMUX_MODULE_CHANNEL) + channel; /* Store handle */ s_DMAHandle[channelIndex] = handle; /* Enable NVIC interrupt. */ EnableIRQ(s_dmaIRQNumber[channelIndex]); } void DMA_PrepareTransfer(dma_transfer_config_t *config, void *srcAddr, uint32_t srcWidth, void *destAddr, uint32_t destWidth, uint32_t transferBytes, dma_transfer_type_t type) { assert(config != NULL); assert(srcAddr != NULL); assert(destAddr != NULL); assert(srcWidth == 1U || srcWidth == 2U || srcWidth == 4U); assert(destWidth == 1U || destWidth == 2U || destWidth == 4U); config->srcAddr = (uint32_t)srcAddr; config->destAddr = (uint32_t)destAddr; config->transferSize = transferBytes; switch (srcWidth) { case 1U: config->srcSize = kDMA_Transfersize8bits; break; case 2U: config->srcSize = kDMA_Transfersize16bits; break; case 4U: config->srcSize = kDMA_Transfersize32bits; break; default: break; } switch (destWidth) { case 1U: config->destSize = kDMA_Transfersize8bits; break; case 2U: config->destSize = kDMA_Transfersize16bits; break; case 4U: config->destSize = kDMA_Transfersize32bits; break; default: break; } switch (type) { case kDMA_MemoryToMemory: config->enableSrcIncrement = true; config->enableDestIncrement = true; break; case kDMA_PeripheralToMemory: config->enableSrcIncrement = false; config->enableDestIncrement = true; break; case kDMA_MemoryToPeripheral: config->enableSrcIncrement = true; config->enableDestIncrement = false; break; default: break; } } void DMA_SetCallback(dma_handle_t *handle, dma_callback callback, void *userData) { assert(handle != NULL); handle->callback = callback; handle->userData = userData; } status_t DMA_SubmitTransfer(dma_handle_t *handle, const dma_transfer_config_t *config, uint32_t options) { assert(handle != NULL); assert(config != NULL); /* Check if DMA is busy */ if (handle->base->DMA[handle->channel].DSR_BCR & DMA_DSR_BCR_BSY_MASK) { return kStatus_DMA_Busy; } DMA_ResetChannel(handle->base, handle->channel); DMA_SetTransferConfig(handle->base, handle->channel, config); if (options & kDMA_EnableInterrupt) { DMA_EnableInterrupts(handle->base, handle->channel); } return kStatus_Success; } void DMA_AbortTransfer(dma_handle_t *handle) { assert(handle != NULL); handle->base->DMA[handle->channel].DCR &= ~DMA_DCR_ERQ_MASK; /* clear all status bit */ handle->base->DMA[handle->channel].DSR_BCR |= DMA_DSR_BCR_DONE(true); } void DMA_HandleIRQ(dma_handle_t *handle) { assert(handle != NULL); /* Clear interrupt pending bit */ DMA_ClearChannelStatusFlags(handle->base, handle->channel, kDMA_TransactionsDoneFlag); if (handle->callback) { (handle->callback)(handle, handle->userData); } } #if defined(FSL_FEATURE_DMAMUX_MODULE_CHANNEL) && (FSL_FEATURE_DMAMUX_MODULE_CHANNEL == 4U) void DMA0_DriverIRQHandler(void) { DMA_HandleIRQ(s_DMAHandle[0]); } void DMA1_DriverIRQHandler(void) { DMA_HandleIRQ(s_DMAHandle[1]); } void DMA2_DriverIRQHandler(void) { DMA_HandleIRQ(s_DMAHandle[2]); } void DMA3_DriverIRQHandler(void) { DMA_HandleIRQ(s_DMAHandle[3]); } #endif /* FSL_FEATURE_DMAMUX_MODULE_CHANNEL */