Skip to content

Commit c210063

Browse files
mtk-rex-bc-chenvireshk
authored andcommitted
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>
1 parent 6a17b38 commit c210063

1 file changed

Lines changed: 82 additions & 8 deletions

File tree

drivers/cpufreq/mediatek-cpufreq.c

Lines changed: 82 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
272334
static 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

426500
static int mtk_cpufreq_init(struct cpufreq_policy *policy)

0 commit comments

Comments
 (0)