lan78xx: PHY DSP registers initialization to address EEE link drop issues with long...
authorRaghuram Chary J <raghuramchary.jallipalli@microchip.com>
Wed, 11 Apr 2018 15:06:36 +0000 (20:36 +0530)
committerDavid S. Miller <davem@davemloft.net>
Fri, 13 Apr 2018 01:46:10 +0000 (21:46 -0400)
The patch is to configure DSP registers of PHY device
to handle Gbe-EEE failures with >40m cable length.

Fixes: 55d7de9de6c3 ("Microchip's LAN7800 family USB 2/3 to 10/100/1000 Ethernet device driver")
Signed-off-by: Raghuram Chary J <raghuramchary.jallipalli@microchip.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/phy/microchip.c
include/linux/microchipphy.h

index 0f293ef289356b1639da4a6619b176b9f6c56da6..a97ac8c12c4cc227176fc013296676856979bdaa 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/ethtool.h>
 #include <linux/phy.h>
 #include <linux/microchipphy.h>
+#include <linux/delay.h>
 
 #define DRIVER_AUTHOR  "WOOJUNG HUH <woojung.huh@microchip.com>"
 #define DRIVER_DESC    "Microchip LAN88XX PHY driver"
@@ -30,6 +31,16 @@ struct lan88xx_priv {
        __u32   wolopts;
 };
 
+static int lan88xx_read_page(struct phy_device *phydev)
+{
+       return __phy_read(phydev, LAN88XX_EXT_PAGE_ACCESS);
+}
+
+static int lan88xx_write_page(struct phy_device *phydev, int page)
+{
+       return __phy_write(phydev, LAN88XX_EXT_PAGE_ACCESS, page);
+}
+
 static int lan88xx_phy_config_intr(struct phy_device *phydev)
 {
        int rc;
@@ -66,6 +77,150 @@ static int lan88xx_suspend(struct phy_device *phydev)
        return 0;
 }
 
+static int lan88xx_TR_reg_set(struct phy_device *phydev, u16 regaddr,
+                             u32 data)
+{
+       int val, save_page, ret = 0;
+       u16 buf;
+
+       /* Save current page */
+       save_page = phy_save_page(phydev);
+       if (save_page < 0) {
+               pr_warn("Failed to get current page\n");
+               goto err;
+       }
+
+       /* Switch to TR page */
+       lan88xx_write_page(phydev, LAN88XX_EXT_PAGE_ACCESS_TR);
+
+       ret = __phy_write(phydev, LAN88XX_EXT_PAGE_TR_LOW_DATA,
+                         (data & 0xFFFF));
+       if (ret < 0) {
+               pr_warn("Failed to write TR low data\n");
+               goto err;
+       }
+
+       ret = __phy_write(phydev, LAN88XX_EXT_PAGE_TR_HIGH_DATA,
+                         (data & 0x00FF0000) >> 16);
+       if (ret < 0) {
+               pr_warn("Failed to write TR high data\n");
+               goto err;
+       }
+
+       /* Config control bits [15:13] of register */
+       buf = (regaddr & ~(0x3 << 13));/* Clr [14:13] to write data in reg */
+       buf |= 0x8000; /* Set [15] to Packet transmit */
+
+       ret = __phy_write(phydev, LAN88XX_EXT_PAGE_TR_CR, buf);
+       if (ret < 0) {
+               pr_warn("Failed to write data in reg\n");
+               goto err;
+       }
+
+       usleep_range(1000, 2000);/* Wait for Data to be written */
+       val = __phy_read(phydev, LAN88XX_EXT_PAGE_TR_CR);
+       if (!(val & 0x8000))
+               pr_warn("TR Register[0x%X] configuration failed\n", regaddr);
+err:
+       return phy_restore_page(phydev, save_page, ret);
+}
+
+static void lan88xx_config_TR_regs(struct phy_device *phydev)
+{
+       int err;
+
+       /* Get access to Channel 0x1, Node 0xF , Register 0x01.
+        * Write 24-bit value 0x12B00A to register. Setting MrvlTrFix1000Kf,
+        * MrvlTrFix1000Kp, MasterEnableTR bits.
+        */
+       err = lan88xx_TR_reg_set(phydev, 0x0F82, 0x12B00A);
+       if (err < 0)
+               pr_warn("Failed to Set Register[0x0F82]\n");
+
+       /* Get access to Channel b'10, Node b'1101, Register 0x06.
+        * Write 24-bit value 0xD2C46F to register. Setting SSTrKf1000Slv,
+        * SSTrKp1000Mas bits.
+        */
+       err = lan88xx_TR_reg_set(phydev, 0x168C, 0xD2C46F);
+       if (err < 0)
+               pr_warn("Failed to Set Register[0x168C]\n");
+
+       /* Get access to Channel b'10, Node b'1111, Register 0x11.
+        * Write 24-bit value 0x620 to register. Setting rem_upd_done_thresh
+        * bits
+        */
+       err = lan88xx_TR_reg_set(phydev, 0x17A2, 0x620);
+       if (err < 0)
+               pr_warn("Failed to Set Register[0x17A2]\n");
+
+       /* Get access to Channel b'10, Node b'1101, Register 0x10.
+        * Write 24-bit value 0xEEFFDD to register. Setting
+        * eee_TrKp1Long_1000, eee_TrKp2Long_1000, eee_TrKp3Long_1000,
+        * eee_TrKp1Short_1000,eee_TrKp2Short_1000, eee_TrKp3Short_1000 bits.
+        */
+       err = lan88xx_TR_reg_set(phydev, 0x16A0, 0xEEFFDD);
+       if (err < 0)
+               pr_warn("Failed to Set Register[0x16A0]\n");
+
+       /* Get access to Channel b'10, Node b'1101, Register 0x13.
+        * Write 24-bit value 0x071448 to register. Setting
+        * slv_lpi_tr_tmr_val1, slv_lpi_tr_tmr_val2 bits.
+        */
+       err = lan88xx_TR_reg_set(phydev, 0x16A6, 0x071448);
+       if (err < 0)
+               pr_warn("Failed to Set Register[0x16A6]\n");
+
+       /* Get access to Channel b'10, Node b'1101, Register 0x12.
+        * Write 24-bit value 0x13132F to register. Setting
+        * slv_sigdet_timer_val1, slv_sigdet_timer_val2 bits.
+        */
+       err = lan88xx_TR_reg_set(phydev, 0x16A4, 0x13132F);
+       if (err < 0)
+               pr_warn("Failed to Set Register[0x16A4]\n");
+
+       /* Get access to Channel b'10, Node b'1101, Register 0x14.
+        * Write 24-bit value 0x0 to register. Setting eee_3level_delay,
+        * eee_TrKf_freeze_delay bits.
+        */
+       err = lan88xx_TR_reg_set(phydev, 0x16A8, 0x0);
+       if (err < 0)
+               pr_warn("Failed to Set Register[0x16A8]\n");
+
+       /* Get access to Channel b'01, Node b'1111, Register 0x34.
+        * Write 24-bit value 0x91B06C to register. Setting
+        * FastMseSearchThreshLong1000, FastMseSearchThreshShort1000,
+        * FastMseSearchUpdGain1000 bits.
+        */
+       err = lan88xx_TR_reg_set(phydev, 0x0FE8, 0x91B06C);
+       if (err < 0)
+               pr_warn("Failed to Set Register[0x0FE8]\n");
+
+       /* Get access to Channel b'01, Node b'1111, Register 0x3E.
+        * Write 24-bit value 0xC0A028 to register. Setting
+        * FastMseKp2ThreshLong1000, FastMseKp2ThreshShort1000,
+        * FastMseKp2UpdGain1000, FastMseKp2ExitEn1000 bits.
+        */
+       err = lan88xx_TR_reg_set(phydev, 0x0FFC, 0xC0A028);
+       if (err < 0)
+               pr_warn("Failed to Set Register[0x0FFC]\n");
+
+       /* Get access to Channel b'01, Node b'1111, Register 0x35.
+        * Write 24-bit value 0x041600 to register. Setting
+        * FastMseSearchPhShNum1000, FastMseSearchClksPerPh1000,
+        * FastMsePhChangeDelay1000 bits.
+        */
+       err = lan88xx_TR_reg_set(phydev, 0x0FEA, 0x041600);
+       if (err < 0)
+               pr_warn("Failed to Set Register[0x0FEA]\n");
+
+       /* Get access to Channel b'10, Node b'1101, Register 0x03.
+        * Write 24-bit value 0x000004 to register. Setting TrFreeze bits.
+        */
+       err = lan88xx_TR_reg_set(phydev, 0x1686, 0x000004);
+       if (err < 0)
+               pr_warn("Failed to Set Register[0x1686]\n");
+}
+
 static int lan88xx_probe(struct phy_device *phydev)
 {
        struct device *dev = &phydev->mdio.dev;
@@ -132,6 +287,25 @@ static void lan88xx_set_mdix(struct phy_device *phydev)
        phy_write(phydev, LAN88XX_EXT_PAGE_ACCESS, LAN88XX_EXT_PAGE_SPACE_0);
 }
 
+static int lan88xx_config_init(struct phy_device *phydev)
+{
+       int val;
+
+       genphy_config_init(phydev);
+       /*Zerodetect delay enable */
+       val = phy_read_mmd(phydev, MDIO_MMD_PCS,
+                          PHY_ARDENNES_MMD_DEV_3_PHY_CFG);
+       val |= PHY_ARDENNES_MMD_DEV_3_PHY_CFG_ZD_DLY_EN_;
+
+       phy_write_mmd(phydev, MDIO_MMD_PCS, PHY_ARDENNES_MMD_DEV_3_PHY_CFG,
+                     val);
+
+       /* Config DSP registers */
+       lan88xx_config_TR_regs(phydev);
+
+       return 0;
+}
+
 static int lan88xx_config_aneg(struct phy_device *phydev)
 {
        lan88xx_set_mdix(phydev);
@@ -151,7 +325,7 @@ static struct phy_driver microchip_phy_driver[] = {
        .probe          = lan88xx_probe,
        .remove         = lan88xx_remove,
 
-       .config_init    = genphy_config_init,
+       .config_init    = lan88xx_config_init,
        .config_aneg    = lan88xx_config_aneg,
 
        .ack_interrupt  = lan88xx_phy_ack_interrupt,
@@ -160,6 +334,8 @@ static struct phy_driver microchip_phy_driver[] = {
        .suspend        = lan88xx_suspend,
        .resume         = genphy_resume,
        .set_wol        = lan88xx_set_wol,
+       .read_page      = lan88xx_read_page,
+       .write_page     = lan88xx_write_page,
 } };
 
 module_phy_driver(microchip_phy_driver);
index eb492d47f7171fe4c6a18e2fbbc6f9234085ca5d..8f9c90379732b3a14ad7510ee1dad294f6d7feb9 100644 (file)
 #define        LAN88XX_MMD3_CHIP_ID                    (32877)
 #define        LAN88XX_MMD3_CHIP_REV                   (32878)
 
+/* DSP registers */
+#define PHY_ARDENNES_MMD_DEV_3_PHY_CFG         (0x806A)
+#define PHY_ARDENNES_MMD_DEV_3_PHY_CFG_ZD_DLY_EN_      (0x2000)
+#define LAN88XX_EXT_PAGE_ACCESS_TR             (0x52B5)
+#define LAN88XX_EXT_PAGE_TR_CR                 16
+#define LAN88XX_EXT_PAGE_TR_LOW_DATA           17
+#define LAN88XX_EXT_PAGE_TR_HIGH_DATA          18
+
 #endif /* _MICROCHIPPHY_H */