Discussion:
[uClinux-dev] [PATCH m68knommu] Add the m54xx fec driver
Philippe De Muyter
2012-09-24 08:05:16 UTC
Permalink
Hello,

I have cleaned up and updated to 3.6-rc5 my previous port of the
freescale-written driver for the fast Ethernet Controller of the M547x
and M548x ColdFires. It seems from comments found in Freescale sources
that this uses a MultiChannel DMA controller marketed as MCD and available
also in the NPC8220 also from Freescale. Therefore, I have split the
submission in three parts :
A generic MCD dma driver
The M54xx instantiation of the MCD driver
The FEC driver for M54xx

I know there are still lines above 80 characters, but I feel they must be
left that way. There are also parts of an unfinished netpoll interface.

Feel free to test and comment.

Philippe
Philippe De Muyter
2012-09-24 08:05:18 UTC
Permalink
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
Philippe De Muyter
2012-09-24 08:05:17 UTC
Permalink
Add the Freescale-provided MultiChannel DMA driver for ColdFire
M54xx and MPC8220 processors.
This driver is needed for the ethernet FEC driver of the ColdFire
M547x and M548x processors. It is not yet dmaengine-enabled, but
that's not needed for the above FEC driver. I have however installed
it in the driver/dma tree, and that needs a small rule change
in drivers/Makefile to enter drivers/dma on CONFIG_DMADEVICES
instead of CONFIG_DMAENGINE.

Signed-off-by: Philippe De Muyter <phdm at macqel.be>
---
arch/m68k/Kconfig.cpu | 2 +
drivers/Makefile | 2 +-
drivers/dma/Kconfig | 9 +
drivers/dma/Makefile | 1 +
drivers/dma/fsl_mcd_dma/MCD_dmaApi.c | 963 ++++++++++++
drivers/dma/fsl_mcd_dma/MCD_tasks.c | 2425 +++++++++++++++++++++++++++++++
drivers/dma/fsl_mcd_dma/MCD_tasksInit.c | 274 ++++
drivers/dma/fsl_mcd_dma/MCD_tasksInit.h | 76 +
drivers/dma/fsl_mcd_dma/Makefile | 1 +
include/linux/MCD_dma.h | 376 +++++
10 files changed, 4128 insertions(+), 1 deletions(-)
create mode 100644 drivers/dma/fsl_mcd_dma/MCD_dmaApi.c
create mode 100644 drivers/dma/fsl_mcd_dma/MCD_tasks.c
create mode 100644 drivers/dma/fsl_mcd_dma/MCD_tasksInit.c
create mode 100644 drivers/dma/fsl_mcd_dma/MCD_tasksInit.h
create mode 100644 drivers/dma/fsl_mcd_dma/Makefile
create mode 100644 include/linux/MCD_dma.h

diff --git a/arch/m68k/Kconfig.cpu b/arch/m68k/Kconfig.cpu
index c4eb79e..b7c89d1 100644
--- a/arch/m68k/Kconfig.cpu
+++ b/arch/m68k/Kconfig.cpu
@@ -241,6 +241,8 @@ config M5407

config M54xx
bool
+ select HAS_DMA
+ select DMADEVICES

config M547x
bool "MCF547x"
diff --git a/drivers/Makefile b/drivers/Makefile
index 5b42184..c036212 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -22,7 +22,7 @@ obj-$(CONFIG_PNP) += pnp/
obj-y += amba/
# Many drivers will want to use DMA so this has to be made available
# really early.
-obj-$(CONFIG_DMA_ENGINE) += dma/
+obj-$(CONFIG_DMADEVICES) += dma/

obj-$(CONFIG_VIRTIO) += virtio/
obj-$(CONFIG_XEN) += xen/
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index d06ea29..04639eb 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -107,6 +107,15 @@ config FSL_DMA
The Elo is the DMA controller on some 82xx and 83xx parts, and the
Elo Plus is the DMA controller on 85xx and 86xx parts.

+config FSL_MCD_DMA
+ bool "Freescale MultiChannel DMA (MCD) support"
+ depends on PPC_MPC8220 || M54xx
+ ---help---
+ This enables generic support for the Freescale MultiChannel DMA (MCD)
+ available on MPC8220 and ColdFire 547x/548x family.
+ This driver is used by the specific dma driver for the target CPU.
+ Some drivers, especially the FEC DMA driver, need it.
+
config MPC512X_DMA
tristate "Freescale MPC512x built-in DMA engine support"
depends on PPC_MPC512x || PPC_MPC831x
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index 4cf6b12..64d8465 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_DMATEST) += dmatest.o
obj-$(CONFIG_INTEL_IOATDMA) += ioat/
obj-$(CONFIG_INTEL_IOP_ADMA) += iop-adma.o
obj-$(CONFIG_FSL_DMA) += fsldma.o
+obj-$(CONFIG_FSL_MCD_DMA) += fsl_mcd_dma/
obj-$(CONFIG_MPC512X_DMA) += mpc512x_dma.o
obj-$(CONFIG_MV_XOR) += mv_xor.o
obj-$(CONFIG_DW_DMAC) += dw_dmac.o
diff --git a/drivers/dma/fsl_mcd_dma/MCD_dmaApi.c b/drivers/dma/fsl_mcd_dma/MCD_dmaApi.c
new file mode 100644
index 0000000..06606a0
--- /dev/null
+++ b/drivers/dma/fsl_mcd_dma/MCD_dmaApi.c
@@ -0,0 +1,963 @@
+/*
+ * drivers/dma/MCD_dmaApi.c
+ *
+ * Copyright (C) 2004-2008 Freescale Semiconductor, Inc.
+ * Kurt Mahan <kmahan at freescale.com>
+ * readl/writel conversion and other cleanup
+ * (C) Copyright 2010-2012 Philippe De Muyter <phdm at macqel.be> Macq SA
+ *
+ * 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/MCD_dma.h>
+#include <linux/io.h>
+#include "MCD_tasksInit.h"
+
+/********************************************************************/
+/*
+ * This is an API-internal pointer to the DMA's registers
+ */
+struct dmaRegs *MCD_dmaBar;
+
+/*
+ * MCD_realTaskTableSrc & MCD_modelTaskTableSrc get relocated to on-chip
+ * SRAM, at which point we access them as these tables
+ */
+struct TaskTableEntry *MCD_taskTable;
+struct TaskTableEntry *MCD_modelTaskTable;
+
+
+/*
+ * MCD_chStatus[] is an array of status indicators for remembering
+ * whether a DMA has ever been attempted on each channel, pausing
+ * status, etc.
+ */
+static int MCD_chStatus[NCHANNELS] = {
+ MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA,
+ MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA,
+ MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA,
+ MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA
+};
+
+/*
+ * Prototypes for local functions
+ */
+static void MCD_memcpy(int *dest, int *src, u32 size);
+static void MCD_resmActions(int channel);
+
+/*
+ * Buffer descriptors used for storage of progress info for single Dmas
+ * Also used as storage for the DMA for CRCs for single DMAs
+ * Otherwise, the DMA does not parse these buffer descriptors
+ */
+#ifndef MCD_INCLUDE_EU
+struct MCD_bufDesc MCD_singleBufDescs[NCHANNELS];
+#endif
+struct MCD_bufDesc *MCD_relocBuffDesc;
+
+
+/*
+ * Defines for the debug control register's functions
+ */
+#define DBG_CTL_COMP1_TASK (0x00002000) /* have comparator 1 look for a task # */
+#define DBG_CTL_ENABLE (DBG_CTL_AUTO_ARM | \
+ DBG_CTL_BREAK | \
+ DBG_CTL_INT_BREAK | \
+ DBG_CTL_COMP1_TASK)
+#define DBG_CTL_DISABLE (DBG_CTL_AUTO_ARM | \
+ DBG_CTL_INT_BREAK | \
+ DBG_CTL_COMP1_TASK)
+#define DBG_KILL_ALL_STAT (0xFFFFFFFF)
+
+/*
+ * Offset to context save area where progress info is stored
+ */
+#define CSAVE_OFFSET 10
+#define CURRBD ((CSAVE_OFFSET + 4) * 4)
+#define DCOUNT ((CSAVE_OFFSET + 6) * 4)
+#define DESTPTR ((CSAVE_OFFSET + 5) * 4)
+#define SRCPTR ((CSAVE_OFFSET + 7) * 4)
+
+/*
+ * Defines for Byte Swapping
+ */
+#define MCD_BYTE_SWAP_KILLER 0xFFF8888F
+#define MCD_NO_BYTE_SWAP_ATALL 0x00040000
+
+/*
+ * Execution Unit Identifiers
+ */
+#define MAC 0 /* legacy - not used */
+#define LUAC 1 /* legacy - not used */
+#define CRC 2 /* legacy - not used */
+#define LURC 3 /* Logic Unit with CRC */
+
+/*
+ * Task Identifiers
+ */
+#define TASK_CHAINNOEU 0
+#define TASK_SINGLENOEU 1
+#ifdef MCD_INCLUDE_EU
+#define TASK_CHAINEU 2
+#define TASK_SINGLEEU 3
+#define TASK_FECRX 4
+#define TASK_FECTX 5
+#else
+#define TASK_CHAINEU 0
+#define TASK_SINGLEEU 1
+#define TASK_FECRX 2
+#define TASK_FECTX 3
+#endif
+
+/*
+ * Structure to remember which variant is on which channel
+ */
+struct MCD_remVariants {
+ int remDestRsdIncr; /* -1,0,1 */
+ int remSrcRsdIncr; /* -1,0,1 */
+ s16 remDestIncr; /* DestIncr */
+ s16 remSrcIncr; /* srcIncr */
+ u32 remXferSize; /* xferSize */
+};
+
+/*
+ * Structure to remember the startDma parameters for each channel
+ */
+struct MCD_remVariants MCD_remVariants[NCHANNELS];
+
+/********************************************************************/
+/*
+ * Function: MCD_initDma
+ * Purpose: Initializes the DMA API by setting up a pointer to the DMA
+ * registers, relocating and creating the appropriate task
+ * structures, and setting up some global settings
+ * Arguments:
+ * dmaBarAddr - pointer to the multichannel DMA registers
+ * taskTableDest - location to move DMA task code and structs to
+ * flags - operational parameters
+ * Return Value:
+ * MCD_TABLE_UNALIGNED if taskTableDest is not 512-byte aligned
+ * MCD_OK otherwise
+ */
+
+int MCD_initDma(struct dmaRegs *dmaBarAddr, void *taskTableDest, u32 flags)
+{
+ int i;
+ struct TaskTableEntry *entryPtr, *tte;
+ u16 control;
+
+ /* Setup the local pointer to register set */
+ MCD_dmaBar = dmaBarAddr;
+
+ /* Do we need to move/create a task table */
+ if ((flags & MCD_RELOC_TASKS) != 0) {
+ int fixedSize;
+ u32 *fixedPtr;
+ int varTabsOffset, funcDescTabsOffset, contextSavesOffset;
+ int taskDescTabsOffset;
+ int varTabsSize, funcDescTabsSize, contextSavesSize;
+ int taskTableSize, taskDescTabSize;
+
+ int i;
+
+ /* Check if physical address is aligned on 512 byte boundary */
+ if (((u32)taskTableDest & 0x000001ff) != 0)
+ return MCD_TABLE_UNALIGNED;
+
+ /* set up local pointer to task Table */
+ MCD_taskTable = taskTableDest;
+
+ /*
+ * Create a task table:
+ * - compute aligned base offsets for variable tables and
+ * function descriptor tables, then
+ * - loop through the task table and setup the pointers
+ * - copy over model task table with the the actual task
+ * descriptor tables
+ */
+ taskTableSize = NCHANNELS * sizeof(struct TaskTableEntry);
+ /* Align variable tables to size */
+ varTabsOffset = taskTableSize + (u32)taskTableDest;
+ varTabsOffset = ALIGN(varTabsOffset, VAR_TAB_SIZE);
+ /* Align function descriptor tables */
+ varTabsSize = NCHANNELS * VAR_TAB_SIZE;
+ funcDescTabsOffset = varTabsOffset + varTabsSize;
+ funcDescTabsOffset = ALIGN(funcDescTabsOffset, FUNCDESC_TAB_SIZE);
+
+ funcDescTabsSize = FUNCDESC_TAB_NUM * FUNCDESC_TAB_SIZE;
+ contextSavesOffset = funcDescTabsOffset + funcDescTabsSize;
+ contextSavesSize = (NCHANNELS * CONTEXT_SAVE_SIZE);
+ fixedSize = taskTableSize + varTabsSize + funcDescTabsSize +
+ contextSavesSize;
+
+ /* Zero the thing out */
+ fixedPtr = (u32 *)taskTableDest;
+ for (i = 0; i < (fixedSize/4); i++)
+ fixedPtr[i] = 0;
+
+ entryPtr = (struct TaskTableEntry *)MCD_taskTable;
+ /* Set up fixed pointers */
+ for (i = 0; i < NCHANNELS; i++) {
+ tte = &entryPtr[i];
+ tte->varTab = (u32)varTabsOffset; /* update ptr to local value */
+ tte->FDTandFlags = (u32)funcDescTabsOffset | MCD_TT_FLAGS_DEF;
+ tte->contextSaveSpace = (u32)contextSavesOffset;
+ varTabsOffset += VAR_TAB_SIZE;
+#ifdef MCD_INCLUDE_EU /* if not there is only one, just point to the same one */
+ funcDescTabsOffset += FUNCDESC_TAB_SIZE;
+#endif
+ contextSavesOffset += CONTEXT_SAVE_SIZE;
+ }
+ /* Copy over the function descriptor table */
+ for (i = 0; i < FUNCDESC_TAB_NUM; i++) {
+ tte = &entryPtr[i];
+ MCD_memcpy((void *)(tte->FDTandFlags & ~MCD_TT_FLAGS_MASK),
+ (void *)MCD_funcDescTab0, FUNCDESC_TAB_SIZE);
+ }
+
+ /* Copy model task table to where the context save stuff leaves off */
+ MCD_modelTaskTable = (struct TaskTableEntry *)contextSavesOffset;
+
+ MCD_memcpy((void *)MCD_modelTaskTable, (void *)MCD_modelTaskTableSrc,
+ NUMOFVARIANTS * sizeof(struct TaskTableEntry));
+
+ /* Point to local version of model task table */
+ entryPtr = MCD_modelTaskTable;
+ taskDescTabsOffset = (u32)MCD_modelTaskTable +
+ (NUMOFVARIANTS * sizeof(struct TaskTableEntry));
+
+ /* Copy actual task code and update TDT ptrs in local model task table */
+ for (i = 0; i < NUMOFVARIANTS; i++) {
+ tte = &entryPtr[i];
+ taskDescTabSize = tte->TDTend - tte->TDTstart + 4;
+ MCD_memcpy((void *)taskDescTabsOffset, (void *)tte->TDTstart, taskDescTabSize);
+ tte->TDTstart = (u32)taskDescTabsOffset;
+ taskDescTabsOffset += taskDescTabSize;
+ tte->TDTend = (u32)taskDescTabsOffset - 4;
+ }
+#ifdef MCD_INCLUDE_EU
+ /*
+ * Tack single DMA BDs onto end of code so API controls where
+ * they are since DMA might write to them
+ */
+ MCD_relocBuffDesc = (struct MCD_bufDesc *)(entryPtr[NUMOFVARIANTS - 1].TDTend + 4);
+#else
+ /*
+ * DMA does not touch them so they can be wherever and we don't
+ * need to waste SRAM on them
+ */
+ MCD_relocBuffDesc = MCD_singleBufDescs;
+#endif
+ } else {
+ /*
+ * Point the would-be relocated task tables and the buffer
+ * descriptors to the ones the linker generated
+ */
+ if (((u32)MCD_realTaskTableSrc & 0x000001ff) != 0)
+ return MCD_TABLE_UNALIGNED;
+
+ entryPtr = (struct TaskTableEntry *)MCD_realTaskTableSrc;
+ for (i = 0; i < NCHANNELS; i++) {
+ tte = &entryPtr[i];
+ if (((tte->varTab & (VAR_TAB_SIZE - 1)) != 0) ||
+ ((tte->FDTandFlags & (FUNCDESC_TAB_SIZE - 1)) != 0))
+ return MCD_TABLE_UNALIGNED;
+ }
+
+ MCD_taskTable = (struct TaskTableEntry *)MCD_realTaskTableSrc;
+ MCD_modelTaskTable = (struct TaskTableEntry *)MCD_modelTaskTableSrc;
+ MCD_relocBuffDesc = MCD_singleBufDescs;
+ }
+
+ /* Make all channels inactive, and remember them as such: */
+ writel((u32) MCD_taskTable, &MCD_dmaBar->taskbar);
+ for (i = 0; i < NCHANNELS; i++) {
+ writew(0x0, &MCD_dmaBar->taskControl[i]);
+ MCD_chStatus[i] = MCD_NO_DMA;
+ }
+
+ /* Set up pausing mechanism to inactive state: */
+ writel(0, &MCD_dmaBar->debugComp1);
+ writel(0, &MCD_dmaBar->debugComp2);
+ writel(DBG_CTL_DISABLE, &MCD_dmaBar->debugControl);
+ writel(DBG_KILL_ALL_STAT, &MCD_dmaBar->debugStatus);
+
+ /* Enable or disable commbus prefetch */
+ control = readw(&MCD_dmaBar->ptdControl);
+ if ((flags & MCD_COMM_PREFETCH_EN) != 0)
+ control &= ~PTD_CTL_COMM_PREFETCH;
+ else
+ control |= PTD_CTL_COMM_PREFETCH;
+ writew(control, &MCD_dmaBar->ptdControl);
+
+ return MCD_OK;
+}
+/*********************** End of MCD_initDma() ***********************/
+
+/********************************************************************/
+/* Function: MCD_dmaStatus
+ * Purpose: Returns the status of the DMA on the requested channel
+ * Arguments: channel - channel number
+ * Returns: Predefined status indicators
+ */
+int MCD_dmaStatus(int channel)
+{
+ u16 tcrValue;
+
+ if ((channel < 0) || (channel >= NCHANNELS))
+ return MCD_CHANNEL_INVALID;
+
+ tcrValue = readw(&MCD_dmaBar->taskControl[channel]);
+ if ((tcrValue & TASK_CTL_EN) == 0) {
+ /* Nothing running if last reported with task enabled */
+ if (MCD_chStatus[channel] == MCD_RUNNING
+ || MCD_chStatus[channel] == MCD_IDLE)
+ MCD_chStatus[channel] = MCD_DONE;
+ } else { /* something is running */
+ /* There are three possibilities: paused, running or idle. */
+ if (MCD_chStatus[channel] == MCD_RUNNING
+ || MCD_chStatus[channel] == MCD_IDLE) {
+ writel(PTD_DBG_TSK_VLD_INIT, &MCD_dmaBar->ptdDebug);
+ /* Determine which initiator is asserted. */
+ if ((readl(&MCD_dmaBar->ptdDebug) >> channel) & 0x1)
+ MCD_chStatus[channel] = MCD_RUNNING;
+ else
+ MCD_chStatus[channel] = MCD_IDLE;
+ /* Do not change the status if it is already paused */
+ }
+ }
+ return MCD_chStatus[channel];
+}
+/******************** End of MCD_dmaStatus() ************************/
+
+/********************************************************************/
+/* Function: MCD_startDma
+ * Ppurpose: Starts a particular kind of DMA
+ * Arguments: see below
+ * Returns: MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
+ */
+
+int MCD_startDma(
+ const int channel, /* the channel on which to run the DMA */
+ s8 *srcAddr, /* the address to move data from, or physical buffer-descriptor address */
+ s16 srcIncr, /* the amount to increment the source address per transfer */
+ s8 *destAddr, /* the address to move data to */
+ s16 destIncr, /* the amount to increment the destination address per transfer */
+ u32 dmaSize, /* the number of bytes to transfer independent of the transfer size */
+ u32 xferSize, /* the number bytes in of each data movement (1, 2, or 4) */
+ u32 initiator, /* what device initiates the DMA */
+ int priority, /* priority of the DMA */
+ u32 flags, /* flags describing the DMA */
+ u32 funcDesc /* a description of byte swapping, bit swapping, and CRC actions */
+#ifdef MCD_NEED_ADDR_TRANS
+ s8 *srcAddrVirt /* virtual buffer descriptor address TBD */
+#endif
+)
+{
+ int srcRsdIncr, destRsdIncr;
+ int *cSave;
+ short xferSizeIncr;
+ int tcrCount = 0;
+#ifdef MCD_INCLUDE_EU
+ u32 *realFuncArray;
+#endif
+ u16 control;
+ struct MCD_remVariants *var;
+ struct TaskTableEntry *tte;
+ u32 css;
+ struct TaskTableEntry *mmte;
+
+ if ((channel < 0) || (channel >= NCHANNELS))
+ return MCD_CHANNEL_INVALID;
+
+#ifndef MCD_INCLUDE_EU
+ funcDesc = MCD_FUNC_NOEU1;
+#endif
+
+#ifdef MCD_DEBUG
+printf("startDma:Setting up params\n");
+#endif
+
+ /* Enable task-wise priority */
+ control = readl(&MCD_dmaBar->ptdControl);
+ writel(control | 0x8000, &MCD_dmaBar->ptdControl);
+
+ /* Calculate additional parameters to the regular DMA calls. */
+ srcRsdIncr = srcIncr < 0 ? -1 : (srcIncr > 0 ? 1 : 0);
+ destRsdIncr = destIncr < 0 ? -1 : (destIncr > 0 ? 1 : 0);
+ xferSizeIncr = (xferSize & 0xffff) | 0x20000000;
+
+ /* Remember which variant is running for each channel */
+ var = &MCD_remVariants[channel];
+ var->remSrcRsdIncr = srcRsdIncr;
+ var->remDestRsdIncr = destRsdIncr;
+ var->remDestIncr = destIncr;
+ var->remSrcIncr = srcIncr;
+ var->remXferSize = xferSize;
+
+ tte = &MCD_taskTable[channel];
+
+ cSave = (int *)(tte->contextSaveSpace + CURRBD);
+
+#ifdef MCD_INCLUDE_EU
+ realFuncArray = (u32 *) (tte->FDTandFlags & 0xffffff00);
+
+ /*
+ * Modify the LURC's normal and byte-residue-loop functions
+ * according to parameter.
+ */
+ switch (xferSize) {
+ case 4:
+ realFuncArray[(LURC*16)] = funcDesc;
+ break;
+ case 2:
+ realFuncArray[(LURC*16)] = funcDesc & 0xfffff00f;
+ break;
+ case 1:
+ default:
+ realFuncArray[(LURC*16)] = funcDesc & 0xffff000f;
+ break;
+ }
+
+ realFuncArray[(LURC*16+1)] = 0
+ | (funcDesc & MCD_BYTE_SWAP_KILLER)
+ | MCD_NO_BYTE_SWAP_ATALL;
+#endif
+
+ /* Write the initiator field in the TCR and set the initiator-hold bit */
+ writew(0
+ | (initiator << 8)
+ | TASK_CTL_HIPRITSKEN
+ | TASK_CTL_HLDINITNUM,
+ &MCD_dmaBar->taskControl[channel]);
+
+ /*
+ * Current versions of the MPC8220 MCD have a hardware quirk that could
+ * cause the write to the TCR to collide with an MDE access to the
+ * initiator-register file, so we have to verify that the write occurred
+ * correctly by reading back the value. On MCF547x/8x devices and any
+ * future revisions of the MPC8220, this loop will not be entered.
+ */
+ while (((readw(&MCD_dmaBar->taskControl[channel]) & 0x1fff) !=
+ ((initiator << 8) | TASK_CTL_HIPRITSKEN | TASK_CTL_HLDINITNUM)) &&
+ (tcrCount < 1000)) {
+ tcrCount++;
+ writew(0
+ | (initiator << 8)
+ | TASK_CTL_HIPRITSKEN
+ | TASK_CTL_HLDINITNUM,
+ &MCD_dmaBar->taskControl[channel]);
+ }
+
+ writeb(priority & PRIORITY_PRI_MASK, &MCD_dmaBar->priority[channel]);
+
+ if (channel < 8 && channel >= 0) {
+ u32 tasksize = readl(&MCD_dmaBar->taskSize0);
+ int shift = (7 - channel) * 4;
+ u32 xfermask;
+
+ tasksize &= ~(0xf << shift);
+ xfermask = xferSize & 3;
+ xfermask |= xfermask << 2;
+ tasksize |= xfermask << shift;
+ writel(tasksize, &MCD_dmaBar->taskSize0);
+ } else {
+ u32 tasksize = readl(&MCD_dmaBar->taskSize1);
+ int shift = (15 - channel) * 4;
+ u32 xfermask;
+
+ tasksize &= ~(0xf << shift);
+ xfermask = xferSize & 3;
+ xfermask |= xfermask << 2;
+ tasksize |= xfermask << shift;
+ writel(tasksize, &MCD_dmaBar->taskSize1);
+ }
+
+ /* Setup task table flags/options */
+ tte->FDTandFlags &= ~MCD_TT_FLAGS_MASK;
+ tte->FDTandFlags |= (MCD_TT_FLAGS_MASK & flags);
+
+ if (flags & MCD_FECTX_DMA) {
+ /* TDTStart and TDTEnd */
+ mmte = &MCD_modelTaskTable[TASK_FECTX];
+ tte->TDTstart = mmte->TDTstart;
+ tte->TDTend = mmte->TDTend;
+ MCD_startDmaENetXmit(srcAddr, srcAddr, destAddr, MCD_taskTable,
+ channel);
+ } else if (flags & MCD_FECRX_DMA) {
+ /* TDTStart and TDTEnd */
+ mmte = &MCD_modelTaskTable[TASK_FECRX];
+ tte->TDTstart = mmte->TDTstart;
+ tte->TDTend = mmte->TDTend;
+ MCD_startDmaENetRcv(srcAddr, srcAddr, destAddr, MCD_taskTable,
+ channel);
+ } else if (flags & MCD_SINGLE_DMA) {
+ struct MCD_bufDesc *mrbd;
+
+ /*
+ * This buffer descriptor is used for storing off initial
+ * parameters * for later progress query calculation and for
+ * the DMA to write the resulting checksum. The DMA does not
+ * use this to determine how to * operate, that info is passed
+ * with the init routine
+ */
+ mrbd = &MCD_relocBuffDesc[channel];
+ mrbd->srcAddr = srcAddr;
+ mrbd->destAddr = destAddr;
+ mrbd->lastDestAddr = destAddr;
+ mrbd->dmaSize = dmaSize;
+ mrbd->flags = 0; /* not used */
+ mrbd->csumResult = 0; /* not used */
+ mrbd->next = 0; /* not used */
+
+ /* Initialize the progress-querying stuff to show no progress:*/
+ css = tte->contextSaveSpace;
+ writel((int)srcAddr, css + SRCPTR);
+ writel((int)destAddr, css + DESTPTR);
+ writel(0, css + DCOUNT);
+ writel((u32)mrbd, css + CURRBD);
+
+ if (funcDesc == MCD_FUNC_NOEU1 || funcDesc == MCD_FUNC_NOEU2) {
+ /* TDTStart and TDTEnd */
+ mmte = &MCD_modelTaskTable[TASK_SINGLENOEU];
+ tte->TDTstart = mmte->TDTstart;
+ tte->TDTend = mmte->TDTend;
+ MCD_startDmaSingleNoEu(srcAddr, srcIncr, destAddr,
+ destIncr, dmaSize,
+ xferSizeIncr, flags, (int *)mrbd,
+ cSave, MCD_taskTable, channel);
+ } else {
+ /* TDTStart and TDTEnd */
+ mmte = &MCD_modelTaskTable[TASK_SINGLEEU];
+ tte->TDTstart = mmte->TDTstart;
+ tte->TDTend = mmte->TDTend;
+ MCD_startDmaSingleEu(srcAddr, srcIncr, destAddr,
+ destIncr, dmaSize,
+ xferSizeIncr, flags, (int *)mrbd,
+ cSave, MCD_taskTable, channel);
+ }
+ } else /* Chained DMA */ {
+ struct MCD_bufDesc *mbd;
+
+ /* Initialize the progress-querying stuff to show no progress:*/
+#if 1 /* (!defined(MCD_NEED_ADDR_TRANS)) */
+ mbd = (struct MCD_bufDesc *) srcAddr;
+#else /* if using address translation, need the virtual addr of the first buffdesc */
+ mbd = (struct MCD_bufDesc *) srcAddrVirt;
+#endif
+ css = tte->contextSaveSpace;
+ writel((int)mbd->srcAddr, css + SRCPTR);
+ writel((int)mbd->destAddr, css + DESTPTR);
+ writel(0, css + DCOUNT);
+ writel((u32)srcAddr, css + CURRBD);
+
+ if (funcDesc == MCD_FUNC_NOEU1 || funcDesc == MCD_FUNC_NOEU2) {
+ /* TDTStart and TDTEnd */
+ mmte = &MCD_modelTaskTable[TASK_CHAINNOEU];
+ tte->TDTstart = mmte->TDTstart;
+ tte->TDTend = mmte->TDTend;
+ MCD_startDmaChainNoEu((int *)srcAddr, srcIncr, destIncr,
+ xferSize, xferSizeIncr, cSave,
+ MCD_taskTable, channel);
+ } else {
+ /* TDTStart and TDTEnd */
+ mmte = &MCD_modelTaskTable[TASK_CHAINEU];
+ tte->TDTstart = mmte->TDTstart;
+ tte->TDTend = mmte->TDTend;
+ MCD_startDmaChainEu((int *)srcAddr, srcIncr, destIncr,
+ xferSize, xferSizeIncr, cSave,
+ MCD_taskTable, channel);
+ }
+ }
+
+ MCD_chStatus[channel] = MCD_IDLE;
+ return MCD_OK;
+}
+
+/************************ End of MCD_startDma() *********************/
+
+/********************************************************************/
+/* Function: MCD_XferProgrQuery
+ * Purpose: Returns progress of DMA on requested channel
+ * Arguments: channel - channel to retrieve progress for
+ * progRep - pointer to user supplied MCD_XferProg struct
+ * Returns: MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
+ *
+ * Notes:
+ * MCD_XferProgrQuery() upon completing or after aborting a DMA, or
+ * while the DMA is in progress, this function returns the first
+ * DMA-destination address not (or not yet) used in the DMA. When
+ * encountering a non-ready buffer descriptor, the information for
+ * the last completed descriptor is returned.
+ *
+ * MCD_XferProgQuery() has to avoid the possibility of getting
+ * partially-updated information in the event that we should happen
+ * to query DMA progress just as the DMA is updating it. It does that
+ * by taking advantage of the fact context is not saved frequently for
+ * the most part. We therefore read it at least twice until we get the
+ * same information twice in a row.
+ *
+ * Because a small, but not insignificant, amount of time is required
+ * to write out the progress-query information, especially upon
+ * completion of the DMA, it would be wise to guarantee some time lag
+ * between successive readings of the progress-query information.
+ */
+
+/*
+ * How many iterations of the loop below to execute to stabilize values
+ */
+#define STABTIME 0
+
+int MCD_XferProgrQuery(const int channel, struct MCD_XferProg *progRep)
+{
+ struct MCD_XferProg prevRep;
+ int again; /* true if we are to try again to get consistent results */
+ int i; /* used as a time-waste counter */
+ int destDiffBytes; /* Total number of bytes that we think actually got xfered. */
+ int numIterations; /* number of iterations */
+ int bytesNotXfered; /* bytes that did not get xfered. */
+ s8 *LWAlignedInitDestAddr, *LWAlignedCurrDestAddr;
+ int subModVal, addModVal; /* Mode values to added and subtracted from
+ the final destAddr */
+ struct TaskTableEntry *tte;
+ u32 css;
+ struct MCD_remVariants *var;
+
+ if ((channel < 0) || (channel >= NCHANNELS))
+ return MCD_CHANNEL_INVALID;
+
+ tte = &MCD_taskTable[channel];
+ css = tte->contextSaveSpace;
+
+ /* Read a trial value for the progress-reporting values */
+ prevRep.lastSrcAddr = (s8 *)readl(css + SRCPTR);
+ prevRep.lastDestAddr = (s8 *)readl(css + DESTPTR);
+ prevRep.dmaSize = readl(css + DCOUNT);
+ prevRep.currBufDesc = (struct MCD_bufDesc *)readl(css + CURRBD);
+
+ /* Repeatedly reread those values until they match previous values: */
+ do {
+ /* Take a little bit of time to ensure stability: */
+ for (i = 0; i < STABTIME; i++)
+ i += i >> 2; /* make sure this loop does something so
+ that it doesn't get optimized out */
+ /* Check them again: */
+ progRep->lastSrcAddr = (s8 *)readl(css + SRCPTR);
+ progRep->lastDestAddr = (s8 *)readl(css + DESTPTR);
+ progRep->dmaSize = readl(css + DCOUNT);
+ progRep->currBufDesc = (struct MCD_bufDesc *)readl(css + CURRBD);
+
+ /* See if they match: */
+ if (prevRep.lastSrcAddr != progRep->lastSrcAddr
+ || prevRep.lastDestAddr != progRep->lastDestAddr
+ || prevRep.dmaSize != progRep->dmaSize
+ || prevRep.currBufDesc != progRep->currBufDesc) {
+ /* If they don't match, remember previous values and try again:*/
+ prevRep.lastSrcAddr = progRep->lastSrcAddr;
+ prevRep.lastDestAddr = progRep->lastDestAddr;
+ prevRep.dmaSize = progRep->dmaSize;
+ prevRep.currBufDesc = progRep->currBufDesc;
+ again = MCD_TRUE;
+ } else
+ again = MCD_FALSE;
+ } while (again == MCD_TRUE);
+
+
+ /* Update dmaSize and lastDestAddr */
+ var = &MCD_remVariants[channel];
+ switch (var->remDestRsdIncr) {
+ case MINUS1:
+ subModVal = ((int)progRep->lastDestAddr)
+ & ((var->remXferSize) - 1);
+ addModVal = ((int)progRep->currBufDesc->destAddr)
+ & ((var->remXferSize) - 1);
+ LWAlignedInitDestAddr = (progRep->currBufDesc->destAddr) - addModVal;
+ LWAlignedCurrDestAddr = (progRep->lastDestAddr) - subModVal;
+ destDiffBytes = LWAlignedInitDestAddr - LWAlignedCurrDestAddr;
+ bytesNotXfered = (destDiffBytes/var->remDestIncr) *
+ (var->remDestIncr + var->remXferSize);
+ progRep->dmaSize = destDiffBytes - bytesNotXfered + addModVal - subModVal;
+ break;
+ case ZERO:
+ progRep->lastDestAddr = progRep->currBufDesc->destAddr;
+ break;
+ case PLUS1:
+ /* This value has to be subtracted from the final calculated dmaSize. */
+ subModVal = ((int)progRep->currBufDesc->destAddr)
+ & ((var->remXferSize) - 1);
+ /* These bytes are already in lastDestAddr. */
+ addModVal = ((int)progRep->lastDestAddr)
+ & ((var->remXferSize) - 1);
+ LWAlignedInitDestAddr = (progRep->currBufDesc->destAddr) - subModVal;
+ LWAlignedCurrDestAddr = (progRep->lastDestAddr) - addModVal;
+ destDiffBytes = (progRep->lastDestAddr - LWAlignedInitDestAddr);
+ numIterations = (LWAlignedCurrDestAddr - LWAlignedInitDestAddr)/var->remDestIncr;
+ bytesNotXfered = numIterations *
+ (var->remDestIncr - var->remXferSize);
+ progRep->dmaSize = destDiffBytes - bytesNotXfered - subModVal;
+ break;
+ default:
+ break;
+ }
+
+ /* This covers M1,P1,Z for source */
+ switch (var->remSrcRsdIncr) {
+ case MINUS1:
+ progRep->lastSrcAddr = progRep->currBufDesc->srcAddr +
+ (var->remSrcIncr * (progRep->dmaSize/var->remXferSize));
+ break;
+ case ZERO:
+ progRep->lastSrcAddr = progRep->currBufDesc->srcAddr;
+ break;
+ case PLUS1:
+ progRep->lastSrcAddr = progRep->currBufDesc->srcAddr +
+ (var->remSrcIncr * (progRep->dmaSize/var->remXferSize));
+ break;
+ default:
+ break;
+ }
+
+ return MCD_OK;
+}
+/******************* End of MCD_XferProgrQuery() ********************/
+
+/********************************************************************/
+/* MCD_resmActions() does the majority of the actions of a DMA resume.
+ * It is called from MCD_killDma() and MCD_resumeDma(). It has to be
+ * a separate function because the kill function has to negate the task
+ * enable before resuming it, but the resume function has to do nothing
+ * if there is no DMA on that channel (i.e., if the enable bit is 0).
+ */
+static void MCD_resmActions(int channel)
+{
+ u32 status;
+
+ writel(DBG_CTL_DISABLE, &MCD_dmaBar->debugControl);
+ status = readl(&MCD_dmaBar->debugStatus);
+ writel(status, &MCD_dmaBar->debugStatus);
+
+ /* Determine which initiators are asserted */
+ writel(PTD_DBG_TSK_VLD_INIT, &MCD_dmaBar->ptdDebug);
+
+ if ((readl(&MCD_dmaBar->ptdDebug) >> channel) & 0x1)
+ MCD_chStatus[channel] = MCD_RUNNING;
+ else
+ MCD_chStatus[channel] = MCD_IDLE;
+}
+/********************* End of MCD_resmActions() *********************/
+
+/********************************************************************/
+/* Function: MCD_killDma
+ * Purpose: Halt the DMA on the requested channel, without any
+ * intention of resuming the DMA.
+ * Arguments: channel - requested channel
+ * Returns: MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
+ *
+ * Notes:
+ * A DMA may be killed from any state, including paused state, and it
+ * always goes to the MCD_HALTED state even if it is killed while in
+ * the MCD_NO_DMA or MCD_IDLE states.
+ */
+int MCD_killDma(int channel)
+{
+ if ((channel < 0) || (channel >= NCHANNELS))
+ return MCD_CHANNEL_INVALID;
+
+ writew(0x0, &MCD_dmaBar->taskControl[channel]);
+
+ /* Clean up after a paused task */
+ if (MCD_chStatus[channel] == MCD_PAUSED) {
+ u32 status;
+
+ writel(DBG_CTL_DISABLE, &MCD_dmaBar->debugControl);
+ status = readl(&MCD_dmaBar->debugStatus);
+ writel(status, &MCD_dmaBar->debugStatus);
+ }
+
+ MCD_chStatus[channel] = MCD_HALTED;
+
+ return MCD_OK;
+}
+/************************ End of MCD_killDma() **********************/
+
+/********************************************************************/
+/* Function: MCD_continDma
+ * Purpose: Continue a DMA which as stopped due to encountering an
+ * unready buffer descriptor.
+ * Arguments: channel - channel to continue the DMA on
+ * Returns: MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
+ *
+ * Notes:
+ * This routine does not check to see if there is a task which can
+ * be continued. Also this routine should not be used with single DMAs.
+ */
+int MCD_continDma(int channel)
+{
+ u16 tcrValue;
+
+ if ((channel < 0) || (channel >= NCHANNELS))
+ return MCD_CHANNEL_INVALID;
+
+ tcrValue = readw(&MCD_dmaBar->taskControl[channel]);
+ writew(tcrValue | TASK_CTL_EN, &MCD_dmaBar->taskControl[channel]);
+ MCD_chStatus[channel] = MCD_RUNNING;
+
+ return MCD_OK;
+}
+/********************** End of MCD_continDma() **********************/
+
+/*********************************************************************
+ * MCD_pauseDma() and MCD_resumeDma() below use the DMA's debug unit
+ * to freeze a task and resume it. We freeze a task by breakpointing
+ * on the stated task. That is, not any specific place in the task,
+ * but any time that task executes. In particular, when that task
+ * executes, we want to freeze that task and only that task.
+ *
+ * The bits of the debug control register influence interrupts vs.
+ * breakpoints as follows:
+ * - Bits 14 and 0 enable or disable debug functions. If enabled, you
+ * will get the interrupt but you may or may not get a breakpoint.
+ * - Bits 2 and 1 decide whether you also get a breakpoint in addition
+ * to an interrupt.
+ *
+ * The debug unit can do these actions in response to either internally
+ * detected breakpoint conditions from the comparators, or in response
+ * to the external breakpoint pin, or both.
+ * - Bits 14 and 1 perform the above-described functions for
+ * internally-generated conditions, i.e., the debug comparators.
+ * - Bits 0 and 2 perform the above-described functions for external
+ * conditions, i.e., the breakpoint external pin.
+ *
+ * Note that, although you "always" get the interrupt when you turn
+ * the debug functions, the interrupt can nevertheless, if desired, be
+ * masked by the corresponding bit in the PTD's IMR. Note also that
+ * this means that bits 14 and 0 must enable debug functions before
+ * bits 1 and 2, respectively, have any effect.
+ *
+ * NOTE: It's extremely important to not pause more than one DMA channel
+ * at a time.
+ ********************************************************************/
+
+/********************************************************************/
+/* Function: MCD_pauseDma
+ * Purpose: Pauses the DMA on a given channel (if any DMA is running
+ * on that channel).
+ * Arguments: channel
+ * Returns: MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
+ */
+int MCD_pauseDma(int channel)
+{
+ if ((channel < 0) || (channel >= NCHANNELS))
+ return MCD_CHANNEL_INVALID;
+
+ if (readw(&MCD_dmaBar->taskControl[channel]) & TASK_CTL_EN) {
+ writel(channel, &MCD_dmaBar->debugComp1);
+ writel(DBG_CTL_ENABLE | (1 << (channel + 16)),
+ &MCD_dmaBar->debugControl);
+ MCD_chStatus[channel] = MCD_PAUSED;
+ }
+ return MCD_OK;
+}
+/************************* End of MCD_pauseDma() ********************/
+
+/********************************************************************/
+/* Function: MCD_resumeDma
+ * Purpose: Resumes the DMA on a given channel (if any DMA is
+ * running on that channel).
+ * Arguments: channel - channel on which to resume DMA
+ * Returns: MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
+ */
+int MCD_resumeDma(int channel)
+{
+ if ((channel < 0) || (channel >= NCHANNELS))
+ return MCD_CHANNEL_INVALID;
+
+ if (readw(&MCD_dmaBar->taskControl[channel]) & TASK_CTL_EN)
+ MCD_resmActions(channel);
+
+ return MCD_OK;
+}
+/************************ End of MCD_resumeDma() ********************/
+
+/********************************************************************/
+/* Function: MCD_csumQuery
+ * Purpose: Provide the checksum after performing a non-chained DMA
+ * Arguments: channel - channel to report on
+ * csum - pointer to where to write the checksum/CRC
+ * Returns: MCD_ERROR if the channel is invalid, else MCD_OK
+ *
+ * Notes:
+ *
+ */
+int MCD_csumQuery(int channel, u32 *csum)
+{
+#ifdef MCD_INCLUDE_EU
+ if ((channel < 0) || (channel >= NCHANNELS))
+ return MCD_CHANNEL_INVALID;
+
+ *csum = MCD_relocBuffDesc[channel].csumResult;
+ return MCD_OK;
+#else
+ return MCD_ERROR;
+#endif
+}
+/*********************** End of MCD_resumeDma() *********************/
+
+/********************************************************************/
+/* Function: MCD_getCodeSize
+ * Purpose: Provide the size requirements of the microcoded tasks
+ * Returns: Size in bytes
+ */
+int MCD_getCodeSize(void)
+{
+#ifdef MCD_INCLUDE_EU
+ return 0x2b64;
+#else
+ return 0x1744;
+#endif
+}
+/********************** End of MCD_getCodeSize() ********************/
+
+/********************************************************************/
+/* Function: MCD_getVersion
+ * Purpose: Provide the version string and number
+ * Arguments: longVersion - user supplied pointer to a pointer to a char
+ * which points to the version string
+ * Returns: Version number and version string (by reference)
+ */
+char MCD_versionString[] = "Multi-channel DMA API v1.0";
+#define MCD_REV_MAJOR 0x01
+#define MCD_REV_MINOR 0x00
+
+int MCD_getVersion(char **longVersion)
+{
+ *longVersion = MCD_versionString;
+ return (MCD_REV_MAJOR << 8) | MCD_REV_MINOR;
+}
+/********************** End of MCD_getVersion() *********************/
+
+/********************************************************************/
+/* Private version of memcpy()
+ * Note that everything this is used for is longword-aligned.
+ */
+static void MCD_memcpy(int *dest, int *src, u32 size)
+{
+ u32 i;
+
+ for (i = 0; i < size; i += sizeof(int), dest++, src++)
+ *dest = *src;
+}
+/********************************************************************/
diff --git a/drivers/dma/fsl_mcd_dma/MCD_tasks.c b/drivers/dma/fsl_mcd_dma/MCD_tasks.c
new file mode 100644
index 0000000..677ed9b
--- /dev/null
+++ b/drivers/dma/fsl_mcd_dma/MCD_tasks.c
@@ -0,0 +1,2425 @@
+/*
+ * drivers/dma/MCD_tasks.c
+ *
+ * Copyright (C) 2004-2008 Freescale Semiconductor, Inc.
+ * Kurt Mahan <kmahan at freescale.com>
+ *
+ * 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/MCD_dma.h>
+
+u32 MCD_varTab0[];
+u32 MCD_varTab1[];
+u32 MCD_varTab2[];
+u32 MCD_varTab3[];
+u32 MCD_varTab4[];
+u32 MCD_varTab5[];
+u32 MCD_varTab6[];
+u32 MCD_varTab7[];
+u32 MCD_varTab8[];
+u32 MCD_varTab9[];
+u32 MCD_varTab10[];
+u32 MCD_varTab11[];
+u32 MCD_varTab12[];
+u32 MCD_varTab13[];
+u32 MCD_varTab14[];
+u32 MCD_varTab15[];
+
+u32 MCD_funcDescTab0[];
+#ifdef MCD_INCLUDE_EU
+u32 MCD_funcDescTab1[];
+u32 MCD_funcDescTab2[];
+u32 MCD_funcDescTab3[];
+u32 MCD_funcDescTab4[];
+u32 MCD_funcDescTab5[];
+u32 MCD_funcDescTab6[];
+u32 MCD_funcDescTab7[];
+u32 MCD_funcDescTab8[];
+u32 MCD_funcDescTab9[];
+u32 MCD_funcDescTab10[];
+u32 MCD_funcDescTab11[];
+u32 MCD_funcDescTab12[];
+u32 MCD_funcDescTab13[];
+u32 MCD_funcDescTab14[];
+u32 MCD_funcDescTab15[];
+#endif
+
+u32 MCD_contextSave0[];
+u32 MCD_contextSave1[];
+u32 MCD_contextSave2[];
+u32 MCD_contextSave3[];
+u32 MCD_contextSave4[];
+u32 MCD_contextSave5[];
+u32 MCD_contextSave6[];
+u32 MCD_contextSave7[];
+u32 MCD_contextSave8[];
+u32 MCD_contextSave9[];
+u32 MCD_contextSave10[];
+u32 MCD_contextSave11[];
+u32 MCD_contextSave12[];
+u32 MCD_contextSave13[];
+u32 MCD_contextSave14[];
+u32 MCD_contextSave15[];
+
+const u32 MCD_realTaskTableSrc[] = {
+ 0x00000000,
+ 0x00000000,
+ (u32)MCD_varTab0, /* Task 0 Variable Table */
+ (u32)MCD_funcDescTab0, /* Task 0 Function Descriptor Table & Flags */
+ 0x00000000,
+ 0x00000000,
+ (u32)MCD_contextSave0, /* Task 0 context save space */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ (u32)MCD_varTab1, /* Task 1 Variable Table */
+#ifdef MCD_INCLUDE_EU
+ (u32)MCD_funcDescTab1, /* Task 1 Function Descriptor Table & Flags */
+#else
+ (u32)MCD_funcDescTab0, /* Task 0 Function Descriptor Table & Flags */
+#endif
+ 0x00000000,
+ 0x00000000,
+ (u32)MCD_contextSave1, /* Task 1 context save space */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ (u32)MCD_varTab2, /* Task 2 Variable Table */
+#ifdef MCD_INCLUDE_EU
+ (u32)MCD_funcDescTab2, /* Task 2 Function Descriptor Table & Flags */
+#else
+ (u32)MCD_funcDescTab0, /* Task 0 Function Descriptor Table & Flags */
+#endif
+ 0x00000000,
+ 0x00000000,
+ (u32)MCD_contextSave2, /* Task 2 context save space */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ (u32)MCD_varTab3, /* Task 3 Variable Table */
+#ifdef MCD_INCLUDE_EU
+ (u32)MCD_funcDescTab3, /* Task 3 Function Descriptor Table & Flags */
+#else
+ (u32)MCD_funcDescTab0, /* Task 0 Function Descriptor Table & Flags */
+#endif
+ 0x00000000,
+ 0x00000000,
+ (u32)MCD_contextSave3, /* Task 3 context save space */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ (u32)MCD_varTab4, /* Task 4 Variable Table */
+#ifdef MCD_INCLUDE_EU
+ (u32)MCD_funcDescTab4, /* Task 4 Function Descriptor Table & Flags */
+#else
+ (u32)MCD_funcDescTab0, /* Task 0 Function Descriptor Table & Flags */
+#endif
+ 0x00000000,
+ 0x00000000,
+ (u32)MCD_contextSave4, /* Task 4 context save space */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ (u32)MCD_varTab5, /* Task 5 Variable Table */
+#ifdef MCD_INCLUDE_EU
+ (u32)MCD_funcDescTab5, /* Task 5 Function Descriptor Table & Flags */
+#else
+ (u32)MCD_funcDescTab0, /* Task 0 Function Descriptor Table & Flags */
+#endif
+ 0x00000000,
+ 0x00000000,
+ (u32)MCD_contextSave5, /* Task 5 context save space */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ (u32)MCD_varTab6, /* Task 6 Variable Table */
+#ifdef MCD_INCLUDE_EU
+ (u32)MCD_funcDescTab6, /* Task 6 Function Descriptor Table & Flags */
+#else
+ (u32)MCD_funcDescTab0, /* Task 0 Function Descriptor Table & Flags */
+#endif
+ 0x00000000,
+ 0x00000000,
+ (u32)MCD_contextSave6, /* Task 6 context save space */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ (u32)MCD_varTab7, /* Task 7 Variable Table */
+#ifdef MCD_INCLUDE_EU
+ (u32)MCD_funcDescTab7, /* Task 7 Function Descriptor Table & Flags */
+#else
+ (u32)MCD_funcDescTab0, /* Task 0 Function Descriptor Table & Flags */
+#endif
+ 0x00000000,
+ 0x00000000,
+ (u32)MCD_contextSave7, /* Task 7 context save space */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ (u32)MCD_varTab8, /* Task 8 Variable Table */
+#ifdef MCD_INCLUDE_EU
+ (u32)MCD_funcDescTab8, /* Task 8 Function Descriptor Table & Flags */
+#else
+ (u32)MCD_funcDescTab0, /* Task 0 Function Descriptor Table & Flags */
+#endif
+ 0x00000000,
+ 0x00000000,
+ (u32)MCD_contextSave8, /* Task 8 context save space */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ (u32)MCD_varTab9, /* Task 9 Variable Table */
+#ifdef MCD_INCLUDE_EU
+ (u32)MCD_funcDescTab9, /* Task 9 Function Descriptor Table & Flags */
+#else
+ (u32)MCD_funcDescTab0, /* Task 0 Function Descriptor Table & Flags */
+#endif
+ 0x00000000,
+ 0x00000000,
+ (u32)MCD_contextSave9, /* Task 9 context save space */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ (u32)MCD_varTab10, /* Task 10 Variable Table */
+#ifdef MCD_INCLUDE_EU
+ (u32)MCD_funcDescTab10, /* Task 10 Function Descriptor Table & Flags */
+#else
+ (u32)MCD_funcDescTab0, /* Task 0 Function Descriptor Table & Flags */
+#endif
+ 0x00000000,
+ 0x00000000,
+ (u32)MCD_contextSave10, /* Task 10 context save space */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ (u32)MCD_varTab11, /* Task 11 Variable Table */
+#ifdef MCD_INCLUDE_EU
+ (u32)MCD_funcDescTab11, /* Task 11 Function Descriptor Table & Flags */
+#else
+ (u32)MCD_funcDescTab0, /* Task 0 Function Descriptor Table & Flags */
+#endif
+ 0x00000000,
+ 0x00000000,
+ (u32)MCD_contextSave11, /* Task 11 context save space */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ (u32)MCD_varTab12, /* Task 12 Variable Table */
+#ifdef MCD_INCLUDE_EU
+ (u32)MCD_funcDescTab12, /* Task 12 Function Descriptor Table & Flags */
+#else
+ (u32)MCD_funcDescTab0, /* Task 0 Function Descriptor Table & Flags */
+#endif
+ 0x00000000,
+ 0x00000000,
+ (u32)MCD_contextSave12, /* Task 12 context save space */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ (u32)MCD_varTab13, /* Task 13 Variable Table */
+#ifdef MCD_INCLUDE_EU
+ (u32)MCD_funcDescTab13, /* Task 13 Function Descriptor Table & Flags */
+#else
+ (u32)MCD_funcDescTab0, /* Task 0 Function Descriptor Table & Flags */
+#endif
+ 0x00000000,
+ 0x00000000,
+ (u32)MCD_contextSave13, /* Task 13 context save space */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ (u32)MCD_varTab14, /* Task 14 Variable Table */
+#ifdef MCD_INCLUDE_EU
+ (u32)MCD_funcDescTab14, /* Task 14 Function Descriptor Table & Flags */
+#else
+ (u32)MCD_funcDescTab0, /* Task 0 Function Descriptor Table & Flags */
+#endif
+ 0x00000000,
+ 0x00000000,
+ (u32)MCD_contextSave14, /* Task 14 context save space */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ (u32)MCD_varTab15, /* Task 15 Variable Table */
+#ifdef MCD_INCLUDE_EU
+ (u32)MCD_funcDescTab15, /* Task 15 Function Descriptor Table & Flags */
+#else
+ (u32)MCD_funcDescTab0, /* Task 0 Function Descriptor Table & Flags */
+#endif
+ 0x00000000,
+ 0x00000000,
+ (u32)MCD_contextSave15, /* Task 15 context save space */
+ 0x00000000,
+};
+
+
+u32 MCD_varTab0[] = { /* Task 0 Variable Table */
+ 0x00000000, /* var[0] */
+ 0x00000000, /* var[1] */
+ 0x00000000, /* var[2] */
+ 0x00000000, /* var[3] */
+ 0x00000000, /* var[4] */
+ 0x00000000, /* var[5] */
+ 0x00000000, /* var[6] */
+ 0x00000000, /* var[7] */
+ 0x00000000, /* var[8] */
+ 0x00000000, /* var[9] */
+ 0x00000000, /* var[10] */
+ 0x00000000, /* var[11] */
+ 0x00000000, /* var[12] */
+ 0x00000000, /* var[13] */
+ 0x00000000, /* var[14] */
+ 0x00000000, /* var[15] */
+ 0x00000000, /* var[16] */
+ 0x00000000, /* var[17] */
+ 0x00000000, /* var[18] */
+ 0x00000000, /* var[19] */
+ 0x00000000, /* var[20] */
+ 0x00000000, /* var[21] */
+ 0x00000000, /* var[22] */
+ 0x00000000, /* var[23] */
+ 0xe0000000, /* inc[0] */
+ 0x20000000, /* inc[1] */
+ 0x2000ffff, /* inc[2] */
+ 0x00000000, /* inc[3] */
+ 0x00000000, /* inc[4] */
+ 0x00000000, /* inc[5] */
+ 0x00000000, /* inc[6] */
+ 0x00000000, /* inc[7] */
+};
+
+
+u32 MCD_varTab1[] = { /* Task 1 Variable Table */
+ 0x00000000, /* var[0] */
+ 0x00000000, /* var[1] */
+ 0x00000000, /* var[2] */
+ 0x00000000, /* var[3] */
+ 0x00000000, /* var[4] */
+ 0x00000000, /* var[5] */
+ 0x00000000, /* var[6] */
+ 0x00000000, /* var[7] */
+ 0x00000000, /* var[8] */
+ 0x00000000, /* var[9] */
+ 0x00000000, /* var[10] */
+ 0x00000000, /* var[11] */
+ 0x00000000, /* var[12] */
+ 0x00000000, /* var[13] */
+ 0x00000000, /* var[14] */
+ 0x00000000, /* var[15] */
+ 0x00000000, /* var[16] */
+ 0x00000000, /* var[17] */
+ 0x00000000, /* var[18] */
+ 0x00000000, /* var[19] */
+ 0x00000000, /* var[20] */
+ 0x00000000, /* var[21] */
+ 0x00000000, /* var[22] */
+ 0x00000000, /* var[23] */
+ 0xe0000000, /* inc[0] */
+ 0x20000000, /* inc[1] */
+ 0x2000ffff, /* inc[2] */
+ 0x00000000, /* inc[3] */
+ 0x00000000, /* inc[4] */
+ 0x00000000, /* inc[5] */
+ 0x00000000, /* inc[6] */
+ 0x00000000, /* inc[7] */
+};
+
+u32 MCD_varTab2[] = { /* Task 2 Variable Table */
+ 0x00000000, /* var[0] */
+ 0x00000000, /* var[1] */
+ 0x00000000, /* var[2] */
+ 0x00000000, /* var[3] */
+ 0x00000000, /* var[4] */
+ 0x00000000, /* var[5] */
+ 0x00000000, /* var[6] */
+ 0x00000000, /* var[7] */
+ 0x00000000, /* var[8] */
+ 0x00000000, /* var[9] */
+ 0x00000000, /* var[10] */
+ 0x00000000, /* var[11] */
+ 0x00000000, /* var[12] */
+ 0x00000000, /* var[13] */
+ 0x00000000, /* var[14] */
+ 0x00000000, /* var[15] */
+ 0x00000000, /* var[16] */
+ 0x00000000, /* var[17] */
+ 0x00000000, /* var[18] */
+ 0x00000000, /* var[19] */
+ 0x00000000, /* var[20] */
+ 0x00000000, /* var[21] */
+ 0x00000000, /* var[22] */
+ 0x00000000, /* var[23] */
+ 0xe0000000, /* inc[0] */
+ 0x20000000, /* inc[1] */
+ 0x2000ffff, /* inc[2] */
+ 0x00000000, /* inc[3] */
+ 0x00000000, /* inc[4] */
+ 0x00000000, /* inc[5] */
+ 0x00000000, /* inc[6] */
+ 0x00000000, /* inc[7] */
+};
+
+u32 MCD_varTab3[] = { /* Task 3 Variable Table */
+ 0x00000000, /* var[0] */
+ 0x00000000, /* var[1] */
+ 0x00000000, /* var[2] */
+ 0x00000000, /* var[3] */
+ 0x00000000, /* var[4] */
+ 0x00000000, /* var[5] */
+ 0x00000000, /* var[6] */
+ 0x00000000, /* var[7] */
+ 0x00000000, /* var[8] */
+ 0x00000000, /* var[9] */
+ 0x00000000, /* var[10] */
+ 0x00000000, /* var[11] */
+ 0x00000000, /* var[12] */
+ 0x00000000, /* var[13] */
+ 0x00000000, /* var[14] */
+ 0x00000000, /* var[15] */
+ 0x00000000, /* var[16] */
+ 0x00000000, /* var[17] */
+ 0x00000000, /* var[18] */
+ 0x00000000, /* var[19] */
+ 0x00000000, /* var[20] */
+ 0x00000000, /* var[21] */
+ 0x00000000, /* var[22] */
+ 0x00000000, /* var[23] */
+ 0xe0000000, /* inc[0] */
+ 0x20000000, /* inc[1] */
+ 0x2000ffff, /* inc[2] */
+ 0x00000000, /* inc[3] */
+ 0x00000000, /* inc[4] */
+ 0x00000000, /* inc[5] */
+ 0x00000000, /* inc[6] */
+ 0x00000000, /* inc[7] */
+};
+
+u32 MCD_varTab4[] = { /* Task 4 Variable Table */
+ 0x00000000, /* var[0] */
+ 0x00000000, /* var[1] */
+ 0x00000000, /* var[2] */
+ 0x00000000, /* var[3] */
+ 0x00000000, /* var[4] */
+ 0x00000000, /* var[5] */
+ 0x00000000, /* var[6] */
+ 0x00000000, /* var[7] */
+ 0x00000000, /* var[8] */
+ 0x00000000, /* var[9] */
+ 0x00000000, /* var[10] */
+ 0x00000000, /* var[11] */
+ 0x00000000, /* var[12] */
+ 0x00000000, /* var[13] */
+ 0x00000000, /* var[14] */
+ 0x00000000, /* var[15] */
+ 0x00000000, /* var[16] */
+ 0x00000000, /* var[17] */
+ 0x00000000, /* var[18] */
+ 0x00000000, /* var[19] */
+ 0x00000000, /* var[20] */
+ 0x00000000, /* var[21] */
+ 0x00000000, /* var[22] */
+ 0x00000000, /* var[23] */
+ 0xe0000000, /* inc[0] */
+ 0x20000000, /* inc[1] */
+ 0x2000ffff, /* inc[2] */
+ 0x00000000, /* inc[3] */
+ 0x00000000, /* inc[4] */
+ 0x00000000, /* inc[5] */
+ 0x00000000, /* inc[6] */
+ 0x00000000, /* inc[7] */
+};
+
+u32 MCD_varTab5[] = { /* Task 5 Variable Table */
+ 0x00000000, /* var[0] */
+ 0x00000000, /* var[1] */
+ 0x00000000, /* var[2] */
+ 0x00000000, /* var[3] */
+ 0x00000000, /* var[4] */
+ 0x00000000, /* var[5] */
+ 0x00000000, /* var[6] */
+ 0x00000000, /* var[7] */
+ 0x00000000, /* var[8] */
+ 0x00000000, /* var[9] */
+ 0x00000000, /* var[10] */
+ 0x00000000, /* var[11] */
+ 0x00000000, /* var[12] */
+ 0x00000000, /* var[13] */
+ 0x00000000, /* var[14] */
+ 0x00000000, /* var[15] */
+ 0x00000000, /* var[16] */
+ 0x00000000, /* var[17] */
+ 0x00000000, /* var[18] */
+ 0x00000000, /* var[19] */
+ 0x00000000, /* var[20] */
+ 0x00000000, /* var[21] */
+ 0x00000000, /* var[22] */
+ 0x00000000, /* var[23] */
+ 0xe0000000, /* inc[0] */
+ 0x20000000, /* inc[1] */
+ 0x2000ffff, /* inc[2] */
+ 0x00000000, /* inc[3] */
+ 0x00000000, /* inc[4] */
+ 0x00000000, /* inc[5] */
+ 0x00000000, /* inc[6] */
+ 0x00000000, /* inc[7] */
+};
+
+u32 MCD_varTab6[] = { /* Task 6 Variable Table */
+ 0x00000000, /* var[0] */
+ 0x00000000, /* var[1] */
+ 0x00000000, /* var[2] */
+ 0x00000000, /* var[3] */
+ 0x00000000, /* var[4] */
+ 0x00000000, /* var[5] */
+ 0x00000000, /* var[6] */
+ 0x00000000, /* var[7] */
+ 0x00000000, /* var[8] */
+ 0x00000000, /* var[9] */
+ 0x00000000, /* var[10] */
+ 0x00000000, /* var[11] */
+ 0x00000000, /* var[12] */
+ 0x00000000, /* var[13] */
+ 0x00000000, /* var[14] */
+ 0x00000000, /* var[15] */
+ 0x00000000, /* var[16] */
+ 0x00000000, /* var[17] */
+ 0x00000000, /* var[18] */
+ 0x00000000, /* var[19] */
+ 0x00000000, /* var[20] */
+ 0x00000000, /* var[21] */
+ 0x00000000, /* var[22] */
+ 0x00000000, /* var[23] */
+ 0xe0000000, /* inc[0] */
+ 0x20000000, /* inc[1] */
+ 0x2000ffff, /* inc[2] */
+ 0x00000000, /* inc[3] */
+ 0x00000000, /* inc[4] */
+ 0x00000000, /* inc[5] */
+ 0x00000000, /* inc[6] */
+ 0x00000000, /* inc[7] */
+};
+
+u32 MCD_varTab7[] = { /* Task 7 Variable Table */
+ 0x00000000, /* var[0] */
+ 0x00000000, /* var[1] */
+ 0x00000000, /* var[2] */
+ 0x00000000, /* var[3] */
+ 0x00000000, /* var[4] */
+ 0x00000000, /* var[5] */
+ 0x00000000, /* var[6] */
+ 0x00000000, /* var[7] */
+ 0x00000000, /* var[8] */
+ 0x00000000, /* var[9] */
+ 0x00000000, /* var[10] */
+ 0x00000000, /* var[11] */
+ 0x00000000, /* var[12] */
+ 0x00000000, /* var[13] */
+ 0x00000000, /* var[14] */
+ 0x00000000, /* var[15] */
+ 0x00000000, /* var[16] */
+ 0x00000000, /* var[17] */
+ 0x00000000, /* var[18] */
+ 0x00000000, /* var[19] */
+ 0x00000000, /* var[20] */
+ 0x00000000, /* var[21] */
+ 0x00000000, /* var[22] */
+ 0x00000000, /* var[23] */
+ 0xe0000000, /* inc[0] */
+ 0x20000000, /* inc[1] */
+ 0x2000ffff, /* inc[2] */
+ 0x00000000, /* inc[3] */
+ 0x00000000, /* inc[4] */
+ 0x00000000, /* inc[5] */
+ 0x00000000, /* inc[6] */
+ 0x00000000, /* inc[7] */
+};
+
+u32 MCD_varTab8[] = { /* Task 8 Variable Table */
+ 0x00000000, /* var[0] */
+ 0x00000000, /* var[1] */
+ 0x00000000, /* var[2] */
+ 0x00000000, /* var[3] */
+ 0x00000000, /* var[4] */
+ 0x00000000, /* var[5] */
+ 0x00000000, /* var[6] */
+ 0x00000000, /* var[7] */
+ 0x00000000, /* var[8] */
+ 0x00000000, /* var[9] */
+ 0x00000000, /* var[10] */
+ 0x00000000, /* var[11] */
+ 0x00000000, /* var[12] */
+ 0x00000000, /* var[13] */
+ 0x00000000, /* var[14] */
+ 0x00000000, /* var[15] */
+ 0x00000000, /* var[16] */
+ 0x00000000, /* var[17] */
+ 0x00000000, /* var[18] */
+ 0x00000000, /* var[19] */
+ 0x00000000, /* var[20] */
+ 0x00000000, /* var[21] */
+ 0x00000000, /* var[22] */
+ 0x00000000, /* var[23] */
+ 0xe0000000, /* inc[0] */
+ 0x20000000, /* inc[1] */
+ 0x2000ffff, /* inc[2] */
+ 0x00000000, /* inc[3] */
+ 0x00000000, /* inc[4] */
+ 0x00000000, /* inc[5] */
+ 0x00000000, /* inc[6] */
+ 0x00000000, /* inc[7] */
+};
+
+u32 MCD_varTab9[] = { /* Task 9 Variable Table */
+ 0x00000000, /* var[0] */
+ 0x00000000, /* var[1] */
+ 0x00000000, /* var[2] */
+ 0x00000000, /* var[3] */
+ 0x00000000, /* var[4] */
+ 0x00000000, /* var[5] */
+ 0x00000000, /* var[6] */
+ 0x00000000, /* var[7] */
+ 0x00000000, /* var[8] */
+ 0x00000000, /* var[9] */
+ 0x00000000, /* var[10] */
+ 0x00000000, /* var[11] */
+ 0x00000000, /* var[12] */
+ 0x00000000, /* var[13] */
+ 0x00000000, /* var[14] */
+ 0x00000000, /* var[15] */
+ 0x00000000, /* var[16] */
+ 0x00000000, /* var[17] */
+ 0x00000000, /* var[18] */
+ 0x00000000, /* var[19] */
+ 0x00000000, /* var[20] */
+ 0x00000000, /* var[21] */
+ 0x00000000, /* var[22] */
+ 0x00000000, /* var[23] */
+ 0xe0000000, /* inc[0] */
+ 0x20000000, /* inc[1] */
+ 0x2000ffff, /* inc[2] */
+ 0x00000000, /* inc[3] */
+ 0x00000000, /* inc[4] */
+ 0x00000000, /* inc[5] */
+ 0x00000000, /* inc[6] */
+ 0x00000000, /* inc[7] */
+};
+
+u32 MCD_varTab10[] = { /* Task 10 Variable Table */
+ 0x00000000, /* var[0] */
+ 0x00000000, /* var[1] */
+ 0x00000000, /* var[2] */
+ 0x00000000, /* var[3] */
+ 0x00000000, /* var[4] */
+ 0x00000000, /* var[5] */
+ 0x00000000, /* var[6] */
+ 0x00000000, /* var[7] */
+ 0x00000000, /* var[8] */
+ 0x00000000, /* var[9] */
+ 0x00000000, /* var[10] */
+ 0x00000000, /* var[11] */
+ 0x00000000, /* var[12] */
+ 0x00000000, /* var[13] */
+ 0x00000000, /* var[14] */
+ 0x00000000, /* var[15] */
+ 0x00000000, /* var[16] */
+ 0x00000000, /* var[17] */
+ 0x00000000, /* var[18] */
+ 0x00000000, /* var[19] */
+ 0x00000000, /* var[20] */
+ 0x00000000, /* var[21] */
+ 0x00000000, /* var[22] */
+ 0x00000000, /* var[23] */
+ 0xe0000000, /* inc[0] */
+ 0x20000000, /* inc[1] */
+ 0x2000ffff, /* inc[2] */
+ 0x00000000, /* inc[3] */
+ 0x00000000, /* inc[4] */
+ 0x00000000, /* inc[5] */
+ 0x00000000, /* inc[6] */
+ 0x00000000, /* inc[7] */
+};
+
+u32 MCD_varTab11[] = { /* Task 11 Variable Table */
+ 0x00000000, /* var[0] */
+ 0x00000000, /* var[1] */
+ 0x00000000, /* var[2] */
+ 0x00000000, /* var[3] */
+ 0x00000000, /* var[4] */
+ 0x00000000, /* var[5] */
+ 0x00000000, /* var[6] */
+ 0x00000000, /* var[7] */
+ 0x00000000, /* var[8] */
+ 0x00000000, /* var[9] */
+ 0x00000000, /* var[10] */
+ 0x00000000, /* var[11] */
+ 0x00000000, /* var[12] */
+ 0x00000000, /* var[13] */
+ 0x00000000, /* var[14] */
+ 0x00000000, /* var[15] */
+ 0x00000000, /* var[16] */
+ 0x00000000, /* var[17] */
+ 0x00000000, /* var[18] */
+ 0x00000000, /* var[19] */
+ 0x00000000, /* var[20] */
+ 0x00000000, /* var[21] */
+ 0x00000000, /* var[22] */
+ 0x00000000, /* var[23] */
+ 0xe0000000, /* inc[0] */
+ 0x20000000, /* inc[1] */
+ 0x2000ffff, /* inc[2] */
+ 0x00000000, /* inc[3] */
+ 0x00000000, /* inc[4] */
+ 0x00000000, /* inc[5] */
+ 0x00000000, /* inc[6] */
+ 0x00000000, /* inc[7] */
+};
+
+u32 MCD_varTab12[] = { /* Task 12 Variable Table */
+ 0x00000000, /* var[0] */
+ 0x00000000, /* var[1] */
+ 0x00000000, /* var[2] */
+ 0x00000000, /* var[3] */
+ 0x00000000, /* var[4] */
+ 0x00000000, /* var[5] */
+ 0x00000000, /* var[6] */
+ 0x00000000, /* var[7] */
+ 0x00000000, /* var[8] */
+ 0x00000000, /* var[9] */
+ 0x00000000, /* var[10] */
+ 0x00000000, /* var[11] */
+ 0x00000000, /* var[12] */
+ 0x00000000, /* var[13] */
+ 0x00000000, /* var[14] */
+ 0x00000000, /* var[15] */
+ 0x00000000, /* var[16] */
+ 0x00000000, /* var[17] */
+ 0x00000000, /* var[18] */
+ 0x00000000, /* var[19] */
+ 0x00000000, /* var[20] */
+ 0x00000000, /* var[21] */
+ 0x00000000, /* var[22] */
+ 0x00000000, /* var[23] */
+ 0xe0000000, /* inc[0] */
+ 0x20000000, /* inc[1] */
+ 0x2000ffff, /* inc[2] */
+ 0x00000000, /* inc[3] */
+ 0x00000000, /* inc[4] */
+ 0x00000000, /* inc[5] */
+ 0x00000000, /* inc[6] */
+ 0x00000000, /* inc[7] */
+};
+
+u32 MCD_varTab13[] = { /* Task 13 Variable Table */
+ 0x00000000, /* var[0] */
+ 0x00000000, /* var[1] */
+ 0x00000000, /* var[2] */
+ 0x00000000, /* var[3] */
+ 0x00000000, /* var[4] */
+ 0x00000000, /* var[5] */
+ 0x00000000, /* var[6] */
+ 0x00000000, /* var[7] */
+ 0x00000000, /* var[8] */
+ 0x00000000, /* var[9] */
+ 0x00000000, /* var[10] */
+ 0x00000000, /* var[11] */
+ 0x00000000, /* var[12] */
+ 0x00000000, /* var[13] */
+ 0x00000000, /* var[14] */
+ 0x00000000, /* var[15] */
+ 0x00000000, /* var[16] */
+ 0x00000000, /* var[17] */
+ 0x00000000, /* var[18] */
+ 0x00000000, /* var[19] */
+ 0x00000000, /* var[20] */
+ 0x00000000, /* var[21] */
+ 0x00000000, /* var[22] */
+ 0x00000000, /* var[23] */
+ 0xe0000000, /* inc[0] */
+ 0x20000000, /* inc[1] */
+ 0x2000ffff, /* inc[2] */
+ 0x00000000, /* inc[3] */
+ 0x00000000, /* inc[4] */
+ 0x00000000, /* inc[5] */
+ 0x00000000, /* inc[6] */
+ 0x00000000, /* inc[7] */
+};
+
+u32 MCD_varTab14[] = { /* Task 14 Variable Table */
+ 0x00000000, /* var[0] */
+ 0x00000000, /* var[1] */
+ 0x00000000, /* var[2] */
+ 0x00000000, /* var[3] */
+ 0x00000000, /* var[4] */
+ 0x00000000, /* var[5] */
+ 0x00000000, /* var[6] */
+ 0x00000000, /* var[7] */
+ 0x00000000, /* var[8] */
+ 0x00000000, /* var[9] */
+ 0x00000000, /* var[10] */
+ 0x00000000, /* var[11] */
+ 0x00000000, /* var[12] */
+ 0x00000000, /* var[13] */
+ 0x00000000, /* var[14] */
+ 0x00000000, /* var[15] */
+ 0x00000000, /* var[16] */
+ 0x00000000, /* var[17] */
+ 0x00000000, /* var[18] */
+ 0x00000000, /* var[19] */
+ 0x00000000, /* var[20] */
+ 0x00000000, /* var[21] */
+ 0x00000000, /* var[22] */
+ 0x00000000, /* var[23] */
+ 0xe0000000, /* inc[0] */
+ 0x20000000, /* inc[1] */
+ 0x2000ffff, /* inc[2] */
+ 0x00000000, /* inc[3] */
+ 0x00000000, /* inc[4] */
+ 0x00000000, /* inc[5] */
+ 0x00000000, /* inc[6] */
+ 0x00000000, /* inc[7] */
+};
+
+u32 MCD_varTab15[] = { /* Task 15 Variable Table */
+ 0x00000000, /* var[0] */
+ 0x00000000, /* var[1] */
+ 0x00000000, /* var[2] */
+ 0x00000000, /* var[3] */
+ 0x00000000, /* var[4] */
+ 0x00000000, /* var[5] */
+ 0x00000000, /* var[6] */
+ 0x00000000, /* var[7] */
+ 0x00000000, /* var[8] */
+ 0x00000000, /* var[9] */
+ 0x00000000, /* var[10] */
+ 0x00000000, /* var[11] */
+ 0x00000000, /* var[12] */
+ 0x00000000, /* var[13] */
+ 0x00000000, /* var[14] */
+ 0x00000000, /* var[15] */
+ 0x00000000, /* var[16] */
+ 0x00000000, /* var[17] */
+ 0x00000000, /* var[18] */
+ 0x00000000, /* var[19] */
+ 0x00000000, /* var[20] */
+ 0x00000000, /* var[21] */
+ 0x00000000, /* var[22] */
+ 0x00000000, /* var[23] */
+ 0xe0000000, /* inc[0] */
+ 0x20000000, /* inc[1] */
+ 0x2000ffff, /* inc[2] */
+ 0x00000000, /* inc[3] */
+ 0x00000000, /* inc[4] */
+ 0x00000000, /* inc[5] */
+ 0x00000000, /* inc[6] */
+ 0x00000000, /* inc[7] */
+};
+
+u32 MCD_funcDescTab0[] = { /* Task 0 Function Descriptor Table */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0xa0045670, /* mainFunc(), EU# 3 */
+ 0xa0000000, /* rsduFunc(), EU# 3 */
+ 0xa0000000, /* crcAccumVal(), EU# 3 */
+ 0x20000000, /* setCrcAccum(), EU# 3 */
+ 0x21800000, /* and(), EU# 3 */
+ 0x21e00000, /* or(), EU# 3 */
+ 0x20400000, /* add(), EU# 3 */
+ 0x20500000, /* sub(), EU# 3 */
+ 0x205a0000, /* andNot(), EU# 3 */
+ 0x20a00000, /* shiftR(), EU# 3 */
+ 0x202fa000, /* andReadyBit(), EU# 3 */
+ 0x202f9000, /* andNotReadyBit(), EU# 3 */
+ 0x202ea000, /* andWrapBit(), EU# 3 */
+ 0x202da000, /* andLastBit(), EU# 3 */
+ 0x202e2000, /* andInterruptBit(), EU# 3 */
+ 0x202f2000, /* andCrcRestartBit(), EU# 3 */
+};
+
+#ifdef MCD_INCLUDE_EU
+u32 MCD_funcDescTab1[] = { /* Task 1 Function Descriptor Table */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0xa0045670, /* mainFunc(), EU# 3 */
+ 0xa0000000, /* rsduFunc(), EU# 3 */
+ 0xa0000000, /* crcAccumVal(), EU# 3 */
+ 0x20000000, /* setCrcAccum(), EU# 3 */
+ 0x21800000, /* and(), EU# 3 */
+ 0x21e00000, /* or(), EU# 3 */
+ 0x20400000, /* add(), EU# 3 */
+ 0x20500000, /* sub(), EU# 3 */
+ 0x205a0000, /* andNot(), EU# 3 */
+ 0x20a00000, /* shiftR(), EU# 3 */
+ 0x202fa000, /* andReadyBit(), EU# 3 */
+ 0x202f9000, /* andNotReadyBit(), EU# 3 */
+ 0x202ea000, /* andWrapBit(), EU# 3 */
+ 0x202da000, /* andLastBit(), EU# 3 */
+ 0x202e2000, /* andInterruptBit(), EU# 3 */
+ 0x202f2000, /* andCrcRestartBit(), EU# 3 */
+};
+
+u32 MCD_funcDescTab2[] = { /* Task 2 Function Descriptor Table */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0xa0045670, /* mainFunc(), EU# 3 */
+ 0xa0000000, /* rsduFunc(), EU# 3 */
+ 0xa0000000, /* crcAccumVal(), EU# 3 */
+ 0x20000000, /* setCrcAccum(), EU# 3 */
+ 0x21800000, /* and(), EU# 3 */
+ 0x21e00000, /* or(), EU# 3 */
+ 0x20400000, /* add(), EU# 3 */
+ 0x20500000, /* sub(), EU# 3 */
+ 0x205a0000, /* andNot(), EU# 3 */
+ 0x20a00000, /* shiftR(), EU# 3 */
+ 0x202fa000, /* andReadyBit(), EU# 3 */
+ 0x202f9000, /* andNotReadyBit(), EU# 3 */
+ 0x202ea000, /* andWrapBit(), EU# 3 */
+ 0x202da000, /* andLastBit(), EU# 3 */
+ 0x202e2000, /* andInterruptBit(), EU# 3 */
+ 0x202f2000, /* andCrcRestartBit(), EU# 3 */
+};
+
+u32 MCD_funcDescTab3[] = { /* Task 3 Function Descriptor Table */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0xa0045670, /* mainFunc(), EU# 3 */
+ 0xa0000000, /* rsduFunc(), EU# 3 */
+ 0xa0000000, /* crcAccumVal(), EU# 3 */
+ 0x20000000, /* setCrcAccum(), EU# 3 */
+ 0x21800000, /* and(), EU# 3 */
+ 0x21e00000, /* or(), EU# 3 */
+ 0x20400000, /* add(), EU# 3 */
+ 0x20500000, /* sub(), EU# 3 */
+ 0x205a0000, /* andNot(), EU# 3 */
+ 0x20a00000, /* shiftR(), EU# 3 */
+ 0x202fa000, /* andReadyBit(), EU# 3 */
+ 0x202f9000, /* andNotReadyBit(), EU# 3 */
+ 0x202ea000, /* andWrapBit(), EU# 3 */
+ 0x202da000, /* andLastBit(), EU# 3 */
+ 0x202e2000, /* andInterruptBit(), EU# 3 */
+ 0x202f2000, /* andCrcRestartBit(), EU# 3 */
+};
+
+u32 MCD_funcDescTab4[] = { /* Task 4 Function Descriptor Table */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0xa0045670, /* mainFunc(), EU# 3 */
+ 0xa0000000, /* rsduFunc(), EU# 3 */
+ 0xa0000000, /* crcAccumVal(), EU# 3 */
+ 0x20000000, /* setCrcAccum(), EU# 3 */
+ 0x21800000, /* and(), EU# 3 */
+ 0x21e00000, /* or(), EU# 3 */
+ 0x20400000, /* add(), EU# 3 */
+ 0x20500000, /* sub(), EU# 3 */
+ 0x205a0000, /* andNot(), EU# 3 */
+ 0x20a00000, /* shiftR(), EU# 3 */
+ 0x202fa000, /* andReadyBit(), EU# 3 */
+ 0x202f9000, /* andNotReadyBit(), EU# 3 */
+ 0x202ea000, /* andWrapBit(), EU# 3 */
+ 0x202da000, /* andLastBit(), EU# 3 */
+ 0x202e2000, /* andInterruptBit(), EU# 3 */
+ 0x202f2000, /* andCrcRestartBit(), EU# 3 */
+};
+
+u32 MCD_funcDescTab5[] = { /* Task 5 Function Descriptor Table */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0xa0045670, /* mainFunc(), EU# 3 */
+ 0xa0000000, /* rsduFunc(), EU# 3 */
+ 0xa0000000, /* crcAccumVal(), EU# 3 */
+ 0x20000000, /* setCrcAccum(), EU# 3 */
+ 0x21800000, /* and(), EU# 3 */
+ 0x21e00000, /* or(), EU# 3 */
+ 0x20400000, /* add(), EU# 3 */
+ 0x20500000, /* sub(), EU# 3 */
+ 0x205a0000, /* andNot(), EU# 3 */
+ 0x20a00000, /* shiftR(), EU# 3 */
+ 0x202fa000, /* andReadyBit(), EU# 3 */
+ 0x202f9000, /* andNotReadyBit(), EU# 3 */
+ 0x202ea000, /* andWrapBit(), EU# 3 */
+ 0x202da000, /* andLastBit(), EU# 3 */
+ 0x202e2000, /* andInterruptBit(), EU# 3 */
+ 0x202f2000, /* andCrcRestartBit(), EU# 3 */
+};
+
+u32 MCD_funcDescTab6[] = { /* Task 6 Function Descriptor Table */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0xa0045670, /* mainFunc(), EU# 3 */
+ 0xa0000000, /* rsduFunc(), EU# 3 */
+ 0xa0000000, /* crcAccumVal(), EU# 3 */
+ 0x20000000, /* setCrcAccum(), EU# 3 */
+ 0x21800000, /* and(), EU# 3 */
+ 0x21e00000, /* or(), EU# 3 */
+ 0x20400000, /* add(), EU# 3 */
+ 0x20500000, /* sub(), EU# 3 */
+ 0x205a0000, /* andNot(), EU# 3 */
+ 0x20a00000, /* shiftR(), EU# 3 */
+ 0x202fa000, /* andReadyBit(), EU# 3 */
+ 0x202f9000, /* andNotReadyBit(), EU# 3 */
+ 0x202ea000, /* andWrapBit(), EU# 3 */
+ 0x202da000, /* andLastBit(), EU# 3 */
+ 0x202e2000, /* andInterruptBit(), EU# 3 */
+ 0x202f2000, /* andCrcRestartBit(), EU# 3 */
+};
+
+u32 MCD_funcDescTab7[] = { /* Task 7 Function Descriptor Table */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0xa0045670, /* mainFunc(), EU# 3 */
+ 0xa0000000, /* rsduFunc(), EU# 3 */
+ 0xa0000000, /* crcAccumVal(), EU# 3 */
+ 0x20000000, /* setCrcAccum(), EU# 3 */
+ 0x21800000, /* and(), EU# 3 */
+ 0x21e00000, /* or(), EU# 3 */
+ 0x20400000, /* add(), EU# 3 */
+ 0x20500000, /* sub(), EU# 3 */
+ 0x205a0000, /* andNot(), EU# 3 */
+ 0x20a00000, /* shiftR(), EU# 3 */
+ 0x202fa000, /* andReadyBit(), EU# 3 */
+ 0x202f9000, /* andNotReadyBit(), EU# 3 */
+ 0x202ea000, /* andWrapBit(), EU# 3 */
+ 0x202da000, /* andLastBit(), EU# 3 */
+ 0x202e2000, /* andInterruptBit(), EU# 3 */
+ 0x202f2000, /* andCrcRestartBit(), EU# 3 */
+};
+
+u32 MCD_funcDescTab8[] = { /* Task 8 Function Descriptor Table */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0xa0045670, /* mainFunc(), EU# 3 */
+ 0xa0000000, /* rsduFunc(), EU# 3 */
+ 0xa0000000, /* crcAccumVal(), EU# 3 */
+ 0x20000000, /* setCrcAccum(), EU# 3 */
+ 0x21800000, /* and(), EU# 3 */
+ 0x21e00000, /* or(), EU# 3 */
+ 0x20400000, /* add(), EU# 3 */
+ 0x20500000, /* sub(), EU# 3 */
+ 0x205a0000, /* andNot(), EU# 3 */
+ 0x20a00000, /* shiftR(), EU# 3 */
+ 0x202fa000, /* andReadyBit(), EU# 3 */
+ 0x202f9000, /* andNotReadyBit(), EU# 3 */
+ 0x202ea000, /* andWrapBit(), EU# 3 */
+ 0x202da000, /* andLastBit(), EU# 3 */
+ 0x202e2000, /* andInterruptBit(), EU# 3 */
+ 0x202f2000, /* andCrcRestartBit(), EU# 3 */
+};
+
+u32 MCD_funcDescTab9[] = { /* Task 9 Function Descriptor Table */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0xa0045670, /* mainFunc(), EU# 3 */
+ 0xa0000000, /* rsduFunc(), EU# 3 */
+ 0xa0000000, /* crcAccumVal(), EU# 3 */
+ 0x20000000, /* setCrcAccum(), EU# 3 */
+ 0x21800000, /* and(), EU# 3 */
+ 0x21e00000, /* or(), EU# 3 */
+ 0x20400000, /* add(), EU# 3 */
+ 0x20500000, /* sub(), EU# 3 */
+ 0x205a0000, /* andNot(), EU# 3 */
+ 0x20a00000, /* shiftR(), EU# 3 */
+ 0x202fa000, /* andReadyBit(), EU# 3 */
+ 0x202f9000, /* andNotReadyBit(), EU# 3 */
+ 0x202ea000, /* andWrapBit(), EU# 3 */
+ 0x202da000, /* andLastBit(), EU# 3 */
+ 0x202e2000, /* andInterruptBit(), EU# 3 */
+ 0x202f2000, /* andCrcRestartBit(), EU# 3 */
+};
+
+u32 MCD_funcDescTab10[] = { /* Task 10 Function Descriptor Table */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0xa0045670, /* mainFunc(), EU# 3 */
+ 0xa0000000, /* rsduFunc(), EU# 3 */
+ 0xa0000000, /* crcAccumVal(), EU# 3 */
+ 0x20000000, /* setCrcAccum(), EU# 3 */
+ 0x21800000, /* and(), EU# 3 */
+ 0x21e00000, /* or(), EU# 3 */
+ 0x20400000, /* add(), EU# 3 */
+ 0x20500000, /* sub(), EU# 3 */
+ 0x205a0000, /* andNot(), EU# 3 */
+ 0x20a00000, /* shiftR(), EU# 3 */
+ 0x202fa000, /* andReadyBit(), EU# 3 */
+ 0x202f9000, /* andNotReadyBit(), EU# 3 */
+ 0x202ea000, /* andWrapBit(), EU# 3 */
+ 0x202da000, /* andLastBit(), EU# 3 */
+ 0x202e2000, /* andInterruptBit(), EU# 3 */
+ 0x202f2000, /* andCrcRestartBit(), EU# 3 */
+};
+
+u32 MCD_funcDescTab11[] = { /* Task 11 Function Descriptor Table */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0xa0045670, /* mainFunc(), EU# 3 */
+ 0xa0000000, /* rsduFunc(), EU# 3 */
+ 0xa0000000, /* crcAccumVal(), EU# 3 */
+ 0x20000000, /* setCrcAccum(), EU# 3 */
+ 0x21800000, /* and(), EU# 3 */
+ 0x21e00000, /* or(), EU# 3 */
+ 0x20400000, /* add(), EU# 3 */
+ 0x20500000, /* sub(), EU# 3 */
+ 0x205a0000, /* andNot(), EU# 3 */
+ 0x20a00000, /* shiftR(), EU# 3 */
+ 0x202fa000, /* andReadyBit(), EU# 3 */
+ 0x202f9000, /* andNotReadyBit(), EU# 3 */
+ 0x202ea000, /* andWrapBit(), EU# 3 */
+ 0x202da000, /* andLastBit(), EU# 3 */
+ 0x202e2000, /* andInterruptBit(), EU# 3 */
+ 0x202f2000, /* andCrcRestartBit(), EU# 3 */
+};
+
+u32 MCD_funcDescTab12[] = { /* Task 12 Function Descriptor Table */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0xa0045670, /* mainFunc(), EU# 3 */
+ 0xa0000000, /* rsduFunc(), EU# 3 */
+ 0xa0000000, /* crcAccumVal(), EU# 3 */
+ 0x20000000, /* setCrcAccum(), EU# 3 */
+ 0x21800000, /* and(), EU# 3 */
+ 0x21e00000, /* or(), EU# 3 */
+ 0x20400000, /* add(), EU# 3 */
+ 0x20500000, /* sub(), EU# 3 */
+ 0x205a0000, /* andNot(), EU# 3 */
+ 0x20a00000, /* shiftR(), EU# 3 */
+ 0x202fa000, /* andReadyBit(), EU# 3 */
+ 0x202f9000, /* andNotReadyBit(), EU# 3 */
+ 0x202ea000, /* andWrapBit(), EU# 3 */
+ 0x202da000, /* andLastBit(), EU# 3 */
+ 0x202e2000, /* andInterruptBit(), EU# 3 */
+ 0x202f2000, /* andCrcRestartBit(), EU# 3 */
+};
+
+u32 MCD_funcDescTab13[] = { /* Task 13 Function Descriptor Table */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0xa0045670, /* mainFunc(), EU# 3 */
+ 0xa0000000, /* rsduFunc(), EU# 3 */
+ 0xa0000000, /* crcAccumVal(), EU# 3 */
+ 0x20000000, /* setCrcAccum(), EU# 3 */
+ 0x21800000, /* and(), EU# 3 */
+ 0x21e00000, /* or(), EU# 3 */
+ 0x20400000, /* add(), EU# 3 */
+ 0x20500000, /* sub(), EU# 3 */
+ 0x205a0000, /* andNot(), EU# 3 */
+ 0x20a00000, /* shiftR(), EU# 3 */
+ 0x202fa000, /* andReadyBit(), EU# 3 */
+ 0x202f9000, /* andNotReadyBit(), EU# 3 */
+ 0x202ea000, /* andWrapBit(), EU# 3 */
+ 0x202da000, /* andLastBit(), EU# 3 */
+ 0x202e2000, /* andInterruptBit(), EU# 3 */
+ 0x202f2000, /* andCrcRestartBit(), EU# 3 */
+};
+
+u32 MCD_funcDescTab14[] = { /* Task 14 Function Descriptor Table */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0xa0045670, /* mainFunc(), EU# 3 */
+ 0xa0000000, /* rsduFunc(), EU# 3 */
+ 0xa0000000, /* crcAccumVal(), EU# 3 */
+ 0x20000000, /* setCrcAccum(), EU# 3 */
+ 0x21800000, /* and(), EU# 3 */
+ 0x21e00000, /* or(), EU# 3 */
+ 0x20400000, /* add(), EU# 3 */
+ 0x20500000, /* sub(), EU# 3 */
+ 0x205a0000, /* andNot(), EU# 3 */
+ 0x20a00000, /* shiftR(), EU# 3 */
+ 0x202fa000, /* andReadyBit(), EU# 3 */
+ 0x202f9000, /* andNotReadyBit(), EU# 3 */
+ 0x202ea000, /* andWrapBit(), EU# 3 */
+ 0x202da000, /* andLastBit(), EU# 3 */
+ 0x202e2000, /* andInterruptBit(), EU# 3 */
+ 0x202f2000, /* andCrcRestartBit(), EU# 3 */
+};
+
+u32 MCD_funcDescTab15[] = { /* Task 15 Function Descriptor Table */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0xa0045670, /* mainFunc(), EU# 3 */
+ 0xa0000000, /* rsduFunc(), EU# 3 */
+ 0xa0000000, /* crcAccumVal(), EU# 3 */
+ 0x20000000, /* setCrcAccum(), EU# 3 */
+ 0x21800000, /* and(), EU# 3 */
+ 0x21e00000, /* or(), EU# 3 */
+ 0x20400000, /* add(), EU# 3 */
+ 0x20500000, /* sub(), EU# 3 */
+ 0x205a0000, /* andNot(), EU# 3 */
+ 0x20a00000, /* shiftR(), EU# 3 */
+ 0x202fa000, /* andReadyBit(), EU# 3 */
+ 0x202f9000, /* andNotReadyBit(), EU# 3 */
+ 0x202ea000, /* andWrapBit(), EU# 3 */
+ 0x202da000, /* andLastBit(), EU# 3 */
+ 0x202e2000, /* andInterruptBit(), EU# 3 */
+ 0x202f2000, /* andCrcRestartBit(), EU# 3 */
+};
+#endif /*MCD_INCLUDE_EU*/
+
+u32 MCD_contextSave0[128]; /* Task 0 context save space */
+u32 MCD_contextSave1[128]; /* Task 1 context save space */
+u32 MCD_contextSave2[128]; /* Task 2 context save space */
+u32 MCD_contextSave3[128]; /* Task 3 context save space */
+u32 MCD_contextSave4[128]; /* Task 4 context save space */
+u32 MCD_contextSave5[128]; /* Task 5 context save space */
+u32 MCD_contextSave6[128]; /* Task 6 context save space */
+u32 MCD_contextSave7[128]; /* Task 7 context save space */
+u32 MCD_contextSave8[128]; /* Task 8 context save space */
+u32 MCD_contextSave9[128]; /* Task 9 context save space */
+u32 MCD_contextSave10[128]; /* Task 10 context save space */
+u32 MCD_contextSave11[128]; /* Task 11 context save space */
+u32 MCD_contextSave12[128]; /* Task 12 context save space */
+u32 MCD_contextSave13[128]; /* Task 13 context save space */
+u32 MCD_contextSave14[128]; /* Task 14 context save space */
+u32 MCD_contextSave15[128]; /* Task 15 context save space */
+
+u32 MCD_ChainNoEu_TDT[];
+u32 MCD_SingleNoEu_TDT[];
+#ifdef MCD_INCLUDE_EU
+u32 MCD_ChainEu_TDT[];
+u32 MCD_SingleEu_TDT[];
+#endif
+u32 MCD_ENetRcv_TDT[];
+u32 MCD_ENetXmit_TDT[];
+
+const u32 MCD_modelTaskTableSrc[] = {
+ (u32)MCD_ChainNoEu_TDT,
+ (u32)&((u8 *)MCD_ChainNoEu_TDT)[0x0000016c],
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ (u32)MCD_SingleNoEu_TDT,
+ (u32)&((u8 *)MCD_SingleNoEu_TDT)[0x000000d4],
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+#ifdef MCD_INCLUDE_EU
+ (u32)MCD_ChainEu_TDT,
+ (u32)&((u8 *)MCD_ChainEu_TDT)[0x000001b4],
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ (u32)MCD_SingleEu_TDT,
+ (u32)&((u8 *)MCD_SingleEu_TDT)[0x00000124],
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+#endif
+ (u32)MCD_ENetRcv_TDT,
+ (u32)&((u8 *)MCD_ENetRcv_TDT)[0x000000a4],
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ (u32)MCD_ENetXmit_TDT,
+ (u32)&((u8 *)MCD_ENetXmit_TDT)[0x000000d0],
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
+u32 MCD_ChainNoEu_TDT[] = {
+ 0x80004000, /* 0000(:370): LCDEXT: idx0 = 0x00000000; ; */
+ 0x8118801b, /* 0004(:370): LCD: idx1 = var2; idx1 once var0; idx1 += inc3 */
+ 0xb8c60018, /* 0008(:371): LCD: idx2 = *(idx1 + var12); idx2 once var0; idx2 += inc3 */
+ 0x10002b10, /* 000C(:372): DRD1A: var10 = idx2; FN=0 MORE init=0 WS=0 RS=0 */
+ 0x7000000d, /* 0010(:373): DRD2A: EU0=0 EU1=0 EU2=0 EU3=13 EXT MORE init=0 WS=0 RS=0 */
+ 0x018cf89f, /* 0014(:373): DRD2B1: var6 = EU3(); EU3(idx2) */
+ 0x6000000a, /* 0018(:374): DRD2A: EU0=0 EU1=0 EU2=0 EU3=10 EXT init=0 WS=0 RS=0 */
+ 0x080cf89f, /* 001C(:374): DRD2B1: idx0 = EU3(); EU3(idx2) */
+ 0x000001f8, /* 0020(:0): NOP */
+ 0x98180364, /* 0024(:378): LCD: idx0 = idx0; idx0 == var13; idx0 += inc4 */
+ 0x8118801b, /* 0028(:380): LCD: idx1 = var2; idx1 once var0; idx1 += inc3 */
+ 0xf8c6001a, /* 002C(:381): LCDEXT: idx2 = *(idx1 + var12 + 8); idx2 once var0; idx2 += inc3 */
+ 0xb8c6601b, /* 0030(:382): LCD: idx3 = *(idx1 + var12 + 12); ; idx3 += inc3 */
+ 0x10002710, /* 0034(:384): DRD1A: var9 = idx2; FN=0 MORE init=0 WS=0 RS=0 */
+ 0x00000f18, /* 0038(:385): DRD1A: var3 = idx3; FN=0 init=0 WS=0 RS=0 */
+ 0xb8c6001d, /* 003C(:387): LCD: idx2 = *(idx1 + var12 + 20); idx2 once var0; idx2 += inc3 */
+ 0x10001310, /* 0040(:388): DRD1A: var4 = idx2; FN=0 MORE init=0 WS=0 RS=0 */
+ 0x60000007, /* 0044(:389): DRD2A: EU0=0 EU1=0 EU2=0 EU3=7 EXT init=0 WS=0 RS=0 */
+ 0x014cf88b, /* 0048(:389): DRD2B1: var5 = EU3(); EU3(idx2,var11) */
+ 0x98c6001c, /* 004C(:391): LCD: idx2 = idx1 + var12 + 4; idx2 once var0; idx2 += inc3 */
+ 0x00000710, /* 0050(:392): DRD1A: var1 = idx2; FN=0 init=0 WS=0 RS=0 */
+ 0x98c70018, /* 0054(:393): LCD: idx2 = idx1 + var14; idx2 once var0; idx2 += inc3 */
+ 0x10001f10, /* 0058(:394): DRD1A: var7 = idx2; FN=0 MORE init=0 WS=0 RS=0 */
+ 0x0000c818, /* 005C(:395): DRD1A: *idx2 = var3; FN=0 init=0 WS=0 RS=0 */
+ 0x000001f8, /* 0060(:0): NOP */
+ 0xc1476018, /* 0064(:399): LCDEXT: idx1 = var2 + var14; ; idx1 += inc3 */
+ 0xc003231d, /* 0068(:399): LCDEXT: idx2 = var0, idx3 = var6; idx3 == var12; idx2 += inc3, idx3 += inc5 */
+ 0x811a601b, /* 006C(:400): LCD: idx4 = var2; ; idx4 += inc3 */
+ 0xc1862102, /* 0070(:403): LCDEXT: idx5 = var3, idx6 = var12; idx6 < var4; idx5 += inc0, idx6 += inc2 */
+ 0x849be009, /* 0074(:403): LCD: idx7 = var9; ; idx7 += inc1 */
+ 0x03fed7b8, /* 0078(:406): DRD1A: *idx7; FN=0 init=31 WS=3 RS=3 */
+ 0xda9b001b, /* 007C(:408): LCDEXT: idx5 = idx5, idx6 = idx6; idx5 once var0; idx5 += inc3, idx6 += inc3 */
+ 0x9b9be01b, /* 0080(:408): LCD: idx7 = idx7; ; idx7 += inc3 */
+ 0x1000cb20, /* 0084(:409): DRD1A: *idx2 = idx4; FN=0 MORE init=0 WS=0 RS=0 */
+ 0x70000006, /* 0088(:410): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */
+ 0x088cf88f, /* 008C(:410): DRD2B1: idx2 = EU3(); EU3(idx2,var15) */
+ 0x1000cb28, /* 0090(:411): DRD1A: *idx2 = idx5; FN=0 MORE init=0 WS=0 RS=0 */
+ 0x70000006, /* 0094(:412): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */
+ 0x088cf88f, /* 0098(:412): DRD2B1: idx2 = EU3(); EU3(idx2,var15) */
+ 0x1000cb30, /* 009C(:413): DRD1A: *idx2 = idx6; FN=0 MORE init=0 WS=0 RS=0 */
+ 0x70000006, /* 00A0(:414): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */
+ 0x088cf88f, /* 00A4(:414): DRD2B1: idx2 = EU3(); EU3(idx2,var15) */
+ 0x1000cb38, /* 00A8(:415): DRD1A: *idx2 = idx7; FN=0 MORE init=0 WS=0 RS=0 */
+ 0x0000c728, /* 00AC(:416): DRD1A: *idx1 = idx5; FN=0 init=0 WS=0 RS=0 */
+ 0x000001f8, /* 00B0(:0): NOP */
+ 0xc1476018, /* 00B4(:420): LCDEXT: idx1 = var2 + var14; ; idx1 += inc3 */
+ 0xc003241d, /* 00B8(:420): LCDEXT: idx2 = var0, idx3 = var6; idx3 == var16; idx2 += inc3, idx3 += inc5 */
+ 0x811a601b, /* 00BC(:421): LCD: idx4 = var2; ; idx4 += inc3 */
+ 0xda9b001b, /* 00C0(:424): LCDEXT: idx5 = idx5, idx6 = idx6; idx5 once var0; idx5 += inc3, idx6 += inc3 */
+ 0x9b9be01b, /* 00C4(:424): LCD: idx7 = idx7; ; idx7 += inc3 */
+ 0x0000d3a0, /* 00C8(:425): DRD1A: *idx4; FN=0 init=0 WS=0 RS=0 */
+ 0xc1862102, /* 00CC(:427): LCDEXT: idx5 = var3, idx6 = var12; idx6 < var4; idx5 += inc0, idx6 += inc2 */
+ 0x849be009, /* 00D0(:427): LCD: idx7 = var9; ; idx7 += inc1 */
+ 0x0bfed7b8, /* 00D4(:430): DRD1A: *idx7; FN=0 TFD init=31 WS=3 RS=3 */
+ 0xda9b001b, /* 00D8(:432): LCDEXT: idx5 = idx5, idx6 = idx6; idx5 once var0; idx5 += inc3, idx6 += inc3 */
+ 0x9b9be01b, /* 00DC(:432): LCD: idx7 = idx7; ; idx7 += inc3 */
+ 0x1000cb20, /* 00E0(:433): DRD1A: *idx2 = idx4; FN=0 MORE init=0 WS=0 RS=0 */
+ 0x70000006, /* 00E4(:434): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */
+ 0x088cf88f, /* 00E8(:434): DRD2B1: idx2 = EU3(); EU3(idx2,var15) */
+ 0x1000cb28, /* 00EC(:435): DRD1A: *idx2 = idx5; FN=0 MORE init=0 WS=0 RS=0 */
+ 0x70000006, /* 00F0(:436): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */
+ 0x088cf88f, /* 00F4(:436): DRD2B1: idx2 = EU3(); EU3(idx2,var15) */
+ 0x1000cb30, /* 00F8(:437): DRD1A: *idx2 = idx6; FN=0 MORE init=0 WS=0 RS=0 */
+ 0x70000006, /* 00FC(:438): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */
+ 0x088cf88f, /* 0100(:438): DRD2B1: idx2 = EU3(); EU3(idx2,var15) */
+ 0x1000cb38, /* 0104(:439): DRD1A: *idx2 = idx7; FN=0 MORE init=0 WS=0 RS=0 */
+ 0x0000c728, /* 0108(:440): DRD1A: *idx1 = idx5; FN=0 init=0 WS=0 RS=0 */
+ 0x000001f8, /* 010C(:0): NOP */
+ 0x8118801b, /* 0110(:444): LCD: idx1 = var2; idx1 once var0; idx1 += inc3 */
+ 0xd8c60018, /* 0114(:446): LCDEXT: idx2 = idx1 + var12; idx2 once var0; idx2 += inc3 */
+ 0x98c6601c, /* 0118(:446): LCD: idx3 = idx1 + var12 + 4; ; idx3 += inc3 */
+ 0x6000000b, /* 011C(:447): DRD2A: EU0=0 EU1=0 EU2=0 EU3=11 EXT init=0 WS=0 RS=0 */
+ 0x0c8cfc9f, /* 0120(:447): DRD2B1: *idx2 = EU3(); EU3(*idx2) */
+ 0x000001f8, /* 0124(:0): NOP */
+ 0xa146001e, /* 0128(:450): LCD: idx1 = *(var2 + var12 + 24); idx1 once var0; idx1 += inc3 */
+ 0x10000b08, /* 012C(:451): DRD1A: var2 = idx1; FN=0 MORE init=0 WS=0 RS=0 */
+ 0x10002050, /* 0130(:452): DRD1A: var8 = var10; FN=0 MORE init=0 WS=0 RS=0 */
+ 0xb8c60018, /* 0134(:453): LCD: idx2 = *(idx1 + var12); idx2 once var0; idx2 += inc3 */
+ 0x10002b10, /* 0138(:454): DRD1A: var10 = idx2; FN=0 MORE init=0 WS=0 RS=0 */
+ 0x7000000a, /* 013C(:455): DRD2A: EU0=0 EU1=0 EU2=0 EU3=10 EXT MORE init=0 WS=0 RS=0 */
+ 0x080cf89f, /* 0140(:455): DRD2B1: idx0 = EU3(); EU3(idx2) */
+ 0x6000000d, /* 0144(:456): DRD2A: EU0=0 EU1=0 EU2=0 EU3=13 EXT init=0 WS=0 RS=0 */
+ 0x018cf89f, /* 0148(:456): DRD2B1: var6 = EU3(); EU3(idx2) */
+ 0x000001f8, /* 014C(:0): NOP */
+ 0x8618801b, /* 0150(:462): LCD: idx1 = var12; idx1 once var0; idx1 += inc3 */
+ 0x7000000e, /* 0154(:463): DRD2A: EU0=0 EU1=0 EU2=0 EU3=14 EXT MORE init=0 WS=0 RS=0 */
+ 0x084cf21f, /* 0158(:463): DRD2B1: idx1 = EU3(); EU3(var8) */
+ 0xd8990336, /* 015C(:464): LCDEXT: idx2 = idx1; idx2 > var12; idx2 += inc6 */
+ 0x8019801b, /* 0160(:464): LCD: idx3 = var0; idx3 once var0; idx3 += inc3 */
+ 0x040001f8, /* 0164(:465): DRD1A: FN=0 INT init=0 WS=0 RS=0 */
+ 0x000001f8, /* 0168(:0): NOP */
+ 0x000001f8, /* 016C(:0): NOP */
+};
+u32 MCD_SingleNoEu_TDT[] = {
+ 0x8198001b, /* 0000(:657): LCD: idx0 = var3; idx0 once var0; idx0 += inc3 */
+ 0x7000000d, /* 0004(:658): DRD2A: EU0=0 EU1=0 EU2=0 EU3=13 EXT MORE init=0 WS=0 RS=0 */
+ 0x080cf81f, /* 0008(:658): DRD2B1: idx0 = EU3(); EU3(idx0) */
+ 0x8198801b, /* 000C(:659): LCD: idx1 = var3; idx1 once var0; idx1 += inc3 */
+ 0x6000000e, /* 0010(:660): DRD2A: EU0=0 EU1=0 EU2=0 EU3=14 EXT init=0 WS=0 RS=0 */
+ 0x084cf85f, /* 0014(:660): DRD2B1: idx1 = EU3(); EU3(idx1) */
+ 0x000001f8, /* 0018(:0): NOP */
+ 0x8298001b, /* 001C(:664): LCD: idx0 = var5; idx0 once var0; idx0 += inc3 */
+ 0x7000000d, /* 0020(:665): DRD2A: EU0=0 EU1=0 EU2=0 EU3=13 EXT MORE init=0 WS=0 RS=0 */
+ 0x010cf81f, /* 0024(:665): DRD2B1: var4 = EU3(); EU3(idx0) */
+ 0x6000000e, /* 0028(:666): DRD2A: EU0=0 EU1=0 EU2=0 EU3=14 EXT init=0 WS=0 RS=0 */
+ 0x018cf81f, /* 002C(:666): DRD2B1: var6 = EU3(); EU3(idx0) */
+ 0xc202601b, /* 0030(:669): LCDEXT: idx0 = var4, idx1 = var4; ; idx0 += inc3, idx1 += inc3 */
+ 0xc002221c, /* 0034(:669): LCDEXT: idx2 = var0, idx3 = var4; idx3 == var8; idx2 += inc3, idx3 += inc4 */
+ 0x809a601b, /* 0038(:670): LCD: idx4 = var1; ; idx4 += inc3 */
+ 0xc10420c2, /* 003C(:673): LCDEXT: idx5 = var2, idx6 = var8; idx6 < var3; idx5 += inc0, idx6 += inc2 */
+ 0x839be009, /* 0040(:673): LCD: idx7 = var7; ; idx7 += inc1 */
+ 0x03fed7b8, /* 0044(:676): DRD1A: *idx7; FN=0 init=31 WS=3 RS=3 */
+ 0xda9b001b, /* 0048(:678): LCDEXT: idx5 = idx5, idx6 = idx6; idx5 once var0; idx5 += inc3, idx6 += inc3 */
+ 0x9b9be01b, /* 004C(:678): LCD: idx7 = idx7; ; idx7 += inc3 */
+ 0x70000006, /* 0050(:680): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */
+ 0x088cf889, /* 0054(:680): DRD2B1: idx2 = EU3(); EU3(idx2,var9) */
+ 0x1000cb28, /* 0058(:681): DRD1A: *idx2 = idx5; FN=0 MORE init=0 WS=0 RS=0 */
+ 0x70000006, /* 005C(:682): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */
+ 0x088cf889, /* 0060(:682): DRD2B1: idx2 = EU3(); EU3(idx2,var9) */
+ 0x1000cb30, /* 0064(:683): DRD1A: *idx2 = idx6; FN=0 MORE init=0 WS=0 RS=0 */
+ 0x70000006, /* 0068(:684): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */
+ 0x088cf889, /* 006C(:684): DRD2B1: idx2 = EU3(); EU3(idx2,var9) */
+ 0x0000cb38, /* 0070(:685): DRD1A: *idx2 = idx7; FN=0 init=0 WS=0 RS=0 */
+ 0x000001f8, /* 0074(:0): NOP */
+ 0xc202601b, /* 0078(:689): LCDEXT: idx0 = var4, idx1 = var4; ; idx0 += inc3, idx1 += inc3 */
+ 0xc002229c, /* 007C(:689): LCDEXT: idx2 = var0, idx3 = var4; idx3 == var10; idx2 += inc3, idx3 += inc4 */
+ 0x809a601b, /* 0080(:690): LCD: idx4 = var1; ; idx4 += inc3 */
+ 0xda9b001b, /* 0084(:693): LCDEXT: idx5 = idx5, idx6 = idx6; idx5 once var0; idx5 += inc3, idx6 += inc3 */
+ 0x9b9be01b, /* 0088(:693): LCD: idx7 = idx7; ; idx7 += inc3 */
+ 0x0000d3a0, /* 008C(:694): DRD1A: *idx4; FN=0 init=0 WS=0 RS=0 */
+ 0xc10420c2, /* 0090(:696): LCDEXT: idx5 = var2, idx6 = var8; idx6 < var3; idx5 += inc0, idx6 += inc2 */
+ 0x839be009, /* 0094(:696): LCD: idx7 = var7; ; idx7 += inc1 */
+ 0x0bfed7b8, /* 0098(:699): DRD1A: *idx7; FN=0 TFD init=31 WS=3 RS=3 */
+ 0xda9b001b, /* 009C(:701): LCDEXT: idx5 = idx5, idx6 = idx6; idx5 once var0; idx5 += inc3, idx6 += inc3 */
+ 0x9b9be01b, /* 00A0(:701): LCD: idx7 = idx7; ; idx7 += inc3 */
+ 0x70000006, /* 00A4(:703): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */
+ 0x088cf889, /* 00A8(:703): DRD2B1: idx2 = EU3(); EU3(idx2,var9) */
+ 0x1000cb28, /* 00AC(:704): DRD1A: *idx2 = idx5; FN=0 MORE init=0 WS=0 RS=0 */
+ 0x70000006, /* 00B0(:705): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */
+ 0x088cf889, /* 00B4(:705): DRD2B1: idx2 = EU3(); EU3(idx2,var9) */
+ 0x1000cb30, /* 00B8(:706): DRD1A: *idx2 = idx6; FN=0 MORE init=0 WS=0 RS=0 */
+ 0x70000006, /* 00BC(:707): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */
+ 0x088cf889, /* 00C0(:707): DRD2B1: idx2 = EU3(); EU3(idx2,var9) */
+ 0x0000cb38, /* 00C4(:708): DRD1A: *idx2 = idx7; FN=0 init=0 WS=0 RS=0 */
+ 0x000001f8, /* 00C8(:0): NOP */
+ 0xc318022d, /* 00CC(:712): LCDEXT: idx0 = var6; idx0 > var8; idx0 += inc5 */
+ 0x8018801b, /* 00D0(:712): LCD: idx1 = var0; idx1 once var0; idx1 += inc3 */
+ 0x040001f8, /* 00D4(:713): DRD1A: FN=0 INT init=0 WS=0 RS=0 */
+};
+#ifdef MCD_INCLUDE_EU
+u32 MCD_ChainEu_TDT[] = {
+ 0x80004000, /* 0000(:947): LCDEXT: idx0 = 0x00000000; ; */
+ 0x8198801b, /* 0004(:947): LCD: idx1 = var3; idx1 once var0; idx1 += inc3 */
+ 0xb8c68018, /* 0008(:948): LCD: idx2 = *(idx1 + var13); idx2 once var0; idx2 += inc3 */
+ 0x10002f10, /* 000C(:949): DRD1A: var11 = idx2; FN=0 MORE init=0 WS=0 RS=0 */
+ 0x7000000d, /* 0010(:950): DRD2A: EU0=0 EU1=0 EU2=0 EU3=13 EXT MORE init=0 WS=0 RS=0 */
+ 0x01ccf89f, /* 0014(:950): DRD2B1: var7 = EU3(); EU3(idx2) */
+ 0x6000000a, /* 0018(:951): DRD2A: EU0=0 EU1=0 EU2=0 EU3=10 EXT init=0 WS=0 RS=0 */
+ 0x080cf89f, /* 001C(:951): DRD2B1: idx0 = EU3(); EU3(idx2) */
+ 0x000001f8, /* 0020(:0): NOP */
+ 0x981803a4, /* 0024(:955): LCD: idx0 = idx0; idx0 == var14; idx0 += inc4 */
+ 0x8198801b, /* 0028(:957): LCD: idx1 = var3; idx1 once var0; idx1 += inc3 */
+ 0xf8c6801a, /* 002C(:958): LCDEXT: idx2 = *(idx1 + var13 + 8); idx2 once var0; idx2 += inc3 */
+ 0xb8c6e01b, /* 0030(:959): LCD: idx3 = *(idx1 + var13 + 12); ; idx3 += inc3 */
+ 0x10002b10, /* 0034(:961): DRD1A: var10 = idx2; FN=0 MORE init=0 WS=0 RS=0 */
+ 0x00001318, /* 0038(:962): DRD1A: var4 = idx3; FN=0 init=0 WS=0 RS=0 */
+ 0xb8c6801d, /* 003C(:964): LCD: idx2 = *(idx1 + var13 + 20); idx2 once var0; idx2 += inc3 */
+ 0x10001710, /* 0040(:965): DRD1A: var5 = idx2; FN=0 MORE init=0 WS=0 RS=0 */
+ 0x60000007, /* 0044(:966): DRD2A: EU0=0 EU1=0 EU2=0 EU3=7 EXT init=0 WS=0 RS=0 */
+ 0x018cf88c, /* 0048(:966): DRD2B1: var6 = EU3(); EU3(idx2,var12) */
+ 0x98c6801c, /* 004C(:968): LCD: idx2 = idx1 + var13 + 4; idx2 once var0; idx2 += inc3 */
+ 0x00000b10, /* 0050(:969): DRD1A: var2 = idx2; FN=0 init=0 WS=0 RS=0 */
+ 0x98c78018, /* 0054(:970): LCD: idx2 = idx1 + var15; idx2 once var0; idx2 += inc3 */
+ 0x10002310, /* 0058(:971): DRD1A: var8 = idx2; FN=0 MORE init=0 WS=0 RS=0 */
+ 0x0000c820, /* 005C(:972): DRD1A: *idx2 = var4; FN=0 init=0 WS=0 RS=0 */
+ 0x000001f8, /* 0060(:0): NOP */
+ 0x8698801b, /* 0064(:976): LCD: idx1 = var13; idx1 once var0; idx1 += inc3 */
+ 0x7000000f, /* 0068(:977): DRD2A: EU0=0 EU1=0 EU2=0 EU3=15 EXT MORE init=0 WS=0 RS=0 */
+ 0x084cf2df, /* 006C(:977): DRD2B1: idx1 = EU3(); EU3(var11) */
+ 0xd899042d, /* 0070(:978): LCDEXT: idx2 = idx1; idx2 >= var16; idx2 += inc5 */
+ 0x8019801b, /* 0074(:978): LCD: idx3 = var0; idx3 once var0; idx3 += inc3 */
+ 0x60000003, /* 0078(:979): DRD2A: EU0=0 EU1=0 EU2=0 EU3=3 EXT init=0 WS=0 RS=0 */
+ 0x2cd7c7df, /* 007C(:979): DRD2B2: EU3(var13) */
+ 0xd8990364, /* 0080(:980): LCDEXT: idx2 = idx1; idx2 == var13; idx2 += inc4 */
+ 0x8019801b, /* 0084(:980): LCD: idx3 = var0; idx3 once var0; idx3 += inc3 */
+ 0x60000003, /* 0088(:981): DRD2A: EU0=0 EU1=0 EU2=0 EU3=3 EXT init=0 WS=0 RS=0 */
+ 0x2c17c7df, /* 008C(:981): DRD2B2: EU3(var1) */
+ 0x000001f8, /* 0090(:0): NOP */
+ 0xc1c7e018, /* 0094(:984): LCDEXT: idx1 = var3 + var15; ; idx1 += inc3 */
+ 0xc003a35e, /* 0098(:984): LCDEXT: idx2 = var0, idx3 = var7; idx3 == var13; idx2 += inc3, idx3 += inc6 */
+ 0x819a601b, /* 009C(:985): LCD: idx4 = var3; ; idx4 += inc3 */
+ 0xc206a142, /* 00A0(:988): LCDEXT: idx5 = var4, idx6 = var13; idx6 < var5; idx5 += inc0, idx6 += inc2 */
+ 0x851be009, /* 00A4(:988): LCD: idx7 = var10; ; idx7 += inc1 */
+ 0x63fe0000, /* 00A8(:991): DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT init=31 WS=3 RS=3 */
+ 0x0d4cfddf, /* 00AC(:991): DRD2B1: *idx5 = EU3(); EU3(*idx7) */
+ 0xda9b001b, /* 00B0(:993): LCDEXT: idx5 = idx5, idx6 = idx6; idx5 once var0; idx5 += inc3, idx6 += inc3 */
+ 0x9b9be01b, /* 00B4(:993): LCD: idx7 = idx7; ; idx7 += inc3 */
+ 0x70000002, /* 00B8(:994): DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT MORE init=0 WS=0 RS=0 */
+ 0x004cf81f, /* 00BC(:994): DRD2B1: var1 = EU3(); EU3(idx0) */
+ 0x1000cb20, /* 00C0(:995): DRD1A: *idx2 = idx4; FN=0 MORE init=0 WS=0 RS=0 */
+ 0x70000006, /* 00C4(:996): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */
+ 0x088cf891, /* 00C8(:996): DRD2B1: idx2 = EU3(); EU3(idx2,var17) */
+ 0x1000cb28, /* 00CC(:997): DRD1A: *idx2 = idx5; FN=0 MORE init=0 WS=0 RS=0 */
+ 0x70000006, /* 00D0(:998): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */
+ 0x088cf891, /* 00D4(:998): DRD2B1: idx2 = EU3(); EU3(idx2,var17) */
+ 0x1000cb30, /* 00D8(:999): DRD1A: *idx2 = idx6; FN=0 MORE init=0 WS=0 RS=0 */
+ 0x70000006, /* 00DC(:1000): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */
+ 0x088cf891, /* 00E0(:1000): DRD2B1: idx2 = EU3(); EU3(idx2,var17) */
+ 0x1000cb38, /* 00E4(:1001): DRD1A: *idx2 = idx7; FN=0 MORE init=0 WS=0 RS=0 */
+ 0x0000c728, /* 00E8(:1002): DRD1A: *idx1 = idx5; FN=0 init=0 WS=0 RS=0 */
+ 0x000001f8, /* 00EC(:0): NOP */
+ 0xc1c7e018, /* 00F0(:1006): LCDEXT: idx1 = var3 + var15; ; idx1 += inc3 */
+ 0xc003a49e, /* 00F4(:1006): LCDEXT: idx2 = var0, idx3 = var7; idx3 == var18; idx2 += inc3, idx3 += inc6 */
+ 0x819a601b, /* 00F8(:1007): LCD: idx4 = var3; ; idx4 += inc3 */
+ 0xda9b001b, /* 00FC(:1010): LCDEXT: idx5 = idx5, idx6 = idx6; idx5 once var0; idx5 += inc3, idx6 += inc3 */
+ 0x9b9be01b, /* 0100(:1010): LCD: idx7 = idx7; ; idx7 += inc3 */
+ 0x0000d3a0, /* 0104(:1011): DRD1A: *idx4; FN=0 init=0 WS=0 RS=0 */
+ 0xc206a142, /* 0108(:1013): LCDEXT: idx5 = var4, idx6 = var13; idx6 < var5; idx5 += inc0, idx6 += inc2 */
+ 0x851be009, /* 010C(:1013): LCD: idx7 = var10; ; idx7 += inc1 */
+ 0x6bfe0000, /* 0110(:1016): DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 TFD EXT init=31 WS=3 RS=3 */
+ 0x0d4cfddf, /* 0114(:1016): DRD2B1: *idx5 = EU3(); EU3(*idx7) */
+ 0xda9b001b, /* 0118(:1018): LCDEXT: idx5 = idx5, idx6 = idx6; idx5 once var0; idx5 += inc3, idx6 += inc3 */
+ 0x9b9be01b, /* 011C(:1018): LCD: idx7 = idx7; ; idx7 += inc3 */
+ 0x70000002, /* 0120(:1019): DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT MORE init=0 WS=0 RS=0 */
+ 0x004cf81f, /* 0124(:1019): DRD2B1: var1 = EU3(); EU3(idx0) */
+ 0x1000cb20, /* 0128(:1020): DRD1A: *idx2 = idx4; FN=0 MORE init=0 WS=0 RS=0 */
+ 0x70000006, /* 012C(:1021): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */
+ 0x088cf891, /* 0130(:1021): DRD2B1: idx2 = EU3(); EU3(idx2,var17) */
+ 0x1000cb28, /* 0134(:1022): DRD1A: *idx2 = idx5; FN=0 MORE init=0 WS=0 RS=0 */
+ 0x70000006, /* 0138(:1023): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */
+ 0x088cf891, /* 013C(:1023): DRD2B1: idx2 = EU3(); EU3(idx2,var17) */
+ 0x1000cb30, /* 0140(:1024): DRD1A: *idx2 = idx6; FN=0 MORE init=0 WS=0 RS=0 */
+ 0x70000006, /* 0144(:1025): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */
+ 0x088cf891, /* 0148(:1025): DRD2B1: idx2 = EU3(); EU3(idx2,var17) */
+ 0x1000cb38, /* 014C(:1026): DRD1A: *idx2 = idx7; FN=0 MORE init=0 WS=0 RS=0 */
+ 0x0000c728, /* 0150(:1027): DRD1A: *idx1 = idx5; FN=0 init=0 WS=0 RS=0 */
+ 0x000001f8, /* 0154(:0): NOP */
+ 0x8198801b, /* 0158(:1031): LCD: idx1 = var3; idx1 once var0; idx1 += inc3 */
+ 0xd8c68018, /* 015C(:1033): LCDEXT: idx2 = idx1 + var13; idx2 once var0; idx2 += inc3 */
+ 0x98c6e01c, /* 0160(:1033): LCD: idx3 = idx1 + var13 + 4; ; idx3 += inc3 */
+ 0x6000000b, /* 0164(:1034): DRD2A: EU0=0 EU1=0 EU2=0 EU3=11 EXT init=0 WS=0 RS=0 */
+ 0x0c8cfc9f, /* 0168(:1034): DRD2B1: *idx2 = EU3(); EU3(*idx2) */
+ 0x0000cc08, /* 016C(:1035): DRD1A: *idx3 = var1; FN=0 init=0 WS=0 RS=0 */
+ 0xa1c6801e, /* 0170(:1038): LCD: idx1 = *(var3 + var13 + 24); idx1 once var0; idx1 += inc3 */
+ 0x10000f08, /* 0174(:1039): DRD1A: var3 = idx1; FN=0 MORE init=0 WS=0 RS=0 */
+ 0x10002458, /* 0178(:1040): DRD1A: var9 = var11; FN=0 MORE init=0 WS=0 RS=0 */
+ 0xb8c68018, /* 017C(:1041): LCD: idx2 = *(idx1 + var13); idx2 once var0; idx2 += inc3 */
+ 0x10002f10, /* 0180(:1042): DRD1A: var11 = idx2; FN=0 MORE init=0 WS=0 RS=0 */
+ 0x7000000a, /* 0184(:1043): DRD2A: EU0=0 EU1=0 EU2=0 EU3=10 EXT MORE init=0 WS=0 RS=0 */
+ 0x080cf89f, /* 0188(:1043): DRD2B1: idx0 = EU3(); EU3(idx2) */
+ 0x6000000d, /* 018C(:1044): DRD2A: EU0=0 EU1=0 EU2=0 EU3=13 EXT init=0 WS=0 RS=0 */
+ 0x01ccf89f, /* 0190(:1044): DRD2B1: var7 = EU3(); EU3(idx2) */
+ 0x000001f8, /* 0194(:0): NOP */
+ 0x8698801b, /* 0198(:1050): LCD: idx1 = var13; idx1 once var0; idx1 += inc3 */
+ 0x7000000e, /* 019C(:1051): DRD2A: EU0=0 EU1=0 EU2=0 EU3=14 EXT MORE init=0 WS=0 RS=0 */
+ 0x084cf25f, /* 01A0(:1051): DRD2B1: idx1 = EU3(); EU3(var9) */
+ 0xd899037f, /* 01A4(:1052): LCDEXT: idx2 = idx1; idx2 > var13; idx2 += inc7 */
+ 0x8019801b, /* 01A8(:1052): LCD: idx3 = var0; idx3 once var0; idx3 += inc3 */
+ 0x040001f8, /* 01AC(:1053): DRD1A: FN=0 INT init=0 WS=0 RS=0 */
+ 0x000001f8, /* 01B0(:0): NOP */
+ 0x000001f8, /* 01B4(:0): NOP */
+};
+u32 MCD_SingleEu_TDT[] = {
+ 0x8218001b, /* 0000(:1248): LCD: idx0 = var4; idx0 once var0; idx0 += inc3 */
+ 0x7000000d, /* 0004(:1249): DRD2A: EU0=0 EU1=0 EU2=0 EU3=13 EXT MORE init=0 WS=0 RS=0 */
+ 0x080cf81f, /* 0008(:1249): DRD2B1: idx0 = EU3(); EU3(idx0) */
+ 0x8218801b, /* 000C(:1250): LCD: idx1 = var4; idx1 once var0; idx1 += inc3 */
+ 0x6000000e, /* 0010(:1251): DRD2A: EU0=0 EU1=0 EU2=0 EU3=14 EXT init=0 WS=0 RS=0 */
+ 0x084cf85f, /* 0014(:1251): DRD2B1: idx1 = EU3(); EU3(idx1) */
+ 0x000001f8, /* 0018(:0): NOP */
+ 0x8318001b, /* 001C(:1255): LCD: idx0 = var6; idx0 once var0; idx0 += inc3 */
+ 0x7000000d, /* 0020(:1256): DRD2A: EU0=0 EU1=0 EU2=0 EU3=13 EXT MORE init=0 WS=0 RS=0 */
+ 0x014cf81f, /* 0024(:1256): DRD2B1: var5 = EU3(); EU3(idx0) */
+ 0x6000000e, /* 0028(:1257): DRD2A: EU0=0 EU1=0 EU2=0 EU3=14 EXT init=0 WS=0 RS=0 */
+ 0x01ccf81f, /* 002C(:1257): DRD2B1: var7 = EU3(); EU3(idx0) */
+ 0x8498001b, /* 0030(:1260): LCD: idx0 = var9; idx0 once var0; idx0 += inc3 */
+ 0x7000000f, /* 0034(:1261): DRD2A: EU0=0 EU1=0 EU2=0 EU3=15 EXT MORE init=0 WS=0 RS=0 */
+ 0x080cf19f, /* 0038(:1261): DRD2B1: idx0 = EU3(); EU3(var6) */
+ 0xd81882a4, /* 003C(:1262): LCDEXT: idx1 = idx0; idx1 >= var10; idx1 += inc4 */
+ 0x8019001b, /* 0040(:1262): LCD: idx2 = var0; idx2 once var0; idx2 += inc3 */
+ 0x60000003, /* 0044(:1263): DRD2A: EU0=0 EU1=0 EU2=0 EU3=3 EXT init=0 WS=0 RS=0 */
+ 0x2c97c7df, /* 0048(:1263): DRD2B2: EU3(var9) */
+ 0xd818826d, /* 004C(:1264): LCDEXT: idx1 = idx0; idx1 == var9; idx1 += inc5 */
+ 0x8019001b, /* 0050(:1264): LCD: idx2 = var0; idx2 once var0; idx2 += inc3 */
+ 0x60000003, /* 0054(:1265): DRD2A: EU0=0 EU1=0 EU2=0 EU3=3 EXT init=0 WS=0 RS=0 */
+ 0x2c17c7df, /* 0058(:1265): DRD2B2: EU3(var1) */
+ 0x000001f8, /* 005C(:0): NOP */
+ 0xc282e01b, /* 0060(:1268): LCDEXT: idx0 = var5, idx1 = var5; ; idx0 += inc3, idx1 += inc3 */
+ 0xc002a25e, /* 0064(:1268): LCDEXT: idx2 = var0, idx3 = var5; idx3 == var9; idx2 += inc3, idx3 += inc6 */
+ 0x811a601b, /* 0068(:1269): LCD: idx4 = var2; ; idx4 += inc3 */
+ 0xc184a102, /* 006C(:1272): LCDEXT: idx5 = var3, idx6 = var9; idx6 < var4; idx5 += inc0, idx6 += inc2 */
+ 0x841be009, /* 0070(:1272): LCD: idx7 = var8; ; idx7 += inc1 */
+ 0x63fe0000, /* 0074(:1275): DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT init=31 WS=3 RS=3 */
+ 0x0d4cfddf, /* 0078(:1275): DRD2B1: *idx5 = EU3(); EU3(*idx7) */
+ 0xda9b001b, /* 007C(:1277): LCDEXT: idx5 = idx5, idx6 = idx6; idx5 once var0; idx5 += inc3, idx6 += inc3 */
+ 0x9b9be01b, /* 0080(:1277): LCD: idx7 = idx7; ; idx7 += inc3 */
+ 0x70000002, /* 0084(:1279): DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT MORE init=0 WS=0 RS=0 */
+ 0x004cf99f, /* 0088(:1279): DRD2B1: var1 = EU3(); EU3(idx6) */
+ 0x70000006, /* 008C(:1280): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */
+ 0x088cf88b, /* 0090(:1280): DRD2B1: idx2 = EU3(); EU3(idx2,var11) */
+ 0x1000cb28, /* 0094(:1281): DRD1A: *idx2 = idx5; FN=0 MORE init=0 WS=0 RS=0 */
+ 0x70000006, /* 0098(:1282): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */
+ 0x088cf88b, /* 009C(:1282): DRD2B1: idx2 = EU3(); EU3(idx2,var11) */
+ 0x1000cb30, /* 00A0(:1283): DRD1A: *idx2 = idx6; FN=0 MORE init=0 WS=0 RS=0 */
+ 0x70000006, /* 00A4(:1284): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */
+ 0x088cf88b, /* 00A8(:1284): DRD2B1: idx2 = EU3(); EU3(idx2,var11) */
+ 0x0000cb38, /* 00AC(:1285): DRD1A: *idx2 = idx7; FN=0 init=0 WS=0 RS=0 */
+ 0x000001f8, /* 00B0(:0): NOP */
+ 0xc282e01b, /* 00B4(:1289): LCDEXT: idx0 = var5, idx1 = var5; ; idx0 += inc3, idx1 += inc3 */
+ 0xc002a31e, /* 00B8(:1289): LCDEXT: idx2 = var0, idx3 = var5; idx3 == var12; idx2 += inc3, idx3 += inc6 */
+ 0x811a601b, /* 00BC(:1290): LCD: idx4 = var2; ; idx4 += inc3 */
+ 0xda9b001b, /* 00C0(:1293): LCDEXT: idx5 = idx5, idx6 = idx6; idx5 once var0; idx5 += inc3, idx6 += inc3 */
+ 0x9b9be01b, /* 00C4(:1293): LCD: idx7 = idx7; ; idx7 += inc3 */
+ 0x0000d3a0, /* 00C8(:1294): DRD1A: *idx4; FN=0 init=0 WS=0 RS=0 */
+ 0xc184a102, /* 00CC(:1296): LCDEXT: idx5 = var3, idx6 = var9; idx6 < var4; idx5 += inc0, idx6 += inc2 */
+ 0x841be009, /* 00D0(:1296): LCD: idx7 = var8; ; idx7 += inc1 */
+ 0x6bfe0000, /* 00D4(:1299): DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 TFD EXT init=31 WS=3 RS=3 */
+ 0x0d4cfddf, /* 00D8(:1299): DRD2B1: *idx5 = EU3(); EU3(*idx7) */
+ 0xda9b001b, /* 00DC(:1301): LCDEXT: idx5 = idx5, idx6 = idx6; idx5 once var0; idx5 += inc3, idx6 += inc3 */
+ 0x9b9be01b, /* 00E0(:1301): LCD: idx7 = idx7; ; idx7 += inc3 */
+ 0x70000002, /* 00E4(:1303): DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT MORE init=0 WS=0 RS=0 */
+ 0x004cf99f, /* 00E8(:1303): DRD2B1: var1 = EU3(); EU3(idx6) */
+ 0x70000006, /* 00EC(:1304): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */
+ 0x088cf88b, /* 00F0(:1304): DRD2B1: idx2 = EU3(); EU3(idx2,var11) */
+ 0x1000cb28, /* 00F4(:1305): DRD1A: *idx2 = idx5; FN=0 MORE init=0 WS=0 RS=0 */
+ 0x70000006, /* 00F8(:1306): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */
+ 0x088cf88b, /* 00FC(:1306): DRD2B1: idx2 = EU3(); EU3(idx2,var11) */
+ 0x1000cb30, /* 0100(:1307): DRD1A: *idx2 = idx6; FN=0 MORE init=0 WS=0 RS=0 */
+ 0x70000006, /* 0104(:1308): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */
+ 0x088cf88b, /* 0108(:1308): DRD2B1: idx2 = EU3(); EU3(idx2,var11) */
+ 0x0000cb38, /* 010C(:1309): DRD1A: *idx2 = idx7; FN=0 init=0 WS=0 RS=0 */
+ 0x000001f8, /* 0110(:0): NOP */
+ 0x8144801c, /* 0114(:1312): LCD: idx0 = var2 + var9 + 4; idx0 once var0; idx0 += inc3 */
+ 0x0000c008, /* 0118(:1313): DRD1A: *idx0 = var1; FN=0 init=0 WS=0 RS=0 */
+ 0xc398027f, /* 011C(:1315): LCDEXT: idx0 = var7; idx0 > var9; idx0 += inc7 */
+ 0x8018801b, /* 0120(:1315): LCD: idx1 = var0; idx1 once var0; idx1 += inc3 */
+ 0x040001f8, /* 0124(:1316): DRD1A: FN=0 INT init=0 WS=0 RS=0 */
+};
+#endif
+u32 MCD_ENetRcv_TDT[] = {
+ 0x80004000, /* 0000(:1389): LCDEXT: idx0 = 0x00000000; ; */
+ 0x81988000, /* 0004(:1389): LCD: idx1 = var3; idx1 once var0; idx1 += inc0 */
+ 0x10000788, /* 0008(:1390): DRD1A: var1 = *idx1; FN=0 MORE init=0 WS=0 RS=0 */
+ 0x6000000a, /* 000C(:1391): DRD2A: EU0=0 EU1=0 EU2=0 EU3=10 EXT init=0 WS=0 RS=0 */
+ 0x080cf05f, /* 0010(:1391): DRD2B1: idx0 = EU3(); EU3(var1) */
+ 0x98180209, /* 0014(:1394): LCD: idx0 = idx0; idx0 != var8; idx0 += inc1 */
+ 0x81c40004, /* 0018(:1396): LCD: idx1 = var3 + var8 + 4; idx1 once var0; idx1 += inc0 */
+ 0x7000000e, /* 001C(:1397): DRD2A: EU0=0 EU1=0 EU2=0 EU3=14 EXT MORE init=0 WS=0 RS=0 */
+ 0x010cf05f, /* 0020(:1397): DRD2B1: var4 = EU3(); EU3(var1) */
+ 0x7000000c, /* 0024(:1398): DRD2A: EU0=0 EU1=0 EU2=0 EU3=12 EXT MORE init=0 WS=0 RS=0 */
+ 0x01ccf05f, /* 0028(:1398): DRD2B1: var7 = EU3(); EU3(var1) */
+ 0x70000004, /* 002C(:1399): DRD2A: EU0=0 EU1=0 EU2=0 EU3=4 EXT MORE init=0 WS=0 RS=0 */
+ 0x014cf049, /* 0030(:1399): DRD2B1: var5 = EU3(); EU3(var1,var9) */
+ 0x70000004, /* 0034(:1400): DRD2A: EU0=0 EU1=0 EU2=0 EU3=4 EXT MORE init=0 WS=0 RS=0 */
+ 0x004cf04a, /* 0038(:1400): DRD2B1: var1 = EU3(); EU3(var1,var10) */
+ 0x00000b88, /* 003C(:1403): DRD1A: var2 = *idx1; FN=0 init=0 WS=0 RS=0 */
+ 0xc4030150, /* 0040(:1406): LCDEXT: idx1 = var8, idx2 = var6; idx1 < var5; idx1 += inc2, idx2 += inc0 */
+ 0x8119e012, /* 0044(:1406): LCD: idx3 = var2; ; idx3 += inc2 */
+ 0x03e0cf90, /* 0048(:1409): DRD1A: *idx3 = *idx2; FN=0 init=31 WS=0 RS=0 */
+ 0x81188000, /* 004C(:1412): LCD: idx1 = var2; idx1 once var0; idx1 += inc0 */
+ 0x000ac788, /* 0050(:1413): DRD1A: *idx1 = *idx1; FN=0 init=0 WS=1 RS=1 */
+ 0xc4030000, /* 0054(:1415): LCDEXT: idx1 = var8, idx2 = var6; idx1 once var0; idx1 += inc0, idx2 += inc0 */
+ 0x8199e000, /* 0058(:1415): LCD: idx3 = var3; ; idx3 += inc0 */
+ 0x63e00004, /* 005C(:1418): DRD2A: EU0=0 EU1=0 EU2=0 EU3=4 EXT init=31 WS=0 RS=0 */
+ 0x084cfc8b, /* 0060(:1418): DRD2B1: idx1 = EU3(); EU3(*idx2,var11) */
+ 0xd8990000, /* 0064(:1421): LCDEXT: idx1 = idx1, idx2 = idx2; idx1 once var0; idx1 += inc0, idx2 += inc0 */
+ 0x9999e000, /* 0068(:1421): LCD: idx3 = idx3; ; idx3 += inc0 */
+ 0x60000005, /* 006C(:1422): DRD2A: EU0=0 EU1=0 EU2=0 EU3=5 EXT init=0 WS=0 RS=0 */
+ 0x0cccf841, /* 0070(:1422): DRD2B1: *idx3 = EU3(); EU3(idx1,var1) */
+ 0x81c60000, /* 0074(:1427): LCD: idx1 = var3 + var12; idx1 once var0; idx1 += inc0 */
+ 0xc399021b, /* 0078(:1429): LCDEXT: idx2 = var7; idx2 > var8; idx2 += inc3 */
+ 0x80198000, /* 007C(:1429): LCD: idx3 = var0; idx3 once var0; idx3 += inc0 */
+ 0x00008400, /* 0080(:1430): DRD1A: idx1 = var0; FN=0 init=0 WS=0 RS=0 */
+ 0x00000f08, /* 0084(:1431): DRD1A: var3 = idx1; FN=0 init=0 WS=0 RS=0 */
+ 0x81988000, /* 0088(:1434): LCD: idx1 = var3; idx1 once var0; idx1 += inc0 */
+ 0x10000788, /* 008C(:1435): DRD1A: var1 = *idx1; FN=0 MORE init=0 WS=0 RS=0 */
+ 0x6000000a, /* 0090(:1436): DRD2A: EU0=0 EU1=0 EU2=0 EU3=10 EXT init=0 WS=0 RS=0 */
+ 0x080cf05f, /* 0094(:1436): DRD2B1: idx0 = EU3(); EU3(var1) */
+ 0xc2188209, /* 0098(:1439): LCDEXT: idx1 = var4; idx1 != var8; idx1 += inc1 */
+ 0x80190000, /* 009C(:1439): LCD: idx2 = var0; idx2 once var0; idx2 += inc0 */
+ 0x040001f8, /* 00A0(:1440): DRD1A: FN=0 INT init=0 WS=0 RS=0 */
+ 0x000001f8, /* 00A4(:0): NOP */
+};
+u32 MCD_ENetXmit_TDT[] = {
+ 0x80004000, /* 0000(:1515): LCDEXT: idx0 = 0x00000000; ; */
+ 0x81988000, /* 0004(:1515): LCD: idx1 = var3; idx1 once var0; idx1 += inc0 */
+ 0x10000788, /* 0008(:1516): DRD1A: var1 = *idx1; FN=0 MORE init=0 WS=0 RS=0 */
+ 0x6000000a, /* 000C(:1517): DRD2A: EU0=0 EU1=0 EU2=0 EU3=10 EXT init=0 WS=0 RS=0 */
+ 0x080cf05f, /* 0010(:1517): DRD2B1: idx0 = EU3(); EU3(var1) */
+ 0x98180309, /* 0014(:1520): LCD: idx0 = idx0; idx0 != var12; idx0 += inc1 */
+ 0x80004003, /* 0018(:1522): LCDEXT: idx1 = 0x00000003; ; */
+ 0x81c60004, /* 001C(:1522): LCD: idx2 = var3 + var12 + 4; idx2 once var0; idx2 += inc0 */
+ 0x7000000e, /* 0020(:1523): DRD2A: EU0=0 EU1=0 EU2=0 EU3=14 EXT MORE init=0 WS=0 RS=0 */
+ 0x014cf05f, /* 0024(:1523): DRD2B1: var5 = EU3(); EU3(var1) */
+ 0x7000000c, /* 0028(:1524): DRD2A: EU0=0 EU1=0 EU2=0 EU3=12 EXT MORE init=0 WS=0 RS=0 */
+ 0x028cf05f, /* 002C(:1524): DRD2B1: var10 = EU3(); EU3(var1) */
+ 0x7000000d, /* 0030(:1525): DRD2A: EU0=0 EU1=0 EU2=0 EU3=13 EXT MORE init=0 WS=0 RS=0 */
+ 0x018cf05f, /* 0034(:1525): DRD2B1: var6 = EU3(); EU3(var1) */
+ 0x70000004, /* 0038(:1526): DRD2A: EU0=0 EU1=0 EU2=0 EU3=4 EXT MORE init=0 WS=0 RS=0 */
+ 0x01ccf04d, /* 003C(:1526): DRD2B1: var7 = EU3(); EU3(var1,var13) */
+ 0x10000b90, /* 0040(:1527): DRD1A: var2 = *idx2; FN=0 MORE init=0 WS=0 RS=0 */
+ 0x60000004, /* 0044(:1528): DRD2A: EU0=0 EU1=0 EU2=0 EU3=4 EXT init=0 WS=0 RS=0 */
+ 0x020cf0a1, /* 0048(:1528): DRD2B1: var8 = EU3(); EU3(var2,idx1) */
+ 0xc3188312, /* 004C(:1531): LCDEXT: idx1 = var6; idx1 > var12; idx1 += inc2 */
+ 0x83c70000, /* 0050(:1531): LCD: idx2 = var7 + var14; idx2 once var0; idx2 += inc0 */
+ 0x00001f10, /* 0054(:1532): DRD1A: var7 = idx2; FN=0 init=0 WS=0 RS=0 */
+ 0xc583a3c3, /* 0058(:1534): LCDEXT: idx1 = var11, idx2 = var7; idx2 >= var15; idx1 += inc0, idx2 += inc3 */
+ 0x81042325, /* 005C(:1534): LCD: idx3 = var2, idx4 = var8; idx4 == var12; idx3 += inc4, idx4 += inc5 */
+ 0x03e0c798, /* 0060(:1539): DRD1A: *idx1 = *idx3; FN=0 init=31 WS=0 RS=0 */
+ 0xd8990000, /* 0064(:1542): LCDEXT: idx1 = idx1, idx2 = idx2; idx1 once var0; idx1 += inc0, idx2 += inc0 */
+ 0x9999e000, /* 0068(:1542): LCD: idx3 = idx3; ; idx3 += inc0 */
+ 0x000acf98, /* 006C(:1543): DRD1A: *idx3 = *idx3; FN=0 init=0 WS=1 RS=1 */
+ 0xd8992306, /* 0070(:1545): LCDEXT: idx1 = idx1, idx2 = idx2; idx2 > var12; idx1 += inc0, idx2 += inc6 */
+ 0x9999e03f, /* 0074(:1545): LCD: idx3 = idx3; ; idx3 += inc7 */
+ 0x03eac798, /* 0078(:1548): DRD1A: *idx1 = *idx3; FN=0 init=31 WS=1 RS=1 */
+ 0xd8990000, /* 007C(:1551): LCDEXT: idx1 = idx1, idx2 = idx2; idx1 once var0; idx1 += inc0, idx2 += inc0 */
+ 0x9999e000, /* 0080(:1551): LCD: idx3 = idx3; ; idx3 += inc0 */
+ 0x000acf98, /* 0084(:1552): DRD1A: *idx3 = *idx3; FN=0 init=0 WS=1 RS=1 */
+ 0xd8990000, /* 0088(:1554): LCDEXT: idx1 = idx1, idx2 = idx2; idx1 once var0; idx1 += inc0, idx2 += inc0 */
+ 0x99832302, /* 008C(:1554): LCD: idx3 = idx3, idx4 = var6; idx4 > var12; idx3 += inc0, idx4 += inc2 */
+ 0x0beac798, /* 0090(:1557): DRD1A: *idx1 = *idx3; FN=0 TFD init=31 WS=1 RS=1 */
+ 0x81988000, /* 0094(:1559): LCD: idx1 = var3; idx1 once var0; idx1 += inc0 */
+ 0x6000000b, /* 0098(:1560): DRD2A: EU0=0 EU1=0 EU2=0 EU3=11 EXT init=0 WS=0 RS=0 */
+ 0x0c4cfc5f, /* 009C(:1560): DRD2B1: *idx1 = EU3(); EU3(*idx1) */
+ 0x81c80000, /* 00A0(:1562): LCD: idx1 = var3 + var16; idx1 once var0; idx1 += inc0 */
+ 0xc5190312, /* 00A4(:1564): LCDEXT: idx2 = var10; idx2 > var12; idx2 += inc2 */
+ 0x80198000, /* 00A8(:1564): LCD: idx3 = var0; idx3 once var0; idx3 += inc0 */
+ 0x00008400, /* 00AC(:1565): DRD1A: idx1 = var0; FN=0 init=0 WS=0 RS=0 */
+ 0x00000f08, /* 00B0(:1566): DRD1A: var3 = idx1; FN=0 init=0 WS=0 RS=0 */
+ 0x81988000, /* 00B4(:1569): LCD: idx1 = var3; idx1 once var0; idx1 += inc0 */
+ 0x10000788, /* 00B8(:1570): DRD1A: var1 = *idx1; FN=0 MORE init=0 WS=0 RS=0 */
+ 0x6000000a, /* 00BC(:1571): DRD2A: EU0=0 EU1=0 EU2=0 EU3=10 EXT init=0 WS=0 RS=0 */
+ 0x080cf05f, /* 00C0(:1571): DRD2B1: idx0 = EU3(); EU3(var1) */
+ 0xc2988309, /* 00C4(:1574): LCDEXT: idx1 = var5; idx1 != var12; idx1 += inc1 */
+ 0x80190000, /* 00C8(:1574): LCD: idx2 = var0; idx2 once var0; idx2 += inc0 */
+ 0x040001f8, /* 00CC(:1575): DRD1A: FN=0 INT init=0 WS=0 RS=0 */
+ 0x000001f8, /* 00D0(:0): NOP */
+};
+
+#ifdef MCD_INCLUDE_EU
+MCD_bufDesc MCD_singleBufDescs[NCHANNELS];
+#endif
diff --git a/drivers/dma/fsl_mcd_dma/MCD_tasksInit.c b/drivers/dma/fsl_mcd_dma/MCD_tasksInit.c
new file mode 100644
index 0000000..28b9717
--- /dev/null
+++ b/drivers/dma/fsl_mcd_dma/MCD_tasksInit.c
@@ -0,0 +1,274 @@
+/*
+ * drivers/dma/MCD_tasksInit.c
+ *
+ * Copyright (C) 2004-2008 Freescale Semiconductor, Inc.
+ * Kurt Mahan <kmahan at freescale.com>
+ * readl/writel conversion and other cleanup
+ * (C) Copyright 2010-2012 Philippe De Muyter <phdm at macqel.be> Macq SA
+ *
+ * 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
+ */
+
+/*
+ * Autogenerated - Do not edit!
+ */
+
+#include <linux/MCD_dma.h>
+#include <linux/io.h>
+#include "MCD_tasksInit.h"
+
+#define MCD_SET_VAR(varTab, idx, value) writel(value, (u32 *)(varTab) + idx)
+
+#define U16PAIR(m, l) ((u32)(m << 16) | (0xffff & l))
+
+
+/*
+ * Task 0
+ */
+
+void MCD_startDmaChainNoEu(int *currBD, short srcIncr, short destIncr,
+ int xferSize, short xferSizeIncr, int *cSave,
+ struct TaskTableEntry *taskTable, int channel)
+{
+ u32 var = taskTable[channel].varTab;
+ u16 tcrValue;
+
+ MCD_SET_VAR(var, 2, (u32)currBD); /* var[2] */
+ MCD_SET_VAR(var, 25, U16PAIR(0xe000, srcIncr)); /* inc[1] */
+ MCD_SET_VAR(var, 24, U16PAIR(0xe000, destIncr)); /* inc[0] */
+ MCD_SET_VAR(var, 11, (u32)xferSize); /* var[11] */
+ MCD_SET_VAR(var, 26, U16PAIR(0x2000, xferSizeIncr)); /* inc[2] */
+ MCD_SET_VAR(var, 0, (u32)cSave); /* var[0] */
+ MCD_SET_VAR(var, 1, (u32)0x00000000); /* var[1] */
+ MCD_SET_VAR(var, 3, (u32)0x00000000); /* var[3] */
+ MCD_SET_VAR(var, 4, (u32)0x00000000); /* var[4] */
+ MCD_SET_VAR(var, 5, (u32)0x00000000); /* var[5] */
+ MCD_SET_VAR(var, 6, (u32)0x00000000); /* var[6] */
+ MCD_SET_VAR(var, 7, (u32)0x00000000); /* var[7] */
+ MCD_SET_VAR(var, 8, (u32)0x00000000); /* var[8] */
+ MCD_SET_VAR(var, 9, (u32)0x00000000); /* var[9] */
+ MCD_SET_VAR(var, 10, (u32)0x00000000); /* var[10] */
+ MCD_SET_VAR(var, 12, (u32)0x00000000); /* var[12] */
+ MCD_SET_VAR(var, 13, (u32)0x80000000); /* var[13] */
+ MCD_SET_VAR(var, 14, (u32)0x00000010); /* var[14] */
+ MCD_SET_VAR(var, 15, (u32)0x00000004); /* var[15] */
+ MCD_SET_VAR(var, 16, (u32)0x08000000); /* var[16] */
+ MCD_SET_VAR(var, 27, (u32)0x00000000); /* inc[3] */
+ MCD_SET_VAR(var, 28, (u32)0x80000000); /* inc[4] */
+ MCD_SET_VAR(var, 29, (u32)0x80000001); /* inc[5] */
+ MCD_SET_VAR(var, 30, (u32)0x40000000); /* inc[6] */
+
+ /* Set the task's Enable bit in its Task Control Register */
+ tcrValue = readw(&MCD_dmaBar->taskControl[channel]);
+ writew(tcrValue | 0x8000, &MCD_dmaBar->taskControl[channel]);
+}
+
+
+/*
+ * Task 1
+ */
+
+void MCD_startDmaSingleNoEu(char *srcAddr, short srcIncr, char *destAddr,
+ short destIncr, int dmaSize, short xferSizeIncr,
+ int flags, int *currBD, int *cSave,
+ struct TaskTableEntry *taskTable, int channel)
+{
+ u32 var = taskTable[channel].varTab;
+ u16 tcrValue;
+
+ MCD_SET_VAR(var, 7, (u32)srcAddr); /* var[7] */
+ MCD_SET_VAR(var, 25, U16PAIR(0xe000, srcIncr)); /* inc[1] */
+ MCD_SET_VAR(var, 2, (u32)destAddr); /* var[2] */
+ MCD_SET_VAR(var, 24, U16PAIR(0xe000, destIncr)); /* inc[0] */
+ MCD_SET_VAR(var, 3, (u32)dmaSize); /* var[3] */
+ MCD_SET_VAR(var, 26, U16PAIR(0x2000, xferSizeIncr)); /* inc[2] */
+ MCD_SET_VAR(var, 5, (u32)flags); /* var[5] */
+ MCD_SET_VAR(var, 1, (u32)currBD); /* var[1] */
+ MCD_SET_VAR(var, 0, (u32)cSave); /* var[0] */
+ MCD_SET_VAR(var, 4, (u32)0x00000000); /* var[4] */
+ MCD_SET_VAR(var, 6, (u32)0x00000000); /* var[6] */
+ MCD_SET_VAR(var, 8, (u32)0x00000000); /* var[8] */
+ MCD_SET_VAR(var, 9, (u32)0x00000004); /* var[9] */
+ MCD_SET_VAR(var, 10, (u32)0x08000000); /* var[10] */
+ MCD_SET_VAR(var, 27, (u32)0x00000000); /* inc[3] */
+ MCD_SET_VAR(var, 28, (u32)0x80000001); /* inc[4] */
+ MCD_SET_VAR(var, 29, (u32)0x40000000); /* inc[5] */
+
+ /* Set the task's Enable bit in its Task Control Register */
+ tcrValue = readw(&MCD_dmaBar->taskControl[channel]);
+ writew(tcrValue | 0x8000, &MCD_dmaBar->taskControl[channel]);
+}
+
+
+/*
+ * Task 2
+ */
+
+void MCD_startDmaChainEu(int *currBD, short srcIncr, short destIncr,
+ int xferSize, short xferSizeIncr, int *cSave,
+ struct TaskTableEntry *taskTable, int channel)
+{
+ u32 var = taskTable[channel].varTab;
+ u16 tcrValue;
+
+ MCD_SET_VAR(var, 3, (u32)currBD); /* var[3] */
+ MCD_SET_VAR(var, 25, U16PAIR(0xe000, srcIncr)); /* inc[1] */
+ MCD_SET_VAR(var, 24, U16PAIR(0xe000, destIncr)); /* inc[0] */
+ MCD_SET_VAR(var, 12, (u32)xferSize); /* var[12] */
+ MCD_SET_VAR(var, 26, U16PAIR(0x2000, xferSizeIncr)); /* inc[2] */
+ MCD_SET_VAR(var, 0, (u32)cSave); /* var[0] */
+ MCD_SET_VAR(var, 1, (u32)0x00000000); /* var[1] */
+ MCD_SET_VAR(var, 2, (u32)0x00000000); /* var[2] */
+ MCD_SET_VAR(var, 4, (u32)0x00000000); /* var[4] */
+ MCD_SET_VAR(var, 5, (u32)0x00000000); /* var[5] */
+ MCD_SET_VAR(var, 6, (u32)0x00000000); /* var[6] */
+ MCD_SET_VAR(var, 7, (u32)0x00000000); /* var[7] */
+ MCD_SET_VAR(var, 8, (u32)0x00000000); /* var[8] */
+ MCD_SET_VAR(var, 9, (u32)0x00000000); /* var[9] */
+ MCD_SET_VAR(var, 10, (u32)0x00000000); /* var[10] */
+ MCD_SET_VAR(var, 11, (u32)0x00000000); /* var[11] */
+ MCD_SET_VAR(var, 13, (u32)0x00000000); /* var[13] */
+ MCD_SET_VAR(var, 14, (u32)0x80000000); /* var[14] */
+ MCD_SET_VAR(var, 15, (u32)0x00000010); /* var[15] */
+ MCD_SET_VAR(var, 16, (u32)0x00000001); /* var[16] */
+ MCD_SET_VAR(var, 17, (u32)0x00000004); /* var[17] */
+ MCD_SET_VAR(var, 18, (u32)0x08000000); /* var[18] */
+ MCD_SET_VAR(var, 27, (u32)0x00000000); /* inc[3] */
+ MCD_SET_VAR(var, 28, (u32)0x80000000); /* inc[4] */
+ MCD_SET_VAR(var, 29, (u32)0xc0000000); /* inc[5] */
+ MCD_SET_VAR(var, 30, (u32)0x80000001); /* inc[6] */
+ MCD_SET_VAR(var, 31, (u32)0x40000000); /* inc[7] */
+
+ /* Set the task's Enable bit in its Task Control Register */
+ tcrValue = readw(&MCD_dmaBar->taskControl[channel]);
+ writew(tcrValue | 0x8000, &MCD_dmaBar->taskControl[channel]);
+}
+
+
+/*
+ * Task 3
+ */
+
+void MCD_startDmaSingleEu(char *srcAddr, short srcIncr, char *destAddr,
+ short destIncr, int dmaSize, short xferSizeIncr,
+ int flags, int *currBD, int *cSave,
+ struct TaskTableEntry *taskTable, int channel)
+{
+ u32 var = taskTable[channel].varTab;
+ u16 tcrValue;
+
+ MCD_SET_VAR(var, 8, (u32)srcAddr); /* var[8] */
+ MCD_SET_VAR(var, 25, U16PAIR(0xe000, srcIncr)); /* inc[1] */
+ MCD_SET_VAR(var, 3, (u32)destAddr); /* var[3] */
+ MCD_SET_VAR(var, 24, U16PAIR(0xe000, destIncr)); /* inc[0] */
+ MCD_SET_VAR(var, 4, (u32)dmaSize); /* var[4] */
+ MCD_SET_VAR(var, 26, U16PAIR(0x2000, xferSizeIncr)); /* inc[2] */
+ MCD_SET_VAR(var, 6, (u32)flags); /* var[6] */
+ MCD_SET_VAR(var, 2, (u32)currBD); /* var[2] */
+ MCD_SET_VAR(var, 0, (u32)cSave); /* var[0] */
+ MCD_SET_VAR(var, 1, (u32)0x00000000); /* var[1] */
+ MCD_SET_VAR(var, 5, (u32)0x00000000); /* var[5] */
+ MCD_SET_VAR(var, 7, (u32)0x00000000); /* var[7] */
+ MCD_SET_VAR(var, 9, (u32)0x00000000); /* var[9] */
+ MCD_SET_VAR(var, 10, (u32)0x00000001); /* var[10] */
+ MCD_SET_VAR(var, 11, (u32)0x00000004); /* var[11] */
+ MCD_SET_VAR(var, 12, (u32)0x08000000); /* var[12] */
+ MCD_SET_VAR(var, 27, (u32)0x00000000); /* inc[3] */
+ MCD_SET_VAR(var, 28, (u32)0xc0000000); /* inc[4] */
+ MCD_SET_VAR(var, 29, (u32)0x80000000); /* inc[5] */
+ MCD_SET_VAR(var, 30, (u32)0x80000001); /* inc[6] */
+ MCD_SET_VAR(var, 31, (u32)0x40000000); /* inc[7] */
+
+ /* Set the task's Enable bit in its Task Control Register */
+ tcrValue = readw(&MCD_dmaBar->taskControl[channel]);
+ writew(tcrValue | 0x8000, &MCD_dmaBar->taskControl[channel]);
+}
+
+
+/*
+ * Task 4
+ */
+
+void MCD_startDmaENetRcv(char *bDBase, char *currBD, char *rcvFifoPtr,
+ struct TaskTableEntry *taskTable, int channel)
+{
+ u32 var = taskTable[channel].varTab;
+ u16 tcrValue;
+
+ MCD_SET_VAR(var, 0, (u32)bDBase); /* var[0] */
+ MCD_SET_VAR(var, 3, (u32)currBD); /* var[3] */
+ MCD_SET_VAR(var, 6, (u32)rcvFifoPtr); /* var[6] */
+ MCD_SET_VAR(var, 1, (u32)0x00000000); /* var[1] */
+ MCD_SET_VAR(var, 2, (u32)0x00000000); /* var[2] */
+ MCD_SET_VAR(var, 4, (u32)0x00000000); /* var[4] */
+ MCD_SET_VAR(var, 5, (u32)0x00000000); /* var[5] */
+ MCD_SET_VAR(var, 7, (u32)0x00000000); /* var[7] */
+ MCD_SET_VAR(var, 8, (u32)0x00000000); /* var[8] */
+ MCD_SET_VAR(var, 9, (u32)0x0000ffff); /* var[9] */
+ MCD_SET_VAR(var, 10, (u32)0x30000000); /* var[10] */
+ MCD_SET_VAR(var, 11, (u32)0x0fffffff); /* var[11] */
+ MCD_SET_VAR(var, 12, (u32)0x00000008); /* var[12] */
+ MCD_SET_VAR(var, 24, (u32)0x00000000); /* inc[0] */
+ MCD_SET_VAR(var, 25, (u32)0x60000000); /* inc[1] */
+ MCD_SET_VAR(var, 26, (u32)0x20000004); /* inc[2] */
+ MCD_SET_VAR(var, 27, (u32)0x40000000); /* inc[3] */
+
+ /* Set the task's Enable bit in its Task Control Register */
+ tcrValue = readw(&MCD_dmaBar->taskControl[channel]);
+ writew(tcrValue | 0x8000, &MCD_dmaBar->taskControl[channel]);
+}
+
+
+/*
+ * Task 5
+ */
+
+void MCD_startDmaENetXmit(char *bDBase, char *currBD, char *xmitFifoPtr,
+ struct TaskTableEntry *taskTable, int channel)
+{
+ u32 var = taskTable[channel].varTab;
+ u16 tcrValue;
+
+ MCD_SET_VAR(var, 0, (u32)bDBase); /* var[0] */
+ MCD_SET_VAR(var, 3, (u32)currBD); /* var[3] */
+ MCD_SET_VAR(var, 11, (u32)xmitFifoPtr); /* var[11] */
+ MCD_SET_VAR(var, 1, (u32)0x00000000); /* var[1] */
+ MCD_SET_VAR(var, 2, (u32)0x00000000); /* var[2] */
+ MCD_SET_VAR(var, 4, (u32)0x00000000); /* var[4] */
+ MCD_SET_VAR(var, 5, (u32)0x00000000); /* var[5] */
+ MCD_SET_VAR(var, 6, (u32)0x00000000); /* var[6] */
+ MCD_SET_VAR(var, 7, (u32)0x00000000); /* var[7] */
+ MCD_SET_VAR(var, 8, (u32)0x00000000); /* var[8] */
+ MCD_SET_VAR(var, 9, (u32)0x00000000); /* var[9] */
+ MCD_SET_VAR(var, 10, (u32)0x00000000); /* var[10] */
+ MCD_SET_VAR(var, 12, (u32)0x00000000); /* var[12] */
+ MCD_SET_VAR(var, 13, (u32)0x0000ffff); /* var[13] */
+ MCD_SET_VAR(var, 14, (u32)0xffffffff); /* var[14] */
+ MCD_SET_VAR(var, 15, (u32)0x00000004); /* var[15] */
+ MCD_SET_VAR(var, 16, (u32)0x00000008); /* var[16] */
+ MCD_SET_VAR(var, 24, (u32)0x00000000); /* inc[0] */
+ MCD_SET_VAR(var, 25, (u32)0x60000000); /* inc[1] */
+ MCD_SET_VAR(var, 26, (u32)0x40000000); /* inc[2] */
+ MCD_SET_VAR(var, 27, (u32)0xc000fffc); /* inc[3] */
+ MCD_SET_VAR(var, 28, (u32)0xe0000004); /* inc[4] */
+ MCD_SET_VAR(var, 29, (u32)0x80000000); /* inc[5] */
+ MCD_SET_VAR(var, 30, (u32)0x4000ffff); /* inc[6] */
+ MCD_SET_VAR(var, 31, (u32)0xe0000001); /* inc[7] */
+
+ /* Set the task's Enable bit in its Task Control Register */
+ tcrValue = readw(&MCD_dmaBar->taskControl[channel]);
+ writew(tcrValue | 0x8000, &MCD_dmaBar->taskControl[channel]);
+}
diff --git a/drivers/dma/fsl_mcd_dma/MCD_tasksInit.h b/drivers/dma/fsl_mcd_dma/MCD_tasksInit.h
new file mode 100644
index 0000000..0a9722c
--- /dev/null
+++ b/drivers/dma/fsl_mcd_dma/MCD_tasksInit.h
@@ -0,0 +1,76 @@
+/*
+ * drivers/dma/MCD_tasksInit.h
+ *
+ * Copyright (C) 2004-2008 Freescale Semiconductor, Inc.
+ * Kurt Mahan <kmahan at freescale.com>
+ *
+ * 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
+ */
+#ifndef MCD_TSK_INIT_H
+#define MCD_TSK_INIT_H 1
+
+/*
+ * Autogenerated - Do not edit!
+ */
+
+/*
+ * Task 0
+ */
+void MCD_startDmaChainNoEu(int *currBD, short srcIncr, short destIncr,
+ int xferSize, short xferSizeIncr, int *cSave,
+ struct TaskTableEntry *taskTable, int channel);
+
+
+/*
+ * Task 1
+ */
+void MCD_startDmaSingleNoEu(char *srcAddr, short srcIncr, char *destAddr,
+ short destIncr, int dmaSize, short xferSizeIncr,
+ int flags, int *currBD, int *cSave,
+ struct TaskTableEntry *taskTable, int channel);
+
+
+/*
+ * Task 2
+ */
+void MCD_startDmaChainEu(int *currBD, short srcIncr, short destIncr,
+ int xferSize, short xferSizeIncr, int *cSave,
+ struct TaskTableEntry *taskTable, int channel);
+
+
+/*
+ * Task 3
+ */
+void MCD_startDmaSingleEu(char *srcAddr, short srcIncr, char *destAddr,
+ short destIncr, int dmaSize, short xferSizeIncr,
+ int flags, int *currBD, int *cSave,
+ struct TaskTableEntry *taskTable, int channel);
+
+
+/*
+ * Task 4
+ */
+void MCD_startDmaENetRcv(char *bDBase, char *currBD, char *rcvFifoPtr,
+ struct TaskTableEntry *taskTable, int channel);
+
+
+/*
+ * Task 5
+ */
+void MCD_startDmaENetXmit(char *bDBase, char *currBD, char *xmitFifoPtr,
+ struct TaskTableEntry *taskTable, int channel);
+
+#endif /* MCD_TSK_INIT_H */
diff --git a/drivers/dma/fsl_mcd_dma/Makefile b/drivers/dma/fsl_mcd_dma/Makefile
new file mode 100644
index 0000000..6bdd725
--- /dev/null
+++ b/drivers/dma/fsl_mcd_dma/Makefile
@@ -0,0 +1 @@
+obj-y += MCD_dmaApi.o MCD_tasks.o MCD_tasksInit.o
diff --git a/include/linux/MCD_dma.h b/include/linux/MCD_dma.h
new file mode 100644
index 0000000..da0a928
--- /dev/null
+++ b/include/linux/MCD_dma.h
@@ -0,0 +1,376 @@
+/*
+ * drivers/dma/MCD_dma.h
+ *
+ * Copyright (C) 2004-2008 Freescale Semiconductor, Inc.
+ * Kurt Mahan <kmahan at freescale.com>
+ *
+ * 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
+ */
+#ifndef _MCD_API_H
+#define _MCD_API_H
+
+/*
+ * Turn Execution Unit tasks ON (#define) or OFF (#undef)
+ */
+#undef MCD_INCLUDE_EU
+
+/*
+ * Number of DMA channels
+ */
+#define NCHANNELS 16
+
+/*
+ * Total number of variants
+ */
+#ifdef MCD_INCLUDE_EU
+#define NUMOFVARIANTS 6
+#else
+#define NUMOFVARIANTS 4
+#endif
+
+/*
+ * Define sizes of the various tables
+ */
+#define TASK_TABLE_SIZE (NCHANNELS*32)
+#define VAR_TAB_SIZE (128)
+#define CONTEXT_SAVE_SIZE (128)
+#define FUNCDESC_TAB_SIZE (256)
+
+#ifdef MCD_INCLUDE_EU
+#define FUNCDESC_TAB_NUM 16
+#else
+#define FUNCDESC_TAB_NUM 1
+#endif
+
+
+#ifndef DEFINESONLY
+
+#include <asm-generic/int-ll64.h>
+
+/*
+ * These structures represent the internal registers of the
+ * multi-channel DMA
+ */
+struct dmaRegs {
+ u32 taskbar; /* task table base address register */
+ u32 currPtr;
+ u32 endPtr;
+ u32 varTablePtr;
+ u16 dma_rsvd0;
+ u16 ptdControl; /* ptd control */
+ u32 intPending; /* interrupt pending register */
+ u32 intMask; /* interrupt mask register */
+ u16 taskControl[16]; /* task control registers */
+ u8 priority[32]; /* priority registers */
+ u32 initiatorMux; /* initiator mux control */
+ u32 taskSize0; /* task size control register 0. */
+ u32 taskSize1; /* task size control register 1. */
+ u32 dma_rsvd1; /* reserved */
+ u32 dma_rsvd2; /* reserved */
+ u32 debugComp1; /* debug comparator 1 */
+ u32 debugComp2; /* debug comparator 2 */
+ u32 debugControl; /* debug control */
+ u32 debugStatus; /* debug status */
+ u32 ptdDebug; /* priority task decode debug */
+ u32 dma_rsvd3[31]; /* reserved */
+};
+
+extern struct dmaRegs *MCD_dmaBar;
+
+#endif
+
+/*
+ * PTD contrl reg bits
+ */
+#define PTD_CTL_TSK_PRI 0x8000
+#define PTD_CTL_COMM_PREFETCH 0x0001
+
+/*
+ * Task Control reg bits and field masks
+ */
+#define TASK_CTL_EN 0x8000
+#define TASK_CTL_VALID 0x4000
+#define TASK_CTL_ALWAYS 0x2000
+#define TASK_CTL_INIT_MASK 0x1f00
+#define TASK_CTL_ASTRT 0x0080
+#define TASK_CTL_HIPRITSKEN 0x0040
+#define TASK_CTL_HLDINITNUM 0x0020
+#define TASK_CTL_ASTSKNUM_MASK 0x000f
+
+/*
+ * Priority reg bits and field masks
+ */
+#define PRIORITY_HLD 0x80
+#define PRIORITY_PRI_MASK 0x07
+
+/*
+ * Debug Control reg bits and field masks
+ */
+#define DBG_CTL_BLOCK_TASKS_MASK 0xffff0000
+#define DBG_CTL_AUTO_ARM 0x00008000
+#define DBG_CTL_BREAK 0x00004000
+#define DBG_CTL_COMP1_TYP_MASK 0x00003800
+#define DBG_CTL_COMP2_TYP_MASK 0x00000070
+#define DBG_CTL_EXT_BREAK 0x00000004
+#define DBG_CTL_INT_BREAK 0x00000002
+
+/*
+ * PTD Debug reg selector addresses
+ * This reg must be written with a value to show the contents of
+ * one of the desired internal register.
+ */
+#define PTD_DBG_REQ 0x00 /* shows the state of 31 initiators */
+#define PTD_DBG_TSK_VLD_INIT 0x01 /* shows which 16 tasks are valid and
+ have initiators asserted */
+
+
+/*
+ * General return values
+ */
+#define MCD_OK 0
+#define MCD_ERROR -1
+#define MCD_TABLE_UNALIGNED -2
+#define MCD_CHANNEL_INVALID -3
+
+/*
+ * MCD_initDma input flags
+ */
+#define MCD_RELOC_TASKS 0x00000001
+#define MCD_NO_RELOC_TASKS 0x00000000
+#define MCD_COMM_PREFETCH_EN 0x00000002 /* Commbus Prefetching - MCF547x/548x ONLY */
+
+/*
+ * MCD_dmaStatus Status Values for each channel
+ */
+#define MCD_NO_DMA 1 /* No DMA has been requested since reset */
+#define MCD_IDLE 2 /* DMA active, but the initiator is currently inactive */
+#define MCD_RUNNING 3 /* DMA active, and the initiator is currently active */
+#define MCD_PAUSED 4 /* DMA active but it is currently paused */
+#define MCD_HALTED 5 /* the most recent DMA has been killed with MCD_killTask() */
+#define MCD_DONE 6 /* the most recent DMA has completed. */
+
+
+/*
+ * MCD_startDma parameter defines
+ */
+
+/*
+ * Constants for the funcDesc parameter
+ */
+/* Byte swapping: */
+#define MCD_NO_BYTE_SWAP 0x00045670 /* to disable byte swapping. */
+#define MCD_BYTE_REVERSE 0x00076540 /* to reverse the bytes of each u32 of the DMAed data. */
+#define MCD_U16_REVERSE 0x00067450 /* to reverse the 16-bit halves of
+ each 32-bit data value being DMAed.*/
+#define MCD_U16_BYTE_REVERSE 0x00054760 /* to reverse the byte halves of each
+ 16-bit half of each 32-bit data value DMAed */
+#define MCD_NO_BIT_REV 0x00000000 /* do not reverse the bits of each byte DMAed. */
+#define MCD_BIT_REV 0x00088880 /* reverse the bits of each byte DMAed */
+/* CRCing: */
+#define MCD_CRC16 0xc0100000 /* to perform CRC-16 on DMAed data. */
+#define MCD_CRCCCITT 0xc0200000 /* to perform CRC-CCITT on DMAed data. */
+#define MCD_CRC32 0xc0300000 /* to perform CRC-32 on DMAed data. */
+#define MCD_CSUMINET 0xc0400000 /* to perform internet checksums on DMAed data.*/
+#define MCD_NO_CSUM 0xa0000000 /* to perform no checksumming. */
+
+#define MCD_FUNC_NOEU1 (MCD_NO_BYTE_SWAP | MCD_NO_BIT_REV | MCD_NO_CSUM)
+#define MCD_FUNC_NOEU2 (MCD_NO_BYTE_SWAP | MCD_NO_CSUM)
+
+/*
+ * Constants for the flags parameter
+ */
+#define MCD_TT_FLAGS_RL 0x00000001 /* Read line */
+#define MCD_TT_FLAGS_CW 0x00000002 /* Combine Writes */
+#define MCD_TT_FLAGS_SP 0x00000004 /* Speculative prefetch(XLB) MCF547x/548x ONLY */
+#define MCD_TT_FLAGS_PI 0x00000040 /* Precise Increment */
+#define MCD_TT_FLAGS_MASK 0x000000ff
+#define MCD_TT_FLAGS_DEF (MCD_TT_FLAGS_RL | MCD_TT_FLAGS_CW)
+
+#define MCD_SINGLE_DMA 0x00000100 /* Unchained DMA */
+#define MCD_CHAIN_DMA /* TBD */
+#define MCD_EU_DMA /* TBD */
+#define MCD_FECTX_DMA 0x00001000 /* FEC TX ring DMA */
+#define MCD_FECRX_DMA 0x00002000 /* FEC RX ring DMA */
+
+
+/* these flags are valid for MCD_startDma and the chained buffer descriptors */
+#define MCD_BUF_READY 0x80000000 /* indicates that this buffer is now under the DMA's control */
+#define MCD_WRAP 0x20000000 /* to tell the FEC Dmas to wrap to the first BD */
+#define MCD_INTERRUPT 0x10000000 /* to generate an interrupt after completion of the DMA. */
+#define MCD_END_FRAME 0x08000000 /* tell the DMA to end the frame when transferring
+ last byte of data in buffer */
+#define MCD_CRC_RESTART 0x40000000 /* to empty out the accumulated checksum
+ prior to performing the DMA. */
+
+/* Defines for the FEC buffer descriptor control/status word */
+#define MCD_FEC_BUF_READY 0x8000
+#define MCD_FEC_WRAP 0x2000
+#define MCD_FEC_INTERRUPT 0x1000
+#define MCD_FEC_END_FRAME 0x0800
+
+
+/*
+ * Defines for general intuitiveness
+ */
+
+#define MCD_TRUE 1
+#define MCD_FALSE 0
+
+/*
+ * Three different cases for destination and source.
+ */
+#define MINUS1 -1
+#define ZERO 0
+#define PLUS1 1
+
+#ifndef DEFINESONLY
+
+/* Task Table Entry struct */
+struct TaskTableEntry {
+ u32 TDTstart; /* task descriptor table start */
+ u32 TDTend; /* task descriptor table end */
+ u32 varTab; /* variable table start */
+ u32 FDTandFlags; /* function descriptor table start and flags */
+ u32 descAddrAndStatus;
+ u32 modifiedVarTab;
+ u32 contextSaveSpace; /* context save space start */
+ u32 literalBases;
+};
+
+/*
+ * These are the real and model task tables as generated by the
+ * build process
+ */
+/* let's match the current definition in MCD_tasks.c */
+extern const u32 MCD_realTaskTableSrc[];
+extern const u32 MCD_modelTaskTableSrc[];
+
+extern u32 MCD_funcDescTab0[];
+
+/* Chained buffer descriptor */
+struct MCD_bufDesc {
+ u32 flags; /* flags describing the DMA */
+ u32 csumResult; /* checksum from checksumming performed since last checksum reset */
+ s8 *srcAddr; /* the address to move data from */
+ s8 *destAddr; /* the address to move data to */
+ s8 *lastDestAddr; /* the last address written to */
+ u32 dmaSize; /* the number of bytes to transfer independent of the transfer size */
+ struct MCD_bufDesc *next; /* next buffer descriptor in chain */
+ u32 info; /* private information about this descriptor; DMA does not affect it */
+};
+
+extern struct MCD_bufDesc MCD_singleBufDescs[NCHANNELS];
+
+/* Progress Query struct */
+struct MCD_XferProg {
+ s8 *lastSrcAddr; /* the most-recent or last, post-increment source address */
+ s8 *lastDestAddr; /* the most-recent or last, post-increment destination address */
+ u32 dmaSize; /* the amount of data transferred for the current buffer */
+ struct MCD_bufDesc *currBufDesc;/* pointer to the current buffer descriptor being DMAed */
+};
+
+
+/* FEC buffer descriptor */
+struct MCD_bufDescFec {
+ u16 statCtrl;
+ u16 length;
+ u32 dataPointer;
+};
+
+
+/*************************************************************************/
+/*
+ * API function Prototypes - see MCD_dmaApi.c for further notes
+ */
+
+/*
+ * MCD_startDma starts a particular kind of DMA .
+ */
+int MCD_startDma(
+ int channel, /* the channel on which to run the DMA */
+ s8 *srcAddr, /* the address to move data from, or buffer-descriptor address */
+ s16 srcIncr, /* the amount to increment the source address per transfer */
+ s8 *destAddr, /* the address to move data to */
+ s16 destIncr, /* the amount to increment the destination address per transfer */
+ u32 dmaSize, /* the number of bytes to transfer independent of the transfer size */
+ u32 xferSize, /* the number of bytes in each data movement (1, 2, or 4) */
+ u32 initiator, /* what device initiates the DMA */
+ int priority, /* priority of the DMA */
+ u32 flags, /* flags describing the DMA */
+ u32 funcDesc /* a description of byte swapping, bit swapping, and CRC actions */
+);
+
+/*
+ * MCD_initDma() initializes the DMA API by setting up a pointer to the DMA
+ * registers, relocating and creating the appropriate task structures, and
+ * setting up some global settings
+ */
+int MCD_initDma(struct dmaRegs *sDmaBarAddr, void *taskTableDest, u32 flags);
+
+/*
+ * MCD_dmaStatus() returns the status of the DMA on the requested channel.
+ */
+int MCD_dmaStatus(int channel);
+
+/*
+ * MCD_XferProgrQuery() returns progress of DMA on requested channel
+ */
+int MCD_XferProgrQuery(int channel, struct MCD_XferProg *progRep);
+
+/*
+ * MCD_killDma() halts the DMA on the requested channel, without any
+ * intention of resuming the DMA.
+ */
+int MCD_killDma(int channel);
+
+/*
+ * MCD_continDma() continues a DMA which as stopped due to encountering an
+ * unready buffer descriptor.
+ */
+int MCD_continDma(int channel);
+
+/*
+ * MCD_pauseDma() pauses the DMA on the given channel ( if any DMA is
+ * running on that channel).
+ */
+int MCD_pauseDma(int channel);
+
+/*
+ * MCD_resumeDma() resumes the DMA on a given channel (if any DMA is
+ * running on that channel).
+ */
+int MCD_resumeDma(int channel);
+
+/*
+ * MCD_csumQuery provides the checksum/CRC after performing a non-chained DMA
+ */
+int MCD_csumQuery(int channel, u32 *csum);
+
+/*
+ * MCD_getCodeSize provides the packed size required by the microcoded task
+ * and structures.
+ */
+int MCD_getCodeSize(void);
+
+/*
+ * MCD_getVersion provides a pointer to a version string and returns a
+ * version number.
+ */
+int MCD_getVersion(char **longVersion);
+
+#endif /* DEFINESONLY */
+
+#endif /* _MCD_API_H */
--
1.7.1
Philippe De Muyter
2012-09-24 08:05:19 UTC
Permalink
This is a fully functionnal ethernet driver for the MCF547x and MCF548x
processors, tested on the M5484EVB board and on a custom board inpired
by the M5484EVB board. It implements a FEC+DMA driver and a mdio driver.

Original work was made by freescale for 2.6.25, but never submitted for
mainline, but cache support, mdio driver, phylib support, general
cleanup and 2.6.30-3.6 ports are mine.

Signed-off-by: Philippe De Muyter <phdm at macqel.be>
---
arch/m68k/include/asm/m54xxsim.h | 2 +
arch/m68k/kernel/setup_no.c | 5 +
drivers/net/ethernet/freescale/Kconfig | 26 +-
drivers/net/ethernet/freescale/Makefile | 1 +
drivers/net/ethernet/freescale/fec_m54xx.c | 1506 ++++++++++++++++++++++++++++
drivers/net/ethernet/freescale/fec_m54xx.h | 144 +++
6 files changed, 1683 insertions(+), 1 deletions(-)
create mode 100644 drivers/net/ethernet/freescale/fec_m54xx.c
create mode 100644 drivers/net/ethernet/freescale/fec_m54xx.h

diff --git a/arch/m68k/include/asm/m54xxsim.h b/arch/m68k/include/asm/m54xxsim.h
index f5531d5..b4c81bf 100644
--- a/arch/m68k/include/asm/m54xxsim.h
+++ b/arch/m68k/include/asm/m54xxsim.h
@@ -46,6 +46,8 @@
#define MCF_IRQ_UART2 (MCFINT_VECBASE + 33)
#define MCF_IRQ_UART3 (MCFINT_VECBASE + 32)
#define MCF_IRQ_DMA (MCFINT_VECBASE + 48) /* DMA */
+#define MCF_IRQ_FEC0 (MCFINT_VECBASE + 39) /* FEC0 */
+#define MCF_IRQ_FEC1 (MCFINT_VECBASE + 38) /* FEC1 */

/*
* Generic GPIO support
diff --git a/arch/m68k/kernel/setup_no.c b/arch/m68k/kernel/setup_no.c
index 71fb299..10131b4 100644
--- a/arch/m68k/kernel/setup_no.c
+++ b/arch/m68k/kernel/setup_no.c
@@ -261,6 +261,11 @@ void __init setup_arch(char **cmdline_p)
paging_init();
}

+const char *machdep_get_mac_address(int i)
+{
+ return 0;
+}
+
/*
* Get CPU information for use by the procfs.
*/
diff --git a/drivers/net/ethernet/freescale/Kconfig b/drivers/net/ethernet/freescale/Kconfig
index 3574e14..64d8fc6 100644
--- a/drivers/net/ethernet/freescale/Kconfig
+++ b/drivers/net/ethernet/freescale/Kconfig
@@ -7,7 +7,7 @@ config NET_VENDOR_FREESCALE
default y
depends on FSL_SOC || QUICC_ENGINE || CPM1 || CPM2 || PPC_MPC512x || \
M523x || M527x || M5272 || M528x || M520x || M532x || \
- ARCH_MXC || ARCH_MXS || (PPC_MPC52xx && PPC_BESTCOMM)
+ M54xx || ARCH_MXC || ARCH_MXS || (PPC_MPC52xx && PPC_BESTCOMM)
---help---
If you have a network (Ethernet) card belonging to this class, say Y
and read the Ethernet-HOWTO, available from
@@ -30,6 +30,30 @@ config FEC
Say Y here if you want to use the built-in 10/100 Fast ethernet
controller on some Motorola ColdFire and Freescale i.MX processors.

+config FEC_54xx
+ tristate "MCF547x/MCF548x Fast Ethernet Controller support"
+ depends on M54xx
+ default y
+ select CRC32
+ select PHYLIB
+ select M54xx_DMA
+ help
+ The MCF547x and MCF548x have a built-in Fast Ethernet Controller.
+ This is not the same FEC controller as on other ColdFire as here
+ the DMA controller is not reserved to the FEC driver, but made
+ available for general DMA work.
+ Saying Y here will include support for this device in the kernel.
+
+config FEC2
+ bool "Second FEC ethernet controller (on some ColdFire CPUs)"
+ depends on FEC || FEC_54xx
+ default y
+ help
+ Say Y here if you want to use the second built-in 10/100 Fast
+ ethernet controller on some Motorola ColdFire processors. On M54xx,
+ If your second ethernet port is not connected, saying N here will
+ free 2 DMA channels and allow you to use FEC io ports as GPIO's.
+
config FEC_MPC52xx
tristate "FEC MPC52xx driver"
depends on PPC_MPC52xx && PPC_BESTCOMM
diff --git a/drivers/net/ethernet/freescale/Makefile b/drivers/net/ethernet/freescale/Makefile
index 1752488..05a5022 100644
--- a/drivers/net/ethernet/freescale/Makefile
+++ b/drivers/net/ethernet/freescale/Makefile
@@ -3,6 +3,7 @@
#

obj-$(CONFIG_FEC) += fec.o
+obj-$(CONFIG_FEC_54xx) += fec_m54xx.o
obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx.o
ifeq ($(CONFIG_FEC_MPC52xx_MDIO),y)
obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx_phy.o
diff --git a/drivers/net/ethernet/freescale/fec_m54xx.c b/drivers/net/ethernet/freescale/fec_m54xx.c
new file mode 100644
index 0000000..b28c89a
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fec_m54xx.c
@@ -0,0 +1,1506 @@
+/*
+ * Performance and stability improvements: (C) Copyright 2008,
+ * Daniel Krueger, SYSTEC electronic GmbH
+ *
+ * Code crunched to get it to work on 2.6.24 -- FEC cleanup coming
+ * soon -- Kurt Mahan
+ *
+ * 2.6.30 and above port, cleanup, cache support, netdev_ops, mdio,
+ * phy & ethtool support,
+ * (C) Copyright 2010-2012 Philippe De Muyter <phdm at macqel.be> Macq SA
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/crc32.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/bitops.h>
+
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+
+#include <asm/m54xxdma_api.h>
+#include <asm/m54xxsram.h>
+#include <asm/irq.h>
+#include <asm/cacheflush.h>
+/*
+ * txd's and rxd's are in System SRAM which is uncached
+ * real buffers are in sdram which is cached
+ */
+#define flush_and_invalidate_dcache() flush_cache_all()
+
+#include "fec_m54xx.h"
+#include <linux/phy.h>
+
+#ifdef CONFIG_FEC2
+#define FEC_MAX_PORTS 2
+#else
+#define FEC_MAX_PORTS 1
+#endif
+
+#define FEC_MII_TIMEOUT 1000 /* us */
+#define FEC_TX_TIMEOUT (1 * HZ)
+
+#define FEC_TX_BUF_NUMBER (8)
+#define FEC_RX_BUF_NUMBER (64)
+
+#define FEC_TX_INDEX_MASK (0x7)
+#define FEC_RX_INDEX_MASK (0x3f)
+
+#define MAC_ADDR_LEN 6
+
+#define VERSION "0.30"
+MODULE_DESCRIPTION("DMA Fast Ethernet Controller driver ver " VERSION);
+
+/* fec private */
+struct fec_priv {
+ struct net_device *netdev; /* owning net device */
+ void *fecpriv_txbuf[FEC_TX_BUF_NUMBER]; /* tx buffer ptrs */
+ struct MCD_bufDescFec *fecpriv_txdesc; /* tx descriptor ptrs */
+ /* fecpriv_current_tx changed only by fec_interrupt_fec_tx_handler */
+ unsigned int fecpriv_current_tx; /* current tx desc index */
+ /* fecpriv_next_tx changed only by fec_start_tx */
+ unsigned int fecpriv_next_tx; /* next tx desc index */
+ unsigned int fecpriv_current_rx; /* current rx desc index */
+ struct MCD_bufDescFec *fecpriv_rxdesc; /* rx descriptor ptrs */
+ struct sk_buff *askb_rx[FEC_RX_BUF_NUMBER]; /* rx SKB ptrs */
+ unsigned int fecpriv_initiator_rx; /* rx dma initiator */
+ unsigned int fecpriv_initiator_tx; /* tx dma initiator */
+ int fecpriv_fec_rx_channel; /* rx dma channel */
+ int fecpriv_fec_tx_channel; /* tx dma channel */
+ int fecpriv_rx_requestor; /* rx dma requestor */
+ int fecpriv_tx_requestor; /* tx dma requestor */
+ unsigned char *fecpriv_mac_addr; /* private fec mac addr */
+ struct net_device_stats fecpriv_stat; /* stats ptr */
+ spinlock_t fecpriv_lock;
+ int fecpriv_rxflag;
+ struct tasklet_struct fecpriv_tasklet_reinit;
+ int index; /* fec hw number */
+#if 0
+ int in_poll;
+#endif
+
+ int duplex;
+ int speed;
+
+ /* phy link details */
+ int phy_addr;
+ struct phy_device *phydev;
+ enum phy_state link;
+
+ /* MDIO bus details */
+ unsigned int phy_speed;
+ struct completion mdio_done;
+};
+
+/* default fec0 address */
+unsigned char fec0_addr[MAC_ADDR_LEN] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x50 };
+
+#ifdef CONFIG_FEC2
+/* default fec1 address */
+unsigned char fec1_addr[MAC_ADDR_LEN] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x51 };
+#endif
+
+extern const char *machdep_get_mac_address(int i);
+
+/* based on generic_adjust_link from fs_enet-main.c */
+static void fec_adjust_link(struct net_device *dev)
+{
+ struct fec_priv *fp = netdev_priv(dev);
+ struct phy_device *phydev = fp->phydev;
+ int new_state = 0;
+
+ if (phydev->link != PHY_DOWN) {
+ if (phydev->duplex != fp->duplex) {
+ unsigned long base_addr = (unsigned long) dev->base_addr;
+ u32 rcntrl;
+ u32 tcntrl;
+
+ new_state = 1;
+ fp->duplex = phydev->duplex;
+
+ rcntrl = readl(base_addr + FEC_RCR);
+ tcntrl = readl(base_addr + FEC_TCR);
+
+ rcntrl &= ~FEC_RCR_DRT;
+ tcntrl &= ~FEC_TCR_FDEN;
+ if (phydev->duplex == DUPLEX_FULL)
+ /* Enable the full duplex mode */
+ tcntrl |= FEC_TCR_FDEN;
+ else
+ /* Disable reception of frames while transmitting */
+ rcntrl |= FEC_RCR_DRT;
+
+ writel(rcntrl, base_addr + FEC_RCR);
+ writel(tcntrl, base_addr + FEC_TCR);
+ }
+
+ if (phydev->speed != fp->speed) {
+ new_state = 1;
+ fp->speed = phydev->speed;
+ }
+
+ if (fp->link == PHY_DOWN) {
+ new_state = 1;
+ fp->link = phydev->link;
+ }
+
+ } else if (fp->link) {
+ new_state = 1;
+ fp->link = PHY_DOWN;
+ fp->speed = 0;
+ fp->duplex = -1;
+ }
+
+ if (new_state /* && netif_msg_link(fp)*/)
+ phy_print_status(phydev);
+}
+
+static int fec_init_phy(struct net_device *dev)
+{
+ struct fec_priv *fp = netdev_priv(dev);
+ struct phy_device *phydev;
+ char phy_id[MII_BUS_ID_SIZE + 3];
+
+ snprintf(phy_id, sizeof(phy_id), "%x:%02x", 0xfec, fp->phy_addr);
+
+ fp->link = PHY_DOWN;
+ fp->speed = 0;
+ fp->duplex = -1;
+
+ phydev = phy_connect(dev, phy_id, &fec_adjust_link, 0, PHY_INTERFACE_MODE_MII);
+ if (IS_ERR(phydev)) {
+ dev_err(&dev->dev, "phy_connect failed\n");
+ return PTR_ERR(phydev);
+ }
+ dev_info(&dev->dev,
+ "attached phy %i (OUI/model = %06x/%02x) to driver %s\n",
+ phydev->addr, (phydev->phy_id >> 10) & 0x3fffff,
+ (phydev->phy_id >> 4) & 0x3f, phydev->drv->name);
+
+ fp->phydev = phydev;
+
+ return 0;
+}
+
+static int fec_phy_start(struct net_device *dev)
+{
+ struct fec_priv *fp = netdev_priv(dev);
+ int err;
+
+ /*
+ * on the freescale dev board, a DUAL phy is used :
+ * PHY 0 for FEC 0 and PHY 1 for FEC 1
+ */
+ fp->phy_addr = fp->index;
+
+ err = fec_init_phy(dev);
+ if (err) {
+ dev_err(&dev->dev, "fec_init_phy failed\n");
+ return err;
+ }
+
+ /* reset phy - this also wakes it from PDOWN */
+ phy_write(fp->phydev, MII_BMCR, BMCR_RESET);
+ phy_start(fp->phydev);
+
+ return 0;
+}
+
+/* ethtool interface -- copy of fec_mpc52xx.c */
+#if 0
+static void fec_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
+ strcpy(info->driver, DRIVER_NAME);
+}
+#endif
+
+static int fec_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct fec_priv *priv = netdev_priv(dev);
+
+ if (!priv->phydev)
+ return -ENODEV;
+
+ return phy_ethtool_gset(priv->phydev, cmd);
+}
+
+static int fec_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct fec_priv *priv = netdev_priv(dev);
+
+ if (!priv->phydev)
+ return -ENODEV;
+
+ return phy_ethtool_sset(priv->phydev, cmd);
+}
+
+#if 0
+static u32 fec_get_msglevel(struct net_device *dev)
+{
+ struct fec_priv *priv = netdev_priv(dev);
+ return priv->msg_enable;
+}
+
+static void fec_set_msglevel(struct net_device *dev, u32 level)
+{
+ struct fec_priv *priv = netdev_priv(dev);
+ priv->msg_enable = level;
+}
+#endif
+
+static const struct ethtool_ops fec_ethtool_ops = {
+#if 0
+ .get_drvinfo = fec_get_drvinfo,
+#endif
+ .get_settings = fec_get_settings,
+ .set_settings = fec_set_settings,
+ .get_link = ethtool_op_get_link,
+#if 0
+ .get_msglevel = fec_get_msglevel,
+ .set_msglevel = fec_set_msglevel,
+#endif
+};
+
+
+static int fec_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ struct fec_priv *priv = netdev_priv(dev);
+
+ if (!priv->phydev)
+ return -ENOTSUPP;
+
+ return phy_mii_ioctl(priv->phydev, rq, cmd);
+}
+
+static int fec_mdio_transfer(struct mii_bus *bus, int phy_addr,
+ int reg, u32 value)
+{
+ struct fec_priv *priv = (struct fec_priv *)bus->priv;
+ unsigned long base_addr = (unsigned long) priv->netdev->base_addr;
+ unsigned long time_left;
+
+ /*
+ * Set MII speed to 2.5 MHz
+ */
+ writel((((MCF_BUSCLK + 4999999) / 5000000) & 0x3F) << 1, base_addr + FEC_MSCR);
+
+ value |= (phy_addr << 23);
+ value |= (reg << 18);
+ value |= FEC_MMFR_ST | FEC_MMFR_TA;
+
+ init_completion(&priv->mdio_done);
+ writel(value, base_addr + FEC_MMFR);
+
+ /* wait for end of transfer, this takes about 23 us on lite5200b */
+ time_left = wait_for_completion_timeout(&priv->mdio_done,
+ usecs_to_jiffies(FEC_MII_TIMEOUT));
+
+ writel(0, base_addr + FEC_MSCR);
+
+ if (time_left == 0) {
+ pr_err("%s : timeout accessing phy%d/reg%d\n",
+ bus->name, phy_addr, reg);
+ return -ETIMEDOUT;
+ }
+
+ return (value & FEC_MMFR_OP_READ) ?
+ (readl(base_addr + FEC_MMFR) & FEC_MMFR_DATA) : 0;
+}
+
+static int fec_mdio_read(struct mii_bus *bus, int phy_addr, int reg)
+{
+ return fec_mdio_transfer(bus, phy_addr, reg, FEC_MMFR_OP_READ);
+}
+
+static int fec_mdio_write(struct mii_bus *bus, int phy_addr, int reg, u16 data)
+{
+ return fec_mdio_transfer(bus, phy_addr, reg, data | FEC_MMFR_OP_WRITE);
+}
+
+static int __init fec_mdio_init(struct net_device *dev)
+{
+ struct mii_bus *bus;
+ int err;
+ int i;
+ unsigned long addr;
+
+ bus = mdiobus_alloc();
+ if (bus == NULL)
+ return -ENOMEM;
+
+ bus->name = "FEC 0 MII bus";
+ bus->read = fec_mdio_read;
+ bus->write = fec_mdio_write;
+ /*
+ * on the freescale dev board, both PHY's (actually a DUAL phy)
+ * are connected via the MDIO bus of FEC0.
+ * PHY 0 for FEC 0 and PHY 1 for FEC 1
+ */
+ bus->phy_mask = ~((1 << FEC_MAX_PORTS) - 1);
+
+ /* setup irqs */
+ bus->irq = kmalloc(sizeof(bus->irq[0]) * PHY_MAX_ADDR, GFP_KERNEL);
+ if (bus->irq == NULL) {
+ err = -ENOMEM;
+ goto out_free;
+ }
+ for (i = 0; i < PHY_MAX_ADDR; i++)
+ bus->irq[i] = PHY_POLL;
+
+ snprintf(bus->id, MII_BUS_ID_SIZE, "%x", 0xfec);
+ bus->priv = netdev_priv(dev);
+
+ /* enable MII interrupt */
+ addr = dev->base_addr + FEC_EIMR;
+ writel(readl(addr) | FEC_EIR_MII, addr);
+
+ err = mdiobus_register(bus);
+ if (err)
+ goto out_unmap;
+
+ return 0;
+
+out_unmap:
+out_free:
+ kfree(bus->irq);
+ mdiobus_free(bus);
+
+ return err;
+}
+
+/************************************************************************
+* +NAME: fec_get_stats
+*
+* RETURNS: This function returns the statistical information.
+*************************************************************************/
+struct net_device_stats *fec_get_stats(struct net_device *dev)
+{
+ struct fec_priv *fp = netdev_priv(dev);
+ struct net_device_stats *statp = &fp->fecpriv_stat;
+ unsigned long base_addr = dev->base_addr;
+
+ /* Receive the statistical information */
+ statp->rx_packets = readl(base_addr + FECSTAT_RMON_R_PACKETS);
+ statp->tx_packets = readl(base_addr + FECSTAT_RMON_T_PACKETS);
+ statp->rx_bytes = readl(base_addr + FECSTAT_RMON_R_OCTETS);
+ statp->tx_bytes = readl(base_addr + FECSTAT_RMON_T_OCTETS);
+
+ statp->multicast = readl(base_addr + FECSTAT_RMON_R_MC_PKT);
+ statp->collisions = readl(base_addr + FECSTAT_RMON_T_COL);
+
+ statp->rx_length_errors = readl(base_addr + FECSTAT_RMON_R_UNDERSIZE) +
+ readl(base_addr + FECSTAT_RMON_R_OVERSIZE) +
+ readl(base_addr + FECSTAT_RMON_R_FRAG) +
+ readl(base_addr + FECSTAT_RMON_R_JAB);
+ statp->rx_crc_errors = readl(base_addr + FECSTAT_IEEE_R_CRC);
+ statp->rx_frame_errors = readl(base_addr + FECSTAT_IEEE_R_ALIGN);
+ statp->rx_over_errors = readl(base_addr + FECSTAT_IEEE_R_MACERR);
+
+ statp->tx_carrier_errors = readl(base_addr + FECSTAT_IEEE_T_CSERR);
+ statp->tx_fifo_errors = readl(base_addr + FECSTAT_IEEE_T_MACERR);
+ statp->tx_window_errors = readl(base_addr + FECSTAT_IEEE_T_LCOL);
+
+ /* I hope that one frame doesn't have more than one error */
+ statp->rx_errors = statp->rx_length_errors +
+ statp->rx_crc_errors +
+ statp->rx_frame_errors +
+ statp->rx_over_errors +
+ statp->rx_dropped;
+ statp->tx_errors = statp->tx_carrier_errors +
+ statp->tx_fifo_errors +
+ statp->tx_window_errors +
+ statp->tx_aborted_errors +
+ statp->tx_heartbeat_errors +
+ statp->tx_dropped;
+
+ return statp;
+}
+
+/************************************************************************
+* NAME: fec_set_multicast_list
+*
+* DESCRIPTION: This function sets the frame filtering parameters
+*************************************************************************/
+void fec_set_multicast_list(struct net_device *dev)
+{
+ unsigned int crc;
+ unsigned long base_addr = (unsigned long) dev->base_addr;
+ struct netdev_hw_addr *ha;
+ u32 gaur, galr;
+
+ if (dev->flags & IFF_PROMISC || dev->flags & IFF_ALLMULTI) {
+ /* Allow all incoming frames */
+ writel(0xFFFFFFFF, base_addr + FEC_GALR);
+ writel(0xFFFFFFFF, base_addr + FEC_GAUR);
+ return;
+ }
+
+ /* Reset the group address register */
+ galr = 0x00000000;
+ gaur = 0x00000000;
+
+ /* Process all addresses */
+ netdev_for_each_mc_addr(ha, dev) {
+ /* Calculate crc value for the current address */
+ crc = ether_crc_le(MAC_ADDR_LEN, ha->addr) >> 26;
+
+ /* Add this value */
+ crc &= 0x3F;
+ if (crc > 31)
+ gaur |= 0x1 << (crc - 32);
+ else
+ galr |= 0x1 << crc;
+ }
+ writel(galr, base_addr + FEC_GALR);
+ writel(gaur, base_addr + FEC_GAUR);
+}
+
+/************************************************************************
+* NAME: fec_set_mac_address
+*
+* DESCRIPTION: This function sets the MAC address
+*************************************************************************/
+int fec_set_mac_address(struct net_device *dev, void *p)
+{
+ struct fec_priv *fp = netdev_priv(dev);
+ unsigned long base_addr = (unsigned long) dev->base_addr;
+ struct sockaddr *addr = p;
+
+ if (netif_running(dev))
+ return -EBUSY;
+
+ /* Copy a new address to the device structure */
+ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+ /* Copy a new address to the private structure */
+ memcpy(fp->fecpriv_mac_addr, addr->sa_data, MAC_ADDR_LEN);
+
+ /* Set the address to the registers */
+ writel((dev->dev_addr[0] << 24) | (dev->dev_addr[1] << 16) |
+ (dev->dev_addr[2] << 8) | dev->dev_addr[3], base_addr + FEC_PALR);
+ writel((dev->dev_addr[4] << 24) | (dev->dev_addr[5] << 16) | 0x8808,
+ base_addr + FEC_PAUR);
+
+ return 0;
+}
+
+/************************************************************************
+* NAME: fec_start_tx
+*
+* DESCRIPTION: This function starts transmission of the frame using DMA
+*
+* RETURNS: This function always returns zero.
+*************************************************************************/
+int fec_start_tx(struct sk_buff *skb, struct net_device *dev)
+{
+ struct fec_priv *fp = netdev_priv(dev);
+ struct MCD_bufDescFec *txd = fp->fecpriv_txdesc;
+ int n = fp->fecpriv_next_tx;
+ void *data, *data_aligned;
+ int offset;
+
+ data = kmalloc(skb->len + 15, GFP_DMA | GFP_ATOMIC);
+
+ if (!data) {
+ fp->fecpriv_stat.tx_dropped++;
+ dev_kfree_skb(skb);
+ return 0;
+ }
+
+ offset = (((unsigned long)virt_to_phys(data) + 15) & 0xFFFFFFF0) -
+ (unsigned long)virt_to_phys(data);
+ data_aligned = (void *)((unsigned long)data + offset);
+ memcpy(data_aligned, skb->data, skb->len);
+
+ /* flush data cache before initializing the descriptor and starting DMA */
+ flush_dcache_range(virt_to_phys(data_aligned), skb->len);
+
+ spin_lock_irq(&fp->fecpriv_lock);
+
+ /* Initialize the descriptor */
+ fp->fecpriv_txbuf[n] = data;
+ txd[n].dataPointer = (unsigned int) virt_to_phys(data_aligned);
+ txd[n].length = skb->len;
+ txd[n].statCtrl |= (MCD_FEC_END_FRAME | MCD_FEC_BUF_READY);
+ n = (n + 1) & FEC_TX_INDEX_MASK;
+ fp->fecpriv_next_tx = n;
+
+ if (fp->fecpriv_txbuf[fp->fecpriv_current_tx] && fp->fecpriv_current_tx == n)
+ netif_stop_queue(dev);
+
+ spin_unlock_irq(&fp->fecpriv_lock);
+
+ /* Tell the DMA to continue the transmission */
+ MCD_continDma(fp->fecpriv_fec_tx_channel);
+
+ dev_kfree_skb(skb);
+
+ dev->trans_start = jiffies;
+
+ return 0;
+}
+
+/************************************************************************
+* NAME: fec_tx_timeout
+*
+* DESCRIPTION: If the interrupt processing of received frames was lost
+* and DMA stopped the reception, this function clears
+* the transmission descriptors and starts DMA
+*
+*************************************************************************/
+void fec_tx_timeout(struct net_device *dev)
+{
+ int i;
+ struct fec_priv *fp = netdev_priv(dev);
+ struct MCD_bufDescFec *txd = fp->fecpriv_txdesc;
+ unsigned long base_addr = (unsigned long) dev->base_addr;
+ u32 fecfrst;
+
+ spin_lock_irq(&fp->fecpriv_lock);
+ MCD_killDma(fp->fecpriv_fec_tx_channel);
+ for (i = 0; i < FEC_TX_BUF_NUMBER; i++) {
+ if (fp->fecpriv_txbuf[i]) {
+ kfree(fp->fecpriv_txbuf[i]);
+ fp->fecpriv_txbuf[i] = NULL;
+ }
+ txd[i].statCtrl = MCD_FEC_INTERRUPT;
+ }
+ txd[i - 1].statCtrl |= MCD_FEC_WRAP;
+
+ fp->fecpriv_current_tx = fp->fecpriv_next_tx = 0;
+
+ /* Reset FIFOs */
+ fecfrst = FEC_SW_RST | FEC_RST_CTL;
+ writel(fecfrst, base_addr + FEC_FECFRST);
+ fecfrst &= ~FEC_SW_RST;
+ writel(fecfrst, base_addr + FEC_FECFRST);
+
+#if 0
+ /* Reset and disable FEC */
+ writel(FEC_ECR_RESET, base_addr + FEC_ECR);
+#endif
+
+ /* Enable FEC */
+ writel(FEC_ECR_ETHEREN, base_addr + FEC_ECR);
+
+ MCD_startDma(fp->fecpriv_fec_tx_channel, (char *) txd, 0,
+ (unsigned char *) (base_addr + FEC_FECTFDR), 0,
+ FEC_MAX_FRM_SIZE, 0, fp->fecpriv_initiator_tx,
+ FEC_TX_DMA_PRI, MCD_FECTX_DMA | MCD_INTERRUPT,
+ MCD_NO_CSUM | MCD_NO_BYTE_SWAP);
+
+ spin_unlock_irq(&fp->fecpriv_lock);
+
+ netif_wake_queue(dev);
+}
+
+/************************************************************************
+* NAME: fec_interrupt_tx_handler
+*
+* DESCRIPTION: This function is called when the data
+* transmission from the buffer to the FEC is completed.
+*
+*************************************************************************/
+void fec_interrupt_fec_tx_handler(void *voidp)
+{
+ struct net_device *dev = voidp;
+ struct fec_priv *fp = netdev_priv(dev);
+ void **txb = fp->fecpriv_txbuf;
+ int c = fp->fecpriv_current_tx;
+
+ /* Release the socket buffer */
+ if (txb[c]) {
+ kfree(txb[c]);
+ txb[c] = NULL;
+ }
+ c = (c + 1) & FEC_TX_INDEX_MASK;
+
+ if (MCD_dmaStatus(fp->fecpriv_fec_tx_channel) == MCD_DONE) {
+ for (; c != fp->fecpriv_next_tx; c = (c + 1) & FEC_TX_INDEX_MASK) {
+ if (txb[c]) {
+ kfree(txb[c]);
+ txb[c] = NULL;
+ }
+ }
+ }
+ fp->fecpriv_current_tx = c;
+
+ if (netif_queue_stopped(dev))
+ netif_wake_queue(dev);
+}
+
+/************************************************************************
+* NAME: fec_interrupt_rx_handler
+*
+* DESCRIPTION: This function is called when the data
+* reception from the FEC to the reception buffer is completed.
+*
+*************************************************************************/
+void fec_interrupt_fec_rx_handler(void *voidp)
+{
+ struct net_device *dev = voidp;
+ struct fec_priv *fp = netdev_priv(dev);
+ struct MCD_bufDescFec *rxd = fp->fecpriv_rxdesc;
+ struct sk_buff **rxskb = fp->askb_rx;
+ struct sk_buff *skb;
+ int i;
+ int c = fp->fecpriv_current_rx;
+
+ fp->fecpriv_rxflag = 1;
+ /* Some buffers can be missed */
+ if (!(rxd[c].statCtrl & MCD_FEC_END_FRAME)) {
+ /* Find a valid index */
+ for (i = 0; i < FEC_RX_BUF_NUMBER && !(rxd[c].statCtrl & MCD_FEC_END_FRAME); i++, c = (c + 1) & FEC_RX_INDEX_MASK)
+ ;
+
+ if (i == FEC_RX_BUF_NUMBER) {
+ /* There are no data to process */
+ /* Tell the DMA to continue the reception */
+ MCD_continDma(fp->fecpriv_fec_rx_channel);
+
+ fp->fecpriv_rxflag = 0;
+
+ return;
+ }
+ }
+
+ for (; rxd[c].statCtrl & MCD_FEC_END_FRAME; c = (c + 1) & FEC_RX_INDEX_MASK) {
+ if ((rxd[c].length <= FEC_MAXBUF_SIZE) &&
+ (rxd[c].length > 4)) { /* --tym-- */
+ skb = rxskb[c];
+ if (!skb)
+ fp->fecpriv_stat.rx_dropped++;
+ else {
+ /*
+ * invalidate data cache before initializing
+ * the descriptor and starting DMAs
+ */
+ cache_clear(virt_to_phys(skb->data), skb->len);
+
+ skb_put(skb, rxd[c].length - 4);
+ skb->protocol = eth_type_trans(skb, dev);
+ netif_rx(skb);
+ }
+ rxd[c].statCtrl &= ~MCD_FEC_END_FRAME;
+ /* allocate new skbuff */
+ rxskb[c] = alloc_skb(FEC_MAXBUF_SIZE + 16, /*GFP_ATOMIC |*/ GFP_DMA);
+ if (!rxskb[c]) {
+ rxd[c].dataPointer = 0;
+ rxd[c].length = 0;
+ fp->fecpriv_stat.rx_dropped++;
+ } else {
+#if 0
+if (!fp->in_poll)
+ pr_debug("rxskb[%d] = %p\n", c, rxskb[c]);
+#endif
+ skb_reserve(rxskb[c], 16);
+ rxskb[c]->dev = dev;
+
+ /*
+ * invalidate data cache before initializing
+ * the descriptor and starting DMAs
+ */
+ cache_clear(virt_to_phys(rxskb[c]->data), FEC_MAXBUF_SIZE);
+
+ rxd[c].dataPointer = (unsigned int) virt_to_phys(rxskb[c]->data);
+ rxd[c].length = FEC_MAXBUF_SIZE;
+ rxd[c].statCtrl |= MCD_FEC_BUF_READY;
+ }
+ }
+ }
+
+ fp->fecpriv_current_rx = c;
+
+ /* Tell the DMA to continue the reception */
+ MCD_continDma(fp->fecpriv_fec_rx_channel);
+
+ fp->fecpriv_rxflag = 0;
+}
+
+/************************************************************************
+* NAME: fec_interrupt_handler
+*
+* DESCRIPTION: This function is called when some special errors occur
+*
+*************************************************************************/
+irqreturn_t fec_interrupt_handler(int irq, void *dev_id)
+{
+ struct net_device *dev = (struct net_device *)dev_id;
+ struct fec_priv *fp = netdev_priv(dev);
+ unsigned long base_addr = (unsigned long) dev->base_addr;
+ unsigned long events;
+ u32 fecfrst;
+
+ /* Read and clear the events */
+ events = readl(base_addr + FEC_EIR) & readl(base_addr + FEC_EIMR);
+
+ if (events & FEC_EIR_HBERR) {
+ fp->fecpriv_stat.tx_heartbeat_errors++;
+ writel(FEC_EIR_HBERR, base_addr + FEC_EIR);
+ }
+
+ /* receive/transmit FIFO error */
+ if (events & (FEC_EIR_RFERR | FEC_EIR_XFERR)) {
+ /* kill DMA receive channel */
+ MCD_killDma(fp->fecpriv_fec_rx_channel);
+
+ /* kill running transmission by DMA */
+ MCD_killDma(fp->fecpriv_fec_tx_channel);
+
+ /* Reset FIFOs */
+ fecfrst = FEC_SW_RST | FEC_RST_CTL;
+ writel(fecfrst, base_addr + FEC_FECFRST);
+ fecfrst &= ~FEC_SW_RST;
+ writel(fecfrst, base_addr + FEC_FECFRST);
+
+ /* reset receive FIFO status register */
+ writel(FEC_FECRFSR_FAE |
+ FEC_FECRFSR_RXW |
+ FEC_FECRFSR_UF,
+ base_addr + FEC_FECRFSR);
+
+ /* reset transmit FIFO status register */
+ writel(FEC_FECTFSR_FAE |
+ FEC_FECTFSR_TXW |
+ FEC_FECTFSR_UF |
+ FEC_FECTFSR_OF,
+ base_addr + FEC_FECTFSR);
+
+ /* reset RFERR and XFERR event */
+ writel(FEC_EIR_RFERR | FEC_EIR_XFERR, base_addr + FEC_EIR);
+
+ /* stop queue */
+ netif_stop_queue(dev);
+
+ /* execute reinitialization as tasklet */
+ tasklet_schedule(&fp->fecpriv_tasklet_reinit);
+
+ fp->fecpriv_stat.rx_dropped++;
+ }
+
+ /* transmit FIFO underrun */
+ if (events & FEC_EIR_XFUN) {
+ /* reset XFUN event */
+ writel(FEC_EIR_XFUN, base_addr + FEC_EIR);
+ fp->fecpriv_stat.tx_aborted_errors++;
+ }
+
+ /* late collision */
+ if (events & FEC_EIR_LC) {
+ /* reset LC event */
+ writel(FEC_EIR_LC, base_addr + FEC_EIR);
+ fp->fecpriv_stat.tx_aborted_errors++;
+ }
+
+ /* collision retry limit */
+ if (events & FEC_EIR_RL) {
+ /* reset RL event */
+ writel(FEC_EIR_RL, base_addr + FEC_EIR);
+ fp->fecpriv_stat.tx_aborted_errors++;
+ }
+
+ /* MII transfer completed */
+ if (events & FEC_EIR_MII) {
+ complete(&fp->mdio_done);
+ writel(FEC_EIR_MII, base_addr + FEC_EIR);
+ }
+ return 0;
+}
+
+/************************************************************************
+* NAME: fec_interrupt_reinit
+*
+* DESCRIPTION: This function is called from interrupt handler
+* when controller must be reinitialized.
+*
+*************************************************************************/
+void fec_interrupt_fec_reinit(unsigned long data)
+{
+ int i;
+ struct net_device *dev = (struct net_device *)data;
+ struct fec_priv *fp = netdev_priv(dev);
+ struct MCD_bufDescFec *rxd = fp->fecpriv_rxdesc;
+ struct MCD_bufDescFec *txd = fp->fecpriv_txdesc;
+ struct sk_buff **rxskb = fp->askb_rx;
+ unsigned long base_addr = (unsigned long) dev->base_addr;
+
+#if 0
+if (!fp->in_poll)
+ pr_debug("fec_interrupt_fec_reinit\n");
+#endif
+ /* Initialize reception descriptors and start DMA for the reception */
+ for (i = 0; i < FEC_RX_BUF_NUMBER; i++) {
+ if (!rxskb[i]) {
+ rxskb[i] = alloc_skb(FEC_MAXBUF_SIZE + 16, GFP_ATOMIC | GFP_DMA);
+ if (!rxskb[i]) {
+ rxd[i].dataPointer = 0;
+ rxd[i].statCtrl = 0;
+ rxd[i].length = 0;
+ continue;
+ }
+#if 0
+if (!fp->in_poll)
+ pr_debug("rxskb[%d] = %p\n", i, rxskb[i]);
+#endif
+ rxskb[i]->dev = dev;
+ skb_reserve(rxskb[i], 16);
+ }
+ rxd[i].dataPointer = (unsigned int) virt_to_phys(rxskb[i]->data);
+ rxd[i].statCtrl = MCD_FEC_BUF_READY | MCD_FEC_INTERRUPT;
+ rxd[i].length = FEC_MAXBUF_SIZE;
+ }
+
+ rxd[i - 1].statCtrl |= MCD_FEC_WRAP;
+ fp->fecpriv_current_rx = 0;
+
+ /* restart frame transmission */
+ for (i = 0; i < FEC_TX_BUF_NUMBER; i++) {
+ if (fp->fecpriv_txbuf[i]) {
+ kfree(fp->fecpriv_txbuf[i]);
+ fp->fecpriv_txbuf[i] = NULL;
+ fp->fecpriv_stat.tx_dropped++;
+ }
+ txd[i].statCtrl = MCD_FEC_INTERRUPT;
+ }
+ txd[i - 1].statCtrl |= MCD_FEC_WRAP;
+ fp->fecpriv_current_tx = fp->fecpriv_next_tx = 0;
+
+ /* flush entire data cache before restarting the DMA */
+ flush_and_invalidate_dcache();
+
+ /* restart DMA from beginning */
+ MCD_startDma(fp->fecpriv_fec_rx_channel, (char *) rxd, 0,
+ (unsigned char *) (base_addr + FEC_FECRFDR), 0,
+ FEC_MAX_FRM_SIZE, 0, fp->fecpriv_initiator_rx,
+ FEC_RX_DMA_PRI, MCD_FECRX_DMA | MCD_INTERRUPT,
+ MCD_NO_CSUM | MCD_NO_BYTE_SWAP);
+
+ MCD_startDma(fp->fecpriv_fec_tx_channel, (char *) txd, 0,
+ (unsigned char *) (base_addr + FEC_FECTFDR), 0,
+ FEC_MAX_FRM_SIZE, 0, fp->fecpriv_initiator_tx,
+ FEC_TX_DMA_PRI, MCD_FECTX_DMA | MCD_INTERRUPT,
+ MCD_NO_CSUM | MCD_NO_BYTE_SWAP);
+
+ /* Enable FEC */
+ writel(FEC_ECR_ETHEREN, base_addr + FEC_ECR);
+
+ netif_wake_queue(dev);
+}
+
+/************************************************************************
+* NAME: fec_open
+*
+* DESCRIPTION: This function performs the initialization of FEC
+*
+* RETURNS: If no error occurs, this function returns zero.
+*************************************************************************/
+int fec_open(struct net_device *dev)
+{
+ struct fec_priv *fp = netdev_priv(dev);
+ struct MCD_bufDescFec *rxd = fp->fecpriv_rxdesc;
+ struct MCD_bufDescFec *txd = fp->fecpriv_txdesc;
+ struct sk_buff **rxskb = fp->askb_rx;
+ unsigned long base_addr = (unsigned long) dev->base_addr;
+ int i;
+ int channel;
+ int error_code = -EBUSY;
+ u32 fecfrst;
+ u32 rcntl;
+
+ /* Receive the DMA channels */
+ channel = dma_set_channel_fec(fp->fecpriv_rx_requestor);
+
+ if (channel == -1) {
+ pr_err("Rx Dma channel cannot be reserved\n");
+ goto ERRORS;
+ }
+
+ fp->fecpriv_fec_rx_channel = channel;
+
+ dma_connect(channel, fec_interrupt_fec_rx_handler, dev);
+
+ channel = dma_set_channel_fec(fp->fecpriv_tx_requestor);
+
+ if (channel == -1) {
+ pr_err("Tx Dma channel cannot be reserved\n");
+ goto ERRORS;
+ }
+
+ fp->fecpriv_fec_tx_channel = channel;
+
+ dma_connect(channel, fec_interrupt_fec_tx_handler, dev);
+
+ /* init tasklet for controller reinitialization */
+ tasklet_init(&fp->fecpriv_tasklet_reinit, fec_interrupt_fec_reinit,
+ (unsigned long) dev);
+
+ /* Reset FIFOs */
+ fecfrst = FEC_SW_RST | FEC_RST_CTL;
+ writel(fecfrst, base_addr + FEC_FECFRST);
+ fecfrst &= ~FEC_SW_RST;
+ writel(fecfrst, base_addr + FEC_FECFRST);
+
+ /* Reset and disable FEC */
+ writel(FEC_ECR_RESET, base_addr + FEC_ECR);
+
+ udelay(10);
+
+ /* Clear all events */
+ writel(FEC_EIR_CLEAR, base_addr + FEC_EIR);
+
+ /* Reset FIFO status */
+ writel(FEC_FECTFSR_MSK, base_addr + FEC_FECTFSR);
+ writel(FEC_FECRFSR_MSK, base_addr + FEC_FECRFSR);
+
+ /* Set the default address */
+ writel((dev->dev_addr[0] << 24) | (dev->dev_addr[1] << 16) |
+ (dev->dev_addr[2] << 8) | dev->dev_addr[3], base_addr + FEC_PALR);
+ writel((dev->dev_addr[4] << 24) | (dev->dev_addr[5] << 16) | 0x8808,
+ base_addr + FEC_PAUR);
+
+ /* Reset the group address descriptor */
+ writel(0x00000000, base_addr + FEC_GALR);
+ writel(0x00000000, base_addr + FEC_GAUR);
+
+ /* Reset the individual address descriptor */
+ writel(0x00000000, base_addr + FEC_IALR);
+ writel(0x00000000, base_addr + FEC_IAUR);
+
+ /* Set the receive control register */
+ rcntl = FEC_RCR_MAX_FRM_SIZE | FEC_RCR_MII;
+ writel(rcntl, base_addr + FEC_RCR);
+
+ /* Set the receive FIFO control register */
+ writel(FEC_FECRFCR_FRM | FEC_FECRFCR_GR
+ | (FEC_FECRFCR_MSK /* disable all but ... */
+ & ~FEC_FECRFCR_FAE /* enable frame accept error */
+ & ~FEC_FECRFCR_RXW /* enable receive wait condition */
+#if 0
+ & ~FEC_FECRFCR_UF /* enable FIFO underflow */
+#endif
+ ), base_addr + FEC_FECRFCR);
+
+ /* Set the receive FIFO alarm register */
+ writel(FEC_FECRFAR_ALARM, base_addr + FEC_FECRFAR);
+
+ /* Set the transmit FIFO control register */
+ writel(FEC_FECTFCR_FRM | FEC_FECTFCR_GR
+ | (FEC_FECTFCR_MSK /* disable all but ... */
+ & ~FEC_FECTFCR_FAE /* enable frame accept error */
+#if 0
+ & ~FEC_FECTFCR_TXW /* enable transmit wait condition */
+ & ~FEC_FECTFCR_UF /* enable FIFO underflow */
+#endif
+ & ~FEC_FECTFCR_OF), /* enable FIFO overflow */
+ base_addr + FEC_FECTFCR);
+
+ /* Set the transmit FIFO alarm register */
+ writel(FEC_FECTFAR_ALARM, base_addr + FEC_FECTFAR);
+
+ /* Set the Tx FIFO watermark */
+ writel(FEC_FECTFWR_XWMRK, base_addr + FEC_FECTFWR);
+
+ /* Enable the transmitter to append the CRC */
+ writel(FEC_CTCWR_TFCW_CRC, base_addr + FEC_CTCWR);
+
+ /* Enable the ethernet interrupts */ /* FIXME : too late for mdio bus */
+ writel(FEC_EIMR_DISABLE
+ | FEC_EIR_LC
+ | FEC_EIR_RL
+ | FEC_EIR_HBERR
+ | FEC_EIR_XFUN
+ | FEC_EIR_XFERR
+ | FEC_EIR_RFERR
+ | FEC_EIR_MII,
+ base_addr + FEC_EIMR);
+
+ if (fp->phydev->duplex == DUPLEX_FULL)
+ /* Enable the full duplex mode */
+ writel(FEC_TCR_FDEN | FEC_TCR_HBC, base_addr + FEC_TCR);
+ else {
+ /* Disable reception of frames while transmitting */
+ rcntl |= FEC_RCR_DRT;
+ writel(rcntl, base_addr + FEC_RCR);
+ }
+
+ /* Enable MIB */
+ writel(FEC_MIBC_ENABLE, base_addr + FEC_MIBC);
+
+ /* Enable FEC */
+ writel(FEC_ECR_ETHEREN, base_addr + FEC_ECR);
+
+ /* Initialize tx descriptors and start DMA for the transmission */
+ for (i = 0; i < FEC_TX_BUF_NUMBER; i++)
+ txd[i].statCtrl = MCD_FEC_INTERRUPT;
+
+ txd[i - 1].statCtrl |= MCD_FEC_WRAP;
+
+ fp->fecpriv_current_tx = fp->fecpriv_next_tx = 0;
+
+ MCD_startDma(fp->fecpriv_fec_tx_channel, (char *) txd, 0,
+ (unsigned char *) (base_addr + FEC_FECTFDR), 0,
+ FEC_MAX_FRM_SIZE, 0, fp->fecpriv_initiator_tx,
+ FEC_TX_DMA_PRI, MCD_FECTX_DMA | MCD_INTERRUPT,
+ MCD_NO_CSUM | MCD_NO_BYTE_SWAP);
+
+ /* Initialize rx descriptors and start DMA for the reception */
+ for (i = 0; i < FEC_RX_BUF_NUMBER; i++) {
+ rxskb[i] = alloc_skb(FEC_MAXBUF_SIZE + 16, GFP_DMA);
+ if (!rxskb[i]) {
+ rxd[i].dataPointer = 0;
+ rxd[i].statCtrl = 0;
+ rxd[i].length = 0;
+ } else {
+#if 0
+if (!fp->in_poll)
+ pr_debug("rxskb[%d] = %p\n", i, rxskb[i]);
+#endif
+ skb_reserve(rxskb[i], 16);
+ rxskb[i]->dev = dev;
+ rxd[i].dataPointer = (unsigned int) virt_to_phys(rxskb[i]->data);
+ rxd[i].statCtrl = MCD_FEC_BUF_READY | MCD_FEC_INTERRUPT;
+ rxd[i].length = FEC_MAXBUF_SIZE;
+ }
+ }
+
+ rxd[i - 1].statCtrl |= MCD_FEC_WRAP;
+ fp->fecpriv_current_rx = 0;
+
+ /* flush entire data cache before restarting the DMA */
+ flush_and_invalidate_dcache();
+
+ MCD_startDma(fp->fecpriv_fec_rx_channel, (char *) rxd, 0,
+ (unsigned char *) (base_addr + FEC_FECRFDR), 0,
+ FEC_MAX_FRM_SIZE, 0, fp->fecpriv_initiator_rx,
+ FEC_RX_DMA_PRI, MCD_FECRX_DMA | MCD_INTERRUPT,
+ MCD_NO_CSUM | MCD_NO_BYTE_SWAP);
+
+ netif_start_queue(dev);
+ return 0;
+
+ERRORS:
+
+ /* Remove the channels and return with the error code */
+ if (fp->fecpriv_fec_rx_channel != -1) {
+ dma_disconnect(fp->fecpriv_fec_rx_channel);
+ dma_remove_channel_by_number(fp->fecpriv_fec_rx_channel);
+ fp->fecpriv_fec_rx_channel = -1;
+ }
+
+ if (fp->fecpriv_fec_tx_channel != -1) {
+ dma_disconnect(fp->fecpriv_fec_tx_channel);
+ dma_remove_channel_by_number(fp->fecpriv_fec_tx_channel);
+ fp->fecpriv_fec_tx_channel = -1;
+ }
+
+ return error_code;
+}
+
+/************************************************************************
+* NAME: fec_close
+*
+* DESCRIPTION: This function performs the graceful stop of the
+* transmission and disables FEC
+*
+* RETURNS: This function always returns zero.
+*************************************************************************/
+int fec_close(struct net_device *dev)
+{
+ struct fec_priv *fp = netdev_priv(dev);
+ unsigned long base_addr = (unsigned long) dev->base_addr;
+ unsigned long time;
+ int i;
+ unsigned long addr;
+
+ netif_stop_queue(dev);
+
+ /* Perform the graceful stop */
+ addr = dev->base_addr + FEC_TCR;
+ writel(readl(addr) | FEC_TCR_GTS, addr);
+
+ time = jiffies;
+
+ /* Wait for the graceful stop */
+ while (!(readl(base_addr + FEC_EIR) & FEC_EIR_GRA) && jiffies - time < FEC_GR_TIMEOUT * HZ)
+ schedule();
+
+ /* Disable FEC */
+ writel(FEC_ECR_DISABLE, base_addr + FEC_ECR);
+
+ /* Reset the DMA channels */
+ spin_lock_irq(&fp->fecpriv_lock);
+ MCD_killDma(fp->fecpriv_fec_tx_channel);
+ spin_unlock_irq(&fp->fecpriv_lock);
+ dma_remove_channel_by_number(fp->fecpriv_fec_tx_channel);
+ dma_disconnect(fp->fecpriv_fec_tx_channel);
+ fp->fecpriv_fec_tx_channel = -1;
+
+ for (i = 0; i < FEC_TX_BUF_NUMBER; i++) {
+ if (fp->fecpriv_txbuf[i]) {
+ kfree(fp->fecpriv_txbuf[i]);
+ fp->fecpriv_txbuf[i] = NULL;
+ }
+ }
+
+ spin_lock_irq(&fp->fecpriv_lock);
+ MCD_killDma(fp->fecpriv_fec_rx_channel);
+ spin_unlock_irq(&fp->fecpriv_lock);
+
+ dma_remove_channel_by_number(fp->fecpriv_fec_rx_channel);
+ dma_disconnect(fp->fecpriv_fec_rx_channel);
+ fp->fecpriv_fec_rx_channel = -1;
+
+ for (i = 0; i < FEC_RX_BUF_NUMBER; i++) {
+ if (fp->askb_rx[i]) {
+ kfree_skb(fp->askb_rx[i]);
+ fp->askb_rx[i] = NULL;
+ }
+ }
+
+ return 0;
+}
+
+#ifndef MODULE
+/************************************************************************
+* NAME: fec_str_to_mac
+*
+* DESCRIPTION: This function interprets the character string into MAC addr
+*
+*************************************************************************/
+int fec_str_to_mac(char *str_mac, unsigned char *addr)
+{
+ unsigned long val;
+ char c;
+ unsigned long octet[MAC_ADDR_LEN], *octetptr = octet;
+ int i;
+
+again:
+ val = 0;
+ while ((c = *str_mac) != '\0') {
+ c = hex_to_bin(c);
+ if (c >= 0) {
+ val = (val * 16) + c;
+ str_mac++;
+ continue;
+ }
+ break;
+ }
+ if (*str_mac == ':') {
+ *octetptr++ = val, str_mac++;
+ if (octetptr >= octet + MAC_ADDR_LEN)
+ return 1;
+ goto again;
+ }
+
+ /* Check for trailing characters */
+ if (*str_mac && !(*str_mac == ' '))
+ return 1;
+
+ *octetptr++ = val;
+
+ if ((octetptr - octet) == MAC_ADDR_LEN) {
+ for (i = 0; i <= MAC_ADDR_LEN; i++)
+ addr[i] = octet[i];
+ } else
+ return 1;
+
+ return 0;
+}
+
+/************************************************************************
+* NAME: fec_mac_setup0
+*
+* DESCRIPTION: This function sets the MAC address of FEC0 from command line
+*
+*************************************************************************/
+int __init fec_mac_setup0(char *s)
+{
+ if (!s || !*s)
+ return 1;
+
+ if (fec_str_to_mac(s, fec0_addr))
+ pr_err("Invalid MAC address from command line for FEC0");
+ return 1;
+}
+__setup("mac0=", fec_mac_setup0);
+
+#ifdef CONFIG_FEC2
+/************************************************************************
+* NAME: fec_mac_setup1
+*
+* DESCRIPTION: This function sets the MAC address of FEC1 from command line
+*
+*************************************************************************/
+int __init fec_mac_setup1(char *s)
+{
+ if (!s || !*s)
+ return 1;
+
+ if (fec_str_to_mac(s, fec1_addr))
+ pr_err("Invalid MAC address from command line for FEC1");
+ return 1;
+}
+__setup("mac1=", fec_mac_setup1);
+#endif
+#endif
+
+#undef CONFIG_NET_POLL_CONTROLLER
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/*
+ * Polling 'interrupt' - used by things like netconsole to send skbs
+ * without having to re-enable interrupts. It's not called while
+ * the interrupt routine is executing.
+ */
+
+static void fec_poll(struct net_device *dev)
+{
+#if 0
+ struct fec_priv *fp = netdev_priv(dev);
+#endif
+ /* disable_irq here is not very nice, but with the lockless
+ interrupt handler we have no other choice. */
+#if 0
+ fp->in_poll = 1;
+#endif
+ disable_irq(112);
+ disable_irq(dev->irq);
+ fec_interrupt_handler(dev->irq, dev);
+ fec_interrupt_fec_rx_handler(dev);
+ fec_interrupt_fec_tx_handler(dev);
+ enable_irq(dev->irq);
+ enable_irq(112);
+#if 0
+ fp->in_poll = 0;
+#endif
+}
+#endif
+
+static const struct net_device_ops fec_netdev_ops = {
+ .ndo_open = fec_open,
+ .ndo_stop = fec_close,
+ .ndo_start_xmit = fec_start_tx,
+ .ndo_set_rx_mode = fec_set_multicast_list,
+ .ndo_set_mac_address = fec_set_mac_address,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_tx_timeout = fec_tx_timeout,
+ .ndo_get_stats = fec_get_stats,
+ .ndo_do_ioctl = fec_ioctl,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = fec_poll,
+#endif
+};
+
+/*
+ * Initialize a FEC device
+ */
+int fec_enet_init(struct net_device *dev)
+{
+ static int index;
+ struct fec_priv *fp = netdev_priv(dev);
+ const void *mac_addr;
+ int i;
+ unsigned long addr;
+
+ fp->index = index;
+#if 0
+ fp->in_poll = 0;
+#endif
+ fp->netdev = dev;
+
+ if (index == 0) {
+ /* disable fec0 */
+ writel(FEC_ECR_DISABLE, FEC_BASE_ADDR_FEC0 + FEC_ECR);
+
+ /* setup the interrupt handler */
+ dev->irq = MCF_IRQ_FEC0;
+
+ if (request_irq(dev->irq, fec_interrupt_handler,
+ IRQF_DISABLED, "ColdFire FEC 0", dev)) {
+ dev->irq = 0;
+ pr_err("Cannot allocate FEC0 IRQ\n");
+#if 0
+ } else {
+ /* interrupt priority and level */
+ MCF_ICR(ISC_FEC0) = ILP_FEC0;
+#endif
+ }
+
+ /* fec base address */
+ dev->base_addr = FEC_BASE_ADDR_FEC0;
+
+ /* requestor numbers */
+ fp->fecpriv_rx_requestor = DMA_FEC0_RX;
+ fp->fecpriv_tx_requestor = DMA_FEC0_TX;
+
+ /* tx descriptors */
+ fp->fecpriv_txdesc = (void *)FEC_TX_DESC_FEC0;
+
+ /* rx descriptors */
+ fp->fecpriv_rxdesc = (void *)FEC_RX_DESC_FEC0;
+
+ /* mac addr */
+ mac_addr = machdep_get_mac_address(index);
+ if (mac_addr)
+ memcpy(fec0_addr, mac_addr, MAC_ADDR_LEN);
+ fp->fecpriv_mac_addr = fec0_addr;
+ } else {
+ /* disable fec1 */
+ writel(FEC_ECR_DISABLE, FEC_BASE_ADDR_FEC1 + FEC_ECR);
+#ifdef CONFIG_FEC2
+ /* setup the interrupt handler */
+ dev->irq = MCF_IRQ_FEC1;
+
+ if (request_irq(dev->irq, fec_interrupt_handler,
+ IRQF_DISABLED, "ColdFire FEC 1", dev)) {
+ dev->irq = 0;
+ pr_err("Cannot allocate FEC1 IRQ\n");
+#if 0
+ } else {
+ /* interrupt priority and level */
+ MCF_ICR(ISC_FEC1) = ILP_FEC1;
+#endif
+ }
+
+ /* fec base address */
+ dev->base_addr = FEC_BASE_ADDR_FEC1;
+
+ /* requestor numbers */
+ fp->fecpriv_rx_requestor = DMA_FEC1_RX;
+ fp->fecpriv_tx_requestor = DMA_FEC1_TX;
+
+ /* tx descriptors */
+ fp->fecpriv_txdesc = (void *)FEC_TX_DESC_FEC1;
+
+ /* rx descriptors */
+ fp->fecpriv_rxdesc = (void *)FEC_RX_DESC_FEC1;
+
+ /* mac addr */
+ mac_addr = machdep_get_mac_address(index);
+ if (mac_addr)
+ memcpy(fec1_addr, mac_addr, MAC_ADDR_LEN);
+ fp->fecpriv_mac_addr = fec1_addr;
+#endif
+ }
+
+ /* clear MIB */
+ memset((void *) (dev->base_addr + 0x200), 0, FEC_MIB_LEN);
+
+ /* clear the statistics structure */
+ memset((void *) &(fp->fecpriv_stat), 0,
+ sizeof(struct net_device_stats));
+
+ /* grab the FEC initiators */
+ dma_set_initiator(fp->fecpriv_tx_requestor);
+ fp->fecpriv_initiator_tx = dma_get_initiator(fp->fecpriv_tx_requestor);
+ dma_set_initiator(fp->fecpriv_rx_requestor);
+ fp->fecpriv_initiator_rx = dma_get_initiator(fp->fecpriv_rx_requestor);
+
+ /* reset the DMA channels */
+ fp->fecpriv_fec_rx_channel = -1;
+ fp->fecpriv_fec_tx_channel = -1;
+
+ for (i = 0; i < FEC_RX_BUF_NUMBER; i++)
+ fp->askb_rx[i] = NULL;
+
+ /* initialize the pointers to the socket buffers */
+ for (i = 0; i < FEC_TX_BUF_NUMBER; i++)
+ fp->fecpriv_txbuf[i] = NULL;
+
+ ether_setup(dev);
+
+ dev->watchdog_timeo = FEC_TX_TIMEOUT;
+ dev->netdev_ops = &fec_netdev_ops;
+ dev->ethtool_ops = &fec_ethtool_ops;
+
+
+ memcpy(dev->dev_addr, fp->fecpriv_mac_addr, ETH_ALEN);
+
+ spin_lock_init(&fp->fecpriv_lock);
+
+ /* Initialize FEC/I2C/IRQ Pin Assignment Register */
+ writew((readw(FEC_GPIO_PAR_FECI2CIRQ) & 0xF) | FEC_FECI2CIRQ,
+ FEC_GPIO_PAR_FECI2CIRQ);
+
+ /* set MII mode (as opposed to 7-wires mode) */
+ addr = dev->base_addr + FEC_RCR;
+ writel(readl(addr) | FEC_RCR_MII, addr);
+
+ index++;
+ return 0;
+}
+
+/*
+ * Stop a device
+ */
+void fec_stop(struct net_device *dev)
+{
+ struct fec_priv *fp = netdev_priv(dev);
+
+ dma_remove_initiator(fp->fecpriv_initiator_tx);
+ dma_remove_initiator(fp->fecpriv_initiator_rx);
+
+ if (dev->irq)
+ free_irq(dev->irq, dev);
+}
+
+/*
+ * Module Initialization
+ */
+int __init fec_init(void)
+{
+ struct net_device *dev;
+ int i;
+ int err;
+
+ pr_info("FEC ENET (DMA) Version %s\n", VERSION);
+
+ for (i = 0; i < FEC_MAX_PORTS; i++) {
+ dev = alloc_etherdev(sizeof(struct fec_priv));
+ if (!dev)
+ return -ENOMEM;
+ netif_carrier_off(dev);
+ err = fec_enet_init(dev);
+ if (err) {
+ free_netdev(dev);
+ continue;
+ }
+ if (register_netdev(dev) != 0) {
+ free_netdev(dev);
+ return -EIO;
+ }
+
+ /*
+ * On the freescale dev board, E0MDC & E0MDIO are
+ * connected to a dual phy. E1MDC & E1MDIO are unused.
+ * In other words, only fec 0 can communicate with
+ * the dual phy.
+ */
+ if (i == 0)
+ fec_mdio_init(dev);
+
+ fec_phy_start(dev);
+
+ pr_info("%s: ethernet %pM\n",
+ dev->name, dev->dev_addr);
+ }
+ return 0;
+}
+
+/* module_exit(fec_cleanup); */
+module_init(fec_init);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/freescale/fec_m54xx.h b/drivers/net/ethernet/freescale/fec_m54xx.h
new file mode 100644
index 0000000..022ee32
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fec_m54xx.h
@@ -0,0 +1,144 @@
+
+#define FEC_BASE_ADDR_FEC0 ((unsigned int)MCF_MBAR + 0x9000)
+#define FEC_BASE_ADDR_FEC1 ((unsigned int)MCF_MBAR + 0x9800)
+
+#define FEC_GPIO_PAR_FECI2CIRQ ((unsigned int)MCF_MBAR + 0xA44)
+#define FEC_FECI2CIRQ (0xFFC0)
+
+#define FEC_ECR_DISABLE (0x00000000)
+
+#define FEC_EIR 0x004
+#define FEC_EIMR 0x008
+#define FEC_ECR 0x024
+#define FEC_MMFR 0x040
+#define FEC_MSCR 0x044
+#define FEC_MIBC 0x064
+#define FEC_RCR 0x084
+#define FEC_TCR 0x0C4
+#define FEC_PALR 0x0E4
+#define FEC_PAUR 0x0E8
+#define FEC_IAUR 0x118
+#define FEC_IALR 0x11C
+#define FEC_GAUR 0x120
+#define FEC_GALR 0x124
+#define FEC_FECTFWR 0x144
+#define FEC_FECRFDR 0x184
+#define FEC_FECRFSR 0x188
+#define FEC_FECRFCR 0x18C
+#define FEC_FECRFAR 0x198
+#define FEC_FECTFDR 0x1A4
+#define FEC_FECTFSR 0x1A8
+#define FEC_FECTFCR 0x1AC
+#define FEC_FECTFAR 0x1B8
+#define FEC_FECFRST 0x1C4
+#define FEC_CTCWR 0x1C8
+#define FECSTAT_RMON_T_PACKETS 0x204
+#define FECSTAT_RMON_T_COL 0x224
+#define FECSTAT_RMON_T_OCTETS 0x244
+#define FECSTAT_IEEE_T_DROP 0x248
+#define FECSTAT_IEEE_T_FRAME_OK 0x24C
+#define FECSTAT_IEEE_T_LCOL 0x25C
+#define FECSTAT_IEEE_T_MACERR 0x264
+#define FECSTAT_IEEE_T_CSERR 0x268
+#define FECSTAT_IEEE_T_OCTETS_OK 0x274
+#define FECSTAT_RMON_R_PACKETS 0x284
+#define FECSTAT_RMON_R_MC_PKT 0x28C
+#define FECSTAT_RMON_R_UNDERSIZE 0x294
+#define FECSTAT_RMON_R_OVERSIZE 0x298
+#define FECSTAT_RMON_R_FRAG 0x29C
+#define FECSTAT_RMON_R_JAB 0x2A0
+#define FECSTAT_RMON_R_OCTETS 0x2C4
+#define FECSTAT_IEEE_R_DROP 0x2C8
+#define FECSTAT_IEEE_R_FRAME_OK 0x2CC
+#define FECSTAT_IEEE_R_CRC 0x2D0
+#define FECSTAT_IEEE_R_ALIGN 0x2D4
+#define FECSTAT_IEEE_R_MACERR 0x2D8
+#define FECSTAT_IEEE_R_OCTETS_OK 0x2E0
+
+#define FEC_MAX_FRM_SIZE (1518)
+#define FEC_MAXBUF_SIZE (1520)
+
+/* Register values */
+#define FEC_ECR_RESET (0x00000001)
+
+#define FEC_EIR_CLEAR (0xFFFFFFFF)
+#define FEC_EIR_RL (0x00100000)
+#define FEC_EIR_HBERR (0x80000000)
+#define FEC_EIR_BABR (0x40000000) /* babbling receive error */
+#define FEC_EIR_BABT (0x20000000) /* babbling transmit error */
+#define FEC_EIR_GRA (0x10000000)
+#define FEC_EIR_TXF (0x08000000) /* transmit frame interrupt */
+#define FEC_EIR_MII (0x00800000) /* MII interrupt */
+#define FEC_EIR_LC (0x00200000) /* late collision */
+#define FEC_EIR_XFUN (0x00080000) /* transmit FIFO underrun */
+#define FEC_EIR_XFERR (0x00040000) /* transmit FIFO error */
+#define FEC_EIR_RFERR (0x00020000) /* receive FIFO error */
+
+#define FEC_RCR_MAX_FRM_SIZE (FEC_MAX_FRM_SIZE << 16)
+#define FEC_RCR_MII (0x00000004)
+#define FEC_FECRFCR_FAE (0x00400000) /* frame accept error */
+#define FEC_FECRFCR_RXW (0x00200000) /* receive wait condition */
+#define FEC_FECRFCR_UF (0x00100000) /* receive FIFO underflow */
+#define FEC_FECRFCR_FRM (0x08000000)
+#define FEC_FECRFCR_GR (0x7 << 24)
+
+#define FEC_EIMR_DISABLE (0x00000000)
+
+#define FEC_FECRFAR_ALARM (0x300)
+#define FEC_FECTFCR_FRM (0x08000000)
+#define FEC_FECTFCR_GR (0x7 << 24)
+#define FEC_FECTFCR_FAE (0x00400000) /* frame accept error */
+#define FEC_FECTFCR_TXW (0x00040000) /* transmit wait condition */
+#define FEC_FECTFCR_UF (0x00100000) /* transmit FIFO underflow */
+#define FEC_FECTFCR_OF (0x00080000) /* transmit FIFO overflow */
+
+#define FEC_FECTFAR_ALARM (0x100)
+#define FEC_FECTFWR_XWMRK (0x00000000)
+
+#define FEC_FECTFSR_MSK (0xC0B00000)
+#define FEC_FECTFSR_TXW (0x40000000) /* transmit wait condition */
+#define FEC_FECTFSR_FAE (0x00800000) /* frame accept error */
+#define FEC_FECTFSR_UF (0x00200000) /* transmit FIFO underflow */
+#define FEC_FECTFSR_OF (0x00100000) /* transmit FIFO overflow */
+
+#define FEC_FECRFSR_MSK (0x80F00000)
+#define FEC_FECRFSR_FAE (0x00800000) /* frame accept error */
+#define FEC_FECRFSR_RXW (0x00400000) /* receive wait condition */
+#define FEC_FECRFSR_UF (0x00200000) /* receive FIFO underflow */
+
+#define FEC_CTCWR_TFCW_CRC (0x03000000)
+#define FEC_TCR_FDEN (0x00000004)
+#define FEC_TCR_HBC (0x00000002)
+#define FEC_RCR_DRT (0x00000002)
+#define FEC_EIMR_MASK (FEC_EIR_RL | FEC_EIR_HBERR)
+#define FEC_ECR_ETHEREN (0x00000002)
+#define FEC_FECTFCR_MSK (0x00FC0000)
+#define FEC_FECRFCR_MSK (0x00F80000)
+#define FEC_TCR_GTS (0x00000001)
+#define FEC_MIBC_ENABLE (0x00000000)
+#define FEC_MIB_LEN (228)
+#define FEC_PHY_ADDR (0x01)
+
+#define FEC_RX_DMA_PRI (6)
+#define FEC_TX_DMA_PRI (6)
+
+#define FEC_RX_DESC_FEC0 (SYS_SRAM_FEC_START)
+#define FEC_TX_DESC_FEC0 (FEC_RX_DESC_FEC0 + FEC_RX_BUF_NUMBER * sizeof(struct MCD_bufDescFec))
+
+#define FEC_RX_DESC_FEC1 (SYS_SRAM_FEC_START + SYS_SRAM_FEC_SIZE/2)
+#define FEC_TX_DESC_FEC1 (FEC_RX_DESC_FEC1 + FEC_RX_BUF_NUMBER * sizeof(struct MCD_bufDescFec))
+
+#define FEC_MMFR_ST (0x40000000)
+#define FEC_MMFR_OP_READ (0x20000000)
+#define FEC_MMFR_OP_WRITE (0x10020000)
+#define FEC_MMFR_TA (0x00020000)
+#define FEC_MMFR_DATA (0x0000ffff) /* PHY data mask */
+
+#define FEC_FLAGS_RX (0x00000001)
+
+#define FEC_CRCPOL (0xEDB88320)
+
+#define FEC_GR_TIMEOUT (1)
+
+#define FEC_SW_RST 0x2000000
+#define FEC_RST_CTL 0x1000000
--
1.7.1
Philippe De Muyter
2012-09-25 20:20:07 UTC
Permalink
Hello Stany

[CCing uclinux-dev]
Hello Philippe,
diff --git a/drivers/net/ethernet/freescale/fec_m54xx.c b/drivers/net/ethernet/freescale/fec_m54xx.c
index 4204a14..f6cafc6 100644
--- a/drivers/net/ethernet/freescale/fec_m54xx.c
+++ b/drivers/net/ethernet/freescale/fec_m54xx.c
@@ -41,6 +41,10 @@
*/
#define flush_and_invalidate_dcache() flush_cache_all()
+#ifdef CONFIG_MMU
+#define flush_dcache_range(A, L) flush_cf_dcache(A, L)
+#endif
+
#include "fec_m54xx.h"
#include <linux/phy.h>
Unfortunately, that's wromg. Read the comment in
arch/m68k/include/asm/cacheflush_mm.h :

/*
* Use the ColdFire cpushl instruction to push (and invalidate) cache lines.
* The start and end addresses are cache line numbers not memory addresses.
*/

So IIRC flush_cf_icache, flush_cf_dcache and flush_cf_bcache seemed uselesss
to me.

You should rather use 'mcf_cache_push'.
I'll keep you informed of my results.
Thanks

Philippe
Philippe De Muyter
2012-09-25 20:34:05 UTC
Permalink
Post by Philippe De Muyter
You should rather use 'mcf_cache_push'.
I should have written:

You should rather use '__flush_cache_all'

And that should probably go in arch/m68k/include/asm/cacheflush_mm.h,
as long as arch/m68k/include/asm/cacheflush_mm.h and
arch/m68k/include/asm/cacheflush_no.h are separate files.

Philippe
Philippe De Muyter
2012-09-26 09:33:20 UTC
Permalink
Helo,
Flushing all caches for each sent frame might not be a good solution. I think that performances will be very bad. I'll look at this point in my tests.
It might be more interesting to use caches in write through mode, or forcing theses explicit data out of cache.
I (and the default for M54xx) use the write through mode.

Philippe
If kmalloc with GFP_DMA returns data that is not write cached (ideally SRAM for performances) there is no need to flush caches.
Regards,
-----Original Message-----
From: Philippe De Muyter [mailto:phdm at macqel.be]
Sent: Tue 9/25/2012 10:34 PM
To: Stany MARCEL
Cc: uclinux-dev at uclinux.org
Subject: Re: [uClinux-dev] [PATCH 3/3] m68knommu: Add ethernet driver forMCF547x/MCF548x
Post by Philippe De Muyter
You should rather use 'mcf_cache_push'.
You should rather use '__flush_cache_all'
And that should probably go in arch/m68k/include/asm/cacheflush_mm.h,
as long as arch/m68k/include/asm/cacheflush_mm.h and
arch/m68k/include/asm/cacheflush_no.h are separate files.
Philippe
--
Philippe De Muyter +32 2 6101532 Macq SA rue de l'Aeronef 2 B-1140 Bruxelles
Greg Ungerer
2012-09-26 12:07:53 UTC
Permalink
Post by Philippe De Muyter
Hello Stany
[CCing uclinux-dev]
Hello Philippe,
diff --git a/drivers/net/ethernet/freescale/fec_m54xx.c b/drivers/net/ethernet/freescale/fec_m54xx.c
index 4204a14..f6cafc6 100644
--- a/drivers/net/ethernet/freescale/fec_m54xx.c
+++ b/drivers/net/ethernet/freescale/fec_m54xx.c
@@ -41,6 +41,10 @@
*/
#define flush_and_invalidate_dcache() flush_cache_all()
+#ifdef CONFIG_MMU
+#define flush_dcache_range(A, L) flush_cf_dcache(A, L)
Drivers shouldn't be calling these architecture flush functions at all.
They must use the DMA API and the functions it defines. See

Documentation/DMA-API.txt

For example look at the use of dma_map_single()/dma_unmap_single()
in drivers/net/ethernet/freescale/fec.c. (Ignore the almost certainly
bogus cache_flush_all() for CONFIG_M532x).

Regards
Greg



------------------------------------------------------------------------
Greg Ungerer -- Principal Engineer EMAIL: gerg at snapgear.com
SnapGear Group, McAfee PHONE: +61 7 3435 2888
8 Gardner Close, FAX: +61 7 3891 3630
Milton, QLD, 4064, Australia WEB: http://www.SnapGear.com
Greg Ungerer
2012-09-27 06:04:50 UTC
Permalink
Hi Stany,
Are cache flush needed as GFP_DMA flags are used for memory allocations (kmalloc and skbuff) ?
Yes, you will still need to flush caches. Allocating with GFP_DMA means
that the memory you get is capable of being DMA'ed from and to.
Is not the responsibility of arch dependent file to allocate DMA'able memory when this flag is used.
Its is DMA'able, but it is not normally cache coherent.

Regards
Greg
-----Original Message-----
From: Greg Ungerer [mailto:gerg at snapgear.com]
Sent: Wed 9/26/2012 2:07 PM
To: uClinux development list
Cc: Philippe De Muyter; Stany MARCEL
Subject: Re: [uClinux-dev] [PATCH 3/3] m68knommu: Add ethernet driver for MCF547x/MCF548x
Post by Philippe De Muyter
Hello Stany
[CCing uclinux-dev]
Hello Philippe,
diff --git a/drivers/net/ethernet/freescale/fec_m54xx.c b/drivers/net/ethernet/freescale/fec_m54xx.c
index 4204a14..f6cafc6 100644
--- a/drivers/net/ethernet/freescale/fec_m54xx.c
+++ b/drivers/net/ethernet/freescale/fec_m54xx.c
@@ -41,6 +41,10 @@
*/
#define flush_and_invalidate_dcache() flush_cache_all()
+#ifdef CONFIG_MMU
+#define flush_dcache_range(A, L) flush_cf_dcache(A, L)
Drivers shouldn't be calling these architecture flush functions at all.
They must use the DMA API and the functions it defines. See
Documentation/DMA-API.txt
For example look at the use of dma_map_single()/dma_unmap_single()
in drivers/net/ethernet/freescale/fec.c. (Ignore the almost certainly
bogus cache_flush_all() for CONFIG_M532x).
Regards
Greg
------------------------------------------------------------------------
Greg Ungerer -- Principal Engineer EMAIL: gerg at snapgear.com
SnapGear Group, McAfee PHONE: +61 7 3435 2888
8 Gardner Close, FAX: +61 7 3891 3630
Milton, QLD, 4064, Australia WEB: http://www.SnapGear.com
--
------------------------------------------------------------------------
Greg Ungerer -- Principal Engineer EMAIL: gerg at snapgear.com
SnapGear Group, McAfee PHONE: +61 7 3435 2888
8 Gardner Close FAX: +61 7 3217 5323
Milton, QLD, 4064, Australia WEB: http://www.SnapGear.com
Greg Ungerer
2012-10-04 06:56:35 UTC
Permalink
Hi Philippe,

I think this needs to be done as a platform driver. It is really the
standard way to deal with platform specifics cleanly. I know this
hardware really only exists on one device, but that is no reason
not to do it. Follow the example of the other Freescale FEC driver.
It won't really change the code too much, it just makes the
platform hardware specifics more cleanly separated from the driver
proper.

A few inline comments below too.
This is a fully functionnal ethernet driver for the MCF547x and MCF548x
^^^^^^^^^^^
functional
processors, tested on the M5484EVB board and on a custom board inpired
by the M5484EVB board. It implements a FEC+DMA driver and a mdio driver.
Original work was made by freescale for 2.6.25, but never submitted for
mainline, but cache support, mdio driver, phylib support, general
cleanup and 2.6.30-3.6 ports are mine.
Signed-off-by: Philippe De Muyter <phdm at macqel.be>
---
arch/m68k/include/asm/m54xxsim.h | 2 +
arch/m68k/kernel/setup_no.c | 5 +
drivers/net/ethernet/freescale/Kconfig | 26 +-
drivers/net/ethernet/freescale/Makefile | 1 +
drivers/net/ethernet/freescale/fec_m54xx.c | 1506 ++++++++++++++++++++++++++++
drivers/net/ethernet/freescale/fec_m54xx.h | 144 +++
6 files changed, 1683 insertions(+), 1 deletions(-)
create mode 100644 drivers/net/ethernet/freescale/fec_m54xx.c
create mode 100644 drivers/net/ethernet/freescale/fec_m54xx.h
diff --git a/arch/m68k/include/asm/m54xxsim.h b/arch/m68k/include/asm/m54xxsim.h
index f5531d5..b4c81bf 100644
--- a/arch/m68k/include/asm/m54xxsim.h
+++ b/arch/m68k/include/asm/m54xxsim.h
@@ -46,6 +46,8 @@
#define MCF_IRQ_UART2 (MCFINT_VECBASE + 33)
#define MCF_IRQ_UART3 (MCFINT_VECBASE + 32)
#define MCF_IRQ_DMA (MCFINT_VECBASE + 48) /* DMA */
+#define MCF_IRQ_FEC0 (MCFINT_VECBASE + 39) /* FEC0 */
+#define MCF_IRQ_FEC1 (MCFINT_VECBASE + 38) /* FEC1 */
/*
* Generic GPIO support
If you want to separate out these types of changes into separate
patches I will happily push them via the m68knommu tree right now.
diff --git a/arch/m68k/kernel/setup_no.c b/arch/m68k/kernel/setup_no.c
index 71fb299..10131b4 100644
--- a/arch/m68k/kernel/setup_no.c
+++ b/arch/m68k/kernel/setup_no.c
@@ -261,6 +261,11 @@ void __init setup_arch(char **cmdline_p)
paging_init();
}
+const char *machdep_get_mac_address(int i)
+{
+ return 0;
+}
+
/*
* Get CPU information for use by the procfs.
*/
This really seems like the wrong place to deal with this.
Doing as a platform driver should make this go away anyway.
diff --git a/drivers/net/ethernet/freescale/Kconfig b/drivers/net/ethernet/freescale/Kconfig
index 3574e14..64d8fc6 100644
--- a/drivers/net/ethernet/freescale/Kconfig
+++ b/drivers/net/ethernet/freescale/Kconfig
@@ -7,7 +7,7 @@ config NET_VENDOR_FREESCALE
default y
depends on FSL_SOC || QUICC_ENGINE || CPM1 || CPM2 || PPC_MPC512x || \
M523x || M527x || M5272 || M528x || M520x || M532x || \
- ARCH_MXC || ARCH_MXS || (PPC_MPC52xx && PPC_BESTCOMM)
+ M54xx || ARCH_MXC || ARCH_MXS || (PPC_MPC52xx && PPC_BESTCOMM)
---help---
If you have a network (Ethernet) card belonging to this class, say Y
and read the Ethernet-HOWTO, available from
@@ -30,6 +30,30 @@ config FEC
Say Y here if you want to use the built-in 10/100 Fast ethernet
controller on some Motorola ColdFire and Freescale i.MX processors.
+config FEC_54xx
+ tristate "MCF547x/MCF548x Fast Ethernet Controller support"
+ depends on M54xx
+ default y
+ select CRC32
+ select PHYLIB
+ select M54xx_DMA
+ help
+ The MCF547x and MCF548x have a built-in Fast Ethernet Controller.
+ This is not the same FEC controller as on other ColdFire as here
+ the DMA controller is not reserved to the FEC driver, but made
+ available for general DMA work.
+ Saying Y here will include support for this device in the kernel.
+
+config FEC2
+ bool "Second FEC ethernet controller (on some ColdFire CPUs)"
+ depends on FEC || FEC_54xx
+ default y
+ help
+ Say Y here if you want to use the second built-in 10/100 Fast
+ ethernet controller on some Motorola ColdFire processors. On M54xx,
+ If your second ethernet port is not connected, saying N here will
+ free 2 DMA channels and allow you to use FEC io ports as GPIO's.
+
With a platform driver you won't want this. The similar configuration
we had for the other common Freescale FEC driver got removed. We don't
want to re-introduce it again :-)
config FEC_MPC52xx
tristate "FEC MPC52xx driver"
depends on PPC_MPC52xx && PPC_BESTCOMM
diff --git a/drivers/net/ethernet/freescale/Makefile b/drivers/net/ethernet/freescale/Makefile
index 1752488..05a5022 100644
--- a/drivers/net/ethernet/freescale/Makefile
+++ b/drivers/net/ethernet/freescale/Makefile
@@ -3,6 +3,7 @@
#
obj-$(CONFIG_FEC) += fec.o
+obj-$(CONFIG_FEC_54xx) += fec_m54xx.o
obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx.o
ifeq ($(CONFIG_FEC_MPC52xx_MDIO),y)
obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx_phy.o
diff --git a/drivers/net/ethernet/freescale/fec_m54xx.c b/drivers/net/ethernet/freescale/fec_m54xx.c
new file mode 100644
index 0000000..b28c89a
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fec_m54xx.c
@@ -0,0 +1,1506 @@
+/*
+ * Performance and stability improvements: (C) Copyright 2008,
+ * Daniel Krueger, SYSTEC electronic GmbH
+ *
+ * Code crunched to get it to work on 2.6.24 -- FEC cleanup coming
+ * soon -- Kurt Mahan
+ *
+ * 2.6.30 and above port, cleanup, cache support, netdev_ops, mdio,
+ * phy & ethtool support,
+ * (C) Copyright 2010-2012 Philippe De Muyter <phdm at macqel.be> Macq SA
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/crc32.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/bitops.h>
+
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+
+#include <asm/m54xxdma_api.h>
+#include <asm/m54xxsram.h>
+#include <asm/irq.h>
+#include <asm/cacheflush.h>
+/*
+ * txd's and rxd's are in System SRAM which is uncached
+ * real buffers are in sdram which is cached
+ */
+#define flush_and_invalidate_dcache() flush_cache_all()
+
+#include "fec_m54xx.h"
+#include <linux/phy.h>
+
+#ifdef CONFIG_FEC2
+#define FEC_MAX_PORTS 2
+#else
+#define FEC_MAX_PORTS 1
+#endif
+
+#define FEC_MII_TIMEOUT 1000 /* us */
+#define FEC_TX_TIMEOUT (1 * HZ)
+
+#define FEC_TX_BUF_NUMBER (8)
+#define FEC_RX_BUF_NUMBER (64)
+
+#define FEC_TX_INDEX_MASK (0x7)
+#define FEC_RX_INDEX_MASK (0x3f)
+
+#define MAC_ADDR_LEN 6
+
+#define VERSION "0.30"
+MODULE_DESCRIPTION("DMA Fast Ethernet Controller driver ver " VERSION);
+
+/* fec private */
+struct fec_priv {
+ struct net_device *netdev; /* owning net device */
+ void *fecpriv_txbuf[FEC_TX_BUF_NUMBER]; /* tx buffer ptrs */
+ struct MCD_bufDescFec *fecpriv_txdesc; /* tx descriptor ptrs */
+ /* fecpriv_current_tx changed only by fec_interrupt_fec_tx_handler */
+ unsigned int fecpriv_current_tx; /* current tx desc index */
+ /* fecpriv_next_tx changed only by fec_start_tx */
+ unsigned int fecpriv_next_tx; /* next tx desc index */
+ unsigned int fecpriv_current_rx; /* current rx desc index */
+ struct MCD_bufDescFec *fecpriv_rxdesc; /* rx descriptor ptrs */
+ struct sk_buff *askb_rx[FEC_RX_BUF_NUMBER]; /* rx SKB ptrs */
+ unsigned int fecpriv_initiator_rx; /* rx dma initiator */
+ unsigned int fecpriv_initiator_tx; /* tx dma initiator */
+ int fecpriv_fec_rx_channel; /* rx dma channel */
+ int fecpriv_fec_tx_channel; /* tx dma channel */
+ int fecpriv_rx_requestor; /* rx dma requestor */
+ int fecpriv_tx_requestor; /* tx dma requestor */
+ unsigned char *fecpriv_mac_addr; /* private fec mac addr */
+ struct net_device_stats fecpriv_stat; /* stats ptr */
+ spinlock_t fecpriv_lock;
+ int fecpriv_rxflag;
+ struct tasklet_struct fecpriv_tasklet_reinit;
+ int index; /* fec hw number */
+#if 0
+ int in_poll;
+#endif
+
+ int duplex;
+ int speed;
+
+ /* phy link details */
+ int phy_addr;
+ struct phy_device *phydev;
+ enum phy_state link;
+
+ /* MDIO bus details */
+ unsigned int phy_speed;
+ struct completion mdio_done;
+};
+
+/* default fec0 address */
+unsigned char fec0_addr[MAC_ADDR_LEN] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x50 };
+
+#ifdef CONFIG_FEC2
+/* default fec1 address */
+unsigned char fec1_addr[MAC_ADDR_LEN] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x51 };
+#endif
I am sure the netdev people will have something to say on having
defaul MAC addresses. I think it is generally frowned upon. It is
much better just configure it with ifconfig from user space.
+extern const char *machdep_get_mac_address(int i);
+
+/* based on generic_adjust_link from fs_enet-main.c */
+static void fec_adjust_link(struct net_device *dev)
+{
+ struct fec_priv *fp = netdev_priv(dev);
+ struct phy_device *phydev = fp->phydev;
+ int new_state = 0;
+
+ if (phydev->link != PHY_DOWN) {
+ if (phydev->duplex != fp->duplex) {
+ unsigned long base_addr = (unsigned long) dev->base_addr;
+ u32 rcntrl;
+ u32 tcntrl;
+
+ new_state = 1;
+ fp->duplex = phydev->duplex;
+
+ rcntrl = readl(base_addr + FEC_RCR);
+ tcntrl = readl(base_addr + FEC_TCR);
I like the use of readl/writel!
+ rcntrl &= ~FEC_RCR_DRT;
+ tcntrl &= ~FEC_TCR_FDEN;
+ if (phydev->duplex == DUPLEX_FULL)
+ /* Enable the full duplex mode */
+ tcntrl |= FEC_TCR_FDEN;
+ else
+ /* Disable reception of frames while transmitting */
+ rcntrl |= FEC_RCR_DRT;
+
+ writel(rcntrl, base_addr + FEC_RCR);
+ writel(tcntrl, base_addr + FEC_TCR);
+ }
+
+ if (phydev->speed != fp->speed) {
+ new_state = 1;
+ fp->speed = phydev->speed;
+ }
+
+ if (fp->link == PHY_DOWN) {
+ new_state = 1;
+ fp->link = phydev->link;
+ }
+
+ } else if (fp->link) {
+ new_state = 1;
+ fp->link = PHY_DOWN;
+ fp->speed = 0;
+ fp->duplex = -1;
+ }
+
+ if (new_state /* && netif_msg_link(fp)*/)
+ phy_print_status(phydev);
+}
+
+static int fec_init_phy(struct net_device *dev)
+{
+ struct fec_priv *fp = netdev_priv(dev);
+ struct phy_device *phydev;
+ char phy_id[MII_BUS_ID_SIZE + 3];
+
+ snprintf(phy_id, sizeof(phy_id), "%x:%02x", 0xfec, fp->phy_addr);
+
+ fp->link = PHY_DOWN;
+ fp->speed = 0;
+ fp->duplex = -1;
+
+ phydev = phy_connect(dev, phy_id, &fec_adjust_link, 0, PHY_INTERFACE_MODE_MII);
+ if (IS_ERR(phydev)) {
+ dev_err(&dev->dev, "phy_connect failed\n");
+ return PTR_ERR(phydev);
+ }
+ dev_info(&dev->dev,
+ "attached phy %i (OUI/model = %06x/%02x) to driver %s\n",
+ phydev->addr, (phydev->phy_id >> 10) & 0x3fffff,
+ (phydev->phy_id >> 4) & 0x3f, phydev->drv->name);
+
+ fp->phydev = phydev;
+
+ return 0;
+}
+
+static int fec_phy_start(struct net_device *dev)
+{
+ struct fec_priv *fp = netdev_priv(dev);
+ int err;
+
+ /*
+ * PHY 0 for FEC 0 and PHY 1 for FEC 1
+ */
+ fp->phy_addr = fp->index;
+
+ err = fec_init_phy(dev);
+ if (err) {
+ dev_err(&dev->dev, "fec_init_phy failed\n");
+ return err;
+ }
+
+ /* reset phy - this also wakes it from PDOWN */
+ phy_write(fp->phydev, MII_BMCR, BMCR_RESET);
+ phy_start(fp->phydev);
+
+ return 0;
+}
+
+/* ethtool interface -- copy of fec_mpc52xx.c */
+#if 0
+static void fec_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
+ strcpy(info->driver, DRIVER_NAME);
+}
+#endif
If you done with the debug and older cruft it might be time to remove it.
+static int fec_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct fec_priv *priv = netdev_priv(dev);
+
+ if (!priv->phydev)
+ return -ENODEV;
+
+ return phy_ethtool_gset(priv->phydev, cmd);
+}
+
+static int fec_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct fec_priv *priv = netdev_priv(dev);
+
+ if (!priv->phydev)
+ return -ENODEV;
+
+ return phy_ethtool_sset(priv->phydev, cmd);
+}
+
+#if 0
+static u32 fec_get_msglevel(struct net_device *dev)
+{
+ struct fec_priv *priv = netdev_priv(dev);
+ return priv->msg_enable;
+}
+
+static void fec_set_msglevel(struct net_device *dev, u32 level)
+{
+ struct fec_priv *priv = netdev_priv(dev);
+ priv->msg_enable = level;
+}
+#endif
+
+static const struct ethtool_ops fec_ethtool_ops = {
+#if 0
+ .get_drvinfo = fec_get_drvinfo,
+#endif
+ .get_settings = fec_get_settings,
+ .set_settings = fec_set_settings,
+ .get_link = ethtool_op_get_link,
+#if 0
+ .get_msglevel = fec_get_msglevel,
+ .set_msglevel = fec_set_msglevel,
+#endif
+};
+
+
+static int fec_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ struct fec_priv *priv = netdev_priv(dev);
+
+ if (!priv->phydev)
+ return -ENOTSUPP;
+
+ return phy_mii_ioctl(priv->phydev, rq, cmd);
+}
+
+static int fec_mdio_transfer(struct mii_bus *bus, int phy_addr,
+ int reg, u32 value)
+{
+ struct fec_priv *priv = (struct fec_priv *)bus->priv;
+ unsigned long base_addr = (unsigned long) priv->netdev->base_addr;
+ unsigned long time_left;
+
+ /*
+ * Set MII speed to 2.5 MHz
+ */
+ writel((((MCF_BUSCLK + 4999999) / 5000000) & 0x3F) << 1, base_addr + FEC_MSCR);
Eventually this will need to use the clk api.
But for now I am not really too worried.
+ value |= (phy_addr << 23);
+ value |= (reg << 18);
+ value |= FEC_MMFR_ST | FEC_MMFR_TA;
+
+ init_completion(&priv->mdio_done);
+ writel(value, base_addr + FEC_MMFR);
+
+ /* wait for end of transfer, this takes about 23 us on lite5200b */
+ time_left = wait_for_completion_timeout(&priv->mdio_done,
+ usecs_to_jiffies(FEC_MII_TIMEOUT));
+
+ writel(0, base_addr + FEC_MSCR);
+
+ if (time_left == 0) {
+ pr_err("%s : timeout accessing phy%d/reg%d\n",
+ bus->name, phy_addr, reg);
+ return -ETIMEDOUT;
+ }
+
+ return (value & FEC_MMFR_OP_READ) ?
+ (readl(base_addr + FEC_MMFR) & FEC_MMFR_DATA) : 0;
+}
+
+static int fec_mdio_read(struct mii_bus *bus, int phy_addr, int reg)
+{
+ return fec_mdio_transfer(bus, phy_addr, reg, FEC_MMFR_OP_READ);
+}
+
+static int fec_mdio_write(struct mii_bus *bus, int phy_addr, int reg, u16 data)
+{
+ return fec_mdio_transfer(bus, phy_addr, reg, data | FEC_MMFR_OP_WRITE);
+}
+
+static int __init fec_mdio_init(struct net_device *dev)
+{
+ struct mii_bus *bus;
+ int err;
+ int i;
+ unsigned long addr;
+
+ bus = mdiobus_alloc();
+ if (bus == NULL)
+ return -ENOMEM;
+
+ bus->name = "FEC 0 MII bus";
+ bus->read = fec_mdio_read;
+ bus->write = fec_mdio_write;
+ /*
+ * on the freescale dev board, both PHY's (actually a DUAL phy)
+ * are connected via the MDIO bus of FEC0.
+ * PHY 0 for FEC 0 and PHY 1 for FEC 1
+ */
+ bus->phy_mask = ~((1 << FEC_MAX_PORTS) - 1);
+
+ /* setup irqs */
+ bus->irq = kmalloc(sizeof(bus->irq[0]) * PHY_MAX_ADDR, GFP_KERNEL);
+ if (bus->irq == NULL) {
+ err = -ENOMEM;
+ goto out_free;
+ }
+ for (i = 0; i < PHY_MAX_ADDR; i++)
+ bus->irq[i] = PHY_POLL;
+
+ snprintf(bus->id, MII_BUS_ID_SIZE, "%x", 0xfec);
+ bus->priv = netdev_priv(dev);
+
+ /* enable MII interrupt */
+ addr = dev->base_addr + FEC_EIMR;
+ writel(readl(addr) | FEC_EIR_MII, addr);
+
+ err = mdiobus_register(bus);
+ if (err)
+ goto out_unmap;
+
+ return 0;
+
+ kfree(bus->irq);
+ mdiobus_free(bus);
+
+ return err;
+}
+
+/************************************************************************
+* +NAME: fec_get_stats
+*
+* RETURNS: This function returns the statistical information.
+*************************************************************************/
+struct net_device_stats *fec_get_stats(struct net_device *dev)
+{
+ struct fec_priv *fp = netdev_priv(dev);
+ struct net_device_stats *statp = &fp->fecpriv_stat;
+ unsigned long base_addr = dev->base_addr;
+
+ /* Receive the statistical information */
+ statp->rx_packets = readl(base_addr + FECSTAT_RMON_R_PACKETS);
+ statp->tx_packets = readl(base_addr + FECSTAT_RMON_T_PACKETS);
+ statp->rx_bytes = readl(base_addr + FECSTAT_RMON_R_OCTETS);
+ statp->tx_bytes = readl(base_addr + FECSTAT_RMON_T_OCTETS);
+
+ statp->multicast = readl(base_addr + FECSTAT_RMON_R_MC_PKT);
+ statp->collisions = readl(base_addr + FECSTAT_RMON_T_COL);
+
+ statp->rx_length_errors = readl(base_addr + FECSTAT_RMON_R_UNDERSIZE) +
+ readl(base_addr + FECSTAT_RMON_R_OVERSIZE) +
+ readl(base_addr + FECSTAT_RMON_R_FRAG) +
+ readl(base_addr + FECSTAT_RMON_R_JAB);
+ statp->rx_crc_errors = readl(base_addr + FECSTAT_IEEE_R_CRC);
+ statp->rx_frame_errors = readl(base_addr + FECSTAT_IEEE_R_ALIGN);
+ statp->rx_over_errors = readl(base_addr + FECSTAT_IEEE_R_MACERR);
+
+ statp->tx_carrier_errors = readl(base_addr + FECSTAT_IEEE_T_CSERR);
+ statp->tx_fifo_errors = readl(base_addr + FECSTAT_IEEE_T_MACERR);
+ statp->tx_window_errors = readl(base_addr + FECSTAT_IEEE_T_LCOL);
+
+ /* I hope that one frame doesn't have more than one error */
+ statp->rx_errors = statp->rx_length_errors +
+ statp->rx_crc_errors +
+ statp->rx_frame_errors +
+ statp->rx_over_errors +
+ statp->rx_dropped;
+ statp->tx_errors = statp->tx_carrier_errors +
+ statp->tx_fifo_errors +
+ statp->tx_window_errors +
+ statp->tx_aborted_errors +
+ statp->tx_heartbeat_errors +
+ statp->tx_dropped;
+
+ return statp;
+}
+
+/************************************************************************
+* NAME: fec_set_multicast_list
+*
+* DESCRIPTION: This function sets the frame filtering parameters
+*************************************************************************/
+void fec_set_multicast_list(struct net_device *dev)
+{
+ unsigned int crc;
+ unsigned long base_addr = (unsigned long) dev->base_addr;
+ struct netdev_hw_addr *ha;
+ u32 gaur, galr;
+
+ if (dev->flags & IFF_PROMISC || dev->flags & IFF_ALLMULTI) {
+ /* Allow all incoming frames */
+ writel(0xFFFFFFFF, base_addr + FEC_GALR);
+ writel(0xFFFFFFFF, base_addr + FEC_GAUR);
+ return;
+ }
+
+ /* Reset the group address register */
+ galr = 0x00000000;
+ gaur = 0x00000000;
+
+ /* Process all addresses */
+ netdev_for_each_mc_addr(ha, dev) {
+ /* Calculate crc value for the current address */
+ crc = ether_crc_le(MAC_ADDR_LEN, ha->addr) >> 26;
+
+ /* Add this value */
+ crc &= 0x3F;
+ if (crc > 31)
+ gaur |= 0x1 << (crc - 32);
+ else
+ galr |= 0x1 << crc;
+ }
+ writel(galr, base_addr + FEC_GALR);
+ writel(gaur, base_addr + FEC_GAUR);
+}
+
+/************************************************************************
+* NAME: fec_set_mac_address
+*
+* DESCRIPTION: This function sets the MAC address
+*************************************************************************/
+int fec_set_mac_address(struct net_device *dev, void *p)
+{
+ struct fec_priv *fp = netdev_priv(dev);
+ unsigned long base_addr = (unsigned long) dev->base_addr;
+ struct sockaddr *addr = p;
+
+ if (netif_running(dev))
+ return -EBUSY;
+
+ /* Copy a new address to the device structure */
+ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+ /* Copy a new address to the private structure */
+ memcpy(fp->fecpriv_mac_addr, addr->sa_data, MAC_ADDR_LEN);
+
+ /* Set the address to the registers */
+ writel((dev->dev_addr[0] << 24) | (dev->dev_addr[1] << 16) |
+ (dev->dev_addr[2] << 8) | dev->dev_addr[3], base_addr + FEC_PALR);
+ writel((dev->dev_addr[4] << 24) | (dev->dev_addr[5] << 16) | 0x8808,
+ base_addr + FEC_PAUR);
+
+ return 0;
+}
+
+/************************************************************************
+* NAME: fec_start_tx
+*
+* DESCRIPTION: This function starts transmission of the frame using DMA
+*
+* RETURNS: This function always returns zero.
+*************************************************************************/
+int fec_start_tx(struct sk_buff *skb, struct net_device *dev)
+{
+ struct fec_priv *fp = netdev_priv(dev);
+ struct MCD_bufDescFec *txd = fp->fecpriv_txdesc;
+ int n = fp->fecpriv_next_tx;
+ void *data, *data_aligned;
+ int offset;
+
+ data = kmalloc(skb->len + 15, GFP_DMA | GFP_ATOMIC);
+
+ if (!data) {
+ fp->fecpriv_stat.tx_dropped++;
+ dev_kfree_skb(skb);
+ return 0;
+ }
+
+ offset = (((unsigned long)virt_to_phys(data) + 15) & 0xFFFFFFF0) -
+ (unsigned long)virt_to_phys(data);
+ data_aligned = (void *)((unsigned long)data + offset);
+ memcpy(data_aligned, skb->data, skb->len);
+
+ /* flush data cache before initializing the descriptor and starting DMA */
+ flush_dcache_range(virt_to_phys(data_aligned), skb->len);
If I compile this with the MMU enabled I get:

CC drivers/net/ethernet/freescale/fec_m54xx.o
drivers/net/ethernet/freescale/fec_m54xx.c: In function ?fec_start_tx?:
drivers/net/ethernet/freescale/fec_m54xx.c:530:2: error: implicit declaration of function ?flush_dcache_range?

Problem is flush_dcache_range() only exists for non-MMU compiles.

This needs to be changed to use the DMA API. With the use of
dma_map_single() and friends you won't need to use any flush_*()
calls at all. (The other FEC driver is a good example of its
use).
+ spin_lock_irq(&fp->fecpriv_lock);
+
+ /* Initialize the descriptor */
+ fp->fecpriv_txbuf[n] = data;
+ txd[n].dataPointer = (unsigned int) virt_to_phys(data_aligned);
+ txd[n].length = skb->len;
+ txd[n].statCtrl |= (MCD_FEC_END_FRAME | MCD_FEC_BUF_READY);
+ n = (n + 1) & FEC_TX_INDEX_MASK;
+ fp->fecpriv_next_tx = n;
+
+ if (fp->fecpriv_txbuf[fp->fecpriv_current_tx] && fp->fecpriv_current_tx == n)
+ netif_stop_queue(dev);
+
+ spin_unlock_irq(&fp->fecpriv_lock);
+
+ /* Tell the DMA to continue the transmission */
+ MCD_continDma(fp->fecpriv_fec_tx_channel);
+
+ dev_kfree_skb(skb);
+
+ dev->trans_start = jiffies;
+
+ return 0;
+}
+
+/************************************************************************
+* NAME: fec_tx_timeout
+*
+* DESCRIPTION: If the interrupt processing of received frames was lost
+* and DMA stopped the reception, this function clears
+* the transmission descriptors and starts DMA
+*
+*************************************************************************/
+void fec_tx_timeout(struct net_device *dev)
+{
+ int i;
+ struct fec_priv *fp = netdev_priv(dev);
+ struct MCD_bufDescFec *txd = fp->fecpriv_txdesc;
+ unsigned long base_addr = (unsigned long) dev->base_addr;
+ u32 fecfrst;
+
+ spin_lock_irq(&fp->fecpriv_lock);
+ MCD_killDma(fp->fecpriv_fec_tx_channel);
+ for (i = 0; i < FEC_TX_BUF_NUMBER; i++) {
+ if (fp->fecpriv_txbuf[i]) {
+ kfree(fp->fecpriv_txbuf[i]);
+ fp->fecpriv_txbuf[i] = NULL;
+ }
+ txd[i].statCtrl = MCD_FEC_INTERRUPT;
+ }
+ txd[i - 1].statCtrl |= MCD_FEC_WRAP;
+
+ fp->fecpriv_current_tx = fp->fecpriv_next_tx = 0;
+
+ /* Reset FIFOs */
+ fecfrst = FEC_SW_RST | FEC_RST_CTL;
+ writel(fecfrst, base_addr + FEC_FECFRST);
+ fecfrst &= ~FEC_SW_RST;
+ writel(fecfrst, base_addr + FEC_FECFRST);
+
+#if 0
+ /* Reset and disable FEC */
+ writel(FEC_ECR_RESET, base_addr + FEC_ECR);
+#endif
+
+ /* Enable FEC */
+ writel(FEC_ECR_ETHEREN, base_addr + FEC_ECR);
+
+ MCD_startDma(fp->fecpriv_fec_tx_channel, (char *) txd, 0,
+ (unsigned char *) (base_addr + FEC_FECTFDR), 0,
+ FEC_MAX_FRM_SIZE, 0, fp->fecpriv_initiator_tx,
+ FEC_TX_DMA_PRI, MCD_FECTX_DMA | MCD_INTERRUPT,
+ MCD_NO_CSUM | MCD_NO_BYTE_SWAP);
+
+ spin_unlock_irq(&fp->fecpriv_lock);
+
+ netif_wake_queue(dev);
+}
+
+/************************************************************************
+* NAME: fec_interrupt_tx_handler
+*
+* DESCRIPTION: This function is called when the data
+* transmission from the buffer to the FEC is completed.
+*
+*************************************************************************/
+void fec_interrupt_fec_tx_handler(void *voidp)
+{
+ struct net_device *dev = voidp;
+ struct fec_priv *fp = netdev_priv(dev);
+ void **txb = fp->fecpriv_txbuf;
+ int c = fp->fecpriv_current_tx;
+
+ /* Release the socket buffer */
+ if (txb[c]) {
+ kfree(txb[c]);
+ txb[c] = NULL;
+ }
+ c = (c + 1) & FEC_TX_INDEX_MASK;
+
+ if (MCD_dmaStatus(fp->fecpriv_fec_tx_channel) == MCD_DONE) {
+ for (; c != fp->fecpriv_next_tx; c = (c + 1) & FEC_TX_INDEX_MASK) {
+ if (txb[c]) {
+ kfree(txb[c]);
+ txb[c] = NULL;
+ }
+ }
+ }
+ fp->fecpriv_current_tx = c;
+
+ if (netif_queue_stopped(dev))
+ netif_wake_queue(dev);
+}
+
+/************************************************************************
+* NAME: fec_interrupt_rx_handler
+*
+* DESCRIPTION: This function is called when the data
+* reception from the FEC to the reception buffer is completed.
+*
+*************************************************************************/
+void fec_interrupt_fec_rx_handler(void *voidp)
+{
+ struct net_device *dev = voidp;
+ struct fec_priv *fp = netdev_priv(dev);
+ struct MCD_bufDescFec *rxd = fp->fecpriv_rxdesc;
+ struct sk_buff **rxskb = fp->askb_rx;
+ struct sk_buff *skb;
+ int i;
+ int c = fp->fecpriv_current_rx;
+
+ fp->fecpriv_rxflag = 1;
+ /* Some buffers can be missed */
+ if (!(rxd[c].statCtrl & MCD_FEC_END_FRAME)) {
+ /* Find a valid index */
+ for (i = 0; i < FEC_RX_BUF_NUMBER && !(rxd[c].statCtrl & MCD_FEC_END_FRAME); i++, c = (c + 1) & FEC_RX_INDEX_MASK)
+ ;
+
+ if (i == FEC_RX_BUF_NUMBER) {
+ /* There are no data to process */
+ /* Tell the DMA to continue the reception */
+ MCD_continDma(fp->fecpriv_fec_rx_channel);
+
+ fp->fecpriv_rxflag = 0;
+
+ return;
+ }
+ }
+
+ for (; rxd[c].statCtrl & MCD_FEC_END_FRAME; c = (c + 1) & FEC_RX_INDEX_MASK) {
+ if ((rxd[c].length <= FEC_MAXBUF_SIZE) &&
+ (rxd[c].length > 4)) { /* --tym-- */
+ skb = rxskb[c];
+ if (!skb)
+ fp->fecpriv_stat.rx_dropped++;
+ else {
+ /*
+ * invalidate data cache before initializing
+ * the descriptor and starting DMAs
+ */
+ cache_clear(virt_to_phys(skb->data), skb->len);
+
+ skb_put(skb, rxd[c].length - 4);
+ skb->protocol = eth_type_trans(skb, dev);
+ netif_rx(skb);
+ }
+ rxd[c].statCtrl &= ~MCD_FEC_END_FRAME;
+ /* allocate new skbuff */
+ rxskb[c] = alloc_skb(FEC_MAXBUF_SIZE + 16, /*GFP_ATOMIC |*/ GFP_DMA);
+ if (!rxskb[c]) {
+ rxd[c].dataPointer = 0;
+ rxd[c].length = 0;
+ fp->fecpriv_stat.rx_dropped++;
+ } else {
+#if 0
+if (!fp->in_poll)
+ pr_debug("rxskb[%d] = %p\n", c, rxskb[c]);
+#endif
+ skb_reserve(rxskb[c], 16);
+ rxskb[c]->dev = dev;
+
+ /*
+ * invalidate data cache before initializing
+ * the descriptor and starting DMAs
+ */
+ cache_clear(virt_to_phys(rxskb[c]->data), FEC_MAXBUF_SIZE);
+
+ rxd[c].dataPointer = (unsigned int) virt_to_phys(rxskb[c]->data);
+ rxd[c].length = FEC_MAXBUF_SIZE;
+ rxd[c].statCtrl |= MCD_FEC_BUF_READY;
+ }
+ }
+ }
+
+ fp->fecpriv_current_rx = c;
+
+ /* Tell the DMA to continue the reception */
+ MCD_continDma(fp->fecpriv_fec_rx_channel);
+
+ fp->fecpriv_rxflag = 0;
+}
+
+/************************************************************************
+* NAME: fec_interrupt_handler
+*
+* DESCRIPTION: This function is called when some special errors occur
+*
+*************************************************************************/
+irqreturn_t fec_interrupt_handler(int irq, void *dev_id)
+{
+ struct net_device *dev = (struct net_device *)dev_id;
+ struct fec_priv *fp = netdev_priv(dev);
+ unsigned long base_addr = (unsigned long) dev->base_addr;
+ unsigned long events;
+ u32 fecfrst;
+
+ /* Read and clear the events */
+ events = readl(base_addr + FEC_EIR) & readl(base_addr + FEC_EIMR);
+
+ if (events & FEC_EIR_HBERR) {
+ fp->fecpriv_stat.tx_heartbeat_errors++;
+ writel(FEC_EIR_HBERR, base_addr + FEC_EIR);
+ }
+
+ /* receive/transmit FIFO error */
+ if (events & (FEC_EIR_RFERR | FEC_EIR_XFERR)) {
+ /* kill DMA receive channel */
+ MCD_killDma(fp->fecpriv_fec_rx_channel);
+
+ /* kill running transmission by DMA */
+ MCD_killDma(fp->fecpriv_fec_tx_channel);
+
+ /* Reset FIFOs */
+ fecfrst = FEC_SW_RST | FEC_RST_CTL;
+ writel(fecfrst, base_addr + FEC_FECFRST);
+ fecfrst &= ~FEC_SW_RST;
+ writel(fecfrst, base_addr + FEC_FECFRST);
+
+ /* reset receive FIFO status register */
+ writel(FEC_FECRFSR_FAE |
+ FEC_FECRFSR_RXW |
+ FEC_FECRFSR_UF,
+ base_addr + FEC_FECRFSR);
+
+ /* reset transmit FIFO status register */
+ writel(FEC_FECTFSR_FAE |
+ FEC_FECTFSR_TXW |
+ FEC_FECTFSR_UF |
+ FEC_FECTFSR_OF,
+ base_addr + FEC_FECTFSR);
+
+ /* reset RFERR and XFERR event */
+ writel(FEC_EIR_RFERR | FEC_EIR_XFERR, base_addr + FEC_EIR);
+
+ /* stop queue */
+ netif_stop_queue(dev);
+
+ /* execute reinitialization as tasklet */
+ tasklet_schedule(&fp->fecpriv_tasklet_reinit);
+
+ fp->fecpriv_stat.rx_dropped++;
+ }
+
+ /* transmit FIFO underrun */
+ if (events & FEC_EIR_XFUN) {
+ /* reset XFUN event */
+ writel(FEC_EIR_XFUN, base_addr + FEC_EIR);
+ fp->fecpriv_stat.tx_aborted_errors++;
+ }
+
+ /* late collision */
+ if (events & FEC_EIR_LC) {
+ /* reset LC event */
+ writel(FEC_EIR_LC, base_addr + FEC_EIR);
+ fp->fecpriv_stat.tx_aborted_errors++;
+ }
+
+ /* collision retry limit */
+ if (events & FEC_EIR_RL) {
+ /* reset RL event */
+ writel(FEC_EIR_RL, base_addr + FEC_EIR);
+ fp->fecpriv_stat.tx_aborted_errors++;
+ }
+
+ /* MII transfer completed */
+ if (events & FEC_EIR_MII) {
+ complete(&fp->mdio_done);
+ writel(FEC_EIR_MII, base_addr + FEC_EIR);
+ }
+ return 0;
+}
+
+/************************************************************************
+* NAME: fec_interrupt_reinit
+*
+* DESCRIPTION: This function is called from interrupt handler
+* when controller must be reinitialized.
+*
+*************************************************************************/
+void fec_interrupt_fec_reinit(unsigned long data)
+{
+ int i;
+ struct net_device *dev = (struct net_device *)data;
+ struct fec_priv *fp = netdev_priv(dev);
+ struct MCD_bufDescFec *rxd = fp->fecpriv_rxdesc;
+ struct MCD_bufDescFec *txd = fp->fecpriv_txdesc;
+ struct sk_buff **rxskb = fp->askb_rx;
+ unsigned long base_addr = (unsigned long) dev->base_addr;
+
+#if 0
+if (!fp->in_poll)
+ pr_debug("fec_interrupt_fec_reinit\n");
+#endif
+ /* Initialize reception descriptors and start DMA for the reception */
+ for (i = 0; i < FEC_RX_BUF_NUMBER; i++) {
+ if (!rxskb[i]) {
+ rxskb[i] = alloc_skb(FEC_MAXBUF_SIZE + 16, GFP_ATOMIC | GFP_DMA);
+ if (!rxskb[i]) {
+ rxd[i].dataPointer = 0;
+ rxd[i].statCtrl = 0;
+ rxd[i].length = 0;
+ continue;
+ }
+#if 0
+if (!fp->in_poll)
+ pr_debug("rxskb[%d] = %p\n", i, rxskb[i]);
+#endif
+ rxskb[i]->dev = dev;
+ skb_reserve(rxskb[i], 16);
+ }
+ rxd[i].dataPointer = (unsigned int) virt_to_phys(rxskb[i]->data);
+ rxd[i].statCtrl = MCD_FEC_BUF_READY | MCD_FEC_INTERRUPT;
+ rxd[i].length = FEC_MAXBUF_SIZE;
+ }
+
+ rxd[i - 1].statCtrl |= MCD_FEC_WRAP;
+ fp->fecpriv_current_rx = 0;
+
+ /* restart frame transmission */
+ for (i = 0; i < FEC_TX_BUF_NUMBER; i++) {
+ if (fp->fecpriv_txbuf[i]) {
+ kfree(fp->fecpriv_txbuf[i]);
+ fp->fecpriv_txbuf[i] = NULL;
+ fp->fecpriv_stat.tx_dropped++;
+ }
+ txd[i].statCtrl = MCD_FEC_INTERRUPT;
+ }
+ txd[i - 1].statCtrl |= MCD_FEC_WRAP;
+ fp->fecpriv_current_tx = fp->fecpriv_next_tx = 0;
+
+ /* flush entire data cache before restarting the DMA */
+ flush_and_invalidate_dcache();
+
+ /* restart DMA from beginning */
+ MCD_startDma(fp->fecpriv_fec_rx_channel, (char *) rxd, 0,
+ (unsigned char *) (base_addr + FEC_FECRFDR), 0,
+ FEC_MAX_FRM_SIZE, 0, fp->fecpriv_initiator_rx,
+ FEC_RX_DMA_PRI, MCD_FECRX_DMA | MCD_INTERRUPT,
+ MCD_NO_CSUM | MCD_NO_BYTE_SWAP);
+
+ MCD_startDma(fp->fecpriv_fec_tx_channel, (char *) txd, 0,
+ (unsigned char *) (base_addr + FEC_FECTFDR), 0,
+ FEC_MAX_FRM_SIZE, 0, fp->fecpriv_initiator_tx,
+ FEC_TX_DMA_PRI, MCD_FECTX_DMA | MCD_INTERRUPT,
+ MCD_NO_CSUM | MCD_NO_BYTE_SWAP);
+
+ /* Enable FEC */
+ writel(FEC_ECR_ETHEREN, base_addr + FEC_ECR);
+
+ netif_wake_queue(dev);
+}
+
+/************************************************************************
+* NAME: fec_open
+*
+* DESCRIPTION: This function performs the initialization of FEC
+*
+* RETURNS: If no error occurs, this function returns zero.
+*************************************************************************/
+int fec_open(struct net_device *dev)
+{
+ struct fec_priv *fp = netdev_priv(dev);
+ struct MCD_bufDescFec *rxd = fp->fecpriv_rxdesc;
+ struct MCD_bufDescFec *txd = fp->fecpriv_txdesc;
+ struct sk_buff **rxskb = fp->askb_rx;
+ unsigned long base_addr = (unsigned long) dev->base_addr;
+ int i;
+ int channel;
+ int error_code = -EBUSY;
+ u32 fecfrst;
+ u32 rcntl;
+
+ /* Receive the DMA channels */
+ channel = dma_set_channel_fec(fp->fecpriv_rx_requestor);
+
+ if (channel == -1) {
+ pr_err("Rx Dma channel cannot be reserved\n");
+ goto ERRORS;
+ }
+
+ fp->fecpriv_fec_rx_channel = channel;
+
+ dma_connect(channel, fec_interrupt_fec_rx_handler, dev);
+
+ channel = dma_set_channel_fec(fp->fecpriv_tx_requestor);
+
+ if (channel == -1) {
+ pr_err("Tx Dma channel cannot be reserved\n");
+ goto ERRORS;
+ }
+
+ fp->fecpriv_fec_tx_channel = channel;
+
+ dma_connect(channel, fec_interrupt_fec_tx_handler, dev);
+
+ /* init tasklet for controller reinitialization */
+ tasklet_init(&fp->fecpriv_tasklet_reinit, fec_interrupt_fec_reinit,
+ (unsigned long) dev);
+
+ /* Reset FIFOs */
+ fecfrst = FEC_SW_RST | FEC_RST_CTL;
+ writel(fecfrst, base_addr + FEC_FECFRST);
+ fecfrst &= ~FEC_SW_RST;
+ writel(fecfrst, base_addr + FEC_FECFRST);
+
+ /* Reset and disable FEC */
+ writel(FEC_ECR_RESET, base_addr + FEC_ECR);
+
+ udelay(10);
+
+ /* Clear all events */
+ writel(FEC_EIR_CLEAR, base_addr + FEC_EIR);
+
+ /* Reset FIFO status */
+ writel(FEC_FECTFSR_MSK, base_addr + FEC_FECTFSR);
+ writel(FEC_FECRFSR_MSK, base_addr + FEC_FECRFSR);
+
+ /* Set the default address */
+ writel((dev->dev_addr[0] << 24) | (dev->dev_addr[1] << 16) |
+ (dev->dev_addr[2] << 8) | dev->dev_addr[3], base_addr + FEC_PALR);
+ writel((dev->dev_addr[4] << 24) | (dev->dev_addr[5] << 16) | 0x8808,
+ base_addr + FEC_PAUR);
+
+ /* Reset the group address descriptor */
+ writel(0x00000000, base_addr + FEC_GALR);
+ writel(0x00000000, base_addr + FEC_GAUR);
+
+ /* Reset the individual address descriptor */
+ writel(0x00000000, base_addr + FEC_IALR);
+ writel(0x00000000, base_addr + FEC_IAUR);
+
+ /* Set the receive control register */
+ rcntl = FEC_RCR_MAX_FRM_SIZE | FEC_RCR_MII;
+ writel(rcntl, base_addr + FEC_RCR);
+
+ /* Set the receive FIFO control register */
+ writel(FEC_FECRFCR_FRM | FEC_FECRFCR_GR
+ | (FEC_FECRFCR_MSK /* disable all but ... */
+ & ~FEC_FECRFCR_FAE /* enable frame accept error */
+ & ~FEC_FECRFCR_RXW /* enable receive wait condition */
+#if 0
+ & ~FEC_FECRFCR_UF /* enable FIFO underflow */
+#endif
+ ), base_addr + FEC_FECRFCR);
+
+ /* Set the receive FIFO alarm register */
+ writel(FEC_FECRFAR_ALARM, base_addr + FEC_FECRFAR);
+
+ /* Set the transmit FIFO control register */
+ writel(FEC_FECTFCR_FRM | FEC_FECTFCR_GR
+ | (FEC_FECTFCR_MSK /* disable all but ... */
+ & ~FEC_FECTFCR_FAE /* enable frame accept error */
+#if 0
+ & ~FEC_FECTFCR_TXW /* enable transmit wait condition */
+ & ~FEC_FECTFCR_UF /* enable FIFO underflow */
+#endif
+ & ~FEC_FECTFCR_OF), /* enable FIFO overflow */
+ base_addr + FEC_FECTFCR);
+
+ /* Set the transmit FIFO alarm register */
+ writel(FEC_FECTFAR_ALARM, base_addr + FEC_FECTFAR);
+
+ /* Set the Tx FIFO watermark */
+ writel(FEC_FECTFWR_XWMRK, base_addr + FEC_FECTFWR);
+
+ /* Enable the transmitter to append the CRC */
+ writel(FEC_CTCWR_TFCW_CRC, base_addr + FEC_CTCWR);
+
+ /* Enable the ethernet interrupts */ /* FIXME : too late for mdio bus */
+ writel(FEC_EIMR_DISABLE
+ | FEC_EIR_LC
+ | FEC_EIR_RL
+ | FEC_EIR_HBERR
+ | FEC_EIR_XFUN
+ | FEC_EIR_XFERR
+ | FEC_EIR_RFERR
+ | FEC_EIR_MII,
+ base_addr + FEC_EIMR);
+
+ if (fp->phydev->duplex == DUPLEX_FULL)
+ /* Enable the full duplex mode */
+ writel(FEC_TCR_FDEN | FEC_TCR_HBC, base_addr + FEC_TCR);
+ else {
+ /* Disable reception of frames while transmitting */
+ rcntl |= FEC_RCR_DRT;
+ writel(rcntl, base_addr + FEC_RCR);
+ }
+
+ /* Enable MIB */
+ writel(FEC_MIBC_ENABLE, base_addr + FEC_MIBC);
+
+ /* Enable FEC */
+ writel(FEC_ECR_ETHEREN, base_addr + FEC_ECR);
+
+ /* Initialize tx descriptors and start DMA for the transmission */
+ for (i = 0; i < FEC_TX_BUF_NUMBER; i++)
+ txd[i].statCtrl = MCD_FEC_INTERRUPT;
+
+ txd[i - 1].statCtrl |= MCD_FEC_WRAP;
+
+ fp->fecpriv_current_tx = fp->fecpriv_next_tx = 0;
+
+ MCD_startDma(fp->fecpriv_fec_tx_channel, (char *) txd, 0,
+ (unsigned char *) (base_addr + FEC_FECTFDR), 0,
+ FEC_MAX_FRM_SIZE, 0, fp->fecpriv_initiator_tx,
+ FEC_TX_DMA_PRI, MCD_FECTX_DMA | MCD_INTERRUPT,
+ MCD_NO_CSUM | MCD_NO_BYTE_SWAP);
+
+ /* Initialize rx descriptors and start DMA for the reception */
+ for (i = 0; i < FEC_RX_BUF_NUMBER; i++) {
+ rxskb[i] = alloc_skb(FEC_MAXBUF_SIZE + 16, GFP_DMA);
+ if (!rxskb[i]) {
+ rxd[i].dataPointer = 0;
+ rxd[i].statCtrl = 0;
+ rxd[i].length = 0;
+ } else {
+#if 0
+if (!fp->in_poll)
+ pr_debug("rxskb[%d] = %p\n", i, rxskb[i]);
+#endif
+ skb_reserve(rxskb[i], 16);
+ rxskb[i]->dev = dev;
+ rxd[i].dataPointer = (unsigned int) virt_to_phys(rxskb[i]->data);
+ rxd[i].statCtrl = MCD_FEC_BUF_READY | MCD_FEC_INTERRUPT;
+ rxd[i].length = FEC_MAXBUF_SIZE;
+ }
+ }
+
+ rxd[i - 1].statCtrl |= MCD_FEC_WRAP;
+ fp->fecpriv_current_rx = 0;
+
+ /* flush entire data cache before restarting the DMA */
+ flush_and_invalidate_dcache();
+
+ MCD_startDma(fp->fecpriv_fec_rx_channel, (char *) rxd, 0,
+ (unsigned char *) (base_addr + FEC_FECRFDR), 0,
+ FEC_MAX_FRM_SIZE, 0, fp->fecpriv_initiator_rx,
+ FEC_RX_DMA_PRI, MCD_FECRX_DMA | MCD_INTERRUPT,
+ MCD_NO_CSUM | MCD_NO_BYTE_SWAP);
+
+ netif_start_queue(dev);
+ return 0;
+
+
+ /* Remove the channels and return with the error code */
+ if (fp->fecpriv_fec_rx_channel != -1) {
+ dma_disconnect(fp->fecpriv_fec_rx_channel);
+ dma_remove_channel_by_number(fp->fecpriv_fec_rx_channel);
+ fp->fecpriv_fec_rx_channel = -1;
+ }
+
+ if (fp->fecpriv_fec_tx_channel != -1) {
+ dma_disconnect(fp->fecpriv_fec_tx_channel);
+ dma_remove_channel_by_number(fp->fecpriv_fec_tx_channel);
+ fp->fecpriv_fec_tx_channel = -1;
+ }
+
+ return error_code;
+}
+
+/************************************************************************
+* NAME: fec_close
+*
+* DESCRIPTION: This function performs the graceful stop of the
+* transmission and disables FEC
+*
+* RETURNS: This function always returns zero.
+*************************************************************************/
+int fec_close(struct net_device *dev)
+{
+ struct fec_priv *fp = netdev_priv(dev);
+ unsigned long base_addr = (unsigned long) dev->base_addr;
+ unsigned long time;
+ int i;
+ unsigned long addr;
+
+ netif_stop_queue(dev);
+
+ /* Perform the graceful stop */
+ addr = dev->base_addr + FEC_TCR;
+ writel(readl(addr) | FEC_TCR_GTS, addr);
+
+ time = jiffies;
+
+ /* Wait for the graceful stop */
+ while (!(readl(base_addr + FEC_EIR) & FEC_EIR_GRA) && jiffies - time < FEC_GR_TIMEOUT * HZ)
+ schedule();
+
+ /* Disable FEC */
+ writel(FEC_ECR_DISABLE, base_addr + FEC_ECR);
+
+ /* Reset the DMA channels */
+ spin_lock_irq(&fp->fecpriv_lock);
+ MCD_killDma(fp->fecpriv_fec_tx_channel);
+ spin_unlock_irq(&fp->fecpriv_lock);
+ dma_remove_channel_by_number(fp->fecpriv_fec_tx_channel);
+ dma_disconnect(fp->fecpriv_fec_tx_channel);
+ fp->fecpriv_fec_tx_channel = -1;
+
+ for (i = 0; i < FEC_TX_BUF_NUMBER; i++) {
+ if (fp->fecpriv_txbuf[i]) {
+ kfree(fp->fecpriv_txbuf[i]);
+ fp->fecpriv_txbuf[i] = NULL;
+ }
+ }
+
+ spin_lock_irq(&fp->fecpriv_lock);
+ MCD_killDma(fp->fecpriv_fec_rx_channel);
+ spin_unlock_irq(&fp->fecpriv_lock);
+
+ dma_remove_channel_by_number(fp->fecpriv_fec_rx_channel);
+ dma_disconnect(fp->fecpriv_fec_rx_channel);
+ fp->fecpriv_fec_rx_channel = -1;
+
+ for (i = 0; i < FEC_RX_BUF_NUMBER; i++) {
+ if (fp->askb_rx[i]) {
+ kfree_skb(fp->askb_rx[i]);
+ fp->askb_rx[i] = NULL;
+ }
+ }
+
+ return 0;
+}
+
+#ifndef MODULE
+/************************************************************************
+* NAME: fec_str_to_mac
+*
+* DESCRIPTION: This function interprets the character string into MAC addr
+*
+*************************************************************************/
+int fec_str_to_mac(char *str_mac, unsigned char *addr)
+{
+ unsigned long val;
+ char c;
+ unsigned long octet[MAC_ADDR_LEN], *octetptr = octet;
+ int i;
+
+ val = 0;
+ while ((c = *str_mac) != '\0') {
+ c = hex_to_bin(c);
+ if (c >= 0) {
+ val = (val * 16) + c;
+ str_mac++;
+ continue;
+ }
+ break;
+ }
+ if (*str_mac == ':') {
+ *octetptr++ = val, str_mac++;
+ if (octetptr >= octet + MAC_ADDR_LEN)
+ return 1;
+ goto again;
+ }
+
+ /* Check for trailing characters */
+ if (*str_mac && !(*str_mac == ' '))
+ return 1;
+
+ *octetptr++ = val;
+
+ if ((octetptr - octet) == MAC_ADDR_LEN) {
+ for (i = 0; i <= MAC_ADDR_LEN; i++)
+ addr[i] = octet[i];
+ } else
+ return 1;
+
+ return 0;
+}
+
+/************************************************************************
+* NAME: fec_mac_setup0
+*
+* DESCRIPTION: This function sets the MAC address of FEC0 from command line
+*
+*************************************************************************/
+int __init fec_mac_setup0(char *s)
+{
+ if (!s || !*s)
+ return 1;
+
+ if (fec_str_to_mac(s, fec0_addr))
+ pr_err("Invalid MAC address from command line for FEC0");
+ return 1;
+}
+__setup("mac0=", fec_mac_setup0);
+
+#ifdef CONFIG_FEC2
+/************************************************************************
+* NAME: fec_mac_setup1
+*
+* DESCRIPTION: This function sets the MAC address of FEC1 from command line
+*
+*************************************************************************/
+int __init fec_mac_setup1(char *s)
+{
+ if (!s || !*s)
+ return 1;
+
+ if (fec_str_to_mac(s, fec1_addr))
+ pr_err("Invalid MAC address from command line for FEC1");
+ return 1;
+}
+__setup("mac1=", fec_mac_setup1);
+#endif
+#endif
+
+#undef CONFIG_NET_POLL_CONTROLLER
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/*
+ * Polling 'interrupt' - used by things like netconsole to send skbs
+ * without having to re-enable interrupts. It's not called while
+ * the interrupt routine is executing.
+ */
+
+static void fec_poll(struct net_device *dev)
+{
+#if 0
+ struct fec_priv *fp = netdev_priv(dev);
+#endif
+ /* disable_irq here is not very nice, but with the lockless
+ interrupt handler we have no other choice. */
+#if 0
+ fp->in_poll = 1;
+#endif
+ disable_irq(112);
+ disable_irq(dev->irq);
+ fec_interrupt_handler(dev->irq, dev);
+ fec_interrupt_fec_rx_handler(dev);
+ fec_interrupt_fec_tx_handler(dev);
+ enable_irq(dev->irq);
+ enable_irq(112);
+#if 0
+ fp->in_poll = 0;
+#endif
+}
+#endif
+
+static const struct net_device_ops fec_netdev_ops = {
+ .ndo_open = fec_open,
+ .ndo_stop = fec_close,
+ .ndo_start_xmit = fec_start_tx,
+ .ndo_set_rx_mode = fec_set_multicast_list,
+ .ndo_set_mac_address = fec_set_mac_address,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_tx_timeout = fec_tx_timeout,
+ .ndo_get_stats = fec_get_stats,
+ .ndo_do_ioctl = fec_ioctl,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = fec_poll,
+#endif
+};
+
+/*
+ * Initialize a FEC device
+ */
+int fec_enet_init(struct net_device *dev)
+{
+ static int index;
+ struct fec_priv *fp = netdev_priv(dev);
+ const void *mac_addr;
+ int i;
+ unsigned long addr;
+
+ fp->index = index;
+#if 0
+ fp->in_poll = 0;
+#endif
+ fp->netdev = dev;
+
+ if (index == 0) {
+ /* disable fec0 */
+ writel(FEC_ECR_DISABLE, FEC_BASE_ADDR_FEC0 + FEC_ECR);
+
+ /* setup the interrupt handler */
+ dev->irq = MCF_IRQ_FEC0;
+
+ if (request_irq(dev->irq, fec_interrupt_handler,
+ IRQF_DISABLED, "ColdFire FEC 0", dev)) {
+ dev->irq = 0;
+ pr_err("Cannot allocate FEC0 IRQ\n");
+#if 0
+ } else {
+ /* interrupt priority and level */
+ MCF_ICR(ISC_FEC0) = ILP_FEC0;
+#endif
+ }
+
+ /* fec base address */
+ dev->base_addr = FEC_BASE_ADDR_FEC0;
+
+ /* requestor numbers */
+ fp->fecpriv_rx_requestor = DMA_FEC0_RX;
+ fp->fecpriv_tx_requestor = DMA_FEC0_TX;
+
+ /* tx descriptors */
+ fp->fecpriv_txdesc = (void *)FEC_TX_DESC_FEC0;
+
+ /* rx descriptors */
+ fp->fecpriv_rxdesc = (void *)FEC_RX_DESC_FEC0;
+
+ /* mac addr */
+ mac_addr = machdep_get_mac_address(index);
+ if (mac_addr)
+ memcpy(fec0_addr, mac_addr, MAC_ADDR_LEN);
+ fp->fecpriv_mac_addr = fec0_addr;
+ } else {
+ /* disable fec1 */
+ writel(FEC_ECR_DISABLE, FEC_BASE_ADDR_FEC1 + FEC_ECR);
+#ifdef CONFIG_FEC2
+ /* setup the interrupt handler */
+ dev->irq = MCF_IRQ_FEC1;
+
+ if (request_irq(dev->irq, fec_interrupt_handler,
+ IRQF_DISABLED, "ColdFire FEC 1", dev)) {
+ dev->irq = 0;
+ pr_err("Cannot allocate FEC1 IRQ\n");
+#if 0
+ } else {
+ /* interrupt priority and level */
+ MCF_ICR(ISC_FEC1) = ILP_FEC1;
+#endif
+ }
+
+ /* fec base address */
+ dev->base_addr = FEC_BASE_ADDR_FEC1;
+
+ /* requestor numbers */
+ fp->fecpriv_rx_requestor = DMA_FEC1_RX;
+ fp->fecpriv_tx_requestor = DMA_FEC1_TX;
+
+ /* tx descriptors */
+ fp->fecpriv_txdesc = (void *)FEC_TX_DESC_FEC1;
+
+ /* rx descriptors */
+ fp->fecpriv_rxdesc = (void *)FEC_RX_DESC_FEC1;
+
+ /* mac addr */
+ mac_addr = machdep_get_mac_address(index);
+ if (mac_addr)
+ memcpy(fec1_addr, mac_addr, MAC_ADDR_LEN);
+ fp->fecpriv_mac_addr = fec1_addr;
+#endif
+ }
+
+ /* clear MIB */
+ memset((void *) (dev->base_addr + 0x200), 0, FEC_MIB_LEN);
+
+ /* clear the statistics structure */
+ memset((void *) &(fp->fecpriv_stat), 0,
+ sizeof(struct net_device_stats));
+
+ /* grab the FEC initiators */
+ dma_set_initiator(fp->fecpriv_tx_requestor);
+ fp->fecpriv_initiator_tx = dma_get_initiator(fp->fecpriv_tx_requestor);
+ dma_set_initiator(fp->fecpriv_rx_requestor);
+ fp->fecpriv_initiator_rx = dma_get_initiator(fp->fecpriv_rx_requestor);
+
+ /* reset the DMA channels */
+ fp->fecpriv_fec_rx_channel = -1;
+ fp->fecpriv_fec_tx_channel = -1;
+
+ for (i = 0; i < FEC_RX_BUF_NUMBER; i++)
+ fp->askb_rx[i] = NULL;
+
+ /* initialize the pointers to the socket buffers */
+ for (i = 0; i < FEC_TX_BUF_NUMBER; i++)
+ fp->fecpriv_txbuf[i] = NULL;
+
+ ether_setup(dev);
+
+ dev->watchdog_timeo = FEC_TX_TIMEOUT;
+ dev->netdev_ops = &fec_netdev_ops;
+ dev->ethtool_ops = &fec_ethtool_ops;
+
+
+ memcpy(dev->dev_addr, fp->fecpriv_mac_addr, ETH_ALEN);
+
+ spin_lock_init(&fp->fecpriv_lock);
+
+ /* Initialize FEC/I2C/IRQ Pin Assignment Register */
+ writew((readw(FEC_GPIO_PAR_FECI2CIRQ) & 0xF) | FEC_FECI2CIRQ,
+ FEC_GPIO_PAR_FECI2CIRQ);
+
+ /* set MII mode (as opposed to 7-wires mode) */
+ addr = dev->base_addr + FEC_RCR;
+ writel(readl(addr) | FEC_RCR_MII, addr);
+
+ index++;
+ return 0;
+}
+
+/*
+ * Stop a device
+ */
+void fec_stop(struct net_device *dev)
+{
+ struct fec_priv *fp = netdev_priv(dev);
+
+ dma_remove_initiator(fp->fecpriv_initiator_tx);
+ dma_remove_initiator(fp->fecpriv_initiator_rx);
+
+ if (dev->irq)
+ free_irq(dev->irq, dev);
+}
+
+/*
+ * Module Initialization
+ */
+int __init fec_init(void)
+{
+ struct net_device *dev;
+ int i;
+ int err;
+
+ pr_info("FEC ENET (DMA) Version %s\n", VERSION);
+
+ for (i = 0; i < FEC_MAX_PORTS; i++) {
+ dev = alloc_etherdev(sizeof(struct fec_priv));
+ if (!dev)
+ return -ENOMEM;
+ netif_carrier_off(dev);
+ err = fec_enet_init(dev);
+ if (err) {
+ free_netdev(dev);
+ continue;
+ }
+ if (register_netdev(dev) != 0) {
+ free_netdev(dev);
+ return -EIO;
+ }
+
+ /*
+ * On the freescale dev board, E0MDC & E0MDIO are
+ * connected to a dual phy. E1MDC & E1MDIO are unused.
+ * In other words, only fec 0 can communicate with
+ * the dual phy.
+ */
+ if (i == 0)
+ fec_mdio_init(dev);
+
+ fec_phy_start(dev);
+
+ pr_info("%s: ethernet %pM\n",
+ dev->name, dev->dev_addr);
+ }
+ return 0;
+}
+
+/* module_exit(fec_cleanup); */
+module_init(fec_init);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/freescale/fec_m54xx.h b/drivers/net/ethernet/freescale/fec_m54xx.h
new file mode 100644
index 0000000..022ee32
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fec_m54xx.h
@@ -0,0 +1,144 @@
+
+#define FEC_BASE_ADDR_FEC0 ((unsigned int)MCF_MBAR + 0x9000)
+#define FEC_BASE_ADDR_FEC1 ((unsigned int)MCF_MBAR + 0x9800)
+
+#define FEC_GPIO_PAR_FECI2CIRQ ((unsigned int)MCF_MBAR + 0xA44)
+#define FEC_FECI2CIRQ (0xFFC0)
These belong in the m54xxsim.h. They are specific to the 5475/5485, that is
that nice platform separate again :-)
+#define FEC_ECR_DISABLE (0x00000000)
+
+#define FEC_EIR 0x004
+#define FEC_EIMR 0x008
+#define FEC_ECR 0x024
+#define FEC_MMFR 0x040
+#define FEC_MSCR 0x044
+#define FEC_MIBC 0x064
+#define FEC_RCR 0x084
+#define FEC_TCR 0x0C4
+#define FEC_PALR 0x0E4
+#define FEC_PAUR 0x0E8
+#define FEC_IAUR 0x118
+#define FEC_IALR 0x11C
+#define FEC_GAUR 0x120
+#define FEC_GALR 0x124
+#define FEC_FECTFWR 0x144
+#define FEC_FECRFDR 0x184
+#define FEC_FECRFSR 0x188
+#define FEC_FECRFCR 0x18C
+#define FEC_FECRFAR 0x198
+#define FEC_FECTFDR 0x1A4
+#define FEC_FECTFSR 0x1A8
+#define FEC_FECTFCR 0x1AC
+#define FEC_FECTFAR 0x1B8
+#define FEC_FECFRST 0x1C4
+#define FEC_CTCWR 0x1C8
+#define FECSTAT_RMON_T_PACKETS 0x204
+#define FECSTAT_RMON_T_COL 0x224
+#define FECSTAT_RMON_T_OCTETS 0x244
+#define FECSTAT_IEEE_T_DROP 0x248
+#define FECSTAT_IEEE_T_FRAME_OK 0x24C
+#define FECSTAT_IEEE_T_LCOL 0x25C
+#define FECSTAT_IEEE_T_MACERR 0x264
+#define FECSTAT_IEEE_T_CSERR 0x268
+#define FECSTAT_IEEE_T_OCTETS_OK 0x274
+#define FECSTAT_RMON_R_PACKETS 0x284
+#define FECSTAT_RMON_R_MC_PKT 0x28C
+#define FECSTAT_RMON_R_UNDERSIZE 0x294
+#define FECSTAT_RMON_R_OVERSIZE 0x298
+#define FECSTAT_RMON_R_FRAG 0x29C
+#define FECSTAT_RMON_R_JAB 0x2A0
+#define FECSTAT_RMON_R_OCTETS 0x2C4
+#define FECSTAT_IEEE_R_DROP 0x2C8
+#define FECSTAT_IEEE_R_FRAME_OK 0x2CC
+#define FECSTAT_IEEE_R_CRC 0x2D0
+#define FECSTAT_IEEE_R_ALIGN 0x2D4
+#define FECSTAT_IEEE_R_MACERR 0x2D8
+#define FECSTAT_IEEE_R_OCTETS_OK 0x2E0
+
+#define FEC_MAX_FRM_SIZE (1518)
+#define FEC_MAXBUF_SIZE (1520)
+
+/* Register values */
+#define FEC_ECR_RESET (0x00000001)
+
+#define FEC_EIR_CLEAR (0xFFFFFFFF)
+#define FEC_EIR_RL (0x00100000)
+#define FEC_EIR_HBERR (0x80000000)
+#define FEC_EIR_BABR (0x40000000) /* babbling receive error */
+#define FEC_EIR_BABT (0x20000000) /* babbling transmit error */
+#define FEC_EIR_GRA (0x10000000)
+#define FEC_EIR_TXF (0x08000000) /* transmit frame interrupt */
+#define FEC_EIR_MII (0x00800000) /* MII interrupt */
+#define FEC_EIR_LC (0x00200000) /* late collision */
+#define FEC_EIR_XFUN (0x00080000) /* transmit FIFO underrun */
+#define FEC_EIR_XFERR (0x00040000) /* transmit FIFO error */
+#define FEC_EIR_RFERR (0x00020000) /* receive FIFO error */
+
+#define FEC_RCR_MAX_FRM_SIZE (FEC_MAX_FRM_SIZE << 16)
+#define FEC_RCR_MII (0x00000004)
+#define FEC_FECRFCR_FAE (0x00400000) /* frame accept error */
+#define FEC_FECRFCR_RXW (0x00200000) /* receive wait condition */
+#define FEC_FECRFCR_UF (0x00100000) /* receive FIFO underflow */
+#define FEC_FECRFCR_FRM (0x08000000)
+#define FEC_FECRFCR_GR (0x7 << 24)
+
+#define FEC_EIMR_DISABLE (0x00000000)
+
+#define FEC_FECRFAR_ALARM (0x300)
+#define FEC_FECTFCR_FRM (0x08000000)
+#define FEC_FECTFCR_GR (0x7 << 24)
+#define FEC_FECTFCR_FAE (0x00400000) /* frame accept error */
+#define FEC_FECTFCR_TXW (0x00040000) /* transmit wait condition */
+#define FEC_FECTFCR_UF (0x00100000) /* transmit FIFO underflow */
+#define FEC_FECTFCR_OF (0x00080000) /* transmit FIFO overflow */
+
+#define FEC_FECTFAR_ALARM (0x100)
+#define FEC_FECTFWR_XWMRK (0x00000000)
+
+#define FEC_FECTFSR_MSK (0xC0B00000)
+#define FEC_FECTFSR_TXW (0x40000000) /* transmit wait condition */
+#define FEC_FECTFSR_FAE (0x00800000) /* frame accept error */
+#define FEC_FECTFSR_UF (0x00200000) /* transmit FIFO underflow */
+#define FEC_FECTFSR_OF (0x00100000) /* transmit FIFO overflow */
+
+#define FEC_FECRFSR_MSK (0x80F00000)
+#define FEC_FECRFSR_FAE (0x00800000) /* frame accept error */
+#define FEC_FECRFSR_RXW (0x00400000) /* receive wait condition */
+#define FEC_FECRFSR_UF (0x00200000) /* receive FIFO underflow */
+
+#define FEC_CTCWR_TFCW_CRC (0x03000000)
+#define FEC_TCR_FDEN (0x00000004)
+#define FEC_TCR_HBC (0x00000002)
+#define FEC_RCR_DRT (0x00000002)
+#define FEC_EIMR_MASK (FEC_EIR_RL | FEC_EIR_HBERR)
+#define FEC_ECR_ETHEREN (0x00000002)
+#define FEC_FECTFCR_MSK (0x00FC0000)
+#define FEC_FECRFCR_MSK (0x00F80000)
+#define FEC_TCR_GTS (0x00000001)
+#define FEC_MIBC_ENABLE (0x00000000)
+#define FEC_MIB_LEN (228)
+#define FEC_PHY_ADDR (0x01)
+
+#define FEC_RX_DMA_PRI (6)
+#define FEC_TX_DMA_PRI (6)
+
+#define FEC_RX_DESC_FEC0 (SYS_SRAM_FEC_START)
+#define FEC_TX_DESC_FEC0 (FEC_RX_DESC_FEC0 + FEC_RX_BUF_NUMBER * sizeof(struct MCD_bufDescFec))
+
+#define FEC_RX_DESC_FEC1 (SYS_SRAM_FEC_START + SYS_SRAM_FEC_SIZE/2)
+#define FEC_TX_DESC_FEC1 (FEC_RX_DESC_FEC1 + FEC_RX_BUF_NUMBER * sizeof(struct MCD_bufDescFec))
+
+#define FEC_MMFR_ST (0x40000000)
+#define FEC_MMFR_OP_READ (0x20000000)
+#define FEC_MMFR_OP_WRITE (0x10020000)
+#define FEC_MMFR_TA (0x00020000)
+#define FEC_MMFR_DATA (0x0000ffff) /* PHY data mask */
+
+#define FEC_FLAGS_RX (0x00000001)
+
+#define FEC_CRCPOL (0xEDB88320)
+
+#define FEC_GR_TIMEOUT (1)
+
+#define FEC_SW_RST 0x2000000
+#define FEC_RST_CTL 0x1000000
Regards
Greg
--
------------------------------------------------------------------------
Greg Ungerer -- Principal Engineer EMAIL: gerg at snapgear.com
SnapGear Group, McAfee PHONE: +61 7 3435 2888
8 Gardner Close FAX: +61 7 3217 5323
Milton, QLD, 4064, Australia WEB: http://www.SnapGear.com
Philippe De Muyter
2012-10-04 07:34:48 UTC
Permalink
Hi Greg,
Post by Greg Ungerer
Hi Philippe,
I think this needs to be done as a platform driver. It is really the
standard way to deal with platform specifics cleanly. I know this
hardware really only exists on one device, but that is no reason
not to do it. Follow the example of the other Freescale FEC driver.
It won't really change the code too much, it just makes the
platform hardware specifics more cleanly separated from the driver
proper.
A few inline comments below too.
Thanks for your comments. I had already started the conversion
to the dma_map_single api, but I am worried that those functions
are not inlined altough IIRC they often resolve to nothing (for the
unmap case) or to a single asm("nop") (for the map case).

I'll look at your other comments, and especially the notion of
platform driver, that I do not really know.

Best regards

Philippe
--
Philippe De Muyter +32 2 6101532 Macq SA rue de l'Aeronef 2 B-1140 Bruxelles
Greg Ungerer
2012-10-04 13:33:32 UTC
Permalink
Hi Philippe,
Post by Philippe De Muyter
Post by Greg Ungerer
Hi Philippe,
I think this needs to be done as a platform driver. It is really the
standard way to deal with platform specifics cleanly. I know this
hardware really only exists on one device, but that is no reason
not to do it. Follow the example of the other Freescale FEC driver.
It won't really change the code too much, it just makes the
platform hardware specifics more cleanly separated from the driver
proper.
A few inline comments below too.
Thanks for your comments. I had already started the conversion
to the dma_map_single api, but I am worried that those functions
are not inlined altough IIRC they often resolve to nothing (for the
unmap case) or to a single asm("nop") (for the map case).
I'll look at your other comments, and especially the notion of
platform driver, that I do not really know.
My biggest concern is the amount of MCD/DMA support code. And it is
all done quite differently to everything else in the kernel. We may
get a bit of push back from kernel folk who look after DMA.

Regards
Greg


------------------------------------------------------------------------
Greg Ungerer -- Principal Engineer EMAIL: gerg at snapgear.com
SnapGear Group, McAfee PHONE: +61 7 3435 2888
8 Gardner Close, FAX: +61 7 3891 3630
Milton, QLD, 4064, Australia WEB: http://www.SnapGear.com
Philippe De Muyter
2012-10-04 14:56:01 UTC
Permalink
Hi Greg,
Post by Greg Ungerer
Hi Philippe,
Post by Philippe De Muyter
Post by Greg Ungerer
Hi Philippe,
I think this needs to be done as a platform driver. It is really the
standard way to deal with platform specifics cleanly. I know this
hardware really only exists on one device, but that is no reason
not to do it. Follow the example of the other Freescale FEC driver.
It won't really change the code too much, it just makes the
platform hardware specifics more cleanly separated from the driver
proper.
A few inline comments below too.
Thanks for your comments. I had already started the conversion
to the dma_map_single api, but I am worried that those functions
are not inlined altough IIRC they often resolve to nothing (for the
unmap case) or to a single asm("nop") (for the map case).
I'll look at your other comments, and especially the notion of
platform driver, that I do not really know.
My biggest concern is the amount of MCD/DMA support code. And it is
all done quite differently to everything else in the kernel. We may
get a bit of push back from kernel folk who look after DMA.
Actually, there is already a similar code in arch/powerpc/sysdev/bestcomm
(also from freescale, maybe an identical part, but I did not find any
usable doc), but the powerpc folks kept that hidden in the arch/powerpc
tree, instead of installing it in drivers/dma.

I wanted rather to make the MCD DMA code visible, so that if freescale
reuses it for a powerpc (mpc) or arm (iMX) part it does not end duplicated in
the kernel tree. But if that's a too hard way, let's keep it hidden
in arch/m68k.

Best regards

Philippe
--
Philippe De Muyter +32 2 6101532 Macq SA rue de l'Aeronef 2 B-1140 Bruxelles
Philippe De Muyter
2012-10-04 15:03:29 UTC
Permalink
Hi Greg,
Post by Philippe De Muyter
Post by Greg Ungerer
My biggest concern is the amount of MCD/DMA support code. And it is
all done quite differently to everything else in the kernel. We may
get a bit of push back from kernel folk who look after DMA.
Actually, there is already a similar code in arch/powerpc/sysdev/bestcomm
(also from freescale, maybe an identical part, but I did not find any
usable doc), but the powerpc folks kept that hidden in the arch/powerpc
tree, instead of installing it in drivers/dma.
The MCD DMA or DMA FEC code from freescale has a comment implying that this
was first used in the MPC8220 part. And Montavista has a MPC8220 port, but
I did not find it, so I do not know where they installed the MCD DMA driver.

Philippe
--
Philippe De Muyter +32 2 6101532 Macq SA rue de l'Aeronef 2 B-1140 Bruxelles
Greg Ungerer
2012-10-09 06:12:44 UTC
Permalink
Hi Philippe,
Post by Philippe De Muyter
Post by Philippe De Muyter
Post by Greg Ungerer
My biggest concern is the amount of MCD/DMA support code. And it is
all done quite differently to everything else in the kernel. We may
get a bit of push back from kernel folk who look after DMA.
Actually, there is already a similar code in arch/powerpc/sysdev/bestcomm
(also from freescale, maybe an identical part, but I did not find any
usable doc), but the powerpc folks kept that hidden in the arch/powerpc
tree, instead of installing it in drivers/dma.
The MCD DMA or DMA FEC code from freescale has a comment implying that this
was first used in the MPC8220 part. And Montavista has a MPC8220 port, but
I did not find it, so I do not know where they installed the MCD DMA driver.
Ok, looks like there is a bit a variance in all this.
Probably the best thing to do is post the patches on the linux kernel
mailing list then, asking for direction on a dma driver.

I have no problem with it going into the arch/m68k area. So that is
always an option.

Regards
Greg
--
------------------------------------------------------------------------
Greg Ungerer -- Principal Engineer EMAIL: gerg at snapgear.com
SnapGear Group, McAfee PHONE: +61 7 3435 2888
8 Gardner Close FAX: +61 7 3217 5323
Milton, QLD, 4064, Australia WEB: http://www.SnapGear.com
Philippe De Muyter
2012-10-09 09:07:58 UTC
Permalink
[CCing lkml, linux-ppc, netdev, linux-m68k]

Hello kernel sources architects

I have a working driver for the m54xx FEC ethernet driver that I
would like to integrate in the kernel tree. Problems are that
- this driver needs an associated DMA driver (provided by FreeScale)
wich is not dma-engine enabled
- they're are already many fec drivers in the kernel tree, and
at least one, fec_mpc52xx.c, seems to be very similar (information
below), to the one for the mcf54xx, except it uses a differently
named associated DMA driver (BestComm/SmartDma/SDMA) which is also
not dma-engine enabled, and even kept hidden in /arch/powerpc where
it is inaccessible when compiling for m68k. The underlying DMA part
from Freescale however seems similar to the one used in the
m54xx. (again, see information below)

So, now I am lost, what should I do ?

The current state of my patches
[http://mailman.uclinux.org/pipermail/uclinux-dev/2012-September/052147.html]
is pushing the freescale provided MCD_DMA dma driver to /drivers/dma,
without adding the dma-engine compatibility layer, and adding the specific
fec_m54xx ethernet driver to /drivers/net/ethernet/freescale

Best regards

Philippe
Post by Greg Ungerer
Hi Philippe,
Post by Philippe De Muyter
Post by Philippe De Muyter
Post by Greg Ungerer
My biggest concern is the amount of MCD/DMA support code. And it is
all done quite differently to everything else in the kernel. We may
get a bit of push back from kernel folk who look after DMA.
Actually, there is already a similar code in arch/powerpc/sysdev/bestcomm
(also from freescale, maybe an identical part, but I did not find any
usable doc), but the powerpc folks kept that hidden in the arch/powerpc
tree, instead of installing it in drivers/dma.
The MCD DMA or DMA FEC code from freescale has a comment implying that this
was first used in the MPC8220 part. And Montavista has a MPC8220 port, but
I did not find it, so I do not know where they installed the MCD DMA driver.
Ok, looks like there is a bit a variance in all this.
I also began to read the mpc5200 user's guide parts about the fec and
BestComm/SmartDma/SDMA (not sure which one is the official FreeScale name)
and they look very similar, but not identical, to their m54xx counterparts.

It seems possible to make the fec_mpc52xx.c driver work for the m54xx
but that needs at least:
- moving some files or part of them from /arch/powerpc/sysdev and
/arch/powerpc/include/asm to /drivers/dma and /include/linux,
- renaming the fec_mpc52xx files to a more sensible name,
- providing out_be32 and in_be32 in /arch/m68k/include/asm/io.h,
- and then unifying the interface to BestComm/SmartDma/SDMA and MCD_DMA
in mcf_52xx.c.

An additional problem is that the freescale docs for powerpcs and for
coldfires do not use the same mnemonics for the same registers.

e.g. FEC registers
offset MPC5200 MCF5484
====== ======= =======
000 FEC_ID n/a
004 IEVENT EIR
008 IMASK EIMR
010 R_DES_ACTIVE n/a
014 X_DES_ACTIVE n/a
024 ECNTRL ECR
040 MII_DATA MDATA
044 MII_SPEED MSCR
064 MIB_CONTROL MIBC
084 R_CNTRL RCR
088 R_HASH RHR
0C4 X_CNTRL TCR
0E4 PADDR1 PALR
0E8 PADDR2 PAHR
0EC OP_PAUSE OPD
118 IADDR1 IAUR
11C IADDR1 IALR
120 GADDR1 GAUR
124 GADDR2 GALR
144 X_WMRK FECTFWR
184 RFIFO_DATA FECRFDR
188 RFIFO_STATUS FECRFSR
18C RFIFO_CONTROL FECRFCR
190 RFIFO_LRF_PTR FECRLRFP
194 RFIFO_LWF_PTR FECRLWFP
198 RFIFO_ALARM FECRFAR
19C RFIFO_RDPTR FECRFRP
1A0 RFIFO_WRPTR FECRFWP
1A4 TFIFO_DATA FECTFDR
1A8 TFIFO_STATUS FECTFSR
1AC TFIFO_CONTROL FECTFCR
1B0 TFIFO_LRF_PTR FECTLRFP
1B4 TFIFO_LWF_PTR FECTLWFP
1B8 TFIFO_ALARM FECTFAR
1BC TFIFO_RDPTR FECTFRP
1C0 TFIFO_WRPTR FECTFWP
1C4 RESET_CNTRL FECFRST
1C8 XMIT_FSM FECCTCWR
Post by Greg Ungerer
Probably the best thing to do is post the patches on the linux kernel
mailing list then, asking for direction on a dma driver.
I have no problem with it going into the arch/m68k area. So that is
always an option.
For the dma engines, the similarity is also obvious. For example, find
below side by side mpc52xx and m54xx definitions for the
main DMA registers :

from mpc52xx.h from MCD_dma.h
/* SDMA */ /* MCD_DMA */
struct mpc52xx_sdma { struct dmaRegs {
u32 taskBar; /* 0x00 */ u32 taskbar;
u32 currentPointer; /* 0x04 */ u32 currPtr;
u32 endPointer; /* 0x08 */ u32 endPtr;
u32 variablePointer; /* 0x0c */ u32 varTablePtr;

u8 IntVect1; /* 0x10 */ u16 dma_rsvd0;
u8 IntVect2; /* 0x11 */
u16 PtdCntrl; /* 0x12 */ u16 ptdControl;

u32 IntPend; /* 0x14 */ u32 intPending;
u32 IntMask; /* 0x18 */ u32 intMask;

u16 tcr[16]; /* 0x1c .. 0x3a */ u16 taskControl[16];

u8 ipr[32]; /* 0x3c .. 0x5b */ u8 priority[32];

u32 cReqSelect; /* 0x5c */ u32 initiatorMux;
u32 task_size0; /* 0x60 */ u32 taskSize0;
u32 task_size1; /* 0x64 */ u32 taskSize1;
u32 MDEDebug; /* 0x68 */ u32 dma_rsvd1;
u32 ADSDebug; /* 0x6c */ u32 dma_rsvd2;
u32 Value1; /* 0x70 */ u32 debugComp1;
u32 Value2; /* 0x74 */ u32 debugComp2;
u32 Control; /* 0x78 */ u32 debugControl;
u32 Status; /* 0x7c */ u32 debugStatus;
u32 PTDDebug; /* 0x80 */ u32 ptdDebug;
}; };
Greg Ungerer
2012-10-16 06:39:05 UTC
Permalink
Hi Philippe,
Post by Philippe De Muyter
[CCing lkml, linux-ppc, netdev, linux-m68k]
Hello kernel sources architects
I have a working driver for the m54xx FEC ethernet driver that I
would like to integrate in the kernel tree. Problems are that
- this driver needs an associated DMA driver (provided by FreeScale)
wich is not dma-engine enabled
- they're are already many fec drivers in the kernel tree, and
at least one, fec_mpc52xx.c, seems to be very similar (information
below), to the one for the mcf54xx, except it uses a differently
named associated DMA driver (BestComm/SmartDma/SDMA) which is also
not dma-engine enabled, and even kept hidden in /arch/powerpc where
it is inaccessible when compiling for m68k. The underlying DMA part
from Freescale however seems similar to the one used in the
m54xx. (again, see information below)
So, now I am lost, what should I do ?
The current state of my patches
[http://mailman.uclinux.org/pipermail/uclinux-dev/2012-September/052147.html]
is pushing the freescale provided MCD_DMA dma driver to /drivers/dma,
without adding the dma-engine compatibility layer, and adding the specific
fec_m54xx ethernet driver to /drivers/net/ethernet/freescale
Do you get any responses?
I didn't see any...

Regards
Greg
Post by Philippe De Muyter
Post by Greg Ungerer
Hi Philippe,
Post by Philippe De Muyter
Post by Philippe De Muyter
Post by Greg Ungerer
My biggest concern is the amount of MCD/DMA support code. And it is
all done quite differently to everything else in the kernel. We may
get a bit of push back from kernel folk who look after DMA.
Actually, there is already a similar code in arch/powerpc/sysdev/bestcomm
(also from freescale, maybe an identical part, but I did not find any
usable doc), but the powerpc folks kept that hidden in the arch/powerpc
tree, instead of installing it in drivers/dma.
The MCD DMA or DMA FEC code from freescale has a comment implying that this
was first used in the MPC8220 part. And Montavista has a MPC8220 port, but
I did not find it, so I do not know where they installed the MCD DMA driver.
Ok, looks like there is a bit a variance in all this.
I also began to read the mpc5200 user's guide parts about the fec and
BestComm/SmartDma/SDMA (not sure which one is the official FreeScale name)
and they look very similar, but not identical, to their m54xx counterparts.
It seems possible to make the fec_mpc52xx.c driver work for the m54xx
- moving some files or part of them from /arch/powerpc/sysdev and
/arch/powerpc/include/asm to /drivers/dma and /include/linux,
- renaming the fec_mpc52xx files to a more sensible name,
- providing out_be32 and in_be32 in /arch/m68k/include/asm/io.h,
- and then unifying the interface to BestComm/SmartDma/SDMA and MCD_DMA
in mcf_52xx.c.
An additional problem is that the freescale docs for powerpcs and for
coldfires do not use the same mnemonics for the same registers.
e.g. FEC registers
offset MPC5200 MCF5484
====== ======= =======
000 FEC_ID n/a
004 IEVENT EIR
008 IMASK EIMR
010 R_DES_ACTIVE n/a
014 X_DES_ACTIVE n/a
024 ECNTRL ECR
040 MII_DATA MDATA
044 MII_SPEED MSCR
064 MIB_CONTROL MIBC
084 R_CNTRL RCR
088 R_HASH RHR
0C4 X_CNTRL TCR
0E4 PADDR1 PALR
0E8 PADDR2 PAHR
0EC OP_PAUSE OPD
118 IADDR1 IAUR
11C IADDR1 IALR
120 GADDR1 GAUR
124 GADDR2 GALR
144 X_WMRK FECTFWR
184 RFIFO_DATA FECRFDR
188 RFIFO_STATUS FECRFSR
18C RFIFO_CONTROL FECRFCR
190 RFIFO_LRF_PTR FECRLRFP
194 RFIFO_LWF_PTR FECRLWFP
198 RFIFO_ALARM FECRFAR
19C RFIFO_RDPTR FECRFRP
1A0 RFIFO_WRPTR FECRFWP
1A4 TFIFO_DATA FECTFDR
1A8 TFIFO_STATUS FECTFSR
1AC TFIFO_CONTROL FECTFCR
1B0 TFIFO_LRF_PTR FECTLRFP
1B4 TFIFO_LWF_PTR FECTLWFP
1B8 TFIFO_ALARM FECTFAR
1BC TFIFO_RDPTR FECTFRP
1C0 TFIFO_WRPTR FECTFWP
1C4 RESET_CNTRL FECFRST
1C8 XMIT_FSM FECCTCWR
Post by Greg Ungerer
Probably the best thing to do is post the patches on the linux kernel
mailing list then, asking for direction on a dma driver.
I have no problem with it going into the arch/m68k area. So that is
always an option.
For the dma engines, the similarity is also obvious. For example, find
below side by side mpc52xx and m54xx definitions for the
from mpc52xx.h from MCD_dma.h
/* SDMA */ /* MCD_DMA */
struct mpc52xx_sdma { struct dmaRegs {
u32 taskBar; /* 0x00 */ u32 taskbar;
u32 currentPointer; /* 0x04 */ u32 currPtr;
u32 endPointer; /* 0x08 */ u32 endPtr;
u32 variablePointer; /* 0x0c */ u32 varTablePtr;
u8 IntVect1; /* 0x10 */ u16 dma_rsvd0;
u8 IntVect2; /* 0x11 */
u16 PtdCntrl; /* 0x12 */ u16 ptdControl;
u32 IntPend; /* 0x14 */ u32 intPending;
u32 IntMask; /* 0x18 */ u32 intMask;
u16 tcr[16]; /* 0x1c .. 0x3a */ u16 taskControl[16];
u8 ipr[32]; /* 0x3c .. 0x5b */ u8 priority[32];
u32 cReqSelect; /* 0x5c */ u32 initiatorMux;
u32 task_size0; /* 0x60 */ u32 taskSize0;
u32 task_size1; /* 0x64 */ u32 taskSize1;
u32 MDEDebug; /* 0x68 */ u32 dma_rsvd1;
u32 ADSDebug; /* 0x6c */ u32 dma_rsvd2;
u32 Value1; /* 0x70 */ u32 debugComp1;
u32 Value2; /* 0x74 */ u32 debugComp2;
u32 Control; /* 0x78 */ u32 debugControl;
u32 Status; /* 0x7c */ u32 debugStatus;
u32 PTDDebug; /* 0x80 */ u32 ptdDebug;
}; };
--
------------------------------------------------------------------------
Greg Ungerer -- Principal Engineer EMAIL: gerg at snapgear.com
SnapGear Group, McAfee PHONE: +61 7 3435 2888
8 Gardner Close FAX: +61 7 3217 5323
Milton, QLD, 4064, Australia WEB: http://www.SnapGear.com
Philippe De Muyter
2012-10-16 08:03:49 UTC
Permalink
Hi Greg,
Post by Greg Ungerer
Hi Philippe,
Post by Philippe De Muyter
[CCing lkml, linux-ppc, netdev, linux-m68k]
Hello kernel sources architects
I have a working driver for the m54xx FEC ethernet driver that I
would like to integrate in the kernel tree. Problems are that
- this driver needs an associated DMA driver (provided by FreeScale)
wich is not dma-engine enabled
- they're are already many fec drivers in the kernel tree, and
at least one, fec_mpc52xx.c, seems to be very similar (information
below), to the one for the mcf54xx, except it uses a differently
named associated DMA driver (BestComm/SmartDma/SDMA) which is also
not dma-engine enabled, and even kept hidden in /arch/powerpc where
it is inaccessible when compiling for m68k. The underlying DMA part
from Freescale however seems similar to the one used in the
m54xx. (again, see information below)
So, now I am lost, what should I do ?
The current state of my patches
[http://mailman.uclinux.org/pipermail/uclinux-dev/2012-September/052147.html]
is pushing the freescale provided MCD_DMA dma driver to /drivers/dma,
without adding the dma-engine compatibility layer, and adding the specific
fec_m54xx ethernet driver to /drivers/net/ethernet/freescale
Do you get any responses?
I didn't see any...
No, and none also about my simpler patch moving arch/powerpc/sysdev/bestcomm
to drivers/dma/bestcomm (except a private and useful one telling me how to
set '-M' option as default for 'git format-patch'), but at least this simpler
patch seems to be in a wait bucket at
http://patchwork.ozlabs.org/project/linuxppc-dev/list/.

Regards

Philippe

PS: -M as default for 'git format-patch':

put
[diff]
renames = true
in .git/config
Post by Greg Ungerer
Regards
Greg
Post by Philippe De Muyter
Post by Greg Ungerer
Hi Philippe,
Post by Philippe De Muyter
Post by Philippe De Muyter
Post by Greg Ungerer
My biggest concern is the amount of MCD/DMA support code. And it is
all done quite differently to everything else in the kernel. We may
get a bit of push back from kernel folk who look after DMA.
Actually, there is already a similar code in
arch/powerpc/sysdev/bestcomm
(also from freescale, maybe an identical part, but I did not find any
usable doc), but the powerpc folks kept that hidden in the arch/powerpc
tree, instead of installing it in drivers/dma.
The MCD DMA or DMA FEC code from freescale has a comment implying that this
was first used in the MPC8220 part. And Montavista has a MPC8220 port, but
I did not find it, so I do not know where they installed the MCD DMA driver.
Ok, looks like there is a bit a variance in all this.
I also began to read the mpc5200 user's guide parts about the fec and
BestComm/SmartDma/SDMA (not sure which one is the official FreeScale name)
and they look very similar, but not identical, to their m54xx
counterparts.
It seems possible to make the fec_mpc52xx.c driver work for the m54xx
- moving some files or part of them from /arch/powerpc/sysdev and
/arch/powerpc/include/asm to /drivers/dma and /include/linux,
- renaming the fec_mpc52xx files to a more sensible name,
- providing out_be32 and in_be32 in /arch/m68k/include/asm/io.h,
- and then unifying the interface to BestComm/SmartDma/SDMA and MCD_DMA
in mcf_52xx.c.
An additional problem is that the freescale docs for powerpcs and for
coldfires do not use the same mnemonics for the same registers.
e.g. FEC registers
offset MPC5200 MCF5484
====== ======= =======
000 FEC_ID n/a
004 IEVENT EIR
008 IMASK EIMR
010 R_DES_ACTIVE n/a
014 X_DES_ACTIVE n/a
024 ECNTRL ECR
040 MII_DATA MDATA
044 MII_SPEED MSCR
064 MIB_CONTROL MIBC
084 R_CNTRL RCR
088 R_HASH RHR
0C4 X_CNTRL TCR
0E4 PADDR1 PALR
0E8 PADDR2 PAHR
0EC OP_PAUSE OPD
118 IADDR1 IAUR
11C IADDR1 IALR
120 GADDR1 GAUR
124 GADDR2 GALR
144 X_WMRK FECTFWR
184 RFIFO_DATA FECRFDR
188 RFIFO_STATUS FECRFSR
18C RFIFO_CONTROL FECRFCR
190 RFIFO_LRF_PTR FECRLRFP
194 RFIFO_LWF_PTR FECRLWFP
198 RFIFO_ALARM FECRFAR
19C RFIFO_RDPTR FECRFRP
1A0 RFIFO_WRPTR FECRFWP
1A4 TFIFO_DATA FECTFDR
1A8 TFIFO_STATUS FECTFSR
1AC TFIFO_CONTROL FECTFCR
1B0 TFIFO_LRF_PTR FECTLRFP
1B4 TFIFO_LWF_PTR FECTLWFP
1B8 TFIFO_ALARM FECTFAR
1BC TFIFO_RDPTR FECTFRP
1C0 TFIFO_WRPTR FECTFWP
1C4 RESET_CNTRL FECFRST
1C8 XMIT_FSM FECCTCWR
Post by Greg Ungerer
Probably the best thing to do is post the patches on the linux kernel
mailing list then, asking for direction on a dma driver.
I have no problem with it going into the arch/m68k area. So that is
always an option.
For the dma engines, the similarity is also obvious. For example, find
below side by side mpc52xx and m54xx definitions for the
from mpc52xx.h from MCD_dma.h
/* SDMA */ /* MCD_DMA */
struct mpc52xx_sdma { struct dmaRegs {
u32 taskBar; /* 0x00 */ u32 taskbar;
u32 currentPointer; /* 0x04 */ u32 currPtr;
u32 endPointer; /* 0x08 */ u32 endPtr;
u32 variablePointer; /* 0x0c */ u32 varTablePtr;
u8 IntVect1; /* 0x10 */ u16 dma_rsvd0;
u8 IntVect2; /* 0x11 */
u16 PtdCntrl; /* 0x12 */ u16 ptdControl;
u32 IntPend; /* 0x14 */ u32 intPending;
u32 IntMask; /* 0x18 */ u32 intMask;
u16 tcr[16]; /* 0x1c .. 0x3a */ u16 taskControl[16];
u8 ipr[32]; /* 0x3c .. 0x5b */ u8 priority[32];
u32 cReqSelect; /* 0x5c */ u32 initiatorMux;
u32 task_size0; /* 0x60 */ u32 taskSize0;
u32 task_size1; /* 0x64 */ u32 taskSize1;
u32 MDEDebug; /* 0x68 */ u32 dma_rsvd1;
u32 ADSDebug; /* 0x6c */ u32 dma_rsvd2;
u32 Value1; /* 0x70 */ u32 debugComp1;
u32 Value2; /* 0x74 */ u32 debugComp2;
u32 Control; /* 0x78 */ u32 debugControl;
u32 Status; /* 0x7c */ u32 debugStatus;
u32 PTDDebug; /* 0x80 */ u32 ptdDebug;
}; };
Greg Ungerer
2012-10-24 06:30:08 UTC
Permalink
Hi Philippe,
Post by Philippe De Muyter
Post by Greg Ungerer
Post by Philippe De Muyter
[CCing lkml, linux-ppc, netdev, linux-m68k]
Hello kernel sources architects
I have a working driver for the m54xx FEC ethernet driver that I
would like to integrate in the kernel tree. Problems are that
- this driver needs an associated DMA driver (provided by FreeScale)
wich is not dma-engine enabled
- they're are already many fec drivers in the kernel tree, and
at least one, fec_mpc52xx.c, seems to be very similar (information
below), to the one for the mcf54xx, except it uses a differently
named associated DMA driver (BestComm/SmartDma/SDMA) which is also
not dma-engine enabled, and even kept hidden in /arch/powerpc where
it is inaccessible when compiling for m68k. The underlying DMA part
from Freescale however seems similar to the one used in the
m54xx. (again, see information below)
So, now I am lost, what should I do ?
The current state of my patches
[http://mailman.uclinux.org/pipermail/uclinux-dev/2012-September/052147.html]
is pushing the freescale provided MCD_DMA dma driver to /drivers/dma,
without adding the dma-engine compatibility layer, and adding the specific
fec_m54xx ethernet driver to /drivers/net/ethernet/freescale
Do you get any responses?
I didn't see any...
No, and none also about my simpler patch moving arch/powerpc/sysdev/bestcomm
to drivers/dma/bestcomm (except a private and useful one telling me how to
set '-M' option as default for 'git format-patch'), but at least this simpler
patch seems to be in a wait bucket at
http://patchwork.ozlabs.org/project/linuxppc-dev/list/.
Well, something useful then :-)

Feel free to send me the m68k header file updates as a patch (or patches
as appropriate), lets get those in now. They are worthwhile changes
on their own.

In light of no other other feedback you may want to push ahead then
with your patches to put the DMA engine code in drivers/dma. That
does seem like the right place to put it.

The new fec driver code should go to the netdev list for review.

Regards
Greg
Post by Philippe De Muyter
Regards
Philippe
put
[diff]
renames = true
in .git/config
Post by Greg Ungerer
Regards
Greg
Post by Philippe De Muyter
Post by Greg Ungerer
Hi Philippe,
Post by Philippe De Muyter
Post by Philippe De Muyter
Post by Greg Ungerer
My biggest concern is the amount of MCD/DMA support code. And it is
all done quite differently to everything else in the kernel. We may
get a bit of push back from kernel folk who look after DMA.
Actually, there is already a similar code in
arch/powerpc/sysdev/bestcomm
(also from freescale, maybe an identical part, but I did not find any
usable doc), but the powerpc folks kept that hidden in the arch/powerpc
tree, instead of installing it in drivers/dma.
The MCD DMA or DMA FEC code from freescale has a comment implying that this
was first used in the MPC8220 part. And Montavista has a MPC8220 port, but
I did not find it, so I do not know where they installed the MCD DMA driver.
Ok, looks like there is a bit a variance in all this.
I also began to read the mpc5200 user's guide parts about the fec and
BestComm/SmartDma/SDMA (not sure which one is the official FreeScale name)
and they look very similar, but not identical, to their m54xx counterparts.
It seems possible to make the fec_mpc52xx.c driver work for the m54xx
- moving some files or part of them from /arch/powerpc/sysdev and
/arch/powerpc/include/asm to /drivers/dma and /include/linux,
- renaming the fec_mpc52xx files to a more sensible name,
- providing out_be32 and in_be32 in /arch/m68k/include/asm/io.h,
- and then unifying the interface to BestComm/SmartDma/SDMA and MCD_DMA
in mcf_52xx.c.
An additional problem is that the freescale docs for powerpcs and for
coldfires do not use the same mnemonics for the same registers.
e.g. FEC registers
offset MPC5200 MCF5484
====== ======= =======
000 FEC_ID n/a
004 IEVENT EIR
008 IMASK EIMR
010 R_DES_ACTIVE n/a
014 X_DES_ACTIVE n/a
024 ECNTRL ECR
040 MII_DATA MDATA
044 MII_SPEED MSCR
064 MIB_CONTROL MIBC
084 R_CNTRL RCR
088 R_HASH RHR
0C4 X_CNTRL TCR
0E4 PADDR1 PALR
0E8 PADDR2 PAHR
0EC OP_PAUSE OPD
118 IADDR1 IAUR
11C IADDR1 IALR
120 GADDR1 GAUR
124 GADDR2 GALR
144 X_WMRK FECTFWR
184 RFIFO_DATA FECRFDR
188 RFIFO_STATUS FECRFSR
18C RFIFO_CONTROL FECRFCR
190 RFIFO_LRF_PTR FECRLRFP
194 RFIFO_LWF_PTR FECRLWFP
198 RFIFO_ALARM FECRFAR
19C RFIFO_RDPTR FECRFRP
1A0 RFIFO_WRPTR FECRFWP
1A4 TFIFO_DATA FECTFDR
1A8 TFIFO_STATUS FECTFSR
1AC TFIFO_CONTROL FECTFCR
1B0 TFIFO_LRF_PTR FECTLRFP
1B4 TFIFO_LWF_PTR FECTLWFP
1B8 TFIFO_ALARM FECTFAR
1BC TFIFO_RDPTR FECTFRP
1C0 TFIFO_WRPTR FECTFWP
1C4 RESET_CNTRL FECFRST
1C8 XMIT_FSM FECCTCWR
Post by Greg Ungerer
Probably the best thing to do is post the patches on the linux kernel
mailing list then, asking for direction on a dma driver.
I have no problem with it going into the arch/m68k area. So that is
always an option.
For the dma engines, the similarity is also obvious. For example, find
below side by side mpc52xx and m54xx definitions for the
from mpc52xx.h from MCD_dma.h
/* SDMA */ /* MCD_DMA */
struct mpc52xx_sdma { struct dmaRegs {
u32 taskBar; /* 0x00 */ u32 taskbar;
u32 currentPointer; /* 0x04 */ u32 currPtr;
u32 endPointer; /* 0x08 */ u32 endPtr;
u32 variablePointer; /* 0x0c */ u32 varTablePtr;
u8 IntVect1; /* 0x10 */ u16 dma_rsvd0;
u8 IntVect2; /* 0x11 */
u16 PtdCntrl; /* 0x12 */ u16 ptdControl;
u32 IntPend; /* 0x14 */ u32 intPending;
u32 IntMask; /* 0x18 */ u32 intMask;
u16 tcr[16]; /* 0x1c .. 0x3a */ u16 taskControl[16];
u8 ipr[32]; /* 0x3c .. 0x5b */ u8 priority[32];
u32 cReqSelect; /* 0x5c */ u32 initiatorMux;
u32 task_size0; /* 0x60 */ u32 taskSize0;
u32 task_size1; /* 0x64 */ u32 taskSize1;
u32 MDEDebug; /* 0x68 */ u32 dma_rsvd1;
u32 ADSDebug; /* 0x6c */ u32 dma_rsvd2;
u32 Value1; /* 0x70 */ u32 debugComp1;
u32 Value2; /* 0x74 */ u32 debugComp2;
u32 Control; /* 0x78 */ u32 debugControl;
u32 Status; /* 0x7c */ u32 debugStatus;
u32 PTDDebug; /* 0x80 */ u32 ptdDebug;
}; };
--
------------------------------------------------------------------------
Greg Ungerer -- Principal Engineer EMAIL: gerg at snapgear.com
SnapGear Group, McAfee PHONE: +61 7 3435 2888
8 Gardner Close FAX: +61 7 3217 5323
Milton, QLD, 4064, Australia WEB: http://www.SnapGear.com
Greg Ungerer
2012-10-04 07:06:02 UTC
Permalink
Hi Philippe,
Post by Philippe De Muyter
I have cleaned up and updated to 3.6-rc5 my previous port of the
freescale-written driver for the fast Ethernet Controller of the M547x
and M548x ColdFires. It seems from comments found in Freescale sources
that this uses a MultiChannel DMA controller marketed as MCD and available
also in the NPC8220 also from Freescale. Therefore, I have split the
A generic MCD dma driver
The M54xx instantiation of the MCD driver
The FEC driver for M54xx
I know there are still lines above 80 characters, but I feel they must be
left that way. There are also parts of an unfinished netpoll interface.
Feel free to test and comment.
I assume the ultimate goal is to get into into the mainline kernel?
(I hope so, I really want to see this working for good :-)

I am responding to each patch on that basis - so I am being a bit
picky on the details.

The driver parts (driver/net/ethernet/freescale/*) will need to be
reviewed on the netdev mailing list at some point. And really need
to go via Dave Millers netdev tree. I am not sure who looks after
the drivers/dma, but scripts/get_maintainer.pl gives a few suggestions.

Would pay to send it to the m68k list as well.

Regards
Greg



------------------------------------------------------------------------
Greg Ungerer -- Principal Engineer EMAIL: gerg at snapgear.com
SnapGear Group, McAfee PHONE: +61 7 3435 2888
8 Gardner Close FAX: +61 7 3217 5323
Milton, QLD, 4064, Australia WEB: http://www.SnapGear.com
Steven King
2014-05-31 02:09:34 UTC
Permalink
Post by Philippe De Muyter
Hello,
I have cleaned up and updated to 3.6-rc5 my previous port of the
freescale-written driver for the fast Ethernet Controller of the M547x
and M548x ColdFires. It seems from comments found in Freescale sources
that this uses a MultiChannel DMA controller marketed as MCD and available
also in the NPC8220 also from Freescale. Therefore, I have split the
A generic MCD dma driver
The M54xx instantiation of the MCD driver
The FEC driver for M54xx
I know there are still lines above 80 characters, but I feel they must be
left that way. There are also parts of an unfinished netpoll interface.
Feel free to test and comment.
So whatever happened with this? Was there ever any feedback from the other
maintainers?

For what it is worth, I was able to take the original patches and rebase them
to v3.15-rc6 with just a couple of very minor changes and produce a working
ethernet for my 5484 system.
Greg Ungerer
2014-06-02 06:55:31 UTC
Permalink
Post by Steven King
Post by Philippe De Muyter
Hello,
I have cleaned up and updated to 3.6-rc5 my previous port of the
freescale-written driver for the fast Ethernet Controller of the M547x
and M548x ColdFires. It seems from comments found in Freescale sources
that this uses a MultiChannel DMA controller marketed as MCD and available
also in the NPC8220 also from Freescale. Therefore, I have split the
A generic MCD dma driver
The M54xx instantiation of the MCD driver
The FEC driver for M54xx
I know there are still lines above 80 characters, but I feel they must be
left that way. There are also parts of an unfinished netpoll interface.
Feel free to test and comment.
So whatever happened with this? Was there ever any feedback from the other
maintainers?
For what it is worth, I was able to take the original patches and rebase them
to v3.15-rc6 with just a couple of very minor changes and produce a working
ethernet for my 5484 system.
I don't recall seeing too much. Time to try again?

Regards
Greg

Loading...