]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
net: phy: phy-c45: add OATC14 10BASE-T1S PHY cable diagnostic support
authorParthiban Veerasooran <parthiban.veerasooran@microchip.com>
Wed, 5 Nov 2025 05:12:12 +0000 (10:42 +0530)
committerJakub Kicinski <kuba@kernel.org>
Sat, 8 Nov 2025 02:52:33 +0000 (18:52 -0800)
Add support for Open Alliance TC14 (OATC14) 10BASE-T1S PHYs cable
diagnostic feature.

This patch implements:
- genphy_c45_oatc14_cable_test_start() to initiate a cable test
- genphy_c45_oatc14_cable_test_get_status() to retrieve test results
- Helper function to map PHY cable test status to ethtool result codes
- Function declarations and exports for use by PHY drivers

This enables ethtool to report ok, open, short, and undetectable cable
conditions on OATC14 10Base-T1S PHYs.

Open Alliance TC14 10BASE-T1S Advanced Diagnostic PHY Features
Specification ref:
https://opensig.org/wp-content/uploads/2025/06/OPEN_Alliance_10BASE-T1S_Advanced_PHY_features_for-automotive_Ethernet_V2.1b.pdf

Signed-off-by: Parthiban Veerasooran <parthiban.veerasooran@microchip.com>
Link: https://patch.msgid.link/20251105051213.50443-2-parthiban.veerasooran@microchip.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/phy/mdio-open-alliance.h
drivers/net/phy/phy-c45.c
include/linux/phy.h

index 931e14660d759ac77549a48217b07f4b97301790..6850a3f0b31e2059695b81a99cb7afecd248c6bd 100644 (file)
 /* 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__ */
index 1a7b32be4625c70c237901a7a68bcec514d6ee5d..e8e5be4684ab976062b4c5a6ba81e91013bae577 100644 (file)
@@ -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);
index d145a200ea21123950b13463d0eb7379670a932a..bf5457341ca80a3bf1982b1030a181efbc4b880d 100644 (file)
@@ -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);