kernel: backport upstream realtek PHY patches
Some checks are pending
Build Kernel / Build all affected Kernels (push) Waiting to run
Build all core packages / Build all core packages for selected target (push) Waiting to run

Changelog:
18aa36238a4d: net: phy: realtek: add interrupt support for RTL8221B
61958b33ef0b: net: phy: realtek: Add RTL8224 cable testing support
ffff5c8fc2af: net: phy: realtek: fix rtl8221b-vm-cg name
2c67301584f2: net: phy: realtek: Avoid PHYCR2 access if PHYCR2 not present
f63f21e82eca: net: phy: realtek: support for TRIGGER_NETDEV_LINK on RTL8211E and RTL8211F
a9b24b3583ae: net: phy: realtek: add error handling to rtl8211f_get_wol

Signed-off-by: Aleksander Jan Bajkowski <olek2@wp.pl>
Link: https://github.com/openwrt/openwrt/pull/20650
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
This commit is contained in:
Aleksander Jan Bajkowski 2025-11-02 16:11:08 +01:00 committed by Hauke Mehrtens
parent 35a86267e9
commit 787c1106d5
30 changed files with 1357 additions and 257 deletions

View file

@ -0,0 +1,39 @@
From a9b24b3583ae1da7dbda031f141264f2da260219 Mon Sep 17 00:00:00 2001
From: Daniel Braunwarth <daniel.braunwarth@kuka.com>
Date: Tue, 24 Jun 2025 16:17:33 +0200
Subject: [PATCH] net: phy: realtek: add error handling to rtl8211f_get_wol
We should check if the WOL settings was successfully read from the PHY.
In case this fails we cannot just use the error code and proceed.
Signed-off-by: Daniel Braunwarth <daniel.braunwarth@kuka.com>
Reported-by: Jon Hunter <jonathanh@nvidia.com>
Closes: https://lore.kernel.org/baaa083b-9a69-460f-ab35-2a7cb3246ffd@nvidia.com
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://patch.msgid.link/20250624-realtek_fixes-v1-1-02a0b7c369bc@kuka.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/phy/realtek/realtek_main.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
--- a/drivers/net/phy/realtek/realtek_main.c
+++ b/drivers/net/phy/realtek/realtek_main.c
@@ -436,9 +436,15 @@ static irqreturn_t rtl8211f_handle_inter
static void rtl8211f_get_wol(struct phy_device *dev, struct ethtool_wolinfo *wol)
{
+ int wol_events;
+
wol->supported = WAKE_MAGIC;
- if (phy_read_paged(dev, RTL8211F_WOL_SETTINGS_PAGE, RTL8211F_WOL_SETTINGS_EVENTS)
- & RTL8211F_WOL_EVENT_MAGIC)
+
+ wol_events = phy_read_paged(dev, RTL8211F_WOL_SETTINGS_PAGE, RTL8211F_WOL_SETTINGS_EVENTS);
+ if (wol_events < 0)
+ return;
+
+ if (wol_events & RTL8211F_WOL_EVENT_MAGIC)
wol->wolopts = WAKE_MAGIC;
}

View file

@ -0,0 +1,105 @@
From f63f21e82ecafd288b100ea161247820bf1e92c4 Mon Sep 17 00:00:00 2001
From: Aleksander Jan Bajkowski <olek2@wp.pl>
Date: Mon, 25 Aug 2025 23:09:49 +0200
Subject: [PATCH] net: phy: realtek: support for TRIGGER_NETDEV_LINK on
RTL8211E and RTL8211F
This patch adds support for the TRIGGER_NETDEV_LINK trigger. It activates
the LED when a link is established, regardless of the speed.
Tested on Orange Pi PC2 with RTL8211E PHY.
Signed-off-by: Aleksander Jan Bajkowski <olek2@wp.pl>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://patch.msgid.link/20250825211059.143231-1-olek2@wp.pl
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/phy/realtek/realtek_main.c | 39 +++++++++++++++++++++-----
1 file changed, 32 insertions(+), 7 deletions(-)
--- a/drivers/net/phy/realtek/realtek_main.c
+++ b/drivers/net/phy/realtek/realtek_main.c
@@ -648,7 +648,8 @@ static int rtl821x_resume(struct phy_dev
static int rtl8211x_led_hw_is_supported(struct phy_device *phydev, u8 index,
unsigned long rules)
{
- const unsigned long mask = BIT(TRIGGER_NETDEV_LINK_10) |
+ const unsigned long mask = BIT(TRIGGER_NETDEV_LINK) |
+ BIT(TRIGGER_NETDEV_LINK_10) |
BIT(TRIGGER_NETDEV_LINK_100) |
BIT(TRIGGER_NETDEV_LINK_1000) |
BIT(TRIGGER_NETDEV_RX) |
@@ -706,6 +707,12 @@ static int rtl8211f_led_hw_control_get(s
if (val & RTL8211F_LEDCR_LINK_1000)
__set_bit(TRIGGER_NETDEV_LINK_1000, rules);
+ if ((val & RTL8211F_LEDCR_LINK_10) &&
+ (val & RTL8211F_LEDCR_LINK_100) &&
+ (val & RTL8211F_LEDCR_LINK_1000)) {
+ __set_bit(TRIGGER_NETDEV_LINK, rules);
+ }
+
if (val & RTL8211F_LEDCR_ACT_TXRX) {
__set_bit(TRIGGER_NETDEV_RX, rules);
__set_bit(TRIGGER_NETDEV_TX, rules);
@@ -723,14 +730,20 @@ static int rtl8211f_led_hw_control_set(s
if (index >= RTL8211x_LED_COUNT)
return -EINVAL;
- if (test_bit(TRIGGER_NETDEV_LINK_10, &rules))
+ if (test_bit(TRIGGER_NETDEV_LINK, &rules) ||
+ test_bit(TRIGGER_NETDEV_LINK_10, &rules)) {
reg |= RTL8211F_LEDCR_LINK_10;
+ }
- if (test_bit(TRIGGER_NETDEV_LINK_100, &rules))
+ if (test_bit(TRIGGER_NETDEV_LINK, &rules) ||
+ test_bit(TRIGGER_NETDEV_LINK_100, &rules)) {
reg |= RTL8211F_LEDCR_LINK_100;
+ }
- if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules))
+ if (test_bit(TRIGGER_NETDEV_LINK, &rules) ||
+ test_bit(TRIGGER_NETDEV_LINK_1000, &rules)) {
reg |= RTL8211F_LEDCR_LINK_1000;
+ }
if (test_bit(TRIGGER_NETDEV_RX, &rules) ||
test_bit(TRIGGER_NETDEV_TX, &rules)) {
@@ -778,6 +791,12 @@ static int rtl8211e_led_hw_control_get(s
if (cr2 & RTL8211E_LEDCR2_LINK_1000)
__set_bit(TRIGGER_NETDEV_LINK_1000, rules);
+ if ((cr2 & RTL8211E_LEDCR2_LINK_10) &&
+ (cr2 & RTL8211E_LEDCR2_LINK_100) &&
+ (cr2 & RTL8211E_LEDCR2_LINK_1000)) {
+ __set_bit(TRIGGER_NETDEV_LINK, rules);
+ }
+
return ret;
}
@@ -805,14 +824,20 @@ static int rtl8211e_led_hw_control_set(s
if (ret < 0)
return ret;
- if (test_bit(TRIGGER_NETDEV_LINK_10, &rules))
+ if (test_bit(TRIGGER_NETDEV_LINK, &rules) ||
+ test_bit(TRIGGER_NETDEV_LINK_10, &rules)) {
cr2 |= RTL8211E_LEDCR2_LINK_10;
+ }
- if (test_bit(TRIGGER_NETDEV_LINK_100, &rules))
+ if (test_bit(TRIGGER_NETDEV_LINK, &rules) ||
+ test_bit(TRIGGER_NETDEV_LINK_100, &rules)) {
cr2 |= RTL8211E_LEDCR2_LINK_100;
+ }
- if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules))
+ if (test_bit(TRIGGER_NETDEV_LINK, &rules) ||
+ test_bit(TRIGGER_NETDEV_LINK_1000, &rules)) {
cr2 |= RTL8211E_LEDCR2_LINK_1000;
+ }
cr2 <<= RTL8211E_LEDCR2_SHIFT * index;
ret = rtl821x_modify_ext_page(phydev, RTL8211E_LEDCR_EXT_PAGE,

View file

@ -0,0 +1,61 @@
From 2c67301584f2671e320236df6bbe75ae09feb4d0 Mon Sep 17 00:00:00 2001
From: Marek Vasut <marek.vasut@mailbox.org>
Date: Sat, 11 Oct 2025 13:02:49 +0200
Subject: [PATCH] net: phy: realtek: Avoid PHYCR2 access if PHYCR2 not present
The driver is currently checking for PHYCR2 register presence in
rtl8211f_config_init(), but it does so after accessing PHYCR2 to
disable EEE. This was introduced in commit bfc17c165835 ("net:
phy: realtek: disable PHY-mode EEE"). Move the PHYCR2 presence
test before the EEE disablement and simplify the code.
Fixes: bfc17c165835 ("net: phy: realtek: disable PHY-mode EEE")
Signed-off-by: Marek Vasut <marek.vasut@mailbox.org>
Reviewed-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
Link: https://patch.msgid.link/20251011110309.12664-1-marek.vasut@mailbox.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/phy/realtek/realtek_main.c | 23 +++++++++++------------
1 file changed, 11 insertions(+), 12 deletions(-)
--- a/drivers/net/phy/realtek/realtek_main.c
+++ b/drivers/net/phy/realtek/realtek_main.c
@@ -589,26 +589,25 @@ static int rtl8211f_config_init(struct p
str_enabled_disabled(val_rxdly));
}
+ if (!priv->has_phycr2)
+ return 0;
+
/* Disable PHY-mode EEE so LPI is passed to the MAC */
ret = phy_modify_paged(phydev, RTL8211F_PHYCR_PAGE, RTL8211F_PHYCR2,
RTL8211F_PHYCR2_PHY_EEE_ENABLE, 0);
if (ret)
return ret;
- if (priv->has_phycr2) {
- ret = phy_modify_paged(phydev, RTL8211F_PHYCR_PAGE,
- RTL8211F_PHYCR2, RTL8211F_CLKOUT_EN,
- priv->phycr2);
- if (ret < 0) {
- dev_err(dev, "clkout configuration failed: %pe\n",
- ERR_PTR(ret));
- return ret;
- }
-
- return genphy_soft_reset(phydev);
+ ret = phy_modify_paged(phydev, RTL8211F_PHYCR_PAGE,
+ RTL8211F_PHYCR2, RTL8211F_CLKOUT_EN,
+ priv->phycr2);
+ if (ret < 0) {
+ dev_err(dev, "clkout configuration failed: %pe\n",
+ ERR_PTR(ret));
+ return ret;
}
- return 0;
+ return genphy_soft_reset(phydev);
}
static int rtl821x_suspend(struct phy_device *phydev)

View file

@ -0,0 +1,70 @@
From ffff5c8fc2af2218a3332b3d5b97654599d50cde Mon Sep 17 00:00:00 2001
From: Aleksander Jan Bajkowski <olek2@wp.pl>
Date: Thu, 16 Oct 2025 21:22:52 +0200
Subject: [PATCH] net: phy: realtek: fix rtl8221b-vm-cg name
When splitting the RTL8221B-VM-CG into C22 and C45 variants, the name was
accidentally changed to RTL8221B-VN-CG. This patch brings back the previous
part number.
Fixes: ad5ce743a6b0 ("net: phy: realtek: Add driver instances for rtl8221b via Clause 45")
Signed-off-by: Aleksander Jan Bajkowski <olek2@wp.pl>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20251016192325.2306757-1-olek2@wp.pl
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/phy/realtek/realtek_main.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
--- a/drivers/net/phy/realtek/realtek_main.c
+++ b/drivers/net/phy/realtek/realtek_main.c
@@ -156,7 +156,7 @@
#define RTL_8211FVD_PHYID 0x001cc878
#define RTL_8221B 0x001cc840
#define RTL_8221B_VB_CG 0x001cc849
-#define RTL_8221B_VN_CG 0x001cc84a
+#define RTL_8221B_VM_CG 0x001cc84a
#define RTL_8251B 0x001cc862
#define RTL_8261C 0x001cc890
@@ -1415,16 +1415,16 @@ static int rtl8221b_vb_cg_c45_match_phy_
return rtlgen_is_c45_match(phydev, RTL_8221B_VB_CG, true);
}
-static int rtl8221b_vn_cg_c22_match_phy_device(struct phy_device *phydev,
+static int rtl8221b_vm_cg_c22_match_phy_device(struct phy_device *phydev,
const struct phy_driver *phydrv)
{
- return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, false);
+ return rtlgen_is_c45_match(phydev, RTL_8221B_VM_CG, false);
}
-static int rtl8221b_vn_cg_c45_match_phy_device(struct phy_device *phydev,
+static int rtl8221b_vm_cg_c45_match_phy_device(struct phy_device *phydev,
const struct phy_driver *phydrv)
{
- return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, true);
+ return rtlgen_is_c45_match(phydev, RTL_8221B_VM_CG, true);
}
static int rtl_internal_nbaset_match_phy_device(struct phy_device *phydev,
@@ -1771,7 +1771,7 @@ static struct phy_driver realtek_drvs[]
.suspend = genphy_c45_pma_suspend,
.resume = rtlgen_c45_resume,
}, {
- .match_phy_device = rtl8221b_vn_cg_c22_match_phy_device,
+ .match_phy_device = rtl8221b_vm_cg_c22_match_phy_device,
.name = "RTL8221B-VM-CG 2.5Gbps PHY (C22)",
.probe = rtl822x_probe,
.get_features = rtl822x_get_features,
@@ -1784,8 +1784,8 @@ static struct phy_driver realtek_drvs[]
.read_page = rtl821x_read_page,
.write_page = rtl821x_write_page,
}, {
- .match_phy_device = rtl8221b_vn_cg_c45_match_phy_device,
- .name = "RTL8221B-VN-CG 2.5Gbps PHY (C45)",
+ .match_phy_device = rtl8221b_vm_cg_c45_match_phy_device,
+ .name = "RTL8221B-VM-CG 2.5Gbps PHY (C45)",
.probe = rtl822x_probe,
.config_init = rtl822xb_config_init,
.get_rate_matching = rtl822xb_get_rate_matching,

View file

@ -0,0 +1,272 @@
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/netdevice.h>
@@ -129,6 +130,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)
@@ -1345,6 +1367,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;
@@ -1822,11 +2006,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",

View file

@ -0,0 +1,105 @@
From 18aa36238a4d835c1644dcccd63d32c7fdd4b310 Mon Sep 17 00:00:00 2001
From: Jianhui Zhao <zhaojh329@gmail.com>
Date: Sun, 2 Nov 2025 16:26:37 +0100
Subject: [PATCH] net: phy: realtek: add interrupt support for RTL8221B
This commit introduces interrupt support for RTL8221B (C45 mode).
Interrupts are mapped on the VEND2 page. VEND2 registers are only
accessible via C45 reads and cannot be accessed by C45 over C22.
Signed-off-by: Jianhui Zhao <zhaojh329@gmail.com>
[Enable only link state change interrupts]
Signed-off-by: Aleksander Jan Bajkowski <olek2@wp.pl>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://patch.msgid.link/20251102152644.1676482-1-olek2@wp.pl
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/phy/realtek/realtek_main.c | 56 ++++++++++++++++++++++++++
1 file changed, 56 insertions(+)
--- a/drivers/net/phy/realtek/realtek_main.c
+++ b/drivers/net/phy/realtek/realtek_main.c
@@ -130,6 +130,11 @@
*/
#define RTL822X_VND2_C22_REG(reg) (0xa400 + 2 * (reg))
+#define RTL8221B_VND2_INER 0xa4d2
+#define RTL8221B_VND2_INER_LINK_STATUS BIT(4)
+
+#define RTL8221B_VND2_INSR 0xa4d4
+
#define RTL8224_MII_RTCT 0x11
#define RTL8224_MII_RTCT_ENABLE BIT(0)
#define RTL8224_MII_RTCT_PAIR_A BIT(4)
@@ -1772,6 +1777,53 @@ static irqreturn_t rtl9000a_handle_inter
return IRQ_HANDLED;
}
+static int rtl8221b_ack_interrupt(struct phy_device *phydev)
+{
+ int err;
+
+ err = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL8221B_VND2_INSR);
+
+ return (err < 0) ? err : 0;
+}
+
+static int rtl8221b_config_intr(struct phy_device *phydev)
+{
+ int err;
+
+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
+ err = rtl8221b_ack_interrupt(phydev);
+ if (err)
+ return err;
+
+ err = phy_write_mmd(phydev, MDIO_MMD_VEND2, RTL8221B_VND2_INER,
+ RTL8221B_VND2_INER_LINK_STATUS);
+ } else {
+ err = phy_write_mmd(phydev, MDIO_MMD_VEND2,
+ RTL8221B_VND2_INER, 0);
+ if (err)
+ return err;
+
+ err = rtl8221b_ack_interrupt(phydev);
+ }
+
+ return err;
+}
+
+static irqreturn_t rtl8221b_handle_interrupt(struct phy_device *phydev)
+{
+ int err;
+
+ err = rtl8221b_ack_interrupt(phydev);
+ if (err) {
+ phy_error(phydev);
+ return IRQ_NONE;
+ }
+
+ phy_trigger_machine(phydev);
+
+ return IRQ_HANDLED;
+}
+
static struct phy_driver realtek_drvs[] = {
{
PHY_ID_MATCH_EXACT(0x00008201),
@@ -1946,6 +1998,8 @@ static struct phy_driver realtek_drvs[]
}, {
.match_phy_device = rtl8221b_vb_cg_c45_match_phy_device,
.name = "RTL8221B-VB-CG 2.5Gbps PHY (C45)",
+ .config_intr = rtl8221b_config_intr,
+ .handle_interrupt = rtl8221b_handle_interrupt,
.probe = rtl822x_probe,
.config_init = rtl822xb_config_init,
.get_rate_matching = rtl822xb_get_rate_matching,
@@ -1970,6 +2024,8 @@ static struct phy_driver realtek_drvs[]
}, {
.match_phy_device = rtl8221b_vm_cg_c45_match_phy_device,
.name = "RTL8221B-VM-CG 2.5Gbps PHY (C45)",
+ .config_intr = rtl8221b_config_intr,
+ .handle_interrupt = rtl8221b_handle_interrupt,
.probe = rtl822x_probe,
.config_init = rtl822xb_config_init,
.get_rate_matching = rtl822xb_get_rate_matching,

View file

@ -0,0 +1,39 @@
From a9b24b3583ae1da7dbda031f141264f2da260219 Mon Sep 17 00:00:00 2001
From: Daniel Braunwarth <daniel.braunwarth@kuka.com>
Date: Tue, 24 Jun 2025 16:17:33 +0200
Subject: [PATCH] net: phy: realtek: add error handling to rtl8211f_get_wol
We should check if the WOL settings was successfully read from the PHY.
In case this fails we cannot just use the error code and proceed.
Signed-off-by: Daniel Braunwarth <daniel.braunwarth@kuka.com>
Reported-by: Jon Hunter <jonathanh@nvidia.com>
Closes: https://lore.kernel.org/baaa083b-9a69-460f-ab35-2a7cb3246ffd@nvidia.com
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://patch.msgid.link/20250624-realtek_fixes-v1-1-02a0b7c369bc@kuka.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/phy/realtek/realtek_main.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
--- a/drivers/net/phy/realtek/realtek_main.c
+++ b/drivers/net/phy/realtek/realtek_main.c
@@ -436,9 +436,15 @@ static irqreturn_t rtl8211f_handle_inter
static void rtl8211f_get_wol(struct phy_device *dev, struct ethtool_wolinfo *wol)
{
+ int wol_events;
+
wol->supported = WAKE_MAGIC;
- if (phy_read_paged(dev, RTL8211F_WOL_SETTINGS_PAGE, RTL8211F_WOL_SETTINGS_EVENTS)
- & RTL8211F_WOL_EVENT_MAGIC)
+
+ wol_events = phy_read_paged(dev, RTL8211F_WOL_SETTINGS_PAGE, RTL8211F_WOL_SETTINGS_EVENTS);
+ if (wol_events < 0)
+ return;
+
+ if (wol_events & RTL8211F_WOL_EVENT_MAGIC)
wol->wolopts = WAKE_MAGIC;
}

View file

@ -0,0 +1,105 @@
From f63f21e82ecafd288b100ea161247820bf1e92c4 Mon Sep 17 00:00:00 2001
From: Aleksander Jan Bajkowski <olek2@wp.pl>
Date: Mon, 25 Aug 2025 23:09:49 +0200
Subject: [PATCH] net: phy: realtek: support for TRIGGER_NETDEV_LINK on
RTL8211E and RTL8211F
This patch adds support for the TRIGGER_NETDEV_LINK trigger. It activates
the LED when a link is established, regardless of the speed.
Tested on Orange Pi PC2 with RTL8211E PHY.
Signed-off-by: Aleksander Jan Bajkowski <olek2@wp.pl>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://patch.msgid.link/20250825211059.143231-1-olek2@wp.pl
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/phy/realtek/realtek_main.c | 39 +++++++++++++++++++++-----
1 file changed, 32 insertions(+), 7 deletions(-)
--- a/drivers/net/phy/realtek/realtek_main.c
+++ b/drivers/net/phy/realtek/realtek_main.c
@@ -648,7 +648,8 @@ static int rtl821x_resume(struct phy_dev
static int rtl8211x_led_hw_is_supported(struct phy_device *phydev, u8 index,
unsigned long rules)
{
- const unsigned long mask = BIT(TRIGGER_NETDEV_LINK_10) |
+ const unsigned long mask = BIT(TRIGGER_NETDEV_LINK) |
+ BIT(TRIGGER_NETDEV_LINK_10) |
BIT(TRIGGER_NETDEV_LINK_100) |
BIT(TRIGGER_NETDEV_LINK_1000) |
BIT(TRIGGER_NETDEV_RX) |
@@ -706,6 +707,12 @@ static int rtl8211f_led_hw_control_get(s
if (val & RTL8211F_LEDCR_LINK_1000)
__set_bit(TRIGGER_NETDEV_LINK_1000, rules);
+ if ((val & RTL8211F_LEDCR_LINK_10) &&
+ (val & RTL8211F_LEDCR_LINK_100) &&
+ (val & RTL8211F_LEDCR_LINK_1000)) {
+ __set_bit(TRIGGER_NETDEV_LINK, rules);
+ }
+
if (val & RTL8211F_LEDCR_ACT_TXRX) {
__set_bit(TRIGGER_NETDEV_RX, rules);
__set_bit(TRIGGER_NETDEV_TX, rules);
@@ -723,14 +730,20 @@ static int rtl8211f_led_hw_control_set(s
if (index >= RTL8211x_LED_COUNT)
return -EINVAL;
- if (test_bit(TRIGGER_NETDEV_LINK_10, &rules))
+ if (test_bit(TRIGGER_NETDEV_LINK, &rules) ||
+ test_bit(TRIGGER_NETDEV_LINK_10, &rules)) {
reg |= RTL8211F_LEDCR_LINK_10;
+ }
- if (test_bit(TRIGGER_NETDEV_LINK_100, &rules))
+ if (test_bit(TRIGGER_NETDEV_LINK, &rules) ||
+ test_bit(TRIGGER_NETDEV_LINK_100, &rules)) {
reg |= RTL8211F_LEDCR_LINK_100;
+ }
- if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules))
+ if (test_bit(TRIGGER_NETDEV_LINK, &rules) ||
+ test_bit(TRIGGER_NETDEV_LINK_1000, &rules)) {
reg |= RTL8211F_LEDCR_LINK_1000;
+ }
if (test_bit(TRIGGER_NETDEV_RX, &rules) ||
test_bit(TRIGGER_NETDEV_TX, &rules)) {
@@ -778,6 +791,12 @@ static int rtl8211e_led_hw_control_get(s
if (cr2 & RTL8211E_LEDCR2_LINK_1000)
__set_bit(TRIGGER_NETDEV_LINK_1000, rules);
+ if ((cr2 & RTL8211E_LEDCR2_LINK_10) &&
+ (cr2 & RTL8211E_LEDCR2_LINK_100) &&
+ (cr2 & RTL8211E_LEDCR2_LINK_1000)) {
+ __set_bit(TRIGGER_NETDEV_LINK, rules);
+ }
+
return ret;
}
@@ -805,14 +824,20 @@ static int rtl8211e_led_hw_control_set(s
if (ret < 0)
return ret;
- if (test_bit(TRIGGER_NETDEV_LINK_10, &rules))
+ if (test_bit(TRIGGER_NETDEV_LINK, &rules) ||
+ test_bit(TRIGGER_NETDEV_LINK_10, &rules)) {
cr2 |= RTL8211E_LEDCR2_LINK_10;
+ }
- if (test_bit(TRIGGER_NETDEV_LINK_100, &rules))
+ if (test_bit(TRIGGER_NETDEV_LINK, &rules) ||
+ test_bit(TRIGGER_NETDEV_LINK_100, &rules)) {
cr2 |= RTL8211E_LEDCR2_LINK_100;
+ }
- if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules))
+ if (test_bit(TRIGGER_NETDEV_LINK, &rules) ||
+ test_bit(TRIGGER_NETDEV_LINK_1000, &rules)) {
cr2 |= RTL8211E_LEDCR2_LINK_1000;
+ }
cr2 <<= RTL8211E_LEDCR2_SHIFT * index;
ret = rtl821x_modify_ext_page(phydev, RTL8211E_LEDCR_EXT_PAGE,

View file

@ -0,0 +1,61 @@
From 2c67301584f2671e320236df6bbe75ae09feb4d0 Mon Sep 17 00:00:00 2001
From: Marek Vasut <marek.vasut@mailbox.org>
Date: Sat, 11 Oct 2025 13:02:49 +0200
Subject: [PATCH] net: phy: realtek: Avoid PHYCR2 access if PHYCR2 not present
The driver is currently checking for PHYCR2 register presence in
rtl8211f_config_init(), but it does so after accessing PHYCR2 to
disable EEE. This was introduced in commit bfc17c165835 ("net:
phy: realtek: disable PHY-mode EEE"). Move the PHYCR2 presence
test before the EEE disablement and simplify the code.
Fixes: bfc17c165835 ("net: phy: realtek: disable PHY-mode EEE")
Signed-off-by: Marek Vasut <marek.vasut@mailbox.org>
Reviewed-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
Link: https://patch.msgid.link/20251011110309.12664-1-marek.vasut@mailbox.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/phy/realtek/realtek_main.c | 23 +++++++++++------------
1 file changed, 11 insertions(+), 12 deletions(-)
--- a/drivers/net/phy/realtek/realtek_main.c
+++ b/drivers/net/phy/realtek/realtek_main.c
@@ -589,26 +589,25 @@ static int rtl8211f_config_init(struct p
str_enabled_disabled(val_rxdly));
}
+ if (!priv->has_phycr2)
+ return 0;
+
/* Disable PHY-mode EEE so LPI is passed to the MAC */
ret = phy_modify_paged(phydev, RTL8211F_PHYCR_PAGE, RTL8211F_PHYCR2,
RTL8211F_PHYCR2_PHY_EEE_ENABLE, 0);
if (ret)
return ret;
- if (priv->has_phycr2) {
- ret = phy_modify_paged(phydev, RTL8211F_PHYCR_PAGE,
- RTL8211F_PHYCR2, RTL8211F_CLKOUT_EN,
- priv->phycr2);
- if (ret < 0) {
- dev_err(dev, "clkout configuration failed: %pe\n",
- ERR_PTR(ret));
- return ret;
- }
-
- return genphy_soft_reset(phydev);
+ ret = phy_modify_paged(phydev, RTL8211F_PHYCR_PAGE,
+ RTL8211F_PHYCR2, RTL8211F_CLKOUT_EN,
+ priv->phycr2);
+ if (ret < 0) {
+ dev_err(dev, "clkout configuration failed: %pe\n",
+ ERR_PTR(ret));
+ return ret;
}
- return 0;
+ return genphy_soft_reset(phydev);
}
static int rtl821x_suspend(struct phy_device *phydev)

View file

@ -0,0 +1,70 @@
From ffff5c8fc2af2218a3332b3d5b97654599d50cde Mon Sep 17 00:00:00 2001
From: Aleksander Jan Bajkowski <olek2@wp.pl>
Date: Thu, 16 Oct 2025 21:22:52 +0200
Subject: [PATCH] net: phy: realtek: fix rtl8221b-vm-cg name
When splitting the RTL8221B-VM-CG into C22 and C45 variants, the name was
accidentally changed to RTL8221B-VN-CG. This patch brings back the previous
part number.
Fixes: ad5ce743a6b0 ("net: phy: realtek: Add driver instances for rtl8221b via Clause 45")
Signed-off-by: Aleksander Jan Bajkowski <olek2@wp.pl>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20251016192325.2306757-1-olek2@wp.pl
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/phy/realtek/realtek_main.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
--- a/drivers/net/phy/realtek/realtek_main.c
+++ b/drivers/net/phy/realtek/realtek_main.c
@@ -156,7 +156,7 @@
#define RTL_8211FVD_PHYID 0x001cc878
#define RTL_8221B 0x001cc840
#define RTL_8221B_VB_CG 0x001cc849
-#define RTL_8221B_VN_CG 0x001cc84a
+#define RTL_8221B_VM_CG 0x001cc84a
#define RTL_8251B 0x001cc862
#define RTL_8261C 0x001cc890
@@ -1387,16 +1387,16 @@ static int rtl8221b_vb_cg_c45_match_phy_
return rtlgen_is_c45_match(phydev, RTL_8221B_VB_CG, true);
}
-static int rtl8221b_vn_cg_c22_match_phy_device(struct phy_device *phydev,
+static int rtl8221b_vm_cg_c22_match_phy_device(struct phy_device *phydev,
const struct phy_driver *phydrv)
{
- return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, false);
+ return rtlgen_is_c45_match(phydev, RTL_8221B_VM_CG, false);
}
-static int rtl8221b_vn_cg_c45_match_phy_device(struct phy_device *phydev,
+static int rtl8221b_vm_cg_c45_match_phy_device(struct phy_device *phydev,
const struct phy_driver *phydrv)
{
- return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, true);
+ return rtlgen_is_c45_match(phydev, RTL_8221B_VM_CG, true);
}
static int rtl_internal_nbaset_match_phy_device(struct phy_device *phydev,
@@ -1743,7 +1743,7 @@ static struct phy_driver realtek_drvs[]
.suspend = genphy_c45_pma_suspend,
.resume = rtlgen_c45_resume,
}, {
- .match_phy_device = rtl8221b_vn_cg_c22_match_phy_device,
+ .match_phy_device = rtl8221b_vm_cg_c22_match_phy_device,
.name = "RTL8221B-VM-CG 2.5Gbps PHY (C22)",
.probe = rtl822x_probe,
.get_features = rtl822x_get_features,
@@ -1756,8 +1756,8 @@ static struct phy_driver realtek_drvs[]
.read_page = rtl821x_read_page,
.write_page = rtl821x_write_page,
}, {
- .match_phy_device = rtl8221b_vn_cg_c45_match_phy_device,
- .name = "RTL8221B-VN-CG 2.5Gbps PHY (C45)",
+ .match_phy_device = rtl8221b_vm_cg_c45_match_phy_device,
+ .name = "RTL8221B-VM-CG 2.5Gbps PHY (C45)",
.probe = rtl822x_probe,
.config_init = rtl822xb_config_init,
.get_rate_matching = rtl822xb_get_rate_matching,

View file

@ -0,0 +1,272 @@
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/netdevice.h>
@@ -129,6 +130,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)
@@ -1317,6 +1339,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;
@@ -1794,11 +1978,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",

View file

@ -0,0 +1,105 @@
From 18aa36238a4d835c1644dcccd63d32c7fdd4b310 Mon Sep 17 00:00:00 2001
From: Jianhui Zhao <zhaojh329@gmail.com>
Date: Sun, 2 Nov 2025 16:26:37 +0100
Subject: [PATCH] net: phy: realtek: add interrupt support for RTL8221B
This commit introduces interrupt support for RTL8221B (C45 mode).
Interrupts are mapped on the VEND2 page. VEND2 registers are only
accessible via C45 reads and cannot be accessed by C45 over C22.
Signed-off-by: Jianhui Zhao <zhaojh329@gmail.com>
[Enable only link state change interrupts]
Signed-off-by: Aleksander Jan Bajkowski <olek2@wp.pl>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://patch.msgid.link/20251102152644.1676482-1-olek2@wp.pl
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/phy/realtek/realtek_main.c | 56 ++++++++++++++++++++++++++
1 file changed, 56 insertions(+)
--- a/drivers/net/phy/realtek/realtek_main.c
+++ b/drivers/net/phy/realtek/realtek_main.c
@@ -130,6 +130,11 @@
*/
#define RTL822X_VND2_C22_REG(reg) (0xa400 + 2 * (reg))
+#define RTL8221B_VND2_INER 0xa4d2
+#define RTL8221B_VND2_INER_LINK_STATUS BIT(4)
+
+#define RTL8221B_VND2_INSR 0xa4d4
+
#define RTL8224_MII_RTCT 0x11
#define RTL8224_MII_RTCT_ENABLE BIT(0)
#define RTL8224_MII_RTCT_PAIR_A BIT(4)
@@ -1744,6 +1749,53 @@ static irqreturn_t rtl9000a_handle_inter
return IRQ_HANDLED;
}
+static int rtl8221b_ack_interrupt(struct phy_device *phydev)
+{
+ int err;
+
+ err = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL8221B_VND2_INSR);
+
+ return (err < 0) ? err : 0;
+}
+
+static int rtl8221b_config_intr(struct phy_device *phydev)
+{
+ int err;
+
+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
+ err = rtl8221b_ack_interrupt(phydev);
+ if (err)
+ return err;
+
+ err = phy_write_mmd(phydev, MDIO_MMD_VEND2, RTL8221B_VND2_INER,
+ RTL8221B_VND2_INER_LINK_STATUS);
+ } else {
+ err = phy_write_mmd(phydev, MDIO_MMD_VEND2,
+ RTL8221B_VND2_INER, 0);
+ if (err)
+ return err;
+
+ err = rtl8221b_ack_interrupt(phydev);
+ }
+
+ return err;
+}
+
+static irqreturn_t rtl8221b_handle_interrupt(struct phy_device *phydev)
+{
+ int err;
+
+ err = rtl8221b_ack_interrupt(phydev);
+ if (err) {
+ phy_error(phydev);
+ return IRQ_NONE;
+ }
+
+ phy_trigger_machine(phydev);
+
+ return IRQ_HANDLED;
+}
+
static struct phy_driver realtek_drvs[] = {
{
PHY_ID_MATCH_EXACT(0x00008201),
@@ -1918,6 +1970,8 @@ static struct phy_driver realtek_drvs[]
}, {
.match_phy_device = rtl8221b_vb_cg_c45_match_phy_device,
.name = "RTL8221B-VB-CG 2.5Gbps PHY (C45)",
+ .config_intr = rtl8221b_config_intr,
+ .handle_interrupt = rtl8221b_handle_interrupt,
.probe = rtl822x_probe,
.config_init = rtl822xb_config_init,
.get_rate_matching = rtl822xb_get_rate_matching,
@@ -1942,6 +1996,8 @@ static struct phy_driver realtek_drvs[]
}, {
.match_phy_device = rtl8221b_vm_cg_c45_match_phy_device,
.name = "RTL8221B-VM-CG 2.5Gbps PHY (C45)",
+ .config_intr = rtl8221b_config_intr,
+ .handle_interrupt = rtl8221b_handle_interrupt,
.probe = rtl822x_probe,
.config_init = rtl822xb_config_init,
.get_rate_matching = rtl822xb_get_rate_matching,

View file

@ -15,7 +15,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
--- a/drivers/net/phy/realtek/realtek_main.c
+++ b/drivers/net/phy/realtek/realtek_main.c
@@ -1675,6 +1675,7 @@ static struct phy_driver realtek_drvs[]
@@ -1941,6 +1941,7 @@ static struct phy_driver realtek_drvs[]
}, {
.name = "RTL8226 2.5Gbps PHY",
.match_phy_device = rtl8226_match_phy_device,
@ -23,7 +23,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
.get_features = rtl822x_get_features,
.config_aneg = rtl822x_config_aneg,
.read_status = rtl822x_read_status,
@@ -1685,6 +1686,7 @@ static struct phy_driver realtek_drvs[]
@@ -1951,6 +1952,7 @@ static struct phy_driver realtek_drvs[]
}, {
.match_phy_device = rtl8221b_match_phy_device,
.name = "RTL8226B_RTL8221B 2.5Gbps PHY",
@ -31,7 +31,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
.get_features = rtl822x_get_features,
.config_aneg = rtl822x_config_aneg,
.config_init = rtl822xb_config_init,
@@ -1707,6 +1709,7 @@ static struct phy_driver realtek_drvs[]
@@ -1973,6 +1975,7 @@ static struct phy_driver realtek_drvs[]
}, {
PHY_ID_MATCH_EXACT(0x001cc848),
.name = "RTL8226B-CG_RTL8221B-CG 2.5Gbps PHY",
@ -39,7 +39,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
.get_features = rtl822x_get_features,
.config_aneg = rtl822x_config_aneg,
.config_init = rtl822xb_config_init,
@@ -1719,6 +1722,7 @@ static struct phy_driver realtek_drvs[]
@@ -1985,6 +1988,7 @@ static struct phy_driver realtek_drvs[]
}, {
.match_phy_device = rtl8221b_vb_cg_c22_match_phy_device,
.name = "RTL8221B-VB-CG 2.5Gbps PHY (C22)",
@ -47,26 +47,26 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
.probe = rtl822x_probe,
.get_features = rtl822x_get_features,
.config_aneg = rtl822x_config_aneg,
@@ -1732,6 +1736,7 @@ static struct phy_driver realtek_drvs[]
}, {
.match_phy_device = rtl8221b_vb_cg_c45_match_phy_device,
@@ -2000,6 +2004,7 @@ static struct phy_driver realtek_drvs[]
.name = "RTL8221B-VB-CG 2.5Gbps PHY (C45)",
.config_intr = rtl8221b_config_intr,
.handle_interrupt = rtl8221b_handle_interrupt,
+ .soft_reset = rtl822x_c45_soft_reset,
.probe = rtl822x_probe,
.config_init = rtl822xb_config_init,
.get_rate_matching = rtl822xb_get_rate_matching,
@@ -1743,6 +1748,7 @@ static struct phy_driver realtek_drvs[]
@@ -2011,6 +2016,7 @@ static struct phy_driver realtek_drvs[]
}, {
.match_phy_device = rtl8221b_vn_cg_c22_match_phy_device,
.match_phy_device = rtl8221b_vm_cg_c22_match_phy_device,
.name = "RTL8221B-VM-CG 2.5Gbps PHY (C22)",
+ .soft_reset = genphy_soft_reset,
.probe = rtl822x_probe,
.get_features = rtl822x_get_features,
.config_aneg = rtl822x_config_aneg,
@@ -1756,6 +1762,7 @@ static struct phy_driver realtek_drvs[]
}, {
.match_phy_device = rtl8221b_vn_cg_c45_match_phy_device,
.name = "RTL8221B-VN-CG 2.5Gbps PHY (C45)",
@@ -2026,6 +2032,7 @@ static struct phy_driver realtek_drvs[]
.name = "RTL8221B-VM-CG 2.5Gbps PHY (C45)",
.config_intr = rtl8221b_config_intr,
.handle_interrupt = rtl8221b_handle_interrupt,
+ .soft_reset = rtl822x_c45_soft_reset,
.probe = rtl822x_probe,
.config_init = rtl822xb_config_init,

View file

@ -20,7 +20,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
--- a/drivers/net/phy/realtek/realtek_main.c
+++ b/drivers/net/phy/realtek/realtek_main.c
@@ -1035,8 +1035,8 @@ static int rtl822x_probe(struct phy_devi
@@ -1092,8 +1092,8 @@ static int rtl822x_probe(struct phy_devi
static int rtl822x_set_serdes_option_mode(struct phy_device *phydev, bool gen1)
{
bool has_2500, has_sgmii;
@ -30,7 +30,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
has_2500 = test_bit(PHY_INTERFACE_MODE_2500BASEX,
phydev->host_interfaces) ||
@@ -1078,18 +1078,42 @@ static int rtl822x_set_serdes_option_mod
@@ -1135,18 +1135,42 @@ static int rtl822x_set_serdes_option_mod
RTL822X_VND1_SERDES_OPTION,
RTL822X_VND1_SERDES_OPTION_MODE_MASK,
mode);

View file

@ -18,7 +18,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
--- a/drivers/net/phy/realtek/realtek_main.c
+++ b/drivers/net/phy/realtek/realtek_main.c
@@ -1343,9 +1343,11 @@ static bool rtlgen_supports_2_5gbps(stru
@@ -1562,9 +1562,11 @@ static bool rtlgen_supports_2_5gbps(stru
{
int val;

View file

@ -13,9 +13,9 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
--- a/drivers/net/phy/realtek/realtek_main.c
+++ b/drivers/net/phy/realtek/realtek_main.c
@@ -129,6 +129,10 @@
*/
#define RTL822X_VND2_C22_REG(reg) (0xa400 + 2 * (reg))
@@ -156,6 +156,10 @@
#define RTL8224_SRAM_RTCT_LEN(pair) (0x8028 + (pair) * 4)
+#define RTL8221B_PHYCR1 0xa430
+#define RTL8221B_PHYCR1_ALDPS_EN BIT(2)
@ -24,7 +24,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
#define RTL8366RB_POWER_SAVE 0x15
#define RTL8366RB_POWER_SAVE_ON BIT(12)
@@ -1095,6 +1099,15 @@ static int rtl822x_set_serdes_option_mod
@@ -1152,6 +1156,15 @@ static int rtl822x_set_serdes_option_mod
return ret;
}

View file

@ -14,7 +14,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
Signed-off-by: Mieczyslaw Nalewaj <namiltd@yahoo.com>
--- a/drivers/net/phy/realtek/realtek_main.c
+++ b/drivers/net/phy/realtek/realtek_main.c
@@ -1400,10 +1400,32 @@ static int rtl8226_match_phy_device(stru
@@ -1619,10 +1619,32 @@ static int rtl8226_match_phy_device(stru
static int rtlgen_is_c45_match(struct phy_device *phydev, unsigned int id,
bool is_c45)
{

View file

@ -1,102 +0,0 @@
From d7943c31d57c11e1a517aa3ce2006fca44866870 Mon Sep 17 00:00:00 2001
From: Jianhui Zhao <zhaojh329@gmail.com>
Date: Sun, 24 Sep 2023 22:15:00 +0800
Subject: [PATCH] net: phy: realtek: add interrupt support for RTL8221B
This commit introduces interrupt support for RTL8221B.
Signed-off-by: Jianhui Zhao <zhaojh329@gmail.com>
---
drivers/net/phy/realtek/realtek_main.c | 47 +++++++++++++++++++++++++++++++++++++++
1 file changed, 47 insertions(+)
--- a/drivers/net/phy/realtek/realtek_main.c
+++ b/drivers/net/phy/realtek/realtek_main.c
@@ -1619,6 +1619,51 @@ static irqreturn_t rtl9000a_handle_inter
return IRQ_HANDLED;
}
+static int rtl8221b_ack_interrupt(struct phy_device *phydev)
+{
+ int err;
+
+ err = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xa4d4);
+
+ return (err < 0) ? err : 0;
+}
+
+static int rtl8221b_config_intr(struct phy_device *phydev)
+{
+ int err;
+
+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
+ err = rtl8221b_ack_interrupt(phydev);
+ if (err)
+ return err;
+
+ err = phy_write_mmd(phydev, MDIO_MMD_VEND2, 0xa4d2, 0x7ff);
+ } else {
+ err = phy_write_mmd(phydev, MDIO_MMD_VEND2, 0xa4d2, 0x0);
+ if (err)
+ return err;
+
+ err = rtl8221b_ack_interrupt(phydev);
+ }
+
+ return err;
+}
+
+static irqreturn_t rtl8221b_handle_interrupt(struct phy_device *phydev)
+{
+ int err;
+
+ err = rtl8221b_ack_interrupt(phydev);
+ if (err) {
+ phy_error(phydev);
+ return IRQ_NONE;
+ }
+
+ phy_trigger_machine(phydev);
+
+ return IRQ_HANDLED;
+}
+
static struct phy_driver realtek_drvs[] = {
{
PHY_ID_MATCH_EXACT(0x00008201),
@@ -1783,6 +1828,8 @@ static struct phy_driver realtek_drvs[]
}, {
.match_phy_device = rtl8221b_vb_cg_c22_match_phy_device,
.name = "RTL8221B-VB-CG 2.5Gbps PHY (C22)",
+ .config_intr = rtl8221b_config_intr,
+ .handle_interrupt = rtl8221b_handle_interrupt,
.soft_reset = genphy_soft_reset,
.probe = rtl822x_probe,
.get_features = rtl822x_get_features,
@@ -1797,6 +1844,8 @@ static struct phy_driver realtek_drvs[]
}, {
.match_phy_device = rtl8221b_vb_cg_c45_match_phy_device,
.name = "RTL8221B-VB-CG 2.5Gbps PHY (C45)",
+ .config_intr = rtl8221b_config_intr,
+ .handle_interrupt = rtl8221b_handle_interrupt,
.soft_reset = rtl822x_c45_soft_reset,
.probe = rtl822x_probe,
.config_init = rtl822xb_config_init,
@@ -1809,6 +1858,8 @@ static struct phy_driver realtek_drvs[]
}, {
.match_phy_device = rtl8221b_vn_cg_c22_match_phy_device,
.name = "RTL8221B-VM-CG 2.5Gbps PHY (C22)",
+ .config_intr = rtl8221b_config_intr,
+ .handle_interrupt = rtl8221b_handle_interrupt,
.soft_reset = genphy_soft_reset,
.probe = rtl822x_probe,
.get_features = rtl822x_get_features,
@@ -1823,6 +1874,8 @@ static struct phy_driver realtek_drvs[]
}, {
.match_phy_device = rtl8221b_vn_cg_c45_match_phy_device,
.name = "RTL8221B-VN-CG 2.5Gbps PHY (C45)",
+ .config_intr = rtl8221b_config_intr,
+ .handle_interrupt = rtl8221b_handle_interrupt,
.soft_reset = rtl822x_c45_soft_reset,
.probe = rtl822x_probe,
.config_init = rtl822xb_config_init,

View file

@ -15,7 +15,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
--- a/drivers/net/phy/realtek/realtek_main.c
+++ b/drivers/net/phy/realtek/realtek_main.c
@@ -1259,6 +1259,9 @@ static int rtl822x_c45_get_features(stru
@@ -1316,6 +1316,9 @@ static int rtl822x_c45_get_features(stru
linkmode_set_bit(ETHTOOL_LINK_MODE_TP_BIT,
phydev->supported);

View file

@ -15,7 +15,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
--- a/drivers/net/phy/realtek/realtek_main.c
+++ b/drivers/net/phy/realtek/realtek_main.c
@@ -1139,6 +1139,22 @@ static int rtl822xb_config_init(struct p
@@ -1196,6 +1196,22 @@ static int rtl822xb_config_init(struct p
return rtl822x_set_serdes_option_mode(phydev, false);
}
@ -38,7 +38,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
static int rtl822xb_get_rate_matching(struct phy_device *phydev,
phy_interface_t iface)
{
@@ -1851,7 +1867,7 @@ static struct phy_driver realtek_drvs[]
@@ -2070,7 +2086,7 @@ static struct phy_driver realtek_drvs[]
.handle_interrupt = rtl8221b_handle_interrupt,
.soft_reset = rtl822x_c45_soft_reset,
.probe = rtl822x_probe,
@ -47,7 +47,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
.get_rate_matching = rtl822xb_get_rate_matching,
.get_features = rtl822x_c45_get_features,
.config_aneg = rtl822x_c45_config_aneg,
@@ -1881,7 +1897,7 @@ static struct phy_driver realtek_drvs[]
@@ -2098,7 +2114,7 @@ static struct phy_driver realtek_drvs[]
.handle_interrupt = rtl8221b_handle_interrupt,
.soft_reset = rtl822x_c45_soft_reset,
.probe = rtl822x_probe,

View file

@ -13,7 +13,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
--- a/drivers/net/phy/realtek/realtek_main.c
+++ b/drivers/net/phy/realtek/realtek_main.c
@@ -1050,6 +1050,11 @@ static int rtl822x_set_serdes_option_mod
@@ -1107,6 +1107,11 @@ static int rtl822x_set_serdes_option_mod
phydev->host_interfaces) ||
phydev->interface == PHY_INTERFACE_MODE_SGMII;

View file

@ -15,7 +15,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
--- a/drivers/net/phy/realtek/realtek_main.c
+++ b/drivers/net/phy/realtek/realtek_main.c
@@ -1647,6 +1647,7 @@ static struct phy_driver realtek_drvs[]
@@ -1913,6 +1913,7 @@ static struct phy_driver realtek_drvs[]
}, {
.name = "RTL8226 2.5Gbps PHY",
.match_phy_device = rtl8226_match_phy_device,
@ -23,7 +23,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
.get_features = rtl822x_get_features,
.config_aneg = rtl822x_config_aneg,
.read_status = rtl822x_read_status,
@@ -1657,6 +1658,7 @@ static struct phy_driver realtek_drvs[]
@@ -1923,6 +1924,7 @@ static struct phy_driver realtek_drvs[]
}, {
.match_phy_device = rtl8221b_match_phy_device,
.name = "RTL8226B_RTL8221B 2.5Gbps PHY",
@ -31,7 +31,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
.get_features = rtl822x_get_features,
.config_aneg = rtl822x_config_aneg,
.config_init = rtl822xb_config_init,
@@ -1669,6 +1671,7 @@ static struct phy_driver realtek_drvs[]
@@ -1935,6 +1937,7 @@ static struct phy_driver realtek_drvs[]
}, {
PHY_ID_MATCH_EXACT(0x001cc838),
.name = "RTL8226-CG 2.5Gbps PHY",
@ -39,7 +39,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
.get_features = rtl822x_get_features,
.config_aneg = rtl822x_config_aneg,
.read_status = rtl822x_read_status,
@@ -1679,6 +1682,7 @@ static struct phy_driver realtek_drvs[]
@@ -1945,6 +1948,7 @@ static struct phy_driver realtek_drvs[]
}, {
PHY_ID_MATCH_EXACT(0x001cc848),
.name = "RTL8226B-CG_RTL8221B-CG 2.5Gbps PHY",
@ -47,7 +47,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
.get_features = rtl822x_get_features,
.config_aneg = rtl822x_config_aneg,
.config_init = rtl822xb_config_init,
@@ -1691,6 +1695,7 @@ static struct phy_driver realtek_drvs[]
@@ -1957,6 +1961,7 @@ static struct phy_driver realtek_drvs[]
}, {
.match_phy_device = rtl8221b_vb_cg_c22_match_phy_device,
.name = "RTL8221B-VB-CG 2.5Gbps PHY (C22)",
@ -55,26 +55,26 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
.probe = rtl822x_probe,
.get_features = rtl822x_get_features,
.config_aneg = rtl822x_config_aneg,
@@ -1704,6 +1709,7 @@ static struct phy_driver realtek_drvs[]
}, {
.match_phy_device = rtl8221b_vb_cg_c45_match_phy_device,
@@ -1972,6 +1977,7 @@ static struct phy_driver realtek_drvs[]
.name = "RTL8221B-VB-CG 2.5Gbps PHY (C45)",
.config_intr = rtl8221b_config_intr,
.handle_interrupt = rtl8221b_handle_interrupt,
+ .soft_reset = genphy_soft_reset,
.probe = rtl822x_probe,
.config_init = rtl822xb_config_init,
.get_rate_matching = rtl822xb_get_rate_matching,
@@ -1715,6 +1721,7 @@ static struct phy_driver realtek_drvs[]
@@ -1983,6 +1989,7 @@ static struct phy_driver realtek_drvs[]
}, {
.match_phy_device = rtl8221b_vn_cg_c22_match_phy_device,
.match_phy_device = rtl8221b_vm_cg_c22_match_phy_device,
.name = "RTL8221B-VM-CG 2.5Gbps PHY (C22)",
+ .soft_reset = genphy_soft_reset,
.probe = rtl822x_probe,
.get_features = rtl822x_get_features,
.config_aneg = rtl822x_config_aneg,
@@ -1728,6 +1735,7 @@ static struct phy_driver realtek_drvs[]
}, {
.match_phy_device = rtl8221b_vn_cg_c45_match_phy_device,
.name = "RTL8221B-VN-CG 2.5Gbps PHY (C45)",
@@ -1998,6 +2005,7 @@ static struct phy_driver realtek_drvs[]
.name = "RTL8221B-VM-CG 2.5Gbps PHY (C45)",
.config_intr = rtl8221b_config_intr,
.handle_interrupt = rtl8221b_handle_interrupt,
+ .soft_reset = genphy_soft_reset,
.probe = rtl822x_probe,
.config_init = rtl822xb_config_init,

View file

@ -20,7 +20,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
--- a/drivers/net/phy/realtek/realtek_main.c
+++ b/drivers/net/phy/realtek/realtek_main.c
@@ -1035,8 +1035,8 @@ static int rtl822x_probe(struct phy_devi
@@ -1092,8 +1092,8 @@ static int rtl822x_probe(struct phy_devi
static int rtl822xb_config_init(struct phy_device *phydev)
{
bool has_2500, has_sgmii;
@ -30,7 +30,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
has_2500 = test_bit(PHY_INTERFACE_MODE_2500BASEX,
phydev->host_interfaces) ||
@@ -1086,7 +1086,29 @@ static int rtl822xb_config_init(struct p
@@ -1143,7 +1143,29 @@ static int rtl822xb_config_init(struct p
if (ret < 0)
return ret;

View file

@ -18,7 +18,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
--- a/drivers/net/phy/realtek/realtek_main.c
+++ b/drivers/net/phy/realtek/realtek_main.c
@@ -1313,9 +1313,11 @@ static bool rtlgen_supports_2_5gbps(stru
@@ -1532,9 +1532,11 @@ static bool rtlgen_supports_2_5gbps(stru
{
int val;

View file

@ -13,9 +13,9 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
--- a/drivers/net/phy/realtek/realtek_main.c
+++ b/drivers/net/phy/realtek/realtek_main.c
@@ -129,6 +129,10 @@
*/
#define RTL822X_VND2_C22_REG(reg) (0xa400 + 2 * (reg))
@@ -156,6 +156,10 @@
#define RTL8224_SRAM_RTCT_LEN(pair) (0x8028 + (pair) * 4)
+#define RTL8221B_PHYCR1 0xa430
+#define RTL8221B_PHYCR1_ALDPS_EN BIT(2)
@ -24,7 +24,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
#define RTL8366RB_POWER_SAVE 0x15
#define RTL8366RB_POWER_SAVE_ON BIT(12)
@@ -1090,6 +1094,15 @@ static int rtl822xb_config_init(struct p
@@ -1147,6 +1151,15 @@ static int rtl822xb_config_init(struct p
if (ret < 0)
return ret;

View file

@ -14,7 +14,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
Signed-off-by: Mieczyslaw Nalewaj <namiltd@yahoo.com>
--- a/drivers/net/phy/realtek/realtek_main.c
+++ b/drivers/net/phy/realtek/realtek_main.c
@@ -1370,10 +1370,32 @@ static int rtl8226_match_phy_device(stru
@@ -1589,10 +1589,32 @@ static int rtl8226_match_phy_device(stru
static int rtlgen_is_c45_match(struct phy_device *phydev, unsigned int id,
bool is_c45)
{

View file

@ -1,102 +0,0 @@
From d7943c31d57c11e1a517aa3ce2006fca44866870 Mon Sep 17 00:00:00 2001
From: Jianhui Zhao <zhaojh329@gmail.com>
Date: Sun, 24 Sep 2023 22:15:00 +0800
Subject: [PATCH] net: phy: realtek: add interrupt support for RTL8221B
This commit introduces interrupt support for RTL8221B.
Signed-off-by: Jianhui Zhao <zhaojh329@gmail.com>
---
drivers/net/phy/realtek/realtek_main.c | 47 +++++++++++++++++++++++++++++++++++++++
1 file changed, 47 insertions(+)
--- a/drivers/net/phy/realtek/realtek_main.c
+++ b/drivers/net/phy/realtek/realtek_main.c
@@ -1589,6 +1589,51 @@ static irqreturn_t rtl9000a_handle_inter
return IRQ_HANDLED;
}
+static int rtl8221b_ack_interrupt(struct phy_device *phydev)
+{
+ int err;
+
+ err = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xa4d4);
+
+ return (err < 0) ? err : 0;
+}
+
+static int rtl8221b_config_intr(struct phy_device *phydev)
+{
+ int err;
+
+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
+ err = rtl8221b_ack_interrupt(phydev);
+ if (err)
+ return err;
+
+ err = phy_write_mmd(phydev, MDIO_MMD_VEND2, 0xa4d2, 0x7ff);
+ } else {
+ err = phy_write_mmd(phydev, MDIO_MMD_VEND2, 0xa4d2, 0x0);
+ if (err)
+ return err;
+
+ err = rtl8221b_ack_interrupt(phydev);
+ }
+
+ return err;
+}
+
+static irqreturn_t rtl8221b_handle_interrupt(struct phy_device *phydev)
+{
+ int err;
+
+ err = rtl8221b_ack_interrupt(phydev);
+ if (err) {
+ phy_error(phydev);
+ return IRQ_NONE;
+ }
+
+ phy_trigger_machine(phydev);
+
+ return IRQ_HANDLED;
+}
+
static struct phy_driver realtek_drvs[] = {
{
PHY_ID_MATCH_EXACT(0x00008201),
@@ -1754,6 +1799,8 @@ static struct phy_driver realtek_drvs[]
}, {
.match_phy_device = rtl8221b_vb_cg_c22_match_phy_device,
.name = "RTL8221B-VB-CG 2.5Gbps PHY (C22)",
+ .config_intr = rtl8221b_config_intr,
+ .handle_interrupt = rtl8221b_handle_interrupt,
.soft_reset = genphy_soft_reset,
.probe = rtl822x_probe,
.get_features = rtl822x_get_features,
@@ -1768,6 +1815,8 @@ static struct phy_driver realtek_drvs[]
}, {
.match_phy_device = rtl8221b_vb_cg_c45_match_phy_device,
.name = "RTL8221B-VB-CG 2.5Gbps PHY (C45)",
+ .config_intr = rtl8221b_config_intr,
+ .handle_interrupt = rtl8221b_handle_interrupt,
.soft_reset = genphy_soft_reset,
.probe = rtl822x_probe,
.config_init = rtl822xb_config_init,
@@ -1780,6 +1829,8 @@ static struct phy_driver realtek_drvs[]
}, {
.match_phy_device = rtl8221b_vn_cg_c22_match_phy_device,
.name = "RTL8221B-VM-CG 2.5Gbps PHY (C22)",
+ .config_intr = rtl8221b_config_intr,
+ .handle_interrupt = rtl8221b_handle_interrupt,
.soft_reset = genphy_soft_reset,
.probe = rtl822x_probe,
.get_features = rtl822x_get_features,
@@ -1794,6 +1845,8 @@ static struct phy_driver realtek_drvs[]
}, {
.match_phy_device = rtl8221b_vn_cg_c45_match_phy_device,
.name = "RTL8221B-VN-CG 2.5Gbps PHY (C45)",
+ .config_intr = rtl8221b_config_intr,
+ .handle_interrupt = rtl8221b_handle_interrupt,
.soft_reset = genphy_soft_reset,
.probe = rtl822x_probe,
.config_init = rtl822xb_config_init,

View file

@ -15,7 +15,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
--- a/drivers/net/phy/realtek/realtek_main.c
+++ b/drivers/net/phy/realtek/realtek_main.c
@@ -1244,6 +1244,9 @@ static int rtl822x_c45_get_features(stru
@@ -1301,6 +1301,9 @@ static int rtl822x_c45_get_features(stru
linkmode_set_bit(ETHTOOL_LINK_MODE_TP_BIT,
phydev->supported);

View file

@ -15,7 +15,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
--- a/drivers/net/phy/realtek/realtek_main.c
+++ b/drivers/net/phy/realtek/realtek_main.c
@@ -1124,6 +1124,22 @@ static int rtl822xb_config_init(struct p
@@ -1181,6 +1181,22 @@ static int rtl822xb_config_init(struct p
return 0;
}
@ -38,7 +38,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
static int rtl822xb_get_rate_matching(struct phy_device *phydev,
phy_interface_t iface)
{
@@ -1822,7 +1838,7 @@ static struct phy_driver realtek_drvs[]
@@ -2041,7 +2057,7 @@ static struct phy_driver realtek_drvs[]
.handle_interrupt = rtl8221b_handle_interrupt,
.soft_reset = genphy_soft_reset,
.probe = rtl822x_probe,
@ -47,7 +47,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
.get_rate_matching = rtl822xb_get_rate_matching,
.get_features = rtl822x_c45_get_features,
.config_aneg = rtl822x_c45_config_aneg,
@@ -1852,7 +1868,7 @@ static struct phy_driver realtek_drvs[]
@@ -2069,7 +2085,7 @@ static struct phy_driver realtek_drvs[]
.handle_interrupt = rtl8221b_handle_interrupt,
.soft_reset = genphy_soft_reset,
.probe = rtl822x_probe,

View file

@ -13,7 +13,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
--- a/drivers/net/phy/realtek/realtek_main.c
+++ b/drivers/net/phy/realtek/realtek_main.c
@@ -1050,6 +1050,11 @@ static int rtl822xb_config_init(struct p
@@ -1107,6 +1107,11 @@ static int rtl822xb_config_init(struct p
phydev->host_interfaces) ||
phydev->interface == PHY_INTERFACE_MODE_SGMII;