]> git.baikalelectronics.ru Git - kernel.git/commitdiff
net: phy: at803x: Support downstream SFP cage
authorRobert Hancock <robert.hancock@calian.com>
Tue, 25 Jan 2022 16:54:10 +0000 (10:54 -0600)
committerDavid S. Miller <davem@davemloft.net>
Thu, 27 Jan 2022 13:28:20 +0000 (13:28 +0000)
Add support for downstream SFP cages for AR8031 and AR8033. This is
primarily intended for fiber modules or direct-attach cables, however
copper modules which work in 1000Base-X mode may also function. Such
modules are allowed with a warning.

Signed-off-by: Robert Hancock <robert.hancock@calian.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/phy/at803x.c

index 3f3d4c164df402b70a0dd6e75dab211c70e36977..f504fe536fe4f2dfcdafb527e92ed7a6e1b57bb9 100644 (file)
@@ -19,6 +19,8 @@
 #include <linux/regulator/of_regulator.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/consumer.h>
+#include <linux/phylink.h>
+#include <linux/sfp.h>
 #include <dt-bindings/net/qca-ar803x.h>
 
 #define AT803X_SPECIFIC_FUNCTION_CONTROL       0x10
@@ -664,6 +666,55 @@ static int at8031_register_regulators(struct phy_device *phydev)
        return 0;
 }
 
+static int at803x_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
+{
+       struct phy_device *phydev = upstream;
+       __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_support);
+       __ETHTOOL_DECLARE_LINK_MODE_MASK(sfp_support);
+       phy_interface_t iface;
+
+       linkmode_zero(phy_support);
+       phylink_set(phy_support, 1000baseX_Full);
+       phylink_set(phy_support, 1000baseT_Full);
+       phylink_set(phy_support, Autoneg);
+       phylink_set(phy_support, Pause);
+       phylink_set(phy_support, Asym_Pause);
+
+       linkmode_zero(sfp_support);
+       sfp_parse_support(phydev->sfp_bus, id, sfp_support);
+       /* Some modules support 10G modes as well as others we support.
+        * Mask out non-supported modes so the correct interface is picked.
+        */
+       linkmode_and(sfp_support, phy_support, sfp_support);
+
+       if (linkmode_empty(sfp_support)) {
+               dev_err(&phydev->mdio.dev, "incompatible SFP module inserted\n");
+               return -EINVAL;
+       }
+
+       iface = sfp_select_interface(phydev->sfp_bus, sfp_support);
+
+       /* Only 1000Base-X is supported by AR8031/8033 as the downstream SerDes
+        * interface for use with SFP modules.
+        * However, some copper modules detected as having a preferred SGMII
+        * interface do default to and function in 1000Base-X mode, so just
+        * print a warning and allow such modules, as they may have some chance
+        * of working.
+        */
+       if (iface == PHY_INTERFACE_MODE_SGMII)
+               dev_warn(&phydev->mdio.dev, "module may not function if 1000Base-X not supported\n");
+       else if (iface != PHY_INTERFACE_MODE_1000BASEX)
+               return -EINVAL;
+
+       return 0;
+}
+
+static const struct sfp_upstream_ops at803x_sfp_ops = {
+       .attach = phy_sfp_attach,
+       .detach = phy_sfp_detach,
+       .module_insert = at803x_sfp_insert,
+};
+
 static int at803x_parse_dt(struct phy_device *phydev)
 {
        struct device_node *node = phydev->mdio.dev.of_node;
@@ -771,6 +822,11 @@ static int at803x_parse_dt(struct phy_device *phydev)
                        phydev_err(phydev, "failed to get VDDIO regulator\n");
                        return PTR_ERR(priv->vddio);
                }
+
+               /* Only AR8031/8033 support 1000Base-X for SFP modules */
+               ret = phy_sfp_probe(phydev, &at803x_sfp_ops);
+               if (ret < 0)
+                       return ret;
        }
 
        return 0;