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 /*
216 * keep minimum bandwidth vote for "video-mem" path,
217 * so that clks can be disabled during vdec_session_release().
218 * Actual bandwidth drop will be done during device supend
219 * so that device can power down without any warnings.
220 */
221
222 if (!total_avg && !total_peak)
223 total_avg = kbps_to_icc(1000);
224
225 dev_dbg(core->dev, VDBGL "total: avg_bw: %u, peak_bw: %u\n",
226 total_avg, total_peak);
227
228 return icc_set_bw(core->video_path, total_avg, total_peak);
229 }
230
load_scale_v1(struct venus_inst * inst)231 static int load_scale_v1(struct venus_inst *inst)
232 {
233 struct venus_core *core = inst->core;
234 const struct freq_tbl *table = core->res->freq_tbl;
235 unsigned int num_rows = core->res->freq_tbl_size;
236 unsigned long freq = table[0].freq;
237 struct device *dev = core->dev;
238 u32 mbs_per_sec;
239 unsigned int i;
240 int ret;
241
242 mbs_per_sec = load_per_type(core, VIDC_SESSION_TYPE_ENC) +
243 load_per_type(core, VIDC_SESSION_TYPE_DEC);
244
245 if (mbs_per_sec > core->res->max_load)
246 dev_warn(dev, "HW is overloaded, needed: %d max: %d\n",
247 mbs_per_sec, core->res->max_load);
248
249 if (!mbs_per_sec && num_rows > 1) {
250 freq = table[num_rows - 1].freq;
251 goto set_freq;
252 }
253
254 for (i = 0; i < num_rows; i++) {
255 if (mbs_per_sec > table[i].load)
256 break;
257 freq = table[i].freq;
258 }
259
260 set_freq:
261
262 ret = core_clks_set_rate(core, freq);
263 if (ret) {
264 dev_err(dev, "failed to set clock rate %lu (%d)\n",
265 freq, ret);
266 return ret;
267 }
268
269 ret = load_scale_bw(core);
270 if (ret) {
271 dev_err(dev, "failed to set bandwidth (%d)\n",
272 ret);
273 return ret;
274 }
275
276 return 0;
277 }
278
core_get_v1(struct device * dev)279 static int core_get_v1(struct device *dev)
280 {
281 struct venus_core *core = dev_get_drvdata(dev);
282
283 return core_clks_get(core);
284 }
285
core_power_v1(struct device * dev,int on)286 static int core_power_v1(struct device *dev, int on)
287 {
288 struct venus_core *core = dev_get_drvdata(dev);
289 int ret = 0;
290
291 if (on == POWER_ON)
292 ret = core_clks_enable(core);
293 else
294 core_clks_disable(core);
295
296 return ret;
297 }
298
299 static const struct venus_pm_ops pm_ops_v1 = {
300 .core_get = core_get_v1,
301 .core_power = core_power_v1,
302 .load_scale = load_scale_v1,
303 };
304
305 static void
vcodec_control_v3(struct venus_core * core,u32 session_type,bool enable)306 vcodec_control_v3(struct venus_core *core, u32 session_type, bool enable)
307 {
308 void __iomem *ctrl;
309
310 if (session_type == VIDC_SESSION_TYPE_DEC)
311 ctrl = core->base + WRAPPER_VDEC_VCODEC_POWER_CONTROL;
312 else
313 ctrl = core->base + WRAPPER_VENC_VCODEC_POWER_CONTROL;
314
315 if (enable)
316 writel(0, ctrl);
317 else
318 writel(1, ctrl);
319 }
320
vdec_get_v3(struct device * dev)321 static int vdec_get_v3(struct device *dev)
322 {
323 struct venus_core *core = dev_get_drvdata(dev);
324
325 return vcodec_clks_get(core, dev, core->vcodec0_clks,
326 core->res->vcodec0_clks);
327 }
328
vdec_power_v3(struct device * dev,int on)329 static int vdec_power_v3(struct device *dev, int on)
330 {
331 struct venus_core *core = dev_get_drvdata(dev);
332 int ret = 0;
333
334 vcodec_control_v3(core, VIDC_SESSION_TYPE_DEC, true);
335
336 if (on == POWER_ON)
337 ret = vcodec_clks_enable(core, core->vcodec0_clks);
338 else
339 vcodec_clks_disable(core, core->vcodec0_clks);
340
341 vcodec_control_v3(core, VIDC_SESSION_TYPE_DEC, false);
342
343 return ret;
344 }
345
venc_get_v3(struct device * dev)346 static int venc_get_v3(struct device *dev)
347 {
348 struct venus_core *core = dev_get_drvdata(dev);
349
350 return vcodec_clks_get(core, dev, core->vcodec1_clks,
351 core->res->vcodec1_clks);
352 }
353
venc_power_v3(struct device * dev,int on)354 static int venc_power_v3(struct device *dev, int on)
355 {
356 struct venus_core *core = dev_get_drvdata(dev);
357 int ret = 0;
358
359 vcodec_control_v3(core, VIDC_SESSION_TYPE_ENC, true);
360
361 if (on == POWER_ON)
362 ret = vcodec_clks_enable(core, core->vcodec1_clks);
363 else
364 vcodec_clks_disable(core, core->vcodec1_clks);
365
366 vcodec_control_v3(core, VIDC_SESSION_TYPE_ENC, false);
367
368 return ret;
369 }
370
371 static const struct venus_pm_ops pm_ops_v3 = {
372 .core_get = core_get_v1,
373 .core_power = core_power_v1,
374 .vdec_get = vdec_get_v3,
375 .vdec_power = vdec_power_v3,
376 .venc_get = venc_get_v3,
377 .venc_power = venc_power_v3,
378 .load_scale = load_scale_v1,
379 };
380
vcodec_control_v4(struct venus_core * core,u32 coreid,bool enable)381 static int vcodec_control_v4(struct venus_core *core, u32 coreid, bool enable)
382 {
383 void __iomem *ctrl, *stat;
384 u32 val;
385 int ret;
386
387 if (coreid == VIDC_CORE_ID_1) {
388 ctrl = core->base + WRAPPER_VCODEC0_MMCC_POWER_CONTROL;
389 stat = core->base + WRAPPER_VCODEC0_MMCC_POWER_STATUS;
390 } else {
391 ctrl = core->base + WRAPPER_VCODEC1_MMCC_POWER_CONTROL;
392 stat = core->base + WRAPPER_VCODEC1_MMCC_POWER_STATUS;
393 }
394
395 if (enable) {
396 writel(0, ctrl);
397
398 ret = readl_poll_timeout(stat, val, val & BIT(1), 1, 100);
399 if (ret)
400 return ret;
401 } else {
402 writel(1, ctrl);
403
404 ret = readl_poll_timeout(stat, val, !(val & BIT(1)), 1, 100);
405 if (ret)
406 return ret;
407 }
408
409 return 0;
410 }
411
poweroff_coreid(struct venus_core * core,unsigned int coreid_mask)412 static int poweroff_coreid(struct venus_core *core, unsigned int coreid_mask)
413 {
414 int ret;
415
416 if (coreid_mask & VIDC_CORE_ID_1) {
417 ret = vcodec_control_v4(core, VIDC_CORE_ID_1, true);
418 if (ret)
419 return ret;
420
421 vcodec_clks_disable(core, core->vcodec0_clks);
422
423 ret = vcodec_control_v4(core, VIDC_CORE_ID_1, false);
424 if (ret)
425 return ret;
426
427 ret = pm_runtime_put_sync(core->pmdomains[1]);
428 if (ret < 0)
429 return ret;
430 }
431
432 if (coreid_mask & VIDC_CORE_ID_2) {
433 ret = vcodec_control_v4(core, VIDC_CORE_ID_2, true);
434 if (ret)
435 return ret;
436
437 vcodec_clks_disable(core, core->vcodec1_clks);
438
439 ret = vcodec_control_v4(core, VIDC_CORE_ID_2, false);
440 if (ret)
441 return ret;
442
443 ret = pm_runtime_put_sync(core->pmdomains[2]);
444 if (ret < 0)
445 return ret;
446 }
447
448 return 0;
449 }
450
poweron_coreid(struct venus_core * core,unsigned int coreid_mask)451 static int poweron_coreid(struct venus_core *core, unsigned int coreid_mask)
452 {
453 int ret;
454
455 if (coreid_mask & VIDC_CORE_ID_1) {
456 ret = pm_runtime_get_sync(core->pmdomains[1]);
457 if (ret < 0)
458 return ret;
459
460 ret = vcodec_control_v4(core, VIDC_CORE_ID_1, true);
461 if (ret)
462 return ret;
463
464 ret = vcodec_clks_enable(core, core->vcodec0_clks);
465 if (ret)
466 return ret;
467
468 ret = vcodec_control_v4(core, VIDC_CORE_ID_1, false);
469 if (ret < 0)
470 return ret;
471 }
472
473 if (coreid_mask & VIDC_CORE_ID_2) {
474 ret = pm_runtime_get_sync(core->pmdomains[2]);
475 if (ret < 0)
476 return ret;
477
478 ret = vcodec_control_v4(core, VIDC_CORE_ID_2, true);
479 if (ret)
480 return ret;
481
482 ret = vcodec_clks_enable(core, core->vcodec1_clks);
483 if (ret)
484 return ret;
485
486 ret = vcodec_control_v4(core, VIDC_CORE_ID_2, false);
487 if (ret < 0)
488 return ret;
489 }
490
491 return 0;
492 }
493
494 static void
min_loaded_core(struct venus_inst * inst,u32 * min_coreid,u32 * min_load)495 min_loaded_core(struct venus_inst *inst, u32 *min_coreid, u32 *min_load)
496 {
497 u32 mbs_per_sec, load, core1_load = 0, core2_load = 0;
498 u32 cores_max = core_num_max(inst);
499 struct venus_core *core = inst->core;
500 struct venus_inst *inst_pos;
501 unsigned long vpp_freq;
502 u32 coreid;
503
504 mutex_lock(&core->lock);
505
506 list_for_each_entry(inst_pos, &core->instances, list) {
507 if (inst_pos == inst)
508 continue;
509
510 if (inst_pos->state != INST_START)
511 continue;
512
513 vpp_freq = inst_pos->clk_data.codec_freq_data->vpp_freq;
514 coreid = inst_pos->clk_data.core_id;
515
516 mbs_per_sec = load_per_instance(inst_pos);
517 load = mbs_per_sec * vpp_freq;
518
519 if ((coreid & VIDC_CORE_ID_3) == VIDC_CORE_ID_3) {
520 core1_load += load / 2;
521 core2_load += load / 2;
522 } else if (coreid & VIDC_CORE_ID_1) {
523 core1_load += load;
524 } else if (coreid & VIDC_CORE_ID_2) {
525 core2_load += load;
526 }
527 }
528
529 *min_coreid = core1_load <= core2_load ?
530 VIDC_CORE_ID_1 : VIDC_CORE_ID_2;
531 *min_load = min(core1_load, core2_load);
532
533 if (cores_max < VIDC_CORE_ID_2 || core->res->vcodec_num < 2) {
534 *min_coreid = VIDC_CORE_ID_1;
535 *min_load = core1_load;
536 }
537
538 mutex_unlock(&core->lock);
539 }
540
decide_core(struct venus_inst * inst)541 static int decide_core(struct venus_inst *inst)
542 {
543 const u32 ptype = HFI_PROPERTY_CONFIG_VIDEOCORES_USAGE;
544 struct venus_core *core = inst->core;
545 u32 min_coreid, min_load, inst_load;
546 struct hfi_videocores_usage_type cu;
547 unsigned long max_freq;
548
549 if (legacy_binding) {
550 if (inst->session_type == VIDC_SESSION_TYPE_DEC)
551 cu.video_core_enable_mask = VIDC_CORE_ID_1;
552 else
553 cu.video_core_enable_mask = VIDC_CORE_ID_2;
554
555 goto done;
556 }
557
558 if (inst->clk_data.core_id != VIDC_CORE_ID_DEFAULT)
559 return 0;
560
561 inst_load = load_per_instance(inst);
562 inst_load *= inst->clk_data.codec_freq_data->vpp_freq;
563 max_freq = core->res->freq_tbl[0].freq;
564
565 min_loaded_core(inst, &min_coreid, &min_load);
566
567 if ((inst_load + min_load) > max_freq) {
568 dev_warn(core->dev, "HW is overloaded, needed: %u max: %lu\n",
569 inst_load, max_freq);
570 return -EINVAL;
571 }
572
573 inst->clk_data.core_id = min_coreid;
574 cu.video_core_enable_mask = min_coreid;
575
576 done:
577 return hfi_session_set_property(inst, ptype, &cu);
578 }
579
acquire_core(struct venus_inst * inst)580 static int acquire_core(struct venus_inst *inst)
581 {
582 struct venus_core *core = inst->core;
583 unsigned int coreid_mask = 0;
584
585 if (inst->core_acquired)
586 return 0;
587
588 inst->core_acquired = true;
589
590 if (inst->clk_data.core_id & VIDC_CORE_ID_1) {
591 if (core->core0_usage_count++)
592 return 0;
593
594 coreid_mask = VIDC_CORE_ID_1;
595 }
596
597 if (inst->clk_data.core_id & VIDC_CORE_ID_2) {
598 if (core->core1_usage_count++)
599 return 0;
600
601 coreid_mask |= VIDC_CORE_ID_2;
602 }
603
604 return poweron_coreid(core, coreid_mask);
605 }
606
release_core(struct venus_inst * inst)607 static int release_core(struct venus_inst *inst)
608 {
609 struct venus_core *core = inst->core;
610 unsigned int coreid_mask = 0;
611 int ret;
612
613 if (!inst->core_acquired)
614 return 0;
615
616 if (inst->clk_data.core_id & VIDC_CORE_ID_1) {
617 if (--core->core0_usage_count)
618 goto done;
619
620 coreid_mask = VIDC_CORE_ID_1;
621 }
622
623 if (inst->clk_data.core_id & VIDC_CORE_ID_2) {
624 if (--core->core1_usage_count)
625 goto done;
626
627 coreid_mask |= VIDC_CORE_ID_2;
628 }
629
630 ret = poweroff_coreid(core, coreid_mask);
631 if (ret)
632 return ret;
633
634 done:
635 inst->clk_data.core_id = VIDC_CORE_ID_DEFAULT;
636 inst->core_acquired = false;
637 return 0;
638 }
639
coreid_power_v4(struct venus_inst * inst,int on)640 static int coreid_power_v4(struct venus_inst *inst, int on)
641 {
642 struct venus_core *core = inst->core;
643 int ret;
644
645 if (legacy_binding)
646 return 0;
647
648 if (on == POWER_ON) {
649 ret = decide_core(inst);
650 if (ret)
651 return ret;
652
653 mutex_lock(&core->lock);
654 ret = acquire_core(inst);
655 mutex_unlock(&core->lock);
656 } else {
657 mutex_lock(&core->lock);
658 ret = release_core(inst);
659 mutex_unlock(&core->lock);
660 }
661
662 return ret;
663 }
664
vdec_get_v4(struct device * dev)665 static int vdec_get_v4(struct device *dev)
666 {
667 struct venus_core *core = dev_get_drvdata(dev);
668
669 if (!legacy_binding)
670 return 0;
671
672 return vcodec_clks_get(core, dev, core->vcodec0_clks,
673 core->res->vcodec0_clks);
674 }
675
vdec_put_v4(struct device * dev)676 static void vdec_put_v4(struct device *dev)
677 {
678 struct venus_core *core = dev_get_drvdata(dev);
679 unsigned int i;
680
681 if (!legacy_binding)
682 return;
683
684 for (i = 0; i < core->res->vcodec_clks_num; i++)
685 core->vcodec0_clks[i] = NULL;
686 }
687
vdec_power_v4(struct device * dev,int on)688 static int vdec_power_v4(struct device *dev, int on)
689 {
690 struct venus_core *core = dev_get_drvdata(dev);
691 int ret;
692
693 if (!legacy_binding)
694 return 0;
695
696 ret = vcodec_control_v4(core, VIDC_CORE_ID_1, true);
697 if (ret)
698 return ret;
699
700 if (on == POWER_ON)
701 ret = vcodec_clks_enable(core, core->vcodec0_clks);
702 else
703 vcodec_clks_disable(core, core->vcodec0_clks);
704
705 vcodec_control_v4(core, VIDC_CORE_ID_1, false);
706
707 return ret;
708 }
709
venc_get_v4(struct device * dev)710 static int venc_get_v4(struct device *dev)
711 {
712 struct venus_core *core = dev_get_drvdata(dev);
713
714 if (!legacy_binding)
715 return 0;
716
717 return vcodec_clks_get(core, dev, core->vcodec1_clks,
718 core->res->vcodec1_clks);
719 }
720
venc_put_v4(struct device * dev)721 static void venc_put_v4(struct device *dev)
722 {
723 struct venus_core *core = dev_get_drvdata(dev);
724 unsigned int i;
725
726 if (!legacy_binding)
727 return;
728
729 for (i = 0; i < core->res->vcodec_clks_num; i++)
730 core->vcodec1_clks[i] = NULL;
731 }
732
venc_power_v4(struct device * dev,int on)733 static int venc_power_v4(struct device *dev, int on)
734 {
735 struct venus_core *core = dev_get_drvdata(dev);
736 int ret;
737
738 if (!legacy_binding)
739 return 0;
740
741 ret = vcodec_control_v4(core, VIDC_CORE_ID_2, true);
742 if (ret)
743 return ret;
744
745 if (on == POWER_ON)
746 ret = vcodec_clks_enable(core, core->vcodec1_clks);
747 else
748 vcodec_clks_disable(core, core->vcodec1_clks);
749
750 vcodec_control_v4(core, VIDC_CORE_ID_2, false);
751
752 return ret;
753 }
754
vcodec_domains_get(struct device * dev)755 static int vcodec_domains_get(struct device *dev)
756 {
757 int ret;
758 struct opp_table *opp_table;
759 struct device **opp_virt_dev;
760 struct venus_core *core = dev_get_drvdata(dev);
761 const struct venus_resources *res = core->res;
762 struct device *pd;
763 unsigned int i;
764
765 if (!res->vcodec_pmdomains_num)
766 goto skip_pmdomains;
767
768 for (i = 0; i < res->vcodec_pmdomains_num; i++) {
769 pd = dev_pm_domain_attach_by_name(dev,
770 res->vcodec_pmdomains[i]);
771 if (IS_ERR(pd))
772 return PTR_ERR(pd);
773 core->pmdomains[i] = pd;
774 }
775
776 core->pd_dl_venus = device_link_add(dev, core->pmdomains[0],
777 DL_FLAG_PM_RUNTIME |
778 DL_FLAG_STATELESS |
779 DL_FLAG_RPM_ACTIVE);
780 if (!core->pd_dl_venus)
781 return -ENODEV;
782
783 skip_pmdomains:
784 if (!core->has_opp_table)
785 return 0;
786
787 /* Attach the power domain for setting performance state */
788 opp_table = dev_pm_opp_attach_genpd(dev, res->opp_pmdomain, &opp_virt_dev);
789 if (IS_ERR(opp_table)) {
790 ret = PTR_ERR(opp_table);
791 goto opp_attach_err;
792 }
793
794 core->opp_pmdomain = *opp_virt_dev;
795 core->opp_dl_venus = device_link_add(dev, core->opp_pmdomain,
796 DL_FLAG_RPM_ACTIVE |
797 DL_FLAG_PM_RUNTIME |
798 DL_FLAG_STATELESS);
799 if (!core->opp_dl_venus) {
800 ret = -ENODEV;
801 goto opp_dl_add_err;
802 }
803
804 return 0;
805
806 opp_dl_add_err:
807 dev_pm_opp_detach_genpd(core->opp_table);
808 opp_attach_err:
809 if (core->pd_dl_venus) {
810 device_link_del(core->pd_dl_venus);
811 for (i = 0; i < res->vcodec_pmdomains_num; i++) {
812 if (IS_ERR_OR_NULL(core->pmdomains[i]))
813 continue;
814 dev_pm_domain_detach(core->pmdomains[i], true);
815 }
816 }
817 return ret;
818 }
819
vcodec_domains_put(struct device * dev)820 static void vcodec_domains_put(struct device *dev)
821 {
822 struct venus_core *core = dev_get_drvdata(dev);
823 const struct venus_resources *res = core->res;
824 unsigned int i;
825
826 if (!res->vcodec_pmdomains_num)
827 goto skip_pmdomains;
828
829 if (core->pd_dl_venus)
830 device_link_del(core->pd_dl_venus);
831
832 for (i = 0; i < res->vcodec_pmdomains_num; i++) {
833 if (IS_ERR_OR_NULL(core->pmdomains[i]))
834 continue;
835 dev_pm_domain_detach(core->pmdomains[i], true);
836 }
837
838 skip_pmdomains:
839 if (!core->has_opp_table)
840 return;
841
842 if (core->opp_dl_venus)
843 device_link_del(core->opp_dl_venus);
844
845 dev_pm_opp_detach_genpd(core->opp_table);
846 }
847
core_get_v4(struct device * dev)848 static int core_get_v4(struct device *dev)
849 {
850 struct venus_core *core = dev_get_drvdata(dev);
851 const struct venus_resources *res = core->res;
852 int ret;
853
854 ret = core_clks_get(core);
855 if (ret)
856 return ret;
857
858 if (!res->vcodec_pmdomains_num)
859 legacy_binding = true;
860
861 dev_info(dev, "%s legacy binding\n", legacy_binding ? "" : "non");
862
863 ret = vcodec_clks_get(core, dev, core->vcodec0_clks, res->vcodec0_clks);
864 if (ret)
865 return ret;
866
867 ret = vcodec_clks_get(core, dev, core->vcodec1_clks, res->vcodec1_clks);
868 if (ret)
869 return ret;
870
871 if (legacy_binding)
872 return 0;
873
874 core->opp_table = dev_pm_opp_set_clkname(dev, "core");
875 if (IS_ERR(core->opp_table))
876 return PTR_ERR(core->opp_table);
877
878 if (core->res->opp_pmdomain) {
879 ret = dev_pm_opp_of_add_table(dev);
880 if (!ret) {
881 core->has_opp_table = true;
882 } else if (ret != -ENODEV) {
883 dev_err(dev, "invalid OPP table in device tree\n");
884 dev_pm_opp_put_clkname(core->opp_table);
885 return ret;
886 }
887 }
888
889 ret = vcodec_domains_get(dev);
890 if (ret) {
891 if (core->has_opp_table)
892 dev_pm_opp_of_remove_table(dev);
893 dev_pm_opp_put_clkname(core->opp_table);
894 return ret;
895 }
896
897 return 0;
898 }
899
core_put_v4(struct device * dev)900 static void core_put_v4(struct device *dev)
901 {
902 struct venus_core *core = dev_get_drvdata(dev);
903
904 if (legacy_binding)
905 return;
906
907 vcodec_domains_put(dev);
908
909 if (core->has_opp_table)
910 dev_pm_opp_of_remove_table(dev);
911 if (core->opp_table)
912 dev_pm_opp_put_clkname(core->opp_table);
913
914 }
915
core_power_v4(struct device * dev,int on)916 static int core_power_v4(struct device *dev, int on)
917 {
918 struct venus_core *core = dev_get_drvdata(dev);
919 int ret = 0;
920
921 if (on == POWER_ON) {
922 ret = core_clks_enable(core);
923 } else {
924 /* Drop the performance state vote */
925 if (core->opp_pmdomain)
926 dev_pm_opp_set_rate(dev, 0);
927
928 core_clks_disable(core);
929 }
930
931 return ret;
932 }
933
calculate_inst_freq(struct venus_inst * inst,unsigned long filled_len)934 static unsigned long calculate_inst_freq(struct venus_inst *inst,
935 unsigned long filled_len)
936 {
937 unsigned long vpp_freq = 0, vsp_freq = 0;
938 u32 fps = (u32)inst->fps;
939 u32 mbs_per_sec;
940
941 mbs_per_sec = load_per_instance(inst) / fps;
942
943 vpp_freq = mbs_per_sec * inst->clk_data.codec_freq_data->vpp_freq;
944 /* 21 / 20 is overhead factor */
945 vpp_freq += vpp_freq / 20;
946 vsp_freq = mbs_per_sec * inst->clk_data.codec_freq_data->vsp_freq;
947
948 /* 10 / 7 is overhead factor */
949 if (inst->session_type == VIDC_SESSION_TYPE_ENC)
950 vsp_freq += (inst->controls.enc.bitrate * 10) / 7;
951 else
952 vsp_freq += ((fps * filled_len * 8) * 10) / 7;
953
954 return max(vpp_freq, vsp_freq);
955 }
956
load_scale_v4(struct venus_inst * inst)957 static int load_scale_v4(struct venus_inst *inst)
958 {
959 struct venus_core *core = inst->core;
960 const struct freq_tbl *table = core->res->freq_tbl;
961 unsigned int num_rows = core->res->freq_tbl_size;
962 struct device *dev = core->dev;
963 unsigned long freq = 0, freq_core1 = 0, freq_core2 = 0;
964 unsigned long filled_len = 0;
965 int i, ret;
966
967 for (i = 0; i < inst->num_input_bufs; i++)
968 filled_len = max(filled_len, inst->payloads[i]);
969
970 if (inst->session_type == VIDC_SESSION_TYPE_DEC && !filled_len)
971 return 0;
972
973 freq = calculate_inst_freq(inst, filled_len);
974 inst->clk_data.freq = freq;
975
976 mutex_lock(&core->lock);
977 list_for_each_entry(inst, &core->instances, list) {
978 if (inst->clk_data.core_id == VIDC_CORE_ID_1) {
979 freq_core1 += inst->clk_data.freq;
980 } else if (inst->clk_data.core_id == VIDC_CORE_ID_2) {
981 freq_core2 += inst->clk_data.freq;
982 } else if (inst->clk_data.core_id == VIDC_CORE_ID_3) {
983 freq_core1 += inst->clk_data.freq;
984 freq_core2 += inst->clk_data.freq;
985 }
986 }
987 mutex_unlock(&core->lock);
988
989 freq = max(freq_core1, freq_core2);
990
991 if (freq >= table[0].freq) {
992 freq = table[0].freq;
993 dev_warn(dev, "HW is overloaded, needed: %lu max: %lu\n",
994 freq, table[0].freq);
995 goto set_freq;
996 }
997
998 for (i = num_rows - 1 ; i >= 0; i--) {
999 if (freq <= table[i].freq) {
1000 freq = table[i].freq;
1001 break;
1002 }
1003 }
1004
1005 set_freq:
1006
1007 ret = core_clks_set_rate(core, freq);
1008 if (ret) {
1009 dev_err(dev, "failed to set clock rate %lu (%d)\n",
1010 freq, ret);
1011 return ret;
1012 }
1013
1014 ret = load_scale_bw(core);
1015 if (ret) {
1016 dev_err(dev, "failed to set bandwidth (%d)\n",
1017 ret);
1018 return ret;
1019 }
1020
1021 return 0;
1022 }
1023
1024 static const struct venus_pm_ops pm_ops_v4 = {
1025 .core_get = core_get_v4,
1026 .core_put = core_put_v4,
1027 .core_power = core_power_v4,
1028 .vdec_get = vdec_get_v4,
1029 .vdec_put = vdec_put_v4,
1030 .vdec_power = vdec_power_v4,
1031 .venc_get = venc_get_v4,
1032 .venc_put = venc_put_v4,
1033 .venc_power = venc_power_v4,
1034 .coreid_power = coreid_power_v4,
1035 .load_scale = load_scale_v4,
1036 };
1037
venus_pm_get(enum hfi_version version)1038 const struct venus_pm_ops *venus_pm_get(enum hfi_version version)
1039 {
1040 switch (version) {
1041 case HFI_VERSION_1XX:
1042 default:
1043 return &pm_ops_v1;
1044 case HFI_VERSION_3XX:
1045 return &pm_ops_v3;
1046 case HFI_VERSION_4XX:
1047 return &pm_ops_v4;
1048 }
1049
1050 return NULL;
1051 }
1052