This driver is not (yet) dmaengine enabled, but is needed by the
ethernet fec driver for the ColdFire M54xx processors.
Original work was made by Kurt Mahan at Freescale.

Signed-off-by: Philippe De Muyter <p...@macqel.be>
---
 arch/m68k/include/asm/m54xxdma.h     |   67 +++++
 arch/m68k/include/asm/m54xxdma_api.h |   62 ++++
 arch/m68k/include/asm/m54xxsim.h     |    1 +
 arch/m68k/include/asm/m54xxsram.h    |   11 +
 drivers/dma/Kconfig                  |   10 +
 drivers/dma/fsl_mcd_dma/Makefile     |    1 +
 drivers/dma/fsl_mcd_dma/m54xx_dma.c  |  519 ++++++++++++++++++++++++++++++++++
 7 files changed, 671 insertions(+), 0 deletions(-)
 create mode 100644 arch/m68k/include/asm/m54xxdma.h
 create mode 100644 arch/m68k/include/asm/m54xxdma_api.h
 create mode 100644 arch/m68k/include/asm/m54xxsram.h
 create mode 100644 drivers/dma/fsl_mcd_dma/m54xx_dma.c

diff --git a/arch/m68k/include/asm/m54xxdma.h b/arch/m68k/include/asm/m54xxdma.h
new file mode 100644
index 0000000..cc57872
--- /dev/null
+++ b/arch/m68k/include/asm/m54xxdma.h
@@ -0,0 +1,67 @@
+/*
+ *     ColdFire 547x/548x DMA controller support.
+ */
+#ifndef __MCF548X_DMA_H__
+#define __MCF548X_DMA_H__
+
+
+/* Register read/write macros */
+#define MCF_DMA_DIPR    (MCF_MBAR+0x008014)
+#define MCF_DMA_DIMR    (MCF_MBAR+0x008018)
+#define MCF_DMA_IMCR    (MCF_MBAR+0x00805C)
+
+/* Bit definitions and macros for MCF_DMA_DIPR */
+#define MCF_DMA_DIPR_TASK(x)         (1 << (x))
+
+/* Bit definitions and macros for MCF_DMA_DIMR */
+#define MCF_DMA_DIMR_TASK(x)         (1 << (x))
+
+/* Bit definitions and macros for MCF_DMA_IMCR */
+#define MCF_DMA_IMCR_SRC16(x)        (((x)&0x00000003)<<0)
+#define MCF_DMA_IMCR_SRC17(x)        (((x)&0x00000003)<<2)
+#define MCF_DMA_IMCR_SRC18(x)        (((x)&0x00000003)<<4)
+#define MCF_DMA_IMCR_SRC19(x)        (((x)&0x00000003)<<6)
+#define MCF_DMA_IMCR_SRC20(x)        (((x)&0x00000003)<<8)
+#define MCF_DMA_IMCR_SRC21(x)        (((x)&0x00000003)<<10)
+#define MCF_DMA_IMCR_SRC22(x)        (((x)&0x00000003)<<12)
+#define MCF_DMA_IMCR_SRC23(x)        (((x)&0x00000003)<<14)
+#define MCF_DMA_IMCR_SRC24(x)        (((x)&0x00000003)<<16)
+#define MCF_DMA_IMCR_SRC25(x)        (((x)&0x00000003)<<18)
+#define MCF_DMA_IMCR_SRC26(x)        (((x)&0x00000003)<<20)
+#define MCF_DMA_IMCR_SRC27(x)        (((x)&0x00000003)<<22)
+#define MCF_DMA_IMCR_SRC28(x)        (((x)&0x00000003)<<24)
+#define MCF_DMA_IMCR_SRC29(x)        (((x)&0x00000003)<<26)
+#define MCF_DMA_IMCR_SRC30(x)        (((x)&0x00000003)<<28)
+#define MCF_DMA_IMCR_SRC31(x)        (((x)&0x00000003)<<30)
+#define MCF_DMA_IMCR_SRC16_FEC0RX    (0x00000000)
+#define MCF_DMA_IMCR_SRC17_FEC0TX    (0x00000000)
+#define MCF_DMA_IMCR_SRC18_FEC0RX    (0x00000020)
+#define MCF_DMA_IMCR_SRC19_FEC0TX    (0x00000080)
+#define MCF_DMA_IMCR_SRC20_FEC1RX    (0x00000100)
+#define MCF_DMA_IMCR_SRC21_DREQ1     (0x00000000)
+#define MCF_DMA_IMCR_SRC21_FEC1TX    (0x00000400)
+#define MCF_DMA_IMCR_SRC22_FEC0RX    (0x00001000)
+#define MCF_DMA_IMCR_SRC23_FEC0TX    (0x00004000)
+#define MCF_DMA_IMCR_SRC24_CTM0      (0x00010000)
+#define MCF_DMA_IMCR_SRC24_FEC1RX    (0x00020000)
+#define MCF_DMA_IMCR_SRC25_CTM1      (0x00040000)
+#define MCF_DMA_IMCR_SRC25_FEC1TX    (0x00080000)
+#define MCF_DMA_IMCR_SRC26_USBEP4    (0x00000000)
+#define MCF_DMA_IMCR_SRC26_CTM2      (0x00200000)
+#define MCF_DMA_IMCR_SRC27_USBEP5    (0x00000000)
+#define MCF_DMA_IMCR_SRC27_CTM3      (0x00800000)
+#define MCF_DMA_IMCR_SRC28_USBEP6    (0x00000000)
+#define MCF_DMA_IMCR_SRC28_CTM4      (0x01000000)
+#define MCF_DMA_IMCR_SRC28_DREQ1     (0x02000000)
+#define MCF_DMA_IMCR_SRC28_PSC2RX    (0x03000000)
+#define MCF_DMA_IMCR_SRC29_DREQ1     (0x04000000)
+#define MCF_DMA_IMCR_SRC29_CTM5      (0x08000000)
+#define MCF_DMA_IMCR_SRC29_PSC2TX    (0x0C000000)
+#define MCF_DMA_IMCR_SRC30_FEC1RX    (0x00000000)
+#define MCF_DMA_IMCR_SRC30_CTM6      (0x10000000)
+#define MCF_DMA_IMCR_SRC30_PSC3RX    (0x30000000)
+#define MCF_DMA_IMCR_SRC31_FEC1TX    (0x00000000)
+#define MCF_DMA_IMCR_SRC31_CTM7      (0x80000000)
+#define MCF_DMA_IMCR_SRC31_PSC3TX    (0xC0000000)
+
+#endif /* __MCF548X_DMA_H__ */
diff --git a/arch/m68k/include/asm/m54xxdma_api.h 
b/arch/m68k/include/asm/m54xxdma_api.h
new file mode 100644
index 0000000..22bfb23
--- /dev/null
+++ b/arch/m68k/include/asm/m54xxdma_api.h
@@ -0,0 +1,62 @@
+/************************************************
+ *     Multichannel DMA definitions            *
+ ************************************************/
+#include <linux/MCD_dma.h>
+
+struct scatterlist;
+
+#define MAX_DMA_CHANNELS NCHANNELS
+/*
+ *  identifiers for each initiator/requestor
+ */
+#define DMA_ALWAYS      (0)
+#define DMA_DSPI_RX     (1)
+#define DMA_DSPI_TX     (2)
+#define DMA_DREQ0       (3)
+#define DMA_PSC0_RX     (4)
+#define DMA_PSC0_TX     (5)
+#define DMA_USBEP0      (6)
+#define DMA_USBEP1      (7)
+#define DMA_USBEP2      (8)
+#define DMA_USBEP3      (9)
+#define DMA_PCI_TX      (10)
+#define DMA_PCI_RX      (11)
+#define DMA_PSC1_RX     (12)
+#define DMA_PSC1_TX     (13)
+#define DMA_I2C_RX      (14)
+#define DMA_I2C_TX      (15)
+#define DMA_FEC0_RX     (16)
+#define DMA_FEC0_TX     (17)
+#define DMA_FEC1_RX     (18)
+#define DMA_FEC1_TX     (19)
+#define DMA_DREQ1       (20)
+#define DMA_CTM0        (21)
+#define DMA_CTM1        (22)
+#define DMA_CTM2        (23)
+#define DMA_CTM3        (24)
+#define DMA_CTM4        (25)
+#define DMA_CTM5        (26)
+#define DMA_CTM6        (27)
+#define DMA_CTM7        (28)
+#define DMA_USBEP4      (29)
+#define DMA_USBEP5      (30)
+#define DMA_USBEP6      (31)
+#define DMA_PSC2_RX     (32)
+#define DMA_PSC2_TX     (33)
+#define DMA_PSC3_RX     (34)
+#define DMA_PSC3_TX     (35)
+#define DMA_FEC_RX(x)   ((x == 0) ? DMA_FEC0_RX : DMA_FEC1_RX)
+#define DMA_FEC_TX(x)   ((x == 0) ? DMA_FEC0_TX : DMA_FEC1_TX)
+
+int  dma_set_initiator(int);
+unsigned int dma_get_initiator(int);
+void dma_remove_initiator(int);
+int dma_set_channel(int);
+int dma_get_channel(int);
+void dma_remove_channel(int);
+int dma_set_channel_fec(int requestor);
+typedef void (*dma_handler_t)(void *);
+int dma_connect(int channel, dma_handler_t address, void *dev);
+int dma_disconnect(int channel);
+void dma_remove_channel_by_number(int channel);
+int dma_init(void);
diff --git a/arch/m68k/include/asm/m54xxsim.h b/arch/m68k/include/asm/m54xxsim.h
index d3c5e0d..f5531d5 100644
--- a/arch/m68k/include/asm/m54xxsim.h
+++ b/arch/m68k/include/asm/m54xxsim.h
@@ -45,6 +45,7 @@
 #define MCF_IRQ_UART1          (MCFINT_VECBASE + 34)
 #define MCF_IRQ_UART2          (MCFINT_VECBASE + 33)
 #define MCF_IRQ_UART3          (MCFINT_VECBASE + 32)
+#define MCF_IRQ_DMA            (MCFINT_VECBASE + 48)   /* DMA */
 
 /*
  *     Generic GPIO support
diff --git a/arch/m68k/include/asm/m54xxsram.h 
b/arch/m68k/include/asm/m54xxsram.h
new file mode 100644
index 0000000..db25fb5
--- /dev/null
+++ b/arch/m68k/include/asm/m54xxsram.h
@@ -0,0 +1,11 @@
+#ifndef SYS_SRAM_H
+#define SYS_SRAM_H
+
+#define SYS_SRAM_DMA_START     (MCF_MBAR + 0x10000)
+#define SYS_SRAM_DMA_SIZE      8192
+#define SYS_SRAM_FEC_START     (SYS_SRAM_DMA_START + SYS_SRAM_DMA_SIZE)
+#define SYS_SRAM_FEC_SIZE      2048
+#define SYS_SRAM_SEC_START     (SYS_SRAM_FEC_START + SYS_SRAM_FEC_SIZE)
+#define SYS_SRAM_SEC_SIZE      1280
+
+#endif /* SYS_SRAM_H */
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 04639eb..55b8d88 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -116,6 +116,16 @@ config FSL_MCD_DMA
          This driver is used by the specific dma driver for the target CPU.
          Some drivers, especially the FEC DMA driver, need it.
 
+config M54xx_DMA
+       bool "ColdFire M54xx MultiChannel DMA (MCD) support"
+       depends on M54xx
+       select FSL_MCD_DMA
+       ---help---
+         This enables support for the ColdFire 547x/548x family
+         MultiChannel DMA (MCD) support.  It is currently only
+         needed by the M54xx FEC driver, as it is not dmaengine-enabled.
+         If you want it, say Y
+
 config MPC512X_DMA
        tristate "Freescale MPC512x built-in DMA engine support"
        depends on PPC_MPC512x || PPC_MPC831x
diff --git a/drivers/dma/fsl_mcd_dma/Makefile b/drivers/dma/fsl_mcd_dma/Makefile
index 6bdd725..8e70307 100644
--- a/drivers/dma/fsl_mcd_dma/Makefile
+++ b/drivers/dma/fsl_mcd_dma/Makefile
@@ -1 +1,2 @@
 obj-y  += MCD_dmaApi.o MCD_tasks.o MCD_tasksInit.o
+obj-$(CONFIG_M54xx_DMA)        += m54xx_dma.o
diff --git a/drivers/dma/fsl_mcd_dma/m54xx_dma.c 
b/drivers/dma/fsl_mcd_dma/m54xx_dma.c
new file mode 100644
index 0000000..9e6f1fe
--- /dev/null
+++ b/drivers/dma/fsl_mcd_dma/m54xx_dma.c
@@ -0,0 +1,519 @@
+/*
+ * arch/m68k/coldfire/m547x_8x-dma.c
+ *
+ * Coldfire M547x/M548x DMA
+ *
+ * Copyright (c) 2008 Freescale Semiconductor, Inc.
+ *     Kurt Mahan <kma...@freescale.com>
+ *
+ * This code is based on patches from the Freescale M547x_8x BSP
+ * release mcf547x_8x-20070107-ltib.iso
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <asm/irq.h>
+#include <asm/m54xxdma.h>
+#include <asm/m54xxdma_api.h>
+#include <asm/coldfire.h>
+#include <asm/m54xxsram.h>
+#include <asm/mcfsim.h>
+
+/*
+ * This global keeps track of which initiators have been
+ * used of the available assignments.  Initiators 0-15 are
+ * hardwired.  Initiators 16-31 are multiplexed and controlled
+ * via the Initiatior Mux Control Registe (IMCR).  The
+ * assigned requestor is stored with the associated initiator
+ * number.
+ */
+static int used_reqs[32] = {
+       DMA_ALWAYS, DMA_DSPI_RX, DMA_DSPI_TX, DMA_DREQ0,
+       DMA_PSC0_RX, DMA_PSC0_TX, DMA_USBEP0, DMA_USBEP1,
+       DMA_USBEP2, DMA_USBEP3, DMA_PCI_TX, DMA_PCI_RX,
+       DMA_PSC1_RX, DMA_PSC1_TX, DMA_I2C_RX, DMA_I2C_TX,
+       0, 0, 0, 0,
+       0, 0, 0, 0,
+       0, 0, 0, 0,
+       0, 0, 0, 0
+};
+
+/*
+ * This global keeps track of which channels have been assigned
+ * to tasks.  This methology assumes that no single initiator
+ * will be tied to more than one task/channel
+ */
+static char used_channel[16] = {
+       -1, -1, -1, -1, -1, -1, -1, -1,
+       -1, -1, -1, -1, -1, -1, -1, -1
+};
+
+dma_handler_t connected_channel[16];
+void *connected_dev[16];
+
+/**
+ * dma_set_initiator - enable initiator
+ * @initiator: initiator identifier
+ *
+ * Returns 0 of successful, non-zero otherwise
+ *
+ * Attempt to enable the provided Initiator in the Initiator
+ * Mux Control Register.
+ */
+int dma_set_initiator(int initiator)
+{
+       switch (initiator) {
+       case DMA_ALWAYS:
+       case DMA_DSPI_RX:
+       case DMA_DSPI_TX:
+       case DMA_DREQ0:
+       case DMA_PSC0_RX:
+       case DMA_PSC0_TX:
+       case DMA_USBEP0:
+       case DMA_USBEP1:
+       case DMA_USBEP2:
+       case DMA_USBEP3:
+       case DMA_PCI_TX:
+       case DMA_PCI_RX:
+       case DMA_PSC1_RX:
+       case DMA_PSC1_TX:
+       case DMA_I2C_RX:
+       case DMA_I2C_TX:
+               /*
+                * These initiators are always active
+                */
+               break;
+
+       case DMA_FEC0_RX:
+               writel((readl(MCF_DMA_IMCR) & ~MCF_DMA_IMCR_SRC16(3))
+                   | MCF_DMA_IMCR_SRC16_FEC0RX, MCF_DMA_IMCR);
+               used_reqs[16] = DMA_FEC0_RX;
+               break;
+
+       case DMA_FEC0_TX:
+               writel((readl(MCF_DMA_IMCR) & ~MCF_DMA_IMCR_SRC17(3))
+                   | MCF_DMA_IMCR_SRC17_FEC0TX, MCF_DMA_IMCR);
+               used_reqs[17] = DMA_FEC0_TX;
+               break;
+
+       case DMA_FEC1_RX:
+               writel((readl(MCF_DMA_IMCR) & ~MCF_DMA_IMCR_SRC20(3))
+                   | MCF_DMA_IMCR_SRC20_FEC1RX, MCF_DMA_IMCR);
+               used_reqs[20] = DMA_FEC1_RX;
+               break;
+
+       case DMA_FEC1_TX:
+               if (used_reqs[21] == 0) {
+                       writel((readl(MCF_DMA_IMCR) & ~MCF_DMA_IMCR_SRC21(3))
+                           | MCF_DMA_IMCR_SRC21_FEC1TX, MCF_DMA_IMCR);
+                       used_reqs[21] = DMA_FEC1_TX;
+               } else if (used_reqs[25] == 0) {
+                       writel((readl(MCF_DMA_IMCR) & ~MCF_DMA_IMCR_SRC25(3))
+                           | MCF_DMA_IMCR_SRC25_FEC1TX, MCF_DMA_IMCR);
+                       used_reqs[25] = DMA_FEC1_TX;
+               } else if (used_reqs[31] == 0) {
+                       writel((readl(MCF_DMA_IMCR) & ~MCF_DMA_IMCR_SRC31(3))
+                           | MCF_DMA_IMCR_SRC31_FEC1TX, MCF_DMA_IMCR);
+                       used_reqs[31] = DMA_FEC1_TX;
+               } else          /* No empty slots */
+                       return 1;
+               break;
+
+       case DMA_DREQ1:
+               if (used_reqs[29] == 0) {
+                       writel((readl(MCF_DMA_IMCR) & ~MCF_DMA_IMCR_SRC29(3))
+                           | MCF_DMA_IMCR_SRC29_DREQ1, MCF_DMA_IMCR);
+                       used_reqs[29] = DMA_DREQ1;
+               } else if (used_reqs[21] == 0) {
+                       writel((readl(MCF_DMA_IMCR) & ~MCF_DMA_IMCR_SRC21(3))
+                           | MCF_DMA_IMCR_SRC21_DREQ1, MCF_DMA_IMCR);
+                       used_reqs[21] = DMA_DREQ1;
+               } else          /* No empty slots */
+                       return 1;
+               break;
+
+       case DMA_CTM0:
+               if (used_reqs[24] == 0) {
+                       writel((readl(MCF_DMA_IMCR) & ~MCF_DMA_IMCR_SRC24(3))
+                           | MCF_DMA_IMCR_SRC24_CTM0, MCF_DMA_IMCR);
+                       used_reqs[24] = DMA_CTM0;
+               } else          /* No empty slots */
+                       return 1;
+               break;
+
+       case DMA_CTM1:
+               if (used_reqs[25] == 0) {
+                       writel((readl(MCF_DMA_IMCR) & ~MCF_DMA_IMCR_SRC25(3))
+                           | MCF_DMA_IMCR_SRC25_CTM1, MCF_DMA_IMCR);
+                       used_reqs[25] = DMA_CTM1;
+               } else          /* No empty slots */
+                       return 1;
+               break;
+
+       case DMA_CTM2:
+               if (used_reqs[26] == 0) {
+                       writel((readl(MCF_DMA_IMCR) & ~MCF_DMA_IMCR_SRC26(3))
+                           | MCF_DMA_IMCR_SRC26_CTM2, MCF_DMA_IMCR);
+                       used_reqs[26] = DMA_CTM2;
+               } else          /* No empty slots */
+                       return 1;
+               break;
+
+       case DMA_CTM3:
+               if (used_reqs[27] == 0) {
+                       writel((readl(MCF_DMA_IMCR) & ~MCF_DMA_IMCR_SRC27(3))
+                           | MCF_DMA_IMCR_SRC27_CTM3, MCF_DMA_IMCR);
+                       used_reqs[27] = DMA_CTM3;
+               } else          /* No empty slots */
+                       return 1;
+               break;
+
+       case DMA_CTM4:
+               if (used_reqs[28] == 0) {
+                       writel((readl(MCF_DMA_IMCR) & ~MCF_DMA_IMCR_SRC28(3))
+                           | MCF_DMA_IMCR_SRC28_CTM4, MCF_DMA_IMCR);
+                       used_reqs[28] = DMA_CTM4;
+               } else          /* No empty slots */
+                       return 1;
+               break;
+
+       case DMA_CTM5:
+               if (used_reqs[29] == 0) {
+                       writel((readl(MCF_DMA_IMCR) & ~MCF_DMA_IMCR_SRC29(3))
+                           | MCF_DMA_IMCR_SRC29_CTM5, MCF_DMA_IMCR);
+                       used_reqs[29] = DMA_CTM5;
+               } else          /* No empty slots */
+                       return 1;
+               break;
+
+       case DMA_CTM6:
+               if (used_reqs[30] == 0) {
+                       writel((readl(MCF_DMA_IMCR) & ~MCF_DMA_IMCR_SRC30(3))
+                           | MCF_DMA_IMCR_SRC30_CTM6, MCF_DMA_IMCR);
+                       used_reqs[30] = DMA_CTM6;
+               } else          /* No empty slots */
+                       return 1;
+               break;
+
+       case DMA_CTM7:
+               if (used_reqs[31] == 0) {
+                       writel((readl(MCF_DMA_IMCR) & ~MCF_DMA_IMCR_SRC31(3))
+                           | MCF_DMA_IMCR_SRC31_CTM7, MCF_DMA_IMCR);
+                       used_reqs[31] = DMA_CTM7;
+               } else          /* No empty slots */
+                       return 1;
+               break;
+
+       case DMA_USBEP4:
+               if (used_reqs[26] == 0) {
+                       writel((readl(MCF_DMA_IMCR) & ~MCF_DMA_IMCR_SRC26(3))
+                           | MCF_DMA_IMCR_SRC26_USBEP4, MCF_DMA_IMCR);
+                       used_reqs[26] = DMA_USBEP4;
+               } else          /* No empty slots */
+                       return 1;
+               break;
+
+       case DMA_USBEP5:
+               if (used_reqs[27] == 0) {
+                       writel((readl(MCF_DMA_IMCR) & ~MCF_DMA_IMCR_SRC27(3))
+                           | MCF_DMA_IMCR_SRC27_USBEP5, MCF_DMA_IMCR);
+                       used_reqs[27] = DMA_USBEP5;
+               } else          /* No empty slots */
+                       return 1;
+               break;
+
+       case DMA_USBEP6:
+               if (used_reqs[28] == 0) {
+                       writel((readl(MCF_DMA_IMCR) & ~MCF_DMA_IMCR_SRC28(3))
+                           | MCF_DMA_IMCR_SRC28_USBEP6, MCF_DMA_IMCR);
+                       used_reqs[28] = DMA_USBEP6;
+               } else          /* No empty slots */
+                       return 1;
+               break;
+
+       case DMA_PSC2_RX:
+               if (used_reqs[28] == 0) {
+                       writel((readl(MCF_DMA_IMCR) & ~MCF_DMA_IMCR_SRC28(3))
+                           | MCF_DMA_IMCR_SRC28_PSC2RX, MCF_DMA_IMCR);
+                       used_reqs[28] = DMA_PSC2_RX;
+               } else          /* No empty slots */
+                       return 1;
+               break;
+
+       case DMA_PSC2_TX:
+               if (used_reqs[29] == 0) {
+                       writel((readl(MCF_DMA_IMCR) & ~MCF_DMA_IMCR_SRC29(3))
+                           | MCF_DMA_IMCR_SRC29_PSC2TX, MCF_DMA_IMCR);
+                       used_reqs[29] = DMA_PSC2_TX;
+               } else          /* No empty slots */
+                       return 1;
+               break;
+
+       case DMA_PSC3_RX:
+               if (used_reqs[30] == 0) {
+                       writel((readl(MCF_DMA_IMCR) & ~MCF_DMA_IMCR_SRC30(3))
+                           | MCF_DMA_IMCR_SRC30_PSC3RX, MCF_DMA_IMCR);
+                       used_reqs[30] = DMA_PSC3_RX;
+               } else          /* No empty slots */
+                       return 1;
+               break;
+
+       case DMA_PSC3_TX:
+               if (used_reqs[31] == 0) {
+                       writel((readl(MCF_DMA_IMCR) & ~MCF_DMA_IMCR_SRC31(3))
+                           | MCF_DMA_IMCR_SRC31_PSC3TX, MCF_DMA_IMCR);
+                       used_reqs[31] = DMA_PSC3_TX;
+               } else          /* No empty slots */
+                       return 1;
+               break;
+
+       default:
+               return 1;
+       }
+       return 0;
+}
+
+/**
+ * dma_get_initiator - get the initiator for the given requestor
+ * @requestor: initiator identifier
+ *
+ * Returns initiator number (0-31) if assigned or just 0
+ */
+unsigned int dma_get_initiator(int requestor)
+{
+       u32 i;
+
+       for (i = 0; i < sizeof(used_reqs); ++i) {
+               if (used_reqs[i] == requestor)
+                       return i;
+       }
+       return 0;
+}
+
+/**
+ * dma_remove_initiator - remove the given initiator from active list
+ * @requestor: requestor to remove
+ */
+void dma_remove_initiator(int requestor)
+{
+       u32 i;
+
+       for (i = 0; i < sizeof(used_reqs); ++i) {
+               if (used_reqs[i] == requestor) {
+                       used_reqs[i] = -1;
+                       break;
+               }
+       }
+}
+
+/**
+ * dma_set_channel_fec: find available channel for fec and mark
+ * @requestor: initiator/requestor identifier
+ *
+ * Returns first avaialble channel (0-5) or -1 if all occupied
+ */
+int dma_set_channel_fec(int requestor)
+{
+       u32 i, t;
+
+#ifdef CONFIG_FEC2
+       t = 4;
+#else
+       t = 2;
+#endif
+
+       for (i = 0; i < t ; ++i) {
+               if (used_channel[i] == -1) {
+                       used_channel[i] = requestor;
+                       return i;
+               }
+       }
+       /* All channels taken */
+       return -1;
+}
+
+/**
+ * dma_set_channel - find an available channel and mark as used
+ * @requestor: initiator/requestor identifier
+ *
+ * Returns first available channel (6-15) or -1 if all occupied
+ */
+int dma_set_channel(int requestor)
+{
+       u32 i;
+#ifdef CONFIG_FEC2
+       i = 4;
+#else
+       i = 2;
+#endif
+
+       for (; i < 16; ++i)
+               if (used_channel[i] == -1) {
+                       used_channel[i] = requestor;
+                       return i;
+               }
+
+       /* All channels taken */
+       return -1;
+}
+
+/**
+ * dma_get_channel - get the channel being initiated by the requestor
+ * @requestor: initiator/requestor identifier
+ *
+ * Returns Initiator for requestor or -1 if not found
+ */
+int dma_get_channel(int requestor)
+{
+       u32 i;
+
+       for (i = 0; i < sizeof(used_channel); ++i) {
+               if (used_channel[i] == requestor)
+                       return i;
+       }
+       return -1;
+}
+
+/**
+ * dma_connect - connect a channel with reference on data
+ * @channel: channel number
+ * @address: reference address of data
+ *
+ * Returns 0 if success or -1 if invalid channel
+ */
+int dma_connect(int channel, dma_handler_t address, void *dev)
+{
+       if ((channel < 16) && (channel >= 0)) {
+               connected_channel[channel] = address;
+               connected_dev[channel] = dev;
+               return 0;
+       }
+       return -1;
+}
+
+/**
+ * dma_disconnect - disconnect a channel
+ * @channel: channel number
+ *
+ * Returns 0 if success or -1 if invalid channel
+ */
+int dma_disconnect(int channel)
+{
+       if ((channel < 16) && (channel >= 0)) {
+               connected_channel[channel] = 0;
+               connected_dev[channel] = 0;
+               return 0;
+       }
+       return -1;
+}
+
+/**
+ * dma_remove_channel - remove channel from the active list
+ * @requestor: initiator/requestor identifier
+ */
+void dma_remove_channel(int requestor)
+{
+       u32 i;
+
+       for (i = 0; i < sizeof(used_channel); ++i) {
+               if (used_channel[i] == requestor) {
+                       used_channel[i] = -1;
+                       break;
+               }
+       }
+}
+
+/**
+ * dma_interrupt_handler - dma interrupt handler
+ * @irq: interrupt number
+ * @dev_id: data
+ *
+ * Returns IRQ_HANDLED
+ */
+irqreturn_t dma_interrupt_handler(int irq, void *dev_id)
+{
+       u32 i, interrupts;
+
+       /*
+        * Determine which interrupt(s) triggered by AND'ing the
+        * pending interrupts with those that aren't masked.
+        */
+       interrupts = readl(MCF_DMA_DIPR);
+       writel(interrupts, MCF_DMA_DIPR);
+
+       for (i = 0; i < 16; ++i, interrupts >>= 1) {
+               if (interrupts & 0x1)
+                       if (connected_channel[i] != 0)
+                               connected_channel[i](connected_dev[i]);
+       }
+
+       return IRQ_HANDLED;
+}
+
+/**
+ * dma_remove_channel_by_number - clear dma channel
+ * @channel: channel number to clear
+ */
+void dma_remove_channel_by_number(int channel)
+{
+       if ((channel < sizeof(used_channel)) && (channel >= 0))
+               used_channel[channel] = -1;
+}
+
+/**
+ * dma_init - initialize the dma subsystem
+ *
+ * Returns 0 if success non-zero if failure
+ *
+ * Handles the DMA initialization during device setup.
+ */
+int __devinit dma_init()
+{
+       int result;
+       char *dma_version_str;
+
+       MCD_getVersion(&dma_version_str);
+       pr_info("m547x_8x DMA: Initialize %s\n", dma_version_str);
+
+       /* attempt to setup dma interrupt handler */
+       if (request_irq(MCF_IRQ_DMA, dma_interrupt_handler, IRQF_DISABLED,
+                       "MCD-DMA", NULL)) {
+               pr_err("MCD-DMA: Cannot allocate the DMA IRQ(48)\n");
+               return 1;
+       }
+
+       writel(0, MCF_DMA_DIMR);
+       writel(0xFFFFFFFF, MCF_DMA_DIPR);
+
+#if 0
+       MCF_ICR(ISC_DMA) = ILP_DMA;
+#endif
+
+       result = MCD_initDma((struct dmaRegs *) (MCF_MBAR + 0x8000),
+                       (void *) SYS_SRAM_DMA_START, MCD_RELOC_TASKS);
+       if (result != MCD_OK) {
+               pr_err("MCD-DMA: Cannot perform DMA initialization\n");
+               free_irq(MCF_IRQ_DMA, NULL);
+               return 1;
+       }
+
+       return 0;
+}
+device_initcall(dma_init);
-- 
1.7.1

_______________________________________________
uClinux-dev mailing list
uClinux-dev@uclinux.org
http://mailman.uclinux.org/mailman/listinfo/uclinux-dev
This message was resent by uclinux-dev@uclinux.org
To unsubscribe see:
http://mailman.uclinux.org/mailman/options/uclinux-dev

Reply via email to