Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: phy: phy-c45: add SQI and SQI+ support for OATC14 10Base-T1S PHYs

Add support for reading Signal Quality Indicator (SQI) and enhanced SQI+
from OATC14 10Base-T1S PHYs.

- Introduce MDIO register definitions for DCQ_SQI and DCQ_SQIPLUS.
- Add `genphy_c45_oatc14_get_sqi_max()` to return the maximum supported
SQI/SQI+ level.
- Add `genphy_c45_oatc14_get_sqi()` to return the current SQI or SQI+
value.
- Update `include/linux/phy.h` to expose the new APIs.

SQI+ capability is read from the Advanced Diagnostic Features Capability
register (ADFCAP). If SQI+ is supported, the driver calculates the value
from the MSBs of the DCQ_SQIPLUS register; otherwise, it falls back to
basic SQI (0-7 levels). This enables ethtool to report the SQI value for
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>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://patch.msgid.link/20251201032346.6699-2-parthiban.veerasooran@microchip.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Parthiban Veerasooran and committed by
Jakub Kicinski
5e1bf5ae 8d537e33

+179
+13
drivers/net/phy/mdio-open-alliance.h
··· 56 56 /* Advanced Diagnostic Features Capability Register*/ 57 57 #define MDIO_OATC14_ADFCAP 0xcc00 58 58 #define OATC14_ADFCAP_HDD_CAPABILITY GENMASK(10, 8) 59 + #define OATC14_ADFCAP_SQIPLUS_CAPABILITY GENMASK(4, 1) 60 + #define OATC14_ADFCAP_SQI_CAPABILITY BIT(0) 59 61 60 62 /* Harness Defect Detection Register */ 61 63 #define MDIO_OATC14_HDD 0xcc01 ··· 66 64 #define OATC14_HDD_START_CONTROL BIT(13) 67 65 #define OATC14_HDD_VALID BIT(2) 68 66 #define OATC14_HDD_SHORT_OPEN_STATUS GENMASK(1, 0) 67 + 68 + /* Dynamic Channel Quality SQI Register */ 69 + #define MDIO_OATC14_DCQ_SQI 0xcc03 70 + #define OATC14_DCQ_SQI_VALUE GENMASK(2, 0) 71 + 72 + /* Dynamic Channel Quality SQI Plus Register */ 73 + #define MDIO_OATC14_DCQ_SQIPLUS 0xcc04 74 + #define OATC14_DCQ_SQIPLUS_VALUE GENMASK(7, 0) 75 + 76 + /* SQI is supported using 3 bits means 8 levels (0-7) */ 77 + #define OATC14_SQI_MAX_LEVEL 7 69 78 70 79 /* Bus Short/Open Status: 71 80 * 0 0 - no fault; everything is ok. (Default)
+137
drivers/net/phy/phy-c45.c
··· 1695 1695 OATC14_HDD_START_CONTROL); 1696 1696 } 1697 1697 EXPORT_SYMBOL(genphy_c45_oatc14_cable_test_start); 1698 + 1699 + /** 1700 + * oatc14_update_sqi_capability - Read and update OATC14 10Base-T1S PHY SQI/SQI+ 1701 + * capability 1702 + * @phydev: Pointer to the PHY device structure 1703 + * 1704 + * This helper reads the OATC14 ADFCAP capability register to determine whether 1705 + * the PHY supports SQI or SQI+ reporting. 1706 + * 1707 + * SQI+ capability is detected first. The SQI+ field indicates the number of 1708 + * valid MSBs (3–8), corresponding to 8–256 SQI+ levels. When present, the 1709 + * function stores the number of SQI+ bits and computes the maximum SQI+ value 1710 + * as (2^bits - 1). 1711 + * 1712 + * If SQI+ is not supported, the function checks for basic SQI capability, 1713 + * which provides 0–7 SQI levels. 1714 + * 1715 + * On success, the capability information is stored in 1716 + * @phydev->oatc14_sqi_capability and marked as updated. 1717 + * 1718 + * Return: 1719 + * * 0 - capability successfully read and stored 1720 + * * -EOPNOTSUPP - SQI/SQI+ not supported by this PHY 1721 + * * Negative errno on read failure 1722 + */ 1723 + static int oatc14_update_sqi_capability(struct phy_device *phydev) 1724 + { 1725 + u8 bits; 1726 + int ret; 1727 + 1728 + ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, MDIO_OATC14_ADFCAP); 1729 + if (ret < 0) 1730 + return ret; 1731 + 1732 + /* Check for SQI+ capability 1733 + * 0 - SQI+ is not supported 1734 + * (3-8) bits for (8-256) SQI+ levels supported 1735 + */ 1736 + bits = FIELD_GET(OATC14_ADFCAP_SQIPLUS_CAPABILITY, ret); 1737 + if (bits) { 1738 + phydev->oatc14_sqi_capability.sqiplus_bits = bits; 1739 + /* Max sqi+ level supported: (2 ^ bits) - 1 */ 1740 + phydev->oatc14_sqi_capability.sqi_max = BIT(bits) - 1; 1741 + goto update_done; 1742 + } 1743 + 1744 + /* Check for SQI capability 1745 + * 0 - SQI is not supported 1746 + * 1 - SQI is supported (0-7 levels) 1747 + */ 1748 + if (ret & OATC14_ADFCAP_SQI_CAPABILITY) { 1749 + phydev->oatc14_sqi_capability.sqi_max = OATC14_SQI_MAX_LEVEL; 1750 + goto update_done; 1751 + } 1752 + 1753 + return -EOPNOTSUPP; 1754 + 1755 + update_done: 1756 + phydev->oatc14_sqi_capability.updated = true; 1757 + return 0; 1758 + } 1759 + 1760 + /** 1761 + * genphy_c45_oatc14_get_sqi_max - Get maximum supported SQI or SQI+ level of 1762 + * OATC14 10Base-T1S PHY 1763 + * @phydev: pointer to the PHY device structure 1764 + * 1765 + * This function returns the maximum supported Signal Quality Indicator (SQI) or 1766 + * SQI+ level. The SQI capability is updated on first invocation if it has not 1767 + * already been updated. 1768 + * 1769 + * Return: 1770 + * * Maximum SQI/SQI+ level supported 1771 + * * Negative errno on capability read failure 1772 + */ 1773 + int genphy_c45_oatc14_get_sqi_max(struct phy_device *phydev) 1774 + { 1775 + int ret; 1776 + 1777 + if (!phydev->oatc14_sqi_capability.updated) { 1778 + ret = oatc14_update_sqi_capability(phydev); 1779 + if (ret) 1780 + return ret; 1781 + } 1782 + 1783 + return phydev->oatc14_sqi_capability.sqi_max; 1784 + } 1785 + EXPORT_SYMBOL(genphy_c45_oatc14_get_sqi_max); 1786 + 1787 + /** 1788 + * genphy_c45_oatc14_get_sqi - Get Signal Quality Indicator (SQI) from an OATC14 1789 + * 10Base-T1S PHY 1790 + * @phydev: pointer to the PHY device structure 1791 + * 1792 + * This function reads the SQI+ or SQI value from an OATC14-compatible 1793 + * 10Base-T1S PHY. If SQI+ capability is supported, the function returns the 1794 + * extended SQI+ value; otherwise, it returns the basic SQI value. The SQI 1795 + * capability is updated on first invocation if it has not already been updated. 1796 + * 1797 + * Return: 1798 + * * SQI/SQI+ value on success 1799 + * * Negative errno on read failure 1800 + */ 1801 + int genphy_c45_oatc14_get_sqi(struct phy_device *phydev) 1802 + { 1803 + u8 shift; 1804 + int ret; 1805 + 1806 + if (!phydev->oatc14_sqi_capability.updated) { 1807 + ret = oatc14_update_sqi_capability(phydev); 1808 + if (ret) 1809 + return ret; 1810 + } 1811 + 1812 + /* Calculate and return SQI+ value if supported */ 1813 + if (phydev->oatc14_sqi_capability.sqiplus_bits) { 1814 + ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, 1815 + MDIO_OATC14_DCQ_SQIPLUS); 1816 + if (ret < 0) 1817 + return ret; 1818 + 1819 + /* SQI+ uses N MSBs out of 8 bits, left-aligned with padding 1's 1820 + * Calculate the right-shift needed to isolate the N bits. 1821 + */ 1822 + shift = 8 - phydev->oatc14_sqi_capability.sqiplus_bits; 1823 + 1824 + return (ret & OATC14_DCQ_SQIPLUS_VALUE) >> shift; 1825 + } 1826 + 1827 + /* Read and return SQI value if SQI+ capability is not supported */ 1828 + ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, MDIO_OATC14_DCQ_SQI); 1829 + if (ret < 0) 1830 + return ret; 1831 + 1832 + return ret & OATC14_DCQ_SQI_VALUE; 1833 + } 1834 + EXPORT_SYMBOL(genphy_c45_oatc14_get_sqi);
+29
include/linux/phy.h
··· 531 531 struct macsec_ops; 532 532 533 533 /** 534 + * struct phy_oatc14_sqi_capability - SQI capability information for OATC14 535 + * 10Base-T1S PHY 536 + * @updated: Indicates whether the SQI capability fields have been updated. 537 + * @sqi_max: Maximum supported Signal Quality Indicator (SQI) level reported by 538 + * the PHY. 539 + * @sqiplus_bits: Bits for SQI+ levels supported by the PHY. 540 + * 0 - SQI+ is not supported 541 + * 3 - SQI+ is supported, using 3 bits (8 levels) 542 + * 4 - SQI+ is supported, using 4 bits (16 levels) 543 + * 5 - SQI+ is supported, using 5 bits (32 levels) 544 + * 6 - SQI+ is supported, using 6 bits (64 levels) 545 + * 7 - SQI+ is supported, using 7 bits (128 levels) 546 + * 8 - SQI+ is supported, using 8 bits (256 levels) 547 + * 548 + * This structure is used by the OATC14 10Base-T1S PHY driver to store the SQI 549 + * and SQI+ capability information retrieved from the PHY. 550 + */ 551 + struct phy_oatc14_sqi_capability { 552 + bool updated; 553 + int sqi_max; 554 + u8 sqiplus_bits; 555 + }; 556 + 557 + /** 534 558 * struct phy_device - An instance of a PHY 535 559 * 536 560 * @mdio: MDIO bus this PHY is on ··· 650 626 * @link_down_events: Number of times link was lost 651 627 * @shared: Pointer to private data shared by phys in one package 652 628 * @priv: Pointer to driver private data 629 + * @oatc14_sqi_capability: SQI capability information for OATC14 10Base-T1S PHY 653 630 * 654 631 * interrupts currently only supports enabled or disabled, 655 632 * but could be changed in the future to support enabling ··· 797 772 /* MACsec management functions */ 798 773 const struct macsec_ops *macsec_ops; 799 774 #endif 775 + 776 + struct phy_oatc14_sqi_capability oatc14_sqi_capability; 800 777 }; 801 778 802 779 /* Generic phy_device::dev_flags */ ··· 2284 2257 int genphy_c45_oatc14_cable_test_start(struct phy_device *phydev); 2285 2258 int genphy_c45_oatc14_cable_test_get_status(struct phy_device *phydev, 2286 2259 bool *finished); 2260 + int genphy_c45_oatc14_get_sqi_max(struct phy_device *phydev); 2261 + int genphy_c45_oatc14_get_sqi(struct phy_device *phydev); 2287 2262 2288 2263 /* The gen10g_* functions are the old Clause 45 stub */ 2289 2264 int gen10g_config_aneg(struct phy_device *phydev);