Skip to content

Commit 6a17b38

Browse files
jiaweichang-mtkvireshk
authored andcommitted
cpufreq: mediatek: Refine mtk_cpufreq_voltage_tracking()
Because the difference of sram and proc should in a range of min_volt_shift and max_volt_shift. We need to adjust the sram and proc step by step. We replace VOLT_TOL (voltage tolerance) with the platform data and update the logic to determine the voltage boundary and invoking regulator_set_voltage. - Use 'sram_min_volt' and 'sram_max_volt' to determine the voltage boundary of sram regulator. - Use (sram_min_volt - min_volt_shift) and 'proc_max_volt' to determine the voltage boundary of vproc regulator. Moreover, to prevent infinite loop when tracking voltage, we calculate the maximum value for each platform data. We assume min voltage is 0 and tracking target voltage using min_volt_shift for each iteration. The retry_max is 3 times of expeted iteration count. 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> Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
1 parent ead858b commit 6a17b38

1 file changed

Lines changed: 51 additions & 96 deletions

File tree

drivers/cpufreq/mediatek-cpufreq.c

Lines changed: 51 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,14 @@
88
#include <linux/cpu.h>
99
#include <linux/cpufreq.h>
1010
#include <linux/cpumask.h>
11+
#include <linux/minmax.h>
1112
#include <linux/module.h>
1213
#include <linux/of.h>
1314
#include <linux/of_platform.h>
1415
#include <linux/platform_device.h>
1516
#include <linux/pm_opp.h>
1617
#include <linux/regulator/consumer.h>
1718

18-
#define VOLT_TOL (10000)
19-
2019
struct mtk_cpufreq_platform_data {
2120
int min_volt_shift;
2221
int max_volt_shift;
@@ -48,6 +47,7 @@ struct mtk_cpu_dvfs_info {
4847
bool need_voltage_tracking;
4948
int pre_vproc;
5049
const struct mtk_cpufreq_platform_data *soc_data;
50+
int vtrack_max;
5151
};
5252

5353
static struct platform_device *cpufreq_pdev;
@@ -73,98 +73,52 @@ static int mtk_cpufreq_voltage_tracking(struct mtk_cpu_dvfs_info *info,
7373
struct regulator *proc_reg = info->proc_reg;
7474
struct regulator *sram_reg = info->sram_reg;
7575
int pre_vproc, pre_vsram, new_vsram, vsram, vproc, ret;
76+
int retry = info->vtrack_max;
7677

7778
pre_vproc = regulator_get_voltage(proc_reg);
7879
if (pre_vproc < 0) {
7980
dev_err(info->cpu_dev,
8081
"invalid Vproc value: %d\n", pre_vproc);
8182
return pre_vproc;
8283
}
83-
/* Vsram should not exceed the maximum allowed voltage of SoC. */
84-
new_vsram = min(new_vproc + soc_data->min_volt_shift,
85-
soc_data->sram_max_volt);
86-
87-
if (pre_vproc < new_vproc) {
88-
/*
89-
* When scaling up voltages, Vsram and Vproc scale up step
90-
* by step. At each step, set Vsram to (Vproc + 200mV) first,
91-
* then set Vproc to (Vsram - 100mV).
92-
* Keep doing it until Vsram and Vproc hit target voltages.
93-
*/
94-
do {
95-
pre_vsram = regulator_get_voltage(sram_reg);
96-
if (pre_vsram < 0) {
97-
dev_err(info->cpu_dev,
98-
"invalid Vsram value: %d\n", pre_vsram);
99-
return pre_vsram;
100-
}
101-
pre_vproc = regulator_get_voltage(proc_reg);
102-
if (pre_vproc < 0) {
103-
dev_err(info->cpu_dev,
104-
"invalid Vproc value: %d\n", pre_vproc);
105-
return pre_vproc;
106-
}
107-
108-
vsram = min(new_vsram,
109-
pre_vproc + soc_data->min_volt_shift);
11084

111-
if (vsram + VOLT_TOL >= soc_data->sram_max_volt) {
112-
vsram = soc_data->sram_max_volt;
85+
pre_vsram = regulator_get_voltage(sram_reg);
86+
if (pre_vsram < 0) {
87+
dev_err(info->cpu_dev, "invalid Vsram value: %d\n", pre_vsram);
88+
return pre_vsram;
89+
}
11390

114-
/*
115-
* If the target Vsram hits the maximum voltage,
116-
* try to set the exact voltage value first.
117-
*/
118-
ret = regulator_set_voltage(sram_reg, vsram,
119-
vsram);
120-
if (ret)
121-
ret = regulator_set_voltage(sram_reg,
122-
vsram - VOLT_TOL,
123-
vsram);
91+
new_vsram = clamp(new_vproc + soc_data->min_volt_shift,
92+
soc_data->sram_min_volt, soc_data->sram_max_volt);
12493

125-
vproc = new_vproc;
126-
} else {
127-
ret = regulator_set_voltage(sram_reg, vsram,
128-
vsram + VOLT_TOL);
94+
do {
95+
if (pre_vproc <= new_vproc) {
96+
vsram = clamp(pre_vproc + soc_data->max_volt_shift,
97+
soc_data->sram_min_volt, new_vsram);
98+
ret = regulator_set_voltage(sram_reg, vsram,
99+
soc_data->sram_max_volt);
129100

130-
vproc = vsram - soc_data->min_volt_shift;
131-
}
132101
if (ret)
133102
return ret;
134103

104+
if (vsram == soc_data->sram_max_volt ||
105+
new_vsram == soc_data->sram_min_volt)
106+
vproc = new_vproc;
107+
else
108+
vproc = vsram - soc_data->min_volt_shift;
109+
135110
ret = regulator_set_voltage(proc_reg, vproc,
136-
vproc + VOLT_TOL);
111+
soc_data->proc_max_volt);
137112
if (ret) {
138113
regulator_set_voltage(sram_reg, pre_vsram,
139-
pre_vsram);
114+
soc_data->sram_max_volt);
140115
return ret;
141116
}
142-
} while (vproc < new_vproc || vsram < new_vsram);
143-
} else if (pre_vproc > new_vproc) {
144-
/*
145-
* When scaling down voltages, Vsram and Vproc scale down step
146-
* by step. At each step, set Vproc to (Vsram - 200mV) first,
147-
* then set Vproc to (Vproc + 100mV).
148-
* Keep doing it until Vsram and Vproc hit target voltages.
149-
*/
150-
do {
151-
pre_vproc = regulator_get_voltage(proc_reg);
152-
if (pre_vproc < 0) {
153-
dev_err(info->cpu_dev,
154-
"invalid Vproc value: %d\n", pre_vproc);
155-
return pre_vproc;
156-
}
157-
pre_vsram = regulator_get_voltage(sram_reg);
158-
if (pre_vsram < 0) {
159-
dev_err(info->cpu_dev,
160-
"invalid Vsram value: %d\n", pre_vsram);
161-
return pre_vsram;
162-
}
163-
117+
} else if (pre_vproc > new_vproc) {
164118
vproc = max(new_vproc,
165119
pre_vsram - soc_data->max_volt_shift);
166120
ret = regulator_set_voltage(proc_reg, vproc,
167-
vproc + VOLT_TOL);
121+
soc_data->proc_max_volt);
168122
if (ret)
169123
return ret;
170124

@@ -174,32 +128,24 @@ static int mtk_cpufreq_voltage_tracking(struct mtk_cpu_dvfs_info *info,
174128
vsram = max(new_vsram,
175129
vproc + soc_data->min_volt_shift);
176130

177-
if (vsram + VOLT_TOL >= soc_data->sram_max_volt) {
178-
vsram = soc_data->sram_max_volt;
179-
180-
/*
181-
* If the target Vsram hits the maximum voltage,
182-
* try to set the exact voltage value first.
183-
*/
184-
ret = regulator_set_voltage(sram_reg, vsram,
185-
vsram);
186-
if (ret)
187-
ret = regulator_set_voltage(sram_reg,
188-
vsram - VOLT_TOL,
189-
vsram);
190-
} else {
191-
ret = regulator_set_voltage(sram_reg, vsram,
192-
vsram + VOLT_TOL);
193-
}
194-
131+
ret = regulator_set_voltage(sram_reg, vsram,
132+
soc_data->sram_max_volt);
195133
if (ret) {
196134
regulator_set_voltage(proc_reg, pre_vproc,
197-
pre_vproc);
135+
soc_data->proc_max_volt);
198136
return ret;
199137
}
200-
} while (vproc > new_vproc + VOLT_TOL ||
201-
vsram > new_vsram + VOLT_TOL);
202-
}
138+
}
139+
140+
pre_vproc = vproc;
141+
pre_vsram = vsram;
142+
143+
if (--retry < 0) {
144+
dev_err(info->cpu_dev,
145+
"over loop count, failed to set voltage\n");
146+
return -EINVAL;
147+
}
148+
} while (vproc != new_vproc || vsram != new_vsram);
203149

204150
return 0;
205151
}
@@ -261,8 +207,8 @@ static int mtk_cpufreq_set_target(struct cpufreq_policy *policy,
261207
* If the new voltage or the intermediate voltage is higher than the
262208
* current voltage, scale up voltage first.
263209
*/
264-
target_vproc = (inter_vproc > vproc) ? inter_vproc : vproc;
265-
if (pre_vproc < target_vproc) {
210+
target_vproc = max(inter_vproc, vproc);
211+
if (pre_vproc <= target_vproc) {
266212
ret = mtk_cpufreq_set_voltage(info, target_vproc);
267213
if (ret) {
268214
dev_err(cpu_dev,
@@ -417,6 +363,15 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)
417363
*/
418364
info->need_voltage_tracking = (info->sram_reg != NULL);
419365

366+
/*
367+
* We assume min voltage is 0 and tracking target voltage using
368+
* min_volt_shift for each iteration.
369+
* The vtrack_max is 3 times of expeted iteration count.
370+
*/
371+
info->vtrack_max = 3 * DIV_ROUND_UP(max(info->soc_data->sram_max_volt,
372+
info->soc_data->proc_max_volt),
373+
info->soc_data->min_volt_shift);
374+
420375
return 0;
421376

422377
out_disable_inter_clock:

0 commit comments

Comments
 (0)