Merge branches 'acpi-apei', 'acpi-misc' and 'acpi-processor'
[linux-2.6-microblaze.git] / drivers / media / platform / qcom / venus / pm_helpers.c
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }