xref: /OK3568_Linux_fs/kernel/drivers/soc/rockchip/rockchip_pvtm.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Rockchip PVTM support.
4  *
5  * Copyright (c) 2016 Rockchip Electronics Co. Ltd.
6  * Author: Finley Xiao <finley.xiao@rock-chips.com>
7  */
8 
9 #include <linux/clk.h>
10 #include <linux/delay.h>
11 #include <linux/device.h>
12 #include <linux/debugfs.h>
13 #include <linux/io.h>
14 #include <linux/mfd/syscon.h>
15 #include <linux/module.h>
16 #include <linux/of.h>
17 #include <linux/of_clk.h>
18 #include <linux/of_platform.h>
19 #include <linux/platform_device.h>
20 #include <linux/regmap.h>
21 #include <linux/reset.h>
22 #include <linux/slab.h>
23 #include <linux/soc/rockchip/pvtm.h>
24 #include <linux/thermal.h>
25 
26 #define wr_mask_bit(v, off, mask)	((v) << (off) | (mask) << (16 + off))
27 
28 #define PVTM(_id, _name, _num_rings, _start, _en, _cal, _done, _freq)	\
29 {					\
30 	.id = _id,			\
31 	.name = _name,			\
32 	.num_rings = _num_rings,	\
33 	.bit_start = _start,		\
34 	.bit_en = _en,			\
35 	.reg_cal = _cal,		\
36 	.bit_freq_done = _done,		\
37 	.reg_freq = _freq,		\
38 }
39 
40 struct rockchip_pvtm;
41 
42 struct rockchip_pvtm_ops {
43 	u32 (*get_value)(struct rockchip_pvtm *pvtm, unsigned int ring_sel,
44 			 unsigned int time_us);
45 	void (*set_ring_sel)(struct rockchip_pvtm *pvtm, unsigned int ring_sel);
46 };
47 
48 struct rockchip_pvtm_info {
49 	u32 reg_cal;
50 	u32 reg_freq;
51 	unsigned char id;
52 	unsigned char *name;
53 	unsigned int num_rings;
54 	unsigned int bit_start;
55 	unsigned int bit_en;
56 	unsigned int bit_freq_done;
57 };
58 
59 struct rockchip_pvtm_data {
60 	u32 con;
61 	u32 sta;
62 	unsigned int num_pvtms;
63 	const struct rockchip_pvtm_info *infos;
64 	const struct rockchip_pvtm_ops ops;
65 };
66 
67 struct rockchip_pvtm {
68 	u32 con;
69 	u32 sta;
70 	struct list_head node;
71 	struct device *dev;
72 	struct regmap *grf;
73 	void __iomem *base;
74 	int num_clks;
75 	struct clk_bulk_data *clks;
76 	struct reset_control *rst;
77 	struct thermal_zone_device *tz;
78 	const struct rockchip_pvtm_info *info;
79 	const struct rockchip_pvtm_ops *ops;
80 	struct dentry *dentry;
81 };
82 
83 static LIST_HEAD(pvtm_list);
84 
85 #ifdef CONFIG_DEBUG_FS
86 static struct dentry *rockchip_pvtm_debugfs_root;
87 
pvtm_value_show(struct seq_file * s,void * data)88 static int pvtm_value_show(struct seq_file *s, void *data)
89 {
90 	struct rockchip_pvtm *pvtm = (struct rockchip_pvtm *)s->private;
91 	u32 value;
92 	int i, ret, cur_temp;
93 
94 	if (!pvtm || !pvtm->ops->get_value) {
95 		seq_puts(s, "unsupported\n");
96 		return 0;
97 	}
98 
99 	if (pvtm->tz && pvtm->tz->ops && pvtm->tz->ops->get_temp) {
100 		ret = pvtm->tz->ops->get_temp(pvtm->tz, &cur_temp);
101 		if (ret)
102 			dev_err(pvtm->dev, "debug failed to get temp\n");
103 		else
104 			seq_printf(s, "temp: %d ", cur_temp);
105 	}
106 	seq_puts(s, "pvtm: ");
107 	for (i = 0; i < pvtm->info->num_rings; i++) {
108 		value = pvtm->ops->get_value(pvtm, i, 1000);
109 		seq_printf(s, "%d ", value);
110 	}
111 	seq_puts(s, "\n");
112 
113 	return 0;
114 }
115 
pvtm_value_open(struct inode * inode,struct file * file)116 static int pvtm_value_open(struct inode *inode, struct file *file)
117 {
118 	return single_open(file, pvtm_value_show, inode->i_private);
119 }
120 
121 static const struct file_operations pvtm_value_fops = {
122 	.open		= pvtm_value_open,
123 	.read		= seq_read,
124 	.llseek		= seq_lseek,
125 	.release	= single_release,
126 };
127 
rockchip_pvtm_debugfs_init(void)128 static int rockchip_pvtm_debugfs_init(void)
129 {
130 	rockchip_pvtm_debugfs_root = debugfs_create_dir("pvtm", NULL);
131 	if (IS_ERR_OR_NULL(rockchip_pvtm_debugfs_root)) {
132 		pr_err("Failed to create pvtm debug directory\n");
133 		rockchip_pvtm_debugfs_root = NULL;
134 		return -ENOMEM;
135 	}
136 
137 	return 0;
138 }
139 
rockchip_pvtm_debugfs_exit(void)140 static void rockchip_pvtm_debugfs_exit(void)
141 {
142 	debugfs_remove_recursive(rockchip_pvtm_debugfs_root);
143 }
144 
rockchip_pvtm_add_debugfs(struct rockchip_pvtm * pvtm)145 static int rockchip_pvtm_add_debugfs(struct rockchip_pvtm *pvtm)
146 {
147 	struct dentry *d;
148 
149 	if (!rockchip_pvtm_debugfs_root)
150 		return 0;
151 
152 	pvtm->dentry = debugfs_create_dir(pvtm->info->name,
153 					  rockchip_pvtm_debugfs_root);
154 	if (!pvtm->dentry) {
155 		dev_err(pvtm->dev, "failed to create pvtm %s debug dir\n",
156 			pvtm->info->name);
157 		return -ENOMEM;
158 	}
159 
160 	d = debugfs_create_file("value", 0444, pvtm->dentry,
161 				(void *)pvtm, &pvtm_value_fops);
162 	if (!d) {
163 		dev_err(pvtm->dev, "failed to pvtm %s value node\n",
164 			pvtm->info->name);
165 		debugfs_remove_recursive(pvtm->dentry);
166 		return -ENOMEM;
167 	}
168 
169 	return 0;
170 }
171 #else
rockchip_pvtm_debugfs_init(void)172 static inline int rockchip_pvtm_debugfs_init(void)
173 {
174 	return 0;
175 }
176 
rockchip_pvtm_debugfs_exit(void)177 static inline void rockchip_pvtm_debugfs_exit(void)
178 {
179 }
180 
rockchip_pvtm_add_debugfs(struct rockchip_pvtm * pvtm)181 static inline int rockchip_pvtm_add_debugfs(struct rockchip_pvtm *pvtm)
182 {
183 	return 0;
184 }
185 #endif
186 
rockchip_pvtm_reset(struct rockchip_pvtm * pvtm)187 static int rockchip_pvtm_reset(struct rockchip_pvtm *pvtm)
188 {
189 	int ret;
190 
191 	ret = reset_control_assert(pvtm->rst);
192 	if (ret) {
193 		dev_err(pvtm->dev, "failed to assert pvtm %d\n", ret);
194 		return ret;
195 	}
196 
197 	udelay(2);
198 
199 	ret = reset_control_deassert(pvtm->rst);
200 	if (ret) {
201 		dev_err(pvtm->dev, "failed to deassert pvtm %d\n", ret);
202 		return ret;
203 	}
204 
205 	return 0;
206 }
207 
rockchip_get_pvtm_value(unsigned int id,unsigned int ring_sel,unsigned int time_us)208 u32 rockchip_get_pvtm_value(unsigned int id, unsigned int ring_sel,
209 			    unsigned int time_us)
210 {
211 	struct rockchip_pvtm *p, *pvtm = NULL;
212 
213 	if (list_empty(&pvtm_list)) {
214 		pr_err("pvtm list NULL\n");
215 		return -EINVAL;
216 	}
217 
218 	list_for_each_entry(p, &pvtm_list, node) {
219 		if (p->info->id == id) {
220 			pvtm = p;
221 			break;
222 		}
223 	}
224 
225 	if (!pvtm) {
226 		pr_err("invalid pvtm id %d\n", id);
227 		return -EINVAL;
228 	}
229 
230 	if (ring_sel >= pvtm->info->num_rings) {
231 		pr_err("invalid pvtm ring %d\n", ring_sel);
232 		return -EINVAL;
233 	}
234 
235 	return pvtm->ops->get_value(pvtm, ring_sel, time_us);
236 }
237 EXPORT_SYMBOL(rockchip_get_pvtm_value);
238 
rockchip_pvtm_delay(unsigned int delay)239 static void rockchip_pvtm_delay(unsigned int delay)
240 {
241 	unsigned int ms = delay / 1000;
242 	unsigned int us = delay % 1000;
243 
244 	if (ms > 0) {
245 		if (ms < 20)
246 			us += ms * 1000;
247 		else
248 			msleep(ms);
249 	}
250 
251 	if (us >= 10)
252 		usleep_range(us, us + 100);
253 	else
254 		udelay(us);
255 }
256 
px30_pvtm_set_ring_sel(struct rockchip_pvtm * pvtm,unsigned int ring_sel)257 static void px30_pvtm_set_ring_sel(struct rockchip_pvtm *pvtm,
258 				   unsigned int ring_sel)
259 {
260 	unsigned int id = pvtm->info->id;
261 
262 	regmap_write(pvtm->grf, pvtm->con,
263 		     wr_mask_bit(ring_sel, (id * 0x4 + 0x2), 0x3));
264 }
265 
rk1808_pvtm_set_ring_sel(struct rockchip_pvtm * pvtm,unsigned int ring_sel)266 static void rk1808_pvtm_set_ring_sel(struct rockchip_pvtm *pvtm,
267 				     unsigned int ring_sel)
268 {
269 	regmap_write(pvtm->grf, pvtm->con,
270 		     wr_mask_bit(ring_sel, 0x2, 0x7));
271 }
272 
rk3399_pvtm_set_ring_sel(struct rockchip_pvtm * pvtm,unsigned int ring_sel)273 static void rk3399_pvtm_set_ring_sel(struct rockchip_pvtm *pvtm,
274 				     unsigned int ring_sel)
275 {
276 	unsigned int id = pvtm->info->id;
277 
278 	if (id == 1) {
279 		regmap_write(pvtm->grf, pvtm->con + 0x14,
280 			     wr_mask_bit(ring_sel >> 0x3, 0, 0x1));
281 		ring_sel &= 0x3;
282 	}
283 	if (id != 4)
284 		regmap_write(pvtm->grf, pvtm->con,
285 			     wr_mask_bit(ring_sel, (id * 0x4 + 0x2), 0x3));
286 }
287 
rockchip_pvtm_get_value(struct rockchip_pvtm * pvtm,unsigned int ring_sel,unsigned int time_us)288 static u32 rockchip_pvtm_get_value(struct rockchip_pvtm *pvtm,
289 				   unsigned int ring_sel,
290 				   unsigned int time_us)
291 {
292 	const struct rockchip_pvtm_info *info = pvtm->info;
293 	unsigned int clk_cnt, check_cnt = 100;
294 	u32 sta, val = 0;
295 	int ret;
296 
297 	ret = clk_bulk_prepare_enable(pvtm->num_clks, pvtm->clks);
298 	if (ret < 0) {
299 		dev_err(pvtm->dev, "failed to prepare/enable pvtm clks\n");
300 		return 0;
301 	}
302 	ret = rockchip_pvtm_reset(pvtm);
303 	if (ret) {
304 		dev_err(pvtm->dev, "failed to reset pvtm\n");
305 		goto disable_clks;
306 	}
307 
308 	/* if last status is enabled, stop calculating cycles first*/
309 	regmap_read(pvtm->grf, pvtm->con, &sta);
310 	if (sta & BIT(info->bit_en))
311 		regmap_write(pvtm->grf, pvtm->con,
312 			     wr_mask_bit(0, info->bit_start, 0x1));
313 
314 	regmap_write(pvtm->grf, pvtm->con,
315 		     wr_mask_bit(0x1, info->bit_en, 0x1));
316 
317 	if (pvtm->ops->set_ring_sel)
318 		pvtm->ops->set_ring_sel(pvtm, ring_sel);
319 
320 	/* clk = 24 Mhz, T = 1 / 24 us */
321 	clk_cnt = time_us * 24;
322 	regmap_write(pvtm->grf, pvtm->con + info->reg_cal, clk_cnt);
323 
324 	regmap_write(pvtm->grf, pvtm->con,
325 		     wr_mask_bit(0x1, info->bit_start, 0x1));
326 
327 	rockchip_pvtm_delay(time_us);
328 
329 	while (check_cnt) {
330 		regmap_read(pvtm->grf, pvtm->sta, &sta);
331 		if (sta & BIT(info->bit_freq_done))
332 			break;
333 		udelay(4);
334 		check_cnt--;
335 	}
336 
337 	if (check_cnt) {
338 		regmap_read(pvtm->grf, pvtm->sta + info->reg_freq, &val);
339 	} else {
340 		dev_err(pvtm->dev, "wait pvtm_done timeout!\n");
341 		val = 0;
342 	}
343 
344 	regmap_write(pvtm->grf, pvtm->con,
345 		     wr_mask_bit(0, info->bit_start, 0x1));
346 
347 	regmap_write(pvtm->grf, pvtm->con,
348 		     wr_mask_bit(0, info->bit_en, 0x1));
349 
350 disable_clks:
351 	clk_bulk_disable_unprepare(pvtm->num_clks, pvtm->clks);
352 
353 	return val;
354 }
355 
rv1106_core_pvtm_set_ring_sel(struct rockchip_pvtm * pvtm,unsigned int ring_sel)356 static void rv1106_core_pvtm_set_ring_sel(struct rockchip_pvtm *pvtm,
357 					  unsigned int ring_sel)
358 {
359 	writel_relaxed(wr_mask_bit(ring_sel + 4, 0x2, 0x7), pvtm->base + pvtm->con);
360 }
361 
rv1126_pvtm_set_ring_sel(struct rockchip_pvtm * pvtm,unsigned int ring_sel)362 static void rv1126_pvtm_set_ring_sel(struct rockchip_pvtm *pvtm,
363 				     unsigned int ring_sel)
364 {
365 	writel_relaxed(wr_mask_bit(ring_sel, 0x2, 0x7), pvtm->base + pvtm->con);
366 }
367 
rv1126_pvtm_get_value(struct rockchip_pvtm * pvtm,unsigned int ring_sel,unsigned int time_us)368 static u32 rv1126_pvtm_get_value(struct rockchip_pvtm *pvtm,
369 				 unsigned int ring_sel,
370 				 unsigned int time_us)
371 {
372 	const struct rockchip_pvtm_info *info = pvtm->info;
373 	unsigned int clk_cnt, check_cnt = 100;
374 	u32 sta, val = 0;
375 	int ret;
376 
377 	ret = clk_bulk_prepare_enable(pvtm->num_clks, pvtm->clks);
378 	if (ret < 0) {
379 		dev_err(pvtm->dev, "failed to prepare/enable pvtm clks\n");
380 		return 0;
381 	}
382 	ret = rockchip_pvtm_reset(pvtm);
383 	if (ret) {
384 		dev_err(pvtm->dev, "failed to reset pvtm\n");
385 		goto disable_clks;
386 	}
387 
388 	/* if last status is enabled, stop calculating cycles first*/
389 	sta = readl_relaxed(pvtm->base + pvtm->con);
390 	if (sta & BIT(info->bit_en))
391 		writel_relaxed(wr_mask_bit(0, info->bit_start, 0x1),
392 			       pvtm->base + pvtm->con);
393 
394 	writel_relaxed(wr_mask_bit(0x1, info->bit_en, 0x1),
395 		       pvtm->base + pvtm->con);
396 
397 	if (pvtm->ops->set_ring_sel)
398 		pvtm->ops->set_ring_sel(pvtm, ring_sel);
399 
400 	/* clk = 24 Mhz, T = 1 / 24 us */
401 	clk_cnt = time_us * 24;
402 	writel_relaxed(clk_cnt, pvtm->base + pvtm->con + info->reg_cal);
403 
404 	writel_relaxed(wr_mask_bit(0x1, info->bit_start, 0x1),
405 		       pvtm->base + pvtm->con);
406 
407 	rockchip_pvtm_delay(time_us);
408 
409 	while (check_cnt) {
410 		sta = readl_relaxed(pvtm->base + pvtm->sta);
411 		if (sta & BIT(info->bit_freq_done))
412 			break;
413 		udelay(4);
414 		check_cnt--;
415 	}
416 
417 	if (check_cnt) {
418 		val = readl_relaxed(pvtm->base + pvtm->sta + info->reg_freq);
419 	} else {
420 		dev_err(pvtm->dev, "wait pvtm_done timeout!\n");
421 		val = 0;
422 	}
423 
424 	writel_relaxed(wr_mask_bit(0, info->bit_start, 0x1),
425 		       pvtm->base + pvtm->con);
426 	writel_relaxed(wr_mask_bit(0, info->bit_en, 0x1),
427 		       pvtm->base + pvtm->con);
428 
429 disable_clks:
430 	clk_bulk_disable_unprepare(pvtm->num_clks, pvtm->clks);
431 
432 	return val;
433 }
434 
435 static const struct rockchip_pvtm_info px30_pvtm_infos[] = {
436 	PVTM(0, "core", 3, 0, 1, 0x4, 0, 0x4),
437 };
438 
439 static const struct rockchip_pvtm_data px30_pvtm = {
440 	.con = 0x80,
441 	.sta = 0x88,
442 	.num_pvtms = ARRAY_SIZE(px30_pvtm_infos),
443 	.infos = px30_pvtm_infos,
444 	.ops = {
445 		.get_value = rockchip_pvtm_get_value,
446 		.set_ring_sel = px30_pvtm_set_ring_sel,
447 	},
448 };
449 
450 static const struct rockchip_pvtm_info px30_pmupvtm_infos[] = {
451 	PVTM(1, "pmu", 1, 0, 1, 0x4, 0, 0x4),
452 };
453 
454 static const struct rockchip_pvtm_data px30_pmupvtm = {
455 	.con = 0x180,
456 	.sta = 0x190,
457 	.num_pvtms = ARRAY_SIZE(px30_pmupvtm_infos),
458 	.infos = px30_pmupvtm_infos,
459 	.ops =  {
460 		.get_value = rockchip_pvtm_get_value,
461 	},
462 };
463 
464 static const struct rockchip_pvtm_info rk1808_pvtm_infos[] = {
465 	PVTM(0, "core", 5, 0, 1, 0x4, 0, 0x4),
466 };
467 
468 static const struct rockchip_pvtm_data rk1808_pvtm = {
469 	.con = 0x80,
470 	.sta = 0x88,
471 	.num_pvtms = ARRAY_SIZE(rk1808_pvtm_infos),
472 	.infos = rk1808_pvtm_infos,
473 	.ops = {
474 		.get_value = rockchip_pvtm_get_value,
475 		.set_ring_sel = rk1808_pvtm_set_ring_sel,
476 	},
477 };
478 
479 static const struct rockchip_pvtm_info rk1808_pmupvtm_infos[] = {
480 	PVTM(1, "pmu", 1, 0, 1, 0x4, 0, 0x4),
481 };
482 
483 static const struct rockchip_pvtm_data rk1808_pmupvtm = {
484 	.con = 0x180,
485 	.sta = 0x190,
486 	.num_pvtms = ARRAY_SIZE(rk1808_pmupvtm_infos),
487 	.infos = rk1808_pmupvtm_infos,
488 	.ops = {
489 		.get_value = rockchip_pvtm_get_value,
490 	},
491 };
492 
493 static const struct rockchip_pvtm_info rk1808_npupvtm_infos[] = {
494 	PVTM(2, "npu", 5, 0, 1, 0x4, 0, 0x4),
495 };
496 
497 static const struct rockchip_pvtm_data rk1808_npupvtm = {
498 	.con = 0x780,
499 	.sta = 0x788,
500 	.num_pvtms = ARRAY_SIZE(rk1808_npupvtm_infos),
501 	.infos = rk1808_npupvtm_infos,
502 	.ops = {
503 		.get_value = rockchip_pvtm_get_value,
504 		.set_ring_sel = rk1808_pvtm_set_ring_sel,
505 	},
506 };
507 
508 static const struct rockchip_pvtm_info rk3288_pvtm_infos[] = {
509 	PVTM(0, "core", 1, 0, 1, 0x4, 1, 0x4),
510 	PVTM(1, "gpu", 1, 8, 9, 0x8, 0, 0x8),
511 };
512 
513 static const struct rockchip_pvtm_data rk3288_pvtm = {
514 	.con = 0x368,
515 	.sta = 0x374,
516 	.num_pvtms = ARRAY_SIZE(rk3288_pvtm_infos),
517 	.infos = rk3288_pvtm_infos,
518 	.ops = {
519 		.get_value = rockchip_pvtm_get_value,
520 	},
521 };
522 
523 static const struct rockchip_pvtm_data rk3308_pmupvtm = {
524 	.con = 0x440,
525 	.sta = 0x448,
526 	.num_pvtms = ARRAY_SIZE(px30_pmupvtm_infos),
527 	.infos = px30_pmupvtm_infos,
528 	.ops = {
529 		.get_value = rockchip_pvtm_get_value,
530 	},
531 };
532 
533 static const struct rockchip_pvtm_info rk3399_pvtm_infos[] = {
534 	PVTM(0, "core_l", 4, 0, 1, 0x4, 0, 0x4),
535 	PVTM(1, "core_b", 6, 4, 5, 0x8, 1, 0x8),
536 	PVTM(2, "ddr", 4, 8, 9, 0xc, 3, 0x10),
537 	PVTM(3, "gpu", 4, 12, 13, 0x10, 2, 0xc),
538 };
539 
540 static const struct rockchip_pvtm_data rk3399_pvtm = {
541 	.con = 0xe600,
542 	.sta = 0xe620,
543 	.num_pvtms = ARRAY_SIZE(rk3399_pvtm_infos),
544 	.infos = rk3399_pvtm_infos,
545 	.ops = {
546 		.get_value = rockchip_pvtm_get_value,
547 		.set_ring_sel = rk3399_pvtm_set_ring_sel,
548 	},
549 };
550 
551 static const struct rockchip_pvtm_info rk3399_pmupvtm_infos[] = {
552 	PVTM(4, "pmu", 1, 0, 1, 0x4, 0, 0x4),
553 };
554 
555 static const struct rockchip_pvtm_data rk3399_pmupvtm = {
556 	.con = 0x240,
557 	.sta = 0x248,
558 	.num_pvtms = ARRAY_SIZE(rk3399_pmupvtm_infos),
559 	.infos = rk3399_pmupvtm_infos,
560 	.ops = {
561 		.get_value = rockchip_pvtm_get_value,
562 	},
563 };
564 
565 static const struct rockchip_pvtm_info rk3568_corepvtm_infos[] = {
566 	PVTM(0, "core", 7, 0, 1, 0x4, 0, 0x4),
567 };
568 
569 static const struct rockchip_pvtm_data rk3568_corepvtm = {
570 	.con = 0x4,
571 	.sta = 0x80,
572 	.num_pvtms = ARRAY_SIZE(rk3568_corepvtm_infos),
573 	.infos = rk3568_corepvtm_infos,
574 	.ops = {
575 		.get_value = rv1126_pvtm_get_value,
576 		.set_ring_sel = rv1126_pvtm_set_ring_sel,
577 	},
578 };
579 
580 static const struct rockchip_pvtm_info rk3568_gpupvtm_infos[] = {
581 	PVTM(1, "gpu", 7, 0, 1, 0x4, 0, 0x4),
582 };
583 
584 static const struct rockchip_pvtm_data rk3568_gpupvtm = {
585 	.con = 0x4,
586 	.sta = 0x80,
587 	.num_pvtms = ARRAY_SIZE(rk3568_gpupvtm_infos),
588 	.infos = rk3568_gpupvtm_infos,
589 	.ops = {
590 		.get_value = rv1126_pvtm_get_value,
591 		.set_ring_sel = rv1126_pvtm_set_ring_sel,
592 	},
593 };
594 
595 static const struct rockchip_pvtm_info rk3568_npupvtm_infos[] = {
596 	PVTM(2, "npu", 7, 0, 1, 0x4, 0, 0x4),
597 };
598 
599 static const struct rockchip_pvtm_data rk3568_npupvtm = {
600 	.con = 0x4,
601 	.sta = 0x80,
602 	.num_pvtms = ARRAY_SIZE(rk3568_npupvtm_infos),
603 	.infos = rk3568_npupvtm_infos,
604 	.ops = {
605 		.get_value = rv1126_pvtm_get_value,
606 		.set_ring_sel = rv1126_pvtm_set_ring_sel,
607 	},
608 };
609 
610 static const struct rockchip_pvtm_info rk3588_bigcore0_pvtm_infos[] = {
611 	PVTM(0, "bigcore0", 7, 0, 1, 0x4, 0, 0x4),
612 };
613 
614 static const struct rockchip_pvtm_data rk3588_bigcore0_pvtm = {
615 	.con = 0x4,
616 	.sta = 0x80,
617 	.num_pvtms = ARRAY_SIZE(rk3588_bigcore0_pvtm_infos),
618 	.infos = rk3588_bigcore0_pvtm_infos,
619 	.ops = {
620 		.get_value = rv1126_pvtm_get_value,
621 		.set_ring_sel = rv1126_pvtm_set_ring_sel,
622 	},
623 };
624 
625 static const struct rockchip_pvtm_info rk3588_bigcore1_pvtm_infos[] = {
626 	PVTM(1, "bigcore1", 7, 0, 1, 0x4, 0, 0x4),
627 };
628 
629 static const struct rockchip_pvtm_data rk3588_bigcore1_pvtm = {
630 	.con = 0x4,
631 	.sta = 0x80,
632 	.num_pvtms = ARRAY_SIZE(rk3588_bigcore1_pvtm_infos),
633 	.infos = rk3588_bigcore1_pvtm_infos,
634 	.ops = {
635 		.get_value = rv1126_pvtm_get_value,
636 		.set_ring_sel = rv1126_pvtm_set_ring_sel,
637 	},
638 };
639 
640 static const struct rockchip_pvtm_info rk3588_litcore_pvtm_infos[] = {
641 	PVTM(2, "litcore", 7, 0, 1, 0x4, 0, 0x4),
642 };
643 
644 static const struct rockchip_pvtm_data rk3588_litcore_pvtm = {
645 	.con = 0x4,
646 	.sta = 0x80,
647 	.num_pvtms = ARRAY_SIZE(rk3588_litcore_pvtm_infos),
648 	.infos = rk3588_litcore_pvtm_infos,
649 	.ops = {
650 		.get_value = rv1126_pvtm_get_value,
651 		.set_ring_sel = rv1126_pvtm_set_ring_sel,
652 	},
653 };
654 
655 static const struct rockchip_pvtm_info rk3588_npu_pvtm_infos[] = {
656 	PVTM(3, "npu", 2, 0, 1, 0x4, 0, 0x4),
657 };
658 
659 static const struct rockchip_pvtm_data rk3588_npu_pvtm = {
660 	.con = 0x4,
661 	.sta = 0x80,
662 	.num_pvtms = ARRAY_SIZE(rk3588_npu_pvtm_infos),
663 	.infos = rk3588_npu_pvtm_infos,
664 	.ops = {
665 		.get_value = rv1126_pvtm_get_value,
666 		.set_ring_sel = rv1126_pvtm_set_ring_sel,
667 	},
668 };
669 
670 static const struct rockchip_pvtm_info rk3588_gpu_pvtm_infos[] = {
671 	PVTM(4, "gpu", 2, 0, 1, 0x4, 0, 0x4),
672 };
673 
674 static const struct rockchip_pvtm_data rk3588_gpu_pvtm = {
675 	.con = 0x4,
676 	.sta = 0x80,
677 	.num_pvtms = ARRAY_SIZE(rk3588_gpu_pvtm_infos),
678 	.infos = rk3588_gpu_pvtm_infos,
679 	.ops = {
680 		.get_value = rv1126_pvtm_get_value,
681 		.set_ring_sel = rv1126_pvtm_set_ring_sel,
682 	},
683 };
684 
685 static const struct rockchip_pvtm_info rk3588_pmu_pvtm_infos[] = {
686 	PVTM(5, "pmu", 1, 0, 1, 0x4, 0, 0x4),
687 };
688 
689 static const struct rockchip_pvtm_data rk3588_pmu_pvtm = {
690 	.con = 0x4,
691 	.sta = 0x80,
692 	.num_pvtms = ARRAY_SIZE(rk3588_pmu_pvtm_infos),
693 	.infos = rk3588_pmu_pvtm_infos,
694 	.ops = {
695 		.get_value = rv1126_pvtm_get_value,
696 	},
697 };
698 
699 static const struct rockchip_pvtm_info rv1106_corepvtm_infos[] = {
700 	PVTM(0, "core", 2, 0, 1, 0x4, 0, 0x4),
701 };
702 
703 static const struct rockchip_pvtm_data rv1106_corepvtm = {
704 	.con = 0x4,
705 	.sta = 0x80,
706 	.num_pvtms = ARRAY_SIZE(rv1106_corepvtm_infos),
707 	.infos = rv1106_corepvtm_infos,
708 	.ops = {
709 		.get_value = rv1126_pvtm_get_value,
710 		.set_ring_sel = rv1106_core_pvtm_set_ring_sel,
711 	},
712 };
713 
714 static const struct rockchip_pvtm_info rv1106_pmupvtm_infos[] = {
715 	PVTM(1, "pmu", 1, 0, 1, 0x4, 0, 0x4),
716 };
717 
718 static const struct rockchip_pvtm_data rv1106_pmupvtm = {
719 	.con = 0x4,
720 	.sta = 0x80,
721 	.num_pvtms = ARRAY_SIZE(rv1106_pmupvtm_infos),
722 	.infos = rv1106_pmupvtm_infos,
723 	.ops = {
724 		.get_value = rv1126_pvtm_get_value,
725 	},
726 };
727 
728 static const struct rockchip_pvtm_info rv1126_cpupvtm_infos[] = {
729 	PVTM(0, "cpu", 7, 0, 1, 0x4, 0, 0x4),
730 };
731 
732 static const struct rockchip_pvtm_data rv1126_cpupvtm = {
733 	.con = 0x4,
734 	.sta = 0x80,
735 	.num_pvtms = ARRAY_SIZE(rv1126_cpupvtm_infos),
736 	.infos = rv1126_cpupvtm_infos,
737 	.ops = {
738 		.get_value = rv1126_pvtm_get_value,
739 		.set_ring_sel = rv1126_pvtm_set_ring_sel,
740 	},
741 };
742 
743 static const struct rockchip_pvtm_info rv1126_npupvtm_infos[] = {
744 	PVTM(1, "npu", 7, 0, 1, 0x4, 0, 0x4),
745 };
746 
747 static const struct rockchip_pvtm_data rv1126_npupvtm = {
748 	.con = 0x4,
749 	.sta = 0x80,
750 	.num_pvtms = ARRAY_SIZE(rv1126_npupvtm_infos),
751 	.infos = rv1126_npupvtm_infos,
752 	.ops = {
753 		.get_value = rv1126_pvtm_get_value,
754 		.set_ring_sel = rv1126_pvtm_set_ring_sel,
755 	},
756 };
757 
758 static const struct rockchip_pvtm_info rv1126_pmupvtm_infos[] = {
759 	PVTM(2, "pmu", 1, 0, 1, 0x4, 0, 0x4),
760 };
761 
762 static const struct rockchip_pvtm_data rv1126_pmupvtm = {
763 	.con = 0x4,
764 	.sta = 0x80,
765 	.num_pvtms = ARRAY_SIZE(rv1126_pmupvtm_infos),
766 	.infos = rv1126_pmupvtm_infos,
767 	.ops = {
768 		.get_value = rv1126_pvtm_get_value,
769 	},
770 };
771 
772 static const struct of_device_id rockchip_pvtm_match[] = {
773 #ifdef CONFIG_CPU_PX30
774 	{
775 		.compatible = "rockchip,px30-pvtm",
776 		.data = (void *)&px30_pvtm,
777 	},
778 	{
779 		.compatible = "rockchip,px30-pmu-pvtm",
780 		.data = (void *)&px30_pmupvtm,
781 	},
782 #endif
783 #ifdef CONFIG_CPU_RK1808
784 	{
785 		.compatible = "rockchip,rk1808-pvtm",
786 		.data = (void *)&rk1808_pvtm,
787 	},
788 	{
789 		.compatible = "rockchip,rk1808-pmu-pvtm",
790 		.data = (void *)&rk1808_pmupvtm,
791 	},
792 	{
793 		.compatible = "rockchip,rk1808-npu-pvtm",
794 		.data = (void *)&rk1808_npupvtm,
795 	},
796 #endif
797 #ifdef CONFIG_CPU_RK3288
798 	{
799 		.compatible = "rockchip,rk3288-pvtm",
800 		.data = (void *)&rk3288_pvtm,
801 	},
802 #endif
803 #ifdef CONFIG_CPU_RK3308
804 	{
805 		.compatible = "rockchip,rk3308-pvtm",
806 		.data = (void *)&px30_pvtm,
807 	},
808 	{
809 		.compatible = "rockchip,rk3308-pmu-pvtm",
810 		.data = (void *)&rk3308_pmupvtm,
811 	},
812 #endif
813 #ifdef CONFIG_CPU_RK3399
814 	{
815 		.compatible = "rockchip,rk3399-pvtm",
816 		.data = (void *)&rk3399_pvtm,
817 	},
818 	{
819 		.compatible = "rockchip,rk3399-pmu-pvtm",
820 		.data = (void *)&rk3399_pmupvtm,
821 	},
822 #endif
823 #ifdef CONFIG_CPU_RK3568
824 	{
825 		.compatible = "rockchip,rK3568-core-pvtm",
826 		.data = (void *)&rk3568_corepvtm,
827 	},
828 	{
829 		.compatible = "rockchip,rk3568-gpu-pvtm",
830 		.data = (void *)&rk3568_gpupvtm,
831 	},
832 	{
833 		.compatible = "rockchip,rk3568-npu-pvtm",
834 		.data = (void *)&rk3568_npupvtm,
835 	},
836 #endif
837 #ifdef CONFIG_CPU_RK3588
838 	{
839 		.compatible = "rockchip,rk3588-bigcore0-pvtm",
840 		.data = (void *)&rk3588_bigcore0_pvtm,
841 	},
842 	{
843 		.compatible = "rockchip,rk3588-bigcore1-pvtm",
844 		.data = (void *)&rk3588_bigcore1_pvtm,
845 	},
846 	{
847 		.compatible = "rockchip,rk3588-litcore-pvtm",
848 		.data = (void *)&rk3588_litcore_pvtm,
849 	},
850 	{
851 		.compatible = "rockchip,rk3588-gpu-pvtm",
852 		.data = (void *)&rk3588_gpu_pvtm,
853 	},
854 	{
855 		.compatible = "rockchip,rk3588-npu-pvtm",
856 		.data = (void *)&rk3588_npu_pvtm,
857 	},
858 	{
859 		.compatible = "rockchip,rk3588-pmu-pvtm",
860 		.data = (void *)&rk3588_pmu_pvtm,
861 	},
862 #endif
863 #ifdef CONFIG_CPU_RV1106
864 	{
865 		.compatible = "rockchip,rv1106-core-pvtm",
866 		.data = (void *)&rv1106_corepvtm,
867 	},
868 	{
869 		.compatible = "rockchip,rv1106-pmu-pvtm",
870 		.data = (void *)&rv1106_pmupvtm,
871 	},
872 #endif
873 #ifdef CONFIG_CPU_RV1126
874 	{
875 		.compatible = "rockchip,rv1126-cpu-pvtm",
876 		.data = (void *)&rv1126_cpupvtm,
877 	},
878 	{
879 		.compatible = "rockchip,rv1126-npu-pvtm",
880 		.data = (void *)&rv1126_npupvtm,
881 	},
882 	{
883 		.compatible = "rockchip,rv1126-pmu-pvtm",
884 		.data = (void *)&rv1126_pmupvtm,
885 	},
886 #endif
887 	{ /* sentinel */ },
888 };
889 MODULE_DEVICE_TABLE(of, rockchip_pvtm_match);
890 
rockchip_pvtm_get_index(const struct rockchip_pvtm_data * data,u32 ch,u32 * index)891 static int rockchip_pvtm_get_index(const struct rockchip_pvtm_data *data,
892 				   u32 ch, u32 *index)
893 {
894 	int i;
895 
896 	for (i = 0; i < data->num_pvtms; i++) {
897 		if (ch == data->infos[i].id) {
898 			*index = i;
899 			return 0;
900 		}
901 	}
902 
903 	return -EINVAL;
904 }
905 
906 static struct rockchip_pvtm *
rockchip_pvtm_init(struct device * dev,struct device_node * node,const struct rockchip_pvtm_data * data,struct regmap * grf,void __iomem * base)907 rockchip_pvtm_init(struct device *dev, struct device_node *node,
908 		   const struct rockchip_pvtm_data *data,
909 		   struct regmap *grf, void __iomem *base)
910 {
911 	struct rockchip_pvtm *pvtm;
912 	const char *tz_name;
913 	u32 id, index;
914 	int i;
915 
916 	if (of_property_read_u32(node, "reg", &id)) {
917 		dev_err(dev, "%s: failed to retrieve pvtm id\n", node->name);
918 		return NULL;
919 	}
920 	if (rockchip_pvtm_get_index(data, id, &index)) {
921 		dev_err(dev, "%s: invalid pvtm id %d\n", node->name, id);
922 		return NULL;
923 	}
924 
925 	pvtm = devm_kzalloc(dev, sizeof(*pvtm), GFP_KERNEL);
926 	if (!pvtm)
927 		return NULL;
928 
929 	pvtm->dev = dev;
930 	pvtm->grf = grf;
931 	pvtm->base = base;
932 	pvtm->con = data->con;
933 	pvtm->sta = data->sta;
934 	pvtm->ops = &data->ops;
935 	pvtm->info = &data->infos[index];
936 
937 	if (!of_property_read_string(node, "thermal-zone", &tz_name)) {
938 		pvtm->tz = thermal_zone_get_zone_by_name(tz_name);
939 		if (IS_ERR(pvtm->tz)) {
940 			dev_err(pvtm->dev, "failed to retrieve pvtm_tz\n");
941 			pvtm->tz = NULL;
942 		}
943 	}
944 
945 	pvtm->num_clks = of_clk_get_parent_count(node);
946 	if (pvtm->num_clks <= 0) {
947 		dev_err(dev, "%s: does not have clocks\n", node->name);
948 		goto clk_num_err;
949 	}
950 	pvtm->clks = devm_kcalloc(dev, pvtm->num_clks, sizeof(*pvtm->clks),
951 				  GFP_KERNEL);
952 	if (!pvtm->clks)
953 		goto clk_num_err;
954 	for (i = 0; i < pvtm->num_clks; i++) {
955 		pvtm->clks[i].clk = of_clk_get(node, i);
956 		if (IS_ERR(pvtm->clks[i].clk)) {
957 			dev_err(dev, "%s: failed to get clk at index %d\n",
958 				node->name, i);
959 			goto clk_err;
960 		}
961 	}
962 
963 	pvtm->rst = devm_reset_control_array_get_optional_exclusive(dev);
964 	if (IS_ERR(pvtm->rst))
965 		dev_dbg(dev, "%s: failed to get reset\n", node->name);
966 
967 	rockchip_pvtm_add_debugfs(pvtm);
968 
969 	return pvtm;
970 
971 clk_err:
972 	while (--i >= 0)
973 		clk_put(pvtm->clks[i].clk);
974 	devm_kfree(dev, pvtm->clks);
975 clk_num_err:
976 	devm_kfree(dev, pvtm);
977 
978 	return NULL;
979 }
980 
rockchip_pvtm_probe(struct platform_device * pdev)981 static int rockchip_pvtm_probe(struct platform_device *pdev)
982 {
983 	struct device *dev = &pdev->dev;
984 	struct device_node *np = pdev->dev.of_node;
985 	struct device_node *node;
986 	const struct of_device_id *match;
987 	struct rockchip_pvtm *pvtm;
988 	struct regmap *grf = NULL;
989 	void __iomem *base = NULL;
990 
991 	match = of_match_device(dev->driver->of_match_table, dev);
992 	if (!match || !match->data) {
993 		dev_err(dev, "missing pvtm data\n");
994 		return -EINVAL;
995 	}
996 
997 	if (dev->parent && dev->parent->of_node) {
998 		grf = syscon_node_to_regmap(dev->parent->of_node);
999 		if (IS_ERR(grf))
1000 			return PTR_ERR(grf);
1001 	} else {
1002 		base = devm_platform_ioremap_resource(pdev, 0);
1003 		if (IS_ERR(base))
1004 			return PTR_ERR(base);
1005 	}
1006 
1007 	for_each_available_child_of_node(np, node) {
1008 		pvtm = rockchip_pvtm_init(dev, node, match->data, grf, base);
1009 		if (!pvtm) {
1010 			dev_err(dev, "failed to handle node %s\n",
1011 				node->full_name);
1012 			continue;
1013 		}
1014 		list_add(&pvtm->node, &pvtm_list);
1015 		dev_info(dev, "%s probed\n", node->full_name);
1016 	}
1017 
1018 	return 0;
1019 }
1020 
1021 static struct platform_driver rockchip_pvtm_driver = {
1022 	.probe = rockchip_pvtm_probe,
1023 	.driver = {
1024 		.name  = "rockchip-pvtm",
1025 		.of_match_table = rockchip_pvtm_match,
1026 	},
1027 };
1028 
rockchip_pvtm_module_init(void)1029 static int __init rockchip_pvtm_module_init(void)
1030 {
1031 	rockchip_pvtm_debugfs_init();
1032 
1033 	return platform_driver_register(&rockchip_pvtm_driver);
1034 }
1035 module_init(rockchip_pvtm_module_init);
1036 
rockchip_pvtm_module_exit(void)1037 static void __exit rockchip_pvtm_module_exit(void)
1038 {
1039 	rockchip_pvtm_debugfs_exit();
1040 	platform_driver_unregister(&rockchip_pvtm_driver);
1041 }
1042 module_exit(rockchip_pvtm_module_exit);
1043 
1044 MODULE_DESCRIPTION("Rockchip PVTM driver");
1045 MODULE_AUTHOR("Finley Xiao <finley.xiao@rock-chips.com>");
1046 MODULE_LICENSE("GPL v2");
1047