mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-25 00:11:13 +00:00
96 lines
3.2 KiB
Diff
96 lines
3.2 KiB
Diff
|
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;
|