+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;
+}
+
+#define BCM5421_MODE_MASK (1 << 5)
+
+static int bcm5421_poll_link(struct mii_phy* phy)
+{
+ u32 phy_reg;
+ int mode;
+
+ /* find out in what mode we are */
+ phy_write(phy, MII_NCONFIG, 0x1000);
+ phy_reg = phy_read(phy, MII_NCONFIG);
+
+ mode = (phy_reg & BCM5421_MODE_MASK) >> 5;
+
+ if ( mode == BCM54XX_COPPER)
+ return genmii_poll_link(phy);
+
+ /* try to find out wether we have a link */
+ phy_write(phy, MII_NCONFIG, 0x2000);
+ phy_reg = phy_read(phy, MII_NCONFIG);
+
+ if (phy_reg & 0x0020)
+ return 0;
+ else
+ return 1;
+}
+
+static int bcm5421_read_link(struct mii_phy* phy)
+{
+ u32 phy_reg;
+ int mode;
+
+ /* find out in what mode we are */
+ phy_write(phy, MII_NCONFIG, 0x1000);
+ phy_reg = phy_read(phy, MII_NCONFIG);
+
+ mode = (phy_reg & BCM5421_MODE_MASK ) >> 5;
+
+ if ( mode == BCM54XX_COPPER)
+ return bcm54xx_read_link(phy);
+
+ phy->speed = SPEED_1000;
+
+ /* find out wether we are running half- or full duplex */
+ phy_write(phy, MII_NCONFIG, 0x2000);
+ phy_reg = phy_read(phy, MII_NCONFIG);
+
+ if ( (phy_reg & 0x0080) >> 7)
+ phy->duplex |= DUPLEX_HALF;
+ else
+ phy->duplex |= DUPLEX_FULL;
+
+ return 0;
+}
+
+static int bcm5421_enable_fiber(struct mii_phy* phy, int autoneg)
+{
+ /* enable fiber mode */
+ phy_write(phy, MII_NCONFIG, 0x9020);
+ /* LEDs active in both modes, autosense prio = fiber */
+ phy_write(phy, MII_NCONFIG, 0x945f);
+
+ if (!autoneg) {
+ /* switch off fibre autoneg */
+ phy_write(phy, MII_NCONFIG, 0xfc01);
+ phy_write(phy, 0x0b, 0x0004);
+ }
+
+ phy->autoneg = autoneg;
+
+ return 0;
+}
+
+#define BCM5461_FIBER_LINK (1 << 2)
+#define BCM5461_MODE_MASK (3 << 1)
+
+static int bcm5461_poll_link(struct mii_phy* phy)
+{
+ u32 phy_reg;
+ int mode;
+
+ /* find out in what mode we are */
+ phy_write(phy, MII_NCONFIG, 0x7c00);
+ phy_reg = phy_read(phy, MII_NCONFIG);
+
+ mode = (phy_reg & BCM5461_MODE_MASK ) >> 1;
+
+ if ( mode == BCM54XX_COPPER)
+ return genmii_poll_link(phy);
+
+ /* find out wether we have a link */
+ phy_write(phy, MII_NCONFIG, 0x7000);
+ phy_reg = phy_read(phy, MII_NCONFIG);
+
+ if (phy_reg & BCM5461_FIBER_LINK)
+ return 1;
+ else
+ return 0;
+}
+
+#define BCM5461_FIBER_DUPLEX (1 << 3)
+
+static int bcm5461_read_link(struct mii_phy* phy)
+{
+ u32 phy_reg;
+ int mode;
+
+ /* find out in what mode we are */
+ phy_write(phy, MII_NCONFIG, 0x7c00);
+ phy_reg = phy_read(phy, MII_NCONFIG);
+
+ mode = (phy_reg & BCM5461_MODE_MASK ) >> 1;
+
+ if ( mode == BCM54XX_COPPER) {
+ return bcm54xx_read_link(phy);
+ }
+
+ phy->speed = SPEED_1000;
+
+ /* find out wether we are running half- or full duplex */
+ phy_write(phy, MII_NCONFIG, 0x7000);
+ phy_reg = phy_read(phy, MII_NCONFIG);
+
+ if (phy_reg & BCM5461_FIBER_DUPLEX)
+ phy->duplex |= DUPLEX_FULL;
+ else
+ phy->duplex |= DUPLEX_HALF;
+
+ return 0;
+}
+
+static int bcm5461_enable_fiber(struct mii_phy* phy, int autoneg)
+{
+ /* select fiber mode, enable 1000 base-X registers */
+ phy_write(phy, MII_NCONFIG, 0xfc0b);
+
+ if (autoneg) {
+ /* enable fiber with no autonegotiation */
+ phy_write(phy, MII_ADVERTISE, 0x01e0);
+ phy_write(phy, MII_BMCR, 0x1140);
+ } else {
+ /* enable fiber with autonegotiation */
+ phy_write(phy, MII_BMCR, 0x0140);
+ }
+
+ phy->autoneg = autoneg;
+
+ return 0;
+}
+