1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (C) 2019 Linaro Ltd.
4 *
5 * Author: Stanimir Varbanov <stanimir.varbanov@linaro.org>
6 */
7 #include <linux/clk.h>
8 #include <linux/interconnect.h>
9 #include <linux/iopoll.h>
10 #include <linux/kernel.h>
11 #include <linux/pm_domain.h>
12 #include <linux/pm_opp.h>
13 #include <linux/pm_runtime.h>
14 #include <linux/types.h>
15 #include <media/v4l2-mem2mem.h>
16
17 #include "core.h"
18 #include "hfi_parser.h"
19 #include "hfi_venus_io.h"
20 #include "pm_helpers.h"
21
22 static bool legacy_binding;
23
core_clks_get(struct venus_core * core)24 static int core_clks_get(struct venus_core *core)
25 {
26 const struct venus_resources *res = core->res;
27 struct device *dev = core->dev;
28 unsigned int i;
29
30 for (i = 0; i < res->clks_num; i++) {
31 core->clks[i] = devm_clk_get(dev, res->clks[i]);
32 if (IS_ERR(core->clks[i]))
33 return PTR_ERR(core->clks[i]);
34 }
35
36 return 0;
37 }
38
core_clks_enable(struct venus_core * core)39 static int core_clks_enable(struct venus_core *core)
40 {
41 const struct venus_resources *res = core->res;
42 unsigned int i;
43 int ret;
44
45 for (i = 0; i < res->clks_num; i++) {
46 ret = clk_prepare_enable(core->clks[i]);
47 if (ret)
48 goto err;
49 }
50
51 return 0;
52 err:
53 while (i--)
54 clk_disable_unprepare(core->clks[i]);
55
56 return ret;
57 }
58
core_clks_disable(struct venus_core * core)59 static void core_clks_disable(struct venus_core *core)
60 {
61 const struct venus_resources *res = core->res;
62 unsigned int i = res->clks_num;
63
64 while (i--)
65 clk_disable_unprepare(core->clks[i]);
66 }
67
core_clks_set_rate(struct venus_core * core,unsigned long freq)68 static int core_clks_set_rate(struct venus_core *core, unsigned long freq)
69 {
70 int ret;
71
72 ret = dev_pm_opp_set_rate(core->dev, freq);
73 if (ret)
74 return ret;
75
76 ret = clk_set_rate(core->vcodec0_clks[0], freq);
77 if (ret)
78 return ret;
79
80 ret = clk_set_rate(core->vcodec1_clks[0], freq);
81 if (ret)
82 return ret;
83
84 return 0;
85 }
86
vcodec_clks_get(struct venus_core * core,struct device * dev,struct clk ** clks,const char * const * id)87 static int vcodec_clks_get(struct venus_core *core, struct device *dev,
88 struct clk **clks, const char * const *id)
89 {
90 const struct venus_resources *res = core->res;
91 unsigned int i;
92
93 for (i = 0; i < res->vcodec_clks_num; i++) {
94 if (!id[i])
95 continue;
96 clks[i] = devm_clk_get(dev, id[i]);
97 if (IS_ERR(clks[i]))
98 return PTR_ERR(clks[i]);
99 }
100
101 return 0;
102 }
103
vcodec_clks_enable(struct venus_core * core,struct clk ** clks)104 static int vcodec_clks_enable(struct venus_core *core, struct clk **clks)
105 {
106 const struct venus_resources *res = core->res;
107 unsigned int i;
108 int ret;
109
110 for (i = 0; i < res->vcodec_clks_num; i++) {
111 ret = clk_prepare_enable(clks[i]);
112 if (ret)
113 goto err;
114 }
115
116 return 0;
117 err:
118 while (i--)
119 clk_disable_unprepare(clks[i]);
120
121 return ret;
122 }
123
vcodec_clks_disable(struct venus_core * core,struct clk ** clks)124 static void vcodec_clks_disable(struct venus_core *core, struct clk **clks)
125 {
126 const struct venus_resources *res = core->res;
127 unsigned int i = res->vcodec_clks_num;
128
129 while (i--)
130 clk_disable_unprepare(clks[i]);
131 }
132
load_per_instance(struct venus_inst * inst)133 static u32 load_per_instance(struct venus_inst *inst)
134 {
135 u32 mbs;
136
137 if (!inst || !(inst->state >= INST_INIT && inst->state < INST_STOP))
138 return 0;
139
140 mbs = (ALIGN(inst->width, 16) / 16) * (ALIGN(inst->height, 16) / 16);
141
142 return mbs * inst->fps;
143 }
144
load_per_type(struct venus_core * core,u32 session_type)145 static u32 load_per_type(struct venus_core *core, u32 session_type)
146 {
147 struct venus_inst *inst = NULL;
148 u32 mbs_per_sec = 0;
149
150 mutex_lock(&core->lock);
151 list_for_each_entry(inst, &core->instances, list) {
152 if (inst->session_type != session_type)
153 continue;
154
155 mbs_per_sec += load_per_instance(inst);
156 }
157 mutex_unlock(&core->lock);
158
159 return mbs_per_sec;
160 }
161
mbs_to_bw(struct venus_inst * inst,u32 mbs,u32 * avg,u32 * peak)162 static void mbs_to_bw(struct venus_inst *inst, u32 mbs, u32 *avg, u32 *peak)
163 {
164 const struct venus_resources *res = inst->core->res;
165 const struct bw_tbl *bw_tbl;
166 unsigned int num_rows, i;
167
168 *avg = 0;
169 *peak = 0;
170
171 if (mbs == 0)
172 return;
173
174 if (inst->session_type == VIDC_SESSION_TYPE_ENC) {
175 num_rows = res->bw_tbl_enc_size;
176 bw_tbl = res->bw_tbl_enc;
177 } else if (inst->session_type == VIDC_SESSION_TYPE_DEC) {
178 num_rows = res->bw_tbl_dec_size;
179 bw_tbl = res->bw_tbl_dec;
180 } else {
181 return;
182 }
183
184 if (!bw_tbl || num_rows == 0)
185 return;
186
187 for (i = 0; i < num_rows; i++) {
188 if (mbs > bw_tbl[i].mbs_per_sec)
189 break;
190
191 if (inst->dpb_fmt & HFI_COLOR_FORMAT_10_BIT_BASE) {
192 *avg = bw_tbl[i].avg_10bit;
193 *peak = bw_tbl[i].peak_10bit;
194 } else {
195 *avg = bw_tbl[i].avg;
196 *peak = bw_tbl[i].peak;
197 }
198 }
199 }
200
load_scale_bw(struct venus_core * core)201 static int load_scale_bw(struct venus_core *core)
202 {
203 struct venus_inst *inst = NULL;
204 u32 mbs_per_sec, avg, peak, total_avg = 0, total_peak = 0;
205
206 mutex_lock(&core->lock);
207 list_for_each_entry(inst, &core->instances, list) {
208 mbs_per_sec = load_per_instance(inst);
209 mbs_to_bw(inst, mbs_per_sec, &avg, &peak);
210 total_avg += avg;
211 total_peak += peak;
212 }
213 mutex_unlock(&core->lock);
214
215 dev_dbg(core->dev, VDBGL "total: avg_bw: %u, peak_bw: %u\n",
216 total_avg, total_peak);
217
218 return icc_set_bw(core->video_path, total_avg, total_peak);
219 }
220
load_scale_v1(struct venus_inst * inst)221 static int load_scale_v1(struct venus_inst *inst)
222 {
223 struct venus_core *core = inst->core;
224 const struct freq_tbl *table = core->res->freq_tbl;
225 unsigned int num_rows = core->res->freq_tbl_size;
226 unsigned long freq = table[0].freq;
227 struct device *dev = core->dev;
228 u32 mbs_per_sec;
229 unsigned int i;
230 int ret;
231
232 mbs_per_sec = load_per_type(core, VIDC_SESSION_TYPE_ENC) +
233 load_per_type(core, VIDC_SESSION_TYPE_DEC);
234
235 if (mbs_per_sec > core->res->max_load)
236 dev_warn(dev, "HW is overloaded, needed: %d max: %d\n",
237 mbs_per_sec, core->res->max_load);
238
239 if (!mbs_per_sec && num_rows > 1) {
240 freq = table[num_rows - 1].freq;
241 goto set_freq;
242 }
243
244 for (i = 0; i < num_rows; i++) {
245 if (mbs_per_sec > table[i].load)
246 break;
247 freq = table[i].freq;
248 }
249
250 set_freq:
251
252 ret = core_clks_set_rate(core, freq);
253 if (ret) {
254 dev_err(dev, "failed to set clock rate %lu (%d)\n",
255 freq, ret);
256 return ret;
257 }
258
259 ret = load_scale_bw(core);
260 if (ret) {
261 dev_err(dev, "failed to set bandwidth (%d)\n",
262 ret);
263 return ret;
264 }
265
266 return 0;
267 }
268
core_get_v1(struct device * dev)269 static int core_get_v1(struct device *dev)
270 {
271 struct venus_core *core = dev_get_drvdata(dev);
272
273 return core_clks_get(core);
274 }
275
core_power_v1(struct device * dev,int on)276 static int core_power_v1(struct device *dev, int on)
277 {
278 struct venus_core *core = dev_get_drvdata(dev);
279 int ret = 0;
280
281 if (on == POWER_ON)
282 ret = core_clks_enable(core);
283 else
284 core_clks_disable(core);
285
286 return ret;
287 }
288
289 static const struct venus_pm_ops pm_ops_v1 = {
290 .core_get = core_get_v1,
291 .core_power = core_power_v1,
292 .load_scale = load_scale_v1,
293 };
294
295 static void
vcodec_control_v3(struct venus_core * core,u32 session_type,bool enable)296 vcodec_control_v3(struct venus_core *core, u32 session_type, bool enable)
297 {
298 void __iomem *ctrl;
299
300 if (session_type == VIDC_SESSION_TYPE_DEC)
301 ctrl = core->base + WRAPPER_VDEC_VCODEC_POWER_CONTROL;
302 else
303 ctrl = core->base + WRAPPER_VENC_VCODEC_POWER_CONTROL;
304
305 if (enable)
306 writel(0, ctrl);
307 else
308 writel(1, ctrl);
309 }
310
vdec_get_v3(struct device * dev)311 static int vdec_get_v3(struct device *dev)
312 {
313 struct venus_core *core = dev_get_drvdata(dev);
314
315 return vcodec_clks_get(core, dev, core->vcodec0_clks,
316 core->res->vcodec0_clks);
317 }
318
vdec_power_v3(struct device * dev,int on)319 static int vdec_power_v3(struct device *dev, int on)
320 {
321 struct venus_core *core = dev_get_drvdata(dev);
322 int ret = 0;
323
324 vcodec_control_v3(core, VIDC_SESSION_TYPE_DEC, true);
325
326 if (on == POWER_ON)
327 ret = vcodec_clks_enable(core, core->vcodec0_clks);
328 else
329 vcodec_clks_disable(core, core->vcodec0_clks);
330
331 vcodec_control_v3(core, VIDC_SESSION_TYPE_DEC, false);
332
333 return ret;
334 }
335
venc_get_v3(struct device * dev)336 static int venc_get_v3(struct device *dev)
337 {
338 struct venus_core *core = dev_get_drvdata(dev);
339
340 return vcodec_clks_get(core, dev, core->vcodec1_clks,
341 core->res->vcodec1_clks);
342 }
343
venc_power_v3(struct device * dev,int on)344 static int venc_power_v3(struct device *dev, int on)
345 {
346 struct venus_core *core = dev_get_drvdata(dev);
347 int ret = 0;
348
349 vcodec_control_v3(core, VIDC_SESSION_TYPE_ENC, true);
350
351 if (on == POWER_ON)
352 ret = vcodec_clks_enable(core, core->vcodec1_clks);
353 else
354 vcodec_clks_disable(core, core->vcodec1_clks);
355
356 vcodec_control_v3(core, VIDC_SESSION_TYPE_ENC, false);
357
358 return ret;
359 }
360
361 static const struct venus_pm_ops pm_ops_v3 = {
362 .core_get = core_get_v1,
363 .core_power = core_power_v1,
364 .vdec_get = vdec_get_v3,
365 .vdec_power = vdec_power_v3,
366 .venc_get = venc_get_v3,
367 .venc_power = venc_power_v3,
368 .load_scale = load_scale_v1,
369 };
370
vcodec_control_v4(struct venus_core * core,u32 coreid,bool enable)371 static int vcodec_control_v4(struct venus_core *core, u32 coreid, bool enable)
372 {
373 void __iomem *ctrl, *stat;
374 u32 val;
375 int ret;
376
377 if (coreid == VIDC_CORE_ID_1) {
378 ctrl = core->base + WRAPPER_VCODEC0_MMCC_POWER_CONTROL;
379 stat = core->base + WRAPPER_VCODEC0_MMCC_POWER_STATUS;
380 } else {
381 ctrl = core->base + WRAPPER_VCODEC1_MMCC_POWER_CONTROL;
382 stat = core->base + WRAPPER_VCODEC1_MMCC_POWER_STATUS;
383 }
384
385 if (enable) {
386 writel(0, ctrl);
387
388 ret = readl_poll_timeout(stat, val, val & BIT(1), 1, 100);
389 if (ret)
390 return ret;
391 } else {
392 writel(1, ctrl);
393
394 ret = readl_poll_timeout(stat, val, !(val & BIT(1)), 1, 100);
395 if (ret)
396 return ret;
397 }
398
399 return 0;
400 }
401
poweroff_coreid(struct venus_core * core,unsigned int coreid_mask)402 static int poweroff_coreid(struct venus_core *core, unsigned int coreid_mask)
403 {
404 int ret;
405
406 if (coreid_mask & VIDC_CORE_ID_1) {
407 ret = vcodec_control_v4(core, VIDC_CORE_ID_1, true);
408 if (ret)
409 return ret;
410
411 vcodec_clks_disable(core, core->vcodec0_clks);
412
413 ret = vcodec_control_v4(core, VIDC_CORE_ID_1, false);
414 if (ret)
415 return ret;
416
417 ret = pm_runtime_put_sync(core->pmdomains[1]);
418 if (ret < 0)
419 return ret;
420 }
421
422 if (coreid_mask & VIDC_CORE_ID_2) {
423 ret = vcodec_control_v4(core, VIDC_CORE_ID_2, true);
424 if (ret)
425 return ret;
426
427 vcodec_clks_disable(core, core->vcodec1_clks);
428
429 ret = vcodec_control_v4(core, VIDC_CORE_ID_2, false);
430 if (ret)
431 return ret;
432
433 ret = pm_runtime_put_sync(core->pmdomains[2]);
434 if (ret < 0)
435 return ret;
436 }
437
438 return 0;
439 }
440
poweron_coreid(struct venus_core * core,unsigned int coreid_mask)441 static int poweron_coreid(struct venus_core *core, unsigned int coreid_mask)
442 {
443 int ret;
444
445 if (coreid_mask & VIDC_CORE_ID_1) {
446 ret = pm_runtime_get_sync(core->pmdomains[1]);
447 if (ret < 0)
448 return ret;
449
450 ret = vcodec_control_v4(core, VIDC_CORE_ID_1, true);
451 if (ret)
452 return ret;
453
454 ret = vcodec_clks_enable(core, core->vcodec0_clks);
455 if (ret)
456 return ret;
457
458 ret = vcodec_control_v4(core, VIDC_CORE_ID_1, false);
459 if (ret < 0)
460 return ret;
461 }
462
463 if (coreid_mask & VIDC_CORE_ID_2) {
464 ret = pm_runtime_get_sync(core->pmdomains[2]);
465 if (ret < 0)
466 return ret;
467
468 ret = vcodec_control_v4(core, VIDC_CORE_ID_2, true);
469 if (ret)
470 return ret;
471
472 ret = vcodec_clks_enable(core, core->vcodec1_clks);
473 if (ret)
474 return ret;
475
476 ret = vcodec_control_v4(core, VIDC_CORE_ID_2, false);
477 if (ret < 0)
478 return ret;
479 }
480
481 return 0;
482 }
483
484 static void
min_loaded_core(struct venus_inst * inst,u32 * min_coreid,u32 * min_load)485 min_loaded_core(struct venus_inst *inst, u32 *min_coreid, u32 *min_load)
486 {
487 u32 mbs_per_sec, load, core1_load = 0, core2_load = 0;
488 u32 cores_max = core_num_max(inst);
489 struct venus_core *core = inst->core;
490 struct venus_inst *inst_pos;
491 unsigned long vpp_freq;
492 u32 coreid;
493
494 mutex_lock(&core->lock);
495
496 list_for_each_entry(inst_pos, &core->instances, list) {
497 if (inst_pos == inst)
498 continue;
499
500 if (inst_pos->state != INST_START)
501 continue;
502
503 vpp_freq = inst_pos->clk_data.codec_freq_data->vpp_freq;
504 coreid = inst_pos->clk_data.core_id;
505
506 mbs_per_sec = load_per_instance(inst_pos);
507 load = mbs_per_sec * vpp_freq;
508
509 if ((coreid & VIDC_CORE_ID_3) == VIDC_CORE_ID_3) {
510 core1_load += load / 2;
511 core2_load += load / 2;
512 } else if (coreid & VIDC_CORE_ID_1) {
513 core1_load += load;
514 } else if (coreid & VIDC_CORE_ID_2) {
515 core2_load += load;
516 }
517 }
518
519 *min_coreid = core1_load <= core2_load ?
520 VIDC_CORE_ID_1 : VIDC_CORE_ID_2;
521 *min_load = min(core1_load, core2_load);
522
523 if (cores_max < VIDC_CORE_ID_2 || core->res->vcodec_num < 2) {
524 *min_coreid = VIDC_CORE_ID_1;
525 *min_load = core1_load;
526 }
527
528 mutex_unlock(&core->lock);
529 }
530
decide_core(struct venus_inst * inst)531 static int decide_core(struct venus_inst *inst)
532 {
533 const u32 ptype = HFI_PROPERTY_CONFIG_VIDEOCORES_USAGE;
534 struct venus_core *core = inst->core;
535 u32 min_coreid, min_load, inst_load;
536 struct hfi_videocores_usage_type cu;
537 unsigned long max_freq;
538
539 if (legacy_binding) {
540 if (inst->session_type == VIDC_SESSION_TYPE_DEC)
541 cu.video_core_enable_mask = VIDC_CORE_ID_1;
542 else
543 cu.video_core_enable_mask = VIDC_CORE_ID_2;
544
545 goto done;
546 }
547
548 if (inst->clk_data.core_id != VIDC_CORE_ID_DEFAULT)
549 return 0;
550
551 inst_load = load_per_instance(inst);
552 inst_load *= inst->clk_data.codec_freq_data->vpp_freq;
553 max_freq = core->res->freq_tbl[0].freq;
554
555 min_loaded_core(inst, &min_coreid, &min_load);
556
557 if ((inst_load + min_load) > max_freq) {
558 dev_warn(core->dev, "HW is overloaded, needed: %u max: %lu\n",
559 inst_load, max_freq);
560 return -EINVAL;
561 }
562
563 inst->clk_data.core_id = min_coreid;
564 cu.video_core_enable_mask = min_coreid;
565
566 done:
567 return hfi_session_set_property(inst, ptype, &cu);
568 }
569
acquire_core(struct venus_inst * inst)570 static int acquire_core(struct venus_inst *inst)
571 {
572 struct venus_core *core = inst->core;
573 unsigned int coreid_mask = 0;
574
575 if (inst->core_acquired)
576 return 0;
577
578 inst->core_acquired = true;
579
580 if (inst->clk_data.core_id & VIDC_CORE_ID_1) {
581 if (core->core0_usage_count++)
582 return 0;
583
584 coreid_mask = VIDC_CORE_ID_1;
585 }
586
587 if (inst->clk_data.core_id & VIDC_CORE_ID_2) {
588 if (core->core1_usage_count++)
589 return 0;
590
591 coreid_mask |= VIDC_CORE_ID_2;
592 }
593
594 return poweron_coreid(core, coreid_mask);
595 }
596
release_core(struct venus_inst * inst)597 static int release_core(struct venus_inst *inst)
598 {
599 struct venus_core *core = inst->core;
600 unsigned int coreid_mask = 0;
601 int ret;
602
603 if (!inst->core_acquired)
604 return 0;
605
606 if (inst->clk_data.core_id & VIDC_CORE_ID_1) {
607 if (--core->core0_usage_count)
608 goto done;
609
610 coreid_mask = VIDC_CORE_ID_1;
611 }
612
613 if (inst->clk_data.core_id & VIDC_CORE_ID_2) {
614 if (--core->core1_usage_count)
615 goto done;
616
617 coreid_mask |= VIDC_CORE_ID_2;
618 }
619
620 ret = poweroff_coreid(core, coreid_mask);
621 if (ret)
622 return ret;
623
624 done:
625 inst->clk_data.core_id = VIDC_CORE_ID_DEFAULT;
626 inst->core_acquired = false;
627 return 0;
628 }
629
coreid_power_v4(struct venus_inst * inst,int on)630 static int coreid_power_v4(struct venus_inst *inst, int on)
631 {
632 struct venus_core *core = inst->core;
633 int ret;
634
635 if (legacy_binding)
636 return 0;
637
638 if (on == POWER_ON) {
639 ret = decide_core(inst);
640 if (ret)
641 return ret;
642
643 mutex_lock(&core->lock);
644 ret = acquire_core(inst);
645 mutex_unlock(&core->lock);
646 } else {
647 mutex_lock(&core->lock);
648 ret = release_core(inst);
649 mutex_unlock(&core->lock);
650 }
651
652 return ret;
653 }
654
vdec_get_v4(struct device * dev)655 static int vdec_get_v4(struct device *dev)
656 {
657 struct venus_core *core = dev_get_drvdata(dev);
658
659 if (!legacy_binding)
660 return 0;
661
662 return vcodec_clks_get(core, dev, core->vcodec0_clks,
663 core->res->vcodec0_clks);
664 }
665
vdec_put_v4(struct device * dev)666 static void vdec_put_v4(struct device *dev)
667 {
668 struct venus_core *core = dev_get_drvdata(dev);
669 unsigned int i;
670
671 if (!legacy_binding)
672 return;
673
674 for (i = 0; i < core->res->vcodec_clks_num; i++)
675 core->vcodec0_clks[i] = NULL;
676 }
677
vdec_power_v4(struct device * dev,int on)678 static int vdec_power_v4(struct device *dev, int on)
679 {
680 struct venus_core *core = dev_get_drvdata(dev);
681 int ret;
682
683 if (!legacy_binding)
684 return 0;
685
686 ret = vcodec_control_v4(core, VIDC_CORE_ID_1, true);
687 if (ret)
688 return ret;
689
690 if (on == POWER_ON)
691 ret = vcodec_clks_enable(core, core->vcodec0_clks);
692 else
693 vcodec_clks_disable(core, core->vcodec0_clks);
694
695 vcodec_control_v4(core, VIDC_CORE_ID_1, false);
696
697 return ret;
698 }
699
venc_get_v4(struct device * dev)700 static int venc_get_v4(struct device *dev)
701 {
702 struct venus_core *core = dev_get_drvdata(dev);
703
704 if (!legacy_binding)
705 return 0;
706
707 return vcodec_clks_get(core, dev, core->vcodec1_clks,
708 core->res->vcodec1_clks);
709 }
710
venc_put_v4(struct device * dev)711 static void venc_put_v4(struct device *dev)
712 {
713 struct venus_core *core = dev_get_drvdata(dev);
714 unsigned int i;
715
716 if (!legacy_binding)
717 return;
718
719 for (i = 0; i < core->res->vcodec_clks_num; i++)
720 core->vcodec1_clks[i] = NULL;
721 }
722
venc_power_v4(struct device * dev,int on)723 static int venc_power_v4(struct device *dev, int on)
724 {
725 struct venus_core *core = dev_get_drvdata(dev);
726 int ret;
727
728 if (!legacy_binding)
729 return 0;
730
731 ret = vcodec_control_v4(core, VIDC_CORE_ID_2, true);
732 if (ret)
733 return ret;
734
735 if (on == POWER_ON)
736 ret = vcodec_clks_enable(core, core->vcodec1_clks);
737 else
738 vcodec_clks_disable(core, core->vcodec1_clks);
739
740 vcodec_control_v4(core, VIDC_CORE_ID_2, false);
741
742 return ret;
743 }
744
vcodec_domains_get(struct device * dev)745 static int vcodec_domains_get(struct device *dev)
746 {
747 int ret;
748 struct opp_table *opp_table;
749 struct device **opp_virt_dev;
750 struct venus_core *core = dev_get_drvdata(dev);
751 const struct venus_resources *res = core->res;
752 struct device *pd;
753 unsigned int i;
754
755 if (!res->vcodec_pmdomains_num)
756 goto skip_pmdomains;
757
758 for (i = 0; i < res->vcodec_pmdomains_num; i++) {
759 pd = dev_pm_domain_attach_by_name(dev,
760 res->vcodec_pmdomains[i]);
761 if (IS_ERR(pd))
762 return PTR_ERR(pd);
763 core->pmdomains[i] = pd;
764 }
765
766 core->pd_dl_venus = device_link_add(dev, core->pmdomains[0],
767 DL_FLAG_PM_RUNTIME |
768 DL_FLAG_STATELESS |
769 DL_FLAG_RPM_ACTIVE);
770 if (!core->pd_dl_venus)
771 return -ENODEV;
772
773 skip_pmdomains:
774 if (!core->has_opp_table)
775 return 0;
776
777 /* Attach the power domain for setting performance state */
778 opp_table = dev_pm_opp_attach_genpd(dev, res->opp_pmdomain, &opp_virt_dev);
779 if (IS_ERR(opp_table)) {
780 ret = PTR_ERR(opp_table);
781 goto opp_attach_err;
782 }
783
784 core->opp_pmdomain = *opp_virt_dev;
785 core->opp_dl_venus = device_link_add(dev, core->opp_pmdomain,
786 DL_FLAG_RPM_ACTIVE |
787 DL_FLAG_PM_RUNTIME |
788 DL_FLAG_STATELESS);
789 if (!core->opp_dl_venus) {
790 ret = -ENODEV;
791 goto opp_dl_add_err;
792 }
793
794 return 0;
795
796 opp_dl_add_err:
797 dev_pm_opp_detach_genpd(core->opp_table);
798 opp_attach_err:
799 if (core->pd_dl_venus) {
800 device_link_del(core->pd_dl_venus);
801 for (i = 0; i < res->vcodec_pmdomains_num; i++) {
802 if (IS_ERR_OR_NULL(core->pmdomains[i]))
803 continue;
804 dev_pm_domain_detach(core->pmdomains[i], true);
805 }
806 }
807 return ret;
808 }
809
vcodec_domains_put(struct device * dev)810 static void vcodec_domains_put(struct device *dev)
811 {
812 struct venus_core *core = dev_get_drvdata(dev);
813 const struct venus_resources *res = core->res;
814 unsigned int i;
815
816 if (!res->vcodec_pmdomains_num)
817 goto skip_pmdomains;
818
819 if (core->pd_dl_venus)
820 device_link_del(core->pd_dl_venus);
821
822 for (i = 0; i < res->vcodec_pmdomains_num; i++) {
823 if (IS_ERR_OR_NULL(core->pmdomains[i]))
824 continue;
825 dev_pm_domain_detach(core->pmdomains[i], true);
826 }
827
828 skip_pmdomains:
829 if (!core->has_opp_table)
830 return;
831
832 if (core->opp_dl_venus)
833 device_link_del(core->opp_dl_venus);
834
835 dev_pm_opp_detach_genpd(core->opp_table);
836 }
837
core_get_v4(struct device * dev)838 static int core_get_v4(struct device *dev)
839 {
840 struct venus_core *core = dev_get_drvdata(dev);
841 const struct venus_resources *res = core->res;
842 int ret;
843
844 ret = core_clks_get(core);
845 if (ret)
846 return ret;
847
848 if (!res->vcodec_pmdomains_num)
849 legacy_binding = true;
850
851 dev_info(dev, "%s legacy binding\n", legacy_binding ? "" : "non");
852
853 ret = vcodec_clks_get(core, dev, core->vcodec0_clks, res->vcodec0_clks);
854 if (ret)
855 return ret;
856
857 ret = vcodec_clks_get(core, dev, core->vcodec1_clks, res->vcodec1_clks);
858 if (ret)
859 return ret;
860
861 if (legacy_binding)
862 return 0;
863
864 core->opp_table = dev_pm_opp_set_clkname(dev, "core");
865 if (IS_ERR(core->opp_table))
866 return PTR_ERR(core->opp_table);
867
868 if (core->res->opp_pmdomain) {
869 ret = dev_pm_opp_of_add_table(dev);
870 if (!ret) {
871 core->has_opp_table = true;
872 } else if (ret != -ENODEV) {
873 dev_err(dev, "invalid OPP table in device tree\n");
874 dev_pm_opp_put_clkname(core->opp_table);
875 return ret;
876 }
877 }
878
879 ret = vcodec_domains_get(dev);
880 if (ret) {
881 if (core->has_opp_table)
882 dev_pm_opp_of_remove_table(dev);
883 dev_pm_opp_put_clkname(core->opp_table);
884 return ret;
885 }
886
887 return 0;
888 }
889
core_put_v4(struct device * dev)890 static void core_put_v4(struct device *dev)
891 {
892 struct venus_core *core = dev_get_drvdata(dev);
893
894 if (legacy_binding)
895 return;
896
897 vcodec_domains_put(dev);
898
899 if (core->has_opp_table)
900 dev_pm_opp_of_remove_table(dev);
901 if (core->opp_table)
902 dev_pm_opp_put_clkname(core->opp_table);
903
904 }
905
core_power_v4(struct device * dev,int on)906 static int core_power_v4(struct device *dev, int on)
907 {
908 struct venus_core *core = dev_get_drvdata(dev);
909 int ret = 0;
910
911 if (on == POWER_ON) {
912 ret = core_clks_enable(core);
913 } else {
914 /* Drop the performance state vote */
915 if (core->opp_pmdomain)
916 dev_pm_opp_set_rate(dev, 0);
917
918 core_clks_disable(core);
919 }
920
921 return ret;
922 }
923
calculate_inst_freq(struct venus_inst * inst,unsigned long filled_len)924 static unsigned long calculate_inst_freq(struct venus_inst *inst,
925 unsigned long filled_len)
926 {
927 unsigned long vpp_freq = 0, vsp_freq = 0;
928 u32 fps = (u32)inst->fps;
929 u32 mbs_per_sec;
930
931 mbs_per_sec = load_per_instance(inst) / fps;
932
933 vpp_freq = mbs_per_sec * inst->clk_data.codec_freq_data->vpp_freq;
934 /* 21 / 20 is overhead factor */
935 vpp_freq += vpp_freq / 20;
936 vsp_freq = mbs_per_sec * inst->clk_data.codec_freq_data->vsp_freq;
937
938 /* 10 / 7 is overhead factor */
939 if (inst->session_type == VIDC_SESSION_TYPE_ENC)
940 vsp_freq += (inst->controls.enc.bitrate * 10) / 7;
941 else
942 vsp_freq += ((fps * filled_len * 8) * 10) / 7;
943
944 return max(vpp_freq, vsp_freq);
945 }
946
load_scale_v4(struct venus_inst * inst)947 static int load_scale_v4(struct venus_inst *inst)
948 {
949 struct venus_core *core = inst->core;
950 const struct freq_tbl *table = core->res->freq_tbl;
951 unsigned int num_rows = core->res->freq_tbl_size;
952 struct device *dev = core->dev;
953 unsigned long freq = 0, freq_core1 = 0, freq_core2 = 0;
954 unsigned long filled_len = 0;
955 int i, ret;
956
957 for (i = 0; i < inst->num_input_bufs; i++)
958 filled_len = max(filled_len, inst->payloads[i]);
959
960 if (inst->session_type == VIDC_SESSION_TYPE_DEC && !filled_len)
961 return 0;
962
963 freq = calculate_inst_freq(inst, filled_len);
964 inst->clk_data.freq = freq;
965
966 mutex_lock(&core->lock);
967 list_for_each_entry(inst, &core->instances, list) {
968 if (inst->clk_data.core_id == VIDC_CORE_ID_1) {
969 freq_core1 += inst->clk_data.freq;
970 } else if (inst->clk_data.core_id == VIDC_CORE_ID_2) {
971 freq_core2 += inst->clk_data.freq;
972 } else if (inst->clk_data.core_id == VIDC_CORE_ID_3) {
973 freq_core1 += inst->clk_data.freq;
974 freq_core2 += inst->clk_data.freq;
975 }
976 }
977 mutex_unlock(&core->lock);
978
979 freq = max(freq_core1, freq_core2);
980
981 if (freq >= table[0].freq) {
982 freq = table[0].freq;
983 dev_warn(dev, "HW is overloaded, needed: %lu max: %lu\n",
984 freq, table[0].freq);
985 goto set_freq;
986 }
987
988 for (i = num_rows - 1 ; i >= 0; i--) {
989 if (freq <= table[i].freq) {
990 freq = table[i].freq;
991 break;
992 }
993 }
994
995 set_freq:
996
997 ret = core_clks_set_rate(core, freq);
998 if (ret) {
999 dev_err(dev, "failed to set clock rate %lu (%d)\n",
1000 freq, ret);
1001 return ret;
1002 }
1003
1004 ret = load_scale_bw(core);
1005 if (ret) {
1006 dev_err(dev, "failed to set bandwidth (%d)\n",
1007 ret);
1008 return ret;
1009 }
1010
1011 return 0;
1012 }
1013
1014 static const struct venus_pm_ops pm_ops_v4 = {
1015 .core_get = core_get_v4,
1016 .core_put = core_put_v4,
1017 .core_power = core_power_v4,
1018 .vdec_get = vdec_get_v4,
1019 .vdec_put = vdec_put_v4,
1020 .vdec_power = vdec_power_v4,
1021 .venc_get = venc_get_v4,
1022 .venc_put = venc_put_v4,
1023 .venc_power = venc_power_v4,
1024 .coreid_power = coreid_power_v4,
1025 .load_scale = load_scale_v4,
1026 };
1027
venus_pm_get(enum hfi_version version)1028 const struct venus_pm_ops *venus_pm_get(enum hfi_version version)
1029 {
1030 switch (version) {
1031 case HFI_VERSION_1XX:
1032 default:
1033 return &pm_ops_v1;
1034 case HFI_VERSION_3XX:
1035 return &pm_ops_v3;
1036 case HFI_VERSION_4XX:
1037 return &pm_ops_v4;
1038 }
1039
1040 return NULL;
1041 }
1042