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: phy-rockchip-samsung-hdptx: Add clock provider support

The HDMI PHY PLL can be used as an alternative dclk source to RK3588 SoC
CRU. It provides more accurate clock rates required by VOP2 to improve
existing support for display modes handling, which is known to be
problematic when dealing with non-integer refresh rates, among others.

It is worth noting this only works for HDMI 2.0 or below, e.g. cannot be
used to support HDMI 2.1 4K@120Hz mode.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
Link: https://lore.kernel.org/r/20240620-rk3588-hdmiphy-clkprov-v2-4-6a2d2164e508@collabora.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Cristian Ciocaltea and committed by
Vinod Koul
c4b09c56 a652f221

+173 -22
+173 -22
drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
··· 8 8 */ 9 9 #include <linux/bitfield.h> 10 10 #include <linux/clk.h> 11 + #include <linux/clk-provider.h> 11 12 #include <linux/delay.h> 12 13 #include <linux/mfd/syscon.h> 13 14 #include <linux/module.h> ··· 192 191 #define LN3_TX_SER_RATE_SEL_HBR2 BIT(3) 193 192 #define LN3_TX_SER_RATE_SEL_HBR3 BIT(2) 194 193 194 + #define HDMI20_MAX_RATE 600000000 195 + 195 196 struct lcpll_config { 196 197 u32 bit_rate; 197 198 u8 lcvco_mode_en; ··· 276 273 struct clk_bulk_data *clks; 277 274 int nr_clks; 278 275 struct reset_control_bulk_data rsts[RST_MAX]; 276 + 277 + /* clk provider */ 278 + struct clk_hw hw; 279 + unsigned long rate; 280 + 281 + atomic_t usage_count; 279 282 }; 280 283 281 284 static const struct ropll_config ropll_tmds_cfg[] = { ··· 769 760 struct ropll_config rc = {0}; 770 761 int i; 771 762 763 + hdptx->rate = rate * 100; 764 + 772 765 for (i = 0; i < ARRAY_SIZE(ropll_tmds_cfg); i++) 773 766 if (rate == ropll_tmds_cfg[i].bit_rate) { 774 767 cfg = &ropll_tmds_cfg[i]; ··· 834 823 static int rk_hdptx_ropll_tmds_mode_config(struct rk_hdptx_phy *hdptx, 835 824 unsigned int rate) 836 825 { 837 - u32 val; 838 - int ret; 839 - 840 - ret = regmap_read(hdptx->grf, GRF_HDPTX_STATUS, &val); 841 - if (ret) 842 - return ret; 843 - 844 - if (!(val & HDPTX_O_PLL_LOCK_DONE)) { 845 - ret = rk_hdptx_ropll_tmds_cmn_config(hdptx, rate); 846 - if (ret) 847 - return ret; 848 - } 849 - 850 826 rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_common_sb_init_seq); 851 827 852 828 regmap_write(hdptx->regmap, LNTOP_REG(0200), 0x06); ··· 855 857 return rk_hdptx_post_enable_lane(hdptx); 856 858 } 857 859 860 + static int rk_hdptx_phy_consumer_get(struct rk_hdptx_phy *hdptx, 861 + unsigned int rate) 862 + { 863 + u32 status; 864 + int ret; 865 + 866 + if (atomic_inc_return(&hdptx->usage_count) > 1) 867 + return 0; 868 + 869 + ret = regmap_read(hdptx->grf, GRF_HDPTX_STATUS, &status); 870 + if (ret) 871 + goto dec_usage; 872 + 873 + if (status & HDPTX_O_PLL_LOCK_DONE) 874 + dev_warn(hdptx->dev, "PLL locked by unknown consumer!\n"); 875 + 876 + if (rate) { 877 + ret = rk_hdptx_ropll_tmds_cmn_config(hdptx, rate); 878 + if (ret) 879 + goto dec_usage; 880 + } 881 + 882 + return 0; 883 + 884 + dec_usage: 885 + atomic_dec(&hdptx->usage_count); 886 + return ret; 887 + } 888 + 889 + static int rk_hdptx_phy_consumer_put(struct rk_hdptx_phy *hdptx, bool force) 890 + { 891 + u32 status; 892 + int ret; 893 + 894 + ret = atomic_dec_return(&hdptx->usage_count); 895 + if (ret > 0) 896 + return 0; 897 + 898 + if (ret < 0) { 899 + dev_warn(hdptx->dev, "Usage count underflow!\n"); 900 + ret = -EINVAL; 901 + } else { 902 + ret = regmap_read(hdptx->grf, GRF_HDPTX_STATUS, &status); 903 + if (!ret) { 904 + if (status & HDPTX_O_PLL_LOCK_DONE) 905 + rk_hdptx_phy_disable(hdptx); 906 + return 0; 907 + } else if (force) { 908 + return 0; 909 + } 910 + } 911 + 912 + atomic_inc(&hdptx->usage_count); 913 + return ret; 914 + } 915 + 858 916 static int rk_hdptx_phy_power_on(struct phy *phy) 859 917 { 860 918 struct rk_hdptx_phy *hdptx = phy_get_drvdata(phy); 861 919 int bus_width = phy_get_bus_width(hdptx->phy); 920 + int ret; 921 + 862 922 /* 863 923 * FIXME: Temporary workaround to pass pixel_clk_rate 864 924 * from the HDMI bridge driver until phy_configure_opts_hdmi ··· 927 871 dev_dbg(hdptx->dev, "%s bus_width=%x rate=%u\n", 928 872 __func__, bus_width, rate); 929 873 930 - return rk_hdptx_ropll_tmds_mode_config(hdptx, rate); 874 + ret = rk_hdptx_phy_consumer_get(hdptx, rate); 875 + if (ret) 876 + return ret; 877 + 878 + ret = rk_hdptx_ropll_tmds_mode_config(hdptx, rate); 879 + if (ret) 880 + rk_hdptx_phy_consumer_put(hdptx, true); 881 + 882 + return ret; 931 883 } 932 884 933 885 static int rk_hdptx_phy_power_off(struct phy *phy) 934 886 { 935 887 struct rk_hdptx_phy *hdptx = phy_get_drvdata(phy); 936 - u32 val; 937 - int ret; 938 888 939 - ret = regmap_read(hdptx->grf, GRF_HDPTX_STATUS, &val); 940 - if (ret == 0 && (val & HDPTX_O_PLL_LOCK_DONE)) 941 - rk_hdptx_phy_disable(hdptx); 942 - 943 - return ret; 889 + return rk_hdptx_phy_consumer_put(hdptx, false); 944 890 } 945 891 946 892 static const struct phy_ops rk_hdptx_phy_ops = { ··· 950 892 .power_off = rk_hdptx_phy_power_off, 951 893 .owner = THIS_MODULE, 952 894 }; 895 + 896 + static struct rk_hdptx_phy *to_rk_hdptx_phy(struct clk_hw *hw) 897 + { 898 + return container_of(hw, struct rk_hdptx_phy, hw); 899 + } 900 + 901 + static int rk_hdptx_phy_clk_prepare(struct clk_hw *hw) 902 + { 903 + struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw); 904 + 905 + return rk_hdptx_phy_consumer_get(hdptx, hdptx->rate / 100); 906 + } 907 + 908 + static void rk_hdptx_phy_clk_unprepare(struct clk_hw *hw) 909 + { 910 + struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw); 911 + 912 + rk_hdptx_phy_consumer_put(hdptx, true); 913 + } 914 + 915 + static unsigned long rk_hdptx_phy_clk_recalc_rate(struct clk_hw *hw, 916 + unsigned long parent_rate) 917 + { 918 + struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw); 919 + 920 + return hdptx->rate; 921 + } 922 + 923 + static long rk_hdptx_phy_clk_round_rate(struct clk_hw *hw, unsigned long rate, 924 + unsigned long *parent_rate) 925 + { 926 + u32 bit_rate = rate / 100; 927 + int i; 928 + 929 + if (rate > HDMI20_MAX_RATE) 930 + return rate; 931 + 932 + for (i = 0; i < ARRAY_SIZE(ropll_tmds_cfg); i++) 933 + if (bit_rate == ropll_tmds_cfg[i].bit_rate) 934 + break; 935 + 936 + if (i == ARRAY_SIZE(ropll_tmds_cfg) && 937 + !rk_hdptx_phy_clk_pll_calc(bit_rate, NULL)) 938 + return -EINVAL; 939 + 940 + return rate; 941 + } 942 + 943 + static int rk_hdptx_phy_clk_set_rate(struct clk_hw *hw, unsigned long rate, 944 + unsigned long parent_rate) 945 + { 946 + struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw); 947 + 948 + return rk_hdptx_ropll_tmds_cmn_config(hdptx, rate / 100); 949 + } 950 + 951 + static const struct clk_ops hdptx_phy_clk_ops = { 952 + .prepare = rk_hdptx_phy_clk_prepare, 953 + .unprepare = rk_hdptx_phy_clk_unprepare, 954 + .recalc_rate = rk_hdptx_phy_clk_recalc_rate, 955 + .round_rate = rk_hdptx_phy_clk_round_rate, 956 + .set_rate = rk_hdptx_phy_clk_set_rate, 957 + }; 958 + 959 + static int rk_hdptx_phy_clk_register(struct rk_hdptx_phy *hdptx) 960 + { 961 + struct device *dev = hdptx->dev; 962 + const char *name, *pname; 963 + struct clk *refclk; 964 + int ret, id; 965 + 966 + refclk = devm_clk_get(dev, "ref"); 967 + if (IS_ERR(refclk)) 968 + return dev_err_probe(dev, PTR_ERR(refclk), 969 + "Failed to get ref clock\n"); 970 + 971 + id = of_alias_get_id(dev->of_node, "hdptxphy"); 972 + name = id > 0 ? "clk_hdmiphy_pixel1" : "clk_hdmiphy_pixel0"; 973 + pname = __clk_get_name(refclk); 974 + 975 + hdptx->hw.init = CLK_HW_INIT(name, pname, &hdptx_phy_clk_ops, 976 + CLK_GET_RATE_NOCACHE); 977 + 978 + ret = devm_clk_hw_register(dev, &hdptx->hw); 979 + if (ret) 980 + return dev_err_probe(dev, ret, "Failed to register clock\n"); 981 + 982 + ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, &hdptx->hw); 983 + if (ret) 984 + return dev_err_probe(dev, ret, 985 + "Failed to register clk provider\n"); 986 + return 0; 987 + } 953 988 954 989 static int rk_hdptx_phy_runtime_suspend(struct device *dev) 955 990 { ··· 1138 987 reset_control_deassert(hdptx->rsts[RST_CMN].rstc); 1139 988 reset_control_deassert(hdptx->rsts[RST_INIT].rstc); 1140 989 1141 - return 0; 990 + return rk_hdptx_phy_clk_register(hdptx); 1142 991 } 1143 992 1144 993 static const struct dev_pm_ops rk_hdptx_phy_pm_ops = {