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