summaryrefslogtreecommitdiff
path: root/drivers/dmad
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/dmad')
-rw-r--r--drivers/dmad/dmad.c300
-rw-r--r--drivers/dmad/dmad.dir36
-rw-r--r--drivers/dmad/dmad.h158
3 files changed, 494 insertions, 0 deletions
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 <dma/dma.h>
+#include <irq/irq.h>
+#include <utility/assert.h>
+#include <utility/trace.h>
+
+//------------------------------------------------------------------------------
+// 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
+
personal git repositories of Harald Welte. Your mileage may vary