mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-10-31 14:04:26 -04:00 
			
		
		
		
	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 <kandre@ak-online.be> # EAP225-Outdoor v3 Tested-by: Sven Hauer <sven.hauer+github@uniku.de> # EAP225 v4 Signed-off-by: Sander Vanheule <sander@svanheule.net>
		
			
				
	
	
		
			120 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			120 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| From 0a4355c2b7f8ecd5e61cc262ecdbd4a2cce1ea7e Mon Sep 17 00:00:00 2001
 | |
| From: Joakim Zhang <qiangqing.zhang@nxp.com>
 | |
| 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 <qiangqing.zhang@nxp.com>
 | |
| Signed-off-by: David S. Miller <davem@davemloft.net>
 | |
| ---
 | |
|  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 <linux/bitops.h>
 | |
| +#include <linux/of.h>
 | |
|  #include <linux/phy.h>
 | |
|  #include <linux/module.h>
 | |
|  #include <linux/delay.h>
 | |
| @@ -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,
 |