From: Aleksander Jan Bajkowski Date: Sat, 29 Nov 2025 16:55:41 +0000 (+0100) Subject: kernel: backport upstream Realtek PHY patches X-Git-Url: http://git.openwrt.org/?a=commitdiff_plain;h=48c9e5509407c670d8cbf19fb6cb35b9d30d81f8;p=openwrt%2Fstaging%2Fxback.git 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 Link: https://github.com/openwrt/openwrt/pull/20987 Signed-off-by: Hauke Mehrtens --- diff --git a/target/linux/generic/backport-6.12/630-v6.14-PM-sleep-wakeirq-Introduce-device-managed-variant-of.patch b/target/linux/generic/backport-6.12/630-v6.14-PM-sleep-wakeirq-Introduce-device-managed-variant-of.patch new file mode 100644 index 0000000000..081bcda591 --- /dev/null +++ b/target/linux/generic/backport-6.12/630-v6.14-PM-sleep-wakeirq-Introduce-device-managed-variant-of.patch @@ -0,0 +1,74 @@ +From fd8318a32573d73eb20637a0c80689de0dc98169 Mon Sep 17 00:00:00 2001 +From: Peng Fan +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 +Link: https://patch.msgid.link/20250103-wake_irq-v2-1-e3aeff5e9966@nxp.com +Signed-off-by: Rafael J. Wysocki +--- + 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 */ diff --git a/target/linux/generic/backport-6.12/784-02-v6.18-net-phy-realtek-Avoid-PHYCR2-access-if-PHYCR2-not-pr.patch b/target/linux/generic/backport-6.12/784-02-v6.18-net-phy-realtek-Avoid-PHYCR2-access-if-PHYCR2-not-pr.patch new file mode 100644 index 0000000000..681b234fc5 --- /dev/null +++ b/target/linux/generic/backport-6.12/784-02-v6.18-net-phy-realtek-Avoid-PHYCR2-access-if-PHYCR2-not-pr.patch @@ -0,0 +1,61 @@ +From 2c67301584f2671e320236df6bbe75ae09feb4d0 Mon Sep 17 00:00:00 2001 +From: Marek Vasut +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 +Reviewed-by: Maxime Chevallier +Reviewed-by: Russell King (Oracle) +Link: https://patch.msgid.link/20251011110309.12664-1-marek.vasut@mailbox.org +Signed-off-by: Jakub Kicinski +--- + 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) diff --git a/target/linux/generic/backport-6.12/784-02-v6.18-net-phy-realtek-fix-RTL8211F-wake-on-lan-support.patch b/target/linux/generic/backport-6.12/784-02-v6.18-net-phy-realtek-fix-RTL8211F-wake-on-lan-support.patch new file mode 100644 index 0000000000..b5c4f8f9fc --- /dev/null +++ b/target/linux/generic/backport-6.12/784-02-v6.18-net-phy-realtek-fix-RTL8211F-wake-on-lan-support.patch @@ -0,0 +1,352 @@ +From b826bf795564ddef6402cf2cb522ae035bd117ae Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +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) +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/E1um8Ld-008jxD-Mc@rmk-PC.armlinux.org.uk +Signed-off-by: Jakub Kicinski +--- + 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 + #include + #include ++#include + #include + #include + #include +@@ -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, diff --git a/target/linux/generic/backport-6.12/784-02-v6.18-net-phy-realtek-support-for-TRIGGER_NETDEV_LINK-on-R.patch b/target/linux/generic/backport-6.12/784-02-v6.18-net-phy-realtek-support-for-TRIGGER_NETDEV_LINK-on-R.patch deleted file mode 100644 index 83ea4928e9..0000000000 --- a/target/linux/generic/backport-6.12/784-02-v6.18-net-phy-realtek-support-for-TRIGGER_NETDEV_LINK-on-R.patch +++ /dev/null @@ -1,105 +0,0 @@ -From f63f21e82ecafd288b100ea161247820bf1e92c4 Mon Sep 17 00:00:00 2001 -From: Aleksander Jan Bajkowski -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 -Reviewed-by: Andrew Lunn -Link: https://patch.msgid.link/20250825211059.143231-1-olek2@wp.pl -Signed-off-by: Jakub Kicinski ---- - 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, diff --git a/target/linux/generic/backport-6.12/784-03-v6.18-net-phy-realtek-Avoid-PHYCR2-access-if-PHYCR2-not-pr.patch b/target/linux/generic/backport-6.12/784-03-v6.18-net-phy-realtek-Avoid-PHYCR2-access-if-PHYCR2-not-pr.patch deleted file mode 100644 index 681b234fc5..0000000000 --- a/target/linux/generic/backport-6.12/784-03-v6.18-net-phy-realtek-Avoid-PHYCR2-access-if-PHYCR2-not-pr.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 2c67301584f2671e320236df6bbe75ae09feb4d0 Mon Sep 17 00:00:00 2001 -From: Marek Vasut -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 -Reviewed-by: Maxime Chevallier -Reviewed-by: Russell King (Oracle) -Link: https://patch.msgid.link/20251011110309.12664-1-marek.vasut@mailbox.org -Signed-off-by: Jakub Kicinski ---- - 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) diff --git a/target/linux/generic/backport-6.12/784-03-v6.18-net-phy-realtek-fix-rtl8221b-vm-cg-name.patch b/target/linux/generic/backport-6.12/784-03-v6.18-net-phy-realtek-fix-rtl8221b-vm-cg-name.patch new file mode 100644 index 0000000000..ab319f0806 --- /dev/null +++ b/target/linux/generic/backport-6.12/784-03-v6.18-net-phy-realtek-fix-rtl8221b-vm-cg-name.patch @@ -0,0 +1,70 @@ +From ffff5c8fc2af2218a3332b3d5b97654599d50cde Mon Sep 17 00:00:00 2001 +From: Aleksander Jan Bajkowski +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 +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20251016192325.2306757-1-olek2@wp.pl +Signed-off-by: Jakub Kicinski +--- + 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 +@@ -154,7 +154,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 + +@@ -1498,16 +1498,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, +@@ -1854,7 +1854,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, +@@ -1867,8 +1867,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, diff --git a/target/linux/generic/backport-6.12/784-03-v6.18-net-phy-realtek-support-for-TRIGGER_NETDEV_LINK-on-R.patch b/target/linux/generic/backport-6.12/784-03-v6.18-net-phy-realtek-support-for-TRIGGER_NETDEV_LINK-on-R.patch new file mode 100644 index 0000000000..dc8d247dae --- /dev/null +++ b/target/linux/generic/backport-6.12/784-03-v6.18-net-phy-realtek-support-for-TRIGGER_NETDEV_LINK-on-R.patch @@ -0,0 +1,105 @@ +From f63f21e82ecafd288b100ea161247820bf1e92c4 Mon Sep 17 00:00:00 2001 +From: Aleksander Jan Bajkowski +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 +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20250825211059.143231-1-olek2@wp.pl +Signed-off-by: Jakub Kicinski +--- + 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 +@@ -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) + { +- 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) | +@@ -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); + ++ 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); +@@ -830,14 +837,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)) { +@@ -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); + ++ if ((cr2 & RTL8211E_LEDCR2_LINK_10) && ++ (cr2 & RTL8211E_LEDCR2_LINK_100) && ++ (cr2 & RTL8211E_LEDCR2_LINK_1000)) { ++ __set_bit(TRIGGER_NETDEV_LINK, rules); ++ } ++ + return ret; + } + +@@ -912,14 +931,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, diff --git a/target/linux/generic/backport-6.12/784-04-v6.18-net-phy-realtek-fix-rtl8221b-vm-cg-name.patch b/target/linux/generic/backport-6.12/784-04-v6.18-net-phy-realtek-fix-rtl8221b-vm-cg-name.patch deleted file mode 100644 index 402bdeb9a3..0000000000 --- a/target/linux/generic/backport-6.12/784-04-v6.18-net-phy-realtek-fix-rtl8221b-vm-cg-name.patch +++ /dev/null @@ -1,70 +0,0 @@ -From ffff5c8fc2af2218a3332b3d5b97654599d50cde Mon Sep 17 00:00:00 2001 -From: Aleksander Jan Bajkowski -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 -Reviewed-by: Simon Horman -Link: https://patch.msgid.link/20251016192325.2306757-1-olek2@wp.pl -Signed-off-by: Jakub Kicinski ---- - 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, diff --git a/target/linux/generic/backport-6.12/784-05-v6.19-net-phy-realtek-Add-RTL8224-cable-testing-support.patch b/target/linux/generic/backport-6.12/784-05-v6.19-net-phy-realtek-Add-RTL8224-cable-testing-support.patch deleted file mode 100644 index 90a3dc1f7b..0000000000 --- a/target/linux/generic/backport-6.12/784-05-v6.19-net-phy-realtek-Add-RTL8224-cable-testing-support.patch +++ /dev/null @@ -1,272 +0,0 @@ -From 61958b33ef0bab1c1874c933cd3910f495526782 Mon Sep 17 00:00:00 2001 -From: Issam Hamdi -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 -Co-developed-by: Sven Eckelmann -Signed-off-by: Sven Eckelmann -Reviewed-by: Andrew Lunn -Link: https://patch.msgid.link/20251024-rtl8224-cable-test-v1-1-e3cda89ac98f@simonwunderlich.de -Signed-off-by: Jakub Kicinski ---- - 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 -+#include - #include - #include - #include -@@ -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", diff --git a/target/linux/generic/backport-6.12/784-06-v6.19-net-phy-realtek-Add-RTL8224-cable-testing-support.patch b/target/linux/generic/backport-6.12/784-06-v6.19-net-phy-realtek-Add-RTL8224-cable-testing-support.patch new file mode 100644 index 0000000000..d95211dc65 --- /dev/null +++ b/target/linux/generic/backport-6.12/784-06-v6.19-net-phy-realtek-Add-RTL8224-cable-testing-support.patch @@ -0,0 +1,272 @@ +From 61958b33ef0bab1c1874c933cd3910f495526782 Mon Sep 17 00:00:00 2001 +From: Issam Hamdi +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 +Co-developed-by: Sven Eckelmann +Signed-off-by: Sven Eckelmann +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20251024-rtl8224-cable-test-v1-1-e3cda89ac98f@simonwunderlich.de +Signed-off-by: Jakub Kicinski +--- + 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 ++#include + #include + #include + #include +@@ -127,6 +128,27 @@ + */ + #define RTL822X_VND2_C22_REG(reg) (0xa400 + 2 * (reg)) + ++#define RTL8224_MII_RTCT 0x11 ++#define RTL8224_MII_RTCT_ENABLE BIT(0) ++#define RTL8224_MII_RTCT_PAIR_A BIT(4) ++#define RTL8224_MII_RTCT_PAIR_B BIT(5) ++#define RTL8224_MII_RTCT_PAIR_C BIT(6) ++#define RTL8224_MII_RTCT_PAIR_D BIT(7) ++#define RTL8224_MII_RTCT_DONE BIT(15) ++ ++#define RTL8224_MII_SRAM_ADDR 0x1b ++#define RTL8224_MII_SRAM_DATA 0x1c ++ ++#define RTL8224_SRAM_RTCT_FAULT(pair) (0x8026 + (pair) * 4) ++#define RTL8224_SRAM_RTCT_FAULT_BUSY BIT(0) ++#define RTL8224_SRAM_RTCT_FAULT_OPEN BIT(3) ++#define RTL8224_SRAM_RTCT_FAULT_SAME_SHORT BIT(4) ++#define RTL8224_SRAM_RTCT_FAULT_OK BIT(5) ++#define RTL8224_SRAM_RTCT_FAULT_DONE BIT(6) ++#define RTL8224_SRAM_RTCT_FAULT_CROSS_SHORT BIT(7) ++ ++#define RTL8224_SRAM_RTCT_LEN(pair) (0x8028 + (pair) * 4) ++ + #define RTL8366RB_POWER_SAVE 0x15 + #define RTL8366RB_POWER_SAVE_ON BIT(12) + +@@ -1453,6 +1475,168 @@ static int rtl822xb_c45_read_status(stru + return 0; + } + ++static int rtl8224_cable_test_start(struct phy_device *phydev) ++{ ++ u32 val; ++ int ret; ++ ++ /* disable auto-negotiation and force 1000/Full */ ++ ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, ++ RTL822X_VND2_C22_REG(MII_BMCR), ++ BMCR_ANENABLE | BMCR_SPEED100 | BMCR_SPEED10, ++ BMCR_SPEED1000 | BMCR_FULLDPLX); ++ if (ret) ++ return ret; ++ ++ mdelay(500); ++ ++ /* trigger cable test */ ++ val = RTL8224_MII_RTCT_ENABLE; ++ val |= RTL8224_MII_RTCT_PAIR_A; ++ val |= RTL8224_MII_RTCT_PAIR_B; ++ val |= RTL8224_MII_RTCT_PAIR_C; ++ val |= RTL8224_MII_RTCT_PAIR_D; ++ ++ return phy_modify_mmd(phydev, MDIO_MMD_VEND2, ++ RTL822X_VND2_C22_REG(RTL8224_MII_RTCT), ++ RTL8224_MII_RTCT_DONE, val); ++} ++ ++static int rtl8224_sram_read(struct phy_device *phydev, u32 reg) ++{ ++ int ret; ++ ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, ++ RTL822X_VND2_C22_REG(RTL8224_MII_SRAM_ADDR), ++ reg); ++ if (ret) ++ return ret; ++ ++ return phy_read_mmd(phydev, MDIO_MMD_VEND2, ++ RTL822X_VND2_C22_REG(RTL8224_MII_SRAM_DATA)); ++} ++ ++static int rtl8224_pair_len_get(struct phy_device *phydev, u32 pair) ++{ ++ int cable_len; ++ u32 reg_len; ++ int ret; ++ u32 cm; ++ ++ reg_len = RTL8224_SRAM_RTCT_LEN(pair); ++ ++ ret = rtl8224_sram_read(phydev, reg_len); ++ if (ret < 0) ++ return ret; ++ ++ cable_len = ret & 0xff00; ++ ++ ret = rtl8224_sram_read(phydev, reg_len + 1); ++ if (ret < 0) ++ return ret; ++ ++ cable_len |= (ret & 0xff00) >> 8; ++ ++ cable_len -= 620; ++ cable_len = max(cable_len, 0); ++ ++ cm = cable_len * 100 / 78; ++ ++ return cm; ++} ++ ++static int rtl8224_cable_test_result_trans(u32 result) ++{ ++ if (!(result & RTL8224_SRAM_RTCT_FAULT_DONE)) ++ return -EBUSY; ++ ++ if (result & RTL8224_SRAM_RTCT_FAULT_OK) ++ return ETHTOOL_A_CABLE_RESULT_CODE_OK; ++ ++ if (result & RTL8224_SRAM_RTCT_FAULT_OPEN) ++ return ETHTOOL_A_CABLE_RESULT_CODE_OPEN; ++ ++ if (result & RTL8224_SRAM_RTCT_FAULT_SAME_SHORT) ++ return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT; ++ ++ if (result & RTL8224_SRAM_RTCT_FAULT_BUSY) ++ return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC; ++ ++ if (result & RTL8224_SRAM_RTCT_FAULT_CROSS_SHORT) ++ return ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT; ++ ++ return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC; ++} ++ ++static int rtl8224_cable_test_report_pair(struct phy_device *phydev, unsigned int pair) ++{ ++ int fault_rslt; ++ int ret; ++ ++ ret = rtl8224_sram_read(phydev, RTL8224_SRAM_RTCT_FAULT(pair)); ++ if (ret < 0) ++ return ret; ++ ++ fault_rslt = rtl8224_cable_test_result_trans(ret); ++ if (fault_rslt < 0) ++ return 0; ++ ++ ret = ethnl_cable_test_result(phydev, pair, fault_rslt); ++ if (ret < 0) ++ return ret; ++ ++ switch (fault_rslt) { ++ case ETHTOOL_A_CABLE_RESULT_CODE_OPEN: ++ case ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT: ++ case ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT: ++ ret = rtl8224_pair_len_get(phydev, pair); ++ if (ret < 0) ++ return ret; ++ ++ return ethnl_cable_test_fault_length(phydev, pair, ret); ++ default: ++ return 0; ++ } ++} ++ ++static int rtl8224_cable_test_report(struct phy_device *phydev, bool *finished) ++{ ++ unsigned int pair; ++ int ret; ++ ++ for (pair = ETHTOOL_A_CABLE_PAIR_A; pair <= ETHTOOL_A_CABLE_PAIR_D; pair++) { ++ ret = rtl8224_cable_test_report_pair(phydev, pair); ++ if (ret == -EBUSY) { ++ *finished = false; ++ return 0; ++ } ++ ++ if (ret < 0) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int rtl8224_cable_test_get_status(struct phy_device *phydev, bool *finished) ++{ ++ int ret; ++ ++ *finished = false; ++ ++ ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, ++ RTL822X_VND2_C22_REG(RTL8224_MII_RTCT)); ++ if (ret < 0) ++ return ret; ++ ++ if (!(ret & RTL8224_MII_RTCT_DONE)) ++ return 0; ++ ++ *finished = true; ++ ++ return rtl8224_cable_test_report(phydev, finished); ++} ++ + static bool rtlgen_supports_2_5gbps(struct phy_device *phydev) + { + int val; +@@ -1930,11 +2114,14 @@ static struct phy_driver realtek_drvs[] + }, { + PHY_ID_MATCH_EXACT(0x001ccad0), + .name = "RTL8224 2.5Gbps PHY", ++ .flags = PHY_POLL_CABLE_TEST, + .get_features = rtl822x_c45_get_features, + .config_aneg = rtl822x_c45_config_aneg, + .read_status = rtl822x_c45_read_status, + .suspend = genphy_c45_pma_suspend, + .resume = rtlgen_c45_resume, ++ .cable_test_start = rtl8224_cable_test_start, ++ .cable_test_get_status = rtl8224_cable_test_get_status, + }, { + PHY_ID_MATCH_EXACT(0x001cc961), + .name = "RTL8366RB Gigabit Ethernet", diff --git a/target/linux/generic/backport-6.12/784-06-v6.19-net-phy-realtek-add-interrupt-support-for-RTL8221B.patch b/target/linux/generic/backport-6.12/784-06-v6.19-net-phy-realtek-add-interrupt-support-for-RTL8221B.patch deleted file mode 100644 index 496174b251..0000000000 --- a/target/linux/generic/backport-6.12/784-06-v6.19-net-phy-realtek-add-interrupt-support-for-RTL8221B.patch +++ /dev/null @@ -1,105 +0,0 @@ -From 18aa36238a4d835c1644dcccd63d32c7fdd4b310 Mon Sep 17 00:00:00 2001 -From: Jianhui Zhao -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 -[Enable only link state change interrupts] -Signed-off-by: Aleksander Jan Bajkowski -Reviewed-by: Andrew Lunn -Link: https://patch.msgid.link/20251102152644.1676482-1-olek2@wp.pl -Signed-off-by: Jakub Kicinski ---- - 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, diff --git a/target/linux/generic/backport-6.12/784-07-v6.19-net-phy-realtek-add-interrupt-support-for-RTL8221B.patch b/target/linux/generic/backport-6.12/784-07-v6.19-net-phy-realtek-add-interrupt-support-for-RTL8221B.patch new file mode 100644 index 0000000000..2efa4e961b --- /dev/null +++ b/target/linux/generic/backport-6.12/784-07-v6.19-net-phy-realtek-add-interrupt-support-for-RTL8221B.patch @@ -0,0 +1,105 @@ +From 18aa36238a4d835c1644dcccd63d32c7fdd4b310 Mon Sep 17 00:00:00 2001 +From: Jianhui Zhao +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 +[Enable only link state change interrupts] +Signed-off-by: Aleksander Jan Bajkowski +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20251102152644.1676482-1-olek2@wp.pl +Signed-off-by: Jakub Kicinski +--- + 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 +@@ -128,6 +128,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) +@@ -1880,6 +1885,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), +@@ -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)", ++ .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, +@@ -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)", ++ .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, diff --git a/target/linux/generic/backport-6.12/784-08-v6.19-net-phy-realtek-create-rtl8211f_config_rgmii_delay.patch b/target/linux/generic/backport-6.12/784-08-v6.19-net-phy-realtek-create-rtl8211f_config_rgmii_delay.patch new file mode 100644 index 0000000000..0c523ee683 --- /dev/null +++ b/target/linux/generic/backport-6.12/784-08-v6.19-net-phy-realtek-create-rtl8211f_config_rgmii_delay.patch @@ -0,0 +1,128 @@ +From 8e982441ba601d982dd0739972115d85ae01d99b Mon Sep 17 00:00:00 2001 +From: Vladimir Oltean +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 +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20251117234033.345679-2-vladimir.oltean@nxp.com +Signed-off-by: Jakub Kicinski +--- + 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; + diff --git a/target/linux/generic/backport-6.12/784-09-v6.19-net-phy-realtek-eliminate-priv-phycr2-variable.patch b/target/linux/generic/backport-6.12/784-09-v6.19-net-phy-realtek-eliminate-priv-phycr2-variable.patch new file mode 100644 index 0000000000..1c67961d2e --- /dev/null +++ b/target/linux/generic/backport-6.12/784-09-v6.19-net-phy-realtek-eliminate-priv-phycr2-variable.patch @@ -0,0 +1,101 @@ +From 27033d06917758d47162581da7e9de8004049dee Mon Sep 17 00:00:00 2001 +From: Vladimir Oltean +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 +Link: https://patch.msgid.link/20251117234033.345679-3-vladimir.oltean@nxp.com +Signed-off-by: Jakub Kicinski +--- + 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) diff --git a/target/linux/generic/backport-6.12/784-10-v6.19-net-phy-realtek-eliminate-has_phycr2-variable.patch b/target/linux/generic/backport-6.12/784-10-v6.19-net-phy-realtek-eliminate-has_phycr2-variable.patch new file mode 100644 index 0000000000..a78cb3d1cc --- /dev/null +++ b/target/linux/generic/backport-6.12/784-10-v6.19-net-phy-realtek-eliminate-has_phycr2-variable.patch @@ -0,0 +1,55 @@ +From 910ac7bfb1af1ae4cd141ef80e03a6729213c189 Mon Sep 17 00:00:00 2001 +From: Vladimir Oltean +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 +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20251117234033.345679-4-vladimir.oltean@nxp.com +Signed-off-by: Jakub Kicinski +--- + 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 */ diff --git a/target/linux/generic/backport-6.12/784-11-v6.19-net-phy-realtek-allow-CLKOUT-to-be-disabled-on-RTL82.patch b/target/linux/generic/backport-6.12/784-11-v6.19-net-phy-realtek-allow-CLKOUT-to-be-disabled-on-RTL82.patch new file mode 100644 index 0000000000..2a3239d4a2 --- /dev/null +++ b/target/linux/generic/backport-6.12/784-11-v6.19-net-phy-realtek-allow-CLKOUT-to-be-disabled-on-RTL82.patch @@ -0,0 +1,101 @@ +From e1a31c41bef678afe0d99b7f0dc3711a80c68447 Mon Sep 17 00:00:00 2001 +From: Vladimir Oltean +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 +Signed-off-by: Clark Wang +Signed-off-by: Vladimir Oltean +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20251117234033.345679-5-vladimir.oltean@nxp.com +Signed-off-by: Jakub Kicinski +--- + 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; + } + diff --git a/target/linux/generic/backport-6.12/784-12-v6.19-net-phy-realtek-eliminate-priv-phycr1-variable.patch b/target/linux/generic/backport-6.12/784-12-v6.19-net-phy-realtek-eliminate-priv-phycr1-variable.patch new file mode 100644 index 0000000000..a2e5abe93f --- /dev/null +++ b/target/linux/generic/backport-6.12/784-12-v6.19-net-phy-realtek-eliminate-priv-phycr1-variable.patch @@ -0,0 +1,107 @@ +From bb78b71faf60d11a15f07e3390fcfd31e5e523bb Mon Sep 17 00:00:00 2001 +From: Vladimir Oltean +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 +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20251117234033.345679-6-vladimir.oltean@nxp.com +Signed-off-by: Jakub Kicinski +--- + 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; + } diff --git a/target/linux/generic/backport-6.12/784-13-v6.19-net-phy-realtek-create-rtl8211f_config_phy_eee-helpe.patch b/target/linux/generic/backport-6.12/784-13-v6.19-net-phy-realtek-create-rtl8211f_config_phy_eee-helpe.patch new file mode 100644 index 0000000000..54ec217aff --- /dev/null +++ b/target/linux/generic/backport-6.12/784-13-v6.19-net-phy-realtek-create-rtl8211f_config_phy_eee-helpe.patch @@ -0,0 +1,58 @@ +From 4465ae435ddc0162d5033a543658449d53d46d08 Mon Sep 17 00:00:00 2001 +From: Vladimir Oltean +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 +Link: https://patch.msgid.link/20251117234033.345679-7-vladimir.oltean@nxp.com +Signed-off-by: Jakub Kicinski +--- + 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) diff --git a/target/linux/generic/pending-6.12/720-01-net-phy-realtek-use-genphy_soft_reset-for-2.5G-PHYs.patch b/target/linux/generic/pending-6.12/720-01-net-phy-realtek-use-genphy_soft_reset-for-2.5G-PHYs.patch index c36749800a..20b4055632 100644 --- a/target/linux/generic/pending-6.12/720-01-net-phy-realtek-use-genphy_soft_reset-for-2.5G-PHYs.patch +++ b/target/linux/generic/pending-6.12/720-01-net-phy-realtek-use-genphy_soft_reset-for-2.5G-PHYs.patch @@ -15,7 +15,7 @@ Signed-off-by: Daniel Golle --- 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 .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 .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 .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 .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 .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 .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, diff --git a/target/linux/generic/pending-6.12/720-02-net-phy-realtek-disable-SGMII-in-band-AN-for-2-5G-PHYs.patch b/target/linux/generic/pending-6.12/720-02-net-phy-realtek-disable-SGMII-in-band-AN-for-2-5G-PHYs.patch index a3a205532f..3662ac10ae 100644 --- a/target/linux/generic/pending-6.12/720-02-net-phy-realtek-disable-SGMII-in-band-AN-for-2-5G-PHYs.patch +++ b/target/linux/generic/pending-6.12/720-02-net-phy-realtek-disable-SGMII-in-band-AN-for-2-5G-PHYs.patch @@ -20,7 +20,7 @@ Signed-off-by: Daniel Golle --- 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 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); diff --git a/target/linux/generic/pending-6.12/720-03-net-phy-realtek-make-sure-paged-read-is-protected-by.patch b/target/linux/generic/pending-6.12/720-03-net-phy-realtek-make-sure-paged-read-is-protected-by.patch index 1e3af07594..e72748d8f0 100644 --- a/target/linux/generic/pending-6.12/720-03-net-phy-realtek-make-sure-paged-read-is-protected-by.patch +++ b/target/linux/generic/pending-6.12/720-03-net-phy-realtek-make-sure-paged-read-is-protected-by.patch @@ -18,7 +18,7 @@ Signed-off-by: Daniel Golle --- 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; diff --git a/target/linux/generic/pending-6.12/720-04-net-phy-realtek-setup-aldps.patch b/target/linux/generic/pending-6.12/720-04-net-phy-realtek-setup-aldps.patch index 5a908fcef5..29da51b680 100644 --- a/target/linux/generic/pending-6.12/720-04-net-phy-realtek-setup-aldps.patch +++ b/target/linux/generic/pending-6.12/720-04-net-phy-realtek-setup-aldps.patch @@ -13,7 +13,7 @@ Signed-off-by: Daniel Golle --- 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 #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; } diff --git a/target/linux/generic/pending-6.12/720-05-net-phy-realtek-detect-early-version-of-RTL8221B.patch b/target/linux/generic/pending-6.12/720-05-net-phy-realtek-detect-early-version-of-RTL8221B.patch index 7c3a44eaea..79c45a8951 100644 --- a/target/linux/generic/pending-6.12/720-05-net-phy-realtek-detect-early-version-of-RTL8221B.patch +++ b/target/linux/generic/pending-6.12/720-05-net-phy-realtek-detect-early-version-of-RTL8221B.patch @@ -14,7 +14,7 @@ Signed-off-by: Daniel Golle Signed-off-by: Mieczyslaw Nalewaj --- 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) { diff --git a/target/linux/generic/pending-6.12/720-07-net-phy-realtek-mark-existing-MMDs-as-present.patch b/target/linux/generic/pending-6.12/720-07-net-phy-realtek-mark-existing-MMDs-as-present.patch index ed6e29ac8b..c6162f7c1f 100644 --- a/target/linux/generic/pending-6.12/720-07-net-phy-realtek-mark-existing-MMDs-as-present.patch +++ b/target/linux/generic/pending-6.12/720-07-net-phy-realtek-mark-existing-MMDs-as-present.patch @@ -15,7 +15,7 @@ Signed-off-by: Daniel Golle --- 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); diff --git a/target/linux/generic/pending-6.12/720-08-net-phy-realtek-work-around-broken-serdes.patch b/target/linux/generic/pending-6.12/720-08-net-phy-realtek-work-around-broken-serdes.patch index fcf4350fe9..05adfdc8cc 100644 --- a/target/linux/generic/pending-6.12/720-08-net-phy-realtek-work-around-broken-serdes.patch +++ b/target/linux/generic/pending-6.12/720-08-net-phy-realtek-work-around-broken-serdes.patch @@ -15,7 +15,7 @@ Signed-off-by: Daniel Golle --- --- 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 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 .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, diff --git a/target/linux/generic/pending-6.12/720-09-net-phy-realtek-disable-MDIO-broadcast.patch b/target/linux/generic/pending-6.12/720-09-net-phy-realtek-disable-MDIO-broadcast.patch index f2e009bc35..6217e46e82 100644 --- a/target/linux/generic/pending-6.12/720-09-net-phy-realtek-disable-MDIO-broadcast.patch +++ b/target/linux/generic/pending-6.12/720-09-net-phy-realtek-disable-MDIO-broadcast.patch @@ -13,7 +13,7 @@ Signed-off-by: Daniel Golle --- --- 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;