@@ -46,6 +46,11 @@ struct mtk_cpu_dvfs_info {
4646 int intermediate_voltage ;
4747 bool need_voltage_tracking ;
4848 int pre_vproc ;
49+ /* Avoid race condition for regulators between notify and policy */
50+ struct mutex reg_lock ;
51+ struct notifier_block opp_nb ;
52+ unsigned int opp_cpu ;
53+ unsigned long current_freq ;
4954 const struct mtk_cpufreq_platform_data * soc_data ;
5055 int vtrack_max ;
5156};
@@ -182,6 +187,8 @@ static int mtk_cpufreq_set_target(struct cpufreq_policy *policy,
182187
183188 pre_freq_hz = clk_get_rate (cpu_clk );
184189
190+ mutex_lock (& info -> reg_lock );
191+
185192 if (unlikely (info -> pre_vproc <= 0 ))
186193 pre_vproc = regulator_get_voltage (info -> proc_reg );
187194 else
@@ -214,7 +221,7 @@ static int mtk_cpufreq_set_target(struct cpufreq_policy *policy,
214221 dev_err (cpu_dev ,
215222 "cpu%d: failed to scale up voltage!\n" , policy -> cpu );
216223 mtk_cpufreq_set_voltage (info , pre_vproc );
217- return ret ;
224+ goto out ;
218225 }
219226 }
220227
@@ -224,8 +231,7 @@ static int mtk_cpufreq_set_target(struct cpufreq_policy *policy,
224231 dev_err (cpu_dev ,
225232 "cpu%d: failed to re-parent cpu clock!\n" , policy -> cpu );
226233 mtk_cpufreq_set_voltage (info , pre_vproc );
227- WARN_ON (1 );
228- return ret ;
234+ goto out ;
229235 }
230236
231237 /* Set the original PLL to target rate. */
@@ -235,7 +241,7 @@ static int mtk_cpufreq_set_target(struct cpufreq_policy *policy,
235241 "cpu%d: failed to scale cpu clock rate!\n" , policy -> cpu );
236242 clk_set_parent (cpu_clk , armpll );
237243 mtk_cpufreq_set_voltage (info , pre_vproc );
238- return ret ;
244+ goto out ;
239245 }
240246
241247 /* Set parent of CPU clock back to the original PLL. */
@@ -244,8 +250,7 @@ static int mtk_cpufreq_set_target(struct cpufreq_policy *policy,
244250 dev_err (cpu_dev ,
245251 "cpu%d: failed to re-parent cpu clock!\n" , policy -> cpu );
246252 mtk_cpufreq_set_voltage (info , inter_vproc );
247- WARN_ON (1 );
248- return ret ;
253+ goto out ;
249254 }
250255
251256 /*
@@ -260,15 +265,72 @@ static int mtk_cpufreq_set_target(struct cpufreq_policy *policy,
260265 clk_set_parent (cpu_clk , info -> inter_clk );
261266 clk_set_rate (armpll , pre_freq_hz );
262267 clk_set_parent (cpu_clk , armpll );
263- return ret ;
268+ goto out ;
264269 }
265270 }
266271
267- return 0 ;
272+ info -> current_freq = freq_hz ;
273+
274+ out :
275+ mutex_unlock (& info -> reg_lock );
276+
277+ return ret ;
268278}
269279
270280#define DYNAMIC_POWER "dynamic-power-coefficient"
271281
282+ static int mtk_cpufreq_opp_notifier (struct notifier_block * nb ,
283+ unsigned long event , void * data )
284+ {
285+ struct dev_pm_opp * opp = data ;
286+ struct dev_pm_opp * new_opp ;
287+ struct mtk_cpu_dvfs_info * info ;
288+ unsigned long freq , volt ;
289+ struct cpufreq_policy * policy ;
290+ int ret = 0 ;
291+
292+ info = container_of (nb , struct mtk_cpu_dvfs_info , opp_nb );
293+
294+ if (event == OPP_EVENT_ADJUST_VOLTAGE ) {
295+ freq = dev_pm_opp_get_freq (opp );
296+
297+ mutex_lock (& info -> reg_lock );
298+ if (info -> current_freq == freq ) {
299+ volt = dev_pm_opp_get_voltage (opp );
300+ ret = mtk_cpufreq_set_voltage (info , volt );
301+ if (ret )
302+ dev_err (info -> cpu_dev ,
303+ "failed to scale voltage: %d\n" , ret );
304+ }
305+ mutex_unlock (& info -> reg_lock );
306+ } else if (event == OPP_EVENT_DISABLE ) {
307+ freq = dev_pm_opp_get_freq (opp );
308+
309+ /* case of current opp item is disabled */
310+ if (info -> current_freq == freq ) {
311+ freq = 1 ;
312+ new_opp = dev_pm_opp_find_freq_ceil (info -> cpu_dev ,
313+ & freq );
314+ if (IS_ERR (new_opp )) {
315+ dev_err (info -> cpu_dev ,
316+ "all opp items are disabled\n" );
317+ ret = PTR_ERR (new_opp );
318+ return notifier_from_errno (ret );
319+ }
320+
321+ dev_pm_opp_put (new_opp );
322+ policy = cpufreq_cpu_get (info -> opp_cpu );
323+ if (policy ) {
324+ cpufreq_driver_target (policy , freq / 1000 ,
325+ CPUFREQ_RELATION_L );
326+ cpufreq_cpu_put (policy );
327+ }
328+ }
329+ }
330+
331+ return notifier_from_errno (ret );
332+ }
333+
272334static int mtk_cpu_dvfs_info_init (struct mtk_cpu_dvfs_info * info , int cpu )
273335{
274336 struct device * cpu_dev ;
@@ -357,6 +419,17 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)
357419 info -> intermediate_voltage = dev_pm_opp_get_voltage (opp );
358420 dev_pm_opp_put (opp );
359421
422+ mutex_init (& info -> reg_lock );
423+ info -> current_freq = clk_get_rate (info -> cpu_clk );
424+
425+ info -> opp_cpu = cpu ;
426+ info -> opp_nb .notifier_call = mtk_cpufreq_opp_notifier ;
427+ ret = dev_pm_opp_register_notifier (cpu_dev , & info -> opp_nb );
428+ if (ret ) {
429+ dev_err (cpu_dev , "cpu%d: failed to register opp notifier\n" , cpu );
430+ goto out_disable_inter_clock ;
431+ }
432+
360433 /*
361434 * If SRAM regulator is present, software "voltage tracking" is needed
362435 * for this CPU power domain.
@@ -421,6 +494,7 @@ static void mtk_cpu_dvfs_info_release(struct mtk_cpu_dvfs_info *info)
421494 }
422495
423496 dev_pm_opp_of_cpumask_remove_table (& info -> cpus );
497+ dev_pm_opp_unregister_notifier (info -> cpu_dev , & info -> opp_nb );
424498}
425499
426500static int mtk_cpufreq_init (struct cpufreq_policy * policy )
0 commit comments