Commit a2027019 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'add-sqi-and-sqi-support-for-oatc14-10base-t1s-phys-and-microchip-t1s-driver'

Parthiban Veerasooran says:

====================
Add SQI and SQI+ support for OATC14 10Base-T1S PHYs and Microchip T1S driver

This patch series adds Signal Quality Indicator (SQI) and enhanced SQI+
support for OATC14 10Base-T1S PHYs, along with integration into the
Microchip T1S PHY driver. This enables ethtool to report the SQI value for
OATC14 10Base-T1S PHYs.
====================

Link: https://patch.msgid.link/20251201032346.6699-1-parthiban.veerasooran@microchip.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 8d537e33 16416c83
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -56,6 +56,8 @@
/* Advanced Diagnostic Features Capability Register*/
#define MDIO_OATC14_ADFCAP		0xcc00
#define OATC14_ADFCAP_HDD_CAPABILITY	GENMASK(10, 8)
#define OATC14_ADFCAP_SQIPLUS_CAPABILITY	GENMASK(4, 1)
#define OATC14_ADFCAP_SQI_CAPABILITY	BIT(0)

/* Harness Defect Detection Register */
#define MDIO_OATC14_HDD			0xcc01
@@ -65,6 +67,17 @@
#define OATC14_HDD_VALID		BIT(2)
#define OATC14_HDD_SHORT_OPEN_STATUS	GENMASK(1, 0)

/* Dynamic Channel Quality SQI Register */
#define MDIO_OATC14_DCQ_SQI		0xcc03
#define OATC14_DCQ_SQI_VALUE		GENMASK(2, 0)

/* Dynamic Channel Quality SQI Plus Register */
#define MDIO_OATC14_DCQ_SQIPLUS		0xcc04
#define OATC14_DCQ_SQIPLUS_VALUE	GENMASK(7, 0)

/* SQI is supported using 3 bits means 8 levels (0-7) */
#define OATC14_SQI_MAX_LEVEL		7

/* Bus Short/Open Status:
 * 0 0 - no fault; everything is ok. (Default)
 * 0 1 - detected as an open or missing termination(s)
+2 −0
Original line number Diff line number Diff line
@@ -575,6 +575,8 @@ static struct phy_driver microchip_t1s_driver[] = {
		.get_plca_status    = genphy_c45_plca_get_status,
		.cable_test_start   = genphy_c45_oatc14_cable_test_start,
		.cable_test_get_status = genphy_c45_oatc14_cable_test_get_status,
		.get_sqi            = genphy_c45_oatc14_get_sqi,
		.get_sqi_max        = genphy_c45_oatc14_get_sqi_max,
	},
	{
		PHY_ID_MATCH_EXACT(PHY_ID_LAN865X_REVB),
+137 −0
Original line number Diff line number Diff line
@@ -1695,3 +1695,140 @@ int genphy_c45_oatc14_cable_test_start(struct phy_device *phydev)
				OATC14_HDD_START_CONTROL);
}
EXPORT_SYMBOL(genphy_c45_oatc14_cable_test_start);

/**
 * oatc14_update_sqi_capability - Read and update OATC14 10Base-T1S PHY SQI/SQI+
 *                                capability
 * @phydev: Pointer to the PHY device structure
 *
 * This helper reads the OATC14 ADFCAP capability register to determine whether
 * the PHY supports SQI or SQI+ reporting.
 *
 * SQI+ capability is detected first. The SQI+ field indicates the number of
 * valid MSBs (3–8), corresponding to 8–256 SQI+ levels. When present, the
 * function stores the number of SQI+ bits and computes the maximum SQI+ value
 * as (2^bits - 1).
 *
 * If SQI+ is not supported, the function checks for basic SQI capability,
 * which provides 0–7 SQI levels.
 *
 * On success, the capability information is stored in
 * @phydev->oatc14_sqi_capability and marked as updated.
 *
 * Return:
 * * 0        - capability successfully read and stored
 * * -EOPNOTSUPP - SQI/SQI+ not supported by this PHY
 * * Negative errno on read failure
 */
static int oatc14_update_sqi_capability(struct phy_device *phydev)
{
	u8 bits;
	int ret;

	ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, MDIO_OATC14_ADFCAP);
	if (ret < 0)
		return ret;

	/* Check for SQI+ capability
	 * 0 - SQI+ is not supported
	 * (3-8) bits for (8-256) SQI+ levels supported
	 */
	bits = FIELD_GET(OATC14_ADFCAP_SQIPLUS_CAPABILITY, ret);
	if (bits) {
		phydev->oatc14_sqi_capability.sqiplus_bits = bits;
		/* Max sqi+ level supported: (2 ^ bits) - 1 */
		phydev->oatc14_sqi_capability.sqi_max = BIT(bits) - 1;
		goto update_done;
	}

	/* Check for SQI capability
	 * 0 - SQI is not supported
	 * 1 - SQI is supported (0-7 levels)
	 */
	if (ret & OATC14_ADFCAP_SQI_CAPABILITY) {
		phydev->oatc14_sqi_capability.sqi_max = OATC14_SQI_MAX_LEVEL;
		goto update_done;
	}

	return -EOPNOTSUPP;

update_done:
	phydev->oatc14_sqi_capability.updated = true;
	return 0;
}

/**
 * genphy_c45_oatc14_get_sqi_max - Get maximum supported SQI or SQI+ level of
 *				   OATC14 10Base-T1S PHY
 * @phydev: pointer to the PHY device structure
 *
 * This function returns the maximum supported Signal Quality Indicator (SQI) or
 * SQI+ level. The SQI capability is updated on first invocation if it has not
 * already been updated.
 *
 * Return:
 * * Maximum SQI/SQI+ level supported
 * * Negative errno on capability read failure
 */
int genphy_c45_oatc14_get_sqi_max(struct phy_device *phydev)
{
	int ret;

	if (!phydev->oatc14_sqi_capability.updated) {
		ret = oatc14_update_sqi_capability(phydev);
		if (ret)
			return ret;
	}

	return phydev->oatc14_sqi_capability.sqi_max;
}
EXPORT_SYMBOL(genphy_c45_oatc14_get_sqi_max);

/**
 * genphy_c45_oatc14_get_sqi - Get Signal Quality Indicator (SQI) from an OATC14
 *			       10Base-T1S PHY
 * @phydev: pointer to the PHY device structure
 *
 * This function reads the SQI+ or SQI value from an OATC14-compatible
 * 10Base-T1S PHY. If SQI+ capability is supported, the function returns the
 * extended SQI+ value; otherwise, it returns the basic SQI value. The SQI
 * capability is updated on first invocation if it has not already been updated.
 *
 * Return:
 * * SQI/SQI+ value on success
 * * Negative errno on read failure
 */
int genphy_c45_oatc14_get_sqi(struct phy_device *phydev)
{
	u8 shift;
	int ret;

	if (!phydev->oatc14_sqi_capability.updated) {
		ret = oatc14_update_sqi_capability(phydev);
		if (ret)
			return ret;
	}

	/* Calculate and return SQI+ value if supported */
	if (phydev->oatc14_sqi_capability.sqiplus_bits) {
		ret = phy_read_mmd(phydev, MDIO_MMD_VEND2,
				   MDIO_OATC14_DCQ_SQIPLUS);
		if (ret < 0)
			return ret;

		/* SQI+ uses N MSBs out of 8 bits, left-aligned with padding 1's
		 * Calculate the right-shift needed to isolate the N bits.
		 */
		shift = 8 - phydev->oatc14_sqi_capability.sqiplus_bits;

		return (ret & OATC14_DCQ_SQIPLUS_VALUE) >> shift;
	}

	/* Read and return SQI value if SQI+ capability is not supported */
	ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, MDIO_OATC14_DCQ_SQI);
	if (ret < 0)
		return ret;

	return ret & OATC14_DCQ_SQI_VALUE;
}
EXPORT_SYMBOL(genphy_c45_oatc14_get_sqi);
+29 −0
Original line number Diff line number Diff line
@@ -530,6 +530,30 @@ struct phy_c45_device_ids {
struct macsec_context;
struct macsec_ops;

/**
 * struct phy_oatc14_sqi_capability - SQI capability information for OATC14
 *                                    10Base-T1S PHY
 * @updated: Indicates whether the SQI capability fields have been updated.
 * @sqi_max: Maximum supported Signal Quality Indicator (SQI) level reported by
 *           the PHY.
 * @sqiplus_bits: Bits for SQI+ levels supported by the PHY.
 *                0 - SQI+ is not supported
 *                3 - SQI+ is supported, using 3 bits (8 levels)
 *                4 - SQI+ is supported, using 4 bits (16 levels)
 *                5 - SQI+ is supported, using 5 bits (32 levels)
 *                6 - SQI+ is supported, using 6 bits (64 levels)
 *                7 - SQI+ is supported, using 7 bits (128 levels)
 *                8 - SQI+ is supported, using 8 bits (256 levels)
 *
 * This structure is used by the OATC14 10Base-T1S PHY driver to store the SQI
 * and SQI+ capability information retrieved from the PHY.
 */
struct phy_oatc14_sqi_capability {
	bool updated;
	int sqi_max;
	u8 sqiplus_bits;
};

/**
 * struct phy_device - An instance of a PHY
 *
@@ -626,6 +650,7 @@ struct macsec_ops;
 * @link_down_events: Number of times link was lost
 * @shared: Pointer to private data shared by phys in one package
 * @priv: Pointer to driver private data
 * @oatc14_sqi_capability: SQI capability information for OATC14 10Base-T1S PHY
 *
 * interrupts currently only supports enabled or disabled,
 * but could be changed in the future to support enabling
@@ -772,6 +797,8 @@ struct phy_device {
	/* MACsec management functions */
	const struct macsec_ops *macsec_ops;
#endif

	struct phy_oatc14_sqi_capability oatc14_sqi_capability;
};

/* Generic phy_device::dev_flags */
@@ -2257,6 +2284,8 @@ int genphy_c45_an_config_eee_aneg(struct phy_device *phydev);
int genphy_c45_oatc14_cable_test_start(struct phy_device *phydev);
int genphy_c45_oatc14_cable_test_get_status(struct phy_device *phydev,
					    bool *finished);
int genphy_c45_oatc14_get_sqi_max(struct phy_device *phydev);
int genphy_c45_oatc14_get_sqi(struct phy_device *phydev);

/* The gen10g_* functions are the old Clause 45 stub */
int gen10g_config_aneg(struct phy_device *phydev);