]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
net: phy: broadcom: Set proper 1000BaseX/SGMII interface mode for BCM54616S
authorRobert Hancock <robert.hancock@calian.com>
Tue, 16 Feb 2021 22:54:52 +0000 (16:54 -0600)
committerSeth Forshee <seth.forshee@canonical.com>
Thu, 8 Apr 2021 20:42:40 +0000 (15:42 -0500)
BugLink: https://bugs.launchpad.net/bugs/1922601
[ Upstream commit 3afd0218992a8d1398e9791d6c2edd4c948ae7ee ]

The default configuration for the BCM54616S PHY may not match the desired
mode when using 1000BaseX or SGMII interface modes, such as when it is on
an SFP module. Add code to explicitly set the correct mode using
programming sequences provided by Bel-Fuse:

https://www.belfuse.com/resources/datasheets/powersolutions/ds-bps-sfp-1gbt-05-series.pdf
https://www.belfuse.com/resources/datasheets/powersolutions/ds-bps-sfp-1gbt-06-series.pdf

Signed-off-by: Robert Hancock <robert.hancock@calian.com>
Acked-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
drivers/net/phy/broadcom.c
include/linux/brcmphy.h

index 407626ddcae732b9d303b8b51e4cba67857e8249..b160186dc766478b8b689b086718132959e93a03 100644 (file)
@@ -103,6 +103,64 @@ static int bcm54612e_config_init(struct phy_device *phydev)
        return 0;
 }
 
+static int bcm54616s_config_init(struct phy_device *phydev)
+{
+       int rc, val;
+
+       if (phydev->interface != PHY_INTERFACE_MODE_SGMII &&
+           phydev->interface != PHY_INTERFACE_MODE_1000BASEX)
+               return 0;
+
+       /* Ensure proper interface mode is selected. */
+       /* Disable RGMII mode */
+       val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
+       if (val < 0)
+               return val;
+       val &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_EN;
+       val |= MII_BCM54XX_AUXCTL_MISC_WREN;
+       rc = bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC,
+                                 val);
+       if (rc < 0)
+               return rc;
+
+       /* Select 1000BASE-X register set (primary SerDes) */
+       val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_MODE);
+       if (val < 0)
+               return val;
+       val |= BCM54XX_SHD_MODE_1000BX;
+       rc = bcm_phy_write_shadow(phydev, BCM54XX_SHD_MODE, val);
+       if (rc < 0)
+               return rc;
+
+       /* Power down SerDes interface */
+       rc = phy_set_bits(phydev, MII_BMCR, BMCR_PDOWN);
+       if (rc < 0)
+               return rc;
+
+       /* Select proper interface mode */
+       val &= ~BCM54XX_SHD_INTF_SEL_MASK;
+       val |= phydev->interface == PHY_INTERFACE_MODE_SGMII ?
+               BCM54XX_SHD_INTF_SEL_SGMII :
+               BCM54XX_SHD_INTF_SEL_GBIC;
+       rc = bcm_phy_write_shadow(phydev, BCM54XX_SHD_MODE, val);
+       if (rc < 0)
+               return rc;
+
+       /* Power up SerDes interface */
+       rc = phy_clear_bits(phydev, MII_BMCR, BMCR_PDOWN);
+       if (rc < 0)
+               return rc;
+
+       /* Select copper register set */
+       val &= ~BCM54XX_SHD_MODE_1000BX;
+       rc = bcm_phy_write_shadow(phydev, BCM54XX_SHD_MODE, val);
+       if (rc < 0)
+               return rc;
+
+       /* Power up copper interface */
+       return phy_clear_bits(phydev, MII_BMCR, BMCR_PDOWN);
+}
+
 /* Needs SMDSP clock enabled via bcm54xx_phydsp_config() */
 static int bcm50610_a0_workaround(struct phy_device *phydev)
 {
@@ -281,15 +339,17 @@ static int bcm54xx_config_init(struct phy_device *phydev)
 
        bcm54xx_adjust_rxrefclk(phydev);
 
-       if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54210E) {
+       switch (BRCM_PHY_MODEL(phydev)) {
+       case PHY_ID_BCM54210E:
                err = bcm54210e_config_init(phydev);
-               if (err)
-                       return err;
-       } else if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54612E) {
+               break;
+       case PHY_ID_BCM54612E:
                err = bcm54612e_config_init(phydev);
-               if (err)
-                       return err;
-       } else if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54810) {
+               break;
+       case PHY_ID_BCM54616S:
+               err = bcm54616s_config_init(phydev);
+               break;
+       case PHY_ID_BCM54810:
                /* For BCM54810, we need to disable BroadR-Reach function */
                val = bcm_phy_read_exp(phydev,
                                       BCM54810_EXP_BROADREACH_LRE_MISC_CTL);
@@ -297,9 +357,10 @@ static int bcm54xx_config_init(struct phy_device *phydev)
                err = bcm_phy_write_exp(phydev,
                                        BCM54810_EXP_BROADREACH_LRE_MISC_CTL,
                                        val);
-               if (err < 0)
-                       return err;
+               break;
        }
+       if (err)
+               return err;
 
        bcm54xx_phydsp_config(phydev);
 
@@ -478,7 +539,7 @@ static int bcm5481_config_aneg(struct phy_device *phydev)
 
 static int bcm54616s_probe(struct phy_device *phydev)
 {
-       int val, intf_sel;
+       int val;
 
        val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_MODE);
        if (val < 0)
@@ -490,8 +551,7 @@ static int bcm54616s_probe(struct phy_device *phydev)
         * RGMII-1000Base-X is properly supported, but RGMII-100Base-FX
         * support is still missing as of now.
         */
-       intf_sel = (val & BCM54XX_SHD_INTF_SEL_MASK) >> 1;
-       if (intf_sel == 1) {
+       if ((val & BCM54XX_SHD_INTF_SEL_MASK) == BCM54XX_SHD_INTF_SEL_RGMII) {
                val = bcm_phy_read_shadow(phydev, BCM54616S_SHD_100FX_CTRL);
                if (val < 0)
                        return val;
index d0bd226d6bd9617c6a35a920f4e0cb92fa679054..54665952d6ade6dccae69bdc6ea8daa3080cd2f0 100644 (file)
 
 #define MII_BCM54XX_AUXCTL_SHDWSEL_MISC                        0x07
 #define MII_BCM54XX_AUXCTL_SHDWSEL_MISC_WIRESPEED_EN   0x0010
+#define MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_EN       0x0080
 #define MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN  0x0100
 #define MII_BCM54XX_AUXCTL_MISC_FORCE_AMDIX            0x0200
 #define MII_BCM54XX_AUXCTL_MISC_WREN                   0x8000
 /* 11111: Mode Control Register */
 #define BCM54XX_SHD_MODE               0x1f
 #define BCM54XX_SHD_INTF_SEL_MASK      GENMASK(2, 1)   /* INTERF_SEL[1:0] */
+#define BCM54XX_SHD_INTF_SEL_RGMII     0x02
+#define BCM54XX_SHD_INTF_SEL_SGMII     0x04
+#define BCM54XX_SHD_INTF_SEL_GBIC      0x06
 #define BCM54XX_SHD_MODE_1000BX                BIT(0)  /* Enable 1000-X registers */
 
 /*