From e3e12f52b214121840b44c91de5b3e5af5d3eb84 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Mon, 06 Nov 2023 03:04:41 +0000
Subject: [PATCH] rk3568 rt init

---
 kernel/drivers/soc/rockchip/rockchip_opp_select.c |  160 +++++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 149 insertions(+), 11 deletions(-)

diff --git a/kernel/drivers/soc/rockchip/rockchip_opp_select.c b/kernel/drivers/soc/rockchip/rockchip_opp_select.c
index 1520e2f..02bcf82 100644
--- a/kernel/drivers/soc/rockchip/rockchip_opp_select.c
+++ b/kernel/drivers/soc/rockchip/rockchip_opp_select.c
@@ -6,8 +6,10 @@
 #include <linux/clk.h>
 #include <linux/cpufreq.h>
 #include <linux/devfreq.h>
+#include <linux/mfd/syscon.h>
 #include <linux/module.h>
 #include <linux/nvmem-consumer.h>
+#include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 #include <linux/soc/rockchip/pvtm.h>
@@ -51,15 +53,24 @@
 	unsigned int num;
 	unsigned int err;
 	unsigned int ref_temp;
+	unsigned int offset;
 	int temp_prop[2];
 	const char *tz_name;
 	struct thermal_zone_device *tz;
+	struct regmap *grf;
 };
 
 struct lkg_conversion_table {
 	int temp;
 	int conv;
 };
+
+struct otp_opp_info {
+	u16 min_freq;
+	u16 max_freq;
+	u8 volt;
+	u8 length;
+} __packed;
 
 #define PVTM_CH_MAX	8
 #define PVTM_SUB_CH_MAX	8
@@ -298,16 +309,8 @@
 		return -EINVAL;
 	if (of_property_read_u32(np, "rockchip,pvtm-volt", &pvtm->volt))
 		return -EINVAL;
-	if (of_property_read_u32_array(np, "rockchip,pvtm-ch", pvtm->ch, 2))
-		return -EINVAL;
-	if (pvtm->ch[0] >= PVTM_CH_MAX || pvtm->ch[1] >= PVTM_SUB_CH_MAX)
-		return -EINVAL;
 	if (of_property_read_u32(np, "rockchip,pvtm-sample-time",
 				 &pvtm->sample_time))
-		return -EINVAL;
-	if (of_property_read_u32(np, "rockchip,pvtm-number", &pvtm->num))
-		return -EINVAL;
-	if (of_property_read_u32(np, "rockchip,pvtm-error", &pvtm->err))
 		return -EINVAL;
 	if (of_property_read_u32(np, "rockchip,pvtm-ref-temp", &pvtm->ref_temp))
 		return -EINVAL;
@@ -324,6 +327,23 @@
 	if (IS_ERR(pvtm->tz))
 		return -EINVAL;
 	if (!pvtm->tz->ops->get_temp)
+		return -EINVAL;
+	if (of_property_read_bool(np, "rockchip,pvtm-pvtpll")) {
+		if (of_property_read_u32(np, "rockchip,pvtm-offset",
+					 &pvtm->offset))
+			return -EINVAL;
+		pvtm->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
+		if (IS_ERR(pvtm->grf))
+			return -EINVAL;
+		return 0;
+	}
+	if (of_property_read_u32_array(np, "rockchip,pvtm-ch", pvtm->ch, 2))
+		return -EINVAL;
+	if (pvtm->ch[0] >= PVTM_CH_MAX || pvtm->ch[1] >= PVTM_SUB_CH_MAX)
+		return -EINVAL;
+	if (of_property_read_u32(np, "rockchip,pvtm-number", &pvtm->num))
+		return -EINVAL;
+	if (of_property_read_u32(np, "rockchip,pvtm-error", &pvtm->err))
 		return -EINVAL;
 
 	return 0;
@@ -415,7 +435,7 @@
 		 cur_temp, *target_value, avg_value, diff_value);
 
 resetore_volt:
-	regulator_set_voltage(reg, old_volt, old_volt);
+	regulator_set_voltage(reg, old_volt, INT_MAX);
 restore_clk:
 	clk_set_rate(clk, old_freq);
 pvtm_value_out:
@@ -694,6 +714,81 @@
 }
 EXPORT_SYMBOL(rockchip_of_get_lkg_sel);
 
+static int rockchip_get_pvtm_pvtpll(struct device *dev, struct device_node *np,
+				    char *reg_name)
+{
+	struct regulator *reg;
+	struct clk *clk;
+	struct pvtm_config *pvtm;
+	unsigned long old_freq;
+	unsigned int old_volt;
+	int cur_temp, diff_temp, prop_temp, diff_value;
+	int pvtm_value = 0;
+	int ret = 0;
+
+	pvtm = kzalloc(sizeof(*pvtm), GFP_KERNEL);
+	if (!pvtm)
+		return -ENOMEM;
+
+	ret = rockchip_parse_pvtm_config(np, pvtm);
+	if (ret)
+		goto out;
+
+	clk = clk_get(dev, NULL);
+	if (IS_ERR_OR_NULL(clk)) {
+		dev_warn(dev, "Failed to get clk\n");
+		goto out;
+	}
+
+	reg = regulator_get_optional(dev, reg_name);
+	if (IS_ERR_OR_NULL(reg)) {
+		dev_warn(dev, "Failed to get reg\n");
+		clk_put(clk);
+		goto out;
+	}
+	old_freq = clk_get_rate(clk);
+	old_volt = regulator_get_voltage(reg);
+
+	ret = clk_set_rate(clk, pvtm->freq * 1000);
+	if (ret) {
+		dev_err(dev, "Failed to set pvtm freq\n");
+		goto put_reg;
+	}
+	ret = regulator_set_voltage(reg, pvtm->volt, INT_MAX);
+	if (ret) {
+		dev_err(dev, "Failed to set pvtm_volt\n");
+		goto restore_clk;
+	}
+	usleep_range(pvtm->sample_time, pvtm->sample_time + 100);
+
+	ret = regmap_read(pvtm->grf, pvtm->offset, &pvtm_value);
+	if (ret < 0) {
+		dev_err(dev, "failed to get pvtm from 0x%x\n", pvtm->offset);
+		goto resetore_volt;
+	}
+	pvtm->tz->ops->get_temp(pvtm->tz, &cur_temp);
+	diff_temp = (cur_temp / 1000 - pvtm->ref_temp);
+	if (diff_temp < 0)
+		prop_temp = pvtm->temp_prop[0];
+	else
+		prop_temp = pvtm->temp_prop[1];
+	diff_value = diff_temp * prop_temp / 1000;
+	pvtm_value += diff_value;
+
+	dev_info(dev, "pvtm=%d\n", pvtm_value);
+
+resetore_volt:
+	regulator_set_voltage(reg, old_volt, INT_MAX);
+restore_clk:
+	clk_set_rate(clk, old_freq);
+put_reg:
+	regulator_put(reg);
+	clk_put(clk);
+out:
+	kfree(pvtm);
+
+	return pvtm_value;
+}
 
 static int rockchip_get_pvtm(struct device *dev, struct device_node *np,
 			     char *reg_name)
@@ -750,7 +845,10 @@
 	char name[NAME_MAX];
 	int pvtm, ret;
 
-	pvtm = rockchip_get_pvtm(dev, np, reg_name);
+	if (of_property_read_bool(np, "rockchip,pvtm-pvtpll"))
+		pvtm = rockchip_get_pvtm_pvtpll(dev, np, reg_name);
+	else
+		pvtm = rockchip_get_pvtm(dev, np, reg_name);
 	if (pvtm <= 0)
 		return;
 
@@ -910,8 +1008,9 @@
 	struct sel_table *irdrop_table = NULL;
 	struct opp_table *opp_table;
 	struct dev_pm_opp *opp;
+	unsigned long tmp_safe_rate = 0;
 	int evb_irdrop = 0, board_irdrop, delta_irdrop;
-	int tmp_safe_rate = 0, opp_rate, i, ret = 0;
+	int opp_rate, i, ret = 0;
 	u32 max_volt = UINT_MAX;
 	bool reach_max_volt = false;
 
@@ -1003,6 +1102,44 @@
 	mutex_unlock(&opp_table->lock);
 }
 
+static void rockchip_adjust_opp_by_otp(struct device *dev,
+				       struct device_node *np)
+{
+	struct dev_pm_opp *opp;
+	struct opp_table *opp_table;
+	struct otp_opp_info opp_info = {};
+	int ret;
+
+	ret = rockchip_nvmem_cell_read_common(np, "opp-info", &opp_info,
+					      sizeof(opp_info));
+	if (ret || !opp_info.volt)
+		return;
+
+	dev_info(dev, "adjust opp-table by otp: min=%uM, max=%uM, volt=%umV\n",
+		 opp_info.min_freq, opp_info.max_freq, opp_info.volt);
+
+	opp_table = dev_pm_opp_get_opp_table(dev);
+	if (!opp_table)
+		return;
+
+	mutex_lock(&opp_table->lock);
+	list_for_each_entry(opp, &opp_table->opp_list, node) {
+		if (!opp->available)
+			continue;
+		if (opp->rate < opp_info.min_freq * 1000000)
+			continue;
+		if (opp->rate > opp_info.max_freq * 1000000)
+			continue;
+
+		opp->supplies->u_volt += opp_info.volt * 1000;
+		if (opp->supplies->u_volt > opp->supplies->u_volt_max)
+			opp->supplies->u_volt = opp->supplies->u_volt_max;
+	}
+	mutex_unlock(&opp_table->lock);
+
+	dev_pm_opp_put_opp_table(opp_table);
+}
+
 static int rockchip_adjust_opp_table(struct device *dev,
 				     unsigned long scale_rate)
 {
@@ -1049,6 +1186,7 @@
 	of_property_read_u32(np, "rockchip,avs-enable", &avs);
 	of_property_read_u32(np, "rockchip,avs", &avs);
 	of_property_read_u32(np, "rockchip,avs-scale", &avs_scale);
+	rockchip_adjust_opp_by_otp(dev, np);
 	rockchip_adjust_opp_by_mbist_vmin(dev, np);
 	rockchip_adjust_opp_by_irdrop(dev, np, &safe_rate, &max_rate);
 

--
Gitblit v1.6.2