Add BCM5221 phy support.

Sponsored by: Tekvox Inc.
Cc: Jim Reinhart <j...@tekvox.com>
Cc: James Autry <jau...@tekvox.com>
Cc: Matthew Maron <matth...@tekvox.com>
Signed-off-by: Giulio Benetti <giulio.bene...@benettiengineering.com>
---
 drivers/net/phy/broadcom.c | 99 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 99 insertions(+)

diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c
index 36c70da181..a1996e6059 100644
--- a/drivers/net/phy/broadcom.c
+++ b/drivers/net/phy/broadcom.c
@@ -34,6 +34,26 @@
 
 #define MIIM_BCM_CHANNEL_WIDTH    0x2000
 
+#define MII_BCM5221_INTREG             0x1a    /* Interrupt register */
+#define MII_BCM5221_IR_MASK            0x0100  /* Mask all interrupts */
+#define MII_BCM5221_IR_LINK_EN         0x0200  /* Link status change enable */
+#define MII_BCM5221_IR_SPEED_EN        0x0400  /* Link speed change enable */
+#define MII_BCM5221_IR_DUPLEX_EN       0x0800  /* Duplex mode change enable */
+#define MII_BCM5221_IR_ENABLE          0x4000  /* Interrupt enable */
+
+#define MII_BCM5221_BRCMTEST           0x1f    /* Brcm test register */
+#define MII_BCM5221_BT_SRE             0x0080  /* Shadow register enable */
+
+#define MII_BCM5221_AE_GSR             0x1c    /* BCM5221 Auxiliary Error &
+                                                * General Status Register
+                                                */
+#define MII_BCM5221_AE_GSR_DIS_MDIX    0x0800  /* BCM5221 Disable MDIX */
+#define MII_BCM5221_SHDW_AM4_FLPM      0x0002  /* BCM5221 Force Low Power
+                                                * Mode
+                                                */
+
+#define MII_BCM5221_SHDW_AUXMODE4      0x1a    /* Auxiliary mode 4 */
+
 static void bcm_phy_write_misc(struct phy_device *phydev,
                               u16 reg, u16 chl, u16 value)
 {
@@ -311,6 +331,75 @@ static int bcm5482_startup(struct phy_device *phydev)
        return bcm54xx_parse_status(phydev);
 }
 
+static int bcm_bcm5221_config(struct phy_device *phydev)
+{
+       int reg, err, err2, brcmtest;
+
+       phy_reset(phydev);
+
+       /* The datasheet indicates the PHY needs up to 1us to complete a reset,
+        * build some slack here.
+        */
+       udelay(2000);
+
+       /* The PHY requires 65 MDC clock cycles to complete a write operation
+        * and turnaround the line properly.
+        *
+        * We ignore -EIO here as the MDIO controller (e.g.: mdio-bcm-unimac)
+        * may flag the lack of turn-around as a read failure. This is
+        * particularly true with this combination since the MDIO controller
+        * only used 64 MDC cycles. This is not a critical failure in this
+        * specific case and it has no functional impact otherwise, so we let
+        * that one go through. If there is a genuine bus error, the next read
+        * of MII_BCM5221_INTREG will error out.
+        */
+       err = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
+       if (err < 0 && err != -EIO)
+               return err;
+
+       reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BCM5221_INTREG);
+       if (reg < 0)
+               return reg;
+
+       /* Mask interrupts globally since we don't use interrupt */
+       reg = MII_BCM5221_IR_MASK;
+
+       err = phy_write(phydev, MDIO_DEVAD_NONE, MII_BCM5221_INTREG, reg);
+       if (err < 0)
+               return err;
+
+       /* Enable auto MDIX */
+       err = phy_modify(phydev, MDIO_DEVAD_NONE, MII_BCM5221_AE_GSR,
+                        MII_BCM5221_AE_GSR_DIS_MDIX, 0);
+       if (err < 0)
+               return err;
+
+       /* Enable shadow register access */
+       brcmtest = phy_read(phydev, MDIO_DEVAD_NONE, MII_BCM5221_BRCMTEST);
+       if (brcmtest < 0)
+               return brcmtest;
+
+       reg = brcmtest | MII_BCM5221_BT_SRE;
+
+       err = phy_write(phydev, MDIO_DEVAD_NONE, MII_BCM5221_BRCMTEST, reg);
+       if (err < 0)
+               return err;
+
+       /* Exit low power mode */
+       err = phy_modify(phydev, MDIO_DEVAD_NONE, MII_BCM5221_SHDW_AUXMODE4,
+                        MII_BCM5221_SHDW_AM4_FLPM, 0);
+       if (err < 0)
+               goto done;
+
+done:
+       /* Disable shadow register access */
+       err2 = phy_write(phydev, MDIO_DEVAD_NONE, MII_BCM5221_BRCMTEST, 
brcmtest);
+       if (!err)
+               err = err2;
+
+       return err;
+}
+
 U_BOOT_PHY_DRIVER(bcm5461s) = {
        .name = "Broadcom BCM5461S",
        .uid = 0x2060c0,
@@ -350,3 +439,13 @@ U_BOOT_PHY_DRIVER(bcm_cygnus) = {
        .startup = &genphy_startup,
        .shutdown = &genphy_shutdown,
 };
+
+U_BOOT_PHY_DRIVER(BCM5221_driver) = {
+       .name = "Broadcom BCM5221 PHY",
+       .uid = 0x004061e0,
+       .mask = 0xfffff0,
+       .features = PHY_BASIC_FEATURES,
+       .config = &bcm_bcm5221_config,
+       .startup = &genphy_startup,
+       .shutdown = &genphy_shutdown,
+};
-- 
2.34.1

Reply via email to