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.

phy: xilinx: phy-zynqmp: dynamic clock support for power-save

Enabling clock for all the lanes consumes power even PHY is active or
inactive. To resolve this, enable/disable clocks in phy_init/phy_exit.

By default clock is disabled for all the lanes. Whenever phy_init called
from USB, SATA, or display driver, etc. It enabled the required clock
for requested lane. On phy_exit cycle, it disabled clock for the active
PHYs.

During the suspend/resume cycle, each USB/ SATA/ display driver called
phy_exit/phy_init individually. It disabled clock on exit, and enabled
on initialization for the active PHYs.

Signed-off-by: Piyush Mehta <piyush.mehta@amd.com>
Link: https://lore.kernel.org/r/20230613140250.3018947-3-piyush.mehta@amd.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Piyush Mehta and committed by
Vinod Koul
25d70083 b3db66f6

+15 -46
+15 -46
drivers/phy/xilinx/phy-zynqmp.c
··· 572 572 573 573 mutex_lock(&gtr_dev->gtr_mutex); 574 574 575 + /* Configure and enable the clock when peripheral phy_init call */ 576 + if (clk_prepare_enable(gtr_dev->clk[gtr_phy->lane])) 577 + goto out; 578 + 575 579 /* Skip initialization if not required. */ 576 580 if (!xpsgtr_phy_init_required(gtr_phy)) 577 581 goto out; ··· 620 616 static int xpsgtr_phy_exit(struct phy *phy) 621 617 { 622 618 struct xpsgtr_phy *gtr_phy = phy_get_drvdata(phy); 619 + struct xpsgtr_dev *gtr_dev = gtr_phy->dev; 623 620 624 621 gtr_phy->skip_phy_init = false; 622 + 623 + /* Ensure that disable clock only, which configure for lane */ 624 + clk_disable_unprepare(gtr_dev->clk[gtr_phy->lane]); 625 625 626 626 return 0; 627 627 } ··· 832 824 static int xpsgtr_runtime_suspend(struct device *dev) 833 825 { 834 826 struct xpsgtr_dev *gtr_dev = dev_get_drvdata(dev); 835 - unsigned int i; 836 827 837 828 /* Save the snapshot ICM_CFG registers. */ 838 829 gtr_dev->saved_icm_cfg0 = xpsgtr_read(gtr_dev, ICM_CFG0); 839 830 gtr_dev->saved_icm_cfg1 = xpsgtr_read(gtr_dev, ICM_CFG1); 840 - 841 - for (i = 0; i < ARRAY_SIZE(gtr_dev->clk); i++) 842 - clk_disable_unprepare(gtr_dev->clk[i]); 843 831 844 832 return 0; 845 833 } ··· 846 842 unsigned int icm_cfg0, icm_cfg1; 847 843 unsigned int i; 848 844 bool skip_phy_init; 849 - int err; 850 - 851 - for (i = 0; i < ARRAY_SIZE(gtr_dev->clk); i++) { 852 - err = clk_prepare_enable(gtr_dev->clk[i]); 853 - if (err) 854 - goto err_clk_put; 855 - } 856 845 857 846 icm_cfg0 = xpsgtr_read(gtr_dev, ICM_CFG0); 858 847 icm_cfg1 = xpsgtr_read(gtr_dev, ICM_CFG1); ··· 866 869 gtr_dev->phys[i].skip_phy_init = skip_phy_init; 867 870 868 871 return 0; 869 - 870 - err_clk_put: 871 - while (i--) 872 - clk_disable_unprepare(gtr_dev->clk[i]); 873 - 874 - return err; 875 872 } 876 873 877 874 static DEFINE_RUNTIME_DEV_PM_OPS(xpsgtr_pm_ops, xpsgtr_runtime_suspend, ··· 877 886 static int xpsgtr_get_ref_clocks(struct xpsgtr_dev *gtr_dev) 878 887 { 879 888 unsigned int refclk; 880 - int ret; 881 889 882 890 for (refclk = 0; refclk < ARRAY_SIZE(gtr_dev->refclk_sscs); ++refclk) { 883 891 unsigned long rate; ··· 887 897 snprintf(name, sizeof(name), "ref%u", refclk); 888 898 clk = devm_clk_get_optional(gtr_dev->dev, name); 889 899 if (IS_ERR(clk)) { 890 - ret = dev_err_probe(gtr_dev->dev, PTR_ERR(clk), 891 - "Failed to get reference clock %u\n", 892 - refclk); 893 - goto err_clk_put; 900 + return dev_err_probe(gtr_dev->dev, PTR_ERR(clk), 901 + "Failed to get ref clock %u\n", 902 + refclk); 894 903 } 895 904 896 905 if (!clk) 897 906 continue; 898 - 899 - ret = clk_prepare_enable(clk); 900 - if (ret) 901 - goto err_clk_put; 902 907 903 908 gtr_dev->clk[refclk] = clk; 904 909 ··· 914 929 dev_err(gtr_dev->dev, 915 930 "Invalid rate %lu for reference clock %u\n", 916 931 rate, refclk); 917 - ret = -EINVAL; 918 - goto err_clk_put; 932 + return -EINVAL; 919 933 } 920 934 } 921 935 922 936 return 0; 923 - 924 - err_clk_put: 925 - while (refclk--) 926 - clk_disable_unprepare(gtr_dev->clk[refclk]); 927 - 928 - return ret; 929 937 } 930 938 931 939 static int xpsgtr_probe(struct platform_device *pdev) ··· 927 949 struct xpsgtr_dev *gtr_dev; 928 950 struct phy_provider *provider; 929 951 unsigned int port; 930 - unsigned int i; 931 952 int ret; 932 953 933 954 gtr_dev = devm_kzalloc(&pdev->dev, sizeof(*gtr_dev), GFP_KERNEL); ··· 966 989 phy = devm_phy_create(&pdev->dev, np, &xpsgtr_phyops); 967 990 if (IS_ERR(phy)) { 968 991 dev_err(&pdev->dev, "failed to create PHY\n"); 969 - ret = PTR_ERR(phy); 970 - goto err_clk_put; 992 + return PTR_ERR(phy); 971 993 } 972 994 973 995 gtr_phy->phy = phy; ··· 977 1001 provider = devm_of_phy_provider_register(&pdev->dev, xpsgtr_xlate); 978 1002 if (IS_ERR(provider)) { 979 1003 dev_err(&pdev->dev, "registering provider failed\n"); 980 - ret = PTR_ERR(provider); 981 - goto err_clk_put; 1004 + return PTR_ERR(provider); 982 1005 } 983 1006 984 1007 pm_runtime_set_active(gtr_dev->dev); ··· 986 1011 ret = pm_runtime_resume_and_get(gtr_dev->dev); 987 1012 if (ret < 0) { 988 1013 pm_runtime_disable(gtr_dev->dev); 989 - goto err_clk_put; 1014 + return ret; 990 1015 } 991 1016 992 1017 return 0; 993 - 994 - err_clk_put: 995 - for (i = 0; i < ARRAY_SIZE(gtr_dev->clk); i++) 996 - clk_disable_unprepare(gtr_dev->clk[i]); 997 - 998 - return ret; 999 1018 } 1000 1019 1001 1020 static int xpsgtr_remove(struct platform_device *pdev)