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-
2019struct 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
5353static 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
422377out_disable_inter_clock :
0 commit comments