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