diff options
Diffstat (limited to 'target/linux/ep93xx/patches-2.6.30/005-ep93xx-dma.patch')
-rw-r--r-- | target/linux/ep93xx/patches-2.6.30/005-ep93xx-dma.patch | 3622 |
1 files changed, 0 insertions, 3622 deletions
diff --git a/target/linux/ep93xx/patches-2.6.30/005-ep93xx-dma.patch b/target/linux/ep93xx/patches-2.6.30/005-ep93xx-dma.patch deleted file mode 100644 index 3664132021..0000000000 --- a/target/linux/ep93xx/patches-2.6.30/005-ep93xx-dma.patch +++ /dev/null @@ -1,3622 +0,0 @@ ---- /dev/null -+++ b/arch/arm/mach-ep93xx/dma_ep93xx.c -@@ -0,0 +1,2940 @@ -+/****************************************************************************** -+ * arch/arm/mach-ep9312/dma_ep93xx.c -+ * -+ * Support functions for the ep93xx internal DMA channels. -+ * (see also Documentation/arm/ep93xx/dma.txt) -+ * -+ * Copyright (C) 2003 Cirrus Logic -+ * -+ * A large portion of this file is based on the dma api implemented by -+ * Nicolas Pitre, dma-sa1100.c, copyrighted 2000. -+ * -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ ****************************************************************************/ -+#include <linux/autoconf.h> -+#include <linux/module.h> -+#include <linux/init.h> -+#include <linux/sched.h> -+#include <linux/spinlock.h> -+#include <linux/slab.h> -+#include <linux/errno.h> -+#include <linux/delay.h> -+#include <linux/interrupt.h> -+ -+#include <asm/system.h> -+#include <asm/irq.h> -+#include <asm/hardware.h> -+#include <asm/io.h> -+#include <asm/dma.h> -+#include <asm/mach/dma.h> -+#include "dma_ep93xx.h" -+ -+/***************************************************************************** -+ * -+ * Debugging macros -+ * -+ ****************************************************************************/ -+#undef DEBUG -+//#define DEBUG 1 -+#ifdef DEBUG -+#define DPRINTK( fmt, arg... ) printk( fmt, ##arg ) -+#else -+#define DPRINTK( fmt, arg... ) -+#endif -+ -+/***************************************************************************** -+ * -+ * static global variables -+ * -+ ****************************************************************************/ -+ep93xx_dma_t dma_chan[MAX_EP93XX_DMA_CHANNELS]; -+ -+/* -+ * lock used to protect the list of dma channels while searching for a free -+ * channel during dma_request. -+ */ -+//static spinlock_t dma_list_lock; -+static spinlock_t dma_list_lock = SPIN_LOCK_UNLOCKED; -+ -+/***************************************************************************** -+ * -+ * Internal DMA processing functions. -+ * -+ ****************************************************************************/ -+/***************************************************************************** -+ * -+ * get_dma_channel_from_handle() -+ * -+ * If Handle is valid, returns the DMA channel # (0 to 9 for channels 1-10) -+ * If Handle is not valid, returns -1. -+ * -+ ****************************************************************************/ -+static int -+dma_get_channel_from_handle(int handle) -+{ -+ int channel; -+ -+ /* -+ * Get the DMA channel # from the handle. -+ */ -+ channel = ((int)handle & DMA_HANDLE_SPECIFIER_MASK) >> 28; -+ -+ /* -+ * See if this is a valid handle. -+ */ -+ if (dma_chan[channel].last_valid_handle != (int)handle) { -+ DPRINTK("DMA ERROR - invalid handle 0x%x \n", handle); -+ return(-1); -+ } -+ -+ /* -+ * See if this instance is still open -+ */ -+ if (!dma_chan[channel].ref_count ) -+ return(-1); -+ -+ return(channel); -+} -+ -+static void dma_m2m_transfer_done(ep93xx_dma_t *dma) -+{ -+ unsigned int uiCONTROL; -+ unsigned int M2M_reg_base = dma->reg_base; -+ unsigned int read_back; -+ -+ DPRINTK("1 "); -+ -+ outl( 0, M2M_reg_base+M2M_OFFSET_INTERRUPT ); -+ -+ if (dma->total_buffers) { -+ /* -+ * The current_buffer has already been tranfered, so add the -+ * byte count to the total_bytes field. -+ */ -+ dma->total_bytes = dma->total_bytes + -+ dma->buffer_queue[dma->current_buffer].size; -+ -+ /* -+ * Mark the current_buffer as used. -+ */ -+ dma->buffer_queue[dma->current_buffer].used = TRUE; -+ -+ /* -+ * Increment the used buffer counter -+ */ -+ dma->used_buffers++; -+ -+ DPRINTK("#%d", dma->current_buffer); -+ -+ /* -+ * Increment the current_buffer -+ */ -+ dma->current_buffer = (dma->current_buffer + 1) % -+ MAX_EP93XX_DMA_BUFFERS; -+ -+ /* -+ * check if there's a new buffer to transfer. -+ */ -+ if (dma->new_buffers && dma->xfer_enable) { -+ /* -+ * We have a new buffer to transfer so program in the -+ * buffer values. Since a STALL interrupt was -+ * triggered, we program the buffer descriptor 0 -+ * -+ * Set the SAR_BASE/DAR_BASE/BCR registers with values -+ * from the next buffer in the queue. -+ */ -+ outl( dma->buffer_queue[dma->current_buffer].source, -+ M2M_reg_base + M2M_OFFSET_SAR_BASE0 ); -+ -+ outl( dma->buffer_queue[dma->current_buffer].dest, -+ M2M_reg_base + M2M_OFFSET_DAR_BASE0 ); -+ -+ outl( dma->buffer_queue[dma->current_buffer].size, -+ M2M_reg_base + M2M_OFFSET_BCR0 ); -+ -+ DPRINTK("SAR_BASE0 - 0x%x\n", dma->buffer_queue[dma->current_buffer].source); -+ DPRINTK("DAR_BASE0 - 0x%x\n", dma->buffer_queue[dma->current_buffer].dest); -+ DPRINTK("BCR0 - 0x%x\n", dma->buffer_queue[dma->current_buffer].size); -+ -+ /* -+ * Decrement the new buffer counter -+ */ -+ dma->new_buffers--; -+ -+ /* -+ * If there's a second new buffer, we program the -+ * second buffer descriptor. -+ */ -+ if (dma->new_buffers) { -+ outl( dma->buffer_queue[(dma->current_buffer + 1) % -+ MAX_EP93XX_DMA_BUFFERS].source, -+ M2M_reg_base+M2M_OFFSET_SAR_BASE1 ); -+ -+ outl( dma->buffer_queue[(dma->current_buffer + 1) % -+ MAX_EP93XX_DMA_BUFFERS].dest, -+ M2M_reg_base+M2M_OFFSET_DAR_BASE1 ); -+ -+ outl( dma->buffer_queue[(dma->current_buffer + 1) % -+ MAX_EP93XX_DMA_BUFFERS].size, -+ M2M_reg_base+M2M_OFFSET_BCR1 ); -+ -+ uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL); -+ uiCONTROL |= CONTROL_M2M_NFBINTEN; -+ outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL ); -+ -+ dma->new_buffers--; -+ } -+ } else { -+ DPRINTK("2 \n"); -+ /* -+ * There's a chance we setup both buffer descriptors, -+ * but didn't service the NFB quickly enough, causing -+ * the channel to transfer both buffers, then enter the -+ * stall state. So, we need to be able to process the -+ * second buffer. -+ */ -+ if ((dma->used_buffers + dma->new_buffers) < dma->total_buffers) -+ { -+ DPRINTK("3 "); -+ -+ /* -+ * The current_buffer has already been -+ * tranferred, so add the byte count to the -+ * total_bytes field. -+ */ -+ dma->total_bytes = dma->total_bytes + -+ dma->buffer_queue[dma->current_buffer].size; -+ -+ /* -+ * Mark the current_buffer as used. -+ */ -+ dma->buffer_queue[dma->current_buffer].used = TRUE; -+ -+ /* -+ * Increment the used buffer counter -+ */ -+ dma->used_buffers++; -+ -+ DPRINTK("#%d", dma->current_buffer); -+ -+ /* -+ * Increment the current buffer pointer. -+ */ -+ dma->current_buffer = (dma->current_buffer + 1) % -+ MAX_EP93XX_DMA_BUFFERS; -+ -+ } -+ -+ /* -+ * No new buffers to transfer, so disable the channel. -+ */ -+ uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL); -+ uiCONTROL &= ~CONTROL_M2M_ENABLE; -+ outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL ); -+ -+ /* -+ * Indicate that this channel is in the pause by -+ * starvation state by setting the pause bit to true. -+ */ -+ dma->pause = TRUE; -+ } -+ } else { -+ /* -+ * No buffers to transfer, or old buffers to mark as used, -+ * so disable the channel -+ */ -+ uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL); -+ uiCONTROL &= ~CONTROL_M2M_ENABLE; -+ outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL ); -+ -+ /* -+ * Must read the control register back after a write. -+ */ -+ read_back = inl(M2M_reg_base+M2M_OFFSET_CONTROL); -+ -+ /* -+ * Indicate that this channel is in the pause by -+ * starvation state by setting the pause bit to true. -+ */ -+ dma->pause = TRUE; -+ } -+} -+ -+static void dma_m2m_next_frame_buffer(ep93xx_dma_t *dma) -+{ -+ int loop; -+ unsigned int uiCONTROL; -+ unsigned int M2M_reg_base = dma->reg_base; -+ -+ DPRINTK("5 "); -+ -+ if (dma->total_buffers) { -+ DPRINTK("6 "); -+ /* -+ * The iCurrentBuffer has already been transfered. so add the -+ * byte count from the current buffer to the total byte count. -+ */ -+ dma->total_bytes = dma->total_bytes + -+ dma->buffer_queue[dma->current_buffer].size; -+ -+ /* -+ * Mark the Current Buffer as used. -+ */ -+ dma->buffer_queue[dma->current_buffer].used = TRUE; -+ -+ /* -+ * Increment the used buffer counter -+ */ -+ dma->used_buffers++; -+ -+ DPRINTK("#%d", dma->current_buffer); -+ -+ if ((dma->buffer_queue[ -+ (dma->current_buffer + 1) % MAX_EP93XX_DMA_BUFFERS].last) || -+ (dma->new_buffers == 0) || (dma->xfer_enable == FALSE)) { -+ DPRINTK("7 "); -+ -+ /* -+ * This is the last Buffer in this transaction, so -+ * disable the NFB interrupt. We shouldn't get an NFB -+ * int when the FSM moves to the ON state where it -+ * would typically get the NFB int indicating a new -+ * buffer can be programmed. Instead, once in the ON -+ * state, the DMA will just proceed to complete the -+ * transfer of the current buffer, move the FSB -+ * directly to the STALL state where a STALL interrupt -+ * will be generated. -+ */ -+ uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL); -+ uiCONTROL &= ~CONTROL_M2M_NFBINTEN ; -+ outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL ); -+ -+ /* -+ * The current buffer has been transferred, so -+ * increment the current buffer counter to reflect -+ * this. -+ */ -+ dma->current_buffer = (dma->current_buffer + 1) % -+ MAX_EP93XX_DMA_BUFFERS; -+ -+ DPRINTK("End of NFB handling. \n"); -+ DPRINTK("CONTROL - 0x%x \n", -+ inl(M2M_reg_base+M2M_OFFSET_CONTROL) ); -+ DPRINTK("STATUS - 0x%x \n", -+ inl(M2M_reg_base+M2M_OFFSET_STATUS) ); -+ DPRINTK("SAR_BASE0 - 0x%x \n", -+ inl(M2M_reg_base+M2M_OFFSET_SAR_BASE0) ); -+ DPRINTK("SAR_CUR0 - 0x%x \n", -+ inl(M2M_reg_base+M2M_OFFSET_SAR_CURRENT0) ); -+ DPRINTK("DAR_BASE0 - 0x%x \n", -+ inl(M2M_reg_base+M2M_OFFSET_DAR_BASE0) ); -+ DPRINTK("DAR_CUR0 - 0x%x \n", -+ inl(M2M_reg_base+M2M_OFFSET_DAR_CURRENT0) ); -+ -+ DPRINTK("Buffer buf_id source size last used \n"); -+ for (loop = 0; loop < 32; loop ++) -+ DPRINTK("%d 0x%x 0x%x 0x%x %d %d \n", -+ loop, dma->buffer_queue[loop].buf_id, -+ dma->buffer_queue[loop].source, -+ dma->buffer_queue[loop].size, -+ dma->buffer_queue[loop].last, -+ dma->buffer_queue[loop].used); -+ DPRINTK("pause 0x%x 0x%x 0x%x %d %d \n", -+ dma->pause_buf.buf_id, dma->pause_buf.source, -+ dma->pause_buf.size, dma->pause_buf.last, -+ dma->pause_buf.used); -+ -+ DPRINTK("Pause - %d \n", dma->pause); -+ DPRINTK("xfer_enable - %d \n", dma->xfer_enable); -+ DPRINTK("total bytes - 0x%x \n", dma->total_bytes); -+ DPRINTK("total buffer - %d \n", dma->total_buffers); -+ DPRINTK("new buffers - %d \n", dma->new_buffers); -+ DPRINTK("current buffer - %d \n", dma->current_buffer); -+ DPRINTK("last buffer - %d \n", dma->last_buffer); -+ DPRINTK("used buffers - %d \n", dma->used_buffers); -+ DPRINTK("callback addr - 0x%p \n", dma->callback); -+ -+ } else if (dma->new_buffers) { -+ DPRINTK("8 "); -+ /* -+ * We have a new buffer, so increment the current -+ * buffer to point to the next buffer, which is already -+ * programmed into the DMA. Next time around, it'll be -+ * pointing to the current buffer. -+ */ -+ dma->current_buffer = (dma->current_buffer + 1) % -+ MAX_EP93XX_DMA_BUFFERS; -+ -+ /* -+ * We know we have a new buffer to program as the next -+ * buffer, so check which set of SAR_BASE/DAR_BASE/BCR -+ * registers to program. -+ */ -+ if ( inl(M2M_reg_base+M2M_OFFSET_STATUS) & STATUS_M2M_NB ) { -+ /* -+ * Set the SAR_BASE1/DAR_BASE1/BCR1 registers -+ * with values from the next buffer in the -+ * queue. -+ */ -+ outl( dma->buffer_queue[(dma->current_buffer + 1) % -+ MAX_EP93XX_DMA_BUFFERS].source, -+ M2M_reg_base+M2M_OFFSET_SAR_BASE1 ); -+ -+ outl( dma->buffer_queue[(dma->current_buffer + 1) % -+ MAX_EP93XX_DMA_BUFFERS].dest, -+ M2M_reg_base+M2M_OFFSET_DAR_BASE1 ); -+ -+ outl( dma->buffer_queue[(dma->current_buffer + 1) % -+ MAX_EP93XX_DMA_BUFFERS].size, -+ M2M_reg_base+M2M_OFFSET_BCR1 ); -+ } else { -+ /* -+ * Set the SAR_BASE0/DAR_BASE0/BCR0 registers -+ * with values from the next buffer in the -+ * queue. -+ */ -+ outl( dma->buffer_queue[(dma->current_buffer + 1) % -+ MAX_EP93XX_DMA_BUFFERS].source, -+ M2M_reg_base+M2M_OFFSET_SAR_BASE0 ); -+ -+ outl( dma->buffer_queue[(dma->current_buffer + 1) % -+ MAX_EP93XX_DMA_BUFFERS].dest, -+ M2M_reg_base+M2M_OFFSET_DAR_BASE0 ); -+ -+ outl( dma->buffer_queue[(dma->current_buffer + 1) % -+ MAX_EP93XX_DMA_BUFFERS].size, -+ M2M_reg_base+M2M_OFFSET_BCR0 ); -+ } -+ -+ /* -+ * Decrement the new buffers counter -+ */ -+ dma->new_buffers--; -+ } -+ } else { -+ /* -+ * Total number of buffers is 0 - really we should never get -+ * here, but just in case. -+ */ -+ DPRINTK("9 \n"); -+ -+ /* -+ * No new buffers to transfer, so Disable the channel -+ */ -+ uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL); -+ uiCONTROL &= ~CONTROL_M2M_ENABLE; -+ outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL ); -+ -+ /* -+ * Indicate that the channel is paused by starvation. -+ */ -+ dma->pause = 1; -+ } -+} -+ -+/***************************************************************************** -+ * -+ * dma_m2m_irq_handler -+ * -+ ****************************************************************************/ -+static irqreturn_t -+dma_m2m_irq_handler(int irq, void *dev_id) -+{ -+ ep93xx_dma_t *dma = (ep93xx_dma_t *)dev_id; -+ unsigned int M2M_reg_base = dma->reg_base; -+ ep93xx_dma_dev_t dma_int = UNDEF_INT; -+ int status; -+ -+// printk("+m2m irq=%d\n", irq); -+ -+ /* -+ * Determine what kind of dma interrupt this is. -+ */ -+ status = inl(M2M_reg_base + M2M_OFFSET_INTERRUPT); -+ if ( status & INTERRUPT_M2M_DONEINT ) -+ dma_int = DONE; // we're done with a requested dma -+ else if ( status & INTERRUPT_M2M_NFBINT ) -+ dma_int = NFB; // we're done with one dma buffer -+ -+ DPRINTK("IRQ: b=%#x st=%#x\n", (int)dma->current_buffer, dma_int); -+ -+ switch (dma_int) { -+ /* -+ * Next Frame Buffer Interrupt. If there's a new buffer program it -+ * Check if this is the last buffer in the transfer, -+ * and if it is, disable the NFB int to prevent being -+ * interrupted for another buffer when we know there won't be -+ * another. -+ */ -+ case NFB: -+ dma_m2m_next_frame_buffer(dma); -+ break; -+ /* -+ * Done interrupt generated, indicating that the transfer is complete. -+ */ -+ case DONE: -+ dma_m2m_transfer_done(dma); -+ break; -+ -+ default: -+ break; -+ } -+ -+ if ((dma_int != UNDEF_INT) && dma->callback) -+ dma->callback(dma_int, dma->device, dma->user_data); -+ -+ return IRQ_HANDLED; -+} -+ -+/***************************************************************************** -+ * -+ * dma_m2p_irq_handler -+ * -+ * -+ * -+ ****************************************************************************/ -+static irqreturn_t -+dma_m2p_irq_handler(int irq, void *dev_id) -+{ -+ ep93xx_dma_t *dma = (ep93xx_dma_t *) dev_id; -+ unsigned int M2P_reg_base = dma->reg_base; -+ unsigned int read_back; -+ ep93xx_dma_dev_t dma_int = UNDEF_INT; -+ unsigned int loop, uiCONTROL, uiINTERRUPT; -+ -+ /* -+ * Determine what kind of dma interrupt this is. -+ */ -+ if ( inl(M2P_reg_base+M2P_OFFSET_INTERRUPT) & INTERRUPT_M2P_STALLINT ) -+ dma_int = STALL; -+ else if ( inl(M2P_reg_base+M2P_OFFSET_INTERRUPT) & INTERRUPT_M2P_NFBINT ) -+ dma_int = NFB; -+ else if ( inl(M2P_reg_base+M2P_OFFSET_INTERRUPT) & INTERRUPT_M2P_CHERRORINT ) -+ dma_int = CHERROR; -+ -+ /* -+ * Stall Interrupt: The Channel is stalled, meaning nothing is -+ * programmed to transfer right now. So, we're back to the -+ * beginnning. If there's a buffer to transfer, program it into -+ * max and base 0 registers. -+ */ -+ if (dma_int == STALL) { -+ DPRINTK("1 "); -+ -+ if (dma->total_buffers) { -+ /* -+ * The current_buffer has already been tranfered, so -+ * add the byte count to the total_bytes field. -+ */ -+ dma->total_bytes = dma->total_bytes + -+ dma->buffer_queue[dma->current_buffer].size; -+ -+ /* -+ * Mark the current_buffer as used. -+ */ -+ dma->buffer_queue[dma->current_buffer].used = TRUE; -+ -+ /* -+ * Increment the used buffer counter -+ */ -+ dma->used_buffers++; -+ -+ DPRINTK("#%d", dma->current_buffer); -+ -+ /* -+ * Increment the current_buffer -+ */ -+ dma->current_buffer = (dma->current_buffer + 1) % -+ MAX_EP93XX_DMA_BUFFERS; -+ -+ /* -+ * check if there's a new buffer to transfer. -+ */ -+ if (dma->new_buffers && dma->xfer_enable) { -+ /* -+ * We have a new buffer to transfer so program -+ * in the buffer values. Since a STALL -+ * interrupt was triggered, we program the -+ * base0 and maxcnt0 -+ * -+ * Set the MAXCNT0 register with the buffer -+ * size -+ */ -+ outl( dma->buffer_queue[dma->current_buffer].size, -+ M2P_reg_base+M2P_OFFSET_MAXCNT0 ); -+ -+ /* -+ * Set the BASE0 register with the buffer base -+ * address -+ */ -+ outl( dma->buffer_queue[dma->current_buffer].source, -+ M2P_reg_base+M2P_OFFSET_BASE0 ); -+ -+ /* -+ * Decrement the new buffer counter -+ */ -+ dma->new_buffers--; -+ -+ if (dma->new_buffers) { -+ DPRINTK("A "); -+ /* -+ * Set the MAXCNT1 register with the -+ * buffer size -+ */ -+ outl( dma->buffer_queue[(dma->current_buffer + 1) % -+ MAX_EP93XX_DMA_BUFFERS].size, -+ M2P_reg_base+M2P_OFFSET_MAXCNT1 ); -+ -+ /* -+ * Set the BASE1 register with the -+ * buffer base address -+ */ -+ outl( dma->buffer_queue[dma->current_buffer + 1 % -+ MAX_EP93XX_DMA_BUFFERS].source, -+ M2P_reg_base+M2P_OFFSET_BASE1 ); -+ -+ /* -+ * Decrement the new buffer counter -+ */ -+ dma->new_buffers--; -+ -+ /* -+ * Enable the NFB Interrupt. -+ */ -+ uiCONTROL = inl(M2P_reg_base+M2P_OFFSET_CONTROL); -+ uiCONTROL |= CONTROL_M2P_NFBINTEN; -+ outl( uiCONTROL, M2P_reg_base+M2P_OFFSET_CONTROL ); -+ } -+ } else { -+ /* -+ * No new buffers. -+ */ -+ DPRINTK("2 \n"); -+ -+ /* -+ * There's a chance we setup both buffer descriptors, but -+ * didn't service the NFB quickly enough, causing the channel -+ * to transfer both buffers, then enter the stall state. -+ * So, we need to be able to process the second buffer. -+ */ -+ if ((dma->used_buffers + dma->new_buffers) < dma->total_buffers) { -+ DPRINTK("3 "); -+ -+ /* -+ * The current_buffer has already been tranfered, so add the -+ * byte count to the total_bytes field. -+ */ -+ dma->total_bytes = dma->total_bytes + -+ dma->buffer_queue[dma->current_buffer].size; -+ -+ /* -+ * Mark the current_buffer as used. -+ */ -+ dma->buffer_queue[dma->current_buffer].used = TRUE; -+ -+ /* -+ * Increment the used buffer counter -+ */ -+ dma->used_buffers++; -+ -+ DPRINTK("#%d", dma->current_buffer); -+ -+ /* -+ * Increment the current buffer pointer. -+ */ -+ dma->current_buffer = (dma->current_buffer + 1) % -+ MAX_EP93XX_DMA_BUFFERS; -+ -+ } -+ -+ /* -+ * No new buffers to transfer, so disable the channel. -+ */ -+ uiCONTROL = inl(M2P_reg_base+M2P_OFFSET_CONTROL); -+ uiCONTROL &= ~CONTROL_M2P_ENABLE; -+ outl( uiCONTROL, M2P_reg_base+M2P_OFFSET_CONTROL ); -+ -+ /* -+ * Indicate that this channel is in the pause by starvation -+ * state by setting the pause bit to true. -+ */ -+ dma->pause = TRUE; -+ -+ DPRINTK("STATUS - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_STATUS) ); -+ DPRINTK("CONTROL - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_CONTROL) ); -+ DPRINTK("REMAIN - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_REMAIN) ); -+ DPRINTK("PPALLOC - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_PPALLOC) ); -+ DPRINTK("BASE0 - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_BASE0) ); -+ DPRINTK("MAXCNT0 - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_MAXCNT0) ); -+ DPRINTK("CURRENT0 - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_CURRENT0) ); -+ DPRINTK("BASE1 - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_BASE1) ); -+ DPRINTK("MAXCNT1 - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_MAXCNT1) ); -+ DPRINTK("CURRENT1 - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_CURRENT1) ); -+ -+ DPRINTK("Buffer buf_id source size last used \n"); -+ for (loop = 0; loop < 32; loop ++) -+ DPRINTK("%d 0x%x 0x%x 0x%x %d %d \n", -+ loop, dma->buffer_queue[loop].buf_id, dma->buffer_queue[loop].source, -+ dma->buffer_queue[loop].size, -+ dma->buffer_queue[loop].last, dma->buffer_queue[loop].used); -+ DPRINTK("pause 0x%x 0x%x 0x%x %d %d \n", -+ dma->pause_buf.buf_id, dma->pause_buf.source, dma->pause_buf.size, -+ dma->pause_buf.last, dma->pause_buf.used); -+ -+ DPRINTK("Pause - %d \n", dma->pause); -+ DPRINTK("xfer_enable - %d \n", dma->xfer_enable); -+ DPRINTK("total bytes - 0x%x \n", dma->total_bytes); -+ DPRINTK("total buffer - %d \n", dma->total_buffers); -+ DPRINTK("new buffers - %d \n", dma->new_buffers); -+ DPRINTK("current buffer - %d \n", dma->current_buffer); -+ DPRINTK("last buffer - %d \n", dma->last_buffer); -+ DPRINTK("used buffers - %d \n", dma->used_buffers); -+ DPRINTK("callback addr - 0x%p \n", dma->callback); -+ } -+ } else { -+ /* -+ * No buffers to transfer, or old buffers to mark as used, -+ * so Disable the channel -+ */ -+ uiCONTROL = inl(M2P_reg_base+M2P_OFFSET_CONTROL); -+ uiCONTROL &= ~CONTROL_M2P_ENABLE; -+ outl( uiCONTROL, M2P_reg_base+M2P_OFFSET_CONTROL ); -+ -+ /* -+ * Must read the control register back after a write. -+ */ -+ read_back = inl(M2P_reg_base+M2P_OFFSET_CONTROL); -+ -+ /* -+ * Indicate that this channel is in the pause by -+ * starvation state by setting the pause bit to true. -+ */ -+ dma->pause = TRUE; -+ } -+ } -+ -+ /* -+ * Next Frame Buffer Interrupt. If there's a new buffer program it -+ * Check if this is the last buffer in the transfer, -+ * and if it is, disable the NFB int to prevent being -+ * interrupted for another buffer when we know there won't be -+ * another. -+ */ -+ if (dma_int == NFB) { -+ DPRINTK("5 "); -+ -+ if (dma->total_buffers) { -+ DPRINTK("6 "); -+ /* -+ * The iCurrentBuffer has already been transfered. so add the -+ * byte count from the current buffer to the total byte count. -+ */ -+ dma->total_bytes = dma->total_bytes + -+ dma->buffer_queue[dma->current_buffer].size; -+ -+ /* -+ * Mark the Current Buffer as used. -+ */ -+ dma->buffer_queue[dma->current_buffer].used = TRUE; -+ -+ /* -+ * Increment the used buffer counter -+ */ -+ dma->used_buffers++; -+ -+ DPRINTK("#%d", dma->current_buffer); -+ -+ if ((dma->buffer_queue[ -+ (dma->current_buffer + 1) % MAX_EP93XX_DMA_BUFFERS].last) || -+ (dma->new_buffers == 0) || (dma->xfer_enable == FALSE)) { -+ DPRINTK("7 "); -+ -+ /* -+ * This is the last Buffer in this transaction, so disable -+ * the NFB interrupt. We shouldn't get an NFB int when the -+ * FSM moves to the ON state where it would typically get the -+ * NFB int indicating a new buffer can be programmed. -+ * Instead, once in the ON state, the DMA will just proceed -+ * to complet the transfer of the current buffer, move the -+ * FSB directly to the STALL state where a STALL interrupt -+ * will be generated. -+ */ -+ uiCONTROL = inl(M2P_reg_base+M2P_OFFSET_CONTROL); -+ uiCONTROL &= ~CONTROL_M2P_NFBINTEN; -+ outl( uiCONTROL, M2P_reg_base+M2P_OFFSET_CONTROL ); -+ -+ /* -+ * The current buffer has been transferred, so increment -+ * the current buffer counter to reflect this. -+ */ -+ dma->current_buffer = (dma->current_buffer + 1) % MAX_EP93XX_DMA_BUFFERS; -+ -+ DPRINTK("End of NFB handling. \n"); -+ DPRINTK("STATUS - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_STATUS) ); -+ DPRINTK("CONTROL - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_CONTROL) ); -+ DPRINTK("REMAIN - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_REMAIN) ); -+ DPRINTK("PPALLOC - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_PPALLOC) ); -+ DPRINTK("BASE0 - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_BASE0) ); -+ DPRINTK("MAXCNT0 - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_MAXCNT0) ); -+ DPRINTK("CURRENT0 - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_CURRENT0) ); -+ DPRINTK("BASE1 - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_BASE1) ); -+ DPRINTK("MAXCNT1 - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_MAXCNT1) ); -+ DPRINTK("CURRENT1 - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_CURRENT1) ); -+ -+ DPRINTK("Buffer buf_id source size last used \n"); -+ for (loop = 0; loop < 32; loop ++) -+ DPRINTK("%d 0x%x 0x%x 0x%x %d %d \n", -+ loop, dma->buffer_queue[loop].buf_id, dma->buffer_queue[loop].source, -+ dma->buffer_queue[loop].size, -+ dma->buffer_queue[loop].last, dma->buffer_queue[loop].used); -+ DPRINTK("pause 0x%x 0x%x 0x%x %d %d \n", -+ dma->pause_buf.buf_id, dma->pause_buf.source, dma->pause_buf.size, -+ dma->pause_buf.last, dma->pause_buf.used); -+ -+ DPRINTK("Pause - %d \n", dma->pause); -+ DPRINTK("xfer_enable - %d \n", dma->xfer_enable); -+ DPRINTK("total bytes - 0x%x \n", dma->total_bytes); -+ DPRINTK("total buffer - %d \n", dma->total_buffers); -+ DPRINTK("new buffers - %d \n", dma->new_buffers); -+ DPRINTK("current buffer - %d \n", dma->current_buffer); -+ DPRINTK("last buffer - %d \n", dma->last_buffer); -+ DPRINTK("used buffers - %d \n", dma->used_buffers); -+ DPRINTK("callback addr - 0x%p \n", dma->callback); -+ -+ } else if (dma->new_buffers) { -+ DPRINTK("8 "); -+ /* -+ * we have a new buffer, so increment the current buffer to -+ * point to the next buffer, which is already programmed into -+ * the DMA. Next time around, it'll be pointing to the -+ * current buffer. -+ */ -+ dma->current_buffer = (dma->current_buffer + 1) % MAX_EP93XX_DMA_BUFFERS; -+ -+ /* -+ * we know we have a new buffer to program as the next -+ * buffer, so check which set of MAXCNT and BASE registers -+ * to program. -+ */ -+ if ( inl(M2P_reg_base+M2P_OFFSET_STATUS) & STATUS_M2P_NEXTBUFFER ) { -+ /* -+ * Set the MAXCNT1 register with the buffer size -+ */ -+ outl( dma->buffer_queue[ -+ (dma->current_buffer + 1) % MAX_EP93XX_DMA_BUFFERS].size, -+ M2P_reg_base+M2P_OFFSET_MAXCNT1 ); -+ -+ /* -+ * Set the BASE1 register with the buffer base address -+ */ -+ outl( dma->buffer_queue[ -+ (dma->current_buffer + 1) % MAX_EP93XX_DMA_BUFFERS].source, -+ M2P_reg_base+M2P_OFFSET_BASE1 ); -+ } else { -+ /* -+ * Set the MAXCNT0 register with the buffer size -+ */ -+ outl( dma->buffer_queue[ -+ (dma->current_buffer + 1) % MAX_EP93XX_DMA_BUFFERS].size, -+ M2P_reg_base+M2P_OFFSET_MAXCNT0 ); -+ -+ /* -+ * Set the BASE0 register with the buffer base address -+ */ -+ outl( dma->buffer_queue[ -+ (dma->current_buffer + 1) % MAX_EP93XX_DMA_BUFFERS].source, -+ M2P_reg_base+M2P_OFFSET_BASE0 ); -+ } -+ -+ /* -+ * Decrement the new buffers counter -+ */ -+ dma->new_buffers--; -+ } -+ } else { -+ /* -+ * Total number of buffers is 0 - really we should never get here, -+ * but just in case. -+ */ -+ DPRINTK("9 \n"); -+ -+ /* -+ * No new buffers to transfer, so Disable the channel -+ */ -+ uiCONTROL = inl(M2P_reg_base+M2P_OFFSET_CONTROL); -+ uiCONTROL &= ~CONTROL_M2P_ENABLE; -+ outl( uiCONTROL, M2P_reg_base+M2P_OFFSET_CONTROL ); -+ } -+ } -+ -+ /* -+ * Channel Error Interrupt, or perhipheral interrupt, specific to the -+ * memory to/from peripheral channels. -+ */ -+ if (dma_int == CHERROR) { -+ /* -+ * just clear the interrupt, it's really up to the peripheral -+ * driver to determine if any further action is necessary. -+ */ -+ uiINTERRUPT = inl(M2P_reg_base+M2P_OFFSET_INTERRUPT); -+ uiINTERRUPT &= ~INTERRUPT_M2P_CHERRORINT; -+ outl( uiINTERRUPT, M2P_reg_base+M2P_OFFSET_INTERRUPT ); -+ } -+ -+ /* -+ * Make sure the interrupt was valid, and if it was, then check -+ * if a callback function was installed for this DMA channel. If a -+ * callback was installed call it. -+ */ -+ if ((dma_int != UNDEF_INT) && dma->callback) -+ dma->callback(dma_int, dma->device, dma->user_data); -+ -+ return IRQ_HANDLED; -+} -+ -+/***************************************************************************** -+ * -+ * ep9312_dma_open_m2p(int device) -+ * -+ * Description: This function will attempt to open a M2P/P2M DMA channel. -+ * If the open is successful, the channel number is returned, -+ * otherwise a negative number is returned. -+ * -+ * Parameters: -+ * device: device for which the dma channel is requested. -+ * -+ ****************************************************************************/ -+static int -+dma_open_m2p(int device) -+{ -+ int channel = -1; -+ unsigned int loop; -+ unsigned int M2P_reg_base; -+ unsigned int uiPWRCNT; -+ /*unsigned long flags;*/ -+ -+ DPRINTK("DMA Open M2P with hw dev %d\n", device); -+ -+ /* -+ * Lock the dma channel list. -+ */ -+ //spin_lock_irqsave(&dma_list_lock, flags); -+ spin_lock(&dma_list_lock); -+ -+ /* -+ * Verify that the device requesting DMA isn't already using a DMA channel -+ */ -+ if (device >= 10) -+ loop = 1; // Rx transfer requested -+ else -+ loop = 0; // Tx transfer requested -+ -+ for (; loop < 10; loop = loop + 2) -+ /* -+ * Before checking for a matching device, check that the -+ * channel is in use, otherwise the device field is -+ * invalid. -+ */ -+ if (dma_chan[loop].ref_count) -+ if (device == dma_chan[loop].device) { -+ DPRINTK("DMA Open M2P - Error\n"); -+ return(-1); -+ } -+ -+ /* -+ * Get a DMA channel instance for the given hardware device. -+ * If this is a TX look for even numbered channels, else look for -+ * odd numbered channels -+ */ -+ if (device >= 10) -+ loop = 1; /* Rx transfer requested */ -+ else -+ loop = 0; /* Tx transfer requested */ -+ -+ for (; loop < 10; loop = loop + 2) -+ if (!dma_chan[loop].ref_count) { -+ /* -+ * Capture the channel and increment the reference count. -+ */ -+ channel = loop; -+ dma_chan[channel].ref_count++; -+ break; -+ } -+ -+ /* -+ * Unlock the dma channel list. -+ */ -+ //spin_unlock_irqrestore(&dma_list_lock, flags); -+ spin_unlock(&dma_list_lock); -+ /* -+ * See if we got a valid channel. -+ */ -+ if (channel < 0) -+ return(-1); -+ -+ /* -+ * Point regs to the correct dma channel register base. -+ */ -+ M2P_reg_base = dma_chan[channel].reg_base; -+ -+ /* -+ * Turn on the clock for the specified DMA channel -+ * TODO: need to use the correct register name for the -+ * power control register. -+ */ -+ uiPWRCNT = inl(/*SYSCON_PWRCNT*/EP93XX_SYSCON_CLOCK_CONTROL); -+ switch (channel) { -+ case 0: -+ uiPWRCNT |= SYSCON_PWRCNT_DMA_M2PCH0; -+ break; -+ -+ case 1: -+ uiPWRCNT |= SYSCON_PWRCNT_DMA_M2PCH1; -+ break; -+ -+ case 2: -+ uiPWRCNT |= SYSCON_PWRCNT_DMA_M2PCH2; -+ break; -+ -+ case 3: -+ uiPWRCNT |= SYSCON_PWRCNT_DMA_M2PCH3; -+ break; -+ -+ case 4: -+ uiPWRCNT |= SYSCON_PWRCNT_DMA_M2PCH4; -+ break; -+ -+ case 5: -+ uiPWRCNT |= SYSCON_PWRCNT_DMA_M2PCH5; -+ break; -+ -+ case 6: -+ uiPWRCNT |= SYSCON_PWRCNT_DMA_M2PCH6; -+ break; -+ -+ case 7: -+ uiPWRCNT |= SYSCON_PWRCNT_DMA_M2PCH7; -+ break; -+ -+ case 8: -+ uiPWRCNT |= SYSCON_PWRCNT_DMA_M2PCH8; -+ break; -+ -+ case 9: -+ uiPWRCNT |= SYSCON_PWRCNT_DMA_M2PCH9; -+ break; -+ -+ default: -+ return(-1); -+ } -+ outl( uiPWRCNT, /*SYSCON_PWRCNT*/EP93XX_SYSCON_CLOCK_CONTROL ); -+ -+ /* -+ * Clear out the control register before any further setup. -+ */ -+ outl( 0, M2P_reg_base+M2P_OFFSET_CONTROL ); -+ -+ /* -+ * Setup the peripheral port value in the DMA channel registers. -+ */ -+ if (device < 10) -+ outl( (unsigned int)device, M2P_reg_base+M2P_OFFSET_PPALLOC ); -+ else -+ outl( (unsigned int)(device - 10), M2P_reg_base+M2P_OFFSET_PPALLOC ); -+ -+ /* -+ * Let's hold on to the value of the Hw device for comparison later. -+ */ -+ dma_chan[channel].device = device; -+ -+ /* -+ * Success. -+ */ -+ return(channel); -+} -+ -+/***************************************************************************** -+ * -+ * dma_open_m2m(int device) -+ * -+ * Description: This function will attempt to open a M2M DMA channel. -+ * If the open is successful, the channel number is returned, -+ * otherwise a negative number is returned. -+ * -+ * Parameters: -+ * device: device for which the dma channel is requested. -+ * -+ ****************************************************************************/ -+static int -+dma_open_m2m(int device) -+{ -+ int channel = -1; -+ unsigned int loop; -+ unsigned int M2M_reg_base; -+ unsigned int uiPWRCNT, uiCONTROL; -+ /*unsigned long flags;*/ -+ -+ DPRINTK("DMA Open M2M with hw dev %d\n", device); -+ -+ /* -+ * Lock the dma channel list. -+ */ -+ //spin_lock_irqsave(&dma_list_lock, flags); -+ spin_lock(&dma_list_lock); -+ -+ -+ /* -+ * Check if this device is already allocated a channel. -+ * TODO: can one M2M device be allocated multiple channels? -+ */ -+ for (loop = 10; loop < 12; loop++) -+ /* -+ * Before checking for a matching device, check that the -+ * channel is in use, otherwise the device field is -+ * invalid. -+ */ -+ if (dma_chan[loop].ref_count) -+ if (device == dma_chan[loop].device) { -+ DPRINTK("Error - dma_open_m2m - already allocated channel\n"); -+ -+ /* -+ * Unlock the dma channel list. -+ */ -+ //spin_unlock_irqrestore(&dma_list_lock, flags); -+ spin_unlock(&dma_list_lock); -+ /* -+ * Fail. -+ */ -+ return(-1); -+ } -+ -+ /* -+ * Get a DMA channel instance for the given hardware device. -+ */ -+ for (loop = 10; loop < 12; loop++) -+ if (!dma_chan[loop].ref_count) { -+ /* -+ * Capture the channel and increment the reference count. -+ */ -+ channel = loop; -+ dma_chan[channel].ref_count++; -+ break; -+ } -+ -+ /* -+ * Unlock the dma channel list. -+ */ -+ //spin_unlock(dma_list_lock); -+ spin_unlock(&dma_list_lock); -+ //spin_unlock_irqrestore(&dma_list_lock, flags); -+ -+ /* -+ * See if we got a valid channel. -+ */ -+ if (channel < 0) -+ return(-1); -+ -+ /* -+ * Point regs to the correct dma channel register base. -+ */ -+ M2M_reg_base = dma_chan[channel].reg_base; -+ -+ /* -+ * Turn on the clock for the specified DMA channel -+ * TODO: need to use the correct register name for the -+ * power control register. -+ */ -+ uiPWRCNT = inl(/*SYSCON_PWRCNT*/EP93XX_SYSCON_CLOCK_CONTROL); -+ switch (channel) { -+ case 10: -+ uiPWRCNT |= SYSCON_PWRCNT_DMA_M2MCH0; -+ break; -+ -+ case 11: -+ uiPWRCNT |= SYSCON_PWRCNT_DMA_M2MCH1; -+ break; -+ -+ default: -+ return(-1); -+ } -+ outl( uiPWRCNT, /*SYSCON_PWRCNT*/EP93XX_SYSCON_CLOCK_CONTROL); -+ -+ DPRINTK("DMA Open - power control: 0x%x \n", inl(SYSCON_PWRCNT) ); -+ -+ /* -+ * Clear out the control register before any further setup. -+ */ -+ outl( 0, M2M_reg_base+M2M_OFFSET_CONTROL ); -+ -+ /* -+ * Setup the transfer mode and the request source selection within -+ * the DMA M2M channel registers. -+ */ -+ switch (device) { -+ case DMA_MEMORY: -+ /* -+ * Clear TM field, set RSS field to 0 -+ */ -+ uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL); -+ uiCONTROL &= ~(CONTROL_M2M_TM_MASK | CONTROL_M2M_RSS_MASK); -+ outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL ); -+ break; -+ -+ case DMA_IDE: -+ /* -+ * Set RSS field to 3, Set NO_HDSK, Set PW field to 1 -+ */ -+ uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL); -+ uiCONTROL &= ~(CONTROL_M2M_RSS_MASK|CONTROL_M2M_PW_MASK); -+ uiCONTROL |= (3<<CONTROL_M2M_RSS_SHIFT) | -+ CONTROL_M2M_NO_HDSK | -+ (2<<CONTROL_M2M_PW_SHIFT); -+ -+ uiCONTROL &= ~(CONTROL_M2M_ETDP_MASK); -+ uiCONTROL &= ~(CONTROL_M2M_DACKP); -+ uiCONTROL &= ~(CONTROL_M2M_DREQP_MASK); -+ -+ outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL ); -+ inl(M2M_reg_base+M2M_OFFSET_CONTROL); -+ break; -+ -+ case DMARx_SSP: -+ /* -+ * Set RSS field to 1, Set NO_HDSK, Set TM field to 2 -+ */ -+ uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL); -+ uiCONTROL &= ~(CONTROL_M2M_RSS_MASK|CONTROL_M2M_TM_MASK); -+ uiCONTROL |= (1<<CONTROL_M2M_RSS_SHIFT) | -+ CONTROL_M2M_NO_HDSK | -+ (2<<CONTROL_M2M_TM_SHIFT); -+ outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL ); -+ break; -+ -+ case DMATx_SSP: -+ /* -+ * Set RSS field to 2, Set NO_HDSK, Set TM field to 1 -+ */ -+ uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL); -+ uiCONTROL &= ~(CONTROL_M2M_RSS_MASK|CONTROL_M2M_TM_MASK); -+ uiCONTROL |= (2<<CONTROL_M2M_RSS_SHIFT) | -+ CONTROL_M2M_NO_HDSK | -+ (1<<CONTROL_M2M_TM_SHIFT); -+ outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL ); -+ break; -+ -+ case DMATx_EXT_DREQ: -+ /* -+ * Set TM field to 2, set RSS field to 0 -+ */ -+ uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL); -+ uiCONTROL &= ~(CONTROL_M2M_RSS_MASK|CONTROL_M2M_TM_MASK); -+ uiCONTROL |= 1<<CONTROL_M2M_TM_SHIFT; -+ outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL ); -+ break; -+ -+ case DMARx_EXT_DREQ: -+ /* -+ * Set TM field to 2, set RSS field to 0 -+ */ -+ uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL); -+ uiCONTROL &= ~(CONTROL_M2M_RSS_MASK|CONTROL_M2M_TM_MASK); -+ uiCONTROL |= 2<<CONTROL_M2M_TM_SHIFT; -+ outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL ); -+ break; -+ -+ default: -+ return -1; -+ } -+ -+ /* -+ * Let's hold on to the value of the Hw device for comparison later. -+ */ -+ dma_chan[channel].device = device; -+ -+ /* -+ * Success. -+ */ -+ return(channel); -+} -+ -+/***************************************************************************** -+ * -+ * int dma_config_m2m(ep93xx_dma_t * dma, unsigned int flags_m2m, -+ * dma_callback callback, unsigned int user_data) -+ * -+ * Description: Configure the DMA channel and install a callback function. -+ * This function will have to be called for every transfer -+ * -+ * dma: Pointer to the dma instance data for the M2M channel to -+ * configure. -+ * flags_m2m Flags used to configure an M2M dma channel and determine -+ * if a callback function and user_data information are included -+ * in this call. -+ * callback function pointer which is called near the end of the -+ * dma channel's irq handler. -+ * user_data defined by the calling driver. -+ * -+ ****************************************************************************/ -+static int -+dma_config_m2m(ep93xx_dma_t * dma, unsigned int flags_m2m, -+ dma_callback callback, unsigned int user_data) -+{ -+ unsigned long flags; -+ unsigned int M2M_reg_base, uiCONTROL; -+ -+ /* -+ * Make sure the channel is disabled before configuring the channel. -+ * -+ * TODO: Is this correct?? Making a big change here... -+ */ -+ /* if (!dma->pause || (!dma->pause && dma->xfer_enable)) */ -+ if (dma->xfer_enable) { -+ /* -+ * DMA channel is not paused, so we can't configure it. -+ */ -+ DPRINTK("DMA channel not paused, so can't configure! \n"); -+ return(-1); -+ } -+ -+ /* -+ * Mask interrupts. -+ */ -+ local_irq_save(flags); -+ -+ /* -+ * Setup a pointer into the dma channel's register set. -+ */ -+ M2M_reg_base = dma->reg_base; -+ -+ uiCONTROL = inl(M2M_reg_base + M2M_OFFSET_CONTROL); -+ outl(0, M2M_reg_base + M2M_OFFSET_CONTROL); -+ inl(M2M_reg_base + M2M_OFFSET_CONTROL); -+ outl(uiCONTROL, M2M_reg_base + M2M_OFFSET_CONTROL); -+ -+ /* -+ * By default we disable the stall interrupt. -+ */ -+ uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL); -+ uiCONTROL &= ~CONTROL_M2M_STALLINTEN; -+ outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL ); -+ -+ /* -+ * By default we disable the done interrupt. -+ */ -+ uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL); -+ uiCONTROL &= ~CONTROL_M2M_DONEINTEN; -+ outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL ); -+ -+ /* -+ * Set up the transfer control fields based on values passed in -+ * the flags_m2m field. -+ */ -+ uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL); -+ -+ if ( flags_m2m & DESTINATION_HOLD ) -+ uiCONTROL |= CONTROL_M2M_DAH; -+ else -+ uiCONTROL &= ~CONTROL_M2M_DAH; -+ -+ if ( flags_m2m & SOURCE_HOLD ) -+ uiCONTROL |= CONTROL_M2M_SAH; -+ else -+ uiCONTROL &= ~CONTROL_M2M_SAH; -+ -+ uiCONTROL &= ~CONTROL_M2M_TM_MASK; -+ uiCONTROL |= (((flags_m2m & TRANSFER_MODE_MASK) >> TRANSFER_MODE_SHIFT) << -+ CONTROL_M2M_TM_SHIFT) & CONTROL_M2M_TM_MASK; -+ -+ uiCONTROL &= ~CONTROL_M2M_PWSC_MASK; -+ uiCONTROL |= (((flags_m2m & WAIT_STATES_MASK) >> WAIT_STATES_SHIFT) << -+ CONTROL_M2M_PWSC_SHIFT) & CONTROL_M2M_PWSC_MASK; -+ -+ outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL ); -+ inl(M2M_reg_base + M2M_OFFSET_CONTROL); -+ -+ /* -+ * Save the callback function in the dma instance for this channel. -+ */ -+ dma->callback = callback; -+ -+ /* -+ * Save the user data in the the dma instance for this channel. -+ */ -+ dma->user_data = user_data; -+ -+ /* -+ * Put the dma instance into the pause state by setting the -+ * pause bit to true. -+ */ -+ dma->pause = TRUE; -+ -+ local_irq_restore(flags); -+ -+ /* -+ * Success. -+ */ -+ return(0); -+} -+ -+/***************************************************************************** -+ * -+ * int dma_start(int handle, unsigned int channels, unsigned int * handles) -+ * -+ * Description: Initiate a transfer on up to 3 channels. -+ * -+ * handle: handle for the channel to initiate transfer on. -+ * channels: number of channels to initiate transfers on. -+ * handles: pointer to an array of handles, one for each channel which -+ * is to be started. -+ * -+ ****************************************************************************/ -+static int -+dma_start_m2m(int channel, ep93xx_dma_t * dma) -+{ -+ unsigned long flags; -+ unsigned int M2M_reg_base = dma->reg_base; -+ unsigned int uiCONTROL; -+ -+ /* -+ * Mask interrupts while we get this started. -+ */ -+ local_irq_save(flags); -+ -+ /* -+ * Make sure the channel has at least one buffer in the queue. -+ */ -+ if (dma->new_buffers < 1) { -+ /* -+ * Unmask irqs -+ */ -+ local_irq_restore(flags); -+ -+ DPRINTK("DMA Start: Channel starved.\n"); -+ -+ /* -+ * This channel does not have enough buffers queued up, -+ * so enter the pause by starvation state. -+ */ -+ dma->xfer_enable = TRUE; -+ dma->pause = TRUE; -+ -+ /* -+ * Success. -+ */ -+ return(0); -+ } -+ -+ /* -+ * Clear any pending interrupts. -+ */ -+ outl(0x0, M2M_reg_base+M2M_OFFSET_INTERRUPT); -+ -+ /* -+ * Set up one or both buffer descriptors with values from the next one or -+ * two buffers in the queue. By default disable the next frame buffer -+ * interrupt on the channel. -+ */ -+ uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL); -+ uiCONTROL &= ~CONTROL_M2M_NFBINTEN; -+ outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL ); -+ -+ /* -+ * enable the done interrupt. -+ */ -+ uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL); -+ uiCONTROL |= CONTROL_M2M_DONEINTEN; -+ outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL ); -+ -+ /* -+ * Update the dma channel instance transfer state. -+ */ -+ dma->xfer_enable = TRUE; -+ dma->pause = FALSE; -+ -+ /* -+ * Program up the first buffer descriptor with a source and destination -+ * and a byte count. -+ */ -+ outl( dma->buffer_queue[dma->current_buffer].source, -+ M2M_reg_base+M2M_OFFSET_SAR_BASE0 ); -+ -+ outl( dma->buffer_queue[dma->current_buffer].dest, -+ M2M_reg_base+M2M_OFFSET_DAR_BASE0 ); -+ -+ outl( dma->buffer_queue[dma->current_buffer].size, -+ M2M_reg_base+M2M_OFFSET_BCR0 ); -+ -+ /* -+ * Decrement the new buffers counter. -+ */ -+ dma->new_buffers--; -+ -+ /* -+ * Set up the second buffer descriptor with a second buffer if we have -+ * a second buffer. -+ */ -+ if (dma->new_buffers) { -+ outl( dma->buffer_queue[(dma->current_buffer + 1) % -+ MAX_EP93XX_DMA_BUFFERS].source, -+ M2M_reg_base+M2M_OFFSET_SAR_BASE1 ); -+ -+ outl( dma->buffer_queue[(dma->current_buffer + 1) % -+ MAX_EP93XX_DMA_BUFFERS].dest, -+ M2M_reg_base+M2M_OFFSET_DAR_BASE1 ); -+ -+ outl( dma->buffer_queue[(dma->current_buffer + 1) % -+ MAX_EP93XX_DMA_BUFFERS].size, -+ M2M_reg_base+M2M_OFFSET_BCR1 ); -+ -+ uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL); -+ uiCONTROL |= CONTROL_M2M_NFBINTEN; -+ outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL ); -+ -+ dma->new_buffers--; -+ } -+ -+ /* -+ * Now we enable the channel. This initiates the transfer. -+ */ -+ uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL); -+ uiCONTROL |= CONTROL_M2M_ENABLE; -+ outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL ); -+ inl(M2M_reg_base + M2M_OFFSET_CONTROL); -+ -+ /* -+ * If this is a memory to memory transfer, we need to s/w trigger the -+ * transfer by setting the start bit within the control register. -+ */ -+ if (dma->device == DMA_MEMORY) { -+ uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL); -+ uiCONTROL |= CONTROL_M2M_START; -+ outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL ); -+ } -+ -+ DPRINTK("DMA - It's been started!!"); -+ DPRINTK("CONTROL - 0x%x \n", inl(M2M_reg_base+M2M_OFFSET_CONTROL) ); -+ DPRINTK("STATUS - 0x%x \n", inl(M2M_reg_base+M2M_OFFSET_STATUS) ); -+ DPRINTK("BCR0 - 0x%x \n", dma->buffer_queue[dma->current_buffer].size); -+ DPRINTK("SAR_BASE0 - 0x%x \n", inl(M2M_reg_base+M2M_OFFSET_SAR_BASE0) ); -+ DPRINTK("SAR_CUR0 - 0x%x \n", inl(M2M_reg_base+M2M_OFFSET_SAR_CURRENT0) ); -+ DPRINTK("DAR_BASE0 - 0x%x \n", inl(M2M_reg_base+M2M_OFFSET_DAR_BASE0) ); -+ DPRINTK("DAR_CUR0 - 0x%x \n", inl(M2M_reg_base+M2M_OFFSET_DAR_CURRENT0) ); -+ -+ /* -+ * Unmask irqs -+ */ -+ local_irq_restore(flags); -+ -+ /* -+ * Success. -+ */ -+ return(0); -+} -+ -+/***************************************************************************** -+ * -+ * DMA interface functions -+ * -+ ****************************************************************************/ -+ -+/***************************************************************************** -+ * -+ * int dma_init(int handle, unsigned int flags_m2p, unsigned int flags_m2m, -+ * dma_callback callback, unsigned int user_data) -+ * -+ * Description: Configure the DMA channel and install a callback function. -+ * -+ * handle: Handle unique the each instance of the dma interface, used -+ * to verify this call. -+ * flags_m2p Flags used to configure an M2P/P2M dma channel and determine -+ * if a callback function and user_data information are included -+ * in this call. This field should be NULL if handle represents -+ * an M2M channel. -+ * flags_m2m Flags used to configure an M2M dma channel and determine -+ * if a callback function and user_data information are included -+ * in this call. This field should be NULL if handle represents -+ * an M2P/P2M channel. -+ * callback function pointer which is called near the end of the -+ * dma channel's irq handler. -+ * user_data defined by the calling driver. -+ * -+ ****************************************************************************/ -+int -+ep93xx_dma_config(int handle, unsigned int flags_m2p, unsigned int flags_m2m, -+ dma_callback callback, unsigned int user_data) -+{ -+ int channel; -+ ep93xx_dma_t * dma; -+ unsigned long flags; -+ unsigned int M2P_reg_base, uiCONTROL; -+ -+ /* -+ * Get the DMA hw channel # from the handle. -+ */ -+ channel = dma_get_channel_from_handle(handle); -+ -+ /* -+ * See if this is a valid handle. -+ */ -+ if (channel < 0) { -+ printk(KERN_ERR -+ "DMA Config: Invalid dma handle.\n"); -+ return(-EINVAL); -+ } -+ -+ DPRINTK("DMA Config \n"); -+ -+ dma = &dma_chan[channel]; -+ -+ local_irq_save(flags); -+ -+ /* -+ * Check if the channel is currently transferring. -+ */ -+ if (dma->xfer_enable) { -+ local_irq_restore(flags); -+ return(-EINVAL); -+ } -+ -+ /* -+ * Check if this is an m2m function. -+ */ -+ if (channel >= 10) { -+ local_irq_restore(flags); -+ -+ /* -+ * Call another function to handle m2m config. -+ */ -+ return(dma_config_m2m(dma, flags_m2m, callback, user_data)); -+ } -+ -+ /* -+ * Setup a pointer into the dma channel's register set. -+ */ -+ M2P_reg_base = dma->reg_base; -+ -+ /* -+ * By default we enable the stall interrupt. -+ */ -+ uiCONTROL = inl(M2P_reg_base+M2P_OFFSET_CONTROL); -+ uiCONTROL |= CONTROL_M2P_STALLINTEN; -+ outl( uiCONTROL, M2P_reg_base+M2P_OFFSET_CONTROL ); -+ -+ /* -+ * Configure the channel for an error from the peripheral. -+ */ -+ uiCONTROL = inl(M2P_reg_base+M2P_OFFSET_CONTROL); -+ if ( flags_m2p && CHANNEL_ERROR_INT_ENABLE ) -+ uiCONTROL |= CONTROL_M2P_CHERRORINTEN; -+ else -+ uiCONTROL &= ~CONTROL_M2P_CHERRORINTEN; -+ outl( uiCONTROL, M2P_reg_base+M2P_OFFSET_CONTROL ); -+ -+ uiCONTROL = inl(M2P_reg_base+M2P_OFFSET_CONTROL); -+ if ( flags_m2p && CHANNEL_ABORT ) -+ uiCONTROL |= CONTROL_M2P_ABRT; -+ else -+ uiCONTROL &= ~CONTROL_M2P_ABRT; -+ outl( uiCONTROL, M2P_reg_base+M2P_OFFSET_CONTROL ); -+ -+ uiCONTROL = inl(M2P_reg_base+M2P_OFFSET_CONTROL); -+ if ( flags_m2p && IGNORE_CHANNEL_ERROR ) -+ uiCONTROL |= CONTROL_M2P_ICE; -+ else -+ uiCONTROL &= ~CONTROL_M2P_ICE; -+ outl( uiCONTROL, M2P_reg_base+M2P_OFFSET_CONTROL ); -+ -+ /* -+ * Save the callback function in the dma instance for this channel. -+ */ -+ dma->callback = callback; -+ -+ /* -+ * Save the user data in the the dma instance for this channel. -+ */ -+ dma->user_data = user_data; -+ -+ /* -+ * Put the dma instance into the pause state by setting the -+ * pause bit to true. -+ */ -+ dma->pause = TRUE; -+ -+ local_irq_restore(flags); -+ -+ /* -+ * Success. -+ */ -+ return(0); -+} -+ -+/***************************************************************************** -+ * -+ * int dma_start(int handle, unsigned int channels, unsigned int * handles) -+ * -+ * Description: Initiate a transfer on up to 3 channels. -+ * -+ * handle: handle for the channel to initiate transfer on. -+ * channels: number of channels to initiate transfers on. -+ * handles: pointer to an array of handles, one for each channel which -+ * is to be started. -+ * -+ ****************************************************************************/ -+int -+ep93xx_dma_start(int handle, unsigned int channels, unsigned int * handles) -+{ -+ ep93xx_dma_t * dma_pointers[3]; -+ unsigned int M2P_reg_bases[3]; -+ unsigned int loop, uiCONTROL; -+ unsigned long flags; -+ int channel; -+ -+ /* -+ * Get the DMA hw channel # from the handle. -+ */ -+ channel = dma_get_channel_from_handle(handle); -+ -+ /* -+ * See if this is a valid handle. -+ */ -+ if (channel < 0) { -+ printk(KERN_ERR "DMA Start: Invalid dma handle.\n"); -+ return(-EINVAL); -+ } -+ -+ if (channels < 1) { -+ printk(KERN_ERR "DMA Start: Invalid parameter.\n"); -+ return(-EINVAL); -+ } -+ -+ DPRINTK("DMA Start \n"); -+ -+ /* -+ * Mask off registers. -+ */ -+ local_irq_save(flags); -+ -+ /* -+ * Check if this is a start multiple. -+ */ -+ if (channels > 1) { -+ DPRINTK("DMA ERROR: Start, multiple start not supported yet \n"); -+ return(-1); -+ } else { -+ /* -+ * Check if this channel is already transferring. -+ */ -+ if (dma_chan[channel].xfer_enable && !dma_chan[channel].pause) { -+ printk(KERN_ERR -+ "DMA Start: Invalid command for channel %d.\n", channel); -+ -+ /* -+ * Unmask irqs -+ */ -+ local_irq_restore(flags); -+ -+ /* -+ * This channel is already transferring, so return an error. -+ */ -+ return(-EINVAL); -+ } -+ -+ /* -+ * If this is an M2M channel, call a different function. -+ */ -+ if (channel >= 10) { -+ /* -+ * Unmask irqs -+ */ -+ local_irq_restore(flags); -+ -+ /* -+ * Call the m2m start function. Only start one channel. -+ */ -+ return(dma_start_m2m(channel, &dma_chan[channel])); -+ } -+ -+ /* -+ * Make sure the channel has at least one buffer in the queue. -+ */ -+ if (dma_chan[channel].new_buffers < 1) { -+ DPRINTK("DMA Start: Channel starved.\n"); -+ -+ /* -+ * This channel does not have enough buffers queued up, -+ * so enter the pause by starvation state. -+ */ -+ dma_chan[channel].xfer_enable = TRUE; -+ dma_chan[channel].pause = TRUE; -+ -+ /* -+ * Unmask irqs -+ */ -+ local_irq_restore(flags); -+ -+ /* -+ * Success. -+ */ -+ return(0); -+ } -+ -+ /* -+ * Set up a dma instance pointer for this dma channel. -+ */ -+ dma_pointers[0] = &dma_chan[channel]; -+ -+ /* -+ * Set up a pointer to the register set for this channel. -+ */ -+ M2P_reg_bases[0] = dma_pointers[0]->reg_base; -+ } -+ -+ /* -+ * Setup both MAXCNT registers with values from the next two buffers -+ * in the queue, and enable the next frame buffer interrupt on the channel. -+ */ -+ for (loop = 0; loop < channels; loop++) { -+ /* -+ * Check if we need to restore a paused transfer. -+ */ -+ if (dma_pointers[loop]->pause_buf.buf_id != -1) -+ outl( dma_pointers[loop]->pause_buf.size, -+ M2P_reg_bases[loop]+M2P_OFFSET_MAXCNT0 ); -+ else -+ outl( dma_pointers[loop]->buffer_queue[dma_pointers[loop]->current_buffer].size, -+ M2P_reg_bases[loop]+M2P_OFFSET_MAXCNT0 ); -+ } -+ -+ for (loop = 0; loop < channels; loop++) { -+ /* -+ * Enable the specified dma channels. -+ */ -+ uiCONTROL = inl(M2P_reg_bases[loop]+M2P_OFFSET_CONTROL); -+ uiCONTROL |= CONTROL_M2P_ENABLE; -+ outl( uiCONTROL, M2P_reg_bases[loop]+M2P_OFFSET_CONTROL ); -+ -+ /* -+ * Update the dma channel instance transfer state. -+ */ -+ dma_pointers[loop]->xfer_enable = TRUE; -+ dma_pointers[loop]->pause = FALSE; -+ } -+ -+ /* -+ * Program up the BASE0 registers for all specified channels, this -+ * will initiate transfers on all specified channels. -+ */ -+ for (loop = 0; loop < channels; loop++) -+ /* -+ * Check if we need to restore a paused transfer. -+ */ -+ if (dma_pointers[loop]->pause_buf.buf_id != -1) { -+ outl( dma_pointers[loop]->pause_buf.source, -+ M2P_reg_bases[loop]+M2P_OFFSET_BASE0 ); -+ -+ /* -+ * Set the pause buffer to NULL -+ */ -+ dma_pointers[loop]->pause_buf.buf_id = -1; -+ dma_pointers[loop]->pause_buf.size = 0; -+ } else if(dma_pointers[loop]->new_buffers){ -+ outl( dma_pointers[loop]->buffer_queue[ -+ dma_pointers[loop]->current_buffer].source, -+ M2P_reg_bases[loop]+M2P_OFFSET_BASE0 ); -+ dma_pointers[loop]->new_buffers--; -+ -+ } -+ -+ /* -+ * Before restoring irqs setup the second MAXCNT/BASE -+ * register with a second buffer. -+ */ -+ for (loop = 0; loop < channels; loop++) -+ if (dma_pointers[loop]->new_buffers) { -+ /* -+ * By default we enable the next frame buffer interrupt. -+ */ -+ uiCONTROL = inl(M2P_reg_bases[loop]+M2P_OFFSET_CONTROL); -+ uiCONTROL |= CONTROL_M2P_NFBINTEN; -+ outl( uiCONTROL, M2P_reg_bases[loop]+M2P_OFFSET_CONTROL ); -+ -+ outl( dma_pointers[loop]->buffer_queue[ -+ (dma_pointers[loop]->current_buffer + 1) % -+ MAX_EP93XX_DMA_BUFFERS].size, -+ M2P_reg_bases[loop]+M2P_OFFSET_MAXCNT1 ); -+ -+ outl( dma_pointers[loop]->buffer_queue[ -+ (dma_pointers[loop]->current_buffer + 1) % -+ MAX_EP93XX_DMA_BUFFERS].source, -+ M2P_reg_bases[loop]+M2P_OFFSET_BASE1 ); -+ dma_pointers[loop]->new_buffers--; -+ } -+ -+ /* -+ DPRINTK("DMA - It's been started!!"); -+ DPRINTK("STATUS - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_STATUS) ); -+ DPRINTK("CONTROL - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_CONTROL) ); -+ DPRINTK("REMAIN - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_REMAIN) ); -+ DPRINTK("PPALLOC - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_PPALLOC) ); -+ DPRINTK("BASE0 - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_BASE0) ); -+ DPRINTK("MAXCNT0 - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_MAXCNT0) ); -+ DPRINTK("CURRENT0 - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_CURRENT0) ); -+ DPRINTK("BASE1 - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_BASE1) ); -+ DPRINTK("MAXCNT1 - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_MAXCNT1) ); -+ DPRINTK("CURRENT1 - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_CURRENT1) ); -+ -+ DPRINTK("Pause - %d \n", dma_pointers[0]->pause); -+ DPRINTK("xfer_enable - %d \n", dma_pointers[0]->xfer_enable); -+ DPRINTK("total bytes - 0x%x \n", dma_pointers[0]->total_bytes); -+ DPRINTK("total buffer - %d \n", dma_pointers[0]->total_buffers); -+ DPRINTK("new buffers - %d \n", dma_pointers[0]->new_buffers); -+ DPRINTK("current buffer - %d \n", dma_pointers[0]->current_buffer); -+ DPRINTK("last buffer - %d \n", dma_pointers[0]->last_buffer); -+ DPRINTK("used buffers - %d \n", dma_pointers[0]->used_buffers); -+ */ -+ /* -+ * Unmask irqs -+ */ -+ local_irq_restore(flags); -+ -+ /* -+ * Success. -+ */ -+ return(0); -+} -+ -+/***************************************************************************** -+ * -+ * int ep93xx_dma_add_buffer(int handle, unsigned int * address, -+ * unsigned int size, unsigned int last) -+ * -+ * Description: Add a buffer entry to the DMA buffer queue. -+ * -+ * handle: handle for the channel to add this buffer to. -+ * address: Pointer to an integer which is the start address of the -+ * buffer which is to be added to the queue. -+ * size: size of the buffer in bytes. -+ * last: 1 if this is the last buffer in this stream, 0 otherwise. -+ * -+ ****************************************************************************/ -+int -+ep93xx_dma_add_buffer(int handle, unsigned int source, unsigned int dest, -+ unsigned int size, unsigned int last, -+ unsigned int buf_id) -+{ -+ unsigned long flags; -+ ep93xx_dma_t * dma; -+ int channel; -+#if 0 -+ static int peak_total_buffers=0; -+#endif -+ /* -+ * Get the DMA hw channel # from the handle. -+ */ -+ channel = dma_get_channel_from_handle(handle); -+ -+ /* -+ * See if this is a valid handle. -+ */ -+ if (channel < 0) { -+ printk(KERN_ERR -+ "DMA Add Buffer: Invalid dma handle.\n"); -+ return(-EINVAL); -+ } -+ -+ /* -+ * Get a pointer to the dma instance. -+ */ -+ dma = &dma_chan[channel]; -+ -+#if 0 -+ if( dma->total_buffers > peak_total_buffers ) -+ { -+ peak_total_buffers=dma->total_buffers; -+ printk("peak_total_buffers=%d\n", peak_total_buffers ); -+ } -+#endif -+ /* -+ * Mask interrupts and hold on to the original state. -+ */ -+ local_irq_save(flags); -+ -+ /* -+ * If the buffer queue is full, last_buffer is the same as current_buffer and -+ * we're not tranfering, or last_buffer is pointing to a used buffer, then exit. -+ * TODO: do I need to do any more checks? -+ */ -+ if (dma->total_buffers >= MAX_EP93XX_DMA_BUFFERS) -+ { -+ DPRINTK("too many dma buffers: MAX_EP93XX_DMA_BUFFERS set to low ?\n"); -+ /* -+ * Restore the state of the irqs -+ */ -+ local_irq_restore(flags); -+ -+ /* -+ * Fail. -+ */ -+ return(-1); -+ } -+ -+ /* -+ * Add this buffer to the queue -+ */ -+ dma->buffer_queue[dma->last_buffer].source = source; -+ dma->buffer_queue[dma->last_buffer].dest = dest; -+ dma->buffer_queue[dma->last_buffer].size = size; -+ dma->buffer_queue[dma->last_buffer].last = last; -+ dma->buffer_queue[dma->last_buffer].buf_id = buf_id; -+ -+ /* -+ * Reset the used field of the buffer structure. -+ */ -+ dma->buffer_queue[dma->last_buffer].used = FALSE; -+ -+ /* -+ * Increment the End Item Pointer. -+ */ -+ dma->last_buffer = (dma->last_buffer + 1) % MAX_EP93XX_DMA_BUFFERS; -+ -+ /* -+ * Increment the new buffers counter and the total buffers counter -+ */ -+ dma->new_buffers++; -+ dma->total_buffers++; -+ -+ /* -+ * restore the interrupt state. -+ */ -+ local_irq_restore(flags); -+ -+ /* -+ * Check if the channel was starved into a stopped state. -+ */ -+ if (dma->pause && dma->xfer_enable) { -+ if (dma->new_buffers >= 1) { -+ DPRINTK("DMA - calling start from add after starve. \n"); -+ -+ /* -+ * The channel was starved into a stopped state, and we've got -+ * 2 new buffers, so start tranferring again. -+ */ -+ ep93xx_dma_start(handle, 1, 0); -+ } -+ } -+ -+ /* -+ * Success. -+ */ -+ return(0); -+} -+ -+/***************************************************************************** -+ * -+ * int ep93xx_dma_remove_buffer(int handle, unsigned int * address, -+ * unsigned int * size) -+ * -+ * Description: Remove a buffer entry from the DMA buffer queue. If -+ * buffer was removed successfully, return 0, otherwise -+ * return -1. -+ * -+ * handle: handle for the channel to remove a buffer from. -+ * address: Pointer to an integer which is filled in with the start -+ * address of the removed buffer. -+ * size: Pointer to an integer which is filled in with the size in -+ * bytes of the removed buffer. -+ * -+ ****************************************************************************/ -+int -+ep93xx_dma_remove_buffer(int handle, unsigned int * buf_id) -+{ -+ unsigned int test; -+ unsigned int loop; -+ int return_val = -1; -+ unsigned long flags; -+ ep93xx_dma_t *dma; -+ int channel; -+ -+ /* -+ * Get the DMA hw channel # from the handle. -+ */ -+ channel = dma_get_channel_from_handle(handle); -+ -+ /* -+ * See if this is a valid handle. -+ */ -+ if (channel < 0) { -+ printk(KERN_ERR -+ "DMA Remove Buffer: Invalid dma handle.\n"); -+ return(-EINVAL); -+ } -+ -+ dma = &dma_chan[channel]; -+ -+ /* -+ * Mask interrupts and hold on to the original state. -+ */ -+ local_irq_save(flags); -+ -+ /* -+ * Make sure there are used buffers to be returned. -+ */ -+ if (dma->used_buffers) { -+ test = dma->last_buffer; -+ -+ for (loop = 0; loop < MAX_EP93XX_DMA_BUFFERS; loop++) { -+ if (dma->buffer_queue[test].used && (dma->buffer_queue[test].buf_id != -1)) { -+ /*DPRINTK("buffer %d used \n", test); */ -+ -+ /* -+ * This is a used buffer, fill in the buf_id pointer -+ * with the buf_id for this buffer. -+ */ -+ *buf_id = dma->buffer_queue[test].buf_id; -+ -+ /* -+ * Reset this buffer structure -+ */ -+ dma->buffer_queue[test].buf_id = -1; -+ -+ /* -+ * Decrement the used buffer counter, and the total buffer counter. -+ */ -+ dma->used_buffers--; -+ dma->total_buffers--; -+ -+ /* -+ * Successful removal of a buffer, so set the return -+ * value to 0, then exit this loop. -+ */ -+ return_val = 0; -+ break; -+ } -+ -+ /* -+ * This buffer isn't used, let's see if the next one is. -+ */ -+ test = (test + 1) % MAX_EP93XX_DMA_BUFFERS; -+ } -+ } -+ -+ /* -+ * Restore interrupts. -+ */ -+ local_irq_restore(flags); -+ -+ /* -+ * Success. -+ */ -+ return(return_val); -+} -+ -+/***************************************************************************** -+ * -+ * int ep93xx_dma_pause(int handle, unsigned int channels, -+ * unsigned int * handles) -+ * -+ * Description: Disable any ongoing transfer for the given channel, retaining -+ * the state of the current buffer transaction so that upon -+ * resume, the dma will continue where it left off. -+ * -+ * handle: Handle for the channel to be paused. If this is a pause for -+ * for multiple channels, handle is a valid handle for one of -+ * the channels to be paused. -+ * channels: number of channel to pause transfers on. -+ * handles: Pointer to an array of handles, one for each channel which -+ * to be paused. If this pause is intended only for one -+ * channel, this field should be set to NULL. -+ * -+ ****************************************************************************/ -+int -+ep93xx_dma_pause(int handle, unsigned int channels, unsigned int * handles) -+{ -+ unsigned long flags; -+ ep93xx_dma_t * dma; -+ int channel; -+ -+ DPRINTK("ep93xx_dma_pause \n"); -+ -+ /* -+ * Mask interrupts and hold on to the original state. -+ */ -+ local_irq_save(flags); -+ -+ /* -+ * Get the DMA hw channel # from the handle. -+ */ -+ channel = dma_get_channel_from_handle(handle); -+ -+ /* -+ * See if this is a valid handle. -+ */ -+ if (channel < 0) { -+ /* -+ * restore interrupts. -+ */ -+ local_irq_restore(flags); -+ -+ printk(KERN_ERR -+ "DMA Pause: Invalid dma handle.\n"); -+ -+ /* -+ * Fail. -+ */ -+ return(-EINVAL); -+ } -+ -+ DPRINTK("DMA %d: pause \n", channel); -+ -+ /* -+ * Set up a pointer to the dma instance data. -+ */ -+ dma = &dma_chan[channel]; -+ -+ /* -+ * Check if we're already paused. -+ */ -+ if (dma->pause) { -+ /* -+ * We're paused, but are we stopped? -+ */ -+ if (dma->xfer_enable) -+ /* -+ * Put the channel in the stopped state. -+ */ -+ dma->xfer_enable = FALSE; -+ -+ DPRINTK("DMA Pause - already paused."); -+ } else { -+ /* -+ * Put the channel into the stopped state. -+ */ -+ dma->xfer_enable = FALSE; -+ dma->pause = TRUE; -+ } -+ -+ /* -+ * restore interrupts. -+ */ -+ local_irq_restore(flags); -+ -+ /* -+ * Already paused, so exit. -+ */ -+ return(0); -+} -+ -+/***************************************************************************** -+ * -+ * void ep93xx_dma_flush(int handle) -+ * -+ * Description: Flushes all queued buffers and transfers in progress -+ * for the given channel. Return the buffer entries -+ * to the calling function. -+ * -+ * handle: handle for the channel for which the flush is intended. -+ * -+ ****************************************************************************/ -+int -+ep93xx_dma_flush(int handle) -+{ -+ unsigned int loop; -+ unsigned long flags; -+ ep93xx_dma_t * dma; -+ int channel; -+ unsigned int M2P_reg_base,uiCONTROL; -+ -+ /* -+ * Get the DMA hw channel # from the handle. -+ */ -+ channel = dma_get_channel_from_handle(handle); -+ -+ /* -+ * See if this is a valid handle. -+ */ -+ if (channel < 0) { -+ printk(KERN_ERR "DMA Flush: Invalid dma handle.\n"); -+ return(-EINVAL); -+ } -+ -+ DPRINTK("DMA %d: flush \n", channel); -+ -+ /* -+ * Set up a pointer to the dma instance data for this channel -+ */ -+ dma = &dma_chan[channel]; -+ -+ /* -+ * Mask interrupts and hold on to the original state. -+ */ -+ local_irq_save(flags); -+ -+ /* -+ * Disable the dma channel -+ */ -+ if (channel < 10) { -+ /* -+ * M2P channel -+ */ -+ uiCONTROL = inl(dma->reg_base+M2P_OFFSET_CONTROL); -+ uiCONTROL &= ~CONTROL_M2P_ENABLE; -+ outl( uiCONTROL, dma->reg_base+M2P_OFFSET_CONTROL ); -+ } else { -+ /* -+ * M2M channel -+ */ -+ uiCONTROL = inl(dma->reg_base+M2M_OFFSET_CONTROL); -+ uiCONTROL &= ~CONTROL_M2M_ENABLE; -+ outl( uiCONTROL, dma->reg_base+M2M_OFFSET_CONTROL ); -+ } -+ -+ for (loop = 0; loop < MAX_EP93XX_DMA_BUFFERS; loop++) -+ { -+ dma->buffer_queue[loop].buf_id = -1; -+ dma->buffer_queue[loop].last = 0; -+ } -+ -+ /* -+ * Set the Current and Last item to zero. -+ */ -+ dma->current_buffer = 0; -+ dma->last_buffer = 0; -+ -+ /* -+ * Reset the Buffer counters -+ */ -+ dma->used_buffers = 0; -+ dma->new_buffers = 0; -+ dma->total_buffers = 0; -+ -+ /* -+ * reset the Total bytes counter. -+ */ -+ dma->total_bytes = 0; -+ -+ /* -+ * Reset the paused buffer. -+ */ -+ dma->pause_buf.last = 0; -+ dma->pause_buf.buf_id = -1; -+ -+ M2P_reg_base = dma_chan[channel].reg_base; -+ -+ /* -+ * restore interrupts. -+ */ -+ local_irq_restore(flags); -+ -+ /* -+ * Success. -+ */ -+ return(0); -+} -+ -+/***************************************************************************** -+ * -+ * int ep93xx_dma_queue_full(int handle) -+ * -+ * Description: Query to determine if the DMA queue of buffers for -+ * a given channel is full. -+ * 0 = queue is full -+ * 1 = queue is not full -+ * -+ * handle: handle for the channel to query. -+ * -+ ****************************************************************************/ -+int -+ep93xx_dma_queue_full(int handle) -+{ -+ int list_full = 0; -+ unsigned long flags; -+ int channel; -+ -+ /* -+ * Get the DMA hw channel # from the handle. -+ */ -+ channel = dma_get_channel_from_handle(handle); -+ -+ /* -+ * See if this is a valid handle. -+ */ -+ if (channel < 0) { -+ printk(KERN_ERR "DMA Queue Full: Invalid dma handle.\n"); -+ return(-EINVAL); -+ } -+ -+ DPRINTK("DMA %d: queue full \n", channel); -+ -+ /* -+ * Mask interrupts and hold on to the original state. -+ */ -+ local_irq_save(flags); -+ -+ /* -+ * If the last item is equal to the used item then -+ * the queue is full. -+ */ -+ if (dma_chan[channel].total_buffers < MAX_EP93XX_DMA_BUFFERS) -+ list_full = FALSE; -+ else -+ list_full = TRUE; -+ -+ /* -+ * restore interrupts. -+ */ -+ local_irq_restore(flags); -+ -+ return(list_full); -+} -+ -+/***************************************************************************** -+ * -+ * int ep93xx_dma_get_position() -+ * -+ * Description: Takes two integer pointers and fills them with the start -+ * and current address of the buffer currently transferring -+ * on the specified DMA channel. -+ * -+ * handle handle for the channel to query. -+ * *buf_id buffer id for the current buffer transferring on the -+ * dma channel. -+ * *total total bytes transferred on the channel. Only counts -+ * whole buffers transferred. -+ * *current_frac number of bytes transferred so far in the current buffer. -+ ****************************************************************************/ -+int -+ep93xx_dma_get_position(int handle, unsigned int * buf_id, -+ unsigned int * total, unsigned int * current_frac ) -+{ -+ int channel; -+ ep93xx_dma_t * dma; -+ unsigned int buf_id1, total1, current_frac1, buf_id2, total2; -+ unsigned int Status, NextBuffer, StateIsBufNext, M2P_reg_base=0; -+ unsigned int pause1, pause2; -+ -+ /* -+ * Get the DMA hw channel # from the handle. See if this is a -+ * valid handle. -+ */ -+ channel = dma_get_channel_from_handle(handle); -+ if (channel < 0) { -+ printk(KERN_ERR "DMA Get Position: Invalid dma handle.\n"); -+ return(-EINVAL); -+ } -+ -+ dma = &dma_chan[channel]; -+ -+ /* -+ * If DMA moves to a new buffer in the middle of us grabbing the -+ * buffer info, then do it over again. -+ */ -+ do{ -+ buf_id1 = dma->buffer_queue[dma->current_buffer].buf_id; -+ total1 = dma->total_bytes; -+ pause1 = dma->pause; -+ -+ if (channel < 10) { -+ // M2P -+ M2P_reg_base = dma->reg_base; -+ -+ Status = inl(M2P_reg_base+M2P_OFFSET_STATUS); -+ -+ NextBuffer = ((Status & STATUS_M2P_NEXTBUFFER) != 0); -+ -+ StateIsBufNext = ((Status & STATUS_M2P_CURRENT_MASK) == -+ STATUS_M2P_DMA_BUF_NEXT); -+ -+ if( NextBuffer ^ StateIsBufNext ) -+ current_frac1 = inl(M2P_reg_base+M2P_OFFSET_CURRENT1) - -+ inl(M2P_reg_base+M2P_OFFSET_BASE1); -+ else -+ current_frac1 = inl(M2P_reg_base+M2P_OFFSET_CURRENT0) - -+ inl(M2P_reg_base+M2P_OFFSET_BASE0); -+ -+ } else { -+ // M2M - TODO implement this for M2M -+ current_frac1 = 0; -+ } -+ -+ buf_id2 = dma->buffer_queue[dma->current_buffer].buf_id; -+ total2 = dma->total_bytes; -+ pause2 = dma->pause; -+ -+ } while ( (buf_id1 != buf_id2) || (total1 != total2) || (pause1 != pause2) ); -+ -+ if (pause1) -+ current_frac1 = 0; -+ -+ if (buf_id) -+ *buf_id = buf_id1; -+ -+ if (total) -+ *total = total1; -+ -+ if (current_frac) -+ *current_frac = current_frac1; -+ -+// DPRINTK("DMA buf_id %d, total %d, frac %d\n", buf_id1, total1, current_frac1); -+ -+ /* -+ * Success. -+ */ -+ return(0); -+} -+ -+/***************************************************************************** -+ * -+ * int ep93xx_dma_get_total(int handle) -+ * -+ * Description: Returns the total number of bytes transferred on the -+ * specified channel since the channel was requested. -+ * -+ * handle: handle for the channel to query. -+ * -+ ****************************************************************************/ -+int -+ep93xx_dma_get_total(int handle) -+{ -+ int channel; -+ -+ /* -+ * Get the DMA hw channel # from the handle. -+ */ -+ channel = dma_get_channel_from_handle(handle); -+ -+ /* -+ * See if this is a valid handle. -+ */ -+ if (channel < 0) { -+ printk(KERN_ERR "DMA Get Total: Invalid dma handle.\n"); -+ return(-EINVAL); -+ } -+ -+ DPRINTK("DMA %d: total: %d \n", channel, dma_chan[channel].total_bytes); -+ -+ /* -+ * Return the total number of bytes transferred on this channel since -+ * it was requested. -+ */ -+ return(dma_chan[channel].total_bytes); -+} -+ -+/***************************************************************************** -+ * -+ * int ep93xx_dma_is_done(int handle) -+ * -+ * Description: Determines if the specified channel is done -+ * transferring the requested data. -+ * -+ * handle: handle for the channel to query. -+ * -+ ****************************************************************************/ -+int -+ep93xx_dma_is_done(int handle) -+{ -+ ep93xx_dma_t *dma; -+ int channel; -+ -+ /* -+ * Get the DMA hw channel # from the handle. -+ */ -+ channel = dma_get_channel_from_handle(handle); -+ -+ /* -+ * See if this is a valid handle. -+ */ -+ if (channel < 0) { -+ printk(KERN_ERR "ep93xx_dma_is_done: Invalid dma handle.\n"); -+ return(-EINVAL); -+ } -+ -+ /* -+ * Get a pointer to the DMA channel state structure. -+ */ -+ dma = &dma_chan[channel]; -+ -+ /* -+ * See if there are any buffers remaining to be provided to the HW. -+ */ -+ if (dma->new_buffers) -+ return 0; -+ -+ /* -+ * See if this is a M2P or M2M channel. -+ */ -+ if (channel < 10) { -+ /* -+ * If the bytes remaining register of the HW is not zero, then -+ * there is more work to be done. -+ */ -+ if (inl(dma->reg_base + M2P_OFFSET_REMAIN) != 0) -+ return 0; -+ } else { -+ /* -+ * If either byte count register in the HW is not zero, then there -+ * is more work to be done. -+ */ -+ if ((inl(dma->reg_base + M2M_OFFSET_BCR0) != 0) || -+ (inl(dma->reg_base + M2M_OFFSET_BCR1) != 0)) -+ return 0; -+ } -+ -+ /* -+ * The DMA is complete. -+ */ -+ return 1; -+} -+ -+/***************************************************************************** -+ * ep93xx_dma_request -+ * -+ * Description: This function will allocate a DMA channel for a particular -+ * hardware peripheral. Before initiating a transfer on the allocated -+ * channel, the channel must be set up and buffers have to queued up. -+ * -+ * handle: pointer to an integer which is filled in with a unique -+ * handle for this instance of the dma interface. -+ * device_id string with the device name, primarily used by /proc. -+ * device hardware device ID for which the requested dma channel will -+ * transfer data. -+ * -+ ****************************************************************************/ -+int -+ep93xx_dma_request(int * handle, const char *device_id, -+ ep93xx_dma_dev_t device) -+{ -+ ep93xx_dma_t *dma = NULL; -+ int channel; -+ unsigned int error = 0; -+ unsigned int loop; -+ unsigned int M2P_reg_base; -+ -+ /* -+ * Check if the device requesting a DMA channel is a valid device. -+ */ -+ if ((device >= UNDEF_DMA) || (device < 0)) -+ return(-ENODEV); -+ -+ /* -+ * We've got a valid hardware device requesting a DMA channel. -+ * Now check if the device should open an M2P or M2M channel -+ */ -+ if (device < 20) -+ channel = dma_open_m2p(device); -+ else -+ channel = dma_open_m2m(device); -+ -+ /* -+ * Check if we successfully opened a DMA channel -+ */ -+ if (channel < 0) { -+ printk(KERN_ERR "%s: Could not open dma channel for this device.\n", -+ device_id); -+ return(-EBUSY); -+ } -+ -+ dma = &dma_chan[channel]; -+ -+ if(dma->terminated==1) { -+ free_irq(dma->irq, (void *) dma); -+ dma->terminated=0; -+ } -+ -+ /* -+ * Request the appropriate IRQ for the specified channel -+ */ -+ if (channel < 10) -+ error = request_irq(dma->irq, dma_m2p_irq_handler, -+ IRQF_DISABLED, device_id, (void *) dma); -+ else -+ error = request_irq(dma->irq, &dma_m2m_irq_handler, -+ IRQF_DISABLED, device_id, (void *) dma); -+ -+ /* -+ * Check for any errors during the irq request -+ */ -+ if (error) { -+ printk(KERN_ERR "%s: unable to request IRQ %d for DMA channel\n", -+ device_id, dma->irq); -+ return(error); -+ } -+ -+ /* -+ * Generate a valid handle and exit. -+ * -+ * Increment the last valid handle. -+ * Check for wraparound (unlikely, but we like to be complete). -+ */ -+ dma->last_valid_handle++; -+ -+ if ( (dma->last_valid_handle & DMA_HANDLE_SPECIFIER_MASK) != -+ (channel << 28) ) -+ dma->last_valid_handle = (channel << 28) + 1; -+ -+ /* -+ * Fill in the handle pointer with a valid handle for -+ * this dma channel instance. -+ */ -+ *handle = dma->last_valid_handle; -+ -+ DPRINTK("Handle for channel %d: 0x%x\n", channel, *handle); -+ -+ /* -+ * Save the device ID and device name. -+ */ -+ dma->device = device; -+ dma->device_id = device_id; -+ -+ /* -+ * Init all fields within the dma instance. -+ */ -+ for (loop = 0; loop < MAX_EP93XX_DMA_BUFFERS; loop++) -+ dma->buffer_queue[loop].buf_id = -1; -+ -+ /* -+ * Initialize all buffer queue variables. -+ */ -+ dma->current_buffer = 0; -+ dma->last_buffer = 0; -+ -+ dma->new_buffers = 0; -+ dma->used_buffers = 0; -+ dma->total_buffers = 0; -+ -+ /* -+ * Initialize the total bytes variable -+ */ -+ dma->total_bytes = 0; -+ -+ /* -+ * Initialize the transfer and pause state variables to 0. -+ */ -+ dma->xfer_enable = 0; -+ -+ dma->pause = 0; -+ -+ /* -+ * Initialize the pause buffer structure. -+ */ -+ dma->pause_buf.buf_id = -1; -+ -+ /* -+ * Initialize the callback function and user data fields. -+ */ -+ dma->callback = NULL; -+ -+ /* -+ * User data used as a parameter for the Callback function. The user -+ * sets up the data and sends it with the callback function. -+ */ -+ dma->user_data = 0; -+ -+ M2P_reg_base = dma_chan[channel].reg_base; -+ -+ /* -+ * Debugging message. -+ */ -+ DPRINTK("Successfully requested dma channel %d\n", channel); -+ DPRINTK("STATUS - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_STATUS) ); -+ DPRINTK("CONTROL - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_CONTROL) ); -+ DPRINTK("REMAIN - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_REMAIN) ); -+ DPRINTK("PPALLOC - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_PPALLOC) ); -+ DPRINTK("BASE0 - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_BASE0) ); -+ DPRINTK("MAXCNT0 - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_MAXCNT0) ); -+ DPRINTK("CURRENT0 - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_CURRENT0) ); -+ DPRINTK("BASE1 - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_BASE1) ); -+ DPRINTK("MAXCNT1 - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_MAXCNT1) ); -+ DPRINTK("CURRENT1 - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_CURRENT1) ); -+ -+ DPRINTK("Buffer source size last used \n"); -+ for (loop = 0; loop < 5; loop ++) -+ DPRINTK("%d 0x%x 0x%x %d %d \n", -+ loop, dma->buffer_queue[loop].source, dma->buffer_queue[loop].size, -+ dma->buffer_queue[loop].last, dma->buffer_queue[loop].used); -+ DPRINTK("pause 0x%x 0x%x %d %d \n", -+ dma->pause_buf.source, dma->pause_buf.size, -+ dma->pause_buf.last, dma->pause_buf.used); -+ -+ DPRINTK("Pause - %d \n", dma->pause); -+ DPRINTK("xfer_enable - %d \n", dma->xfer_enable); -+ DPRINTK("total bytes - 0x%x \n", dma->total_bytes); -+ DPRINTK("total buffer - %d \n", dma->total_buffers); -+ DPRINTK("new buffers - %d \n", dma->new_buffers); -+ DPRINTK("current buffer - %d \n", dma->current_buffer); -+ DPRINTK("last buffer - %d \n", dma->last_buffer); -+ DPRINTK("used buffers - %d \n", dma->used_buffers); -+ -+ DPRINTK("CURRENT1 - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_CURRENT1) ); -+ DPRINTK("VIC0IRQSTATUS - 0x%x, VIC0INTENABLE - 0x%x \n", -+ *(unsigned int *)(VIC0IRQSTATUS), -+ *(unsigned int *)(VIC0INTENABLE)); -+ -+ /* -+ * Success. -+ */ -+ return(0); -+} -+ -+/***************************************************************************** -+ * -+ * ep93xx_dma_free -+ * -+ * Description: This function will free the dma channel for future requests. -+ * -+ * handle: handle for the channel to be freed. -+ * -+ ****************************************************************************/ -+int -+ep93xx_dma_free(int handle) -+{ -+ ep93xx_dma_t *dma; -+ unsigned int M2M_reg_base, M2P_reg_base, uiCONTROL; -+ int channel; -+ -+ /* -+ * Get the DMA hw channel # from the handle. -+ */ -+ channel = dma_get_channel_from_handle(handle); -+ -+ /* -+ * See if this is a valid handle. -+ */ -+ if (channel < 0) { -+ printk(KERN_ERR "DMA Free: Invalid dma handle.\n"); -+ return(-EINVAL); -+ } -+ -+ /* -+ * Get a pointer to the dma instance. -+ */ -+ dma = &dma_chan[channel]; -+ -+ /* -+ * Disable the dma channel -+ */ -+ if (channel < 10) { -+ /* -+ * M2P channel -+ */ -+ M2P_reg_base = dma->reg_base; -+ -+ uiCONTROL = inl(M2P_reg_base+M2P_OFFSET_CONTROL); -+ uiCONTROL &= ~CONTROL_M2P_ENABLE; -+ outl( uiCONTROL, M2P_reg_base+M2P_OFFSET_CONTROL ); -+ } else { -+ /* -+ * M2M channel -+ */ -+ M2M_reg_base = dma->reg_base; -+ -+ uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL); -+ uiCONTROL &= ~CONTROL_M2M_ENABLE; -+ outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL ); -+ } -+ -+ /* -+ * Free the interrupt servicing this dma channel -+ */ -+ //free_irq(dma->irq, (void *) dma); -+ dma->terminated=1; -+ -+ /* -+ * Decrement the reference count for this instance of the dma interface -+ */ -+ dma->ref_count--; -+ -+ /* -+ * Set the transfer and pause state variables to 0 -+ * (unititialized state). -+ */ -+ dma->xfer_enable = 0; -+ dma->pause = 0; -+ -+ /* -+ * Debugging message. -+ */ -+ DPRINTK("Successfully freed dma channel %d\n", channel); -+ /* -+ * Success. -+ */ -+ return(0); -+} -+ -+/***************************************************************************** -+ * -+ * ep93xx_dma_init(void) -+ * -+ * Description: This function is called during system initialization to -+ * setup the interrupt number and register set base address for each DMA -+ * channel. -+ * -+ ****************************************************************************/ -+static int __init -+ep93xx_dma_init(void) -+{ -+ int channel; -+ -+ /* -+ * Init some values in each dma instance. -+ */ -+ for (channel = 0; channel < MAX_EP93XX_DMA_CHANNELS; channel++) { -+ /* -+ * IRQ for the specified dma channel. -+ */ -+ dma_chan[channel].irq = IRQ_EP93XX_DMAM2P0 + channel; -+ -+ dma_chan[channel].terminated = 0; -+ -+ /* -+ * Initial value of the dma channel handle. -+ */ -+ dma_chan[channel].last_valid_handle = channel << 28; -+ -+ /* -+ * Give the instance a pointer to the dma channel register -+ * base. -+ */ -+ if (channel < 10) -+ dma_chan[channel].reg_base = DMAM2PChannelBase[channel]; -+ else -+ dma_chan[channel].reg_base = DMAM2MChannelBase[channel - 10]; -+ -+ /* -+ * Initialize the reference count for this channel. -+ */ -+ dma_chan[channel].ref_count = 0; -+ } -+ -+ DPRINTK("DMA Interface intitialization complete\n"); -+ -+ /* -+ * Success -+ */ -+ return 0; -+} -+ -+arch_initcall(ep93xx_dma_init); -+ -+EXPORT_SYMBOL(ep93xx_dma_free); -+EXPORT_SYMBOL(ep93xx_dma_request); -+EXPORT_SYMBOL(ep93xx_dma_flush); -+EXPORT_SYMBOL(ep93xx_dma_pause); -+EXPORT_SYMBOL(ep93xx_dma_remove_buffer); -+EXPORT_SYMBOL(ep93xx_dma_add_buffer); -+EXPORT_SYMBOL(ep93xx_dma_start); -+EXPORT_SYMBOL(ep93xx_dma_config); ---- /dev/null -+++ b/arch/arm/mach-ep93xx/dma_ep93xx.h -@@ -0,0 +1,676 @@ -+/***************************************************************************** -+ * -+ * arch/arm/mach-ep93xx/dma_ep93xx.h -+ * -+ * DESCRIPTION: 93XX DMA controller API private defintions. -+ * -+ * Copyright Cirrus Logic Corporation, 2003. All rights reserved -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ ****************************************************************************/ -+#ifndef _EP93XX_DMA_H_ -+#define _EP93XX_DMA_H_ -+ -+// as it turns out the ide dma is the biggest dma buffer hog so far -+// in case the HDD is "thinking" (seek/buffer flush) -+// the continueing r/w DMAs to the HDD will be queued up to up to PRD_ENTRIES entries... -+#include <linux/ide.h> -+#define MAX_EP93XX_DMA_BUFFERS PRD_ENTRIES -+ -+#ifndef TRUE -+#define TRUE 1 -+#endif -+ -+#ifndef FALSE -+#define FALSE 0 -+#endif -+ -+#ifndef NULL -+#define NULL 0 -+#endif -+ -+#define EP93XX_DMA_BASE (EP93XX_AHB_VIRT_BASE + 0x00000000) -+ -+/***************************************************************************** -+ * 0x8000.0000 -> 0x8000.003C M2P Channel 0 Registers (Tx) -+ * 0x8000.0040 -> 0x8000.007C M2P Channel 1 Registers (Rx) -+ * 0x8000.0080 -> 0x8000.00BC M2P Channel 2 Registers (Tx) -+ * 0x8000.00C0 -> 0x8000.00FC M2P Channel 3 Registers (Rx) -+ * 0x8000.0100 -> 0x8000.013C M2M Channel 0 Registers -+ * 0x8000.0140 -> 0x8000.017C M2M Channel 1 Registers -+ * 0x8000.0180 -> 0x8000.01BC Not Used -+ * 0x8000.01C0 -> 0x8000.01FC Not Used -+ * 0x8000.0200 -> 0x8000.023C M2P Channel 5 Registers (Rx) -+ * 0x8000.0240 -> 0x8000.027C M2P Channel 4 Registers (Tx) -+ * 0x8000.0280 -> 0x8000.02BC M2P Channel 7 Registers (Rx) -+ * 0x8000.02C0 -> 0x8000.02FC M2P Channel 6 Registers (Tx) -+ * 0x8000.0300 -> 0x8000.033C M2P Channel 9 Registers (Rx) -+ * 0x8000.0340 -> 0x8000.037C M2P Channel 8 Registers (Tx) -+ * 0x8000.0380 DMA Channel Arbitration register -+ * 0x8000.03C0 DMA Global Interrupt register -+ * 0x8000.03C4 -> 0x8000.03FC Not Used -+ * -+ * -+ * Internal M2P/P2M Channel Register Map -+ * -+ * Offset Name Access Bits Reset Value -+ * 0x00 CONTROL R/W 6 0 -+ * 0x04 INTERRUPT R/W TC* 3 0 -+ * 0x08 PPALLOC R/W 4 channel dependant -+ * (see reg description) -+ * 0x0C STATUS RO 8 0 -+ * 0x10 reserved -+ * 0x14 REMAIN RO 16 0 -+ * 0X18 Reserved -+ * 0X1C Reserved -+ * 0x20 MAXCNT0 R/W 16 0 -+ * 0x24 BASE0 R/W 32 0 -+ * 0x28 CURRENT0 RO 32 0 -+ * 0x2C Reserved -+ * 0x30 MAXCNT1 R/W 16 0 -+ * 0x34 BASE1 R/W 32 0 -+ * 0X38 CURRENT1 RO 32 0 -+ * 0X3C Reserved -+ * -+ * M2M Channel Register Map -+ * Offset Name Access Bits Reset Value -+ * -+ * 0x00 CONTROL R/W 22 0 -+ * 0x04 INTERRUPT R/W TC* 3 0 -+ * 0x08 Reserved -+ * 0x0C STATUS R/W TC* 14 0 -+ * 0x10 BCR0 R/W 16 0 -+ * 0x14 BCR1 R/W 16 0 -+ * 0x18 SAR_BASE0 R/W 32 0 -+ * 0x1C SAR_BASE1 R/W 32 0 -+ * 0x20 Reserved -+ * 0x24 SAR_CURRENT0 RO 32 0 -+ * 0x28 SAR_CURRENT1 RO 32 0 -+ * 0x2C DAR_BASE0 R/W 32 0 -+ * 0x30 DAR_BASE1 R/W 32 0 -+ * 0x34 DAR_CURRENT0 RO 32 0 -+ * 0X38 Reserved -+ * 0X3C DAR_CURRENT1 RO 32 0 -+ * * Write this location once to clear the bit (see -+ * Interrupt/Status register description for which bits -+ * this rule applies to). -+ * -+ ****************************************************************************/ -+ -+ -+/*----------------------------------------------------------------------------------*/ -+/* M2P Registers */ -+/*----------------------------------------------------------------------------------*/ -+/* -+ * M2P CONTROL register bit defines -+ */ -+#define CONTROL_M2P_STALLINTEN 0x00000001 /* Enables the STALL interrupt */ -+#define CONTROL_M2P_NFBINTEN 0x00000002 /* Enables the NFB interrupt */ -+#define CONTROL_M2P_CHERRORINTEN 0x00000008 /* Enables the ChError interrupt*/ -+#define CONTROL_M2P_ENABLE 0x00000010 /* Enables the channel */ -+#define CONTROL_M2P_ABRT 0x00000020 /* Determines how DMA behaves in*/ -+ /* NEXT state with peripheral */ -+ /* error */ -+ /* 0: NEXT -> ON, ignore error */ -+ /* 1: NEXT -> STALL, disable ch.*/ -+#define CONTROL_M2P_ICE 0x00000040 /* Ignore Channel Error */ -+ -+/* -+ * M2P INTERRUPT register bit defines -+ */ -+#define INTERRUPT_M2P_STALLINT 0x00000001 /* Indicates channel stalled. */ -+#define INTERRUPT_M2P_NFBINT 0x00000002 /* Indicates channel is hungry. */ -+#define INTERRUPT_M2P_CHERRORINT 0x00000008 /* Peripheral detects error */ -+ -+ -+/* -+ * STATUS register bit defines -+ */ -+#define STATUS_M2P_STALL 0x00000001 /* A '1' indicates channel is */ -+ /* stalled */ -+#define STATUS_M2P_NFB 0x00000002 /* A '1' indicates channel has moved*/ -+ /* from NEXT state to ON state, but */ -+ /* waiting for next buffer to be */ -+ /* programmed. */ -+#define STATUS_M2P_CHERROR 0x00000008 /* Enables the ChError interrupt */ -+#define STATUS_M2P_CURRENT_MASK 0x00000030 /* Current state of the FSM */ -+#define STATUS_M2P_CURRENT_SHIFT 4 -+#define STATUS_M2P_NEXTBUFFER 0x00000040 /* Informs the int handler after an */ -+ /* NFB int which pair of maxcnt and */ -+ /* base regs to update. */ -+#define STATUS_M2P_BYTES_MASK 0x0000f800 /* number of valid DMA data */ -+#define STATUS_M2P_BYTES_SHIFT 7 /* currently in */ -+ /* packer/unpacker */ -+ -+#define STATUS_M2P_DMA_NO_BUF 0x00000000 -+#define STATUS_M2P_DMA_BUF_ON 0x00000010 -+#define STATUS_M2P_DMA_BUF_NEXT 0x00000020 -+ -+/* -+ * Register masks to mask off reserved bits after reading register. -+ */ -+#define M2P_MASK_PPALLOC 0x0000000f -+#define M2P_MASK_REMAIN 0x0000ffff -+#define M2P_MASK_MAXCNT0 0x0000ffff -+#define M2P_MASK_BASE0 0xffffffff -+#define M2P_MASK_CURRENT0 0xffffffff -+#define M2P_MASK_MAXCNT1 0x0000ffff -+#define M2P_MASK_BASE1 0xffffffff -+#define M2P_MASK_CURRENT1 0xffffffff -+ -+ -+/*----------------------------------------------------------------------------------*/ -+/* M2M Registers */ -+/*----------------------------------------------------------------------------------*/ -+ -+#define CONTROL_M2M_STALLINTEN 0x00000001 /* Enables the STALL interrupt */ -+#define CONTROL_M2M_SCT 0x00000002 /* Source Copy Transfer. Setup a */ -+ /* block transfer from 1 memory source */ -+ /* location. */ -+#define CONTROL_M2M_DONEINTEN 0x00000004 /* Enables the DONE interrupt which */ -+ /* indicates if the xfer completed */ -+ /* successfully */ -+#define CONTROL_M2M_ENABLE 0x00000008 /* Enables the channel */ -+#define CONTROL_M2M_START 0x00000010 /* Initiates the xfer. 'software trigger' */ -+#define CONTROL_M2M_BWC_MASK 0x000001e0 /* Bandwidth control. Indicate number of */ -+#define CONTROL_M2M_BWC_SHIFT 5 /* bytes in a transfer. */ -+#define CONTROL_M2M_PW_MASK 0x00000600 /* Peripheral width. Used for xfers */ -+#define CONTROL_M2M_PW_SHIFT 9 /* between memory and external peripheral. */ -+ /* 00: byte, 01: halfword, 10: word. */ -+#define CONTROL_M2M_DAH 0x00000800 /* Destination Address Hold */ -+#define CONTROL_M2M_SAH 0x00001000 /* Source Address Hold */ -+#define CONTROL_M2M_TM_MASK 0x00006000 /* Transfer Mode. 00: sw triggered, */ -+#define CONTROL_M2M_TM_SHIFT 13 /* 01: hw initiated M2P, 01: hw initiated P2M */ -+#define CONTROL_M2M_ETDP_MASK 0x00018000 /* End-of-Transfer/Terminal Count pin */ -+#define CONTROL_M2M_ETDP_SHIFT 15 /* direction and polarity. */ -+#define CONTROL_M2M_DACKP 0x00020000 /* DMA acknowledge pin polarity */ -+ -+#define CONTROL_M2M_DREQP_MASK 0x00180000 /* DMA request pin polarity. must be set */ -+#define CONTROL_M2M_DREQP_SHIFT 19 /* before enable bit. */ -+#define CONTROL_M2M_NFBINTEN 0x00200000 /* Enables generation of the NFB interrupt. */ -+#define CONTROL_M2M_RSS_MASK 0x00c00000 /* Request source selection: */ -+#define CONTROL_M2M_RSS_SHIFT 22 /* 000 - External DReq[0] */ -+ /* 001 - External DReq[1] */ -+ /* 01X - Internal SSPRx */ -+ /* 10X - Internal SSPTx */ -+ /* 11X - Internal IDE */ -+#define CONTROL_M2M_NO_HDSK 0x01000000 /* No handshake. When set the peripheral doesn't */ -+ /* require the regular handshake protocal. Must */ -+ /* be set for SSP and IDE operations, optional */ -+ /* for external peripherals. */ -+#define CONTROL_M2M_PWSC_MASK 0xfe000000 /* Peripheral wait states count. Gives the latency */ -+#define CONTROL_M2M_PWSC_SHIFT 25 /* (in PCLK cycles) needed by the peripheral to */ -+ /* deassert its' request once the M2M xfer w/ DMA */ -+ /* is complete. */ -+ -+/* -+ * M2M INTERRUPT register bit defines -+ */ -+#define INTERRUPT_M2M_STALLINT 0x00000001 /* Stall interrupt indicates channel stalled. */ -+#define INTERRUPT_M2M_DONEINT 0x00000002 /* Transaction done. */ -+#define INTERRUPT_M2M_NFBINT 0x00000004 /* Next frame buffer interrupt indicates */ -+ /* channel requires a new buffer */ -+ -+ -+ -+/* -+ * M2M STATUS register bit defines -+ */ -+#define STATUS_M2M_STALL 0x00000001 /* A '1' indicates channel is stalled */ -+#define STATUS_M2M_CURRENTSTATE_MASK 0x0000003e /* Indicates state of M2M Channel control */ -+#define STATUS_M2M_CURRENTSTATE_SHIFT 1 /* FSM (0-2): */ -+ /* 000 - IDLE, 001 - STALL, 010 - MEM_RD, */ -+ /* 011 - MEM_WR, 100 - BWC_WAIT */ -+ /* and M2M buffer FSM (3-2): */ -+ /* 00 - NO_BUF, 01 - BUF_ON, 10 - BUF_NEXT */ -+#define STATUS_M2M_DONE 0x00000040 /* Transfer completed successfully if 1. */ -+#define STATUS_M2M_TCS_MASK 0x00000180 /* Terminal Count status. Indicates whether or */ -+#define STATUS_M2M_TCS_SHIFT 7 /* or not the actual byte count reached */ -+ /* programmed limit for buffer descriptor */ -+#define STATUS_M2M_EOTS_MASK 0x00000600 /* End-of-Transfer status for buffer */ -+#define STATUS_M2M_EOTS_SHIFT 9 -+#define STATUS_M2M_NFB 0x00000800 /* A '1' indicates channel has moved */ -+ /* from NEXT state to ON state, but the next */ -+ /* byte count reg for next buffer has not been */ -+ /* programmed yet. */ -+#define STATUS_M2M_NB 0x00001000 /* NextBuffer status. Informs NFB service */ -+ /* routine, after NFB int, which pair of buffer */ -+ /* descriptor registers is free to update. */ -+#define STATUS_M2M_DREQS 0x00002000 /* DREQ status. Reflects the status of the */ -+ /* synchronized external peripherals DMA */ -+ /* request signal. */ -+ -+/* -+ * Register masks to mask off reserved bits after reading register. -+ */ -+#define M2M_MASK_BCR0 0x0000ffff -+#define M2M_MASK_BCR1 0x0000ffff -+#define M2M_MASK_SAR_BASE0 0xffffffff -+#define M2M_MASK_SAR_BASE1 0xffffffff -+#define M2M_MASK_SAR_CURRENT0 0xffffffff -+#define M2M_MASK_SAR_CURRENT1 0xffffffff -+#define M2M_MASK_DAR_BASE0 0xffffffff -+#define M2M_MASK_DAR_BASE1 0xffffffff -+#define M2M_MASK_DAR_CURRENT0 0xffffffff -+#define M2M_MASK_DAR_CURRENT1 0xffffffff -+ -+ -+// -+/* 8000_0000 - 8000_ffff: DMA */ -+#define DMA_OFFSET 0x000000 -+#define DMA_BASE (EP93XX_DMA_BASE) -+#define DMAMP_TX_0_CONTROL (DMA_BASE+0x0000) -+#define DMAMP_TX_0_INTERRUPT (DMA_BASE+0x0004) -+#define DMAMP_TX_0_PPALLOC (DMA_BASE+0x0008) -+#define DMAMP_TX_0_STATUS (DMA_BASE+0x000C) -+#define DMAMP_TX_0_REMAIN (DMA_BASE+0x0014) -+#define DMAMP_TX_0_MAXCNT0 (DMA_BASE+0x0020) -+#define DMAMP_TX_0_BASE0 (DMA_BASE+0x0024) -+#define DMAMP_TX_0_CURRENT0 (DMA_BASE+0x0028) -+#define DMAMP_TX_0_MAXCNT1 (DMA_BASE+0x0030) -+#define DMAMP_TX_0_BASE1 (DMA_BASE+0x0034) -+#define DMAMP_TX_0_CURRENT1 (DMA_BASE+0x0038) -+ -+#define DMAMP_RX_1_CONTROL (DMA_BASE+0x0040) -+#define DMAMP_RX_1_INTERRUPT (DMA_BASE+0x0044) -+#define DMAMP_RX_1_PPALLOC (DMA_BASE+0x0048) -+#define DMAMP_RX_1_STATUS (DMA_BASE+0x004C) -+#define DMAMP_RX_1_REMAIN (DMA_BASE+0x0054) -+#define DMAMP_RX_1_MAXCNT0 (DMA_BASE+0x0060) -+#define DMAMP_RX_1_BASE0 (DMA_BASE+0x0064) -+#define DMAMP_RX_1_CURRENT0 (DMA_BASE+0x0068) -+#define DMAMP_RX_1_MAXCNT1 (DMA_BASE+0x0070) -+#define DMAMP_RX_1_BASE1 (DMA_BASE+0x0074) -+#define DMAMP_RX_1_CURRENT1 (DMA_BASE+0x0078) -+ -+#define DMAMP_TX_2_CONTROL (DMA_BASE+0x0080) -+#define DMAMP_TX_2_INTERRUPT (DMA_BASE+0x0084) -+#define DMAMP_TX_2_PPALLOC (DMA_BASE+0x0088) -+#define DMAMP_TX_2_STATUS (DMA_BASE+0x008C) -+#define DMAMP_TX_2_REMAIN (DMA_BASE+0x0094) -+#define DMAMP_TX_2_MAXCNT0 (DMA_BASE+0x00A0) -+#define DMAMP_TX_2_BASE0 (DMA_BASE+0x00A4) -+#define DMAMP_TX_2_CURRENT0 (DMA_BASE+0x00A8) -+#define DMAMP_TX_2_MAXCNT1 (DMA_BASE+0x00B0) -+#define DMAMP_TX_2_BASE1 (DMA_BASE+0x00B4) -+#define DMAMP_TX_2_CURRENT1 (DMA_BASE+0x00B8) -+ -+#define DMAMP_RX_3_CONTROL (DMA_BASE+0x00C0) -+#define DMAMP_RX_3_INTERRUPT (DMA_BASE+0x00C4) -+#define DMAMP_RX_3_PPALLOC (DMA_BASE+0x00C8) -+#define DMAMP_RX_3_STATUS (DMA_BASE+0x00CC) -+#define DMAMP_RX_3_REMAIN (DMA_BASE+0x00D4) -+#define DMAMP_RX_3_MAXCNT0 (DMA_BASE+0x00E0) -+#define DMAMP_RX_3_BASE0 (DMA_BASE+0x00E4) -+#define DMAMP_RX_3_CURRENT0 (DMA_BASE+0x00E8) -+#define DMAMP_RX_3_MAXCNT1 (DMA_BASE+0x00F0) -+#define DMAMP_RX_3_BASE1 (DMA_BASE+0x00F4) -+#define DMAMP_RX_3_CURRENT1 (DMA_BASE+0x00F8) -+ -+#define DMAMM_0_CONTROL (DMA_BASE+0x0100) -+#define DMAMM_0_INTERRUPT (DMA_BASE+0x0104) -+#define DMAMM_0_STATUS (DMA_BASE+0x010C) -+#define DMAMM_0_BCR0 (DMA_BASE+0x0110) -+#define DMAMM_0_BCR1 (DMA_BASE+0x0114) -+#define DMAMM_0_SAR_BASE0 (DMA_BASE+0x0118) -+#define DMAMM_0_SAR_BASE1 (DMA_BASE+0x011C) -+#define DMAMM_0_SAR_CURRENT0 (DMA_BASE+0x0124) -+#define DMAMM_0_SAR_CURRENT1 (DMA_BASE+0x0128) -+#define DMAMM_0_DAR_BASE0 (DMA_BASE+0x012C) -+#define DMAMM_0_DAR_BASE1 (DMA_BASE+0x0130) -+#define DMAMM_0_DAR_CURRENT0 (DMA_BASE+0x0134) -+#define DMAMM_0_DAR_CURRENT1 (DMA_BASE+0x013C) -+ -+#define DMAMM_1_CONTROL (DMA_BASE+0x0140) -+#define DMAMM_1_INTERRUPT (DMA_BASE+0x0144) -+#define DMAMM_1_STATUS (DMA_BASE+0x014C) -+#define DMAMM_1_BCR0 (DMA_BASE+0x0150) -+#define DMAMM_1_BCR1 (DMA_BASE+0x0154) -+#define DMAMM_1_SAR_BASE0 (DMA_BASE+0x0158) -+#define DMAMM_1_SAR_BASE1 (DMA_BASE+0x015C) -+#define DMAMM_1_SAR_CURRENT0 (DMA_BASE+0x0164) -+#define DMAMM_1_SAR_CURRENT1 (DMA_BASE+0x0168) -+#define DMAMM_1_DAR_BASE0 (DMA_BASE+0x016C) -+#define DMAMM_1_DAR_BASE1 (DMA_BASE+0x0170) -+#define DMAMM_1_DAR_CURRENT0 (DMA_BASE+0x0174) -+#define DMAMM_1_DAR_CURRENT1 (DMA_BASE+0x017C) -+ -+#define DMAMP_RX_5_CONTROL (DMA_BASE+0x0200) -+#define DMAMP_RX_5_INTERRUPT (DMA_BASE+0x0204) -+#define DMAMP_RX_5_PPALLOC (DMA_BASE+0x0208) -+#define DMAMP_RX_5_STATUS (DMA_BASE+0x020C) -+#define DMAMP_RX_5_REMAIN (DMA_BASE+0x0214) -+#define DMAMP_RX_5_MAXCNT0 (DMA_BASE+0x0220) -+#define DMAMP_RX_5_BASE0 (DMA_BASE+0x0224) -+#define DMAMP_RX_5_CURRENT0 (DMA_BASE+0x0228) -+#define DMAMP_RX_5_MAXCNT1 (DMA_BASE+0x0230) -+#define DMAMP_RX_5_BASE1 (DMA_BASE+0x0234) -+#define DMAMP_RX_5_CURRENT1 (DMA_BASE+0x0238) -+ -+#define DMAMP_TX_4_CONTROL (DMA_BASE+0x0240) -+#define DMAMP_TX_4_INTERRUPT (DMA_BASE+0x0244) -+#define DMAMP_TX_4_PPALLOC (DMA_BASE+0x0248) -+#define DMAMP_TX_4_STATUS (DMA_BASE+0x024C) -+#define DMAMP_TX_4_REMAIN (DMA_BASE+0x0254) -+#define DMAMP_TX_4_MAXCNT0 (DMA_BASE+0x0260) -+#define DMAMP_TX_4_BASE0 (DMA_BASE+0x0264) -+#define DMAMP_TX_4_CURRENT0 (DMA_BASE+0x0268) -+#define DMAMP_TX_4_MAXCNT1 (DMA_BASE+0x0270) -+#define DMAMP_TX_4_BASE1 (DMA_BASE+0x0274) -+#define DMAMP_TX_4_CURRENT1 (DMA_BASE+0x0278) -+ -+#define DMAMP_RX_7_CONTROL (DMA_BASE+0x0280) -+#define DMAMP_RX_7_INTERRUPT (DMA_BASE+0x0284) -+#define DMAMP_RX_7_PPALLOC (DMA_BASE+0x0288) -+#define DMAMP_RX_7_STATUS (DMA_BASE+0x028C) -+#define DMAMP_RX_7_REMAIN (DMA_BASE+0x0294) -+#define DMAMP_RX_7_MAXCNT0 (DMA_BASE+0x02A0) -+#define DMAMP_RX_7_BASE0 (DMA_BASE+0x02A4) -+#define DMAMP_RX_7_CURRENT0 (DMA_BASE+0x02A8) -+#define DMAMP_RX_7_MAXCNT1 (DMA_BASE+0x02B0) -+#define DMAMP_RX_7_BASE1 (DMA_BASE+0x02B4) -+#define DMAMP_RX_7_CURRENT1 (DMA_BASE+0x02B8) -+ -+#define DMAMP_TX_6_CONTROL (DMA_BASE+0x02C0) -+#define DMAMP_TX_6_INTERRUPT (DMA_BASE+0x02C4) -+#define DMAMP_TX_6_PPALLOC (DMA_BASE+0x02C8) -+#define DMAMP_TX_6_STATUS (DMA_BASE+0x02CC) -+#define DMAMP_TX_6_REMAIN (DMA_BASE+0x02D4) -+#define DMAMP_TX_6_MAXCNT0 (DMA_BASE+0x02E0) -+#define DMAMP_TX_6_BASE0 (DMA_BASE+0x02E4) -+#define DMAMP_TX_6_CURRENT0 (DMA_BASE+0x02E8) -+#define DMAMP_TX_6_MAXCNT1 (DMA_BASE+0x02F0) -+#define DMAMP_TX_6_BASE1 (DMA_BASE+0x02F4) -+#define DMAMP_TX_6_CURRENT1 (DMA_BASE+0x02F8) -+ -+#define DMAMP_RX_9_CONTROL (DMA_BASE+0x0300) -+#define DMAMP_RX_9_INTERRUPT (DMA_BASE+0x0304) -+#define DMAMP_RX_9_PPALLOC (DMA_BASE+0x0308) -+#define DMAMP_RX_9_STATUS (DMA_BASE+0x030C) -+#define DMAMP_RX_9_REMAIN (DMA_BASE+0x0314) -+#define DMAMP_RX_9_MAXCNT0 (DMA_BASE+0x0320) -+#define DMAMP_RX_9_BASE0 (DMA_BASE+0x0324) -+#define DMAMP_RX_9_CURRENT0 (DMA_BASE+0x0328) -+#define DMAMP_RX_9_MAXCNT1 (DMA_BASE+0x0330) -+#define DMAMP_RX_9_BASE1 (DMA_BASE+0x0334) -+#define DMAMP_RX_9_CURRENT1 (DMA_BASE+0x0338) -+ -+#define DMAMP_TX_8_CONTROL (DMA_BASE+0x0340) -+#define DMAMP_TX_8_INTERRUPT (DMA_BASE+0x0344) -+#define DMAMP_TX_8_PPALLOC (DMA_BASE+0x0348) -+#define DMAMP_TX_8_STATUS (DMA_BASE+0x034C) -+#define DMAMP_TX_8_REMAIN (DMA_BASE+0x0354) -+#define DMAMP_TX_8_MAXCNT0 (DMA_BASE+0x0360) -+#define DMAMP_TX_8_BASE0 (DMA_BASE+0x0364) -+#define DMAMP_TX_8_CURRENT0 (DMA_BASE+0x0368) -+#define DMAMP_TX_8_MAXCNT1 (DMA_BASE+0x0370) -+#define DMAMP_TX_8_BASE1 (DMA_BASE+0x0374) -+#define DMAMP_TX_8_CURRENT1 (DMA_BASE+0x0378) -+ -+#define DMA_ARBITRATION (DMA_BASE+0x0380) -+#define DMA_INTERRUPT (DMA_BASE+0x03C0) -+ -+ -+/* -+ * DMA Register Base addresses and Offsets -+ */ -+#define DMA_M2P_TX_0_BASE DMAMP_TX_0_CONTROL -+#define DMA_M2P_RX_1_BASE DMAMP_RX_1_CONTROL -+#define DMA_M2P_TX_2_BASE DMAMP_TX_2_CONTROL -+#define DMA_M2P_RX_3_BASE DMAMP_RX_3_CONTROL -+#define DMA_M2M_0_BASE DMAMM_0_CONTROL -+#define DMA_M2M_1_BASE DMAMM_1_CONTROL -+#define DMA_M2P_RX_5_BASE DMAMP_RX_5_CONTROL -+#define DMA_M2P_TX_4_BASE DMAMP_TX_4_CONTROL -+#define DMA_M2P_RX_7_BASE DMAMP_RX_7_CONTROL -+#define DMA_M2P_TX_6_BASE DMAMP_TX_6_CONTROL -+#define DMA_M2P_RX_9_BASE DMAMP_RX_9_CONTROL -+#define DMA_M2P_TX_8_BASE DMAMP_TX_8_CONTROL -+ -+#define M2P_OFFSET_CONTROL 0x0000 -+#define M2P_OFFSET_INTERRUPT 0x0004 -+#define M2P_OFFSET_PPALLOC 0x0008 -+#define M2P_OFFSET_STATUS 0x000C -+#define M2P_OFFSET_REMAIN 0x0014 -+#define M2P_OFFSET_MAXCNT0 0x0020 -+#define M2P_OFFSET_BASE0 0x0024 -+#define M2P_OFFSET_CURRENT0 0x0028 -+#define M2P_OFFSET_MAXCNT1 0x0030 -+#define M2P_OFFSET_BASE1 0x0034 -+#define M2P_OFFSET_CURRENT1 0x0038 -+ -+#define M2M_OFFSET_CONTROL 0x0000 -+#define M2M_OFFSET_INTERRUPT 0x0004 -+#define M2M_OFFSET_STATUS 0x000C -+#define M2M_OFFSET_BCR0 0x0010 -+#define M2M_OFFSET_BCR1 0x0014 -+#define M2M_OFFSET_SAR_BASE0 0x0018 -+#define M2M_OFFSET_SAR_BASE1 0x001C -+#define M2M_OFFSET_SAR_CURRENT0 0x0024 -+#define M2M_OFFSET_SAR_CURRENT1 0x0028 -+#define M2M_OFFSET_DAR_BASE0 0x002C -+#define M2M_OFFSET_DAR_BASE1 0x0030 -+#define M2M_OFFSET_DAR_CURRENT0 0x0034 -+#define M2M_OFFSET_DAR_CURRENT1 0x003C -+ -+ -+ -+//----------------------------------------------------------------------------- -+// PWRCNT Register Defines -+//----------------------------------------------------------------------------- -+#define SYSCON_PWRCNT_FIREN 0x80000000 -+#define SYSCON_PWRCNT_UARTBAUD 0x20000000 -+#define SYSCON_PWRCNT_USHEN 0x10000000 -+#define SYSCON_PWRCNT_DMA_M2MCH1 0x08000000 -+#define SYSCON_PWRCNT_DMA_M2MCH0 0x04000000 -+#define SYSCON_PWRCNT_DMA_M2PCH8 0x02000000 -+#define SYSCON_PWRCNT_DMA_M2PCH9 0x01000000 -+#define SYSCON_PWRCNT_DMA_M2PCH6 0x00800000 -+#define SYSCON_PWRCNT_DMA_M2PCH7 0x00400000 -+#define SYSCON_PWRCNT_DMA_M2PCH4 0x00200000 -+#define SYSCON_PWRCNT_DMA_M2PCH5 0x00100000 -+#define SYSCON_PWRCNT_DMA_M2PCH2 0x00080000 -+#define SYSCON_PWRCNT_DMA_M2PCH3 0x00040000 -+#define SYSCON_PWRCNT_DMA_M2PCH0 0x00020000 -+#define SYSCON_PWRCNT_DMA_M2PCH1 0x00010000 -+ -+#ifndef __ASSEMBLY__ -+/* -+ * DMA Register Base addresses -+ */ -+static unsigned int const DMAM2PChannelBase[10] = -+{ -+ DMA_M2P_TX_0_BASE, -+ DMA_M2P_RX_1_BASE, -+ DMA_M2P_TX_2_BASE, -+ DMA_M2P_RX_3_BASE, -+ DMA_M2P_TX_4_BASE, -+ DMA_M2P_RX_5_BASE, -+ DMA_M2P_TX_6_BASE, -+ DMA_M2P_RX_7_BASE, -+ DMA_M2P_TX_8_BASE, -+ DMA_M2P_RX_9_BASE -+}; -+ -+static unsigned int const DMAM2MChannelBase[2] = -+{ -+ DMA_M2M_0_BASE, -+ DMA_M2M_1_BASE -+}; -+ -+#endif /* __ASSEMBLY__ */ -+ -+/***************************************************************************** -+ * -+ * DMA buffer structure type. -+ * -+ ****************************************************************************/ -+typedef struct ep93xx_dma_buffer_s -+{ -+ unsigned int source; /* buffer physical source address. */ -+ unsigned int dest; /* buffer physical destination address, */ -+ /* only used with the 2 M2M channels. */ -+ unsigned int size; /* buffer size in bytes */ -+ unsigned int last; /* 1 if this is the last buffer */ -+ /* in this transaction. If 1, */ -+ /* disable the NFBint so we aren't */ -+ /* interrupted for another buffer */ -+ /* when we know there won't be another. */ -+ unsigned int used; /* This field is set to 1 by the DMA */ -+ /* interface after the buffer is transferred*/ -+ int buf_id; /* unique identifyer specified by the */ -+ /* the driver which requested the dma */ -+} ep93xx_dma_buffer_t; -+ -+typedef ep93xx_dma_buffer_t * ep93xx_dma_buffer_p; -+ -+/***************************************************************************** -+ * -+ * Instance definition for the DMA interface. -+ * -+ ****************************************************************************/ -+typedef struct ep9312_dma_s -+{ -+ /* -+ * This 1 when the instance is in use, and 0 when it's not. -+ */ -+ unsigned int ref_count; -+ -+ /* -+ * This is the last valid handle for this instance. When giving out a -+ * new handle this will be incremented and given out. -+ */ -+ int last_valid_handle; -+ -+ /* -+ * device specifies one of the 20 DMA hardware ports this -+ * DMA channel will service. -+ */ -+ ep93xx_dma_dev_t device; -+ -+ /* -+ * DMABufferQueue is the queue of buffer structure pointers which the -+ * dma channel will use to setup transfers. -+ */ -+ ep93xx_dma_buffer_t buffer_queue[MAX_EP93XX_DMA_BUFFERS]; -+ -+ /* -+ * currnt_buffer : This is the buffer currently being transfered on -+ * this channel. -+ * last_buffer : This is the last buffer for this transfer. -+ * Note: current_buffer + 1 is already programmed into the dma -+ * channel as the next buffer to transfer. Don't write -+ * over either entry. -+ */ -+ int current_buffer; -+ int last_buffer; -+ -+ /* -+ * The following 3 fields are buffer counters. -+ * -+ * iNewBuffers: Buffers in the queue which have not been transfered. -+ * iUsedBuffers: Buffers in the queue which have have been tranferred, -+ * and are waiting to be returned. -+ * iTotalBuffers: Total number of buffers in the queue. -+ */ -+ int new_buffers; -+ int used_buffers; -+ int total_buffers; -+ -+ /* -+ * uiTotalBytes has the total bytes transfered on the channel since the -+ * last flush. This value does not include the bytes tranfered in the -+ * current buffer. A byte count is only added after a complete buffer -+ * is tranfered. -+ */ -+ unsigned int total_bytes; -+ -+ /* -+ * Interrupt number for this channel -+ */ -+ unsigned int irq; -+ -+ /* -+ * Indicates whether or not the channel is currently enabled to transfer -+ * data. -+ */ -+ unsigned int xfer_enable; -+ -+ /* -+ * pause indicates if the dma channel was paused by calling the pause -+ * ioctl. -+ */ -+ unsigned int pause; -+ -+ /* -+ * buffer structure used during a pause to capture the current -+ * address and remaining bytes for the buffer actively being transferred -+ * on the channel. This buffer will be used to reprogram the dma -+ * channel upon a resume. -+ */ -+ ep93xx_dma_buffer_t pause_buf; -+ -+ /* -+ * DMACallback is a function pointer which the calling application can -+ * use install a function to. this fuction can be used to notify the -+ * calling application of an interrupt. -+ */ -+ dma_callback callback; -+ -+ /* -+ * User data used as a parameter for the Callback function. The user -+ * sets up the data and sends it with the callback function. -+ */ -+ unsigned int user_data; -+ -+ /* -+ * A string representation of the device attached to the channel. -+ */ -+ const char * device_id; -+ -+ /* -+ * The register base address for this dma channel. -+ */ -+ unsigned int reg_base; -+ -+ /* -+ * terminated indicates -+ */ -+ unsigned int terminated; -+ -+ -+} ep93xx_dma_t; -+ -+/***************************************************************************** -+ * -+ * DMA macros -+ * -+ ****************************************************************************/ -+#define DMA_HANDLE_SPECIFIER_MASK 0xF0000000 -+#define DMA_CH0_HANDLE_SPECIFIER 0x00000000 -+#define DMA_CH1_HANDLE_SPECIFIER 0x10000000 -+#define DMA_CH2_HANDLE_SPECIFIER 0x20000000 -+#define DMA_CH3_HANDLE_SPECIFIER 0x30000000 -+#define DMA_CH4_HANDLE_SPECIFIER 0x40000000 -+#define DMA_CH5_HANDLE_SPECIFIER 0x50000000 -+#define DMA_CH6_HANDLE_SPECIFIER 0x60000000 -+#define DMA_CH7_HANDLE_SPECIFIER 0x70000000 -+#define DMA_CH8_HANDLE_SPECIFIER 0x80000000 -+#define DMA_CH9_HANDLE_SPECIFIER 0x90000000 -+#define DMA_CH10_HANDLE_SPECIFIER 0xA0000000 -+#define DMA_CH11_HANDLE_SPECIFIER 0xB0000000 -+ -+#endif // _DMADRV_H_ |