diff options
| -rw-r--r-- | recipes/linux/linux-2.6.32/ep93xx/edb9301-fix-machine-id.patch | 19 | ||||
| -rw-r--r-- | recipes/linux/linux-2.6.32/ep93xx/ep93xx-cpuinfo.patch | 43 | ||||
| -rw-r--r-- | recipes/linux/linux-2.6.32/ep93xx/ep93xx-dma.patch | 3641 | ||||
| -rw-r--r-- | recipes/linux/linux-2.6.32/ep93xx/ep93xx-eth.patch | 2718 | ||||
| -rw-r--r-- | recipes/linux/linux-2.6.32/ep93xx/ep93xx-i2c.patch | 234 | ||||
| -rw-r--r-- | recipes/linux/linux-2.6.32/ep93xx/ep93xx-regs.patch | 490 | ||||
| -rw-r--r-- | recipes/linux/linux-2.6.32/ep93xx/ep93xx-snd-ac97.patch | 3829 | ||||
| -rw-r--r-- | recipes/linux/linux-2.6.32/ep93xx/ep93xx-spi.patch | 721 | ||||
| -rw-r--r-- | recipes/linux/linux-2.6.32/ep93xx/ep93xx-touchscreen.patch | 1320 | ||||
| -rw-r--r-- | recipes/linux/linux-2.6.32/ep93xx/series | 7 | ||||
| -rw-r--r-- | recipes/linux/linux-2.6.32/ep93xx/simone-board-def.patch | 1653 | ||||
| -rw-r--r-- | recipes/linux/linux/simone/defconfig | 1751 | ||||
| -rw-r--r-- | recipes/linux/linux_2.6.32.bb | 15 |
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 |
