From 7bf73e270e7f1704b21860712820dcf12b593e91 Mon Sep 17 00:00:00 2001 From: Sander Vanheule Date: Mon, 27 Jun 2022 20:36:32 +0200 Subject: [PATCH] kernel: backport RTL8211F clkout-disable patch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In Linux v5.14 an extra feature was introduced for the RTL8211F phy, allowing to disable a clock output from the phy. Part of that patch is to always (soft) reset the phy upon initialisation. This phy reset is required to have a working ethernet on the TP-Link EAP225-Outdoor v3 and EAP225 v4 after a reboot. Otherwise the ethernet port will only function properly on cold boots. Tested-by: Andre Klärner # EAP225-Outdoor v3 Tested-by: Sven Hauer # EAP225 v4 Signed-off-by: Sander Vanheule --- ...add-dt-property-to-disable-CLKOUT-cl.patch | 119 ++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 target/linux/generic/backport-5.10/796-v5.14-net-phy-realtek-add-dt-property-to-disable-CLKOUT-cl.patch diff --git a/target/linux/generic/backport-5.10/796-v5.14-net-phy-realtek-add-dt-property-to-disable-CLKOUT-cl.patch b/target/linux/generic/backport-5.10/796-v5.14-net-phy-realtek-add-dt-property-to-disable-CLKOUT-cl.patch new file mode 100644 index 00000000000..52a6f83500b --- /dev/null +++ b/target/linux/generic/backport-5.10/796-v5.14-net-phy-realtek-add-dt-property-to-disable-CLKOUT-cl.patch @@ -0,0 +1,119 @@ +From 0a4355c2b7f8ecd5e61cc262ecdbd4a2cce1ea7e Mon Sep 17 00:00:00 2001 +From: Joakim Zhang +Date: Tue, 8 Jun 2021 11:15:33 +0800 +Subject: [PATCH] net: phy: realtek: add dt property to disable CLKOUT clock + +CLKOUT is enabled by default after PHY hardware reset, this patch adds +"realtek,clkout-disable" property for user to disable CLKOUT clock +to save PHY power. + +Per RTL8211F guide, a PHY reset should be issued after setting these +bits in PHYCR2 register. After this patch, CLKOUT clock output to be +disabled. + +Signed-off-by: Joakim Zhang +Signed-off-by: David S. Miller +--- + drivers/net/phy/realtek.c | 42 ++++++++++++++++++++++++++++++++++++++- + 1 file changed, 41 insertions(+), 1 deletion(-) + +--- a/drivers/net/phy/realtek.c ++++ b/drivers/net/phy/realtek.c +@@ -8,6 +8,7 @@ + * Copyright (c) 2004 Freescale Semiconductor, Inc. + */ + #include ++#include + #include + #include + #include +@@ -27,6 +28,7 @@ + #define RTL821x_PAGE_SELECT 0x1f + + #define RTL8211F_PHYCR1 0x18 ++#define RTL8211F_PHYCR2 0x19 + #define RTL8211F_INSR 0x1d + + #define RTL8211F_TX_DELAY BIT(8) +@@ -40,6 +42,8 @@ + #define RTL8211E_TX_DELAY BIT(12) + #define RTL8211E_RX_DELAY BIT(11) + ++#define RTL8211F_CLKOUT_EN BIT(0) ++ + #define RTL8201F_ISR 0x1e + #define RTL8201F_IER 0x13 + +@@ -62,6 +66,10 @@ MODULE_DESCRIPTION("Realtek PHY driver") + MODULE_AUTHOR("Johnson Leung"); + MODULE_LICENSE("GPL"); + ++struct rtl821x_priv { ++ u16 phycr2; ++}; ++ + static int rtl821x_read_page(struct phy_device *phydev) + { + return __phy_read(phydev, RTL821x_PAGE_SELECT); +@@ -72,6 +80,28 @@ static int rtl821x_write_page(struct phy + return __phy_write(phydev, RTL821x_PAGE_SELECT, page); + } + ++static int rtl821x_probe(struct phy_device *phydev) ++{ ++ struct device *dev = &phydev->mdio.dev; ++ struct rtl821x_priv *priv; ++ ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->phycr2 = phy_read_paged(phydev, 0xa43, RTL8211F_PHYCR2); ++ if (priv->phycr2 < 0) ++ return priv->phycr2; ++ ++ priv->phycr2 &= RTL8211F_CLKOUT_EN; ++ if (of_property_read_bool(dev->of_node, "realtek,clkout-disable")) ++ priv->phycr2 &= ~RTL8211F_CLKOUT_EN; ++ ++ phydev->priv = priv; ++ ++ return 0; ++} ++ + static int rtl8201_ack_interrupt(struct phy_device *phydev) + { + int err; +@@ -180,6 +210,7 @@ static int rtl8211c_config_init(struct p + + static int rtl8211f_config_init(struct phy_device *phydev) + { ++ struct rtl821x_priv *priv = phydev->priv; + struct device *dev = &phydev->mdio.dev; + u16 val_txdly, val_rxdly; + u16 val; +@@ -243,7 +274,15 @@ static int rtl8211f_config_init(struct p + val_rxdly ? "enabled" : "disabled"); + } + +- return 0; ++ ret = phy_modify_paged(phydev, 0xa43, 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); + } + + static int rtl821x_resume(struct phy_device *phydev) +@@ -633,6 +672,7 @@ static struct phy_driver realtek_drvs[] + }, { + PHY_ID_MATCH_EXACT(0x001cc916), + .name = "RTL8211F Gigabit Ethernet", ++ .probe = rtl821x_probe, + .config_init = &rtl8211f_config_init, + .ack_interrupt = &rtl8211f_ack_interrupt, + .config_intr = &rtl8211f_config_intr,