Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'disable-clkout-on-rtl8211f-d-i-vd-cg'

Vladimir Oltean says:

====================
Disable CLKOUT on RTL8211F(D)(I)-VD-CG

The Realtek RTL8211F(D)(I)-VD-CG is similar to other RTL8211F models in
that the CLKOUT signal can be turned off - a feature requested to reduce
EMI, and implemented via "realtek,clkout-disable" as documented in
Documentation/devicetree/bindings/net/realtek,rtl82xx.yaml.

It is also dissimilar to said PHY models because it has no PHYCR2
register, and disabling CLKOUT is done through some other register.

The strategy adopted in this 6-patch series is to make the PHY driver
not think in terms of "priv->has_phycr2" and "priv->phycr2", but of more
high-level features ("priv->disable_clk_out") while maintaining behaviour.
Then, the logic is extended for the new PHY.

Very loosely based on previous work from Clark Wang, who took a
different approach, to pretend that the RTL8211FVD_CLKOUT_REG is
actually this PHY's PHYCR2.
====================

Link: https://patch.msgid.link/20251117234033.345679-1-vladimir.oltean@nxp.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+103 -58
+103 -58
drivers/net/phy/realtek/realtek_main.c
··· 90 90 #define RTL8211F_LEDCR_MASK GENMASK(4, 0) 91 91 #define RTL8211F_LEDCR_SHIFT 5 92 92 93 + /* RTL8211F(D)(I)-VD-CG CLKOUT configuration is specified via magic values 94 + * to undocumented register pages. The names here do not reflect the datasheet. 95 + * Unlike other PHY models, CLKOUT configuration does not go through PHYCR2. 96 + */ 97 + #define RTL8211FVD_CLKOUT_PAGE 0xd05 98 + #define RTL8211FVD_CLKOUT_REG 0x11 99 + #define RTL8211FVD_CLKOUT_EN BIT(8) 100 + 93 101 /* RTL8211F RGMII configuration */ 94 102 #define RTL8211F_RGMII_PAGE 0xd08 95 103 ··· 201 193 MODULE_LICENSE("GPL"); 202 194 203 195 struct rtl821x_priv { 204 - u16 phycr1; 205 - u16 phycr2; 206 - bool has_phycr2; 196 + bool enable_aldps; 197 + bool disable_clk_out; 207 198 struct clk *clk; 208 199 /* rtl8211f */ 209 200 u16 iner; ··· 252 245 { 253 246 struct device *dev = &phydev->mdio.dev; 254 247 struct rtl821x_priv *priv; 255 - u32 phy_id = phydev->drv->phy_id; 256 - int ret; 257 248 258 249 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 259 250 if (!priv) ··· 262 257 return dev_err_probe(dev, PTR_ERR(priv->clk), 263 258 "failed to get phy clock\n"); 264 259 265 - ret = phy_read_paged(phydev, RTL8211F_PHYCR_PAGE, RTL8211F_PHYCR1); 266 - if (ret < 0) 267 - return ret; 268 - 269 - priv->phycr1 = ret & (RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF); 270 - if (of_property_read_bool(dev->of_node, "realtek,aldps-enable")) 271 - priv->phycr1 |= RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF; 272 - 273 - priv->has_phycr2 = !(phy_id == RTL_8211FVD_PHYID); 274 - if (priv->has_phycr2) { 275 - ret = phy_read_paged(phydev, RTL8211F_PHYCR_PAGE, RTL8211F_PHYCR2); 276 - if (ret < 0) 277 - return ret; 278 - 279 - priv->phycr2 = ret & RTL8211F_CLKOUT_EN; 280 - if (of_property_read_bool(dev->of_node, "realtek,clkout-disable")) 281 - priv->phycr2 &= ~RTL8211F_CLKOUT_EN; 282 - } 260 + priv->enable_aldps = of_property_read_bool(dev->of_node, 261 + "realtek,aldps-enable"); 262 + priv->disable_clk_out = of_property_read_bool(dev->of_node, 263 + "realtek,clkout-disable"); 283 264 284 265 phydev->priv = priv; 285 266 ··· 578 587 CTL1000_ENABLE_MASTER | CTL1000_AS_MASTER); 579 588 } 580 589 581 - static int rtl8211f_config_init(struct phy_device *phydev) 590 + static int rtl8211f_config_rgmii_delay(struct phy_device *phydev) 582 591 { 583 - struct rtl821x_priv *priv = phydev->priv; 584 - struct device *dev = &phydev->mdio.dev; 585 592 u16 val_txdly, val_rxdly; 586 593 int ret; 587 - 588 - ret = phy_modify_paged_changed(phydev, RTL8211F_PHYCR_PAGE, RTL8211F_PHYCR1, 589 - RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF, 590 - priv->phycr1); 591 - if (ret < 0) { 592 - dev_err(dev, "aldps mode configuration failed: %pe\n", 593 - ERR_PTR(ret)); 594 - return ret; 595 - } 596 594 597 595 switch (phydev->interface) { 598 596 case PHY_INTERFACE_MODE_RGMII: ··· 612 632 RTL8211F_TXCR, RTL8211F_TX_DELAY, 613 633 val_txdly); 614 634 if (ret < 0) { 615 - dev_err(dev, "Failed to update the TX delay register\n"); 635 + phydev_err(phydev, "Failed to update the TX delay register: %pe\n", 636 + ERR_PTR(ret)); 616 637 return ret; 617 638 } else if (ret) { 618 - dev_dbg(dev, 619 - "%s 2ns TX delay (and changing the value from pin-strapping RXD1 or the bootloader)\n", 620 - str_enable_disable(val_txdly)); 639 + phydev_dbg(phydev, 640 + "%s 2ns TX delay (and changing the value from pin-strapping RXD1 or the bootloader)\n", 641 + str_enable_disable(val_txdly)); 621 642 } else { 622 - dev_dbg(dev, 623 - "2ns TX delay was already %s (by pin-strapping RXD1 or bootloader configuration)\n", 624 - str_enabled_disabled(val_txdly)); 643 + phydev_dbg(phydev, 644 + "2ns TX delay was already %s (by pin-strapping RXD1 or bootloader configuration)\n", 645 + str_enabled_disabled(val_txdly)); 625 646 } 626 647 627 648 ret = phy_modify_paged_changed(phydev, RTL8211F_RGMII_PAGE, 628 649 RTL8211F_RXCR, RTL8211F_RX_DELAY, 629 650 val_rxdly); 630 651 if (ret < 0) { 631 - dev_err(dev, "Failed to update the RX delay register\n"); 652 + phydev_err(phydev, "Failed to update the RX delay register: %pe\n", 653 + ERR_PTR(ret)); 632 654 return ret; 633 655 } else if (ret) { 634 - dev_dbg(dev, 635 - "%s 2ns RX delay (and changing the value from pin-strapping RXD0 or the bootloader)\n", 636 - str_enable_disable(val_rxdly)); 656 + phydev_dbg(phydev, 657 + "%s 2ns RX delay (and changing the value from pin-strapping RXD0 or the bootloader)\n", 658 + str_enable_disable(val_rxdly)); 637 659 } else { 638 - dev_dbg(dev, 639 - "2ns RX delay was already %s (by pin-strapping RXD0 or bootloader configuration)\n", 640 - str_enabled_disabled(val_rxdly)); 660 + phydev_dbg(phydev, 661 + "2ns RX delay was already %s (by pin-strapping RXD0 or bootloader configuration)\n", 662 + str_enabled_disabled(val_rxdly)); 641 663 } 642 664 643 - if (!priv->has_phycr2) 665 + return 0; 666 + } 667 + 668 + static int rtl8211f_config_clk_out(struct phy_device *phydev) 669 + { 670 + struct rtl821x_priv *priv = phydev->priv; 671 + int ret; 672 + 673 + /* The value is preserved if the device tree property is absent */ 674 + if (!priv->disable_clk_out) 644 675 return 0; 645 676 646 - /* Disable PHY-mode EEE so LPI is passed to the MAC */ 647 - ret = phy_modify_paged(phydev, RTL8211F_PHYCR_PAGE, RTL8211F_PHYCR2, 648 - RTL8211F_PHYCR2_PHY_EEE_ENABLE, 0); 677 + if (phydev->drv->phy_id == RTL_8211FVD_PHYID) 678 + ret = phy_modify_paged(phydev, RTL8211FVD_CLKOUT_PAGE, 679 + RTL8211FVD_CLKOUT_REG, 680 + RTL8211FVD_CLKOUT_EN, 0); 681 + else 682 + ret = phy_modify_paged(phydev, RTL8211F_PHYCR_PAGE, 683 + RTL8211F_PHYCR2, RTL8211F_CLKOUT_EN, 0); 649 684 if (ret) 650 685 return ret; 651 686 652 - ret = phy_modify_paged(phydev, RTL8211F_PHYCR_PAGE, 653 - RTL8211F_PHYCR2, RTL8211F_CLKOUT_EN, 654 - priv->phycr2); 655 - if (ret < 0) { 687 + return genphy_soft_reset(phydev); 688 + } 689 + 690 + /* Advance Link Down Power Saving (ALDPS) mode changes crystal/clock behaviour, 691 + * which causes the RXC clock signal to stop for tens to hundreds of 692 + * milliseconds. 693 + * 694 + * Some MACs need the RXC clock to support their internal RX logic, so ALDPS is 695 + * only enabled based on an opt-in device tree property. 696 + */ 697 + static int rtl8211f_config_aldps(struct phy_device *phydev) 698 + { 699 + struct rtl821x_priv *priv = phydev->priv; 700 + u16 mask = RTL8211F_ALDPS_PLL_OFF | 701 + RTL8211F_ALDPS_ENABLE | 702 + RTL8211F_ALDPS_XTAL_OFF; 703 + 704 + /* The value is preserved if the device tree property is absent */ 705 + if (!priv->enable_aldps) 706 + return 0; 707 + 708 + return phy_modify_paged(phydev, RTL8211F_PHYCR_PAGE, RTL8211F_PHYCR1, 709 + mask, mask); 710 + } 711 + 712 + static int rtl8211f_config_phy_eee(struct phy_device *phydev) 713 + { 714 + /* RTL8211FVD has no PHYCR2 register */ 715 + if (phydev->drv->phy_id == RTL_8211FVD_PHYID) 716 + return 0; 717 + 718 + /* Disable PHY-mode EEE so LPI is passed to the MAC */ 719 + return phy_modify_paged(phydev, RTL8211F_PHYCR_PAGE, RTL8211F_PHYCR2, 720 + RTL8211F_PHYCR2_PHY_EEE_ENABLE, 0); 721 + } 722 + 723 + static int rtl8211f_config_init(struct phy_device *phydev) 724 + { 725 + struct device *dev = &phydev->mdio.dev; 726 + int ret; 727 + 728 + ret = rtl8211f_config_aldps(phydev); 729 + if (ret) { 730 + dev_err(dev, "aldps mode configuration failed: %pe\n", 731 + ERR_PTR(ret)); 732 + return ret; 733 + } 734 + 735 + ret = rtl8211f_config_rgmii_delay(phydev); 736 + if (ret) 737 + return ret; 738 + 739 + ret = rtl8211f_config_clk_out(phydev); 740 + if (ret) { 656 741 dev_err(dev, "clkout configuration failed: %pe\n", 657 742 ERR_PTR(ret)); 658 743 return ret; 659 744 } 660 745 661 - return genphy_soft_reset(phydev); 746 + return rtl8211f_config_phy_eee(phydev); 662 747 } 663 748 664 749 static int rtl821x_suspend(struct phy_device *phydev)