All of lore.kernel.org
 help / color / mirror / Atom feed
From: Mingkai Hu <Mingkai.hu@freescale.com>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH 05/14] powerpc/qoirq: Add support for FMan ethernet in Independent mode
Date: Thu, 27 Jan 2011 12:52:43 +0800	[thread overview]
Message-ID: <1296103972-2696-6-git-send-email-Mingkai.hu@freescale.com> (raw)
In-Reply-To: <1296103972-2696-5-git-send-email-Mingkai.hu@freescale.com>

From: Dave Liu <daveliu@freescale.com>

Signed-off-by: Dave Liu <daveliu@freescale.com>
Signed-off-by: Andy Fleming <afleming@freescale.com>
Signed-off-by: Timur Tabi <timur@freescale.com>
Signed-off-by: Roy Zang <tie-fei.zang@freescale.com>
Signed-off-by: Dai Haruki <dai.haruki@freescale.com>
Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
Signed-off-by: Ioana Radulescu <ruxandra.radulescu@freescale.com>
Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
Signed-off-by: Mingkai Hu <Mingkai.hu@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@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@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@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@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

  reply	other threads:[~2011-01-27  4:52 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-01-27  4:52 [U-Boot] [PATCH 00/14] powerpc/p4080: add support for FMan ethernet in Independent mode Mingkai Hu
2011-01-27  4:52 ` [U-Boot] [PATCH 01/14] powerpc/p4080: Add function to report which lane is used for a prtcl Mingkai Hu
2011-01-27  4:52   ` [U-Boot] [PATCH 02/14] powerpc/fman: add PHY support for dTSEC Mingkai Hu
2011-01-27  4:52     ` [U-Boot] [PATCH 03/14] powerpc/fman: add dTSEC controller support Mingkai Hu
2011-01-27  4:52       ` [U-Boot] [PATCH 04/14] powerpc/fman: add 10GEC controller and PHY support Mingkai Hu
2011-01-27  4:52         ` Mingkai Hu [this message]
2011-01-27  4:52           ` [U-Boot] [PATCH 06/14] powerpc/corenet_ds: Add fman support Mingkai Hu
2011-01-27  4:52             ` [U-Boot] [PATCH 07/14] tsec: use IO accessories to access the register Mingkai Hu
2011-01-27  4:52               ` [U-Boot] [PATCH 08/14] tsec: arrange the code to avoid useless function declaration Mingkai Hu
2011-01-27  4:52                 ` [U-Boot] [PATCH 09/14] tsec: use general ethernet MII register struct(tsec_mii_t) Mingkai Hu
2011-01-27  4:52                   ` [U-Boot] [PATCH 10/14] tsec: refactor the PHY code to make it reuseable Mingkai Hu
2011-01-27  4:52                     ` [U-Boot] [PATCH 11/14] PHY: add some Vitesse phy support Mingkai Hu
2011-01-27  4:52                       ` [U-Boot] [PATCH 12/14] PHY: add some Broadcom " Mingkai Hu
2011-01-27  4:52                         ` [U-Boot] [PATCH 13/14] PHY: add some Marvell " Mingkai Hu
2011-01-27  4:52                           ` [U-Boot] [PATCH 14/14] PHY: add some misc phy code support Mingkai Hu
2011-01-27  5:44                           ` [U-Boot] [PATCH 13/14] PHY: add some Marvell phy support Macpaul Lin
2011-02-02 22:48                 ` [U-Boot] [PATCH 08/14] tsec: arrange the code to avoid useless function declaration Andy Fleming
2011-02-05 20:26                 ` Kumar Gala
2011-02-02 22:47               ` [U-Boot] [PATCH 07/14] tsec: use IO accessories to access the register Andy Fleming
2011-02-05 20:26               ` Kumar Gala
2011-01-27 17:42             ` [U-Boot] [PATCH 06/14] powerpc/corenet_ds: Add fman support Timur Tabi
2011-01-27 17:40           ` [U-Boot] [PATCH 05/14] powerpc/qoirq: Add support for FMan ethernet in Independent mode Timur Tabi
2011-01-27  6:15     ` [U-Boot] [PATCH 02/14] powerpc/fman: add PHY support for dTSEC Kumar Gala
2011-01-27 16:10     ` Timur Tabi
2011-01-27  6:04 ` [U-Boot] [PATCH 00/14] powerpc/p4080: add support for FMan ethernet in Independent mode Kumar Gala
2011-01-27  6:09   ` Hu Mingkai-B21284

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1296103972-2696-6-git-send-email-Mingkai.hu@freescale.com \
    --to=mingkai.hu@freescale.com \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.