Skip to content
Snippets Groups Projects
4xx_enet.c 61.8 KiB
Newer Older
  • Learn to ignore specific revisions
  • /*-----------------------------------------------------------------------------+
    
     *   This source code is dual-licensed.  You may use it under the terms of the
     *   GNU General Public License version 2, or under the license below.
    
     *	 This source code has been made available to you by IBM on an AS-IS
     *	 basis.	 Anyone receiving this source is licensed under IBM
     *	 copyrights to use it in any way he or she deems fit, including
     *	 copying it, modifying it, compiling it, and redistributing it either
     *	 with or without modifications.	 No license under IBM patents or
     *	 patent applications is to be implied by the copyright license.
    
     *	 Any user of this software should understand that IBM cannot provide
     *	 technical support for this software and will not be responsible for
     *	 any consequences resulting from the use of this software.
    
     *	 Any person who transfers this source code or any derivative work
     *	 must include the IBM copyright notice, this paragraph, and the
     *	 preceding two paragraphs in the transferred software.
    
     *	 COPYRIGHT   I B M   CORPORATION 1995
     *	 LICENSED MATERIAL  -  PROGRAM PROPERTY OF I B M
    
     *-----------------------------------------------------------------------------*/
    /*-----------------------------------------------------------------------------+
     *
    
     *  File Name:	enetemac.c
    
     *  Function:	Device driver for the ethernet EMAC3 macro on the 405GP.
    
     *  Author:	Mark Wisner
    
     *
     *  Change Activity-
     *
    
     *  Date	Description of Change					    BY
     *  ---------	---------------------					    ---
     *  05-May-99	Created							    MKW
     *  27-Jun-99	Clean up						    JWB
     *  16-Jul-99	Added MAL error recovery and better IP packet handling	    MKW
     *  29-Jul-99	Added Full duplex support				    MKW
     *  06-Aug-99	Changed names for Mal CR reg				    MKW
     *  23-Aug-99	Turned off SYE when running at 10Mbs			    MKW
     *  24-Aug-99	Marked descriptor empty after call_xlc			    MKW
     *  07-Sep-99	Set MAL RX buffer size reg to ENET_MAX_MTU_ALIGNED / 16	    MCG
     *		to avoid chaining maximum sized packets. Push starting
     *		RX descriptor address up to the next cache line boundary.
     *  16-Jan-00	Added support for booting with IP of 0x0		    MKW
     *  15-Mar-00	Updated enetInit() to enable broadcast addresses in the
    
     *		EMAC0_RXM register.					    JWB
    
     *  12-Mar-01	anne-sophie.harnois@nextream.fr
     *		 - Variables are compatible with those already defined in
     *		  include/net.h
     *		- Receive buffer descriptor ring is used to send buffers
     *		  to the user
     *		- Info print about send/received/handled packet number if
     *		  INFO_405_ENET is set
     *  17-Apr-01	stefan.roese@esd-electronics.com
     *		- MAL reset in "eth_halt" included
     *		- Enet speed and duplex output now in one line
     *  08-May-01	stefan.roese@esd-electronics.com
     *		- MAL error handling added (eth_init called again)
     *  13-Nov-01	stefan.roese@esd-electronics.com
    
     *		- Set IST bit in EMAC0_MR1 reg upon 100MBit or full duplex
    
     *  04-Jan-02	stefan.roese@esd-electronics.com
     *		- Wait for PHY auto negotiation to complete added
     *  06-Feb-02	stefan.roese@esd-electronics.com
     *		- Bug fixed in waiting for auto negotiation to complete
     *  26-Feb-02	stefan.roese@esd-electronics.com
     *		- rx and tx buffer descriptors now allocated (no fixed address
     *		  used anymore)
     *  17-Jun-02	stefan.roese@esd-electronics.com
     *		- MAL error debug printf 'M' removed (rx de interrupt may
     *		  occur upon many incoming packets with only 4 rx buffers).
    
     *-----------------------------------------------------------------------------*
    
     *  17-Nov-03	travis.sawyer@sandburst.com
     *		- ported from 405gp_enet.c to utilized upto 4 EMAC ports
     *		  in the 440GX.	 This port should work with the 440GP
     *		  (2 EMACs) also
     *  15-Aug-05	sr@denx.de
     *		- merged 405gp_enet.c and 440gx_enet.c to generic 4xx_enet.c
    		  now handling all 4xx cpu's.
    
     *-----------------------------------------------------------------------------*/
    
    #include <config.h>
    #include <common.h>
    #include <net.h>
    #include <asm/processor.h>
    
    #include <asm/cache.h>
    #include <asm/mmu.h>
    
    #include <commproc.h>
    
    #include <asm/ppc4xx.h>
    #include <asm/ppc4xx-emac.h>
    #include <asm/ppc4xx-mal.h>
    
    #include <miiphy.h>
    #include <malloc.h>
    
    
    #if !(defined(CONFIG_MII) || defined(CONFIG_CMD_MII))
    
    #error "CONFIG_MII has to be defined!"
    #endif
    
    #define EMAC_RESET_TIMEOUT 1000 /* 1000 ms reset timeout */
    
    #define PHY_AUTONEGOTIATE_TIMEOUT 5000	/* 5000 ms autonegotiate timeout */
    
    
    /* Ethernet Transmit and Receive Buffers */
    /* AS.HARNOIS
     * In the same way ENET_MAX_MTU and ENET_MAX_MTU_ALIGNED are set from
     * PKTSIZE and PKTSIZE_ALIGN (include/net.h)
     */
    
    #define ENET_MAX_MTU	       PKTSIZE
    
    #define ENET_MAX_MTU_ALIGNED   PKTSIZE_ALIGN
    
    /*-----------------------------------------------------------------------------+
     * Defines for MAL/EMAC interrupt conditions as reported in the UIC (Universal
     * Interrupt Controller).
     *-----------------------------------------------------------------------------*/
    
    #define ETH_IRQ_NUM(dev)	(VECNUM_ETH0 + ((dev) * VECNUM_ETH1_OFFS))
    
    #if defined(CONFIG_HAS_ETH3)
    #if !defined(CONFIG_440GX)
    #define UIC_ETHx	(UIC_MASK(ETH_IRQ_NUM(0)) || UIC_MASK(ETH_IRQ_NUM(1)) || \
    			 UIC_MASK(ETH_IRQ_NUM(2)) || UIC_MASK(ETH_IRQ_NUM(3)))
    #else
    /* Unfortunately 440GX spreads EMAC interrupts on multiple UIC's */
    #define UIC_ETHx	(UIC_MASK(ETH_IRQ_NUM(0)) || UIC_MASK(ETH_IRQ_NUM(1)))
    #define UIC_ETHxB	(UIC_MASK(ETH_IRQ_NUM(2)) || UIC_MASK(ETH_IRQ_NUM(3)))
    #endif /* !defined(CONFIG_440GX) */
    #elif defined(CONFIG_HAS_ETH2)
    #define UIC_ETHx	(UIC_MASK(ETH_IRQ_NUM(0)) || UIC_MASK(ETH_IRQ_NUM(1)) || \
    			 UIC_MASK(ETH_IRQ_NUM(2)))
    #elif defined(CONFIG_HAS_ETH1)
    #define UIC_ETHx	(UIC_MASK(ETH_IRQ_NUM(0)) || UIC_MASK(ETH_IRQ_NUM(1)))
    #else
    #define UIC_ETHx	UIC_MASK(ETH_IRQ_NUM(0))
    #endif
    
    /*
     * Define a default version for UIC_ETHxB for non 440GX so that we can
     * use common code for all 4xx variants
     */
    #if !defined(UIC_ETHxB)
    #define UIC_ETHxB	0
    #endif
    
    #define UIC_MAL_SERR	UIC_MASK(VECNUM_MAL_SERR)
    #define UIC_MAL_TXDE	UIC_MASK(VECNUM_MAL_TXDE)
    #define UIC_MAL_RXDE	UIC_MASK(VECNUM_MAL_RXDE)
    #define UIC_MAL_TXEOB	UIC_MASK(VECNUM_MAL_TXEOB)
    #define UIC_MAL_RXEOB	UIC_MASK(VECNUM_MAL_RXEOB)
    
    #define MAL_UIC_ERR	(UIC_MAL_SERR | UIC_MAL_TXDE | UIC_MAL_RXDE)
    #define MAL_UIC_DEF	(UIC_MAL_RXEOB | MAL_UIC_ERR)
    
    /*
     * We have 3 different interrupt types:
     * - MAL interrupts indicating successful transfer
     * - MAL error interrupts indicating MAL related errors
     * - EMAC interrupts indicating EMAC related errors
     *
     * All those interrupts can be on different UIC's, but since
     * now at least all interrupts from one type are on the same
     * UIC. Only exception is 440GX where the EMAC interrupts are
     * spread over two UIC's!
     */
    
    #if defined(CONFIG_440GX)
    #define UIC_BASE_MAL	UIC1_DCR_BASE
    #define UIC_BASE_MAL_ERR UIC2_DCR_BASE
    #define UIC_BASE_EMAC	UIC2_DCR_BASE
    #define UIC_BASE_EMAC_B	UIC3_DCR_BASE
    #else
    
    #define UIC_BASE_MAL	(UIC0_DCR_BASE + (UIC_NR(VECNUM_MAL_TXEOB) * 0x10))
    #define UIC_BASE_MAL_ERR (UIC0_DCR_BASE + (UIC_NR(VECNUM_MAL_SERR) * 0x10))
    #define UIC_BASE_EMAC	(UIC0_DCR_BASE + (UIC_NR(ETH_IRQ_NUM(0)) * 0x10))
    #define UIC_BASE_EMAC_B	(UIC0_DCR_BASE + (UIC_NR(ETH_IRQ_NUM(0)) * 0x10))
    #endif
    
    #define BI_PHYMODE_NONE	 0
    #define BI_PHYMODE_ZMII	 1
    
    #define BI_PHYMODE_RGMII 2
    
    #define BI_PHYMODE_GMII  3
    #define BI_PHYMODE_RTBI  4
    #define BI_PHYMODE_TBI   5
    
    #if defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
    
        defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
    
        defined(CONFIG_405EX)
    
    #define BI_PHYMODE_SMII  6
    #define BI_PHYMODE_MII   7
    
    #if defined(CONFIG_460EX) || defined(CONFIG_460GT)
    #define BI_PHYMODE_RMII  8
    #endif
    
    #define BI_PHYMODE_SGMII 9
    
    #if defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \
    
        defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
    
        defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
    
        defined(CONFIG_405EX)
    
    #define SDR0_MFR_ETH_CLK_SEL_V(n)	((0x01<<27) / (n+1))
    #endif
    
    #if defined(CONFIG_460EX) || defined(CONFIG_460GT)
    #define SDR0_ETH_CFG_CLK_SEL_V(n)	(0x01 << (8 + n))
    #endif
    
    #if defined(CONFIG_460EX) || defined(CONFIG_460GT)
    #define MAL_RX_CHAN_MUL	8	/* 460EX/GT uses MAL channel 8 for EMAC1 */
    #else
    #define MAL_RX_CHAN_MUL	1
    #endif
    
    
    /*--------------------------------------------------------------------+
     * Fixed PHY (PHY-less) support for Ethernet Ports.
     *--------------------------------------------------------------------*/
    
    /*
     * Some boards do not have a PHY for each ethernet port. These ports
     * are known as Fixed PHY (or PHY-less) ports. For such ports, set
     * the appropriate CONFIG_PHY_ADDR equal to CONFIG_FIXED_PHY and
    
     * then define CONFIG_SYS_FIXED_PHY_PORTS to define what the speed and
    
     * duplex should be for these ports in the board configuration
     * file.
     *
     * For Example:
     *     #define CONFIG_FIXED_PHY   0xFFFFFFFF
     *
     *     #define CONFIG_PHY_ADDR    CONFIG_FIXED_PHY
     *     #define CONFIG_PHY1_ADDR   1
     *     #define CONFIG_PHY2_ADDR   CONFIG_FIXED_PHY
     *     #define CONFIG_PHY3_ADDR   3
     *
    
     *     #define CONFIG_SYS_FIXED_PHY_PORT(devnum,speed,duplex) \
    
     *                     {devnum, speed, duplex},
     *
    
     *     #define CONFIG_SYS_FIXED_PHY_PORTS \
     *                     CONFIG_SYS_FIXED_PHY_PORT(0,1000,FULL) \
     *                     CONFIG_SYS_FIXED_PHY_PORT(2,100,HALF)
    
     */
    
    #ifndef CONFIG_FIXED_PHY
    #define CONFIG_FIXED_PHY	0xFFFFFFFF /* Fixed PHY (PHY-less) */
    #endif
    
    
    #ifndef CONFIG_SYS_FIXED_PHY_PORTS
    #define CONFIG_SYS_FIXED_PHY_PORTS	/* default is an empty array */
    
    #endif
    
    struct fixed_phy_port {
    	unsigned int devnum;	/* ethernet port */
    	unsigned int speed;	/* specified speed 10,100 or 1000 */
    	unsigned int duplex;	/* specified duplex FULL or HALF */
    };
    
    static const struct fixed_phy_port fixed_phy_port[] = {
    
    	CONFIG_SYS_FIXED_PHY_PORTS	/* defined in board configuration file */
    
    /*-----------------------------------------------------------------------------+
     * Global variables. TX and RX descriptors and buffers.
     *-----------------------------------------------------------------------------*/
    
    /*
     * Get count of EMAC devices (doesn't have to be the max. possible number
     * supported by the cpu)
    
     *
     * CONFIG_BOARD_EMAC_COUNT added so now a "dynamic" way to configure the
     * EMAC count is possible. As it is needed for the Kilauea/Haleakala
     * 405EX/405EXr eval board, using the same binary.
    
    #if defined(CONFIG_BOARD_EMAC_COUNT)
    #define LAST_EMAC_NUM	board_emac_count()
    #else /* CONFIG_BOARD_EMAC_COUNT */
    
    #if defined(CONFIG_HAS_ETH3)
    #define LAST_EMAC_NUM	4
    #elif defined(CONFIG_HAS_ETH2)
    #define LAST_EMAC_NUM	3
    #elif defined(CONFIG_HAS_ETH1)
    #define LAST_EMAC_NUM	2
    #else
    #define LAST_EMAC_NUM	1
    #endif
    
    #endif /* CONFIG_BOARD_EMAC_COUNT */
    
    /* normal boards start with EMAC0 */
    #if !defined(CONFIG_EMAC_NR_START)
    #define CONFIG_EMAC_NR_START	0
    #endif
    
    
    #define MAL_RX_DESC_SIZE	2048
    #define MAL_TX_DESC_SIZE	2048
    #define MAL_ALLOC_SIZE		(MAL_TX_DESC_SIZE + MAL_RX_DESC_SIZE)
    
    
    /*-----------------------------------------------------------------------------+
     * Prototypes and externals.
     *-----------------------------------------------------------------------------*/
    static void enet_rcv (struct eth_device *dev, unsigned long malisr);
    
    int enetInt (struct eth_device *dev);
    static void mal_err (struct eth_device *dev, unsigned long isr,
    		     unsigned long uic, unsigned long maldef,
    		     unsigned long mal_errr);
    static void emac_err (struct eth_device *dev, unsigned long isr);
    
    
    extern int phy_setup_aneg (char *devname, unsigned char addr);
    
    extern int emac4xx_miiphy_read (const char *devname, unsigned char addr,
    
    		unsigned char reg, unsigned short *value);
    
    extern int emac4xx_miiphy_write (const char *devname, unsigned char addr,
    
    		unsigned char reg, unsigned short value);
    
    static void emac_loopback_enable(EMAC_4XX_HW_PST hw_p)
    {
    #if defined(CONFIG_440SPE) || \
        defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
        defined(CONFIG_405EX)
    	u32 val;
    
    
    	mfsdr(SDR0_MFR, val);
    
    	val |= SDR0_MFR_ETH_CLK_SEL_V(hw_p->devnum);
    
    	mtsdr(SDR0_MFR, val);
    
    #elif defined(CONFIG_460EX) || defined(CONFIG_460GT)
    	u32 val;
    
    	mfsdr(SDR0_ETH_CFG, val);
    	val |= SDR0_ETH_CFG_CLK_SEL_V(hw_p->devnum);
    	mtsdr(SDR0_ETH_CFG, val);
    #endif
    }
    
    static void emac_loopback_disable(EMAC_4XX_HW_PST hw_p)
    {
    #if defined(CONFIG_440SPE) || \
        defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
        defined(CONFIG_405EX)
    	u32 val;
    
    
    	mfsdr(SDR0_MFR, val);
    
    	val &= ~SDR0_MFR_ETH_CLK_SEL_V(hw_p->devnum);
    
    	mtsdr(SDR0_MFR, val);
    
    #elif defined(CONFIG_460EX) || defined(CONFIG_460GT)
    	u32 val;
    
    	mfsdr(SDR0_ETH_CFG, val);
    	val &= ~SDR0_ETH_CFG_CLK_SEL_V(hw_p->devnum);
    	mtsdr(SDR0_ETH_CFG, val);
    #endif
    }
    
    
    /*-----------------------------------------------------------------------------+
    
    | Disable MAL channel, and EMACn
    +-----------------------------------------------------------------------------*/
    
    static void ppc_4xx_eth_halt (struct eth_device *dev)
    
    	EMAC_4XX_HW_PST hw_p = dev->priv;
    
    	u32 val = 10000;
    
    	out_be32((void *)EMAC0_IER + hw_p->hw_addr, 0x00000000);	/* disable emac interrupts */
    
    
    	/* 1st reset MAL channel */
    	/* Note: writing a 0 to a channel has no effect */
    
    #if defined(CONFIG_405EP) || defined(CONFIG_440EP) || defined(CONFIG_440GR)
    
    	mtdcr (MAL0_TXCARR, (MAL_CR_MMSR >> (hw_p->devnum * 2)));
    
    	mtdcr (MAL0_TXCARR, (MAL_CR_MMSR >> hw_p->devnum));
    
    	mtdcr (MAL0_RXCARR, (MAL_CR_MMSR >> hw_p->devnum));
    
    
    	/* wait for reset */
    
    	while (mfdcr (MAL0_RXCASR) & (MAL_CR_MMSR >> hw_p->devnum)) {
    
    		udelay (1000);	/* Delay 1 MS so as not to hammer the register */
    
    		val--;
    		if (val == 0)
    
    	/* provide clocks for EMAC internal loopback  */
    
    	emac_loopback_enable(hw_p);
    
    	out_be32((void *)EMAC0_MR0 + hw_p->hw_addr, EMAC_MR0_SRST);
    
    	/* remove clocks for EMAC internal loopback  */
    
    	emac_loopback_disable(hw_p);
    
    	hw_p->print_speed = 1;	/* print speed message again next time */
    
    #if defined(CONFIG_460EX) || defined(CONFIG_460GT)
    	/* don't bypass the TAHOE0/TAHOE1 cores for Linux */
    
    	mfsdr(SDR0_ETH_CFG, val);
    	val &= ~(SDR0_ETH_CFG_TAHOE0_BYPASS | SDR0_ETH_CFG_TAHOE1_BYPASS);
    	mtsdr(SDR0_ETH_CFG, val);
    
    int ppc_4xx_eth_setup_bridge(int devnum, bd_t * bis)
    
    {
    	unsigned long pfc1;
    	unsigned long zmiifer;
    	unsigned long rmiifer;
    
    
    	mfsdr(SDR0_PFC1, pfc1);
    
    	pfc1 = SDR0_PFC1_EPS_DECODE(pfc1);
    
    	zmiifer = 0;
    	rmiifer = 0;
    
    	switch (pfc1) {
    	case 1:
    		zmiifer |= ZMII_FER_RMII << ZMII_FER_V(0);
    		zmiifer |= ZMII_FER_RMII << ZMII_FER_V(1);
    		zmiifer |= ZMII_FER_RMII << ZMII_FER_V(2);
    		zmiifer |= ZMII_FER_RMII << ZMII_FER_V(3);
    		bis->bi_phymode[0] = BI_PHYMODE_ZMII;
    		bis->bi_phymode[1] = BI_PHYMODE_ZMII;
    		bis->bi_phymode[2] = BI_PHYMODE_ZMII;
    		bis->bi_phymode[3] = BI_PHYMODE_ZMII;
    		break;
    	case 2:
    
    		zmiifer |= ZMII_FER_SMII << ZMII_FER_V(0);
    		zmiifer |= ZMII_FER_SMII << ZMII_FER_V(1);
    		zmiifer |= ZMII_FER_SMII << ZMII_FER_V(2);
    		zmiifer |= ZMII_FER_SMII << ZMII_FER_V(3);
    
    		bis->bi_phymode[0] = BI_PHYMODE_ZMII;
    		bis->bi_phymode[1] = BI_PHYMODE_ZMII;
    		bis->bi_phymode[2] = BI_PHYMODE_ZMII;
    		bis->bi_phymode[3] = BI_PHYMODE_ZMII;
    		break;
    	case 3:
    		zmiifer |= ZMII_FER_RMII << ZMII_FER_V(0);
    		rmiifer |= RGMII_FER_RGMII << RGMII_FER_V(2);
    		bis->bi_phymode[0] = BI_PHYMODE_ZMII;
    		bis->bi_phymode[1] = BI_PHYMODE_NONE;
    		bis->bi_phymode[2] = BI_PHYMODE_RGMII;
    		bis->bi_phymode[3] = BI_PHYMODE_NONE;
    		break;
    	case 4:
    		zmiifer |= ZMII_FER_SMII << ZMII_FER_V(0);
    		zmiifer |= ZMII_FER_SMII << ZMII_FER_V(1);
    		rmiifer |= RGMII_FER_RGMII << RGMII_FER_V (2);
    		rmiifer |= RGMII_FER_RGMII << RGMII_FER_V (3);
    		bis->bi_phymode[0] = BI_PHYMODE_ZMII;
    		bis->bi_phymode[1] = BI_PHYMODE_ZMII;
    		bis->bi_phymode[2] = BI_PHYMODE_RGMII;
    		bis->bi_phymode[3] = BI_PHYMODE_RGMII;
    		break;
    	case 5:
    		zmiifer |= ZMII_FER_SMII << ZMII_FER_V (0);
    		zmiifer |= ZMII_FER_SMII << ZMII_FER_V (1);
    		zmiifer |= ZMII_FER_SMII << ZMII_FER_V (2);
    		rmiifer |= RGMII_FER_RGMII << RGMII_FER_V(3);
    		bis->bi_phymode[0] = BI_PHYMODE_ZMII;
    		bis->bi_phymode[1] = BI_PHYMODE_ZMII;
    		bis->bi_phymode[2] = BI_PHYMODE_ZMII;
    		bis->bi_phymode[3] = BI_PHYMODE_RGMII;
    		break;
    	case 6:
    		zmiifer |= ZMII_FER_SMII << ZMII_FER_V (0);
    		zmiifer |= ZMII_FER_SMII << ZMII_FER_V (1);
    		rmiifer |= RGMII_FER_RGMII << RGMII_FER_V(2);
    		bis->bi_phymode[0] = BI_PHYMODE_ZMII;
    		bis->bi_phymode[1] = BI_PHYMODE_ZMII;
    		bis->bi_phymode[2] = BI_PHYMODE_RGMII;
    		break;
    	case 0:
    	default:
    		zmiifer = ZMII_FER_MII << ZMII_FER_V(devnum);
    		rmiifer = 0x0;
    		bis->bi_phymode[0] = BI_PHYMODE_ZMII;
    		bis->bi_phymode[1] = BI_PHYMODE_ZMII;
    		bis->bi_phymode[2] = BI_PHYMODE_ZMII;
    		bis->bi_phymode[3] = BI_PHYMODE_ZMII;
    		break;
    	}
    
    	/* Ensure we setup mdio for this devnum and ONLY this devnum */
    	zmiifer |= (ZMII_FER_MDI) << ZMII_FER_V(devnum);
    
    
    	out_be32((void *)ZMII0_FER, zmiifer);
    
    	out_be32((void *)RGMII_FER, rmiifer);
    
    #if defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
    int ppc_4xx_eth_setup_bridge(int devnum, bd_t * bis)
    {
    	unsigned long zmiifer=0x0;
    
    	mfsdr(SDR0_PFC1, pfc1);
    
    	switch (pfc1) {
    
    		/* 1 x GMII port */
    
    		out_be32((void *)ZMII0_FER, 0x00);
    
    		out_be32((void *)RGMII_FER, 0x00000037);
    
    		bis->bi_phymode[0] = BI_PHYMODE_GMII;
    		bis->bi_phymode[1] = BI_PHYMODE_NONE;
    		break;
    
    		/* 2 x RGMII ports */
    
    		out_be32((void *)ZMII0_FER, 0x00);
    
    		out_be32((void *)RGMII_FER, 0x00000055);
    
    		bis->bi_phymode[0] = BI_PHYMODE_RGMII;
    		bis->bi_phymode[1] = BI_PHYMODE_RGMII;
    		break;
    
    		/* 2 x SMII ports */
    
    		out_be32((void *)ZMII0_FER,
    
    			 ((ZMII_FER_SMII) << ZMII_FER_V(0)) |
    			 ((ZMII_FER_SMII) << ZMII_FER_V(1)));
    		out_be32((void *)RGMII_FER, 0x00000000);
    
    		bis->bi_phymode[0] = BI_PHYMODE_SMII;
    		bis->bi_phymode[1] = BI_PHYMODE_SMII;
    		break;
    	case SDR0_PFC1_SELECT_CONFIG_1_2:
    		/* only 1 x MII supported */
    
    		out_be32((void *)ZMII0_FER, (ZMII_FER_MII) << ZMII_FER_V(0));
    
    		out_be32((void *)RGMII_FER, 0x00000000);
    
    		bis->bi_phymode[0] = BI_PHYMODE_MII;
    		bis->bi_phymode[1] = BI_PHYMODE_NONE;
    
    		break;
    	default:
    		break;
    	}
    
    	/* Ensure we setup mdio for this devnum and ONLY this devnum */
    
    	zmiifer = in_be32((void *)ZMII0_FER);
    
    	zmiifer |= (ZMII_FER_MDI) << ZMII_FER_V(devnum);
    
    	out_be32((void *)ZMII0_FER, zmiifer);
    
    
    	return ((int)0x0);
    }
    #endif	/* CONFIG_440EPX */
    
    
    #if defined(CONFIG_405EX)
    int ppc_4xx_eth_setup_bridge(int devnum, bd_t * bis)
    {
    
    	 * The 405EX(r)'s RGMII bridge can operate in one of several
    	 * modes, only one of which (2 x RGMII) allows the
    	 * simultaneous use of both EMACs on the 405EX.
    
    
    	switch (CONFIG_EMAC_PHY_MODE) {
    
    	case EMAC_PHY_MODE_NONE:
    		/* No ports */
    		rgmiifer |= RGMII_FER_DIS	<< 0;
    		rgmiifer |= RGMII_FER_DIS	<< 4;
    		out_be32((void *)RGMII_FER, rgmiifer);
    		bis->bi_phymode[0] = BI_PHYMODE_NONE;
    		bis->bi_phymode[1] = BI_PHYMODE_NONE;
    		break;
    	case EMAC_PHY_MODE_NONE_RGMII:
    		/* 1 x RGMII port on channel 0 */
    		rgmiifer |= RGMII_FER_RGMII	<< 0;
    		rgmiifer |= RGMII_FER_DIS	<< 4;
    		out_be32((void *)RGMII_FER, rgmiifer);
    		bis->bi_phymode[0] = BI_PHYMODE_RGMII;
    		bis->bi_phymode[1] = BI_PHYMODE_NONE;
    		break;
    	case EMAC_PHY_MODE_RGMII_NONE:
    		/* 1 x RGMII port on channel 1 */
    		rgmiifer |= RGMII_FER_DIS	<< 0;
    		rgmiifer |= RGMII_FER_RGMII	<< 4;
    		out_be32((void *)RGMII_FER, rgmiifer);
    		bis->bi_phymode[0] = BI_PHYMODE_NONE;
    		bis->bi_phymode[1] = BI_PHYMODE_RGMII;
    		break;
    	case EMAC_PHY_MODE_RGMII_RGMII:
    
    		/* 2 x RGMII ports */
    
    		rgmiifer |= RGMII_FER_RGMII	<< 0;
    		rgmiifer |= RGMII_FER_RGMII	<< 4;
    		out_be32((void *)RGMII_FER, rgmiifer);
    
    		bis->bi_phymode[0] = BI_PHYMODE_RGMII;
    		bis->bi_phymode[1] = BI_PHYMODE_RGMII;
    		break;
    
    	case EMAC_PHY_MODE_NONE_GMII:
    		/* 1 x GMII port on channel 0 */
    		rgmiifer |= RGMII_FER_GMII	<< 0;
    		rgmiifer |= RGMII_FER_DIS	<< 4;
    		out_be32((void *)RGMII_FER, rgmiifer);
    		bis->bi_phymode[0] = BI_PHYMODE_GMII;
    		bis->bi_phymode[1] = BI_PHYMODE_NONE;
    		break;
    	case EMAC_PHY_MODE_NONE_MII:
    		/* 1 x MII port on channel 0 */
    		rgmiifer |= RGMII_FER_MII	<< 0;
    		rgmiifer |= RGMII_FER_DIS	<< 4;
    		out_be32((void *)RGMII_FER, rgmiifer);
    		bis->bi_phymode[0] = BI_PHYMODE_MII;
    		bis->bi_phymode[1] = BI_PHYMODE_NONE;
    		break;
    	case EMAC_PHY_MODE_GMII_NONE:
    		/* 1 x GMII port on channel 1 */
    		rgmiifer |= RGMII_FER_DIS	<< 0;
    		rgmiifer |= RGMII_FER_GMII	<< 4;
    		out_be32((void *)RGMII_FER, rgmiifer);
    		bis->bi_phymode[0] = BI_PHYMODE_NONE;
    		bis->bi_phymode[1] = BI_PHYMODE_GMII;
    		break;
    	case EMAC_PHY_MODE_MII_NONE:
    		/* 1 x MII port on channel 1 */
    		rgmiifer |= RGMII_FER_DIS	<< 0;
    		rgmiifer |= RGMII_FER_MII	<< 4;
    		out_be32((void *)RGMII_FER, rgmiifer);
    		bis->bi_phymode[0] = BI_PHYMODE_NONE;
    		bis->bi_phymode[1] = BI_PHYMODE_MII;
    
    		break;
    	default:
    		break;
    	}
    
    	/* Ensure we setup mdio for this devnum and ONLY this devnum */
    
    	rgmiifer = in_be32((void *)RGMII_FER);
    	rgmiifer |= (1 << (19-devnum));
    	out_be32((void *)RGMII_FER, rgmiifer);
    
    
    	return ((int)0x0);
    }
    #endif  /* CONFIG_405EX */
    
    
    #if defined(CONFIG_460EX) || defined(CONFIG_460GT)
    int ppc_4xx_eth_setup_bridge(int devnum, bd_t * bis)
    {
    	u32 eth_cfg;
    	u32 zmiifer;		/* ZMII0_FER reg. */
    	u32 rmiifer;		/* RGMII0_FER reg. Bridge 0 */
    	u32 rmiifer1;		/* RGMII0_FER reg. Bridge 1 */
    
    
    	zmiifer  = 0;
    	rmiifer  = 0;
    	rmiifer1 = 0;
    
    
    #if defined(CONFIG_460EX)
    	mode = 9;
    
    	mfsdr(SDR0_ETH_CFG, eth_cfg);
    	if (((eth_cfg & SDR0_ETH_CFG_SGMII0_ENABLE) > 0) &&
    	    ((eth_cfg & SDR0_ETH_CFG_SGMII1_ENABLE) > 0))
    		mode = 11; /* config SGMII */
    
    	mfsdr(SDR0_ETH_CFG, eth_cfg);
    	if (((eth_cfg & SDR0_ETH_CFG_SGMII0_ENABLE) > 0) &&
    	    ((eth_cfg & SDR0_ETH_CFG_SGMII1_ENABLE) > 0) &&
    	    ((eth_cfg & SDR0_ETH_CFG_SGMII2_ENABLE) > 0))
    		mode = 12; /* config SGMII */
    
    	/* TODO:
    	 * NOTE: 460GT has 2 RGMII bridge cores:
    	 *		emac0 ------ RGMII0_BASE
    	 *		           |
    	 *		emac1 -----+
    	 *
    	 *		emac2 ------ RGMII1_BASE
    	 *		           |
    	 *		emac3 -----+
    	 *
    	 *	460EX has 1 RGMII bridge core:
    	 *	and RGMII1_BASE is disabled
    	 *		emac0 ------ RGMII0_BASE
    	 *		           |
    	 *		emac1 -----+
    	 */
    
    	/*
    	 * Right now only 2*RGMII is supported. Please extend when needed.
    	 * sr - 2008-02-19
    
    	 * Add SGMII support.
    	 * vg - 2008-07-28
    
    	case 1:
    		/* 1 MII - 460EX */
    		/* GMC0 EMAC4_0, ZMII Bridge */
    		zmiifer |= ZMII_FER_MII << ZMII_FER_V(0);
    		bis->bi_phymode[0] = BI_PHYMODE_MII;
    		bis->bi_phymode[1] = BI_PHYMODE_NONE;
    		bis->bi_phymode[2] = BI_PHYMODE_NONE;
    		bis->bi_phymode[3] = BI_PHYMODE_NONE;
    		break;
    	case 2:
    		/* 2 MII - 460GT */
    		/* GMC0 EMAC4_0, GMC1 EMAC4_2, ZMII Bridge */
    		zmiifer |= ZMII_FER_MII << ZMII_FER_V(0);
    		zmiifer |= ZMII_FER_MII << ZMII_FER_V(2);
    		bis->bi_phymode[0] = BI_PHYMODE_MII;
    		bis->bi_phymode[1] = BI_PHYMODE_NONE;
    		bis->bi_phymode[2] = BI_PHYMODE_MII;
    		bis->bi_phymode[3] = BI_PHYMODE_NONE;
    		break;
    	case 3:
    		/* 2 RMII - 460EX */
    		/* GMC0 EMAC4_0, GMC0 EMAC4_1, ZMII Bridge */
    		zmiifer |= ZMII_FER_RMII << ZMII_FER_V(0);
    		zmiifer |= ZMII_FER_RMII << ZMII_FER_V(1);
    		bis->bi_phymode[0] = BI_PHYMODE_RMII;
    		bis->bi_phymode[1] = BI_PHYMODE_RMII;
    		bis->bi_phymode[2] = BI_PHYMODE_NONE;
    		bis->bi_phymode[3] = BI_PHYMODE_NONE;
    		break;
    	case 4:
    		/* 4 RMII - 460GT */
    		/* GMC0 EMAC4_0, GMC0 EMAC4_1, GMC1 EMAC4_2, GMC1, EMAC4_3 */
    		/* ZMII Bridge */
    		zmiifer |= ZMII_FER_RMII << ZMII_FER_V(0);
    		zmiifer |= ZMII_FER_RMII << ZMII_FER_V(1);
    		zmiifer |= ZMII_FER_RMII << ZMII_FER_V(2);
    		zmiifer |= ZMII_FER_RMII << ZMII_FER_V(3);
    		bis->bi_phymode[0] = BI_PHYMODE_RMII;
    		bis->bi_phymode[1] = BI_PHYMODE_RMII;
    		bis->bi_phymode[2] = BI_PHYMODE_RMII;
    		bis->bi_phymode[3] = BI_PHYMODE_RMII;
    		break;
    	case 5:
    		/* 2 SMII - 460EX */
    		/* GMC0 EMAC4_0, GMC0 EMAC4_1, ZMII Bridge */
    		zmiifer |= ZMII_FER_SMII << ZMII_FER_V(0);
    		zmiifer |= ZMII_FER_SMII << ZMII_FER_V(1);
    		bis->bi_phymode[0] = BI_PHYMODE_SMII;
    		bis->bi_phymode[1] = BI_PHYMODE_SMII;
    		bis->bi_phymode[2] = BI_PHYMODE_NONE;
    		bis->bi_phymode[3] = BI_PHYMODE_NONE;
    		break;
    	case 6:
    		/* 4 SMII - 460GT */
    		/* GMC0 EMAC4_0, GMC0 EMAC4_1, GMC0 EMAC4_3, GMC0 EMAC4_3 */
    		/* ZMII Bridge */
    		zmiifer |= ZMII_FER_SMII << ZMII_FER_V(0);
    		zmiifer |= ZMII_FER_SMII << ZMII_FER_V(1);
    		zmiifer |= ZMII_FER_SMII << ZMII_FER_V(2);
    		zmiifer |= ZMII_FER_SMII << ZMII_FER_V(3);
    		bis->bi_phymode[0] = BI_PHYMODE_SMII;
    		bis->bi_phymode[1] = BI_PHYMODE_SMII;
    		bis->bi_phymode[2] = BI_PHYMODE_SMII;
    		bis->bi_phymode[3] = BI_PHYMODE_SMII;
    		break;
    	case 7:
    		/* This is the default mode that we want for board bringup - Maple */
    		/* 1 GMII - 460EX */
    		/* GMC0 EMAC4_0, RGMII Bridge 0 */
    		rmiifer |= RGMII_FER_MDIO(0);
    
    		if (devnum == 0) {
    			rmiifer |= RGMII_FER_GMII << RGMII_FER_V(2); /* CH0CFG - EMAC0 */
    			bis->bi_phymode[0] = BI_PHYMODE_GMII;
    			bis->bi_phymode[1] = BI_PHYMODE_NONE;
    			bis->bi_phymode[2] = BI_PHYMODE_NONE;
    			bis->bi_phymode[3] = BI_PHYMODE_NONE;
    		} else {
    			rmiifer |= RGMII_FER_GMII << RGMII_FER_V(3); /* CH1CFG - EMAC1 */
    			bis->bi_phymode[0] = BI_PHYMODE_NONE;
    			bis->bi_phymode[1] = BI_PHYMODE_GMII;
    			bis->bi_phymode[2] = BI_PHYMODE_NONE;
    			bis->bi_phymode[3] = BI_PHYMODE_NONE;
    		}
    		break;
    	case 8:
    		/* 2 GMII - 460GT */
    		/* GMC0 EMAC4_0, RGMII Bridge 0 */
    		/* GMC1 EMAC4_2, RGMII Bridge 1 */
    		rmiifer |= RGMII_FER_GMII << RGMII_FER_V(2);	/* CH0CFG - EMAC0 */
    		rmiifer1 |= RGMII_FER_GMII << RGMII_FER_V(2);	/* CH0CFG - EMAC2 */
    		rmiifer |= RGMII_FER_MDIO(0);			/* enable MDIO - EMAC0 */
    		rmiifer1 |= RGMII_FER_MDIO(0);			/* enable MDIO - EMAC2 */
    
    		bis->bi_phymode[0] = BI_PHYMODE_GMII;
    		bis->bi_phymode[1] = BI_PHYMODE_NONE;
    		bis->bi_phymode[2] = BI_PHYMODE_GMII;
    		bis->bi_phymode[3] = BI_PHYMODE_NONE;
    		break;
    	case 9:
    		/* 2 RGMII - 460EX */
    		/* GMC0 EMAC4_0, GMC0 EMAC4_1, RGMII Bridge 0 */
    		rmiifer |= RGMII_FER_RGMII << RGMII_FER_V(2);
    		rmiifer |= RGMII_FER_RGMII << RGMII_FER_V(3);
    		rmiifer |= RGMII_FER_MDIO(0);			/* enable MDIO - EMAC0 */
    
    		bis->bi_phymode[0] = BI_PHYMODE_RGMII;
    		bis->bi_phymode[1] = BI_PHYMODE_RGMII;
    		bis->bi_phymode[2] = BI_PHYMODE_NONE;
    		bis->bi_phymode[3] = BI_PHYMODE_NONE;
    		break;
    	case 10:
    		/* 4 RGMII - 460GT */
    		/* GMC0 EMAC4_0, GMC0 EMAC4_1, RGMII Bridge 0 */
    		/* GMC1 EMAC4_2, GMC1 EMAC4_3, RGMII Bridge 1 */
    		rmiifer |= RGMII_FER_RGMII << RGMII_FER_V(2);
    		rmiifer |= RGMII_FER_RGMII << RGMII_FER_V(3);
    		rmiifer1 |= RGMII_FER_RGMII << RGMII_FER_V(2);
    		rmiifer1 |= RGMII_FER_RGMII << RGMII_FER_V(3);
    		bis->bi_phymode[0] = BI_PHYMODE_RGMII;
    		bis->bi_phymode[1] = BI_PHYMODE_RGMII;
    		bis->bi_phymode[2] = BI_PHYMODE_RGMII;
    		bis->bi_phymode[3] = BI_PHYMODE_RGMII;
    		break;
    
    	case 11:
    		/* 2 SGMII - 460EX */
    		bis->bi_phymode[0] = BI_PHYMODE_SGMII;
    		bis->bi_phymode[1] = BI_PHYMODE_SGMII;
    		bis->bi_phymode[2] = BI_PHYMODE_NONE;
    		bis->bi_phymode[3] = BI_PHYMODE_NONE;
    		break;
    	case 12:
    		/* 3 SGMII - 460GT */
    		bis->bi_phymode[0] = BI_PHYMODE_SGMII;
    		bis->bi_phymode[1] = BI_PHYMODE_SGMII;
    		bis->bi_phymode[2] = BI_PHYMODE_SGMII;
    		bis->bi_phymode[3] = BI_PHYMODE_NONE;
    		break;
    
    	default:
    		break;
    	}
    
    	/* Set EMAC for MDIO */
    	mfsdr(SDR0_ETH_CFG, eth_cfg);
    	eth_cfg |= SDR0_ETH_CFG_MDIO_SEL_EMAC0;
    	mtsdr(SDR0_ETH_CFG, eth_cfg);
    
    	out_be32((void *)RGMII_FER, rmiifer);
    #if defined(CONFIG_460GT)
    	out_be32((void *)RGMII_FER + RGMII1_BASE_OFFSET, rmiifer1);
    #endif
    
    	/* bypass the TAHOE0/TAHOE1 cores for U-Boot */
    	mfsdr(SDR0_ETH_CFG, eth_cfg);
    	eth_cfg |= (SDR0_ETH_CFG_TAHOE0_BYPASS | SDR0_ETH_CFG_TAHOE1_BYPASS);
    	mtsdr(SDR0_ETH_CFG, eth_cfg);
    
    	return 0;
    }
    #endif /* CONFIG_460EX || CONFIG_460GT */
    
    
    static inline void *malloc_aligned(u32 size, u32 align)
    {
    	return (void *)(((u32)malloc(size + align) + align - 1) &
    			~(align - 1));
    }
    
    
    static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis)
    
    	unsigned long msr;
    	unsigned long speed;
    	unsigned long duplex;
    	unsigned long failsafe;
    	unsigned mode_reg;
    	unsigned short devnum;
    	unsigned short reg_short;
    
    #if defined(CONFIG_440GX) || \
        defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
    
        defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \
    
        defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
    
        defined(CONFIG_405EX)
    
    	u32 opbfreq;
    
    #if defined(CONFIG_440GX) || \
    
        defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
    
        defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
    
        defined(CONFIG_405EX)
    
    	u32 bd_cached;
    	u32 bd_uncached = 0;
    
    #ifdef CONFIG_4xx_DCACHE
    	static u32 last_used_ea = 0;
    #endif
    
    #if defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
        defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
        defined(CONFIG_405EX)
    	int rgmii_channel;
    #endif
    
    	EMAC_4XX_HW_PST hw_p = dev->priv;
    
    
    	/* before doing anything, figure out if we have a MAC address */
    	/* if not, bail */
    
    	if (memcmp (dev->enetaddr, "\0\0\0\0\0\0", 6) == 0) {
    		printf("ERROR: ethaddr not set!\n");
    
    		return -1;
    
    #if defined(CONFIG_440GX) || \
        defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
    
        defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \
    
        defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
    
        defined(CONFIG_405EX)
    
    	/* Need to get the OPB frequency so we can access the PHY */
    	get_sys_info (&sysinfo);
    
    
    	msr = mfmsr ();
    	mtmsr (msr & ~(MSR_EE));	/* disable interrupts */
    
    	devnum = hw_p->devnum;
    
    
    	/* AS.HARNOIS
    	 * We should have :
    
    	 * hw_p->stats.pkts_handled <=	hw_p->stats.pkts_rx <= hw_p->stats.pkts_handled+PKTBUFSRX
    
    	 * In the most cases hw_p->stats.pkts_handled = hw_p->stats.pkts_rx, but it
    	 * is possible that new packets (without relationship with
    	 * current transfer) have got the time to arrived before
    	 * netloop calls eth_halt
    	 */
    	printf ("About preceeding transfer (eth%d):\n"
    		"- Sent packet number %d\n"
    		"- Received packet number %d\n"
    		"- Handled packet number %d\n",
    		hw_p->devnum,
    		hw_p->stats.pkts_tx,
    		hw_p->stats.pkts_rx, hw_p->stats.pkts_handled);
    
    	hw_p->stats.pkts_tx = 0;
    	hw_p->stats.pkts_rx = 0;
    	hw_p->stats.pkts_handled = 0;
    
    	hw_p->print_speed = 1;	/* print speed message again next time */
    
    	hw_p->tx_err_index = 0; /* Transmit Error Index for tx_err_log */
    	hw_p->rx_err_index = 0; /* Receive Error Index for rx_err_log */
    
    
    	hw_p->rx_slot = 0;	/* MAL Receive Slot */
    	hw_p->rx_i_index = 0;	/* Receive Interrupt Queue Index */
    	hw_p->rx_u_index = 0;	/* Receive User Queue Index */
    
    	hw_p->tx_slot = 0;	/* MAL Transmit Slot */
    	hw_p->tx_i_index = 0;	/* Transmit Interrupt Queue Index */
    	hw_p->tx_u_index = 0;	/* Transmit User Queue Index */
    
    
    #if defined(CONFIG_440) && !defined(CONFIG_440SP) && !defined(CONFIG_440SPE)
    
    	/* set RMII mode */
    	/* NOTE: 440GX spec states that mode is mutually exclusive */
    	/* NOTE: Therefore, disable all other EMACS, since we handle */
    	/* NOTE: only one emac at a time */
    	reg = 0;
    
    	out_be32((void *)ZMII0_FER, 0);
    
    #if defined(CONFIG_440GP) || defined(CONFIG_440EP) || defined(CONFIG_440GR)
    
    	out_be32((void *)ZMII0_FER, (ZMII_FER_RMII | ZMII_FER_MDI) << ZMII_FER_V (devnum));
    
    #elif defined(CONFIG_440GX) || \
        defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
        defined(CONFIG_460EX) || defined(CONFIG_460GT)
    
    	ethgroup = ppc_4xx_eth_setup_bridge(devnum, bis);
    
    	out_be32((void *)ZMII0_SSR, ZMII0_SSR_SP << ZMII0_SSR_V(devnum));
    
    #endif /* defined(CONFIG_440) && !defined(CONFIG_440SP) */
    
    #if defined(CONFIG_405EX)
    	ethgroup = ppc_4xx_eth_setup_bridge(devnum, bis);
    #endif
    
    	/* provide clocks for EMAC internal loopback  */
    
    	emac_loopback_enable(hw_p);
    
    	out_be32((void *)EMAC0_MR0 + hw_p->hw_addr, EMAC_MR0_SRST);
    
    	/* remove clocks for EMAC internal loopback  */
    	emac_loopback_disable(hw_p);
    
    
    	failsafe = 1000;
    
    	while ((in_be32((void *)EMAC0_MR0 + hw_p->hw_addr) & (EMAC_MR0_SRST)) && failsafe) {
    
    		udelay (1000);
    		failsafe--;
    	}
    
    	if (failsafe <= 0)
    		printf("\nProblem resetting EMAC!\n");
    
    #if defined(CONFIG_440GX) || \
        defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
    
        defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \
    
        defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
    
        defined(CONFIG_405EX)
    
    	/* Whack the M1 register */
    	mode_reg = 0x0;
    	mode_reg &= ~0x00000038;
    
    	opbfreq = sysinfo.freqOPB / 1000000;
    	if (opbfreq <= 50);
    	else if (opbfreq <= 66)
    
    		mode_reg |= EMAC_MR1_OBCI_66;
    
    	else if (opbfreq <= 83)