kernel: backport upstream Realtek PHY patches

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>
This commit is contained in:
Aleksander Jan Bajkowski 2025-11-29 17:55:41 +01:00 committed by Hauke Mehrtens
parent c9e7f32c4c
commit 48c9e55094
21 changed files with 1011 additions and 35 deletions

View File

@ -0,0 +1,74 @@
From fd8318a32573d73eb20637a0c80689de0dc98169 Mon Sep 17 00:00:00 2001
From: Peng Fan <peng.fan@nxp.com>
Date: Fri, 3 Jan 2025 16:41:13 +0800
Subject: [PATCH] PM: sleep: wakeirq: Introduce device-managed variant of
dev_pm_set_wake_irq()
Add device-managed variant of dev_pm_set_wake_irq which automatically
clear the wake irq on device destruction to simplify error handling
and resource management in drivers.
Signed-off-by: Peng Fan <peng.fan@nxp.com>
Link: https://patch.msgid.link/20250103-wake_irq-v2-1-e3aeff5e9966@nxp.com
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
drivers/base/power/wakeirq.c | 26 ++++++++++++++++++++++++++
include/linux/pm_wakeirq.h | 6 ++++++
2 files changed, 32 insertions(+)
--- a/drivers/base/power/wakeirq.c
+++ b/drivers/base/power/wakeirq.c
@@ -103,6 +103,32 @@ void dev_pm_clear_wake_irq(struct device
}
EXPORT_SYMBOL_GPL(dev_pm_clear_wake_irq);
+static void devm_pm_clear_wake_irq(void *dev)
+{
+ dev_pm_clear_wake_irq(dev);
+}
+
+/**
+ * devm_pm_set_wake_irq - device-managed variant of dev_pm_set_wake_irq
+ * @dev: Device entry
+ * @irq: Device IO interrupt
+ *
+ *
+ * Attach a device IO interrupt as a wake IRQ, same with dev_pm_set_wake_irq,
+ * but the device will be auto clear wake capability on driver detach.
+ */
+int devm_pm_set_wake_irq(struct device *dev, int irq)
+{
+ int ret;
+
+ ret = dev_pm_set_wake_irq(dev, irq);
+ if (ret)
+ return ret;
+
+ return devm_add_action_or_reset(dev, devm_pm_clear_wake_irq, dev);
+}
+EXPORT_SYMBOL_GPL(devm_pm_set_wake_irq);
+
/**
* handle_threaded_wake_irq - Handler for dedicated wake-up interrupts
* @irq: Device specific dedicated wake-up interrupt
--- a/include/linux/pm_wakeirq.h
+++ b/include/linux/pm_wakeirq.h
@@ -10,6 +10,7 @@ extern int dev_pm_set_wake_irq(struct de
extern int dev_pm_set_dedicated_wake_irq(struct device *dev, int irq);
extern int dev_pm_set_dedicated_wake_irq_reverse(struct device *dev, int irq);
extern void dev_pm_clear_wake_irq(struct device *dev);
+extern int devm_pm_set_wake_irq(struct device *dev, int irq);
#else /* !CONFIG_PM */
@@ -32,5 +33,10 @@ static inline void dev_pm_clear_wake_irq
{
}
+static inline int devm_pm_set_wake_irq(struct device *dev, int irq)
+{
+ return 0;
+}
+
#endif /* CONFIG_PM */
#endif /* _LINUX_PM_WAKEIRQ_H */

View File

@ -0,0 +1,352 @@
From b826bf795564ddef6402cf2cb522ae035bd117ae Mon Sep 17 00:00:00 2001
From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
Date: Wed, 13 Aug 2025 11:04:45 +0100
Subject: [PATCH] net: phy: realtek: fix RTL8211F wake-on-lan support
Implement Wake-on-Lan for RTL8211F correctly. The existing
implementation has multiple issues:
1. It assumes that Wake-on-Lan can always be used, whether or not the
interrupt is wired, and whether or not the interrupt is capable of
waking the system. This breaks the ability for MAC drivers to detect
whether the PHY WoL is functional.
2. switching the interrupt pin in the .set_wol() method to PMEB mode
immediately silences link-state interrupts, which breaks phylib
when interrupts are being used rather than polling mode.
3. the code claiming to "reset WOL status" was doing nothing of the
sort. Bit 15 in page 0xd8a register 17 controls WoL reset, and
needs to be pulsed low to reset the WoL state. This bit was always
written as '1', resulting in no reset.
4. not resetting WoL state results in the PMEB pin remaining asserted,
which in turn leads to an interrupt storm. Only resetting the WoL
state in .set_wol() is not sufficient.
5. PMEB mode does not allow software detection of the wake-up event as
there is no status bit to indicate we received the WoL packet.
6. across reboots of at least the Jetson Xavier NX system, the WoL
configuration is preserved.
Fix all of these issues by essentially rewriting the support. We:
1. clear the WoL event enable register at probe time.
2. detect whether we can support wake-up by having a valid interrupt,
and the "wakeup-source" property in DT. If we can, then we mark
the MDIO device as wakeup capable, and associate the interrupt
with the wakeup source.
3. arrange for the get_wol() and set_wol() implementations to handle
the case where the MDIO device has not been marked as wakeup
capable (thereby returning no WoL support, and refusing to enable
WoL support.)
4. avoid switching to PMEB mode, instead using INTB mode with the
interrupt enable, reconfiguring the interrupt enables at suspend
time, and restoring their original state at resume time (we track
the state of the interrupt enable register in .config_intr()
register.)
5. move WoL reset from .set_wol() to the suspend function to ensure
that WoL state is cleared prior to suspend. This is necessary
after the PME interrupt has been enabled as a second WoL packet
will not re-raise a previously cleared PME interrupt.
6. when a PME interrupt (for wakeup) is asserted, pass this to the
PM wakeup so it knows which device woke the system.
This fixes WoL support in the Realtek RTL8211F driver when used on the
nVidia Jetson Xavier NX platform, and needs to be applied before stmmac
patches which allow these platforms to forward the ethtool WoL commands
to the Realtek PHY.
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://patch.msgid.link/E1um8Ld-008jxD-Mc@rmk-PC.armlinux.org.uk
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/phy/realtek/realtek_main.c | 172 ++++++++++++++++++++-----
1 file changed, 140 insertions(+), 32 deletions(-)
--- a/drivers/net/phy/realtek/realtek_main.c
+++ b/drivers/net/phy/realtek/realtek_main.c
@@ -10,6 +10,7 @@
#include <linux/bitops.h>
#include <linux/of.h>
#include <linux/phy.h>
+#include <linux/pm_wakeirq.h>
#include <linux/netdevice.h>
#include <linux/module.h>
#include <linux/delay.h>
@@ -31,6 +32,7 @@
#define RTL821x_INER 0x12
#define RTL8211B_INER_INIT 0x6400
#define RTL8211E_INER_LINK_STATUS BIT(10)
+#define RTL8211F_INER_PME BIT(7)
#define RTL8211F_INER_LINK_STATUS BIT(4)
#define RTL821x_INSR 0x13
@@ -96,17 +98,13 @@
#define RTL8211F_RXCR 0x15
#define RTL8211F_RX_DELAY BIT(3)
-/* RTL8211F WOL interrupt configuration */
-#define RTL8211F_INTBCR_PAGE 0xd40
-#define RTL8211F_INTBCR 0x16
-#define RTL8211F_INTBCR_INTB_PMEB BIT(5)
-
/* RTL8211F WOL settings */
-#define RTL8211F_WOL_SETTINGS_PAGE 0xd8a
+#define RTL8211F_WOL_PAGE 0xd8a
#define RTL8211F_WOL_SETTINGS_EVENTS 16
#define RTL8211F_WOL_EVENT_MAGIC BIT(12)
-#define RTL8211F_WOL_SETTINGS_STATUS 17
-#define RTL8211F_WOL_STATUS_RESET (BIT(15) | 0x1fff)
+#define RTL8211F_WOL_RST_RMSQ 17
+#define RTL8211F_WOL_RG_RSTB BIT(15)
+#define RTL8211F_WOL_RMSQ 0x1fff
/* RTL8211F Unique phyiscal and multicast address (WOL) */
#define RTL8211F_PHYSICAL_ADDR_PAGE 0xd8c
@@ -172,7 +170,8 @@ struct rtl821x_priv {
u16 phycr2;
bool has_phycr2;
struct clk *clk;
- u32 saved_wolopts;
+ /* rtl8211f */
+ u16 iner;
};
static int rtl821x_read_page(struct phy_device *phydev)
@@ -255,6 +254,34 @@ static int rtl821x_probe(struct phy_devi
return 0;
}
+static int rtl8211f_probe(struct phy_device *phydev)
+{
+ struct device *dev = &phydev->mdio.dev;
+ int ret;
+
+ ret = rtl821x_probe(phydev);
+ if (ret < 0)
+ return ret;
+
+ /* Disable all PME events */
+ ret = phy_write_paged(phydev, RTL8211F_WOL_PAGE,
+ RTL8211F_WOL_SETTINGS_EVENTS, 0);
+ if (ret < 0)
+ return ret;
+
+ /* Mark this PHY as wakeup capable and register the interrupt as a
+ * wakeup IRQ if the PHY is marked as a wakeup source in firmware,
+ * and the interrupt is valid.
+ */
+ if (device_property_read_bool(dev, "wakeup-source") &&
+ phy_interrupt_is_valid(phydev)) {
+ device_set_wakeup_capable(dev, true);
+ devm_pm_set_wake_irq(dev, phydev->irq);
+ }
+
+ return ret;
+}
+
static int rtl8201_ack_interrupt(struct phy_device *phydev)
{
int err;
@@ -352,6 +379,7 @@ static int rtl8211e_config_intr(struct p
static int rtl8211f_config_intr(struct phy_device *phydev)
{
+ struct rtl821x_priv *priv = phydev->priv;
u16 val;
int err;
@@ -362,8 +390,10 @@ static int rtl8211f_config_intr(struct p
val = RTL8211F_INER_LINK_STATUS;
err = phy_write_paged(phydev, 0xa42, RTL821x_INER, val);
+ if (err == 0)
+ priv->iner = val;
} else {
- val = 0;
+ priv->iner = val = 0;
err = phy_write_paged(phydev, 0xa42, RTL821x_INER, val);
if (err)
return err;
@@ -426,21 +456,34 @@ static irqreturn_t rtl8211f_handle_inter
return IRQ_NONE;
}
- if (!(irq_status & RTL8211F_INER_LINK_STATUS))
- return IRQ_NONE;
+ if (irq_status & RTL8211F_INER_LINK_STATUS) {
+ phy_trigger_machine(phydev);
+ return IRQ_HANDLED;
+ }
- phy_trigger_machine(phydev);
+ if (irq_status & RTL8211F_INER_PME) {
+ pm_wakeup_event(&phydev->mdio.dev, 0);
+ return IRQ_HANDLED;
+ }
- return IRQ_HANDLED;
+ return IRQ_NONE;
}
static void rtl8211f_get_wol(struct phy_device *dev, struct ethtool_wolinfo *wol)
{
int wol_events;
+ /* If the PHY is not capable of waking the system, then WoL can not
+ * be supported.
+ */
+ if (!device_can_wakeup(&dev->mdio.dev)) {
+ wol->supported = 0;
+ return;
+ }
+
wol->supported = WAKE_MAGIC;
- wol_events = phy_read_paged(dev, RTL8211F_WOL_SETTINGS_PAGE, RTL8211F_WOL_SETTINGS_EVENTS);
+ wol_events = phy_read_paged(dev, RTL8211F_WOL_PAGE, RTL8211F_WOL_SETTINGS_EVENTS);
if (wol_events < 0)
return;
@@ -453,6 +496,9 @@ static int rtl8211f_set_wol(struct phy_d
const u8 *mac_addr = dev->attached_dev->dev_addr;
int oldpage;
+ if (!device_can_wakeup(&dev->mdio.dev))
+ return -EOPNOTSUPP;
+
oldpage = phy_save_page(dev);
if (oldpage < 0)
goto err;
@@ -464,25 +510,23 @@ static int rtl8211f_set_wol(struct phy_d
__phy_write(dev, RTL8211F_PHYSICAL_ADDR_WORD1, mac_addr[3] << 8 | (mac_addr[2]));
__phy_write(dev, RTL8211F_PHYSICAL_ADDR_WORD2, mac_addr[5] << 8 | (mac_addr[4]));
- /* Enable magic packet matching and reset WOL status */
- rtl821x_write_page(dev, RTL8211F_WOL_SETTINGS_PAGE);
+ /* Enable magic packet matching */
+ rtl821x_write_page(dev, RTL8211F_WOL_PAGE);
__phy_write(dev, RTL8211F_WOL_SETTINGS_EVENTS, RTL8211F_WOL_EVENT_MAGIC);
- __phy_write(dev, RTL8211F_WOL_SETTINGS_STATUS, RTL8211F_WOL_STATUS_RESET);
-
- /* Enable the WOL interrupt */
- rtl821x_write_page(dev, RTL8211F_INTBCR_PAGE);
- __phy_set_bits(dev, RTL8211F_INTBCR, RTL8211F_INTBCR_INTB_PMEB);
+ /* Set the maximum packet size, and assert WoL reset */
+ __phy_write(dev, RTL8211F_WOL_RST_RMSQ, RTL8211F_WOL_RMSQ);
} else {
- /* Disable the WOL interrupt */
- rtl821x_write_page(dev, RTL8211F_INTBCR_PAGE);
- __phy_clear_bits(dev, RTL8211F_INTBCR, RTL8211F_INTBCR_INTB_PMEB);
-
- /* Disable magic packet matching and reset WOL status */
- rtl821x_write_page(dev, RTL8211F_WOL_SETTINGS_PAGE);
+ /* Disable magic packet matching */
+ rtl821x_write_page(dev, RTL8211F_WOL_PAGE);
__phy_write(dev, RTL8211F_WOL_SETTINGS_EVENTS, 0);
- __phy_write(dev, RTL8211F_WOL_SETTINGS_STATUS, RTL8211F_WOL_STATUS_RESET);
+
+ /* Place WoL in reset */
+ __phy_clear_bits(dev, RTL8211F_WOL_RST_RMSQ,
+ RTL8211F_WOL_RG_RSTB);
}
+ device_set_wakeup_enable(&dev->mdio.dev, !!(wol->wolopts & WAKE_MAGIC));
+
err:
return phy_restore_page(dev, oldpage, 0);
}
@@ -627,6 +671,52 @@ static int rtl821x_suspend(struct phy_de
return ret;
}
+static int rtl8211f_suspend(struct phy_device *phydev)
+{
+ u16 wol_rst;
+ int ret;
+
+ ret = rtl821x_suspend(phydev);
+ if (ret < 0)
+ return ret;
+
+ /* If a PME event is enabled, then configure the interrupt for
+ * PME events only, disabling link interrupt. We avoid switching
+ * to PMEB mode as we don't have a status bit for that.
+ */
+ if (device_may_wakeup(&phydev->mdio.dev)) {
+ ret = phy_write_paged(phydev, 0xa42, RTL821x_INER,
+ RTL8211F_INER_PME);
+ if (ret < 0)
+ goto err;
+
+ /* Read the INSR to clear any pending interrupt */
+ phy_read_paged(phydev, RTL8211F_INSR_PAGE, RTL8211F_INSR);
+
+ /* Reset the WoL to ensure that an event is picked up.
+ * Unless we do this, even if we receive another packet,
+ * we may not have a PME interrupt raised.
+ */
+ ret = phy_read_paged(phydev, RTL8211F_WOL_PAGE,
+ RTL8211F_WOL_RST_RMSQ);
+ if (ret < 0)
+ goto err;
+
+ wol_rst = ret & ~RTL8211F_WOL_RG_RSTB;
+ ret = phy_write_paged(phydev, RTL8211F_WOL_PAGE,
+ RTL8211F_WOL_RST_RMSQ, wol_rst);
+ if (ret < 0)
+ goto err;
+
+ wol_rst |= RTL8211F_WOL_RG_RSTB;
+ ret = phy_write_paged(phydev, RTL8211F_WOL_PAGE,
+ RTL8211F_WOL_RST_RMSQ, wol_rst);
+ }
+
+err:
+ return ret;
+}
+
static int rtl821x_resume(struct phy_device *phydev)
{
struct rtl821x_priv *priv = phydev->priv;
@@ -644,6 +734,24 @@ static int rtl821x_resume(struct phy_dev
return 0;
}
+static int rtl8211f_resume(struct phy_device *phydev)
+{
+ struct rtl821x_priv *priv = phydev->priv;
+ int ret;
+
+ ret = rtl821x_resume(phydev);
+ if (ret < 0)
+ return ret;
+
+ /* If the device was programmed for a PME event, restore the interrupt
+ * enable so phylib can receive link state interrupts.
+ */
+ if (device_may_wakeup(&phydev->mdio.dev))
+ ret = phy_write_paged(phydev, 0xa42, RTL821x_INER, priv->iner);
+
+ return ret;
+}
+
static int rtl8211x_led_hw_is_supported(struct phy_device *phydev, u8 index,
unsigned long rules)
{
@@ -1639,15 +1747,15 @@ static struct phy_driver realtek_drvs[]
}, {
PHY_ID_MATCH_EXACT(0x001cc916),
.name = "RTL8211F Gigabit Ethernet",
- .probe = rtl821x_probe,
+ .probe = rtl8211f_probe,
.config_init = &rtl8211f_config_init,
.read_status = rtlgen_read_status,
.config_intr = &rtl8211f_config_intr,
.handle_interrupt = rtl8211f_handle_interrupt,
.set_wol = rtl8211f_set_wol,
.get_wol = rtl8211f_get_wol,
- .suspend = rtl821x_suspend,
- .resume = rtl821x_resume,
+ .suspend = rtl8211f_suspend,
+ .resume = rtl8211f_resume,
.read_page = rtl821x_read_page,
.write_page = rtl821x_write_page,
.flags = PHY_ALWAYS_CALL_SUSPEND,

View File

@ -18,7 +18,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
--- a/drivers/net/phy/realtek/realtek_main.c
+++ b/drivers/net/phy/realtek/realtek_main.c
@@ -156,7 +156,7 @@
@@ -154,7 +154,7 @@
#define RTL_8211FVD_PHYID 0x001cc878
#define RTL_8221B 0x001cc840
#define RTL_8221B_VB_CG 0x001cc849
@ -27,7 +27,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
#define RTL_8251B 0x001cc862
#define RTL_8261C 0x001cc890
@@ -1415,16 +1415,16 @@ static int rtl8221b_vb_cg_c45_match_phy_
@@ -1498,16 +1498,16 @@ static int rtl8221b_vb_cg_c45_match_phy_
return rtlgen_is_c45_match(phydev, RTL_8221B_VB_CG, true);
}
@ -48,7 +48,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
}
static int rtl_internal_nbaset_match_phy_device(struct phy_device *phydev,
@@ -1771,7 +1771,7 @@ static struct phy_driver realtek_drvs[]
@@ -1854,7 +1854,7 @@ static struct phy_driver realtek_drvs[]
.suspend = genphy_c45_pma_suspend,
.resume = rtlgen_c45_resume,
}, {
@ -57,7 +57,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
.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[]
@@ -1867,8 +1867,8 @@ static struct phy_driver realtek_drvs[]
.read_page = rtl821x_read_page,
.write_page = rtl821x_write_page,
}, {

View File

@ -19,7 +19,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
--- 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
@@ -755,7 +755,8 @@ static int rtl8211f_resume(struct phy_de
static int rtl8211x_led_hw_is_supported(struct phy_device *phydev, u8 index,
unsigned long rules)
{
@ -29,7 +29,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
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
@@ -813,6 +814,12 @@ static int rtl8211f_led_hw_control_get(s
if (val & RTL8211F_LEDCR_LINK_1000)
__set_bit(TRIGGER_NETDEV_LINK_1000, rules);
@ -42,7 +42,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
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
@@ -830,14 +837,20 @@ static int rtl8211f_led_hw_control_set(s
if (index >= RTL8211x_LED_COUNT)
return -EINVAL;
@ -66,7 +66,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
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
@@ -885,6 +898,12 @@ static int rtl8211e_led_hw_control_get(s
if (cr2 & RTL8211E_LEDCR2_LINK_1000)
__set_bit(TRIGGER_NETDEV_LINK_1000, rules);
@ -79,7 +79,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
return ret;
}
@@ -805,14 +824,20 @@ static int rtl8211e_led_hw_control_set(s
@@ -912,14 +931,20 @@ static int rtl8211e_led_hw_control_set(s
if (ret < 0)
return ret;

View File

@ -57,8 +57,8 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+#include <linux/ethtool_netlink.h>
#include <linux/of.h>
#include <linux/phy.h>
#include <linux/netdevice.h>
@@ -129,6 +130,27 @@
#include <linux/pm_wakeirq.h>
@@ -127,6 +128,27 @@
*/
#define RTL822X_VND2_C22_REG(reg) (0xa400 + 2 * (reg))
@ -86,7 +86,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
#define RTL8366RB_POWER_SAVE 0x15
#define RTL8366RB_POWER_SAVE_ON BIT(12)
@@ -1345,6 +1367,168 @@ static int rtl822xb_c45_read_status(stru
@@ -1453,6 +1475,168 @@ static int rtl822xb_c45_read_status(stru
return 0;
}
@ -255,7 +255,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
static bool rtlgen_supports_2_5gbps(struct phy_device *phydev)
{
int val;
@@ -1822,11 +2006,14 @@ static struct phy_driver realtek_drvs[]
@@ -1930,11 +2114,14 @@ static struct phy_driver realtek_drvs[]
}, {
PHY_ID_MATCH_EXACT(0x001ccad0),
.name = "RTL8224 2.5Gbps PHY",

View File

@ -19,7 +19,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
--- a/drivers/net/phy/realtek/realtek_main.c
+++ b/drivers/net/phy/realtek/realtek_main.c
@@ -130,6 +130,11 @@
@@ -128,6 +128,11 @@
*/
#define RTL822X_VND2_C22_REG(reg) (0xa400 + 2 * (reg))
@ -31,7 +31,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
#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
@@ -1880,6 +1885,53 @@ static irqreturn_t rtl9000a_handle_inter
return IRQ_HANDLED;
}
@ -85,7 +85,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
static struct phy_driver realtek_drvs[] = {
{
PHY_ID_MATCH_EXACT(0x00008201),
@@ -1946,6 +1998,8 @@ static struct phy_driver realtek_drvs[]
@@ -2054,6 +2106,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)",
@ -94,7 +94,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
.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[]
@@ -2078,6 +2132,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)",

View File

@ -0,0 +1,128 @@
From 8e982441ba601d982dd0739972115d85ae01d99b Mon Sep 17 00:00:00 2001
From: Vladimir Oltean <vladimir.oltean@nxp.com>
Date: Tue, 18 Nov 2025 01:40:28 +0200
Subject: [PATCH] net: phy: realtek: create rtl8211f_config_rgmii_delay()
The control flow in rtl8211f_config_init() has some pitfalls which were
probably unintended. Specifically it has an early return:
switch (phydev->interface) {
...
default: /* the rest of the modes imply leaving delay as is. */
return 0;
}
which exits the entire config_init() function. This means it also skips
doing things such as disabling CLKOUT or disabling PHY-mode EEE.
For the RTL8211FS, which uses PHY_INTERFACE_MODE_SGMII, this might be a
problem. However, I don't know that it is, so there is no Fixes: tag.
The issue was observed through code inspection.
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://patch.msgid.link/20251117234033.345679-2-vladimir.oltean@nxp.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/phy/realtek/realtek_main.c | 65 +++++++++++++++-----------
1 file changed, 39 insertions(+), 26 deletions(-)
--- a/drivers/net/phy/realtek/realtek_main.c
+++ b/drivers/net/phy/realtek/realtek_main.c
@@ -587,22 +587,11 @@ static int rtl8211c_config_init(struct p
CTL1000_ENABLE_MASTER | CTL1000_AS_MASTER);
}
-static int rtl8211f_config_init(struct phy_device *phydev)
+static int rtl8211f_config_rgmii_delay(struct phy_device *phydev)
{
- struct rtl821x_priv *priv = phydev->priv;
- struct device *dev = &phydev->mdio.dev;
u16 val_txdly, val_rxdly;
int ret;
- ret = phy_modify_paged_changed(phydev, RTL8211F_PHYCR_PAGE, RTL8211F_PHYCR1,
- RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF,
- priv->phycr1);
- if (ret < 0) {
- dev_err(dev, "aldps mode configuration failed: %pe\n",
- ERR_PTR(ret));
- return ret;
- }
-
switch (phydev->interface) {
case PHY_INTERFACE_MODE_RGMII:
val_txdly = 0;
@@ -632,34 +621,58 @@ static int rtl8211f_config_init(struct p
RTL8211F_TXCR, RTL8211F_TX_DELAY,
val_txdly);
if (ret < 0) {
- dev_err(dev, "Failed to update the TX delay register\n");
+ phydev_err(phydev, "Failed to update the TX delay register: %pe\n",
+ ERR_PTR(ret));
return ret;
} else if (ret) {
- dev_dbg(dev,
- "%s 2ns TX delay (and changing the value from pin-strapping RXD1 or the bootloader)\n",
- str_enable_disable(val_txdly));
+ phydev_dbg(phydev,
+ "%s 2ns TX delay (and changing the value from pin-strapping RXD1 or the bootloader)\n",
+ str_enable_disable(val_txdly));
} else {
- dev_dbg(dev,
- "2ns TX delay was already %s (by pin-strapping RXD1 or bootloader configuration)\n",
- str_enabled_disabled(val_txdly));
+ phydev_dbg(phydev,
+ "2ns TX delay was already %s (by pin-strapping RXD1 or bootloader configuration)\n",
+ str_enabled_disabled(val_txdly));
}
ret = phy_modify_paged_changed(phydev, RTL8211F_RGMII_PAGE,
RTL8211F_RXCR, RTL8211F_RX_DELAY,
val_rxdly);
if (ret < 0) {
- dev_err(dev, "Failed to update the RX delay register\n");
+ phydev_err(phydev, "Failed to update the RX delay register: %pe\n",
+ ERR_PTR(ret));
return ret;
} else if (ret) {
- dev_dbg(dev,
- "%s 2ns RX delay (and changing the value from pin-strapping RXD0 or the bootloader)\n",
- str_enable_disable(val_rxdly));
+ phydev_dbg(phydev,
+ "%s 2ns RX delay (and changing the value from pin-strapping RXD0 or the bootloader)\n",
+ str_enable_disable(val_rxdly));
} else {
- dev_dbg(dev,
- "2ns RX delay was already %s (by pin-strapping RXD0 or bootloader configuration)\n",
- str_enabled_disabled(val_rxdly));
+ phydev_dbg(phydev,
+ "2ns RX delay was already %s (by pin-strapping RXD0 or bootloader configuration)\n",
+ str_enabled_disabled(val_rxdly));
}
+ return 0;
+}
+
+static int rtl8211f_config_init(struct phy_device *phydev)
+{
+ struct rtl821x_priv *priv = phydev->priv;
+ struct device *dev = &phydev->mdio.dev;
+ int ret;
+
+ ret = phy_modify_paged_changed(phydev, RTL8211F_PHYCR_PAGE, RTL8211F_PHYCR1,
+ RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF,
+ priv->phycr1);
+ if (ret < 0) {
+ dev_err(dev, "aldps mode configuration failed: %pe\n",
+ ERR_PTR(ret));
+ return ret;
+ }
+
+ ret = rtl8211f_config_rgmii_delay(phydev);
+ if (ret)
+ return ret;
+
if (!priv->has_phycr2)
return 0;

View File

@ -0,0 +1,101 @@
From 27033d06917758d47162581da7e9de8004049dee Mon Sep 17 00:00:00 2001
From: Vladimir Oltean <vladimir.oltean@nxp.com>
Date: Tue, 18 Nov 2025 01:40:29 +0200
Subject: [PATCH] net: phy: realtek: eliminate priv->phycr2 variable
The RTL8211F(D)(I)-VD-CG PHY also has support for disabling the CLKOUT,
and we'd like to introduce the "realtek,clkout-disable" property for
that.
But it isn't done through the PHYCR2 register, and it becomes awkward to
have the driver pretend that it is. So just replace the machine-level
"u16 phycr2" variable with a logical "bool disable_clk_out", which
scales better to the other PHY as well.
The change is a complete functional equivalent. Before, if the device
tree property was absent, priv->phycr2 would contain the RTL8211F_CLKOUT_EN
bit as read from hardware. Now, we don't save priv->phycr2, but we just
don't call phy_modify_paged() on it. Also, we can simply call
phy_modify_paged() with the "set" argument to 0.
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Link: https://patch.msgid.link/20251117234033.345679-3-vladimir.oltean@nxp.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/phy/realtek/realtek_main.c | 38 ++++++++++++++++----------
1 file changed, 23 insertions(+), 15 deletions(-)
--- a/drivers/net/phy/realtek/realtek_main.c
+++ b/drivers/net/phy/realtek/realtek_main.c
@@ -194,8 +194,8 @@ MODULE_LICENSE("GPL");
struct rtl821x_priv {
u16 phycr1;
- u16 phycr2;
bool has_phycr2;
+ bool disable_clk_out;
struct clk *clk;
/* rtl8211f */
u16 iner;
@@ -266,15 +266,8 @@ static int rtl821x_probe(struct phy_devi
priv->phycr1 |= RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF;
priv->has_phycr2 = !(phy_id == RTL_8211FVD_PHYID);
- if (priv->has_phycr2) {
- ret = phy_read_paged(phydev, RTL8211F_PHYCR_PAGE, RTL8211F_PHYCR2);
- if (ret < 0)
- return ret;
-
- priv->phycr2 = ret & RTL8211F_CLKOUT_EN;
- if (of_property_read_bool(dev->of_node, "realtek,clkout-disable"))
- priv->phycr2 &= ~RTL8211F_CLKOUT_EN;
- }
+ priv->disable_clk_out = of_property_read_bool(dev->of_node,
+ "realtek,clkout-disable");
phydev->priv = priv;
@@ -654,6 +647,23 @@ static int rtl8211f_config_rgmii_delay(s
return 0;
}
+static int rtl8211f_config_clk_out(struct phy_device *phydev)
+{
+ struct rtl821x_priv *priv = phydev->priv;
+ int ret;
+
+ /* The value is preserved if the device tree property is absent */
+ if (!priv->disable_clk_out)
+ return 0;
+
+ ret = phy_modify_paged(phydev, RTL8211F_PHYCR_PAGE,
+ RTL8211F_PHYCR2, RTL8211F_CLKOUT_EN, 0);
+ if (ret)
+ return ret;
+
+ return genphy_soft_reset(phydev);
+}
+
static int rtl8211f_config_init(struct phy_device *phydev)
{
struct rtl821x_priv *priv = phydev->priv;
@@ -682,16 +692,14 @@ static int rtl8211f_config_init(struct p
if (ret)
return ret;
- ret = phy_modify_paged(phydev, RTL8211F_PHYCR_PAGE,
- RTL8211F_PHYCR2, RTL8211F_CLKOUT_EN,
- priv->phycr2);
- if (ret < 0) {
+ ret = rtl8211f_config_clk_out(phydev);
+ if (ret) {
dev_err(dev, "clkout configuration failed: %pe\n",
ERR_PTR(ret));
return ret;
}
- return genphy_soft_reset(phydev);
+ return 0;
}
static int rtl821x_suspend(struct phy_device *phydev)

View File

@ -0,0 +1,55 @@
From 910ac7bfb1af1ae4cd141ef80e03a6729213c189 Mon Sep 17 00:00:00 2001
From: Vladimir Oltean <vladimir.oltean@nxp.com>
Date: Tue, 18 Nov 2025 01:40:30 +0200
Subject: [PATCH] net: phy: realtek: eliminate has_phycr2 variable
This variable is assigned in rtl821x_probe() and used in
rtl8211f_config_init(), which is more complex than it needs to be.
Simply testing the same condition from rtl821x_probe() in
rtl8211f_config_init() yields the same result (the PHY driver ID is a
runtime invariant), but with one temporary variable less.
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://patch.msgid.link/20251117234033.345679-4-vladimir.oltean@nxp.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/phy/realtek/realtek_main.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
--- a/drivers/net/phy/realtek/realtek_main.c
+++ b/drivers/net/phy/realtek/realtek_main.c
@@ -194,7 +194,6 @@ MODULE_LICENSE("GPL");
struct rtl821x_priv {
u16 phycr1;
- bool has_phycr2;
bool disable_clk_out;
struct clk *clk;
/* rtl8211f */
@@ -245,7 +244,6 @@ static int rtl821x_probe(struct phy_devi
{
struct device *dev = &phydev->mdio.dev;
struct rtl821x_priv *priv;
- u32 phy_id = phydev->drv->phy_id;
int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -265,7 +263,6 @@ static int rtl821x_probe(struct phy_devi
if (of_property_read_bool(dev->of_node, "realtek,aldps-enable"))
priv->phycr1 |= RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF;
- priv->has_phycr2 = !(phy_id == RTL_8211FVD_PHYID);
priv->disable_clk_out = of_property_read_bool(dev->of_node,
"realtek,clkout-disable");
@@ -683,7 +680,8 @@ static int rtl8211f_config_init(struct p
if (ret)
return ret;
- if (!priv->has_phycr2)
+ /* RTL8211FVD has no PHYCR2 register */
+ if (phydev->drv->phy_id == RTL_8211FVD_PHYID)
return 0;
/* Disable PHY-mode EEE so LPI is passed to the MAC */

View File

@ -0,0 +1,101 @@
From e1a31c41bef678afe0d99b7f0dc3711a80c68447 Mon Sep 17 00:00:00 2001
From: Vladimir Oltean <vladimir.oltean@nxp.com>
Date: Tue, 18 Nov 2025 01:40:31 +0200
Subject: [PATCH] net: phy: realtek: allow CLKOUT to be disabled on
RTL8211F(D)(I)-VD-CG
Add CLKOUT disable support for RTL8211F(D)(I)-VD-CG. Like with other PHY
variants, this feature might be requested by customers when the clock
output is not used, in order to reduce electromagnetic interference (EMI).
In the common driver, the CLKOUT configuration is done through PHYCR2.
The RTL_8211FVD_PHYID is singled out as not having that register, and
execution in rtl8211f_config_init() returns early after commit
2c67301584f2 ("net: phy: realtek: Avoid PHYCR2 access if PHYCR2 not
present").
But actually CLKOUT is configured through a different register for this
PHY. Instead of pretending this is PHYCR2 (which it is not), just add
some code for modifying this register inside the rtl8211f_disable_clk_out()
function, and move that outside the code portion that runs only if
PHYCR2 exists.
In practice this reorders the PHYCR2 writes to disable PHY-mode EEE and
to disable the CLKOUT for the normal RTL8211F variants, but this should
be perfectly fine.
It was not noted that RTL8211F(D)(I)-VD-CG would need a genphy_soft_reset()
call after disabling the CLKOUT. Despite that, we do it out of caution
and for symmetry with the other RTL8211F models.
Co-developed-by: Clark Wang <xiaoning.wang@nxp.com>
Signed-off-by: Clark Wang <xiaoning.wang@nxp.com>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://patch.msgid.link/20251117234033.345679-5-vladimir.oltean@nxp.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/phy/realtek/realtek_main.c | 31 ++++++++++++++++++--------
1 file changed, 22 insertions(+), 9 deletions(-)
--- a/drivers/net/phy/realtek/realtek_main.c
+++ b/drivers/net/phy/realtek/realtek_main.c
@@ -90,6 +90,14 @@
#define RTL8211F_LEDCR_MASK GENMASK(4, 0)
#define RTL8211F_LEDCR_SHIFT 5
+/* RTL8211F(D)(I)-VD-CG CLKOUT configuration is specified via magic values
+ * to undocumented register pages. The names here do not reflect the datasheet.
+ * Unlike other PHY models, CLKOUT configuration does not go through PHYCR2.
+ */
+#define RTL8211FVD_CLKOUT_PAGE 0xd05
+#define RTL8211FVD_CLKOUT_REG 0x11
+#define RTL8211FVD_CLKOUT_EN BIT(8)
+
/* RTL8211F RGMII configuration */
#define RTL8211F_RGMII_PAGE 0xd08
@@ -653,8 +661,13 @@ static int rtl8211f_config_clk_out(struc
if (!priv->disable_clk_out)
return 0;
- ret = phy_modify_paged(phydev, RTL8211F_PHYCR_PAGE,
- RTL8211F_PHYCR2, RTL8211F_CLKOUT_EN, 0);
+ if (phydev->drv->phy_id == RTL_8211FVD_PHYID)
+ ret = phy_modify_paged(phydev, RTL8211FVD_CLKOUT_PAGE,
+ RTL8211FVD_CLKOUT_REG,
+ RTL8211FVD_CLKOUT_EN, 0);
+ else
+ ret = phy_modify_paged(phydev, RTL8211F_PHYCR_PAGE,
+ RTL8211F_PHYCR2, RTL8211F_CLKOUT_EN, 0);
if (ret)
return ret;
@@ -680,6 +693,13 @@ static int rtl8211f_config_init(struct p
if (ret)
return ret;
+ ret = rtl8211f_config_clk_out(phydev);
+ if (ret) {
+ dev_err(dev, "clkout configuration failed: %pe\n",
+ ERR_PTR(ret));
+ return ret;
+ }
+
/* RTL8211FVD has no PHYCR2 register */
if (phydev->drv->phy_id == RTL_8211FVD_PHYID)
return 0;
@@ -690,13 +710,6 @@ static int rtl8211f_config_init(struct p
if (ret)
return ret;
- ret = rtl8211f_config_clk_out(phydev);
- if (ret) {
- dev_err(dev, "clkout configuration failed: %pe\n",
- ERR_PTR(ret));
- return ret;
- }
-
return 0;
}

View File

@ -0,0 +1,107 @@
From bb78b71faf60d11a15f07e3390fcfd31e5e523bb Mon Sep 17 00:00:00 2001
From: Vladimir Oltean <vladimir.oltean@nxp.com>
Date: Tue, 18 Nov 2025 01:40:32 +0200
Subject: [PATCH] net: phy: realtek: eliminate priv->phycr1 variable
Previous changes have replaced the machine-level priv->phycr2 with a
high-level priv->disable_clk_out. This created a discrepancy with
priv->phycr1 which is resolved here, for uniformity.
One advantage of this new implementation is that we don't read
priv->phycr1 in rtl821x_probe() if we're never going to modify it.
We never test the positive return code from phy_modify_mmd_changed(), so
we could just as well use phy_modify_mmd().
I took the ALDPS feature description from commit d90db36a9e74 ("net:
phy: realtek: add dt property to enable ALDPS mode") and transformed it
into a function comment - the feature is sufficiently non-obvious to
deserve that.
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://patch.msgid.link/20251117234033.345679-6-vladimir.oltean@nxp.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/phy/realtek/realtek_main.c | 44 ++++++++++++++++----------
1 file changed, 28 insertions(+), 16 deletions(-)
--- a/drivers/net/phy/realtek/realtek_main.c
+++ b/drivers/net/phy/realtek/realtek_main.c
@@ -201,7 +201,7 @@ MODULE_AUTHOR("Johnson Leung");
MODULE_LICENSE("GPL");
struct rtl821x_priv {
- u16 phycr1;
+ bool enable_aldps;
bool disable_clk_out;
struct clk *clk;
/* rtl8211f */
@@ -252,7 +252,6 @@ static int rtl821x_probe(struct phy_devi
{
struct device *dev = &phydev->mdio.dev;
struct rtl821x_priv *priv;
- int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -263,14 +262,8 @@ static int rtl821x_probe(struct phy_devi
return dev_err_probe(dev, PTR_ERR(priv->clk),
"failed to get phy clock\n");
- ret = phy_read_paged(phydev, RTL8211F_PHYCR_PAGE, RTL8211F_PHYCR1);
- if (ret < 0)
- return ret;
-
- priv->phycr1 = ret & (RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF);
- if (of_property_read_bool(dev->of_node, "realtek,aldps-enable"))
- priv->phycr1 |= RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF;
-
+ priv->enable_aldps = of_property_read_bool(dev->of_node,
+ "realtek,aldps-enable");
priv->disable_clk_out = of_property_read_bool(dev->of_node,
"realtek,clkout-disable");
@@ -674,17 +667,36 @@ static int rtl8211f_config_clk_out(struc
return genphy_soft_reset(phydev);
}
-static int rtl8211f_config_init(struct phy_device *phydev)
+/* Advance Link Down Power Saving (ALDPS) mode changes crystal/clock behaviour,
+ * which causes the RXC clock signal to stop for tens to hundreds of
+ * milliseconds.
+ *
+ * Some MACs need the RXC clock to support their internal RX logic, so ALDPS is
+ * only enabled based on an opt-in device tree property.
+ */
+static int rtl8211f_config_aldps(struct phy_device *phydev)
{
struct rtl821x_priv *priv = phydev->priv;
+ u16 mask = RTL8211F_ALDPS_PLL_OFF |
+ RTL8211F_ALDPS_ENABLE |
+ RTL8211F_ALDPS_XTAL_OFF;
+
+ /* The value is preserved if the device tree property is absent */
+ if (!priv->enable_aldps)
+ return 0;
+
+ return phy_modify_paged(phydev, RTL8211F_PHYCR_PAGE, RTL8211F_PHYCR1,
+ mask, mask);
+}
+
+static int rtl8211f_config_init(struct phy_device *phydev)
+{
struct device *dev = &phydev->mdio.dev;
int ret;
- ret = phy_modify_paged_changed(phydev, RTL8211F_PHYCR_PAGE, RTL8211F_PHYCR1,
- RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF,
- priv->phycr1);
- if (ret < 0) {
- dev_err(dev, "aldps mode configuration failed: %pe\n",
+ ret = rtl8211f_config_aldps(phydev);
+ if (ret) {
+ dev_err(dev, "aldps mode configuration failed: %pe\n",
ERR_PTR(ret));
return ret;
}

View File

@ -0,0 +1,58 @@
From 4465ae435ddc0162d5033a543658449d53d46d08 Mon Sep 17 00:00:00 2001
From: Vladimir Oltean <vladimir.oltean@nxp.com>
Date: Tue, 18 Nov 2025 01:40:33 +0200
Subject: [PATCH] net: phy: realtek: create rtl8211f_config_phy_eee() helper
To simplify the rtl8211f_config_init() control flow and get rid of
"early" returns for PHYs where the PHYCR2 register is absent, move the
entire logic sub-block that deals with disabling PHY-mode EEE to a
separate function. There, it is much more obvious what the early
"return 0" skips, and it becomes more difficult to accidentally skip
unintended stuff.
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Link: https://patch.msgid.link/20251117234033.345679-7-vladimir.oltean@nxp.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/phy/realtek/realtek_main.c | 23 ++++++++++++-----------
1 file changed, 12 insertions(+), 11 deletions(-)
--- a/drivers/net/phy/realtek/realtek_main.c
+++ b/drivers/net/phy/realtek/realtek_main.c
@@ -689,6 +689,17 @@ static int rtl8211f_config_aldps(struct
mask, mask);
}
+static int rtl8211f_config_phy_eee(struct phy_device *phydev)
+{
+ /* RTL8211FVD has no PHYCR2 register */
+ if (phydev->drv->phy_id == RTL_8211FVD_PHYID)
+ return 0;
+
+ /* Disable PHY-mode EEE so LPI is passed to the MAC */
+ return phy_modify_paged(phydev, RTL8211F_PHYCR_PAGE, RTL8211F_PHYCR2,
+ RTL8211F_PHYCR2_PHY_EEE_ENABLE, 0);
+}
+
static int rtl8211f_config_init(struct phy_device *phydev)
{
struct device *dev = &phydev->mdio.dev;
@@ -712,17 +723,7 @@ static int rtl8211f_config_init(struct p
return ret;
}
- /* RTL8211FVD has no PHYCR2 register */
- if (phydev->drv->phy_id == RTL_8211FVD_PHYID)
- 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;
-
- return 0;
+ return rtl8211f_config_phy_eee(phydev);
}
static int rtl821x_suspend(struct phy_device *phydev)

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
@@ -1941,6 +1941,7 @@ static struct phy_driver realtek_drvs[]
@@ -2094,6 +2094,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,
@@ -1951,6 +1952,7 @@ static struct phy_driver realtek_drvs[]
@@ -2104,6 +2105,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,
@@ -1973,6 +1975,7 @@ static struct phy_driver realtek_drvs[]
@@ -2126,6 +2128,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,
@@ -1985,6 +1988,7 @@ static struct phy_driver realtek_drvs[]
@@ -2138,6 +2141,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,7 +47,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
.probe = rtl822x_probe,
.get_features = rtl822x_get_features,
.config_aneg = rtl822x_config_aneg,
@@ -2000,6 +2004,7 @@ static struct phy_driver realtek_drvs[]
@@ -2153,6 +2157,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,
@ -55,7 +55,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
.probe = rtl822x_probe,
.config_init = rtl822xb_config_init,
.get_rate_matching = rtl822xb_get_rate_matching,
@@ -2011,6 +2016,7 @@ static struct phy_driver realtek_drvs[]
@@ -2164,6 +2169,7 @@ static struct phy_driver realtek_drvs[]
}, {
.match_phy_device = rtl8221b_vm_cg_c22_match_phy_device,
.name = "RTL8221B-VM-CG 2.5Gbps PHY (C22)",
@ -63,7 +63,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
.probe = rtl822x_probe,
.get_features = rtl822x_get_features,
.config_aneg = rtl822x_config_aneg,
@@ -2026,6 +2032,7 @@ static struct phy_driver realtek_drvs[]
@@ -2179,6 +2185,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,

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
@@ -1092,8 +1092,8 @@ static int rtl822x_probe(struct phy_devi
@@ -1245,8 +1245,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) ||
@@ -1135,18 +1135,42 @@ static int rtl822x_set_serdes_option_mod
@@ -1288,18 +1288,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
@@ -1562,9 +1562,11 @@ static bool rtlgen_supports_2_5gbps(stru
@@ -1715,9 +1715,11 @@ static bool rtlgen_supports_2_5gbps(stru
{
int val;

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
@@ -156,6 +156,10 @@
@@ -162,6 +162,10 @@
#define RTL8224_SRAM_RTCT_LEN(pair) (0x8028 + (pair) * 4)
@ -24,7 +24,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
#define RTL8366RB_POWER_SAVE 0x15
#define RTL8366RB_POWER_SAVE_ON BIT(12)
@@ -1152,6 +1156,15 @@ static int rtl822x_set_serdes_option_mod
@@ -1305,6 +1309,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
@@ -1619,10 +1619,32 @@ static int rtl8226_match_phy_device(stru
@@ -1772,10 +1772,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

@ -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
@@ -1316,6 +1316,9 @@ static int rtl822x_c45_get_features(stru
@@ -1469,6 +1469,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
@@ -1196,6 +1196,22 @@ static int rtl822xb_config_init(struct p
@@ -1349,6 +1349,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)
{
@@ -2070,7 +2086,7 @@ static struct phy_driver realtek_drvs[]
@@ -2223,7 +2239,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,
@@ -2098,7 +2114,7 @@ static struct phy_driver realtek_drvs[]
@@ -2251,7 +2267,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
@@ -1107,6 +1107,11 @@ static int rtl822x_set_serdes_option_mod
@@ -1260,6 +1260,11 @@ static int rtl822x_set_serdes_option_mod
phydev->host_interfaces) ||
phydev->interface == PHY_INTERFACE_MODE_SGMII;