xref: /linux/drivers/media/platform/qcom/venus/pm_helpers.c (revision 3a39d672e7f48b8d6b91a09afa4b55352773b4b5)
17482a983SStanimir Varbanov // SPDX-License-Identifier: GPL-2.0
27482a983SStanimir Varbanov /*
37482a983SStanimir Varbanov  * Copyright (C) 2019 Linaro Ltd.
47482a983SStanimir Varbanov  *
57482a983SStanimir Varbanov  * Author: Stanimir Varbanov <stanimir.varbanov@linaro.org>
67482a983SStanimir Varbanov  */
77482a983SStanimir Varbanov #include <linux/clk.h>
87482a983SStanimir Varbanov #include <linux/interconnect.h>
97482a983SStanimir Varbanov #include <linux/iopoll.h>
107482a983SStanimir Varbanov #include <linux/kernel.h>
117482a983SStanimir Varbanov #include <linux/pm_domain.h>
129a538b83SRajendra Nayak #include <linux/pm_opp.h>
137482a983SStanimir Varbanov #include <linux/pm_runtime.h>
143bca4358SStanimir Varbanov #include <linux/reset.h>
157482a983SStanimir Varbanov #include <linux/types.h>
167482a983SStanimir Varbanov #include <media/v4l2-mem2mem.h>
177482a983SStanimir Varbanov 
187482a983SStanimir Varbanov #include "core.h"
194ebf9693SAniket Masule #include "hfi_parser.h"
207482a983SStanimir Varbanov #include "hfi_venus_io.h"
217482a983SStanimir Varbanov #include "pm_helpers.h"
22aa603389SStanimir Varbanov #include "hfi_platform.h"
237482a983SStanimir Varbanov 
247482a983SStanimir Varbanov static bool legacy_binding;
257482a983SStanimir Varbanov 
core_clks_get(struct venus_core * core)267482a983SStanimir Varbanov static int core_clks_get(struct venus_core *core)
277482a983SStanimir Varbanov {
287482a983SStanimir Varbanov 	const struct venus_resources *res = core->res;
297482a983SStanimir Varbanov 	struct device *dev = core->dev;
307482a983SStanimir Varbanov 	unsigned int i;
317482a983SStanimir Varbanov 
327482a983SStanimir Varbanov 	for (i = 0; i < res->clks_num; i++) {
337482a983SStanimir Varbanov 		core->clks[i] = devm_clk_get(dev, res->clks[i]);
347482a983SStanimir Varbanov 		if (IS_ERR(core->clks[i]))
357482a983SStanimir Varbanov 			return PTR_ERR(core->clks[i]);
367482a983SStanimir Varbanov 	}
377482a983SStanimir Varbanov 
387482a983SStanimir Varbanov 	return 0;
397482a983SStanimir Varbanov }
407482a983SStanimir Varbanov 
core_clks_enable(struct venus_core * core)417482a983SStanimir Varbanov static int core_clks_enable(struct venus_core *core)
427482a983SStanimir Varbanov {
437482a983SStanimir Varbanov 	const struct venus_resources *res = core->res;
44c22b1a29SDikshita Agarwal 	const struct freq_tbl *freq_tbl = core->res->freq_tbl;
45c22b1a29SDikshita Agarwal 	unsigned int freq_tbl_size = core->res->freq_tbl_size;
46c22b1a29SDikshita Agarwal 	unsigned long freq;
477482a983SStanimir Varbanov 	unsigned int i;
487482a983SStanimir Varbanov 	int ret;
497482a983SStanimir Varbanov 
50c22b1a29SDikshita Agarwal 	if (!freq_tbl)
51c22b1a29SDikshita Agarwal 		return -EINVAL;
52c22b1a29SDikshita Agarwal 
53c22b1a29SDikshita Agarwal 	freq = freq_tbl[freq_tbl_size - 1].freq;
54c22b1a29SDikshita Agarwal 
557482a983SStanimir Varbanov 	for (i = 0; i < res->clks_num; i++) {
56c22b1a29SDikshita Agarwal 		if (IS_V6(core)) {
57c22b1a29SDikshita Agarwal 			ret = clk_set_rate(core->clks[i], freq);
58c22b1a29SDikshita Agarwal 			if (ret)
59c22b1a29SDikshita Agarwal 				goto err;
60c22b1a29SDikshita Agarwal 		}
61c22b1a29SDikshita Agarwal 
627482a983SStanimir Varbanov 		ret = clk_prepare_enable(core->clks[i]);
637482a983SStanimir Varbanov 		if (ret)
647482a983SStanimir Varbanov 			goto err;
657482a983SStanimir Varbanov 	}
667482a983SStanimir Varbanov 
677482a983SStanimir Varbanov 	return 0;
687482a983SStanimir Varbanov err:
697482a983SStanimir Varbanov 	while (i--)
707482a983SStanimir Varbanov 		clk_disable_unprepare(core->clks[i]);
717482a983SStanimir Varbanov 
727482a983SStanimir Varbanov 	return ret;
737482a983SStanimir Varbanov }
747482a983SStanimir Varbanov 
core_clks_disable(struct venus_core * core)757482a983SStanimir Varbanov static void core_clks_disable(struct venus_core *core)
767482a983SStanimir Varbanov {
777482a983SStanimir Varbanov 	const struct venus_resources *res = core->res;
787482a983SStanimir Varbanov 	unsigned int i = res->clks_num;
797482a983SStanimir Varbanov 
807482a983SStanimir Varbanov 	while (i--)
817482a983SStanimir Varbanov 		clk_disable_unprepare(core->clks[i]);
827482a983SStanimir Varbanov }
837482a983SStanimir Varbanov 
core_clks_set_rate(struct venus_core * core,unsigned long freq)847482a983SStanimir Varbanov static int core_clks_set_rate(struct venus_core *core, unsigned long freq)
857482a983SStanimir Varbanov {
867482a983SStanimir Varbanov 	int ret;
877482a983SStanimir Varbanov 
889a538b83SRajendra Nayak 	ret = dev_pm_opp_set_rate(core->dev, freq);
897482a983SStanimir Varbanov 	if (ret)
907482a983SStanimir Varbanov 		return ret;
917482a983SStanimir Varbanov 
927482a983SStanimir Varbanov 	ret = clk_set_rate(core->vcodec0_clks[0], freq);
937482a983SStanimir Varbanov 	if (ret)
947482a983SStanimir Varbanov 		return ret;
957482a983SStanimir Varbanov 
967482a983SStanimir Varbanov 	ret = clk_set_rate(core->vcodec1_clks[0], freq);
977482a983SStanimir Varbanov 	if (ret)
987482a983SStanimir Varbanov 		return ret;
997482a983SStanimir Varbanov 
1007482a983SStanimir Varbanov 	return 0;
1017482a983SStanimir Varbanov }
1027482a983SStanimir Varbanov 
vcodec_clks_get(struct venus_core * core,struct device * dev,struct clk ** clks,const char * const * id)1037482a983SStanimir Varbanov static int vcodec_clks_get(struct venus_core *core, struct device *dev,
1047482a983SStanimir Varbanov 			   struct clk **clks, const char * const *id)
1057482a983SStanimir Varbanov {
1067482a983SStanimir Varbanov 	const struct venus_resources *res = core->res;
1077482a983SStanimir Varbanov 	unsigned int i;
1087482a983SStanimir Varbanov 
1097482a983SStanimir Varbanov 	for (i = 0; i < res->vcodec_clks_num; i++) {
1107482a983SStanimir Varbanov 		if (!id[i])
1117482a983SStanimir Varbanov 			continue;
1127482a983SStanimir Varbanov 		clks[i] = devm_clk_get(dev, id[i]);
1137482a983SStanimir Varbanov 		if (IS_ERR(clks[i]))
1147482a983SStanimir Varbanov 			return PTR_ERR(clks[i]);
1157482a983SStanimir Varbanov 	}
1167482a983SStanimir Varbanov 
1177482a983SStanimir Varbanov 	return 0;
1187482a983SStanimir Varbanov }
1197482a983SStanimir Varbanov 
vcodec_clks_enable(struct venus_core * core,struct clk ** clks)1207482a983SStanimir Varbanov static int vcodec_clks_enable(struct venus_core *core, struct clk **clks)
1217482a983SStanimir Varbanov {
1227482a983SStanimir Varbanov 	const struct venus_resources *res = core->res;
1237482a983SStanimir Varbanov 	unsigned int i;
1247482a983SStanimir Varbanov 	int ret;
1257482a983SStanimir Varbanov 
1267482a983SStanimir Varbanov 	for (i = 0; i < res->vcodec_clks_num; i++) {
1277482a983SStanimir Varbanov 		ret = clk_prepare_enable(clks[i]);
1287482a983SStanimir Varbanov 		if (ret)
1297482a983SStanimir Varbanov 			goto err;
1307482a983SStanimir Varbanov 	}
1317482a983SStanimir Varbanov 
1327482a983SStanimir Varbanov 	return 0;
1337482a983SStanimir Varbanov err:
1347482a983SStanimir Varbanov 	while (i--)
1357482a983SStanimir Varbanov 		clk_disable_unprepare(clks[i]);
1367482a983SStanimir Varbanov 
1377482a983SStanimir Varbanov 	return ret;
1387482a983SStanimir Varbanov }
1397482a983SStanimir Varbanov 
vcodec_clks_disable(struct venus_core * core,struct clk ** clks)1407482a983SStanimir Varbanov static void vcodec_clks_disable(struct venus_core *core, struct clk **clks)
1417482a983SStanimir Varbanov {
1427482a983SStanimir Varbanov 	const struct venus_resources *res = core->res;
1437482a983SStanimir Varbanov 	unsigned int i = res->vcodec_clks_num;
1447482a983SStanimir Varbanov 
1457482a983SStanimir Varbanov 	while (i--)
1467482a983SStanimir Varbanov 		clk_disable_unprepare(clks[i]);
1477482a983SStanimir Varbanov }
1487482a983SStanimir Varbanov 
load_per_instance(struct venus_inst * inst)1497482a983SStanimir Varbanov static u32 load_per_instance(struct venus_inst *inst)
1507482a983SStanimir Varbanov {
1517482a983SStanimir Varbanov 	u32 mbs;
1527482a983SStanimir Varbanov 
1537482a983SStanimir Varbanov 	if (!inst || !(inst->state >= INST_INIT && inst->state < INST_STOP))
1547482a983SStanimir Varbanov 		return 0;
1557482a983SStanimir Varbanov 
1567482a983SStanimir Varbanov 	mbs = (ALIGN(inst->width, 16) / 16) * (ALIGN(inst->height, 16) / 16);
1577482a983SStanimir Varbanov 
1587482a983SStanimir Varbanov 	return mbs * inst->fps;
1597482a983SStanimir Varbanov }
1607482a983SStanimir Varbanov 
load_per_type(struct venus_core * core,u32 session_type)1617482a983SStanimir Varbanov static u32 load_per_type(struct venus_core *core, u32 session_type)
1627482a983SStanimir Varbanov {
1637482a983SStanimir Varbanov 	struct venus_inst *inst = NULL;
1647482a983SStanimir Varbanov 	u32 mbs_per_sec = 0;
1657482a983SStanimir Varbanov 
1667482a983SStanimir Varbanov 	list_for_each_entry(inst, &core->instances, list) {
1677482a983SStanimir Varbanov 		if (inst->session_type != session_type)
1687482a983SStanimir Varbanov 			continue;
1697482a983SStanimir Varbanov 
1707482a983SStanimir Varbanov 		mbs_per_sec += load_per_instance(inst);
1717482a983SStanimir Varbanov 	}
1727482a983SStanimir Varbanov 
1737482a983SStanimir Varbanov 	return mbs_per_sec;
1747482a983SStanimir Varbanov }
1757482a983SStanimir Varbanov 
mbs_to_bw(struct venus_inst * inst,u32 mbs,u32 * avg,u32 * peak)1767482a983SStanimir Varbanov static void mbs_to_bw(struct venus_inst *inst, u32 mbs, u32 *avg, u32 *peak)
1777482a983SStanimir Varbanov {
1787482a983SStanimir Varbanov 	const struct venus_resources *res = inst->core->res;
1797482a983SStanimir Varbanov 	const struct bw_tbl *bw_tbl;
1807482a983SStanimir Varbanov 	unsigned int num_rows, i;
1817482a983SStanimir Varbanov 
1827482a983SStanimir Varbanov 	*avg = 0;
1837482a983SStanimir Varbanov 	*peak = 0;
1847482a983SStanimir Varbanov 
1857482a983SStanimir Varbanov 	if (mbs == 0)
1867482a983SStanimir Varbanov 		return;
1877482a983SStanimir Varbanov 
1887482a983SStanimir Varbanov 	if (inst->session_type == VIDC_SESSION_TYPE_ENC) {
1897482a983SStanimir Varbanov 		num_rows = res->bw_tbl_enc_size;
1907482a983SStanimir Varbanov 		bw_tbl = res->bw_tbl_enc;
1917482a983SStanimir Varbanov 	} else if (inst->session_type == VIDC_SESSION_TYPE_DEC) {
1927482a983SStanimir Varbanov 		num_rows = res->bw_tbl_dec_size;
1937482a983SStanimir Varbanov 		bw_tbl = res->bw_tbl_dec;
1947482a983SStanimir Varbanov 	} else {
1957482a983SStanimir Varbanov 		return;
1967482a983SStanimir Varbanov 	}
1977482a983SStanimir Varbanov 
1987482a983SStanimir Varbanov 	if (!bw_tbl || num_rows == 0)
1997482a983SStanimir Varbanov 		return;
2007482a983SStanimir Varbanov 
2017482a983SStanimir Varbanov 	for (i = 0; i < num_rows; i++) {
2027bf28a21SVikash Garodia 		if (i != 0 && mbs > bw_tbl[i].mbs_per_sec)
2037482a983SStanimir Varbanov 			break;
2047482a983SStanimir Varbanov 
2057482a983SStanimir Varbanov 		if (inst->dpb_fmt & HFI_COLOR_FORMAT_10_BIT_BASE) {
2067482a983SStanimir Varbanov 			*avg = bw_tbl[i].avg_10bit;
2077482a983SStanimir Varbanov 			*peak = bw_tbl[i].peak_10bit;
2087482a983SStanimir Varbanov 		} else {
2097482a983SStanimir Varbanov 			*avg = bw_tbl[i].avg;
2107482a983SStanimir Varbanov 			*peak = bw_tbl[i].peak;
2117482a983SStanimir Varbanov 		}
2127482a983SStanimir Varbanov 	}
2137482a983SStanimir Varbanov }
2147482a983SStanimir Varbanov 
load_scale_bw(struct venus_core * core)2157482a983SStanimir Varbanov static int load_scale_bw(struct venus_core *core)
2167482a983SStanimir Varbanov {
2177482a983SStanimir Varbanov 	struct venus_inst *inst = NULL;
2187482a983SStanimir Varbanov 	u32 mbs_per_sec, avg, peak, total_avg = 0, total_peak = 0;
2197482a983SStanimir Varbanov 
2207482a983SStanimir Varbanov 	list_for_each_entry(inst, &core->instances, list) {
2217482a983SStanimir Varbanov 		mbs_per_sec = load_per_instance(inst);
2227482a983SStanimir Varbanov 		mbs_to_bw(inst, mbs_per_sec, &avg, &peak);
2237482a983SStanimir Varbanov 		total_avg += avg;
2247482a983SStanimir Varbanov 		total_peak += peak;
2257482a983SStanimir Varbanov 	}
2267482a983SStanimir Varbanov 
227eff5ce02SMansur Alisha Shaik 	/*
228eff5ce02SMansur Alisha Shaik 	 * keep minimum bandwidth vote for "video-mem" path,
229eff5ce02SMansur Alisha Shaik 	 * so that clks can be disabled during vdec_session_release().
230eff5ce02SMansur Alisha Shaik 	 * Actual bandwidth drop will be done during device supend
231eff5ce02SMansur Alisha Shaik 	 * so that device can power down without any warnings.
232eff5ce02SMansur Alisha Shaik 	 */
233eff5ce02SMansur Alisha Shaik 
234eff5ce02SMansur Alisha Shaik 	if (!total_avg && !total_peak)
235eff5ce02SMansur Alisha Shaik 		total_avg = kbps_to_icc(1000);
236eff5ce02SMansur Alisha Shaik 
2378c91dc08SStanimir Varbanov 	dev_dbg(core->dev, VDBGL "total: avg_bw: %u, peak_bw: %u\n",
2387482a983SStanimir Varbanov 		total_avg, total_peak);
2397482a983SStanimir Varbanov 
2407482a983SStanimir Varbanov 	return icc_set_bw(core->video_path, total_avg, total_peak);
2417482a983SStanimir Varbanov }
2427482a983SStanimir Varbanov 
load_scale_v1(struct venus_inst * inst)2437482a983SStanimir Varbanov static int load_scale_v1(struct venus_inst *inst)
2447482a983SStanimir Varbanov {
2457482a983SStanimir Varbanov 	struct venus_core *core = inst->core;
2467482a983SStanimir Varbanov 	const struct freq_tbl *table = core->res->freq_tbl;
2477482a983SStanimir Varbanov 	unsigned int num_rows = core->res->freq_tbl_size;
2487482a983SStanimir Varbanov 	unsigned long freq = table[0].freq;
2497482a983SStanimir Varbanov 	struct device *dev = core->dev;
2507482a983SStanimir Varbanov 	u32 mbs_per_sec;
2517482a983SStanimir Varbanov 	unsigned int i;
25291f2b7d2SMansur Alisha Shaik 	int ret = 0;
2537482a983SStanimir Varbanov 
25491f2b7d2SMansur Alisha Shaik 	mutex_lock(&core->lock);
2557482a983SStanimir Varbanov 	mbs_per_sec = load_per_type(core, VIDC_SESSION_TYPE_ENC) +
2567482a983SStanimir Varbanov 		      load_per_type(core, VIDC_SESSION_TYPE_DEC);
2577482a983SStanimir Varbanov 
2587482a983SStanimir Varbanov 	if (mbs_per_sec > core->res->max_load)
2597482a983SStanimir Varbanov 		dev_warn(dev, "HW is overloaded, needed: %d max: %d\n",
2607482a983SStanimir Varbanov 			 mbs_per_sec, core->res->max_load);
2617482a983SStanimir Varbanov 
2627482a983SStanimir Varbanov 	if (!mbs_per_sec && num_rows > 1) {
2637482a983SStanimir Varbanov 		freq = table[num_rows - 1].freq;
2647482a983SStanimir Varbanov 		goto set_freq;
2657482a983SStanimir Varbanov 	}
2667482a983SStanimir Varbanov 
2677482a983SStanimir Varbanov 	for (i = 0; i < num_rows; i++) {
2687482a983SStanimir Varbanov 		if (mbs_per_sec > table[i].load)
2697482a983SStanimir Varbanov 			break;
2707482a983SStanimir Varbanov 		freq = table[i].freq;
2717482a983SStanimir Varbanov 	}
2727482a983SStanimir Varbanov 
2737482a983SStanimir Varbanov set_freq:
2747482a983SStanimir Varbanov 
2757482a983SStanimir Varbanov 	ret = core_clks_set_rate(core, freq);
2767482a983SStanimir Varbanov 	if (ret) {
2777482a983SStanimir Varbanov 		dev_err(dev, "failed to set clock rate %lu (%d)\n",
2787482a983SStanimir Varbanov 			freq, ret);
27991f2b7d2SMansur Alisha Shaik 		goto exit;
2807482a983SStanimir Varbanov 	}
2817482a983SStanimir Varbanov 
2827482a983SStanimir Varbanov 	ret = load_scale_bw(core);
2837482a983SStanimir Varbanov 	if (ret) {
2847482a983SStanimir Varbanov 		dev_err(dev, "failed to set bandwidth (%d)\n",
2857482a983SStanimir Varbanov 			ret);
28691f2b7d2SMansur Alisha Shaik 		goto exit;
2877482a983SStanimir Varbanov 	}
2887482a983SStanimir Varbanov 
28991f2b7d2SMansur Alisha Shaik exit:
29091f2b7d2SMansur Alisha Shaik 	mutex_unlock(&core->lock);
29191f2b7d2SMansur Alisha Shaik 	return ret;
2927482a983SStanimir Varbanov }
2937482a983SStanimir Varbanov 
core_get_v1(struct venus_core * core)29408b1cf47SBryan O'Donoghue static int core_get_v1(struct venus_core *core)
2957482a983SStanimir Varbanov {
29632158871SStanimir Varbanov 	int ret;
29732158871SStanimir Varbanov 
29832158871SStanimir Varbanov 	ret = core_clks_get(core);
29932158871SStanimir Varbanov 	if (ret)
30032158871SStanimir Varbanov 		return ret;
30132158871SStanimir Varbanov 
3020394360eSYangtao Li 	ret = devm_pm_opp_set_clkname(core->dev, "core");
3030394360eSYangtao Li 	if (ret)
3040394360eSYangtao Li 		return ret;
30532158871SStanimir Varbanov 
30632158871SStanimir Varbanov 	return 0;
30732158871SStanimir Varbanov }
30832158871SStanimir Varbanov 
core_put_v1(struct venus_core * core)30932158871SStanimir Varbanov static void core_put_v1(struct venus_core *core)
31032158871SStanimir Varbanov {
3117482a983SStanimir Varbanov }
3127482a983SStanimir Varbanov 
core_power_v1(struct venus_core * core,int on)31308b1cf47SBryan O'Donoghue static int core_power_v1(struct venus_core *core, int on)
3147482a983SStanimir Varbanov {
3157482a983SStanimir Varbanov 	int ret = 0;
3167482a983SStanimir Varbanov 
3177482a983SStanimir Varbanov 	if (on == POWER_ON)
3187482a983SStanimir Varbanov 		ret = core_clks_enable(core);
3197482a983SStanimir Varbanov 	else
3207482a983SStanimir Varbanov 		core_clks_disable(core);
3217482a983SStanimir Varbanov 
3227482a983SStanimir Varbanov 	return ret;
3237482a983SStanimir Varbanov }
3247482a983SStanimir Varbanov 
3257482a983SStanimir Varbanov static const struct venus_pm_ops pm_ops_v1 = {
3267482a983SStanimir Varbanov 	.core_get = core_get_v1,
32732158871SStanimir Varbanov 	.core_put = core_put_v1,
3287482a983SStanimir Varbanov 	.core_power = core_power_v1,
3297482a983SStanimir Varbanov 	.load_scale = load_scale_v1,
3307482a983SStanimir Varbanov };
3317482a983SStanimir Varbanov 
3327482a983SStanimir Varbanov static void
vcodec_control_v3(struct venus_core * core,u32 session_type,bool enable)3337482a983SStanimir Varbanov vcodec_control_v3(struct venus_core *core, u32 session_type, bool enable)
3347482a983SStanimir Varbanov {
3357482a983SStanimir Varbanov 	void __iomem *ctrl;
3367482a983SStanimir Varbanov 
3377482a983SStanimir Varbanov 	if (session_type == VIDC_SESSION_TYPE_DEC)
338ff2a7013SBryan O'Donoghue 		ctrl = core->wrapper_base + WRAPPER_VDEC_VCODEC_POWER_CONTROL;
3397482a983SStanimir Varbanov 	else
340ff2a7013SBryan O'Donoghue 		ctrl = core->wrapper_base + WRAPPER_VENC_VCODEC_POWER_CONTROL;
3417482a983SStanimir Varbanov 
3427482a983SStanimir Varbanov 	if (enable)
3437482a983SStanimir Varbanov 		writel(0, ctrl);
3447482a983SStanimir Varbanov 	else
3457482a983SStanimir Varbanov 		writel(1, ctrl);
3467482a983SStanimir Varbanov }
3477482a983SStanimir Varbanov 
vdec_get_v3(struct device * dev)3487482a983SStanimir Varbanov static int vdec_get_v3(struct device *dev)
3497482a983SStanimir Varbanov {
3507482a983SStanimir Varbanov 	struct venus_core *core = dev_get_drvdata(dev);
3517482a983SStanimir Varbanov 
3527482a983SStanimir Varbanov 	return vcodec_clks_get(core, dev, core->vcodec0_clks,
3537482a983SStanimir Varbanov 			       core->res->vcodec0_clks);
3547482a983SStanimir Varbanov }
3557482a983SStanimir Varbanov 
vdec_power_v3(struct device * dev,int on)3567482a983SStanimir Varbanov static int vdec_power_v3(struct device *dev, int on)
3577482a983SStanimir Varbanov {
3587482a983SStanimir Varbanov 	struct venus_core *core = dev_get_drvdata(dev);
3597482a983SStanimir Varbanov 	int ret = 0;
3607482a983SStanimir Varbanov 
3617482a983SStanimir Varbanov 	vcodec_control_v3(core, VIDC_SESSION_TYPE_DEC, true);
3627482a983SStanimir Varbanov 
3637482a983SStanimir Varbanov 	if (on == POWER_ON)
3647482a983SStanimir Varbanov 		ret = vcodec_clks_enable(core, core->vcodec0_clks);
3657482a983SStanimir Varbanov 	else
3667482a983SStanimir Varbanov 		vcodec_clks_disable(core, core->vcodec0_clks);
3677482a983SStanimir Varbanov 
3687482a983SStanimir Varbanov 	vcodec_control_v3(core, VIDC_SESSION_TYPE_DEC, false);
3697482a983SStanimir Varbanov 
3707482a983SStanimir Varbanov 	return ret;
3717482a983SStanimir Varbanov }
3727482a983SStanimir Varbanov 
venc_get_v3(struct device * dev)3737482a983SStanimir Varbanov static int venc_get_v3(struct device *dev)
3747482a983SStanimir Varbanov {
3757482a983SStanimir Varbanov 	struct venus_core *core = dev_get_drvdata(dev);
3767482a983SStanimir Varbanov 
3777482a983SStanimir Varbanov 	return vcodec_clks_get(core, dev, core->vcodec1_clks,
3787482a983SStanimir Varbanov 			       core->res->vcodec1_clks);
3797482a983SStanimir Varbanov }
3807482a983SStanimir Varbanov 
venc_power_v3(struct device * dev,int on)3817482a983SStanimir Varbanov static int venc_power_v3(struct device *dev, int on)
3827482a983SStanimir Varbanov {
3837482a983SStanimir Varbanov 	struct venus_core *core = dev_get_drvdata(dev);
3847482a983SStanimir Varbanov 	int ret = 0;
3857482a983SStanimir Varbanov 
3867482a983SStanimir Varbanov 	vcodec_control_v3(core, VIDC_SESSION_TYPE_ENC, true);
3877482a983SStanimir Varbanov 
3887482a983SStanimir Varbanov 	if (on == POWER_ON)
3897482a983SStanimir Varbanov 		ret = vcodec_clks_enable(core, core->vcodec1_clks);
3907482a983SStanimir Varbanov 	else
3917482a983SStanimir Varbanov 		vcodec_clks_disable(core, core->vcodec1_clks);
3927482a983SStanimir Varbanov 
3937482a983SStanimir Varbanov 	vcodec_control_v3(core, VIDC_SESSION_TYPE_ENC, false);
3947482a983SStanimir Varbanov 
3957482a983SStanimir Varbanov 	return ret;
3967482a983SStanimir Varbanov }
3977482a983SStanimir Varbanov 
3987482a983SStanimir Varbanov static const struct venus_pm_ops pm_ops_v3 = {
3997482a983SStanimir Varbanov 	.core_get = core_get_v1,
40032158871SStanimir Varbanov 	.core_put = core_put_v1,
4017482a983SStanimir Varbanov 	.core_power = core_power_v1,
4027482a983SStanimir Varbanov 	.vdec_get = vdec_get_v3,
4037482a983SStanimir Varbanov 	.vdec_power = vdec_power_v3,
4047482a983SStanimir Varbanov 	.venc_get = venc_get_v3,
4057482a983SStanimir Varbanov 	.venc_power = venc_power_v3,
4067482a983SStanimir Varbanov 	.load_scale = load_scale_v1,
4077482a983SStanimir Varbanov };
4087482a983SStanimir Varbanov 
vcodec_control_v4(struct venus_core * core,u32 coreid,bool enable)4097482a983SStanimir Varbanov static int vcodec_control_v4(struct venus_core *core, u32 coreid, bool enable)
4107482a983SStanimir Varbanov {
4117482a983SStanimir Varbanov 	void __iomem *ctrl, *stat;
4127482a983SStanimir Varbanov 	u32 val;
4137482a983SStanimir Varbanov 	int ret;
4147482a983SStanimir Varbanov 
415ec9a652eSJagadeesh Kona 	if (IS_V6(core))
416ec9a652eSJagadeesh Kona 		return dev_pm_genpd_set_hwmode(core->pmdomains->pd_devs[coreid], !enable);
417ec9a652eSJagadeesh Kona 	else if (coreid == VIDC_CORE_ID_1) {
418ff2a7013SBryan O'Donoghue 		ctrl = core->wrapper_base + WRAPPER_VCODEC0_MMCC_POWER_CONTROL;
419ff2a7013SBryan O'Donoghue 		stat = core->wrapper_base + WRAPPER_VCODEC0_MMCC_POWER_STATUS;
4207482a983SStanimir Varbanov 	} else {
421ff2a7013SBryan O'Donoghue 		ctrl = core->wrapper_base + WRAPPER_VCODEC1_MMCC_POWER_CONTROL;
422ff2a7013SBryan O'Donoghue 		stat = core->wrapper_base + WRAPPER_VCODEC1_MMCC_POWER_STATUS;
4237482a983SStanimir Varbanov 	}
4247482a983SStanimir Varbanov 
4257482a983SStanimir Varbanov 	if (enable) {
4267482a983SStanimir Varbanov 		writel(0, ctrl);
4277482a983SStanimir Varbanov 
4287482a983SStanimir Varbanov 		ret = readl_poll_timeout(stat, val, val & BIT(1), 1, 100);
4297482a983SStanimir Varbanov 		if (ret)
4307482a983SStanimir Varbanov 			return ret;
4317482a983SStanimir Varbanov 	} else {
4327482a983SStanimir Varbanov 		writel(1, ctrl);
4337482a983SStanimir Varbanov 
4347482a983SStanimir Varbanov 		ret = readl_poll_timeout(stat, val, !(val & BIT(1)), 1, 100);
4357482a983SStanimir Varbanov 		if (ret)
4367482a983SStanimir Varbanov 			return ret;
4377482a983SStanimir Varbanov 	}
4387482a983SStanimir Varbanov 
4397482a983SStanimir Varbanov 	return 0;
4407482a983SStanimir Varbanov }
4417482a983SStanimir Varbanov 
poweroff_coreid(struct venus_core * core,unsigned int coreid_mask)4427482a983SStanimir Varbanov static int poweroff_coreid(struct venus_core *core, unsigned int coreid_mask)
4437482a983SStanimir Varbanov {
4447482a983SStanimir Varbanov 	int ret;
4457482a983SStanimir Varbanov 
4467482a983SStanimir Varbanov 	if (coreid_mask & VIDC_CORE_ID_1) {
4477482a983SStanimir Varbanov 		ret = vcodec_control_v4(core, VIDC_CORE_ID_1, true);
4487482a983SStanimir Varbanov 		if (ret)
4497482a983SStanimir Varbanov 			return ret;
4507482a983SStanimir Varbanov 
4517482a983SStanimir Varbanov 		vcodec_clks_disable(core, core->vcodec0_clks);
4527482a983SStanimir Varbanov 
453ec9a652eSJagadeesh Kona 		if (!IS_V6(core)) {
4547482a983SStanimir Varbanov 			ret = vcodec_control_v4(core, VIDC_CORE_ID_1, false);
4557482a983SStanimir Varbanov 			if (ret)
4567482a983SStanimir Varbanov 				return ret;
457ec9a652eSJagadeesh Kona 		}
4587482a983SStanimir Varbanov 
459693c301aSUlf Hansson 		ret = pm_runtime_put_sync(core->pmdomains->pd_devs[1]);
4607482a983SStanimir Varbanov 		if (ret < 0)
4617482a983SStanimir Varbanov 			return ret;
4627482a983SStanimir Varbanov 	}
4637482a983SStanimir Varbanov 
4647482a983SStanimir Varbanov 	if (coreid_mask & VIDC_CORE_ID_2) {
4657482a983SStanimir Varbanov 		ret = vcodec_control_v4(core, VIDC_CORE_ID_2, true);
4667482a983SStanimir Varbanov 		if (ret)
4677482a983SStanimir Varbanov 			return ret;
4687482a983SStanimir Varbanov 
4697482a983SStanimir Varbanov 		vcodec_clks_disable(core, core->vcodec1_clks);
4707482a983SStanimir Varbanov 
471ec9a652eSJagadeesh Kona 		if (!IS_V6(core)) {
4727482a983SStanimir Varbanov 			ret = vcodec_control_v4(core, VIDC_CORE_ID_2, false);
4737482a983SStanimir Varbanov 			if (ret)
4747482a983SStanimir Varbanov 				return ret;
475ec9a652eSJagadeesh Kona 		}
4767482a983SStanimir Varbanov 
477693c301aSUlf Hansson 		ret = pm_runtime_put_sync(core->pmdomains->pd_devs[2]);
4787482a983SStanimir Varbanov 		if (ret < 0)
4797482a983SStanimir Varbanov 			return ret;
4807482a983SStanimir Varbanov 	}
4817482a983SStanimir Varbanov 
4827482a983SStanimir Varbanov 	return 0;
4837482a983SStanimir Varbanov }
4847482a983SStanimir Varbanov 
poweron_coreid(struct venus_core * core,unsigned int coreid_mask)4857482a983SStanimir Varbanov static int poweron_coreid(struct venus_core *core, unsigned int coreid_mask)
4867482a983SStanimir Varbanov {
4877482a983SStanimir Varbanov 	int ret;
4887482a983SStanimir Varbanov 
4897482a983SStanimir Varbanov 	if (coreid_mask & VIDC_CORE_ID_1) {
490693c301aSUlf Hansson 		ret = pm_runtime_get_sync(core->pmdomains->pd_devs[1]);
4917482a983SStanimir Varbanov 		if (ret < 0)
4927482a983SStanimir Varbanov 			return ret;
4937482a983SStanimir Varbanov 
494ec9a652eSJagadeesh Kona 		if (!IS_V6(core)) {
4957482a983SStanimir Varbanov 			ret = vcodec_control_v4(core, VIDC_CORE_ID_1, true);
4967482a983SStanimir Varbanov 			if (ret)
4977482a983SStanimir Varbanov 				return ret;
498ec9a652eSJagadeesh Kona 		}
4997482a983SStanimir Varbanov 
5007482a983SStanimir Varbanov 		ret = vcodec_clks_enable(core, core->vcodec0_clks);
5017482a983SStanimir Varbanov 		if (ret)
5027482a983SStanimir Varbanov 			return ret;
5037482a983SStanimir Varbanov 
5047482a983SStanimir Varbanov 		ret = vcodec_control_v4(core, VIDC_CORE_ID_1, false);
5057482a983SStanimir Varbanov 		if (ret < 0)
5067482a983SStanimir Varbanov 			return ret;
5077482a983SStanimir Varbanov 	}
5087482a983SStanimir Varbanov 
5097482a983SStanimir Varbanov 	if (coreid_mask & VIDC_CORE_ID_2) {
510693c301aSUlf Hansson 		ret = pm_runtime_get_sync(core->pmdomains->pd_devs[2]);
5117482a983SStanimir Varbanov 		if (ret < 0)
5127482a983SStanimir Varbanov 			return ret;
5137482a983SStanimir Varbanov 
514ec9a652eSJagadeesh Kona 		if (!IS_V6(core)) {
5157482a983SStanimir Varbanov 			ret = vcodec_control_v4(core, VIDC_CORE_ID_2, true);
5167482a983SStanimir Varbanov 			if (ret)
5177482a983SStanimir Varbanov 				return ret;
518ec9a652eSJagadeesh Kona 		}
5197482a983SStanimir Varbanov 
5207482a983SStanimir Varbanov 		ret = vcodec_clks_enable(core, core->vcodec1_clks);
5217482a983SStanimir Varbanov 		if (ret)
5227482a983SStanimir Varbanov 			return ret;
5237482a983SStanimir Varbanov 
5247482a983SStanimir Varbanov 		ret = vcodec_control_v4(core, VIDC_CORE_ID_2, false);
5257482a983SStanimir Varbanov 		if (ret < 0)
5267482a983SStanimir Varbanov 			return ret;
5277482a983SStanimir Varbanov 	}
5287482a983SStanimir Varbanov 
5297482a983SStanimir Varbanov 	return 0;
5307482a983SStanimir Varbanov }
5317482a983SStanimir Varbanov 
power_save_mode_enable(struct venus_inst * inst,bool enable)5323cfe5815SDikshita Agarwal static inline int power_save_mode_enable(struct venus_inst *inst,
5333cfe5815SDikshita Agarwal 					 bool enable)
5343cfe5815SDikshita Agarwal {
5353cfe5815SDikshita Agarwal 	struct venc_controls *enc_ctr = &inst->controls.enc;
5363cfe5815SDikshita Agarwal 	const u32 ptype = HFI_PROPERTY_CONFIG_VENC_PERF_MODE;
5373cfe5815SDikshita Agarwal 	u32 venc_mode;
5383cfe5815SDikshita Agarwal 	int ret = 0;
5393cfe5815SDikshita Agarwal 
5403cfe5815SDikshita Agarwal 	if (inst->session_type != VIDC_SESSION_TYPE_ENC)
5413cfe5815SDikshita Agarwal 		return 0;
5423cfe5815SDikshita Agarwal 
5433cfe5815SDikshita Agarwal 	if (enc_ctr->bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CQ)
5443cfe5815SDikshita Agarwal 		enable = false;
5453cfe5815SDikshita Agarwal 
5463cfe5815SDikshita Agarwal 	venc_mode = enable ? HFI_VENC_PERFMODE_POWER_SAVE :
5473cfe5815SDikshita Agarwal 		HFI_VENC_PERFMODE_MAX_QUALITY;
5483cfe5815SDikshita Agarwal 
5493cfe5815SDikshita Agarwal 	ret = hfi_session_set_property(inst, ptype, &venc_mode);
5503cfe5815SDikshita Agarwal 	if (ret)
5513cfe5815SDikshita Agarwal 		return ret;
5523cfe5815SDikshita Agarwal 
5533cfe5815SDikshita Agarwal 	inst->flags = enable ? inst->flags | VENUS_LOW_POWER :
5543cfe5815SDikshita Agarwal 		inst->flags & ~VENUS_LOW_POWER;
5553cfe5815SDikshita Agarwal 
5563cfe5815SDikshita Agarwal 	return ret;
5573cfe5815SDikshita Agarwal }
5583cfe5815SDikshita Agarwal 
move_core_to_power_save_mode(struct venus_core * core,u32 core_id)5593cfe5815SDikshita Agarwal static int move_core_to_power_save_mode(struct venus_core *core,
5603cfe5815SDikshita Agarwal 					u32 core_id)
5613cfe5815SDikshita Agarwal {
5623cfe5815SDikshita Agarwal 	struct venus_inst *inst = NULL;
5633cfe5815SDikshita Agarwal 
5643cfe5815SDikshita Agarwal 	mutex_lock(&core->lock);
5653cfe5815SDikshita Agarwal 	list_for_each_entry(inst, &core->instances, list) {
5663cfe5815SDikshita Agarwal 		if (inst->clk_data.core_id == core_id &&
5673cfe5815SDikshita Agarwal 		    inst->session_type == VIDC_SESSION_TYPE_ENC)
5683cfe5815SDikshita Agarwal 			power_save_mode_enable(inst, true);
5693cfe5815SDikshita Agarwal 	}
5703cfe5815SDikshita Agarwal 	mutex_unlock(&core->lock);
5713cfe5815SDikshita Agarwal 	return 0;
5723cfe5815SDikshita Agarwal }
5733cfe5815SDikshita Agarwal 
5744ebf9693SAniket Masule static void
min_loaded_core(struct venus_inst * inst,u32 * min_coreid,u32 * min_load,bool low_power)5753cfe5815SDikshita Agarwal min_loaded_core(struct venus_inst *inst, u32 *min_coreid, u32 *min_load, bool low_power)
5764ebf9693SAniket Masule {
5774ebf9693SAniket Masule 	u32 mbs_per_sec, load, core1_load = 0, core2_load = 0;
5784ebf9693SAniket Masule 	u32 cores_max = core_num_max(inst);
5794ebf9693SAniket Masule 	struct venus_core *core = inst->core;
5804ebf9693SAniket Masule 	struct venus_inst *inst_pos;
5814ebf9693SAniket Masule 	unsigned long vpp_freq;
5824ebf9693SAniket Masule 	u32 coreid;
5834ebf9693SAniket Masule 
5844ebf9693SAniket Masule 	mutex_lock(&core->lock);
5854ebf9693SAniket Masule 
5864ebf9693SAniket Masule 	list_for_each_entry(inst_pos, &core->instances, list) {
5874ebf9693SAniket Masule 		if (inst_pos == inst)
5884ebf9693SAniket Masule 			continue;
589e0eb3481SMansur Alisha Shaik 
590e0eb3481SMansur Alisha Shaik 		if (inst_pos->state != INST_START)
591e0eb3481SMansur Alisha Shaik 			continue;
592e0eb3481SMansur Alisha Shaik 
5933cfe5815SDikshita Agarwal 		if (inst->session_type == VIDC_SESSION_TYPE_DEC)
594aa603389SStanimir Varbanov 			vpp_freq = inst_pos->clk_data.vpp_freq;
5953cfe5815SDikshita Agarwal 		else if (inst->session_type == VIDC_SESSION_TYPE_ENC)
596b1f9bb80SMansur Alisha Shaik 			vpp_freq = low_power ? inst_pos->clk_data.low_power_freq :
597b1f9bb80SMansur Alisha Shaik 				inst_pos->clk_data.vpp_freq;
5983cfe5815SDikshita Agarwal 		else
5993cfe5815SDikshita Agarwal 			continue;
6003cfe5815SDikshita Agarwal 
6014ebf9693SAniket Masule 		coreid = inst_pos->clk_data.core_id;
6024ebf9693SAniket Masule 
6034ebf9693SAniket Masule 		mbs_per_sec = load_per_instance(inst_pos);
6044ebf9693SAniket Masule 		load = mbs_per_sec * vpp_freq;
6054ebf9693SAniket Masule 
6064ebf9693SAniket Masule 		if ((coreid & VIDC_CORE_ID_3) == VIDC_CORE_ID_3) {
6074ebf9693SAniket Masule 			core1_load += load / 2;
6084ebf9693SAniket Masule 			core2_load += load / 2;
6094ebf9693SAniket Masule 		} else if (coreid & VIDC_CORE_ID_1) {
6104ebf9693SAniket Masule 			core1_load += load;
6114ebf9693SAniket Masule 		} else if (coreid & VIDC_CORE_ID_2) {
6124ebf9693SAniket Masule 			core2_load += load;
6134ebf9693SAniket Masule 		}
6144ebf9693SAniket Masule 	}
6154ebf9693SAniket Masule 
6164ebf9693SAniket Masule 	*min_coreid = core1_load <= core2_load ?
6174ebf9693SAniket Masule 			VIDC_CORE_ID_1 : VIDC_CORE_ID_2;
6184ebf9693SAniket Masule 	*min_load = min(core1_load, core2_load);
6194ebf9693SAniket Masule 
6204ebf9693SAniket Masule 	if (cores_max < VIDC_CORE_ID_2 || core->res->vcodec_num < 2) {
6214ebf9693SAniket Masule 		*min_coreid = VIDC_CORE_ID_1;
6224ebf9693SAniket Masule 		*min_load = core1_load;
6234ebf9693SAniket Masule 	}
6244ebf9693SAniket Masule 
6254ebf9693SAniket Masule 	mutex_unlock(&core->lock);
6264ebf9693SAniket Masule }
6274ebf9693SAniket Masule 
decide_core(struct venus_inst * inst)6284ebf9693SAniket Masule static int decide_core(struct venus_inst *inst)
6294ebf9693SAniket Masule {
6304ebf9693SAniket Masule 	const u32 ptype = HFI_PROPERTY_CONFIG_VIDEOCORES_USAGE;
6314ebf9693SAniket Masule 	struct venus_core *core = inst->core;
6323cfe5815SDikshita Agarwal 	u32 min_coreid, min_load, cur_inst_load;
6333cfe5815SDikshita Agarwal 	u32 min_lp_coreid, min_lp_load, cur_inst_lp_load;
6344ebf9693SAniket Masule 	struct hfi_videocores_usage_type cu;
6354ebf9693SAniket Masule 	unsigned long max_freq;
6363cfe5815SDikshita Agarwal 	int ret = 0;
6374ebf9693SAniket Masule 
6384ebf9693SAniket Masule 	if (legacy_binding) {
6394ebf9693SAniket Masule 		if (inst->session_type == VIDC_SESSION_TYPE_DEC)
6404ebf9693SAniket Masule 			cu.video_core_enable_mask = VIDC_CORE_ID_1;
6414ebf9693SAniket Masule 		else
6424ebf9693SAniket Masule 			cu.video_core_enable_mask = VIDC_CORE_ID_2;
6434ebf9693SAniket Masule 
6444ebf9693SAniket Masule 		goto done;
6454ebf9693SAniket Masule 	}
6464ebf9693SAniket Masule 
6474ebf9693SAniket Masule 	if (inst->clk_data.core_id != VIDC_CORE_ID_DEFAULT)
6484ebf9693SAniket Masule 		return 0;
6494ebf9693SAniket Masule 
6503cfe5815SDikshita Agarwal 	cur_inst_load = load_per_instance(inst);
6513cfe5815SDikshita Agarwal 	cur_inst_load *= inst->clk_data.vpp_freq;
6523cfe5815SDikshita Agarwal 	/*TODO : divide this inst->load by work_route */
6533cfe5815SDikshita Agarwal 
6543cfe5815SDikshita Agarwal 	cur_inst_lp_load = load_per_instance(inst);
6553cfe5815SDikshita Agarwal 	cur_inst_lp_load *= inst->clk_data.low_power_freq;
6563cfe5815SDikshita Agarwal 	/*TODO : divide this inst->load by work_route */
6573cfe5815SDikshita Agarwal 
6584ebf9693SAniket Masule 	max_freq = core->res->freq_tbl[0].freq;
6594ebf9693SAniket Masule 
6603cfe5815SDikshita Agarwal 	min_loaded_core(inst, &min_coreid, &min_load, false);
6613cfe5815SDikshita Agarwal 	min_loaded_core(inst, &min_lp_coreid, &min_lp_load, true);
6624ebf9693SAniket Masule 
6633cfe5815SDikshita Agarwal 	if (cur_inst_load + min_load <= max_freq) {
6643cfe5815SDikshita Agarwal 		inst->clk_data.core_id = min_coreid;
6653cfe5815SDikshita Agarwal 		cu.video_core_enable_mask = min_coreid;
6663cfe5815SDikshita Agarwal 	} else if (cur_inst_lp_load + min_load <= max_freq) {
6673cfe5815SDikshita Agarwal 		/* Move current instance to LP and return */
6683cfe5815SDikshita Agarwal 		inst->clk_data.core_id = min_coreid;
6693cfe5815SDikshita Agarwal 		cu.video_core_enable_mask = min_coreid;
6703cfe5815SDikshita Agarwal 		power_save_mode_enable(inst, true);
6713cfe5815SDikshita Agarwal 	} else if (cur_inst_lp_load + min_lp_load <= max_freq) {
6723cfe5815SDikshita Agarwal 		/* Move all instances to LP mode and return */
6733cfe5815SDikshita Agarwal 		inst->clk_data.core_id = min_lp_coreid;
6743cfe5815SDikshita Agarwal 		cu.video_core_enable_mask = min_lp_coreid;
6753cfe5815SDikshita Agarwal 		move_core_to_power_save_mode(core, min_lp_coreid);
6763cfe5815SDikshita Agarwal 	} else {
6773cfe5815SDikshita Agarwal 		dev_warn(core->dev, "HW can't support this load");
6784ebf9693SAniket Masule 		return -EINVAL;
6794ebf9693SAniket Masule 	}
6804ebf9693SAniket Masule 
6814ebf9693SAniket Masule done:
6823cfe5815SDikshita Agarwal 	ret = hfi_session_set_property(inst, ptype, &cu);
6833cfe5815SDikshita Agarwal 	if (ret)
6843cfe5815SDikshita Agarwal 		return ret;
6853cfe5815SDikshita Agarwal 
6863cfe5815SDikshita Agarwal 	return ret;
6874ebf9693SAniket Masule }
6884ebf9693SAniket Masule 
acquire_core(struct venus_inst * inst)6894ebf9693SAniket Masule static int acquire_core(struct venus_inst *inst)
6904ebf9693SAniket Masule {
6914ebf9693SAniket Masule 	struct venus_core *core = inst->core;
6924ebf9693SAniket Masule 	unsigned int coreid_mask = 0;
6934ebf9693SAniket Masule 
6944ebf9693SAniket Masule 	if (inst->core_acquired)
6954ebf9693SAniket Masule 		return 0;
6964ebf9693SAniket Masule 
6974ebf9693SAniket Masule 	inst->core_acquired = true;
6984ebf9693SAniket Masule 
6994ebf9693SAniket Masule 	if (inst->clk_data.core_id & VIDC_CORE_ID_1) {
7004ebf9693SAniket Masule 		if (core->core0_usage_count++)
7014ebf9693SAniket Masule 			return 0;
7024ebf9693SAniket Masule 
7034ebf9693SAniket Masule 		coreid_mask = VIDC_CORE_ID_1;
7044ebf9693SAniket Masule 	}
7054ebf9693SAniket Masule 
7064ebf9693SAniket Masule 	if (inst->clk_data.core_id & VIDC_CORE_ID_2) {
7074ebf9693SAniket Masule 		if (core->core1_usage_count++)
7084ebf9693SAniket Masule 			return 0;
7094ebf9693SAniket Masule 
7104ebf9693SAniket Masule 		coreid_mask |= VIDC_CORE_ID_2;
7114ebf9693SAniket Masule 	}
7124ebf9693SAniket Masule 
7134ebf9693SAniket Masule 	return poweron_coreid(core, coreid_mask);
7144ebf9693SAniket Masule }
7154ebf9693SAniket Masule 
release_core(struct venus_inst * inst)7164ebf9693SAniket Masule static int release_core(struct venus_inst *inst)
7174ebf9693SAniket Masule {
7184ebf9693SAniket Masule 	struct venus_core *core = inst->core;
7194ebf9693SAniket Masule 	unsigned int coreid_mask = 0;
7204ebf9693SAniket Masule 	int ret;
7214ebf9693SAniket Masule 
7224ebf9693SAniket Masule 	if (!inst->core_acquired)
7234ebf9693SAniket Masule 		return 0;
7244ebf9693SAniket Masule 
7254ebf9693SAniket Masule 	if (inst->clk_data.core_id & VIDC_CORE_ID_1) {
7264ebf9693SAniket Masule 		if (--core->core0_usage_count)
7274ebf9693SAniket Masule 			goto done;
7284ebf9693SAniket Masule 
7294ebf9693SAniket Masule 		coreid_mask = VIDC_CORE_ID_1;
7304ebf9693SAniket Masule 	}
7314ebf9693SAniket Masule 
7324ebf9693SAniket Masule 	if (inst->clk_data.core_id & VIDC_CORE_ID_2) {
7334ebf9693SAniket Masule 		if (--core->core1_usage_count)
7344ebf9693SAniket Masule 			goto done;
7354ebf9693SAniket Masule 
7364ebf9693SAniket Masule 		coreid_mask |= VIDC_CORE_ID_2;
7374ebf9693SAniket Masule 	}
7384ebf9693SAniket Masule 
7394ebf9693SAniket Masule 	ret = poweroff_coreid(core, coreid_mask);
7404ebf9693SAniket Masule 	if (ret)
7414ebf9693SAniket Masule 		return ret;
7424ebf9693SAniket Masule 
7434ebf9693SAniket Masule done:
7444ebf9693SAniket Masule 	inst->clk_data.core_id = VIDC_CORE_ID_DEFAULT;
7454ebf9693SAniket Masule 	inst->core_acquired = false;
7464ebf9693SAniket Masule 	return 0;
7474ebf9693SAniket Masule }
7484ebf9693SAniket Masule 
coreid_power_v4(struct venus_inst * inst,int on)7494ebf9693SAniket Masule static int coreid_power_v4(struct venus_inst *inst, int on)
7504ebf9693SAniket Masule {
7514ebf9693SAniket Masule 	struct venus_core *core = inst->core;
7524ebf9693SAniket Masule 	int ret;
7534ebf9693SAniket Masule 
7544ebf9693SAniket Masule 	if (legacy_binding)
7554ebf9693SAniket Masule 		return 0;
7564ebf9693SAniket Masule 
7574ebf9693SAniket Masule 	if (on == POWER_ON) {
7584ebf9693SAniket Masule 		ret = decide_core(inst);
7594ebf9693SAniket Masule 		if (ret)
7604ebf9693SAniket Masule 			return ret;
7614ebf9693SAniket Masule 
7624ebf9693SAniket Masule 		mutex_lock(&core->lock);
7634ebf9693SAniket Masule 		ret = acquire_core(inst);
7644ebf9693SAniket Masule 		mutex_unlock(&core->lock);
7654ebf9693SAniket Masule 	} else {
7664ebf9693SAniket Masule 		mutex_lock(&core->lock);
7674ebf9693SAniket Masule 		ret = release_core(inst);
7684ebf9693SAniket Masule 		mutex_unlock(&core->lock);
7694ebf9693SAniket Masule 	}
7704ebf9693SAniket Masule 
7714ebf9693SAniket Masule 	return ret;
7724ebf9693SAniket Masule }
7734ebf9693SAniket Masule 
vdec_get_v4(struct device * dev)7747482a983SStanimir Varbanov static int vdec_get_v4(struct device *dev)
7757482a983SStanimir Varbanov {
7767482a983SStanimir Varbanov 	struct venus_core *core = dev_get_drvdata(dev);
7777482a983SStanimir Varbanov 
7787482a983SStanimir Varbanov 	if (!legacy_binding)
7797482a983SStanimir Varbanov 		return 0;
7807482a983SStanimir Varbanov 
7817482a983SStanimir Varbanov 	return vcodec_clks_get(core, dev, core->vcodec0_clks,
7827482a983SStanimir Varbanov 			       core->res->vcodec0_clks);
7837482a983SStanimir Varbanov }
7847482a983SStanimir Varbanov 
vdec_put_v4(struct device * dev)7857482a983SStanimir Varbanov static void vdec_put_v4(struct device *dev)
7867482a983SStanimir Varbanov {
7877482a983SStanimir Varbanov 	struct venus_core *core = dev_get_drvdata(dev);
7887482a983SStanimir Varbanov 	unsigned int i;
7897482a983SStanimir Varbanov 
7907482a983SStanimir Varbanov 	if (!legacy_binding)
7917482a983SStanimir Varbanov 		return;
7927482a983SStanimir Varbanov 
7937482a983SStanimir Varbanov 	for (i = 0; i < core->res->vcodec_clks_num; i++)
7947482a983SStanimir Varbanov 		core->vcodec0_clks[i] = NULL;
7957482a983SStanimir Varbanov }
7967482a983SStanimir Varbanov 
vdec_power_v4(struct device * dev,int on)7977482a983SStanimir Varbanov static int vdec_power_v4(struct device *dev, int on)
7987482a983SStanimir Varbanov {
7997482a983SStanimir Varbanov 	struct venus_core *core = dev_get_drvdata(dev);
8007482a983SStanimir Varbanov 	int ret;
8017482a983SStanimir Varbanov 
8027482a983SStanimir Varbanov 	if (!legacy_binding)
8037482a983SStanimir Varbanov 		return 0;
8047482a983SStanimir Varbanov 
8057482a983SStanimir Varbanov 	ret = vcodec_control_v4(core, VIDC_CORE_ID_1, true);
8067482a983SStanimir Varbanov 	if (ret)
8077482a983SStanimir Varbanov 		return ret;
8087482a983SStanimir Varbanov 
8097482a983SStanimir Varbanov 	if (on == POWER_ON)
8107482a983SStanimir Varbanov 		ret = vcodec_clks_enable(core, core->vcodec0_clks);
8117482a983SStanimir Varbanov 	else
8127482a983SStanimir Varbanov 		vcodec_clks_disable(core, core->vcodec0_clks);
8137482a983SStanimir Varbanov 
8147482a983SStanimir Varbanov 	vcodec_control_v4(core, VIDC_CORE_ID_1, false);
8157482a983SStanimir Varbanov 
8167482a983SStanimir Varbanov 	return ret;
8177482a983SStanimir Varbanov }
8187482a983SStanimir Varbanov 
venc_get_v4(struct device * dev)8197482a983SStanimir Varbanov static int venc_get_v4(struct device *dev)
8207482a983SStanimir Varbanov {
8217482a983SStanimir Varbanov 	struct venus_core *core = dev_get_drvdata(dev);
8227482a983SStanimir Varbanov 
8237482a983SStanimir Varbanov 	if (!legacy_binding)
8247482a983SStanimir Varbanov 		return 0;
8257482a983SStanimir Varbanov 
8267482a983SStanimir Varbanov 	return vcodec_clks_get(core, dev, core->vcodec1_clks,
8277482a983SStanimir Varbanov 			       core->res->vcodec1_clks);
8287482a983SStanimir Varbanov }
8297482a983SStanimir Varbanov 
venc_put_v4(struct device * dev)8307482a983SStanimir Varbanov static void venc_put_v4(struct device *dev)
8317482a983SStanimir Varbanov {
8327482a983SStanimir Varbanov 	struct venus_core *core = dev_get_drvdata(dev);
8337482a983SStanimir Varbanov 	unsigned int i;
8347482a983SStanimir Varbanov 
8357482a983SStanimir Varbanov 	if (!legacy_binding)
8367482a983SStanimir Varbanov 		return;
8377482a983SStanimir Varbanov 
8387482a983SStanimir Varbanov 	for (i = 0; i < core->res->vcodec_clks_num; i++)
8397482a983SStanimir Varbanov 		core->vcodec1_clks[i] = NULL;
8407482a983SStanimir Varbanov }
8417482a983SStanimir Varbanov 
venc_power_v4(struct device * dev,int on)8427482a983SStanimir Varbanov static int venc_power_v4(struct device *dev, int on)
8437482a983SStanimir Varbanov {
8447482a983SStanimir Varbanov 	struct venus_core *core = dev_get_drvdata(dev);
8457482a983SStanimir Varbanov 	int ret;
8467482a983SStanimir Varbanov 
8477482a983SStanimir Varbanov 	if (!legacy_binding)
8487482a983SStanimir Varbanov 		return 0;
8497482a983SStanimir Varbanov 
8507482a983SStanimir Varbanov 	ret = vcodec_control_v4(core, VIDC_CORE_ID_2, true);
8517482a983SStanimir Varbanov 	if (ret)
8527482a983SStanimir Varbanov 		return ret;
8537482a983SStanimir Varbanov 
8547482a983SStanimir Varbanov 	if (on == POWER_ON)
8557482a983SStanimir Varbanov 		ret = vcodec_clks_enable(core, core->vcodec1_clks);
8567482a983SStanimir Varbanov 	else
8577482a983SStanimir Varbanov 		vcodec_clks_disable(core, core->vcodec1_clks);
8587482a983SStanimir Varbanov 
8597482a983SStanimir Varbanov 	vcodec_control_v4(core, VIDC_CORE_ID_2, false);
8607482a983SStanimir Varbanov 
8617482a983SStanimir Varbanov 	return ret;
8627482a983SStanimir Varbanov }
8637482a983SStanimir Varbanov 
vcodec_domains_get(struct venus_core * core)86408b1cf47SBryan O'Donoghue static int vcodec_domains_get(struct venus_core *core)
8657482a983SStanimir Varbanov {
8669a538b83SRajendra Nayak 	int ret;
8679a538b83SRajendra Nayak 	struct device **opp_virt_dev;
86808b1cf47SBryan O'Donoghue 	struct device *dev = core->dev;
8697482a983SStanimir Varbanov 	const struct venus_resources *res = core->res;
870693c301aSUlf Hansson 	struct dev_pm_domain_attach_data vcodec_data = {
871693c301aSUlf Hansson 		.pd_names = res->vcodec_pmdomains,
872693c301aSUlf Hansson 		.num_pd_names = res->vcodec_pmdomains_num,
873693c301aSUlf Hansson 		.pd_flags = PD_FLAG_NO_DEV_LINK,
874693c301aSUlf Hansson 	};
8757482a983SStanimir Varbanov 
8767482a983SStanimir Varbanov 	if (!res->vcodec_pmdomains_num)
8779a538b83SRajendra Nayak 		goto skip_pmdomains;
8787482a983SStanimir Varbanov 
879*3b019409SDikshita Agarwal 	ret = devm_pm_domain_attach_list(dev, &vcodec_data, &core->pmdomains);
880693c301aSUlf Hansson 	if (ret < 0)
881693c301aSUlf Hansson 		return ret;
8827482a983SStanimir Varbanov 
8839a538b83SRajendra Nayak skip_pmdomains:
8841d95af02SStanimir Varbanov 	if (!core->res->opp_pmdomain)
8857482a983SStanimir Varbanov 		return 0;
8869a538b83SRajendra Nayak 
8879a538b83SRajendra Nayak 	/* Attach the power domain for setting performance state */
8880394360eSYangtao Li 	ret = devm_pm_opp_attach_genpd(dev, res->opp_pmdomain, &opp_virt_dev);
8890394360eSYangtao Li 	if (ret)
8909a538b83SRajendra Nayak 		goto opp_attach_err;
8919a538b83SRajendra Nayak 
8929a538b83SRajendra Nayak 	core->opp_pmdomain = *opp_virt_dev;
8939a538b83SRajendra Nayak 	core->opp_dl_venus = device_link_add(dev, core->opp_pmdomain,
8949a538b83SRajendra Nayak 					     DL_FLAG_RPM_ACTIVE |
8959a538b83SRajendra Nayak 					     DL_FLAG_PM_RUNTIME |
8969a538b83SRajendra Nayak 					     DL_FLAG_STATELESS);
8979a538b83SRajendra Nayak 	if (!core->opp_dl_venus) {
8989a538b83SRajendra Nayak 		ret = -ENODEV;
8990394360eSYangtao Li 		goto opp_attach_err;
9009a538b83SRajendra Nayak 	}
9019a538b83SRajendra Nayak 
9029a538b83SRajendra Nayak 	return 0;
9039a538b83SRajendra Nayak 
9049a538b83SRajendra Nayak opp_attach_err:
9059a538b83SRajendra Nayak 	return ret;
9067482a983SStanimir Varbanov }
9077482a983SStanimir Varbanov 
vcodec_domains_put(struct venus_core * core)90808b1cf47SBryan O'Donoghue static void vcodec_domains_put(struct venus_core *core)
9097482a983SStanimir Varbanov {
9109a538b83SRajendra Nayak 	if (!core->has_opp_table)
9119a538b83SRajendra Nayak 		return;
9129a538b83SRajendra Nayak 
9139a538b83SRajendra Nayak 	if (core->opp_dl_venus)
9149a538b83SRajendra Nayak 		device_link_del(core->opp_dl_venus);
9157482a983SStanimir Varbanov }
9167482a983SStanimir Varbanov 
core_resets_reset(struct venus_core * core)9173bca4358SStanimir Varbanov static int core_resets_reset(struct venus_core *core)
9183bca4358SStanimir Varbanov {
9193bca4358SStanimir Varbanov 	const struct venus_resources *res = core->res;
920999267d0SColin Ian King 	unsigned int i;
9213bca4358SStanimir Varbanov 	int ret;
9223bca4358SStanimir Varbanov 
9233bca4358SStanimir Varbanov 	if (!res->resets_num)
9243bca4358SStanimir Varbanov 		return 0;
9253bca4358SStanimir Varbanov 
9263bca4358SStanimir Varbanov 	for (i = 0; i < res->resets_num; i++) {
9273bca4358SStanimir Varbanov 		ret = reset_control_assert(core->resets[i]);
9283bca4358SStanimir Varbanov 		if (ret)
9293bca4358SStanimir Varbanov 			goto err;
9303bca4358SStanimir Varbanov 
9313bca4358SStanimir Varbanov 		usleep_range(150, 250);
9323bca4358SStanimir Varbanov 		ret = reset_control_deassert(core->resets[i]);
9333bca4358SStanimir Varbanov 		if (ret)
9343bca4358SStanimir Varbanov 			goto err;
9353bca4358SStanimir Varbanov 	}
9363bca4358SStanimir Varbanov 
9373bca4358SStanimir Varbanov err:
9383bca4358SStanimir Varbanov 	return ret;
9393bca4358SStanimir Varbanov }
9403bca4358SStanimir Varbanov 
core_resets_get(struct venus_core * core)9413bca4358SStanimir Varbanov static int core_resets_get(struct venus_core *core)
9423bca4358SStanimir Varbanov {
9433bca4358SStanimir Varbanov 	struct device *dev = core->dev;
9443bca4358SStanimir Varbanov 	const struct venus_resources *res = core->res;
945999267d0SColin Ian King 	unsigned int i;
9463bca4358SStanimir Varbanov 	int ret;
9473bca4358SStanimir Varbanov 
9483bca4358SStanimir Varbanov 	if (!res->resets_num)
9493bca4358SStanimir Varbanov 		return 0;
9503bca4358SStanimir Varbanov 
9513bca4358SStanimir Varbanov 	for (i = 0; i < res->resets_num; i++) {
9523bca4358SStanimir Varbanov 		core->resets[i] =
9533bca4358SStanimir Varbanov 			devm_reset_control_get_exclusive(dev, res->resets[i]);
9543bca4358SStanimir Varbanov 		if (IS_ERR(core->resets[i])) {
9553bca4358SStanimir Varbanov 			ret = PTR_ERR(core->resets[i]);
9563bca4358SStanimir Varbanov 			return ret;
9573bca4358SStanimir Varbanov 		}
9583bca4358SStanimir Varbanov 	}
9593bca4358SStanimir Varbanov 
9603bca4358SStanimir Varbanov 	return 0;
9613bca4358SStanimir Varbanov }
9623bca4358SStanimir Varbanov 
core_get_v4(struct venus_core * core)96308b1cf47SBryan O'Donoghue static int core_get_v4(struct venus_core *core)
9647482a983SStanimir Varbanov {
96508b1cf47SBryan O'Donoghue 	struct device *dev = core->dev;
9667482a983SStanimir Varbanov 	const struct venus_resources *res = core->res;
9677482a983SStanimir Varbanov 	int ret;
9687482a983SStanimir Varbanov 
9697482a983SStanimir Varbanov 	ret = core_clks_get(core);
9707482a983SStanimir Varbanov 	if (ret)
9717482a983SStanimir Varbanov 		return ret;
9727482a983SStanimir Varbanov 
9737482a983SStanimir Varbanov 	if (!res->vcodec_pmdomains_num)
9747482a983SStanimir Varbanov 		legacy_binding = true;
9757482a983SStanimir Varbanov 
9767482a983SStanimir Varbanov 	dev_info(dev, "%s legacy binding\n", legacy_binding ? "" : "non");
9777482a983SStanimir Varbanov 
9787482a983SStanimir Varbanov 	ret = vcodec_clks_get(core, dev, core->vcodec0_clks, res->vcodec0_clks);
9797482a983SStanimir Varbanov 	if (ret)
9807482a983SStanimir Varbanov 		return ret;
9817482a983SStanimir Varbanov 
9827482a983SStanimir Varbanov 	ret = vcodec_clks_get(core, dev, core->vcodec1_clks, res->vcodec1_clks);
9837482a983SStanimir Varbanov 	if (ret)
9847482a983SStanimir Varbanov 		return ret;
9857482a983SStanimir Varbanov 
9863bca4358SStanimir Varbanov 	ret = core_resets_get(core);
9873bca4358SStanimir Varbanov 	if (ret)
9883bca4358SStanimir Varbanov 		return ret;
9893bca4358SStanimir Varbanov 
9907482a983SStanimir Varbanov 	if (legacy_binding)
9917482a983SStanimir Varbanov 		return 0;
9927482a983SStanimir Varbanov 
9930394360eSYangtao Li 	ret = devm_pm_opp_set_clkname(dev, "core");
9940394360eSYangtao Li 	if (ret)
9950394360eSYangtao Li 		return ret;
9969a538b83SRajendra Nayak 
9971d95af02SStanimir Varbanov 	ret = vcodec_domains_get(core);
9981d95af02SStanimir Varbanov 	if (ret)
9991d95af02SStanimir Varbanov 		return ret;
10001d95af02SStanimir Varbanov 
10019a538b83SRajendra Nayak 	if (core->res->opp_pmdomain) {
10020394360eSYangtao Li 		ret = devm_pm_opp_of_add_table(dev);
10039a538b83SRajendra Nayak 		if (!ret) {
10049a538b83SRajendra Nayak 			core->has_opp_table = true;
10059a538b83SRajendra Nayak 		} else if (ret != -ENODEV) {
10069a538b83SRajendra Nayak 			dev_err(dev, "invalid OPP table in device tree\n");
10077482a983SStanimir Varbanov 			return ret;
10089a538b83SRajendra Nayak 		}
10099a538b83SRajendra Nayak 	}
10109a538b83SRajendra Nayak 
10117482a983SStanimir Varbanov 	return 0;
10127482a983SStanimir Varbanov }
10137482a983SStanimir Varbanov 
core_put_v4(struct venus_core * core)101408b1cf47SBryan O'Donoghue static void core_put_v4(struct venus_core *core)
10157482a983SStanimir Varbanov {
10167482a983SStanimir Varbanov 	if (legacy_binding)
10177482a983SStanimir Varbanov 		return;
10187482a983SStanimir Varbanov 
101908b1cf47SBryan O'Donoghue 	vcodec_domains_put(core);
10207482a983SStanimir Varbanov }
10217482a983SStanimir Varbanov 
core_power_v4(struct venus_core * core,int on)102208b1cf47SBryan O'Donoghue static int core_power_v4(struct venus_core *core, int on)
10237482a983SStanimir Varbanov {
102408b1cf47SBryan O'Donoghue 	struct device *dev = core->dev;
1025693c301aSUlf Hansson 	struct device *pmctrl = core->pmdomains ?
1026693c301aSUlf Hansson 			core->pmdomains->pd_devs[0] : NULL;
10277482a983SStanimir Varbanov 	int ret = 0;
10287482a983SStanimir Varbanov 
10299a538b83SRajendra Nayak 	if (on == POWER_ON) {
1030a76f43a4SStanimir Varbanov 		if (pmctrl) {
1031f6bf35eeSMauro Carvalho Chehab 			ret = pm_runtime_resume_and_get(pmctrl);
1032a76f43a4SStanimir Varbanov 			if (ret < 0) {
1033a76f43a4SStanimir Varbanov 				return ret;
1034a76f43a4SStanimir Varbanov 			}
1035a76f43a4SStanimir Varbanov 		}
1036a76f43a4SStanimir Varbanov 
10373bca4358SStanimir Varbanov 		ret = core_resets_reset(core);
10383bca4358SStanimir Varbanov 		if (ret) {
10393bca4358SStanimir Varbanov 			if (pmctrl)
10403bca4358SStanimir Varbanov 				pm_runtime_put_sync(pmctrl);
10413bca4358SStanimir Varbanov 			return ret;
10423bca4358SStanimir Varbanov 		}
10433bca4358SStanimir Varbanov 
10447482a983SStanimir Varbanov 		ret = core_clks_enable(core);
1045a76f43a4SStanimir Varbanov 		if (ret < 0 && pmctrl)
1046a76f43a4SStanimir Varbanov 			pm_runtime_put_sync(pmctrl);
10479a538b83SRajendra Nayak 	} else {
10489a538b83SRajendra Nayak 		/* Drop the performance state vote */
10499a538b83SRajendra Nayak 		if (core->opp_pmdomain)
10509a538b83SRajendra Nayak 			dev_pm_opp_set_rate(dev, 0);
10519a538b83SRajendra Nayak 
10527482a983SStanimir Varbanov 		core_clks_disable(core);
1053a76f43a4SStanimir Varbanov 
10543bca4358SStanimir Varbanov 		ret = core_resets_reset(core);
10553bca4358SStanimir Varbanov 
1056a76f43a4SStanimir Varbanov 		if (pmctrl)
1057a76f43a4SStanimir Varbanov 			pm_runtime_put_sync(pmctrl);
10589a538b83SRajendra Nayak 	}
10597482a983SStanimir Varbanov 
10607482a983SStanimir Varbanov 	return ret;
10617482a983SStanimir Varbanov }
10627482a983SStanimir Varbanov 
calculate_inst_freq(struct venus_inst * inst,unsigned long filled_len)10637482a983SStanimir Varbanov static unsigned long calculate_inst_freq(struct venus_inst *inst,
10647482a983SStanimir Varbanov 					 unsigned long filled_len)
10657482a983SStanimir Varbanov {
10663cfe5815SDikshita Agarwal 	unsigned long vpp_freq_per_mb = 0, vpp_freq = 0, vsp_freq = 0;
10677482a983SStanimir Varbanov 	u32 fps = (u32)inst->fps;
10687482a983SStanimir Varbanov 	u32 mbs_per_sec;
10697482a983SStanimir Varbanov 
1070b57cf6a0SMansur Alisha Shaik 	mbs_per_sec = load_per_instance(inst);
10717482a983SStanimir Varbanov 
1072d33a9441SStanimir Varbanov 	if (inst->state != INST_START)
1073d33a9441SStanimir Varbanov 		return 0;
1074d33a9441SStanimir Varbanov 
107514442321SMansur Alisha Shaik 	if (inst->session_type == VIDC_SESSION_TYPE_ENC) {
10763cfe5815SDikshita Agarwal 		vpp_freq_per_mb = inst->flags & VENUS_LOW_POWER ?
10773cfe5815SDikshita Agarwal 			inst->clk_data.low_power_freq :
10783cfe5815SDikshita Agarwal 			inst->clk_data.vpp_freq;
10793cfe5815SDikshita Agarwal 
10803cfe5815SDikshita Agarwal 		vpp_freq = mbs_per_sec * vpp_freq_per_mb;
108114442321SMansur Alisha Shaik 	} else {
108214442321SMansur Alisha Shaik 		vpp_freq = mbs_per_sec * inst->clk_data.vpp_freq;
108314442321SMansur Alisha Shaik 	}
108414442321SMansur Alisha Shaik 
10857482a983SStanimir Varbanov 	/* 21 / 20 is overhead factor */
10867482a983SStanimir Varbanov 	vpp_freq += vpp_freq / 20;
1087aa603389SStanimir Varbanov 	vsp_freq = mbs_per_sec * inst->clk_data.vsp_freq;
10887482a983SStanimir Varbanov 
10897482a983SStanimir Varbanov 	/* 10 / 7 is overhead factor */
10907482a983SStanimir Varbanov 	if (inst->session_type == VIDC_SESSION_TYPE_ENC)
10917482a983SStanimir Varbanov 		vsp_freq += (inst->controls.enc.bitrate * 10) / 7;
10927482a983SStanimir Varbanov 	else
10937482a983SStanimir Varbanov 		vsp_freq += ((fps * filled_len * 8) * 10) / 7;
10947482a983SStanimir Varbanov 
10957482a983SStanimir Varbanov 	return max(vpp_freq, vsp_freq);
10967482a983SStanimir Varbanov }
10977482a983SStanimir Varbanov 
load_scale_v4(struct venus_inst * inst)10987482a983SStanimir Varbanov static int load_scale_v4(struct venus_inst *inst)
10997482a983SStanimir Varbanov {
11007482a983SStanimir Varbanov 	struct venus_core *core = inst->core;
11017482a983SStanimir Varbanov 	const struct freq_tbl *table = core->res->freq_tbl;
11027482a983SStanimir Varbanov 	unsigned int num_rows = core->res->freq_tbl_size;
11037482a983SStanimir Varbanov 	struct device *dev = core->dev;
11047482a983SStanimir Varbanov 	unsigned long freq = 0, freq_core1 = 0, freq_core2 = 0;
11057482a983SStanimir Varbanov 	unsigned long filled_len = 0;
110691f2b7d2SMansur Alisha Shaik 	int i, ret = 0;
11077482a983SStanimir Varbanov 
11087482a983SStanimir Varbanov 	for (i = 0; i < inst->num_input_bufs; i++)
11097482a983SStanimir Varbanov 		filled_len = max(filled_len, inst->payloads[i]);
11107482a983SStanimir Varbanov 
11117482a983SStanimir Varbanov 	if (inst->session_type == VIDC_SESSION_TYPE_DEC && !filled_len)
111291f2b7d2SMansur Alisha Shaik 		return ret;
11137482a983SStanimir Varbanov 
11147482a983SStanimir Varbanov 	freq = calculate_inst_freq(inst, filled_len);
11157482a983SStanimir Varbanov 	inst->clk_data.freq = freq;
11167482a983SStanimir Varbanov 
11177482a983SStanimir Varbanov 	mutex_lock(&core->lock);
11187482a983SStanimir Varbanov 	list_for_each_entry(inst, &core->instances, list) {
11197482a983SStanimir Varbanov 		if (inst->clk_data.core_id == VIDC_CORE_ID_1) {
11207482a983SStanimir Varbanov 			freq_core1 += inst->clk_data.freq;
11217482a983SStanimir Varbanov 		} else if (inst->clk_data.core_id == VIDC_CORE_ID_2) {
11227482a983SStanimir Varbanov 			freq_core2 += inst->clk_data.freq;
11237482a983SStanimir Varbanov 		} else if (inst->clk_data.core_id == VIDC_CORE_ID_3) {
11247482a983SStanimir Varbanov 			freq_core1 += inst->clk_data.freq;
11257482a983SStanimir Varbanov 			freq_core2 += inst->clk_data.freq;
11267482a983SStanimir Varbanov 		}
11277482a983SStanimir Varbanov 	}
11287482a983SStanimir Varbanov 
11297482a983SStanimir Varbanov 	freq = max(freq_core1, freq_core2);
11307482a983SStanimir Varbanov 
1131bcf6b264SMansur Alisha Shaik 	if (freq > table[0].freq) {
1132799926a1SMansur Alisha Shaik 		dev_dbg(dev, VDBGL "requested clock rate: %lu scaling clock rate : %lu\n",
11337482a983SStanimir Varbanov 			freq, table[0].freq);
1134799926a1SMansur Alisha Shaik 
1135799926a1SMansur Alisha Shaik 		freq = table[0].freq;
11367482a983SStanimir Varbanov 		goto set_freq;
11377482a983SStanimir Varbanov 	}
11387482a983SStanimir Varbanov 
11397482a983SStanimir Varbanov 	for (i = num_rows - 1 ; i >= 0; i--) {
11407482a983SStanimir Varbanov 		if (freq <= table[i].freq) {
11417482a983SStanimir Varbanov 			freq = table[i].freq;
11427482a983SStanimir Varbanov 			break;
11437482a983SStanimir Varbanov 		}
11447482a983SStanimir Varbanov 	}
11457482a983SStanimir Varbanov 
11467482a983SStanimir Varbanov set_freq:
11477482a983SStanimir Varbanov 
11487482a983SStanimir Varbanov 	ret = core_clks_set_rate(core, freq);
11497482a983SStanimir Varbanov 	if (ret) {
11507482a983SStanimir Varbanov 		dev_err(dev, "failed to set clock rate %lu (%d)\n",
11517482a983SStanimir Varbanov 			freq, ret);
115291f2b7d2SMansur Alisha Shaik 		goto exit;
11537482a983SStanimir Varbanov 	}
11547482a983SStanimir Varbanov 
11557482a983SStanimir Varbanov 	ret = load_scale_bw(core);
11567482a983SStanimir Varbanov 	if (ret) {
11577482a983SStanimir Varbanov 		dev_err(dev, "failed to set bandwidth (%d)\n",
11587482a983SStanimir Varbanov 			ret);
115991f2b7d2SMansur Alisha Shaik 		goto exit;
11607482a983SStanimir Varbanov 	}
11617482a983SStanimir Varbanov 
116291f2b7d2SMansur Alisha Shaik exit:
116391f2b7d2SMansur Alisha Shaik 	mutex_unlock(&core->lock);
116491f2b7d2SMansur Alisha Shaik 	return ret;
11657482a983SStanimir Varbanov }
11667482a983SStanimir Varbanov 
11677482a983SStanimir Varbanov static const struct venus_pm_ops pm_ops_v4 = {
11687482a983SStanimir Varbanov 	.core_get = core_get_v4,
11697482a983SStanimir Varbanov 	.core_put = core_put_v4,
11707482a983SStanimir Varbanov 	.core_power = core_power_v4,
11717482a983SStanimir Varbanov 	.vdec_get = vdec_get_v4,
11727482a983SStanimir Varbanov 	.vdec_put = vdec_put_v4,
11737482a983SStanimir Varbanov 	.vdec_power = vdec_power_v4,
11747482a983SStanimir Varbanov 	.venc_get = venc_get_v4,
11757482a983SStanimir Varbanov 	.venc_put = venc_put_v4,
11767482a983SStanimir Varbanov 	.venc_power = venc_power_v4,
11774ebf9693SAniket Masule 	.coreid_power = coreid_power_v4,
11787482a983SStanimir Varbanov 	.load_scale = load_scale_v4,
11797482a983SStanimir Varbanov };
11807482a983SStanimir Varbanov 
venus_pm_get(enum hfi_version version)11817482a983SStanimir Varbanov const struct venus_pm_ops *venus_pm_get(enum hfi_version version)
11827482a983SStanimir Varbanov {
11837482a983SStanimir Varbanov 	switch (version) {
11847482a983SStanimir Varbanov 	case HFI_VERSION_1XX:
11857482a983SStanimir Varbanov 	default:
11867482a983SStanimir Varbanov 		return &pm_ops_v1;
11877482a983SStanimir Varbanov 	case HFI_VERSION_3XX:
11887482a983SStanimir Varbanov 		return &pm_ops_v3;
11897482a983SStanimir Varbanov 	case HFI_VERSION_4XX:
1190f24afa95SBryan O'Donoghue 	case HFI_VERSION_6XX:
11917482a983SStanimir Varbanov 		return &pm_ops_v4;
11927482a983SStanimir Varbanov 	}
11937482a983SStanimir Varbanov 
11947482a983SStanimir Varbanov 	return NULL;
11957482a983SStanimir Varbanov }
1196