[PATCH] sh: DMA updates

This extends the current SH DMA API somewhat to support a proper virtual
channel abstraction, and also works to represent this through the driver model
by giving each DMAC its own platform device.

There's also a few other minor changes to support a few new CPU subtypes, and
make TEI generation for the SH DMAC configurable.

Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
diff --git a/include/asm-sh/bus-sh.h b/include/asm-sh/bus-sh.h
index 83c5d2f..e42d63b 100644
--- a/include/asm-sh/bus-sh.h
+++ b/include/asm-sh/bus-sh.h
@@ -21,6 +21,7 @@
 	void		*mapbase;
 	unsigned int	irq[6];
 	u64		*dma_mask;
+	u64		coherent_dma_mask;
 };
 
 #define to_sh_dev(d)	container_of((d), struct sh_dev, dev)
diff --git a/include/asm-sh/cpu-sh3/dma.h b/include/asm-sh/cpu-sh3/dma.h
index b972e71..954801b 100644
--- a/include/asm-sh/cpu-sh3/dma.h
+++ b/include/asm-sh/cpu-sh3/dma.h
@@ -3,5 +3,34 @@
 
 #define SH_DMAC_BASE	0xa4000020
 
-#endif /* __ASM_CPU_SH3_DMA_H */
+/* Definitions for the SuperH DMAC */
+#define TM_BURST	0x00000020
+#define TS_8		0x00000000
+#define TS_16		0x00000008
+#define TS_32		0x00000010
+#define TS_128		0x00000018
 
+#define CHCR_TS_MASK	0x18
+#define CHCR_TS_SHIFT	3
+
+#define DMAOR_INIT	DMAOR_DME
+
+/*
+ * The SuperH DMAC supports a number of transmit sizes, we list them here,
+ * with their respective values as they appear in the CHCR registers.
+ */
+enum {
+	XMIT_SZ_8BIT,
+	XMIT_SZ_16BIT,
+	XMIT_SZ_32BIT,
+	XMIT_SZ_128BIT,
+};
+
+static unsigned int ts_shift[] __attribute__ ((used)) = {
+	[XMIT_SZ_8BIT]		= 0,
+	[XMIT_SZ_16BIT]		= 1,
+	[XMIT_SZ_32BIT]		= 2,
+	[XMIT_SZ_128BIT]	= 4,
+};
+
+#endif /* __ASM_CPU_SH3_DMA_H */
diff --git a/include/asm-sh/cpu-sh4/dma.h b/include/asm-sh/cpu-sh4/dma.h
index e2b91ad..0dfe61f 100644
--- a/include/asm-sh/cpu-sh4/dma.h
+++ b/include/asm-sh/cpu-sh4/dma.h
@@ -1,17 +1,49 @@
 #ifndef __ASM_CPU_SH4_DMA_H
 #define __ASM_CPU_SH4_DMA_H
 
+#ifdef CONFIG_CPU_SH4A
+#define SH_DMAC_BASE	0xfc808020
+#else
 #define SH_DMAC_BASE	0xffa00000
+#endif
 
-#define SAR	((unsigned long[]){SH_DMAC_BASE + 0x00, SH_DMAC_BASE + 0x10, \
-				   SH_DMAC_BASE + 0x20, SH_DMAC_BASE + 0x30})
-#define DAR	((unsigned long[]){SH_DMAC_BASE + 0x04, SH_DMAC_BASE + 0x14, \
-				   SH_DMAC_BASE + 0x24, SH_DMAC_BASE + 0x34})
-#define DMATCR	((unsigned long[]){SH_DMAC_BASE + 0x08, SH_DMAC_BASE + 0x18, \
-				   SH_DMAC_BASE + 0x28, SH_DMAC_BASE + 0x38})
-#define CHCR	((unsigned long[]){SH_DMAC_BASE + 0x0c, SH_DMAC_BASE + 0x1c, \
-				   SH_DMAC_BASE + 0x2c, SH_DMAC_BASE + 0x3c})
-#define DMAOR	(SH_DMAC_BASE + 0x40)
+/* Definitions for the SuperH DMAC */
+#define TM_BURST	0x0000080
+#define TS_8		0x00000010
+#define TS_16		0x00000020
+#define TS_32		0x00000030
+#define TS_64		0x00000000
+
+#define CHCR_TS_MASK	0x30
+#define CHCR_TS_SHIFT	4
+
+#define DMAOR_COD	0x00000008
+
+#define DMAOR_INIT	( 0x8000 | DMAOR_DME )
+
+/*
+ * The SuperH DMAC supports a number of transmit sizes, we list them here,
+ * with their respective values as they appear in the CHCR registers.
+ *
+ * Defaults to a 64-bit transfer size.
+ */
+enum {
+	XMIT_SZ_64BIT,
+	XMIT_SZ_8BIT,
+	XMIT_SZ_16BIT,
+	XMIT_SZ_32BIT,
+	XMIT_SZ_256BIT,
+};
+
+/*
+ * The DMA count is defined as the number of bytes to transfer.
+ */
+static unsigned int ts_shift[] __attribute__ ((used)) = {
+	[XMIT_SZ_64BIT]		= 3,
+	[XMIT_SZ_8BIT]		= 0,
+	[XMIT_SZ_16BIT]		= 1,
+	[XMIT_SZ_32BIT]		= 2,
+	[XMIT_SZ_256BIT]	= 5,
+};
 
 #endif /* __ASM_CPU_SH4_DMA_H */
-
diff --git a/include/asm-sh/dma-mapping.h b/include/asm-sh/dma-mapping.h
index d3fa5c2..48f1f42 100644
--- a/include/asm-sh/dma-mapping.h
+++ b/include/asm-sh/dma-mapping.h
@@ -4,6 +4,7 @@
 #include <linux/config.h>
 #include <linux/mm.h>
 #include <asm/scatterlist.h>
+#include <asm/cacheflush.h>
 #include <asm/io.h>
 
 extern struct bus_type pci_bus_type;
@@ -141,24 +142,24 @@
 	}
 }
 
-static inline void dma_sync_single_for_cpu(struct device *dev,
-					   dma_addr_t dma_handle, size_t size,
-					   enum dma_data_direction dir)
+static void dma_sync_single_for_cpu(struct device *dev,
+				    dma_addr_t dma_handle, size_t size,
+				    enum dma_data_direction dir)
 	__attribute__ ((alias("dma_sync_single")));
 
-static inline void dma_sync_single_for_device(struct device *dev,
-					   dma_addr_t dma_handle, size_t size,
-					   enum dma_data_direction dir)
-	__attribute__ ((alias("dma_sync_single")));
-
-static inline void dma_sync_sg_for_cpu(struct device *dev,
-				       struct scatterlist *sg, int nelems,
+static void dma_sync_single_for_device(struct device *dev,
+				       dma_addr_t dma_handle, size_t size,
 				       enum dma_data_direction dir)
+	__attribute__ ((alias("dma_sync_single")));
+
+static void dma_sync_sg_for_cpu(struct device *dev,
+				struct scatterlist *sg, int nelems,
+				enum dma_data_direction dir)
 	__attribute__ ((alias("dma_sync_sg")));
 
-static inline void dma_sync_sg_for_device(struct device *dev,
-				       struct scatterlist *sg, int nelems,
-				       enum dma_data_direction dir)
+static void dma_sync_sg_for_device(struct device *dev,
+				   struct scatterlist *sg, int nelems,
+				   enum dma_data_direction dir)
 	__attribute__ ((alias("dma_sync_sg")));
 
 static inline int dma_get_cache_alignment(void)
diff --git a/include/asm-sh/dma.h b/include/asm-sh/dma.h
index 8e94360..a118a0d4 100644
--- a/include/asm-sh/dma.h
+++ b/include/asm-sh/dma.h
@@ -15,6 +15,7 @@
 #include <linux/spinlock.h>
 #include <linux/wait.h>
 #include <linux/sysdev.h>
+#include <linux/device.h>
 #include <asm/cpu/dma.h>
 #include <asm/semaphore.h>
 
@@ -54,8 +55,8 @@
  * DMA channel capabilities / flags
  */
 enum {
-	DMA_CONFIGURED			= 0x00,
 	DMA_TEI_CAPABLE			= 0x01,
+	DMA_CONFIGURED			= 0x02,
 };
 
 extern spinlock_t dma_spin_lock;
@@ -74,7 +75,8 @@
 struct dma_channel {
 	char dev_id[16];
 
-	unsigned int chan;
+	unsigned int chan;		/* Physical channel number */
+	unsigned int vchan;		/* Virtual channel number */
 	unsigned int mode;
 	unsigned int count;
 
@@ -91,6 +93,8 @@
 };
 
 struct dma_info {
+	struct platform_device *pdev;
+
 	const char *name;
 	unsigned int nr_channels;
 	unsigned long flags;
@@ -130,7 +134,11 @@
 
 #ifdef CONFIG_SYSFS
 /* arch/sh/drivers/dma/dma-sysfs.c */
-extern int dma_create_sysfs_files(struct dma_channel *);
+extern int dma_create_sysfs_files(struct dma_channel *, struct dma_info *);
+extern void dma_remove_sysfs_files(struct dma_channel *, struct dma_info *);
+#else
+#define dma_create_sysfs_file(channel, info)		do { } while (0)
+#define dma_remove_sysfs_file(channel, info)		do { } while (0)
 #endif
 
 #ifdef CONFIG_PCI