All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ben Warren <biggerbadderben@gmail.com>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH 03/10] fec_imx27: driver for FEC ethernet controller on i.MX27
Date: Wed, 06 May 2009 12:51:43 -0700	[thread overview]
Message-ID: <4A01EA4F.3070409@gmail.com> (raw)
In-Reply-To: <1241634633-13917-4-git-send-email-yanok@emcraft.com>

Hi Ilya,

Ilya Yanok wrote:
> Signed-off-by: Ilya Yanok <yanok@emcraft.com>
> ---
>  drivers/net/Makefile       |    1 +
>  drivers/net/fec_imx27.c    |  795 ++++++++++++++++++++++++++++++++++++++++++++
>  drivers/net/fec_imx27.h    |  305 +++++++++++++++++
>  drivers/net/imx27_miiphy.c |  125 +++++++
>  drivers/net/imx27_miiphy.h |  157 +++++++++
>  5 files changed, 1383 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/net/fec_imx27.c
>  create mode 100644 drivers/net/fec_imx27.h
>  create mode 100644 drivers/net/imx27_miiphy.c
>  create mode 100644 drivers/net/imx27_miiphy.h
>
> diff --git a/drivers/net/Makefile b/drivers/net/Makefile
> index a360a50..819e609 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 imx27_miiphy.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..25299b9
> --- /dev/null
> +++ b/drivers/net/fec_imx27.c
> @@ -0,0 +1,795 @@
> +/*
> + * (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
> + */
> +
> +/************************** TODO eth_register + cleanup gfec !! *****/
>   
Huh?
> +
> +
> +#include <common.h>
> +#include <malloc.h>
> +#include <net.h>
> +#include "imx27_miiphy.h"
> +#include "fec_imx27.h"
> +
> +#include <asm/arch/clock.h>
> +#include <asm/arch/imx-regs.h>
> +#include <asm/io.h>
> +
> +#define CONFIG_PHY_ADDR	0
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +#if !(defined(CONFIG_MII) || defined(CONFIG_CMD_MII))
> +#error "CONFIG_MII has to be defined!"
> +#endif
> +
> +//#define CONFIG_FEC_IMX27_DEBUG
>   
Please use #undef instead ( no  C++ -style comments).  Can you use 
debug() instead of this?
> +#ifdef CONFIG_FEC_IMX27_DEBUG
> +#define	PRINTF(fmt,args...)	printf (fmt ,##args)
> +#else
> +#define PRINTF(fmt,args...)
> +#endif
> +
> +static int fec_miiphy_read(struct miiphy_device *mdev, uint8_t phyAddr,
> +	uint8_t regAddr, uint16_t * retVal);
> +static int fec_miiphy_write(struct miiphy_device *mdev, uint8_t phyAddr,
> +	uint8_t regAddr, uint16_t data);
> +
> +typedef struct {
> +	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) */
> +} NBUF;
> +
> +fec_priv gfec=
> +{
> +	.eth       = (ethernet_regs *)IMX_FEC_BASE,
> +	.xcv_type  = MII100,
> +	.rbd_base  = NULL,
> +	.rbd_index = 0,
> +	.tbd_base  = NULL,
> +	.tbd_index = 0,
> +	.miiphy =
> +		{
> +			CONFIG_PHY_ADDR,
> +			fec_miiphy_read,
> +			fec_miiphy_write,
> +			0,
> +			NULL
> +		},
> +	.bd        = NULL,
> +};
> +
> +/*
> + * MII-interface related functions
> + */
> +static int fec_miiphy_read(struct miiphy_device *mdev, uint8_t phyAddr,
> +	uint8_t regAddr, uint16_t * retVal)
> +{
> +	struct eth_device *edev = mdev->edev;
> +	fec_priv *fec = (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);
>   
Line's too long
> +
> +	/*
> +	 * wait for the related interrupt
> +	 */
> +	start = get_timer_masked(); /* get_time_ns(); */
> +	while (!(readl(&fec->eth->ievent) & FEC_IEVENT_MII)) {
> +		if (get_timer (start) > (CONFIG_SYS_HZ /1000)  /* is_timeout(start, MSECOND)*/) {
>   
More long lines, please clean up globally.
> +			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);
> +	PRINTF("fec_miiphy_read: phy: %02x reg:%02x val:%#x\n", phyAddr, regAddr, *retVal);
> +	return 0;
> +}
> +
> +static int fec_miiphy_write(struct miiphy_device *mdev, uint8_t phyAddr,
> +	uint8_t regAddr, uint16_t data)
> +{
> +	struct eth_device *edev = mdev->edev;
> +	fec_priv *fec = (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(); /* get_time_ns(); */
> +	while (!(readl(&fec->eth->ievent) & FEC_IEVENT_MII)) {
> +		if (get_timer (start) > (CONFIG_SYS_HZ /1000)  /* is_timeout(start, MSECOND)*/) {
> +			printf("Write MDIO failed...\n");
> +			return -1;
> +		}
> +	}
> +
> +	/*
> +	 * clear MII interrupt bit
> +	 */
> +	writel(FEC_IEVENT_MII, &fec->eth->ievent);
> +	PRINTF("fec_miiphy_write: phy: %02x reg:%02x val:%#x\n", phyAddr, regAddr, data);
> +
> +	return 0;
> +}
> +
> +static int fec_rx_task_enable(fec_priv *fec)
> +{
> +	writel(1 << 24, &fec->eth->r_des_active);
> +	return 0;
> +}
> +
> +static int fec_rx_task_disable(fec_priv *fec)
> +{
> +	return 0;
> +}
> +
> +static int fec_tx_task_enable(fec_priv *fec)
> +{
> +	writel(1 << 24, &fec->eth->x_des_active);
> +	return 0;
> +}
> +
> +static int fec_tx_task_disable(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(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(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, 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)
> +{
> +	int i;
> +	int uninitialized = 0;
> +
> +	for (i=0;i<6;i++) {
> +		mac[6-1-i] = readl(&IIM_BANK_REG(0,(IIM0_MAC+i)));
> +	}
> +
> +	/* uninitialized if all 00 */
> +	if ((mac[0] == 0) && (mac[1] == 0) && (mac[2] == 0) &&
> +            (mac[3] == 0) && (mac[4] == 0) && (mac[5] == 0))
> +                uninitialized = 1;
> +
> +	/* uninitialized if all FF (could be safe) */
> +        if ((mac[0] == 0xff) && (mac[1] == 0xff) && (mac[2] == 0xff) &&
> +	    (mac[3] == 0xff) && (mac[4] == 0xff) && (mac[5] == 0xff))
> +	        uninitialized = 1;
> +
>   
Please use 'is_valid_ether_addr()' instead.  It's in "include/net.h"
> +	return uninitialized;
> +}
> +
> +static int fec_set_hwaddr(struct eth_device *dev, unsigned char *mac)
> +{
> +	fec_priv *fec = (fec_priv *)dev->priv;
> +//#define WTF_IS_THIS
> +#ifdef WTF_IS_THIS
>   
Please figure out WTF this is, and use it always or delete it.
> +	uint32_t crc = 0xffffffff;	/* initial value */
> +	uint8_t currByte;			/* byte for which to compute the CRC */
> +	int byte;			/* loop - counter */
> +	int bit;			/* loop - counter */
> +
> +	/*
> +	 * The algorithm used is the following:
> +	 * we loop on each of the six bytes of the provided address,
> +	 * and we compute the CRC by left-shifting the previous
> +	 * value by one position, so that each bit in the current
> +	 * byte of the address may contribute the calculation. If
> +	 * the latter and the MSB in the CRC are different, then
> +	 * the CRC value so computed is also ex-ored with the
> +	 * "polynomium generator". The current byte of the address
> +	 * is also shifted right by one bit at each iteration.
> +	 * This is because the CRC generatore in hardware is implemented
> +	 * as a shift-register with as many ex-ores as the radixes
> +	 * in the polynomium. This suggests that we represent the
> +	 * polynomiumm itself as a 32-bit constant.
> +	 */
> +	for (byte = 0; byte < 6; byte++) {
> +		currByte = mac[byte];
> +		for (bit = 0; bit < 8; bit++) {
> +			if ((currByte & 0x01) ^ (crc & 0x01)) {
> +				crc >>= 1;
> +				crc = crc ^ 0xedb88320;
> +			} else {
> +				crc >>= 1;
> +			}
> +			currByte >>= 1;
> +		}
> +	}
> +
> +	crc = crc >> 26;
> +
> +	/*
> +	 * Set individual hash table register
> +	 */
> +	if (crc >= 32) {
> +		fec->eth->iaddr1 = (1 << (crc - 32));
> +		fec->eth->iaddr2 = 0;
> +	} else {
> +		fec->eth->iaddr1 = 0;
> +		fec->eth->iaddr2 = (1 << crc);
> +	}
> +#else
> +	writel(0, &fec->eth->iaddr1);
> +	writel(0, &fec->eth->iaddr2);
> +	writel(0, &fec->eth->gaddr1);
> +	writel(0, &fec->eth->gaddr2);
> +#endif
> +	/*
> +	 * 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)
> +{
> +	fec_priv *fec = (fec_priv *)edev->priv;
> +
> +	PRINTF("fec_open: fec_open(dev)\n");
> +	writel(1 << 2, &fec->eth->x_cntrl);	/* full-duplex, heartbeat disabled */
> +	fec->rbd_index = 0;
> +
> +	/*
> +	 * Enable FEC-Lite controller
> +	 */
> +	writel(FEC_ECNTRL_ETHER_EN, &fec->eth->ecntrl);
> +
> +	if (fec->xcv_type != SEVENWIRE) {
> +		miiphy_wait_aneg(&fec->miiphy);
> +		miiphy_print_status(&fec->miiphy);
> +	}
> +
> +	/*
> +	 * 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 = 0;
> +	uint32_t base;
> +	fec_priv *fec = (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(FEC_BD) + DB_ALIGNMENT );
> +		memset((void *)base, 0, (2 + FEC_RBD_NUM) * sizeof(FEC_BD) + DB_ALIGNMENT);
> +		base += (DB_ALIGNMENT-1);
> +		base &= ~(DB_ALIGNMENT-1);
> +
> +		fec->rbd_base = (FEC_BD*)base;
> +
> +		base += FEC_RBD_NUM * sizeof(FEC_BD);
> +
> +		fec->tbd_base = (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);	/* No MII for 7-wire mode */
> +		PRINTF("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(&fec->miiphy);
> +
> +	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)
> +{
> +	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);
> +
> +	PRINTF("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;
> +	PRINTF("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.
> +	 */
> +	fec_priv *fec = (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 transmitt buffer
>   
s/transmitt/transmit/
> +	 * Note: We are always using the first buffer for transmission,
> +	 * the second will be empty and only used to stop the DMA engine
> +	 */
> +/*	{
> +		int i;
> +		PRINTF("fec_send %d bytes:", length);
> +			for (i=0;i<length;i++)
> +				PRINTF(" %02x", ((char*)packet)[i]);
> +			PRINTF("\n");
> +	}
> +*/	writew(length, &fec->tbd_base[fec->tbd_index].data_length);
>   
No dead code please
> +	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 */
> +	}
> +	PRINTF("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)
> +{
> +	fec_priv *fec = (fec_priv *)dev->priv;
> +	FEC_BD *rbd = &fec->rbd_base[fec->rbd_index];
> +	unsigned long ievent;
> +	int frame_length, len = 0;
> +	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);
> +	PRINTF("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);
> +	PRINTF("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 = (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);
> +/*			PRINTF("fec_recv %d bytes:", frame_length);
> +			for (len=0;len<frame_length;len++)
> +				PRINTF(" %02x", buff[len]);
> +			PRINTF("\n");
> +*/			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;
> +	}
> +	PRINTF("fec_recv: stop\n");
> +
> +	return len;
> +}
> +
> +static int fec_probe(bd_t * bd)
> +{
> +	/*struct fec_platform_data *pdata = (struct fec_platform_data *)dev->platform_data;*/
> +	struct eth_device *edev;
> +	fec_priv *fec = &gfec;
> +	unsigned char ethaddr_str[20];
> +	unsigned char ethaddr[6];
> +	char *tmp = getenv ("ethaddr");
> +	char *end;
> +
> +	/* enable FEC clock */
> +	PCCR1 |= PCCR1_HCLK_FEC;
> +	PCCR0 |= PCCR0_FEC_EN;
> +
> +	/*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 = (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; /*pdata->xcv_type;*/
> +
> +	sprintf(edev->name, "FEC ETHERNET");
> +
> +	if (fec->xcv_type != SEVENWIRE) {
> +		fec->miiphy.read = fec_miiphy_read;
> +		fec->miiphy.write = fec_miiphy_write;
> +		fec->miiphy.address = CONFIG_PHY_ADDR;
> +		fec->miiphy.flags = fec->xcv_type == MII10 ? MIIPHY_FORCE_10 : 0;
> +		fec->miiphy.edev = edev;
> +
> +		/* if multiple PHY have to be supported */
> +		/*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) {
> +		sprintf ((char*)ethaddr_str, "%02X:%02X:%02X:%02X:%02X:%02X",
> +			ethaddr[0], ethaddr[1], ethaddr[2], ethaddr[3],
> +			ethaddr[4], ethaddr[5]);
> +		printf("got MAC address from EEPROM: %s\n",ethaddr_str);
> +		setenv ("ethaddr", (char*)ethaddr_str);
> +	}
> +	memcpy(edev->enetaddr, ethaddr, 6);
> +	fec_set_hwaddr(edev, ethaddr);
> +
> +	return 0;
> +}
> +
> +static int once = 0;
>   
Please give this function scope instead of file scope.
> +
> +int eth_init(bd_t * bd)
> +{
> +
> +	if (!once)
> +	{
> +		PRINTF("eth_init: fec_probe(bd)\n");
> +		fec_probe(bd);
> +		once = 1;
> +	}
> +	PRINTF("eth_init: fec_init(gfec.miiphy.edev, bd)\n");
> +	return fec_init(gfec.miiphy.edev, bd);
> +};
> +
>   
This old-style API is deprecated.  Please remove it.
> +int fec_eth_initialize(bd_t *bd)
> +{
> +int lout=1;
> +
> +	if (!once)
> +	{
> +		PRINTF("eth_init: fec_probe(bd)\n");
> +		lout = fec_probe(bd);
> +		once = 1;
> +	}
> +	return lout;
> +}
>   
Is this really necessary?
> +
> +int eth_send(volatile void *packet, int length)
> +{
> +	PRINTF("eth_send: fec_send(gfec.miiphy.edev, packet 0x%08lx, length)\n", packet);
> +	return fec_send(gfec.miiphy.edev, packet, length);
> +};
> +
> +int eth_rx(void){
> +	PRINTF("eth_rcv: fec_rcv(gfec.miiphy.edev)\n");
> +	return fec_recv(gfec.miiphy.edev);
> +};
> +
> +
> +void eth_halt(void)
> +{
> +	PRINTF("eth_halt: fec_halt(gfec)\n");
> +	fec_halt(NULL);
> +	return;
> +};
>   
Again, the eth_init(), eth_send(), eth_rx() and eth_halt() functions 
need to go.
> +
> +/**
> + * @file
> + * @brief Network driver for FreeScale's FEC implementation.
> + * This type of hardware can be found on i.MX27 CPUs
> + */
> +
>   
What's this all about?
> diff --git a/drivers/net/fec_imx27.h b/drivers/net/fec_imx27.h
> new file mode 100644
> index 0000000..e47a708
> --- /dev/null
> +++ b/drivers/net/fec_imx27.h
> @@ -0,0 +1,305 @@
> +/*
> + * (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
> + */
> +typedef struct ethernet_register_set {
> +
> +/* [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 */
> +} ethernet_regs;
> +
> +#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)
> + */
> +typedef struct buffer_descriptor {
> +	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 */
> +} FEC_BD;
> +
> +/**
> + * Supported phy types on this platform
> + */
> +typedef enum {
> +	SEVENWIRE,	/**< 7-wire       */
> +	MII10,		/**< MII 10Mbps   */
> +	MII100		/**< MII 100Mbps  */
> +} xceiver_type;
> +
> +/**
> + * @brief i.MX27-FEC private structure
> + */
> +typedef struct {
> +	ethernet_regs *eth;		/**< pointer to register'S base */
> +	xceiver_type xcv_type;		/**< transceiver type */
> +	FEC_BD *rbd_base;		/**< RBD ring */
> +	int rbd_index;			/**< next receive BD to read */
> +	FEC_BD *tbd_base;		/**< TBD ring */
> +	int tbd_index;			/**< next transmit BD to write */
> +	struct miiphy_device miiphy;
> +	bd_t * bd;
> +} fec_priv;
> +
> +/**
> + * @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 */
> +#define FEC_RBD_LAST		0x0800	/**< Receive BD status: Buffer is last in frame (useless here!) */
> +#define FEC_RBD_MISS		0x0100	/**< Receive BD status: Miss bit for prom mode */
> +#define FEC_RBD_BC		0x0080	/**< Receive BD status: The received frame is broadcast frame */
> +#define FEC_RBD_MC		0x0040	/**< Receive BD status: The received frame is multicast frame */
> +#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 */
> +
> +/**
> + * @file
> + * @brief Definitions for the FEC driver (i.MX27)
> + */
> +
> diff --git a/drivers/net/imx27_miiphy.c b/drivers/net/imx27_miiphy.c
> new file mode 100644
> index 0000000..11cf7af
> --- /dev/null
> +++ b/drivers/net/imx27_miiphy.c
> @@ -0,0 +1,125 @@
> +/*
> + * miiphy.c - generic phy abstraction
> + *
> + * (C) Copyright 2008 Eric Jarrige <eric.jarrige@armadeus.org>
> + * Copyright (c) 2007 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
> + *
> + * See file CREDITS for list of people who contributed to this
> + * project.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2
> + * as published by the Free Software Foundation.
> + *
> + * 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 "imx27_miiphy.h"
> +
> +int miiphy_restart_aneg(struct miiphy_device *mdev)
> +{
> +	uint16_t status;
> +	int timeout;
> +
> +	/*
> +	 * Wake up from sleep if necessary
> +	 * Reset PHY, then delay 300ns
> +	 */
> +	mdev->write(mdev, mdev->address, MII_SPECIAL, 0x00FF);
> +	mdev->write(mdev, mdev->address, MII_BMCR, BMCR_RESET);
> +	udelay(1000);
> +
> +	if (mdev->flags & MIIPHY_FORCE_10) {
> +		printf("Forcing 10 Mbps ethernet link... ");
> +		mdev->read(mdev, mdev->address, MII_BMSR, &status);
> +		mdev->write(mdev, mdev->address, MII_BMCR, BMCR_FULLDPLX | BMCR_CTST);
> +
> +		timeout = 20;
> +		do {	/* wait for link status to go down */
> +			udelay(10000);
> +			if ((timeout--) == 0) {
> +#if (DEBUG & 0x2)
> +				printf("hmmm, should not have waited...");
> +#endif
> +				break;
> +			}
> +			mdev->read(mdev, mdev->address, MII_BMSR, &status);
> +		} while (status & BMSR_LSTATUS);
> +
> +	} else {	/* MII100 */
> +		/*
> +		 * Set the auto-negotiation advertisement register bits
> +		 */
> +		mdev->write(mdev, mdev->address, MII_ADVERTISE, ADVERTISE_ALL);
> +		mdev->write(mdev, mdev->address, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART);
> +	}
> +
> +	return 0;
> +}
> +
> +int miiphy_wait_aneg(struct miiphy_device *mdev)
> +{
> +	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", mdev->edev->name);
> +			return -1;
> +		}
> +
> +		if (mdev->read(mdev, mdev->address, MII_BMSR, &status)) {
> +			printf("%s: Autonegotiation failed. status: 0x%04x\n", mdev->edev->name, status);
> +			return -1;
> +		}
> +	} while (!(status & BMSR_LSTATUS));
> +
> +	return 0;
> +}
> +
> +int miiphy_print_status(struct miiphy_device *mdev)
> +{
> +	uint16_t bmsr, bmcr, lpa;
> +	char *duplex;
> +	int speed;
> +
> +	if (mdev->read(mdev, mdev->address, MII_BMSR, &bmsr) != 0)
> +		goto err_out;
> +	if (mdev->read(mdev, mdev->address, MII_BMCR, &bmcr) != 0)
> +		goto err_out;
> +	if (mdev->read(mdev, mdev->address, MII_LPA, &lpa) != 0)
> +		goto err_out;
> +
> +	printf("%s: Link is %s", mdev->edev->name,
> +			bmsr & BMSR_LSTATUS ? "up" : "down");
> +
> +	if (bmcr & BMCR_ANENABLE) {
> +		duplex = lpa & LPA_DUPLEX ? "Full" : "Half";
> +		speed = lpa & LPA_100 ? 100 : 10;
> +	} else {
> +		duplex = bmcr & BMCR_FULLDPLX ? "Full" : "Half";
> +		speed = bmcr & BMCR_SPEED100 ? 100 : 10;
> +	}
> +
> +	printf(" - %d/%s\n", speed, duplex);
> +
> +	return 0;
> +err_out:
> +	printf("%s: failed to read\n", mdev->edev->name);
> +	return -1;
> +}
> +
> +
> +
> diff --git a/drivers/net/imx27_miiphy.h b/drivers/net/imx27_miiphy.h
> new file mode 100644
> index 0000000..b381ea4
> --- /dev/null
> +++ b/drivers/net/imx27_miiphy.h
> @@ -0,0 +1,157 @@
> +/*
> + * linux/mii.h: definitions for MII-compatible transceivers
> + * Originally drivers/net/sunhme.h.
> + *
> + * (C) Copyright 2008 Eric Jarrige <eric.jarrige@armadeus.org>
> + * Copyright (C) 1996, 1999, 2001 David S. Miller (davem at redhat.com)
> + */
> +
> +#ifndef _IMX27_MII_PHY_H_
> +#define _IMX27_MII_PHY_H_
> +
> +#include <net.h>
> +
> +#define MIIPHY_FORCE_10	1
> +
> +#define MII_BMCR            0x00        /* Basic mode control register */
> +#define MII_BMSR            0x01        /* Basic mode status register  */
> +#define MII_PHYSID1         0x02        /* PHYS ID 1                   */
> +#define MII_PHYSID2         0x03        /* PHYS ID 2                   */
> +#define MII_ADVERTISE       0x04        /* Advertisement control reg   */
> +#define MII_LPA             0x05        /* Link partner ability reg    */
> +#define MII_EXPANSION       0x06        /* Expansion register          */
> +#define MII_CTRL1000        0x09        /* 1000BASE-T control          */
> +#define MII_STAT1000        0x0a        /* 1000BASE-T status           */
> +#define MII_ESTATUS	    0x0f	/* Extended Status	       */
> +#define MII_SPECIAL         0x12        /* Disconnect counter          */
> +#define MII_FCSCOUNTER      0x13        /* False carrier counter       */
> +#define MII_NWAYTEST        0x14        /* N-way auto-neg test reg     */
> +#define MII_RERRCOUNTER     0x15        /* Receive error counter       */
> +#define MII_SREVISION       0x16        /* Silicon revision            */
> +#define MII_RESV1           0x17        /* Reserved...                 */
> +#define MII_LBRERROR        0x18        /* Lpback, rx, bypass error    */
> +#define MII_PHYADDR         0x19        /* PHY address                 */
> +#define MII_RESV2           0x1a        /* Reserved...                 */
> +#define MII_TPISTATUS       0x1b        /* TPI status for 10mbps       */
> +#define MII_NCONFIG         0x1c        /* Network interface config    */
> +
> +/* Basic mode control register. */
> +#define BMCR_RESV               0x003f  /* Unused...                   */
> +#define BMCR_SPEED1000		0x0040  /* MSB of Speed (1000)         */
> +#define BMCR_CTST               0x0080  /* Collision test              */
> +#define BMCR_FULLDPLX           0x0100  /* Full duplex                 */
> +#define BMCR_ANRESTART          0x0200  /* Auto negotiation restart    */
> +#define BMCR_ISOLATE            0x0400  /* Disconnect DP83840 from MII */
> +#define BMCR_PDOWN              0x0800  /* Powerdown the DP83840       */
> +#define BMCR_ANENABLE           0x1000  /* Enable auto negotiation     */
> +#define BMCR_SPEED100           0x2000  /* Select 100Mbps              */
> +#define BMCR_LOOPBACK           0x4000  /* TXD loopback bits           */
> +#define BMCR_RESET              0x8000  /* Reset the DP83840           */
> +
> +/* Basic mode status register. */
> +#define BMSR_ERCAP              0x0001  /* Ext-reg capability          */
> +#define BMSR_JCD                0x0002  /* Jabber detected             */
> +#define BMSR_LSTATUS            0x0004  /* Link status                 */
> +#define BMSR_ANEGCAPABLE        0x0008  /* Able to do auto-negotiation */
> +#define BMSR_RFAULT             0x0010  /* Remote fault detected       */
> +#define BMSR_ANEGCOMPLETE       0x0020  /* Auto-negotiation complete   */
> +#define BMSR_RESV               0x00c0  /* Unused...                   */
> +#define BMSR_ESTATEN		0x0100	/* Extended Status in R15 */
> +#define BMSR_100HALF2           0x0200  /* Can do 100BASE-T2 HDX */
> +#define BMSR_100FULL2           0x0400  /* Can do 100BASE-T2 FDX */
> +#define BMSR_10HALF             0x0800  /* Can do 10mbps, half-duplex  */
> +#define BMSR_10FULL             0x1000  /* Can do 10mbps, full-duplex  */
> +#define BMSR_100HALF            0x2000  /* Can do 100mbps, half-duplex */
> +#define BMSR_100FULL            0x4000  /* Can do 100mbps, full-duplex */
> +#define BMSR_100BASE4           0x8000  /* Can do 100mbps, 4k packets  */
> +
> +/* Advertisement control register. */
> +#define ADVERTISE_SLCT          0x001f  /* Selector bits               */
> +#define ADVERTISE_CSMA          0x0001  /* Only selector supported     */
> +#define ADVERTISE_10HALF        0x0020  /* Try for 10mbps half-duplex  */
> +#define ADVERTISE_1000XFULL     0x0020  /* Try for 1000BASE-X full-duplex */
> +#define ADVERTISE_10FULL        0x0040  /* Try for 10mbps full-duplex  */
> +#define ADVERTISE_1000XHALF     0x0040  /* Try for 1000BASE-X half-duplex */
> +#define ADVERTISE_100HALF       0x0080  /* Try for 100mbps half-duplex */
> +#define ADVERTISE_1000XPAUSE    0x0080  /* Try for 1000BASE-X pause    */
> +#define ADVERTISE_100FULL       0x0100  /* Try for 100mbps full-duplex */
> +#define ADVERTISE_1000XPSE_ASYM 0x0100  /* Try for 1000BASE-X asym pause */
> +#define ADVERTISE_100BASE4      0x0200  /* Try for 100mbps 4k packets  */
> +#define ADVERTISE_PAUSE_CAP     0x0400  /* Try for pause               */
> +#define ADVERTISE_PAUSE_ASYM    0x0800  /* Try for asymetric pause     */
> +#define ADVERTISE_RESV          0x1000  /* Unused...                   */
> +#define ADVERTISE_RFAULT        0x2000  /* Say we can detect faults    */
> +#define ADVERTISE_LPACK         0x4000  /* Ack link partners response  */
> +#define ADVERTISE_NPAGE         0x8000  /* Next page bit               */
> +
> +#define ADVERTISE_FULL (ADVERTISE_100FULL | ADVERTISE_10FULL | \
> +			ADVERTISE_CSMA)
> +#define ADVERTISE_ALL (ADVERTISE_10HALF | ADVERTISE_10FULL | \
> +                       ADVERTISE_100HALF | ADVERTISE_100FULL)
> +
> +/* Link partner ability register. */
> +#define LPA_SLCT                0x001f  /* Same as advertise selector  */
> +#define LPA_10HALF              0x0020  /* Can do 10mbps half-duplex   */
> +#define LPA_1000XFULL           0x0020  /* Can do 1000BASE-X full-duplex */
> +#define LPA_10FULL              0x0040  /* Can do 10mbps full-duplex   */
> +#define LPA_1000XHALF           0x0040  /* Can do 1000BASE-X half-duplex */
> +#define LPA_100HALF             0x0080  /* Can do 100mbps half-duplex  */
> +#define LPA_1000XPAUSE          0x0080  /* Can do 1000BASE-X pause     */
> +#define LPA_100FULL             0x0100  /* Can do 100mbps full-duplex  */
> +#define LPA_1000XPAUSE_ASYM     0x0100  /* Can do 1000BASE-X pause asym*/
> +#define LPA_100BASE4            0x0200  /* Can do 100mbps 4k packets   */
> +#define LPA_PAUSE_CAP           0x0400  /* Can pause                   */
> +#define LPA_PAUSE_ASYM          0x0800  /* Can pause asymetrically     */
> +#define LPA_RESV                0x1000  /* Unused...                   */
> +#define LPA_RFAULT              0x2000  /* Link partner faulted        */
> +#define LPA_LPACK               0x4000  /* Link partner acked us       */
> +#define LPA_NPAGE               0x8000  /* Next page bit               */
> +
> +#define LPA_DUPLEX		(LPA_10FULL | LPA_100FULL)
> +#define LPA_100			(LPA_100FULL | LPA_100HALF | LPA_100BASE4)
> +
> +/* Expansion register for auto-negotiation. */
> +#define EXPANSION_NWAY          0x0001  /* Can do N-way auto-nego      */
> +#define EXPANSION_LCWP          0x0002  /* Got new RX page code word   */
> +#define EXPANSION_ENABLENPAGE   0x0004  /* This enables npage words    */
> +#define EXPANSION_NPCAPABLE     0x0008  /* Link partner supports npage */
> +#define EXPANSION_MFAULTS       0x0010  /* Multiple faults detected    */
> +#define EXPANSION_RESV          0xffe0  /* Unused...                   */
> +
> +#define ESTATUS_1000_TFULL	0x2000	/* Can do 1000BT Full */
> +#define ESTATUS_1000_THALF	0x1000	/* Can do 1000BT Half */
> +
> +/* N-way test register. */
> +#define NWAYTEST_RESV1          0x00ff  /* Unused...                   */
> +#define NWAYTEST_LOOPBACK       0x0100  /* Enable loopback for N-way   */
> +#define NWAYTEST_RESV2          0xfe00  /* Unused...                   */
> +
> +/* 1000BASE-T Control register */
> +#define ADVERTISE_1000FULL      0x0200  /* Advertise 1000BASE-T full duplex */
> +#define ADVERTISE_1000HALF      0x0100  /* Advertise 1000BASE-T half duplex */
> +
> +/* 1000BASE-T Status register */
> +#define LPA_1000LOCALRXOK       0x2000  /* Link partner local receiver status */
> +#define LPA_1000REMRXOK         0x1000  /* Link partner remote receiver status */
> +#define LPA_1000FULL            0x0800  /* Link partner 1000BASE-T full duplex */
> +#define LPA_1000HALF            0x0400  /* Link partner 1000BASE-T half duplex */
> +
>   
This stuff's all standard (or at least most of it).  Please use what's 
in "include/miiphy.h" intead of redefining.
> +struct miiphy_device {
> +	/*struct device_d dev;*/
> +
> +	int address;	/* The address the phy has on the bus */
> +	int (*read)(struct miiphy_device *mdev, uint8_t phy_addr, uint8_t reg_addr, uint16_t *value);
> +	int (*write)(struct miiphy_device *mdev, uint8_t phy_addr, uint8_t reg_addr, uint16_t data);
> +
> +	int flags;
> +
> +	struct eth_device *edev;
> +};
> +
> +int miiphy_register(struct miiphy_device *mdev);
> +int miiphy_restart_aneg(struct miiphy_device *mdev);
> +int miiphy_wait_aneg(struct miiphy_device *mdev);
> +int miiphy_print_status(struct miiphy_device *mdev);
> +
> +#endif
> +
>   
Can't you use the miiphy framework that's already in place?

regards,
Ben

  reply	other threads:[~2009-05-06 19:51 UTC|newest]

Thread overview: 49+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-05-06 18:30 [U-Boot] [PATCH 00/10] Support for LogicPD i.MX27-LITEKIT development board Ilya Yanok
2009-05-06 18:30 ` [U-Boot] [PATCH 01/10] mx27: basic cpu support Ilya Yanok
2009-05-06 20:30   ` Magnus Lilja
2009-05-06 21:16   ` Wolfgang Denk
2009-05-13 22:54     ` Ilya Yanok
2009-05-14  8:10       ` Wolfgang Denk
2009-05-14  9:23         ` Ilya Yanok
2009-05-14  9:42           ` Wolfgang Denk
2009-05-14 10:26             ` Ilya Yanok
2009-05-14 12:33               ` Wolfgang Denk
2009-05-18 16:59             ` Magnus Lilja
2009-05-18 17:34               ` Scott Wood
2009-05-18 18:42               ` Wolfgang Denk
2009-05-14 13:40         ` Sascha Hauer
2009-05-14 13:56           ` Wolfgang Denk
2009-05-06 18:30 ` [U-Boot] [PATCH 02/10] serial_mx31: allow it to work with mx27 too Ilya Yanok
2009-05-06 21:16   ` Wolfgang Denk
2009-05-06 18:30 ` [U-Boot] [PATCH 03/10] fec_imx27: driver for FEC ethernet controller on i.MX27 Ilya Yanok
2009-05-06 19:51   ` Ben Warren [this message]
2009-05-06 21:20   ` Wolfgang Denk
2009-05-06 18:30 ` [U-Boot] [PATCH 04/10] mxc_nand: add nand driver for MX2/MX3 Ilya Yanok
2009-05-06 20:31   ` Magnus Lilja
2009-05-06 21:25   ` Wolfgang Denk
2009-05-08  8:39   ` Ivo Clarysse
2009-05-08  8:58     ` Magnus Lilja
2009-05-06 18:30 ` [U-Boot] [PATCH 05/10] mxc-mmc: sdhc host driver for MX2 and MX3 proccessor Ilya Yanok
2009-05-08  0:26   ` alfred steele
2009-05-13 21:50   ` alfred steele
2009-05-06 18:30 ` [U-Boot] [PATCH 06/10] arm: add support for CONFIG_GENERIC_MMC Ilya Yanok
2009-05-06 18:30 ` [U-Boot] [PATCH 07/10] mmc: use lldiv() for 64-bit division Ilya Yanok
2009-05-06 20:32   ` Magnus Lilja
2009-05-08 22:42   ` Andy Fleming
2009-05-06 18:30 ` [U-Boot] [PATCH 08/10] mmc: some endianess fixes for generic mmc subsystem Ilya Yanok
2009-05-08 22:43   ` Andy Fleming
2009-05-06 18:30 ` [U-Boot] [PATCH 09/10] mmc: fix mmcinfo command Ilya Yanok
2009-05-08 22:43   ` Andy Fleming
2009-05-06 18:30 ` [U-Boot] [PATCH 10/10] imx27lite: add support for imx27lite board from LogicPD Ilya Yanok
2009-05-06 20:34   ` Magnus Lilja
2009-05-08 18:19     ` Magnus Lilja
2009-05-06 21:29   ` Wolfgang Denk
2009-05-19 16:17   ` Paul Thomas
2009-05-20 18:49     ` Ilya Yanok
2009-05-20 19:49       ` Paul Thomas
2009-05-28 19:46       ` Paul Thomas
2009-05-28 21:45         ` Wolfgang Denk
2009-05-28 21:51           ` Paul Thomas
2009-06-11 22:38           ` Paul Thomas
2009-06-13 23:04             ` Paul Thomas
2009-05-06 21:26 ` [U-Boot] [PATCH 00/10] Support for LogicPD i.MX27-LITEKIT development board Wolfgang Denk

Reply instructions:

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

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

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

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

  git send-email \
    --in-reply-to=4A01EA4F.3070409@gmail.com \
    --to=biggerbadderben@gmail.com \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

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

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