[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(®s->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