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

Merge branch 'net-phy-add-open-alliance-tc14-10base-t1s-phy-cable-diagnostic-support'

Parthiban Veerasooran says:

====================
net: phy: Add Open Alliance TC14 10Base-T1S PHY cable diagnostic support

This patch series adds Open Alliance TC14 (OATC14) 10BASE-T1S cable
diagnostic feature support to the Linux kernel PHY subsystem and enable
this feature for Microchip LAN867x Rev.D0 PHYs. These patches provide
standardized cable test functionality for 10BASE-T1S Ethernet PHYs,
allowing users to perform cable diagnostics via ethtool.

Patch Summary:
1. add OATC14 10BASE-T1S PHY cable diagnostic support
	- Implements support for the OATC14 cable diagnostic feature in
	  Clause 45 PHYs.
	- Adds functions to start a cable test and retrieve its status,
	  mapping hardware results to ethtool codes.
	- Exports these functions for use by PHY drivers.
	- Open Alliance TC14 10BASE-T1S Advanced Diagnostic PHY Features.
	  https://opensig.org/wp-content/uploads/2025/06/OPEN_Alliance_10BASE-T1S_Advanced_PHY_features_for-automotive_Ethernet_V2.1b.pdf

2. add cable diagnostic support for LAN867x Rev.D0
	- Integrates the generic OATC14 cable test functions into the
	  Microchip LAN867x Rev.D0 PHY driver.
	- Enables ethtool cable diagnostics for this PHY, improving
	  troubleshooting and maintenance.
====================

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


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 14003958 f4244094
Loading
Loading
Loading
Loading
+36 −0
Original line number Diff line number Diff line
@@ -43,4 +43,40 @@
/* Version Identifiers */
#define OATC14_IDM		0x0a00

/*
 * Open Alliance TC14 (10BASE-T1S) - Advanced Diagnostic Features Registers
 *
 * Refer to the OPEN Alliance documentation:
 *   https://opensig.org/automotive-ethernet-specifications/
 *
 * Specification:
 *   "10BASE-T1S Advanced Diagnostic PHY Features"
 *   https://opensig.org/wp-content/uploads/2025/06/OPEN_Alliance_10BASE-T1S_Advanced_PHY_features_for-automotive_Ethernet_V2.1b.pdf
 */
/* Advanced Diagnostic Features Capability Register*/
#define MDIO_OATC14_ADFCAP		0xcc00
#define OATC14_ADFCAP_HDD_CAPABILITY	GENMASK(10, 8)

/* Harness Defect Detection Register */
#define MDIO_OATC14_HDD			0xcc01
#define OATC14_HDD_CONTROL		BIT(15)
#define OATC14_HDD_READY		BIT(14)
#define OATC14_HDD_START_CONTROL	BIT(13)
#define OATC14_HDD_VALID		BIT(2)
#define OATC14_HDD_SHORT_OPEN_STATUS	GENMASK(1, 0)

/* Bus Short/Open Status:
 * 0 0 - no fault; everything is ok. (Default)
 * 0 1 - detected as an open or missing termination(s)
 * 1 0 - detected as a short or extra termination(s)
 * 1 1 - fault but fault type not detectable. More details can be available by
 *       vender specific register if supported.
 */
enum oatc14_hdd_status {
	OATC14_HDD_STATUS_CABLE_OK = 0,
	OATC14_HDD_STATUS_OPEN,
	OATC14_HDD_STATUS_SHORT,
	OATC14_HDD_STATUS_NOT_DETECTABLE,
};

#endif /* __MDIO_OPEN_ALLIANCE__ */
+2 −0
Original line number Diff line number Diff line
@@ -573,6 +573,8 @@ static struct phy_driver microchip_t1s_driver[] = {
		.get_plca_cfg	    = genphy_c45_plca_get_cfg,
		.set_plca_cfg	    = lan86xx_plca_set_cfg,
		.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,
	},
	{
		PHY_ID_MATCH_EXACT(PHY_ID_LAN865X_REVB),
+122 −0
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@
#include <linux/mdio.h>
#include <linux/mii.h>
#include <linux/phy.h>
#include <linux/ethtool_netlink.h>

#include "mdio-open-alliance.h"
#include "phylib-internal.h"
@@ -1573,3 +1574,124 @@ int genphy_c45_ethtool_set_eee(struct phy_device *phydev,
	return ret;
}
EXPORT_SYMBOL(genphy_c45_ethtool_set_eee);

/**
 * oatc14_cable_test_get_result_code - Convert hardware cable test status to
 *                                     ethtool result code.
 * @status: The hardware-reported cable test status
 *
 * This helper function maps the OATC14 HDD cable test status to the
 * corresponding ethtool cable test result code. It provides a translation
 * between the device-specific status values and the standardized ethtool
 * result codes.
 *
 * Return:
 * * ETHTOOL_A_CABLE_RESULT_CODE_OK          - Cable is OK
 * * ETHTOOL_A_CABLE_RESULT_CODE_OPEN        - Open circuit detected
 * * ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT  - Short circuit detected
 * * ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC      - Status not detectable or invalid
 */
static int oatc14_cable_test_get_result_code(enum oatc14_hdd_status status)
{
	switch (status) {
	case OATC14_HDD_STATUS_CABLE_OK:
		return ETHTOOL_A_CABLE_RESULT_CODE_OK;
	case OATC14_HDD_STATUS_OPEN:
		return ETHTOOL_A_CABLE_RESULT_CODE_OPEN;
	case OATC14_HDD_STATUS_SHORT:
		return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT;
	case OATC14_HDD_STATUS_NOT_DETECTABLE:
	default:
		return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;
	}
}

/**
 * genphy_c45_oatc14_cable_test_get_status - Get status of OATC14 10Base-T1S
 *                                           PHY cable test.
 * @phydev:   pointer to the PHY device structure
 * @finished: pointer to a boolean set true if the test is complete
 *
 * Retrieves the current status of the OATC14 10Base-T1S PHY cable test.
 * This function reads the OATC14 HDD register to determine whether the test
 * results are valid and whether the test has finished.
 *
 * If the test is complete, the function reports the cable test result via
 * the ethtool cable test interface using ethnl_cable_test_result(), and then
 * clears the test control bit in the PHY register to reset the test state.
 *
 * Return: 0 on success, or a negative error code on failure (e.g. register
 *         read/write error).
 */
int genphy_c45_oatc14_cable_test_get_status(struct phy_device *phydev,
					    bool *finished)
{
	int ret;
	u8 sts;

	*finished = false;

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

	if (!(ret & OATC14_HDD_VALID))
		return 0;

	*finished = true;

	sts = FIELD_GET(OATC14_HDD_SHORT_OPEN_STATUS, ret);

	ret = ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A,
				      oatc14_cable_test_get_result_code(sts));
	if (ret)
		return ret;

	return phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2,
				  MDIO_OATC14_HDD, OATC14_HDD_CONTROL);
}
EXPORT_SYMBOL(genphy_c45_oatc14_cable_test_get_status);

/**
 * genphy_c45_oatc14_cable_test_start - Start a cable test on an OATC14
 *                                      10Base-T1S PHY.
 * @phydev: Pointer to the PHY device structure
 *
 * This function initiates a cable diagnostic test on a Clause 45 OATC14
 * 10Base-T1S capable PHY device. It first reads the PHY’s advanced diagnostic
 * capability register to check if High Definition Diagnostics (HDD) mode is
 * supported. If the PHY does not report HDD capability, cable testing is not
 * supported and the function returns -EOPNOTSUPP.
 *
 * For PHYs that support HDD, the function sets the appropriate control bits in
 * the OATC14_HDD register to enable and start the cable diagnostic test.
 *
 * Return:
 * * 0 on success
 * * -EOPNOTSUPP if the PHY does not support HDD capability
 * * A negative error code on I/O or register access failures
 */
int genphy_c45_oatc14_cable_test_start(struct phy_device *phydev)
{
	int ret;

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

	if (!(ret & OATC14_ADFCAP_HDD_CAPABILITY))
		return -EOPNOTSUPP;

	ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, MDIO_OATC14_HDD,
			       OATC14_HDD_CONTROL);
	if (ret)
		return ret;

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

	return phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, MDIO_OATC14_HDD,
				OATC14_HDD_START_CONTROL);
}
EXPORT_SYMBOL(genphy_c45_oatc14_cable_test_start);
+3 −0
Original line number Diff line number Diff line
@@ -2251,6 +2251,9 @@ int genphy_c45_ethtool_get_eee(struct phy_device *phydev,
int genphy_c45_ethtool_set_eee(struct phy_device *phydev,
			       struct ethtool_keee *data);
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);

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