On Fri, 2022-05-06 at 09:45 +0530, Viresh Kumar wrote: > On 05-05-22, 19:52, Rex-BC Chen wrote: > > > 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@xxxxxxxxxxxx> > > Signed-off-by: Jia-Wei Chang <jia-wei.chang@xxxxxxxxxxxx> > > Signed-off-by: Rex-BC Chen <rex-bc.chen@xxxxxxxxxxxx> > > Reviewed-by: AngeloGioacchino Del Regno < > > angelogioacchino.delregno@xxxxxxxxxxxxx> > > --- > > drivers/cpufreq/mediatek-cpufreq.c | 91 > > +++++++++++++++++++++++++++--- > > 1 file changed, 83 insertions(+), 8 deletions(-) > > > > diff --git a/drivers/cpufreq/mediatek-cpufreq.c > > b/drivers/cpufreq/mediatek-cpufreq.c > > index fe205eca657d..06d80ee06bbf 100644 > > --- 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 opp_freq; > > The name opp_freq doesn't fit well, I renamed it to current_freq. > > > const struct mtk_cpufreq_platform_data *soc_data; > > int vtrack_max; > > }; > > @@ -182,6 +187,8 @@ static int mtk_cpufreq_set_target(struct > > cpufreq_policy *policy, > > > > 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 > > cpufreq_policy *policy, > > 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 > > cpufreq_policy *policy, > > 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 > > cpufreq_policy *policy, > > "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 > > cpufreq_policy *policy, > > 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 > > cpufreq_policy *policy, > > 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->opp_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->opp_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->opp_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,18 @@ static int mtk_cpu_dvfs_info_init(struct > > mtk_cpu_dvfs_info *info, int cpu) > > info->intermediate_voltage = dev_pm_opp_get_voltage(opp); > > dev_pm_opp_put(opp); > > > > + mutex_init(&info->reg_lock); > > + > > + 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; > > + } > > + > > + info->opp_freq = clk_get_rate(info->cpu_clk); > > This is a resource as well, which should have been initialized before > registering notifier. > > Applied with above changes. Thanks. > Hello Viresh, Thanks for your help! BRs, Rex