[Armadeus-commitlog] SF.net SVN: armadeus: [783] branches/apf2/buildroot/target/device/armadeus/ l
Brought to you by:
sszy
|
From: <ar...@us...> - 2008-04-02 11:54:52
|
Revision: 783
http://armadeus.svn.sourceforge.net/armadeus/?rev=783&view=rev
Author: artemys
Date: 2008-04-02 04:54:58 -0700 (Wed, 02 Apr 2008)
Log Message:
-----------
[LINUX] Add support for i.MX27 Ethernet controller (old but working driver)
Added Paths:
-----------
branches/apf2/buildroot/target/device/armadeus/linux/kernel-patches/2.6.25-rc7/220-apf27-pengu-fec-old.diff
Added: branches/apf2/buildroot/target/device/armadeus/linux/kernel-patches/2.6.25-rc7/220-apf27-pengu-fec-old.diff
===================================================================
--- branches/apf2/buildroot/target/device/armadeus/linux/kernel-patches/2.6.25-rc7/220-apf27-pengu-fec-old.diff (rev 0)
+++ branches/apf2/buildroot/target/device/armadeus/linux/kernel-patches/2.6.25-rc7/220-apf27-pengu-fec-old.diff 2008-04-02 11:54:58 UTC (rev 783)
@@ -0,0 +1,3402 @@
+Subject: [@num@/@total@] i.MX27: Adding network support (reference only)
+From: Juergen Beisert <j.b...@pe...>
+
+This patch adds network support for the phyCORE-i.MX27 cpu module (aka
+pcm038). The patch is here for reference only and to make it possible
+for people to actually work with the board. It is more or less a copy of
+the original ifdef-cluttered patch from Freescale, cleaned up to only
+contain i.MX27-FEC code and does not even follow the driver model
+correctly. Has to be reworked before it can go into the mainline.
+
+The FEC is similar to that one on the MPC5200B; we don't know if it is
+worth the effort to merge it with the mpc-fec code. Oppinions?
+
+Signed-off-by: Juergen Beisert <j.b...@pe...>
+
+---
+
+ drivers/net/Kconfig | 7
+ drivers/net/Makefile | 1
+ drivers/net/fec_old.c | 3164 ++++++++++++++++++++++++++++++++++++++++++++++++++
+ drivers/net/fec_old.h | 175 ++
+ 4 files changed, 3347 insertions(+)
+
+Index: drivers/net/Makefile
+===================================================================
+--- linux/drivers/net/Makefile.orig
++++ linux/drivers/net/Makefile
+@@ -104,6 +104,7 @@ obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx
+ ifeq ($(CONFIG_FEC_MPC52xx_MDIO),y)
+ obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx_phy.o
+ endif
++obj-$(CONFIG_FEC_OLD) += fec_old.o
+ obj-$(CONFIG_68360_ENET) += 68360enet.o
+ obj-$(CONFIG_WD80x3) += wd.o 8390.o
+ obj-$(CONFIG_EL2) += 3c503.o 8390.o
+Index: drivers/net/Kconfig
+===================================================================
+--- linux/drivers/net/Kconfig.orig
++++ linux/drivers/net/Kconfig
+@@ -1884,6 +1884,13 @@ config FEC_MPC52xx_MDIO
+ If not sure, enable.
+ If compiled as module, it will be called 'fec_mpc52xx_phy.ko'.
+
++config FEC_OLD
++ tristate "FEC ethernet controller"
++ depends on ARCH_MX2
++ help
++ Say Y here if you want to use the built-in 10/100 Fast ethernet
++ controller on some Motorola/Freescale processors.
++
+ config NE_H8300
+ tristate "NE2000 compatible support for H8/300"
+ depends on H8300
+Index: drivers/net/fec_old.c
+===================================================================
+--- /dev/null
++++ linux/drivers/net/fec_old.c
+@@ -0,0 +1,3164 @@
++/*
++ * Fast Ethernet Controller (FEC) driver for Motorola MPC8xx.
++ * Copyright (c) 1997 Dan Malek (dm...@jl...)
++ *
++ * This version of the driver is specific to the FADS implementation,
++ * since the board contains control registers external to the processor
++ * for the control of the LevelOne LXT970 transceiver. The MPC860T manual
++ * describes connections using the internal parallel port I/O, which
++ * is basically all of Port D.
++ *
++ * Right now, I am very wasteful with the buffers. I allocate memory
++ * pages and then divide them into 2K frame buffers. This way I know I
++ * have buffers large enough to hold one frame within one buffer descriptor.
++ * Once I get this working, I will use 64 or 128 byte CPM buffers, which
++ * will be much more memory efficient and will easily handle lots of
++ * small packets.
++ *
++ * Much better multiple PHY support by Magnus Damm.
++ * Copyright (c) 2000 Ericsson Radio Systems AB.
++ *
++ * Support for FEC controller of ColdFire processors.
++ * Copyright (c) 2001-2005 Greg Ungerer (ge...@sn...)
++ *
++ * Bug fixes and cleanup by Philippe De Muyter (ph...@ma...)
++ * Copyright (c) 2004-2006 Macq Electronique SA.
++ */
++/*
++ * Copyright 2006-2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/string.h>
++#include <linux/ptrace.h>
++#include <linux/errno.h>
++#include <linux/ioport.h>
++#include <linux/slab.h>
++#include <linux/interrupt.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/skbuff.h>
++#include <linux/spinlock.h>
++#include <linux/workqueue.h>
++#include <linux/bitops.h>
++#include <linux/clk.h>
++#include <linux/kthread.h>
++#include <linux/delay.h>
++
++#include <asm/irq.h>
++#include <asm/uaccess.h>
++#include <asm/io.h>
++#include <asm/pgtable.h>
++
++#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || \
++ defined(CONFIG_M5272) || defined(CONFIG_M528x) || \
++ defined(CONFIG_M520x) || defined(CONFIG_M532x)
++#include <asm/coldfire.h>
++#include <asm/mcfsim.h>
++#include "fec_old.h"
++#define FEC_ALIGNMENT (0x03) /*FEC needs 4bytes alignment*/
++#elif defined(CONFIG_ARCH_MXC)
++#include <asm/arch/hardware.h>
++#include <asm/arch/iim.h>
++#include "fec_old.h"
++#define FEC_ALIGNMENT (0x0F) /*FEC needs 128bits(32bytes) alignment*/
++#else
++#include <asm/8xx_immap.h>
++#include <asm/mpc8xx.h>
++#include "commproc.h"
++#define FEC_ALIGNMENT (0x03) /*FEC needs 4bytes alignment */
++#endif
++
++#define FEC_ADDR_ALIGNMENT(x) ((unsigned char *)(((unsigned long )(x) + (FEC_ALIGNMENT)) & (~FEC_ALIGNMENT)))
++
++#if defined(CONFIG_FEC2)
++#define FEC_MAX_PORTS 2
++#else
++#define FEC_MAX_PORTS 1
++#endif
++
++/*
++ * Define the fixed address of the FEC hardware.
++ */
++static unsigned int fec_hw[] = {
++#if defined(CONFIG_M5272)
++ (MCF_MBAR + 0x840),
++#elif defined(CONFIG_M527x)
++ (MCF_MBAR + 0x1000),
++ (MCF_MBAR + 0x1800),
++#elif defined(CONFIG_M523x) || defined(CONFIG_M528x)
++ (MCF_MBAR + 0x1000),
++#elif defined(CONFIG_M520x)
++ (MCF_MBAR+0x30000),
++#elif defined(CONFIG_M532x)
++ (MCF_MBAR+0xfc030000),
++#elif defined(CONFIG_ARCH_MXC)
++ (IO_ADDRESS(FEC_BASE_ADDR)),
++#else
++ &(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec),
++#endif
++};
++
++static unsigned char fec_mac_default[] = {
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++};
++
++/*
++ * Some hardware gets it MAC address out of local flash memory.
++ * if this is non-zero then assume it is the address to get MAC from.
++ */
++#if defined(CONFIG_NETtel)
++#define FEC_FLASHMAC 0xf0006006
++#elif defined(CONFIG_GILBARCONAP) || defined(CONFIG_SCALES)
++#define FEC_FLASHMAC 0xf0006000
++#elif defined (CONFIG_MTD_KeyTechnology)
++#define FEC_FLASHMAC 0xffe04000
++#elif defined(CONFIG_CANCam)
++#define FEC_FLASHMAC 0xf0020000
++#elif defined (CONFIG_M5272C3)
++#define FEC_FLASHMAC (0xffe04000 + 4)
++#elif defined(CONFIG_MOD5272)
++#define FEC_FLASHMAC 0xffc0406b
++#else
++#define FEC_FLASHMAC 0
++#endif
++
++/* Forward declarations of some structures to support different PHYs
++*/
++
++typedef struct {
++ uint mii_data;
++ void (*funct)(uint mii_reg, struct net_device *dev);
++} phy_cmd_t;
++
++typedef struct {
++ uint id;
++ char *name;
++
++ const phy_cmd_t *config;
++ const phy_cmd_t *startup;
++ const phy_cmd_t *ack_int;
++ const phy_cmd_t *shutdown;
++} phy_info_t;
++
++/* The number of Tx and Rx buffers. These are allocated from the page
++ * pool. The code may assume these are power of two, so it it best
++ * to keep them that size.
++ * We don't need to allocate pages for the transmitter. We just use
++ * the skbuffer directly.
++ */
++#define FEC_ENET_RX_PAGES 8
++#define FEC_ENET_RX_FRSIZE 2048
++#define FEC_ENET_RX_FRPPG (PAGE_SIZE / FEC_ENET_RX_FRSIZE)
++#define RX_RING_SIZE (FEC_ENET_RX_FRPPG * FEC_ENET_RX_PAGES)
++#define FEC_ENET_TX_FRSIZE 2048
++#define FEC_ENET_TX_FRPPG (PAGE_SIZE / FEC_ENET_TX_FRSIZE)
++#define TX_RING_SIZE 16 /* Must be power of two */
++#define TX_RING_MOD_MASK 15 /* for this to work */
++
++#if (((RX_RING_SIZE + TX_RING_SIZE) * 8) > PAGE_SIZE)
++#error "FEC: descriptor ring size constants too large"
++#endif
++
++/* Interrupt events/masks.
++*/
++#define FEC_ENET_HBERR ((uint)0x80000000) /* Heartbeat error */
++#define FEC_ENET_BABR ((uint)0x40000000) /* Babbling receiver */
++#define FEC_ENET_BABT ((uint)0x20000000) /* Babbling transmitter */
++#define FEC_ENET_GRA ((uint)0x10000000) /* Graceful stop complete */
++#define FEC_ENET_TXF ((uint)0x08000000) /* Full frame transmitted */
++#define FEC_ENET_TXB ((uint)0x04000000) /* A buffer was transmitted */
++#define FEC_ENET_RXF ((uint)0x02000000) /* Full frame received */
++#define FEC_ENET_RXB ((uint)0x01000000) /* A buffer was received */
++#define FEC_ENET_MII ((uint)0x00800000) /* MII interrupt */
++#define FEC_ENET_EBERR ((uint)0x00400000) /* SDMA bus error */
++
++#ifndef CONFIG_ARCH_MXC
++#define FEC_ENET_MASK ((uint)0xffc00000)
++#else
++#define FEC_ENET_MASK ((uint)0xfff80000)
++#endif
++
++/* The FEC stores dest/src/type, data, and checksum for receive packets.
++ */
++#define PKT_MAXBUF_SIZE 1518
++#define PKT_MINBUF_SIZE 64
++#define PKT_MAXBLR_SIZE 1520
++
++
++/*
++ * The 5270/5271/5280/5282/532x RX control register also contains maximum frame
++ * size bits. Other FEC hardware does not, so we need to take that into
++ * account when setting it.
++ */
++#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
++ defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_ARCH_MXC)
++#define OPT_FRAME_SIZE (PKT_MAXBUF_SIZE << 16)
++#else
++#define OPT_FRAME_SIZE 0
++#endif
++
++/* The FEC buffer descriptors track the ring buffers. The rx_bd_base and
++ * tx_bd_base always point to the base of the buffer descriptors. The
++ * cur_rx and cur_tx point to the currently available buffer.
++ * The dirty_tx tracks the current buffer that is being sent by the
++ * controller. The cur_tx and dirty_tx are equal under both completely
++ * empty and completely full conditions. The empty/ready indicator in
++ * the buffer descriptor determines the actual condition.
++ */
++struct fec_enet_private {
++ /* Hardware registers of the FEC device */
++ volatile fec_t *hwp;
++
++ struct net_device *netdev;
++
++ /* The saved address of a sent-in-place packet/buffer, for skfree(). */
++ unsigned char *tx_bounce[TX_RING_SIZE];
++ struct sk_buff* tx_skbuff[TX_RING_SIZE];
++ struct sk_buff* rx_skbuff[RX_RING_SIZE];
++ ushort skb_cur;
++ ushort skb_dirty;
++
++ /* CPM dual port RAM relative addresses.
++ */
++ void * cbd_mem_base; /* save the virtual base address of rx&tx buffer descripter */
++ cbd_t *rx_bd_base; /* Address of Rx and Tx buffers. */
++ cbd_t *tx_bd_base;
++ cbd_t *cur_rx, *cur_tx; /* The next free ring entry */
++ cbd_t *dirty_tx; /* The ring entries to be free()ed. */
++ struct net_device_stats stats;
++ uint tx_full;
++ spinlock_t lock;
++
++ uint phy_id;
++ uint phy_id_done;
++ uint phy_status;
++ uint phy_speed;
++ phy_info_t const *phy;
++ struct work_struct phy_task;
++
++ uint sequence_done;
++ uint mii_phy_task_queued;
++
++ uint phy_addr;
++
++ int index;
++ int opened;
++ int link;
++ int old_link;
++ int full_duplex;
++
++ struct clk *clk;
++};
++
++static int fec_enet_open(struct net_device *dev);
++static int fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev);
++static void fec_enet_mii(struct net_device *dev);
++static irqreturn_t fec_enet_interrupt(int irq, void * dev_id);
++static void fec_enet_tx(struct net_device *dev);
++static void fec_enet_rx(struct net_device *dev);
++static int fec_enet_close(struct net_device *dev);
++static struct net_device_stats *fec_enet_get_stats(struct net_device *dev);
++static void set_multicast_list(struct net_device *dev);
++static void fec_restart(struct net_device *dev, int duplex);
++static void fec_stop(struct net_device *dev);
++static void fec_set_mac_address(struct net_device *dev);
++
++static void __inline__ fec_dcache_inv_range(void * start, void * end);
++static void __inline__ fec_dcache_flush_range(void * start, void * end);
++
++/*
++ * fec_copy_threshold controls the copy when recieving ethernet frame.
++ * If ethernet header aligns 4bytes, the ip header and upper header will not aligns 4bytes.
++ * The resean is ethernet header is 14bytes.
++ * And the max size of tcp & ip header is 128bytes. Normally it is 40bytes.
++ * So I set the default value between 128 to 256.
++ */
++static int fec_copy_threshold = 192;
++
++/*
++ * fec_device records the devices created for cleanup
++ */
++struct net_device *fec_device[FEC_MAX_PORTS];
++
++/* MII processing. We keep this as simple as possible. Requests are
++ * placed on the list (if there is room). When the request is finished
++ * by the MII, an optional function may be called.
++ */
++typedef struct mii_list {
++ uint mii_regval;
++ void (*mii_func)(uint val, struct net_device *dev);
++ struct mii_list *mii_next;
++} mii_list_t;
++
++#define NMII 20
++static mii_list_t mii_cmds[NMII];
++static mii_list_t *mii_free;
++static mii_list_t *mii_head;
++static mii_list_t *mii_tail;
++
++static int mii_queue(struct net_device *dev, int request,
++ void (*func)(uint, struct net_device *));
++
++/* Make MII read/write commands for the FEC.
++*/
++#define mk_mii_read(REG) (0x60020000 | ((REG & 0x1f) << 18))
++#define mk_mii_write(REG, VAL) (0x50020000 | ((REG & 0x1f) << 18) | \
++ (VAL & 0xffff))
++#define mk_mii_end 0
++
++/* Transmitter timeout.
++*/
++#define TX_TIMEOUT (2*HZ)
++
++/* Register definitions for the PHY.
++*/
++
++#define MII_REG_CR 0 /* Control Register */
++#define MII_REG_SR 1 /* Status Register */
++#define MII_REG_PHYIR1 2 /* PHY Identification Register 1 */
++#define MII_REG_PHYIR2 3 /* PHY Identification Register 2 */
++#define MII_REG_ANAR 4 /* A-N Advertisement Register */
++#define MII_REG_ANLPAR 5 /* A-N Link Partner Ability Register */
++#define MII_REG_ANER 6 /* A-N Expansion Register */
++#define MII_REG_ANNPTR 7 /* A-N Next Page Transmit Register */
++#define MII_REG_ANLPRNPR 8 /* A-N Link Partner Received Next Page Reg. */
++
++/* values for phy_status */
++
++#define PHY_CONF_ANE 0x0001 /* 1 auto-negotiation enabled */
++#define PHY_CONF_LOOP 0x0002 /* 1 loopback mode enabled */
++#define PHY_CONF_SPMASK 0x00f0 /* mask for speed */
++#define PHY_CONF_10HDX 0x0010 /* 10 Mbit half duplex supported */
++#define PHY_CONF_10FDX 0x0020 /* 10 Mbit full duplex supported */
++#define PHY_CONF_100HDX 0x0040 /* 100 Mbit half duplex supported */
++#define PHY_CONF_100FDX 0x0080 /* 100 Mbit full duplex supported */
++
++#define PHY_STAT_LINK 0x0100 /* 1 up - 0 down */
++#define PHY_STAT_FAULT 0x0200 /* 1 remote fault */
++#define PHY_STAT_ANC 0x0400 /* 1 auto-negotiation complete */
++#define PHY_STAT_SPMASK 0xf000 /* mask for speed */
++#define PHY_STAT_10HDX 0x1000 /* 10 Mbit half duplex selected */
++#define PHY_STAT_10FDX 0x2000 /* 10 Mbit full duplex selected */
++#define PHY_STAT_100HDX 0x4000 /* 100 Mbit half duplex selected */
++#define PHY_STAT_100FDX 0x8000 /* 100 Mbit full duplex selected */
++
++
++static int
++fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++ struct fec_enet_private *fep;
++ volatile fec_t *fecp;
++ volatile cbd_t *bdp;
++ unsigned short status;
++
++ fep = netdev_priv(dev);
++ fecp = (volatile fec_t*)dev->base_addr;
++
++ if (!fep->link) {
++ /* Link is down or autonegotiation is in progress. */
++ return 1;
++ }
++
++ /* Fill in a Tx ring entry */
++ bdp = fep->cur_tx;
++
++ status = bdp->cbd_sc;
++#ifndef final_version
++ if (status & BD_ENET_TX_READY) {
++ /* Ooops. All transmit buffers are full. Bail out.
++ * This should not happen, since dev->tbusy should be set.
++ */
++ printk("%s: tx queue full!.\n", dev->name);
++ return 1;
++ }
++#endif
++
++ /* Clear all of the status flags.
++ */
++ status &= ~BD_ENET_TX_STATS;
++
++ /* Set buffer length and buffer pointer.
++ */
++ bdp->cbd_bufaddr = __pa(skb->data);
++ bdp->cbd_datlen = skb->len;
++
++ /*
++ * On some FEC implementations data must be aligned on
++ * 4-byte boundaries. Use bounce buffers to copy data
++ * and get it aligned. Ugh.
++ */
++ if ((bdp->cbd_bufaddr) & FEC_ALIGNMENT) {
++ unsigned int index;
++ index = bdp - fep->tx_bd_base;
++ memcpy(fep->tx_bounce[index], (void *) skb->data, skb->len);
++ bdp->cbd_bufaddr = __pa(fep->tx_bounce[index]);
++ }
++
++ /* Save skb pointer.
++ */
++ fep->tx_skbuff[fep->skb_cur] = skb;
++
++ fep->stats.tx_bytes += skb->len;
++ fep->skb_cur = (fep->skb_cur+1) & TX_RING_MOD_MASK;
++
++ /* Push the data cache so the CPM does not get stale memory
++ * data.
++ */
++ fec_dcache_flush_range(__va(bdp->cbd_bufaddr), __va(bdp->cbd_bufaddr) +
++ bdp->cbd_datlen);
++
++ spin_lock_irq(&fep->lock);
++
++ /* Send it on its way. Tell FEC it's ready, interrupt when done,
++ * it's the last BD of the frame, and to put the CRC on the end.
++ */
++
++ status |= (BD_ENET_TX_READY | BD_ENET_TX_INTR
++ | BD_ENET_TX_LAST | BD_ENET_TX_TC);
++ bdp->cbd_sc = status;
++
++ dev->trans_start = jiffies;
++
++ /* Trigger transmission start */
++ fecp->fec_x_des_active = 0x01000000;
++
++ /* If this was the last BD in the ring, start at the beginning again.
++ */
++ if (status & BD_ENET_TX_WRAP) {
++ bdp = fep->tx_bd_base;
++ } else {
++ bdp++;
++ }
++
++ if (bdp == fep->dirty_tx) {
++ fep->tx_full = 1;
++ netif_stop_queue(dev);
++ }
++
++ fep->cur_tx = (cbd_t *)bdp;
++
++ spin_unlock_irq(&fep->lock);
++
++ return 0;
++}
++
++static void
++fec_timeout(struct net_device *dev)
++{
++ struct fec_enet_private *fep = netdev_priv(dev);
++
++ printk("%s: transmit timed out.\n", dev->name);
++ fep->stats.tx_errors++;
++#ifndef final_version
++ {
++ int i;
++ cbd_t *bdp;
++
++ printk("Ring data dump: cur_tx %lx%s, dirty_tx %lx cur_rx: %lx\n",
++ (unsigned long)fep->cur_tx, fep->tx_full ? " (full)" : "",
++ (unsigned long)fep->dirty_tx,
++ (unsigned long)fep->cur_rx);
++
++ bdp = fep->tx_bd_base;
++ printk(" tx: %u buffers\n", TX_RING_SIZE);
++ for (i = 0 ; i < TX_RING_SIZE; i++) {
++ printk(" %08x: %04x %04x %08x\n",
++ (uint) bdp,
++ bdp->cbd_sc,
++ bdp->cbd_datlen,
++ (int) bdp->cbd_bufaddr);
++ bdp++;
++ }
++
++ bdp = fep->rx_bd_base;
++ printk(" rx: %lu buffers\n", (unsigned long) RX_RING_SIZE);
++ for (i = 0 ; i < RX_RING_SIZE; i++) {
++ printk(" %08x: %04x %04x %08x\n",
++ (uint) bdp,
++ bdp->cbd_sc,
++ bdp->cbd_datlen,
++ (int) bdp->cbd_bufaddr);
++ bdp++;
++ }
++ }
++#endif
++ fec_restart(dev, fep->full_duplex);
++ netif_wake_queue(dev);
++}
++
++/* The interrupt handler.
++ * This is called from the MPC core interrupt.
++ */
++static irqreturn_t
++fec_enet_interrupt(int irq, void * dev_id)
++{
++ struct net_device *dev = dev_id;
++ volatile fec_t *fecp;
++ uint int_events;
++ int handled = 0;
++
++ fecp = (volatile fec_t*)dev->base_addr;
++ /* Get the interrupt events that caused us to be here.
++ */
++ while ((int_events = fecp->fec_ievent) != 0) {
++ fecp->fec_ievent = int_events;
++
++ /* Handle receive event in its own function.
++ */
++ if (int_events & (FEC_ENET_RXF | FEC_ENET_RXB)) {
++
++ handled = 1;
++ fec_enet_rx(dev);
++ }
++
++ /* Transmit OK, or non-fatal error. Update the buffer
++ descriptors. FEC handles all errors, we just discover
++ them as part of the transmit process.
++ */
++ if (int_events & (FEC_ENET_TXF | FEC_ENET_TXB)) {
++ handled = 1;
++ fec_enet_tx(dev);
++ }
++
++ if (int_events & FEC_ENET_MII) {
++ handled = 1;
++ fec_enet_mii(dev);
++ }
++
++ }
++ return IRQ_RETVAL(handled);
++}
++
++
++static void
++fec_enet_tx(struct net_device *dev)
++{
++ struct fec_enet_private *fep;
++ volatile cbd_t *bdp;
++ unsigned short status;
++ struct sk_buff *skb;
++
++ fep = netdev_priv(dev);
++ spin_lock(&fep->lock);
++ bdp = fep->dirty_tx;
++
++ while (((status = bdp->cbd_sc) & BD_ENET_TX_READY) == 0) {
++ if (bdp == fep->cur_tx && fep->tx_full == 0) break;
++
++ skb = fep->tx_skbuff[fep->skb_dirty];
++ /* Check for errors. */
++ if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC |
++ BD_ENET_TX_RL | BD_ENET_TX_UN |
++ BD_ENET_TX_CSL)) {
++ fep->stats.tx_errors++;
++ if (status & BD_ENET_TX_HB) /* No heartbeat */
++ fep->stats.tx_heartbeat_errors++;
++ if (status & BD_ENET_TX_LC) /* Late collision */
++ fep->stats.tx_window_errors++;
++ if (status & BD_ENET_TX_RL) /* Retrans limit */
++ fep->stats.tx_aborted_errors++;
++ if (status & BD_ENET_TX_UN) /* Underrun */
++ fep->stats.tx_fifo_errors++;
++ if (status & BD_ENET_TX_CSL) /* Carrier lost */
++ fep->stats.tx_carrier_errors++;
++ } else {
++ fep->stats.tx_packets++;
++ }
++
++#ifndef final_version
++ if (status & BD_ENET_TX_READY)
++ printk("HEY! Enet xmit interrupt and TX_READY.\n");
++#endif
++ /* Deferred means some collisions occurred during transmit,
++ * but we eventually sent the packet OK.
++ */
++ if (status & BD_ENET_TX_DEF)
++ fep->stats.collisions++;
++
++ /* Free the sk buffer associated with this last transmit.
++ */
++ dev_kfree_skb_any(skb);
++ fep->tx_skbuff[fep->skb_dirty] = NULL;
++ fep->skb_dirty = (fep->skb_dirty + 1) & TX_RING_MOD_MASK;
++
++ /* Update pointer to next buffer descriptor to be transmitted.
++ */
++ if (status & BD_ENET_TX_WRAP)
++ bdp = fep->tx_bd_base;
++ else
++ bdp++;
++
++ /* Since we have freed up a buffer, the ring is no longer
++ * full.
++ */
++ if (fep->tx_full) {
++ fep->tx_full = 0;
++ if (netif_queue_stopped(dev))
++ netif_wake_queue(dev);
++ }
++ }
++ fep->dirty_tx = (cbd_t *)bdp;
++ spin_unlock(&fep->lock);
++}
++
++
++/* During a receive, the cur_rx points to the current incoming buffer.
++ * When we update through the ring, if the next incoming buffer has
++ * not been given to the system, we just set the empty indicator,
++ * effectively tossing the packet.
++ */
++static void
++fec_enet_rx(struct net_device *dev)
++{
++ struct fec_enet_private *fep;
++ volatile fec_t *fecp;
++ volatile cbd_t *bdp;
++ unsigned short status;
++ struct sk_buff *skb;
++ ushort pkt_len;
++ __u8 *data;
++ int rx_index;
++
++#ifdef CONFIG_M532x
++ flush_cache_all();
++#endif
++
++ fep = netdev_priv(dev);
++ fecp = (volatile fec_t*)dev->base_addr;
++
++ /* First, grab all of the stats for the incoming packet.
++ * These get messed up if we get called due to a busy condition.
++ */
++ bdp = fep->cur_rx;
++
++while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) {
++ rx_index = bdp - fep->rx_bd_base;
++#ifndef final_version
++ /* Since we have allocated space to hold a complete frame,
++ * the last indicator should be set.
++ */
++ if ((status & BD_ENET_RX_LAST) == 0)
++ printk("FEC ENET: rcv is not +last\n");
++#endif
++
++ if (!fep->opened)
++ goto rx_processing_done;
++
++ /* Check for errors. */
++ if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO |
++ BD_ENET_RX_CR | BD_ENET_RX_OV)) {
++ fep->stats.rx_errors++;
++ if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH)) {
++ /* Frame too long or too short. */
++ fep->stats.rx_length_errors++;
++ }
++ if (status & BD_ENET_RX_NO) /* Frame alignment */
++ fep->stats.rx_frame_errors++;
++ if (status & BD_ENET_RX_CR) /* CRC Error */
++ fep->stats.rx_crc_errors++;
++ if (status & BD_ENET_RX_OV) /* FIFO overrun */
++ fep->stats.rx_fifo_errors++;
++ }
++
++ /* Report late collisions as a frame error.
++ * On this error, the BD is closed, but we don't know what we
++ * have in the buffer. So, just drop this frame on the floor.
++ */
++ if (status & BD_ENET_RX_CL) {
++ fep->stats.rx_errors++;
++ fep->stats.rx_frame_errors++;
++ goto rx_processing_done;
++ }
++
++ /* Process the incoming frame.
++ */
++ fep->stats.rx_packets++;
++ pkt_len = bdp->cbd_datlen;
++ fep->stats.rx_bytes += pkt_len;
++ data = (__u8*)__va(bdp->cbd_bufaddr);
++ fec_dcache_inv_range(data, data + pkt_len - 4);
++
++ /* This does 16 byte alignment, exactly what we need.
++ * The packet length includes FCS, but we don't want to
++ * include that when passing upstream as it messes up
++ * bridging applications.
++ */
++ if ((pkt_len - 4) < fec_copy_threshold) {
++ skb = dev_alloc_skb(pkt_len);
++ } else {
++ skb = dev_alloc_skb(FEC_ENET_RX_FRSIZE);
++ }
++
++ if (skb == NULL) {
++ printk("%s: Memory squeeze, dropping packet.\n", dev->name);
++ fep->stats.rx_dropped++;
++ } else {
++ if ((pkt_len - 4) < fec_copy_threshold) {
++ skb_reserve(skb, 2); /*skip 2bytes, so ipheader is align 4bytes*/
++ skb_put(skb,pkt_len-4); /* Make room */
++ skb_copy_to_linear_data(skb, (unsigned char *)data,
++ pkt_len-4);
++ } else {
++ struct sk_buff *pskb = fep->rx_skbuff[rx_index];
++
++ fep->rx_skbuff[rx_index] = skb;
++ skb->data = FEC_ADDR_ALIGNMENT(skb->data);
++ bdp->cbd_bufaddr = __pa(skb->data);
++ skb_put(pskb,pkt_len-4); /* Make room */
++ skb = pskb;
++ }
++ skb->dev = dev;
++ skb->protocol=eth_type_trans(skb,dev);
++ netif_rx(skb);
++ }
++ rx_processing_done:
++
++ /* Clear the status flags for this buffer.
++ */
++ status &= ~BD_ENET_RX_STATS;
++
++ /* Mark the buffer empty.
++ */
++ status |= BD_ENET_RX_EMPTY;
++ bdp->cbd_sc = status;
++
++ /* Update BD pointer to next entry.
++ */
++ if (status & BD_ENET_RX_WRAP)
++ bdp = fep->rx_bd_base;
++ else
++ bdp++;
++
++#if 1
++ /* Doing this here will keep the FEC running while we process
++ * incoming frames. On a heavily loaded network, we should be
++ * able to keep up at the expense of system resources.
++ */
++ fecp->fec_r_des_active = 0x01000000;
++#endif
++ } /* while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) */
++ fep->cur_rx = (cbd_t *)bdp;
++
++#if 0
++ /* Doing this here will allow us to process all frames in the
++ * ring before the FEC is allowed to put more there. On a heavily
++ * loaded network, some frames may be lost. Unfortunately, this
++ * increases the interrupt overhead since we can potentially work
++ * our way back to the interrupt return only to come right back
++ * here.
++ */
++ fecp->fec_r_des_active = 0;
++#endif
++}
++
++
++/* called from interrupt context */
++static void
++fec_enet_mii(struct net_device *dev)
++{
++ struct fec_enet_private *fep;
++ volatile fec_t *ep;
++ mii_list_t *mip;
++ uint mii_reg;
++
++ fep = netdev_priv(dev);
++ ep = fep->hwp;
++ mii_reg = ep->fec_mii_data;
++
++ spin_lock(&fep->lock);
++
++ if ((mip = mii_head) == NULL) {
++ printk("MII and no head!\n");
++ goto unlock;
++ }
++
++ if (mip->mii_func != NULL)
++ (*(mip->mii_func))(mii_reg, dev);
++
++ mii_head = mip->mii_next;
++ mip->mii_next = mii_free;
++ mii_free = mip;
++
++ if ((mip = mii_head) != NULL)
++ ep->fec_mii_data = mip->mii_regval;
++
++unlock:
++ spin_unlock(&fep->lock);
++}
++
++static int
++mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_device *))
++{
++ struct fec_enet_private *fep;
++ unsigned long flags;
++ mii_list_t *mip;
++ int retval;
++
++ /* Add PHY address to register command.
++ */
++ fep = netdev_priv(dev);
++ regval |= fep->phy_addr << 23;
++
++ retval = 0;
++
++ spin_lock_irqsave(&fep->lock,flags);
++
++ if ((mip = mii_free) != NULL) {
++ mii_free = mip->mii_next;
++ mip->mii_regval = regval;
++ mip->mii_func = func;
++ mip->mii_next = NULL;
++ if (mii_head) {
++ mii_tail->mii_next = mip;
++ mii_tail = mip;
++ }
++ else {
++ mii_head = mii_tail = mip;
++ fep->hwp->fec_mii_data = regval;
++ }
++ }
++ else {
++ retval = 1;
++ }
++
++ spin_unlock_irqrestore(&fep->lock,flags);
++
++ return(retval);
++}
++
++static void mii_do_cmd(struct net_device *dev, const phy_cmd_t *c)
++{
++ int k;
++
++ if(!c)
++ return;
++
++ for(k = 0; (c+k)->mii_data != mk_mii_end; k++) {
++ mii_queue(dev, (c+k)->mii_data, (c+k)->funct);
++ }
++}
++
++static void mii_parse_sr(uint mii_reg, struct net_device *dev)
++{
++ struct fec_enet_private *fep = netdev_priv(dev);
++ volatile uint *s = &(fep->phy_status);
++ uint status;
++
++ status = *s & ~(PHY_STAT_LINK | PHY_STAT_FAULT | PHY_STAT_ANC);
++
++ if (mii_reg & 0x0004)
++ status |= PHY_STAT_LINK;
++ if (mii_reg & 0x0010)
++ status |= PHY_STAT_FAULT;
++ if (mii_reg & 0x0020)
++ status |= PHY_STAT_ANC;
++
++ *s = status;
++}
++
++static void mii_parse_cr(uint mii_reg, struct net_device *dev)
++{
++ struct fec_enet_private *fep = netdev_priv(dev);
++ volatile uint *s = &(fep->phy_status);
++ uint status;
++ status = *s & ~(PHY_CONF_ANE | PHY_CONF_LOOP);
++
++
++ if (mii_reg & 0x1000)
++ status |= PHY_CONF_ANE;
++ if (mii_reg & 0x4000)
++ status |= PHY_CONF_LOOP;
++ *s = status;
++}
++
++static void mii_parse_anar(uint mii_reg, struct net_device *dev)
++{
++ struct fec_enet_private *fep = netdev_priv(dev);
++ volatile uint *s = &(fep->phy_status);
++ uint status;
++ status = *s & ~(PHY_CONF_SPMASK);
++
++
++ if (mii_reg & 0x0020)
++ status |= PHY_CONF_10HDX;
++ if (mii_reg & 0x0040)
++ status |= PHY_CONF_10FDX;
++ if (mii_reg & 0x0080)
++ status |= PHY_CONF_100HDX;
++ if (mii_reg & 0x00100)
++ status |= PHY_CONF_100FDX;
++ *s = status;
++}
++
++/* ------------------------------------------------------------------------- */
++/* The Level one LXT970 is used by many boards */
++
++#define MII_LXT970_MIRROR 16 /* Mirror register */
++#define MII_LXT970_IER 17 /* Interrupt Enable Register */
++#define MII_LXT970_ISR 18 /* Interrupt Status Register */
++#define MII_LXT970_CONFIG 19 /* Configuration Register */
++#define MII_LXT970_CSR 20 /* Chip Status Register */
++
++static void mii_parse_lxt970_csr(uint mii_reg, struct net_device *dev)
++{
++ struct fec_enet_private *fep = netdev_priv(dev);
++ volatile uint *s = &(fep->phy_status);
++ uint status;
++
++ status = *s & ~(PHY_STAT_SPMASK);
++ if (mii_reg & 0x0800) {
++ if (mii_reg & 0x1000)
++ status |= PHY_STAT_100FDX;
++ else
++ status |= PHY_STAT_100HDX;
++ } else {
++ if (mii_reg & 0x1000)
++ status |= PHY_STAT_10FDX;
++ else
++ status |= PHY_STAT_10HDX;
++ }
++ *s = status;
++}
++
++static phy_cmd_t const phy_cmd_lxt970_config[] = {
++ { mk_mii_read(MII_REG_CR), mii_parse_cr },
++ { mk_mii_read(MII_REG_ANAR), mii_parse_anar },
++ { mk_mii_end, }
++ };
++static phy_cmd_t const phy_cmd_lxt970_startup[] = { /* enable interrupts */
++ { mk_mii_write(MII_LXT970_IER, 0x0002), NULL },
++ { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
++ { mk_mii_end, }
++ };
++static phy_cmd_t const phy_cmd_lxt970_ack_int[] = {
++ /* read SR and ISR to acknowledge */
++ { mk_mii_read(MII_REG_SR), mii_parse_sr },
++ { mk_mii_read(MII_LXT970_ISR), NULL },
++
++ /* find out the current status */
++ { mk_mii_read(MII_LXT970_CSR), mii_parse_lxt970_csr },
++ { mk_mii_end, }
++ };
++static phy_cmd_t const phy_cmd_lxt970_shutdown[] = { /* disable interrupts */
++ { mk_mii_write(MII_LXT970_IER, 0x0000), NULL },
++ { mk_mii_end, }
++ };
++static phy_info_t const phy_info_lxt970 = {
++ .id = 0x07810000,
++ .name = "LXT970",
++ .config = phy_cmd_lxt970_config,
++ .startup = phy_cmd_lxt970_startup,
++ .ack_int = phy_cmd_lxt970_ack_int,
++ .shutdown = phy_cmd_lxt970_shutdown
++};
++
++/* ------------------------------------------------------------------------- */
++/* The Level one LXT971 is used on some of my custom boards */
++
++/* register definitions for the 971 */
++
++#define MII_LXT971_PCR 16 /* Port Control Register */
++#define MII_LXT971_SR2 17 /* Status Register 2 */
++#define MII_LXT971_IER 18 /* Interrupt Enable Register */
++#define MII_LXT971_ISR 19 /* Interrupt Status Register */
++#define MII_LXT971_LCR 20 /* LED Control Register */
++#define MII_LXT971_TCR 30 /* Transmit Control Register */
++
++/*
++ * I had some nice ideas of running the MDIO faster...
++ * The 971 should support 8MHz and I tried it, but things acted really
++ * weird, so 2.5 MHz ought to be enough for anyone...
++ */
++
++static void mii_parse_lxt971_sr2(uint mii_reg, struct net_device *dev)
++{
++ struct fec_enet_private *fep = netdev_priv(dev);
++ volatile uint *s = &(fep->phy_status);
++ uint status;
++
++ status = *s & ~(PHY_STAT_SPMASK | PHY_STAT_LINK | PHY_STAT_ANC);
++
++ if (mii_reg & 0x0400) {
++ fep->link = 1;
++ status |= PHY_STAT_LINK;
++ } else {
++ fep->link = 0;
++ }
++ if (mii_reg & 0x0080)
++ status |= PHY_STAT_ANC;
++ if (mii_reg & 0x4000) {
++ if (mii_reg & 0x0200)
++ status |= PHY_STAT_100FDX;
++ else
++ status |= PHY_STAT_100HDX;
++ } else {
++ if (mii_reg & 0x0200)
++ status |= PHY_STAT_10FDX;
++ else
++ status |= PHY_STAT_10HDX;
++ }
++ if (mii_reg & 0x0008)
++ status |= PHY_STAT_FAULT;
++
++ *s = status;
++}
++
++static phy_cmd_t const phy_cmd_lxt971_config[] = {
++ /* limit to 10MBit because my prototype board
++ * doesn't work with 100. */
++ { mk_mii_read(MII_REG_CR), mii_parse_cr },
++ { mk_mii_read(MII_REG_ANAR), mii_parse_anar },
++ { mk_mii_read(MII_LXT971_SR2), mii_parse_lxt971_sr2 },
++ { mk_mii_end, }
++ };
++static phy_cmd_t const phy_cmd_lxt971_startup[] = { /* enable interrupts */
++ { mk_mii_write(MII_LXT971_IER, 0x00f2), NULL },
++ { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
++ { mk_mii_write(MII_LXT971_LCR, 0xd422), NULL }, /* LED config */
++ /* Somehow does the 971 tell me that the link is down
++ * the first read after power-up.
++ * read here to get a valid value in ack_int */
++ { mk_mii_read(MII_REG_SR), mii_parse_sr },
++ { mk_mii_end, }
++ };
++static phy_cmd_t const phy_cmd_lxt971_ack_int[] = {
++ /* acknowledge the int before reading status ! */
++ { mk_mii_read(MII_LXT971_ISR), NULL },
++ /* find out the current status */
++ { mk_mii_read(MII_REG_SR), mii_parse_sr },
++ { mk_mii_read(MII_LXT971_SR2), mii_parse_lxt971_sr2 },
++ { mk_mii_end, }
++ };
++static phy_cmd_t const phy_cmd_lxt971_shutdown[] = { /* disable interrupts */
++ { mk_mii_write(MII_LXT971_IER, 0x0000), NULL },
++ { mk_mii_end, }
++ };
++static phy_info_t const phy_info_lxt971 = {
++ .id = 0x0001378e,
++ .name = "LXT971",
++ .config = phy_cmd_lxt971_config,
++ .startup = phy_cmd_lxt971_startup,
++ .ack_int = phy_cmd_lxt971_ack_int,
++ .shutdown = phy_cmd_lxt971_shutdown
++};
++
++/* ------------------------------------------------------------------------- */
++/* The Quality Semiconductor QS6612 is used on the RPX CLLF */
++
++/* register definitions */
++
++#define MII_QS6612_MCR 17 /* Mode Control Register */
++#define MII_QS6612_FTR 27 /* Factory Test Register */
++#define MII_QS6612_MCO 28 /* Misc. Control Register */
++#define MII_QS6612_ISR 29 /* Interrupt Source Register */
++#define MII_QS6612_IMR 30 /* Interrupt Mask Register */
++#define MII_QS6612_PCR 31 /* 100BaseTx PHY Control Reg. */
++
++static void mii_parse_qs6612_pcr(uint mii_reg, struct net_device *dev)
++{
++ struct fec_enet_private *fep = netdev_priv(dev);
++ volatile uint *s = &(fep->phy_status);
++ uint status;
++
++ status = *s & ~(PHY_STAT_SPMASK);
++
++ switch((mii_reg >> 2) & 7) {
++ case 1: status |= PHY_STAT_10HDX; break;
++ case 2: status |= PHY_STAT_100HDX; break;
++ case 5: status |= PHY_STAT_10FDX; break;
++ case 6: status |= PHY_STAT_100FDX; break;
++}
++
++ *s = status;
++}
++
++static phy_cmd_t const phy_cmd_qs6612_config[] = {
++ /* The PHY powers up isolated on the RPX,
++ * so send a command to allow operation.
++ */
++ { mk_mii_write(MII_QS6612_PCR, 0x0dc0), NULL },
++
++ /* parse cr and anar to get some info */
++ { mk_mii_read(MII_REG_CR), mii_parse_cr },
++ { mk_mii_read(MII_REG_ANAR), mii_parse_anar },
++ { mk_mii_end, }
++ };
++static phy_cmd_t const phy_cmd_qs6612_startup[] = { /* enable interrupts */
++ { mk_mii_write(MII_QS6612_IMR, 0x003a), NULL },
++ { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
++ { mk_mii_end, }
++ };
++static phy_cmd_t const phy_cmd_qs6612_ack_int[] = {
++ /* we need to read ISR, SR and ANER to acknowledge */
++ { mk_mii_read(MII_QS6612_ISR), NULL },
++ { mk_mii_read(MII_REG_SR), mii_parse_sr },
++ { mk_mii_read(MII_REG_ANER), NULL },
++
++ /* read pcr to get info */
++ { mk_mii_read(MII_QS6612_PCR), mii_parse_qs6612_pcr },
++ { mk_mii_end, }
++ };
++static phy_cmd_t const phy_cmd_qs6612_shutdown[] = { /* disable interrupts */
++ { mk_mii_write(MII_QS6612_IMR, 0x0000), NULL },
++ { mk_mii_end, }
++ };
++static phy_info_t const phy_info_qs6612 = {
++ .id = 0x00181440,
++ .name = "QS6612",
++ .config = phy_cmd_qs6612_config,
++ .startup = phy_cmd_qs6612_startup,
++ .ack_int = phy_cmd_qs6612_ack_int,
++ .shutdown = phy_cmd_qs6612_shutdown
++};
++
++/* ------------------------------------------------------------------------- */
++/* AMD AM79C874 phy */
++
++/* register definitions for the 874 */
++
++#define MII_AM79C874_MFR 16 /* Miscellaneous Feature Register */
++#define MII_AM79C874_ICSR 17 /* Interrupt/Status Register */
++#define MII_AM79C874_DR 18 /* Diagnostic Register */
++#define MII_AM79C874_PMLR 19 /* Power and Loopback Register */
++#define MII_AM79C874_MCR 21 /* ModeControl Register */
++#define MII_AM79C874_DC 23 /* Disconnect Counter */
++#define MII_AM79C874_REC 24 /* Recieve Error Counter */
++
++static void mii_parse_am79c874_dr(uint mii_reg, struct net_device *dev)
++{
++ struct fec_enet_private *fep = netdev_priv(dev);
++ volatile uint *s = &(fep->phy_status);
++ uint status;
++
++ status = *s & ~(PHY_STAT_SPMASK | PHY_STAT_ANC);
++
++ if (mii_reg & 0x0080)
++ status |= PHY_STAT_ANC;
++ if (mii_reg & 0x0400)
++ status |= ((mii_reg & 0x0800) ? PHY_STAT_100FDX : PHY_STAT_100HDX);
++ else
++ status |= ((mii_reg & 0x0800) ? PHY_STAT_10FDX : PHY_STAT_10HDX);
++
++ *s = status;
++}
++
++static phy_cmd_t const phy_cmd_am79c874_config[] = {
++ { mk_mii_read(MII_REG_CR), mii_parse_cr },
++ { mk_mii_read(MII_REG_ANAR), mii_parse_anar },
++ { mk_mii_read(MII_AM79C874_DR), mii_parse_am79c874_dr },
++ { mk_mii_end, }
++ };
++static phy_cmd_t const phy_cmd_am79c874_startup[] = { /* enable interrupts */
++ { mk_mii_write(MII_AM79C874_ICSR, 0xff00), NULL },
++ { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
++ { mk_mii_read(MII_REG_SR), mii_parse_sr },
++ { mk_mii_end, }
++ };
++static phy_cmd_t const phy_cmd_am79c874_ack_int[] = {
++ /* find out the current status */
++ { mk_mii_read(MII_REG_SR), mii_parse_sr },
++ { mk_mii_read(MII_AM79C874_DR), mii_parse_am79c874_dr },
++ /* we only need to read ISR to acknowledge */
++ { mk_mii_read(MII_AM79C874_ICSR), NULL },
++ { mk_mii_end, }
++ };
++static phy_cmd_t const phy_cmd_am79c874_shutdown[] = { /* disable interrupts */
++ { mk_mii_write(MII_AM79C874_ICSR, 0x0000), NULL },
++ { mk_mii_end, }
++ };
++static phy_info_t const phy_info_am79c874 = {
++ .id = 0x00022561,
++ .name = "AM79C874",
++ .config = phy_cmd_am79c874_config,
++ .startup = phy_cmd_am79c874_startup,
++ .ack_int = phy_cmd_am79c874_ack_int,
++ .shutdown = phy_cmd_am79c874_shutdown
++};
++
++
++/* ------------------------------------------------------------------------- */
++/* Kendin KS8721BL phy */
++
++/* register definitions for the 8721 */
++
++#define MII_KS8721BL_RXERCR 21
++#define MII_KS8721BL_ICSR 27
++#define MII_KS8721BL_PHYCR 31
++
++static phy_cmd_t const phy_cmd_ks8721bl_config[] = {
++ { mk_mii_read(MII_REG_CR), mii_parse_cr },
++ { mk_mii_read(MII_REG_ANAR), mii_parse_anar },
++ { mk_mii_end, }
++ };
++static phy_cmd_t const phy_cmd_ks8721bl_startup[] = { /* enable interrupts */
++/* { mk_mii_write(MII_KS8721BL_ICSR, 0xff00), NULL }, */
++ { mk_mii_write(MII_REG_ANAR, 0x01E1), NULL},
++ { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
++ { mk_mii_read(MII_REG_SR), mii_parse_sr },
++ { mk_mii_end, }
++ };
++static phy_cmd_t const phy_cmd_ks8721bl_ack_int[] = {
++ /* find out the current status */
++ { mk_mii_read(MII_REG_SR), mii_parse_sr },
++ /* we only need to read ISR to acknowledge */
++ { mk_mii_read(MII_KS8721BL_ICSR), NULL },
++ { mk_mii_end, }
++ };
++static phy_cmd_t const phy_cmd_ks8721bl_shutdown[] = { /* disable interrupts */
++ { mk_mii_write(MII_KS8721BL_ICSR, 0x0000), NULL },
++ { mk_mii_end, }
++ };
++static phy_info_t const phy_info_ks8721bl = {
++ .id = 0x00022161,
++ .name = "KS8721BL",
++ .config = phy_cmd_ks8721bl_config,
++ .startup = phy_cmd_ks8721bl_startup,
++ .ack_int = phy_cmd_ks8721bl_ack_int,
++ .shutdown = phy_cmd_ks8721bl_shutdown
++};
++
++/* ------------------------------------------------------------------------- */
++/* register definitions for the DP83848 */
++
++#define MII_DP8384X_PHYSTST 16 /* PHY Status Register */
++
++static void mii_parse_dp8384x_sr2(uint mii_reg, struct net_device *dev)
++{
++ struct fec_enet_private *fep = dev->priv;
++ volatile uint *s = &(fep->phy_status);
++
++ *s &= ~(PHY_STAT_SPMASK | PHY_STAT_LINK | PHY_STAT_ANC);
++
++ /* Link up */
++ if (mii_reg & 0x0001) {
++ fep->link = 1;
++ *s |= PHY_STAT_LINK;
++ } else
++ fep->link = 0;
++ /* Status of link */
++ if (mii_reg & 0x0010) /* Autonegotioation complete */
++ *s |= PHY_STAT_ANC;
++ if (mii_reg & 0x0002) { /* 10MBps? */
++ if (mii_reg & 0x0004) /* Full Duplex? */
++ *s |= PHY_STAT_10FDX;
++ else
++ *s |= PHY_STAT_10HDX;
++ } else { /* 100 Mbps? */
++ if (mii_reg & 0x0004) /* Full Duplex? */
++ *s |= PHY_STAT_100FDX;
++ else
++ *s |= PHY_STAT_100HDX;
++ }
++ if (mii_reg & 0x0008)
++ *s |= PHY_STAT_FAULT;
++}
++
++static phy_info_t phy_info_dp83848= {
++ 0x020005c9,
++ "DP83848",
++
++ (const phy_cmd_t []) { /* config */
++ { mk_mii_read(MII_REG_CR), mii_parse_cr },
++ { mk_mii_read(MII_REG_ANAR), mii_parse_anar },
++ { mk_mii_read(MII_DP8384X_PHYSTST), mii_parse_dp8384x_sr2 },
++ { mk_mii_end, }
++ },
++ (const phy_cmd_t []) { /* startup - enable interrupts */
++ { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
++ { mk_mii_read(MII_REG_SR), mii_parse_sr },
++ { mk_mii_end, }
++ },
++ (const phy_cmd_t []) { /* ack_int - never happens, no interrupt */
++ { mk_mii_end, }
++ },
++ (const phy_cmd_t []) { /* shutdown */
++ { mk_mii_end, }
++ },
++};
++
++/* ------------------------------------------------------------------------- */
++
++static phy_info_t const * const phy_info[] = {
++ &phy_info_lxt970,
++ &phy_info_lxt971,
++ &phy_info_qs6612,
++ &phy_info_am79c874,
++ &phy_info_ks8721bl,
++ &phy_info_dp83848,
++ NULL
++};
++
++/* ------------------------------------------------------------------------- */
++#if !defined(CONFIG_M532x)
++#ifdef CONFIG_RPXCLASSIC
++static void
++mii_link_interrupt(void *dev_id);
++#else
++static irqreturn_t
++mii_link_interrupt(int irq, void * dev_id);
++#endif
++#endif
++
++#if defined(CONFIG_M5272)
++
++/*
++ * * do some initializtion based architecture of this chip
++ * */
++static void __inline__ fec_arch_init(void)
++{
++ return;
++}
++/*
++ * * do some cleanup based architecture of this chip
++ * */
++static void __inline__ fec_arch_exit(void)
++{
++ return;
++}
++
++/*
++ * Code specific to Coldfire 5272 setup.
++ */
++static void __inline__ fec_request_intrs(struct net_device *dev)
++{
++ volatile unsigned long *icrp;
++ static const struct idesc {
++ char *name;
++ unsigned short irq;
++ irq_handler_t handler;
++ } *idp, id[] = {
++ { "fec(RX)", 86, fec_enet_interrupt },
++ { "fec(TX)", 87, fec_enet_interrupt },
++ { "fec(OTHER)", 88, fec_enet_interrupt },
++ { "fec(MII)", 66, mii_link_interrupt },
++ { NULL },
++ };
++
++ /* Setup interrupt handlers. */
++ for (idp = id; idp->name; idp++) {
++ if (request_irq(idp->irq, idp->handler, 0, idp->name, dev) != 0)
++ printk("FEC: Could not allocate %s IRQ(%d)!\n", idp->name, idp->irq);
++ }
++
++ /* Unmask interrupt at ColdFire 5272 SIM */
++ icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR3);
++ *icrp = 0x00000ddd;
++ icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1);
++ *icrp = (*icrp & 0x70777777) | 0x0d000000;
++}
++
++static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_private *fep)
++{
++ volatile fec_t *fecp;
++
++ fecp = fep->hwp;
++ fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x04;
++ fecp->fec_x_cntrl = 0x00;
++
++ /*
++ * Set MII speed to 2.5 MHz
++ * See 5272 manual section 11.5.8: MSCR
++ */
++ fep->phy_speed = ((((MCF_CLK / 4) / (2500000 / 10)) + 5) / 10) * 2;
++ fecp->fec_mii_speed = fep->phy_speed;
++
++ fec_restart(dev, 0);
++}
++
++static void __inline__ fec_get_mac(struct net_device *dev)
++{
++ struct fec_enet_private *fep = netdev_priv(dev);
++ volatile fec_t *fecp;
++ unsigned char *iap, tmpaddr[ETH_ALEN];
++
++ fecp = fep->hwp;
++
++ if (FEC_FLASHMAC) {
++ /*
++ * Get MAC address from FLASH.
++ * If it is all 1's or 0's, use the default.
++ */
++ iap = (unsigned char *)FEC_FLASHMAC;
++ if ((iap[0] == 0) && (iap[1] == 0) && (iap[2] == 0) &&
++ (iap[3] == 0) && (iap[4] == 0) && (iap[5] == 0))
++ iap = fec_mac_default;
++ if ((iap[0] == 0xff) && (iap[1] == 0xff) && (iap[2] == 0xff) &&
++ (iap[3] == 0xff) && (iap[4] == 0xff) && (iap[5] == 0xff))
++ iap = fec_mac_default;
++ } else {
++ *((unsigned long *) &tmpaddr[0]) = fecp->fec_addr_low;
++ *((unsigned short *) &tmpaddr[4]) = (fecp->fec_addr_high >> 16);
++ iap = &tmpaddr[0];
++ }
++
++ memcpy(dev->dev_addr, iap, ETH_ALEN);
++
++ /* Adjust MAC if using default MAC address */
++ if (iap == fec_mac_default)
++ dev->dev_addr[ETH_ALEN-1] = fec_mac_default[ETH_ALEN-1] + fep->index;
++}
++
++static void __inline__ fec_enable_phy_intr(void)
++{
++}
++
++static void __inline__ fec_disable_phy_intr(void)
++{
++ volatile unsigned long *icrp;
++ icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1);
++ *icrp = (*icrp & 0x70777777) | 0x08000000;
++}
++
++static void __inline__ fec_phy_ack_intr(void)
++{
++ volatile unsigned long *icrp;
++ /* Acknowledge the interrupt */
++ icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1);
++ *icrp = (*icrp & 0x77777777) | 0x08000000;
++}
++
++static void __inline__ fec_localhw_setup(void)
++{
++}
++
++/*
++ * invalidate dcache related with the virtual memory range(start, end)
++ */
++static void __inline__ fec_dcache_inv_range(void * start, void * end)
++{
++ return ;
++}
++
++/*
++ * flush dcache related with the virtual memory range(start, end)
++ */
++static void __inline__ fec_dcache_flush_range(void * start, void * end)
++{
++ return ;
++}
++
++/*
++ * map memory space (addr, addr+size) to uncachable erea.
++ */
++static unsigned long __inline__ fec_map_uncache(unsigned long addr, int size)
++{
++ return addr;
++}
++
++/*
++ * unmap memory erea started with addr from uncachable erea.
++ */
++static void __inline__ fec_unmap_uncache(void * addr)
++{
++ return ;
++}
++
++/* ------------------------------------------------------------------------- */
++
++#elif defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x)
++
++/*
++ * do some initializtion based architecture of this chip
++ */
++static void __inline__ fec_arch_init(void)
++{
++ return;
++}
++
++/*
++ * do some cleanup based architecture of this chip
++ */
++static void __inline__ fec_arch_exit(void)
++{
++ return;
++}
++
++/*
++ * Code specific to Coldfire 5230/5231/5232/5234/5235,
++ * the 5270/5271/5274/5275 and 5280/5282 setups.
++ */
++static void __inline__ fec_request_intrs(struct net_device *dev)
++{
++ struct fec_enet_private *fep;
++ int b;
++ static const struct idesc {
++ char *name;
++ unsigned short irq;
++ } *idp, id[] = {
++ { "fec(TXF)", 23 },
++ { "fec(TXB)", 24 },
++ { "fec(TXFIFO)", 25 },
++ { "fec(TXCR)", 26 },
++ { "fec(RXF)", 27 },
++ { "fec(RXB)", 28 },
++ { "fec(MII)", 29 },
++ { "fec(LC)", 30 },
++ { "fec(HBERR)", 31 },
++ { "fec(GRA)", 32 },
++ { "fec(EBERR)", 33 },
++ { "fec(BABT)", 34 },
++ { "fec(BABR)", 35 },
++ { NULL },
++ };
++
++ fep = netdev_priv(dev);
++ b = (fep->index) ? 128 : 64;
++
++ /* Setup interrupt handlers. */
++ for (idp = id; idp->name; idp++) {
++ if (request_irq(b+idp->irq, fec_enet_interrupt, 0, idp->name, dev) != 0)
++ printk("FEC: Could not allocate %s IRQ(%d)!\n", idp->name, b+idp->irq);
++ }
++
++ /* Unmask interrupts at ColdFire 5280/5282 interrupt controller */
++ {
++ volatile unsigned char *icrp;
++ volatile unsigned long *imrp;
++ int i, ilip;
++
++ b = (fep->index) ? MCFICM_INTC1 : MCFICM_INTC0;
++ icrp = (volatile unsigned char *) (MCF_IPSBAR + b +
++ MCFINTC_ICR0);
++ for (i = 23, ilip = 0x28; (i < 36); i++)
++ icrp[i] = ilip--;
++
++ imrp = (volatile unsigned long *) (MCF_IPSBAR + b +
++ MCFINTC_IMRH);
++ *imrp &= ~0x0000000f;
++ imrp = (volatile unsigned long *) (MCF_IPSBAR + b +
++ MCFINTC_IMRL);
++ *imrp &= ~0xff800001;
++ }
++
++#if defined(CONFIG_M528x)
++ /* Set up gpio outputs for MII lines */
++ {
++ volatile u16 *gpio_paspar;
++ volatile u8 *gpio_pehlpar;
++
++ gpio_paspar = (volatile u16 *) (MCF_IPSBAR + 0x100056);
++ gpio_pehlpar = (volatile u16 *) (MCF_IPSBAR + 0x100058);
++ *gpio_paspar |= 0x0f00;
++ *gpio_pehlpar = 0xc0;
++ }
++#endif
++}
++
++static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_private *fep)
++{
++ volatile fec_t *fecp;
++
++ fecp = fep->hwp;
++ fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x04;
++ fecp->fec_x_cntrl = 0x00;
++
++ /*
++ * Set MII speed to 2.5 MHz
++ * See 5282 manual section 17.5.4.7: MSCR
++ */
++ fep->phy_speed = ((((MCF_CLK / 2) / (2500000 / 10)) + 5) / 10) * 2;
++ fecp->fec_mii_speed = fep->phy_speed;
++
++ fec_restart(dev, 0);
++}
++
++static void __inline__ fec_get_mac(struct net_device *dev)
++{
++ struct fec_enet_private *fep = netdev_priv(dev);
++ volatile fec_t *fecp;
++ unsigned char *iap, tmpaddr[ETH_ALEN];
++
++ fecp = fep->hwp;
++
++ if (FEC_FLASHMAC) {
++ /*
++ * Get MAC address from FLASH.
++ * If it is all 1's or 0's, use the default.
++ */
++ iap = FEC_FLASHMAC;
++ if ((iap[0] == 0) && (iap[1] == 0) && (iap[2] == 0) &&
++ (iap[3] == 0) && (iap[4] == 0) && (iap[5] == 0))
++ iap = fec_mac_default;
++ if ((iap[0] == 0xff) && (iap[1] == 0xff) && (iap[2] == 0xff) &&
++ (iap[3] == 0xff) && (iap[4] == 0xff) && (iap[5] == 0xff))
++ iap = fec_mac_default;
++ } else {
++ *((unsigned long *) &tmpaddr[0]) = fecp->fec_addr_low;
++ *((unsigned short *) &tmpaddr[4]) = (fecp->fec_addr_high >> 16);
++ iap = &tmpaddr[0];
++ }
++
++ memcpy(dev->dev_addr, iap, ETH_ALEN);
++
++ /* Adjust MAC if using default MAC address */
++ if (iap == fec_mac_default)
++ dev->dev_addr[ETH_ALEN-1] = fec_mac_default[ETH_ALEN-1] + fep->index;
++}
++
++static void __inline__ fec_enable_phy_intr(void)
++{
++}
++
++static void __inline__ fec_disable_phy_intr(void)
++{
++}
++
++static void __inline__ fec_phy_ack_intr(void)
++{
++}
++
++static void __inline__ fec_localhw_setup(void)
++{
++}
++/*
++ * invalidate dcache related with the virtual memory range(start, end)
++ */
++static void __inline__ fec_dcache_inv_range(void * start, void * end)
++{
++ return ;
++}
++
++/*
++ * flush dcache related with the virtual memory range(start, end)
++ */
++static void __inline__ fec_dcache_flush_range(void * start, void * end)
++{
++ return ;
++}
++
++/*
++ * map memory space (addr, addr+size) to uncachable erea.
++ */
++static unsigned long __inline__ fec_map_uncache(unsigned long addr, int size)
++{
++ return addr;
++}
++
++/*
++ * unmap memory erea started with addr from uncachable erea.
++ */
++static void __inline__ fec_unmap_uncache(void * addr)
++{
++ return ;
++}
++
++/* ------------------------------------------------------------------------- */
++
++#elif defined(CONFIG_M520x)
++/*
++ * do some initializtion based architecture of this chip
++ */
++static void __inline__ fec_arch_init(void)
++{
++ return;
++}
++/*
++ * do some cleanup based architecture of this chip
++ */
++static void __inline__ fec_arch_exit(void)
++{
++ return;
++}
++
++/*
++ * Code specific to Coldfire 520x
++ */
++static void __inline__ fec_request_intrs(struct net_device *dev)
++{
++ struct fec_enet_private *fep;
++ int b;
++ static const struct idesc {
++ char *name;
++ unsigned short irq;
++ } *idp, id[] = {
++ { "fec(TXF)", 23 },
++ { "fec(TXB)", 24 },
++ { "fec(TXFIFO)", 25 },
++ { "fec(TXCR)", 26 },
++ { "fec(RXF)", 27 },
++ { "fec(RXB)", 28 },
++ { "fec(MII)", 29 },
++ { "fec(LC)", 30 },
++ { "fec(HBERR)", 31 },
++ { "fec(GRA)", 32 },
++ { "fec(EBERR)", 33 },
++ { "fec(BABT)", 34 },
++ { "fec(BABR)", 35 },
++ { NULL },
++ };
++
++ fep = netdev_priv(dev);
++ b = 64 + 13;
++
++ /* Setup interrupt handlers. */
++ for (idp = id; idp->name; idp++) {
++ if (request_irq(b+idp->irq,fec_enet_interrupt,0,idp->name,dev)!=0)
++ printk("FEC: Could not allocate %s IRQ(%d)!\n", idp->name, b+idp->irq);
++ }
++
++ /* Unmask interrupts at ColdFire interrupt controller */
++ {
++ volatile unsigned char *icrp;
++ volatile unsigned long *imrp;
++
++ icrp = (volatile unsigned char *) (MCF_IPSBAR + MCFICM_INTC0 +
++ MCFINTC_ICR0);
++ for (b = 36; (b < 49); b++)
++ icrp[b] = 0x04;
++ imrp = (volatile unsigned long *) (MCF_IPSBAR + MCFICM_INTC0 +
++ MCFINTC_IMRH);
++ *imrp &= ~0x0001FFF0;
++ }
++ *(volatile unsigned char *)(MCF_IPSBAR + MCF_GPIO_PAR_FEC) |= 0xf0;
++ *(volatile unsigned char *)(MCF_IPSBAR + MCF_GPIO_PAR_FECI2C) |= 0x0f;
++}
++
++static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_private *fep)
++{
++ volatile fec_t *fecp;
++
++ fecp = fep->hwp;
++ fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x04;
++ fecp->fec_x_cntrl = 0x00;
++
++ /*
++ * Set MII speed to 2.5 MHz
++ * See 5282 manual section 17.5.4.7: MSCR
++ */
++ fep->phy_speed = ((((MCF_CLK / 2) / (2500000 / 10)) + 5) / 10) * 2;
++ fecp->fec_mii_speed = fep->phy_speed;
++
++ fec_restart(dev, 0);
++}
++
++static void __inline__ fec_get_mac(struct net_device *dev)
++{
++ struct fec_enet_private *fep = netdev_priv(dev);
++ volatile fec_t *fecp;
++ unsigned char *iap, tmpaddr[ETH_ALEN];
++
++ fecp = fep->hwp;
++
++ if (FEC_FLASHMAC) {
++ /*
++ * Get MAC address from FLASH.
++ * If it is all 1's or 0's, use the default.
++ */
++ iap = FEC_FLASHMAC;
++ if ((iap[0] == 0) && (iap[1] == 0) && (iap[2] == 0) &&
++ (iap[3] == 0) && (iap[4] == 0) && (iap[5] == 0))
++ iap = fec_mac_default;
++ if ((iap[0] == 0xff) && (iap[1] == 0xff) && (iap[2] == 0xff) &&
++ (iap[3] == 0xff) && (iap[4] == 0xff) && (iap[5] == 0xff))
++ iap = fec_mac_default;
++ } else {
++ *((unsigned long *) &tmpaddr[0]) = fecp->fec_addr_low;
++ *((unsigned short *) &tmpaddr[4]) = (fecp->fec_addr_high >> 16);
++ iap = &tmpaddr[0];
++ }
++
++ memcpy(dev->dev_addr, iap, ETH_ALEN);
++
++ /* Adjust MAC if using default MAC address */
++ if (iap == fec_mac_default)
++ dev->dev_addr[ETH_ALEN-1] = fec_mac_default[ETH_ALEN-1] + fep->index;
++}
++
++static void __inline__ fec_enable_phy_intr(void)
++{
++}
++
++static void __inline__ fec_disable_phy_intr(void)
++{
++}
++
++static void __inline__ fec_phy_ack_intr(void)
++{
++}
++
++static void __inline__ fec_localhw_setup(void)
++{
++}
++
++/*
++ * invalidate dcache related with the virtual memory range(start, end)
++ */
++static void __inline__ fec_dcache_inv_range(void * start, void * end)
++{
++ return ;
++}
++
++/*
++ * flush dcache related with the virtual memory range(start, end)
++ */
++static void __inline__ fec_dcache_flush_range(void * start, void * end)
++{
++ return ;
++}
++
++/*
++ * map memory space (addr, addr+size) to uncachable erea.
++ */
++static unsigned long __inline__ fec_map_uncache(unsigned long addr, int size)
++{
++ return addr;
++}
++
++/*
++ * unmap memory erea started with addr from uncachable erea.
++ */
++static void __inline__ fec_unmap_uncache(void * addr)
++{
++ return ;
++}
++
++
++/* ------------------------------------------------------------------------- */
++
++#elif defined(CONFIG_M532x)
++
++/*
++ * do some initializtion based architecture of this chip
++ */
++static void __inline__ fec_arch_init(void)
++{
++ return;
++}
++
++/*
++ * do some cleanup based architecture of this chip
++ */
++static void __inline__ fec_arch_exit(void)
++{
++ return;
++}
++
++/*
++ * Code specific for M532x
++ */
++static void __inline__ fec_request_intrs(struct net_device *dev)
++{
++ struct fec_enet_private *fep;
++ int b;
++ static const struct idesc {
++ char *name;
++ unsigned short irq;
++ } *idp, id[] = {
++ { "fec(TXF)", 36 },
++ { "fec(TXB)", 37 },
++ { "fec(TXFIFO)", 38 },
++ { "fec(TXCR)", 39 },
++ { "fec(RXF)", 40 },
++ { "fec(RXB)", 41 },
++ { "fec(MII)", 42 },
++ { "fec(LC)", 43 },
++ { "fec(HBERR)", 44 },
++ { "fec(GRA)", 45 },
++ { "fec(EBERR)", 46 },
++ { "fec(BABT)", 47 },
++ { "fec(BABR)", 48 },
++ { NULL },
++ };
++
++ fep = netdev_priv(dev);
++ b = (fep->index) ? 128 : 64;
++
++ /* Setup interrupt handlers. */
++ for (idp = id; idp->name; idp++) {
++ if (request_irq(b+idp->irq,fec_enet_interrupt,0,idp->name,dev)!=0)
++ printk("FEC: Could not allocate %s IRQ(%d)!\n",
++ idp->name, b+idp->irq);
++ }
++
++ /* Unmask interrupts */
++ MCF_INTC0_ICR36 = 0x2;
++ MCF_INTC0_ICR37 = 0x2;
++ MCF_INTC0_ICR38 = 0x2;
++ MCF_INTC0_ICR39 = 0x2;
++ MCF_INTC0_ICR40 = 0x2;
++ MCF_INTC0_ICR41 = 0x2;
++ MCF_INTC0_ICR42 = 0x2;
++ MCF_INTC0_ICR43 = 0x2;
++ MCF_INTC0_ICR44 = 0x2;
++ MCF_INTC0_ICR45 = 0x2;
++ MCF_INTC0_ICR46 = 0x2;
++ MCF_INTC0_ICR47 = 0x2;
++ MCF_INTC0_ICR48 = 0x2;
++
++ MCF_INTC0_IMRH &= ~(
++ MCF_INTC_IMRH_INT_MASK36 |
++ MCF_INTC_IMRH_INT_MASK37 |
++ MCF_INTC_IMRH_INT_MASK38 |
++ MCF_INTC_IMRH_INT_MASK39 |
++ MCF_INTC_IMRH_INT_MASK40 |
++ MCF_INTC_IMRH_INT_MASK41 |
++ MCF_INTC_IMRH_INT_MASK42 |
++ MCF_INTC_IMRH_INT_MASK43 |
++ MCF_INTC_IMRH_INT_MASK44 |
++ MCF_INTC_IMRH_INT_MASK45 |
++ MCF_INTC_IMRH_INT_MASK46 |
++ MCF_INTC_IMRH_INT_MASK47 |
++ MCF_INTC_IMRH_INT_MASK48 );
++
++ /* Set up gpio outputs for MII lines */
++ MCF_GPIO_PAR_FECI2C |= (0 |
++ MCF_GPIO_PAR_FECI2C_PAR_MDC_EMDC |
++ MCF_GPIO_PAR_FECI2C_PAR_MDIO_EMDIO);
++ MCF_GPIO_PAR_FEC = (0 |
++ MCF_GPIO_PAR_FEC_PAR_FEC_7W_FEC |
++ MCF_GPIO_PAR_FEC_PAR_FEC_MII_FEC);
++}
++
++static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_private *fep)
++{
++ volatile fec_t *fecp;
++
++ fecp = fep->hwp;
++ fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x04;
++ fecp->fec_x_cntrl = 0x00;
++
++ /*
++ * Set MII speed to 2.5 MHz
++ */
++ fep->phy_speed = ((((MCF_CLK / 2) / (2500000 / 10)) + 5) / 10) * 2;
++ fecp->fec_mii_speed = fep->phy_speed;
++
++ fec_restart(dev, 0);
++}
++
++static void __inline__ fec_get_mac(struct net_device *dev)
++{
++ struct fec_enet_private *fep = netdev_priv(dev);
++ volatile fec_t *fecp;
++ unsigned char *iap, tmpaddr[ETH_ALEN];
++
++ fecp = fep->hwp;
++
++ if (FEC_FLASHMAC) {
++ /*
++ * Get MAC address from FLASH.
++ * If it is all 1's or 0's, use the default.
++ */
++ iap = FEC_FLASHMAC;
++ if ((iap[0] == 0) && (iap[1] == 0) && (iap[2] == 0) &&
++ (iap[3] == 0) && (iap[4] == 0) && (iap[5] == 0))
++ iap = fec_mac_default;
++ if ((iap[0] == 0xff) && (iap[1] == 0xff) && (iap[2] == 0xff) &&
++ (iap[3] == 0xff) && (iap[4] == 0xff) && (iap[5] == 0xff))
++ iap = fec_mac_default;
++ } else {
++ *((unsigned long *) &tmpaddr[0]) = fecp->fec_addr_low;
++ *((unsigned short *) &tmpaddr[4]) = (fecp->fec_addr_high >> 16);
++ iap = &tmpaddr[0];
++ }
++
++ memcpy(dev->dev_addr, iap, ETH_ALEN);
++
++ /* Adjust MAC if using default MAC address */
++ if (iap == fec_mac_default)
++ dev->dev_addr[ETH_ALEN-1] = fec_mac_default[ETH_ALEN-1] + fep->index;
++}
++
++static void __inline__ fec_enable_phy_intr(void)
++{
++}
++
++static void __inline__ fec_disable_phy_intr(void)
++{
++}
++
++static void __inline__ fec_phy_ack_intr(void)
++{
++}
++
++static void __inline__ fec_localhw_setup(void)
++{
++}
++
++/*
++ * in...
[truncated message content] |