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: qcom: qmp-usbc: add DP link and vco_div clocks for DP PHY

USB3DP PHY requires link and vco_div clocks when operating in DP mode.
Extend qmp_usbc_register_clocks and the clock provider logic to register
these clocks along with the existing pipe clock, to support both USB and
DP configurations.

Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Xiangxu Yin <xiangxu.yin@oss.qualcomm.com>
Link: https://patch.msgid.link/20251215-add-displayport-support-for-qcs615-platform-v8-6-cbc72c88a44e@oss.qualcomm.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Xiangxu Yin and committed by
Vinod Koul
049e708e 5b2dd084

+203 -6
+203 -6
drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
··· 22 22 #include <linux/slab.h> 23 23 #include <linux/usb/typec.h> 24 24 #include <linux/usb/typec_mux.h> 25 + #include <dt-bindings/phy/phy-qcom-qmp.h> 25 26 26 27 #include "phy-qcom-qmp-common.h" 27 28 ··· 852 851 return devm_clk_bulk_get_optional(dev, num, qmp->clks); 853 852 } 854 853 855 - static void phy_clk_release_provider(void *res) 854 + static struct clk_hw *qmp_usbc_clks_hw_get(struct of_phandle_args *clkspec, void *data) 856 855 { 857 - of_clk_del_provider(res); 856 + struct qmp_usbc *qmp = data; 857 + 858 + if (clkspec->args_count == 0) 859 + return &qmp->pipe_clk_fixed.hw; 860 + 861 + switch (clkspec->args[0]) { 862 + case QMP_USB43DP_USB3_PIPE_CLK: 863 + return &qmp->pipe_clk_fixed.hw; 864 + case QMP_USB43DP_DP_LINK_CLK: 865 + return &qmp->dp_link_hw; 866 + case QMP_USB43DP_DP_VCO_DIV_CLK: 867 + return &qmp->dp_pixel_hw; 868 + } 869 + 870 + return ERR_PTR(-EINVAL); 858 871 } 859 872 860 873 /* ··· 893 878 { 894 879 struct clk_fixed_rate *fixed = &qmp->pipe_clk_fixed; 895 880 struct clk_init_data init = { }; 881 + char name[64]; 896 882 int ret; 897 883 898 884 ret = of_property_read_string(np, "clock-output-names", &init.name); 899 885 if (ret) { 900 - dev_err(qmp->dev, "%pOFn: No clock-output-names\n", np); 901 - return ret; 886 + /* Clock name is not mandatory. */ 887 + snprintf(name, sizeof(name), "%s::pipe_clk", dev_name(qmp->dev)); 888 + init.name = name; 902 889 } 903 890 904 891 init.ops = &clk_fixed_rate_ops; ··· 909 892 fixed->fixed_rate = 125000000; 910 893 fixed->hw.init = &init; 911 894 912 - ret = devm_clk_hw_register(qmp->dev, &fixed->hw); 895 + return devm_clk_hw_register(qmp->dev, &fixed->hw); 896 + } 897 + 898 + /* 899 + * Display Port PLL driver block diagram for branch clocks 900 + * 901 + * +------------------------------+ 902 + * | DP_VCO_CLK | 903 + * | | 904 + * | +-------------------+ | 905 + * | | (DP PLL/VCO) | | 906 + * | +---------+---------+ | 907 + * | v | 908 + * | +----------+-----------+ | 909 + * | | hsclk_divsel_clk_src | | 910 + * | +----------+-----------+ | 911 + * +------------------------------+ 912 + * | 913 + * +---------<---------v------------>----------+ 914 + * | | 915 + * +--------v----------------+ | 916 + * | dp_phy_pll_link_clk | | 917 + * | link_clk | | 918 + * +--------+----------------+ | 919 + * | | 920 + * | | 921 + * v v 922 + * Input to DISPCC block | 923 + * for link clk, crypto clk | 924 + * and interface clock | 925 + * | 926 + * | 927 + * +--------<------------+-----------------+---<---+ 928 + * | | | 929 + * +----v---------+ +--------v-----+ +--------v------+ 930 + * | vco_divided | | vco_divided | | vco_divided | 931 + * | _clk_src | | _clk_src | | _clk_src | 932 + * | | | | | | 933 + * |divsel_six | | divsel_two | | divsel_four | 934 + * +-------+------+ +-----+--------+ +--------+------+ 935 + * | | | 936 + * v---->----------v-------------<------v 937 + * | 938 + * +----------+-----------------+ 939 + * | dp_phy_pll_vco_div_clk | 940 + * +---------+------------------+ 941 + * | 942 + * v 943 + * Input to DISPCC block 944 + * for DP pixel clock 945 + * 946 + */ 947 + static int qmp_dp_pixel_clk_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) 948 + { 949 + switch (req->rate) { 950 + case 1620000000UL / 2: 951 + case 2700000000UL / 2: 952 + /* 5.4 is same link rate as 2.7GHz, i.e. div 4 */ 953 + return 0; 954 + default: 955 + return -EINVAL; 956 + } 957 + } 958 + 959 + static unsigned long qmp_dp_pixel_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) 960 + { 961 + const struct qmp_usbc *qmp; 962 + const struct phy_configure_opts_dp *dp_opts; 963 + 964 + qmp = container_of(hw, struct qmp_usbc, dp_pixel_hw); 965 + 966 + dp_opts = &qmp->dp_opts; 967 + 968 + switch (dp_opts->link_rate) { 969 + case 1620: 970 + return 1620000000UL / 2; 971 + case 2700: 972 + return 2700000000UL / 2; 973 + case 5400: 974 + return 5400000000UL / 4; 975 + default: 976 + return 0; 977 + } 978 + } 979 + 980 + static const struct clk_ops qmp_dp_pixel_clk_ops = { 981 + .determine_rate = qmp_dp_pixel_clk_determine_rate, 982 + .recalc_rate = qmp_dp_pixel_clk_recalc_rate, 983 + }; 984 + 985 + static int qmp_dp_link_clk_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) 986 + { 987 + switch (req->rate) { 988 + case 162000000: 989 + case 270000000: 990 + case 540000000: 991 + return 0; 992 + default: 993 + return -EINVAL; 994 + } 995 + } 996 + 997 + static unsigned long qmp_dp_link_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) 998 + { 999 + const struct qmp_usbc *qmp; 1000 + const struct phy_configure_opts_dp *dp_opts; 1001 + 1002 + qmp = container_of(hw, struct qmp_usbc, dp_link_hw); 1003 + dp_opts = &qmp->dp_opts; 1004 + 1005 + switch (dp_opts->link_rate) { 1006 + case 1620: 1007 + case 2700: 1008 + case 5400: 1009 + return dp_opts->link_rate * 100000; 1010 + default: 1011 + return 0; 1012 + } 1013 + } 1014 + 1015 + static const struct clk_ops qmp_dp_link_clk_ops = { 1016 + .determine_rate = qmp_dp_link_clk_determine_rate, 1017 + .recalc_rate = qmp_dp_link_clk_recalc_rate, 1018 + }; 1019 + 1020 + static int phy_dp_clks_register(struct qmp_usbc *qmp, struct device_node *np) 1021 + { 1022 + struct clk_init_data init = { }; 1023 + char name[64]; 1024 + int ret; 1025 + 1026 + snprintf(name, sizeof(name), "%s::link_clk", dev_name(qmp->dev)); 1027 + init.ops = &qmp_dp_link_clk_ops; 1028 + init.name = name; 1029 + qmp->dp_link_hw.init = &init; 1030 + ret = devm_clk_hw_register(qmp->dev, &qmp->dp_link_hw); 1031 + if (ret < 0) { 1032 + dev_err(qmp->dev, "link clk reg fail ret=%d\n", ret); 1033 + return ret; 1034 + } 1035 + 1036 + snprintf(name, sizeof(name), "%s::vco_div_clk", dev_name(qmp->dev)); 1037 + init.ops = &qmp_dp_pixel_clk_ops; 1038 + init.name = name; 1039 + qmp->dp_pixel_hw.init = &init; 1040 + ret = devm_clk_hw_register(qmp->dev, &qmp->dp_pixel_hw); 1041 + if (ret) { 1042 + dev_err(qmp->dev, "pxl clk reg fail ret=%d\n", ret); 1043 + return ret; 1044 + } 1045 + 1046 + return 0; 1047 + } 1048 + 1049 + static void phy_clk_release_provider(void *res) 1050 + { 1051 + of_clk_del_provider(res); 1052 + } 1053 + 1054 + static int qmp_usbc_register_clocks(struct qmp_usbc *qmp, struct device_node *np) 1055 + { 1056 + struct clk_fixed_rate *fixed = &qmp->pipe_clk_fixed; 1057 + int ret; 1058 + 1059 + ret = phy_pipe_clk_register(qmp, np); 913 1060 if (ret) 914 1061 return ret; 1062 + 1063 + if (qmp->dp_serdes != 0) { 1064 + ret = phy_dp_clks_register(qmp, np); 1065 + if (ret) 1066 + return ret; 1067 + } 1068 + 1069 + if (np == qmp->dev->of_node) 1070 + return devm_of_clk_add_hw_provider(qmp->dev, qmp_usbc_clks_hw_get, qmp); 915 1071 916 1072 ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, &fixed->hw); 917 1073 if (ret) ··· 1230 1040 if (IS_ERR(base)) 1231 1041 return PTR_ERR(base); 1232 1042 1043 + if (offs->dp_serdes != 0) { 1044 + qmp->dp_serdes = base + offs->dp_serdes; 1045 + qmp->dp_tx = base + offs->dp_txa; 1046 + qmp->dp_tx2 = base + offs->dp_txb; 1047 + qmp->dp_dp_phy = base + offs->dp_dp_phy; 1048 + } 1049 + 1233 1050 qmp->serdes = base + offs->serdes; 1234 1051 qmp->pcs = base + offs->pcs; 1235 1052 if (offs->pcs_misc) ··· 1345 1148 */ 1346 1149 pm_runtime_forbid(dev); 1347 1150 1348 - ret = phy_pipe_clk_register(qmp, np); 1151 + ret = qmp_usbc_register_clocks(qmp, np); 1349 1152 if (ret) 1350 1153 goto err_node_put; 1351 1154