From 1202140b297e7f20481c6ff46f5d98e1295e20e6 Mon Sep 17 00:00:00 2001 From: David Yang Date: Sat, 10 Oct 2026 01:59:30 +0800 Subject: [PATCH 1/3] dt-bindings: net: motorcomm: Add YT861x PHY compatible The YT861x GbE PHYs integrated in YT921x switches honour the "motorcomm,auto-sleep-disabled" device property like the other Motorcomm PHYs. Add ethernet-phy-id01e0.4281. Signed-off-by: David Yang Acked-by: Conor Dooley Link: https://patch.msgid.link/20261009175936.428256-2-mmyangfl@gmail.com Signed-off-by: Jakub Kicinski --- Documentation/devicetree/bindings/net/motorcomm,yt8xxx.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/net/motorcomm,yt8xxx.yaml b/Documentation/devicetree/bindings/net/motorcomm,yt8xxx.yaml index 26688e2302ea..85d01690c856 100644 --- a/Documentation/devicetree/bindings/net/motorcomm,yt8xxx.yaml +++ b/Documentation/devicetree/bindings/net/motorcomm,yt8xxx.yaml @@ -15,6 +15,7 @@ allOf: properties: compatible: enum: + - ethernet-phy-id01e0.4281 - ethernet-phy-id4f51.e91a - ethernet-phy-id4f51.e91b From ae0c7e8d0babb4d7b3935985a4ab2611de765ed5 Mon Sep 17 00:00:00 2001 From: David Yang Date: Sat, 10 Oct 2026 01:59:31 +0800 Subject: [PATCH 2/3] net: phy: motorcomm: Add driver entry for internal YT861x PHYs The YT921x switches integrate GbE PHYs of the YT861x family on the switch-internal MDIO bus exposed by the yt921x DSA driver. Add a driver entry for them. The PHY ID 0x01e04281 is live captured from the switch-internal MDIO bus. The switch SerDes PCS does follow the pattern, 0x4f51e899, though. Signed-off-by: David Yang Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/20261009175936.428256-3-mmyangfl@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/Kconfig | 3 ++- drivers/net/phy/motorcomm.c | 39 +++++++++++++++++++++++++++++++++++-- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index d3835597e379..30e9d22c8d1a 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -363,7 +363,8 @@ config MOTORCOMM_PHY tristate "Motorcomm PHYs" help Enables support for Motorcomm network PHYs. - Currently supports YT85xx Gigabit Ethernet PHYs. + Currently supports YT85xx Gigabit Ethernet PHYs, YT861x PHYs + integrated in YT921x switches, and YT8821 2.5Gbps PHYs. config NATIONAL_PHY tristate "National Semiconductor PHYs" diff --git a/drivers/net/phy/motorcomm.c b/drivers/net/phy/motorcomm.c index 90a4f86f2758..7078c4a0225d 100644 --- a/drivers/net/phy/motorcomm.c +++ b/drivers/net/phy/motorcomm.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * Motorcomm 8511/8521/8522/8531/8531S/8821 PHY driver. + * Motorcomm 8511/8521/8522/8531/8531S/861x/8821 PHY driver. * * Author: Peter Geis * Author: Frank @@ -18,6 +18,8 @@ #define PHY_ID_YT8522 0x4f51e928 #define PHY_ID_YT8531 0x4f51e91b #define PHY_ID_YT8531S 0x4f51e91a +/* Live captured from YT921x switch internal MDIO bus */ +#define PHY_ID_INT861X 0x01e04281 #define PHY_ID_YT8821 0x4f51ea19 /* YT8521/YT8531S/YT8821 Register Overview * UTP Register space | FIBER Register space @@ -2538,6 +2540,29 @@ static int yt8521_get_features(struct phy_device *phydev) return ret; } +/** + * yt861x_config_init() - apply the auto sleep setting to the PHY + * @phydev: a pointer to a &struct phy_device + * + * Auto sleep is enabled by default and a BMCR soft reset does not restore it, + * so apply the setting from config_init. It can be disabled with the + * "motorcomm,auto-sleep-disabled" device property. + * + * Returns: 0 or negative errno code + */ +static int yt861x_config_init(struct phy_device *phydev) +{ + bool sleep; + + sleep = !device_property_read_bool(&phydev->mdio.dev, + "motorcomm,auto-sleep-disabled"); + + return ytphy_modify_ext_with_lock(phydev, + YT8521_EXTREG_SLEEP_CONTROL1_REG, + YT8521_ESC1R_SLEEP_SW, + sleep ? YT8521_ESC1R_SLEEP_SW : 0); +} + /** * yt8821_get_features - read mmd register to get 2.5G capability * @phydev: target phy_device struct @@ -3173,6 +3198,15 @@ static struct phy_driver motorcomm_phy_drvs[] = { .suspend = yt8521_suspend, .resume = yt8521_resume, }, + { + PHY_ID_MATCH_EXACT(PHY_ID_INT861X), + .name = "YT861x Internal Gigabit Ethernet", + .flags = PHY_IS_INTERNAL, + .config_init = yt861x_config_init, + .soft_reset = genphy_soft_reset, + .suspend = genphy_suspend, + .resume = genphy_resume, + }, { PHY_ID_MATCH_EXACT(PHY_ID_YT8821), .name = "YT8821 2.5Gbps PHY", @@ -3194,7 +3228,7 @@ static struct phy_driver motorcomm_phy_drvs[] = { module_phy_driver(motorcomm_phy_drvs); -MODULE_DESCRIPTION("Motorcomm 8511/8521/8531/8531S/8821 PHY driver"); +MODULE_DESCRIPTION("Motorcomm 8511/8521/8531/8531S/861x/8821 PHY driver"); MODULE_AUTHOR("Peter Geis"); MODULE_AUTHOR("Frank"); MODULE_LICENSE("GPL"); @@ -3205,6 +3239,7 @@ static const struct mdio_device_id __maybe_unused motorcomm_tbl[] = { { PHY_ID_MATCH_EXACT(PHY_ID_YT8522) }, { PHY_ID_MATCH_EXACT(PHY_ID_YT8531) }, { PHY_ID_MATCH_EXACT(PHY_ID_YT8531S) }, + { PHY_ID_MATCH_EXACT(PHY_ID_INT861X) }, { PHY_ID_MATCH_EXACT(PHY_ID_YT8821) }, { /* sentinel */ } }; From fc697291ad0a49e19bab683b95dc3d9592223926 Mon Sep 17 00:00:00 2001 From: David Yang Date: Sat, 10 Oct 2026 01:59:32 +0800 Subject: [PATCH 3/3] net: phy: motorcomm: Add cable test support for internal YT861x PHYs Add TDR cable test support for the internal YT861x PHYs, reporting the per-pair result and the fault length. Signed-off-by: David Yang Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/20261009175936.428256-4-mmyangfl@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/motorcomm.c | 113 ++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) diff --git a/drivers/net/phy/motorcomm.c b/drivers/net/phy/motorcomm.c index 7078c4a0225d..463e1ea3efc9 100644 --- a/drivers/net/phy/motorcomm.c +++ b/drivers/net/phy/motorcomm.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -300,6 +301,19 @@ #define YT8531_SCR_CLK_SRC_REF_25M 4 #define YT8531_SCR_CLK_SRC_SSC_25M 5 +/* TDR (cable diagnostic) test control */ +#define YT861X_TDR_CTRL_REG 0x80 +#define YT861X_TDR_CTRL_START BIT(0) + +#define YT861X_TDR_STATUS_REG 0x84 +#define YT861X_TDR_STATUS_BUSY BIT(15) +#define YT861X_TDR_STATUS_PAIR_OK 0 +#define YT861X_TDR_STATUS_PAIR_UNKNOWN 1 +#define YT861X_TDR_STATUS_PAIR_SHORT 2 +#define YT861X_TDR_STATUS_PAIR_OPEN 3 + +#define YT861X_TDR_PAIR_LENGTH_REG(n) (0x87 + (n)) /* in cm */ + #define YT8821_SDS_EXT_CSR_CTRL_REG 0x23 #define YT8821_SDS_EXT_CSR_VCO_LDO_EN BIT(15) #define YT8821_SDS_EXT_CSR_VCO_BIAS_LPF_EN BIT(8) @@ -2563,6 +2577,103 @@ static int yt861x_config_init(struct phy_device *phydev) sleep ? YT8521_ESC1R_SLEEP_SW : 0); } +/** + * yt861x_cable_test_start() - start a cable diagnostic (TDR) test + * @phydev: a pointer to a &struct phy_device + * + * Returns: 0 or negative errno code + */ +static int yt861x_cable_test_start(struct phy_device *phydev) +{ + int ret; + + /* auto sleep would abort the TDR test */ + ret = ytphy_modify_ext_with_lock(phydev, + YT8521_EXTREG_SLEEP_CONTROL1_REG, + YT8521_ESC1R_SLEEP_SW, 0); + if (ret) + return ret; + + ret = ytphy_write_ext_with_lock(phydev, YT861X_TDR_CTRL_REG, + YT861X_TDR_CTRL_START); + if (ret) { + int err = yt861x_config_init(phydev); + + if (err) + phydev_warn(phydev, + "Failed to restore auto sleep: %d\n", + err); + } + + return ret; +} + +/** + * yt861x_cable_test_get_status() - report cable diagnostic test results + * @phydev: a pointer to a &struct phy_device + * @finished: set to true when the test is complete + * + * Returns: 0 or negative errno code + */ +static int yt861x_cable_test_get_status(struct phy_device *phydev, + bool *finished) +{ + int status; + int ret; + + *finished = false; + + status = ytphy_read_ext_with_lock(phydev, YT861X_TDR_STATUS_REG); + if (status < 0) + return status; + + if (status & YT861X_TDR_STATUS_BUSY) + return 0; + + for (int pair = ETHTOOL_A_CABLE_PAIR_A; pair <= ETHTOOL_A_CABLE_PAIR_D; + pair++) { + u8 code; + + switch ((status >> (2 * pair)) & 0x3) { + case YT861X_TDR_STATUS_PAIR_OK: + code = ETHTOOL_A_CABLE_RESULT_CODE_OK; + break; + case YT861X_TDR_STATUS_PAIR_SHORT: + code = ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT; + break; + case YT861X_TDR_STATUS_PAIR_OPEN: + code = ETHTOOL_A_CABLE_RESULT_CODE_OPEN; + break; + default: + code = ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC; + } + + ethnl_cable_test_result(phydev, pair, code); + + if (code != ETHTOOL_A_CABLE_RESULT_CODE_OK && + code != ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC) { + ret = ytphy_read_ext_with_lock(phydev, + YT861X_TDR_PAIR_LENGTH_REG(pair)); + if (ret >= 0) + ethnl_cable_test_fault_length(phydev, pair, + ret); + } + } + + /* the reset below does not restore auto sleep by itself */ + ret = yt861x_config_init(phydev); + if (ret) + return ret; + + ret = genphy_soft_reset(phydev); + if (ret) + return ret; + + *finished = true; + + return 0; +} + /** * yt8821_get_features - read mmd register to get 2.5G capability * @phydev: target phy_device struct @@ -3206,6 +3317,8 @@ static struct phy_driver motorcomm_phy_drvs[] = { .soft_reset = genphy_soft_reset, .suspend = genphy_suspend, .resume = genphy_resume, + .cable_test_start = yt861x_cable_test_start, + .cable_test_get_status = yt861x_cable_test_get_status, }, { PHY_ID_MATCH_EXACT(PHY_ID_YT8821),