Merge branch 'mpc86xx'
[platform/kernel/u-boot.git] / cpu / ppc4xx / 4xx_enet.c
index 79be865..fab65af 100644 (file)
@@ -1,80 +1,80 @@
 /*-----------------------------------------------------------------------------+
  *
- *       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.
+ *      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 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.
+ *      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
+ *      COPYRIGHT   I B M   CORPORATION 1995
+ *      LICENSED MATERIAL  -  PROGRAM PROPERTY OF I B M
  *-----------------------------------------------------------------------------*/
 /*-----------------------------------------------------------------------------+
  *
- *  File Name:  enetemac.c
+ *  File Name: enetemac.c
  *
- *  Function:   Device driver for the ethernet EMAC3 macro on the 405GP.
+ *  Function:  Device driver for the ethernet EMAC3 macro on the 405GP.
  *
- *  Author:     Mark Wisner
+ *  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
- *             EMAC_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 EMAC_M1 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).
+ *  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
+ *             EMAC_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 EMAC_M1 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.
+ *  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>
@@ -90,7 +90,7 @@
 #include "vecnum.h"
 
 /*
- * Only compile for platform with IBM/AMCC EMAC ethernet controller and
+ * Only compile for platform with AMCC EMAC ethernet controller and
  * network support enabled.
  * Remark: CONFIG_405 describes Xilinx PPC405 FPGA without EMAC controller!
  */
 #error "CONFIG_MII has to be defined!"
 #endif
 
-#define EMAC_RESET_TIMEOUT 1000        /* 1000 ms reset timeout */
+#if defined(CONFIG_NETCONSOLE) && !defined(CONFIG_NET_MULTI)
+#error "CONFIG_NET_MULTI has to be defined for NetConsole"
+#endif
+
+#define EMAC_RESET_TIMEOUT 1000 /* 1000 ms reset timeout */
 #define PHY_AUTONEGOTIATE_TIMEOUT 4000 /* 4000 ms autonegotiate timeout */
 
 /* Ethernet Transmit and Receive Buffers */
  * 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          PKTSIZE
 #define ENET_MAX_MTU_ALIGNED   PKTSIZE_ALIGN
 
-/* define the number of channels implemented */
-#define EMAC_RXCHL      EMAC_NUM_DEV
-#define EMAC_TXCHL      EMAC_NUM_DEV
-
 /*-----------------------------------------------------------------------------+
  * Defines for MAL/EMAC interrupt conditions as reported in the UIC (Universal
  * Interrupt Controller).
 
 #undef INFO_4XX_ENET
 
-#define BI_PHYMODE_NONE  0
-#define BI_PHYMODE_ZMII  1
+#define BI_PHYMODE_NONE         0
+#define BI_PHYMODE_ZMII         1
 #define BI_PHYMODE_RGMII 2
 
 
 static uint32_t mal_ier;
 
 #if !defined(CONFIG_NET_MULTI)
-struct eth_device *emac0_dev;
+struct eth_device *emac0_dev = NULL;
 #endif
 
+/*
+ * Get count of EMAC devices (doesn't have to be the max. possible number
+ * supported by the cpu)
+ */
+#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
 
 /*-----------------------------------------------------------------------------+
  * Prototypes and externals.
@@ -154,6 +167,11 @@ static void mal_err (struct eth_device *dev, unsigned long isr,
                     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 (char *devname, unsigned char addr,
+               unsigned char reg, unsigned short *value);
+extern int emac4xx_miiphy_write (char *devname, unsigned char addr,
+               unsigned char reg, unsigned short value);
 
 /*-----------------------------------------------------------------------------+
 | ppc_4xx_eth_halt
@@ -163,6 +181,9 @@ static void ppc_4xx_eth_halt (struct eth_device *dev)
 {
        EMAC_4XX_HW_PST hw_p = dev->priv;
        uint32_t failsafe = 10000;
+#if defined(CONFIG_440SPE)
+       unsigned long mfr;
+#endif
 
        out32 (EMAC_IER + hw_p->hw_addr, 0x00000000);   /* disable emac interrupts */
 
@@ -184,16 +205,30 @@ static void ppc_4xx_eth_halt (struct eth_device *dev)
        }
 
        /* EMAC RESET */
+#if defined(CONFIG_440SPE)
+       /* provide clocks for EMAC internal loopback  */
+       mfsdr (sdr_mfr, mfr);
+       mfr |= 0x08000000;
+       mtsdr(sdr_mfr, mfr);
+#endif
+
        out32 (EMAC_M0 + hw_p->hw_addr, EMAC_M0_SRST);
 
+#if defined(CONFIG_440SPE)
+       /* remove clocks for EMAC internal loopback  */
+       mfsdr (sdr_mfr, mfr);
+       mfr &= ~0x08000000;
+       mtsdr(sdr_mfr, mfr);
+#endif
+
+
+#ifndef CONFIG_NETCONSOLE
        hw_p->print_speed = 1;  /* print speed message again next time */
+#endif
 
        return;
 }
 
-extern int phy_setup_aneg (unsigned char addr);
-extern int miiphy_reset (unsigned char addr);
-
 #if defined (CONFIG_440GX)
 int ppc_4xx_eth_setup_bridge(int devnum, bd_t * bis)
 {
@@ -284,7 +319,7 @@ int ppc_4xx_eth_setup_bridge(int devnum, bd_t * bis)
        return ((int)pfc1);
 
 }
-#endif
+#endif /* CONFIG_440_GX */
 
 static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis)
 {
@@ -297,19 +332,27 @@ static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis)
        unsigned mode_reg;
        unsigned short devnum;
        unsigned short reg_short;
-#if defined(CONFIG_440GX)
+#if defined(CONFIG_440GX) || defined(CONFIG_440SP) || defined(CONFIG_440SPE)
        sys_info_t sysinfo;
-       int ethgroup;
+#if defined(CONFIG_440GX) || defined(CONFIG_440SPE)
+       int ethgroup = -1;
+#endif
+#endif
+#if defined(CONFIG_440SPE)
+       unsigned long mfr;
 #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)
+       if (memcmp (dev->enetaddr, "\0\0\0\0\0\0", 6) == 0) {
+               printf("ERROR: ethaddr not set!\n");
                return -1;
+       }
 
-#if defined(CONFIG_440GX)
+#if defined(CONFIG_440GX) || defined(CONFIG_440SP) || defined(CONFIG_440SPE)
        /* Need to get the OPB frequency so we can access the PHY */
        get_sys_info (&sysinfo);
 #endif
@@ -322,7 +365,7 @@ static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis)
 #ifdef INFO_4XX_ENET
        /* AS.HARNOIS
         * We should have :
-        * hw_p->stats.pkts_handled <=  hw_p->stats.pkts_rx <= hw_p->stats.pkts_handled+PKTBUFSRX
+        * 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
@@ -339,10 +382,11 @@ static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis)
        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 */
 #endif
 
-       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->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 */
@@ -352,7 +396,7 @@ static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis)
        hw_p->tx_i_index = 0;   /* Transmit Interrupt Queue Index */
        hw_p->tx_u_index = 0;   /* Transmit User Queue Index */
 
-#if defined(CONFIG_440)
+#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 */
@@ -362,7 +406,7 @@ static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis)
        udelay (100);
 
 #if defined(CONFIG_440EP) || defined(CONFIG_440GR)
-       out32 (ZMII_FER, (ZMII_FER_RMII | ZMII_FER_MDI) << ZMII_FER_V (devnum));
+       out32 (ZMII_FER, (ZMII_FER_RMII | ZMII_FER_MDI) << ZMII_FER_V (devnum));
 #elif defined(CONFIG_440GX)
        ethgroup = ppc_4xx_eth_setup_bridge(devnum, bis);
 #elif defined(CONFIG_440GP)
@@ -380,11 +424,17 @@ static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis)
 #endif
 
        out32 (ZMII_SSR, ZMII_SSR_SP << ZMII_SSR_V(devnum));
-#endif /* defined(CONFIG_440) */
+#endif /* defined(CONFIG_440) && !defined(CONFIG_440SP) */
 
        __asm__ volatile ("eieio");
 
        /* reset emac so we have access to the phy */
+#if defined(CONFIG_440SPE)
+       /* provide clocks for EMAC internal loopback  */
+       mfsdr (sdr_mfr, mfr);
+       mfr |= 0x08000000;
+       mtsdr(sdr_mfr, mfr);
+#endif
 
        out32 (EMAC_M0 + hw_p->hw_addr, EMAC_M0_SRST);
        __asm__ volatile ("eieio");
@@ -395,7 +445,14 @@ static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis)
                failsafe--;
        }
 
-#if defined(CONFIG_440GX)
+#if defined(CONFIG_440SPE)
+       /* remove clocks for EMAC internal loopback  */
+       mfsdr (sdr_mfr, mfr);
+       mfr &= ~0x08000000;
+       mtsdr(sdr_mfr, mfr);
+#endif
+
+#if defined(CONFIG_440GX) || defined(CONFIG_440SP) || defined(CONFIG_440SPE)
        /* Whack the M1 register */
        mode_reg = 0x0;
        mode_reg &= ~0x00000038;
@@ -410,7 +467,7 @@ static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis)
                mode_reg |= EMAC_M1_OBCI_GT100;
 
        out32 (EMAC_M1 + hw_p->hw_addr, mode_reg);
-#endif /*  defined(CONFIG_440GX) */
+#endif /* defined(CONFIG_440GX) || defined(CONFIG_440SP) */
 
        /* wait for PHY to complete auto negotiation */
        reg_short = 0;
@@ -445,9 +502,9 @@ static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis)
         * otherwise, just check the speeds & feeds
         */
        if (hw_p->first_init == 0) {
-               miiphy_reset (reg);
+               miiphy_reset (dev->name, reg);
 
-#if defined(CONFIG_440GX)
+#if defined(CONFIG_440GX) || defined(CONFIG_440SP) || defined(CONFIG_440SPE)
 #if defined(CONFIG_CIS8201_PHY)
                /*
                 * Cicada 8201 PHY needs to have an extended register whacked
@@ -455,9 +512,9 @@ static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis)
                 */
                if ( ((devnum == 2) || (devnum ==3)) && (4 == ethgroup) ) {
 #if defined(CONFIG_CIS8201_SHORT_ETCH)
-                       miiphy_write (reg, 23, 0x1300);
+                       miiphy_write (dev->name, reg, 23, 0x1300);
 #else
-                       miiphy_write (reg, 23, 0x1000);
+                       miiphy_write (dev->name, reg, 23, 0x1000);
 #endif
                        /*
                         * Vitesse VSC8201/Cicada CIS8201 errata:
@@ -465,26 +522,26 @@ static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis)
                         * This work around (provided by Vitesse) changes
                         * the default timer convergence from 8ms to 12ms
                         */
-                       miiphy_write (reg, 0x1f, 0x2a30);
-                       miiphy_write (reg, 0x08, 0x0200);
-                       miiphy_write (reg, 0x1f, 0x52b5);
-                       miiphy_write (reg, 0x02, 0x0004);
-                       miiphy_write (reg, 0x01, 0x0671);
-                       miiphy_write (reg, 0x00, 0x8fae);
-                       miiphy_write (reg, 0x1f, 0x2a30);
-                       miiphy_write (reg, 0x08, 0x0000);
-                       miiphy_write (reg, 0x1f, 0x0000);
+                       miiphy_write (dev->name, reg, 0x1f, 0x2a30);
+                       miiphy_write (dev->name, reg, 0x08, 0x0200);
+                       miiphy_write (dev->name, reg, 0x1f, 0x52b5);
+                       miiphy_write (dev->name, reg, 0x02, 0x0004);
+                       miiphy_write (dev->name, reg, 0x01, 0x0671);
+                       miiphy_write (dev->name, reg, 0x00, 0x8fae);
+                       miiphy_write (dev->name, reg, 0x1f, 0x2a30);
+                       miiphy_write (dev->name, reg, 0x08, 0x0000);
+                       miiphy_write (dev->name, reg, 0x1f, 0x0000);
                        /* end Vitesse/Cicada errata */
                }
 #endif
 #endif
                /* Start/Restart autonegotiation */
-               phy_setup_aneg (reg);
+               phy_setup_aneg (dev->name, reg);
                udelay (1000);
        }
 #endif /* defined(CONFIG_PHY_RESET) */
 
-       miiphy_read (reg, PHY_BMSR, &reg_short);
+       miiphy_read (dev->name, reg, PHY_BMSR, &reg_short);
 
        /*
         * Wait if PHY is capable of autonegotiation and autonegotiation is not complete
@@ -506,7 +563,7 @@ static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis)
                                putc ('.');
                        }
                        udelay (1000);  /* 1 ms */
-                       miiphy_read (reg, PHY_BMSR, &reg_short);
+                       miiphy_read (dev->name, reg, PHY_BMSR, &reg_short);
 
                }
                puts (" done\n");
@@ -514,8 +571,8 @@ static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis)
        }
 #endif /* #ifndef CONFIG_CS8952_PHY */
 
-       speed = miiphy_speed (reg);
-       duplex = miiphy_duplex (reg);
+       speed = miiphy_speed (dev->name, reg);
+       duplex = miiphy_duplex (dev->name, reg);
 
        if (hw_p->print_speed) {
                hw_p->print_speed = 0;
@@ -523,7 +580,7 @@ static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis)
                        (int) speed, (duplex == HALF) ? "HALF" : "FULL");
        }
 
-#if defined(CONFIG_440)
+#if defined(CONFIG_440) && !defined(CONFIG_440SP) && !defined(CONFIG_440SPE)
 #if defined(CONFIG_440EP) || defined(CONFIG_440GR)
        mfsdr(sdr_mfr, reg);
        if (speed == 100) {
@@ -551,10 +608,10 @@ static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis)
 
                out32 (RGMII_SSR, reg);
        }
-#endif /* defined(CONFIG_440) */
+#endif /* defined(CONFIG_440) && !defined(CONFIG_440SP) */
 
        /* set the Mal configuration reg */
-#if defined(CONFIG_440GX)
+#if defined(CONFIG_440GX) || defined(CONFIG_440SP) || defined(CONFIG_440SPE)
        mtdcr (malmcr, MAL_CR_PLBB | MAL_CR_OPBBL | MAL_CR_LEA |
               MAL_CR_PLBLT_DEFAULT | MAL_CR_EOPIE | 0x00330000);
 #else
@@ -641,7 +698,7 @@ static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis)
        for (i = 0; i < NUM_RX_BUFF; i++) {
                hw_p->rx[i].ctrl = 0;
                hw_p->rx[i].data_len = 0;
-               /*       rx[i].data_ptr = (char *) &rx_buff[i]; */
+               /*       rx[i].data_ptr = (char *) &rx_buff[i]; */
                hw_p->rx[i].data_ptr = (char *) NetRxPackets[i];
                if ((NUM_RX_BUFF - 1) == i)
                        hw_p->rx[i].ctrl |= MAL_RX_CTRL_WRAP;
@@ -737,9 +794,15 @@ static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis)
        mode_reg |= EMAC_M1_RFS_4K | EMAC_M1_TX_FIFO_2K;
 
        /* set speed */
-       if (speed == _1000BASET)
+       if (speed == _1000BASET) {
+#if defined(CONFIG_440SP) || defined(CONFIG_440SPE)
+               unsigned long pfc1;
+               mfsdr (sdr_pfc1, pfc1);
+               pfc1 |= SDR0_PFC1_EM_1000;
+               mtsdr (sdr_pfc1, pfc1);
+#endif
                mode_reg = mode_reg | EMAC_M1_MF_1000MBPS | EMAC_M1_IST;
-       else if (speed == _100BASET)
+       else if (speed == _100BASET)
                mode_reg = mode_reg | EMAC_M1_MF_100MBPS | EMAC_M1_IST;
        else
                mode_reg = mode_reg & ~0x00C00000;      /* 10 MBPS */
@@ -757,9 +820,9 @@ static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis)
        /* set transmit request threshold register */
        out32 (EMAC_TRTR + hw_p->hw_addr, 0x18000000);  /* 256 byte threshold */
 
-       /* set receive  low/high water mark register */
+       /* set receive  low/high water mark register */
 #if defined(CONFIG_440)
-       /* 440GP has a 64 byte burst length */
+       /* 440s has a 64 byte burst length */
        out32 (EMAC_RX_HI_LO_WMARK + hw_p->hw_addr, 0x80009000);
 #else
        /* 405s have a 16 byte burst length */
@@ -864,8 +927,21 @@ static int ppc_4xx_eth_send (struct eth_device *dev, volatile void *ptr,
        }
 }
 
+
 #if defined (CONFIG_440)
 
+#if defined(CONFIG_440SP) || defined(CONFIG_440SPE)
+/*
+ * Hack: On 440SP all enet irq sources are located on UIC1
+ * Needs some cleanup. --sr
+ */
+#define UIC0MSR                uic1msr
+#define UIC0SR         uic1sr
+#else
+#define UIC0MSR                uic0msr
+#define UIC0SR         uic0sr
+#endif
+
 int enetInt (struct eth_device *dev)
 {
        int serviced;
@@ -892,20 +968,17 @@ int enetInt (struct eth_device *dev)
 
        hw_p = dev->priv;
 
-
        /* enter loop that stays in interrupt code until nothing to service */
        do {
                serviced = 0;
 
-               my_uic0msr = mfdcr (uic0msr);
+               my_uic0msr = mfdcr (UIC0MSR);
                my_uic1msr = mfdcr (uic1msr);
 #if defined(CONFIG_440GX)
                my_uic2msr = mfdcr (uic2msr);
 #endif
                if (!(my_uic0msr & (UIC_MRE | UIC_MTE))
-                   && !(my_uic1msr &
-                        (UIC_ETH0 | UIC_ETH1 | UIC_MS | UIC_MTDE |
-                         UIC_MRDE))) {
+                   && !(my_uic1msr & (UIC_ETH0 | UIC_ETH1 | UIC_MS | UIC_MTDE | UIC_MRDE))) {
                        /* not for us */
                        return (rc);
                }
@@ -943,12 +1016,13 @@ int enetInt (struct eth_device *dev)
                        }
                        if ((hw_p->emac_ier & emac_isr)
                            || (my_uic1msr & (UIC_MS | UIC_MTDE | UIC_MRDE))) {
-                               mtdcr (uic0sr, UIC_MRE | UIC_MTE);      /* Clear */
+                               mtdcr (UIC0SR, UIC_MRE | UIC_MTE);      /* Clear */
                                mtdcr (uic1sr, UIC_ETH0 | UIC_MS | UIC_MTDE | UIC_MRDE);        /* Clear */
                                return (rc);    /* we had errors so get out */
                        }
                }
 
+#if !defined(CONFIG_440SP)
                if (hw_p->devnum == 1) {
                        if (UIC_ETH1 & my_uic1msr) {    /* look for EMAC errors */
                                emac_isr = in32 (EMAC_ISR + hw_p->hw_addr);
@@ -960,7 +1034,7 @@ int enetInt (struct eth_device *dev)
                        }
                        if ((hw_p->emac_ier & emac_isr)
                            || (my_uic1msr & (UIC_MS | UIC_MTDE | UIC_MRDE))) {
-                               mtdcr (uic0sr, UIC_MRE | UIC_MTE);      /* Clear */
+                               mtdcr (UIC0SR, UIC_MRE | UIC_MTE);      /* Clear */
                                mtdcr (uic1sr, UIC_ETH1 | UIC_MS | UIC_MTDE | UIC_MRDE);        /* Clear */
                                return (rc);    /* we had errors so get out */
                        }
@@ -977,7 +1051,7 @@ int enetInt (struct eth_device *dev)
                        }
                        if ((hw_p->emac_ier & emac_isr)
                            || (my_uic1msr & (UIC_MS | UIC_MTDE | UIC_MRDE))) {
-                               mtdcr (uic0sr, UIC_MRE | UIC_MTE);      /* Clear */
+                               mtdcr (UIC0SR, UIC_MRE | UIC_MTE);      /* Clear */
                                mtdcr (uic1sr, UIC_MS | UIC_MTDE | UIC_MRDE);   /* Clear */
                                mtdcr (uic2sr, UIC_ETH2);
                                return (rc);    /* we had errors so get out */
@@ -995,24 +1069,26 @@ int enetInt (struct eth_device *dev)
                        }
                        if ((hw_p->emac_ier & emac_isr)
                            || (my_uic1msr & (UIC_MS | UIC_MTDE | UIC_MRDE))) {
-                               mtdcr (uic0sr, UIC_MRE | UIC_MTE);      /* Clear */
+                               mtdcr (UIC0SR, UIC_MRE | UIC_MTE);      /* Clear */
                                mtdcr (uic1sr, UIC_MS | UIC_MTDE | UIC_MRDE);   /* Clear */
                                mtdcr (uic2sr, UIC_ETH3);
                                return (rc);    /* we had errors so get out */
                        }
                }
 #endif /* CONFIG_440GX */
+#endif /* !CONFIG_440SP */
+
                /* handle MAX TX EOB interrupt from a tx */
                if (my_uic0msr & UIC_MTE) {
                        mal_rx_eob = mfdcr (maltxeobisr);
                        mtdcr (maltxeobisr, mal_rx_eob);
-                       mtdcr (uic0sr, UIC_MTE);
+                       mtdcr (UIC0SR, UIC_MTE);
                }
                /* handle MAL RX EOB  interupt from a receive */
                /* check for EOB on valid channels            */
                if (my_uic0msr & UIC_MRE) {
                        mal_rx_eob = mfdcr (malrxeobisr);
-                       if ((mal_rx_eob & (0x80000000 >> hw_p->devnum)) != 0) { /* call emac routine for channel x */
+                       if ((mal_rx_eob & (0x80000000 >> hw_p->devnum)) != 0) { /* call emac routine for channel x */
                                /* clear EOB
                                   mtdcr(malrxeobisr, mal_rx_eob); */
                                enet_rcv (dev, emac_isr);
@@ -1021,7 +1097,8 @@ int enetInt (struct eth_device *dev)
                                rc = 0;
                        }
                }
-               mtdcr (uic0sr, UIC_MRE);        /* Clear */
+
+               mtdcr (UIC0SR, UIC_MRE);        /* Clear */
                mtdcr (uic1sr, UIC_MS | UIC_MTDE | UIC_MRDE);   /* Clear */
                switch (hw_p->devnum) {
                case 0:
@@ -1118,7 +1195,7 @@ int enetInt (struct eth_device *dev)
                if (my_uicmsr & UIC_MAL_RXEOB)
                {
                        mal_rx_eob = mfdcr (malrxeobisr);
-                       if ((mal_rx_eob & (0x80000000 >> hw_p->devnum)) != 0) { /* call emac routine for channel x */
+                       if ((mal_rx_eob & (0x80000000 >> hw_p->devnum)) != 0) { /* call emac routine for channel x */
                                /* clear EOB
                                 mtdcr(malrxeobisr, mal_rx_eob); */
                                enet_rcv (dev, emac_isr);
@@ -1152,7 +1229,7 @@ static void mal_err (struct eth_device *dev, unsigned long isr,
        mtdcr (malrxdeir, 0x80000000);
 
 #ifdef INFO_4XX_ENET
-       printf ("\nMAL error occured.... ISR = %lx UIC = = %lx  MAL_DEF = %lx  MAL_ERR= %lx \n", isr, uic, maldef, mal_errr);
+       printf ("\nMAL error occured.... ISR = %lx UIC = = %lx  MAL_DEF = %lx  MAL_ERR= %lx \n", isr, uic, maldef, mal_errr);
 #endif
 
        eth_init (hw_p->bis);   /* start again... */
@@ -1266,7 +1343,7 @@ static int ppc_4xx_eth_rx (struct eth_device *dev)
        unsigned long msr;
        EMAC_4XX_HW_PST hw_p = dev->priv;
 
-       hw_p->is_receiving = 1; /* tell driver */
+       hw_p->is_receiving = 1; /* tell driver */
 
        for (;;) {
                /* AS.HARNOIS
@@ -1285,8 +1362,8 @@ static int ppc_4xx_eth_rx (struct eth_device *dev)
                length = hw_p->rx[user_index].data_len;
 
                /* Pass the packet up to the protocol layers. */
-               /*       NetReceive(NetRxPackets[rxIdx], length - 4); */
-               /*       NetReceive(NetRxPackets[i], length); */
+               /*       NetReceive(NetRxPackets[rxIdx], length - 4); */
+               /*       NetReceive(NetRxPackets[i], length); */
                NetReceive (NetRxPackets[user_index], length - 4);
                /* Free Recv Buffer */
                hw_p->rx[user_index].ctrl |= MAL_RX_CTRL_EMPTY;
@@ -1303,7 +1380,7 @@ static int ppc_4xx_eth_rx (struct eth_device *dev)
                mtmsr (msr);    /* Enable IRQ's */
        }
 
-       hw_p->is_receiving = 0; /* tell driver */
+       hw_p->is_receiving = 0; /* tell driver */
 
        return length;
 }
@@ -1325,23 +1402,22 @@ int ppc_4xx_eth_initialize (bd_t * bis)
 #endif
        /* set phy num and mode */
        bis->bi_phynum[0] = CONFIG_PHY_ADDR;
+       bis->bi_phymode[0] = 0;
+
 #if defined(CONFIG_PHY1_ADDR)
        bis->bi_phynum[1] = CONFIG_PHY1_ADDR;
+       bis->bi_phymode[1] = 0;
 #endif
 #if defined(CONFIG_440GX)
        bis->bi_phynum[2] = CONFIG_PHY2_ADDR;
        bis->bi_phynum[3] = CONFIG_PHY3_ADDR;
-       bis->bi_phymode[0] = 0;
-       bis->bi_phymode[1] = 0;
        bis->bi_phymode[2] = 2;
        bis->bi_phymode[3] = 2;
 
-#if defined (CONFIG_440GX)
        ppc_4xx_eth_setup_bridge(0, bis);
 #endif
-#endif
 
-       for (eth_num = 0; eth_num < EMAC_NUM_DEV; eth_num++) {
+       for (eth_num = 0; eth_num < LAST_EMAC_NUM; eth_num++) {
 
                /* See if we can actually bring up the interface, otherwise, skip it */
                switch (eth_num) {
@@ -1436,9 +1512,15 @@ int ppc_4xx_eth_initialize (bd_t * bis)
 
                if (0 == virgin) {
                        /* set the MAL IER ??? names may change with new spec ??? */
+#if defined(CONFIG_440SPE)
+                       mal_ier =
+                               MAL_IER_PT | MAL_IER_PRE | MAL_IER_PWE |
+                               MAL_IER_DE | MAL_IER_OTE | MAL_IER_OE | MAL_IER_PE ;
+#else
                        mal_ier =
                                MAL_IER_DE | MAL_IER_NE | MAL_IER_TE |
                                MAL_IER_OPBE | MAL_IER_PLBE;
+#endif
                        mtdcr (malesr, 0xffffffff);     /* clear pending interrupts */
                        mtdcr (maltxdeir, 0xffffffff);  /* clear pending interrupts */
                        mtdcr (malrxdeir, 0xffffffff);  /* clear pending interrupts */
@@ -1469,6 +1551,12 @@ int ppc_4xx_eth_initialize (bd_t * bis)
                emac0_dev = dev;
 #endif
 
+#if defined(CONFIG_NET_MULTI)
+#if defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII)
+               miiphy_register (dev->name,
+                                emac4xx_miiphy_read, emac4xx_miiphy_write);
+#endif
+#endif
        }                       /* end for each supported device */
        return (1);
 }
@@ -1486,12 +1574,16 @@ void eth_halt (void) {
 int eth_init (bd_t *bis)
 {
        ppc_4xx_eth_initialize(bis);
-       return(ppc_4xx_eth_init(emac0_dev, bis));
+       if (emac0_dev) {
+               return ppc_4xx_eth_init(emac0_dev, bis);
+       } else {
+               printf("ERROR: ethaddr not set!\n");
+               return -1;
+       }
 }
 
 int eth_send(volatile void *packet, int length)
 {
-
        return (ppc_4xx_eth_send(emac0_dev, packet, length));
 }
 
@@ -1499,6 +1591,16 @@ int eth_rx(void)
 {
        return (ppc_4xx_eth_rx(emac0_dev));
 }
+
+int emac4xx_miiphy_initialize (bd_t * bis)
+{
+#if defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII)
+       miiphy_register ("ppc_4xx_eth0",
+                        emac4xx_miiphy_read, emac4xx_miiphy_write);
+#endif
+
+       return 0;
+}
 #endif /* !defined(CONFIG_NET_MULTI) */
 
 #endif /* #if (CONFIG_COMMANDS & CFG_CMD_NET) */