[U-Boot] [PATCH 05/14] powerpc/qoirq: Add support for FMan ethernet in Independent mode

Mingkai Hu Mingkai.hu at freescale.com
Thu Jan 27 05:52:43 CET 2011


From: Dave Liu <daveliu at freescale.com>

Signed-off-by: Dave Liu <daveliu at freescale.com>
Signed-off-by: Andy Fleming <afleming at freescale.com>
Signed-off-by: Timur Tabi <timur at freescale.com>
Signed-off-by: Roy Zang <tie-fei.zang at freescale.com>
Signed-off-by: Dai Haruki <dai.haruki at freescale.com>
Signed-off-by: Kim Phillips <kim.phillips at freescale.com>
Signed-off-by: Ioana Radulescu <ruxandra.radulescu at freescale.com>
Signed-off-by: Kumar Gala <galak at kernel.crashing.org>
Signed-off-by: Mingkai Hu <Mingkai.hu at freescale.com>
---
 Makefile                            |    1 +
 arch/powerpc/cpu/mpc85xx/cpu_init.c |    5 +
 arch/powerpc/cpu/mpc8xxx/cpu.c      |    4 +
 drivers/net/Makefile                |    1 +
 drivers/net/fm/Makefile             |   45 ++
 drivers/net/fm/fm.c                 |  519 +++++++++++++++
 drivers/net/fm/fm.h                 |  312 +++++++++
 drivers/net/fm/fm_eth.c             | 1234 +++++++++++++++++++++++++++++++++++
 include/fm_eth.h                    |  348 ++++++++++
 9 files changed, 2469 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/fm/Makefile
 create mode 100644 drivers/net/fm/fm.c
 create mode 100644 drivers/net/fm/fm.h
 create mode 100644 drivers/net/fm/fm_eth.c
 create mode 100644 include/fm_eth.h

diff --git a/Makefile b/Makefile
index 5f93646..a0532e0 100644
--- a/Makefile
+++ b/Makefile
@@ -225,6 +225,7 @@ LIBS += arch/powerpc/cpu/mpc8xxx/lib8xxx.o
 endif
 ifeq ($(CPU),mpc85xx)
 LIBS += drivers/qe/libqe.o
+LIBS += drivers/net/fm/libfm.a
 LIBS += arch/powerpc/cpu/mpc8xxx/ddr/libddr.o
 LIBS += arch/powerpc/cpu/mpc8xxx/lib8xxx.o
 endif
diff --git a/arch/powerpc/cpu/mpc85xx/cpu_init.c b/arch/powerpc/cpu/mpc85xx/cpu_init.c
index 8ece970..0ceec19 100644
--- a/arch/powerpc/cpu/mpc85xx/cpu_init.c
+++ b/arch/powerpc/cpu/mpc85xx/cpu_init.c
@@ -31,6 +31,7 @@
 #include <asm/processor.h>
 #include <ioports.h>
 #include <sata.h>
+#include <fm_eth.h>
 #include <asm/io.h>
 #include <asm/cache.h>
 #include <asm/mmu.h>
@@ -419,6 +420,10 @@ int cpu_init_r(void)
 	isync();
 #endif
 
+#ifdef CONFIG_FMAN_ENET
+	fman_enet_init();
+#endif
+
 	return 0;
 }
 
diff --git a/arch/powerpc/cpu/mpc8xxx/cpu.c b/arch/powerpc/cpu/mpc8xxx/cpu.c
index 4335fb4..97e4fa4 100644
--- a/arch/powerpc/cpu/mpc8xxx/cpu.c
+++ b/arch/powerpc/cpu/mpc8xxx/cpu.c
@@ -27,6 +27,7 @@
 #include <common.h>
 #include <command.h>
 #include <tsec.h>
+#include <fm_eth.h>
 #include <netdev.h>
 #include <asm/cache.h>
 #include <asm/io.h>
@@ -160,5 +161,8 @@ int cpu_eth_init(bd_t *bis)
 	tsec_standard_init(bis);
 #endif
 
+#ifdef CONFIG_FMAN_ENET
+	fm_standard_init(bis);
+#endif
 	return 0;
 }
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index fd9d0b4..3810665 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -80,6 +80,7 @@ COBJS-$(CONFIG_TIGON3) += bcm570x_autoneg.o
 COBJS-$(CONFIG_TIGON3) += 5701rls.o
 COBJS-$(CONFIG_DRIVER_TI_EMAC) += davinci_emac.o
 COBJS-$(CONFIG_TSEC_ENET) += tsec.o
+COBJS-$(CONFIG_FMAN_ENET) += fsl_phy.o
 COBJS-$(CONFIG_TSI108_ETH) += tsi108_eth.o
 COBJS-$(CONFIG_ULI526X) += uli526x.o
 COBJS-$(CONFIG_VSC7385_ENET) += vsc7385.o
diff --git a/drivers/net/fm/Makefile b/drivers/net/fm/Makefile
new file mode 100644
index 0000000..0dc99ca
--- /dev/null
+++ b/drivers/net/fm/Makefile
@@ -0,0 +1,45 @@
+#
+# Copyright 2009-2010 Freescale Semiconductor, Inc.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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 $(TOPDIR)/config.mk
+
+LIB	:= $(obj)libfm.a
+
+COBJS-$(CONFIG_FMAN_ENET) += dtsec.o fm.o fm_eth.o tgec.o tgec_phy.o
+
+COBJS	:= $(COBJS-y)
+SRCS	:= $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS))
+CFLAGS	:= $(CFLAGS) -D__GCC__
+
+all:	$(LIB)
+
+$(LIB):	$(obj).depend $(OBJS)
+	$(AR) $(ARFLAGS) $@ $(OBJS)
+
+#########################################################################
+
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/drivers/net/fm/fm.c b/drivers/net/fm/fm.c
new file mode 100644
index 0000000..ecc4ffc
--- /dev/null
+++ b/drivers/net/fm/fm.c
@@ -0,0 +1,519 @@
+/*
+ * Copyright 2009-2010 Freescale Semiconductor, Inc.
+ *	Dave Liu <daveliu 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 <common.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <asm/errno.h>
+
+#include "fm.h"
+#include "../../qe/qe.h"		/* For struct qe_firmware */
+
+struct fm_global *fman[MAX_NUM_FM];
+
+u32 fm_get_base_addr(int fm, enum fm_block block, int port)
+{
+	u32 addr = 0;
+
+	if (fm == 0)
+		addr = CONFIG_SYS_FSL_FM1_ADDR;
+	else if (fm == 1)
+		addr = CONFIG_SYS_FSL_FM2_ADDR;
+
+	switch (block) {
+	case fm_muram_e: /* muram */
+		addr += 0;
+		break;
+	case fm_bmi_e:
+		addr += 0x80000 + port * 0x1000;
+		break;
+	case fm_qmi_e:
+		addr += 0x80400 + port * 0x1000;
+		break;
+	case fm_parser_e:
+		addr += 0x80800 + port * 0x1000;
+		break;
+	case fm_policer_e:
+		addr += 0xc0000;
+		break;
+	case fm_keygen_e:
+		addr += 0xc1000;
+		break;
+	case fm_dma_e:
+		addr += 0xc2000;
+		break;
+	case fm_fpm_e:
+		addr += 0xc3000;
+		break;
+	case fm_imem_e:
+		addr += 0xc4000;
+		break;
+	case fm_soft_paser_e:
+		addr += 0xc7000;
+		break;
+	case fm_mac_e:
+		addr += port < MAX_NUM_1G_MAC ? (0xe0000 + port * 0x2000)
+			: 0xf0000;
+		break;
+	case fm_mdio_e:
+		addr += port < MAX_NUM_1G_MAC ? (0xe1120 + port * 0x2000)
+			: 0xf1000;
+		break;
+	case fm_1588_tmr_e:
+		addr += 0xfe000;
+		break;
+	}
+	return addr;
+}
+
+int fm_get_port_id(enum fm_port_type type, int num)
+{
+	int port_id, base;
+
+	switch (type) {
+	case fm_port_type_oh_e:
+		base = OH_PORT_ID_BASE;
+		break;
+	case fm_port_type_rx_e:
+		base = RX_PORT_1G_BASE;
+		break;
+	case fm_port_type_rx_10g_e:
+		base = RX_PORT_10G_BASE;
+		break;
+	case fm_port_type_tx_e:
+		base = TX_PORT_1G_BASE;
+		break;
+	case fm_port_type_tx_10g_e:
+		base = TX_PORT_10G_BASE;
+		break;
+	default:
+		base = 0;
+		break;
+	}
+
+	port_id = base + num;
+	return port_id;
+}
+
+/** fm_upload_ucode - Fman microcode upload worker function
+ *
+ *  This function does the actual uploading of an Fman microcode
+ *  to an Fman.
+ */
+static void fm_upload_ucode(int fm, u32 *ucode, unsigned int size)
+{
+	struct fm_iram *iram;
+	unsigned int i;
+	unsigned int timeout = 1000000;
+
+	iram = (struct fm_iram *)fm_get_base_addr(fm, fm_imem_e, 0);
+	/* enable address auto increase */
+	out_be32(&iram->iadd, IRAM_IADD_AIE);
+	/* write microcode to IRAM */
+	for (i = 0; i < size / 4; i++)
+		out_be32(&iram->idata, ucode[i]);
+
+	/* verify if the writing is over */
+	out_be32(&iram->iadd, 0);
+	while ((in_be32(&iram->idata) != ucode[0]) && --timeout);
+
+	/* enable microcode from IRAM */
+	out_be32(&iram->iready, IRAM_READY);
+}
+
+static void fm_init_axi_dma(int fm)
+{
+	struct fm_dma *axi_dma;
+	u32 val;
+
+	axi_dma = (struct fm_dma *)fm_get_base_addr(fm, fm_dma_e, 0);
+	/* clear DMA status */
+	val = in_be32(&axi_dma->fmdmsr);
+	out_be32(&axi_dma->fmdmsr, val | FMDMSR_CLEAR_ALL);
+	/* set DMA mode */
+	val = in_be32(&axi_dma->fmdmmr);
+	out_be32(&axi_dma->fmdmmr, val | FMDMMR_INIT);
+	/* set thresholds - high */
+	out_be32(&axi_dma->fmdmtr, FMDMTR_DEFAULT);
+	/* set hysteresis - low */
+	out_be32(&axi_dma->fmdmhy, FMDMHY_DEFAULT);
+	/* set emergency threshold */
+	out_be32(&axi_dma->fmdmsetr, FMDMSETR_DEFAULT);
+}
+
+u32 fm_muram_alloc(struct fm_muram *mem, u32 size, u32 align)
+{
+	u32 ret;
+	u32 align_mask, off;
+	u32 save;
+
+	align_mask = align - 1;
+	save = mem->alloc;
+
+	if ((off = (save & align_mask)) != 0)
+		mem->alloc += (align - off);
+	if ((off = size & align_mask) != 0)
+		size += (align - off);
+	if ((mem->alloc + size) >= mem->top) {
+		mem->alloc = save;
+		printf("%s: run out of ram.\n", __func__);
+	}
+
+	ret = mem->alloc;
+	mem->alloc += size;
+	memset((void *)ret, 0, size);
+
+	return ret;
+}
+
+static void fm_init_muram(int fm, struct fm_muram *mem)
+{
+	u32 base;
+
+	base = fm_get_base_addr(fm, fm_muram_e, 0);
+	mem->fm = fm;
+	mem->base = base;
+	mem->res_size = FM_MURAM_RES_SIZE;
+	mem->size = FM_MURAM_SIZE;
+	mem->alloc = base + FM_MURAM_RES_SIZE;
+	mem->top = base + FM_MURAM_SIZE;
+}
+
+static void fm_reset(int) __attribute__((__unused__));
+static void fm_reset(int fm)
+{
+	struct fm_fpm *fpm;
+	fpm = (struct fm_fpm *)fm_get_base_addr(fm, fm_fpm_e, 0);
+
+	/* reset entire FMAN and MACs */
+	out_be32(&fpm->fmrstc, FMRSTC_RESET_FMAN);
+	udelay(10);
+}
+
+static u32 fm_assign_risc(int port_id)
+{
+	u32 risc_sel, val;
+	risc_sel = (port_id & 0x1) ? FMFPPRC_RISC2 : FMFPPRC_RISC1;
+	val = (port_id << FMFPPRC_PORTID_SHIFT) & FMFPPRC_PORTID_MASK;
+	val |= ((risc_sel << FMFPPRC_ORA_SHIFT) | risc_sel);
+
+	return val;
+}
+
+static void fm_init_fpm(int fm)
+{
+	struct fm_fpm *fpm;
+	int i, port_id;
+	u32 val;
+
+	fpm = (struct fm_fpm *)fm_get_base_addr(fm, fm_fpm_e, 0);
+
+	val = in_be32(&fpm->fmnee);
+	out_be32(&fpm->fmnee, val | 0x0000000f);
+
+	/* IM mode, each even port ID to RISC#1, each odd port ID to RISC#2 */
+	/* offline/parser port */
+	for (i = 0; i < MAX_NUM_OH_PORT; i++) {
+		port_id = fm_get_port_id(fm_port_type_oh_e, i);
+		val = fm_assign_risc(port_id);
+		out_be32(&fpm->fpmprc, val);
+	}
+	/* Rx 1G port */
+	for (i = 0; i < MAX_NUM_RX_PORT_1G; i++) {
+		port_id = fm_get_port_id(fm_port_type_rx_e, i);
+		val = fm_assign_risc(port_id);
+		out_be32(&fpm->fpmprc, val);
+	}
+	/* Tx 1G port */
+	for (i = 0; i < MAX_NUM_TX_PORT_1G; i++) {
+		port_id = fm_get_port_id(fm_port_type_tx_e, i);
+		val = fm_assign_risc(port_id);
+		out_be32(&fpm->fpmprc, val);
+	}
+	/* Rx 10G port */
+	port_id = fm_get_port_id(fm_port_type_rx_10g_e, 0);
+	val = fm_assign_risc(port_id);
+	out_be32(&fpm->fpmprc, val);
+	/* Tx 10G port */
+	port_id = fm_get_port_id(fm_port_type_tx_10g_e, 0);
+	val = fm_assign_risc(port_id);
+	out_be32(&fpm->fpmprc, val);
+
+	/* disable the dispatch limit in IM case */
+	out_be32(&fpm->fpmflc, FMFPFLC_DEFAULT);
+	/* set the dispatch thresholds */
+	out_be32(&fpm->fpmdis1, FMFPDIST1_DEFAULT);
+	out_be32(&fpm->fpmdis2, FMFPDIST2_DEFAULT);
+	/* clear events */
+	out_be32(&fpm->fmnee, FMFPEE_CLEAR_EVENT);
+
+	/* clear risc events */
+	for (i = 0; i < 4; i++)
+		out_be32(&fpm->fpmcev[i], 0xffffffff);
+
+	/* clear error */
+	out_be32(&fpm->fpmrcr, 0x0000c000);
+}
+
+static void fm_init_bmi(int fm, u32 offset, u32 pool_size)
+{
+	struct fm_bmi_common *bmi;
+	int blk, i, port_id;
+	u32 val;
+
+	bmi = (struct fm_bmi_common *)fm_get_base_addr(fm, fm_bmi_e, 0);
+
+	/* Need 128KB total free buffer pool size */
+	val = offset / 256;
+	blk = pool_size / 256;
+	/* in IM, we must not begin from offset 0 in MURAM */
+	val |= ((blk - 1) << FMBM_CFG1_FBPS_SHIFT);
+	out_be32(&bmi->fmbm_cfg1, val);
+
+	/* max outstanding tasks/dma transfer = 96/24 */
+	out_be32(&bmi->fmbm_cfg2, FMBM_CFG2_INIT);
+
+	/* disable all BMI interrupt */
+	out_be32(&bmi->fmbm_ier, FMBM_IER_DISABLE_ALL);
+
+	/* clear all events */
+	out_be32(&bmi->fmbm_ievr, FMBM_IEVR_CLEAR_ALL);
+
+	/* set port parameters - FMBM_PP_x
+	 * max tasks 10G Rx/Tx=12, 1G Rx/Tx 4, others is 1
+	 * max dma 10G Rx/Tx=3, others is 1
+	 * set port FIFO size - FMBM_PFS_x
+	 * 4KB for all Rx and Tx ports
+	 */
+	/* offline/parser port */
+	for (i = 0; i < MAX_NUM_OH_PORT; i++) {
+		port_id = fm_get_port_id(fm_port_type_oh_e, i);
+		/* max tasks=1, max dma=1, no extra */
+		out_be32(&bmi->fmbm_pp[port_id - 1], 0);
+		/* port FIFO size - 256 bytes, no extra */
+		out_be32(&bmi->fmbm_pfs[port_id - 1], 0);
+	}
+	/* Rx 1G port */
+	for (i = 0; i < MAX_NUM_RX_PORT_1G; i++) {
+		port_id = fm_get_port_id(fm_port_type_rx_e, i);
+		/* max tasks=4, max dma=1, no extra */
+		out_be32(&bmi->fmbm_pp[port_id - 1], 0x03000000);
+		/* FIFO size - 4KB, no extra */
+		out_be32(&bmi->fmbm_pfs[port_id - 1], 0x0000000f);
+	}
+	/* Tx 1G port FIFO size - 4KB, no extra */
+	for (i = 0; i < MAX_NUM_TX_PORT_1G; i++) {
+		port_id = fm_get_port_id(fm_port_type_tx_e, i);
+		/* max tasks=4, max dma=1, no extra */
+		out_be32(&bmi->fmbm_pp[port_id - 1], 0x03000000);
+		/* FIFO size - 4KB, no extra */
+		out_be32(&bmi->fmbm_pfs[port_id - 1], 0x0000000f);
+	}
+	/* Rx 10G port */
+	port_id = fm_get_port_id(fm_port_type_rx_10g_e, 0);
+	/* max tasks=12, max dma=3, no extra */
+	out_be32(&bmi->fmbm_pp[port_id - 1], 0x0b000200);
+	/* FIFO size - 4KB, no extra */
+	out_be32(&bmi->fmbm_pfs[port_id - 1], 0x0000000f);
+
+	/* Tx 10G port */
+	port_id = fm_get_port_id(fm_port_type_tx_10g_e, 0);
+	/* max tasks=12, max dma=3, no extra */
+	out_be32(&bmi->fmbm_pp[port_id - 1], 0x0b000200);
+	/* FIFO size - 4KB, no extra */
+	out_be32(&bmi->fmbm_pfs[port_id - 1], 0x0000000f);
+
+	/* initialize internal buffers data base (linked list) */
+	out_be32(&bmi->fmbm_init, FMBM_INIT_START);
+}
+
+static void fm_init_qmi(int fm)
+{
+	struct fm_qmi_common *qmi;
+
+	qmi = (struct fm_qmi_common *)fm_get_base_addr(fm, fm_qmi_e, 0);
+
+	/* disable enqueue and dequeue of QMI */
+	out_be32(&qmi->fmqm_gc, FMQM_GC_INIT);
+
+	/* disable all error interrupts */
+	out_be32(&qmi->fmqm_eien, FMQM_EIEN_DISABLE_ALL);
+	/* clear all error events */
+	out_be32(&qmi->fmqm_eie, FMQM_EIE_CLEAR_ALL);
+
+	/* disable all interrupts */
+	out_be32(&qmi->fmqm_ien, FMQM_IEN_DISABLE_ALL);
+	/* clear all interrupts */
+	out_be32(&qmi->fmqm_ie, FMQM_IE_CLEAR_ALL);
+}
+
+struct fm_global *fm_get_global(int index)
+{
+	return fman[index];
+}
+
+/*
+ * Upload an Fman firmware
+ *
+ * This function is similar to qe_upload_firmware(), exception that it uploads
+ * a microcode to the Fman instead of the QE.
+ *
+ * Because the process for uploading a microcode to the Fman is similar for
+ * that of the QE, the QE firmware binary format is used for Fman microcode.
+ * It should be possible to unify these two functions, but for now we keep them
+ * separate.
+ */
+static int fman_upload_firmware(struct fm_global *fm,
+				const struct qe_firmware *firmware)
+{
+	unsigned int i;
+	u32 crc;
+	size_t calc_size = sizeof(struct qe_firmware);
+	size_t length;
+	const struct qe_header *hdr;
+
+	if (!firmware) {
+		printf("Fman:  Invalid address for firmware\n");
+		return -EINVAL;
+	}
+
+	hdr = &firmware->header;
+	length = be32_to_cpu(hdr->length);
+
+	/* Check the magic */
+	if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
+		(hdr->magic[2] != 'F')) {
+		printf("Fman: Data at %p is not a firmware\n", firmware);
+		return -EPERM;
+	}
+
+	/* Check the version */
+	if (hdr->version != 1) {
+		printf("Fman: Unsupported firmware version %u\n", hdr->version);
+		return -EPERM;
+	}
+
+	/* Validate some of the fields */
+	if ((firmware->count != 1)) {
+		printf("Fman: Invalid data in firmware header\n");
+		return -EINVAL;
+	}
+
+	/* Validate the length and check if there's a CRC */
+	calc_size += (firmware->count - 1) * sizeof(struct qe_microcode);
+
+	for (i = 0; i < firmware->count; i++)
+		/*
+		 * For situations where the second RISC uses the same microcode
+		 * as the first, the 'code_offset' and 'count' fields will be
+		 * zero, so it's okay to add those.
+		 */
+		calc_size += sizeof(u32) *
+			be32_to_cpu(firmware->microcode[i].count);
+
+	/* Validate the length */
+	if (length != calc_size + sizeof(u32)) {
+		printf("Fman:  Invalid length in firmware header\n");
+		return -EPERM;
+	}
+
+	/*
+	 * Validate the CRC.  We would normally call crc32_no_comp(), but that
+	 * function isn't available unless you turn on JFFS support.
+	 */
+	crc = be32_to_cpu(*(u32 *)((void *)firmware + calc_size));
+	if (crc != (crc32(-1, (const void *)firmware, calc_size) ^ -1)) {
+		printf("Fman Firmware CRC is invalid\n");
+		return -EIO;
+	}
+
+	/* Loop through each microcode. */
+	for (i = 0; i < firmware->count; i++) {
+		const struct qe_microcode *ucode = &firmware->microcode[i];
+
+		/* Upload a microcode if it's present */
+		if (ucode->code_offset) {
+			printf("Fman: Uploading microcode version %u.%u.%u.\n",
+			       ucode->major, ucode->minor, ucode->revision);
+			fm->ucode = (void *) CONFIG_SYS_FMAN_FW_ADDR +
+				ucode->code_offset;
+			fm->ucode_size = sizeof(u32) * ucode->count;
+			fm->ucode_ver = (ucode->major << 16) |
+				(ucode->major << 8) | ucode->revision;
+			fm_upload_ucode(fm->fm, fm->ucode, fm->ucode_size);
+		}
+	}
+
+	return 0;
+}
+
+/* Init common part of FM, index is fm num# like fm as above */
+int fm_init_common(int index)
+{
+	struct fm_global *fm;
+	struct fm_muram *muram;
+	u32 free_pool_offset;
+	int rc;
+
+	fm = (struct fm_global *)malloc(sizeof(struct fm_global));
+	if (!fm) {
+		printf("%s: no memory\n", __func__);
+		return -ENOMEM;
+	}
+	/* set it to global */
+	fman[index] = fm;
+	/* zero the fm_global */
+	memset(fm, 0, sizeof(struct fm_global));
+
+	/* init muram */
+	muram = &fm->muram;
+	fm_init_muram(index, muram);
+
+	/* save these information */
+	fm->fm = index;
+
+	/* Upload the Fman microcode if it's present */
+#ifdef CONFIG_SYS_FMAN_FW_ADDR
+	rc = fman_upload_firmware(fm, (void *) CONFIG_SYS_FMAN_FW_ADDR);
+	if (rc)
+		return rc;
+#endif
+
+	/* alloc free buffer pool in MURAM */
+	fm->free_pool_base = fm_muram_alloc(muram, FM_FREE_POOL_SIZE,
+				FM_FREE_POOL_ALIGN);
+	if (!fm->free_pool_base) {
+		printf("%s: no muram for free buffer pool\n", __func__);
+		return -ENOMEM;
+	}
+	free_pool_offset = fm->free_pool_base - muram->base;
+	fm->free_pool_size = FM_FREE_POOL_SIZE;
+
+	/* init qmi */
+	fm_init_qmi(index);
+	/* init fpm */
+	fm_init_fpm(index);
+	/* int axi dma */
+	fm_init_axi_dma(index);
+	/* init bmi common */
+	fm_init_bmi(index, free_pool_offset, fm->free_pool_size);
+
+	return 0;
+}
+
diff --git a/drivers/net/fm/fm.h b/drivers/net/fm/fm.h
new file mode 100644
index 0000000..5d68a9c
--- /dev/null
+++ b/drivers/net/fm/fm.h
@@ -0,0 +1,312 @@
+/*
+ * Copyright 2009-2010 Freescale Semiconductor, Inc.
+ *	Dave Liu <daveliu 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 __FM_H__
+#define __FM_H__
+
+#include <common.h>
+#include <fm_eth.h>
+#include <asm/fsl_enet.h>
+#include <asm/fsl_fman.h>
+
+#define MAX_NUM_FM		2
+#define MAX_NUM_1G_MAC		5 /* max number of 1G MAC per FM */
+
+/* Port ID
+ */
+#define OH_PORT_ID_BASE		0x01
+#define MAX_NUM_OH_PORT		7
+#define RX_PORT_1G_BASE		0x08
+#define MAX_NUM_RX_PORT_1G	4
+#define RX_PORT_10G_BASE	0x10
+#define TX_PORT_1G_BASE		0x28
+#define MAX_NUM_TX_PORT_1G	4
+#define TX_PORT_10G_BASE	0x30
+
+enum fm_port_type {
+	fm_port_type_oh_e,
+	fm_port_type_rx_e,
+	fm_port_type_rx_10g_e,
+	fm_port_type_tx_e,
+	fm_port_type_tx_10g_e
+};
+
+/* NIA - next invoked action
+ */
+#define NIA_ENG_RISC		0x00000000
+#define NIA_ENG_MASK		0x007c0000
+
+/* action code
+ */
+#define NIA_RISC_AC_CC		0x00000006
+#define NIA_RISC_AC_IM_TX	0x00000008 /* independent mode Tx */
+#define NIA_RISC_AC_IM_RX	0x0000000a /* independent mode Rx */
+#define NIA_RISC_AC_HC		0x0000000c
+
+enum fm_block {
+	fm_muram_e,
+	fm_bmi_e,
+	fm_qmi_e,
+	fm_parser_e,
+	fm_policer_e,
+	fm_keygen_e,
+	fm_dma_e,
+	fm_fpm_e,
+	fm_imem_e,
+	fm_soft_paser_e,
+	fm_mac_e, /* 1gmac(1-4), 10gmac */
+	fm_mdio_e, /* 5 mdio, the 5th match to 10gmac */
+	fm_1588_tmr_e
+};
+
+/* FM MURAM
+ */
+struct fm_muram {
+	u32 base;
+	u32 top;
+	u32 size;
+	u32 res_size;
+	u32 fm;
+	u32 alloc;
+};
+#define FM_MURAM_SIZE		0x28000
+#define FM_MURAM_RES_SIZE	0x01000
+
+/* FM IRAM registers
+ */
+struct fm_iram {
+	u32 iadd; /* instruction address register */
+	u32 idata; /* instruction data register */
+	u32 itcfg; /* timing config register */
+	u32 iready; /* ready register */
+	u32 res[0x1FFFC];
+} __attribute__ ((packed));
+
+#define IRAM_IADD_AIE		0x80000000 /* address auto increase enable */
+#define IRAM_READY		0x80000000 /* ready to use */
+
+
+/* FMDMSR - Fman DMA status register */
+#define FMDMSR_CMDQNE		0x10000000 /* command queue not empty */
+#define FMDMSR_BER		0x08000000 /* bus error event occurred on bus */
+#define FMDMSR_RDB_ECC		0x04000000 /* read buffer ECC error */
+#define FMDMSR_WRB_SECC		0x02000000 /* write buffer ECC error on system side */
+#define FMDMSR_WRB_FECC		0x01000000 /* write buffer ECC error on Fman side */
+#define FMDMSR_DPEXT_SECC	0x00800000 /* dual port external ECC error on system side */
+#define FMDMSR_DPEXT_FECC	0x00400000 /* dual port external ECC error on Fman side */
+#define FMDMSR_DPDAT_SECC	0x00200000 /* dual port data ECC error on system side */
+#define FMDMSR_DPDAT_FECC	0x00100000 /* dual port data ECC error on Fman side */
+#define FMDMSR_SPDAT_FECC	0x00080000 /* single port data ECC error on Fman side */
+
+#define FMDMSR_CLEAR_ALL	(FMDMSR_BER | FMDMSR_RDB_ECC \
+				| FMDMSR_WRB_SECC | FMDMSR_WRB_FECC \
+				| FMDMSR_DPEXT_SECC | FMDMSR_DPEXT_FECC \
+				| FMDMSR_DPDAT_SECC | FMDMSR_DPDAT_FECC \
+				| FMDMSR_SPDAT_FECC)
+
+/* FMDMMR - FMan DMA mode register
+ */
+#define FMDMMR_CACHE_OVRD_MASK	0xc0000000 /* override cache field one the command bus */
+#define FMDMMR_CACHE_NO_CACHING	0x00000000 /* 00 - no override, no caching */
+#define FMDMMR_CACHE_NO_STASH	0x40000000 /* 01 - data should not be stashed in cache */
+#define FMDMMR_CACHE_MAY_STASH	0x80000000 /* 10 - data may be stashed in cache */
+#define FMDMMR_CACHE_STASH	0xc0000000 /* 11 - data should be stashed in cache */
+#define FMDMMR_AID_OVRD		0x20000000 /* AID override, AID='0000' */
+#define FMDMMR_SBER		0x10000000 /* stop the DMA transaction if a bus error */
+#define FMDMMR_AXI_DBG_MASK	0x0f000000 /* number of beates to be written to external mem */
+#define FMDMMR_AXI_DBG_SHIFT	24
+#define FMDMMR_ERRD_EN		0x00800000 /* enable read port emergency */
+#define FMDMMR_ERWR_EN		0x00400000 /* enable write port emergency */
+#define FMDMMR_BER_EN		0x00200000 /* enable external bus error event */
+#define FMDMMR_EB_EN		0x00100000 /* enable emergency towards external bus */
+#define FMDMMR_ERRD_EME		0x00080000 /* set manual emergency on read port */
+#define FMDMMR_ERWR_EME		0x00040000 /* set manual emergency on write port */
+#define FMDMMR_EB_EME_MASK	0x00030000 /* priority on external bus */
+#define FMDMMR_EB_EME_NORMAL	0x00000000 /* 00 - normal */
+#define FMDMMR_EB_EME_EBS	0x00010000 /* 01 - extended bus service */
+#define FMDMMR_EB_EME_SOS	0x00020000 /* 10 - SOS priority */
+#define FMDMMR_EB_EME_EBSSOS	0x00030000 /* 11 - EBS + SOS priority */
+#define FMDMMR_PROT0		0x00001000 /* bus protection - privilege */
+#define FMDMMR_PROT2		0x00000400 /* bus protection - instruction */
+#define FMDMMR_BMI_EMR		0x00000040 /* SOS emergency is set by BMI */
+#define FMDMMR_ECC_MASK		0x00000020 /* enable ECC error events */
+#define FMDMMR_AID_TNUM		0x00000010 /* choose the 4 LSB bits of TNUM output on AID */
+
+#define FMDMMR_INIT		(FMDMMR_SBER)
+
+/* FMDMTR - FMan DMA threshold register
+ */
+#define FMDMTR_DEFAULT		0x18600060 /* high- cmd=24, read/write internal buf=96 */
+
+/* FMDMHY - FMan DMA hysteresis register
+ */
+#define FMDMHY_DEFAULT		0x10400040 /* low- cmd=16, read/write internal buf=64 */
+
+/* FMDMSETR - FMan DMA SOS emergency threshold register
+ */
+#define FMDMSETR_DEFAULT	0x00000000
+
+#define FMFPPRC_PORTID_MASK	0x3f000000
+#define FMFPPRC_PORTID_SHIFT	24
+#define FMFPPRC_ORA_SHIFT	16
+#define FMFPPRC_RISC1		0x00000001
+#define FMFPPRC_RISC2		0x00000002
+#define FMFPPRC_RISC_ALL	(FMFPPRC_RISC1 | FMFPPRC_RSIC2)
+
+#define FMFPFLC_DEFAULT		0x00000000 /* no dispatch limitation */
+#define FMFPDIST1_DEFAULT	0x10101010
+#define FMFPDIST2_DEFAULT	0x10101010
+
+#define FMRSTC_RESET_FMAN	0x80000000 /* reset entire FMAN and MACs */
+
+/* FMFP_EE - FPM event and enable register
+ */
+#define FMFPEE_DECC		0x80000000 /* double ECC erorr on FPM ram access */
+#define FMFPEE_STL		0x40000000 /* stall of task ... */
+#define FMFPEE_SECC		0x20000000 /* single ECC error */
+#define FMFPEE_RFM		0x00010000 /* release FMan */
+#define FMFPEE_DECC_EN		0x00008000 /* double ECC interrupt enable */
+#define FMFPEE_STL_EN		0x00004000 /* stall of task interrupt enable */
+#define FMFPEE_SECC_EN		0x00002000 /* single ECC error interrupt enable */
+#define FMFPEE_EHM		0x00000008 /* external halt enable */
+#define FMFPEE_UEC		0x00000004 /* FMan is not halted */
+#define FMFPEE_CER		0x00000002 /* only errornous task stalled */
+#define FMFPEE_DER		0x00000001 /* DMA error is just reported */
+
+#define FMFPEE_CLEAR_EVENT	(FMFPEE_DECC | FMFPEE_STL | FMFPEE_SECC | FMFPEE_EHM | FMFPEE_UEC | FMFPEE_CER | FMFPEE_DER | FMFPEE_RFM)
+
+/* FMBM_INIT - BMI initialization register
+ */
+#define FMBM_INIT_START		0x80000000 /* start to init the internal buf linked list */
+
+/* FMBM_CFG1 - BMI configuration 1
+ */
+#define FMBM_CFG1_FBPS_MASK	0x03ff0000 /* Free buffer pool size */
+#define FMBM_CFG1_FBPS_SHIFT	16
+#define FMBM_CFG1_FBPO_MASK	0x000003ff /* Free buffer pool offset */
+#define FMBM_CFG1_FBPO_INIT	0x00000010
+
+/* FMBM_CFG2 - BMI configuration 2
+ */
+#define FMBM_CFG2_TNTSKS_MASK	0x007f0000 /* Total number of task */
+#define FMBM_CFG2_TNTSKS_SHIFT	16
+#define FMBM_CFG2_TDMA_MASK	0x0000003f /* Total DMA */
+
+#define FMBM_CFG2_INIT		0x00600018 /* max outstanding tasks/dma transfer = 96/24 */
+
+/* FMBM_IEVR - interrupt event
+ */
+#define FMBM_IEVR_PEC		0x80000000 /* pipeline table ECC error detected */
+#define FMBM_IEVR_LEC		0x40000000 /* linked list RAM ECC error */
+#define FMBM_IEVR_SEC		0x20000000 /* statistics count RAM ECC error */
+#define FMBM_IEVR_CLEAR_ALL	(FMBM_IEVR_PEC | FMBM_IEVR_LEC | FMBM_IEVR_SEC)
+
+/* FMBM_IER - interrupt enable
+ */
+#define FMBM_IER_PECE		0x80000000 /* PEC interrupt enable */
+#define FMBM_IER_LECE		0x40000000 /* LEC interrupt enable */
+#define FMBM_IER_SECE		0x20000000 /* SEC interrupt enable */
+
+#define FMBM_IER_DISABLE_ALL	0x00000000
+
+/* FMQM_GC - global configuration
+ */
+#define FMQM_GC_ENQ_EN		0x80000000 /* enqueue enable */
+#define FMQM_GC_DEQ_EN		0x40000000 /* dequeue enable */
+#define FMQM_GC_STEN		0x10000000 /* enable global statistic counters */
+#define FMQM_GC_ENQ_THR_MASK	0x00003f00 /* max number of enqueue Tnum */
+#define FMQM_GC_ENQ_THR_SHIFT	8
+#define FMQM_GC_DEQ_THR_MASK	0x0000003f /* max number of dequeue Tnum */
+
+#define FMQM_GC_INIT		0x00003030 /* enqueue/dequeue disable */
+
+/* FMQM_EIE - error interrupt event register
+ */
+#define FMQM_EIE_DEE		0x80000000 /* double-bit ECC detected */
+#define FMQM_EIE_DFUPE		0x40000000 /* dequeue from unkown PortID error */
+#define FMQM_EIE_CLEAR_ALL	(FMQM_EIE_DEE | FMQM_EIE_DFUPE)
+
+/* FMQM_EIEN - error interrupt enable register
+ */
+#define FMQM_EIEN_DEEN		0x80000000 /* double-bit ECC interrupt enable */
+#define FMQM_EIEN_DFUPEN	0x40000000 /* dequeue from unkown PortID int enable */
+#define FMQM_EIEN_DISABLE_ALL	0x00000000
+
+/* FMQM_IE - interrupt event register
+ */
+#define FMQM_IE_SEE		0x80000000 /* single-bit ECC error detected */
+#define FMQM_IE_CLEAR_ALL	FMQM_IE_SEE
+
+/* FMQM_IEN - interrupt enable register
+ */
+#define FMQM_IEN_SEE		0x80000000 /* single-bit ECC error interrupt enable */
+#define FMQM_IEN_DISABLE_ALL	0x00000000
+
+struct fm_global {
+	int fm;			/* 0-FM1, 1-FM2 */
+	u32 ucode_ver;		/* microcode version */
+	u32 *ucode;		/* microcode */
+	u32 ucode_size;
+	struct fm_muram muram;	/* muram info structure */
+	u32 free_pool_base;	/* Free buffer pool base - FIFO */
+	u32 free_pool_size;
+};
+
+#define FM_FREE_POOL_SIZE	0x20000 /* 128K bytes */
+#define FM_FREE_POOL_ALIGN	256
+
+u32 fm_get_base_addr(int fm, enum fm_block block, int port);
+int fm_get_port_id(enum fm_port_type type, int num);
+u32 fm_muram_alloc(struct fm_muram *mem, u32 size, u32 align);
+int fm_init_common(int index);
+struct fm_global *fm_get_global(int index);
+
+/* Fman ethernet private struct */
+typedef struct fm_eth {
+	enum fm_port port;
+	int fm_index;			/* Fman index */
+	u32 num;			/* 0-3: dTSEC0-3 and 4: TGEC */
+	int rx_port;			/* Rx port for the ethernet */
+	int tx_port;			/* Tx port for the ethernet */
+	enum fm_eth_type type;		/* 1G or 10G ethernet */
+	enum fsl_phy_enet_if enet_if;
+	struct fm_global *fm;		/* Fman global information */
+	struct fsl_enet_mac *mac;	/* MAC controller */
+	struct phy_info *phyinfo;
+	struct mii_info *mii_info;
+	void *phyregs;
+	int phyaddr;
+	struct eth_device *dev;
+	struct fm_port_global_pram *rx_pram; /* Rx parameter table */
+	struct fm_port_global_pram *tx_pram; /* Tx parameter table */
+	void *rx_bd_ring;		/* Rx BD ring base */
+	void *cur_rxbd;			/* current Rx BD */
+	void *rx_buf;			/* Rx buffer base */
+	void *tx_bd_ring;		/* Tx BD ring base */
+	void *cur_txbd;			/* current Tx BD */
+} __attribute__ ((packed)) fm_eth_t;
+
+#define RX_BD_RING_SIZE		8
+#define TX_BD_RING_SIZE		8
+#define MAX_RXBUF_LOG2		11
+#define MAX_RXBUF_LEN		(1 << MAX_RXBUF_LOG2)
+
+#endif /* __FM_H__ */
+
diff --git a/drivers/net/fm/fm_eth.c b/drivers/net/fm/fm_eth.c
new file mode 100644
index 0000000..17b6807
--- /dev/null
+++ b/drivers/net/fm/fm_eth.c
@@ -0,0 +1,1234 @@
+/*
+ * Copyright 2009-2010 Freescale Semiconductor, Inc.
+ *	Dave Liu <daveliu 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 <common.h>
+#include <asm/io.h>
+#include <malloc.h>
+#include <net.h>
+#include <hwconfig.h>
+#include <fm_eth.h>
+#include <asm/fsl_serdes.h>
+
+#include "fm.h"
+#include "miiphy.h"
+#include "dtsec.h"
+#include "tgec.h"
+#include "../fsl_phy.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define MAXCONTROLLERS	(10)
+static struct eth_device *devlist[MAXCONTROLLERS];
+static int num_controllers;
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) \
+	&& !defined(BITBANGMII)
+static int cur_mdio45_dev;
+extern void tgec_write_phy_reg(struct tgec_mdio_controller *regs, int port_addr,
+		int dev_addr, int regnum, int value);
+extern int tgec_read_phy_reg(struct tgec_mdio_controller *regs, int port_addr,
+		int dev_addr, int regnum);
+extern void mux_mdio_for_fm(enum fm_port port, int fm, int num);
+#endif
+
+struct fm_eth_info fm1_dtsec_info[CONFIG_SYS_NUM_FM1_DTSEC] = {
+#if (CONFIG_SYS_NUM_FM1_DTSEC >= 1)
+	FM_DTSEC_INFO_INITIALIZER(1, 1),
+#endif
+#if (CONFIG_SYS_NUM_FM1_DTSEC >= 2)
+	FM_DTSEC_INFO_INITIALIZER(1, 2),
+#endif
+#if (CONFIG_SYS_NUM_FM1_DTSEC >= 3)
+	FM_DTSEC_INFO_INITIALIZER(1, 3),
+#endif
+#if (CONFIG_SYS_NUM_FM1_DTSEC >= 4)
+	FM_DTSEC_INFO_INITIALIZER(1, 4),
+#endif
+#if (CONFIG_SYS_NUM_FM1_DTSEC >= 5)
+	FM_DTSEC_INFO_INITIALIZER(1, 5),
+#endif
+};
+
+struct fm_eth_info fm1_10gec_info[CONFIG_SYS_NUM_FM1_10GEC] = {
+	FM_TGEC_INFO_INITIALIZER(1, 1),
+};
+
+#if (CONFIG_SYS_NUM_FMAN == 2)
+struct fm_eth_info fm2_dtsec_info[CONFIG_SYS_NUM_FM2_DTSEC] = {
+	FM_DTSEC_INFO_INITIALIZER(2, 1),
+	FM_DTSEC_INFO_INITIALIZER(2, 2),
+	FM_DTSEC_INFO_INITIALIZER(2, 3),
+	FM_DTSEC_INFO_INITIALIZER(2, 4),
+};
+
+struct fm_eth_info fm2_10gec_info[CONFIG_SYS_NUM_FM2_10GEC] = {
+	FM_TGEC_INFO_INITIALIZER(2, 1),
+};
+#endif
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) \
+	&& !defined(BITBANGMII)
+/*
+ * Find a device index from the devlist by name
+ *
+ * Returns:
+ *  The index where the device is located, -1 on error
+ */
+static int miiphy_find_dev_by_name(const char *devname)
+{
+	int i;
+
+	for (i = 0; i < num_controllers; i++) {
+		if (strncmp(devname, devlist[i]->name, strlen(devname)) == 0)
+			break;
+	}
+
+	/* If device cannot be found, returns -1 */
+	if (i == num_controllers) {
+		printf("%s: device %s not found in devlist\n",
+				__func__, devname);
+		i = -1;
+	}
+
+	return i;
+}
+
+static int dtsec_miiphy_read(const char *devname, unsigned char addr,
+		unsigned char reg, unsigned short *value)
+{
+	int devindex = 0;
+	struct fm_eth *fm;
+
+	if (devname == NULL || value == NULL) {
+		printf("%s: NULL pointer given\n", __func__);
+	} else {
+		devindex = miiphy_find_dev_by_name(devname);
+		if (devindex >= 0) {
+			tsec_mii_t *phyregs;
+
+			fm = devlist[devindex]->priv;
+			phyregs = fm->phyregs;
+			mux_mdio_for_fm(fm->port, fm->fm_index, fm->num);
+			*value = tsec_local_mdio_read(phyregs, addr, 0, reg);
+		}
+	}
+
+	return 0;
+}
+
+static int dtsec_miiphy_write(const char *devname, unsigned char addr,
+		unsigned char reg, unsigned short value)
+{
+	int devindex = 0;
+	struct fm_eth *fm;
+
+	if (devname == NULL) {
+		printf("%s: NULL pointer given\n", __func__);
+	} else {
+		devindex = miiphy_find_dev_by_name(devname);
+		if (devindex >= 0) {
+			tsec_mii_t *phyregs;
+
+			fm = devlist[devindex]->priv;
+			phyregs = fm->phyregs;
+			mux_mdio_for_fm(fm->port, fm->fm_index, fm->num);
+			tsec_local_mdio_write(phyregs, addr, 0, reg, value);
+		}
+	}
+
+	return 0;
+}
+
+int do_mdio45(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	int port;
+	int dev;
+	int reg;
+	struct tgec_mdio_controller *regs;
+	struct fm_eth *fm_eth;
+	int result;
+
+	if (argc < 3) {
+		cmd_usage(cmdtp);
+		return 1;
+	}
+
+	if (argc == 3) {
+		int dev;
+
+		if (strcmp(argv[1], "device")) {
+			cmd_usage(cmdtp);
+			return 1;
+		}
+		dev = miiphy_find_dev_by_name(argv[2]);
+
+		if (dev >= 0)
+			cur_mdio45_dev = dev;
+
+		return 0;
+	}
+
+	port = (int)simple_strtoul(argv[2], NULL, 10);
+	dev = (int)simple_strtoul(argv[3], NULL, 10);
+	reg = (int)simple_strtoul(argv[4], NULL, 10);
+
+	fm_eth = devlist[cur_mdio45_dev]->priv;
+	regs = fm_eth->phyregs;
+
+	mux_mdio_for_fm(fm_eth->port, fm_eth->fm_index, fm_eth->num);
+
+	if (strcmp(argv[1], "read") == 0) {
+		result = tgec_read_phy_reg(regs, port, dev, reg);
+		printf("Read %d %d %d: %x\n", port, dev, reg, result);
+	} else if (strcmp(argv[1], "write") == 0 && argc > 5)
+		tgec_write_phy_reg(regs, port, dev, reg,
+				(int)simple_strtoul(argv[5], NULL, 16));
+
+	return 0;
+}
+U_BOOT_CMD(
+	mdio45,	6,	1,	do_mdio45,
+	"MDIO Clause 45 utility commands",
+	"mdio45 device <devname> - Set controller to <devname>\n"
+	"mdio45 read   <portaddr> <devaddr> <reg> - read <reg> [0-65535] of device <devaddr> [1-31] on PHY <portaddr> [0-31]\n"
+	"mdio45 write  <portaddr> <devaddr> <reg> <data> - write reg <reg> [0-65535] of device <devaddr> [1-31] on PHY <portaddr> [0-31]\n"
+);
+
+#define TBIANA_SETTINGS ( \
+		TBIANA_ASYMMETRIC_PAUSE \
+		| TBIANA_SYMMETRIC_PAUSE \
+		| TBIANA_FULL_DUPLEX \
+		)
+
+#define TBICR_SETTINGS ( \
+		TBICR_ANEG_ENABLE \
+		| TBICR_RESTART_ANEG \
+		| TBICR_FULL_DUPLEX \
+		| TBICR_SPEED1_SET \
+		)
+
+/* Configure the TBI for SGMII operation */
+void dtsec_configure_serdes(struct fm_eth *priv)
+{
+	struct dtsec *regs = priv->mac->base;
+	tsec_mii_t *phyregs = priv->mac->phyregs;
+
+	/* Access TBI PHY registers at given TSEC register offset as
+	 * opposed to the register offset used for external PHY accesses */
+	tsec_local_mdio_write(phyregs, regs->tbipa, 0, TBI_TBICON,
+			TBICON_CLK_SELECT);
+	tsec_local_mdio_write(phyregs, regs->tbipa, 0, TBI_ANA,
+			TBIANA_SETTINGS);
+	tsec_local_mdio_write(phyregs, regs->tbipa, 0, TBI_CR, TBICR_SETTINGS);
+}
+
+static struct phy_info *dtsec_init_phy(struct eth_device *dev,
+					struct mii_info *mii_info)
+{
+	struct fm_eth *fm_eth;
+	struct dtsec *regs;
+	tsec_mii_t *miiregs;
+	struct phy_info *curphy;
+	int timeout = 1000000;
+
+	mii_info->advertising = (ADVERTISED_10baseT_Half |
+				ADVERTISED_10baseT_Full |
+				ADVERTISED_100baseT_Half |
+				ADVERTISED_100baseT_Full |
+				ADVERTISED_1000baseT_Full);
+
+	fm_eth = dev->priv;
+	regs = (struct dtsec *)fm_eth->mac->base;
+	miiregs = (tsec_mii_t *)fm_eth->mac->phyregs;
+
+	/* Assign a Physical address to the TBI */
+	out_be32(&regs->tbipa, CONFIG_SYS_TBIPA_VALUE);
+
+	out_be32(&miiregs->miimcfg, MIIMCFG_RESET_MGMT);
+	out_be32(&miiregs->miimcfg, 0);
+	out_be32(&miiregs->miimcfg, MIIMCFG_INIT_VALUE);
+	asm("sync");
+	while (in_be32(&miiregs->miimind)&MIIMIND_BUSY && timeout--);
+
+	if (fm_eth->enet_if == SGMII)
+		dtsec_configure_serdes(fm_eth);
+
+	/* Get the cmd structure corresponding to the attached PHY */
+	curphy = tsec_get_phy_info(mii_info);
+	if (curphy == NULL) {
+		printf("%s: No PHY found\n", dev->name);
+		return NULL;
+	}
+
+	return curphy;
+}
+
+static struct phy_info *tgec_init_phy(struct eth_device *dev,
+					struct mii_info *mii_info)
+{
+	struct phy_info *curphy;
+	struct fm_eth *fm;
+	char phyopt[20];
+
+	fm = dev->priv;
+
+	mii_info->advertising = (ADVERTISED_100baseT_Full |
+				ADVERTISED_1000baseT_Full |
+				ADVERTISED_10000baseT_Full);
+
+	/* Get the cmd structure corresponding to the attached PHY */
+	curphy = tgec_get_phy_info(mii_info);
+	if (curphy == NULL)
+		printf("%s: No PHY found\n", dev->name);
+
+	cur_mdio45_dev = miiphy_find_dev_by_name(dev->name);
+
+	sprintf(phyopt, "fsl_fm%d_xaui_phy", fm->fm_index + 1);
+
+	if (hwconfig_arg_cmp(phyopt, "xfi"))
+		mii_info->port = PORT_FIBRE;
+
+	return curphy;
+}
+#endif
+
+static u16 muram_readw(u16 *addr)
+{
+	u32 base = (u32)addr & ~0x3;
+	u32 val32 = *(u32 *)base;
+	int byte_pos;
+	u16 ret;
+
+	byte_pos = (u32)addr & 0x3;
+	if (byte_pos)
+		ret = (u16)(val32 & 0x0000ffff);
+	else
+		ret = (u16)((val32 & 0xffff0000) >> 16);
+
+	return ret;
+}
+
+static void muram_writew(u16 *addr, u16 val)
+{
+	u32 base = (u32)addr & ~0x3;
+	u32 org32 = *(u32 *)base;
+	u32 val32;
+	int byte_pos;
+
+	byte_pos = (u32)addr & 0x3;
+	if (byte_pos)
+		val32 = (org32 & 0xffff0000) | val;
+	else
+		val32 = (org32 & 0x0000ffff) | ((u32)val << 16);
+
+	*(u32 *)base = val32;
+}
+
+
+static void bmi_rx_port_enable(int fm, int port)
+{
+	struct fm_bmi_rx_port *rx_port;
+	u32 val;
+
+	rx_port = (struct fm_bmi_rx_port *)fm_get_base_addr(fm,
+					fm_bmi_e, port);
+	val = in_be32(&rx_port->fmbm_rcfg);
+	val |= FMBM_RCFG_EN;
+	out_be32(&rx_port->fmbm_rcfg, val);
+}
+
+static void bmi_rx_port_disable(int fm, int port)
+{
+	struct fm_bmi_rx_port *rx_port;
+	u32 val;
+	int timeout = 1000000;
+
+	rx_port = (struct fm_bmi_rx_port *)fm_get_base_addr(fm,
+					fm_bmi_e, port);
+	val = in_be32(&rx_port->fmbm_rcfg);
+	val &= ~FMBM_RCFG_EN;
+	out_be32(&rx_port->fmbm_rcfg, val);
+
+	/* wait until the rx port is not busy */
+	while ((in_be32(&rx_port->fmbm_rst) & FMBM_RST_BSY) && timeout--);
+}
+
+static void bmi_rx_port_init(int fm, int port)
+{
+	struct fm_bmi_rx_port *rx_port;
+	rx_port = (struct fm_bmi_rx_port *)fm_get_base_addr(fm,
+					fm_bmi_e, port);
+
+	/* set BMI to independent mode, Rx port disable */
+	out_be32(&rx_port->fmbm_rcfg, FMBM_RCFG_IM);
+	/* set Rx DMA attributes - no swap, no stash/no optimization */
+	out_be32(&rx_port->fmbm_rda, FMBM_RDA_INIT);
+	/* set Rx FIFO parameters */
+	out_be32(&rx_port->fmbm_rfp, FMBM_RFP_DEFAULT);
+	/* set Rx frame end parameters */
+	out_be32(&rx_port->fmbm_rfed, FMBM_RFED_DEFAULT);
+	/* set Rx IC parameters */
+	out_be32(&rx_port->fmbm_ricp, FMBM_RICP_DEFAULT);
+	/* clear FOF in IM case */
+	out_be32(&rx_port->fmbm_rim, 0);
+	/* Rx frame next engine -RISC */
+	out_be32(&rx_port->fmbm_rfne, NIA_ENG_RISC | NIA_RISC_AC_IM_RX);
+	/* Rx command attribute - no order */
+	out_be32(&rx_port->fmbm_rfca, FMBM_RFCA_DEFAULT);
+	/* enable Rx statistic counters */
+	out_be32(&rx_port->fmbm_rstc, FMBM_RSTC_EN);
+	/* disable Rx performance counters */
+	out_be32(&rx_port->fmbm_rpc, 0);
+}
+
+static void bmi_tx_port_enable(int fm, int port)
+{
+	struct fm_bmi_tx_port *tx_port;
+	u32 val;
+
+	tx_port = (struct fm_bmi_tx_port *)fm_get_base_addr(fm,
+					fm_bmi_e, port);
+	val = in_be32(&tx_port->fmbm_tcfg);
+	val |= FMBM_TCFG_EN;
+	out_be32(&tx_port->fmbm_tcfg, val);
+}
+
+static void bmi_tx_port_disable(int fm, int port)
+{
+	struct fm_bmi_tx_port *tx_port;
+	u32 val;
+	int timeout = 1000000;
+
+	tx_port = (struct fm_bmi_tx_port *)fm_get_base_addr(fm,
+					fm_bmi_e, port);
+	val = in_be32(&tx_port->fmbm_tcfg);
+	val &= ~FMBM_TCFG_EN;
+	out_be32(&tx_port->fmbm_tcfg, val);
+
+	/* wait until the tx port is not busy */
+	while ((in_be32(&tx_port->fmbm_tst) & FMBM_TST_BSY) && timeout--);
+}
+
+static void bmi_tx_port_init(int fm, int port)
+{
+	struct fm_bmi_tx_port *tx_port;
+
+	tx_port = (struct fm_bmi_tx_port *)fm_get_base_addr(fm,
+					fm_bmi_e, port);
+
+	/* set BMI to independent mode, Tx port disable */
+	out_be32(&tx_port->fmbm_tcfg, FMBM_TCFG_IM);
+	/* set Tx DMA attributes - no stash/no swap */
+	out_be32(&tx_port->fmbm_tda, FMBM_TDA_INIT);
+	/* set Tx FIFO parameters - pipeline depth=1, low comfort 20*256B */
+	out_be32(&tx_port->fmbm_tfp, FMBM_TFP_INIT);
+	/* set Tx frame margins parameters */
+	out_be32(&tx_port->fmbm_tfed, FMBM_TFED_DEFAULT);
+	/* set Tx IC parameters */
+	out_be32(&tx_port->fmbm_ticp, FMBM_TICP_DEFAULT);
+	/* Tx frame next engine -RISC */
+	out_be32(&tx_port->fmbm_tfne, NIA_ENG_RISC | NIA_RISC_AC_IM_TX);
+	out_be32(&tx_port->fmbm_tfene, NIA_ENG_RISC | NIA_RISC_AC_IM_TX);
+	/* Tx command attribute */
+	out_be32(&tx_port->fmbm_tfca, FMBM_TFCA_DEFAULT);
+	/* enable Tx statistic counters */
+	out_be32(&tx_port->fmbm_tstc, FMBM_TSTC_EN);
+	/* disable Tx performance counters */
+	out_be32(&tx_port->fmbm_tpc, 0);
+}
+
+static void fmc_tx_port_graceful_stop_enable(struct fm_eth *fm_eth)
+{
+	struct fm_port_global_pram *pram;
+
+	pram = fm_eth->tx_pram;
+	/* graceful stop transmission of frames */
+	pram->mode |= PRAM_MODE_GRACEFUL_STOP;
+	__asm__ __volatile__ ("sync");
+}
+
+static void fmc_tx_port_graceful_stop_disable(struct fm_eth *fm_eth)
+{
+	struct fm_port_global_pram *pram;
+
+	pram = fm_eth->tx_pram;
+	/* re-enable transmission of frames */
+	pram->mode &= ~PRAM_MODE_GRACEFUL_STOP;
+	__asm__ __volatile__ ("sync");
+}
+
+static int fm_eth_rx_port_parameter_init(struct fm_eth *fm_eth)
+{
+	struct fm_global *fm;
+	struct fm_muram *muram;
+	struct fm_port_global_pram *pram;
+	u32 pram_page_offset;
+	void *rx_bd_ring_base;
+	void *rx_buf_pool;
+	struct fm_port_bd *rxbd;
+	struct fm_port_qd *rxqd;
+	struct fm_bmi_rx_port *bmi_rx_port;
+	int i;
+
+	fm = fm_eth->fm;
+	muram = &fm->muram;
+
+	/* alloc global parameter ram at MURAM */
+	pram = (struct fm_port_global_pram *)fm_muram_alloc(muram,
+		FM_PRAM_SIZE, FM_PRAM_ALIGN);
+	fm_eth->rx_pram = pram;
+
+	/* parameter page offset to MURAM */
+	pram_page_offset = (u32)pram - muram->base;
+
+	/* enable global mode- snooping data buffers and BDs */
+	pram->mode = PRAM_MODE_GLOBAL;
+
+	/* init the Rx queue descriptor pionter */
+	pram->rxqd_ptr = pram_page_offset + 0x20;
+
+	/* set the max receive buffer length, power of 2 */
+	muram_writew(&pram->mrblr, MAX_RXBUF_LOG2);
+
+	/* alloc Rx buffer descriptors from main memory */
+	rx_bd_ring_base = malloc(sizeof(struct fm_port_bd)
+			* RX_BD_RING_SIZE);
+	if (!rx_bd_ring_base)
+		return 0;
+	memset(rx_bd_ring_base, 0, sizeof(struct fm_port_bd)
+			* RX_BD_RING_SIZE);
+
+	/* alloc Rx buffer from main memory */
+	rx_buf_pool = malloc(MAX_RXBUF_LEN * RX_BD_RING_SIZE);
+	if (!rx_buf_pool)
+		return 0;
+	memset(rx_buf_pool, 0, MAX_RXBUF_LEN * RX_BD_RING_SIZE);
+
+	/* save them to fm_eth */
+	fm_eth->rx_bd_ring = rx_bd_ring_base;
+	fm_eth->cur_rxbd = rx_bd_ring_base;
+	fm_eth->rx_buf = rx_buf_pool;
+
+	/* init Rx BDs ring */
+	rxbd = (struct fm_port_bd *)rx_bd_ring_base;
+	for (i = 0; i < RX_BD_RING_SIZE; i++) {
+		rxbd->status = RxBD_EMPTY;
+		rxbd->len = 0;
+		rxbd->buf_ptr_hi = 0;
+		rxbd->buf_ptr_lo = (u32)rx_buf_pool + i * MAX_RXBUF_LEN;
+		rxbd++;
+	}
+
+	/* set the Rx queue descriptor */
+	rxqd = &pram->rxqd;
+	muram_writew(&rxqd->gen, 0);
+	muram_writew(&rxqd->bd_ring_base_hi, 0);
+	rxqd->bd_ring_base_lo = (u32)rx_bd_ring_base;
+	muram_writew(&rxqd->bd_ring_size, sizeof(struct fm_port_bd)
+			* RX_BD_RING_SIZE);
+	muram_writew(&rxqd->offset_in, 0);
+	muram_writew(&rxqd->offset_out, 0);
+
+	/* set IM parameter ram pointer to Rx Frame Queue ID */
+	bmi_rx_port = (struct fm_bmi_rx_port *)fm_get_base_addr(fm->fm,
+					fm_bmi_e, fm_eth->rx_port);
+	out_be32(&bmi_rx_port->fmbm_rfqid, pram_page_offset);
+
+	return 1;
+}
+
+static int fm_eth_tx_port_parameter_init(struct fm_eth *fm_eth)
+{
+	struct fm_global *fm;
+	struct fm_muram *muram;
+	struct fm_port_global_pram *pram;
+	u32 pram_page_offset;
+	void *tx_bd_ring_base;
+	struct fm_port_bd *txbd;
+	struct fm_port_qd *txqd;
+	struct fm_bmi_tx_port *bmi_tx_port;
+	int i;
+
+	fm = fm_eth->fm;
+	muram = &fm->muram;
+
+	/* alloc global parameter ram at MURAM */
+	pram = (struct fm_port_global_pram *)fm_muram_alloc(muram,
+		FM_PRAM_SIZE, FM_PRAM_ALIGN);
+	fm_eth->tx_pram = pram;
+
+	/* parameter page offset to MURAM */
+	pram_page_offset = (u32)pram - muram->base;
+
+	/* enable global mode- snooping data buffers and BDs */
+	pram->mode = PRAM_MODE_GLOBAL;
+
+	/* init the Tx queue descriptor pionter */
+	pram->txqd_ptr = pram_page_offset + 0x40;
+
+	/* alloc Tx buffer descriptors from main memory */
+	tx_bd_ring_base = malloc(sizeof(struct fm_port_bd)
+			* TX_BD_RING_SIZE);
+	if (!tx_bd_ring_base)
+		return 0;
+	memset(tx_bd_ring_base, 0, sizeof(struct fm_port_bd)
+			* TX_BD_RING_SIZE);
+	/* save it to fm_eth */
+	fm_eth->tx_bd_ring = tx_bd_ring_base;
+	fm_eth->cur_txbd = tx_bd_ring_base;
+
+	/* init Tx BDs ring */
+	txbd = (struct fm_port_bd *)tx_bd_ring_base;
+	for (i = 0; i < TX_BD_RING_SIZE; i++) {
+		txbd->status = TxBD_LAST;
+		txbd->len = 0;
+		txbd->buf_ptr_hi = 0;
+		txbd->buf_ptr_lo = 0;
+	}
+
+	/* set the Tx queue decriptor */
+	txqd = &pram->txqd;
+	muram_writew(&txqd->bd_ring_base_hi, 0);
+	txqd->bd_ring_base_lo = (u32)tx_bd_ring_base;
+	muram_writew(&txqd->bd_ring_size, sizeof(struct fm_port_bd)
+			* TX_BD_RING_SIZE);
+	muram_writew(&txqd->offset_in, 0);
+	muram_writew(&txqd->offset_out, 0);
+
+	/* set IM parameter ram pointer to Tx Confirmation Frame Queue ID */
+	bmi_tx_port = (struct fm_bmi_tx_port *)fm_get_base_addr(fm->fm,
+					fm_bmi_e, fm_eth->tx_port);
+	out_be32(&bmi_tx_port->fmbm_tcfqid, pram_page_offset);
+
+	return 1;
+}
+
+static int fm_eth_init(struct fm_eth *fm_eth)
+{
+
+	if (!fm_eth_rx_port_parameter_init(fm_eth))
+		return 0;
+
+	if (!fm_eth_tx_port_parameter_init(fm_eth))
+		return 0;
+
+	return 1;
+}
+
+static int fm_eth_startup(struct fm_eth *fm_eth)
+{
+	struct fsl_enet_mac *mac;
+	mac = fm_eth->mac;
+
+	/* Rx/TxBDs, Rx/TxQDs, Rx buff and parameter ram init */
+	if (!fm_eth_init(fm_eth))
+		return 0;
+	/* setup the MAC controller */
+	if (mac->init_mac)
+		mac->init_mac(mac);
+
+	/* For some reason we need to set SPEED_100 */
+	if ((fm_eth->enet_if == SGMII) && mac->set_if_mode)
+		mac->set_if_mode(mac, fm_eth->enet_if, SPEED_100);
+
+	/* init bmi rx port, IM mode and disable */
+	bmi_rx_port_init(fm_eth->fm_index, fm_eth->rx_port);
+	/* init bmi tx port, IM mode and disable */
+	bmi_tx_port_init(fm_eth->fm_index, fm_eth->tx_port);
+
+	return 1;
+}
+
+static int fm_eth_open(struct eth_device *dev, bd_t *bd)
+{
+	struct fm_eth *fm_eth;
+	struct fsl_enet_mac *mac;
+
+	fm_eth = (struct fm_eth *)dev->priv;
+	mac = fm_eth->mac;
+
+	/* setup the MAC address */
+	if (dev->enetaddr[0] & 0x01) {
+		printf("%s: MacAddress is multcast address\n",	__func__);
+		return 1;
+	}
+	if (mac->set_mac_addr)
+		mac->set_mac_addr(mac, dev->enetaddr);
+
+	/* enable bmi Rx port */
+	bmi_rx_port_enable(fm_eth->fm_index, fm_eth->rx_port);
+	/* enable MAC rx/tx port */
+	if (mac->enable_mac)
+		mac->enable_mac(mac);
+	/* enable bmi Tx port */
+	bmi_tx_port_enable(fm_eth->fm_index, fm_eth->tx_port);
+	/* re-enable transmission of frame */
+	fmc_tx_port_graceful_stop_disable(fm_eth);
+
+#ifdef CONFIG_MII
+	mux_mdio_for_fm(fm_eth->port, fm_eth->fm_index, fm_eth->num);
+
+	if (fm_eth->phyinfo && fm_eth->phyinfo->startup)
+		fm_eth->phyinfo->startup(fm_eth->mii_info);
+#else
+	fm_eth->mii_info->speed = SPEED_1000;
+	fm_eth->mii_info->link = 1;
+	fm_eth->mii_info->duplex = DUPLEX_FULL;
+#endif
+
+	/* set the MAC-PHY mode */
+	if (mac->set_if_mode)
+		mac->set_if_mode(mac, fm_eth->enet_if, fm_eth->mii_info->speed);
+
+	return fm_eth->mii_info->link ? 0 : -1;
+}
+
+static void fm_eth_halt(struct eth_device *dev)
+{
+	struct fm_eth *fm_eth;
+	struct fsl_enet_mac *mac;
+
+	fm_eth = (struct fm_eth *)dev->priv;
+	mac = fm_eth->mac;
+
+	/* graceful stop the transmission of frames */
+	fmc_tx_port_graceful_stop_enable(fm_eth);
+	/* disable bmi Tx port */
+	bmi_tx_port_disable(fm_eth->fm_index, fm_eth->tx_port);
+	/* disable MAC rx/tx port */
+	if (mac->disable_mac)
+		mac->disable_mac(mac);
+	/* disable bmi Rx port */
+	bmi_rx_port_disable(fm_eth->fm_index, fm_eth->rx_port);
+
+#ifdef CONFIG_MII
+	mux_mdio_for_fm(fm_eth->port, fm_eth->fm_index, fm_eth->num);
+
+	if (fm_eth->phyinfo && fm_eth->phyinfo->shutdown)
+		fm_eth->phyinfo->shutdown(fm_eth->mii_info);
+#endif
+}
+
+static int fm_eth_send(struct eth_device *dev, volatile void *buf, int len)
+{
+	struct fm_eth *fm_eth;
+	struct fm_port_global_pram *pram;
+	volatile struct fm_port_bd *txbd, *txbd_base;
+	u16 offset_in;
+	int i;
+
+	fm_eth = (struct fm_eth *)dev->priv;
+	pram = fm_eth->tx_pram;
+	txbd = fm_eth->cur_txbd;
+
+	/* find one empty TxBD */
+	for (i = 0; txbd->status & TxBD_READY; i++) {
+		udelay(1000);
+		if (i > 0x1000) {
+			printf("%s: Tx buffer not ready\n", dev->name);
+			return 0;
+		}
+	}
+	/* setup TxBD */
+	txbd->buf_ptr_hi = 0;
+	txbd->buf_ptr_lo = (u32)buf;
+	txbd->len = len;
+	__asm__ __volatile__ ("sync");
+	txbd->status = TxBD_READY | TxBD_LAST;
+	__asm__ __volatile__ ("sync");
+
+	/* update TxQD, let RISC to send the packet */
+	offset_in = muram_readw(&pram->txqd.offset_in);
+	offset_in += SIZEOFBD;
+	if (offset_in >= muram_readw(&pram->txqd.bd_ring_size))
+		offset_in = 0;
+	muram_writew(&pram->txqd.offset_in, offset_in);
+	__asm__ __volatile__ ("sync");
+
+	/* wait for buffer to be transmitted */
+	for (i = 0; txbd->status & TxBD_READY; i++) {
+		udelay(1000);
+		if (i > 0x10000) {
+			printf("%s: Tx error\n", dev->name);
+			return 0;
+		}
+	}
+
+	/* advance the TxBD */
+	txbd++;
+	txbd_base = (struct fm_port_bd *)fm_eth->tx_bd_ring;
+	if (txbd >= (txbd_base + TX_BD_RING_SIZE))
+		txbd = txbd_base;
+	/* update current txbd */
+	fm_eth->cur_txbd = (void *)txbd;
+
+	return 1;
+}
+
+static int fm_eth_recv(struct eth_device *dev)
+{
+	struct fm_eth *fm_eth;
+	struct fm_port_global_pram *pram;
+	volatile struct fm_port_bd *rxbd, *rxbd_base;
+	u16 status, len;
+	u8 *data;
+	u16 offset_out;
+
+	fm_eth = (struct fm_eth *)dev->priv;
+	pram = fm_eth->rx_pram;
+	rxbd = fm_eth->cur_rxbd;
+	status = rxbd->status;
+
+	while (!(status & RxBD_EMPTY)) {
+		if (!(status & RxBD_ERROR)) {
+			data = (u8 *)rxbd->buf_ptr_lo;
+			len = rxbd->len;
+			NetReceive(data, len);
+		} else {
+			printf("%s: Rx error\n", dev->name);
+			return 0;
+		}
+
+		/* clear the RxBDs */
+		rxbd->status = RxBD_EMPTY;
+		rxbd->len = 0;
+		__asm__ __volatile__ ("sync");
+
+		/* advance RxBD */
+		rxbd++;
+		rxbd_base = (struct fm_port_bd *)fm_eth->rx_bd_ring;
+		if (rxbd >= (rxbd_base + RX_BD_RING_SIZE))
+			rxbd = rxbd_base;
+		/* read next status */
+		status = rxbd->status;
+
+		/* update RxQD */
+		offset_out = muram_readw(&pram->rxqd.offset_out);
+		offset_out += SIZEOFBD;
+		if (offset_out >= muram_readw(&pram->rxqd.bd_ring_size))
+			offset_out = 0;
+		muram_writew(&pram->rxqd.offset_out, offset_out);
+		__asm__ __volatile__ ("sync");
+	}
+	fm_eth->cur_rxbd = (void *)rxbd;
+
+	return 1;
+}
+
+static int fm_eth_init_mac(struct fm_eth *fm_eth)
+{
+	struct fsl_enet_mac *mac;
+	int fm, num;
+	void *base, *phyregs = NULL;
+
+	mac = fm_eth->mac;
+	fm = fm_eth->fm_index;
+	num = fm_eth->num;
+
+	/* Get the mac registers base address */
+	base = (void *)fm_get_base_addr(fm, fm_mac_e, num);
+	phyregs = (void *)fm_get_base_addr(fm, fm_mdio_e, num);
+
+	/* alloc mac controller */
+	mac = malloc(sizeof(struct fsl_enet_mac));
+	if (!mac)
+		return 0;
+	memset(mac, 0, sizeof(struct fsl_enet_mac));
+
+	/* save the mac to fm_eth struct */
+	fm_eth->mac = mac;
+
+	if (fm_eth->type == fm_eth_1g_e)
+		init_dtsec(mac, base, phyregs, MAX_RXBUF_LEN);
+	else
+		init_tgec(mac, base, phyregs, MAX_RXBUF_LEN);
+
+	return 1;
+}
+
+static int init_phy(struct eth_device *dev)
+{
+	struct fm_eth *fm_eth = dev->priv;
+	struct mii_info	*mii_info;
+#ifdef CONFIG_MII
+	struct phy_info *curphy;
+#endif
+
+	mii_info = malloc(sizeof(*mii_info));
+	if (!mii_info) {
+		printf("%s: Could not allocate mii_info", dev->name);
+		return -1;
+	}
+	memset(mii_info, 0, sizeof(*mii_info));
+
+	mii_info->duplex = DUPLEX_FULL;
+	mii_info->link = 0;
+
+	mii_info->autoneg = 1;
+	mii_info->mii_id = fm_eth->phyaddr;
+
+	mii_info->priv = fm_eth;
+	mii_info->dev = dev;
+	fm_eth->mii_info = mii_info;
+
+	mii_info->phyregs = fm_eth->phyregs;
+
+#ifdef CONFIG_MII
+	mux_mdio_for_fm(fm_eth->port, fm_eth->fm_index, fm_eth->num);
+
+	if (fm_eth->type == fm_eth_1g_e)
+		curphy = dtsec_init_phy(dev, mii_info);
+	else
+		curphy = tgec_init_phy(dev, mii_info);
+
+	fm_eth->phyinfo = curphy;
+
+	if (!curphy)
+		return -1;
+
+	if (curphy->config)
+		curphy->config(fm_eth->mii_info);
+#endif
+
+	return 0;
+}
+
+static int fm_eth_initialize(struct fm_global *fm, struct fm_eth_info *info)
+{
+	struct eth_device *dev;
+	struct fm_eth *fm_eth;
+	int rx_port, tx_port;
+	int i, num;
+
+	/* alloc eth device */
+	dev = (struct eth_device *)malloc(sizeof(struct eth_device));
+	if (!dev)
+		return 0;
+	memset(dev, 0, sizeof(struct eth_device));
+
+	/* alloc the FMan ethernet private struct */
+	fm_eth = (struct fm_eth *)malloc(sizeof(struct fm_eth));
+	if (!fm_eth)
+		return 0;
+	memset(fm_eth, 0, sizeof(struct fm_eth));
+
+	/* save the fm global to Fman ethernet struct */
+	fm_eth->fm = fm;
+	/* save the fm num# to Fman ethernet struct */
+	fm_eth->fm_index = fm->fm;
+	/* save num to Fman ethenet (0-3: dTSEC, 4: TGEC) */
+	num = info->num;
+	fm_eth->num = num;
+	fm_eth->port = info->port;
+	fm_eth->type = info->type;
+
+	/* Rx port and Tx port for the Fman ethernet */
+	if (fm_eth->type == fm_eth_1g_e) {
+		rx_port = fm_get_port_id(fm_port_type_rx_e, num);
+		tx_port = fm_get_port_id(fm_port_type_tx_e, num);
+	} else {
+		rx_port = fm_get_port_id(fm_port_type_rx_10g_e, 0);
+		tx_port = fm_get_port_id(fm_port_type_tx_10g_e, 0);
+	}
+	fm_eth->rx_port = rx_port;
+	fm_eth->tx_port = tx_port;
+
+	/* init global mac structure */
+	if (!fm_eth_init_mac(fm_eth))
+		return 0;
+
+	/* keep same as the manual, we call FMAN1, FMAN2, DTSEC1, DTSEC2, etc */
+	if (fm_eth->type == fm_eth_1g_e)
+		sprintf(dev->name, "FM%d at DTSEC%d", fm->fm + 1, num + 1);
+	else
+		sprintf(dev->name, "FM%d at TGEC%d", fm->fm + 1, 1);
+
+	devlist[num_controllers++] = dev;
+	dev->iobase = 0;
+	dev->priv = (void *)fm_eth;
+	dev->init = fm_eth_open;
+	dev->halt = fm_eth_halt;
+	dev->send = fm_eth_send;
+	dev->recv = fm_eth_recv;
+	fm_eth->dev = dev;
+
+	/* clear the ethernet address */
+	for (i = 0; i < 6; i++)
+		dev->enetaddr[i] = 0;
+	eth_register(dev);
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) \
+	&& !defined(BITBANGMII)
+	miiphy_register(dev->name, dtsec_miiphy_read, dtsec_miiphy_write);
+#endif
+
+	fm_eth->phyaddr = info->phy_addr;
+	fm_eth->phyregs = info->phy_regs;
+	fm_eth->enet_if = info->enet_if;
+
+	/* startup the FM im */
+	if (!fm_eth_startup(fm_eth))
+		return 0;
+
+	if (init_phy(dev))
+		return 0;
+
+	return 1;
+}
+
+int fm_standard_init(bd_t *bis)
+{
+	int i;
+	struct fm_global *fm;
+
+	if (fm_init_common(0))
+		return 0;
+
+	fm = fm_get_global(0);
+
+	for (i = 0; i < CONFIG_SYS_NUM_FM1_DTSEC; i++) {
+		if (fm1_dtsec_info[i].enabled) {
+			if (!fm_eth_initialize(fm, &fm1_dtsec_info[i]))
+				return 0;
+		}
+	}
+	for (i = 0; i < CONFIG_SYS_NUM_FM1_10GEC; i++) {
+		if (fm1_10gec_info[i].enabled) {
+			if (!fm_eth_initialize(fm, &fm1_10gec_info[i]))
+				return 0;
+		}
+	}
+
+#if (CONFIG_SYS_NUM_FMAN == 2)
+	if (fm_init_common(1))
+		return 0;
+
+	fm = fm_get_global(1);
+
+	for (i = 0; i < CONFIG_SYS_NUM_FM2_DTSEC; i++) {
+		if (fm2_dtsec_info[i].enabled) {
+			if (!fm_eth_initialize(fm, &fm2_dtsec_info[i]))
+				return 0;
+		}
+	}
+	for (i = 0; i < CONFIG_SYS_NUM_FM2_10GEC; i++) {
+		if (fm2_10gec_info[i].enabled) {
+			if (!fm_eth_initialize(fm, &fm2_10gec_info[i]))
+				return 0;
+		}
+	}
+#endif
+
+	return 1;
+}
+
+static int is_device_enabled(u32 devdisr_mask)
+{
+	ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+	u32 devdisr2 = in_be32(&gur->devdisr2);
+
+	return !(devdisr_mask & devdisr2);
+}
+
+/* Init data structures based on HW cfg */
+void fman_enet_init(void)
+{
+	int i;
+	ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+	u32 rcwsr11 = in_be32(&gur->rcwsr[11]);
+
+	for (i = 0; i < CONFIG_SYS_NUM_FM1_DTSEC; i++) {
+		if (is_device_enabled(fm1_dtsec_info[i].devdisr_mask)) {
+			fm1_dtsec_info[i].enabled = 1;
+			fm1_dtsec_info[i].enet_if = SGMII;
+		} else {
+			fm1_dtsec_info[i].enabled = 0;
+		}
+	}
+	for (i = 0; i < CONFIG_SYS_NUM_FM1_10GEC; i++) {
+		if (is_device_enabled(fm1_10gec_info[i].devdisr_mask)) {
+			fm1_10gec_info[i].enabled = 1;
+			fm1_10gec_info[i].enet_if = XAUI;
+		} else {
+			fm1_10gec_info[i].enabled = 0;
+		}
+		if (!is_serdes_configured(XAUI_FM1))
+			fm1_10gec_info[i].enabled = 0;
+	}
+
+	if (!is_serdes_configured(SGMII_FM1_DTSEC1))
+		fm1_dtsec_info[0].enabled = 0;
+
+	if ((rcwsr11 & FSL_CORENET_RCWSR11_EC1) ==
+		FSL_CORENET_RCWSR11_EC1_FM1_DTSEC1) {
+		fm1_dtsec_info[0].enabled = 1;
+		fm1_dtsec_info[0].enet_if = RGMII;
+	}
+
+	if ((rcwsr11 & FSL_CORENET_RCWSR11_EC2) ==
+		FSL_CORENET_RCWSR11_EC2_FM1_DTSEC2) {
+		fm1_dtsec_info[1].enabled = 1;
+		fm1_dtsec_info[1].enet_if = RGMII;
+	}
+
+#if (CONFIG_SYS_NUM_FMAN == 2)
+	for (i = 0; i < CONFIG_SYS_NUM_FM2_DTSEC; i++) {
+		if (is_device_enabled(fm2_dtsec_info[i].devdisr_mask)) {
+			fm2_dtsec_info[i].enabled = 1;
+			fm2_dtsec_info[i].enet_if = SGMII;
+		} else {
+			fm2_dtsec_info[i].enabled = 0;
+		}
+	}
+	for (i = 0; i < CONFIG_SYS_NUM_FM2_10GEC; i++) {
+		if (is_device_enabled(fm2_10gec_info[i].devdisr_mask)) {
+			fm2_10gec_info[i].enabled = 1;
+			fm2_10gec_info[i].enet_if = XAUI;
+		} else {
+			fm2_10gec_info[i].enabled = 0;
+		}
+		if (!is_serdes_configured(XAUI_FM2))
+			fm2_10gec_info[i].enabled = 0;
+	}
+
+	if ((rcwsr11 & FSL_CORENET_RCWSR11_EC2) ==
+		FSL_CORENET_RCWSR11_EC2_FM2_DTSEC1) {
+		fm2_dtsec_info[0].enabled = 1;
+		fm2_dtsec_info[0].enet_if = RGMII;
+	}
+#endif
+
+	return ;
+}
+
+void fm_info_set_phy_address(enum fm_port port, int address)
+{
+	switch (port) {
+	case FM1_DTSEC1:
+	case FM1_DTSEC2:
+	case FM1_DTSEC3:
+	case FM1_DTSEC4:
+	case FM1_DTSEC5:
+		fm1_dtsec_info[port - FM1_DTSEC1].phy_addr = address;
+		break;
+	case FM1_10GEC1:
+		fm1_10gec_info[port - FM1_10GEC1].phy_addr = address;
+		break;
+#if (CONFIG_SYS_NUM_FMAN == 2)
+	case FM2_DTSEC1:
+	case FM2_DTSEC2:
+	case FM2_DTSEC3:
+	case FM2_DTSEC4:
+		fm2_dtsec_info[port - FM2_DTSEC1].phy_addr = address;
+		break;
+	case FM2_10GEC1:
+		fm2_10gec_info[port - FM2_10GEC1].phy_addr = address;
+		break;
+#endif
+	default:
+		break;
+	};
+}
+
+enum fsl_phy_enet_if fm_info_get_enet_if(enum fm_port port)
+{
+	switch (port) {
+	case FM1_DTSEC1:
+	case FM1_DTSEC2:
+	case FM1_DTSEC3:
+	case FM1_DTSEC4:
+	case FM1_DTSEC5:
+		if (fm1_dtsec_info[port - FM1_DTSEC1].enabled)
+			return fm1_dtsec_info[port - FM1_DTSEC1].enet_if;
+		break;
+	case FM1_10GEC1:
+		if (fm1_10gec_info[port - FM1_10GEC1].enabled)
+			return fm1_10gec_info[port - FM1_10GEC1].enet_if;
+		break;
+#if (CONFIG_SYS_NUM_FMAN == 2)
+	case FM2_DTSEC1:
+	case FM2_DTSEC2:
+	case FM2_DTSEC3:
+	case FM2_DTSEC4:
+		if (fm2_dtsec_info[port - FM2_DTSEC1].enabled)
+			return fm2_dtsec_info[port - FM2_DTSEC1].enet_if;
+		break;
+	case FM2_10GEC1:
+		if (fm2_10gec_info[port - FM2_10GEC1].enabled)
+			return fm2_10gec_info[port - FM2_10GEC1].enet_if;
+		break;
+#endif
+	default:
+		break;
+	};
+
+	return FSL_ETH_IF_NONE;
+}
+
+static void
+__def_board_ft_fman_fixup_port(void *blob, char * prop, phys_addr_t pa,
+				enum fm_port port, int offset)
+{
+	return ;
+}
+
+void board_ft_fman_fixup_port(void *blob, char * prop, phys_addr_t pa,
+				enum fm_port port, int offset)
+	 __attribute__((weak, alias("__def_board_ft_fman_fixup_port")));
+
+static void ft_fman_fixup_port(void *blob, struct fm_eth_info *info, char *prop)
+{
+	int off, ph;
+	phys_addr_t paddr = CONFIG_SYS_CCSRBAR_PHYS + info->compat_offset;
+
+	off = fdt_node_offset_by_compat_reg(blob, prop, paddr);
+
+	if (info->enabled) {
+		fdt_fixup_phy_connection(blob, off, info->enet_if);
+		board_ft_fman_fixup_port(blob, prop, paddr, info->port, off);
+		return ;
+	}
+
+	/* board code might have caused offset to change */
+	off = fdt_node_offset_by_compat_reg(blob, prop, paddr);
+
+	/* disable both the mac node and the node that has a handle to it */
+	fdt_setprop_string(blob, off, "status", "disabled");
+
+	ph = fdt_get_phandle(blob, off);
+	do_fixup_by_prop(blob, "fsl,fman-mac", &ph, sizeof(ph),
+		"status", "disabled", strlen("disabled") + 1, 1);
+}
+
+void fdt_fixup_fman_ethernet(void *blob)
+{
+	int i;
+
+	for (i = 0; i < CONFIG_SYS_NUM_FM1_DTSEC; i++)
+		ft_fman_fixup_port(blob, &fm1_dtsec_info[i], "fsl,fman-1g-mac");
+	for (i = 0; i < CONFIG_SYS_NUM_FM1_10GEC; i++)
+		ft_fman_fixup_port(blob, &fm1_10gec_info[i], "fsl,fman-10g-mac");
+
+#if (CONFIG_SYS_NUM_FMAN == 2)
+	for (i = 0; i < CONFIG_SYS_NUM_FM2_DTSEC; i++)
+		ft_fman_fixup_port(blob, &fm2_dtsec_info[i], "fsl,fman-1g-mac");
+	for (i = 0; i < CONFIG_SYS_NUM_FM2_10GEC; i++)
+		ft_fman_fixup_port(blob, &fm2_10gec_info[i], "fsl,fman-10g-mac");
+#endif
+}
diff --git a/include/fm_eth.h b/include/fm_eth.h
new file mode 100644
index 0000000..199bcd9
--- /dev/null
+++ b/include/fm_eth.h
@@ -0,0 +1,348 @@
+/*
+ * Copyright 2009-2010 Freescale Semiconductor, Inc.
+ *	Dave Liu <daveliu 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 __FM_ETH_H__
+#define __FM_ETH_H__
+
+#include <common.h>
+#include <asm/types.h>
+#include <asm/fsl_enet.h>
+
+enum fm_port {
+	FM1_DTSEC1,
+	FM1_DTSEC2,
+	FM1_DTSEC3,
+	FM1_DTSEC4,
+	FM1_DTSEC5,
+	FM1_10GEC1,
+	FM2_DTSEC1,
+	FM2_DTSEC2,
+	FM2_DTSEC3,
+	FM2_DTSEC4,
+	FM2_10GEC1,
+	NUM_FM_PORTS,
+};
+
+struct fm_bmi_rx_port {
+	u32 fmbm_rcfg;	/* Rx configuration */
+	u32 fmbm_rst;	/* Rx status */
+	u32 fmbm_rda;	/* Rx DMA attributes */
+	u32 fmbm_rfp;	/* Rx FIFO parameters */
+	u32 fmbm_rfed;	/* Rx frame end data */
+	u32 fmbm_ricp;	/* Rx internal context parameters */
+	u32 fmbm_rim;	/* Rx internal margins */
+	u32 fmbm_rebm;	/* Rx external buffer margins */
+	u32 fmbm_rfne;	/* Rx frame next engine */
+	u32 fmbm_rfca;	/* Rx frame command attributes */
+	u32 fmbm_rfpne;	/* Rx frame parser next engine */
+	u32 fmbm_rpso;	/* Rx parse start offset */
+	u32 fmbm_rpp;	/* Rx policer profile */
+	u32 fmbm_rccb;	/* Rx coarse classification base */
+	u32 res1[0x2];
+	u32 fmbm_rprai[0x8];	/* Rx parse results array Initialization */
+	u32 fmbm_rfqid;		/* Rx frame queue ID */
+	u32 fmbm_refqid;	/* Rx error frame queue ID */
+	u32 fmbm_rfsdm;		/* Rx frame status discard mask */
+	u32 fmbm_rfsem;		/* Rx frame status error mask */
+	u32 fmbm_rfene;		/* Rx frame enqueue next engine */
+	u32 res2[0x23];
+	u32 fmbm_ebmpi[0x8];	/* buffer manager pool information */
+	u32 fmbm_acnt[0x8];	/* allocate counter */
+	u32 res3[0x8];
+	u32 fmbm_cgm[0x8];	/* congestion group map */
+	u32 fmbm_mpd;		/* BMan pool depletion */
+	u32 res4[0x1F];
+	u32 fmbm_rstc;		/* Rx statistics counters */
+	u32 fmbm_rfrc;		/* Rx frame counters */
+	u32 fmbm_rfbc;		/* Rx bad frames counter */
+	u32 fmbm_rlfc;		/* Rx large frames counter */
+	u32 fmbm_rffc;		/* Rx filter frames counter */
+	u32 fmbm_rfdc;		/* Rx frame discard counter */
+	u32 fmbm_rfldec;	/* Rx frames list DMA error counter */
+	u32 fmbm_rodc;		/* Rx out of buffers discard counter */
+	u32 fmbm_rbdc;		/* Rx buffers deallocate counter */
+	u32 res5[0x17];
+	u32 fmbm_rpc;		/* Rx performance counters */
+	u32 fmbm_rpcp;		/* Rx performance count parameters */
+	u32 fmbm_rccn;		/* Rx cycle counter */
+	u32 fmbm_rtuc;		/* Rx tasks utilization counter */
+	u32 fmbm_rrquc;		/* Rx receive queue utilization counter */
+	u32 fmbm_rduc;		/* Rx DMA utilization counter */
+	u32 fmbm_rfuc;		/* Rx FIFO utilization counter */
+	u32 fmbm_rpac;		/* Rx pause activation counter */
+	u32 res6[0x18];
+	u32 fmbm_rdbg;		/* Rx debug configuration */
+} __attribute__ ((packed));
+
+/* FMBM_RCFG - Rx configuration
+ */
+#define FMBM_RCFG_EN		0x80000000 /* port is enabled to receive data */
+#define FMBM_RCFG_FDOVR		0x02000000 /* frame discard override */
+#define FMBM_RCFG_IM		0x01000000 /* independent mode */
+
+/* FMBM_RST - Rx status
+ */
+#define FMBM_RST_BSY		0x80000000 /* Rx port is busy */
+
+/* FMBM_RDA - Rx DMA attributes
+ */
+#define FMBM_RDA_SWAP_MASK	0xc0000000
+#define FMBM_RDA_SWAP_SHIFT	30
+#define FMBM_RDA_NO_SWAP	0x00000000
+#define FMBM_RDA_SWAP_LE	0x40000000 /* swapped in powerpc little endian mode */
+#define FMBM_RDA_SWAP_BE	0x80000000 /* swapped in big endian mode */
+#define FMBM_RDA_ICC_MASK	0x30000000
+#define FMBM_RDA_ICC_NOSTASH	0x00000000 /* IC write cacheable, no allocate */
+#define FMBM_RDA_ICC_STASH	0x10000000 /* IC write cacheable and allocate */
+#define FMBM_RDA_FHC_MASK	0x0c000000
+#define FMBM_RDA_FHC_NOSTASH	0x00000000 /* frame header write cacheable, no allocate */
+#define FMBM_RDA_FHC_STASH	0x04000000 /* frame header write cacheable and allocate */
+#define FMBM_RDA_SGC_MASK	0x03000000
+#define FMBM_RDA_SGC_NOSTASH	0x00000000 /* scatter gather write cacheable, no alloc */
+#define FMBM_RDA_SGC_STASH	0x01000000 /* scatter gather write cacheable and alloc */
+#define FMBM_RDA_WOPT_MASK	0x00300000
+#define FMBM_RDA_NO_OPT		0x00000000
+#define FMBM_RDA_WRITE_OPT	0x00100000 /* allow to write more bytes than the actual */
+
+#define FMBM_RDA_MASK_ALL	(FMBM_RDA_SWAP_MASK | FMBM_RDA_ICC_MASK \
+				| FMBM_RDA_FHC_MASK | FMBM_RDA_SGC_MASK \
+				| FMBM_RDA_WOPT_MASK)
+
+#define FMBM_RDA_INIT		0x00000000
+
+/* FMBM_RFP - Rx FIFO parameters
+ */
+#define FMBM_RFP_DEFAULT	0x03ff03ff
+
+/* FMBM_RFED - Rx Frame end data
+ */
+#define FMBM_RFED_DEFAULT	0x00000000
+
+/* FMBM_RICP - Rx internal context
+ */
+#define FMBM_RICP_DEFAULT	0x00000002
+
+/* FMBM_RFCA - Rx frame command attributes
+ */
+#define FMBM_RFCA_ORDER		0x80000000
+#define FMBM_RFCA_SYNC		0x02000000
+#define FMBM_RFCA_DEFAULT	0x003c0000
+
+/* FMBM_RSTC - Rx statistics
+ */
+#define FMBM_RSTC_EN		0x80000000 /* statistics counters enable */
+
+struct fm_bmi_tx_port {
+	u32 fmbm_tcfg;	/* Tx configuration */
+	u32 fmbm_tst;	/* Tx status */
+	u32 fmbm_tda;	/* Tx DMA attributes */
+	u32 fmbm_tfp;	/* Tx FIFO parameters */
+	u32 fmbm_tfed;	/* Tx frame end data */
+	u32 fmbm_ticp;	/* Tx internal context parameters */
+	u32 fmbm_tfne;	/* Tx frame next engine */
+	u32 fmbm_tfca;	/* Tx frame command attributes */
+	u32 fmbm_tcfqid;/* Tx confirmation frame queue ID */
+	u32 fmbm_tfeqid;/* Tx error frame queue ID */
+	u32 fmbm_tfene;	/* Tx frame enqueue next engine */
+	u32 fmbm_trlmts;/* Tx rate limiter scale */
+	u32 fmbm_trlmt;	/* Tx rate limiter */
+	u32 res0[0x73];
+	u32 fmbm_tstc;	/* Tx statistics counters */
+	u32 fmbm_tfrc;	/* Tx frame counter */
+	u32 fmbm_tfdc;	/* Tx frames discard counter */
+	u32 fmbm_tfledc;/* Tx frame length error discard counter */
+	u32 fmbm_tfufdc;/* Tx frame unsupported format discard counter */
+	u32 fmbm_tbdc;	/* Tx buffers deallocate counter */
+	u32 res1[0x1a];
+	u32 fmbm_tpc;	/* Tx performance counters */
+	u32 fmbm_tpcp;	/* Tx performance count parameters */
+	u32 fmbm_tccn;	/* Tx cycle counter */
+	u32 fmbm_ttuc;	/* Tx tasks utilization counter */
+	u32 fmbm_ttcquc;/* Tx transmit confirm queue utilization counter */
+	u32 fmbm_tduc;	/* Tx DMA utilization counter */
+	u32 fmbm_tfuc;	/* Tx FIFO utilization counter */
+	u32 res2[0x19];
+	u32 fmbm_tdcfg;	/* Tx debug configuration */
+} __attribute__ ((packed));
+
+/* FMBM_TCFG - Tx configuration
+ */
+#define FMBM_TCFG_EN	0x80000000 /* port is enabled to transmit data */
+#define FMBM_TCFG_IM	0x01000000 /* independent mode enable */
+
+/* FMBM_TST - Tx status
+ */
+#define FMBM_TST_BSY		0x80000000 /* Tx port is busy */
+
+/* FMBM_TDA - Tx DMA attributes
+ */
+#define FMBM_TDA_INIT		0x00000000 /* No swap, no stashing */
+
+/* FMBM_TFP - Tx FIFO parameters
+ */
+#define FMBM_TFP_INIT		0x00000013 /* pipeline=1, low comfort=5KB */
+
+/* FMBM_TFED - Tx frame end data
+ */
+#define FMBM_TFED_DEFAULT	0x00000000
+
+/* FMBM_TICP - Tx internal context parameters
+ */
+#define FMBM_TICP_DEFAULT	0x00000000
+
+/* FMBM_TFCA - Tx frame command attributes
+ */
+#define FMBM_TFCA_DEFAULT	0x00040000
+
+/* FMBM_TSTC - Tx statistics counters
+ */
+#define FMBM_TSTC_EN		0x80000000
+
+/* Rx/Tx buffer descriptor
+ */
+struct fm_port_bd {
+	u16 status;
+	u16 len;
+	u32 res0;
+	u16 res1;
+	u16 buf_ptr_hi;
+	u32 buf_ptr_lo;
+} __attribute__ ((packed));
+
+#define SIZEOFBD		sizeof(struct fm_port_bd)
+
+/* Common BD flags
+*/
+#define BD_LAST			0x0800
+
+/* Rx BD status flags
+*/
+#define RxBD_EMPTY		0x8000
+#define RxBD_LAST		BD_LAST
+#define RxBD_FIRST		0x0400
+#define RxBD_PHYS_ERR		0x0008
+#define RxBD_SIZE_ERR		0x0004
+#define RxBD_ERROR		(RxBD_PHYS_ERR | RxBD_SIZE_ERR)
+
+/* Tx BD status flags
+*/
+#define TxBD_READY		0x8000
+#define TxBD_LAST		BD_LAST
+
+/* Rx/Tx queue descriptor
+ */
+struct fm_port_qd {
+	u16 gen;
+	u16 bd_ring_base_hi;
+	u32 bd_ring_base_lo;
+	u16 bd_ring_size;
+	u16 offset_in;
+	u16 offset_out;
+	u16 res0;
+	u32 res1[0x4];
+} __attribute__ ((packed));
+
+#define QD_RXF_INT_MASK		0x0010 /* 1=set interrupt for receive frame */
+#define QD_BSY_INT_MASK		0x0008 /* 1=set interrupt for receive busy event */
+#define QD_FPMEVT_SEL_MASK	0x0003
+
+/* IM global parameter RAM
+ */
+struct fm_port_global_pram {
+	u32 mode;	/* independent mode register */
+	u32 rxqd_ptr;	/* Rx queue descriptor pointer, RxQD size=32 bytes
+			   8 bytes aligned, independent mode page address + 0x20 */
+	u32 txqd_ptr;	/* Tx queue descriptor pointer, TxQD size=32 bytes
+			   8 bytes aligned, independent mode page address + 0x40 */
+	u16 mrblr;	/* max Rx buffer length, set its value to the power of 2 */
+	u16 rxqd_bsy_cnt;	/* RxQD busy counter, should be cleared */
+	u32 res0[0x4];
+	struct fm_port_qd rxqd;	/* Rx queue descriptor */
+	struct fm_port_qd txqd;	/* Tx queue descriptor */
+	u32 res1[0x28];
+} __attribute__ ((packed));
+
+#define FM_PRAM_SIZE		sizeof(struct fm_port_global_pram)
+#define FM_PRAM_ALIGN		256
+#define PRAM_MODE_GLOBAL	0x20000000
+#define PRAM_MODE_GRACEFUL_STOP	0x00800000
+
+/****************************
+ * Fman ethernet
+ ****************************/
+enum fm_eth_type {
+	fm_eth_1g_e,
+	fm_eth_10g_e,
+};
+
+/* Fman MAC controller
+ */
+#define CONFIG_SYS_FM1_DTSEC1_MDIO_ADDR	(CONFIG_SYS_FSL_FM1_ADDR + 0xe1120)
+#define CONFIG_SYS_FM1_TGEC_MDIO_ADDR	(CONFIG_SYS_FSL_FM1_ADDR + 0xf1000)
+
+/* Fman ethernet info struct */
+#define FM_ETH_INFO_INITIALIZER(idx, pregs) \
+	.fm		= idx,						\
+	.phy_regs	= (void *)pregs,				\
+	.enet_if	= FSL_ETH_IF_NONE,				\
+
+#define FM_DTSEC_INFO_INITIALIZER(idx, n) \
+{									\
+	FM_ETH_INFO_INITIALIZER(idx, CONFIG_SYS_FM1_DTSEC1_MDIO_ADDR)	\
+	.num		= n - 1,					\
+	.type		= fm_eth_1g_e,					\
+	.port		= FM##idx##_DTSEC##n,				\
+	.devdisr_mask	= FSL_CORENET_DEVDISR2_DTSEC##idx##_##n,	\
+	.compat_offset	= CONFIG_SYS_FSL_FM##idx##_OFFSET +		\
+				offsetof(struct ccsr_fman, mac[n-1]),	\
+}
+
+#define FM_TGEC_INFO_INITIALIZER(idx, n) \
+{									\
+	FM_ETH_INFO_INITIALIZER(idx, CONFIG_SYS_FM1_TGEC_MDIO_ADDR)	\
+	.num		= n + 3,					\
+	.type		= fm_eth_10g_e,					\
+	.port		= FM##idx##_10GEC##n,				\
+	.devdisr_mask	= FSL_CORENET_DEVDISR2_10GEC##idx,		\
+	.compat_offset	= CONFIG_SYS_FSL_FM##idx##_OFFSET +		\
+				offsetof(struct ccsr_fman, fm_10gec),	\
+}
+
+struct fm_eth_info {
+	int enabled;
+	u32 devdisr_mask;
+	int fm;
+	int num;
+	enum fm_port port;
+	enum fm_eth_type type;
+	u8 phy_addr;
+	void *phy_regs;
+	enum fsl_phy_enet_if enet_if;
+	u32 compat_offset;
+};
+
+int fm_standard_init(bd_t *bis);
+int fm_initialize(int index, struct fm_eth_info *fm_info, int num);
+void fman_enet_init(void);
+void fdt_fixup_fman_ethernet(void *fdt);
+enum fsl_phy_enet_if fm_info_get_enet_if(enum fm_port port);
+void fm_info_set_phy_address(enum fm_port port, int address);
+
+#endif
-- 
1.6.4




More information about the U-Boot mailing list