]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - cpu/ppc4xx/4xx_enet.c
[PATCH] Add support for AMCC Taishan PPC440GX eval board
[karo-tx-uboot.git] / cpu / ppc4xx / 4xx_enet.c
index d3f1de4359ba1a1166dd043eb87b29f4e418ecd9..4f5558328a27ea8e334963ca82377814102150c5 100644 (file)
 #error "CONFIG_MII has to be defined!"
 #endif
 
+#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 */
 
 #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).
 #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)
+#define BI_PHYMODE_SMII  6
+#define BI_PHYMODE_MII   7
+#endif
 
+#if defined(CONFIG_440SPE) || defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
+#define SDR0_MFR_ETH_CLK_SEL_V(n)      ((0x01<<27) / (n+1))
+#endif
 
 /*-----------------------------------------------------------------------------+
  * Global variables. TX and RX descriptors and buffers.
@@ -142,6 +152,24 @@ static uint32_t mal_ier;
 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
+
+/* normal boards start with EMAC0 */
+#if !defined(CONFIG_EMAC_NR_START)
+#define CONFIG_EMAC_NR_START   0
+#endif
 
 /*-----------------------------------------------------------------------------+
  * Prototypes and externals.
@@ -154,6 +182,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 +196,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) || defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
+       unsigned long mfr;
+#endif
 
        out32 (EMAC_IER + hw_p->hw_addr, 0x00000000);   /* disable emac interrupts */
 
@@ -184,16 +220,30 @@ static void ppc_4xx_eth_halt (struct eth_device *dev)
        }
 
        /* EMAC RESET */
+#if defined(CONFIG_440SPE) || defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
+       /* provide clocks for EMAC internal loopback  */
+       mfsdr (sdr_mfr, mfr);
+       mfr |= SDR0_MFR_ETH_CLK_SEL_V(hw_p->devnum);
+       mtsdr(sdr_mfr, mfr);
+#endif
+
        out32 (EMAC_M0 + hw_p->hw_addr, EMAC_M0_SRST);
 
+#if defined(CONFIG_440SPE) || defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
+       /* remove clocks for EMAC internal loopback  */
+       mfsdr (sdr_mfr, mfr);
+       mfr &= ~SDR0_MFR_ETH_CLK_SEL_V(hw_p->devnum);
+       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)
 {
@@ -219,10 +269,10 @@ int ppc_4xx_eth_setup_bridge(int devnum, bd_t * bis)
                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);
+               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;
@@ -282,9 +332,49 @@ int ppc_4xx_eth_setup_bridge(int devnum, bd_t * bis)
        out32 (RGMII_FER, rmiifer);
 
        return ((int)pfc1);
+}
+#endif /* CONFIG_440_GX */
+
+#if defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
+int ppc_4xx_eth_setup_bridge(int devnum, bd_t * bis)
+{
+       unsigned long zmiifer=0x0;
+
+       /*
+        * Right now only 2*RGMII is supported. Please extend when needed.
+        * sr - 2006-08-29
+        */
+       switch (1) {
+       case 0:
+               /* 1 x GMII port */
+               out32 (ZMII_FER, 0x00);
+               out32 (RGMII_FER, 0x00000037);
+               bis->bi_phymode[0] = BI_PHYMODE_GMII;
+               bis->bi_phymode[1] = BI_PHYMODE_NONE;
+               break;
+       case 1:
+               /* 2 x RGMII ports */
+               out32 (ZMII_FER, 0x00);
+               out32 (RGMII_FER, 0x00000055);
+               bis->bi_phymode[0] = BI_PHYMODE_RGMII;
+               bis->bi_phymode[1] = BI_PHYMODE_RGMII;
+               break;
+       case 2:
+               /* 2 x SMII ports */
+
+               break;
+       default:
+               break;
+       }
+
+       /* Ensure we setup mdio for this devnum and ONLY this devnum */
+       zmiifer = in32 (ZMII_FER);
+       zmiifer |= (ZMII_FER_MDI) << ZMII_FER_V(devnum);
+       out32 (ZMII_FER, zmiifer);
 
+       return ((int)0x0);
 }
-#endif
+#endif /* CONFIG_440EPX */
 
 static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis)
 {
@@ -297,11 +387,20 @@ 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_440EPX) || defined(CONFIG_440GRX) || \
+    defined(CONFIG_440SP) || defined(CONFIG_440SPE)
        sys_info_t sysinfo;
-       int ethgroup;
+#if defined(CONFIG_440GX) || defined(CONFIG_440SPE) || \
+    defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
+       int ethgroup = -1;
+#endif
+#endif
+#if defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || 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 */
@@ -311,7 +410,9 @@ static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis)
                return -1;
        }
 
-#if defined(CONFIG_440GX)
+#if defined(CONFIG_440GX) || \
+    defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+    defined(CONFIG_440SP) || defined(CONFIG_440SPE)
        /* Need to get the OPB frequency so we can access the PHY */
        get_sys_info (&sysinfo);
 #endif
@@ -341,6 +442,7 @@ 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 */
@@ -354,7 +456,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 */
@@ -365,7 +467,7 @@ static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis)
 
 #if defined(CONFIG_440EP) || defined(CONFIG_440GR)
        out32 (ZMII_FER, (ZMII_FER_RMII | ZMII_FER_MDI) << ZMII_FER_V (devnum));
-#elif defined(CONFIG_440GX)
+#elif defined(CONFIG_440GX) || defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
        ethgroup = ppc_4xx_eth_setup_bridge(devnum, bis);
 #elif defined(CONFIG_440GP)
        /* set RMII mode */
@@ -373,8 +475,7 @@ static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis)
 #else
        if ((devnum == 0) || (devnum == 1)) {
                out32 (ZMII_FER, (ZMII_FER_SMII | ZMII_FER_MDI) << ZMII_FER_V (devnum));
-       }
-       else { /* ((devnum == 2) || (devnum == 3)) */
+       } else { /* ((devnum == 2) || (devnum == 3)) */
                out32 (ZMII_FER, ZMII_FER_MDI << ZMII_FER_V (devnum));
                out32 (RGMII_FER, ((RGMII_FER_RGMII << RGMII_FER_V (2)) |
                                   (RGMII_FER_RGMII << RGMII_FER_V (3))));
@@ -382,11 +483,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) || defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
+       /* provide clocks for EMAC internal loopback  */
+       mfsdr (sdr_mfr, mfr);
+       mfr |= SDR0_MFR_ETH_CLK_SEL_V(devnum);
+       mtsdr(sdr_mfr, mfr);
+#endif
 
        out32 (EMAC_M0 + hw_p->hw_addr, EMAC_M0_SRST);
        __asm__ volatile ("eieio");
@@ -396,8 +503,19 @@ static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis)
                udelay (1000);
                failsafe--;
        }
+       if (failsafe <= 0)
+               printf("\nProblem resetting EMAC!\n");
+
+#if defined(CONFIG_440SPE) || defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
+       /* remove clocks for EMAC internal loopback  */
+       mfsdr (sdr_mfr, mfr);
+       mfr &= ~SDR0_MFR_ETH_CLK_SEL_V(devnum);
+       mtsdr(sdr_mfr, mfr);
+#endif
 
-#if defined(CONFIG_440GX)
+#if defined(CONFIG_440GX) || \
+    defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+    defined(CONFIG_440SP) || defined(CONFIG_440SPE)
        /* Whack the M1 register */
        mode_reg = 0x0;
        mode_reg &= ~0x00000038;
@@ -412,7 +530,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;
@@ -447,19 +565,28 @@ 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);
+#if defined(CONFIG_M88E1111_PHY)
+               miiphy_write (dev->name, reg, 0x14, 0x0ce3);
+               miiphy_write (dev->name, reg, 0x18, 0x4101);
+               miiphy_write (dev->name, reg, 0x09, 0x0e00);
+               miiphy_write (dev->name, reg, 0x04, 0x01e1);
+#endif
+               miiphy_reset (dev->name, reg);
+
+#if defined(CONFIG_440GX) || \
+    defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+    defined(CONFIG_440SP) || defined(CONFIG_440SPE)
 
-#if defined(CONFIG_440GX)
 #if defined(CONFIG_CIS8201_PHY)
                /*
                 * Cicada 8201 PHY needs to have an extended register whacked
                 * for RGMII mode.
                 */
-               if ( ((devnum == 2) || (devnum ==3)) && (4 == ethgroup) ) {
+               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:
@@ -467,26 +594,46 @@ 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
+
+#if defined(CONFIG_ET1011C_PHY)
+               /*
+                * Agere ET1011c PHY needs to have an extended register whacked
+                * for RGMII mode.
+                */
+               if (((devnum == 2) || (devnum ==3)) && (4 == ethgroup)) {
+                       miiphy_read (dev->name, reg, 0x16, &reg_short);
+                       reg_short &= ~(0x7);
+                       reg_short |= 0x6;       /* RGMII DLL Delay*/
+                       miiphy_write (dev->name, reg, 0x16, reg_short);
+
+                       miiphy_read (dev->name, reg, 0x17, &reg_short);
+                       reg_short &= ~(0x40);
+                       miiphy_write (dev->name, reg, 0x17, reg_short);
+
+                       miiphy_write(dev->name, reg, 0x1c, 0x74f0);
+               }
+#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
@@ -508,7 +655,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");
@@ -516,16 +663,18 @@ 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;
-               printf ("ENET Speed is %d Mbps - %s duplex connection\n",
-                       (int) speed, (duplex == HALF) ? "HALF" : "FULL");
+               printf ("ENET Speed is %d Mbps - %s duplex connection (EMAC%d)\n",
+                       (int) speed, (duplex == HALF) ? "HALF" : "FULL",
+                       hw_p->devnum);
        }
 
-#if defined(CONFIG_440)
+#if defined(CONFIG_440) && !defined(CONFIG_440SP) && !defined(CONFIG_440SPE) && \
+    !defined(CONFIG_440EPX) && !defined(CONFIG_440GRX)
 #if defined(CONFIG_440EP) || defined(CONFIG_440GR)
        mfsdr(sdr_mfr, reg);
        if (speed == 100) {
@@ -548,15 +697,34 @@ static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis)
                        reg = (RGMII_SSR_SP_1000MBPS << RGMII_SSR_V (devnum));
                else if (speed == 100)
                        reg = (RGMII_SSR_SP_100MBPS << RGMII_SSR_V (devnum));
-               else
+               else if (speed == 10)
                        reg = (RGMII_SSR_SP_10MBPS << RGMII_SSR_V (devnum));
-
+               else {
+                       printf("Error in RGMII Speed\n");
+                       return -1;
+               }
                out32 (RGMII_SSR, reg);
        }
-#endif /* defined(CONFIG_440) */
+#endif /* defined(CONFIG_440) && !defined(CONFIG_440SP) */
+
+#if defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
+       if (speed == 1000)
+               reg = (RGMII_SSR_SP_1000MBPS << RGMII_SSR_V (devnum));
+       else if (speed == 100)
+               reg = (RGMII_SSR_SP_100MBPS << RGMII_SSR_V (devnum));
+       else if (speed == 10)
+               reg = (RGMII_SSR_SP_10MBPS << RGMII_SSR_V (devnum));
+       else {
+               printf("Error in RGMII Speed\n");
+               return -1;
+       }
+       out32 (RGMII_SSR, reg);
+#endif
 
        /* set the Mal configuration reg */
-#if defined(CONFIG_440GX)
+#if defined(CONFIG_440GX) || \
+    defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+    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
@@ -650,7 +818,7 @@ static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis)
                hw_p->rx[i].ctrl |= MAL_RX_CTRL_EMPTY | MAL_RX_CTRL_INTR;
                hw_p->rx_ready[i] = -1;
 #if 0
-               printf ("RX_BUFF %d @ 0x%08lx\n", i, (ulong) rx[i].data_ptr);
+               printf ("RX_BUFF %d @ 0x%08lx\n", i, (ulong) hw_p->rx[i].data_ptr);
 #endif
        }
 
@@ -739,9 +907,17 @@ 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) || \
+    defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
+               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 */
@@ -761,7 +937,7 @@ static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis)
 
        /* 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 */
@@ -866,8 +1042,29 @@ 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
+
+#if defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
+#define UICMSR_ETHX    uic0msr
+#define UICSR_ETHX     uic0sr
+#else
+#define UICMSR_ETHX    uic1msr
+#define UICSR_ETHX     uic1sr
+#endif
+
 int enetInt (struct eth_device *dev)
 {
        int serviced;
@@ -876,6 +1073,7 @@ int enetInt (struct eth_device *dev)
        unsigned long emac_isr = 0;
        unsigned long mal_rx_eob;
        unsigned long my_uic0msr, my_uic1msr;
+       unsigned long my_uicmsr_ethx;
 
 #if defined(CONFIG_440GX)
        unsigned long my_uic2msr;
@@ -894,20 +1092,20 @@ 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
+               my_uicmsr_ethx = mfdcr (UICMSR_ETHX);
+
                if (!(my_uic0msr & (UIC_MRE | UIC_MTE))
-                   && !(my_uic1msr &
-                        (UIC_ETH0 | UIC_ETH1 | UIC_MS | UIC_MTDE |
-                         UIC_MRDE))) {
+                   && !(my_uic1msr & (UIC_MS | UIC_MTDE | UIC_MRDE))
+                   && !(my_uicmsr_ethx & (UIC_ETH0 | UIC_ETH1))) {
                        /* not for us */
                        return (rc);
                }
@@ -926,8 +1124,7 @@ int enetInt (struct eth_device *dev)
                        mal_isr = mfdcr (malesr);
                        /* look for mal error */
                        if (my_uic1msr & (UIC_MS | UIC_MTDE | UIC_MRDE)) {
-                               mal_err (dev, mal_isr, my_uic0msr,
-                                        MAL_UIC_DEF, MAL_UIC_ERR);
+                               mal_err (dev, mal_isr, my_uic1msr, MAL_UIC_DEF, MAL_UIC_ERR);
                                serviced = 1;
                                rc = 0;
                        }
@@ -935,7 +1132,7 @@ int enetInt (struct eth_device *dev)
 
                /* port by port dispatch of emac interrupts */
                if (hw_p->devnum == 0) {
-                       if (UIC_ETH0 & my_uic1msr) {    /* look for EMAC errors */
+                       if (UIC_ETH0 & my_uicmsr_ethx) {        /* look for EMAC errors */
                                emac_isr = in32 (EMAC_ISR + hw_p->hw_addr);
                                if ((hw_p->emac_ier & emac_isr) != 0) {
                                        emac_err (dev, emac_isr);
@@ -945,14 +1142,16 @@ 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 (uic1sr, UIC_ETH0 | UIC_MS | UIC_MTDE | UIC_MRDE);        /* Clear */
+                               mtdcr (UIC0SR, UIC_MRE | UIC_MTE);      /* Clear */
+                               mtdcr (uic1sr, UIC_MS | UIC_MTDE | UIC_MRDE);   /* Clear */
+                               mtdcr (UICSR_ETHX, UIC_ETH0); /* 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 */
+                       if (UIC_ETH1 & my_uicmsr_ethx) {        /* look for EMAC errors */
                                emac_isr = in32 (EMAC_ISR + hw_p->hw_addr);
                                if ((hw_p->emac_ier & emac_isr) != 0) {
                                        emac_err (dev, emac_isr);
@@ -962,8 +1161,9 @@ 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 (uic1sr, UIC_ETH1 | UIC_MS | UIC_MTDE | UIC_MRDE);        /* Clear */
+                               mtdcr (UIC0SR, UIC_MRE | UIC_MTE);      /* Clear */
+                               mtdcr (uic1sr, UIC_MS | UIC_MTDE | UIC_MRDE); /* Clear */
+                               mtdcr (UICSR_ETHX, UIC_ETH1); /* Clear */
                                return (rc);    /* we had errors so get out */
                        }
                }
@@ -979,7 +1179,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 */
@@ -997,18 +1197,20 @@ 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            */
@@ -1023,14 +1225,15 @@ 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:
-                       mtdcr (uic1sr, UIC_ETH0);
+                       mtdcr (UICSR_ETHX, UIC_ETH0);
                        break;
                case 1:
-                       mtdcr (uic1sr, UIC_ETH1);
+                       mtdcr (UICSR_ETHX, UIC_ETH1);
                        break;
 #if defined (CONFIG_440GX)
                case 2:
@@ -1316,6 +1519,8 @@ int ppc_4xx_eth_initialize (bd_t * bis)
        struct eth_device *dev;
        int eth_num = 0;
        EMAC_4XX_HW_PST hw = NULL;
+       u8 ethaddr[4 + CONFIG_EMAC_NR_START][6];
+       u32 hw_addr[4];
 
 #if defined(CONFIG_440GX)
        unsigned long pfc1;
@@ -1325,60 +1530,69 @@ int ppc_4xx_eth_initialize (bd_t * bis)
        pfc1 |= 0x01200000;
        mtsdr (sdr_pfc1, pfc1);
 #endif
-       /* set phy num and mode */
-       bis->bi_phynum[0] = CONFIG_PHY_ADDR;
-#if defined(CONFIG_PHY1_ADDR)
-       bis->bi_phynum[1] = CONFIG_PHY1_ADDR;
-#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++) {
+       /* first clear all mac-addresses */
+       for (eth_num = 0; eth_num < LAST_EMAC_NUM; eth_num++)
+               memcpy(ethaddr[eth_num], "\0\0\0\0\0\0", 6);
 
-               /* See if we can actually bring up the interface, otherwise, skip it */
+       for (eth_num = 0; eth_num < LAST_EMAC_NUM; eth_num++) {
                switch (eth_num) {
                default:                /* fall through */
                case 0:
-                       if (memcmp (bis->bi_enetaddr, "\0\0\0\0\0\0", 6) == 0) {
-                               bis->bi_phymode[eth_num] = BI_PHYMODE_NONE;
-                               continue;
-                       }
+                       memcpy(ethaddr[eth_num + CONFIG_EMAC_NR_START],
+                              bis->bi_enetaddr, 6);
+                       hw_addr[eth_num] = 0x0;
                        break;
 #ifdef CONFIG_HAS_ETH1
                case 1:
-                       if (memcmp (bis->bi_enet1addr, "\0\0\0\0\0\0", 6) == 0) {
-                               bis->bi_phymode[eth_num] = BI_PHYMODE_NONE;
-                               continue;
-                       }
+                       memcpy(ethaddr[eth_num + CONFIG_EMAC_NR_START],
+                              bis->bi_enet1addr, 6);
+                       hw_addr[eth_num] = 0x100;
                        break;
 #endif
 #ifdef CONFIG_HAS_ETH2
                case 2:
-                       if (memcmp (bis->bi_enet2addr, "\0\0\0\0\0\0", 6) == 0) {
-                               bis->bi_phymode[eth_num] = BI_PHYMODE_NONE;
-                               continue;
-                       }
+                       memcpy(ethaddr[eth_num + CONFIG_EMAC_NR_START],
+                              bis->bi_enet2addr, 6);
+                       hw_addr[eth_num] = 0x400;
                        break;
 #endif
 #ifdef CONFIG_HAS_ETH3
                case 3:
-                       if (memcmp (bis->bi_enet3addr, "\0\0\0\0\0\0", 6) == 0) {
-                               bis->bi_phymode[eth_num] = BI_PHYMODE_NONE;
-                               continue;
-                       }
+                       memcpy(ethaddr[eth_num + CONFIG_EMAC_NR_START],
+                              bis->bi_enet3addr, 6);
+                       hw_addr[eth_num] = 0x600;
                        break;
 #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[2] = 2;
+       bis->bi_phymode[3] = 2;
+
+       ppc_4xx_eth_setup_bridge(0, bis);
+#endif
+
+       for (eth_num = 0; eth_num < LAST_EMAC_NUM; eth_num++) {
+               /*
+                * See if we can actually bring up the interface,
+                * otherwise, skip it
+                */
+               if (memcmp (ethaddr[eth_num], "\0\0\0\0\0\0", 6) == 0) {
+                       bis->bi_phymode[eth_num] = BI_PHYMODE_NONE;
+                       continue;
+               }
 
                /* Allocate device structure */
                dev = (struct eth_device *) malloc (sizeof (*dev));
@@ -1400,36 +1614,12 @@ int ppc_4xx_eth_initialize (bd_t * bis)
                }
                memset(hw, 0, sizeof(*hw));
 
-               switch (eth_num) {
-               default:                /* fall through */
-               case 0:
-                       hw->hw_addr = 0;
-                       memcpy (dev->enetaddr, bis->bi_enetaddr, 6);
-                       break;
-#ifdef CONFIG_HAS_ETH1
-               case 1:
-                       hw->hw_addr = 0x100;
-                       memcpy (dev->enetaddr, bis->bi_enet1addr, 6);
-                       break;
-#endif
-#ifdef CONFIG_HAS_ETH2
-               case 2:
-                       hw->hw_addr = 0x400;
-                       memcpy (dev->enetaddr, bis->bi_enet2addr, 6);
-                       break;
-#endif
-#ifdef CONFIG_HAS_ETH3
-               case 3:
-                       hw->hw_addr = 0x600;
-                       memcpy (dev->enetaddr, bis->bi_enet3addr, 6);
-                       break;
-#endif
-               }
-
+               hw->hw_addr = hw_addr[eth_num];
+               memcpy (dev->enetaddr, ethaddr[eth_num], 6);
                hw->devnum = eth_num;
                hw->print_speed = 1;
 
-               sprintf (dev->name, "ppc_4xx_eth%d", eth_num);
+               sprintf (dev->name, "ppc_4xx_eth%d", eth_num - CONFIG_EMAC_NR_START);
                dev->priv = (void *) hw;
                dev->init = ppc_4xx_eth_init;
                dev->halt = ppc_4xx_eth_halt;
@@ -1438,9 +1628,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) || defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
+                       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 */
@@ -1471,11 +1667,16 @@ 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);
 }
 
-
 #if !defined(CONFIG_NET_MULTI)
 void eth_halt (void) {
        if (emac0_dev) {
@@ -1505,6 +1706,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) */