[XFS] Fix merge failures
[pandora-kernel.git] / drivers / net / phy / broadcom.c
index 4b4dc98..190efc3 100644 (file)
@@ -17,6 +17,8 @@
 #include <linux/module.h>
 #include <linux/phy.h>
 
+#define PHY_ID_BCM50610                0x0143bd60
+
 #define MII_BCM54XX_ECR                0x10    /* BCM54xx extended control register */
 #define MII_BCM54XX_ECR_IM     0x1000  /* Interrupt mask */
 #define MII_BCM54XX_ECR_IF     0x0800  /* Interrupt force */
 #define MII_BCM54XX_SHD_VAL(x) ((x & 0x1f) << 10)
 #define MII_BCM54XX_SHD_DATA(x)        ((x & 0x3ff) << 0)
 
+/*
+ * AUXILIARY CONTROL SHADOW ACCESS REGISTERS.  (PHY REG 0x18)
+ */
+#define MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL      0x0000
+#define MII_BCM54XX_AUXCTL_ACTL_TX_6DB         0x0400
+#define MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA      0x0800
+
+#define MII_BCM54XX_AUXCTL_MISC_WREN   0x8000
+#define MII_BCM54XX_AUXCTL_MISC_FORCE_AMDIX    0x0200
+#define MII_BCM54XX_AUXCTL_MISC_RDSEL_MISC     0x7000
+#define MII_BCM54XX_AUXCTL_SHDWSEL_MISC        0x0007
+
+#define MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL      0x0000
+
+
 /*
  * Broadcom LED source encodings.  These are used in BCM5461, BCM5481,
  * BCM5482, and possibly some others.
 #define BCM5482_SHD_MODE       0x1f    /* 11111: Mode Control Register */
 #define BCM5482_SHD_MODE_1000BX        0x0001  /* Enable 1000BASE-X registers */
 
+/*
+ * EXPANSION SHADOW ACCESS REGISTERS.  (PHY REG 0x15, 0x16, and 0x17)
+ */
+#define MII_BCM54XX_EXP_AADJ1CH0               0x001f
+#define  MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN 0x0200
+#define  MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF   0x0100
+#define MII_BCM54XX_EXP_AADJ1CH3               0x601f
+#define  MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ     0x0002
+#define MII_BCM54XX_EXP_EXP08                  0x0F08
+#define  MII_BCM54XX_EXP_EXP08_RJCT_2MHZ       0x0001
+#define  MII_BCM54XX_EXP_EXP08_EARLY_DAC_WAKE  0x0200
+#define MII_BCM54XX_EXP_EXP75                  0x0f75
+#define  MII_BCM54XX_EXP_EXP75_VDACCTRL                0x003c
+#define MII_BCM54XX_EXP_EXP96                  0x0f96
+#define  MII_BCM54XX_EXP_EXP96_MYST            0x0010
+#define MII_BCM54XX_EXP_EXP97                  0x0f97
+#define  MII_BCM54XX_EXP_EXP97_MYST            0x0c0c
+
 /*
  * BCM5482: Secondary SerDes registers
  */
@@ -128,40 +163,93 @@ static int bcm54xx_shadow_write(struct phy_device *phydev, u16 shadow, u16 val)
                         MII_BCM54XX_SHD_DATA(val));
 }
 
-/*
- * Indirect register access functions for the Expansion Registers
- * and Secondary SerDes registers (when sec_serdes=1).
- */
-static int bcm54xx_exp_read(struct phy_device *phydev,
-                           int sec_serdes, u8 regnum)
+/* Indirect register access functions for the Expansion Registers */
+static int bcm54xx_exp_read(struct phy_device *phydev, u8 regnum)
 {
        int val;
 
-       phy_write(phydev, MII_BCM54XX_EXP_SEL,
-                 (sec_serdes ? MII_BCM54XX_EXP_SEL_SSD :
-                               MII_BCM54XX_EXP_SEL_ER) |
-                 regnum);
+       val = phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum);
+       if (val < 0)
+               return val;
+
        val = phy_read(phydev, MII_BCM54XX_EXP_DATA);
-       phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum);
+
+       /* Restore default value.  It's O.K. if this write fails. */
+       phy_write(phydev, MII_BCM54XX_EXP_SEL, 0);
 
        return val;
 }
 
-static int bcm54xx_exp_write(struct phy_device *phydev,
-                            int sec_serdes, u8 regnum, u16 val)
+static int bcm54xx_exp_write(struct phy_device *phydev, u16 regnum, u16 val)
 {
        int ret;
 
-       phy_write(phydev, MII_BCM54XX_EXP_SEL,
-                 (sec_serdes ? MII_BCM54XX_EXP_SEL_SSD :
-                               MII_BCM54XX_EXP_SEL_ER) |
-                 regnum);
+       ret = phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum);
+       if (ret < 0)
+               return ret;
+
        ret = phy_write(phydev, MII_BCM54XX_EXP_DATA, val);
-       phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum);
+
+       /* Restore default value.  It's O.K. if this write fails. */
+       phy_write(phydev, MII_BCM54XX_EXP_SEL, 0);
 
        return ret;
 }
 
+static int bcm54xx_auxctl_write(struct phy_device *phydev, u16 regnum, u16 val)
+{
+       return phy_write(phydev, MII_BCM54XX_AUX_CTL, regnum | val);
+}
+
+static int bcm50610_a0_workaround(struct phy_device *phydev)
+{
+       int err;
+
+       err = bcm54xx_auxctl_write(phydev,
+                                  MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL,
+                                  MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA |
+                                  MII_BCM54XX_AUXCTL_ACTL_TX_6DB);
+       if (err < 0)
+               return err;
+
+       err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP08,
+                               MII_BCM54XX_EXP_EXP08_RJCT_2MHZ |
+                               MII_BCM54XX_EXP_EXP08_EARLY_DAC_WAKE);
+       if (err < 0)
+               goto error;
+
+       err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_AADJ1CH0,
+                               MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN |
+                               MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF);
+       if (err < 0)
+               goto error;
+
+       err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_AADJ1CH3,
+                                       MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ);
+       if (err < 0)
+               goto error;
+
+       err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP75,
+                               MII_BCM54XX_EXP_EXP75_VDACCTRL);
+       if (err < 0)
+               goto error;
+
+       err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP96,
+                               MII_BCM54XX_EXP_EXP96_MYST);
+       if (err < 0)
+               goto error;
+
+       err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP97,
+                               MII_BCM54XX_EXP_EXP97_MYST);
+
+error:
+       bcm54xx_auxctl_write(phydev,
+                            MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL,
+                            MII_BCM54XX_AUXCTL_ACTL_TX_6DB);
+
+       return err;
+}
+
 static int bcm54xx_config_init(struct phy_device *phydev)
 {
        int reg, err;
@@ -183,6 +271,13 @@ static int bcm54xx_config_init(struct phy_device *phydev)
        err = phy_write(phydev, MII_BCM54XX_IMR, reg);
        if (err < 0)
                return err;
+
+       if (phydev->drv->phy_id == PHY_ID_BCM50610) {
+               err = bcm50610_a0_workaround(phydev);
+               if (err < 0)
+                       return err;
+       }
+
        return 0;
 }
 
@@ -205,18 +300,27 @@ static int bcm5482_config_init(struct phy_device *phydev)
                /*
                 * Enable SGMII slave mode and auto-detection
                 */
-               reg = bcm54xx_exp_read(phydev, 1, BCM5482_SSD_SGMII_SLAVE);
-               bcm54xx_exp_write(phydev, 1, BCM5482_SSD_SGMII_SLAVE,
-                                 reg |
-                                 BCM5482_SSD_SGMII_SLAVE_EN |
-                                 BCM5482_SSD_SGMII_SLAVE_AD);
+               reg = BCM5482_SSD_SGMII_SLAVE | MII_BCM54XX_EXP_SEL_SSD;
+               err = bcm54xx_exp_read(phydev, reg);
+               if (err < 0)
+                       return err;
+               err = bcm54xx_exp_write(phydev, reg, err |
+                                       BCM5482_SSD_SGMII_SLAVE_EN |
+                                       BCM5482_SSD_SGMII_SLAVE_AD);
+               if (err < 0)
+                       return err;
 
                /*
                 * Disable secondary SerDes powerdown
                 */
-               reg = bcm54xx_exp_read(phydev, 1, BCM5482_SSD_1000BX_CTL);
-               bcm54xx_exp_write(phydev, 1, BCM5482_SSD_1000BX_CTL,
-                                 reg & ~BCM5482_SSD_1000BX_CTL_PWRDOWN);
+               reg = BCM5482_SSD_1000BX_CTL | MII_BCM54XX_EXP_SEL_SSD;
+               err = bcm54xx_exp_read(phydev, reg);
+               if (err < 0)
+                       return err;
+               err = bcm54xx_exp_write(phydev, reg,
+                                       err & ~BCM5482_SSD_1000BX_CTL_PWRDOWN);
+               if (err < 0)
+                       return err;
 
                /*
                 * Select 1000BASE-X register set (primary SerDes)
@@ -335,7 +439,8 @@ static struct phy_driver bcm5411_driver = {
        .phy_id         = 0x00206070,
        .phy_id_mask    = 0xfffffff0,
        .name           = "Broadcom BCM5411",
-       .features       = PHY_GBIT_FEATURES,
+       .features       = PHY_GBIT_FEATURES |
+                         SUPPORTED_Pause | SUPPORTED_Asym_Pause,
        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
        .config_init    = bcm54xx_config_init,
        .config_aneg    = genphy_config_aneg,
@@ -349,7 +454,8 @@ static struct phy_driver bcm5421_driver = {
        .phy_id         = 0x002060e0,
        .phy_id_mask    = 0xfffffff0,
        .name           = "Broadcom BCM5421",
-       .features       = PHY_GBIT_FEATURES,
+       .features       = PHY_GBIT_FEATURES |
+                         SUPPORTED_Pause | SUPPORTED_Asym_Pause,
        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
        .config_init    = bcm54xx_config_init,
        .config_aneg    = genphy_config_aneg,
@@ -363,7 +469,8 @@ static struct phy_driver bcm5461_driver = {
        .phy_id         = 0x002060c0,
        .phy_id_mask    = 0xfffffff0,
        .name           = "Broadcom BCM5461",
-       .features       = PHY_GBIT_FEATURES,
+       .features       = PHY_GBIT_FEATURES |
+                         SUPPORTED_Pause | SUPPORTED_Asym_Pause,
        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
        .config_init    = bcm54xx_config_init,
        .config_aneg    = genphy_config_aneg,
@@ -377,7 +484,8 @@ static struct phy_driver bcm5464_driver = {
        .phy_id         = 0x002060b0,
        .phy_id_mask    = 0xfffffff0,
        .name           = "Broadcom BCM5464",
-       .features       = PHY_GBIT_FEATURES,
+       .features       = PHY_GBIT_FEATURES |
+                         SUPPORTED_Pause | SUPPORTED_Asym_Pause,
        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
        .config_init    = bcm54xx_config_init,
        .config_aneg    = genphy_config_aneg,
@@ -391,7 +499,8 @@ static struct phy_driver bcm5481_driver = {
        .phy_id         = 0x0143bca0,
        .phy_id_mask    = 0xfffffff0,
        .name           = "Broadcom BCM5481",
-       .features       = PHY_GBIT_FEATURES,
+       .features       = PHY_GBIT_FEATURES |
+                         SUPPORTED_Pause | SUPPORTED_Asym_Pause,
        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
        .config_init    = bcm54xx_config_init,
        .config_aneg    = bcm5481_config_aneg,
@@ -405,7 +514,8 @@ static struct phy_driver bcm5482_driver = {
        .phy_id         = 0x0143bcb0,
        .phy_id_mask    = 0xfffffff0,
        .name           = "Broadcom BCM5482",
-       .features       = PHY_GBIT_FEATURES,
+       .features       = PHY_GBIT_FEATURES |
+                         SUPPORTED_Pause | SUPPORTED_Asym_Pause,
        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
        .config_init    = bcm5482_config_init,
        .config_aneg    = genphy_config_aneg,
@@ -415,6 +525,36 @@ static struct phy_driver bcm5482_driver = {
        .driver         = { .owner = THIS_MODULE },
 };
 
+static struct phy_driver bcm50610_driver = {
+       .phy_id         = PHY_ID_BCM50610,
+       .phy_id_mask    = 0xfffffff0,
+       .name           = "Broadcom BCM50610",
+       .features       = PHY_GBIT_FEATURES |
+                         SUPPORTED_Pause | SUPPORTED_Asym_Pause,
+       .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+       .config_init    = bcm54xx_config_init,
+       .config_aneg    = genphy_config_aneg,
+       .read_status    = genphy_read_status,
+       .ack_interrupt  = bcm54xx_ack_interrupt,
+       .config_intr    = bcm54xx_config_intr,
+       .driver         = { .owner = THIS_MODULE },
+};
+
+static struct phy_driver bcm57780_driver = {
+       .phy_id         = 0x03625d90,
+       .phy_id_mask    = 0xfffffff0,
+       .name           = "Broadcom BCM57780",
+       .features       = PHY_GBIT_FEATURES |
+                         SUPPORTED_Pause | SUPPORTED_Asym_Pause,
+       .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+       .config_init    = bcm54xx_config_init,
+       .config_aneg    = genphy_config_aneg,
+       .read_status    = genphy_read_status,
+       .ack_interrupt  = bcm54xx_ack_interrupt,
+       .config_intr    = bcm54xx_config_intr,
+       .driver         = { .owner = THIS_MODULE },
+};
+
 static int __init broadcom_init(void)
 {
        int ret;
@@ -437,8 +577,18 @@ static int __init broadcom_init(void)
        ret = phy_driver_register(&bcm5482_driver);
        if (ret)
                goto out_5482;
+       ret = phy_driver_register(&bcm50610_driver);
+       if (ret)
+               goto out_50610;
+       ret = phy_driver_register(&bcm57780_driver);
+       if (ret)
+               goto out_57780;
        return ret;
 
+out_57780:
+       phy_driver_unregister(&bcm50610_driver);
+out_50610:
+       phy_driver_unregister(&bcm5482_driver);
 out_5482:
        phy_driver_unregister(&bcm5481_driver);
 out_5481:
@@ -455,6 +605,8 @@ out_5411:
 
 static void __exit broadcom_exit(void)
 {
+       phy_driver_unregister(&bcm57780_driver);
+       phy_driver_unregister(&bcm50610_driver);
        phy_driver_unregister(&bcm5482_driver);
        phy_driver_unregister(&bcm5481_driver);
        phy_driver_unregister(&bcm5464_driver);