aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/mvebu/patches-4.14/410-sfp-hack-allow-marvell-10G-phy-support-to-use-SFP.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/mvebu/patches-4.14/410-sfp-hack-allow-marvell-10G-phy-support-to-use-SFP.patch')
-rw-r--r--target/linux/mvebu/patches-4.14/410-sfp-hack-allow-marvell-10G-phy-support-to-use-SFP.patch131
1 files changed, 131 insertions, 0 deletions
diff --git a/target/linux/mvebu/patches-4.14/410-sfp-hack-allow-marvell-10G-phy-support-to-use-SFP.patch b/target/linux/mvebu/patches-4.14/410-sfp-hack-allow-marvell-10G-phy-support-to-use-SFP.patch
new file mode 100644
index 0000000000..6ca43043fa
--- /dev/null
+++ b/target/linux/mvebu/patches-4.14/410-sfp-hack-allow-marvell-10G-phy-support-to-use-SFP.patch
@@ -0,0 +1,131 @@
+From 4a4aca08b11501cb1b2c509113bbb65eb66a1f45 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Fri, 14 Apr 2017 14:21:25 +0100
+Subject: sfp: hack: allow marvell 10G phy support to use SFP
+
+Allow the Marvell 10G PHY to register with the SFP bus, so that SFP+
+cages can work. This bypasses phylink, meaning that socket status
+is not taken into account for the link state. Also, the tx-disable
+signal must be commented out in DT for this to work...
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/marvell10g.c | 54 +++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 53 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/phy/marvell10g.c
++++ b/drivers/net/phy/marvell10g.c
+@@ -15,8 +15,10 @@
+ * If both the fiber and copper ports are connected, the first to gain
+ * link takes priority and the other port is completely locked out.
+ */
++#include <linux/of.h>
+ #include <linux/phy.h>
+ #include <linux/marvell_phy.h>
++#include <linux/sfp.h>
+
+ enum {
+ MV_PCS_BASE_T = 0x0000,
+@@ -38,6 +40,11 @@ enum {
+ MV_AN_RESULT_SPD_10000 = BIT(15),
+ };
+
++struct mv3310_priv {
++ struct device_node *sfp_node;
++ struct sfp_bus *sfp_bus;
++};
++
+ static int mv3310_modify(struct phy_device *phydev, int devad, u16 reg,
+ u16 mask, u16 bits)
+ {
+@@ -56,17 +63,52 @@ static int mv3310_modify(struct phy_devi
+ return ret < 0 ? ret : 1;
+ }
+
++static int mv3310_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
++{
++ struct phy_device *phydev = upstream;
++ struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
++
++ if (sfp_parse_interface(priv->sfp_bus, id) != PHY_INTERFACE_MODE_10GKR) {
++ dev_err(&phydev->mdio.dev, "incompatible SFP module inserted\n");
++ return -EINVAL;
++ }
++ return 0;
++}
++
++static const struct sfp_upstream_ops mv3310_sfp_ops = {
++ .module_insert = mv3310_sfp_insert,
++};
++
+ static int mv3310_probe(struct phy_device *phydev)
+ {
++ struct mv3310_priv *priv;
+ u32 mmd_mask = MDIO_DEVS_PMAPMD | MDIO_DEVS_AN;
+
+ if (!phydev->is_c45 ||
+ (phydev->c45_ids.devices_in_package & mmd_mask) != mmd_mask)
+ return -ENODEV;
+
++ priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
++
++ dev_set_drvdata(&phydev->mdio.dev, priv);
++
++ if (phydev->mdio.dev.of_node)
++ priv->sfp_node = of_parse_phandle(phydev->mdio.dev.of_node,
++ "sfp", 0);
++
+ return 0;
+ }
+
++static void mv3310_remove(struct phy_device *phydev)
++{
++ struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
++
++ if (priv->sfp_bus)
++ sfp_unregister_upstream(priv->sfp_bus);
++}
++
+ /*
+ * Resetting the MV88X3310 causes it to become non-responsive. Avoid
+ * setting the reset bit(s).
+@@ -78,6 +120,7 @@ static int mv3310_soft_reset(struct phy_
+
+ static int mv3310_config_init(struct phy_device *phydev)
+ {
++ struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(supported) = { 0, };
+ u32 mask;
+ int val;
+@@ -166,6 +209,14 @@ static int mv3310_config_init(struct phy
+ phydev->supported &= mask;
+ phydev->advertising &= phydev->supported;
+
++ /* Would be nice to do this in the probe function, but unfortunately,
++ * phylib doesn't have phydev->attached_dev set there.
++ */
++ if (priv->sfp_node && !priv->sfp_bus)
++ priv->sfp_bus = sfp_register_upstream(priv->sfp_node,
++ phydev->attached_dev,
++ phydev, &mv3310_sfp_ops);
++
+ return 0;
+ }
+
+@@ -349,12 +400,13 @@ static struct phy_driver mv3310_drivers[
+ SUPPORTED_FIBRE |
+ SUPPORTED_10000baseT_Full |
+ SUPPORTED_Backplane,
+- .probe = mv3310_probe,
+ .soft_reset = mv3310_soft_reset,
+ .config_init = mv3310_config_init,
++ .probe = mv3310_probe,
+ .config_aneg = mv3310_config_aneg,
+ .aneg_done = mv3310_aneg_done,
+ .read_status = mv3310_read_status,
++ .remove = mv3310_remove,
+ },
+ };
+