• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2015 Linaro Ltd.
4  * Author: Pi-Cheng Chen <pi-cheng.chen@linaro.org>
5  */
6 
7 #include <linux/clk.h>
8 #include <linux/cpu.h>
9 #include <linux/cpufreq.h>
10 #include <linux/cpumask.h>
11 #include <linux/module.h>
12 #include <linux/of.h>
13 #include <linux/platform_device.h>
14 #include <linux/pm_opp.h>
15 #include <linux/regulator/consumer.h>
16 #include <linux/slab.h>
17 #include <linux/thermal.h>
18 
19 #define MIN_VOLT_SHIFT		(100000)
20 #define MAX_VOLT_SHIFT		(200000)
21 #define MAX_VOLT_LIMIT		(1150000)
22 #define VOLT_TOL		(10000)
23 
24 /*
25  * The struct mtk_cpu_dvfs_info holds necessary information for doing CPU DVFS
26  * on each CPU power/clock domain of Mediatek SoCs. Each CPU cluster in
27  * Mediatek SoCs has two voltage inputs, Vproc and Vsram. In some cases the two
28  * voltage inputs need to be controlled under a hardware limitation:
29  * 100mV < Vsram - Vproc < 200mV
30  *
31  * When scaling the clock frequency of a CPU clock domain, the clock source
32  * needs to be switched to another stable PLL clock temporarily until
33  * the original PLL becomes stable at target frequency.
34  */
35 struct mtk_cpu_dvfs_info {
36 	struct cpumask cpus;
37 	struct device *cpu_dev;
38 	struct regulator *proc_reg;
39 	struct regulator *sram_reg;
40 	struct clk *cpu_clk;
41 	struct clk *inter_clk;
42 	struct list_head list_head;
43 	int intermediate_voltage;
44 	bool need_voltage_tracking;
45 };
46 
47 static struct platform_device *cpufreq_pdev;
48 
49 static LIST_HEAD(dvfs_info_list);
50 
mtk_cpu_dvfs_info_lookup(int cpu)51 static struct mtk_cpu_dvfs_info *mtk_cpu_dvfs_info_lookup(int cpu)
52 {
53 	struct mtk_cpu_dvfs_info *info;
54 
55 	list_for_each_entry(info, &dvfs_info_list, list_head) {
56 		if (cpumask_test_cpu(cpu, &info->cpus))
57 			return info;
58 	}
59 
60 	return NULL;
61 }
62 
mtk_cpufreq_voltage_tracking(struct mtk_cpu_dvfs_info * info,int new_vproc)63 static int mtk_cpufreq_voltage_tracking(struct mtk_cpu_dvfs_info *info,
64 					int new_vproc)
65 {
66 	struct regulator *proc_reg = info->proc_reg;
67 	struct regulator *sram_reg = info->sram_reg;
68 	int old_vproc, old_vsram, new_vsram, vsram, vproc, ret;
69 
70 	old_vproc = regulator_get_voltage(proc_reg);
71 	if (old_vproc < 0) {
72 		pr_err("%s: invalid Vproc value: %d\n", __func__, old_vproc);
73 		return old_vproc;
74 	}
75 	/* Vsram should not exceed the maximum allowed voltage of SoC. */
76 	new_vsram = min(new_vproc + MIN_VOLT_SHIFT, MAX_VOLT_LIMIT);
77 
78 	if (old_vproc < new_vproc) {
79 		/*
80 		 * When scaling up voltages, Vsram and Vproc scale up step
81 		 * by step. At each step, set Vsram to (Vproc + 200mV) first,
82 		 * then set Vproc to (Vsram - 100mV).
83 		 * Keep doing it until Vsram and Vproc hit target voltages.
84 		 */
85 		do {
86 			old_vsram = regulator_get_voltage(sram_reg);
87 			if (old_vsram < 0) {
88 				pr_err("%s: invalid Vsram value: %d\n",
89 				       __func__, old_vsram);
90 				return old_vsram;
91 			}
92 			old_vproc = regulator_get_voltage(proc_reg);
93 			if (old_vproc < 0) {
94 				pr_err("%s: invalid Vproc value: %d\n",
95 				       __func__, old_vproc);
96 				return old_vproc;
97 			}
98 
99 			vsram = min(new_vsram, old_vproc + MAX_VOLT_SHIFT);
100 
101 			if (vsram + VOLT_TOL >= MAX_VOLT_LIMIT) {
102 				vsram = MAX_VOLT_LIMIT;
103 
104 				/*
105 				 * If the target Vsram hits the maximum voltage,
106 				 * try to set the exact voltage value first.
107 				 */
108 				ret = regulator_set_voltage(sram_reg, vsram,
109 							    vsram);
110 				if (ret)
111 					ret = regulator_set_voltage(sram_reg,
112 							vsram - VOLT_TOL,
113 							vsram);
114 
115 				vproc = new_vproc;
116 			} else {
117 				ret = regulator_set_voltage(sram_reg, vsram,
118 							    vsram + VOLT_TOL);
119 
120 				vproc = vsram - MIN_VOLT_SHIFT;
121 			}
122 			if (ret)
123 				return ret;
124 
125 			ret = regulator_set_voltage(proc_reg, vproc,
126 						    vproc + VOLT_TOL);
127 			if (ret) {
128 				regulator_set_voltage(sram_reg, old_vsram,
129 						      old_vsram);
130 				return ret;
131 			}
132 		} while (vproc < new_vproc || vsram < new_vsram);
133 	} else if (old_vproc > new_vproc) {
134 		/*
135 		 * When scaling down voltages, Vsram and Vproc scale down step
136 		 * by step. At each step, set Vproc to (Vsram - 200mV) first,
137 		 * then set Vproc to (Vproc + 100mV).
138 		 * Keep doing it until Vsram and Vproc hit target voltages.
139 		 */
140 		do {
141 			old_vproc = regulator_get_voltage(proc_reg);
142 			if (old_vproc < 0) {
143 				pr_err("%s: invalid Vproc value: %d\n",
144 				       __func__, old_vproc);
145 				return old_vproc;
146 			}
147 			old_vsram = regulator_get_voltage(sram_reg);
148 			if (old_vsram < 0) {
149 				pr_err("%s: invalid Vsram value: %d\n",
150 				       __func__, old_vsram);
151 				return old_vsram;
152 			}
153 
154 			vproc = max(new_vproc, old_vsram - MAX_VOLT_SHIFT);
155 			ret = regulator_set_voltage(proc_reg, vproc,
156 						    vproc + VOLT_TOL);
157 			if (ret)
158 				return ret;
159 
160 			if (vproc == new_vproc)
161 				vsram = new_vsram;
162 			else
163 				vsram = max(new_vsram, vproc + MIN_VOLT_SHIFT);
164 
165 			if (vsram + VOLT_TOL >= MAX_VOLT_LIMIT) {
166 				vsram = MAX_VOLT_LIMIT;
167 
168 				/*
169 				 * If the target Vsram hits the maximum voltage,
170 				 * try to set the exact voltage value first.
171 				 */
172 				ret = regulator_set_voltage(sram_reg, vsram,
173 							    vsram);
174 				if (ret)
175 					ret = regulator_set_voltage(sram_reg,
176 							vsram - VOLT_TOL,
177 							vsram);
178 			} else {
179 				ret = regulator_set_voltage(sram_reg, vsram,
180 							    vsram + VOLT_TOL);
181 			}
182 
183 			if (ret) {
184 				regulator_set_voltage(proc_reg, old_vproc,
185 						      old_vproc);
186 				return ret;
187 			}
188 		} while (vproc > new_vproc + VOLT_TOL ||
189 			 vsram > new_vsram + VOLT_TOL);
190 	}
191 
192 	return 0;
193 }
194 
mtk_cpufreq_set_voltage(struct mtk_cpu_dvfs_info * info,int vproc)195 static int mtk_cpufreq_set_voltage(struct mtk_cpu_dvfs_info *info, int vproc)
196 {
197 	if (info->need_voltage_tracking)
198 		return mtk_cpufreq_voltage_tracking(info, vproc);
199 	else
200 		return regulator_set_voltage(info->proc_reg, vproc,
201 					     vproc + VOLT_TOL);
202 }
203 
mtk_cpufreq_set_target(struct cpufreq_policy * policy,unsigned int index)204 static int mtk_cpufreq_set_target(struct cpufreq_policy *policy,
205 				  unsigned int index)
206 {
207 	struct cpufreq_frequency_table *freq_table = policy->freq_table;
208 	struct clk *cpu_clk = policy->clk;
209 	struct clk *armpll = clk_get_parent(cpu_clk);
210 	struct mtk_cpu_dvfs_info *info = policy->driver_data;
211 	struct device *cpu_dev = info->cpu_dev;
212 	struct dev_pm_opp *opp;
213 	long freq_hz, old_freq_hz;
214 	int vproc, old_vproc, inter_vproc, target_vproc, ret;
215 
216 	inter_vproc = info->intermediate_voltage;
217 
218 	old_freq_hz = clk_get_rate(cpu_clk);
219 	old_vproc = regulator_get_voltage(info->proc_reg);
220 	if (old_vproc < 0) {
221 		pr_err("%s: invalid Vproc value: %d\n", __func__, old_vproc);
222 		return old_vproc;
223 	}
224 
225 	freq_hz = freq_table[index].frequency * 1000;
226 
227 	opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz);
228 	if (IS_ERR(opp)) {
229 		pr_err("cpu%d: failed to find OPP for %ld\n",
230 		       policy->cpu, freq_hz);
231 		return PTR_ERR(opp);
232 	}
233 	vproc = dev_pm_opp_get_voltage(opp);
234 	dev_pm_opp_put(opp);
235 
236 	/*
237 	 * If the new voltage or the intermediate voltage is higher than the
238 	 * current voltage, scale up voltage first.
239 	 */
240 	target_vproc = (inter_vproc > vproc) ? inter_vproc : vproc;
241 	if (old_vproc < target_vproc) {
242 		ret = mtk_cpufreq_set_voltage(info, target_vproc);
243 		if (ret) {
244 			pr_err("cpu%d: failed to scale up voltage!\n",
245 			       policy->cpu);
246 			mtk_cpufreq_set_voltage(info, old_vproc);
247 			return ret;
248 		}
249 	}
250 
251 	/* Reparent the CPU clock to intermediate clock. */
252 	ret = clk_set_parent(cpu_clk, info->inter_clk);
253 	if (ret) {
254 		pr_err("cpu%d: failed to re-parent cpu clock!\n",
255 		       policy->cpu);
256 		mtk_cpufreq_set_voltage(info, old_vproc);
257 		WARN_ON(1);
258 		return ret;
259 	}
260 
261 	/* Set the original PLL to target rate. */
262 	ret = clk_set_rate(armpll, freq_hz);
263 	if (ret) {
264 		pr_err("cpu%d: failed to scale cpu clock rate!\n",
265 		       policy->cpu);
266 		clk_set_parent(cpu_clk, armpll);
267 		mtk_cpufreq_set_voltage(info, old_vproc);
268 		return ret;
269 	}
270 
271 	/* Set parent of CPU clock back to the original PLL. */
272 	ret = clk_set_parent(cpu_clk, armpll);
273 	if (ret) {
274 		pr_err("cpu%d: failed to re-parent cpu clock!\n",
275 		       policy->cpu);
276 		mtk_cpufreq_set_voltage(info, inter_vproc);
277 		WARN_ON(1);
278 		return ret;
279 	}
280 
281 	/*
282 	 * If the new voltage is lower than the intermediate voltage or the
283 	 * original voltage, scale down to the new voltage.
284 	 */
285 	if (vproc < inter_vproc || vproc < old_vproc) {
286 		ret = mtk_cpufreq_set_voltage(info, vproc);
287 		if (ret) {
288 			pr_err("cpu%d: failed to scale down voltage!\n",
289 			       policy->cpu);
290 			clk_set_parent(cpu_clk, info->inter_clk);
291 			clk_set_rate(armpll, old_freq_hz);
292 			clk_set_parent(cpu_clk, armpll);
293 			return ret;
294 		}
295 	}
296 
297 	return 0;
298 }
299 
300 #define DYNAMIC_POWER "dynamic-power-coefficient"
301 
mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info * info,int cpu)302 static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)
303 {
304 	struct device *cpu_dev;
305 	struct regulator *proc_reg = ERR_PTR(-ENODEV);
306 	struct regulator *sram_reg = ERR_PTR(-ENODEV);
307 	struct clk *cpu_clk = ERR_PTR(-ENODEV);
308 	struct clk *inter_clk = ERR_PTR(-ENODEV);
309 	struct dev_pm_opp *opp;
310 	unsigned long rate;
311 	int ret;
312 
313 	cpu_dev = get_cpu_device(cpu);
314 	if (!cpu_dev) {
315 		pr_err("failed to get cpu%d device\n", cpu);
316 		return -ENODEV;
317 	}
318 
319 	cpu_clk = clk_get(cpu_dev, "cpu");
320 	if (IS_ERR(cpu_clk)) {
321 		if (PTR_ERR(cpu_clk) == -EPROBE_DEFER)
322 			pr_warn("cpu clk for cpu%d not ready, retry.\n", cpu);
323 		else
324 			pr_err("failed to get cpu clk for cpu%d\n", cpu);
325 
326 		ret = PTR_ERR(cpu_clk);
327 		return ret;
328 	}
329 
330 	inter_clk = clk_get(cpu_dev, "intermediate");
331 	if (IS_ERR(inter_clk)) {
332 		if (PTR_ERR(inter_clk) == -EPROBE_DEFER)
333 			pr_warn("intermediate clk for cpu%d not ready, retry.\n",
334 				cpu);
335 		else
336 			pr_err("failed to get intermediate clk for cpu%d\n",
337 			       cpu);
338 
339 		ret = PTR_ERR(inter_clk);
340 		goto out_free_resources;
341 	}
342 
343 	proc_reg = regulator_get_optional(cpu_dev, "proc");
344 	if (IS_ERR(proc_reg)) {
345 		if (PTR_ERR(proc_reg) == -EPROBE_DEFER)
346 			pr_warn("proc regulator for cpu%d not ready, retry.\n",
347 				cpu);
348 		else
349 			pr_err("failed to get proc regulator for cpu%d\n",
350 			       cpu);
351 
352 		ret = PTR_ERR(proc_reg);
353 		goto out_free_resources;
354 	}
355 
356 	/* Both presence and absence of sram regulator are valid cases. */
357 	sram_reg = regulator_get_exclusive(cpu_dev, "sram");
358 
359 	/* Get OPP-sharing information from "operating-points-v2" bindings */
360 	ret = dev_pm_opp_of_get_sharing_cpus(cpu_dev, &info->cpus);
361 	if (ret) {
362 		pr_err("failed to get OPP-sharing information for cpu%d\n",
363 		       cpu);
364 		goto out_free_resources;
365 	}
366 
367 	ret = dev_pm_opp_of_cpumask_add_table(&info->cpus);
368 	if (ret) {
369 		pr_warn("no OPP table for cpu%d\n", cpu);
370 		goto out_free_resources;
371 	}
372 
373 	/* Search a safe voltage for intermediate frequency. */
374 	rate = clk_get_rate(inter_clk);
375 	opp = dev_pm_opp_find_freq_ceil(cpu_dev, &rate);
376 	if (IS_ERR(opp)) {
377 		pr_err("failed to get intermediate opp for cpu%d\n", cpu);
378 		ret = PTR_ERR(opp);
379 		goto out_free_opp_table;
380 	}
381 	info->intermediate_voltage = dev_pm_opp_get_voltage(opp);
382 	dev_pm_opp_put(opp);
383 
384 	info->cpu_dev = cpu_dev;
385 	info->proc_reg = proc_reg;
386 	info->sram_reg = IS_ERR(sram_reg) ? NULL : sram_reg;
387 	info->cpu_clk = cpu_clk;
388 	info->inter_clk = inter_clk;
389 
390 	/*
391 	 * If SRAM regulator is present, software "voltage tracking" is needed
392 	 * for this CPU power domain.
393 	 */
394 	info->need_voltage_tracking = !IS_ERR(sram_reg);
395 
396 	return 0;
397 
398 out_free_opp_table:
399 	dev_pm_opp_of_cpumask_remove_table(&info->cpus);
400 
401 out_free_resources:
402 	if (!IS_ERR(proc_reg))
403 		regulator_put(proc_reg);
404 	if (!IS_ERR(sram_reg))
405 		regulator_put(sram_reg);
406 	if (!IS_ERR(cpu_clk))
407 		clk_put(cpu_clk);
408 	if (!IS_ERR(inter_clk))
409 		clk_put(inter_clk);
410 
411 	return ret;
412 }
413 
mtk_cpu_dvfs_info_release(struct mtk_cpu_dvfs_info * info)414 static void mtk_cpu_dvfs_info_release(struct mtk_cpu_dvfs_info *info)
415 {
416 	if (!IS_ERR(info->proc_reg))
417 		regulator_put(info->proc_reg);
418 	if (!IS_ERR(info->sram_reg))
419 		regulator_put(info->sram_reg);
420 	if (!IS_ERR(info->cpu_clk))
421 		clk_put(info->cpu_clk);
422 	if (!IS_ERR(info->inter_clk))
423 		clk_put(info->inter_clk);
424 
425 	dev_pm_opp_of_cpumask_remove_table(&info->cpus);
426 }
427 
mtk_cpufreq_init(struct cpufreq_policy * policy)428 static int mtk_cpufreq_init(struct cpufreq_policy *policy)
429 {
430 	struct mtk_cpu_dvfs_info *info;
431 	struct cpufreq_frequency_table *freq_table;
432 	int ret;
433 
434 	info = mtk_cpu_dvfs_info_lookup(policy->cpu);
435 	if (!info) {
436 		pr_err("dvfs info for cpu%d is not initialized.\n",
437 		       policy->cpu);
438 		return -EINVAL;
439 	}
440 
441 	ret = dev_pm_opp_init_cpufreq_table(info->cpu_dev, &freq_table);
442 	if (ret) {
443 		pr_err("failed to init cpufreq table for cpu%d: %d\n",
444 		       policy->cpu, ret);
445 		return ret;
446 	}
447 
448 	cpumask_copy(policy->cpus, &info->cpus);
449 	policy->freq_table = freq_table;
450 	policy->driver_data = info;
451 	policy->clk = info->cpu_clk;
452 
453 	dev_pm_opp_of_register_em(info->cpu_dev, policy->cpus);
454 
455 	return 0;
456 }
457 
mtk_cpufreq_exit(struct cpufreq_policy * policy)458 static int mtk_cpufreq_exit(struct cpufreq_policy *policy)
459 {
460 	struct mtk_cpu_dvfs_info *info = policy->driver_data;
461 
462 	dev_pm_opp_free_cpufreq_table(info->cpu_dev, &policy->freq_table);
463 
464 	return 0;
465 }
466 
467 static struct cpufreq_driver mtk_cpufreq_driver = {
468 	.flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK |
469 		 CPUFREQ_HAVE_GOVERNOR_PER_POLICY |
470 		 CPUFREQ_IS_COOLING_DEV,
471 	.verify = cpufreq_generic_frequency_table_verify,
472 	.target_index = mtk_cpufreq_set_target,
473 	.get = cpufreq_generic_get,
474 	.init = mtk_cpufreq_init,
475 	.exit = mtk_cpufreq_exit,
476 	.name = "mtk-cpufreq",
477 	.attr = cpufreq_generic_attr,
478 };
479 
mtk_cpufreq_probe(struct platform_device * pdev)480 static int mtk_cpufreq_probe(struct platform_device *pdev)
481 {
482 	struct mtk_cpu_dvfs_info *info, *tmp;
483 	int cpu, ret;
484 
485 	for_each_possible_cpu(cpu) {
486 		info = mtk_cpu_dvfs_info_lookup(cpu);
487 		if (info)
488 			continue;
489 
490 		info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
491 		if (!info) {
492 			ret = -ENOMEM;
493 			goto release_dvfs_info_list;
494 		}
495 
496 		ret = mtk_cpu_dvfs_info_init(info, cpu);
497 		if (ret) {
498 			dev_err(&pdev->dev,
499 				"failed to initialize dvfs info for cpu%d\n",
500 				cpu);
501 			goto release_dvfs_info_list;
502 		}
503 
504 		list_add(&info->list_head, &dvfs_info_list);
505 	}
506 
507 	ret = cpufreq_register_driver(&mtk_cpufreq_driver);
508 	if (ret) {
509 		dev_err(&pdev->dev, "failed to register mtk cpufreq driver\n");
510 		goto release_dvfs_info_list;
511 	}
512 
513 	return 0;
514 
515 release_dvfs_info_list:
516 	list_for_each_entry_safe(info, tmp, &dvfs_info_list, list_head) {
517 		mtk_cpu_dvfs_info_release(info);
518 		list_del(&info->list_head);
519 	}
520 
521 	return ret;
522 }
523 
524 static struct platform_driver mtk_cpufreq_platdrv = {
525 	.driver = {
526 		.name	= "mtk-cpufreq",
527 	},
528 	.probe		= mtk_cpufreq_probe,
529 };
530 
531 /* List of machines supported by this driver */
532 static const struct of_device_id mtk_cpufreq_machines[] __initconst = {
533 	{ .compatible = "mediatek,mt2701", },
534 	{ .compatible = "mediatek,mt2712", },
535 	{ .compatible = "mediatek,mt7622", },
536 	{ .compatible = "mediatek,mt7623", },
537 	{ .compatible = "mediatek,mt817x", },
538 	{ .compatible = "mediatek,mt8173", },
539 	{ .compatible = "mediatek,mt8176", },
540 	{ .compatible = "mediatek,mt8183", },
541 	{ .compatible = "mediatek,mt8516", },
542 
543 	{ }
544 };
545 MODULE_DEVICE_TABLE(of, mtk_cpufreq_machines);
546 
mtk_cpufreq_driver_init(void)547 static int __init mtk_cpufreq_driver_init(void)
548 {
549 	struct device_node *np;
550 	const struct of_device_id *match;
551 	int err;
552 
553 	np = of_find_node_by_path("/");
554 	if (!np)
555 		return -ENODEV;
556 
557 	match = of_match_node(mtk_cpufreq_machines, np);
558 	of_node_put(np);
559 	if (!match) {
560 		pr_debug("Machine is not compatible with mtk-cpufreq\n");
561 		return -ENODEV;
562 	}
563 
564 	err = platform_driver_register(&mtk_cpufreq_platdrv);
565 	if (err)
566 		return err;
567 
568 	/*
569 	 * Since there's no place to hold device registration code and no
570 	 * device tree based way to match cpufreq driver yet, both the driver
571 	 * and the device registration codes are put here to handle defer
572 	 * probing.
573 	 */
574 	cpufreq_pdev = platform_device_register_simple("mtk-cpufreq", -1, NULL, 0);
575 	if (IS_ERR(cpufreq_pdev)) {
576 		pr_err("failed to register mtk-cpufreq platform device\n");
577 		platform_driver_unregister(&mtk_cpufreq_platdrv);
578 		return PTR_ERR(cpufreq_pdev);
579 	}
580 
581 	return 0;
582 }
module_init(mtk_cpufreq_driver_init)583 module_init(mtk_cpufreq_driver_init)
584 
585 static void __exit mtk_cpufreq_driver_exit(void)
586 {
587 	platform_device_unregister(cpufreq_pdev);
588 	platform_driver_unregister(&mtk_cpufreq_platdrv);
589 }
590 module_exit(mtk_cpufreq_driver_exit)
591 
592 MODULE_DESCRIPTION("MediaTek CPUFreq driver");
593 MODULE_AUTHOR("Pi-Cheng Chen <pi-cheng.chen@linaro.org>");
594 MODULE_LICENSE("GPL v2");
595