[openwrt/openwrt] ipq40xx: qca807x: add SFP improvements

LEDE Commits lede-commits at lists.infradead.org
Sun Oct 2 14:05:39 PDT 2022


blocktrron pushed a commit to openwrt/openwrt.git, branch master:
https://git.openwrt.org/378d1a65698eb8060d0a28c438d718a917afcb56

commit 378d1a65698eb8060d0a28c438d718a917afcb56
Author: Robert Marko <robert.marko at sartura.hr>
AuthorDate: Mon Oct 25 18:30:00 2021 +0200

    ipq40xx: qca807x: add SFP improvements
    
    Currently, QCA807x doesnt do any kind of validation to see whether it
    actually supports the inserted module.
    
    So lets add checks to allow only 1000BaseX and 100BaseFX based modules.
    
    While adding validation, move fiber configuration to insert/remove events
    instead of always doing it at config time.
    This allows getting rid of the DT property for fiber enable and now only
    the upstream sfp phandle is required.
    
    Since we are refactoring fiber related code, lets heavily simplify the
    status polling as the current logic is overcomplicated due to previous
    wish to support non standard SFP cages that dont have pins properly
    connected, that is removed now and only proper SFP cages will work.
    
    Signed-off-by: Robert Marko <robert.marko at sartura.hr>
---
 .../linux/ipq40xx/files/drivers/net/phy/qca807x.c  | 140 +++++++++++----------
 1 file changed, 74 insertions(+), 66 deletions(-)

diff --git a/target/linux/ipq40xx/files/drivers/net/phy/qca807x.c b/target/linux/ipq40xx/files/drivers/net/phy/qca807x.c
index 8d523548e5..d56e9f9cda 100644
--- a/target/linux/ipq40xx/files/drivers/net/phy/qca807x.c
+++ b/target/linux/ipq40xx/files/drivers/net/phy/qca807x.c
@@ -64,6 +64,8 @@
 
 #define QCA807X_CHIP_CONFIGURATION				0x1f
 #define QCA807X_BT_BX_REG_SEL					BIT(15)
+#define QCA807X_BT_BX_REG_SEL_FIBER				0
+#define QCA807X_BT_BX_REG_SEL_COPPER				1
 #define QCA807X_CHIP_CONFIGURATION_MODE_CFG_MASK		GENMASK(3, 0)
 #define QCA807X_CHIP_CONFIGURATION_MODE_QSGMII_SGMII		4
 #define QCA807X_CHIP_CONFIGURATION_MODE_PSGMII_FIBER		3
@@ -400,19 +402,9 @@ static int qca807x_gpio(struct phy_device *phydev)
 }
 #endif
 
-static int qca807x_read_copper_status(struct phy_device *phydev, bool combo_port)
+static int qca807x_read_copper_status(struct phy_device *phydev)
 {
-	int ss, err, page, old_link = phydev->link;
-
-	/* Only combo port has dual pages */
-	if (combo_port) {
-		/* Check whether copper page is set and set if needed */
-		page = phy_read(phydev, QCA807X_CHIP_CONFIGURATION);
-		if (!(page & QCA807X_BT_BX_REG_SEL)) {
-			page |= QCA807X_BT_BX_REG_SEL;
-			phy_write(phydev, QCA807X_CHIP_CONFIGURATION, page);
-		}
-	}
+	int ss, err, old_link = phydev->link;
 
 	/* Update the link, but return if there was an error */
 	err = genphy_update_link(phydev);
@@ -487,16 +479,9 @@ static int qca807x_read_copper_status(struct phy_device *phydev, bool combo_port
 	return 0;
 }
 
-static int qca807x_read_fiber_status(struct phy_device *phydev, bool combo_port)
+static int qca807x_read_fiber_status(struct phy_device *phydev)
 {
-	int ss, err, page, lpa, old_link = phydev->link;
-
-	/* Check whether fiber page is set and set if needed */
-	page = phy_read(phydev, QCA807X_CHIP_CONFIGURATION);
-	if (page & QCA807X_BT_BX_REG_SEL) {
-		page &= ~QCA807X_BT_BX_REG_SEL;
-		phy_write(phydev, QCA807X_CHIP_CONFIGURATION, page);
-	}
+	int ss, err, lpa, old_link = phydev->link;
 
 	/* Update the link, but return if there was an error */
 	err = genphy_update_link(phydev);
@@ -559,28 +544,17 @@ static int qca807x_read_fiber_status(struct phy_device *phydev, bool combo_port)
 
 static int qca807x_read_status(struct phy_device *phydev)
 {
-	int val;
-
-	/* Check for Combo port */
-	if (phy_read(phydev, QCA807X_CHIP_CONFIGURATION)) {
-		/* Check for fiber mode first */
-		if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->supported)) {
-			/* Check for actual detected media */
-			val = phy_read(phydev, QCA807X_MEDIA_SELECT_STATUS);
-			if (val & QCA807X_MEDIA_DETECTED_COPPER) {
-				qca807x_read_copper_status(phydev, true);
-			} else if ((val & QCA807X_MEDIA_DETECTED_1000_BASE_X) ||
-				   (val & QCA807X_MEDIA_DETECTED_100_BASE_FX)) {
-				qca807x_read_fiber_status(phydev, true);
-			}
-		} else {
-			qca807x_read_copper_status(phydev, true);
+	if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->supported)) {
+		switch (phydev->port) {
+		case PORT_FIBRE:
+			return qca807x_read_fiber_status(phydev);
+		case PORT_TP:
+			return qca807x_read_copper_status(phydev);
+		default:
+			return -EINVAL;
 		}
-	} else {
-		qca807x_read_copper_status(phydev, false);
-	}
-
-	return 0;
+	} else
+		return qca807x_read_copper_status(phydev);
 }
 
 static int qca807x_config_intr(struct phy_device *phydev)
@@ -683,9 +657,63 @@ static int qca807x_led_config(struct phy_device *phydev)
 		return 0;
 }
 
+static int qca807x_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
+{
+	struct phy_device *phydev = upstream;
+	__ETHTOOL_DECLARE_LINK_MODE_MASK(support) = { 0, };
+	phy_interface_t iface;
+	int ret;
+
+	sfp_parse_support(phydev->sfp_bus, id, support);
+	iface = sfp_select_interface(phydev->sfp_bus, support);
+
+	dev_info(&phydev->mdio.dev, "%s SFP module inserted\n", phy_modes(iface));
+
+	switch (iface) {
+	case PHY_INTERFACE_MODE_1000BASEX:
+	case PHY_INTERFACE_MODE_100BASEX:
+		/* Set PHY mode to PSGMII combo (1/4 copper + combo ports) mode */
+		ret = phy_modify(phydev,
+				 QCA807X_CHIP_CONFIGURATION,
+				 QCA807X_CHIP_CONFIGURATION_MODE_CFG_MASK,
+				 QCA807X_CHIP_CONFIGURATION_MODE_PSGMII_FIBER);
+		/* Enable fiber mode autodection (1000Base-X or 100Base-FX) */
+		ret = phy_set_bits_mmd(phydev,
+				       MDIO_MMD_AN,
+				       QCA807X_MMD7_FIBER_MODE_AUTO_DETECTION,
+				       QCA807X_MMD7_FIBER_MODE_AUTO_DETECTION_EN);
+		/* Select fiber page */
+		ret = phy_clear_bits(phydev,
+				     QCA807X_CHIP_CONFIGURATION,
+				     QCA807X_BT_BX_REG_SEL);
+
+		phydev->port = PORT_FIBRE;
+		break;
+	default:
+		dev_err(&phydev->mdio.dev, "Incompatible SFP module inserted\n");
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+static void qca807x_sfp_remove(void *upstream)
+{
+	struct phy_device *phydev = upstream;
+
+	/* Select copper page */
+	phy_set_bits(phydev,
+		     QCA807X_CHIP_CONFIGURATION,
+		     QCA807X_BT_BX_REG_SEL);
+
+	phydev->port = PORT_TP;
+}
+
 static const struct sfp_upstream_ops qca807x_sfp_ops = {
 	.attach = phy_sfp_attach,
 	.detach = phy_sfp_detach,
+	.module_insert = qca807x_sfp_insert,
+	.module_remove = qca807x_sfp_remove,
 };
 
 static int qca807x_config(struct phy_device *phydev)
@@ -696,28 +724,7 @@ static int qca807x_config(struct phy_device *phydev)
 
 	/* Check for Combo port */
 	if (phy_read(phydev, QCA807X_CHIP_CONFIGURATION)) {
-		int fiber_mode_autodect;
 		int psgmii_serdes;
-		int chip_config;
-
-		if (of_property_read_bool(node, "qcom,fiber-enable")) {
-			/* Enable fiber mode autodection (1000Base-X or 100Base-FX) */
-			fiber_mode_autodect = phy_read_mmd(phydev, MDIO_MMD_AN,
-							   QCA807X_MMD7_FIBER_MODE_AUTO_DETECTION);
-			fiber_mode_autodect |= QCA807X_MMD7_FIBER_MODE_AUTO_DETECTION_EN;
-			phy_write_mmd(phydev, MDIO_MMD_AN, QCA807X_MMD7_FIBER_MODE_AUTO_DETECTION,
-				      fiber_mode_autodect);
-
-			/* Enable 4 copper + combo port mode */
-			chip_config = phy_read(phydev, QCA807X_CHIP_CONFIGURATION);
-			chip_config &= ~QCA807X_CHIP_CONFIGURATION_MODE_CFG_MASK;
-			chip_config |= FIELD_PREP(QCA807X_CHIP_CONFIGURATION_MODE_CFG_MASK,
-						  QCA807X_CHIP_CONFIGURATION_MODE_PSGMII_FIBER);
-			phy_write(phydev, QCA807X_CHIP_CONFIGURATION, chip_config);
-
-			linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->supported);
-			linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->advertising);
-		}
 
 		/* Prevent PSGMII going into hibernation via PSGMII self test */
 		psgmii_serdes = phy_read_mmd(phydev, MDIO_MMD_PCS, PSGMII_MMD3_SERDES_CONTROL);
@@ -761,9 +768,10 @@ static int qca807x_probe(struct phy_device *phydev)
 	}
 
 	/* Attach SFP bus on combo port*/
-	if (of_property_read_bool(node, "qcom,fiber-enable")) {
-		if (phy_read(phydev, QCA807X_CHIP_CONFIGURATION))
-			ret = phy_sfp_probe(phydev, &qca807x_sfp_ops);
+	if (phy_read(phydev, QCA807X_CHIP_CONFIGURATION)) {
+		ret = phy_sfp_probe(phydev, &qca807x_sfp_ops);
+		linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->supported);
+		linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->advertising);
 	}
 
 	return ret;




More information about the lede-commits mailing list