aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/mediatek/patches-5.15/350-11-cpufreq-mediatek-Add-opp-notification-support.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/mediatek/patches-5.15/350-11-cpufreq-mediatek-Add-opp-notification-support.patch')
-rw-r--r--target/linux/mediatek/patches-5.15/350-11-cpufreq-mediatek-Add-opp-notification-support.patch184
1 files changed, 184 insertions, 0 deletions
diff --git a/target/linux/mediatek/patches-5.15/350-11-cpufreq-mediatek-Add-opp-notification-support.patch b/target/linux/mediatek/patches-5.15/350-11-cpufreq-mediatek-Add-opp-notification-support.patch
new file mode 100644
index 0000000000..2cb99b907a
--- /dev/null
+++ b/target/linux/mediatek/patches-5.15/350-11-cpufreq-mediatek-Add-opp-notification-support.patch
@@ -0,0 +1,184 @@
+From 01be227eff7e5fc01f7c8de8f6daddd5fb17ddd1 Mon Sep 17 00:00:00 2001
+From: Rex-BC Chen <rex-bc.chen@mediatek.com>
+Date: Thu, 5 May 2022 19:52:21 +0800
+Subject: [PATCH 11/21] cpufreq: mediatek: Add opp notification support
+
+From this opp notifier, cpufreq should listen to opp notification and do
+proper actions when receiving events of disable and voltage adjustment.
+
+One of the user for this opp notifier is MediaTek SVS.
+The MediaTek Smart Voltage Scaling (SVS) is a hardware which calculates
+suitable SVS bank voltages to OPP voltage table.
+
+Signed-off-by: Andrew-sh.Cheng <andrew-sh.cheng@mediatek.com>
+Signed-off-by: Jia-Wei Chang <jia-wei.chang@mediatek.com>
+Signed-off-by: Rex-BC Chen <rex-bc.chen@mediatek.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+[ Viresh: Renamed opp_freq as current_freq and moved its initialization ]
+Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
+---
+ drivers/cpufreq/mediatek-cpufreq.c | 90 +++++++++++++++++++++++++++---
+ 1 file changed, 82 insertions(+), 8 deletions(-)
+
+--- a/drivers/cpufreq/mediatek-cpufreq.c
++++ b/drivers/cpufreq/mediatek-cpufreq.c
+@@ -46,6 +46,11 @@ struct mtk_cpu_dvfs_info {
+ int intermediate_voltage;
+ bool need_voltage_tracking;
+ int pre_vproc;
++ /* Avoid race condition for regulators between notify and policy */
++ struct mutex reg_lock;
++ struct notifier_block opp_nb;
++ unsigned int opp_cpu;
++ unsigned long current_freq;
+ const struct mtk_cpufreq_platform_data *soc_data;
+ int vtrack_max;
+ };
+@@ -182,6 +187,8 @@ static int mtk_cpufreq_set_target(struct
+
+ pre_freq_hz = clk_get_rate(cpu_clk);
+
++ mutex_lock(&info->reg_lock);
++
+ if (unlikely(info->pre_vproc <= 0))
+ pre_vproc = regulator_get_voltage(info->proc_reg);
+ else
+@@ -214,7 +221,7 @@ static int mtk_cpufreq_set_target(struct
+ dev_err(cpu_dev,
+ "cpu%d: failed to scale up voltage!\n", policy->cpu);
+ mtk_cpufreq_set_voltage(info, pre_vproc);
+- return ret;
++ goto out;
+ }
+ }
+
+@@ -224,8 +231,7 @@ static int mtk_cpufreq_set_target(struct
+ dev_err(cpu_dev,
+ "cpu%d: failed to re-parent cpu clock!\n", policy->cpu);
+ mtk_cpufreq_set_voltage(info, pre_vproc);
+- WARN_ON(1);
+- return ret;
++ goto out;
+ }
+
+ /* Set the original PLL to target rate. */
+@@ -235,7 +241,7 @@ static int mtk_cpufreq_set_target(struct
+ "cpu%d: failed to scale cpu clock rate!\n", policy->cpu);
+ clk_set_parent(cpu_clk, armpll);
+ mtk_cpufreq_set_voltage(info, pre_vproc);
+- return ret;
++ goto out;
+ }
+
+ /* Set parent of CPU clock back to the original PLL. */
+@@ -244,8 +250,7 @@ static int mtk_cpufreq_set_target(struct
+ dev_err(cpu_dev,
+ "cpu%d: failed to re-parent cpu clock!\n", policy->cpu);
+ mtk_cpufreq_set_voltage(info, inter_vproc);
+- WARN_ON(1);
+- return ret;
++ goto out;
+ }
+
+ /*
+@@ -260,15 +265,72 @@ static int mtk_cpufreq_set_target(struct
+ clk_set_parent(cpu_clk, info->inter_clk);
+ clk_set_rate(armpll, pre_freq_hz);
+ clk_set_parent(cpu_clk, armpll);
+- return ret;
++ goto out;
+ }
+ }
+
+- return 0;
++ info->current_freq = freq_hz;
++
++out:
++ mutex_unlock(&info->reg_lock);
++
++ return ret;
+ }
+
+ #define DYNAMIC_POWER "dynamic-power-coefficient"
+
++static int mtk_cpufreq_opp_notifier(struct notifier_block *nb,
++ unsigned long event, void *data)
++{
++ struct dev_pm_opp *opp = data;
++ struct dev_pm_opp *new_opp;
++ struct mtk_cpu_dvfs_info *info;
++ unsigned long freq, volt;
++ struct cpufreq_policy *policy;
++ int ret = 0;
++
++ info = container_of(nb, struct mtk_cpu_dvfs_info, opp_nb);
++
++ if (event == OPP_EVENT_ADJUST_VOLTAGE) {
++ freq = dev_pm_opp_get_freq(opp);
++
++ mutex_lock(&info->reg_lock);
++ if (info->current_freq == freq) {
++ volt = dev_pm_opp_get_voltage(opp);
++ ret = mtk_cpufreq_set_voltage(info, volt);
++ if (ret)
++ dev_err(info->cpu_dev,
++ "failed to scale voltage: %d\n", ret);
++ }
++ mutex_unlock(&info->reg_lock);
++ } else if (event == OPP_EVENT_DISABLE) {
++ freq = dev_pm_opp_get_freq(opp);
++
++ /* case of current opp item is disabled */
++ if (info->current_freq == freq) {
++ freq = 1;
++ new_opp = dev_pm_opp_find_freq_ceil(info->cpu_dev,
++ &freq);
++ if (IS_ERR(new_opp)) {
++ dev_err(info->cpu_dev,
++ "all opp items are disabled\n");
++ ret = PTR_ERR(new_opp);
++ return notifier_from_errno(ret);
++ }
++
++ dev_pm_opp_put(new_opp);
++ policy = cpufreq_cpu_get(info->opp_cpu);
++ if (policy) {
++ cpufreq_driver_target(policy, freq / 1000,
++ CPUFREQ_RELATION_L);
++ cpufreq_cpu_put(policy);
++ }
++ }
++ }
++
++ return notifier_from_errno(ret);
++}
++
+ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)
+ {
+ struct device *cpu_dev;
+@@ -357,6 +419,17 @@ static int mtk_cpu_dvfs_info_init(struct
+ info->intermediate_voltage = dev_pm_opp_get_voltage(opp);
+ dev_pm_opp_put(opp);
+
++ mutex_init(&info->reg_lock);
++ info->current_freq = clk_get_rate(info->cpu_clk);
++
++ info->opp_cpu = cpu;
++ info->opp_nb.notifier_call = mtk_cpufreq_opp_notifier;
++ ret = dev_pm_opp_register_notifier(cpu_dev, &info->opp_nb);
++ if (ret) {
++ dev_err(cpu_dev, "cpu%d: failed to register opp notifier\n", cpu);
++ goto out_disable_inter_clock;
++ }
++
+ /*
+ * If SRAM regulator is present, software "voltage tracking" is needed
+ * for this CPU power domain.
+@@ -421,6 +494,7 @@ static void mtk_cpu_dvfs_info_release(st
+ }
+
+ dev_pm_opp_of_cpumask_remove_table(&info->cpus);
++ dev_pm_opp_unregister_notifier(info->cpu_dev, &info->opp_nb);
+ }
+
+ static int mtk_cpufreq_init(struct cpufreq_policy *policy)