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
rv1126_pvtm_set_ring_sel(struct rockchip_pvtm * pvtm,unsigned int ring_sel)356 static void rv1126_pvtm_set_ring_sel(struct rockchip_pvtm *pvtm,
357 unsigned int ring_sel)
358 {
359 writel_relaxed(wr_mask_bit(ring_sel, 0x2, 0x7), pvtm->base + pvtm->con);
360 }
361
rv1126_pvtm_get_value(struct rockchip_pvtm * pvtm,unsigned int ring_sel,unsigned int time_us)362 static u32 rv1126_pvtm_get_value(struct rockchip_pvtm *pvtm,
363 unsigned int ring_sel,
364 unsigned int time_us)
365 {
366 const struct rockchip_pvtm_info *info = pvtm->info;
367 unsigned int clk_cnt, check_cnt = 100;
368 u32 sta, val = 0;
369 int ret;
370
371 ret = clk_bulk_prepare_enable(pvtm->num_clks, pvtm->clks);
372 if (ret < 0) {
373 dev_err(pvtm->dev, "failed to prepare/enable pvtm clks\n");
374 return 0;
375 }
376 ret = rockchip_pvtm_reset(pvtm);
377 if (ret) {
378 dev_err(pvtm->dev, "failed to reset pvtm\n");
379 goto disable_clks;
380 }
381
382 /* if last status is enabled, stop calculating cycles first*/
383 sta = readl_relaxed(pvtm->base + pvtm->con);
384 if (sta & BIT(info->bit_en))
385 writel_relaxed(wr_mask_bit(0, info->bit_start, 0x1),
386 pvtm->base + pvtm->con);
387
388 writel_relaxed(wr_mask_bit(0x1, info->bit_en, 0x1),
389 pvtm->base + pvtm->con);
390
391 if (pvtm->ops->set_ring_sel)
392 pvtm->ops->set_ring_sel(pvtm, ring_sel);
393
394 /* clk = 24 Mhz, T = 1 / 24 us */
395 clk_cnt = time_us * 24;
396 writel_relaxed(clk_cnt, pvtm->base + pvtm->con + info->reg_cal);
397
398 writel_relaxed(wr_mask_bit(0x1, info->bit_start, 0x1),
399 pvtm->base + pvtm->con);
400
401 rockchip_pvtm_delay(time_us);
402
403 while (check_cnt) {
404 sta = readl_relaxed(pvtm->base + pvtm->sta);
405 if (sta & BIT(info->bit_freq_done))
406 break;
407 udelay(4);
408 check_cnt--;
409 }
410
411 if (check_cnt) {
412 val = readl_relaxed(pvtm->base + pvtm->sta + info->reg_freq);
413 } else {
414 dev_err(pvtm->dev, "wait pvtm_done timeout!\n");
415 val = 0;
416 }
417
418 writel_relaxed(wr_mask_bit(0, info->bit_start, 0x1),
419 pvtm->base + pvtm->con);
420 writel_relaxed(wr_mask_bit(0, info->bit_en, 0x1),
421 pvtm->base + pvtm->con);
422
423 disable_clks:
424 clk_bulk_disable_unprepare(pvtm->num_clks, pvtm->clks);
425
426 return val;
427 }
428
429 static const struct rockchip_pvtm_info px30_pvtm_infos[] = {
430 PVTM(0, "core", 3, 0, 1, 0x4, 0, 0x4),
431 };
432
433 static const struct rockchip_pvtm_data px30_pvtm = {
434 .con = 0x80,
435 .sta = 0x88,
436 .num_pvtms = ARRAY_SIZE(px30_pvtm_infos),
437 .infos = px30_pvtm_infos,
438 .ops = {
439 .get_value = rockchip_pvtm_get_value,
440 .set_ring_sel = px30_pvtm_set_ring_sel,
441 },
442 };
443
444 static const struct rockchip_pvtm_info px30_pmupvtm_infos[] = {
445 PVTM(1, "pmu", 1, 0, 1, 0x4, 0, 0x4),
446 };
447
448 static const struct rockchip_pvtm_data px30_pmupvtm = {
449 .con = 0x180,
450 .sta = 0x190,
451 .num_pvtms = ARRAY_SIZE(px30_pmupvtm_infos),
452 .infos = px30_pmupvtm_infos,
453 .ops = {
454 .get_value = rockchip_pvtm_get_value,
455 },
456 };
457
458 static const struct rockchip_pvtm_info rk1808_pvtm_infos[] = {
459 PVTM(0, "core", 5, 0, 1, 0x4, 0, 0x4),
460 };
461
462 static const struct rockchip_pvtm_data rk1808_pvtm = {
463 .con = 0x80,
464 .sta = 0x88,
465 .num_pvtms = ARRAY_SIZE(rk1808_pvtm_infos),
466 .infos = rk1808_pvtm_infos,
467 .ops = {
468 .get_value = rockchip_pvtm_get_value,
469 .set_ring_sel = rk1808_pvtm_set_ring_sel,
470 },
471 };
472
473 static const struct rockchip_pvtm_info rk1808_pmupvtm_infos[] = {
474 PVTM(1, "pmu", 1, 0, 1, 0x4, 0, 0x4),
475 };
476
477 static const struct rockchip_pvtm_data rk1808_pmupvtm = {
478 .con = 0x180,
479 .sta = 0x190,
480 .num_pvtms = ARRAY_SIZE(rk1808_pmupvtm_infos),
481 .infos = rk1808_pmupvtm_infos,
482 .ops = {
483 .get_value = rockchip_pvtm_get_value,
484 },
485 };
486
487 static const struct rockchip_pvtm_info rk1808_npupvtm_infos[] = {
488 PVTM(2, "npu", 5, 0, 1, 0x4, 0, 0x4),
489 };
490
491 static const struct rockchip_pvtm_data rk1808_npupvtm = {
492 .con = 0x780,
493 .sta = 0x788,
494 .num_pvtms = ARRAY_SIZE(rk1808_npupvtm_infos),
495 .infos = rk1808_npupvtm_infos,
496 .ops = {
497 .get_value = rockchip_pvtm_get_value,
498 .set_ring_sel = rk1808_pvtm_set_ring_sel,
499 },
500 };
501
502 static const struct rockchip_pvtm_info rk3288_pvtm_infos[] = {
503 PVTM(0, "core", 1, 0, 1, 0x4, 1, 0x4),
504 PVTM(1, "gpu", 1, 8, 9, 0x8, 0, 0x8),
505 };
506
507 static const struct rockchip_pvtm_data rk3288_pvtm = {
508 .con = 0x368,
509 .sta = 0x374,
510 .num_pvtms = ARRAY_SIZE(rk3288_pvtm_infos),
511 .infos = rk3288_pvtm_infos,
512 .ops = {
513 .get_value = rockchip_pvtm_get_value,
514 },
515 };
516
517 static const struct rockchip_pvtm_data rk3308_pmupvtm = {
518 .con = 0x440,
519 .sta = 0x448,
520 .num_pvtms = ARRAY_SIZE(px30_pmupvtm_infos),
521 .infos = px30_pmupvtm_infos,
522 .ops = {
523 .get_value = rockchip_pvtm_get_value,
524 },
525 };
526
527 static const struct rockchip_pvtm_info rk3399_pvtm_infos[] = {
528 PVTM(0, "core_l", 4, 0, 1, 0x4, 0, 0x4),
529 PVTM(1, "core_b", 6, 4, 5, 0x8, 1, 0x8),
530 PVTM(2, "ddr", 4, 8, 9, 0xc, 3, 0x10),
531 PVTM(3, "gpu", 4, 12, 13, 0x10, 2, 0xc),
532 };
533
534 static const struct rockchip_pvtm_data rk3399_pvtm = {
535 .con = 0xe600,
536 .sta = 0xe620,
537 .num_pvtms = ARRAY_SIZE(rk3399_pvtm_infos),
538 .infos = rk3399_pvtm_infos,
539 .ops = {
540 .get_value = rockchip_pvtm_get_value,
541 .set_ring_sel = rk3399_pvtm_set_ring_sel,
542 },
543 };
544
545 static const struct rockchip_pvtm_info rk3399_pmupvtm_infos[] = {
546 PVTM(4, "pmu", 1, 0, 1, 0x4, 0, 0x4),
547 };
548
549 static const struct rockchip_pvtm_data rk3399_pmupvtm = {
550 .con = 0x240,
551 .sta = 0x248,
552 .num_pvtms = ARRAY_SIZE(rk3399_pmupvtm_infos),
553 .infos = rk3399_pmupvtm_infos,
554 .ops = {
555 .get_value = rockchip_pvtm_get_value,
556 },
557 };
558
559 static const struct rockchip_pvtm_info rk3568_corepvtm_infos[] = {
560 PVTM(0, "core", 7, 0, 1, 0x4, 0, 0x4),
561 };
562
563 static const struct rockchip_pvtm_data rk3568_corepvtm = {
564 .con = 0x4,
565 .sta = 0x80,
566 .num_pvtms = ARRAY_SIZE(rk3568_corepvtm_infos),
567 .infos = rk3568_corepvtm_infos,
568 .ops = {
569 .get_value = rv1126_pvtm_get_value,
570 .set_ring_sel = rv1126_pvtm_set_ring_sel,
571 },
572 };
573
574 static const struct rockchip_pvtm_info rk3568_gpupvtm_infos[] = {
575 PVTM(1, "gpu", 7, 0, 1, 0x4, 0, 0x4),
576 };
577
578 static const struct rockchip_pvtm_data rk3568_gpupvtm = {
579 .con = 0x4,
580 .sta = 0x80,
581 .num_pvtms = ARRAY_SIZE(rk3568_gpupvtm_infos),
582 .infos = rk3568_gpupvtm_infos,
583 .ops = {
584 .get_value = rv1126_pvtm_get_value,
585 .set_ring_sel = rv1126_pvtm_set_ring_sel,
586 },
587 };
588
589 static const struct rockchip_pvtm_info rk3568_npupvtm_infos[] = {
590 PVTM(2, "npu", 7, 0, 1, 0x4, 0, 0x4),
591 };
592
593 static const struct rockchip_pvtm_data rk3568_npupvtm = {
594 .con = 0x4,
595 .sta = 0x80,
596 .num_pvtms = ARRAY_SIZE(rk3568_npupvtm_infos),
597 .infos = rk3568_npupvtm_infos,
598 .ops = {
599 .get_value = rv1126_pvtm_get_value,
600 .set_ring_sel = rv1126_pvtm_set_ring_sel,
601 },
602 };
603
604 static const struct rockchip_pvtm_info rk3588_bigcore0_pvtm_infos[] = {
605 PVTM(0, "bigcore0", 7, 0, 1, 0x4, 0, 0x4),
606 };
607
608 static const struct rockchip_pvtm_data rk3588_bigcore0_pvtm = {
609 .con = 0x4,
610 .sta = 0x80,
611 .num_pvtms = ARRAY_SIZE(rk3588_bigcore0_pvtm_infos),
612 .infos = rk3588_bigcore0_pvtm_infos,
613 .ops = {
614 .get_value = rv1126_pvtm_get_value,
615 .set_ring_sel = rv1126_pvtm_set_ring_sel,
616 },
617 };
618
619 static const struct rockchip_pvtm_info rk3588_bigcore1_pvtm_infos[] = {
620 PVTM(1, "bigcore1", 7, 0, 1, 0x4, 0, 0x4),
621 };
622
623 static const struct rockchip_pvtm_data rk3588_bigcore1_pvtm = {
624 .con = 0x4,
625 .sta = 0x80,
626 .num_pvtms = ARRAY_SIZE(rk3588_bigcore1_pvtm_infos),
627 .infos = rk3588_bigcore1_pvtm_infos,
628 .ops = {
629 .get_value = rv1126_pvtm_get_value,
630 .set_ring_sel = rv1126_pvtm_set_ring_sel,
631 },
632 };
633
634 static const struct rockchip_pvtm_info rk3588_litcore_pvtm_infos[] = {
635 PVTM(2, "litcore", 7, 0, 1, 0x4, 0, 0x4),
636 };
637
638 static const struct rockchip_pvtm_data rk3588_litcore_pvtm = {
639 .con = 0x4,
640 .sta = 0x80,
641 .num_pvtms = ARRAY_SIZE(rk3588_litcore_pvtm_infos),
642 .infos = rk3588_litcore_pvtm_infos,
643 .ops = {
644 .get_value = rv1126_pvtm_get_value,
645 .set_ring_sel = rv1126_pvtm_set_ring_sel,
646 },
647 };
648
649 static const struct rockchip_pvtm_info rk3588_npu_pvtm_infos[] = {
650 PVTM(3, "npu", 2, 0, 1, 0x4, 0, 0x4),
651 };
652
653 static const struct rockchip_pvtm_data rk3588_npu_pvtm = {
654 .con = 0x4,
655 .sta = 0x80,
656 .num_pvtms = ARRAY_SIZE(rk3588_npu_pvtm_infos),
657 .infos = rk3588_npu_pvtm_infos,
658 .ops = {
659 .get_value = rv1126_pvtm_get_value,
660 .set_ring_sel = rv1126_pvtm_set_ring_sel,
661 },
662 };
663
664 static const struct rockchip_pvtm_info rk3588_gpu_pvtm_infos[] = {
665 PVTM(4, "gpu", 2, 0, 1, 0x4, 0, 0x4),
666 };
667
668 static const struct rockchip_pvtm_data rk3588_gpu_pvtm = {
669 .con = 0x4,
670 .sta = 0x80,
671 .num_pvtms = ARRAY_SIZE(rk3588_gpu_pvtm_infos),
672 .infos = rk3588_gpu_pvtm_infos,
673 .ops = {
674 .get_value = rv1126_pvtm_get_value,
675 .set_ring_sel = rv1126_pvtm_set_ring_sel,
676 },
677 };
678
679 static const struct rockchip_pvtm_info rk3588_pmu_pvtm_infos[] = {
680 PVTM(5, "pmu", 1, 0, 1, 0x4, 0, 0x4),
681 };
682
683 static const struct rockchip_pvtm_data rk3588_pmu_pvtm = {
684 .con = 0x4,
685 .sta = 0x80,
686 .num_pvtms = ARRAY_SIZE(rk3588_pmu_pvtm_infos),
687 .infos = rk3588_pmu_pvtm_infos,
688 .ops = {
689 .get_value = rv1126_pvtm_get_value,
690 },
691 };
692
693 static const struct rockchip_pvtm_info rv1126_cpupvtm_infos[] = {
694 PVTM(0, "cpu", 7, 0, 1, 0x4, 0, 0x4),
695 };
696
697 static const struct rockchip_pvtm_data rv1126_cpupvtm = {
698 .con = 0x4,
699 .sta = 0x80,
700 .num_pvtms = ARRAY_SIZE(rv1126_cpupvtm_infos),
701 .infos = rv1126_cpupvtm_infos,
702 .ops = {
703 .get_value = rv1126_pvtm_get_value,
704 .set_ring_sel = rv1126_pvtm_set_ring_sel,
705 },
706 };
707
708 static const struct rockchip_pvtm_info rv1126_npupvtm_infos[] = {
709 PVTM(1, "npu", 7, 0, 1, 0x4, 0, 0x4),
710 };
711
712 static const struct rockchip_pvtm_data rv1126_npupvtm = {
713 .con = 0x4,
714 .sta = 0x80,
715 .num_pvtms = ARRAY_SIZE(rv1126_npupvtm_infos),
716 .infos = rv1126_npupvtm_infos,
717 .ops = {
718 .get_value = rv1126_pvtm_get_value,
719 .set_ring_sel = rv1126_pvtm_set_ring_sel,
720 },
721 };
722
723 static const struct rockchip_pvtm_info rv1126_pmupvtm_infos[] = {
724 PVTM(2, "pmu", 1, 0, 1, 0x4, 0, 0x4),
725 };
726
727 static const struct rockchip_pvtm_data rv1126_pmupvtm = {
728 .con = 0x4,
729 .sta = 0x80,
730 .num_pvtms = ARRAY_SIZE(rv1126_pmupvtm_infos),
731 .infos = rv1126_pmupvtm_infos,
732 .ops = {
733 .get_value = rv1126_pvtm_get_value,
734 },
735 };
736
737 static const struct of_device_id rockchip_pvtm_match[] = {
738 {
739 .compatible = "rockchip,px30-pvtm",
740 .data = (void *)&px30_pvtm,
741 },
742 {
743 .compatible = "rockchip,px30-pmu-pvtm",
744 .data = (void *)&px30_pmupvtm,
745 },
746 {
747 .compatible = "rockchip,rk1808-pvtm",
748 .data = (void *)&rk1808_pvtm,
749 },
750 {
751 .compatible = "rockchip,rk1808-pmu-pvtm",
752 .data = (void *)&rk1808_pmupvtm,
753 },
754 {
755 .compatible = "rockchip,rk1808-npu-pvtm",
756 .data = (void *)&rk1808_npupvtm,
757 },
758 {
759 .compatible = "rockchip,rk3288-pvtm",
760 .data = (void *)&rk3288_pvtm,
761 },
762 {
763 .compatible = "rockchip,rk3308-pvtm",
764 .data = (void *)&px30_pvtm,
765 },
766 {
767 .compatible = "rockchip,rk3308-pmu-pvtm",
768 .data = (void *)&rk3308_pmupvtm,
769 },
770 {
771 .compatible = "rockchip,rk3399-pvtm",
772 .data = (void *)&rk3399_pvtm,
773 },
774 {
775 .compatible = "rockchip,rk3399-pmu-pvtm",
776 .data = (void *)&rk3399_pmupvtm,
777 },
778 {
779 .compatible = "rockchip,rK3568-core-pvtm",
780 .data = (void *)&rk3568_corepvtm,
781 },
782 {
783 .compatible = "rockchip,rk3568-gpu-pvtm",
784 .data = (void *)&rk3568_gpupvtm,
785 },
786 {
787 .compatible = "rockchip,rk3568-npu-pvtm",
788 .data = (void *)&rk3568_npupvtm,
789 },
790 {
791 .compatible = "rockchip,rk3588-bigcore0-pvtm",
792 .data = (void *)&rk3588_bigcore0_pvtm,
793 },
794 {
795 .compatible = "rockchip,rk3588-bigcore1-pvtm",
796 .data = (void *)&rk3588_bigcore1_pvtm,
797 },
798 {
799 .compatible = "rockchip,rk3588-litcore-pvtm",
800 .data = (void *)&rk3588_litcore_pvtm,
801 },
802 {
803 .compatible = "rockchip,rk3588-gpu-pvtm",
804 .data = (void *)&rk3588_gpu_pvtm,
805 },
806 {
807 .compatible = "rockchip,rk3588-npu-pvtm",
808 .data = (void *)&rk3588_npu_pvtm,
809 },
810 {
811 .compatible = "rockchip,rk3588-pmu-pvtm",
812 .data = (void *)&rk3588_pmu_pvtm,
813 },
814 {
815 .compatible = "rockchip,rv1126-cpu-pvtm",
816 .data = (void *)&rv1126_cpupvtm,
817 },
818 {
819 .compatible = "rockchip,rv1126-npu-pvtm",
820 .data = (void *)&rv1126_npupvtm,
821 },
822 {
823 .compatible = "rockchip,rv1126-pmu-pvtm",
824 .data = (void *)&rv1126_pmupvtm,
825 },
826 { /* sentinel */ },
827 };
828 MODULE_DEVICE_TABLE(of, rockchip_pvtm_match);
829
rockchip_pvtm_get_index(const struct rockchip_pvtm_data * data,u32 ch,u32 * index)830 static int rockchip_pvtm_get_index(const struct rockchip_pvtm_data *data,
831 u32 ch, u32 *index)
832 {
833 int i;
834
835 for (i = 0; i < data->num_pvtms; i++) {
836 if (ch == data->infos[i].id) {
837 *index = i;
838 return 0;
839 }
840 }
841
842 return -EINVAL;
843 }
844
845 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)846 rockchip_pvtm_init(struct device *dev, struct device_node *node,
847 const struct rockchip_pvtm_data *data,
848 struct regmap *grf, void __iomem *base)
849 {
850 struct rockchip_pvtm *pvtm;
851 const char *tz_name;
852 u32 id, index;
853 int i;
854
855 if (of_property_read_u32(node, "reg", &id)) {
856 dev_err(dev, "%s: failed to retrieve pvtm id\n", node->name);
857 return NULL;
858 }
859 if (rockchip_pvtm_get_index(data, id, &index)) {
860 dev_err(dev, "%s: invalid pvtm id %d\n", node->name, id);
861 return NULL;
862 }
863
864 pvtm = devm_kzalloc(dev, sizeof(*pvtm), GFP_KERNEL);
865 if (!pvtm)
866 return NULL;
867
868 pvtm->dev = dev;
869 pvtm->grf = grf;
870 pvtm->base = base;
871 pvtm->con = data->con;
872 pvtm->sta = data->sta;
873 pvtm->ops = &data->ops;
874 pvtm->info = &data->infos[index];
875
876 if (!of_property_read_string(node, "thermal-zone", &tz_name)) {
877 pvtm->tz = thermal_zone_get_zone_by_name(tz_name);
878 if (IS_ERR(pvtm->tz)) {
879 dev_err(pvtm->dev, "failed to retrieve pvtm_tz\n");
880 pvtm->tz = NULL;
881 }
882 }
883
884 pvtm->num_clks = of_clk_get_parent_count(node);
885 if (pvtm->num_clks <= 0) {
886 dev_err(dev, "%s: does not have clocks\n", node->name);
887 goto clk_num_err;
888 }
889 pvtm->clks = devm_kcalloc(dev, pvtm->num_clks, sizeof(*pvtm->clks),
890 GFP_KERNEL);
891 if (!pvtm->clks)
892 goto clk_num_err;
893 for (i = 0; i < pvtm->num_clks; i++) {
894 pvtm->clks[i].clk = of_clk_get(node, i);
895 if (IS_ERR(pvtm->clks[i].clk)) {
896 dev_err(dev, "%s: failed to get clk at index %d\n",
897 node->name, i);
898 goto clk_err;
899 }
900 }
901
902 pvtm->rst = devm_reset_control_array_get_optional_exclusive(dev);
903 if (IS_ERR(pvtm->rst))
904 dev_dbg(dev, "%s: failed to get reset\n", node->name);
905
906 rockchip_pvtm_add_debugfs(pvtm);
907
908 return pvtm;
909
910 clk_err:
911 while (--i >= 0)
912 clk_put(pvtm->clks[i].clk);
913 devm_kfree(dev, pvtm->clks);
914 clk_num_err:
915 devm_kfree(dev, pvtm);
916
917 return NULL;
918 }
919
rockchip_pvtm_probe(struct platform_device * pdev)920 static int rockchip_pvtm_probe(struct platform_device *pdev)
921 {
922 struct device *dev = &pdev->dev;
923 struct device_node *np = pdev->dev.of_node;
924 struct device_node *node;
925 const struct of_device_id *match;
926 struct rockchip_pvtm *pvtm;
927 struct regmap *grf = NULL;
928 void __iomem *base = NULL;
929
930 match = of_match_device(dev->driver->of_match_table, dev);
931 if (!match || !match->data) {
932 dev_err(dev, "missing pvtm data\n");
933 return -EINVAL;
934 }
935
936 if (dev->parent && dev->parent->of_node) {
937 grf = syscon_node_to_regmap(dev->parent->of_node);
938 if (IS_ERR(grf))
939 return PTR_ERR(grf);
940 } else {
941 base = devm_platform_ioremap_resource(pdev, 0);
942 if (IS_ERR(base))
943 return PTR_ERR(base);
944 }
945
946 for_each_available_child_of_node(np, node) {
947 pvtm = rockchip_pvtm_init(dev, node, match->data, grf, base);
948 if (!pvtm) {
949 dev_err(dev, "failed to handle node %s\n",
950 node->full_name);
951 continue;
952 }
953 list_add(&pvtm->node, &pvtm_list);
954 dev_info(dev, "%s probed\n", node->full_name);
955 }
956
957 return 0;
958 }
959
960 static struct platform_driver rockchip_pvtm_driver = {
961 .probe = rockchip_pvtm_probe,
962 .driver = {
963 .name = "rockchip-pvtm",
964 .of_match_table = rockchip_pvtm_match,
965 },
966 };
967
rockchip_pvtm_module_init(void)968 static int __init rockchip_pvtm_module_init(void)
969 {
970 rockchip_pvtm_debugfs_init();
971
972 return platform_driver_register(&rockchip_pvtm_driver);
973 }
974 module_init(rockchip_pvtm_module_init);
975
rockchip_pvtm_module_exit(void)976 static void __exit rockchip_pvtm_module_exit(void)
977 {
978 rockchip_pvtm_debugfs_exit();
979 platform_driver_unregister(&rockchip_pvtm_driver);
980 }
981 module_exit(rockchip_pvtm_module_exit);
982
983 MODULE_DESCRIPTION("Rockchip PVTM driver");
984 MODULE_AUTHOR("Finley Xiao <finley.xiao@rock-chips.com>");
985 MODULE_LICENSE("GPL v2");
986