--- /dev/null
+From dc4d5fcc5d365c9f70ea3f5c09bdf70e988fad50 Mon Sep 17 00:00:00 2001
+From: Robert Hancock <robert.hancock@calian.com>
+Date: Tue, 25 Jan 2022 10:54:10 -0600
+Subject: [PATCH] net: phy: at803x: Support downstream SFP cage
+
+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 | 56 ++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 56 insertions(+)
+
+--- a/drivers/net/phy/at803x.c
++++ b/drivers/net/phy/at803x.c
+@@ -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
+@@ -551,6 +553,55 @@ static bool at803x_match_phy_id(struct p
+ == (phy_id & phydev->drv->phy_id_mask);
+ }
+
++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;
+@@ -639,6 +690,11 @@ static int at803x_parse_dt(struct phy_de
+ 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;