1 /*
2 * Rockchip CPUFreq Driver
3 *
4 * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
11 * kind, whether express or implied; without even the implied warranty
12 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16 #include <linux/clk.h>
17 #include <linux/cpu.h>
18 #include <linux/cpufreq.h>
19 #include <linux/err.h>
20 #include <linux/init.h>
21 #include <linux/kernel.h>
22 #include <linux/mfd/syscon.h>
23 #include <linux/module.h>
24 #include <linux/nvmem-consumer.h>
25 #include <linux/of.h>
26 #include <linux/of_address.h>
27 #include <linux/platform_device.h>
28 #include <linux/pm_opp.h>
29 #include <linux/slab.h>
30 #include <linux/regmap.h>
31 #include <linux/regulator/consumer.h>
32 #include <linux/rockchip/cpu.h>
33 #include <soc/rockchip/rockchip_opp_select.h>
34 #include <soc/rockchip/rockchip_system_monitor.h>
35
36 #include "cpufreq-dt.h"
37 #include "rockchip-cpufreq.h"
38
39 struct cluster_info {
40 struct list_head list_head;
41 struct monitor_dev_info *mdev_info;
42 struct rockchip_opp_info opp_info;
43 cpumask_t cpus;
44 int scale;
45 };
46 static LIST_HEAD(cluster_info_list);
47
px30_get_soc_info(struct device *dev, struct device_node *np, int *bin, int *process)48 static int px30_get_soc_info(struct device *dev, struct device_node *np, int *bin, int *process)
49 {
50 int ret = 0;
51 u8 value = 0;
52
53 if (!bin) {
54 return 0;
55 }
56
57 if (of_property_match_string(np, "nvmem-cell-names", "performance") >= 0) {
58 ret = rockchip_nvmem_cell_read_u8(np, "performance", &value);
59 if (ret) {
60 dev_err(dev, "Failed to get soc performance value\n");
61 return ret;
62 }
63 *bin = value;
64 }
65 if (*bin >= ROCKCHIP_SOC_INFO_ZERO) {
66 dev_info(dev, "bin=%d\n", *bin);
67 }
68
69 return ret;
70 }
71
rk3288_get_soc_info(struct device *dev, struct device_node *np, int *bin, int *process)72 static int rk3288_get_soc_info(struct device *dev, struct device_node *np, int *bin, int *process)
73 {
74 int ret = 0;
75 u8 value = 0;
76 char *name;
77
78 if (!bin) {
79 goto next;
80 }
81 if (of_property_match_string(np, "nvmem-cell-names", "special") >= 0) {
82 ret = rockchip_nvmem_cell_read_u8(np, "special", &value);
83 if (ret) {
84 dev_err(dev, "Failed to get soc special value\n");
85 goto out;
86 }
87 if (value == 0xc) {
88 *bin = ROCKCHIP_SOC_INFO_ZERO;
89 } else {
90 *bin = ROCKCHIP_SOC_INFO_ONE;
91 }
92 }
93
94 if (soc_is_rk3288w()) {
95 name = "performance-w";
96 } else {
97 name = "performance";
98 }
99
100 if (of_property_match_string(np, "nvmem-cell-names", name) >= 0) {
101 ret = rockchip_nvmem_cell_read_u8(np, name, &value);
102 if (ret) {
103 dev_err(dev, "Failed to get soc performance value\n");
104 goto out;
105 }
106 if (value & 0x2) {
107 *bin = ROCKCHIP_SOC_INFO_THREE;
108 } else if (value & 0x01) {
109 *bin = ROCKCHIP_SOC_INFO_TWO;
110 }
111 }
112 if (*bin >= ROCKCHIP_SOC_INFO_ZERO) {
113 dev_info(dev, "bin=%d\n", *bin);
114 }
115
116 next:
117 if (!process) {
118 goto out;
119 }
120 if (of_property_match_string(np, "nvmem-cell-names", "process") >= 0) {
121 ret = rockchip_nvmem_cell_read_u8(np, "process", &value);
122 if (ret) {
123 dev_err(dev, "Failed to get soc process version\n");
124 goto out;
125 }
126 if (soc_is_rk3288() && (value == 0 || value == 1)) {
127 *process = 0;
128 }
129 }
130 if (*process >= 0) {
131 dev_info(dev, "process=%d\n", *process);
132 }
133
134 out:
135 return ret;
136 }
137
rk3399_get_soc_info(struct device *dev, struct device_node *np, int *bin, int *process)138 static int rk3399_get_soc_info(struct device *dev, struct device_node *np, int *bin, int *process)
139 {
140 int ret = 0;
141 u8 value = 0;
142
143 if (!bin) {
144 return 0;
145 }
146
147 if (of_property_match_string(np, "nvmem-cell-names", "specification_serial_number") >= 0) {
148 ret = rockchip_nvmem_cell_read_u8(np, "specification_serial_number", &value);
149 if (ret) {
150 dev_err(dev, "Failed to get specification_serial_number\n");
151 goto out;
152 }
153
154 if (value == 0xb) {
155 *bin = ROCKCHIP_SOC_INFO_ZERO;
156 } else if (value == 0x1) {
157 if (of_property_match_string(np, "nvmem-cell-names", "customer_demand") >= 0) {
158 ret = rockchip_nvmem_cell_read_u8(np, "customer_demand", &value);
159 if (ret) {
160 dev_err(dev, "Failed to get customer_demand\n");
161 goto out;
162 }
163 if (value == 0x0) {
164 *bin = ROCKCHIP_SOC_INFO_ZERO;
165 } else {
166 *bin = ROCKCHIP_SOC_INFO_ONE;
167 }
168 }
169 } else if (value == 0x10) {
170 *bin = ROCKCHIP_SOC_INFO_ONE;
171 }
172 }
173
174 out:
175 if (*bin >= ROCKCHIP_SOC_INFO_ZERO) {
176 dev_info(dev, "bin=%d\n", *bin);
177 }
178
179 return ret;
180 }
181
rk3588_cpu_set_read_margin(struct device *dev, struct rockchip_opp_info *opp_info, unsigned long volt)182 static int rk3588_cpu_set_read_margin(struct device *dev, struct rockchip_opp_info *opp_info, unsigned long volt)
183 {
184 bool is_found = false;
185 u32 rm;
186 int i;
187
188 if (!opp_info->grf || !opp_info->volt_rm_tbl) {
189 return 0;
190 }
191
192 for (i = 0; opp_info->volt_rm_tbl[i].rm != VOLT_RM_TABLE_END; i++) {
193 if (volt >= opp_info->volt_rm_tbl[i].volt) {
194 rm = opp_info->volt_rm_tbl[i].rm;
195 is_found = true;
196 break;
197 }
198 }
199
200 if (!is_found) {
201 return 0;
202 }
203 if (rm == opp_info->current_rm) {
204 return 0;
205 }
206
207 dev_dbg(dev, "set rm to %d\n", rm);
208 regmap_write(opp_info->grf, 0x20, 0x001c0000 | (rm << 0x2));
209 regmap_write(opp_info->grf, 0x28, 0x003c0000 | (rm << 0x2));
210 regmap_write(opp_info->grf, 0x2c, 0x003c0000 | (rm << 0x2));
211 regmap_write(opp_info->grf, 0x30, 0x00200020);
212 udelay(1);
213 regmap_write(opp_info->grf, 0x30, 0x00200000);
214
215 opp_info->current_rm = rm;
216
217 return 0;
218 }
219
rv1126_get_soc_info(struct device *dev, struct device_node *np, int *bin, int *process)220 static int rv1126_get_soc_info(struct device *dev, struct device_node *np, int *bin, int *process)
221 {
222 int ret = 0;
223 u8 value = 0;
224
225 if (of_property_match_string(np, "nvmem-cell-names", "performance") >= 0) {
226 ret = rockchip_nvmem_cell_read_u8(np, "performance", &value);
227 if (ret) {
228 dev_err(dev, "Failed to get soc performance value\n");
229 return ret;
230 }
231 if (value == 0x1) {
232 *bin = ROCKCHIP_SOC_INFO_ONE;
233 } else {
234 *bin = ROCKCHIP_SOC_INFO_ZERO;
235 }
236 }
237 if (*bin >= ROCKCHIP_SOC_INFO_ZERO) {
238 dev_info(dev, "bin=%d\n", *bin);
239 }
240
241 return ret;
242 }
243
244 static const struct rockchip_opp_data px30_cpu_opp_data = {
245 .get_soc_info = px30_get_soc_info,
246 };
247
248 static const struct rockchip_opp_data rk3288_cpu_opp_data = {
249 .get_soc_info = rk3288_get_soc_info,
250 };
251
252 static const struct rockchip_opp_data rk3399_cpu_opp_data = {
253 .get_soc_info = rk3399_get_soc_info,
254 };
255
256 static const struct rockchip_opp_data rk3588_cpu_opp_data = {
257 .set_read_margin = rk3588_cpu_set_read_margin,
258 };
259
260 static const struct rockchip_opp_data rv1126_cpu_opp_data = {
261 .get_soc_info = rv1126_get_soc_info,
262 };
263
264 static const struct of_device_id rockchip_cpufreq_of_match[] = {
265 {
266 .compatible = "rockchip,px30",
267 .data = (void *)&px30_cpu_opp_data,
268 },
269 {
270 .compatible = "rockchip,rk3288",
271 .data = (void *)&rk3288_cpu_opp_data,
272 },
273 {
274 .compatible = "rockchip,rk3288w",
275 .data = (void *)&rk3288_cpu_opp_data,
276 },
277 {
278 .compatible = "rockchip,rk3326",
279 .data = (void *)&px30_cpu_opp_data,
280 },
281 {
282 .compatible = "rockchip,rk3399",
283 .data = (void *)&rk3399_cpu_opp_data,
284 },
285 {
286 .compatible = "rockchip,rk3588",
287 .data = (void *)&rk3588_cpu_opp_data,
288 },
289 {
290 .compatible = "rockchip,rv1109",
291 .data = (void *)&rv1126_cpu_opp_data,
292 },
293 {
294 .compatible = "rockchip,rv1126",
295 .data = (void *)&rv1126_cpu_opp_data,
296 },
297 {},
298 };
299
rockchip_cluster_info_lookup(int cpu)300 static struct cluster_info *rockchip_cluster_info_lookup(int cpu)
301 {
302 struct cluster_info *cluster;
303
304 list_for_each_entry(cluster, &cluster_info_list, list_head)
305 {
306 if (cpumask_test_cpu(cpu, &cluster->cpus)) {
307 return cluster;
308 }
309 }
310
311 return NULL;
312 }
313
rockchip_cpufreq_set_volt(struct device *dev, struct regulator *reg, struct dev_pm_opp_supply *supply, char *reg_name)314 static int rockchip_cpufreq_set_volt(struct device *dev, struct regulator *reg, struct dev_pm_opp_supply *supply,
315 char *reg_name)
316 {
317 int ret;
318
319 dev_dbg(dev, "%s: %s voltages (uV): %lu %lu %lu\n", __func__, reg_name, supply->u_volt_min, supply->u_volt,
320 supply->u_volt_max);
321
322 ret = regulator_set_voltage_triplet(reg, supply->u_volt_min, supply->u_volt, supply->u_volt_max);
323 if (ret) {
324 dev_err(dev, "%s: failed to set voltage (%lu %lu %lu uV): %d\n", __func__, supply->u_volt_min, supply->u_volt,
325 supply->u_volt_max, ret);
326 }
327
328 return ret;
329 }
330
cpu_opp_helper(struct dev_pm_set_opp_data *data)331 static int cpu_opp_helper(struct dev_pm_set_opp_data *data)
332 {
333 struct dev_pm_opp_supply *old_supply_vdd = &data->old_opp.supplies[0];
334 struct dev_pm_opp_supply *old_supply_mem = &data->old_opp.supplies[1];
335 struct dev_pm_opp_supply *new_supply_vdd = &data->new_opp.supplies[0];
336 struct dev_pm_opp_supply *new_supply_mem = &data->new_opp.supplies[1];
337 struct regulator *vdd_reg = data->regulators[0];
338 struct regulator *mem_reg = data->regulators[1];
339 struct device *dev = data->dev;
340 struct clk *clk = data->clk;
341 struct cluster_info *cluster;
342 struct rockchip_opp_info *opp_info;
343 unsigned long old_freq = data->old_opp.rate;
344 unsigned long new_freq = data->new_opp.rate;
345 int ret = 0;
346
347 cluster = rockchip_cluster_info_lookup(dev->id);
348 if (!cluster) {
349 return -EINVAL;
350 }
351 opp_info = &cluster->opp_info;
352
353 /* Scaling up? Scale voltage before frequency */
354 if (new_freq >= old_freq) {
355 ret = rockchip_cpufreq_set_volt(dev, mem_reg, new_supply_mem, "mem");
356 if (ret) {
357 goto restore_voltage;
358 }
359 ret = rockchip_cpufreq_set_volt(dev, vdd_reg, new_supply_vdd, "vdd");
360 if (ret) {
361 goto restore_voltage;
362 }
363 if (opp_info->data->set_read_margin) {
364 opp_info->data->set_read_margin(dev, opp_info, new_supply_vdd->u_volt);
365 }
366 }
367
368 /* Change frequency */
369 dev_dbg(dev, "%s: switching OPP: %lu Hz --> %lu Hz\n", __func__, old_freq, new_freq);
370 ret = clk_set_rate(clk, new_freq);
371 if (ret) {
372 dev_err(dev, "%s: failed to set clk rate: %d\n", __func__, ret);
373 goto restore_rm;
374 }
375
376 /* Scaling down? Scale voltage after frequency */
377 if (new_freq < old_freq) {
378 if (opp_info->data->set_read_margin) {
379 opp_info->data->set_read_margin(dev, opp_info, new_supply_vdd->u_volt);
380 }
381 ret = rockchip_cpufreq_set_volt(dev, vdd_reg, new_supply_vdd, "vdd");
382 if (ret) {
383 goto restore_freq;
384 }
385 ret = rockchip_cpufreq_set_volt(dev, mem_reg, new_supply_mem, "mem");
386 if (ret) {
387 goto restore_freq;
388 }
389 }
390
391 return 0;
392
393 restore_freq:
394 if (clk_set_rate(clk, old_freq)) {
395 dev_err(dev, "%s: failed to restore old-freq (%lu Hz)\n", __func__, old_freq);
396 }
397 restore_rm:
398 if (opp_info->data->set_read_margin) {
399 opp_info->data->set_read_margin(dev, opp_info, old_supply_vdd->u_volt);
400 }
401 restore_voltage:
402 rockchip_cpufreq_set_volt(dev, mem_reg, old_supply_mem, "mem");
403 rockchip_cpufreq_set_volt(dev, vdd_reg, old_supply_vdd, "vdd");
404
405 return ret;
406 }
407
rockchip_cpufreq_cluster_init(int cpu, struct cluster_info *cluster)408 static int rockchip_cpufreq_cluster_init(int cpu, struct cluster_info *cluster)
409 {
410 struct rockchip_opp_info *opp_info = &cluster->opp_info;
411 struct opp_table *pname_table = NULL;
412 struct opp_table *reg_table = NULL;
413 struct opp_table *opp_table;
414 struct device_node *np;
415 struct device *dev;
416 const char *const reg_names[] = {"cpu", "mem"};
417 char *reg_name = NULL;
418 int bin = -EINVAL;
419 int process = -EINVAL;
420 int volt_sel = -EINVAL;
421 int ret = 0;
422
423 dev = get_cpu_device(cpu);
424 if (!dev) {
425 return -ENODEV;
426 }
427
428 if (of_find_property(dev->of_node, "cpu-supply", NULL)) {
429 reg_name = "cpu";
430 } else if (of_find_property(dev->of_node, "cpu0-supply", NULL)) {
431 reg_name = "cpu0";
432 } else {
433 return -ENOENT;
434 }
435
436 np = of_parse_phandle(dev->of_node, "operating-points-v2", 0);
437 if (!np) {
438 dev_warn(dev, "OPP-v2 not supported\n");
439 return -ENOENT;
440 }
441
442 ret = dev_pm_opp_of_get_sharing_cpus(dev, &cluster->cpus);
443 if (ret) {
444 dev_err(dev, "Failed to get sharing cpus\n");
445 goto np_err;
446 }
447
448 rockchip_get_opp_data(rockchip_cpufreq_of_match, opp_info);
449 if (opp_info->data && opp_info->data->set_read_margin) {
450 opp_info->current_rm = UINT_MAX;
451 opp_info->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
452 if (IS_ERR(opp_info->grf)) {
453 opp_info->grf = NULL;
454 }
455 rockchip_get_volt_rm_table(dev, np, "volt-mem-read-margin", &opp_info->volt_rm_tbl);
456 }
457 if (opp_info->data && opp_info->data->get_soc_info) {
458 opp_info->data->get_soc_info(dev, np, &bin, &process);
459 }
460 rockchip_get_scale_volt_sel(dev, "cpu_leakage", reg_name, bin, process, &cluster->scale, &volt_sel);
461 pname_table = rockchip_set_opp_prop_name(dev, process, volt_sel);
462 if (IS_ERR(pname_table)) {
463 ret = PTR_ERR(pname_table);
464 goto np_err;
465 }
466
467 if (of_find_property(dev->of_node, "cpu-supply", NULL) && of_find_property(dev->of_node, "mem-supply", NULL)) {
468 reg_table = dev_pm_opp_set_regulators(dev, reg_names, ARRAY_SIZE(reg_names));
469 if (IS_ERR(reg_table)) {
470 ret = PTR_ERR(reg_table);
471 goto pname_opp_table;
472 }
473 opp_table = dev_pm_opp_register_set_opp_helper(dev, cpu_opp_helper);
474 if (IS_ERR(opp_table)) {
475 ret = PTR_ERR(opp_table);
476 goto reg_opp_table;
477 }
478 }
479
480 of_node_put(np);
481
482 return 0;
483
484 reg_opp_table:
485 if (reg_table) {
486 dev_pm_opp_put_regulators(reg_table);
487 }
488 pname_opp_table:
489 if (pname_table) {
490 dev_pm_opp_put_prop_name(pname_table);
491 }
492 np_err:
493 of_node_put(np);
494
495 return ret;
496 }
497
rockchip_cpufreq_adjust_power_scale(struct device *dev)498 int rockchip_cpufreq_adjust_power_scale(struct device *dev)
499 {
500 struct cluster_info *cluster;
501
502 cluster = rockchip_cluster_info_lookup(dev->id);
503 if (!cluster) {
504 return -EINVAL;
505 }
506 rockchip_adjust_power_scale(dev, cluster->scale);
507
508 return 0;
509 }
510 EXPORT_SYMBOL_GPL(rockchip_cpufreq_adjust_power_scale);
511
rockchip_cpufreq_opp_set_rate(struct device *dev, unsigned long target_freq)512 int rockchip_cpufreq_opp_set_rate(struct device *dev, unsigned long target_freq)
513 {
514 struct cluster_info *cluster;
515 int ret = 0;
516
517 cluster = rockchip_cluster_info_lookup(dev->id);
518 if (!cluster) {
519 return -EINVAL;
520 }
521
522 rockchip_monitor_volt_adjust_lock(cluster->mdev_info);
523 ret = dev_pm_opp_set_rate(dev, target_freq);
524 rockchip_monitor_volt_adjust_unlock(cluster->mdev_info);
525
526 return ret;
527 }
528 EXPORT_SYMBOL_GPL(rockchip_cpufreq_opp_set_rate);
529
rockchip_cpufreq_suspend(struct cpufreq_policy *policy)530 static int rockchip_cpufreq_suspend(struct cpufreq_policy *policy)
531 {
532 int ret = 0;
533
534 ret = cpufreq_generic_suspend(policy);
535 if (!ret) {
536 rockchip_monitor_suspend_low_temp_adjust(policy->cpu);
537 }
538
539 return ret;
540 }
541
rockchip_cpufreq_notifier(struct notifier_block *nb, unsigned long event, void *data)542 static int rockchip_cpufreq_notifier(struct notifier_block *nb, unsigned long event, void *data)
543 {
544 struct device *dev;
545 struct cpufreq_policy *policy = data;
546 struct cluster_info *cluster;
547 struct monitor_dev_profile *mdevp = NULL;
548 struct monitor_dev_info *mdev_info = NULL;
549
550 dev = get_cpu_device(policy->cpu);
551 if (!dev) {
552 return NOTIFY_BAD;
553 }
554
555 cluster = rockchip_cluster_info_lookup(policy->cpu);
556 if (!cluster) {
557 return NOTIFY_BAD;
558 }
559
560 if (event == CPUFREQ_CREATE_POLICY) {
561 mdevp = kzalloc(sizeof(*mdevp), GFP_KERNEL);
562 if (!mdevp) {
563 return NOTIFY_BAD;
564 }
565 mdevp->type = MONITOR_TPYE_CPU;
566 mdevp->low_temp_adjust = rockchip_monitor_cpu_low_temp_adjust;
567 mdevp->high_temp_adjust = rockchip_monitor_cpu_high_temp_adjust;
568 mdevp->update_volt = rockchip_monitor_check_rate_volt;
569 mdevp->data = (void *)policy;
570 mdevp->opp_info = &cluster->opp_info;
571 cpumask_copy(&mdevp->allowed_cpus, policy->cpus);
572 mdev_info = rockchip_system_monitor_register(dev, mdevp);
573 if (IS_ERR(mdev_info)) {
574 kfree(mdevp);
575 dev_err(dev, "failed to register system monitor\n");
576 return NOTIFY_BAD;
577 }
578 mdev_info->devp = mdevp;
579 cluster->mdev_info = mdev_info;
580 } else if (event == CPUFREQ_REMOVE_POLICY) {
581 if (cluster->mdev_info) {
582 kfree(cluster->mdev_info->devp);
583 rockchip_system_monitor_unregister(cluster->mdev_info);
584 cluster->mdev_info = NULL;
585 }
586 }
587
588 return NOTIFY_OK;
589 }
590
591 static struct notifier_block rockchip_cpufreq_notifier_block = {
592 .notifier_call = rockchip_cpufreq_notifier,
593 };
594
rockchip_cpufreq_driver_init(void)595 static int __init rockchip_cpufreq_driver_init(void)
596 {
597 struct cluster_info *cluster, *pos;
598 struct cpufreq_dt_platform_data pdata = {0};
599 int cpu, ret;
600
601 for_each_possible_cpu(cpu)
602 {
603 cluster = rockchip_cluster_info_lookup(cpu);
604 if (cluster) {
605 continue;
606 }
607
608 cluster = kzalloc(sizeof(*cluster), GFP_KERNEL);
609 if (!cluster) {
610 ret = -ENOMEM;
611 goto release_cluster_info;
612 }
613
614 ret = rockchip_cpufreq_cluster_init(cpu, cluster);
615 if (ret) {
616 pr_err("Failed to initialize dvfs info cpu%d\n", cpu);
617 goto release_cluster_info;
618 }
619 list_add(&cluster->list_head, &cluster_info_list);
620 }
621
622 pdata.have_governor_per_policy = true;
623 pdata.suspend = rockchip_cpufreq_suspend;
624
625 ret = cpufreq_register_notifier(&rockchip_cpufreq_notifier_block, CPUFREQ_POLICY_NOTIFIER);
626 if (ret) {
627 pr_err("failed to register cpufreq notifier\n");
628 goto release_cluster_info;
629 }
630
631 return PTR_ERR_OR_ZERO(
632 platform_device_register_data(NULL, "cpufreq-dt", -1, (void *)&pdata, sizeof(struct cpufreq_dt_platform_data)));
633
634 release_cluster_info:
635 list_for_each_entry_safe(cluster, pos, &cluster_info_list, list_head)
636 {
637 list_del(&cluster->list_head);
638 kfree(cluster);
639 }
640 return ret;
641 }
642 module_init(rockchip_cpufreq_driver_init);
643
644 MODULE_AUTHOR("Finley Xiao <finley.xiao@rock-chips.com>");
645 MODULE_DESCRIPTION("Rockchip cpufreq driver");
646 MODULE_LICENSE("GPL v2");
647