fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / net / sungem_phy.c
index dd37860..d21991e 100644 (file)
@@ -1,12 +1,11 @@
 /*
  * PHY drivers for the sungem ethernet driver.
- * 
+ *
  * This file could be shared with other drivers.
- * 
- * (c) 2002, Benjamin Herrenscmidt (benh@kernel.crashing.org)
+ *
+ * (c) 2002-2007, Benjamin Herrenscmidt (benh@kernel.crashing.org)
  *
  * TODO:
- *  - Implement WOL
  *  - Add support for PHYs that provide an IRQ line
  *  - Eventually moved the entire polling state machine in
  *    there (out of the eth driver), so that it can easily be
@@ -19,7 +18,6 @@
  *    of darwin, still need to reverse engineer that
  */
 
-#include <linux/config.h>
 
 #include <linux/module.h>
 
 #include <linux/ethtool.h>
 #include <linux/delay.h>
 
+#ifdef CONFIG_PPC_PMAC
+#include <asm/prom.h>
+#endif
+
 #include "sungem_phy.h"
 
 /* Link modes of the BCM5400 PHY */
-static int phy_BCM5400_link_table[8][3] = {
+static const int phy_BCM5400_link_table[8][3] = {
        { 0, 0, 0 },    /* No link */
        { 0, 0, 0 },    /* 10BT Half Duplex */
        { 1, 0, 0 },    /* 10BT Full Duplex */
@@ -70,7 +72,7 @@ static int reset_one_mii_phy(struct mii_phy* phy, int phy_id)
 {
        u16 val;
        int limit = 10000;
-       
+
        val = __phy_read(phy, phy_id, MII_BMCR);
        val &= ~(BMCR_ISOLATE | BMCR_PDOWN);
        val |= BMCR_RESET;
@@ -86,7 +88,7 @@ static int reset_one_mii_phy(struct mii_phy* phy, int phy_id)
        }
        if ((val & BMCR_ISOLATE) && limit > 0)
                __phy_write(phy, phy_id, MII_BMCR, val & ~BMCR_ISOLATE);
-       
+
        return (limit <= 0);
 }
 
@@ -98,25 +100,15 @@ static int bcm5201_init(struct mii_phy* phy)
        data &= ~MII_BCM5201_MULTIPHY_SUPERISOLATE;
        phy_write(phy, MII_BCM5201_MULTIPHY, data);
 
+       phy_write(phy, MII_BCM5201_INTERRUPT, 0);
+
        return 0;
 }
 
-static int bcm5201_suspend(struct mii_phy* phy, int wol_options)
+static int bcm5201_suspend(struct mii_phy* phy)
 {
-       if (!wol_options)
-               phy_write(phy, MII_BCM5201_INTERRUPT, 0);
-
-       /* Here's a strange hack used by both MacOS 9 and X */
-       phy_write(phy, MII_LPA, phy_read(phy, MII_LPA));
-       
-       if (!wol_options) {
-#if 0 /* Commented out in Darwin... someone has those dawn docs ? */
-               u16 val = phy_read(phy, MII_BCM5201_AUXMODE2)
-               phy_write(phy, MII_BCM5201_AUXMODE2,
-                         val & ~MII_BCM5201_AUXMODE2_LOWPOWER);
-#endif                 
-               phy_write(phy, MII_BCM5201_MULTIPHY, MII_BCM5201_MULTIPHY_SUPERISOLATE);
-       }
+       phy_write(phy, MII_BCM5201_INTERRUPT, 0);
+       phy_write(phy, MII_BCM5201_MULTIPHY, MII_BCM5201_MULTIPHY_SUPERISOLATE);
 
        return 0;
 }
@@ -144,6 +136,59 @@ static int bcm5221_init(struct mii_phy* phy)
        return 0;
 }
 
+static int bcm5221_suspend(struct mii_phy* phy)
+{
+       u16 data;
+
+       data = phy_read(phy, MII_BCM5221_TEST);
+       phy_write(phy, MII_BCM5221_TEST,
+               data | MII_BCM5221_TEST_ENABLE_SHADOWS);
+
+       data = phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
+       phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
+                 data | MII_BCM5221_SHDOW_AUX_MODE4_IDDQMODE);
+
+       return 0;
+}
+
+static int bcm5241_init(struct mii_phy* phy)
+{
+       u16 data;
+
+       data = phy_read(phy, MII_BCM5221_TEST);
+       phy_write(phy, MII_BCM5221_TEST,
+               data | MII_BCM5221_TEST_ENABLE_SHADOWS);
+
+       data = phy_read(phy, MII_BCM5221_SHDOW_AUX_STAT2);
+       phy_write(phy, MII_BCM5221_SHDOW_AUX_STAT2,
+               data | MII_BCM5221_SHDOW_AUX_STAT2_APD);
+
+       data = phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
+       phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
+               data & ~MII_BCM5241_SHDOW_AUX_MODE4_STANDBYPWR);
+
+       data = phy_read(phy, MII_BCM5221_TEST);
+       phy_write(phy, MII_BCM5221_TEST,
+               data & ~MII_BCM5221_TEST_ENABLE_SHADOWS);
+
+       return 0;
+}
+
+static int bcm5241_suspend(struct mii_phy* phy)
+{
+       u16 data;
+
+       data = phy_read(phy, MII_BCM5221_TEST);
+       phy_write(phy, MII_BCM5221_TEST,
+               data | MII_BCM5221_TEST_ENABLE_SHADOWS);
+
+       data = phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
+       phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
+                 data | MII_BCM5241_SHDOW_AUX_MODE4_STANDBYPWR);
+
+       return 0;
+}
+
 static int bcm5400_init(struct mii_phy* phy)
 {
        u16 data;
@@ -152,16 +197,16 @@ static int bcm5400_init(struct mii_phy* phy)
        data = phy_read(phy, MII_BCM5400_AUXCONTROL);
        data |= MII_BCM5400_AUXCONTROL_PWR10BASET;
        phy_write(phy, MII_BCM5400_AUXCONTROL, data);
-       
+
        data = phy_read(phy, MII_BCM5400_GB_CONTROL);
        data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
        phy_write(phy, MII_BCM5400_GB_CONTROL, data);
-       
+
        udelay(100);
 
        /* Reset and configure cascaded 10/100 PHY */
        (void)reset_one_mii_phy(phy, 0x1f);
-       
+
        data = __phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY);
        data |= MII_BCM5201_MULTIPHY_SERIALMODE;
        __phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data);
@@ -173,7 +218,7 @@ static int bcm5400_init(struct mii_phy* phy)
        return 0;
 }
 
-static int bcm5400_suspend(struct mii_phy* phy, int wol_options)
+static int bcm5400_suspend(struct mii_phy* phy)
 {
 #if 0 /* Commented out in Darwin... someone has those dawn docs ? */
        phy_write(phy, MII_BMCR, BMCR_PDOWN);
@@ -191,7 +236,7 @@ static int bcm5401_init(struct mii_phy* phy)
                /* Some revisions of 5401 appear to need this
                 * initialisation sequence to disable, according
                 * to OF, "tap power management"
-                * 
+                *
                 * WARNING ! OF and Darwin don't agree on the
                 * register addresses. OF seem to interpret the
                 * register numbers below as decimal
@@ -211,7 +256,7 @@ static int bcm5401_init(struct mii_phy* phy)
                phy_write(phy, 0x17, 0x201f);
                phy_write(phy, 0x15, 0x0a20);
        }
-       
+
        /* Configure for gigabit full duplex */
        data = phy_read(phy, MII_BCM5400_GB_CONTROL);
        data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
@@ -221,7 +266,7 @@ static int bcm5401_init(struct mii_phy* phy)
 
        /* Reset and configure cascaded 10/100 PHY */
        (void)reset_one_mii_phy(phy, 0x1f);
-       
+
        data = __phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY);
        data |= MII_BCM5201_MULTIPHY_SERIALMODE;
        __phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data);
@@ -229,7 +274,7 @@ static int bcm5401_init(struct mii_phy* phy)
        return 0;
 }
 
-static int bcm5401_suspend(struct mii_phy* phy, int wol_options)
+static int bcm5401_suspend(struct mii_phy* phy)
 {
 #if 0 /* Commented out in Darwin... someone has those dawn docs ? */
        phy_write(phy, MII_BMCR, BMCR_PDOWN);
@@ -262,11 +307,11 @@ static int bcm5411_init(struct mii_phy* phy)
 
        /* Reset and configure cascaded 10/100 PHY */
        (void)reset_one_mii_phy(phy, 0x1f);
-       
+
        return 0;
 }
 
-static int bcm5411_suspend(struct mii_phy* phy, int wol_options)
+static int generic_suspend(struct mii_phy* phy)
 {
        phy_write(phy, MII_BMCR, BMCR_PDOWN);
 
@@ -276,10 +321,12 @@ static int bcm5411_suspend(struct mii_phy* phy, int wol_options)
 static int bcm5421_init(struct mii_phy* phy)
 {
        u16 data;
-       int rev;
+       unsigned int id;
 
-       rev = phy_read(phy, MII_PHYSID2) & 0x000f;
-       if (rev == 0) {
+       id = (phy_read(phy, MII_PHYSID1) << 16 | phy_read(phy, MII_PHYSID2));
+
+       /* Revision 0 of 5421 needs some fixups */
+       if (id == 0x002060e0) {
                /* This is borrowed from MacOS
                 */
                phy_write(phy, 0x18, 0x1007);
@@ -292,21 +339,52 @@ static int bcm5421_init(struct mii_phy* phy)
                data = phy_read(phy, 0x15);
                phy_write(phy, 0x15, data | 0x0200);
        }
-#if 0
-       /* This has to be verified before I enable it */
-       /* Enable automatic low-power */
-       phy_write(phy, 0x1c, 0x9002);
-       phy_write(phy, 0x1c, 0xa821);
-       phy_write(phy, 0x1c, 0x941d);
-#endif
+
+       /* Pick up some init code from OF for K2 version */
+       if ((id & 0xfffffff0) == 0x002062e0) {
+               phy_write(phy, 4, 0x01e1);
+               phy_write(phy, 9, 0x0300);
+       }
+
+       /* Check if we can enable automatic low power */
+#ifdef CONFIG_PPC_PMAC
+       if (phy->platform_data) {
+               struct device_node *np = of_get_parent(phy->platform_data);
+               int can_low_power = 1;
+               if (np == NULL || get_property(np, "no-autolowpower", NULL))
+                       can_low_power = 0;
+               if (can_low_power) {
+                       /* Enable automatic low-power */
+                       phy_write(phy, 0x1c, 0x9002);
+                       phy_write(phy, 0x1c, 0xa821);
+                       phy_write(phy, 0x1c, 0x941d);
+               }
+       }
+#endif /* CONFIG_PPC_PMAC */
+
+       return 0;
+}
+
+static int bcm5421_enable_fiber(struct mii_phy* phy)
+{
+       /* enable fiber mode */
+       phy_write(phy, MII_NCONFIG, 0x9020);
+       /* LEDs active in both modes, autosense prio = fiber */
+       phy_write(phy, MII_NCONFIG, 0x945f);
+
+       /* switch off fibre autoneg */
+       phy_write(phy, MII_NCONFIG, 0xfc01);
+       phy_write(phy, 0x0b, 0x0004);
+
        return 0;
 }
 
-static int bcm5421k2_init(struct mii_phy* phy)
+static int bcm5461_enable_fiber(struct mii_phy* phy)
 {
-       /* Init code borrowed from OF */
-       phy_write(phy, 4, 0x01e1);
-       phy_write(phy, 9, 0x0300);
+       phy_write(phy, MII_NCONFIG, 0xfc0c);
+       phy_write(phy, MII_BMCR, 0x4140);
+       phy_write(phy, MII_NCONFIG, 0xfc0b);
+       phy_write(phy, MII_BMCR, 0x0140);
 
        return 0;
 }
@@ -314,7 +392,7 @@ static int bcm5421k2_init(struct mii_phy* phy)
 static int bcm54xx_setup_aneg(struct mii_phy *phy, u32 advertise)
 {
        u16 ctl, adv;
-       
+
        phy->autoneg = 1;
        phy->speed = SPEED_10;
        phy->duplex = DUPLEX_HALF;
@@ -332,6 +410,10 @@ static int bcm54xx_setup_aneg(struct mii_phy *phy, u32 advertise)
                adv |= ADVERTISE_100HALF;
        if (advertise & ADVERTISED_100baseT_Full)
                adv |= ADVERTISE_100FULL;
+       if (advertise & ADVERTISED_Pause)
+               adv |= ADVERTISE_PAUSE_CAP;
+       if (advertise & ADVERTISED_Asym_Pause)
+               adv |= ADVERTISE_PAUSE_ASYM;
        phy_write(phy, MII_ADVERTISE, adv);
 
        /* Setup 1000BT advertise */
@@ -354,7 +436,7 @@ static int bcm54xx_setup_aneg(struct mii_phy *phy, u32 advertise)
 static int bcm54xx_setup_forced(struct mii_phy *phy, int speed, int fd)
 {
        u16 ctl;
-       
+
        phy->autoneg = 0;
        phy->speed = speed;
        phy->duplex = fd;
@@ -380,7 +462,7 @@ static int bcm54xx_setup_forced(struct mii_phy *phy, int speed, int fd)
                ctl |= BMCR_FULLDPLX;
 
        // XXX Should we set the sungem to GII now on 1000BT ?
-       
+
        phy_write(phy, MII_BMCR, ctl);
 
        return 0;
@@ -388,19 +470,22 @@ static int bcm54xx_setup_forced(struct mii_phy *phy, int speed, int fd)
 
 static int bcm54xx_read_link(struct mii_phy *phy)
 {
-       int link_mode;  
+       int link_mode;
        u16 val;
-       
+
        if (phy->autoneg) {
                val = phy_read(phy, MII_BCM5400_AUXSTATUS);
                link_mode = ((val & MII_BCM5400_AUXSTATUS_LINKMODE_MASK) >>
                             MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT);
-               phy->duplex = phy_BCM5400_link_table[link_mode][0] ? DUPLEX_FULL : DUPLEX_HALF;
+               phy->duplex = phy_BCM5400_link_table[link_mode][0] ?
+                       DUPLEX_FULL : DUPLEX_HALF;
                phy->speed = phy_BCM5400_link_table[link_mode][2] ?
                                SPEED_1000 :
-                               (phy_BCM5400_link_table[link_mode][1] ? SPEED_100 : SPEED_10);
+                               (phy_BCM5400_link_table[link_mode][1] ?
+                                SPEED_100 : SPEED_10);
                val = phy_read(phy, MII_LPA);
-               phy->pause = ((val & LPA_PAUSE) != 0);
+               phy->pause = (phy->duplex == DUPLEX_FULL) &&
+                       ((val & LPA_PAUSE) != 0);
        }
        /* On non-aneg, we assume what we put in BMCR is the speed,
         * though magic-aneg shouldn't prevent this case from occurring
@@ -409,10 +494,32 @@ static int bcm54xx_read_link(struct mii_phy *phy)
        return 0;
 }
 
+static int marvell88e1111_init(struct mii_phy* phy)
+{
+       u16 rev;
+
+       /* magic init sequence for rev 0 */
+       rev = phy_read(phy, MII_PHYSID2) & 0x000f;
+       if (rev == 0) {
+               phy_write(phy, 0x1d, 0x000a);
+               phy_write(phy, 0x1e, 0x0821);
+
+               phy_write(phy, 0x1d, 0x0006);
+               phy_write(phy, 0x1e, 0x8600);
+
+               phy_write(phy, 0x1d, 0x000b);
+               phy_write(phy, 0x1e, 0x0100);
+
+               phy_write(phy, 0x1d, 0x0004);
+               phy_write(phy, 0x1e, 0x4850);
+       }
+       return 0;
+}
+
 static int marvell_setup_aneg(struct mii_phy *phy, u32 advertise)
 {
        u16 ctl, adv;
-       
+
        phy->autoneg = 1;
        phy->speed = SPEED_10;
        phy->duplex = DUPLEX_HALF;
@@ -430,6 +537,10 @@ static int marvell_setup_aneg(struct mii_phy *phy, u32 advertise)
                adv |= ADVERTISE_100HALF;
        if (advertise & ADVERTISED_100baseT_Full)
                adv |= ADVERTISE_100FULL;
+       if (advertise & ADVERTISED_Pause)
+               adv |= ADVERTISE_PAUSE_CAP;
+       if (advertise & ADVERTISED_Asym_Pause)
+               adv |= ADVERTISE_PAUSE_ASYM;
        phy_write(phy, MII_ADVERTISE, adv);
 
        /* Setup 1000BT advertise & enable crossover detect
@@ -459,7 +570,7 @@ static int marvell_setup_aneg(struct mii_phy *phy, u32 advertise)
 static int marvell_setup_forced(struct mii_phy *phy, int speed, int fd)
 {
        u16 ctl, ctl2;
-       
+
        phy->autoneg = 0;
        phy->speed = speed;
        phy->duplex = fd;
@@ -500,7 +611,7 @@ static int marvell_setup_forced(struct mii_phy *phy, int speed, int fd)
        phy_write(phy, MII_1000BASETCONTROL, ctl2);
 
        // XXX Should we set the sungem to GII now on 1000BT ?
-       
+
        phy_write(phy, MII_BMCR, ctl);
 
        return 0;
@@ -508,7 +619,7 @@ static int marvell_setup_forced(struct mii_phy *phy, int speed, int fd)
 
 static int marvell_read_link(struct mii_phy *phy)
 {
-       u16 status;
+       u16 status, pmask;
 
        if (phy->autoneg) {
                status = phy_read(phy, MII_M1011_PHY_SPEC_STATUS);
@@ -524,7 +635,9 @@ static int marvell_read_link(struct mii_phy *phy)
                        phy->duplex = DUPLEX_FULL;
                else
                        phy->duplex = DUPLEX_HALF;
-               phy->pause = 0; /* XXX Check against spec ! */
+               pmask = MII_M1011_PHY_SPEC_STATUS_TX_PAUSE |
+                       MII_M1011_PHY_SPEC_STATUS_RX_PAUSE;
+               phy->pause = (status & pmask) == pmask;
        }
        /* On non-aneg, we assume what we put in BMCR is the speed,
         * though magic-aneg shouldn't prevent this case from occurring
@@ -536,7 +649,7 @@ static int marvell_read_link(struct mii_phy *phy)
 static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
 {
        u16 ctl, adv;
-       
+
        phy->autoneg = 1;
        phy->speed = SPEED_10;
        phy->duplex = DUPLEX_HALF;
@@ -554,6 +667,10 @@ static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
                adv |= ADVERTISE_100HALF;
        if (advertise & ADVERTISED_100baseT_Full)
                adv |= ADVERTISE_100FULL;
+       if (advertise & ADVERTISED_Pause)
+               adv |= ADVERTISE_PAUSE_CAP;
+       if (advertise & ADVERTISED_Asym_Pause)
+               adv |= ADVERTISE_PAUSE_ASYM;
        phy_write(phy, MII_ADVERTISE, adv);
 
        /* Start/Restart aneg */
@@ -567,7 +684,7 @@ static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
 static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd)
 {
        u16 ctl;
-       
+
        phy->autoneg = 0;
        phy->speed = speed;
        phy->duplex = fd;
@@ -600,7 +717,7 @@ static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd)
 static int genmii_poll_link(struct mii_phy *phy)
 {
        u16 status;
-       
+
        (void)phy_read(phy, MII_BMSR);
        status = phy_read(phy, MII_BMSR);
        if ((status & BMSR_LSTATUS) == 0)
@@ -625,7 +742,8 @@ static int genmii_read_link(struct mii_phy *phy)
                        phy->speed = SPEED_100;
                else
                        phy->speed = SPEED_10;
-               phy->pause = 0;
+               phy->pause = (phy->duplex == DUPLEX_FULL) &&
+                       ((lpa & LPA_PAUSE) != 0);
        }
        /* On non-aneg, we assume what we put in BMCR is the speed,
         * though magic-aneg shouldn't prevent this case from occurring
@@ -635,11 +753,19 @@ static int genmii_read_link(struct mii_phy *phy)
 }
 
 
-#define MII_BASIC_FEATURES     (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | \
-                                SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \
-                                SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII)
-#define MII_GBIT_FEATURES      (MII_BASIC_FEATURES | \
-                                SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full)
+#define MII_BASIC_FEATURES \
+       (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |      \
+        SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |    \
+        SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII |     \
+        SUPPORTED_Pause)
+
+/* On gigabit capable PHYs, we advertise Pause support but not asym pause
+ * support for now as I'm not sure it's supported and Darwin doesn't do
+ * it neither. --BenH.
+ */
+#define MII_GBIT_FEATURES \
+       (MII_BASIC_FEATURES |   \
+        SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full)
 
 /* Broadcom BCM 5201 */
 static struct mii_phy_ops bcm5201_phy_ops = {
@@ -662,7 +788,7 @@ static struct mii_phy_def bcm5201_phy_def = {
 
 /* Broadcom BCM 5221 */
 static struct mii_phy_ops bcm5221_phy_ops = {
-       .suspend        = bcm5201_suspend,
+       .suspend        = bcm5221_suspend,
        .init           = bcm5221_init,
        .setup_aneg     = genmii_setup_aneg,
        .setup_forced   = genmii_setup_forced,
@@ -679,6 +805,24 @@ static struct mii_phy_def bcm5221_phy_def = {
        .ops            = &bcm5221_phy_ops
 };
 
+/* Broadcom BCM 5241 */
+static struct mii_phy_ops bcm5241_phy_ops = {
+       .suspend        = bcm5241_suspend,
+       .init           = bcm5241_init,
+       .setup_aneg     = genmii_setup_aneg,
+       .setup_forced   = genmii_setup_forced,
+       .poll_link      = genmii_poll_link,
+       .read_link      = genmii_read_link,
+};
+static struct mii_phy_def bcm5241_phy_def = {
+       .phy_id         = 0x0143bc30,
+       .phy_id_mask    = 0xfffffff0,
+       .name           = "BCM5241",
+       .features       = MII_BASIC_FEATURES,
+       .magic_aneg     = 1,
+       .ops            = &bcm5241_phy_ops
+};
+
 /* Broadcom BCM 5400 */
 static struct mii_phy_ops bcm5400_phy_ops = {
        .init           = bcm5400_init,
@@ -720,7 +864,7 @@ static struct mii_phy_def bcm5401_phy_def = {
 /* Broadcom BCM 5411 */
 static struct mii_phy_ops bcm5411_phy_ops = {
        .init           = bcm5411_init,
-       .suspend        = bcm5411_suspend,
+       .suspend        = generic_suspend,
        .setup_aneg     = bcm54xx_setup_aneg,
        .setup_forced   = bcm54xx_setup_forced,
        .poll_link      = genmii_poll_link,
@@ -739,11 +883,12 @@ static struct mii_phy_def bcm5411_phy_def = {
 /* Broadcom BCM 5421 */
 static struct mii_phy_ops bcm5421_phy_ops = {
        .init           = bcm5421_init,
-       .suspend        = bcm5411_suspend,
+       .suspend        = generic_suspend,
        .setup_aneg     = bcm54xx_setup_aneg,
        .setup_forced   = bcm54xx_setup_forced,
        .poll_link      = genmii_poll_link,
        .read_link      = bcm54xx_read_link,
+       .enable_fiber   = bcm5421_enable_fiber,
 };
 
 static struct mii_phy_def bcm5421_phy_def = {
@@ -757,8 +902,8 @@ static struct mii_phy_def bcm5421_phy_def = {
 
 /* Broadcom BCM 5421 built-in K2 */
 static struct mii_phy_ops bcm5421k2_phy_ops = {
-       .init           = bcm5421k2_init,
-       .suspend        = bcm5411_suspend,
+       .init           = bcm5421_init,
+       .suspend        = generic_suspend,
        .setup_aneg     = bcm54xx_setup_aneg,
        .setup_forced   = bcm54xx_setup_forced,
        .poll_link      = genmii_poll_link,
@@ -774,24 +919,88 @@ static struct mii_phy_def bcm5421k2_phy_def = {
        .ops            = &bcm5421k2_phy_ops
 };
 
-/* Marvell 88E1101 (Apple seem to deal with 2 different revs,
- * I masked out the 8 last bits to get both, but some specs
- * would be useful here) --BenH.
- */
-static struct mii_phy_ops marvell_phy_ops = {
+static struct mii_phy_ops bcm5461_phy_ops = {
+       .init           = bcm5421_init,
+       .suspend        = generic_suspend,
+       .setup_aneg     = bcm54xx_setup_aneg,
+       .setup_forced   = bcm54xx_setup_forced,
+       .poll_link      = genmii_poll_link,
+       .read_link      = bcm54xx_read_link,
+       .enable_fiber   = bcm5461_enable_fiber,
+};
+
+static struct mii_phy_def bcm5461_phy_def = {
+       .phy_id         = 0x002060c0,
+       .phy_id_mask    = 0xfffffff0,
+       .name           = "BCM5461",
+       .features       = MII_GBIT_FEATURES,
+       .magic_aneg     = 1,
+       .ops            = &bcm5461_phy_ops
+};
+
+/* Broadcom BCM 5462 built-in Vesta */
+static struct mii_phy_ops bcm5462V_phy_ops = {
+       .init           = bcm5421_init,
+       .suspend        = generic_suspend,
+       .setup_aneg     = bcm54xx_setup_aneg,
+       .setup_forced   = bcm54xx_setup_forced,
+       .poll_link      = genmii_poll_link,
+       .read_link      = bcm54xx_read_link,
+};
+
+static struct mii_phy_def bcm5462V_phy_def = {
+       .phy_id         = 0x002060d0,
+       .phy_id_mask    = 0xfffffff0,
+       .name           = "BCM5462-Vesta",
+       .features       = MII_GBIT_FEATURES,
+       .magic_aneg     = 1,
+       .ops            = &bcm5462V_phy_ops
+};
+
+/* Marvell 88E1101 amd 88E1111 */
+static struct mii_phy_ops marvell88e1101_phy_ops = {
+       .suspend        = generic_suspend,
+       .setup_aneg     = marvell_setup_aneg,
+       .setup_forced   = marvell_setup_forced,
+       .poll_link      = genmii_poll_link,
+       .read_link      = marvell_read_link
+};
+
+static struct mii_phy_ops marvell88e1111_phy_ops = {
+       .init           = marvell88e1111_init,
+       .suspend        = generic_suspend,
        .setup_aneg     = marvell_setup_aneg,
        .setup_forced   = marvell_setup_forced,
        .poll_link      = genmii_poll_link,
        .read_link      = marvell_read_link
 };
 
-static struct mii_phy_def marvell_phy_def = {
-       .phy_id         = 0x01410c00,
-       .phy_id_mask    = 0xffffff00,
-       .name           = "Marvell 88E1101",
+/* two revs in darwin for the 88e1101 ... I could use a datasheet
+ * to get the proper names...
+ */
+static struct mii_phy_def marvell88e1101v1_phy_def = {
+       .phy_id         = 0x01410c20,
+       .phy_id_mask    = 0xfffffff0,
+       .name           = "Marvell 88E1101v1",
        .features       = MII_GBIT_FEATURES,
        .magic_aneg     = 1,
-       .ops            = &marvell_phy_ops
+       .ops            = &marvell88e1101_phy_ops
+};
+static struct mii_phy_def marvell88e1101v2_phy_def = {
+       .phy_id         = 0x01410c60,
+       .phy_id_mask    = 0xfffffff0,
+       .name           = "Marvell 88E1101v2",
+       .features       = MII_GBIT_FEATURES,
+       .magic_aneg     = 1,
+       .ops            = &marvell88e1101_phy_ops
+};
+static struct mii_phy_def marvell88e1111_phy_def = {
+       .phy_id         = 0x01410cc0,
+       .phy_id_mask    = 0xfffffff0,
+       .name           = "Marvell 88E1111",
+       .features       = MII_GBIT_FEATURES,
+       .magic_aneg     = 1,
+       .ops            = &marvell88e1111_phy_ops
 };
 
 /* Generic implementation for most 10/100 PHYs */
@@ -814,12 +1023,17 @@ static struct mii_phy_def genmii_phy_def = {
 static struct mii_phy_def* mii_phy_table[] = {
        &bcm5201_phy_def,
        &bcm5221_phy_def,
+       &bcm5241_phy_def,
        &bcm5400_phy_def,
        &bcm5401_phy_def,
        &bcm5411_phy_def,
        &bcm5421_phy_def,
        &bcm5421k2_phy_def,
-       &marvell_phy_def,
+       &bcm5461_phy_def,
+       &bcm5462V_phy_def,
+       &marvell88e1101v1_phy_def,
+       &marvell88e1101v2_phy_def,
+       &marvell88e1111_phy_def,
        &genmii_phy_def,
        NULL
 };
@@ -835,13 +1049,13 @@ int mii_phy_probe(struct mii_phy *phy, int mii_id)
         * may re-probe the PHY regulary
         */
        phy->mii_id = mii_id;
-       
+
        /* Take PHY out of isloate mode and reset it. */
        rc = reset_one_mii_phy(phy, mii_id);
        if (rc)
                goto fail;
 
-       /* Read ID and find matching entry */   
+       /* Read ID and find matching entry */
        id = (phy_read(phy, MII_PHYSID1) << 16 | phy_read(phy, MII_PHYSID2));
        printk(KERN_DEBUG "PHY ID: %x, addr: %x\n", id, mii_id);
        for (i=0; (def = mii_phy_table[i]) != NULL; i++)
@@ -852,7 +1066,7 @@ int mii_phy_probe(struct mii_phy *phy, int mii_id)
                goto fail;
 
        phy->def = def;
-       
+
        return 0;
 fail:
        phy->speed = 0;