patch-2.4.3 linux/arch/ppc/8xx_io/fec.c

Next file: linux/arch/ppc/8xx_io/uart.c
Previous file: linux/arch/ppc/8xx_io/enet.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.2/linux/arch/ppc/8xx_io/fec.c linux/arch/ppc/8xx_io/fec.c
@@ -8,7 +8,9 @@
  * describes connections using the internal parallel port I/O, which
  * is basically all of Port D.
  *
- * Right now, I am very watseful with the buffers.  I allocate memory
+ * Includes support for the following PHYs: QS6612, LXT970, LXT971/2.
+ *
+ * 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
@@ -18,13 +20,16 @@
  * Much better multiple PHY support by Magnus Damm.
  * Copyright (c) 2000 Ericsson Radio Systems AB.
  *
+ * Make use of MII for PHY control configurable.
+ * Some fixes.
+ * Copyright (c) 2000 Wolfgang Denk, DENX Software Engineering.
  */
 
 /* List of PHYs we wish to support.
 */
-#define CONFIG_FEC_LXT970
-#define CONFIG_FEC_LXT971
-#define CONFIG_FEC_QS6612
+#undef	CONFIG_FEC_LXT970
+#define	CONFIG_FEC_LXT971
+#undef	CONFIG_FEC_QS6612
 
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -54,6 +59,7 @@
 #include <asm/uaccess.h>
 #include "commproc.h"
 
+#ifdef	CONFIG_USE_MDIO
 /* Forward declarations of some structures to support different PHYs
 */
 
@@ -71,6 +77,7 @@
 	const phy_cmd_t *ack_int;
 	const phy_cmd_t *shutdown;
 } phy_info_t;
+#endif	/* CONFIG_USE_MDIO */
 
 /* 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 is best
@@ -78,20 +85,20 @@
  * We don't need to allocate pages for the transmitter.  We just use
  * the skbuffer directly.
  */
-#if 1
-#define FEC_ENET_RX_PAGES	4
+#ifdef CONFIG_ENET_BIG_BUFFERS
+#define FEC_ENET_RX_PAGES	16
 #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 TX_RING_SIZE		8	/* Must be power of two */
-#define TX_RING_MOD_MASK	7	/*   for this to work */
+#define TX_RING_SIZE		16	/* Must be power of two */
+#define TX_RING_MOD_MASK	15	/*   for this to work */
 #else
-#define FEC_ENET_RX_PAGES	16
+#define FEC_ENET_RX_PAGES	4
 #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 TX_RING_SIZE		16	/* Must be power of two */
-#define TX_RING_MOD_MASK	15	/*   for this to work */
+#define TX_RING_SIZE		8	/* Must be power of two */
+#define TX_RING_MOD_MASK	7	/*   for this to work */
 #endif
 
 /* Interrupt events/masks.
@@ -107,6 +114,26 @@
 #define FEC_ENET_MII	((uint)0x00800000)	/* MII interrupt */
 #define FEC_ENET_EBERR	((uint)0x00400000)	/* SDMA bus error */
 
+/*
+*/
+#define FEC_ECNTRL_PINMUX	0x00000004
+#define FEC_ECNTRL_ETHER_EN	0x00000002
+#define FEC_ECNTRL_RESET	0x00000001
+
+#define FEC_RCNTRL_BC_REJ	0x00000010
+#define FEC_RCNTRL_PROM		0x00000008
+#define FEC_RCNTRL_MII_MODE	0x00000004
+#define FEC_RCNTRL_DRT		0x00000002
+#define FEC_RCNTRL_LOOP		0x00000001
+
+#define FEC_TCNTRL_FDEN		0x00000004
+#define FEC_TCNTRL_HBC		0x00000002
+#define FEC_TCNTRL_GTS		0x00000001
+
+/* Delay to wait for FEC reset command to complete (in us)
+*/
+#define FEC_RESET_DELAY		50
+
 /* The FEC stores dest/src/type, data, and checksum for receive packets.
  */
 #define PKT_MAXBUF_SIZE		1518
@@ -138,6 +165,7 @@
 	uint	tx_full;
 	spinlock_t lock;
 
+#ifdef	CONFIG_USE_MDIO
 	uint	phy_id;
 	uint	phy_id_done;
 	uint	phy_status;
@@ -148,6 +176,7 @@
 	uint	sequence_done;
 
 	uint	phy_addr;
+#endif	/* CONFIG_USE_MDIO */
 
 	int	link;
 	int	old_link;
@@ -165,7 +194,9 @@
 
 static int fec_enet_open(struct net_device *dev);
 static int fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev);
+#ifdef	CONFIG_USE_MDIO
 static void fec_enet_mii(struct net_device *dev);
+#endif	/* CONFIG_USE_MDIO */
 static void fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs);
 #ifdef CONFIG_FEC_PACKETHOOK
 static void  fec_enet_tx(struct net_device *dev, __u32 regval);
@@ -181,6 +212,7 @@
 static void fec_stop(struct net_device *dev);
 static	ushort	my_enet_addr[3];
 
+#ifdef	CONFIG_USE_MDIO
 /* 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.
@@ -197,7 +229,7 @@
 mii_list_t	*mii_head;
 mii_list_t	*mii_tail;
 
-static int	mii_queue(struct net_device *dev, int request, 
+static int	mii_queue(struct net_device *dev, int request,
 				void (*func)(uint, struct net_device *));
 
 /* Make MII read/write commands for the FEC.
@@ -206,11 +238,13 @@
 #define mk_mii_write(REG, VAL)	(0x50020000 | ((REG & 0x1f) << 18) | \
 						(VAL & 0xffff))
 #define mk_mii_end	0
+#endif	/* CONFIG_USE_MDIO */
 
 /* Transmitter timeout.
 */
 #define TX_TIMEOUT (2*HZ)
 
+#ifdef	CONFIG_USE_MDIO
 /* Register definitions for the PHY.
 */
 
@@ -218,7 +252,7 @@
 #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_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          */
@@ -230,18 +264,19 @@
 #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_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_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_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 */ 
+#define PHY_STAT_100FDX	0x8000  /* 100 Mbit full duplex selected */
+#endif	/* CONFIG_USE_MDIO */
 
 #ifdef CONFIG_FEC_PACKETHOOK
 int
@@ -291,7 +326,7 @@
 	fep->ph_proto = 0;
 	fep->ph_regaddr = NULL;
 	fep->ph_priv = NULL;
-	
+
 	fep->ph_lock = 0;
 
 	return retval;
@@ -345,7 +380,7 @@
 
 	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.
 	 */
@@ -404,7 +439,7 @@
 	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", 
+		printk("  %08x: %04x %04x %08x\n",
 		       (uint) bdp,
 		       bdp->cbd_sc,
 		       bdp->cbd_datlen,
@@ -443,7 +478,6 @@
 
 	if (fep->ph_regaddr) regval = *fep->ph_regaddr;
 #endif
-
 	fecp = (volatile fec_t*)dev->base_addr;
 
 	/* Get the interrupt events that caused us to be here.
@@ -478,9 +512,13 @@
 		}
 
 		if (int_events & FEC_ENET_MII) {
+#ifdef	CONFIG_USE_MDIO
 			fec_enet_mii(dev);
+#else
+printk("%s[%d] %s: unexpected FEC_ENET_MII event\n", __FILE__,__LINE__,__FUNCTION__);
+#endif	/* CONFIG_USE_MDIO */
 		}
-	
+
 	}
 }
 
@@ -541,23 +579,23 @@
 		 */
 		if (bdp->cbd_sc & BD_ENET_TX_DEF)
 			fep->stats.collisions++;
-	    
+
 		/* Free the sk buffer associated with this last transmit.
 		 */
 #if 0
 printk("TXI: %x %x %x\n", bdp, skb, fep->skb_dirty);
 #endif
-		dev_kfree_skb(skb/*, FREE_WRITE*/);
+		dev_kfree_skb_irq (skb/*, FREE_WRITE*/);
 		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 (bdp->cbd_sc & BD_ENET_TX_WRAP)
 			bdp = fep->tx_bd_base;
 		else
 			bdp++;
-	    
+
 		/* Since we have freed up a buffer, the ring is no longer
 		 * full.
 		 */
@@ -617,7 +655,7 @@
 	/* Check for errors. */
 	if (bdp->cbd_sc & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO |
 			   BD_ENET_RX_CR | BD_ENET_RX_OV)) {
-		fep->stats.rx_errors++;       
+		fep->stats.rx_errors++;
 		if (bdp->cbd_sc & (BD_ENET_RX_LG | BD_ENET_RX_SH)) {
 		/* Frame too long or too short. */
 			fep->stats.rx_length_errors++;
@@ -703,7 +741,7 @@
 		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
@@ -732,6 +770,7 @@
 }
 
 
+#ifdef	CONFIG_USE_MDIO
 static void
 fec_enet_mii(struct net_device *dev)
 {
@@ -743,7 +782,7 @@
 	fep = (struct fec_enet_private *)dev->priv;
 	ep = &(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec);
 	mii_reg = ep->fec_mii_data;
-	
+
 	if ((mip = mii_head) == NULL) {
 		printk("MII and no head!\n");
 		return;
@@ -756,8 +795,9 @@
 	mip->mii_next = mii_free;
 	mii_free = mip;
 
-	if ((mip = mii_head) != NULL)
+	if ((mip = mii_head) != NULL) {
 		ep->fec_mii_data = mip->mii_regval;
+	}
 }
 
 static int
@@ -786,13 +826,11 @@
 		if (mii_head) {
 			mii_tail->mii_next = mip;
 			mii_tail = mip;
-		}
-		else {
+		} else {
 			mii_head = mii_tail = mip;
 			(&(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec))->fec_mii_data = regval;
 		}
-	}
-	else {
+	} else {
 		retval = 1;
 	}
 
@@ -808,7 +846,7 @@
 	if(!c)
 		return;
 
-	for(k = 0; (c+k)->mii_data != mk_mii_end; k++) 
+	for(k = 0; (c+k)->mii_data != mk_mii_end; k++)
 		mii_queue(dev, (c+k)->mii_data, (c+k)->funct);
 }
 
@@ -896,7 +934,7 @@
 }
 
 static phy_info_t phy_info_lxt970 = {
-	0x07810000, 
+	0x07810000,
 	"LXT970",
 
 	(const phy_cmd_t []) {  /* config */
@@ -919,12 +957,12 @@
 	},
 	(const phy_cmd_t []) { /* 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, }
 	},
@@ -933,7 +971,7 @@
 		{ mk_mii_end, }
 	},
 };
-	
+
 #endif /* CONFIG_FEC_LXT970 */
 
 /* ------------------------------------------------------------------------- */
@@ -950,7 +988,7 @@
 #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...
@@ -980,14 +1018,11 @@
 }
 
 static phy_info_t phy_info_lxt971 = {
-	0x0001378e, 
+	0x0001378e,
 	"LXT971",
-	
-	(const phy_cmd_t []) {  /* config */  
-		/* limit to 10MBit because my protorype board 
-		 * doesn't work with 100. */
 
-		{ mk_mii_write(MII_REG_ANAR, 0x061), NULL }, /* 10 MBit */
+	(const phy_cmd_t []) {  /* config */
+//		{ mk_mii_write(MII_REG_ANAR, 0x021), NULL }, /* 10  Mbps, HD */
 		{ mk_mii_read(MII_REG_CR), mii_parse_cr },
 		{ mk_mii_read(MII_REG_ANAR), mii_parse_anar },
 		{ mk_mii_end, }
@@ -995,12 +1030,12 @@
 	(const phy_cmd_t []) {  /* startup - enable interrupts */
 		{ mk_mii_write(MII_LXT971_IER, 0x00f2), NULL },
 		{ mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
-	
+
 		/* 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_read(MII_REG_SR), mii_parse_sr },
 		{ mk_mii_end, }
 	},
 	(const phy_cmd_t []) { /* ack_int */
@@ -1008,9 +1043,9 @@
 
 		{ mk_mii_read(MII_REG_SR), mii_parse_sr },
 		{ mk_mii_read(MII_LXT971_SR2), mii_parse_lxt971_sr2 },
-		
+
 		/* we only need to read ISR to acknowledge */
-		
+
 		{ mk_mii_read(MII_LXT971_ISR), NULL },
 		{ mk_mii_end, }
 	},
@@ -1053,13 +1088,13 @@
 }
 
 static phy_info_t phy_info_qs6612 = {
-	0x00181440, 
+	0x00181440,
 	"QS6612",
-	
-	(const phy_cmd_t []) {  /* config */  
-//	{ mk_mii_write(MII_REG_ANAR, 0x061), NULL }, /* 10 MBit */
 
-		/* The PHY powers up isolated on the RPX, 
+	(const phy_cmd_t []) {  /* config */
+//	{ mk_mii_write(MII_REG_ANAR, 0x061), NULL }, /* 10  Mbps */
+
+		/* The PHY powers up isolated on the RPX,
 		 * so send a command to allow operation.
 		 */
 
@@ -1077,9 +1112,9 @@
 		{ mk_mii_end, }
 	},
 	(const phy_cmd_t []) { /* 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 },
@@ -1134,10 +1169,10 @@
 		printk("link up");
 
 		switch(*s & PHY_STAT_SPMASK) {
-		case PHY_STAT_100FDX: printk(", 100MBit Full Duplex"); break;
-		case PHY_STAT_100HDX: printk(", 100MBit Half Duplex"); break;
-		case PHY_STAT_10FDX: printk(", 10MBit Full Duplex"); break;
-		case PHY_STAT_10HDX: printk(", 10MBit Half Duplex"); break;
+		case PHY_STAT_100FDX: printk(", 100 Mbps Full Duplex"); break;
+		case PHY_STAT_100HDX: printk(", 100 Mbps Half Duplex"); break;
+		case PHY_STAT_10FDX: printk(", 10 Mbps Full Duplex"); break;
+		case PHY_STAT_10HDX: printk(", 10 Mbps Half Duplex"); break;
 		default:
 			printk(", Unknown speed/duplex");
 		}
@@ -1177,7 +1212,7 @@
 
 	if (*s & PHY_CONF_LOOP)
 		printk(", loopback enabled");
-	
+
 	printk(".\n");
 
 	fep->sequence_done = 1;
@@ -1194,7 +1229,7 @@
 
 	if (fep->link) {
 		duplex = 0;
-		if (fep->phy_status 
+		if (fep->phy_status
 		    & (PHY_STAT_100FDX | PHY_STAT_10FDX))
 			duplex = 1;
 		fec_restart(dev, duplex);
@@ -1245,18 +1280,20 @@
 
 	fep = dev->priv;
 	fep->phy_id |= (mii_reg & 0xffff);
-	printk("fec: Phy @ 0x%x, type 0x%08x\n", fep->phy_addr, fep->phy_id);
 
 	for(i = 0; phy_info[i]; i++)
 		if(phy_info[i]->id == (fep->phy_id >> 4))
 			break;
 
 	if(!phy_info[i])
-		panic("%s: PHY id 0x%08x is not supported!\n", 
+		panic("%s: PHY id 0x%08x is not supported!\n",
 		      dev->name, fep->phy_id);
-      
+
 	fep->phy = phy_info[i];
 	fep->phy_id_done = 1;
+
+	printk("%s: Phy @ 0x%x, type %s (0x%08x)\n",
+		dev->name, fep->phy_addr, fep->phy->name, fep->phy_id);
 }
 
 /* Scan all of the MII PHY addresses looking for someone to respond
@@ -1270,25 +1307,23 @@
 
 	fep = dev->priv;
 
-	if (fep->phy_addr < 32) {
-		if ((phytype = (mii_reg & 0xffff)) != 0xffff) {
-			
-			/* Got first part of ID, now get remainder.
-			*/
-			fep->phy_id = phytype << 16;
-			mii_queue(dev, mk_mii_read(MII_REG_PHYIR2),
-							mii_discover_phy3);
-		}
-		else {
-			fep->phy_addr++;
+	if ((phytype = (mii_reg & 0xffff)) != 0xffff) {
+
+		/* Got first part of ID, now get remainder.
+		*/
+		fep->phy_id = phytype << 16;
+		mii_queue(dev, mk_mii_read(MII_REG_PHYIR2), mii_discover_phy3);
+	} else {
+		fep->phy_addr++;
+		if (fep->phy_addr < 32) {
 			mii_queue(dev, mk_mii_read(MII_REG_PHYIR1),
 							mii_discover_phy);
+		} else {
+			printk("fec: No PHY device found.\n");
 		}
 	}
-	else {
-		printk("FEC: No PHY device found.\n");
-	}
 }
+#endif	/* CONFIG_USE_MDIO */
 
 /* This interrupt occurs when the PHY detects a link change.
 */
@@ -1299,16 +1334,36 @@
 mii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs)
 #endif
 {
+#ifdef	CONFIG_USE_MDIO
 	struct	net_device *dev = dev_id;
 	struct fec_enet_private *fep = dev->priv;
+	volatile immap_t *immap = (immap_t *)IMAP_ADDR;
+	volatile fec_t *fecp = &(immap->im_cpm.cp_fec);
+	unsigned int ecntrl = fecp->fec_ecntrl;
+
+	/* We need the FEC enabled to access the MII
+	*/
+	if ((ecntrl & FEC_ECNTRL_ETHER_EN) == 0) {
+		fecp->fec_ecntrl |= FEC_ECNTRL_ETHER_EN;
+	}
+#endif	/* CONFIG_USE_MDIO */
 
 #if 0
 	disable_irq(fep->mii_irq);  /* disable now, enable later */
 #endif
 
+
+#ifdef	CONFIG_USE_MDIO
 	mii_do_cmd(dev, fep->phy->ack_int);
 	mii_do_cmd(dev, phy_cmd_relink);  /* restart and display status */
 
+	if ((ecntrl & FEC_ECNTRL_ETHER_EN) == 0) {
+		fecp->fec_ecntrl = ecntrl;	/* restore old settings */
+	}
+#else
+printk("%s[%d] %s: unexpected Link interrupt\n", __FILE__,__LINE__,__FUNCTION__);
+#endif	/* CONFIG_USE_MDIO */
+
 }
 
 static int
@@ -1320,6 +1375,7 @@
 	 * a simple way to do that.
 	 */
 
+#ifdef	CONFIG_USE_MDIO
 	fep->sequence_done = 0;
 	fep->link = 0;
 
@@ -1327,7 +1383,6 @@
 		mii_do_cmd(dev, fep->phy->ack_int);
 		mii_do_cmd(dev, fep->phy->config);
 		mii_do_cmd(dev, phy_cmd_config);  /* display configuration */
-
 		while(!fep->sequence_done)
 			schedule();
 
@@ -1335,8 +1390,12 @@
 		netif_start_queue(dev);
 		return 0;		/* Success */
 	}
-
 	return -ENODEV;		/* No PHY we understand */
+#else
+	fep->link = 1;
+	netif_start_queue(dev);
+	return 0;	/* Success */
+#endif	/* CONFIG_USE_MDIO */
 
 }
 
@@ -1377,13 +1436,13 @@
 	ep = &(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec);
 
 	if (dev->flags&IFF_PROMISC) {
-	  
+
 		/* Log any net taps. */
 		printk("%s: Promiscuous mode enabled.\n", dev->name);
-		ep->fec_r_cntrl |= 0x0008;
+		ep->fec_r_cntrl |= FEC_RCNTRL_PROM;
 	} else {
 
-		ep->fec_r_cntrl &= ~0x0008;
+		ep->fec_r_cntrl &= ~FEC_RCNTRL_PROM;
 
 		if (dev->flags & IFF_ALLMULTI) {
 			/* Catch all multicast addresses, so set the
@@ -1404,7 +1463,7 @@
 			dmi = dev->mc_list;
 
 			for (i=0; i<dev->mc_count; i++) {
-				
+
 				/* Only support group multicast for now.
 				*/
 				if (!(dmi->dmi_addr[0] & 1))
@@ -1448,7 +1507,7 @@
 	volatile	fec_t	*fecp;
 	bd_t		*bd;
 	extern		uint	_get_IMMR(void);
-#ifdef CONFIG_RPXCLASSIC
+#ifdef CONFIG_SCC_ENET
 	unsigned char	tmpaddr[6];
 #endif
 
@@ -1472,8 +1531,15 @@
 
 	/* Whack a reset.  We should wait for this.
 	*/
-	fecp->fec_ecntrl = 1;
-	udelay(10);
+	fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_RESET;
+	for (i = 0;
+	     (fecp->fec_ecntrl & FEC_ECNTRL_RESET) && (i < FEC_RESET_DELAY);
+	     ++i) {
+		udelay(1);
+	}
+	if (i == FEC_RESET_DELAY) {
+		printk ("FEC Reset timeout!\n");
+	}
 
 	/* Set the Ethernet address.  If using multiple Enets on the 8xx,
 	 * this needs some work to get unique addresses.
@@ -1481,12 +1547,13 @@
 	eap = (unsigned char *)my_enet_addr;
 	iap = bd->bi_enetaddr;
 
-#ifdef CONFIG_RPXCLASSIC
-	/* The Embedded Planet boards have only one MAC address in
-	 * the EEPROM, but can have two Ethernet ports.  For the
-	 * FEC port, we create another address by setting one of
-	 * the address bits above something that would have (up to
-	 * now) been allocated.
+#ifdef CONFIG_SCC_ENET
+	/*
+         * If a board has Ethernet configured both on a SCC and the
+         * FEC, it needs (at least) 2 MAC addresses (we know that Sun
+         * disagrees, but anyway). For the FEC port, we create
+         * another address by setting one of the address bits above
+         * something that would have (up to now) been allocated.
 	 */
 	for (i=0; i<6; i++)
 		tmpaddr[i] = *iap++;
@@ -1494,8 +1561,9 @@
 	iap = tmpaddr;
 #endif
 
-	for (i=0; i<6; i++)
+	for (i=0; i<6; i++) {
 		dev->dev_addr[i] = *eap++ = *iap++;
+	}
 
 	/* Allocate memory for buffer descriptors.
 	*/
@@ -1518,9 +1586,6 @@
 	fep->rx_bd_base = cbd_base;
 	fep->tx_bd_base = cbd_base + RX_RING_SIZE;
 
-	fep->dirty_tx = fep->cur_tx = fep->tx_bd_base;
-	fep->cur_rx = fep->rx_bd_base;
-
 	fep->skb_cur = fep->skb_dirty = 0;
 
 	/* Initialize the receive buffer descriptors.
@@ -1565,22 +1630,27 @@
 	*/
 	if (request_8xxirq(FEC_INTERRUPT, fec_enet_interrupt, 0, "fec", dev) != 0)
 		panic("Could not allocate FEC IRQ!");
+
 #ifdef CONFIG_RPXCLASSIC
 	/* Make Port C, bit 15 an input that causes interrupts.
 	*/
 	immap->im_ioport.iop_pcpar &= ~0x0001;
 	immap->im_ioport.iop_pcdir &= ~0x0001;
-	immap->im_ioport.iop_pcso &= ~0x0001;
-	immap->im_ioport.iop_pcint |= 0x0001;
+	immap->im_ioport.iop_pcso  &= ~0x0001;
+	immap->im_ioport.iop_pcint |=  0x0001;
 	cpm_install_handler(CPMVEC_PIO_PC15, mii_link_interrupt, dev);
 
 	/* Make LEDS reflect Link status.
 	*/
 	*((uint *) RPX_CSR_ADDR) &= ~BCSR2_FETHLEDMODE;
 #endif
-#ifdef CONFIG_FADS
-	if (request_8xxirq(SIU_IRQ2, mii_link_interrupt, 0, "mii", dev) != 0)
+
+#ifdef PHY_INTERRUPT
+	if (request_8xxirq(PHY_INTERRUPT, mii_link_interrupt, 0, "mii", dev) != 0)
 		panic("Could not allocate MII IRQ!");
+
+	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_siel |=
+		(0x80000000 >> PHY_INTERRUPT);
 #endif
 
 	dev->base_addr = (unsigned long)fecp;
@@ -1595,9 +1665,11 @@
 	dev->get_stats = fec_enet_get_stats;
 	dev->set_multicast_list = set_multicast_list;
 
+#ifdef	CONFIG_USE_MDIO
 	for (i=0; i<NMII-1; i++)
 		mii_cmds[i].mii_next = &mii_cmds[i+1];
 	mii_free = mii_cmds;
+#endif	/* CONFIG_USE_MDIO */
 
 	/* Configure all of port D for MII.
 	*/
@@ -1609,23 +1681,46 @@
 		immap->im_ioport.iop_pddir = 0x1c58;	/* Pre rev. D */
 	else
 		immap->im_ioport.iop_pddir = 0x1fff;	/* Rev. D and later */
-	
+
+#ifdef	CONFIG_USE_MDIO
 	/* Set MII speed to 2.5 MHz
 	*/
-	fecp->fec_mii_speed = fep->phy_speed = 
-		((bd->bi_busfreq * 1000000) / 2500000) & 0x7e;
+	fecp->fec_mii_speed = fep->phy_speed =
+		(
+		  ( ((bd->bi_intfreq * 1000000) + 500000) / 2500000 / 2 )
+		  & 0x3F
+		) << 1;
+#else
+	fecp->fec_mii_speed = 0;	/* turn off MDIO */
+#endif	/* CONFIG_USE_MDIO */
 
-	printk("%s: FEC ENET Version 0.2, ", dev->name);
-	for (i=0; i<5; i++)
-		printk("%02x:", dev->dev_addr[i]);
-	printk("%02x\n", dev->dev_addr[5]);
+	printk ("%s: FEC ENET Version 0.2, FEC irq %d"
+#ifdef PHY_INTERRUPT
+		", MII irq %d"
+#endif
+		", addr ",
+		dev->name, FEC_INTERRUPT
+#ifdef PHY_INTERRUPT
+		, PHY_INTERRUPT
+#endif
+	);
+	for (i=0; i<6; i++)
+		printk("%02x%c", dev->dev_addr[i], (i==5) ? '\n' : ':');
 
+#ifdef	CONFIG_USE_MDIO	/* start in full duplex mode, and negotiate speed */
+	fec_restart (dev, 1);
+#else			/* always use half duplex mode only */
+	fec_restart (dev, 0);
+#endif
+
+#ifdef	CONFIG_USE_MDIO
 	/* Queue up command to detect the PHY and initialize the
 	 * remainder of the interface.
 	 */
 	fep->phy_id_done = 0;
 	fep->phy_addr = 0;
 	mii_queue(dev, mk_mii_read(MII_REG_PHYIR1), mii_discover_phy);
+#endif	/* CONFIG_USE_MDIO */
 
 	return 0;
 }
@@ -1639,7 +1734,6 @@
 {
 	struct fec_enet_private *fep;
 	int i;
-	unsigned char	*eap;
 	volatile	cbd_t	*bdp;
 	volatile	immap_t	*immap;
 	volatile	fec_t	*fecp;
@@ -1652,33 +1746,25 @@
 
 	/* Whack a reset.  We should wait for this.
 	*/
-	fecp->fec_ecntrl = 1;
-	udelay(10);
-
-	/* Enable interrupts we wish to service.
-	*/
-	fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB |
-				FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII);
-
-	/* Clear any outstanding interrupt.
-	*/
-	fecp->fec_ievent = 0xffc0;
-
-	fecp->fec_ivec = (FEC_INTERRUPT/2) << 29;
+	fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_RESET;
+	for (i = 0;
+	     (fecp->fec_ecntrl & FEC_ECNTRL_RESET) && (i < FEC_RESET_DELAY);
+	     ++i) {
+		udelay(1);
+	}
+	if (i == FEC_RESET_DELAY) {
+		printk ("FEC Reset timeout!\n");
+	}
 
 	/* Set station address.
 	*/
-	fecp->fec_addr_low = (my_enet_addr[0] << 16) | my_enet_addr[1];
-	fecp->fec_addr_high = my_enet_addr[2];
-
-	eap = (unsigned char *)&my_enet_addr[0];
-	for (i=0; i<6; i++)
-		dev->dev_addr[i] = *eap++;
+	fecp->fec_addr_low  = (my_enet_addr[0] << 16) | my_enet_addr[1];
+	fecp->fec_addr_high =  my_enet_addr[2];
 
 	/* Reset all multicast.
 	*/
 	fecp->fec_hash_table_high = 0;
-	fecp->fec_hash_table_low = 0;
+	fecp->fec_hash_table_low  = 0;
 
 	/* Set maximum receive buffer size.
 	*/
@@ -1739,12 +1825,12 @@
 	/* Enable MII mode.
 	*/
 	if (duplex) {
-		fecp->fec_r_cntrl = 0x04;	/* MII enable */
-		fecp->fec_x_cntrl = 0x04;	/* FD enable */
+		fecp->fec_r_cntrl = FEC_RCNTRL_MII_MODE;	/* MII enable */
+		fecp->fec_x_cntrl = FEC_TCNTRL_FDEN;		/* FD enable */
 	}
 	else {
-		fecp->fec_r_cntrl = 0x06;	/* MII enable|No Rcv on Xmit */
-		fecp->fec_x_cntrl = 0x00;
+		fecp->fec_r_cntrl = FEC_RCNTRL_MII_MODE | FEC_RCNTRL_DRT;
+		fecp->fec_x_cntrl = 0;
 	}
 	fep->full_duplex = duplex;
 
@@ -1752,13 +1838,26 @@
 	*/
 	fecp->fec_fun_code = 0x78000000;
 
+#ifdef	CONFIG_USE_MDIO
 	/* Set MII speed.
 	*/
 	fecp->fec_mii_speed = fep->phy_speed;
+#endif	/* CONFIG_USE_MDIO */
+
+	/* Clear any outstanding interrupt.
+	*/
+	fecp->fec_ievent = 0xffc0;
+
+	fecp->fec_ivec = (FEC_INTERRUPT/2) << 29;
+
+	/* Enable interrupts we wish to service.
+	*/
+	fecp->fec_imask = ( FEC_ENET_TXF | FEC_ENET_TXB |
+			    FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII );
 
 	/* And last, enable the transmit and receive processing.
 	*/
-	fecp->fec_ecntrl = 6;
+	fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN;
 	fecp->fec_r_des_active = 0x01000000;
 }
 
@@ -1768,33 +1867,45 @@
 	volatile	immap_t	*immap;
 	volatile	fec_t	*fecp;
 	struct fec_enet_private *fep;
+	int i;
 
 	immap = (immap_t *)IMAP_ADDR;	/* pointer to internal registers */
-	
+
 	fecp = &(immap->im_cpm.cp_fec);
-	
+
+	if ((fecp->fec_ecntrl & FEC_ECNTRL_ETHER_EN) == 0)
+		return;	/* already down */
+
 	fep = dev->priv;
 
 
 	fecp->fec_x_cntrl = 0x01;	/* Graceful transmit stop */
 
-	while(!(fecp->fec_ievent & 0x10000000));
-
-	/* Whack a reset.  We should wait for this.
-	*/
-	fecp->fec_ecntrl = 1;
-	udelay(10);
+	for (i = 0;
+	     ((fecp->fec_ievent & 0x10000000) == 0) && (i < FEC_RESET_DELAY);
+	     ++i) {
+		udelay(1);
+	}
+	if (i == FEC_RESET_DELAY) {
+		printk ("FEC timeout on graceful transmit stop\n");
+	}
 
 	/* Clear outstanding MII command interrupts.
 	*/
 	fecp->fec_ievent = FEC_ENET_MII;
 
-	/* Enable MII command finihed interrupt 
+	/* Enable MII command finished interrupt
 	*/
 	fecp->fec_ivec = (FEC_INTERRUPT/2) << 29;
 	fecp->fec_imask = FEC_ENET_MII;
 
+#ifdef	CONFIG_USE_MDIO
 	/* Set MII speed.
 	*/
 	fecp->fec_mii_speed = fep->phy_speed;
+#endif	/* CONFIG_USE_MDIO */
+
+	/* Disable FEC
+	*/
+	fecp->fec_ecntrl &= ~(FEC_ECNTRL_ETHER_EN);
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)