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