mirror of
git://git.openwrt.org/openwrt/openwrt.git
synced 2025-12-06 12:44:00 -05:00
Backport of the latest upstream Realtek PHY patches. WoL uses devm_pm_set_wake_irq(), so the patch that adds this function has also been backported. Changelog: 4465ae435ddc net: phy: realtek: create rtl8211f_config_phy_eee() helper bb78b71faf60 net: phy: realtek: eliminate priv->phycr1 variable e1a31c41bef6 net: phy: realtek: allow CLKOUT to be disabled on RTL8211F(D)(I)-VD-CG 910ac7bfb1af net: phy: realtek: eliminate has_phycr2 variable 27033d069177 net: phy: realtek: eliminate priv->phycr2 variable 8e982441ba60 net: phy: realtek: create rtl8211f_config_rgmii_delay() b826bf795564 net: phy: realtek: fix RTL8211F wake-on-lan support Tested on Netgear WAX206 with RTL8221B-VB-CG. Signed-off-by: Aleksander Jan Bajkowski <olek2@wp.pl> Link: https://github.com/openwrt/openwrt/pull/20987 Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
273 lines
7.4 KiB
Diff
273 lines
7.4 KiB
Diff
From 61958b33ef0bab1c1874c933cd3910f495526782 Mon Sep 17 00:00:00 2001
|
|
From: Issam Hamdi <ih@simonwunderlich.de>
|
|
Date: Fri, 24 Oct 2025 11:49:00 +0200
|
|
Subject: [PATCH] net: phy: realtek: Add RTL8224 cable testing support
|
|
|
|
The RTL8224 can detect open pairs and short types (in same pair or some
|
|
other pair). The distance to this problem can be estimated. This is done
|
|
for each of the 4 pairs separately.
|
|
|
|
It is not meant to be run while there is an active link partner because
|
|
this interferes with the active test pulses.
|
|
|
|
Output with open 50 m cable:
|
|
|
|
Pair A code Open Circuit, source: TDR
|
|
Pair A, fault length: 51.79m, source: TDR
|
|
Pair B code Open Circuit, source: TDR
|
|
Pair B, fault length: 51.28m, source: TDR
|
|
Pair C code Open Circuit, source: TDR
|
|
Pair C, fault length: 50.46m, source: TDR
|
|
Pair D code Open Circuit, source: TDR
|
|
Pair D, fault length: 51.12m, source: TDR
|
|
|
|
Terminated cable:
|
|
|
|
Pair A code OK, source: TDR
|
|
Pair B code OK, source: TDR
|
|
Pair C code OK, source: TDR
|
|
Pair D code OK, source: TDR
|
|
|
|
Shorted cable (both short types are at roughly the same distance)
|
|
|
|
Pair A code Short to another pair, source: TDR
|
|
Pair A, fault length: 2.35m, source: TDR
|
|
Pair B code Short to another pair, source: TDR
|
|
Pair B, fault length: 2.15m, source: TDR
|
|
Pair C code OK, source: TDR
|
|
Pair D code Short within Pair, source: TDR
|
|
Pair D, fault length: 1.94m, source: TDR
|
|
|
|
Signed-off-by: Issam Hamdi <ih@simonwunderlich.de>
|
|
Co-developed-by: Sven Eckelmann <se@simonwunderlich.de>
|
|
Signed-off-by: Sven Eckelmann <se@simonwunderlich.de>
|
|
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
|
Link: https://patch.msgid.link/20251024-rtl8224-cable-test-v1-1-e3cda89ac98f@simonwunderlich.de
|
|
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
|
---
|
|
drivers/net/phy/realtek/realtek_main.c | 187 +++++++++++++++++++++++++
|
|
1 file changed, 187 insertions(+)
|
|
|
|
--- a/drivers/net/phy/realtek/realtek_main.c
|
|
+++ b/drivers/net/phy/realtek/realtek_main.c
|
|
@@ -8,6 +8,7 @@
|
|
* Copyright (c) 2004 Freescale Semiconductor, Inc.
|
|
*/
|
|
#include <linux/bitops.h>
|
|
+#include <linux/ethtool_netlink.h>
|
|
#include <linux/of.h>
|
|
#include <linux/phy.h>
|
|
#include <linux/pm_wakeirq.h>
|
|
@@ -127,6 +128,27 @@
|
|
*/
|
|
#define RTL822X_VND2_C22_REG(reg) (0xa400 + 2 * (reg))
|
|
|
|
+#define RTL8224_MII_RTCT 0x11
|
|
+#define RTL8224_MII_RTCT_ENABLE BIT(0)
|
|
+#define RTL8224_MII_RTCT_PAIR_A BIT(4)
|
|
+#define RTL8224_MII_RTCT_PAIR_B BIT(5)
|
|
+#define RTL8224_MII_RTCT_PAIR_C BIT(6)
|
|
+#define RTL8224_MII_RTCT_PAIR_D BIT(7)
|
|
+#define RTL8224_MII_RTCT_DONE BIT(15)
|
|
+
|
|
+#define RTL8224_MII_SRAM_ADDR 0x1b
|
|
+#define RTL8224_MII_SRAM_DATA 0x1c
|
|
+
|
|
+#define RTL8224_SRAM_RTCT_FAULT(pair) (0x8026 + (pair) * 4)
|
|
+#define RTL8224_SRAM_RTCT_FAULT_BUSY BIT(0)
|
|
+#define RTL8224_SRAM_RTCT_FAULT_OPEN BIT(3)
|
|
+#define RTL8224_SRAM_RTCT_FAULT_SAME_SHORT BIT(4)
|
|
+#define RTL8224_SRAM_RTCT_FAULT_OK BIT(5)
|
|
+#define RTL8224_SRAM_RTCT_FAULT_DONE BIT(6)
|
|
+#define RTL8224_SRAM_RTCT_FAULT_CROSS_SHORT BIT(7)
|
|
+
|
|
+#define RTL8224_SRAM_RTCT_LEN(pair) (0x8028 + (pair) * 4)
|
|
+
|
|
#define RTL8366RB_POWER_SAVE 0x15
|
|
#define RTL8366RB_POWER_SAVE_ON BIT(12)
|
|
|
|
@@ -1453,6 +1475,168 @@ static int rtl822xb_c45_read_status(stru
|
|
return 0;
|
|
}
|
|
|
|
+static int rtl8224_cable_test_start(struct phy_device *phydev)
|
|
+{
|
|
+ u32 val;
|
|
+ int ret;
|
|
+
|
|
+ /* disable auto-negotiation and force 1000/Full */
|
|
+ ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2,
|
|
+ RTL822X_VND2_C22_REG(MII_BMCR),
|
|
+ BMCR_ANENABLE | BMCR_SPEED100 | BMCR_SPEED10,
|
|
+ BMCR_SPEED1000 | BMCR_FULLDPLX);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ mdelay(500);
|
|
+
|
|
+ /* trigger cable test */
|
|
+ val = RTL8224_MII_RTCT_ENABLE;
|
|
+ val |= RTL8224_MII_RTCT_PAIR_A;
|
|
+ val |= RTL8224_MII_RTCT_PAIR_B;
|
|
+ val |= RTL8224_MII_RTCT_PAIR_C;
|
|
+ val |= RTL8224_MII_RTCT_PAIR_D;
|
|
+
|
|
+ return phy_modify_mmd(phydev, MDIO_MMD_VEND2,
|
|
+ RTL822X_VND2_C22_REG(RTL8224_MII_RTCT),
|
|
+ RTL8224_MII_RTCT_DONE, val);
|
|
+}
|
|
+
|
|
+static int rtl8224_sram_read(struct phy_device *phydev, u32 reg)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND2,
|
|
+ RTL822X_VND2_C22_REG(RTL8224_MII_SRAM_ADDR),
|
|
+ reg);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ return phy_read_mmd(phydev, MDIO_MMD_VEND2,
|
|
+ RTL822X_VND2_C22_REG(RTL8224_MII_SRAM_DATA));
|
|
+}
|
|
+
|
|
+static int rtl8224_pair_len_get(struct phy_device *phydev, u32 pair)
|
|
+{
|
|
+ int cable_len;
|
|
+ u32 reg_len;
|
|
+ int ret;
|
|
+ u32 cm;
|
|
+
|
|
+ reg_len = RTL8224_SRAM_RTCT_LEN(pair);
|
|
+
|
|
+ ret = rtl8224_sram_read(phydev, reg_len);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+
|
|
+ cable_len = ret & 0xff00;
|
|
+
|
|
+ ret = rtl8224_sram_read(phydev, reg_len + 1);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+
|
|
+ cable_len |= (ret & 0xff00) >> 8;
|
|
+
|
|
+ cable_len -= 620;
|
|
+ cable_len = max(cable_len, 0);
|
|
+
|
|
+ cm = cable_len * 100 / 78;
|
|
+
|
|
+ return cm;
|
|
+}
|
|
+
|
|
+static int rtl8224_cable_test_result_trans(u32 result)
|
|
+{
|
|
+ if (!(result & RTL8224_SRAM_RTCT_FAULT_DONE))
|
|
+ return -EBUSY;
|
|
+
|
|
+ if (result & RTL8224_SRAM_RTCT_FAULT_OK)
|
|
+ return ETHTOOL_A_CABLE_RESULT_CODE_OK;
|
|
+
|
|
+ if (result & RTL8224_SRAM_RTCT_FAULT_OPEN)
|
|
+ return ETHTOOL_A_CABLE_RESULT_CODE_OPEN;
|
|
+
|
|
+ if (result & RTL8224_SRAM_RTCT_FAULT_SAME_SHORT)
|
|
+ return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT;
|
|
+
|
|
+ if (result & RTL8224_SRAM_RTCT_FAULT_BUSY)
|
|
+ return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;
|
|
+
|
|
+ if (result & RTL8224_SRAM_RTCT_FAULT_CROSS_SHORT)
|
|
+ return ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT;
|
|
+
|
|
+ return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;
|
|
+}
|
|
+
|
|
+static int rtl8224_cable_test_report_pair(struct phy_device *phydev, unsigned int pair)
|
|
+{
|
|
+ int fault_rslt;
|
|
+ int ret;
|
|
+
|
|
+ ret = rtl8224_sram_read(phydev, RTL8224_SRAM_RTCT_FAULT(pair));
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+
|
|
+ fault_rslt = rtl8224_cable_test_result_trans(ret);
|
|
+ if (fault_rslt < 0)
|
|
+ return 0;
|
|
+
|
|
+ ret = ethnl_cable_test_result(phydev, pair, fault_rslt);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+
|
|
+ switch (fault_rslt) {
|
|
+ case ETHTOOL_A_CABLE_RESULT_CODE_OPEN:
|
|
+ case ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT:
|
|
+ case ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT:
|
|
+ ret = rtl8224_pair_len_get(phydev, pair);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+
|
|
+ return ethnl_cable_test_fault_length(phydev, pair, ret);
|
|
+ default:
|
|
+ return 0;
|
|
+ }
|
|
+}
|
|
+
|
|
+static int rtl8224_cable_test_report(struct phy_device *phydev, bool *finished)
|
|
+{
|
|
+ unsigned int pair;
|
|
+ int ret;
|
|
+
|
|
+ for (pair = ETHTOOL_A_CABLE_PAIR_A; pair <= ETHTOOL_A_CABLE_PAIR_D; pair++) {
|
|
+ ret = rtl8224_cable_test_report_pair(phydev, pair);
|
|
+ if (ret == -EBUSY) {
|
|
+ *finished = false;
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int rtl8224_cable_test_get_status(struct phy_device *phydev, bool *finished)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ *finished = false;
|
|
+
|
|
+ ret = phy_read_mmd(phydev, MDIO_MMD_VEND2,
|
|
+ RTL822X_VND2_C22_REG(RTL8224_MII_RTCT));
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+
|
|
+ if (!(ret & RTL8224_MII_RTCT_DONE))
|
|
+ return 0;
|
|
+
|
|
+ *finished = true;
|
|
+
|
|
+ return rtl8224_cable_test_report(phydev, finished);
|
|
+}
|
|
+
|
|
static bool rtlgen_supports_2_5gbps(struct phy_device *phydev)
|
|
{
|
|
int val;
|
|
@@ -1930,11 +2114,14 @@ static struct phy_driver realtek_drvs[]
|
|
}, {
|
|
PHY_ID_MATCH_EXACT(0x001ccad0),
|
|
.name = "RTL8224 2.5Gbps PHY",
|
|
+ .flags = PHY_POLL_CABLE_TEST,
|
|
.get_features = rtl822x_c45_get_features,
|
|
.config_aneg = rtl822x_c45_config_aneg,
|
|
.read_status = rtl822x_c45_read_status,
|
|
.suspend = genphy_c45_pma_suspend,
|
|
.resume = rtlgen_c45_resume,
|
|
+ .cable_test_start = rtl8224_cable_test_start,
|
|
+ .cable_test_get_status = rtl8224_cable_test_get_status,
|
|
}, {
|
|
PHY_ID_MATCH_EXACT(0x001cc961),
|
|
.name = "RTL8366RB Gigabit Ethernet",
|