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