hc
2024-01-03 2f7c68cb55ecb7331f2381deb497c27155f32faf
kernel/drivers/soc/rockchip/rockchip_opp_select.c
....@@ -12,6 +12,7 @@
1212 #include <linux/nvmem-consumer.h>
1313 #include <linux/regmap.h>
1414 #include <linux/regulator/consumer.h>
15
+#include <linux/rockchip/rockchip_sip.h>
1516 #include <linux/slab.h>
1617 #include <linux/soc/rockchip/pvtm.h>
1718 #include <linux/thermal.h>
....@@ -1004,15 +1005,15 @@
10041005 }
10051006
10061007 if (of_property_read_u32(np, "rockchip,pvtpll-len-min-rate", &min_rate))
1007
- return;
1008
+ goto out;
10081009 if (of_property_read_u32(np, "rockchip,pvtpll-len-max-rate", &max_rate))
1009
- return;
1010
+ goto out;
10101011 if (of_property_read_u32(np, "rockchip,pvtpll-len-margin", &margin))
1011
- return;
1012
+ goto out;
10121013
10131014 opp_table = dev_pm_opp_get_opp_table(info->dev);
10141015 if (!opp_table)
1015
- return;
1016
+ goto out;
10161017 old_rate = clk_get_rate(opp_table->clk);
10171018 opp_flag = OPP_ADD_LENGTH | ((margin & OPP_LENGTH_MASK) << OPP_LENGTH_SHIFT);
10181019
....@@ -1033,8 +1034,97 @@
10331034 clk_set_rate(opp_table->clk, old_rate);
10341035
10351036 dev_pm_opp_put_opp_table(opp_table);
1037
+out:
1038
+ of_node_put(np);
10361039 }
10371040 EXPORT_SYMBOL(rockchip_pvtpll_add_length);
1041
+
1042
+void rockchip_init_pvtpll_table(struct rockchip_opp_info *info, int bin)
1043
+{
1044
+ struct device_node *np = NULL;
1045
+ struct property *prop = NULL;
1046
+ struct of_phandle_args clkspec = { 0 };
1047
+ struct arm_smccc_res res;
1048
+ char prop_name[NAME_MAX];
1049
+ u32 *value;
1050
+ int count;
1051
+ int ret, i;
1052
+
1053
+ if (!info)
1054
+ return;
1055
+
1056
+ np = of_parse_phandle(info->dev->of_node, "operating-points-v2", 0);
1057
+ if (!np) {
1058
+ dev_warn(info->dev, "OPP-v2 not supported\n");
1059
+ return;
1060
+ }
1061
+
1062
+ ret = of_parse_phandle_with_args(info->dev->of_node, "clocks",
1063
+ "#clock-cells", 0, &clkspec);
1064
+ if (ret)
1065
+ goto out;
1066
+ info->pvtpll_clk_id = clkspec.args[0];
1067
+ of_node_put(clkspec.np);
1068
+
1069
+ res = sip_smc_get_pvtpll_info(PVTPLL_GET_INFO, info->pvtpll_clk_id);
1070
+ if (res.a0)
1071
+ goto out;
1072
+ if (!res.a1)
1073
+ info->pvtpll_low_temp = true;
1074
+
1075
+ if (bin > 0) {
1076
+ snprintf(prop_name, sizeof(prop_name),
1077
+ "rockchip,pvtpll-table-B%d", bin);
1078
+ prop = of_find_property(np, prop_name, NULL);
1079
+ }
1080
+ if (!prop)
1081
+ sprintf(prop_name, "rockchip,pvtpll-table");
1082
+
1083
+ prop = of_find_property(np, prop_name, NULL);
1084
+ if (!prop)
1085
+ goto out;
1086
+
1087
+ count = of_property_count_u32_elems(np, prop_name);
1088
+ if (count < 0) {
1089
+ dev_err(info->dev, "%s: Invalid %s property (%d)\n",
1090
+ __func__, prop_name, count);
1091
+ goto out;
1092
+ } else if (count % 5) {
1093
+ dev_err(info->dev, "Invalid count of %s\n", prop_name);
1094
+ goto out;
1095
+ }
1096
+
1097
+ value = kmalloc_array(count, sizeof(*value), GFP_KERNEL);
1098
+ if (!value)
1099
+ goto out;
1100
+ ret = of_property_read_u32_array(np, prop_name, value, count);
1101
+ if (ret) {
1102
+ dev_err(info->dev, "%s: error parsing %s: %d\n",
1103
+ __func__, prop_name, ret);
1104
+ goto free_value;
1105
+ }
1106
+
1107
+ for (i = 0; i < count; i += 5) {
1108
+ res = sip_smc_pvtpll_config(PVTPLL_ADJUST_TABLE,
1109
+ info->pvtpll_clk_id, value[i],
1110
+ value[i + 1], value[i + 2],
1111
+ value[i + 3], value[i + 4]);
1112
+ if (res.a0) {
1113
+ dev_err(info->dev,
1114
+ "%s: error cfg clk_id=%u %u %u %u %u %u (%d)\n",
1115
+ __func__, info->pvtpll_clk_id, value[i],
1116
+ value[i + 1], value[i + 2], value[i + 3],
1117
+ value[i + 4], (int)res.a0);
1118
+ goto free_value;
1119
+ }
1120
+ }
1121
+
1122
+free_value:
1123
+ kfree(value);
1124
+out:
1125
+ of_node_put(np);
1126
+}
1127
+EXPORT_SYMBOL(rockchip_init_pvtpll_table);
10381128
10391129 static int rockchip_get_pvtm_pvtpll(struct device *dev, struct device_node *np,
10401130 char *reg_name)
....@@ -1186,10 +1276,15 @@
11861276 snprintf(name, sizeof(name),
11871277 "rockchip,p%d-pvtm-voltage-sel", process);
11881278 prop = of_find_property(np, name, NULL);
1189
- } else if (bin >= 0) {
1279
+ } else if (bin > 0) {
11901280 of_property_read_u32(np, "rockchip,pvtm-hw", &hw);
11911281 if (hw && (hw & BIT(bin))) {
11921282 sprintf(name, "rockchip,pvtm-voltage-sel-hw");
1283
+ prop = of_find_property(np, name, NULL);
1284
+ }
1285
+ if (!prop) {
1286
+ snprintf(name, sizeof(name),
1287
+ "rockchip,pvtm-voltage-sel-B%d", bin);
11931288 prop = of_find_property(np, name, NULL);
11941289 }
11951290 }
....@@ -1633,6 +1728,10 @@
16331728 rockchip_adjust_opp_by_irdrop(dev, np, &safe_rate, &max_rate);
16341729
16351730 dev_info(dev, "avs=%d\n", avs);
1731
+
1732
+ if (!safe_rate && !scale)
1733
+ goto out_np;
1734
+
16361735 clk = of_clk_get_by_name(np, NULL);
16371736 if (IS_ERR(clk)) {
16381737 if (!safe_rate)
....@@ -1646,14 +1745,14 @@
16461745
16471746 if (safe_rate)
16481747 irdrop_scale = rockchip_pll_clk_rate_to_scale(clk, safe_rate);
1649
- if (max_rate)
1650
- opp_scale = rockchip_pll_clk_rate_to_scale(clk, max_rate);
16511748 target_scale = max(irdrop_scale, scale);
16521749 if (target_scale <= 0)
16531750 goto out_clk;
16541751 dev_dbg(dev, "target_scale=%d, irdrop_scale=%d, scale=%d\n",
16551752 target_scale, irdrop_scale, scale);
16561753
1754
+ if (max_rate)
1755
+ opp_scale = rockchip_pll_clk_rate_to_scale(clk, max_rate);
16571756 if (avs == AVS_SCALING_RATE) {
16581757 ret = rockchip_pll_clk_adaptive_scaling(clk, target_scale);
16591758 if (ret)
....@@ -1838,13 +1937,78 @@
18381937 }
18391938 EXPORT_SYMBOL(rockchip_set_intermediate_rate);
18401939
1940
+static int rockchip_get_opp_clk(struct device *dev, struct device_node *np,
1941
+ struct rockchip_opp_info *info)
1942
+{
1943
+ struct clk_bulk_data *clks;
1944
+ struct of_phandle_args clkspec;
1945
+ int ret = 0, num_clks = 0, i;
1946
+
1947
+ if (of_find_property(np, "rockchip,opp-clocks", NULL)) {
1948
+ num_clks = of_count_phandle_with_args(np, "rockchip,opp-clocks",
1949
+ "#clock-cells");
1950
+ if (num_clks <= 0)
1951
+ return 0;
1952
+ clks = devm_kcalloc(dev, num_clks, sizeof(*clks), GFP_KERNEL);
1953
+ if (!clks)
1954
+ return -ENOMEM;
1955
+ for (i = 0; i < num_clks; i++) {
1956
+ ret = of_parse_phandle_with_args(np,
1957
+ "rockchip,opp-clocks",
1958
+ "#clock-cells", i,
1959
+ &clkspec);
1960
+ if (ret < 0) {
1961
+ dev_err(dev, "%s: failed to parse opp clk %d\n",
1962
+ np->name, i);
1963
+ goto error;
1964
+ }
1965
+ clks[i].clk = of_clk_get_from_provider(&clkspec);
1966
+ of_node_put(clkspec.np);
1967
+ if (IS_ERR(clks[i].clk)) {
1968
+ ret = PTR_ERR(clks[i].clk);
1969
+ clks[i].clk = NULL;
1970
+ dev_err(dev, "%s: failed to get opp clk %d\n",
1971
+ np->name, i);
1972
+ goto error;
1973
+ }
1974
+ }
1975
+ } else {
1976
+ num_clks = of_clk_get_parent_count(np);
1977
+ if (num_clks <= 0)
1978
+ return 0;
1979
+ clks = devm_kcalloc(dev, num_clks, sizeof(*clks), GFP_KERNEL);
1980
+ if (!clks)
1981
+ return -ENOMEM;
1982
+ for (i = 0; i < num_clks; i++) {
1983
+ clks[i].clk = of_clk_get(np, i);
1984
+ if (IS_ERR(clks[i].clk)) {
1985
+ ret = PTR_ERR(clks[i].clk);
1986
+ clks[i].clk = NULL;
1987
+ dev_err(dev, "%s: failed to get clk %d\n",
1988
+ np->name, i);
1989
+ goto error;
1990
+ }
1991
+ }
1992
+ }
1993
+ info->clks = clks;
1994
+ info->num_clks = num_clks;
1995
+
1996
+ return 0;
1997
+error:
1998
+ while (--i >= 0)
1999
+ clk_put(clks[i].clk);
2000
+ devm_kfree(dev, clks);
2001
+
2002
+ return ret;
2003
+}
2004
+
18412005 int rockchip_init_opp_table(struct device *dev, struct rockchip_opp_info *info,
18422006 char *lkg_name, char *reg_name)
18432007 {
18442008 struct device_node *np;
18452009 int bin = -EINVAL, process = -EINVAL;
18462010 int scale = 0, volt_sel = -EINVAL;
1847
- int ret = 0, num_clks = 0, i;
2011
+ int ret = 0;
18482012 u32 freq;
18492013
18502014 /* Get OPP descriptor node */
....@@ -1857,24 +2021,10 @@
18572021 goto next;
18582022 info->dev = dev;
18592023
1860
- num_clks = of_clk_get_parent_count(np);
1861
- if (num_clks > 0) {
1862
- info->clks = devm_kcalloc(dev, num_clks, sizeof(*info->clks),
1863
- GFP_KERNEL);
1864
- if (!info->clks) {
1865
- ret = -ENOMEM;
1866
- goto out;
1867
- }
1868
- for (i = 0; i < num_clks; i++) {
1869
- info->clks[i].clk = of_clk_get(np, i);
1870
- if (IS_ERR(info->clks[i].clk)) {
1871
- ret = PTR_ERR(info->clks[i].clk);
1872
- dev_err(dev, "%s: failed to get clk %d\n",
1873
- np->name, i);
1874
- goto out;
1875
- }
1876
- }
1877
- info->num_clks = num_clks;
2024
+ ret = rockchip_get_opp_clk(dev, np, info);
2025
+ if (ret)
2026
+ goto out;
2027
+ if (info->clks) {
18782028 ret = clk_bulk_prepare_enable(info->num_clks, info->clks);
18792029 if (ret) {
18802030 dev_err(dev, "failed to enable opp clks\n");
....@@ -1900,6 +2050,7 @@
19002050
19012051 next:
19022052 rockchip_get_soc_info(dev, np, &bin, &process);
2053
+ rockchip_init_pvtpll_table(info, bin);
19032054 rockchip_get_scale_volt_sel(dev, lkg_name, reg_name, bin, process,
19042055 &scale, &volt_sel);
19052056 if (info && info->data && info->data->set_soc_info)
....@@ -1925,6 +2076,31 @@
19252076 }
19262077 EXPORT_SYMBOL(rockchip_init_opp_table);
19272078
2079
+void rockchip_uninit_opp_table(struct device *dev, struct rockchip_opp_info *info)
2080
+{
2081
+ struct opp_table *opp_table;
2082
+
2083
+ if (info) {
2084
+ kfree(info->opp_table);
2085
+ info->opp_table = NULL;
2086
+ devm_kfree(dev, info->clks);
2087
+ info->clks = NULL;
2088
+ devm_kfree(dev, info->volt_rm_tbl);
2089
+ info->volt_rm_tbl = NULL;
2090
+ }
2091
+
2092
+ opp_table = dev_pm_opp_get_opp_table(dev);
2093
+ if (IS_ERR(opp_table))
2094
+ return;
2095
+ dev_pm_opp_of_remove_table(dev);
2096
+ if (opp_table->prop_name)
2097
+ dev_pm_opp_put_prop_name(opp_table);
2098
+ if (opp_table->supported_hw)
2099
+ dev_pm_opp_put_supported_hw(opp_table);
2100
+ dev_pm_opp_put_opp_table(opp_table);
2101
+}
2102
+EXPORT_SYMBOL(rockchip_uninit_opp_table);
2103
+
19282104 MODULE_DESCRIPTION("ROCKCHIP OPP Select");
19292105 MODULE_AUTHOR("Finley Xiao <finley.xiao@rock-chips.com>, Liang Chen <cl@rock-chips.com>");
19302106 MODULE_LICENSE("GPL");