From 044ad7c3987460ede48ff27afd6bdb0ca05a0432 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 4 Jul 2011 20:52:54 +0200 Subject: import at91lib from at91lib_20100901_softpack_1_9_v_1_0_svn_v15011 it's sad to see that atmel doesn't publish their svn repo or has a centralized location or even puts proper version/release info into the library itself --- drivers/dmad/dmad.c | 300 ++++++++++++++++++++++++++++++++++++++++++++++++++ drivers/dmad/dmad.dir | 36 ++++++ drivers/dmad/dmad.h | 158 ++++++++++++++++++++++++++ 3 files changed, 494 insertions(+) create mode 100644 drivers/dmad/dmad.c create mode 100644 drivers/dmad/dmad.dir create mode 100644 drivers/dmad/dmad.h (limited to 'drivers/dmad') diff --git a/drivers/dmad/dmad.c b/drivers/dmad/dmad.c new file mode 100644 index 0000000..75187d0 --- /dev/null +++ b/drivers/dmad/dmad.c @@ -0,0 +1,300 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "dmad.h" +#include +#include +#include +#include + +//------------------------------------------------------------------------------ +// Local types +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +/// DMA transfer descriptor. Tracks the status and parameters of a transfer +/// on the DMA bus. +//------------------------------------------------------------------------------ +typedef struct _DmaTransfer { + /// Buffer transfer status. + volatile unsigned char status; + /// Transfer buffer size in byte. + unsigned int bufSize; + /// Total transfer size to byte. + volatile unsigned int transferSize; + /// Optional callback function. + DmaCallback callback; +} DmaTransfer; + +//------------------------------------------------------------------------------ +/// DMAD driver structure. Monitors the status of transfers on all +/// DMA channels. +//------------------------------------------------------------------------------ +typedef struct _Dmad { + + /// List of transfers occuring on each channel. + DmaTransfer transfers[DMA_CHANNEL_NUM]; +} Dmad; + +//------------------------------------------------------------------------------ +// Local variables +//------------------------------------------------------------------------------ + +/// Global DMA transfer instance. +static Dmad dmad; + +//------------------------------------------------------------------------------ +// Local functions +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +/// This handler function must be called by the DMAC interrupt service routine. +/// Identifies which event was activated and calls the associated function. +//------------------------------------------------------------------------------ +void DMAD_Handler() +{ + unsigned int status; + unsigned char channel; + DmaTransfer *pTransfer; + status = DMA_GetStatus(); + // Check if the buffer transfer completed is set. + if(status & AT91C_BTC) + { + // Scan each channel status. + for(channel = 0; channel < DMA_CHANNEL_NUM; channel++) { + if(!(status & (DMA_BTC << channel))){ + continue; + } + + dmad.transfers[channel].transferSize -= dmad.transfers[channel].bufSize; + // if next buffer is to be the last buffer in the transfer, then clear the automatic mode bit. + if(dmad.transfers[channel].transferSize <= dmad.transfers[channel].bufSize) { + DMA_ClearAutoMode(channel); + } + // Transfer finished + if(dmad.transfers[channel].transferSize == 0) { + pTransfer = &(dmad.transfers[channel]); + pTransfer->callback(); + DMA_DisableIt(DMA_BTC << channel); + DMA_DisableChannel(channel); + } + else + { + // Write the KEEPON field to clear the STALL states. + DMA_KeeponChannel(channel); + } + } + } +} + +//------------------------------------------------------------------------------ +/// Initializes the DMA controller. +/// \param channel Particular channel number +/// \param defaultHandler Using the default dmad interrupt handler. +//------------------------------------------------------------------------------ +void DMAD_Initialize(unsigned char channel, unsigned char defaultHandler) +{ + unsigned int status; + unsigned int flag; + + // Enable peripheral clock +#if !defined(at91sam9rl64) + AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_HDMA; +#endif + + // Read the channel handler status to ensure the channel is a free channel. + status = DMA_GetChannelStatus(); + TRACE_INFO ("DMAD_Initialize channel %x \n\r", channel); + SANITY_CHECK(!(status & (1 << channel))); + // Clear any pending interrupts on the channel. + DMA_GetStatus(); + // Disble the channel. + DMA_DisableChannel(channel); + // Disable the interrupt + flag = 0xffffff; + DMA_DisableIt(flag); + // Enable DMA. + DMA_Enable(); + if(defaultHandler) + { + IRQ_ConfigureIT(AT91C_ID_HDMA, 0, DMAD_Handler); + IRQ_EnableIT(AT91C_ID_HDMA); + } + // Initialize transfer instance. + dmad.transfers[channel].transferSize = 0; +} + +//------------------------------------------------------------------------------ +/// Configure the DMA transfer buffer by giving transfer mode, it could be single +/// buffer or multi-buffer(LLI/auto-reload/contiguous buffers) with or without +/// Picture-In-Picture mode. +/// \param channel Particular channel number. +/// \param sourceTransferMode Source buffer transfer mode. +/// \param destTransferMode Destination buffer transfer mode. +/// \param lli Pointer to a DmaLinkList structure instance. +/// \param pip Pointer to a PictureInPicture structure. +//------------------------------------------------------------------------------ +unsigned char DMAD_Configure_Buffer(unsigned char channel, + unsigned char sourceTransferMode, + unsigned char destTransferMode, + DmaLinkList *lli, + PictureInPicture *pip) +{ + DmaTransfer *pTransfer = &(dmad.transfers[channel]); + // Check that no transfer is pending on the channel + if (pTransfer-> transferSize > 0 ) { + TRACE_ERROR("DAM transfer is already pending\n\r"); + return DMAD_ERROR_BUSY; + } + // Configure source transfer mode. + DMA_SetSourceBufferMode(channel, sourceTransferMode, 0); + + // Configure destination transfer mode. + DMA_SetDestBufferMode(channel, destTransferMode, 0); + + if(lli){ + DMA_SetDescriptorAddr(channel, (unsigned int)(&lli[0])); + } + else { + DMA_SetDescriptorAddr(channel, 0); + } + + if(pip){ + #if defined(AT91C_SRC_PIP) + // If source picture-in-picture mode is enabled, program the DMAC_SPIP. + if(pip->pipSourceBoundarySize){ + // If destination picture-in-picture mode is enabled, program the DMAC_DPIP. + DMA_SPIPconfiguration(channel, pip->pipSourceHoleSize, pip->pipSourceBoundarySize); + } + #endif + + #if defined(AT91C_DST_PIP) + if(pip->pipDestBoundarySize){ + DMA_DPIPconfiguration(channel, pip->pipDestHoleSize, pip->pipDestBoundarySize); + } + #endif + } + return 0; +} + +//------------------------------------------------------------------------------ +/// Configure the DMA transfer control infomation. +/// \param channel Particular channel number. +/// \param bufSize Buffer transfer size in byte. +/// \param sourceWidth Source transfer width. +/// \param destWidth Destination transfer width. +/// \param sourceAddress Destination transfer width. +/// \param destAddress Destination transfer width. +//------------------------------------------------------------------------------ +unsigned char DMAD_Configure_TransferController(unsigned char channel, + unsigned int bufSize, + unsigned char sourceWidth, + unsigned char destWidth, + unsigned int sourceAddress, + unsigned int destAddress) +{ + DmaTransfer *pTransfer = &(dmad.transfers[channel]); + // Check that no transfer is pending on the channel + if (pTransfer-> transferSize > 0 ) { + TRACE_ERROR("DAM transfer is already pending\n\r"); + return DMAD_ERROR_BUSY; + } + pTransfer->bufSize = bufSize; + + // Set up the transfer width and transfer size. + DMA_SetSourceBufferSize(channel, bufSize, sourceWidth, destWidth, 0); + + if(sourceAddress) { + // Write the starting source address. + DMA_SetSourceAddr(channel, sourceAddress); + } + if(destAddress){ + // Write the starting destination address. + DMA_SetDestinationAddr(channel, destAddress); + } + return 0; +} + +//------------------------------------------------------------------------------ +/// Starts buffer transfer on the given channel +/// \param channel Particular channel number. +/// \param size Total transfer size in byte. +/// \param callback Optional callback function. +/// \param polling Polling channel status enable. +//------------------------------------------------------------------------------ +unsigned char DMAD_BufferTransfer(unsigned char channel, + unsigned int size, + DmaCallback callback, + unsigned char polling) +{ + DmaTransfer *pTransfer = &(dmad.transfers[channel]); + // Check that no transfer is pending on the channel + if (pTransfer-> transferSize > 0 ) { + TRACE_ERROR("DAM transfer is already pending\n\r"); + return DMAD_ERROR_BUSY; + } + pTransfer->status = DMAD_ERROR_BUSY; + pTransfer->transferSize = size; + pTransfer->callback = callback; + + if(!polling){ + DMA_EnableIt(DMA_BTC << channel); + } + // Enable the channel. + DMA_EnableChannel(channel); + + if(polling){ + while ((DMA_GetChannelStatus() & (DMA_ENA << channel)) == (DMA_ENA << channel)); + if (pTransfer->callback) { + pTransfer->callback(); + } + pTransfer->transferSize = 0; + DMA_DisableChannel(channel); + } + return 0; +} + +//------------------------------------------------------------------------------ +/// Returns 1 if no transfer is currently pending on the given channel; +/// otherwise, returns 0. +/// \param channel Channel number. +//------------------------------------------------------------------------------ +unsigned char DMAD_IsFinished(unsigned char channel) +{ + SANITY_CHECK(channel <= DMA_CHANNEL_NUM); + if (dmad.transfers[channel].transferSize > 0) { + return 0; + } + else { + DMA_DisableChannel(channel); + return 1; + } +} diff --git a/drivers/dmad/dmad.dir b/drivers/dmad/dmad.dir new file mode 100644 index 0000000..a9ec454 --- /dev/null +++ b/drivers/dmad/dmad.dir @@ -0,0 +1,36 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \dir +/// +/// !!!Contents +/// +/// This directory contains the source code for the DMA driver in dmad.h. +//------------------------------------------------------------------------------ diff --git a/drivers/dmad/dmad.h b/drivers/dmad/dmad.h new file mode 100644 index 0000000..dfb0886 --- /dev/null +++ b/drivers/dmad/dmad.h @@ -0,0 +1,158 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \unit +/// +/// !!!Purpose +/// +/// The %Dma driver is a high level dma driver which performs DMA device Initializes, +/// tansfer mode configuration and dma transfer. +/// +/// !!!Usage +/// +/// -# Initializes a %Dma controller and dma transfer instance. +/// Initializes dma for specified channel using DMAD_Initialize(). +/// -# Configures the %Dma transfer buffer by giving transfer mode, transfer mode +/// for source peripheral and destination peripheral could be single buffer or +/// multi-buffer(LLI/auto-reload/contiguous buffers) with or without +/// Picture-In-Picture mode. +/// DMAD_Configure_Buffer() +/// \code +/// // Configure multi-buffer transfer with source address auto-reloaded and +/// contiguous destination address. +/// DMAD_Configure_Buffer(DMA_CHANNEL_1, +/// DMA_TRANSFER_RELOAD, +/// DMA_TRANSFER_CONTIGUOUS, +/// 0, +/// 0); +/// \endcode +/// -# Configures the %Dma characteristics (such as source/destination +/// single transfer width, buffer transfer size and source/destionation +/// start addreass for the device corresponding to the specified channle +/// using DMAD_Configure_TransferController(). +/// -# Starts a %Dma transfer using DMAD_BufferTransfer(). +/// The transfer is performed using the %Dma channels. +/// -# Initialize the total size to be transfered. +/// -# Initialize the callback function if specified. +/// -# Enable the interrupt for specified %dma channel. +/// -# Enable the specified %dma channel. +/// -# Example for transfering buffer through the %Dma. +/// \code +/// // Start channel 1 transfer. Source image auto-reload 4 times. +/// and transfer to destination continguous. +/// DMAD_BufferTransfer(DMA_CHANNEL_1, bufferSize * 4, TestCallback, 0); +/// while (!DMAD_IsFinished(DMA_CHANNEL_1)); +/// \endcode +/// -# The DMAD_Handler() must be called by the DMA Interrupt Service Routine +/// with the corresponding %Dma instance. It is invokes to check for pending +/// interrupts. +/// - Example for initializing %Dma interrupt handler in upper application. +/// \code +/// AIC_ConfigureIT(AT91C_ID_HDMA, 0, DMAD_Handler); +/// \endcode +//------------------------------------------------------------------------------ + +#ifndef DMAD_H +#define DMAD_H + +//------------------------------------------------------------------------------ +// Global definitions +//------------------------------------------------------------------------------ +/// DMA driver is currently busy. +#define DMAD_ERROR_BUSY 1 +/// Using the default interrupt handler of the DMAD +#define DMAD_USE_DEFAULT_IT 1 +#define DMAD_NO_DEFAULT_IT 0 + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +/// DMA driver callback function. +typedef void (*DmaCallback)(); + +//------------------------------------------------------------------------------ +/// DMA multi buffer transfer Linker List Item structure. +//------------------------------------------------------------------------------ +typedef struct _DmaLinkList { + /// Source address. + unsigned int sourceAddress; + /// Destination address. + unsigned int destAddress; + /// Control A value. + unsigned int controlA; + /// Control B value. + unsigned int controlB; + /// Descriptor Address. + unsigned int descriptor; +} DmaLinkList; + +//------------------------------------------------------------------------------ +/// DMA picture-in-picture mode configuration structure. +//------------------------------------------------------------------------------ +typedef struct _PictureInPicture { + /// Size in byte add to the source address in PIP. + unsigned short pipSourceHoleSize; + /// Number of transfer in byte to perform before the source address increase. + unsigned short pipSourceBoundarySize; + /// Size in byte add to the destination address in PIP. + unsigned short pipDestHoleSize; + /// Number of transfer in byte to perform before the destination address increase. + unsigned short pipDestBoundarySize; +} PictureInPicture; + + +//------------------------------------------------------------------------------ +// Global functions +//------------------------------------------------------------------------------ +extern void DMAD_Initialize(unsigned char channel, unsigned char defaultHandler); + +extern unsigned char DMAD_Configure_Buffer(unsigned char channel, + unsigned char sourceTransferMode, + unsigned char destTransferMode, + DmaLinkList *lli, + PictureInPicture *pip); + +extern unsigned char DMAD_Configure_TransferController(unsigned char channel, + unsigned int bufSize, + unsigned char sourceWidth, + unsigned char destWidth, + unsigned int sourceAddress, + unsigned int destAddress); + +extern unsigned char DMAD_BufferTransfer(unsigned char channel, + unsigned int size, + DmaCallback callback, + unsigned char polling); + +extern unsigned char DMAD_IsFinished(unsigned char channel); + +#endif //#ifndef DMAD_H + -- cgit v1.2.3