From 2f7c68cb55ecb7331f2381deb497c27155f32faf Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Wed, 03 Jan 2024 09:43:39 +0000
Subject: [PATCH] update kernel to 5.10.198

---
 kernel/drivers/soc/rockchip/rockchip_opp_select.c |  228 ++++++++++++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 202 insertions(+), 26 deletions(-)

diff --git a/kernel/drivers/soc/rockchip/rockchip_opp_select.c b/kernel/drivers/soc/rockchip/rockchip_opp_select.c
index 8caae5c..6c496ad 100644
--- a/kernel/drivers/soc/rockchip/rockchip_opp_select.c
+++ b/kernel/drivers/soc/rockchip/rockchip_opp_select.c
@@ -12,6 +12,7 @@
 #include <linux/nvmem-consumer.h>
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
+#include <linux/rockchip/rockchip_sip.h>
 #include <linux/slab.h>
 #include <linux/soc/rockchip/pvtm.h>
 #include <linux/thermal.h>
@@ -1004,15 +1005,15 @@
 	}
 
 	if (of_property_read_u32(np, "rockchip,pvtpll-len-min-rate", &min_rate))
-		return;
+		goto out;
 	if (of_property_read_u32(np, "rockchip,pvtpll-len-max-rate", &max_rate))
-		return;
+		goto out;
 	if (of_property_read_u32(np, "rockchip,pvtpll-len-margin", &margin))
-		return;
+		goto out;
 
 	opp_table = dev_pm_opp_get_opp_table(info->dev);
 	if (!opp_table)
-		return;
+		goto out;
 	old_rate = clk_get_rate(opp_table->clk);
 	opp_flag = OPP_ADD_LENGTH | ((margin & OPP_LENGTH_MASK) << OPP_LENGTH_SHIFT);
 
@@ -1033,8 +1034,97 @@
 	clk_set_rate(opp_table->clk, old_rate);
 
 	dev_pm_opp_put_opp_table(opp_table);
+out:
+	of_node_put(np);
 }
 EXPORT_SYMBOL(rockchip_pvtpll_add_length);
+
+void rockchip_init_pvtpll_table(struct rockchip_opp_info *info, int bin)
+{
+	struct device_node *np = NULL;
+	struct property *prop = NULL;
+	struct of_phandle_args clkspec = { 0 };
+	struct arm_smccc_res res;
+	char prop_name[NAME_MAX];
+	u32 *value;
+	int count;
+	int ret, i;
+
+	if (!info)
+		return;
+
+	np = of_parse_phandle(info->dev->of_node, "operating-points-v2", 0);
+	if (!np) {
+		dev_warn(info->dev, "OPP-v2 not supported\n");
+		return;
+	}
+
+	ret = of_parse_phandle_with_args(info->dev->of_node, "clocks",
+					"#clock-cells", 0, &clkspec);
+	if (ret)
+		goto out;
+	info->pvtpll_clk_id = clkspec.args[0];
+	of_node_put(clkspec.np);
+
+	res = sip_smc_get_pvtpll_info(PVTPLL_GET_INFO, info->pvtpll_clk_id);
+	if (res.a0)
+		goto out;
+	if (!res.a1)
+		info->pvtpll_low_temp = true;
+
+	if (bin > 0) {
+		snprintf(prop_name, sizeof(prop_name),
+			 "rockchip,pvtpll-table-B%d", bin);
+		prop = of_find_property(np, prop_name, NULL);
+	}
+	if (!prop)
+		sprintf(prop_name, "rockchip,pvtpll-table");
+
+	prop = of_find_property(np, prop_name, NULL);
+	if (!prop)
+		goto out;
+
+	count = of_property_count_u32_elems(np, prop_name);
+	if (count < 0) {
+		dev_err(info->dev, "%s: Invalid %s property (%d)\n",
+			__func__, prop_name, count);
+		goto out;
+	} else if (count % 5) {
+		dev_err(info->dev, "Invalid count of %s\n", prop_name);
+		goto out;
+	}
+
+	value = kmalloc_array(count, sizeof(*value), GFP_KERNEL);
+	if (!value)
+		goto out;
+	ret = of_property_read_u32_array(np, prop_name, value, count);
+	if (ret) {
+		dev_err(info->dev, "%s: error parsing %s: %d\n",
+			__func__, prop_name, ret);
+		goto free_value;
+	}
+
+	for (i = 0; i < count; i += 5) {
+		res = sip_smc_pvtpll_config(PVTPLL_ADJUST_TABLE,
+					    info->pvtpll_clk_id, value[i],
+					    value[i + 1], value[i + 2],
+					    value[i + 3], value[i + 4]);
+		if (res.a0) {
+			dev_err(info->dev,
+				"%s: error cfg clk_id=%u %u %u %u %u %u (%d)\n",
+				__func__, info->pvtpll_clk_id, value[i],
+				value[i + 1], value[i + 2], value[i + 3],
+				value[i + 4], (int)res.a0);
+			goto free_value;
+		}
+	}
+
+free_value:
+	kfree(value);
+out:
+	of_node_put(np);
+}
+EXPORT_SYMBOL(rockchip_init_pvtpll_table);
 
 static int rockchip_get_pvtm_pvtpll(struct device *dev, struct device_node *np,
 				    char *reg_name)
@@ -1186,10 +1276,15 @@
 		snprintf(name, sizeof(name),
 			 "rockchip,p%d-pvtm-voltage-sel", process);
 		prop = of_find_property(np, name, NULL);
-	} else if (bin >= 0) {
+	} else if (bin > 0) {
 		of_property_read_u32(np, "rockchip,pvtm-hw", &hw);
 		if (hw && (hw & BIT(bin))) {
 			sprintf(name, "rockchip,pvtm-voltage-sel-hw");
+			prop = of_find_property(np, name, NULL);
+		}
+		if (!prop) {
+			snprintf(name, sizeof(name),
+				 "rockchip,pvtm-voltage-sel-B%d", bin);
 			prop = of_find_property(np, name, NULL);
 		}
 	}
@@ -1633,6 +1728,10 @@
 	rockchip_adjust_opp_by_irdrop(dev, np, &safe_rate, &max_rate);
 
 	dev_info(dev, "avs=%d\n", avs);
+
+	if (!safe_rate && !scale)
+		goto out_np;
+
 	clk = of_clk_get_by_name(np, NULL);
 	if (IS_ERR(clk)) {
 		if (!safe_rate)
@@ -1646,14 +1745,14 @@
 
 	if (safe_rate)
 		irdrop_scale = rockchip_pll_clk_rate_to_scale(clk, safe_rate);
-	if (max_rate)
-		opp_scale = rockchip_pll_clk_rate_to_scale(clk, max_rate);
 	target_scale = max(irdrop_scale, scale);
 	if (target_scale <= 0)
 		goto out_clk;
 	dev_dbg(dev, "target_scale=%d, irdrop_scale=%d, scale=%d\n",
 		target_scale, irdrop_scale, scale);
 
+	if (max_rate)
+		opp_scale = rockchip_pll_clk_rate_to_scale(clk, max_rate);
 	if (avs == AVS_SCALING_RATE) {
 		ret = rockchip_pll_clk_adaptive_scaling(clk, target_scale);
 		if (ret)
@@ -1838,13 +1937,78 @@
 }
 EXPORT_SYMBOL(rockchip_set_intermediate_rate);
 
+static int rockchip_get_opp_clk(struct device *dev, struct device_node *np,
+				struct rockchip_opp_info *info)
+{
+	struct clk_bulk_data *clks;
+	struct of_phandle_args clkspec;
+	int ret = 0, num_clks = 0, i;
+
+	if (of_find_property(np, "rockchip,opp-clocks", NULL)) {
+		num_clks = of_count_phandle_with_args(np, "rockchip,opp-clocks",
+						      "#clock-cells");
+		if (num_clks <= 0)
+			return 0;
+		clks = devm_kcalloc(dev, num_clks, sizeof(*clks), GFP_KERNEL);
+		if (!clks)
+			return -ENOMEM;
+		for (i = 0; i < num_clks; i++) {
+			ret = of_parse_phandle_with_args(np,
+							 "rockchip,opp-clocks",
+							 "#clock-cells", i,
+							 &clkspec);
+			if (ret < 0) {
+				dev_err(dev, "%s: failed to parse opp clk %d\n",
+					np->name, i);
+				goto error;
+			}
+			clks[i].clk = of_clk_get_from_provider(&clkspec);
+			of_node_put(clkspec.np);
+			if (IS_ERR(clks[i].clk)) {
+				ret = PTR_ERR(clks[i].clk);
+				clks[i].clk = NULL;
+				dev_err(dev, "%s: failed to get opp clk %d\n",
+					np->name, i);
+				goto error;
+			}
+		}
+	} else {
+		num_clks = of_clk_get_parent_count(np);
+		if (num_clks <= 0)
+			return 0;
+		clks = devm_kcalloc(dev, num_clks, sizeof(*clks), GFP_KERNEL);
+		if (!clks)
+			return -ENOMEM;
+		for (i = 0; i < num_clks; i++) {
+			clks[i].clk = of_clk_get(np, i);
+			if (IS_ERR(clks[i].clk)) {
+				ret = PTR_ERR(clks[i].clk);
+				clks[i].clk = NULL;
+				dev_err(dev, "%s: failed to get clk %d\n",
+					np->name, i);
+				goto error;
+			}
+		}
+	}
+	info->clks = clks;
+	info->num_clks = num_clks;
+
+	return 0;
+error:
+	while (--i >= 0)
+		clk_put(clks[i].clk);
+	devm_kfree(dev, clks);
+
+	return ret;
+}
+
 int rockchip_init_opp_table(struct device *dev, struct rockchip_opp_info *info,
 			    char *lkg_name, char *reg_name)
 {
 	struct device_node *np;
 	int bin = -EINVAL, process = -EINVAL;
 	int scale = 0, volt_sel = -EINVAL;
-	int ret = 0, num_clks = 0, i;
+	int ret = 0;
 	u32 freq;
 
 	/* Get OPP descriptor node */
@@ -1857,24 +2021,10 @@
 		goto next;
 	info->dev = dev;
 
-	num_clks = of_clk_get_parent_count(np);
-	if (num_clks > 0) {
-		info->clks = devm_kcalloc(dev, num_clks, sizeof(*info->clks),
-					  GFP_KERNEL);
-		if (!info->clks) {
-			ret = -ENOMEM;
-			goto out;
-		}
-		for (i = 0; i < num_clks; i++) {
-			info->clks[i].clk = of_clk_get(np, i);
-			if (IS_ERR(info->clks[i].clk)) {
-				ret = PTR_ERR(info->clks[i].clk);
-				dev_err(dev, "%s: failed to get clk %d\n",
-					np->name, i);
-				goto out;
-			}
-		}
-		info->num_clks = num_clks;
+	ret = rockchip_get_opp_clk(dev, np, info);
+	if (ret)
+		goto out;
+	if (info->clks) {
 		ret = clk_bulk_prepare_enable(info->num_clks, info->clks);
 		if (ret) {
 			dev_err(dev, "failed to enable opp clks\n");
@@ -1900,6 +2050,7 @@
 
 next:
 	rockchip_get_soc_info(dev, np, &bin, &process);
+	rockchip_init_pvtpll_table(info, bin);
 	rockchip_get_scale_volt_sel(dev, lkg_name, reg_name, bin, process,
 				    &scale, &volt_sel);
 	if (info && info->data && info->data->set_soc_info)
@@ -1925,6 +2076,31 @@
 }
 EXPORT_SYMBOL(rockchip_init_opp_table);
 
+void rockchip_uninit_opp_table(struct device *dev, struct rockchip_opp_info *info)
+{
+	struct opp_table *opp_table;
+
+	if (info) {
+		kfree(info->opp_table);
+		info->opp_table = NULL;
+		devm_kfree(dev, info->clks);
+		info->clks = NULL;
+		devm_kfree(dev, info->volt_rm_tbl);
+		info->volt_rm_tbl = NULL;
+	}
+
+	opp_table = dev_pm_opp_get_opp_table(dev);
+	if (IS_ERR(opp_table))
+		return;
+	dev_pm_opp_of_remove_table(dev);
+	if (opp_table->prop_name)
+		dev_pm_opp_put_prop_name(opp_table);
+	if (opp_table->supported_hw)
+		dev_pm_opp_put_supported_hw(opp_table);
+	dev_pm_opp_put_opp_table(opp_table);
+}
+EXPORT_SYMBOL(rockchip_uninit_opp_table);
+
 MODULE_DESCRIPTION("ROCKCHIP OPP Select");
 MODULE_AUTHOR("Finley Xiao <finley.xiao@rock-chips.com>, Liang Chen <cl@rock-chips.com>");
 MODULE_LICENSE("GPL");

--
Gitblit v1.6.2