| 
					
				 | 
			
			
				@@ -0,0 +1,198 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* linux/arch/arm/plat-s3c24xx/dma.c 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Copyright 2003-2006 Simtec Electronics 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *	Ben Dooks <ben@simtec.co.uk> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * S3C2410 DMA core 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * http://armlinux.simtec.co.uk/ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * This program is free software; you can redistribute it and/or modify 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * it under the terms of the GNU General Public License version 2 as 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * published by the Free Software Foundation. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+*/ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#ifdef CONFIG_S3C2410_DMA_DEBUG 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#define DEBUG 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <linux/module.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <linux/init.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <linux/sched.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <linux/spinlock.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <linux/interrupt.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <linux/syscore_ops.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <linux/slab.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <linux/errno.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <linux/io.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <asm/irq.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <mach/hardware.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <mach/dma.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <mach/map.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <plat/dma-s3c24xx.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <plat/regs-dma.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* io map for dma */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void __iomem *dma_base; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static struct kmem_cache *dma_kmem; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static int dma_channels; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static struct s3c24xx_dma_selection dma_sel; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* debugging functions */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#define BUF_MAGIC (0xcafebabe) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#define dmawarn(fmt...) printk(KERN_DEBUG fmt) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#define dma_regaddr(chan, reg) ((chan)->regs + (reg)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#if 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#define dma_wrreg(chan, reg, val) writel((val), (chan)->regs + (reg)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static inline void 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+dma_wrreg(struct s3c2410_dma_chan *chan, int reg, unsigned long val) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	pr_debug("writing %08x to register %08x\n",(unsigned int)val,reg); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	writel(val, dma_regaddr(chan, reg)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#define dma_rdreg(chan, reg) readl((chan)->regs + (reg)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* captured register state for debug */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+struct s3c2410_dma_regstate { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	unsigned long         dcsrc; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	unsigned long         disrc; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	unsigned long         dstat; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	unsigned long         dcon; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	unsigned long         dmsktrig; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#ifdef CONFIG_S3C2410_DMA_DEBUG 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* dmadbg_showregs 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * simple debug routine to print the current state of the dma registers 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+*/ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+dmadbg_capture(struct s3c2410_dma_chan *chan, struct s3c2410_dma_regstate *regs) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	regs->dcsrc    = dma_rdreg(chan, S3C2410_DMA_DCSRC); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	regs->disrc    = dma_rdreg(chan, S3C2410_DMA_DISRC); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	regs->dstat    = dma_rdreg(chan, S3C2410_DMA_DSTAT); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	regs->dcon     = dma_rdreg(chan, S3C2410_DMA_DCON); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	regs->dmsktrig = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+dmadbg_dumpregs(const char *fname, int line, struct s3c2410_dma_chan *chan, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		 struct s3c2410_dma_regstate *regs) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	printk(KERN_DEBUG "dma%d: %s:%d: DCSRC=%08lx, DISRC=%08lx, DSTAT=%08lx DMT=%02lx, DCON=%08lx\n", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	       chan->number, fname, line, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	       regs->dcsrc, regs->disrc, regs->dstat, regs->dmsktrig, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	       regs->dcon); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+dmadbg_showchan(const char *fname, int line, struct s3c2410_dma_chan *chan) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	struct s3c2410_dma_regstate state; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	dmadbg_capture(chan, &state); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	printk(KERN_DEBUG "dma%d: %s:%d: ls=%d, cur=%p, %p %p\n", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	       chan->number, fname, line, chan->load_state, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	       chan->curr, chan->next, chan->end); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	dmadbg_dumpregs(fname, line, chan, &state); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+dmadbg_showregs(const char *fname, int line, struct s3c2410_dma_chan *chan) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	struct s3c2410_dma_regstate state; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	dmadbg_capture(chan, &state); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	dmadbg_dumpregs(fname, line, chan, &state); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#define dbg_showregs(chan) dmadbg_showregs(__func__, __LINE__, (chan)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#define dbg_showchan(chan) dmadbg_showchan(__func__, __LINE__, (chan)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#define dbg_showregs(chan) do { } while(0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#define dbg_showchan(chan) do { } while(0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#endif /* CONFIG_S3C2410_DMA_DEBUG */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* s3c2410_dma_stats_timeout 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Update DMA stats from timeout info 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+*/ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+s3c2410_dma_stats_timeout(struct s3c2410_dma_stats *stats, int val) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (stats == NULL) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (val > stats->timeout_longest) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		stats->timeout_longest = val; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (val < stats->timeout_shortest) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		stats->timeout_shortest = val; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	stats->timeout_avg += val; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* s3c2410_dma_waitforload 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * wait for the DMA engine to load a buffer, and update the state accordingly 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+*/ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static int 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+s3c2410_dma_waitforload(struct s3c2410_dma_chan *chan, int line) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	int timeout = chan->load_timeout; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	int took; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (chan->load_state != S3C2410_DMALOAD_1LOADED) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		printk(KERN_ERR "dma%d: s3c2410_dma_waitforload() called in loadstate %d from line %d\n", chan->number, chan->load_state, line); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (chan->stats != NULL) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		chan->stats->loads++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	while (--timeout > 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if ((dma_rdreg(chan, S3C2410_DMA_DSTAT) << (32-20)) != 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			took = chan->load_timeout - timeout; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			s3c2410_dma_stats_timeout(chan->stats, took); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			switch (chan->load_state) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			case S3C2410_DMALOAD_1LOADED: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				chan->load_state = S3C2410_DMALOAD_1RUNNING; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			default: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				printk(KERN_ERR "dma%d: unknown load_state in s3c2410_dma_waitforload() %d\n", chan->number, chan->load_state); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			return 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (chan->stats != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		chan->stats->timeout_failed++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 |