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