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