[uClinux-dev] [PATCH 2/3] m68knommu: Add the m54xx-specific bits for the MultiChannel DMA driver

Philippe De Muyter phdm at macqel.be
Mon Sep 24 04:05:18 EDT 2012


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 <phdm at 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 <kmahan at 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



More information about the uClinux-dev mailing list