summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--recipes/linux/linux-2.6.32/ep93xx/edb9301-fix-machine-id.patch19
-rw-r--r--recipes/linux/linux-2.6.32/ep93xx/ep93xx-cpuinfo.patch43
-rw-r--r--recipes/linux/linux-2.6.32/ep93xx/ep93xx-dma.patch3641
-rw-r--r--recipes/linux/linux-2.6.32/ep93xx/ep93xx-eth.patch2718
-rw-r--r--recipes/linux/linux-2.6.32/ep93xx/ep93xx-i2c.patch234
-rw-r--r--recipes/linux/linux-2.6.32/ep93xx/ep93xx-regs.patch490
-rw-r--r--recipes/linux/linux-2.6.32/ep93xx/ep93xx-snd-ac97.patch3829
-rw-r--r--recipes/linux/linux-2.6.32/ep93xx/ep93xx-spi.patch721
-rw-r--r--recipes/linux/linux-2.6.32/ep93xx/ep93xx-touchscreen.patch1320
-rw-r--r--recipes/linux/linux-2.6.32/ep93xx/series7
-rw-r--r--recipes/linux/linux-2.6.32/ep93xx/simone-board-def.patch1653
-rw-r--r--recipes/linux/linux/simone/defconfig1751
-rw-r--r--recipes/linux/linux_2.6.32.bb15
13 files changed, 16440 insertions, 1 deletions
diff --git a/recipes/linux/linux-2.6.32/ep93xx/edb9301-fix-machine-id.patch b/recipes/linux/linux-2.6.32/ep93xx/edb9301-fix-machine-id.patch
new file mode 100644
index 0000000000..7fc04bd321
--- /dev/null
+++ b/recipes/linux/linux-2.6.32/ep93xx/edb9301-fix-machine-id.patch
@@ -0,0 +1,19 @@
+---
+ arch/arm/tools/mach-types | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- linux-2.6.31.orig/arch/arm/tools/mach-types
++++ linux-2.6.31/arch/arm/tools/mach-types
+@@ -473,11 +473,11 @@ hawk MACH_HAWK HAWK 456
+ ccat91sbc001 MACH_CCAT91SBC001 CCAT91SBC001 457
+ expresso MACH_EXPRESSO EXPRESSO 458
+ h4000 MACH_H4000 H4000 459
+ dino MACH_DINO DINO 460
+ ml675k MACH_ML675K ML675K 461
+-edb9301 MACH_EDB9301 EDB9301 462
++edb9301 MACH_EDB9301 EDB9301 454
+ edb9315 MACH_EDB9315 EDB9315 463
+ reciva_tt MACH_RECIVA_TT RECIVA_TT 464
+ cstcb01 MACH_CSTCB01 CSTCB01 465
+ cstcb1 MACH_CSTCB1 CSTCB1 466
+ shadwell MACH_SHADWELL SHADWELL 467
diff --git a/recipes/linux/linux-2.6.32/ep93xx/ep93xx-cpuinfo.patch b/recipes/linux/linux-2.6.32/ep93xx/ep93xx-cpuinfo.patch
new file mode 100644
index 0000000000..5409bf72db
--- /dev/null
+++ b/recipes/linux/linux-2.6.32/ep93xx/ep93xx-cpuinfo.patch
@@ -0,0 +1,43 @@
+---
+ arch/arm/kernel/setup.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+--- linux-2.6.32.orig/arch/arm/kernel/setup.c
++++ linux-2.6.32/arch/arm/kernel/setup.c
+@@ -41,10 +41,15 @@
+ #include <asm/mach/irq.h>
+ #include <asm/mach/time.h>
+ #include <asm/traps.h>
+ #include <asm/unwind.h>
+
++#if defined(CONFIG_ARCH_EP93XX)
++#include <mach/io.h>
++#include <mach/ep93xx-regs.h>
++#endif
++
+ #include "compat.h"
+ #include "atags.h"
+ #include "tcm.h"
+
+ #ifndef MEM_SIZE
+@@ -858,13 +863,20 @@ static int c_show(struct seq_file *m, vo
+ seq_printf(m, "CPU revision\t: %d\n", read_cpuid_id() & 15);
+
+ seq_puts(m, "\n");
+
+ seq_printf(m, "Hardware\t: %s\n", machine_name);
++#if defined(CONFIG_ARCH_EP93XX)
++ seq_printf(m, "Revision\t: %04x\n",
++ *((unsigned int *)EP93XX_SYSCON_CHIP_ID) >> 28);
++ seq_printf(m, "Serial\t\t: %016x\n",
++ *((unsigned int *)EP93XX_SECURITY_UNIQID));
++#else
+ seq_printf(m, "Revision\t: %04x\n", system_rev);
+ seq_printf(m, "Serial\t\t: %08x%08x\n",
+ system_serial_high, system_serial_low);
++#endif
+
+ return 0;
+ }
+
+ static void *c_start(struct seq_file *m, loff_t *pos)
diff --git a/recipes/linux/linux-2.6.32/ep93xx/ep93xx-dma.patch b/recipes/linux/linux-2.6.32/ep93xx/ep93xx-dma.patch
new file mode 100644
index 0000000000..c8e6c0f8a3
--- /dev/null
+++ b/recipes/linux/linux-2.6.32/ep93xx/ep93xx-dma.patch
@@ -0,0 +1,3641 @@
+---
+ arch/arm/mach-ep93xx/Makefile | 2
+ arch/arm/mach-ep93xx/dma_ep93xx.c | 2940 ++++++++++++++++++++++++++++++++++++++
+ arch/arm/mach-ep93xx/dma_ep93xx.h | 676 ++++++++
+ 3 files changed, 3617 insertions(+), 1 deletion(-)
+
+--- linux-2.6.31.orig/arch/arm/mach-ep93xx/Makefile
++++ linux-2.6.31/arch/arm/mach-ep93xx/Makefile
+@@ -1,9 +1,9 @@
+ #
+ # Makefile for the linux kernel.
+ #
+-obj-y := core.o clock.o dma-m2p.o gpio.o
++obj-y := core.o clock.o dma-m2p.o gpio.o dma_ep93xx.o
+ obj-m :=
+ obj-n :=
+ obj- :=
+
+ obj-$(CONFIG_MACH_ADSSPHERE) += adssphere.o
+--- /dev/null
++++ linux-2.6.31/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 &am