public inbox for u-boot@lists.denx.de
 help / color / mirror / Atom feed
* [U-Boot] [PATCH 3/7] fec_imx27: driver for FEC ethernet controller on i.MX27
  2009-05-19 23:55 [U-Boot] [PATCH 00/10][v2] Support for LogicPD i.MX27-LITEKIT development board Ilya Yanok
@ 2009-05-19 23:55 ` Ilya Yanok
  2009-05-26  5:38   ` Ben Warren
  2009-06-15 14:01   ` Johan
  0 siblings, 2 replies; 18+ messages in thread
From: Ilya Yanok @ 2009-05-19 23:55 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Ilya Yanok <yanok@emcraft.com>
---
 cpu/arm926ejs/mx27/generic.c |   10 +
 drivers/net/Makefile         |    1 +
 drivers/net/fec_imx27.c      |  705 ++++++++++++++++++++++++++++++++++++++++++
 drivers/net/fec_imx27.h      |  302 ++++++++++++++++++
 include/netdev.h             |    1 +
 5 files changed, 1019 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/fec_imx27.c
 create mode 100644 drivers/net/fec_imx27.h

diff --git a/cpu/arm926ejs/mx27/generic.c b/cpu/arm926ejs/mx27/generic.c
index 850d5e6..e820d94 100644
--- a/cpu/arm926ejs/mx27/generic.c
+++ b/cpu/arm926ejs/mx27/generic.c
@@ -20,6 +20,7 @@
 
 #include <common.h>
 #include <div64.h>
+#include <netdev.h>
 #include <asm/io.h>
 #include <asm/arch/imx-regs.h>
 
@@ -159,6 +160,15 @@ int print_cpuinfo (void)
 }
 #endif
 
+int cpu_eth_init(bd_t *bis)
+{
+#if defined(CONFIG_FEC_IMX27)
+	return fecimx27_initialize(bis);
+#else
+	return 0;
+#endif
+}
+
 void imx_gpio_mode(int gpio_mode)
 {
 	struct gpio_regs *regs = (struct gpio_regs *)IMX_GPIO_BASE;
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index a360a50..ac68beb 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -34,6 +34,7 @@ COBJS-$(CONFIG_DRIVER_CS8900) += cs8900.o
 COBJS-$(CONFIG_TULIP) += dc2114x.o
 COBJS-$(CONFIG_DRIVER_DM9000) += dm9000x.o
 COBJS-$(CONFIG_DNET) += dnet.o
+COBJS-$(CONFIG_FEC_IMX27) += fec_imx27.o
 COBJS-$(CONFIG_E1000) += e1000.o
 COBJS-$(CONFIG_EEPRO100) += eepro100.o
 COBJS-$(CONFIG_ENC28J60) += enc28j60.o
diff --git a/drivers/net/fec_imx27.c b/drivers/net/fec_imx27.c
new file mode 100644
index 0000000..4ade348
--- /dev/null
+++ b/drivers/net/fec_imx27.c
@@ -0,0 +1,705 @@
+/*
+ * (C) Copyright 2009 Ilya Yanok, Emcraft Systems Ltd <yanok@emcraft.com>
+ * (C) Copyright 2008,2009 Eric Jarrige <eric.jarrige@armadeus.org>
+ * (C) Copyright 2008 Armadeus Systems nc
+ * (C) Copyright 2007 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
+ * (C) Copyright 2007 Pengutronix, Juergen Beisert <j.beisert@pengutronix.de>
+ *
+ * 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 <net.h>
+#include <miiphy.h>
+#include "fec_imx27.h"
+
+#include <asm/arch/clock.h>
+#include <asm/arch/imx-regs.h>
+#include <asm/io.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifndef CONFIG_MII
+#error "CONFIG_MII has to be defined!"
+#endif
+
+#undef DEBUG
+
+struct nbuf {
+	uint8_t data[1500];	/**< actual data */
+	int length;		/**< actual length */
+	int used;		/**< buffer in use or not */
+	uint8_t head[16];	/**< MAC header(6 + 6 + 2) + 2(aligned) */
+};
+
+struct fec_priv gfec = {
+	.eth       = (struct ethernet_regs *)IMX_FEC_BASE,
+	.xcv_type  = MII100,
+	.rbd_base  = NULL,
+	.rbd_index = 0,
+	.tbd_base  = NULL,
+	.tbd_index = 0,
+	.bd        = NULL,
+};
+
+/*
+ * MII-interface related functions
+ */
+static int fec_miiphy_read(char *dev, uint8_t phyAddr, uint8_t regAddr,
+		uint16_t *retVal)
+{
+	struct eth_device *edev = eth_get_dev_by_name(dev);
+	struct fec_priv *fec = (struct fec_priv *)edev->priv;
+
+	uint32_t reg;		/* convenient holder for the PHY register */
+	uint32_t phy;		/* convenient holder for the PHY */
+	uint32_t start;
+
+	/*
+	 * reading from any PHY's register is done by properly
+	 * programming the FEC's MII data register.
+	 */
+	writel(FEC_IEVENT_MII, &fec->eth->ievent);
+	reg = regAddr << FEC_MII_DATA_RA_SHIFT;
+	phy = phyAddr << FEC_MII_DATA_PA_SHIFT;
+
+	writel(FEC_MII_DATA_ST | FEC_MII_DATA_OP_RD | FEC_MII_DATA_TA |
+			phy | reg, &fec->eth->mii_data);
+
+	/*
+	 * wait for the related interrupt
+	 */
+	start = get_timer_masked();
+	while (!(readl(&fec->eth->ievent) & FEC_IEVENT_MII)) {
+		if (get_timer(start) > (CONFIG_SYS_HZ / 1000)) {
+			printf("Read MDIO failed...\n");
+			return -1;
+		}
+	}
+
+	/*
+	 * clear mii interrupt bit
+	 */
+	writel(FEC_IEVENT_MII, &fec->eth->ievent);
+
+	/*
+	 * it's now safe to read the PHY's register
+	 */
+	*retVal = readl(&fec->eth->mii_data);
+	debug("fec_miiphy_read: phy: %02x reg:%02x val:%#x\n", phyAddr,
+			regAddr, *retVal);
+	return 0;
+}
+
+static int fec_miiphy_write(char *dev, uint8_t phyAddr, uint8_t regAddr,
+		uint16_t data)
+{
+	struct eth_device *edev = eth_get_dev_by_name(dev);
+	struct fec_priv *fec = (struct fec_priv *)edev->priv;
+
+	uint32_t reg;		/* convenient holder for the PHY register */
+	uint32_t phy;		/* convenient holder for the PHY */
+	uint32_t start;
+
+	reg = regAddr << FEC_MII_DATA_RA_SHIFT;
+	phy = phyAddr << FEC_MII_DATA_PA_SHIFT;
+
+	writel(FEC_MII_DATA_ST | FEC_MII_DATA_OP_WR |
+		FEC_MII_DATA_TA | phy | reg | data, &fec->eth->mii_data);
+
+	/*
+	 * wait for the MII interrupt
+	 */
+	start = get_timer_masked();
+	while (!(readl(&fec->eth->ievent) & FEC_IEVENT_MII)) {
+		if (get_timer(start) > (CONFIG_SYS_HZ / 1000)) {
+			printf("Write MDIO failed...\n");
+			return -1;
+		}
+	}
+
+	/*
+	 * clear MII interrupt bit
+	 */
+	writel(FEC_IEVENT_MII, &fec->eth->ievent);
+	debug("fec_miiphy_write: phy: %02x reg:%02x val:%#x\n", phyAddr,
+			regAddr, data);
+
+	return 0;
+}
+
+static int miiphy_restart_aneg(struct eth_device *dev)
+{
+	/*
+	 * Wake up from sleep if necessary
+	 * Reset PHY, then delay 300ns
+	 */
+	miiphy_write(dev->name, 0, PHY_MIPGSR, 0x00FF);
+	miiphy_write(dev->name, 0, PHY_BMCR, PHY_BMCR_RESET);
+	udelay(1000);
+
+	/*
+	 * Set the auto-negotiation advertisement register bits
+	 */
+	miiphy_write(dev->name, 0, PHY_ANAR, 0x1e0);
+	miiphy_write(dev->name, 0, PHY_BMCR, PHY_BMCR_AUTON | PHY_BMCR_RST_NEG);
+
+	return 0;
+}
+
+static int miiphy_wait_aneg(struct eth_device *dev)
+{
+	uint32_t start;
+	uint16_t status;
+
+	/*
+	 * Wait for AN completion
+	 */
+	start = get_timer_masked(); /* get_time_ns(); */
+	do {
+		if (get_timer(start) > (CONFIG_SYS_HZ * 5)) {
+			printf("%s: Autonegotiation timeout\n", dev->name);
+			return -1;
+		}
+
+		if (miiphy_read(dev->name, 0, PHY_BMSR, &status)) {
+			printf("%s: Autonegotiation failed. status: 0x%04x\n",
+					dev->name, status);
+			return -1;
+		}
+	} while (!(status & PHY_BMSR_LS));
+
+	return 0;
+}
+static int fec_rx_task_enable(struct fec_priv *fec)
+{
+	writel(1 << 24, &fec->eth->r_des_active);
+	return 0;
+}
+
+static int fec_rx_task_disable(struct fec_priv *fec)
+{
+	return 0;
+}
+
+static int fec_tx_task_enable(struct fec_priv *fec)
+{
+	writel(1 << 24, &fec->eth->x_des_active);
+	return 0;
+}
+
+static int fec_tx_task_disable(struct fec_priv *fec)
+{
+	return 0;
+}
+
+/**
+ * Initialize receive task's buffer descriptors
+ * @param[in] fec all we know about the device yet
+ * @param[in] count receive buffer count to be allocated
+ * @param[in] size size of each receive buffer
+ * @return 0 on success
+ *
+ * For this task we need additional memory for the data buffers. And each
+ * data buffer requires some alignment. Thy must be aligned to a specific
+ * boundary each (DB_DATA_ALIGNMENT).
+ */
+static int fec_rbd_init(struct fec_priv *fec, int count, int size, int once)
+{
+	int ix;
+	uint32_t p = 0;
+
+	if (!once) {
+		/* reserve data memory and consider alignment */
+		p = (uint32_t)malloc(size * count + DB_DATA_ALIGNMENT);
+		memset((void *)p, 0, size * count + DB_DATA_ALIGNMENT);
+		p += DB_DATA_ALIGNMENT-1;
+		p &= ~(DB_DATA_ALIGNMENT-1);
+	}
+
+	for (ix = 0; ix < count; ix++) {
+		if (!once) {
+			writel(p, &fec->rbd_base[ix].data_pointer);
+			p += size;
+		}
+		writew(FEC_RBD_EMPTY, &fec->rbd_base[ix].status);
+		writew(0, &fec->rbd_base[ix].data_length);
+	}
+	/*
+	 * mark the last RBD to close the ring
+	 */
+	writew(FEC_RBD_WRAP | FEC_RBD_EMPTY, &fec->rbd_base[ix - 1].status);
+	fec->rbd_index = 0;
+
+	return 0;
+}
+
+/**
+ * Initialize transmit task's buffer descriptors
+ * @param[in] fec all we know about the device yet
+ *
+ * Transmit buffers are created externally. We only have to init the BDs here.\n
+ * Note: There is a race condition in the hardware. When only one BD is in
+ * use it must be marked with the WRAP bit to use it for every transmitt.
+ * This bit in combination with the READY bit results into double transmit
+ * of each data buffer. It seems the state machine checks READY earlier then
+ * resetting it after the first transfer.
+ * Using two BDs solves this issue.
+ */
+static void fec_tbd_init(struct fec_priv *fec)
+{
+	writew(0x0000, &fec->tbd_base[0].status);
+	writew(FEC_TBD_WRAP, &fec->tbd_base[1].status);
+	fec->tbd_index = 0;
+}
+
+/**
+ * Mark the given read buffer descriptor as free
+ * @param[in] last 1 if this is the last buffer descriptor in the chain, else 0
+ * @param[in] pRbd buffer descriptor to mark free again
+ */
+static void fec_rbd_clean(int last, struct fec_bd *pRbd)
+{
+	/*
+	 * Reset buffer descriptor as empty
+	 */
+	if (last)
+		writew(FEC_RBD_WRAP | FEC_RBD_EMPTY, &pRbd->status);
+	else
+		writew(FEC_RBD_EMPTY, &pRbd->status);
+	/*
+	 * no data in it
+	 */
+	writew(0, &pRbd->data_length);
+}
+
+static int fec_get_hwaddr(struct eth_device *dev, unsigned char *mac)
+{
+	struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE;
+	int i;
+
+	for (i = 0; i < 6; i++)
+		mac[6-1-i] = readl(&iim->IIM_BANK_AREA0[IIM0_MAC + i]);
+
+	return is_valid_ether_addr(mac);
+}
+
+static int fec_set_hwaddr(struct eth_device *dev, unsigned char *mac)
+{
+	struct fec_priv *fec = (struct fec_priv *)dev->priv;
+
+	writel(0, &fec->eth->iaddr1);
+	writel(0, &fec->eth->iaddr2);
+	writel(0, &fec->eth->gaddr1);
+	writel(0, &fec->eth->gaddr2);
+
+	/*
+	 * Set physical address
+	 */
+	writel((mac[0] << 24) + (mac[1] << 16) + (mac[2] << 8) + mac[3],
+			&fec->eth->paddr1);
+	writel((mac[4] << 24) + (mac[5] << 16) + 0x8808, &fec->eth->paddr2);
+
+	return 0;
+}
+
+/**
+ * Start the FEC engine
+ * @param[in] dev Our device to handle
+ */
+static int fec_open(struct eth_device *edev)
+{
+	struct fec_priv *fec = (struct fec_priv *)edev->priv;
+
+	debug("fec_open: fec_open(dev)\n");
+	/* full-duplex, heartbeat disabled */
+	writel(1 << 2, &fec->eth->x_cntrl);
+	fec->rbd_index = 0;
+
+	/*
+	 * Enable FEC-Lite controller
+	 */
+	writel(FEC_ECNTRL_ETHER_EN, &fec->eth->ecntrl);
+
+	miiphy_wait_aneg(edev);
+	miiphy_speed(edev->name, 0);
+	miiphy_duplex(edev->name, 0);
+
+	/*
+	 * Enable SmartDMA receive task
+	 */
+	fec_rx_task_enable(fec);
+
+	udelay(100000);
+	return 0;
+}
+
+static int fec_init(struct eth_device *dev, bd_t* bd)
+{
+	static int once;
+	uint32_t base;
+	struct fec_priv *fec = (struct fec_priv *)dev->priv;
+
+	if (!once) {
+		/*
+		 * reserve memory for both buffer descriptor chains at once
+		 * Datasheet forces the startaddress of each chain is 16 byte
+		 * aligned
+		 */
+		base = (uint32_t)malloc((2 + FEC_RBD_NUM) *
+				sizeof(struct fec_bd) + DB_ALIGNMENT);
+		memset((void *)base, 0, (2 + FEC_RBD_NUM) *
+				sizeof(struct fec_bd) + DB_ALIGNMENT);
+		base += (DB_ALIGNMENT-1);
+		base &= ~(DB_ALIGNMENT-1);
+
+		fec->rbd_base = (struct fec_bd *)base;
+
+		base += FEC_RBD_NUM * sizeof(struct fec_bd);
+
+		fec->tbd_base = (struct fec_bd *)base;
+	}
+
+	/*
+	 * Set interrupt mask register
+	 */
+	writel(0x00000000, &fec->eth->imask);
+
+	/*
+	 * Clear FEC-Lite interrupt event register(IEVENT)
+	 */
+	writel(0xffffffff, &fec->eth->ievent);
+
+
+	/*
+	 * Set FEC-Lite receive control register(R_CNTRL):
+	 */
+	if (fec->xcv_type == SEVENWIRE) {
+		/*
+		 * Frame length=1518; 7-wire mode
+		 */
+		writel(0x05ee0020, &fec->eth->r_cntrl);	/* FIXME 0x05ee0000 */
+	} else {
+		/*
+		 * Frame length=1518; MII mode;
+		 */
+		writel(0x05ee0024, &fec->eth->r_cntrl);	/* FIXME 0x05ee0004 */
+		/*
+		 * Set MII_SPEED = (1/(mii_speed * 2)) * System Clock
+		 * and do not drop the Preamble.
+		 */
+		writel((((imx_get_ahbclk() / 1000000) + 2) / 5) << 1,
+				&fec->eth->mii_speed);
+		debug("fec_init: mii_speed %#lx\n",
+				(((imx_get_ahbclk() / 1000000) + 2) / 5) << 1);
+	}
+	/*
+	 * Set Opcode/Pause Duration Register
+	 */
+	writel(0x00010020, &fec->eth->op_pause);	/* FIXME 0xffff0020; */
+	writel(0x2, &fec->eth->x_wmrk);
+	/*
+	 * Set multicast address filter
+	 */
+	writel(0x00000000, &fec->eth->gaddr1);
+	writel(0x00000000, &fec->eth->gaddr2);
+
+
+	/* clear MIB RAM */
+	long *mib_ptr = (long *)(IMX_FEC_BASE + 0x200);
+	while (mib_ptr <= (long *)(IMX_FEC_BASE + 0x2FC))
+		*mib_ptr++ = 0;
+
+	/* FIFO receive start register */
+	writel(0x520, &fec->eth->r_fstart);
+
+	/* size and address of each buffer */
+	writel(FEC_MAX_PKT_SIZE, &fec->eth->emrbr);
+	writel((uint32_t)fec->tbd_base, &fec->eth->etdsr);
+	writel((uint32_t)fec->rbd_base, &fec->eth->erdsr);
+
+	/*
+	 * Initialize RxBD/TxBD rings
+	 */
+	fec_rbd_init(fec, FEC_RBD_NUM, FEC_MAX_PKT_SIZE, once);
+	fec_tbd_init(fec);
+
+
+	if (fec->xcv_type != SEVENWIRE)
+		miiphy_restart_aneg(dev);
+
+	once = 1;	/* malloc done now (and once) */
+
+	fec_open(dev);
+	return 0;
+}
+
+/**
+ * Halt the FEC engine
+ * @param[in] dev Our device to handle
+ */
+static void fec_halt(struct eth_device *dev)
+{
+	struct fec_priv *fec = &gfec;
+	int counter = 0xffff;
+
+	/*
+	 * issue graceful stop command to the FEC transmitter if necessary
+	 */
+	writel(FEC_ECNTRL_RESET | readl(&fec->eth->x_cntrl),
+			&fec->eth->x_cntrl);
+
+	debug("eth_halt: wait for stop regs\n");
+	/*
+	 * wait for graceful stop to register
+	 */
+	while ((counter--) && (!(readl(&fec->eth->ievent) & FEC_IEVENT_GRA)))
+		;	/* FIXME ensure time */
+
+	/*
+	 * Disable SmartDMA tasks
+	 */
+	fec_tx_task_disable(fec);
+	fec_rx_task_disable(fec);
+
+	/*
+	 * Disable the Ethernet Controller
+	 * Note: this will also reset the BD index counter!
+	 */
+	writel(0, &fec->eth->ecntrl);
+	fec->rbd_index = 0;
+	fec->tbd_index = 0;
+	debug("eth_halt: done\n");
+}
+
+/**
+ * Transmit one frame
+ * @param[in] dev Our ethernet device to handle
+ * @param[in] packet Pointer to the data to be transmitted
+ * @param[in] length Data count in bytes
+ * @return 0 on success
+ */
+static int fec_send(struct eth_device *dev, volatile void* packet, int length)
+{
+	unsigned int status;
+
+	/*
+	 * This routine transmits one frame.  This routine only accepts
+	 * 6-byte Ethernet addresses.
+	 */
+	struct fec_priv *fec = (struct fec_priv *)dev->priv;
+
+	/*
+	 * Check for valid length of data.
+	 */
+	if ((length > 1500) || (length <= 0)) {
+		printf("Payload (%d) to large!\n", length);
+		return -1;
+	}
+
+	/*
+	 * Setup the transmit buffer
+	 * Note: We are always using the first buffer for transmission,
+	 * the second will be empty and only used to stop the DMA engine
+	 */
+	writew(length, &fec->tbd_base[fec->tbd_index].data_length);
+	writel((uint32_t)packet, &fec->tbd_base[fec->tbd_index].data_pointer);
+	/*
+	 * update BD's status now
+	 * This block:
+	 * - is always the last in a chain (means no chain)
+	 * - should transmitt the CRC
+	 * - might be the last BD in the list, so the address counter should
+	 *   wrap (-> keep the WRAP flag)
+	 */
+	status = readw(&fec->tbd_base[fec->tbd_index].status) & FEC_TBD_WRAP;
+	status |= FEC_TBD_LAST | FEC_TBD_TC | FEC_TBD_READY;
+	writew(status, &fec->tbd_base[fec->tbd_index].status);
+
+	/*
+	 * Enable SmartDMA transmit task
+	 */
+	fec_tx_task_enable(fec);
+
+	/*
+	 * wait until frame is sent .
+	 */
+	while (readw(&fec->tbd_base[fec->tbd_index].status) & FEC_TBD_READY) {
+		/* FIXME: Timeout */
+	}
+	debug("fec_send: status 0x%x index %d\n",
+			readw(&fec->tbd_base[fec->tbd_index].status),
+			fec->tbd_index);
+	/* for next transmission use the other buffer */
+	if (fec->tbd_index)
+		fec->tbd_index = 0;
+	else
+		fec->tbd_index = 1;
+
+	return 0;
+}
+
+/**
+ * Pull one frame from the card
+ * @param[in] dev Our ethernet device to handle
+ * @return Length of packet read
+ */
+static int fec_recv(struct eth_device *dev)
+{
+	struct fec_priv *fec = (struct fec_priv *)dev->priv;
+	struct fec_bd *rbd = &fec->rbd_base[fec->rbd_index];
+	unsigned long ievent;
+	int frame_length, len = 0;
+	struct nbuf *frame;
+	uint16_t bd_status;
+	uchar buff[FEC_MAX_PKT_SIZE];
+
+	/*
+	 * Check if any critical events have happened
+	 */
+	ievent = readl(&fec->eth->ievent);
+	writel(ievent, &fec->eth->ievent);
+	debug("fec_recv: ievent 0x%x\n", ievent);
+	if (ievent & FEC_IEVENT_BABR) {
+		fec_halt(dev);
+		fec_init(dev, fec->bd);
+		printf("some error: 0x%08lx\n", ievent);
+		return 0;
+	}
+	if (ievent & FEC_IEVENT_HBERR) {
+		/* Heartbeat error */
+		writel(0x00000001 | readl(&fec->eth->x_cntrl),
+				&fec->eth->x_cntrl);
+	}
+	if (ievent & FEC_IEVENT_GRA) {
+		/* Graceful stop complete */
+		if (readl(&fec->eth->x_cntrl) & 0x00000001) {
+			fec_halt(dev);
+			writel(~0x00000001 & readl(&fec->eth->x_cntrl),
+					&fec->eth->x_cntrl);
+			fec_init(dev, fec->bd);
+		}
+	}
+
+	/*
+	 * ensure reading the right buffer status
+	 */
+	bd_status = readw(&rbd->status);
+	debug("fec_recv: status 0x%x\n", bd_status);
+
+	if (!(bd_status & FEC_RBD_EMPTY)) {
+		if ((bd_status & FEC_RBD_LAST) && !(bd_status & FEC_RBD_ERR) &&
+			((readw(&rbd->data_length) - 4) > 14)) {
+			/*
+			 * Get buffer address and size
+			 */
+			frame = (struct nbuf *)readl(&rbd->data_pointer);
+			frame_length = readw(&rbd->data_length) - 4;
+			/*
+			 *  Fill the buffer and pass it to upper layers
+			 */
+			memcpy(buff, frame->data, frame_length);
+			NetReceive(buff, frame_length);
+			len = frame_length;
+		} else {
+			if (bd_status & FEC_RBD_ERR)
+				printf("error frame: 0x%08lx 0x%08x\n",
+						(ulong)rbd->data_pointer,
+						bd_status);
+		}
+		/*
+		 * free the current buffer, restart the engine
+		 * and move forward to the next buffer
+		 */
+		fec_rbd_clean(fec->rbd_index == (FEC_RBD_NUM - 1) ? 1 : 0, rbd);
+		fec_rx_task_enable(fec);
+		fec->rbd_index = (fec->rbd_index + 1) % FEC_RBD_NUM;
+	}
+	debug("fec_recv: stop\n");
+
+	return len;
+}
+
+static int fec_probe(bd_t *bd)
+{
+	struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE;
+	struct eth_device *edev;
+	struct fec_priv *fec = &gfec;
+	unsigned char ethaddr_str[20];
+	unsigned char ethaddr[6];
+	char *tmp = getenv("ethaddr");
+	char *end;
+
+	/* enable FEC clock */
+	writel(readl(&pll->PCCR1) | PCCR1_HCLK_FEC, &pll->PCCR1);
+	writel(readl(&pll->PCCR0) | PCCR0_FEC_EN, &pll->PCCR0);
+
+	/* create and fill edev struct */
+	edev = (struct eth_device *)malloc(sizeof(struct eth_device));
+	edev->priv = fec;
+	edev->init = fec_init;
+	edev->send = fec_send;
+	edev->recv = fec_recv;
+	edev->halt = fec_halt;
+
+	fec->eth = (struct ethernet_regs *)IMX_FEC_BASE;
+	fec->bd = bd;
+
+	/* Reset chip. */
+	writel(FEC_ECNTRL_RESET, &fec->eth->ecntrl);
+	while (readl(&fec->eth->ecntrl) & 1)
+		udelay(10);
+
+	fec->xcv_type = MII100;
+
+	sprintf(edev->name, "FEC ETHERNET");
+
+	miiphy_register(edev->name, fec_miiphy_read, fec_miiphy_write);
+
+	eth_register(edev);
+
+	if ((NULL != tmp) && (12 <= strlen(tmp))) {
+		int i;
+		/* convert MAC from string to int */
+		for (i = 0; i < 6; i++) {
+			ethaddr[i] = tmp ? simple_strtoul(tmp, &end, 16) : 0;
+			if (tmp)
+				tmp = (*end) ? end + 1 : end;
+		}
+	} else if (fec_get_hwaddr(edev, ethaddr) == 0) {
+		printf("got MAC address from EEPROM: %pM\n", ethaddr);
+		setenv("ethaddr", (char *)ethaddr_str);
+	}
+	memcpy(edev->enetaddr, ethaddr, 6);
+	fec_set_hwaddr(edev, ethaddr);
+
+	return 0;
+}
+
+int fecimx27_initialize(bd_t *bd)
+{
+	int lout = 1;
+	static int once;
+
+	if (!once) {
+		debug("eth_init: fec_probe(bd)\n");
+		lout = fec_probe(bd);
+		once = 1;
+	}
+	return lout;
+}
+
diff --git a/drivers/net/fec_imx27.h b/drivers/net/fec_imx27.h
new file mode 100644
index 0000000..926c0d7
--- /dev/null
+++ b/drivers/net/fec_imx27.h
@@ -0,0 +1,302 @@
+/*
+ * (C) Copyright 2009 Ilya Yanok, Emcraft Systems Ltd <yanok@emcraft.com>
+ * (C) Copyright 2008 Armadeus Systems, nc
+ * (C) Copyright 2008 Eric Jarrige <eric.jarrige@armadeus.org>
+ * (C) Copyright 2007 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
+ * (C) Copyright 2007 Pengutronix, Juergen Beisert <j.beisert@pengutronix.de>
+ *
+ * (C) Copyright 2003
+ * Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+ *
+ * This file is based on mpc4200fec.h
+ * (C) Copyright Motorola, Inc., 2000
+ *
+ * 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 __IMX27_FEC_H
+#define __IMX27_FEC_H
+
+/**
+ * Layout description of the FEC
+ */
+struct ethernet_regs {
+
+/* [10:2]addr = 00 */
+
+/*  Control and status Registers (offset 000-1FF) */
+
+	uint32_t RES0[1];		/* MBAR_ETH + 0x000 */
+	uint32_t ievent;		/* MBAR_ETH + 0x004 */
+	uint32_t imask;			/* MBAR_ETH + 0x008 */
+
+	uint32_t RES1[1];		/* MBAR_ETH + 0x00C */
+	uint32_t r_des_active;		/* MBAR_ETH + 0x010 */
+	uint32_t x_des_active;		/* MBAR_ETH + 0x014 */
+	uint32_t RES2[3];		/* MBAR_ETH + 0x018-20 */
+	uint32_t ecntrl;		/* MBAR_ETH + 0x024 */
+
+	uint32_t RES3[6];		/* MBAR_ETH + 0x028-03C */
+	uint32_t mii_data;		/* MBAR_ETH + 0x040 */
+	uint32_t mii_speed;		/* MBAR_ETH + 0x044 */
+	uint32_t RES4[7];		/* MBAR_ETH + 0x048-60 */
+	uint32_t mib_control;		/* MBAR_ETH + 0x064 */
+
+	uint32_t RES5[7];		/* MBAR_ETH + 0x068-80 */
+	uint32_t r_cntrl;		/* MBAR_ETH + 0x084 */
+	uint32_t RES6[15];		/* MBAR_ETH + 0x088-C0 */
+	uint32_t x_cntrl;		/* MBAR_ETH + 0x0C4 */
+	uint32_t RES7[7];		/* MBAR_ETH + 0x0C8-E0 */
+	uint32_t paddr1;		/* MBAR_ETH + 0x0E4 */
+	uint32_t paddr2;		/* MBAR_ETH + 0x0E8 */
+	uint32_t op_pause;		/* MBAR_ETH + 0x0EC */
+
+	uint32_t RES8[10];		/* MBAR_ETH + 0x0F0-114 */
+	uint32_t iaddr1;		/* MBAR_ETH + 0x118 */
+	uint32_t iaddr2;		/* MBAR_ETH + 0x11C */
+	uint32_t gaddr1;		/* MBAR_ETH + 0x120 */
+	uint32_t gaddr2;		/* MBAR_ETH + 0x124 */
+	uint32_t RES9[7];		/* MBAR_ETH + 0x128-140 */
+
+	uint32_t x_wmrk;		/* MBAR_ETH + 0x144 */
+	uint32_t RES10[1];		/* MBAR_ETH + 0x148 */
+	uint32_t r_bound;		/* MBAR_ETH + 0x14C */
+	uint32_t r_fstart;		/* MBAR_ETH + 0x150 */
+	uint32_t RES11[11];		/* MBAR_ETH + 0x154-17C */
+	uint32_t erdsr;			/* MBAR_ETH + 0x180 */
+	uint32_t etdsr;			/* MBAR_ETH + 0x184 */
+	uint32_t emrbr;			/* MBAR_ETH + 0x188 */
+	uint32_t RES12[29];		/* MBAR_ETH + 0x18C-1FC */
+
+/*  MIB COUNTERS (Offset 200-2FF) */
+
+	uint32_t rmon_t_drop;		/* MBAR_ETH + 0x200 */
+	uint32_t rmon_t_packets;	/* MBAR_ETH + 0x204 */
+	uint32_t rmon_t_bc_pkt;		/* MBAR_ETH + 0x208 */
+	uint32_t rmon_t_mc_pkt;		/* MBAR_ETH + 0x20C */
+	uint32_t rmon_t_crc_align;	/* MBAR_ETH + 0x210 */
+	uint32_t rmon_t_undersize;	/* MBAR_ETH + 0x214 */
+	uint32_t rmon_t_oversize;	/* MBAR_ETH + 0x218 */
+	uint32_t rmon_t_frag;		/* MBAR_ETH + 0x21C */
+	uint32_t rmon_t_jab;		/* MBAR_ETH + 0x220 */
+	uint32_t rmon_t_col;		/* MBAR_ETH + 0x224 */
+	uint32_t rmon_t_p64;		/* MBAR_ETH + 0x228 */
+	uint32_t rmon_t_p65to127;	/* MBAR_ETH + 0x22C */
+	uint32_t rmon_t_p128to255;	/* MBAR_ETH + 0x230 */
+	uint32_t rmon_t_p256to511;	/* MBAR_ETH + 0x234 */
+	uint32_t rmon_t_p512to1023;	/* MBAR_ETH + 0x238 */
+	uint32_t rmon_t_p1024to2047;	/* MBAR_ETH + 0x23C */
+	uint32_t rmon_t_p_gte2048;	/* MBAR_ETH + 0x240 */
+	uint32_t rmon_t_octets;		/* MBAR_ETH + 0x244 */
+	uint32_t ieee_t_drop;		/* MBAR_ETH + 0x248 */
+	uint32_t ieee_t_frame_ok;	/* MBAR_ETH + 0x24C */
+	uint32_t ieee_t_1col;		/* MBAR_ETH + 0x250 */
+	uint32_t ieee_t_mcol;		/* MBAR_ETH + 0x254 */
+	uint32_t ieee_t_def;		/* MBAR_ETH + 0x258 */
+	uint32_t ieee_t_lcol;		/* MBAR_ETH + 0x25C */
+	uint32_t ieee_t_excol;		/* MBAR_ETH + 0x260 */
+	uint32_t ieee_t_macerr;		/* MBAR_ETH + 0x264 */
+	uint32_t ieee_t_cserr;		/* MBAR_ETH + 0x268 */
+	uint32_t ieee_t_sqe;		/* MBAR_ETH + 0x26C */
+	uint32_t t_fdxfc;		/* MBAR_ETH + 0x270 */
+	uint32_t ieee_t_octets_ok;	/* MBAR_ETH + 0x274 */
+
+	uint32_t RES13[2];		/* MBAR_ETH + 0x278-27C */
+	uint32_t rmon_r_drop;		/* MBAR_ETH + 0x280 */
+	uint32_t rmon_r_packets;	/* MBAR_ETH + 0x284 */
+	uint32_t rmon_r_bc_pkt;		/* MBAR_ETH + 0x288 */
+	uint32_t rmon_r_mc_pkt;		/* MBAR_ETH + 0x28C */
+	uint32_t rmon_r_crc_align;	/* MBAR_ETH + 0x290 */
+	uint32_t rmon_r_undersize;	/* MBAR_ETH + 0x294 */
+	uint32_t rmon_r_oversize;	/* MBAR_ETH + 0x298 */
+	uint32_t rmon_r_frag;		/* MBAR_ETH + 0x29C */
+	uint32_t rmon_r_jab;		/* MBAR_ETH + 0x2A0 */
+
+	uint32_t rmon_r_resvd_0;	/* MBAR_ETH + 0x2A4 */
+
+	uint32_t rmon_r_p64;		/* MBAR_ETH + 0x2A8 */
+	uint32_t rmon_r_p65to127;	/* MBAR_ETH + 0x2AC */
+	uint32_t rmon_r_p128to255;	/* MBAR_ETH + 0x2B0 */
+	uint32_t rmon_r_p256to511;	/* MBAR_ETH + 0x2B4 */
+	uint32_t rmon_r_p512to1023;	/* MBAR_ETH + 0x2B8 */
+	uint32_t rmon_r_p1024to2047;	/* MBAR_ETH + 0x2BC */
+	uint32_t rmon_r_p_gte2048;	/* MBAR_ETH + 0x2C0 */
+	uint32_t rmon_r_octets;		/* MBAR_ETH + 0x2C4 */
+	uint32_t ieee_r_drop;		/* MBAR_ETH + 0x2C8 */
+	uint32_t ieee_r_frame_ok;	/* MBAR_ETH + 0x2CC */
+	uint32_t ieee_r_crc;		/* MBAR_ETH + 0x2D0 */
+	uint32_t ieee_r_align;		/* MBAR_ETH + 0x2D4 */
+	uint32_t r_macerr;		/* MBAR_ETH + 0x2D8 */
+	uint32_t r_fdxfc;		/* MBAR_ETH + 0x2DC */
+	uint32_t ieee_r_octets_ok;	/* MBAR_ETH + 0x2E0 */
+
+	uint32_t RES14[6];		/* MBAR_ETH + 0x2E4-2FC */
+
+	uint32_t RES15[64];		/* MBAR_ETH + 0x300-3FF */
+};
+
+#define FEC_IEVENT_HBERR		0x80000000
+#define FEC_IEVENT_BABR			0x40000000
+#define FEC_IEVENT_BABT			0x20000000
+#define FEC_IEVENT_GRA			0x10000000
+#define FEC_IEVENT_TXF			0x08000000
+#define FEC_IEVENT_TXB			0x04000000
+#define FEC_IEVENT_RXF			0x02000000
+#define FEC_IEVENT_RXB			0x01000000
+#define FEC_IEVENT_MII			0x00800000
+#define FEC_IEVENT_EBERR		0x00400000
+#define FEC_IEVENT_LC			0x00200000
+#define FEC_IEVENT_RL			0x00100000
+#define FEC_IEVENT_UN			0x00080000
+
+#define FEC_IMASK_HBERR			0x80000000
+#define FEC_IMASK_BABR			0x40000000
+#define FEC_IMASKT_BABT			0x20000000
+#define FEC_IMASK_GRA			0x10000000
+#define FEC_IMASKT_TXF			0x08000000
+#define FEC_IMASK_TXB			0x04000000
+#define FEC_IMASKT_RXF			0x02000000
+#define FEC_IMASK_RXB			0x01000000
+#define FEC_IMASK_MII			0x00800000
+#define FEC_IMASK_EBERR			0x00400000
+#define FEC_IMASK_LC			0x00200000
+#define FEC_IMASKT_RL			0x00100000
+#define FEC_IMASK_UN			0x00080000
+
+
+#define FEC_RCNTRL_MAX_FL_SHIFT		16
+#define FEC_RCNTRL_LOOP			0x00000001
+#define FEC_RCNTRL_DRT			0x00000002
+#define FEC_RCNTRL_MII_MODE		0x00000004
+#define FEC_RCNTRL_PROM			0x00000008
+#define FEC_RCNTRL_BC_REJ		0x00000010
+#define FEC_RCNTRL_FCE			0x00000020
+
+#define FEC_TCNTRL_GTS			0x00000001
+#define FEC_TCNTRL_HBC			0x00000002
+#define FEC_TCNTRL_FDEN			0x00000004
+#define FEC_TCNTRL_TFC_PAUSE		0x00000008
+#define FEC_TCNTRL_RFC_PAUSE		0x00000010
+
+#define FEC_ECNTRL_RESET		0x00000001	/* reset the FEC */
+#define FEC_ECNTRL_ETHER_EN		0x00000002	/* enable the FEC */
+
+/**
+ * @brief Descriptor buffer alignment
+ *
+ * i.MX27 requires a 16 byte alignment (but for the first element only)
+ */
+#define DB_ALIGNMENT		16
+
+/**
+ * @brief Data buffer alignment
+ *
+ * i.MX27 requires a four byte alignment for transmit and 16 bits
+ * alignment for receive so take 16
+ * Note: Valid for member data_pointer in struct buffer_descriptor
+ */
+#define DB_DATA_ALIGNMENT	16
+
+/**
+ * @brief Receive & Transmit Buffer Descriptor definitions
+ *
+ * Note: The first BD must be aligned (see DB_ALIGNMENT)
+ */
+struct fec_bd {
+	uint16_t data_length;		/* payload's length in bytes */
+	uint16_t status;		/* BD's staus (see datasheet) */
+	uint32_t data_pointer;		/* payload's buffer address */
+};
+
+/**
+ * Supported phy types on this platform
+ */
+enum xceiver_type {
+	SEVENWIRE,	/* 7-wire       */
+	MII10,		/* MII 10Mbps   */
+	MII100		/* MII 100Mbps  */
+};
+
+/**
+ * @brief i.MX27-FEC private structure
+ */
+struct fec_priv {
+	struct ethernet_regs *eth;	/* pointer to register'S base */
+	enum xceiver_type xcv_type;	/* transceiver type */
+	struct fec_bd *rbd_base;	/* RBD ring */
+	int rbd_index;			/* next receive BD to read */
+	struct fec_bd *tbd_base;	/* TBD ring */
+	int tbd_index;			/* next transmit BD to write */
+	bd_t *bd;
+};
+
+/**
+ * @brief Numbers of buffer descriptors for receiving
+ *
+ * The number defines the stocked memory buffers for the receiving task.
+ * Larger values makes no sense in this limited environment.
+ */
+#define FEC_RBD_NUM		64
+
+/**
+ * @brief Define the ethernet packet size limit in memory
+ *
+ * Note: Do not shrink this number. This will force the FEC to spread larger
+ * frames in more than one BD. This is nothing to worry about, but the current
+ * driver can't handle it.
+ */
+#define FEC_MAX_PKT_SIZE	1536
+
+/* Receive BD status bits */
+#define FEC_RBD_EMPTY	0x8000	/* Receive BD status: Buffer is empty */
+#define FEC_RBD_WRAP	0x2000	/* Receive BD status: Last BD in ring */
+/* Receive BD status: Buffer is last in frame (useless here!) */
+#define FEC_RBD_LAST	0x0800
+#define FEC_RBD_MISS	0x0100	/* Receive BD status: Miss bit for prom mode */
+/* Receive BD status: The received frame is broadcast frame */
+#define FEC_RBD_BC	0x0080
+/* Receive BD status: The received frame is multicast frame */
+#define FEC_RBD_MC	0x0040
+#define FEC_RBD_LG	0x0020	/* Receive BD status: Frame length violation */
+#define FEC_RBD_NO	0x0010	/* Receive BD status: Nonoctet align frame */
+#define FEC_RBD_CR	0x0004	/* Receive BD status: CRC error */
+#define FEC_RBD_OV	0x0002	/* Receive BD status: Receive FIFO overrun */
+#define FEC_RBD_TR	0x0001	/* Receive BD status: Frame is truncated */
+#define FEC_RBD_ERR	(FEC_RBD_LG | FEC_RBD_NO | FEC_RBD_CR | \
+			FEC_RBD_OV | FEC_RBD_TR)
+
+/* Transmit BD status bits */
+#define FEC_TBD_READY	0x8000	/* Tansmit BD status: Buffer is ready */
+#define FEC_TBD_WRAP	0x2000	/* Tansmit BD status: Mark as last BD in ring */
+#define FEC_TBD_LAST	0x0800	/* Tansmit BD status: Buffer is last in frame */
+#define FEC_TBD_TC	0x0400	/* Tansmit BD status: Transmit the CRC */
+#define FEC_TBD_ABC	0x0200	/* Tansmit BD status: Append bad CRC */
+
+/* MII-related definitios */
+#define FEC_MII_DATA_ST		0x40000000	/* Start of frame delimiter */
+#define FEC_MII_DATA_OP_RD	0x20000000	/* Perform a read operation */
+#define FEC_MII_DATA_OP_WR	0x10000000	/* Perform a write operation */
+#define FEC_MII_DATA_PA_MSK	0x0f800000	/* PHY Address field mask */
+#define FEC_MII_DATA_RA_MSK	0x007c0000	/* PHY Register field mask */
+#define FEC_MII_DATA_TA		0x00020000	/* Turnaround */
+#define FEC_MII_DATA_DATAMSK	0x0000ffff	/* PHY data field */
+
+#define FEC_MII_DATA_RA_SHIFT	18	/* MII Register address bits */
+#define FEC_MII_DATA_PA_SHIFT	23	/* MII PHY address bits */
+
+#endif	/* __IMX27_FEC_H */
diff --git a/include/netdev.h b/include/netdev.h
index 63cf730..2d999ad 100644
--- a/include/netdev.h
+++ b/include/netdev.h
@@ -49,6 +49,7 @@ int e1000_initialize(bd_t *bis);
 int eepro100_initialize(bd_t *bis);
 int eth_3com_initialize (bd_t * bis);
 int fec_initialize (bd_t *bis);
+int fecimx27_initialize (bd_t *bis);
 int greth_initialize(bd_t *bis);
 void gt6426x_eth_initialize(bd_t *bis);
 int inca_switch_initialize(bd_t *bis);
-- 
1.6.0.6

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [U-Boot] [PATCH 3/7] fec_imx27: driver for FEC ethernet controller on i.MX27
  2009-05-19 23:55 ` [U-Boot] [PATCH 3/7] fec_imx27: driver for FEC ethernet controller on i.MX27 Ilya Yanok
@ 2009-05-26  5:38   ` Ben Warren
  2009-06-07 23:08     ` Ilya Yanok
  2009-11-17  2:46     ` alfred steele
  2009-06-15 14:01   ` Johan
  1 sibling, 2 replies; 18+ messages in thread
From: Ben Warren @ 2009-05-26  5:38 UTC (permalink / raw)
  To: u-boot

Hi Ilya,

Thanks for making all the improvements:

Ilya Yanok wrote:
> Signed-off-by: Ilya Yanok <yanok@emcraft.com>
> ---
>  cpu/arm926ejs/mx27/generic.c |   10 +
>  drivers/net/Makefile         |    1 +
>  drivers/net/fec_imx27.c      |  705 ++++++++++++++++++++++++++++++++++++++++++
>  drivers/net/fec_imx27.h      |  302 ++++++++++++++++++
>  include/netdev.h             |    1 +
>  5 files changed, 1019 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/net/fec_imx27.c
>  create mode 100644 drivers/net/fec_imx27.h
>
>   
Naive question: Is this FEC truly unique to the iMX27?  If not you 
should pick a more generic name.

<snip>
> diff --git a/cpu/arm926ejs/mx27/generic.c b/cpu/arm926ejs/mx27/generic.c
> index 850d5e6..e820d94 100644
> --- a/cpu/arm926ejs/mx27/generic.c
> +++ b/cpu/arm926ejs/mx27/generic.c
> @@ -20,6 +20,7 @@
>  
>  #include <common.h>
>  #include <div64.h>
> +#include <netdev.h>
>  #include <asm/io.h>
>  #include <asm/arch/imx-regs.h>
>  
> @@ -159,6 +160,15 @@ int print_cpuinfo (void)
>  }
>  #endif
>  
> +int cpu_eth_init(bd_t *bis)
> +{
> +#if defined(CONFIG_FEC_IMX27)
> +	return fecimx27_initialize(bis);
> +#else
> +	return 0;
> +#endif
> +}
> +
>  void imx_gpio_mode(int gpio_mode)
>  {
>  	struct gpio_regs *regs = (struct gpio_regs *)IMX_GPIO_BASE;
> diff --git a/drivers/net/Makefile b/drivers/net/Makefile
> index a360a50..ac68beb 100644
> --- a/drivers/net/Makefile
> +++ b/drivers/net/Makefile
> @@ -34,6 +34,7 @@ COBJS-$(CONFIG_DRIVER_CS8900) += cs8900.o
>  COBJS-$(CONFIG_TULIP) += dc2114x.o
>  COBJS-$(CONFIG_DRIVER_DM9000) += dm9000x.o
>  COBJS-$(CONFIG_DNET) += dnet.o
> +COBJS-$(CONFIG_FEC_IMX27) += fec_imx27.o
>   
Please keep this sorted alphabetically.
>  COBJS-$(CONFIG_E1000) += e1000.o
>  COBJS-$(CONFIG_EEPRO100) += eepro100.o
>  COBJS-$(CONFIG_ENC28J60) += enc28j60.o
> diff --git a/drivers/net/fec_imx27.c b/drivers/net/fec_imx27.c
> new file mode 100644
> index 0000000..4ade348
> --- /dev/null
> +++ b/drivers/net/fec_imx27.c
> @@ -0,0 +1,705 @@
> +/*
> + * (C) Copyright 2009 Ilya Yanok, Emcraft Systems Ltd <yanok@emcraft.com>
> + * (C) Copyright 2008,2009 Eric Jarrige <eric.jarrige@armadeus.org>
> + * (C) Copyright 2008 Armadeus Systems nc
> + * (C) Copyright 2007 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
> + * (C) Copyright 2007 Pengutronix, Juergen Beisert <j.beisert@pengutronix.de>
> + *
> + * 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 <net.h>
> +#include <miiphy.h>
> +#include "fec_imx27.h"
> +
> +#include <asm/arch/clock.h>
> +#include <asm/arch/imx-regs.h>
> +#include <asm/io.h>
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +#ifndef CONFIG_MII
> +#error "CONFIG_MII has to be defined!"
> +#endif
> +
> +#undef DEBUG
> +
> +struct nbuf {
> +	uint8_t data[1500];	/**< actual data */
>   
I think 'u8' and friends are more commonly used in U-boot, but am not 
too fussy about this.
> +	int length;		/**< actual length */
> +	int used;		/**< buffer in use or not */
> +	uint8_t head[16];	/**< MAC header(6 + 6 + 2) + 2(aligned) */
> +};
> +
> +struct fec_priv gfec = {
> +	.eth       = (struct ethernet_regs *)IMX_FEC_BASE,
> +	.xcv_type  = MII100,
> +	.rbd_base  = NULL,
> +	.rbd_index = 0,
> +	.tbd_base  = NULL,
> +	.tbd_index = 0,
> +	.bd        = NULL,
> +};
> +
> +/*
> + * MII-interface related functions
> + */
> +static int fec_miiphy_read(char *dev, uint8_t phyAddr, uint8_t regAddr,
> +		uint16_t *retVal)
> +{
> +	struct eth_device *edev = eth_get_dev_by_name(dev);
> +	struct fec_priv *fec = (struct fec_priv *)edev->priv;
> +
> +	uint32_t reg;		/* convenient holder for the PHY register */
> +	uint32_t phy;		/* convenient holder for the PHY */
> +	uint32_t start;
> +
> +	/*
> +	 * reading from any PHY's register is done by properly
> +	 * programming the FEC's MII data register.
> +	 */
> +	writel(FEC_IEVENT_MII, &fec->eth->ievent);
> +	reg = regAddr << FEC_MII_DATA_RA_SHIFT;
> +	phy = phyAddr << FEC_MII_DATA_PA_SHIFT;
> +
> +	writel(FEC_MII_DATA_ST | FEC_MII_DATA_OP_RD | FEC_MII_DATA_TA |
> +			phy | reg, &fec->eth->mii_data);
> +
> +	/*
> +	 * wait for the related interrupt
> +	 */
> +	start = get_timer_masked();
> +	while (!(readl(&fec->eth->ievent) & FEC_IEVENT_MII)) {
> +		if (get_timer(start) > (CONFIG_SYS_HZ / 1000)) {
> +			printf("Read MDIO failed...\n");
> +			return -1;
> +		}
> +	}
> +
> +	/*
> +	 * clear mii interrupt bit
> +	 */
> +	writel(FEC_IEVENT_MII, &fec->eth->ievent);
> +
> +	/*
> +	 * it's now safe to read the PHY's register
> +	 */
> +	*retVal = readl(&fec->eth->mii_data);
> +	debug("fec_miiphy_read: phy: %02x reg:%02x val:%#x\n", phyAddr,
> +			regAddr, *retVal);
> +	return 0;
> +}
> +
> +static int fec_miiphy_write(char *dev, uint8_t phyAddr, uint8_t regAddr,
> +		uint16_t data)
> +{
> +	struct eth_device *edev = eth_get_dev_by_name(dev);
> +	struct fec_priv *fec = (struct fec_priv *)edev->priv;
> +
> +	uint32_t reg;		/* convenient holder for the PHY register */
> +	uint32_t phy;		/* convenient holder for the PHY */
> +	uint32_t start;
> +
> +	reg = regAddr << FEC_MII_DATA_RA_SHIFT;
> +	phy = phyAddr << FEC_MII_DATA_PA_SHIFT;
> +
> +	writel(FEC_MII_DATA_ST | FEC_MII_DATA_OP_WR |
> +		FEC_MII_DATA_TA | phy | reg | data, &fec->eth->mii_data);
> +
> +	/*
> +	 * wait for the MII interrupt
> +	 */
> +	start = get_timer_masked();
> +	while (!(readl(&fec->eth->ievent) & FEC_IEVENT_MII)) {
> +		if (get_timer(start) > (CONFIG_SYS_HZ / 1000)) {
> +			printf("Write MDIO failed...\n");
> +			return -1;
> +		}
> +	}
> +
> +	/*
> +	 * clear MII interrupt bit
> +	 */
> +	writel(FEC_IEVENT_MII, &fec->eth->ievent);
> +	debug("fec_miiphy_write: phy: %02x reg:%02x val:%#x\n", phyAddr,
> +			regAddr, data);
> +
> +	return 0;
> +}
> +
> +static int miiphy_restart_aneg(struct eth_device *dev)
> +{
> +	/*
> +	 * Wake up from sleep if necessary
> +	 * Reset PHY, then delay 300ns
> +	 */
> +	miiphy_write(dev->name, 0, PHY_MIPGSR, 0x00FF);
> +	miiphy_write(dev->name, 0, PHY_BMCR, PHY_BMCR_RESET);
> +	udelay(1000);
> +
> +	/*
> +	 * Set the auto-negotiation advertisement register bits
> +	 */
> +	miiphy_write(dev->name, 0, PHY_ANAR, 0x1e0);
> +	miiphy_write(dev->name, 0, PHY_BMCR, PHY_BMCR_AUTON | PHY_BMCR_RST_NEG);
> +
> +	return 0;
> +}
> +
> +static int miiphy_wait_aneg(struct eth_device *dev)
> +{
> +	uint32_t start;
> +	uint16_t status;
> +
> +	/*
> +	 * Wait for AN completion
> +	 */
> +	start = get_timer_masked(); /* get_time_ns(); */
> +	do {
> +		if (get_timer(start) > (CONFIG_SYS_HZ * 5)) {
> +			printf("%s: Autonegotiation timeout\n", dev->name);
> +			return -1;
> +		}
> +
> +		if (miiphy_read(dev->name, 0, PHY_BMSR, &status)) {
> +			printf("%s: Autonegotiation failed. status: 0x%04x\n",
> +					dev->name, status);
> +			return -1;
> +		}
> +	} while (!(status & PHY_BMSR_LS));
> +
> +	return 0;
> +}
> +static int fec_rx_task_enable(struct fec_priv *fec)
> +{
> +	writel(1 << 24, &fec->eth->r_des_active);
> +	return 0;
> +}
> +
> +static int fec_rx_task_disable(struct fec_priv *fec)
> +{
> +	return 0;
> +}
> +
> +static int fec_tx_task_enable(struct fec_priv *fec)
> +{
> +	writel(1 << 24, &fec->eth->x_des_active);
> +	return 0;
> +}
> +
> +static int fec_tx_task_disable(struct fec_priv *fec)
> +{
> +	return 0;
> +}
> +
> +/**
> + * Initialize receive task's buffer descriptors
> + * @param[in] fec all we know about the device yet
> + * @param[in] count receive buffer count to be allocated
> + * @param[in] size size of each receive buffer
> + * @return 0 on success
> + *
> + * For this task we need additional memory for the data buffers. And each
> + * data buffer requires some alignment. Thy must be aligned to a specific
> + * boundary each (DB_DATA_ALIGNMENT).
> + */
> +static int fec_rbd_init(struct fec_priv *fec, int count, int size, int once)
> +{
> +	int ix;
> +	uint32_t p = 0;
> +
> +	if (!once) {
> +		/* reserve data memory and consider alignment */
> +		p = (uint32_t)malloc(size * count + DB_DATA_ALIGNMENT);
> +		memset((void *)p, 0, size * count + DB_DATA_ALIGNMENT);
> +		p += DB_DATA_ALIGNMENT-1;
> +		p &= ~(DB_DATA_ALIGNMENT-1);
> +	}
> +
> +	for (ix = 0; ix < count; ix++) {
> +		if (!once) {
> +			writel(p, &fec->rbd_base[ix].data_pointer);
> +			p += size;
> +		}
> +		writew(FEC_RBD_EMPTY, &fec->rbd_base[ix].status);
> +		writew(0, &fec->rbd_base[ix].data_length);
> +	}
> +	/*
> +	 * mark the last RBD to close the ring
> +	 */
> +	writew(FEC_RBD_WRAP | FEC_RBD_EMPTY, &fec->rbd_base[ix - 1].status);
> +	fec->rbd_index = 0;
> +
> +	return 0;
> +}
> +
> +/**
> + * Initialize transmit task's buffer descriptors
> + * @param[in] fec all we know about the device yet
> + *
> + * Transmit buffers are created externally. We only have to init the BDs here.\n
> + * Note: There is a race condition in the hardware. When only one BD is in
> + * use it must be marked with the WRAP bit to use it for every transmitt.
> + * This bit in combination with the READY bit results into double transmit
> + * of each data buffer. It seems the state machine checks READY earlier then
> + * resetting it after the first transfer.
> + * Using two BDs solves this issue.
> + */
> +static void fec_tbd_init(struct fec_priv *fec)
> +{
> +	writew(0x0000, &fec->tbd_base[0].status);
> +	writew(FEC_TBD_WRAP, &fec->tbd_base[1].status);
> +	fec->tbd_index = 0;
> +}
> +
> +/**
> + * Mark the given read buffer descriptor as free
> + * @param[in] last 1 if this is the last buffer descriptor in the chain, else 0
> + * @param[in] pRbd buffer descriptor to mark free again
> + */
> +static void fec_rbd_clean(int last, struct fec_bd *pRbd)
> +{
> +	/*
> +	 * Reset buffer descriptor as empty
> +	 */
> +	if (last)
> +		writew(FEC_RBD_WRAP | FEC_RBD_EMPTY, &pRbd->status);
> +	else
> +		writew(FEC_RBD_EMPTY, &pRbd->status);
> +	/*
> +	 * no data in it
> +	 */
> +	writew(0, &pRbd->data_length);
> +}
> +
> +static int fec_get_hwaddr(struct eth_device *dev, unsigned char *mac)
> +{
> +	struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE;
> +	int i;
> +
> +	for (i = 0; i < 6; i++)
> +		mac[6-1-i] = readl(&iim->IIM_BANK_AREA0[IIM0_MAC + i]);
> +
> +	return is_valid_ether_addr(mac);
> +}
> +
> +static int fec_set_hwaddr(struct eth_device *dev, unsigned char *mac)
> +{
> +	struct fec_priv *fec = (struct fec_priv *)dev->priv;
> +
> +	writel(0, &fec->eth->iaddr1);
> +	writel(0, &fec->eth->iaddr2);
> +	writel(0, &fec->eth->gaddr1);
> +	writel(0, &fec->eth->gaddr2);
> +
> +	/*
> +	 * Set physical address
> +	 */
> +	writel((mac[0] << 24) + (mac[1] << 16) + (mac[2] << 8) + mac[3],
> +			&fec->eth->paddr1);
> +	writel((mac[4] << 24) + (mac[5] << 16) + 0x8808, &fec->eth->paddr2);
> +
> +	return 0;
> +}
> +
> +/**
> + * Start the FEC engine
> + * @param[in] dev Our device to handle
> + */
> +static int fec_open(struct eth_device *edev)
> +{
> +	struct fec_priv *fec = (struct fec_priv *)edev->priv;
> +
> +	debug("fec_open: fec_open(dev)\n");
> +	/* full-duplex, heartbeat disabled */
> +	writel(1 << 2, &fec->eth->x_cntrl);
> +	fec->rbd_index = 0;
> +
> +	/*
> +	 * Enable FEC-Lite controller
> +	 */
> +	writel(FEC_ECNTRL_ETHER_EN, &fec->eth->ecntrl);
> +
> +	miiphy_wait_aneg(edev);
> +	miiphy_speed(edev->name, 0);
> +	miiphy_duplex(edev->name, 0);
> +
> +	/*
> +	 * Enable SmartDMA receive task
> +	 */
> +	fec_rx_task_enable(fec);
> +
> +	udelay(100000);
> +	return 0;
> +}
> +
> +static int fec_init(struct eth_device *dev, bd_t* bd)
> +{
> +	static int once;
> +	uint32_t base;
> +	struct fec_priv *fec = (struct fec_priv *)dev->priv;
> +
> +	if (!once) {
> +		/*
> +		 * reserve memory for both buffer descriptor chains at once
> +		 * Datasheet forces the startaddress of each chain is 16 byte
> +		 * aligned
> +		 */
> +		base = (uint32_t)malloc((2 + FEC_RBD_NUM) *
> +				sizeof(struct fec_bd) + DB_ALIGNMENT);
> +		memset((void *)base, 0, (2 + FEC_RBD_NUM) *
> +				sizeof(struct fec_bd) + DB_ALIGNMENT);
> +		base += (DB_ALIGNMENT-1);
> +		base &= ~(DB_ALIGNMENT-1);
> +
> +		fec->rbd_base = (struct fec_bd *)base;
> +
> +		base += FEC_RBD_NUM * sizeof(struct fec_bd);
> +
> +		fec->tbd_base = (struct fec_bd *)base;
> +	}
>   
If it's possible that an SOC will someday exist with more than one 
controller this singleton stuff will have to go.  Do you really need it 
here?  Your 'halt' function should free the memory so that it's safe to 
call init() more than once.
<snip>
> sprintf(edev->name, "FEC ETHERNET");
>   
You have a very specific driver name.  Why make it generic here?
> +
> +	miiphy_register(edev->name, fec_miiphy_read, fec_miiphy_write);
> +
> +	eth_register(edev);
> +
> +	if ((NULL != tmp) && (12 <= strlen(tmp))) {
> +		int i;
> +		/* convert MAC from string to int */
> +		for (i = 0; i < 6; i++) {
> +			ethaddr[i] = tmp ? simple_strtoul(tmp, &end, 16) : 0;
> +			if (tmp)
> +				tmp = (*end) ? end + 1 : end;
> +		}
> +	} else if (fec_get_hwaddr(edev, ethaddr) == 0) {
> +		printf("got MAC address from EEPROM: %pM\n", ethaddr);
> +		setenv("ethaddr", (char *)ethaddr_str);
> +	}
> +	memcpy(edev->enetaddr, ethaddr, 6);
> +	fec_set_hwaddr(edev, ethaddr);
> +
> +	return 0;
> +}
> +
> +int fecimx27_initialize(bd_t *bd)
> +{
> +	int lout = 1;
> +	static int once;
> +
> +	if (!once) {
> +		debug("eth_init: fec_probe(bd)\n");
> +		lout = fec_probe(bd);
> +		once = 1;
> +	}
> +	return lout;
> +}
>   
I don't like this singleton stuff.  You're artificially limiting this 
driver to a single instance.
<snip>

hanks for your submission!
Ben

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [U-Boot] [PATCH 3/7] fec_imx27: driver for FEC ethernet controller on i.MX27
  2009-05-26  5:38   ` Ben Warren
@ 2009-06-07 23:08     ` Ilya Yanok
  2009-11-17  2:46     ` alfred steele
  1 sibling, 0 replies; 18+ messages in thread
From: Ilya Yanok @ 2009-06-07 23:08 UTC (permalink / raw)
  To: u-boot

Hi Ben,

thanks for the review.

Ben Warren wrote:
> Naive question: Is this FEC truly unique to the iMX27?  If not you
> should pick a more generic name.

Uh... I think the hardware is pretty the same as that is handled by
mcffec.c driver but merging won't be very easy...

Regards, Ilya.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [U-Boot] [PATCH 3/7] fec_imx27: driver for FEC ethernet controller on i.MX27
  2009-06-08  0:12 [U-Boot] [PATCH 0/7][v3] Support for LogicPD i.MX27-LITEKIT development board Ilya Yanok
@ 2009-06-08  0:12 ` Ilya Yanok
  0 siblings, 0 replies; 18+ messages in thread
From: Ilya Yanok @ 2009-06-08  0:12 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Ilya Yanok <yanok@emcraft.com>
---
 cpu/arm926ejs/mx27/generic.c |   10 +
 drivers/net/Makefile         |    1 +
 drivers/net/fec_imx27.c      |  713 ++++++++++++++++++++++++++++++++++++++++++
 drivers/net/fec_imx27.h      |  304 ++++++++++++++++++
 include/netdev.h             |    1 +
 5 files changed, 1029 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/fec_imx27.c
 create mode 100644 drivers/net/fec_imx27.h

diff --git a/cpu/arm926ejs/mx27/generic.c b/cpu/arm926ejs/mx27/generic.c
index eab54d8..b52f934 100644
--- a/cpu/arm926ejs/mx27/generic.c
+++ b/cpu/arm926ejs/mx27/generic.c
@@ -20,6 +20,7 @@
 
 #include <common.h>
 #include <div64.h>
+#include <netdev.h>
 #include <asm/io.h>
 #include <asm/arch/imx-regs.h>
 
@@ -159,6 +160,15 @@ int print_cpuinfo (void)
 }
 #endif
 
+int cpu_eth_init(bd_t *bis)
+{
+#if defined(CONFIG_FEC_IMX27)
+	return fecimx27_initialize(bis);
+#else
+	return 0;
+#endif
+}
+
 void imx_gpio_mode(int gpio_mode)
 {
 	struct gpio_regs *regs = (struct gpio_regs *)IMX_GPIO_BASE;
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index a360a50..8bbbd2b 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -37,6 +37,7 @@ COBJS-$(CONFIG_DNET) += dnet.o
 COBJS-$(CONFIG_E1000) += e1000.o
 COBJS-$(CONFIG_EEPRO100) += eepro100.o
 COBJS-$(CONFIG_ENC28J60) += enc28j60.o
+COBJS-$(CONFIG_FEC_IMX27) += fec_imx27.o
 COBJS-$(CONFIG_FSLDMAFEC) += fsl_mcdmafec.o mcfmii.o
 COBJS-$(CONFIG_GRETH) += greth.o
 COBJS-$(CONFIG_INCA_IP_SWITCH) += inca-ip_sw.o
diff --git a/drivers/net/fec_imx27.c b/drivers/net/fec_imx27.c
new file mode 100644
index 0000000..f26ae9e
--- /dev/null
+++ b/drivers/net/fec_imx27.c
@@ -0,0 +1,713 @@
+/*
+ * (C) Copyright 2009 Ilya Yanok, Emcraft Systems Ltd <yanok@emcraft.com>
+ * (C) Copyright 2008,2009 Eric Jarrige <eric.jarrige@armadeus.org>
+ * (C) Copyright 2008 Armadeus Systems nc
+ * (C) Copyright 2007 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
+ * (C) Copyright 2007 Pengutronix, Juergen Beisert <j.beisert@pengutronix.de>
+ *
+ * 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 <net.h>
+#include <miiphy.h>
+#include "fec_imx27.h"
+
+#include <asm/arch/clock.h>
+#include <asm/arch/imx-regs.h>
+#include <asm/io.h>
+#include <asm/errno.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifndef CONFIG_MII
+#error "CONFIG_MII has to be defined!"
+#endif
+
+#undef DEBUG
+
+struct nbuf {
+	uint8_t data[1500];	/**< actual data */
+	int length;		/**< actual length */
+	int used;		/**< buffer in use or not */
+	uint8_t head[16];	/**< MAC header(6 + 6 + 2) + 2(aligned) */
+};
+
+struct fec_priv gfec = {
+	.eth       = (struct ethernet_regs *)IMX_FEC_BASE,
+	.xcv_type  = MII100,
+	.rbd_base  = NULL,
+	.rbd_index = 0,
+	.tbd_base  = NULL,
+	.tbd_index = 0,
+	.bd        = NULL,
+};
+
+/*
+ * MII-interface related functions
+ */
+static int fec_miiphy_read(char *dev, uint8_t phyAddr, uint8_t regAddr,
+		uint16_t *retVal)
+{
+	struct eth_device *edev = eth_get_dev_by_name(dev);
+	struct fec_priv *fec = (struct fec_priv *)edev->priv;
+
+	uint32_t reg;		/* convenient holder for the PHY register */
+	uint32_t phy;		/* convenient holder for the PHY */
+	uint32_t start;
+
+	/*
+	 * reading from any PHY's register is done by properly
+	 * programming the FEC's MII data register.
+	 */
+	writel(FEC_IEVENT_MII, &fec->eth->ievent);
+	reg = regAddr << FEC_MII_DATA_RA_SHIFT;
+	phy = phyAddr << FEC_MII_DATA_PA_SHIFT;
+
+	writel(FEC_MII_DATA_ST | FEC_MII_DATA_OP_RD | FEC_MII_DATA_TA |
+			phy | reg, &fec->eth->mii_data);
+
+	/*
+	 * wait for the related interrupt
+	 */
+	start = get_timer_masked();
+	while (!(readl(&fec->eth->ievent) & FEC_IEVENT_MII)) {
+		if (get_timer(start) > (CONFIG_SYS_HZ / 1000)) {
+			printf("Read MDIO failed...\n");
+			return -1;
+		}
+	}
+
+	/*
+	 * clear mii interrupt bit
+	 */
+	writel(FEC_IEVENT_MII, &fec->eth->ievent);
+
+	/*
+	 * it's now safe to read the PHY's register
+	 */
+	*retVal = readl(&fec->eth->mii_data);
+	debug("fec_miiphy_read: phy: %02x reg:%02x val:%#x\n", phyAddr,
+			regAddr, *retVal);
+	return 0;
+}
+
+static int fec_miiphy_write(char *dev, uint8_t phyAddr, uint8_t regAddr,
+		uint16_t data)
+{
+	struct eth_device *edev = eth_get_dev_by_name(dev);
+	struct fec_priv *fec = (struct fec_priv *)edev->priv;
+
+	uint32_t reg;		/* convenient holder for the PHY register */
+	uint32_t phy;		/* convenient holder for the PHY */
+	uint32_t start;
+
+	reg = regAddr << FEC_MII_DATA_RA_SHIFT;
+	phy = phyAddr << FEC_MII_DATA_PA_SHIFT;
+
+	writel(FEC_MII_DATA_ST | FEC_MII_DATA_OP_WR |
+		FEC_MII_DATA_TA | phy | reg | data, &fec->eth->mii_data);
+
+	/*
+	 * wait for the MII interrupt
+	 */
+	start = get_timer_masked();
+	while (!(readl(&fec->eth->ievent) & FEC_IEVENT_MII)) {
+		if (get_timer(start) > (CONFIG_SYS_HZ / 1000)) {
+			printf("Write MDIO failed...\n");
+			return -1;
+		}
+	}
+
+	/*
+	 * clear MII interrupt bit
+	 */
+	writel(FEC_IEVENT_MII, &fec->eth->ievent);
+	debug("fec_miiphy_write: phy: %02x reg:%02x val:%#x\n", phyAddr,
+			regAddr, data);
+
+	return 0;
+}
+
+static int miiphy_restart_aneg(struct eth_device *dev)
+{
+	/*
+	 * Wake up from sleep if necessary
+	 * Reset PHY, then delay 300ns
+	 */
+	miiphy_write(dev->name, 0, PHY_MIPGSR, 0x00FF);
+	miiphy_write(dev->name, 0, PHY_BMCR, PHY_BMCR_RESET);
+	udelay(1000);
+
+	/*
+	 * Set the auto-negotiation advertisement register bits
+	 */
+	miiphy_write(dev->name, 0, PHY_ANAR, 0x1e0);
+	miiphy_write(dev->name, 0, PHY_BMCR, PHY_BMCR_AUTON | PHY_BMCR_RST_NEG);
+
+	return 0;
+}
+
+static int miiphy_wait_aneg(struct eth_device *dev)
+{
+	uint32_t start;
+	uint16_t status;
+
+	/*
+	 * Wait for AN completion
+	 */
+	start = get_timer_masked(); /* get_time_ns(); */
+	do {
+		if (get_timer(start) > (CONFIG_SYS_HZ * 5)) {
+			printf("%s: Autonegotiation timeout\n", dev->name);
+			return -1;
+		}
+
+		if (miiphy_read(dev->name, 0, PHY_BMSR, &status)) {
+			printf("%s: Autonegotiation failed. status: 0x%04x\n",
+					dev->name, status);
+			return -1;
+		}
+	} while (!(status & PHY_BMSR_LS));
+
+	return 0;
+}
+static int fec_rx_task_enable(struct fec_priv *fec)
+{
+	writel(1 << 24, &fec->eth->r_des_active);
+	return 0;
+}
+
+static int fec_rx_task_disable(struct fec_priv *fec)
+{
+	return 0;
+}
+
+static int fec_tx_task_enable(struct fec_priv *fec)
+{
+	writel(1 << 24, &fec->eth->x_des_active);
+	return 0;
+}
+
+static int fec_tx_task_disable(struct fec_priv *fec)
+{
+	return 0;
+}
+
+/**
+ * Initialize receive task's buffer descriptors
+ * @param[in] fec all we know about the device yet
+ * @param[in] count receive buffer count to be allocated
+ * @param[in] size size of each receive buffer
+ * @return 0 on success
+ *
+ * For this task we need additional memory for the data buffers. And each
+ * data buffer requires some alignment. Thy must be aligned to a specific
+ * boundary each (DB_DATA_ALIGNMENT).
+ */
+static int fec_rbd_init(struct fec_priv *fec, int count, int size)
+{
+	int ix;
+	uint32_t p = 0;
+
+	/* reserve data memory and consider alignment */
+	fec->rdb_ptr = malloc(size * count + DB_DATA_ALIGNMENT);
+	p = (uint32_t)fec->rdb_ptr;
+	if (!p) {
+		puts("fec_imx27: not enough malloc memory!\n");
+		return -ENOMEM;
+	}
+	memset((void *)p, 0, size * count + DB_DATA_ALIGNMENT);
+	p += DB_DATA_ALIGNMENT-1;
+	p &= ~(DB_DATA_ALIGNMENT-1);
+
+	for (ix = 0; ix < count; ix++) {
+		writel(p, &fec->rbd_base[ix].data_pointer);
+		p += size;
+		writew(FEC_RBD_EMPTY, &fec->rbd_base[ix].status);
+		writew(0, &fec->rbd_base[ix].data_length);
+	}
+	/*
+	 * mark the last RBD to close the ring
+	 */
+	writew(FEC_RBD_WRAP | FEC_RBD_EMPTY, &fec->rbd_base[ix - 1].status);
+	fec->rbd_index = 0;
+
+	return 0;
+}
+
+/**
+ * Initialize transmit task's buffer descriptors
+ * @param[in] fec all we know about the device yet
+ *
+ * Transmit buffers are created externally. We only have to init the BDs here.\n
+ * Note: There is a race condition in the hardware. When only one BD is in
+ * use it must be marked with the WRAP bit to use it for every transmitt.
+ * This bit in combination with the READY bit results into double transmit
+ * of each data buffer. It seems the state machine checks READY earlier then
+ * resetting it after the first transfer.
+ * Using two BDs solves this issue.
+ */
+static void fec_tbd_init(struct fec_priv *fec)
+{
+	writew(0x0000, &fec->tbd_base[0].status);
+	writew(FEC_TBD_WRAP, &fec->tbd_base[1].status);
+	fec->tbd_index = 0;
+}
+
+/**
+ * Mark the given read buffer descriptor as free
+ * @param[in] last 1 if this is the last buffer descriptor in the chain, else 0
+ * @param[in] pRbd buffer descriptor to mark free again
+ */
+static void fec_rbd_clean(int last, struct fec_bd *pRbd)
+{
+	/*
+	 * Reset buffer descriptor as empty
+	 */
+	if (last)
+		writew(FEC_RBD_WRAP | FEC_RBD_EMPTY, &pRbd->status);
+	else
+		writew(FEC_RBD_EMPTY, &pRbd->status);
+	/*
+	 * no data in it
+	 */
+	writew(0, &pRbd->data_length);
+}
+
+static int fec_get_hwaddr(struct eth_device *dev, unsigned char *mac)
+{
+	struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE;
+	int i;
+
+	for (i = 0; i < 6; i++)
+		mac[6-1-i] = readl(&iim->iim_bank_area0[IIM0_MAC + i]);
+
+	return is_valid_ether_addr(mac);
+}
+
+static int fec_set_hwaddr(struct eth_device *dev, unsigned char *mac)
+{
+	struct fec_priv *fec = (struct fec_priv *)dev->priv;
+
+	writel(0, &fec->eth->iaddr1);
+	writel(0, &fec->eth->iaddr2);
+	writel(0, &fec->eth->gaddr1);
+	writel(0, &fec->eth->gaddr2);
+
+	/*
+	 * Set physical address
+	 */
+	writel((mac[0] << 24) + (mac[1] << 16) + (mac[2] << 8) + mac[3],
+			&fec->eth->paddr1);
+	writel((mac[4] << 24) + (mac[5] << 16) + 0x8808, &fec->eth->paddr2);
+
+	return 0;
+}
+
+/**
+ * Start the FEC engine
+ * @param[in] dev Our device to handle
+ */
+static int fec_open(struct eth_device *edev)
+{
+	struct fec_priv *fec = (struct fec_priv *)edev->priv;
+
+	debug("fec_open: fec_open(dev)\n");
+	/* full-duplex, heartbeat disabled */
+	writel(1 << 2, &fec->eth->x_cntrl);
+	fec->rbd_index = 0;
+
+	/*
+	 * Enable FEC-Lite controller
+	 */
+	writel(FEC_ECNTRL_ETHER_EN, &fec->eth->ecntrl);
+
+	miiphy_wait_aneg(edev);
+	miiphy_speed(edev->name, 0);
+	miiphy_duplex(edev->name, 0);
+
+	/*
+	 * Enable SmartDMA receive task
+	 */
+	fec_rx_task_enable(fec);
+
+	udelay(100000);
+	return 0;
+}
+
+static int fec_init(struct eth_device *dev, bd_t* bd)
+{
+	uint32_t base;
+	struct fec_priv *fec = (struct fec_priv *)dev->priv;
+
+	/*
+	 * reserve memory for both buffer descriptor chains at once
+	 * Datasheet forces the startaddress of each chain is 16 byte
+	 * aligned
+	 */
+	fec->base_ptr = malloc((2 + FEC_RBD_NUM) *
+			sizeof(struct fec_bd) + DB_ALIGNMENT);
+	base = (uint32_t)fec->base_ptr;
+	if (!base) {
+		puts("fec_imx27: not enough malloc memory!\n");
+		return -ENOMEM;
+	}
+	memset((void *)base, 0, (2 + FEC_RBD_NUM) *
+			sizeof(struct fec_bd) + DB_ALIGNMENT);
+	base += (DB_ALIGNMENT-1);
+	base &= ~(DB_ALIGNMENT-1);
+
+	fec->rbd_base = (struct fec_bd *)base;
+
+	base += FEC_RBD_NUM * sizeof(struct fec_bd);
+
+	fec->tbd_base = (struct fec_bd *)base;
+
+	/*
+	 * Set interrupt mask register
+	 */
+	writel(0x00000000, &fec->eth->imask);
+
+	/*
+	 * Clear FEC-Lite interrupt event register(IEVENT)
+	 */
+	writel(0xffffffff, &fec->eth->ievent);
+
+
+	/*
+	 * Set FEC-Lite receive control register(R_CNTRL):
+	 */
+	if (fec->xcv_type == SEVENWIRE) {
+		/*
+		 * Frame length=1518; 7-wire mode
+		 */
+		writel(0x05ee0020, &fec->eth->r_cntrl);	/* FIXME 0x05ee0000 */
+	} else {
+		/*
+		 * Frame length=1518; MII mode;
+		 */
+		writel(0x05ee0024, &fec->eth->r_cntrl);	/* FIXME 0x05ee0004 */
+		/*
+		 * Set MII_SPEED = (1/(mii_speed * 2)) * System Clock
+		 * and do not drop the Preamble.
+		 */
+		writel((((imx_get_ahbclk() / 1000000) + 2) / 5) << 1,
+				&fec->eth->mii_speed);
+		debug("fec_init: mii_speed %#lx\n",
+				(((imx_get_ahbclk() / 1000000) + 2) / 5) << 1);
+	}
+	/*
+	 * Set Opcode/Pause Duration Register
+	 */
+	writel(0x00010020, &fec->eth->op_pause);	/* FIXME 0xffff0020; */
+	writel(0x2, &fec->eth->x_wmrk);
+	/*
+	 * Set multicast address filter
+	 */
+	writel(0x00000000, &fec->eth->gaddr1);
+	writel(0x00000000, &fec->eth->gaddr2);
+
+
+	/* clear MIB RAM */
+	long *mib_ptr = (long *)(IMX_FEC_BASE + 0x200);
+	while (mib_ptr <= (long *)(IMX_FEC_BASE + 0x2FC))
+		*mib_ptr++ = 0;
+
+	/* FIFO receive start register */
+	writel(0x520, &fec->eth->r_fstart);
+
+	/* size and address of each buffer */
+	writel(FEC_MAX_PKT_SIZE, &fec->eth->emrbr);
+	writel((uint32_t)fec->tbd_base, &fec->eth->etdsr);
+	writel((uint32_t)fec->rbd_base, &fec->eth->erdsr);
+
+	/*
+	 * Initialize RxBD/TxBD rings
+	 */
+	if (fec_rbd_init(fec, FEC_RBD_NUM, FEC_MAX_PKT_SIZE) < 0) {
+		free(fec->base_ptr);
+		return -ENOMEM;
+	}
+	fec_tbd_init(fec);
+
+
+	if (fec->xcv_type != SEVENWIRE)
+		miiphy_restart_aneg(dev);
+
+	fec_open(dev);
+	return 0;
+}
+
+/**
+ * Halt the FEC engine
+ * @param[in] dev Our device to handle
+ */
+static void fec_halt(struct eth_device *dev)
+{
+	struct fec_priv *fec = &gfec;
+	int counter = 0xffff;
+
+	/*
+	 * issue graceful stop command to the FEC transmitter if necessary
+	 */
+	writel(FEC_ECNTRL_RESET | readl(&fec->eth->x_cntrl),
+			&fec->eth->x_cntrl);
+
+	debug("eth_halt: wait for stop regs\n");
+	/*
+	 * wait for graceful stop to register
+	 */
+	while ((counter--) && (!(readl(&fec->eth->ievent) & FEC_IEVENT_GRA)))
+		;	/* FIXME ensure time */
+
+	/*
+	 * Disable SmartDMA tasks
+	 */
+	fec_tx_task_disable(fec);
+	fec_rx_task_disable(fec);
+
+	/*
+	 * Disable the Ethernet Controller
+	 * Note: this will also reset the BD index counter!
+	 */
+	writel(0, &fec->eth->ecntrl);
+	fec->rbd_index = 0;
+	fec->tbd_index = 0;
+	free(fec->rdb_ptr);
+	free(fec->base_ptr);
+	debug("eth_halt: done\n");
+}
+
+/**
+ * Transmit one frame
+ * @param[in] dev Our ethernet device to handle
+ * @param[in] packet Pointer to the data to be transmitted
+ * @param[in] length Data count in bytes
+ * @return 0 on success
+ */
+static int fec_send(struct eth_device *dev, volatile void* packet, int length)
+{
+	unsigned int status;
+
+	/*
+	 * This routine transmits one frame.  This routine only accepts
+	 * 6-byte Ethernet addresses.
+	 */
+	struct fec_priv *fec = (struct fec_priv *)dev->priv;
+
+	/*
+	 * Check for valid length of data.
+	 */
+	if ((length > 1500) || (length <= 0)) {
+		printf("Payload (%d) to large!\n", length);
+		return -1;
+	}
+
+	/*
+	 * Setup the transmit buffer
+	 * Note: We are always using the first buffer for transmission,
+	 * the second will be empty and only used to stop the DMA engine
+	 */
+	writew(length, &fec->tbd_base[fec->tbd_index].data_length);
+	writel((uint32_t)packet, &fec->tbd_base[fec->tbd_index].data_pointer);
+	/*
+	 * update BD's status now
+	 * This block:
+	 * - is always the last in a chain (means no chain)
+	 * - should transmitt the CRC
+	 * - might be the last BD in the list, so the address counter should
+	 *   wrap (-> keep the WRAP flag)
+	 */
+	status = readw(&fec->tbd_base[fec->tbd_index].status) & FEC_TBD_WRAP;
+	status |= FEC_TBD_LAST | FEC_TBD_TC | FEC_TBD_READY;
+	writew(status, &fec->tbd_base[fec->tbd_index].status);
+
+	/*
+	 * Enable SmartDMA transmit task
+	 */
+	fec_tx_task_enable(fec);
+
+	/*
+	 * wait until frame is sent .
+	 */
+	while (readw(&fec->tbd_base[fec->tbd_index].status) & FEC_TBD_READY) {
+		/* FIXME: Timeout */
+	}
+	debug("fec_send: status 0x%x index %d\n",
+			readw(&fec->tbd_base[fec->tbd_index].status),
+			fec->tbd_index);
+	/* for next transmission use the other buffer */
+	if (fec->tbd_index)
+		fec->tbd_index = 0;
+	else
+		fec->tbd_index = 1;
+
+	return 0;
+}
+
+/**
+ * Pull one frame from the card
+ * @param[in] dev Our ethernet device to handle
+ * @return Length of packet read
+ */
+static int fec_recv(struct eth_device *dev)
+{
+	struct fec_priv *fec = (struct fec_priv *)dev->priv;
+	struct fec_bd *rbd = &fec->rbd_base[fec->rbd_index];
+	unsigned long ievent;
+	int frame_length, len = 0;
+	struct nbuf *frame;
+	uint16_t bd_status;
+	uchar buff[FEC_MAX_PKT_SIZE];
+
+	/*
+	 * Check if any critical events have happened
+	 */
+	ievent = readl(&fec->eth->ievent);
+	writel(ievent, &fec->eth->ievent);
+	debug("fec_recv: ievent 0x%x\n", ievent);
+	if (ievent & FEC_IEVENT_BABR) {
+		fec_halt(dev);
+		fec_init(dev, fec->bd);
+		printf("some error: 0x%08lx\n", ievent);
+		return 0;
+	}
+	if (ievent & FEC_IEVENT_HBERR) {
+		/* Heartbeat error */
+		writel(0x00000001 | readl(&fec->eth->x_cntrl),
+				&fec->eth->x_cntrl);
+	}
+	if (ievent & FEC_IEVENT_GRA) {
+		/* Graceful stop complete */
+		if (readl(&fec->eth->x_cntrl) & 0x00000001) {
+			fec_halt(dev);
+			writel(~0x00000001 & readl(&fec->eth->x_cntrl),
+					&fec->eth->x_cntrl);
+			fec_init(dev, fec->bd);
+		}
+	}
+
+	/*
+	 * ensure reading the right buffer status
+	 */
+	bd_status = readw(&rbd->status);
+	debug("fec_recv: status 0x%x\n", bd_status);
+
+	if (!(bd_status & FEC_RBD_EMPTY)) {
+		if ((bd_status & FEC_RBD_LAST) && !(bd_status & FEC_RBD_ERR) &&
+			((readw(&rbd->data_length) - 4) > 14)) {
+			/*
+			 * Get buffer address and size
+			 */
+			frame = (struct nbuf *)readl(&rbd->data_pointer);
+			frame_length = readw(&rbd->data_length) - 4;
+			/*
+			 *  Fill the buffer and pass it to upper layers
+			 */
+			memcpy(buff, frame->data, frame_length);
+			NetReceive(buff, frame_length);
+			len = frame_length;
+		} else {
+			if (bd_status & FEC_RBD_ERR)
+				printf("error frame: 0x%08lx 0x%08x\n",
+						(ulong)rbd->data_pointer,
+						bd_status);
+		}
+		/*
+		 * free the current buffer, restart the engine
+		 * and move forward to the next buffer
+		 */
+		fec_rbd_clean(fec->rbd_index == (FEC_RBD_NUM - 1) ? 1 : 0, rbd);
+		fec_rx_task_enable(fec);
+		fec->rbd_index = (fec->rbd_index + 1) % FEC_RBD_NUM;
+	}
+	debug("fec_recv: stop\n");
+
+	return len;
+}
+
+static int fec_probe(bd_t *bd)
+{
+	struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE;
+	struct eth_device *edev;
+	struct fec_priv *fec = &gfec;
+	unsigned char ethaddr_str[20];
+	unsigned char ethaddr[6];
+	char *tmp = getenv("ethaddr");
+	char *end;
+
+	/* enable FEC clock */
+	writel(readl(&pll->pccr1) | PCCR1_HCLK_FEC, &pll->pccr1);
+	writel(readl(&pll->pccr0) | PCCR0_FEC_EN, &pll->pccr0);
+
+	/* create and fill edev struct */
+	edev = (struct eth_device *)malloc(sizeof(struct eth_device));
+	if (!edev) {
+		puts("fec_imx27: not enough malloc memory!\n");
+		return -ENOMEM;
+	}
+	edev->priv = fec;
+	edev->init = fec_init;
+	edev->send = fec_send;
+	edev->recv = fec_recv;
+	edev->halt = fec_halt;
+
+	fec->eth = (struct ethernet_regs *)IMX_FEC_BASE;
+	fec->bd = bd;
+
+	/* Reset chip. */
+	writel(FEC_ECNTRL_RESET, &fec->eth->ecntrl);
+	while (readl(&fec->eth->ecntrl) & 1)
+		udelay(10);
+
+	fec->xcv_type = MII100;
+
+	sprintf(edev->name, "FEC_i.MX27");
+
+	miiphy_register(edev->name, fec_miiphy_read, fec_miiphy_write);
+
+	eth_register(edev);
+
+	if ((NULL != tmp) && (12 <= strlen(tmp))) {
+		int i;
+		/* convert MAC from string to int */
+		for (i = 0; i < 6; i++) {
+			ethaddr[i] = tmp ? simple_strtoul(tmp, &end, 16) : 0;
+			if (tmp)
+				tmp = (*end) ? end + 1 : end;
+		}
+	} else if (fec_get_hwaddr(edev, ethaddr) == 0) {
+		printf("got MAC address from EEPROM: %pM\n", ethaddr);
+		setenv("ethaddr", (char *)ethaddr_str);
+	}
+	memcpy(edev->enetaddr, ethaddr, 6);
+	fec_set_hwaddr(edev, ethaddr);
+
+	return 0;
+}
+
+int fecimx27_initialize(bd_t *bd)
+{
+	int lout = 1;
+
+	debug("eth_init: fec_probe(bd)\n");
+	lout = fec_probe(bd);
+
+	return lout;
+}
+
diff --git a/drivers/net/fec_imx27.h b/drivers/net/fec_imx27.h
new file mode 100644
index 0000000..57e5427
--- /dev/null
+++ b/drivers/net/fec_imx27.h
@@ -0,0 +1,304 @@
+/*
+ * (C) Copyright 2009 Ilya Yanok, Emcraft Systems Ltd <yanok@emcraft.com>
+ * (C) Copyright 2008 Armadeus Systems, nc
+ * (C) Copyright 2008 Eric Jarrige <eric.jarrige@armadeus.org>
+ * (C) Copyright 2007 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
+ * (C) Copyright 2007 Pengutronix, Juergen Beisert <j.beisert@pengutronix.de>
+ *
+ * (C) Copyright 2003
+ * Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+ *
+ * This file is based on mpc4200fec.h
+ * (C) Copyright Motorola, Inc., 2000
+ *
+ * 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 __IMX27_FEC_H
+#define __IMX27_FEC_H
+
+/**
+ * Layout description of the FEC
+ */
+struct ethernet_regs {
+
+/* [10:2]addr = 00 */
+
+/*  Control and status Registers (offset 000-1FF) */
+
+	uint32_t res0[1];		/* MBAR_ETH + 0x000 */
+	uint32_t ievent;		/* MBAR_ETH + 0x004 */
+	uint32_t imask;			/* MBAR_ETH + 0x008 */
+
+	uint32_t res1[1];		/* MBAR_ETH + 0x00C */
+	uint32_t r_des_active;		/* MBAR_ETH + 0x010 */
+	uint32_t x_des_active;		/* MBAR_ETH + 0x014 */
+	uint32_t res2[3];		/* MBAR_ETH + 0x018-20 */
+	uint32_t ecntrl;		/* MBAR_ETH + 0x024 */
+
+	uint32_t res3[6];		/* MBAR_ETH + 0x028-03C */
+	uint32_t mii_data;		/* MBAR_ETH + 0x040 */
+	uint32_t mii_speed;		/* MBAR_ETH + 0x044 */
+	uint32_t res4[7];		/* MBAR_ETH + 0x048-60 */
+	uint32_t mib_control;		/* MBAR_ETH + 0x064 */
+
+	uint32_t res5[7];		/* MBAR_ETH + 0x068-80 */
+	uint32_t r_cntrl;		/* MBAR_ETH + 0x084 */
+	uint32_t res6[15];		/* MBAR_ETH + 0x088-C0 */
+	uint32_t x_cntrl;		/* MBAR_ETH + 0x0C4 */
+	uint32_t res7[7];		/* MBAR_ETH + 0x0C8-E0 */
+	uint32_t paddr1;		/* MBAR_ETH + 0x0E4 */
+	uint32_t paddr2;		/* MBAR_ETH + 0x0E8 */
+	uint32_t op_pause;		/* MBAR_ETH + 0x0EC */
+
+	uint32_t res8[10];		/* MBAR_ETH + 0x0F0-114 */
+	uint32_t iaddr1;		/* MBAR_ETH + 0x118 */
+	uint32_t iaddr2;		/* MBAR_ETH + 0x11C */
+	uint32_t gaddr1;		/* MBAR_ETH + 0x120 */
+	uint32_t gaddr2;		/* MBAR_ETH + 0x124 */
+	uint32_t res9[7];		/* MBAR_ETH + 0x128-140 */
+
+	uint32_t x_wmrk;		/* MBAR_ETH + 0x144 */
+	uint32_t res10[1];		/* MBAR_ETH + 0x148 */
+	uint32_t r_bound;		/* MBAR_ETH + 0x14C */
+	uint32_t r_fstart;		/* MBAR_ETH + 0x150 */
+	uint32_t res11[11];		/* MBAR_ETH + 0x154-17C */
+	uint32_t erdsr;			/* MBAR_ETH + 0x180 */
+	uint32_t etdsr;			/* MBAR_ETH + 0x184 */
+	uint32_t emrbr;			/* MBAR_ETH + 0x188 */
+	uint32_t res12[29];		/* MBAR_ETH + 0x18C-1FC */
+
+/*  MIB COUNTERS (Offset 200-2FF) */
+
+	uint32_t rmon_t_drop;		/* MBAR_ETH + 0x200 */
+	uint32_t rmon_t_packets;	/* MBAR_ETH + 0x204 */
+	uint32_t rmon_t_bc_pkt;		/* MBAR_ETH + 0x208 */
+	uint32_t rmon_t_mc_pkt;		/* MBAR_ETH + 0x20C */
+	uint32_t rmon_t_crc_align;	/* MBAR_ETH + 0x210 */
+	uint32_t rmon_t_undersize;	/* MBAR_ETH + 0x214 */
+	uint32_t rmon_t_oversize;	/* MBAR_ETH + 0x218 */
+	uint32_t rmon_t_frag;		/* MBAR_ETH + 0x21C */
+	uint32_t rmon_t_jab;		/* MBAR_ETH + 0x220 */
+	uint32_t rmon_t_col;		/* MBAR_ETH + 0x224 */
+	uint32_t rmon_t_p64;		/* MBAR_ETH + 0x228 */
+	uint32_t rmon_t_p65to127;	/* MBAR_ETH + 0x22C */
+	uint32_t rmon_t_p128to255;	/* MBAR_ETH + 0x230 */
+	uint32_t rmon_t_p256to511;	/* MBAR_ETH + 0x234 */
+	uint32_t rmon_t_p512to1023;	/* MBAR_ETH + 0x238 */
+	uint32_t rmon_t_p1024to2047;	/* MBAR_ETH + 0x23C */
+	uint32_t rmon_t_p_gte2048;	/* MBAR_ETH + 0x240 */
+	uint32_t rmon_t_octets;		/* MBAR_ETH + 0x244 */
+	uint32_t ieee_t_drop;		/* MBAR_ETH + 0x248 */
+	uint32_t ieee_t_frame_ok;	/* MBAR_ETH + 0x24C */
+	uint32_t ieee_t_1col;		/* MBAR_ETH + 0x250 */
+	uint32_t ieee_t_mcol;		/* MBAR_ETH + 0x254 */
+	uint32_t ieee_t_def;		/* MBAR_ETH + 0x258 */
+	uint32_t ieee_t_lcol;		/* MBAR_ETH + 0x25C */
+	uint32_t ieee_t_excol;		/* MBAR_ETH + 0x260 */
+	uint32_t ieee_t_macerr;		/* MBAR_ETH + 0x264 */
+	uint32_t ieee_t_cserr;		/* MBAR_ETH + 0x268 */
+	uint32_t ieee_t_sqe;		/* MBAR_ETH + 0x26C */
+	uint32_t t_fdxfc;		/* MBAR_ETH + 0x270 */
+	uint32_t ieee_t_octets_ok;	/* MBAR_ETH + 0x274 */
+
+	uint32_t res13[2];		/* MBAR_ETH + 0x278-27C */
+	uint32_t rmon_r_drop;		/* MBAR_ETH + 0x280 */
+	uint32_t rmon_r_packets;	/* MBAR_ETH + 0x284 */
+	uint32_t rmon_r_bc_pkt;		/* MBAR_ETH + 0x288 */
+	uint32_t rmon_r_mc_pkt;		/* MBAR_ETH + 0x28C */
+	uint32_t rmon_r_crc_align;	/* MBAR_ETH + 0x290 */
+	uint32_t rmon_r_undersize;	/* MBAR_ETH + 0x294 */
+	uint32_t rmon_r_oversize;	/* MBAR_ETH + 0x298 */
+	uint32_t rmon_r_frag;		/* MBAR_ETH + 0x29C */
+	uint32_t rmon_r_jab;		/* MBAR_ETH + 0x2A0 */
+
+	uint32_t rmon_r_resvd_0;	/* MBAR_ETH + 0x2A4 */
+
+	uint32_t rmon_r_p64;		/* MBAR_ETH + 0x2A8 */
+	uint32_t rmon_r_p65to127;	/* MBAR_ETH + 0x2AC */
+	uint32_t rmon_r_p128to255;	/* MBAR_ETH + 0x2B0 */
+	uint32_t rmon_r_p256to511;	/* MBAR_ETH + 0x2B4 */
+	uint32_t rmon_r_p512to1023;	/* MBAR_ETH + 0x2B8 */
+	uint32_t rmon_r_p1024to2047;	/* MBAR_ETH + 0x2BC */
+	uint32_t rmon_r_p_gte2048;	/* MBAR_ETH + 0x2C0 */
+	uint32_t rmon_r_octets;		/* MBAR_ETH + 0x2C4 */
+	uint32_t ieee_r_drop;		/* MBAR_ETH + 0x2C8 */
+	uint32_t ieee_r_frame_ok;	/* MBAR_ETH + 0x2CC */
+	uint32_t ieee_r_crc;		/* MBAR_ETH + 0x2D0 */
+	uint32_t ieee_r_align;		/* MBAR_ETH + 0x2D4 */
+	uint32_t r_macerr;		/* MBAR_ETH + 0x2D8 */
+	uint32_t r_fdxfc;		/* MBAR_ETH + 0x2DC */
+	uint32_t ieee_r_octets_ok;	/* MBAR_ETH + 0x2E0 */
+
+	uint32_t res14[6];		/* MBAR_ETH + 0x2E4-2FC */
+
+	uint32_t res15[64];		/* MBAR_ETH + 0x300-3FF */
+};
+
+#define FEC_IEVENT_HBERR		0x80000000
+#define FEC_IEVENT_BABR			0x40000000
+#define FEC_IEVENT_BABT			0x20000000
+#define FEC_IEVENT_GRA			0x10000000
+#define FEC_IEVENT_TXF			0x08000000
+#define FEC_IEVENT_TXB			0x04000000
+#define FEC_IEVENT_RXF			0x02000000
+#define FEC_IEVENT_RXB			0x01000000
+#define FEC_IEVENT_MII			0x00800000
+#define FEC_IEVENT_EBERR		0x00400000
+#define FEC_IEVENT_LC			0x00200000
+#define FEC_IEVENT_RL			0x00100000
+#define FEC_IEVENT_UN			0x00080000
+
+#define FEC_IMASK_HBERR			0x80000000
+#define FEC_IMASK_BABR			0x40000000
+#define FEC_IMASKT_BABT			0x20000000
+#define FEC_IMASK_GRA			0x10000000
+#define FEC_IMASKT_TXF			0x08000000
+#define FEC_IMASK_TXB			0x04000000
+#define FEC_IMASKT_RXF			0x02000000
+#define FEC_IMASK_RXB			0x01000000
+#define FEC_IMASK_MII			0x00800000
+#define FEC_IMASK_EBERR			0x00400000
+#define FEC_IMASK_LC			0x00200000
+#define FEC_IMASKT_RL			0x00100000
+#define FEC_IMASK_UN			0x00080000
+
+
+#define FEC_RCNTRL_MAX_FL_SHIFT		16
+#define FEC_RCNTRL_LOOP			0x00000001
+#define FEC_RCNTRL_DRT			0x00000002
+#define FEC_RCNTRL_MII_MODE		0x00000004
+#define FEC_RCNTRL_PROM			0x00000008
+#define FEC_RCNTRL_BC_REJ		0x00000010
+#define FEC_RCNTRL_FCE			0x00000020
+
+#define FEC_TCNTRL_GTS			0x00000001
+#define FEC_TCNTRL_HBC			0x00000002
+#define FEC_TCNTRL_FDEN			0x00000004
+#define FEC_TCNTRL_TFC_PAUSE		0x00000008
+#define FEC_TCNTRL_RFC_PAUSE		0x00000010
+
+#define FEC_ECNTRL_RESET		0x00000001	/* reset the FEC */
+#define FEC_ECNTRL_ETHER_EN		0x00000002	/* enable the FEC */
+
+/**
+ * @brief Descriptor buffer alignment
+ *
+ * i.MX27 requires a 16 byte alignment (but for the first element only)
+ */
+#define DB_ALIGNMENT		16
+
+/**
+ * @brief Data buffer alignment
+ *
+ * i.MX27 requires a four byte alignment for transmit and 16 bits
+ * alignment for receive so take 16
+ * Note: Valid for member data_pointer in struct buffer_descriptor
+ */
+#define DB_DATA_ALIGNMENT	16
+
+/**
+ * @brief Receive & Transmit Buffer Descriptor definitions
+ *
+ * Note: The first BD must be aligned (see DB_ALIGNMENT)
+ */
+struct fec_bd {
+	uint16_t data_length;		/* payload's length in bytes */
+	uint16_t status;		/* BD's staus (see datasheet) */
+	uint32_t data_pointer;		/* payload's buffer address */
+};
+
+/**
+ * Supported phy types on this platform
+ */
+enum xceiver_type {
+	SEVENWIRE,	/* 7-wire       */
+	MII10,		/* MII 10Mbps   */
+	MII100		/* MII 100Mbps  */
+};
+
+/**
+ * @brief i.MX27-FEC private structure
+ */
+struct fec_priv {
+	struct ethernet_regs *eth;	/* pointer to register'S base */
+	enum xceiver_type xcv_type;	/* transceiver type */
+	struct fec_bd *rbd_base;	/* RBD ring */
+	int rbd_index;			/* next receive BD to read */
+	struct fec_bd *tbd_base;	/* TBD ring */
+	int tbd_index;			/* next transmit BD to write */
+	bd_t *bd;
+	void *rdb_ptr;
+	void *base_ptr;
+};
+
+/**
+ * @brief Numbers of buffer descriptors for receiving
+ *
+ * The number defines the stocked memory buffers for the receiving task.
+ * Larger values makes no sense in this limited environment.
+ */
+#define FEC_RBD_NUM		64
+
+/**
+ * @brief Define the ethernet packet size limit in memory
+ *
+ * Note: Do not shrink this number. This will force the FEC to spread larger
+ * frames in more than one BD. This is nothing to worry about, but the current
+ * driver can't handle it.
+ */
+#define FEC_MAX_PKT_SIZE	1536
+
+/* Receive BD status bits */
+#define FEC_RBD_EMPTY	0x8000	/* Receive BD status: Buffer is empty */
+#define FEC_RBD_WRAP	0x2000	/* Receive BD status: Last BD in ring */
+/* Receive BD status: Buffer is last in frame (useless here!) */
+#define FEC_RBD_LAST	0x0800
+#define FEC_RBD_MISS	0x0100	/* Receive BD status: Miss bit for prom mode */
+/* Receive BD status: The received frame is broadcast frame */
+#define FEC_RBD_BC	0x0080
+/* Receive BD status: The received frame is multicast frame */
+#define FEC_RBD_MC	0x0040
+#define FEC_RBD_LG	0x0020	/* Receive BD status: Frame length violation */
+#define FEC_RBD_NO	0x0010	/* Receive BD status: Nonoctet align frame */
+#define FEC_RBD_CR	0x0004	/* Receive BD status: CRC error */
+#define FEC_RBD_OV	0x0002	/* Receive BD status: Receive FIFO overrun */
+#define FEC_RBD_TR	0x0001	/* Receive BD status: Frame is truncated */
+#define FEC_RBD_ERR	(FEC_RBD_LG | FEC_RBD_NO | FEC_RBD_CR | \
+			FEC_RBD_OV | FEC_RBD_TR)
+
+/* Transmit BD status bits */
+#define FEC_TBD_READY	0x8000	/* Tansmit BD status: Buffer is ready */
+#define FEC_TBD_WRAP	0x2000	/* Tansmit BD status: Mark as last BD in ring */
+#define FEC_TBD_LAST	0x0800	/* Tansmit BD status: Buffer is last in frame */
+#define FEC_TBD_TC	0x0400	/* Tansmit BD status: Transmit the CRC */
+#define FEC_TBD_ABC	0x0200	/* Tansmit BD status: Append bad CRC */
+
+/* MII-related definitios */
+#define FEC_MII_DATA_ST		0x40000000	/* Start of frame delimiter */
+#define FEC_MII_DATA_OP_RD	0x20000000	/* Perform a read operation */
+#define FEC_MII_DATA_OP_WR	0x10000000	/* Perform a write operation */
+#define FEC_MII_DATA_PA_MSK	0x0f800000	/* PHY Address field mask */
+#define FEC_MII_DATA_RA_MSK	0x007c0000	/* PHY Register field mask */
+#define FEC_MII_DATA_TA		0x00020000	/* Turnaround */
+#define FEC_MII_DATA_DATAMSK	0x0000ffff	/* PHY data field */
+
+#define FEC_MII_DATA_RA_SHIFT	18	/* MII Register address bits */
+#define FEC_MII_DATA_PA_SHIFT	23	/* MII PHY address bits */
+
+#endif	/* __IMX27_FEC_H */
diff --git a/include/netdev.h b/include/netdev.h
index 63cf730..2d999ad 100644
--- a/include/netdev.h
+++ b/include/netdev.h
@@ -49,6 +49,7 @@ int e1000_initialize(bd_t *bis);
 int eepro100_initialize(bd_t *bis);
 int eth_3com_initialize (bd_t * bis);
 int fec_initialize (bd_t *bis);
+int fecimx27_initialize (bd_t *bis);
 int greth_initialize(bd_t *bis);
 void gt6426x_eth_initialize(bd_t *bis);
 int inca_switch_initialize(bd_t *bis);
-- 
1.6.0.6

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [U-Boot] [PATCH 3/7] fec_imx27: driver for FEC ethernet controller on i.MX27
@ 2009-06-08  2:15 Fabio Estevam
  2009-06-08 13:29 ` Ilya Yanok
  0 siblings, 1 reply; 18+ messages in thread
From: Fabio Estevam @ 2009-06-08  2:15 UTC (permalink / raw)
  To: u-boot




--- On Sun, 6/7/09, Ilya Yanok <yanok@emcraft.com> wrote:

> From: Ilya Yanok <yanok@emcraft.com>
> Subject: Re: [U-Boot] [PATCH 3/7] fec_imx27: driver for FEC ethernet controller on i.MX27
> To: "Ben Warren" <biggerbadderben@gmail.com>
> Cc: u-boot at lists.denx.de
> Date: Sunday, June 7, 2009, 8:08 PM
> Hi Ben,
> 
> thanks for the review.
> 
> Ben Warren wrote:
> > Naive question: Is this FEC truly unique to the
> iMX27?? If not you
> > should pick a more generic name.
> 
> Uh... I think the hardware is pretty the same as that is
> handled by
> mcffec.c driver but merging won't be very easy...

There are other i.MX processors with FEC. As Ben pointed out I also think it would be better if you could use a more generic name for the FEC driver (fec_mxc for example, if the merge with the Coldfire driver is not easy)

Regards,

Fabio Estevam


      

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [U-Boot] [PATCH 3/7] fec_imx27: driver for FEC ethernet controller on i.MX27
  2009-06-08  2:15 [U-Boot] [PATCH 3/7] fec_imx27: driver for FEC ethernet controller on i.MX27 Fabio Estevam
@ 2009-06-08 13:29 ` Ilya Yanok
  0 siblings, 0 replies; 18+ messages in thread
From: Ilya Yanok @ 2009-06-08 13:29 UTC (permalink / raw)
  To: u-boot

Hi Fabio,

Fabio Estevam wrote:
>> Uh... I think the hardware is pretty the same as that is
>> handled by
>> mcffec.c driver but merging won't be very easy...
>>     
>
> There are other i.MX processors with FEC.

Uh... I didn't know that... As far as I can see Linux driver supports
only i.MX27...

Regards, Ilya.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [U-Boot] [PATCH 3/7] fec_imx27: driver for FEC ethernet controller on i.MX27
@ 2009-06-08 21:08 Fabio Estevam
  0 siblings, 0 replies; 18+ messages in thread
From: Fabio Estevam @ 2009-06-08 21:08 UTC (permalink / raw)
  To: u-boot


Hi Ilya,

--- On Mon, 6/8/09, Ilya Yanok <yanok@emcraft.com> wrote:

> > There are other i.MX processors with FEC.
> 
> Uh... I didn't know that... As far as I can see Linux
> driver supports
> only i.MX27...

Yes, only MX27 so far. MX35 also has a FEC.

I sent this patch to the netdev list in order to add MX35 FEC support:
http://patchwork.ozlabs.org/patch/27736/

Regards,

Fabio Estevam


      

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [U-Boot] [PATCH 3/7] fec_imx27: driver for FEC ethernet controller on i.MX27
  2009-05-19 23:55 ` [U-Boot] [PATCH 3/7] fec_imx27: driver for FEC ethernet controller on i.MX27 Ilya Yanok
  2009-05-26  5:38   ` Ben Warren
@ 2009-06-15 14:01   ` Johan
  2009-06-15 19:59     ` Eric Lammerts
  1 sibling, 1 reply; 18+ messages in thread
From: Johan @ 2009-06-15 14:01 UTC (permalink / raw)
  To: u-boot

I have trouble using your patch together with our LogicPD iMX27
Litekit. Seems like the FEC driver does not work well. Here is some
output from when I try to load files with tftp


U-Boot 2009.06-rc1 (jun 15 2009 - 15:46:31)

CPU:   Freescale i.MX27 at 399 MHz

DRAM:  128 MB
Flash:  2 MB
NAND:  64 MiB
In:    serial
Out:   serial
Err:   serial
MMC:  MXC MCI: 0
Hit any key to stop autoboot:  0
=> tftp 0xa0800000 uImage
FEC ETHERNET: Link is up - 100/Full
TFTP from server 172.16.140.75; our IP address is 172.16.140.76
Filename 'uImage'.
Load address: 0xa0800000
Loading: #####T #####################T #########################T ############T#
         #########################T ########################################
         ##T ####################################T #########T T #########
Retry count exceeded; starting again
TFTP from server 172.16.140.75; our IP address is 172.16.140.76
Filename 'uImage'.
Load address: 0xa0800000
Loading: ####################

I have downloaded the imx27lite head from the u-boot testing branch. I
have also tried to patch the u-boot-2009.06-rc3 branch with your
patches, but it does not seem to be any different. Do you have any
ideas what might be wrong?

/Johan



2009/5/20 Ilya Yanok <yanok@emcraft.com>:
> Signed-off-by: Ilya Yanok <yanok@emcraft.com>
> ---
> ?cpu/arm926ejs/mx27/generic.c | ? 10 +
> ?drivers/net/Makefile ? ? ? ? | ? ?1 +
> ?drivers/net/fec_imx27.c ? ? ?| ?705 ++++++++++++++++++++++++++++++++++++++++++
> ?drivers/net/fec_imx27.h ? ? ?| ?302 ++++++++++++++++++
> ?include/netdev.h ? ? ? ? ? ? | ? ?1 +
> ?5 files changed, 1019 insertions(+), 0 deletions(-)
> ?create mode 100644 drivers/net/fec_imx27.c
> ?create mode 100644 drivers/net/fec_imx27.h
>
> diff --git a/cpu/arm926ejs/mx27/generic.c b/cpu/arm926ejs/mx27/generic.c
> index 850d5e6..e820d94 100644
> --- a/cpu/arm926ejs/mx27/generic.c
> +++ b/cpu/arm926ejs/mx27/generic.c
> @@ -20,6 +20,7 @@
>
> ?#include <common.h>
> ?#include <div64.h>
> +#include <netdev.h>
> ?#include <asm/io.h>
> ?#include <asm/arch/imx-regs.h>
>
> @@ -159,6 +160,15 @@ int print_cpuinfo (void)
> ?}
> ?#endif
>
> +int cpu_eth_init(bd_t *bis)
> +{
> +#if defined(CONFIG_FEC_IMX27)
> + ? ? ? return fecimx27_initialize(bis);
> +#else
> + ? ? ? return 0;
> +#endif
> +}
> +
> ?void imx_gpio_mode(int gpio_mode)
> ?{
> ? ? ? ?struct gpio_regs *regs = (struct gpio_regs *)IMX_GPIO_BASE;
> diff --git a/drivers/net/Makefile b/drivers/net/Makefile
> index a360a50..ac68beb 100644
> --- a/drivers/net/Makefile
> +++ b/drivers/net/Makefile
> @@ -34,6 +34,7 @@ COBJS-$(CONFIG_DRIVER_CS8900) += cs8900.o
> ?COBJS-$(CONFIG_TULIP) += dc2114x.o
> ?COBJS-$(CONFIG_DRIVER_DM9000) += dm9000x.o
> ?COBJS-$(CONFIG_DNET) += dnet.o
> +COBJS-$(CONFIG_FEC_IMX27) += fec_imx27.o
> ?COBJS-$(CONFIG_E1000) += e1000.o
> ?COBJS-$(CONFIG_EEPRO100) += eepro100.o
> ?COBJS-$(CONFIG_ENC28J60) += enc28j60.o
> diff --git a/drivers/net/fec_imx27.c b/drivers/net/fec_imx27.c
> new file mode 100644
> index 0000000..4ade348
> --- /dev/null
> +++ b/drivers/net/fec_imx27.c
> @@ -0,0 +1,705 @@
> +/*
> + * (C) Copyright 2009 Ilya Yanok, Emcraft Systems Ltd <yanok@emcraft.com>
> + * (C) Copyright 2008,2009 Eric Jarrige <eric.jarrige@armadeus.org>
> + * (C) Copyright 2008 Armadeus Systems nc
> + * (C) Copyright 2007 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
> + * (C) Copyright 2007 Pengutronix, Juergen Beisert <j.beisert@pengutronix.de>
> + *
> + * 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 <net.h>
> +#include <miiphy.h>
> +#include "fec_imx27.h"
> +
> +#include <asm/arch/clock.h>
> +#include <asm/arch/imx-regs.h>
> +#include <asm/io.h>
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +#ifndef CONFIG_MII
> +#error "CONFIG_MII has to be defined!"
> +#endif
> +
> +#undef DEBUG
> +
> +struct nbuf {
> + ? ? ? uint8_t data[1500]; ? ? /**< actual data */
> + ? ? ? int length; ? ? ? ? ? ? /**< actual length */
> + ? ? ? int used; ? ? ? ? ? ? ? /**< buffer in use or not */
> + ? ? ? uint8_t head[16]; ? ? ? /**< MAC header(6 + 6 + 2) + 2(aligned) */
> +};
> +
> +struct fec_priv gfec = {
> + ? ? ? .eth ? ? ? = (struct ethernet_regs *)IMX_FEC_BASE,
> + ? ? ? .xcv_type ?= MII100,
> + ? ? ? .rbd_base ?= NULL,
> + ? ? ? .rbd_index = 0,
> + ? ? ? .tbd_base ?= NULL,
> + ? ? ? .tbd_index = 0,
> + ? ? ? .bd ? ? ? ?= NULL,
> +};
> +
> +/*
> + * MII-interface related functions
> + */
> +static int fec_miiphy_read(char *dev, uint8_t phyAddr, uint8_t regAddr,
> + ? ? ? ? ? ? ? uint16_t *retVal)
> +{
> + ? ? ? struct eth_device *edev = eth_get_dev_by_name(dev);
> + ? ? ? struct fec_priv *fec = (struct fec_priv *)edev->priv;
> +
> + ? ? ? uint32_t reg; ? ? ? ? ? /* convenient holder for the PHY register */
> + ? ? ? uint32_t phy; ? ? ? ? ? /* convenient holder for the PHY */
> + ? ? ? uint32_t start;
> +
> + ? ? ? /*
> + ? ? ? ?* reading from any PHY's register is done by properly
> + ? ? ? ?* programming the FEC's MII data register.
> + ? ? ? ?*/
> + ? ? ? writel(FEC_IEVENT_MII, &fec->eth->ievent);
> + ? ? ? reg = regAddr << FEC_MII_DATA_RA_SHIFT;
> + ? ? ? phy = phyAddr << FEC_MII_DATA_PA_SHIFT;
> +
> + ? ? ? writel(FEC_MII_DATA_ST | FEC_MII_DATA_OP_RD | FEC_MII_DATA_TA |
> + ? ? ? ? ? ? ? ? ? ? ? phy | reg, &fec->eth->mii_data);
> +
> + ? ? ? /*
> + ? ? ? ?* wait for the related interrupt
> + ? ? ? ?*/
> + ? ? ? start = get_timer_masked();
> + ? ? ? while (!(readl(&fec->eth->ievent) & FEC_IEVENT_MII)) {
> + ? ? ? ? ? ? ? if (get_timer(start) > (CONFIG_SYS_HZ / 1000)) {
> + ? ? ? ? ? ? ? ? ? ? ? printf("Read MDIO failed...\n");
> + ? ? ? ? ? ? ? ? ? ? ? return -1;
> + ? ? ? ? ? ? ? }
> + ? ? ? }
> +
> + ? ? ? /*
> + ? ? ? ?* clear mii interrupt bit
> + ? ? ? ?*/
> + ? ? ? writel(FEC_IEVENT_MII, &fec->eth->ievent);
> +
> + ? ? ? /*
> + ? ? ? ?* it's now safe to read the PHY's register
> + ? ? ? ?*/
> + ? ? ? *retVal = readl(&fec->eth->mii_data);
> + ? ? ? debug("fec_miiphy_read: phy: %02x reg:%02x val:%#x\n", phyAddr,
> + ? ? ? ? ? ? ? ? ? ? ? regAddr, *retVal);
> + ? ? ? return 0;
> +}
> +
> +static int fec_miiphy_write(char *dev, uint8_t phyAddr, uint8_t regAddr,
> + ? ? ? ? ? ? ? uint16_t data)
> +{
> + ? ? ? struct eth_device *edev = eth_get_dev_by_name(dev);
> + ? ? ? struct fec_priv *fec = (struct fec_priv *)edev->priv;
> +
> + ? ? ? uint32_t reg; ? ? ? ? ? /* convenient holder for the PHY register */
> + ? ? ? uint32_t phy; ? ? ? ? ? /* convenient holder for the PHY */
> + ? ? ? uint32_t start;
> +
> + ? ? ? reg = regAddr << FEC_MII_DATA_RA_SHIFT;
> + ? ? ? phy = phyAddr << FEC_MII_DATA_PA_SHIFT;
> +
> + ? ? ? writel(FEC_MII_DATA_ST | FEC_MII_DATA_OP_WR |
> + ? ? ? ? ? ? ? FEC_MII_DATA_TA | phy | reg | data, &fec->eth->mii_data);
> +
> + ? ? ? /*
> + ? ? ? ?* wait for the MII interrupt
> + ? ? ? ?*/
> + ? ? ? start = get_timer_masked();
> + ? ? ? while (!(readl(&fec->eth->ievent) & FEC_IEVENT_MII)) {
> + ? ? ? ? ? ? ? if (get_timer(start) > (CONFIG_SYS_HZ / 1000)) {
> + ? ? ? ? ? ? ? ? ? ? ? printf("Write MDIO failed...\n");
> + ? ? ? ? ? ? ? ? ? ? ? return -1;
> + ? ? ? ? ? ? ? }
> + ? ? ? }
> +
> + ? ? ? /*
> + ? ? ? ?* clear MII interrupt bit
> + ? ? ? ?*/
> + ? ? ? writel(FEC_IEVENT_MII, &fec->eth->ievent);
> + ? ? ? debug("fec_miiphy_write: phy: %02x reg:%02x val:%#x\n", phyAddr,
> + ? ? ? ? ? ? ? ? ? ? ? regAddr, data);
> +
> + ? ? ? return 0;
> +}
> +
> +static int miiphy_restart_aneg(struct eth_device *dev)
> +{
> + ? ? ? /*
> + ? ? ? ?* Wake up from sleep if necessary
> + ? ? ? ?* Reset PHY, then delay 300ns
> + ? ? ? ?*/
> + ? ? ? miiphy_write(dev->name, 0, PHY_MIPGSR, 0x00FF);
> + ? ? ? miiphy_write(dev->name, 0, PHY_BMCR, PHY_BMCR_RESET);
> + ? ? ? udelay(1000);
> +
> + ? ? ? /*
> + ? ? ? ?* Set the auto-negotiation advertisement register bits
> + ? ? ? ?*/
> + ? ? ? miiphy_write(dev->name, 0, PHY_ANAR, 0x1e0);
> + ? ? ? miiphy_write(dev->name, 0, PHY_BMCR, PHY_BMCR_AUTON | PHY_BMCR_RST_NEG);
> +
> + ? ? ? return 0;
> +}
> +
> +static int miiphy_wait_aneg(struct eth_device *dev)
> +{
> + ? ? ? uint32_t start;
> + ? ? ? uint16_t status;
> +
> + ? ? ? /*
> + ? ? ? ?* Wait for AN completion
> + ? ? ? ?*/
> + ? ? ? start = get_timer_masked(); /* get_time_ns(); */
> + ? ? ? do {
> + ? ? ? ? ? ? ? if (get_timer(start) > (CONFIG_SYS_HZ * 5)) {
> + ? ? ? ? ? ? ? ? ? ? ? printf("%s: Autonegotiation timeout\n", dev->name);
> + ? ? ? ? ? ? ? ? ? ? ? return -1;
> + ? ? ? ? ? ? ? }
> +
> + ? ? ? ? ? ? ? if (miiphy_read(dev->name, 0, PHY_BMSR, &status)) {
> + ? ? ? ? ? ? ? ? ? ? ? printf("%s: Autonegotiation failed. status: 0x%04x\n",
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? dev->name, status);
> + ? ? ? ? ? ? ? ? ? ? ? return -1;
> + ? ? ? ? ? ? ? }
> + ? ? ? } while (!(status & PHY_BMSR_LS));
> +
> + ? ? ? return 0;
> +}
> +static int fec_rx_task_enable(struct fec_priv *fec)
> +{
> + ? ? ? writel(1 << 24, &fec->eth->r_des_active);
> + ? ? ? return 0;
> +}
> +
> +static int fec_rx_task_disable(struct fec_priv *fec)
> +{
> + ? ? ? return 0;
> +}
> +
> +static int fec_tx_task_enable(struct fec_priv *fec)
> +{
> + ? ? ? writel(1 << 24, &fec->eth->x_des_active);
> + ? ? ? return 0;
> +}
> +
> +static int fec_tx_task_disable(struct fec_priv *fec)
> +{
> + ? ? ? return 0;
> +}
> +
> +/**
> + * Initialize receive task's buffer descriptors
> + * @param[in] fec all we know about the device yet
> + * @param[in] count receive buffer count to be allocated
> + * @param[in] size size of each receive buffer
> + * @return 0 on success
> + *
> + * For this task we need additional memory for the data buffers. And each
> + * data buffer requires some alignment. Thy must be aligned to a specific
> + * boundary each (DB_DATA_ALIGNMENT).
> + */
> +static int fec_rbd_init(struct fec_priv *fec, int count, int size, int once)
> +{
> + ? ? ? int ix;
> + ? ? ? uint32_t p = 0;
> +
> + ? ? ? if (!once) {
> + ? ? ? ? ? ? ? /* reserve data memory and consider alignment */
> + ? ? ? ? ? ? ? p = (uint32_t)malloc(size * count + DB_DATA_ALIGNMENT);
> + ? ? ? ? ? ? ? memset((void *)p, 0, size * count + DB_DATA_ALIGNMENT);
> + ? ? ? ? ? ? ? p += DB_DATA_ALIGNMENT-1;
> + ? ? ? ? ? ? ? p &= ~(DB_DATA_ALIGNMENT-1);
> + ? ? ? }
> +
> + ? ? ? for (ix = 0; ix < count; ix++) {
> + ? ? ? ? ? ? ? if (!once) {
> + ? ? ? ? ? ? ? ? ? ? ? writel(p, &fec->rbd_base[ix].data_pointer);
> + ? ? ? ? ? ? ? ? ? ? ? p += size;
> + ? ? ? ? ? ? ? }
> + ? ? ? ? ? ? ? writew(FEC_RBD_EMPTY, &fec->rbd_base[ix].status);
> + ? ? ? ? ? ? ? writew(0, &fec->rbd_base[ix].data_length);
> + ? ? ? }
> + ? ? ? /*
> + ? ? ? ?* mark the last RBD to close the ring
> + ? ? ? ?*/
> + ? ? ? writew(FEC_RBD_WRAP | FEC_RBD_EMPTY, &fec->rbd_base[ix - 1].status);
> + ? ? ? fec->rbd_index = 0;
> +
> + ? ? ? return 0;
> +}
> +
> +/**
> + * Initialize transmit task's buffer descriptors
> + * @param[in] fec all we know about the device yet
> + *
> + * Transmit buffers are created externally. We only have to init the BDs here.\n
> + * Note: There is a race condition in the hardware. When only one BD is in
> + * use it must be marked with the WRAP bit to use it for every transmitt.
> + * This bit in combination with the READY bit results into double transmit
> + * of each data buffer. It seems the state machine checks READY earlier then
> + * resetting it after the first transfer.
> + * Using two BDs solves this issue.
> + */
> +static void fec_tbd_init(struct fec_priv *fec)
> +{
> + ? ? ? writew(0x0000, &fec->tbd_base[0].status);
> + ? ? ? writew(FEC_TBD_WRAP, &fec->tbd_base[1].status);
> + ? ? ? fec->tbd_index = 0;
> +}
> +
> +/**
> + * Mark the given read buffer descriptor as free
> + * @param[in] last 1 if this is the last buffer descriptor in the chain, else 0
> + * @param[in] pRbd buffer descriptor to mark free again
> + */
> +static void fec_rbd_clean(int last, struct fec_bd *pRbd)
> +{
> + ? ? ? /*
> + ? ? ? ?* Reset buffer descriptor as empty
> + ? ? ? ?*/
> + ? ? ? if (last)
> + ? ? ? ? ? ? ? writew(FEC_RBD_WRAP | FEC_RBD_EMPTY, &pRbd->status);
> + ? ? ? else
> + ? ? ? ? ? ? ? writew(FEC_RBD_EMPTY, &pRbd->status);
> + ? ? ? /*
> + ? ? ? ?* no data in it
> + ? ? ? ?*/
> + ? ? ? writew(0, &pRbd->data_length);
> +}
> +
> +static int fec_get_hwaddr(struct eth_device *dev, unsigned char *mac)
> +{
> + ? ? ? struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE;
> + ? ? ? int i;
> +
> + ? ? ? for (i = 0; i < 6; i++)
> + ? ? ? ? ? ? ? mac[6-1-i] = readl(&iim->IIM_BANK_AREA0[IIM0_MAC + i]);
> +
> + ? ? ? return is_valid_ether_addr(mac);
> +}
> +
> +static int fec_set_hwaddr(struct eth_device *dev, unsigned char *mac)
> +{
> + ? ? ? struct fec_priv *fec = (struct fec_priv *)dev->priv;
> +
> + ? ? ? writel(0, &fec->eth->iaddr1);
> + ? ? ? writel(0, &fec->eth->iaddr2);
> + ? ? ? writel(0, &fec->eth->gaddr1);
> + ? ? ? writel(0, &fec->eth->gaddr2);
> +
> + ? ? ? /*
> + ? ? ? ?* Set physical address
> + ? ? ? ?*/
> + ? ? ? writel((mac[0] << 24) + (mac[1] << 16) + (mac[2] << 8) + mac[3],
> + ? ? ? ? ? ? ? ? ? ? ? &fec->eth->paddr1);
> + ? ? ? writel((mac[4] << 24) + (mac[5] << 16) + 0x8808, &fec->eth->paddr2);
> +
> + ? ? ? return 0;
> +}
> +
> +/**
> + * Start the FEC engine
> + * @param[in] dev Our device to handle
> + */
> +static int fec_open(struct eth_device *edev)
> +{
> + ? ? ? struct fec_priv *fec = (struct fec_priv *)edev->priv;
> +
> + ? ? ? debug("fec_open: fec_open(dev)\n");
> + ? ? ? /* full-duplex, heartbeat disabled */
> + ? ? ? writel(1 << 2, &fec->eth->x_cntrl);
> + ? ? ? fec->rbd_index = 0;
> +
> + ? ? ? /*
> + ? ? ? ?* Enable FEC-Lite controller
> + ? ? ? ?*/
> + ? ? ? writel(FEC_ECNTRL_ETHER_EN, &fec->eth->ecntrl);
> +
> + ? ? ? miiphy_wait_aneg(edev);
> + ? ? ? miiphy_speed(edev->name, 0);
> + ? ? ? miiphy_duplex(edev->name, 0);
> +
> + ? ? ? /*
> + ? ? ? ?* Enable SmartDMA receive task
> + ? ? ? ?*/
> + ? ? ? fec_rx_task_enable(fec);
> +
> + ? ? ? udelay(100000);
> + ? ? ? return 0;
> +}
> +
> +static int fec_init(struct eth_device *dev, bd_t* bd)
> +{
> + ? ? ? static int once;
> + ? ? ? uint32_t base;
> + ? ? ? struct fec_priv *fec = (struct fec_priv *)dev->priv;
> +
> + ? ? ? if (!once) {
> + ? ? ? ? ? ? ? /*
> + ? ? ? ? ? ? ? ?* reserve memory for both buffer descriptor chains at once
> + ? ? ? ? ? ? ? ?* Datasheet forces the startaddress of each chain is 16 byte
> + ? ? ? ? ? ? ? ?* aligned
> + ? ? ? ? ? ? ? ?*/
> + ? ? ? ? ? ? ? base = (uint32_t)malloc((2 + FEC_RBD_NUM) *
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? sizeof(struct fec_bd) + DB_ALIGNMENT);
> + ? ? ? ? ? ? ? memset((void *)base, 0, (2 + FEC_RBD_NUM) *
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? sizeof(struct fec_bd) + DB_ALIGNMENT);
> + ? ? ? ? ? ? ? base += (DB_ALIGNMENT-1);
> + ? ? ? ? ? ? ? base &= ~(DB_ALIGNMENT-1);
> +
> + ? ? ? ? ? ? ? fec->rbd_base = (struct fec_bd *)base;
> +
> + ? ? ? ? ? ? ? base += FEC_RBD_NUM * sizeof(struct fec_bd);
> +
> + ? ? ? ? ? ? ? fec->tbd_base = (struct fec_bd *)base;
> + ? ? ? }
> +
> + ? ? ? /*
> + ? ? ? ?* Set interrupt mask register
> + ? ? ? ?*/
> + ? ? ? writel(0x00000000, &fec->eth->imask);
> +
> + ? ? ? /*
> + ? ? ? ?* Clear FEC-Lite interrupt event register(IEVENT)
> + ? ? ? ?*/
> + ? ? ? writel(0xffffffff, &fec->eth->ievent);
> +
> +
> + ? ? ? /*
> + ? ? ? ?* Set FEC-Lite receive control register(R_CNTRL):
> + ? ? ? ?*/
> + ? ? ? if (fec->xcv_type == SEVENWIRE) {
> + ? ? ? ? ? ? ? /*
> + ? ? ? ? ? ? ? ?* Frame length=1518; 7-wire mode
> + ? ? ? ? ? ? ? ?*/
> + ? ? ? ? ? ? ? writel(0x05ee0020, &fec->eth->r_cntrl); /* FIXME 0x05ee0000 */
> + ? ? ? } else {
> + ? ? ? ? ? ? ? /*
> + ? ? ? ? ? ? ? ?* Frame length=1518; MII mode;
> + ? ? ? ? ? ? ? ?*/
> + ? ? ? ? ? ? ? writel(0x05ee0024, &fec->eth->r_cntrl); /* FIXME 0x05ee0004 */
> + ? ? ? ? ? ? ? /*
> + ? ? ? ? ? ? ? ?* Set MII_SPEED = (1/(mii_speed * 2)) * System Clock
> + ? ? ? ? ? ? ? ?* and do not drop the Preamble.
> + ? ? ? ? ? ? ? ?*/
> + ? ? ? ? ? ? ? writel((((imx_get_ahbclk() / 1000000) + 2) / 5) << 1,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &fec->eth->mii_speed);
> + ? ? ? ? ? ? ? debug("fec_init: mii_speed %#lx\n",
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (((imx_get_ahbclk() / 1000000) + 2) / 5) << 1);
> + ? ? ? }
> + ? ? ? /*
> + ? ? ? ?* Set Opcode/Pause Duration Register
> + ? ? ? ?*/
> + ? ? ? writel(0x00010020, &fec->eth->op_pause); ? ? ? ?/* FIXME 0xffff0020; */
> + ? ? ? writel(0x2, &fec->eth->x_wmrk);
> + ? ? ? /*
> + ? ? ? ?* Set multicast address filter
> + ? ? ? ?*/
> + ? ? ? writel(0x00000000, &fec->eth->gaddr1);
> + ? ? ? writel(0x00000000, &fec->eth->gaddr2);
> +
> +
> + ? ? ? /* clear MIB RAM */
> + ? ? ? long *mib_ptr = (long *)(IMX_FEC_BASE + 0x200);
> + ? ? ? while (mib_ptr <= (long *)(IMX_FEC_BASE + 0x2FC))
> + ? ? ? ? ? ? ? *mib_ptr++ = 0;
> +
> + ? ? ? /* FIFO receive start register */
> + ? ? ? writel(0x520, &fec->eth->r_fstart);
> +
> + ? ? ? /* size and address of each buffer */
> + ? ? ? writel(FEC_MAX_PKT_SIZE, &fec->eth->emrbr);
> + ? ? ? writel((uint32_t)fec->tbd_base, &fec->eth->etdsr);
> + ? ? ? writel((uint32_t)fec->rbd_base, &fec->eth->erdsr);
> +
> + ? ? ? /*
> + ? ? ? ?* Initialize RxBD/TxBD rings
> + ? ? ? ?*/
> + ? ? ? fec_rbd_init(fec, FEC_RBD_NUM, FEC_MAX_PKT_SIZE, once);
> + ? ? ? fec_tbd_init(fec);
> +
> +
> + ? ? ? if (fec->xcv_type != SEVENWIRE)
> + ? ? ? ? ? ? ? miiphy_restart_aneg(dev);
> +
> + ? ? ? once = 1; ? ? ? /* malloc done now (and once) */
> +
> + ? ? ? fec_open(dev);
> + ? ? ? return 0;
> +}
> +
> +/**
> + * Halt the FEC engine
> + * @param[in] dev Our device to handle
> + */
> +static void fec_halt(struct eth_device *dev)
> +{
> + ? ? ? struct fec_priv *fec = &gfec;
> + ? ? ? int counter = 0xffff;
> +
> + ? ? ? /*
> + ? ? ? ?* issue graceful stop command to the FEC transmitter if necessary
> + ? ? ? ?*/
> + ? ? ? writel(FEC_ECNTRL_RESET | readl(&fec->eth->x_cntrl),
> + ? ? ? ? ? ? ? ? ? ? ? &fec->eth->x_cntrl);
> +
> + ? ? ? debug("eth_halt: wait for stop regs\n");
> + ? ? ? /*
> + ? ? ? ?* wait for graceful stop to register
> + ? ? ? ?*/
> + ? ? ? while ((counter--) && (!(readl(&fec->eth->ievent) & FEC_IEVENT_GRA)))
> + ? ? ? ? ? ? ? ; ? ? ? /* FIXME ensure time */
> +
> + ? ? ? /*
> + ? ? ? ?* Disable SmartDMA tasks
> + ? ? ? ?*/
> + ? ? ? fec_tx_task_disable(fec);
> + ? ? ? fec_rx_task_disable(fec);
> +
> + ? ? ? /*
> + ? ? ? ?* Disable the Ethernet Controller
> + ? ? ? ?* Note: this will also reset the BD index counter!
> + ? ? ? ?*/
> + ? ? ? writel(0, &fec->eth->ecntrl);
> + ? ? ? fec->rbd_index = 0;
> + ? ? ? fec->tbd_index = 0;
> + ? ? ? debug("eth_halt: done\n");
> +}
> +
> +/**
> + * Transmit one frame
> + * @param[in] dev Our ethernet device to handle
> + * @param[in] packet Pointer to the data to be transmitted
> + * @param[in] length Data count in bytes
> + * @return 0 on success
> + */
> +static int fec_send(struct eth_device *dev, volatile void* packet, int length)
> +{
> + ? ? ? unsigned int status;
> +
> + ? ? ? /*
> + ? ? ? ?* This routine transmits one frame. ?This routine only accepts
> + ? ? ? ?* 6-byte Ethernet addresses.
> + ? ? ? ?*/
> + ? ? ? struct fec_priv *fec = (struct fec_priv *)dev->priv;
> +
> + ? ? ? /*
> + ? ? ? ?* Check for valid length of data.
> + ? ? ? ?*/
> + ? ? ? if ((length > 1500) || (length <= 0)) {
> + ? ? ? ? ? ? ? printf("Payload (%d) to large!\n", length);
> + ? ? ? ? ? ? ? return -1;
> + ? ? ? }
> +
> + ? ? ? /*
> + ? ? ? ?* Setup the transmit buffer
> + ? ? ? ?* Note: We are always using the first buffer for transmission,
> + ? ? ? ?* the second will be empty and only used to stop the DMA engine
> + ? ? ? ?*/
> + ? ? ? writew(length, &fec->tbd_base[fec->tbd_index].data_length);
> + ? ? ? writel((uint32_t)packet, &fec->tbd_base[fec->tbd_index].data_pointer);
> + ? ? ? /*
> + ? ? ? ?* update BD's status now
> + ? ? ? ?* This block:
> + ? ? ? ?* - is always the last in a chain (means no chain)
> + ? ? ? ?* - should transmitt the CRC
> + ? ? ? ?* - might be the last BD in the list, so the address counter should
> + ? ? ? ?* ? wrap (-> keep the WRAP flag)
> + ? ? ? ?*/
> + ? ? ? status = readw(&fec->tbd_base[fec->tbd_index].status) & FEC_TBD_WRAP;
> + ? ? ? status |= FEC_TBD_LAST | FEC_TBD_TC | FEC_TBD_READY;
> + ? ? ? writew(status, &fec->tbd_base[fec->tbd_index].status);
> +
> + ? ? ? /*
> + ? ? ? ?* Enable SmartDMA transmit task
> + ? ? ? ?*/
> + ? ? ? fec_tx_task_enable(fec);
> +
> + ? ? ? /*
> + ? ? ? ?* wait until frame is sent .
> + ? ? ? ?*/
> + ? ? ? while (readw(&fec->tbd_base[fec->tbd_index].status) & FEC_TBD_READY) {
> + ? ? ? ? ? ? ? /* FIXME: Timeout */
> + ? ? ? }
> + ? ? ? debug("fec_send: status 0x%x index %d\n",
> + ? ? ? ? ? ? ? ? ? ? ? readw(&fec->tbd_base[fec->tbd_index].status),
> + ? ? ? ? ? ? ? ? ? ? ? fec->tbd_index);
> + ? ? ? /* for next transmission use the other buffer */
> + ? ? ? if (fec->tbd_index)
> + ? ? ? ? ? ? ? fec->tbd_index = 0;
> + ? ? ? else
> + ? ? ? ? ? ? ? fec->tbd_index = 1;
> +
> + ? ? ? return 0;
> +}
> +
> +/**
> + * Pull one frame from the card
> + * @param[in] dev Our ethernet device to handle
> + * @return Length of packet read
> + */
> +static int fec_recv(struct eth_device *dev)
> +{
> + ? ? ? struct fec_priv *fec = (struct fec_priv *)dev->priv;
> + ? ? ? struct fec_bd *rbd = &fec->rbd_base[fec->rbd_index];
> + ? ? ? unsigned long ievent;
> + ? ? ? int frame_length, len = 0;
> + ? ? ? struct nbuf *frame;
> + ? ? ? uint16_t bd_status;
> + ? ? ? uchar buff[FEC_MAX_PKT_SIZE];
> +
> + ? ? ? /*
> + ? ? ? ?* Check if any critical events have happened
> + ? ? ? ?*/
> + ? ? ? ievent = readl(&fec->eth->ievent);
> + ? ? ? writel(ievent, &fec->eth->ievent);
> + ? ? ? debug("fec_recv: ievent 0x%x\n", ievent);
> + ? ? ? if (ievent & FEC_IEVENT_BABR) {
> + ? ? ? ? ? ? ? fec_halt(dev);
> + ? ? ? ? ? ? ? fec_init(dev, fec->bd);
> + ? ? ? ? ? ? ? printf("some error: 0x%08lx\n", ievent);
> + ? ? ? ? ? ? ? return 0;
> + ? ? ? }
> + ? ? ? if (ievent & FEC_IEVENT_HBERR) {
> + ? ? ? ? ? ? ? /* Heartbeat error */
> + ? ? ? ? ? ? ? writel(0x00000001 | readl(&fec->eth->x_cntrl),
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &fec->eth->x_cntrl);
> + ? ? ? }
> + ? ? ? if (ievent & FEC_IEVENT_GRA) {
> + ? ? ? ? ? ? ? /* Graceful stop complete */
> + ? ? ? ? ? ? ? if (readl(&fec->eth->x_cntrl) & 0x00000001) {
> + ? ? ? ? ? ? ? ? ? ? ? fec_halt(dev);
> + ? ? ? ? ? ? ? ? ? ? ? writel(~0x00000001 & readl(&fec->eth->x_cntrl),
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &fec->eth->x_cntrl);
> + ? ? ? ? ? ? ? ? ? ? ? fec_init(dev, fec->bd);
> + ? ? ? ? ? ? ? }
> + ? ? ? }
> +
> + ? ? ? /*
> + ? ? ? ?* ensure reading the right buffer status
> + ? ? ? ?*/
> + ? ? ? bd_status = readw(&rbd->status);
> + ? ? ? debug("fec_recv: status 0x%x\n", bd_status);
> +
> + ? ? ? if (!(bd_status & FEC_RBD_EMPTY)) {
> + ? ? ? ? ? ? ? if ((bd_status & FEC_RBD_LAST) && !(bd_status & FEC_RBD_ERR) &&
> + ? ? ? ? ? ? ? ? ? ? ? ((readw(&rbd->data_length) - 4) > 14)) {
> + ? ? ? ? ? ? ? ? ? ? ? /*
> + ? ? ? ? ? ? ? ? ? ? ? ?* Get buffer address and size
> + ? ? ? ? ? ? ? ? ? ? ? ?*/
> + ? ? ? ? ? ? ? ? ? ? ? frame = (struct nbuf *)readl(&rbd->data_pointer);
> + ? ? ? ? ? ? ? ? ? ? ? frame_length = readw(&rbd->data_length) - 4;
> + ? ? ? ? ? ? ? ? ? ? ? /*
> + ? ? ? ? ? ? ? ? ? ? ? ?* ?Fill the buffer and pass it to upper layers
> + ? ? ? ? ? ? ? ? ? ? ? ?*/
> + ? ? ? ? ? ? ? ? ? ? ? memcpy(buff, frame->data, frame_length);
> + ? ? ? ? ? ? ? ? ? ? ? NetReceive(buff, frame_length);
> + ? ? ? ? ? ? ? ? ? ? ? len = frame_length;
> + ? ? ? ? ? ? ? } else {
> + ? ? ? ? ? ? ? ? ? ? ? if (bd_status & FEC_RBD_ERR)
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? printf("error frame: 0x%08lx 0x%08x\n",
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (ulong)rbd->data_pointer,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? bd_status);
> + ? ? ? ? ? ? ? }
> + ? ? ? ? ? ? ? /*
> + ? ? ? ? ? ? ? ?* free the current buffer, restart the engine
> + ? ? ? ? ? ? ? ?* and move forward to the next buffer
> + ? ? ? ? ? ? ? ?*/
> + ? ? ? ? ? ? ? fec_rbd_clean(fec->rbd_index == (FEC_RBD_NUM - 1) ? 1 : 0, rbd);
> + ? ? ? ? ? ? ? fec_rx_task_enable(fec);
> + ? ? ? ? ? ? ? fec->rbd_index = (fec->rbd_index + 1) % FEC_RBD_NUM;
> + ? ? ? }
> + ? ? ? debug("fec_recv: stop\n");
> +
> + ? ? ? return len;
> +}
> +
> +static int fec_probe(bd_t *bd)
> +{
> + ? ? ? struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE;
> + ? ? ? struct eth_device *edev;
> + ? ? ? struct fec_priv *fec = &gfec;
> + ? ? ? unsigned char ethaddr_str[20];
> + ? ? ? unsigned char ethaddr[6];
> + ? ? ? char *tmp = getenv("ethaddr");
> + ? ? ? char *end;
> +
> + ? ? ? /* enable FEC clock */
> + ? ? ? writel(readl(&pll->PCCR1) | PCCR1_HCLK_FEC, &pll->PCCR1);
> + ? ? ? writel(readl(&pll->PCCR0) | PCCR0_FEC_EN, &pll->PCCR0);
> +
> + ? ? ? /* create and fill edev struct */
> + ? ? ? edev = (struct eth_device *)malloc(sizeof(struct eth_device));
> + ? ? ? edev->priv = fec;
> + ? ? ? edev->init = fec_init;
> + ? ? ? edev->send = fec_send;
> + ? ? ? edev->recv = fec_recv;
> + ? ? ? edev->halt = fec_halt;
> +
> + ? ? ? fec->eth = (struct ethernet_regs *)IMX_FEC_BASE;
> + ? ? ? fec->bd = bd;
> +
> + ? ? ? /* Reset chip. */
> + ? ? ? writel(FEC_ECNTRL_RESET, &fec->eth->ecntrl);
> + ? ? ? while (readl(&fec->eth->ecntrl) & 1)
> + ? ? ? ? ? ? ? udelay(10);
> +
> + ? ? ? fec->xcv_type = MII100;
> +
> + ? ? ? sprintf(edev->name, "FEC ETHERNET");
> +
> + ? ? ? miiphy_register(edev->name, fec_miiphy_read, fec_miiphy_write);
> +
> + ? ? ? eth_register(edev);
> +
> + ? ? ? if ((NULL != tmp) && (12 <= strlen(tmp))) {
> + ? ? ? ? ? ? ? int i;
> + ? ? ? ? ? ? ? /* convert MAC from string to int */
> + ? ? ? ? ? ? ? for (i = 0; i < 6; i++) {
> + ? ? ? ? ? ? ? ? ? ? ? ethaddr[i] = tmp ? simple_strtoul(tmp, &end, 16) : 0;
> + ? ? ? ? ? ? ? ? ? ? ? if (tmp)
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? tmp = (*end) ? end + 1 : end;
> + ? ? ? ? ? ? ? }
> + ? ? ? } else if (fec_get_hwaddr(edev, ethaddr) == 0) {
> + ? ? ? ? ? ? ? printf("got MAC address from EEPROM: %pM\n", ethaddr);
> + ? ? ? ? ? ? ? setenv("ethaddr", (char *)ethaddr_str);
> + ? ? ? }
> + ? ? ? memcpy(edev->enetaddr, ethaddr, 6);
> + ? ? ? fec_set_hwaddr(edev, ethaddr);
> +
> + ? ? ? return 0;
> +}
> +
> +int fecimx27_initialize(bd_t *bd)
> +{
> + ? ? ? int lout = 1;
> + ? ? ? static int once;
> +
> + ? ? ? if (!once) {
> + ? ? ? ? ? ? ? debug("eth_init: fec_probe(bd)\n");
> + ? ? ? ? ? ? ? lout = fec_probe(bd);
> + ? ? ? ? ? ? ? once = 1;
> + ? ? ? }
> + ? ? ? return lout;
> +}
> +
> diff --git a/drivers/net/fec_imx27.h b/drivers/net/fec_imx27.h
> new file mode 100644
> index 0000000..926c0d7
> --- /dev/null
> +++ b/drivers/net/fec_imx27.h
> @@ -0,0 +1,302 @@
> +/*
> + * (C) Copyright 2009 Ilya Yanok, Emcraft Systems Ltd <yanok@emcraft.com>
> + * (C) Copyright 2008 Armadeus Systems, nc
> + * (C) Copyright 2008 Eric Jarrige <eric.jarrige@armadeus.org>
> + * (C) Copyright 2007 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
> + * (C) Copyright 2007 Pengutronix, Juergen Beisert <j.beisert@pengutronix.de>
> + *
> + * (C) Copyright 2003
> + * Wolfgang Denk, DENX Software Engineering, wd at denx.de.
> + *
> + * This file is based on mpc4200fec.h
> + * (C) Copyright Motorola, Inc., 2000
> + *
> + * 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 __IMX27_FEC_H
> +#define __IMX27_FEC_H
> +
> +/**
> + * Layout description of the FEC
> + */
> +struct ethernet_regs {
> +
> +/* [10:2]addr = 00 */
> +
> +/* ?Control and status Registers (offset 000-1FF) */
> +
> + ? ? ? uint32_t RES0[1]; ? ? ? ? ? ? ? /* MBAR_ETH + 0x000 */
> + ? ? ? uint32_t ievent; ? ? ? ? ? ? ? ?/* MBAR_ETH + 0x004 */
> + ? ? ? uint32_t imask; ? ? ? ? ? ? ? ? /* MBAR_ETH + 0x008 */
> +
> + ? ? ? uint32_t RES1[1]; ? ? ? ? ? ? ? /* MBAR_ETH + 0x00C */
> + ? ? ? uint32_t r_des_active; ? ? ? ? ?/* MBAR_ETH + 0x010 */
> + ? ? ? uint32_t x_des_active; ? ? ? ? ?/* MBAR_ETH + 0x014 */
> + ? ? ? uint32_t RES2[3]; ? ? ? ? ? ? ? /* MBAR_ETH + 0x018-20 */
> + ? ? ? uint32_t ecntrl; ? ? ? ? ? ? ? ?/* MBAR_ETH + 0x024 */
> +
> + ? ? ? uint32_t RES3[6]; ? ? ? ? ? ? ? /* MBAR_ETH + 0x028-03C */
> + ? ? ? uint32_t mii_data; ? ? ? ? ? ? ?/* MBAR_ETH + 0x040 */
> + ? ? ? uint32_t mii_speed; ? ? ? ? ? ? /* MBAR_ETH + 0x044 */
> + ? ? ? uint32_t RES4[7]; ? ? ? ? ? ? ? /* MBAR_ETH + 0x048-60 */
> + ? ? ? uint32_t mib_control; ? ? ? ? ? /* MBAR_ETH + 0x064 */
> +
> + ? ? ? uint32_t RES5[7]; ? ? ? ? ? ? ? /* MBAR_ETH + 0x068-80 */
> + ? ? ? uint32_t r_cntrl; ? ? ? ? ? ? ? /* MBAR_ETH + 0x084 */
> + ? ? ? uint32_t RES6[15]; ? ? ? ? ? ? ?/* MBAR_ETH + 0x088-C0 */
> + ? ? ? uint32_t x_cntrl; ? ? ? ? ? ? ? /* MBAR_ETH + 0x0C4 */
> + ? ? ? uint32_t RES7[7]; ? ? ? ? ? ? ? /* MBAR_ETH + 0x0C8-E0 */
> + ? ? ? uint32_t paddr1; ? ? ? ? ? ? ? ?/* MBAR_ETH + 0x0E4 */
> + ? ? ? uint32_t paddr2; ? ? ? ? ? ? ? ?/* MBAR_ETH + 0x0E8 */
> + ? ? ? uint32_t op_pause; ? ? ? ? ? ? ?/* MBAR_ETH + 0x0EC */
> +
> + ? ? ? uint32_t RES8[10]; ? ? ? ? ? ? ?/* MBAR_ETH + 0x0F0-114 */
> + ? ? ? uint32_t iaddr1; ? ? ? ? ? ? ? ?/* MBAR_ETH + 0x118 */
> + ? ? ? uint32_t iaddr2; ? ? ? ? ? ? ? ?/* MBAR_ETH + 0x11C */
> + ? ? ? uint32_t gaddr1; ? ? ? ? ? ? ? ?/* MBAR_ETH + 0x120 */
> + ? ? ? uint32_t gaddr2; ? ? ? ? ? ? ? ?/* MBAR_ETH + 0x124 */
> + ? ? ? uint32_t RES9[7]; ? ? ? ? ? ? ? /* MBAR_ETH + 0x128-140 */
> +
> + ? ? ? uint32_t x_wmrk; ? ? ? ? ? ? ? ?/* MBAR_ETH + 0x144 */
> + ? ? ? uint32_t RES10[1]; ? ? ? ? ? ? ?/* MBAR_ETH + 0x148 */
> + ? ? ? uint32_t r_bound; ? ? ? ? ? ? ? /* MBAR_ETH + 0x14C */
> + ? ? ? uint32_t r_fstart; ? ? ? ? ? ? ?/* MBAR_ETH + 0x150 */
> + ? ? ? uint32_t RES11[11]; ? ? ? ? ? ? /* MBAR_ETH + 0x154-17C */
> + ? ? ? uint32_t erdsr; ? ? ? ? ? ? ? ? /* MBAR_ETH + 0x180 */
> + ? ? ? uint32_t etdsr; ? ? ? ? ? ? ? ? /* MBAR_ETH + 0x184 */
> + ? ? ? uint32_t emrbr; ? ? ? ? ? ? ? ? /* MBAR_ETH + 0x188 */
> + ? ? ? uint32_t RES12[29]; ? ? ? ? ? ? /* MBAR_ETH + 0x18C-1FC */
> +
> +/* ?MIB COUNTERS (Offset 200-2FF) */
> +
> + ? ? ? uint32_t rmon_t_drop; ? ? ? ? ? /* MBAR_ETH + 0x200 */
> + ? ? ? uint32_t rmon_t_packets; ? ? ? ?/* MBAR_ETH + 0x204 */
> + ? ? ? uint32_t rmon_t_bc_pkt; ? ? ? ? /* MBAR_ETH + 0x208 */
> + ? ? ? uint32_t rmon_t_mc_pkt; ? ? ? ? /* MBAR_ETH + 0x20C */
> + ? ? ? uint32_t rmon_t_crc_align; ? ? ?/* MBAR_ETH + 0x210 */
> + ? ? ? uint32_t rmon_t_undersize; ? ? ?/* MBAR_ETH + 0x214 */
> + ? ? ? uint32_t rmon_t_oversize; ? ? ? /* MBAR_ETH + 0x218 */
> + ? ? ? uint32_t rmon_t_frag; ? ? ? ? ? /* MBAR_ETH + 0x21C */
> + ? ? ? uint32_t rmon_t_jab; ? ? ? ? ? ?/* MBAR_ETH + 0x220 */
> + ? ? ? uint32_t rmon_t_col; ? ? ? ? ? ?/* MBAR_ETH + 0x224 */
> + ? ? ? uint32_t rmon_t_p64; ? ? ? ? ? ?/* MBAR_ETH + 0x228 */
> + ? ? ? uint32_t rmon_t_p65to127; ? ? ? /* MBAR_ETH + 0x22C */
> + ? ? ? uint32_t rmon_t_p128to255; ? ? ?/* MBAR_ETH + 0x230 */
> + ? ? ? uint32_t rmon_t_p256to511; ? ? ?/* MBAR_ETH + 0x234 */
> + ? ? ? uint32_t rmon_t_p512to1023; ? ? /* MBAR_ETH + 0x238 */
> + ? ? ? uint32_t rmon_t_p1024to2047; ? ?/* MBAR_ETH + 0x23C */
> + ? ? ? uint32_t rmon_t_p_gte2048; ? ? ?/* MBAR_ETH + 0x240 */
> + ? ? ? uint32_t rmon_t_octets; ? ? ? ? /* MBAR_ETH + 0x244 */
> + ? ? ? uint32_t ieee_t_drop; ? ? ? ? ? /* MBAR_ETH + 0x248 */
> + ? ? ? uint32_t ieee_t_frame_ok; ? ? ? /* MBAR_ETH + 0x24C */
> + ? ? ? uint32_t ieee_t_1col; ? ? ? ? ? /* MBAR_ETH + 0x250 */
> + ? ? ? uint32_t ieee_t_mcol; ? ? ? ? ? /* MBAR_ETH + 0x254 */
> + ? ? ? uint32_t ieee_t_def; ? ? ? ? ? ?/* MBAR_ETH + 0x258 */
> + ? ? ? uint32_t ieee_t_lcol; ? ? ? ? ? /* MBAR_ETH + 0x25C */
> + ? ? ? uint32_t ieee_t_excol; ? ? ? ? ?/* MBAR_ETH + 0x260 */
> + ? ? ? uint32_t ieee_t_macerr; ? ? ? ? /* MBAR_ETH + 0x264 */
> + ? ? ? uint32_t ieee_t_cserr; ? ? ? ? ?/* MBAR_ETH + 0x268 */
> + ? ? ? uint32_t ieee_t_sqe; ? ? ? ? ? ?/* MBAR_ETH + 0x26C */
> + ? ? ? uint32_t t_fdxfc; ? ? ? ? ? ? ? /* MBAR_ETH + 0x270 */
> + ? ? ? uint32_t ieee_t_octets_ok; ? ? ?/* MBAR_ETH + 0x274 */
> +
> + ? ? ? uint32_t RES13[2]; ? ? ? ? ? ? ?/* MBAR_ETH + 0x278-27C */
> + ? ? ? uint32_t rmon_r_drop; ? ? ? ? ? /* MBAR_ETH + 0x280 */
> + ? ? ? uint32_t rmon_r_packets; ? ? ? ?/* MBAR_ETH + 0x284 */
> + ? ? ? uint32_t rmon_r_bc_pkt; ? ? ? ? /* MBAR_ETH + 0x288 */
> + ? ? ? uint32_t rmon_r_mc_pkt; ? ? ? ? /* MBAR_ETH + 0x28C */
> + ? ? ? uint32_t rmon_r_crc_align; ? ? ?/* MBAR_ETH + 0x290 */
> + ? ? ? uint32_t rmon_r_undersize; ? ? ?/* MBAR_ETH + 0x294 */
> + ? ? ? uint32_t rmon_r_oversize; ? ? ? /* MBAR_ETH + 0x298 */
> + ? ? ? uint32_t rmon_r_frag; ? ? ? ? ? /* MBAR_ETH + 0x29C */
> + ? ? ? uint32_t rmon_r_jab; ? ? ? ? ? ?/* MBAR_ETH + 0x2A0 */
> +
> + ? ? ? uint32_t rmon_r_resvd_0; ? ? ? ?/* MBAR_ETH + 0x2A4 */
> +
> + ? ? ? uint32_t rmon_r_p64; ? ? ? ? ? ?/* MBAR_ETH + 0x2A8 */
> + ? ? ? uint32_t rmon_r_p65to127; ? ? ? /* MBAR_ETH + 0x2AC */
> + ? ? ? uint32_t rmon_r_p128to255; ? ? ?/* MBAR_ETH + 0x2B0 */
> + ? ? ? uint32_t rmon_r_p256to511; ? ? ?/* MBAR_ETH + 0x2B4 */
> + ? ? ? uint32_t rmon_r_p512to1023; ? ? /* MBAR_ETH + 0x2B8 */
> + ? ? ? uint32_t rmon_r_p1024to2047; ? ?/* MBAR_ETH + 0x2BC */
> + ? ? ? uint32_t rmon_r_p_gte2048; ? ? ?/* MBAR_ETH + 0x2C0 */
> + ? ? ? uint32_t rmon_r_octets; ? ? ? ? /* MBAR_ETH + 0x2C4 */
> + ? ? ? uint32_t ieee_r_drop; ? ? ? ? ? /* MBAR_ETH + 0x2C8 */
> + ? ? ? uint32_t ieee_r_frame_ok; ? ? ? /* MBAR_ETH + 0x2CC */
> + ? ? ? uint32_t ieee_r_crc; ? ? ? ? ? ?/* MBAR_ETH + 0x2D0 */
> + ? ? ? uint32_t ieee_r_align; ? ? ? ? ?/* MBAR_ETH + 0x2D4 */
> + ? ? ? uint32_t r_macerr; ? ? ? ? ? ? ?/* MBAR_ETH + 0x2D8 */
> + ? ? ? uint32_t r_fdxfc; ? ? ? ? ? ? ? /* MBAR_ETH + 0x2DC */
> + ? ? ? uint32_t ieee_r_octets_ok; ? ? ?/* MBAR_ETH + 0x2E0 */
> +
> + ? ? ? uint32_t RES14[6]; ? ? ? ? ? ? ?/* MBAR_ETH + 0x2E4-2FC */
> +
> + ? ? ? uint32_t RES15[64]; ? ? ? ? ? ? /* MBAR_ETH + 0x300-3FF */
> +};
> +
> +#define FEC_IEVENT_HBERR ? ? ? ? ? ? ? 0x80000000
> +#define FEC_IEVENT_BABR ? ? ? ? ? ? ? ? ? ? ? ?0x40000000
> +#define FEC_IEVENT_BABT ? ? ? ? ? ? ? ? ? ? ? ?0x20000000
> +#define FEC_IEVENT_GRA ? ? ? ? ? ? ? ? 0x10000000
> +#define FEC_IEVENT_TXF ? ? ? ? ? ? ? ? 0x08000000
> +#define FEC_IEVENT_TXB ? ? ? ? ? ? ? ? 0x04000000
> +#define FEC_IEVENT_RXF ? ? ? ? ? ? ? ? 0x02000000
> +#define FEC_IEVENT_RXB ? ? ? ? ? ? ? ? 0x01000000
> +#define FEC_IEVENT_MII ? ? ? ? ? ? ? ? 0x00800000
> +#define FEC_IEVENT_EBERR ? ? ? ? ? ? ? 0x00400000
> +#define FEC_IEVENT_LC ? ? ? ? ? ? ? ? ?0x00200000
> +#define FEC_IEVENT_RL ? ? ? ? ? ? ? ? ?0x00100000
> +#define FEC_IEVENT_UN ? ? ? ? ? ? ? ? ?0x00080000
> +
> +#define FEC_IMASK_HBERR ? ? ? ? ? ? ? ? ? ? ? ?0x80000000
> +#define FEC_IMASK_BABR ? ? ? ? ? ? ? ? 0x40000000
> +#define FEC_IMASKT_BABT ? ? ? ? ? ? ? ? ? ? ? ?0x20000000
> +#define FEC_IMASK_GRA ? ? ? ? ? ? ? ? ?0x10000000
> +#define FEC_IMASKT_TXF ? ? ? ? ? ? ? ? 0x08000000
> +#define FEC_IMASK_TXB ? ? ? ? ? ? ? ? ?0x04000000
> +#define FEC_IMASKT_RXF ? ? ? ? ? ? ? ? 0x02000000
> +#define FEC_IMASK_RXB ? ? ? ? ? ? ? ? ?0x01000000
> +#define FEC_IMASK_MII ? ? ? ? ? ? ? ? ?0x00800000
> +#define FEC_IMASK_EBERR ? ? ? ? ? ? ? ? ? ? ? ?0x00400000
> +#define FEC_IMASK_LC ? ? ? ? ? ? ? ? ? 0x00200000
> +#define FEC_IMASKT_RL ? ? ? ? ? ? ? ? ?0x00100000
> +#define FEC_IMASK_UN ? ? ? ? ? ? ? ? ? 0x00080000
> +
> +
> +#define FEC_RCNTRL_MAX_FL_SHIFT ? ? ? ? ? ? ? ?16
> +#define FEC_RCNTRL_LOOP ? ? ? ? ? ? ? ? ? ? ? ?0x00000001
> +#define FEC_RCNTRL_DRT ? ? ? ? ? ? ? ? 0x00000002
> +#define FEC_RCNTRL_MII_MODE ? ? ? ? ? ?0x00000004
> +#define FEC_RCNTRL_PROM ? ? ? ? ? ? ? ? ? ? ? ?0x00000008
> +#define FEC_RCNTRL_BC_REJ ? ? ? ? ? ? ?0x00000010
> +#define FEC_RCNTRL_FCE ? ? ? ? ? ? ? ? 0x00000020
> +
> +#define FEC_TCNTRL_GTS ? ? ? ? ? ? ? ? 0x00000001
> +#define FEC_TCNTRL_HBC ? ? ? ? ? ? ? ? 0x00000002
> +#define FEC_TCNTRL_FDEN ? ? ? ? ? ? ? ? ? ? ? ?0x00000004
> +#define FEC_TCNTRL_TFC_PAUSE ? ? ? ? ? 0x00000008
> +#define FEC_TCNTRL_RFC_PAUSE ? ? ? ? ? 0x00000010
> +
> +#define FEC_ECNTRL_RESET ? ? ? ? ? ? ? 0x00000001 ? ? ?/* reset the FEC */
> +#define FEC_ECNTRL_ETHER_EN ? ? ? ? ? ?0x00000002 ? ? ?/* enable the FEC */
> +
> +/**
> + * @brief Descriptor buffer alignment
> + *
> + * i.MX27 requires a 16 byte alignment (but for the first element only)
> + */
> +#define DB_ALIGNMENT ? ? ? ? ? 16
> +
> +/**
> + * @brief Data buffer alignment
> + *
> + * i.MX27 requires a four byte alignment for transmit and 16 bits
> + * alignment for receive so take 16
> + * Note: Valid for member data_pointer in struct buffer_descriptor
> + */
> +#define DB_DATA_ALIGNMENT ? ? ?16
> +
> +/**
> + * @brief Receive & Transmit Buffer Descriptor definitions
> + *
> + * Note: The first BD must be aligned (see DB_ALIGNMENT)
> + */
> +struct fec_bd {
> + ? ? ? uint16_t data_length; ? ? ? ? ? /* payload's length in bytes */
> + ? ? ? uint16_t status; ? ? ? ? ? ? ? ?/* BD's staus (see datasheet) */
> + ? ? ? uint32_t data_pointer; ? ? ? ? ?/* payload's buffer address */
> +};
> +
> +/**
> + * Supported phy types on this platform
> + */
> +enum xceiver_type {
> + ? ? ? SEVENWIRE, ? ? ?/* 7-wire ? ? ? */
> + ? ? ? MII10, ? ? ? ? ?/* MII 10Mbps ? */
> + ? ? ? MII100 ? ? ? ? ?/* MII 100Mbps ?*/
> +};
> +
> +/**
> + * @brief i.MX27-FEC private structure
> + */
> +struct fec_priv {
> + ? ? ? struct ethernet_regs *eth; ? ? ?/* pointer to register'S base */
> + ? ? ? enum xceiver_type xcv_type; ? ? /* transceiver type */
> + ? ? ? struct fec_bd *rbd_base; ? ? ? ?/* RBD ring */
> + ? ? ? int rbd_index; ? ? ? ? ? ? ? ? ?/* next receive BD to read */
> + ? ? ? struct fec_bd *tbd_base; ? ? ? ?/* TBD ring */
> + ? ? ? int tbd_index; ? ? ? ? ? ? ? ? ?/* next transmit BD to write */
> + ? ? ? bd_t *bd;
> +};
> +
> +/**
> + * @brief Numbers of buffer descriptors for receiving
> + *
> + * The number defines the stocked memory buffers for the receiving task.
> + * Larger values makes no sense in this limited environment.
> + */
> +#define FEC_RBD_NUM ? ? ? ? ? ?64
> +
> +/**
> + * @brief Define the ethernet packet size limit in memory
> + *
> + * Note: Do not shrink this number. This will force the FEC to spread larger
> + * frames in more than one BD. This is nothing to worry about, but the current
> + * driver can't handle it.
> + */
> +#define FEC_MAX_PKT_SIZE ? ? ? 1536
> +
> +/* Receive BD status bits */
> +#define FEC_RBD_EMPTY ?0x8000 ?/* Receive BD status: Buffer is empty */
> +#define FEC_RBD_WRAP ? 0x2000 ?/* Receive BD status: Last BD in ring */
> +/* Receive BD status: Buffer is last in frame (useless here!) */
> +#define FEC_RBD_LAST ? 0x0800
> +#define FEC_RBD_MISS ? 0x0100 ?/* Receive BD status: Miss bit for prom mode */
> +/* Receive BD status: The received frame is broadcast frame */
> +#define FEC_RBD_BC ? ? 0x0080
> +/* Receive BD status: The received frame is multicast frame */
> +#define FEC_RBD_MC ? ? 0x0040
> +#define FEC_RBD_LG ? ? 0x0020 ?/* Receive BD status: Frame length violation */
> +#define FEC_RBD_NO ? ? 0x0010 ?/* Receive BD status: Nonoctet align frame */
> +#define FEC_RBD_CR ? ? 0x0004 ?/* Receive BD status: CRC error */
> +#define FEC_RBD_OV ? ? 0x0002 ?/* Receive BD status: Receive FIFO overrun */
> +#define FEC_RBD_TR ? ? 0x0001 ?/* Receive BD status: Frame is truncated */
> +#define FEC_RBD_ERR ? ?(FEC_RBD_LG | FEC_RBD_NO | FEC_RBD_CR | \
> + ? ? ? ? ? ? ? ? ? ? ? FEC_RBD_OV | FEC_RBD_TR)
> +
> +/* Transmit BD status bits */
> +#define FEC_TBD_READY ?0x8000 ?/* Tansmit BD status: Buffer is ready */
> +#define FEC_TBD_WRAP ? 0x2000 ?/* Tansmit BD status: Mark as last BD in ring */
> +#define FEC_TBD_LAST ? 0x0800 ?/* Tansmit BD status: Buffer is last in frame */
> +#define FEC_TBD_TC ? ? 0x0400 ?/* Tansmit BD status: Transmit the CRC */
> +#define FEC_TBD_ABC ? ?0x0200 ?/* Tansmit BD status: Append bad CRC */
> +
> +/* MII-related definitios */
> +#define FEC_MII_DATA_ST ? ? ? ? ? ? ? ?0x40000000 ? ? ?/* Start of frame delimiter */
> +#define FEC_MII_DATA_OP_RD ? ? 0x20000000 ? ? ?/* Perform a read operation */
> +#define FEC_MII_DATA_OP_WR ? ? 0x10000000 ? ? ?/* Perform a write operation */
> +#define FEC_MII_DATA_PA_MSK ? ?0x0f800000 ? ? ?/* PHY Address field mask */
> +#define FEC_MII_DATA_RA_MSK ? ?0x007c0000 ? ? ?/* PHY Register field mask */
> +#define FEC_MII_DATA_TA ? ? ? ? ? ? ? ?0x00020000 ? ? ?/* Turnaround */
> +#define FEC_MII_DATA_DATAMSK ? 0x0000ffff ? ? ?/* PHY data field */
> +
> +#define FEC_MII_DATA_RA_SHIFT ?18 ? ? ?/* MII Register address bits */
> +#define FEC_MII_DATA_PA_SHIFT ?23 ? ? ?/* MII PHY address bits */
> +
> +#endif /* __IMX27_FEC_H */
> diff --git a/include/netdev.h b/include/netdev.h
> index 63cf730..2d999ad 100644
> --- a/include/netdev.h
> +++ b/include/netdev.h
> @@ -49,6 +49,7 @@ int e1000_initialize(bd_t *bis);
> ?int eepro100_initialize(bd_t *bis);
> ?int eth_3com_initialize (bd_t * bis);
> ?int fec_initialize (bd_t *bis);
> +int fecimx27_initialize (bd_t *bis);
> ?int greth_initialize(bd_t *bis);
> ?void gt6426x_eth_initialize(bd_t *bis);
> ?int inca_switch_initialize(bd_t *bis);
> --
> 1.6.0.6
>
> _______________________________________________
> U-Boot mailing list
> U-Boot at lists.denx.de
> http://lists.denx.de/mailman/listinfo/u-boot
>

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [U-Boot] [PATCH 3/7] fec_imx27: driver for FEC ethernet controller on i.MX27
  2009-06-15 14:01   ` Johan
@ 2009-06-15 19:59     ` Eric Lammerts
  2009-06-16  7:12       ` Johan
  2009-06-23 17:37       ` [U-Boot] [PATCH 3/7] fec_imx27: driver for FEC Ethernet " Bill Cook
  0 siblings, 2 replies; 18+ messages in thread
From: Eric Lammerts @ 2009-06-15 19:59 UTC (permalink / raw)
  To: u-boot

On 06/15/09 10:01, Johan wrote:
> I have trouble using your patch together with our LogicPD iMX27
> Litekit. Seems like the FEC driver does not work well. Here is some
> output from when I try to load files with tftp

<snip>
> Loading: #####T #####################T #########################T ############T#
>          #########################T ########################################
>          ##T ####################################T #########T T #########
> Retry count exceeded; starting again

<snip>
> I have downloaded the imx27lite head from the u-boot testing branch. I
> have also tried to patch the u-boot-2009.06-rc3 branch with your
> patches, but it does not seem to be any different. Do you have any
> ideas what might be wrong?

Did you have working ethernet before (with a different bootloader or in
Linux)? Do you have the breakout board installed? I have the same board
(but maybe an older revision; about a year old) and with the breakout
board mounted my ethernet would behave the same way as yours. They routed
the MII signals all the way to the headers on the breakout board, and
that causes signal integrity problems. It could be that they fixed it on
later revisions though (not sure).

I'm using u-boot-v2, so I don't know anything about the u-boot fec driver.

Eric

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [U-Boot] [PATCH 3/7] fec_imx27: driver for FEC ethernet controller on i.MX27
  2009-06-15 19:59     ` Eric Lammerts
@ 2009-06-16  7:12       ` Johan
  2009-06-17 22:19         ` Ilya Yanok
  2009-06-19 23:59         ` Wolfgang Denk
  2009-06-23 17:37       ` [U-Boot] [PATCH 3/7] fec_imx27: driver for FEC Ethernet " Bill Cook
  1 sibling, 2 replies; 18+ messages in thread
From: Johan @ 2009-06-16  7:12 UTC (permalink / raw)
  To: u-boot

Seems like that was the trick. After removing the breakout board it
works much better.

I still got some problems which I don't know if its software related.
Sometimes when I power on the board the ethernet LEDs does not turn
green and the network does not work. If I power cycle the board a
number of times the LEDs turn green I can can use the network. Do you
know if that might be hw related or may it be something with the
initialization?

I'll try to test U-boot v2 as you are using and see if it works better.

/Johan

2009/6/15 Eric Lammerts <u-boot@lists.lammerts.org>:
> On 06/15/09 10:01, Johan wrote:
>> I have trouble using your patch together with our LogicPD iMX27
>> Litekit. Seems like the FEC driver does not work well. Here is some
>> output from when I try to load files with tftp
>
> <snip>
>> Loading: #####T #####################T #########################T ############T#
>> ? ? ? ? ?#########################T ########################################
>> ? ? ? ? ?##T ####################################T #########T T #########
>> Retry count exceeded; starting again
>
> <snip>
>> I have downloaded the imx27lite head from the u-boot testing branch. I
>> have also tried to patch the u-boot-2009.06-rc3 branch with your
>> patches, but it does not seem to be any different. Do you have any
>> ideas what might be wrong?
>
> Did you have working ethernet before (with a different bootloader or in
> Linux)? Do you have the breakout board installed? I have the same board
> (but maybe an older revision; about a year old) and with the breakout
> board mounted my ethernet would behave the same way as yours. They routed
> the MII signals all the way to the headers on the breakout board, and
> that causes signal integrity problems. It could be that they fixed it on
> later revisions though (not sure).
>
> I'm using u-boot-v2, so I don't know anything about the u-boot fec driver.
>
> Eric
>

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [U-Boot] [PATCH 3/7] fec_imx27: driver for FEC ethernet controller on i.MX27
  2009-06-16  7:12       ` Johan
@ 2009-06-17 22:19         ` Ilya Yanok
  2009-06-19 23:59         ` Wolfgang Denk
  1 sibling, 0 replies; 18+ messages in thread
From: Ilya Yanok @ 2009-06-17 22:19 UTC (permalink / raw)
  To: u-boot

Hi Johan,

> Seems like that was the trick. After removing the breakout board it
> works much better.
>
> I still got some problems which I don't know if its software related.
> Sometimes when I power on the board the ethernet LEDs does not turn
> green and the network does not work. If I power cycle the board a
> number of times the LEDs turn green I can can use the network. Do you
> know if that might be hw related or may it be something with the
> initialization?
>
> I'll try to test U-boot v2 as you are using and see if it works better.
>   

Our customer reported the same problem but we can't reproduce it on our 
hardware... Could you please tell me if U-Boot v2 works for you well?

Regards, Ilya.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [U-Boot] [PATCH 3/7] fec_imx27: driver for FEC ethernet controller on i.MX27
  2009-06-16  7:12       ` Johan
  2009-06-17 22:19         ` Ilya Yanok
@ 2009-06-19 23:59         ` Wolfgang Denk
  1 sibling, 0 replies; 18+ messages in thread
From: Wolfgang Denk @ 2009-06-19 23:59 UTC (permalink / raw)
  To: u-boot

Dear Johan,

In message <de9b121e0906160012q5975b23cnd320908aee6cd4ab@mail.gmail.com> you wrote:
> Seems like that was the trick. After removing the breakout board it
> works much better.
> 
> I still got some problems which I don't know if its software related.
> Sometimes when I power on the board the ethernet LEDs does not turn
> green and the network does not work. If I power cycle the board a
> number of times the LEDs turn green I can can use the network. Do you
> know if that might be hw related or may it be something with the
> initialization?

This is most likely a hardware problem. Please contach Logic for
information about the required changes on the board.

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
"May the forces of evil become confused on the way to your house."
- George Carlin

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [U-Boot] [PATCH 3/7] fec_imx27: driver for FEC Ethernet controller on i.MX27
  2009-06-15 19:59     ` Eric Lammerts
  2009-06-16  7:12       ` Johan
@ 2009-06-23 17:37       ` Bill Cook
  1 sibling, 0 replies; 18+ messages in thread
From: Bill Cook @ 2009-06-23 17:37 UTC (permalink / raw)
  To: u-boot


> -----Original Message-----
> From: Eric Lammerts [mailto:u-boot at lists.lammerts.org]
> Sent: Monday, June 15, 2009 3:59 PM
> To: Johan
> Cc: u-boot at lists.denx.de; Ilya Yanok
> Subject: Re: [U-Boot] [PATCH 3/7] fec_imx27: driver for FEC ethernet
> controller on i.MX27
>
>
> On 06/15/09 10:01, Johan wrote:
> > I have trouble using your patch together with our LogicPD iMX27
> > Litekit. Seems like the FEC driver does not work well. Here is some
> > output from when I try to load files with tftp
>
> <snip>
> > Loading: #####T #####################T #########################T
> ############T#
> >          #########################T ########################################
> >          ##T ####################################T #########T T #########
> > Retry count exceeded; starting again
>
> <snip>
> > I have downloaded the imx27lite head from the u-boot testing branch. I
> > have also tried to patch the u-boot-2009.06-rc3 branch with your
> > patches, but it does not seem to be any different. Do you have any
> > ideas what might be wrong?
>
> Did you have working ethernet before (with a different bootloader or in
> Linux)? Do you have the breakout board installed? I have the same board
> (but maybe an older revision; about a year old) and with the breakout
> board mounted my ethernet would behave the same way as yours. They routed
> the MII signals all the way to the headers on the breakout board, and
> that causes signal integrity problems. It could be that they fixed it on
> later revisions though (not sure).
>
> I'm using u-boot-v2, so I don't know anything about the u-boot fec driver.
>
> Eric
>
I'm trying to debug ethernet problems on a custom iMX27 board with
same LAN chip as the logicPD liteKit. I don't claim to be an expert,
but it seems that in the fec driver posted by Ilya, the phy address
for MII access is hard coded to a 0, whereas on the board it defaults
to 0x1f. When I turned on DEBUG in fec_imx27.c, the MII reads always
return all 1's. The phy works, but maybe by good fortune, not intent.

Bill Cook
cook at isgchips.com
Imaging Solutions Group Inc;
http://www.isgcameras.com

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [U-Boot] [PATCH 3/7] fec_imx27: driver for FEC ethernet controller on i.MX27
  2009-05-26  5:38   ` Ben Warren
  2009-06-07 23:08     ` Ilya Yanok
@ 2009-11-17  2:46     ` alfred steele
  2009-11-17  2:59       ` Ben Warren
  2009-11-17  6:34       ` Wolfgang Denk
  1 sibling, 2 replies; 18+ messages in thread
From: alfred steele @ 2009-11-17  2:46 UTC (permalink / raw)
  To: u-boot

> Thanks for your submission!
What is the current design on the mxc fec interface's attainment of a
MAC address. From the kernel driver it looks like it looks at the
IIM(IC identification registers) on the MXC platform(like mx51/35) to
look for a programmed mac address and then the set the fec mac to the
same .

Looks like with the current mxc_fec driver there is not support for
the same. I am thinking of a mechanism to hardcode a fake MAC which
would subsequently be picked up by the kernel without using the
bd_info structure.
Any comments/suggestions?

-Alfred.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [U-Boot] [PATCH 3/7] fec_imx27: driver for FEC ethernet controller on i.MX27
  2009-11-17  2:46     ` alfred steele
@ 2009-11-17  2:59       ` Ben Warren
  2009-11-19  1:54         ` alfred steele
  2009-11-17  6:34       ` Wolfgang Denk
  1 sibling, 1 reply; 18+ messages in thread
From: Ben Warren @ 2009-11-17  2:59 UTC (permalink / raw)
  To: u-boot

Hi Alfred,

alfred steele wrote:
>> Thanks for your submission!
>>     
> What is the current design on the mxc fec interface's attainment of a
> MAC address. From the kernel driver it looks like it looks at the
> IIM(IC identification registers) on the MXC platform(like mx51/35) to
> look for a programmed mac address and then the set the fec mac to the
> same .
>
> Looks like with the current mxc_fec driver there is not support for
> the same. I am thinking of a mechanism to hardcode a fake MAC which
> would subsequently be picked up by the kernel without using the
> bd_info structure.
> Any comments/suggestions?
>
> -Alfred.
>   
I don't know much about this driver, but it appears to be doing things 
incorrectly.  The correct flow is as follows.  It is documented in 
'doc/README.enetaddr':

1. The driver's initialize() function read from NVRAM if available.  MAC 
address is stuffed into dev->enetaddr.  The initialize() function should 
not try to get the address from the environment, which is where the 
imx27 driver goes wrong.
2. After all drivers have been initialized, eth_initialize() ( in 
net/eth.c) reads from the environment.  If the value in the environment 
is valid and the value in dev->enetaddr is valid and both are different, 
the user is warned.  The value in the environment overwrites the value 
in dev->enetaddr
3. When a network operation is performed, the driver's init() function 
is called, which is where the address is programmed into the device.

As you can see, if the device is never used, step 3 is never exected and 
the device is never programmed.  This is how it's supposed to work, 
since the U-boot design philosophy dictates that hardware is never 
touched unless it is used in U-boot.  I'm pretty sure hard-coding a fake 
MAC address would run afoul of this rule.

regards,
Ben

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [U-Boot] [PATCH 3/7] fec_imx27: driver for FEC ethernet controller on i.MX27
  2009-11-17  2:46     ` alfred steele
  2009-11-17  2:59       ` Ben Warren
@ 2009-11-17  6:34       ` Wolfgang Denk
  1 sibling, 0 replies; 18+ messages in thread
From: Wolfgang Denk @ 2009-11-17  6:34 UTC (permalink / raw)
  To: u-boot

Dear Alfred Steele,

In message <528f13590911161846q6a91df8awa309d4e1f990d134@mail.gmail.com> you wrote:
> > Thanks for your submission!
> What is the current design on the mxc fec interface's attainment of a
> MAC address. From the kernel driver it looks like it looks at the

There is none.

> IIM(IC identification registers) on the MXC platform(like mx51/35) to
> look for a programmed mac address and then the set the fec mac to the
> same .
> 
> Looks like with the current mxc_fec driver there is not support for
> the same. I am thinking of a mechanism to hardcode a fake MAC which
> would subsequently be picked up by the kernel without using the
> bd_info structure.

You must not do this. First, you must not use any "fake" addresses at
all (especially not since the board most probably has a real one in
the environment). Second, read the FAQ
(http://www.denx.de/wiki/view/DULG/EthernetDoesNotWorkInLinux).

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
ATTENTION: Despite Any Other Listing of Product Contents Found  Here-
on, the Consumer is Advised That, in Actuality, This Product Consists
Of 99.9999999999% Empty Space.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [U-Boot] [PATCH 3/7] fec_imx27: driver for FEC ethernet controller on i.MX27
  2009-11-17  2:59       ` Ben Warren
@ 2009-11-19  1:54         ` alfred steele
  2009-11-19  3:30           ` Ben Warren
  0 siblings, 1 reply; 18+ messages in thread
From: alfred steele @ 2009-11-19  1:54 UTC (permalink / raw)
  To: u-boot

On Mon, Nov 16, 2009 at 8:59 PM, Ben Warren <biggerbadderben@gmail.com> wrote:
> Hi Alfred,
>
> alfred steele wrote:
>>>
>>> Thanks for your submission!
>>>
>>
>> What is the current design on the mxc fec interface's attainment of a
>> MAC address. From the kernel driver it looks like it looks at the
>> IIM(IC identification registers) on the MXC platform(like mx51/35) to
>> look for a programmed mac address and then the set the fec mac to the
>> same .
>>
>> Looks like with the current mxc_fec driver there is not support for
>> the same. I am thinking of a mechanism to hardcode a fake MAC which
>> would subsequently be picked up by the kernel without using the
>> bd_info structure.
>> Any comments/suggestions?
>>
>> -Alfred.
>>
>
> I don't know much about this driver, but it appears to be doing things
> incorrectly. ?The correct flow is as follows. ?It is documented in
> 'doc/README.enetaddr':
>
> 1. The driver's initialize() function read from NVRAM if available. ?MAC
> address is stuffed into dev->enetaddr. ?The initialize() function should not
> try to get the address from the environment, which is where the imx27 driver
> goes wrong.
> 2. After all drivers have been initialized, eth_initialize() ( in net/eth.c)
> reads from the environment. ?If the value in the environment is valid and
> the value in dev->enetaddr is valid and both are different, the user is
> warned. ?The value in the environment overwrites the value in dev->enetaddr
> 3. When a network operation is performed, the driver's init() function is
> called, which is where the address is programmed into the device.
>
> As you can see, if the device is never used, step 3 is never exected and the
> device is never programmed. ?This is how it's supposed to work, since the
> U-boot design philosophy dictates that hardware is never touched unless it
> is used in U-boot. ?I'm pretty sure hard-coding a fake MAC address would run
> afoul of this rule.
Is there a way to pass the information to kernel using either the
dev->enetaddr  without programming the IIM module register. Would i
have to use bd_info structure or can we do without it.? This problem
is specific to the mx27 i guess.
-Alfred

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [U-Boot] [PATCH 3/7] fec_imx27: driver for FEC ethernet controller on i.MX27
  2009-11-19  1:54         ` alfred steele
@ 2009-11-19  3:30           ` Ben Warren
  0 siblings, 0 replies; 18+ messages in thread
From: Ben Warren @ 2009-11-19  3:30 UTC (permalink / raw)
  To: u-boot

Alfred,

On Wed, Nov 18, 2009 at 5:54 PM, alfred steele <alfred.jaquez@gmail.com>wrote:

> On Mon, Nov 16, 2009 at 8:59 PM, Ben Warren <biggerbadderben@gmail.com>
> wrote:
> > Hi Alfred,
> >
> > alfred steele wrote:
> >>>
> >>> Thanks for your submission!
> >>>
> >>
> >> What is the current design on the mxc fec interface's attainment of a
> >> MAC address. From the kernel driver it looks like it looks at the
> >> IIM(IC identification registers) on the MXC platform(like mx51/35) to
> >> look for a programmed mac address and then the set the fec mac to the
> >> same .
> >>
> >> Looks like with the current mxc_fec driver there is not support for
> >> the same. I am thinking of a mechanism to hardcode a fake MAC which
> >> would subsequently be picked up by the kernel without using the
> >> bd_info structure.
> >> Any comments/suggestions?
> >>
> >> -Alfred.
> >>
> >
> > I don't know much about this driver, but it appears to be doing things
> > incorrectly.  The correct flow is as follows.  It is documented in
> > 'doc/README.enetaddr':
> >
> > 1. The driver's initialize() function read from NVRAM if available.  MAC
> > address is stuffed into dev->enetaddr.  The initialize() function should
> not
> > try to get the address from the environment, which is where the imx27
> driver
> > goes wrong.
> > 2. After all drivers have been initialized, eth_initialize() ( in
> net/eth.c)
> > reads from the environment.  If the value in the environment is valid and
> > the value in dev->enetaddr is valid and both are different, the user is
> > warned.  The value in the environment overwrites the value in
> dev->enetaddr
> > 3. When a network operation is performed, the driver's init() function is
> > called, which is where the address is programmed into the device.
> >
> > As you can see, if the device is never used, step 3 is never exected and
> the
> > device is never programmed.  This is how it's supposed to work, since the
> > U-boot design philosophy dictates that hardware is never touched unless
> it
> > is used in U-boot.  I'm pretty sure hard-coding a fake MAC address would
> run
> > afoul of this rule.
> Is there a way to pass the information to kernel using either the
> dev->enetaddr  without programming the IIM module register. Would i
> have to use bd_info structure or can we do without it.? This problem
> is specific to the mx27 i guess.
> -Alfred
>
I'm pretty sure it's a much-discussed ARM peculiarity.  Not at all my area
of expertise, so I'll leave it to others to suggest options.

regards,
Ben

^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2009-11-19  3:30 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-06-08  2:15 [U-Boot] [PATCH 3/7] fec_imx27: driver for FEC ethernet controller on i.MX27 Fabio Estevam
2009-06-08 13:29 ` Ilya Yanok
  -- strict thread matches above, loose matches on Subject: below --
2009-06-08 21:08 Fabio Estevam
2009-06-08  0:12 [U-Boot] [PATCH 0/7][v3] Support for LogicPD i.MX27-LITEKIT development board Ilya Yanok
2009-06-08  0:12 ` [U-Boot] [PATCH 3/7] fec_imx27: driver for FEC ethernet controller on i.MX27 Ilya Yanok
2009-05-19 23:55 [U-Boot] [PATCH 00/10][v2] Support for LogicPD i.MX27-LITEKIT development board Ilya Yanok
2009-05-19 23:55 ` [U-Boot] [PATCH 3/7] fec_imx27: driver for FEC ethernet controller on i.MX27 Ilya Yanok
2009-05-26  5:38   ` Ben Warren
2009-06-07 23:08     ` Ilya Yanok
2009-11-17  2:46     ` alfred steele
2009-11-17  2:59       ` Ben Warren
2009-11-19  1:54         ` alfred steele
2009-11-19  3:30           ` Ben Warren
2009-11-17  6:34       ` Wolfgang Denk
2009-06-15 14:01   ` Johan
2009-06-15 19:59     ` Eric Lammerts
2009-06-16  7:12       ` Johan
2009-06-17 22:19         ` Ilya Yanok
2009-06-19 23:59         ` Wolfgang Denk
2009-06-23 17:37       ` [U-Boot] [PATCH 3/7] fec_imx27: driver for FEC Ethernet " Bill Cook

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox