xref: /openbmc/linux/drivers/media/platform/qcom/venus/pm_helpers.c (revision 26d0dfbb16fcb17d128a79dc70f3020ea6992af0)
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 
41564afe827SDikshita Agarwal 	if (IS_V6(core)) {
41664afe827SDikshita Agarwal 		ctrl = core->wrapper_base + WRAPPER_CORE_POWER_CONTROL_V6;
41764afe827SDikshita Agarwal 		stat = core->wrapper_base + WRAPPER_CORE_POWER_STATUS_V6;
41864afe827SDikshita Agarwal 	} else if (coreid == VIDC_CORE_ID_1) {
419ff2a7013SBryan O'Donoghue 		ctrl = core->wrapper_base + WRAPPER_VCODEC0_MMCC_POWER_CONTROL;
420ff2a7013SBryan O'Donoghue 		stat = core->wrapper_base + WRAPPER_VCODEC0_MMCC_POWER_STATUS;
4217482a983SStanimir Varbanov 	} else {
422ff2a7013SBryan O'Donoghue 		ctrl = core->wrapper_base + WRAPPER_VCODEC1_MMCC_POWER_CONTROL;
423ff2a7013SBryan O'Donoghue 		stat = core->wrapper_base + WRAPPER_VCODEC1_MMCC_POWER_STATUS;
4247482a983SStanimir Varbanov 	}
4257482a983SStanimir Varbanov 
4267482a983SStanimir Varbanov 	if (enable) {
4277482a983SStanimir Varbanov 		writel(0, ctrl);
4287482a983SStanimir Varbanov 
4297482a983SStanimir Varbanov 		ret = readl_poll_timeout(stat, val, val & BIT(1), 1, 100);
4307482a983SStanimir Varbanov 		if (ret)
4317482a983SStanimir Varbanov 			return ret;
4327482a983SStanimir Varbanov 	} else {
4337482a983SStanimir Varbanov 		writel(1, ctrl);
4347482a983SStanimir Varbanov 
4357482a983SStanimir Varbanov 		ret = readl_poll_timeout(stat, val, !(val & BIT(1)), 1, 100);
4367482a983SStanimir Varbanov 		if (ret)
4377482a983SStanimir Varbanov 			return ret;
4387482a983SStanimir Varbanov 	}
4397482a983SStanimir Varbanov 
4407482a983SStanimir Varbanov 	return 0;
4417482a983SStanimir Varbanov }
4427482a983SStanimir Varbanov 
poweroff_coreid(struct venus_core * core,unsigned int coreid_mask)4437482a983SStanimir Varbanov static int poweroff_coreid(struct venus_core *core, unsigned int coreid_mask)
4447482a983SStanimir Varbanov {
4457482a983SStanimir Varbanov 	int ret;
4467482a983SStanimir Varbanov 
4477482a983SStanimir Varbanov 	if (coreid_mask & VIDC_CORE_ID_1) {
4487482a983SStanimir Varbanov 		ret = vcodec_control_v4(core, VIDC_CORE_ID_1, true);
4497482a983SStanimir Varbanov 		if (ret)
4507482a983SStanimir Varbanov 			return ret;
4517482a983SStanimir Varbanov 
4527482a983SStanimir Varbanov 		vcodec_clks_disable(core, core->vcodec0_clks);
4537482a983SStanimir Varbanov 
4547482a983SStanimir Varbanov 		ret = vcodec_control_v4(core, VIDC_CORE_ID_1, false);
4557482a983SStanimir Varbanov 		if (ret)
4567482a983SStanimir Varbanov 			return ret;
4577482a983SStanimir Varbanov 
4587482a983SStanimir Varbanov 		ret = pm_runtime_put_sync(core->pmdomains[1]);
4597482a983SStanimir Varbanov 		if (ret < 0)
4607482a983SStanimir Varbanov 			return ret;
4617482a983SStanimir Varbanov 	}
4627482a983SStanimir Varbanov 
4637482a983SStanimir Varbanov 	if (coreid_mask & VIDC_CORE_ID_2) {
4647482a983SStanimir Varbanov 		ret = vcodec_control_v4(core, VIDC_CORE_ID_2, true);
4657482a983SStanimir Varbanov 		if (ret)
4667482a983SStanimir Varbanov 			return ret;
4677482a983SStanimir Varbanov 
4687482a983SStanimir Varbanov 		vcodec_clks_disable(core, core->vcodec1_clks);
4697482a983SStanimir Varbanov 
4707482a983SStanimir Varbanov 		ret = vcodec_control_v4(core, VIDC_CORE_ID_2, false);
4717482a983SStanimir Varbanov 		if (ret)
4727482a983SStanimir Varbanov 			return ret;
4737482a983SStanimir Varbanov 
4747482a983SStanimir Varbanov 		ret = pm_runtime_put_sync(core->pmdomains[2]);
4757482a983SStanimir Varbanov 		if (ret < 0)
4767482a983SStanimir Varbanov 			return ret;
4777482a983SStanimir Varbanov 	}
4787482a983SStanimir Varbanov 
4797482a983SStanimir Varbanov 	return 0;
4807482a983SStanimir Varbanov }
4817482a983SStanimir Varbanov 
poweron_coreid(struct venus_core * core,unsigned int coreid_mask)4827482a983SStanimir Varbanov static int poweron_coreid(struct venus_core *core, unsigned int coreid_mask)
4837482a983SStanimir Varbanov {
4847482a983SStanimir Varbanov 	int ret;
4857482a983SStanimir Varbanov 
4867482a983SStanimir Varbanov 	if (coreid_mask & VIDC_CORE_ID_1) {
4877482a983SStanimir Varbanov 		ret = pm_runtime_get_sync(core->pmdomains[1]);
4887482a983SStanimir Varbanov 		if (ret < 0)
4897482a983SStanimir Varbanov 			return ret;
4907482a983SStanimir Varbanov 
4917482a983SStanimir Varbanov 		ret = vcodec_control_v4(core, VIDC_CORE_ID_1, true);
4927482a983SStanimir Varbanov 		if (ret)
4937482a983SStanimir Varbanov 			return ret;
4947482a983SStanimir Varbanov 
4957482a983SStanimir Varbanov 		ret = vcodec_clks_enable(core, core->vcodec0_clks);
4967482a983SStanimir Varbanov 		if (ret)
4977482a983SStanimir Varbanov 			return ret;
4987482a983SStanimir Varbanov 
4997482a983SStanimir Varbanov 		ret = vcodec_control_v4(core, VIDC_CORE_ID_1, false);
5007482a983SStanimir Varbanov 		if (ret < 0)
5017482a983SStanimir Varbanov 			return ret;
5027482a983SStanimir Varbanov 	}
5037482a983SStanimir Varbanov 
5047482a983SStanimir Varbanov 	if (coreid_mask & VIDC_CORE_ID_2) {
5057482a983SStanimir Varbanov 		ret = pm_runtime_get_sync(core->pmdomains[2]);
5067482a983SStanimir Varbanov 		if (ret < 0)
5077482a983SStanimir Varbanov 			return ret;
5087482a983SStanimir Varbanov 
5097482a983SStanimir Varbanov 		ret = vcodec_control_v4(core, VIDC_CORE_ID_2, true);
5107482a983SStanimir Varbanov 		if (ret)
5117482a983SStanimir Varbanov 			return ret;
5127482a983SStanimir Varbanov 
5137482a983SStanimir Varbanov 		ret = vcodec_clks_enable(core, core->vcodec1_clks);
5147482a983SStanimir Varbanov 		if (ret)
5157482a983SStanimir Varbanov 			return ret;
5167482a983SStanimir Varbanov 
5177482a983SStanimir Varbanov 		ret = vcodec_control_v4(core, VIDC_CORE_ID_2, false);
5187482a983SStanimir Varbanov 		if (ret < 0)
5197482a983SStanimir Varbanov 			return ret;
5207482a983SStanimir Varbanov 	}
5217482a983SStanimir Varbanov 
5227482a983SStanimir Varbanov 	return 0;
5237482a983SStanimir Varbanov }
5247482a983SStanimir Varbanov 
power_save_mode_enable(struct venus_inst * inst,bool enable)5253cfe5815SDikshita Agarwal static inline int power_save_mode_enable(struct venus_inst *inst,
5263cfe5815SDikshita Agarwal 					 bool enable)
5273cfe5815SDikshita Agarwal {
5283cfe5815SDikshita Agarwal 	struct venc_controls *enc_ctr = &inst->controls.enc;
5293cfe5815SDikshita Agarwal 	const u32 ptype = HFI_PROPERTY_CONFIG_VENC_PERF_MODE;
5303cfe5815SDikshita Agarwal 	u32 venc_mode;
5313cfe5815SDikshita Agarwal 	int ret = 0;
5323cfe5815SDikshita Agarwal 
5333cfe5815SDikshita Agarwal 	if (inst->session_type != VIDC_SESSION_TYPE_ENC)
5343cfe5815SDikshita Agarwal 		return 0;
5353cfe5815SDikshita Agarwal 
5363cfe5815SDikshita Agarwal 	if (enc_ctr->bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CQ)
5373cfe5815SDikshita Agarwal 		enable = false;
5383cfe5815SDikshita Agarwal 
5393cfe5815SDikshita Agarwal 	venc_mode = enable ? HFI_VENC_PERFMODE_POWER_SAVE :
5403cfe5815SDikshita Agarwal 		HFI_VENC_PERFMODE_MAX_QUALITY;
5413cfe5815SDikshita Agarwal 
5423cfe5815SDikshita Agarwal 	ret = hfi_session_set_property(inst, ptype, &venc_mode);
5433cfe5815SDikshita Agarwal 	if (ret)
5443cfe5815SDikshita Agarwal 		return ret;
5453cfe5815SDikshita Agarwal 
5463cfe5815SDikshita Agarwal 	inst->flags = enable ? inst->flags | VENUS_LOW_POWER :
5473cfe5815SDikshita Agarwal 		inst->flags & ~VENUS_LOW_POWER;
5483cfe5815SDikshita Agarwal 
5493cfe5815SDikshita Agarwal 	return ret;
5503cfe5815SDikshita Agarwal }
5513cfe5815SDikshita Agarwal 
move_core_to_power_save_mode(struct venus_core * core,u32 core_id)5523cfe5815SDikshita Agarwal static int move_core_to_power_save_mode(struct venus_core *core,
5533cfe5815SDikshita Agarwal 					u32 core_id)
5543cfe5815SDikshita Agarwal {
5553cfe5815SDikshita Agarwal 	struct venus_inst *inst = NULL;
5563cfe5815SDikshita Agarwal 
5573cfe5815SDikshita Agarwal 	mutex_lock(&core->lock);
5583cfe5815SDikshita Agarwal 	list_for_each_entry(inst, &core->instances, list) {
5593cfe5815SDikshita Agarwal 		if (inst->clk_data.core_id == core_id &&
5603cfe5815SDikshita Agarwal 		    inst->session_type == VIDC_SESSION_TYPE_ENC)
5613cfe5815SDikshita Agarwal 			power_save_mode_enable(inst, true);
5623cfe5815SDikshita Agarwal 	}
5633cfe5815SDikshita Agarwal 	mutex_unlock(&core->lock);
5643cfe5815SDikshita Agarwal 	return 0;
5653cfe5815SDikshita Agarwal }
5663cfe5815SDikshita Agarwal 
5674ebf9693SAniket Masule static void
min_loaded_core(struct venus_inst * inst,u32 * min_coreid,u32 * min_load,bool low_power)5683cfe5815SDikshita Agarwal min_loaded_core(struct venus_inst *inst, u32 *min_coreid, u32 *min_load, bool low_power)
5694ebf9693SAniket Masule {
5704ebf9693SAniket Masule 	u32 mbs_per_sec, load, core1_load = 0, core2_load = 0;
5714ebf9693SAniket Masule 	u32 cores_max = core_num_max(inst);
5724ebf9693SAniket Masule 	struct venus_core *core = inst->core;
5734ebf9693SAniket Masule 	struct venus_inst *inst_pos;
5744ebf9693SAniket Masule 	unsigned long vpp_freq;
5754ebf9693SAniket Masule 	u32 coreid;
5764ebf9693SAniket Masule 
5774ebf9693SAniket Masule 	mutex_lock(&core->lock);
5784ebf9693SAniket Masule 
5794ebf9693SAniket Masule 	list_for_each_entry(inst_pos, &core->instances, list) {
5804ebf9693SAniket Masule 		if (inst_pos == inst)
5814ebf9693SAniket Masule 			continue;
582e0eb3481SMansur Alisha Shaik 
583e0eb3481SMansur Alisha Shaik 		if (inst_pos->state != INST_START)
584e0eb3481SMansur Alisha Shaik 			continue;
585e0eb3481SMansur Alisha Shaik 
5863cfe5815SDikshita Agarwal 		if (inst->session_type == VIDC_SESSION_TYPE_DEC)
587aa603389SStanimir Varbanov 			vpp_freq = inst_pos->clk_data.vpp_freq;
5883cfe5815SDikshita Agarwal 		else if (inst->session_type == VIDC_SESSION_TYPE_ENC)
589b1f9bb80SMansur Alisha Shaik 			vpp_freq = low_power ? inst_pos->clk_data.low_power_freq :
590b1f9bb80SMansur Alisha Shaik 				inst_pos->clk_data.vpp_freq;
5913cfe5815SDikshita Agarwal 		else
5923cfe5815SDikshita Agarwal 			continue;
5933cfe5815SDikshita Agarwal 
5944ebf9693SAniket Masule 		coreid = inst_pos->clk_data.core_id;
5954ebf9693SAniket Masule 
5964ebf9693SAniket Masule 		mbs_per_sec = load_per_instance(inst_pos);
5974ebf9693SAniket Masule 		load = mbs_per_sec * vpp_freq;
5984ebf9693SAniket Masule 
5994ebf9693SAniket Masule 		if ((coreid & VIDC_CORE_ID_3) == VIDC_CORE_ID_3) {
6004ebf9693SAniket Masule 			core1_load += load / 2;
6014ebf9693SAniket Masule 			core2_load += load / 2;
6024ebf9693SAniket Masule 		} else if (coreid & VIDC_CORE_ID_1) {
6034ebf9693SAniket Masule 			core1_load += load;
6044ebf9693SAniket Masule 		} else if (coreid & VIDC_CORE_ID_2) {
6054ebf9693SAniket Masule 			core2_load += load;
6064ebf9693SAniket Masule 		}
6074ebf9693SAniket Masule 	}
6084ebf9693SAniket Masule 
6094ebf9693SAniket Masule 	*min_coreid = core1_load <= core2_load ?
6104ebf9693SAniket Masule 			VIDC_CORE_ID_1 : VIDC_CORE_ID_2;
6114ebf9693SAniket Masule 	*min_load = min(core1_load, core2_load);
6124ebf9693SAniket Masule 
6134ebf9693SAniket Masule 	if (cores_max < VIDC_CORE_ID_2 || core->res->vcodec_num < 2) {
6144ebf9693SAniket Masule 		*min_coreid = VIDC_CORE_ID_1;
6154ebf9693SAniket Masule 		*min_load = core1_load;
6164ebf9693SAniket Masule 	}
6174ebf9693SAniket Masule 
6184ebf9693SAniket Masule 	mutex_unlock(&core->lock);
6194ebf9693SAniket Masule }
6204ebf9693SAniket Masule 
decide_core(struct venus_inst * inst)6214ebf9693SAniket Masule static int decide_core(struct venus_inst *inst)
6224ebf9693SAniket Masule {
6234ebf9693SAniket Masule 	const u32 ptype = HFI_PROPERTY_CONFIG_VIDEOCORES_USAGE;
6244ebf9693SAniket Masule 	struct venus_core *core = inst->core;
6253cfe5815SDikshita Agarwal 	u32 min_coreid, min_load, cur_inst_load;
6263cfe5815SDikshita Agarwal 	u32 min_lp_coreid, min_lp_load, cur_inst_lp_load;
6274ebf9693SAniket Masule 	struct hfi_videocores_usage_type cu;
6284ebf9693SAniket Masule 	unsigned long max_freq;
6293cfe5815SDikshita Agarwal 	int ret = 0;
6304ebf9693SAniket Masule 
6314ebf9693SAniket Masule 	if (legacy_binding) {
6324ebf9693SAniket Masule 		if (inst->session_type == VIDC_SESSION_TYPE_DEC)
6334ebf9693SAniket Masule 			cu.video_core_enable_mask = VIDC_CORE_ID_1;
6344ebf9693SAniket Masule 		else
6354ebf9693SAniket Masule 			cu.video_core_enable_mask = VIDC_CORE_ID_2;
6364ebf9693SAniket Masule 
6374ebf9693SAniket Masule 		goto done;
6384ebf9693SAniket Masule 	}
6394ebf9693SAniket Masule 
6404ebf9693SAniket Masule 	if (inst->clk_data.core_id != VIDC_CORE_ID_DEFAULT)
6414ebf9693SAniket Masule 		return 0;
6424ebf9693SAniket Masule 
6433cfe5815SDikshita Agarwal 	cur_inst_load = load_per_instance(inst);
6443cfe5815SDikshita Agarwal 	cur_inst_load *= inst->clk_data.vpp_freq;
6453cfe5815SDikshita Agarwal 	/*TODO : divide this inst->load by work_route */
6463cfe5815SDikshita Agarwal 
6473cfe5815SDikshita Agarwal 	cur_inst_lp_load = load_per_instance(inst);
6483cfe5815SDikshita Agarwal 	cur_inst_lp_load *= inst->clk_data.low_power_freq;
6493cfe5815SDikshita Agarwal 	/*TODO : divide this inst->load by work_route */
6503cfe5815SDikshita Agarwal 
6514ebf9693SAniket Masule 	max_freq = core->res->freq_tbl[0].freq;
6524ebf9693SAniket Masule 
6533cfe5815SDikshita Agarwal 	min_loaded_core(inst, &min_coreid, &min_load, false);
6543cfe5815SDikshita Agarwal 	min_loaded_core(inst, &min_lp_coreid, &min_lp_load, true);
6554ebf9693SAniket Masule 
6563cfe5815SDikshita Agarwal 	if (cur_inst_load + min_load <= max_freq) {
6573cfe5815SDikshita Agarwal 		inst->clk_data.core_id = min_coreid;
6583cfe5815SDikshita Agarwal 		cu.video_core_enable_mask = min_coreid;
6593cfe5815SDikshita Agarwal 	} else if (cur_inst_lp_load + min_load <= max_freq) {
6603cfe5815SDikshita Agarwal 		/* Move current instance to LP and return */
6613cfe5815SDikshita Agarwal 		inst->clk_data.core_id = min_coreid;
6623cfe5815SDikshita Agarwal 		cu.video_core_enable_mask = min_coreid;
6633cfe5815SDikshita Agarwal 		power_save_mode_enable(inst, true);
6643cfe5815SDikshita Agarwal 	} else if (cur_inst_lp_load + min_lp_load <= max_freq) {
6653cfe5815SDikshita Agarwal 		/* Move all instances to LP mode and return */
6663cfe5815SDikshita Agarwal 		inst->clk_data.core_id = min_lp_coreid;
6673cfe5815SDikshita Agarwal 		cu.video_core_enable_mask = min_lp_coreid;
6683cfe5815SDikshita Agarwal 		move_core_to_power_save_mode(core, min_lp_coreid);
6693cfe5815SDikshita Agarwal 	} else {
6703cfe5815SDikshita Agarwal 		dev_warn(core->dev, "HW can't support this load");
6714ebf9693SAniket Masule 		return -EINVAL;
6724ebf9693SAniket Masule 	}
6734ebf9693SAniket Masule 
6744ebf9693SAniket Masule done:
6753cfe5815SDikshita Agarwal 	ret = hfi_session_set_property(inst, ptype, &cu);
6763cfe5815SDikshita Agarwal 	if (ret)
6773cfe5815SDikshita Agarwal 		return ret;
6783cfe5815SDikshita Agarwal 
6793cfe5815SDikshita Agarwal 	return ret;
6804ebf9693SAniket Masule }
6814ebf9693SAniket Masule 
acquire_core(struct venus_inst * inst)6824ebf9693SAniket Masule static int acquire_core(struct venus_inst *inst)
6834ebf9693SAniket Masule {
6844ebf9693SAniket Masule 	struct venus_core *core = inst->core;
6854ebf9693SAniket Masule 	unsigned int coreid_mask = 0;
6864ebf9693SAniket Masule 
6874ebf9693SAniket Masule 	if (inst->core_acquired)
6884ebf9693SAniket Masule 		return 0;
6894ebf9693SAniket Masule 
6904ebf9693SAniket Masule 	inst->core_acquired = true;
6914ebf9693SAniket Masule 
6924ebf9693SAniket Masule 	if (inst->clk_data.core_id & VIDC_CORE_ID_1) {
6934ebf9693SAniket Masule 		if (core->core0_usage_count++)
6944ebf9693SAniket Masule 			return 0;
6954ebf9693SAniket Masule 
6964ebf9693SAniket Masule 		coreid_mask = VIDC_CORE_ID_1;
6974ebf9693SAniket Masule 	}
6984ebf9693SAniket Masule 
6994ebf9693SAniket Masule 	if (inst->clk_data.core_id & VIDC_CORE_ID_2) {
7004ebf9693SAniket Masule 		if (core->core1_usage_count++)
7014ebf9693SAniket Masule 			return 0;
7024ebf9693SAniket Masule 
7034ebf9693SAniket Masule 		coreid_mask |= VIDC_CORE_ID_2;
7044ebf9693SAniket Masule 	}
7054ebf9693SAniket Masule 
7064ebf9693SAniket Masule 	return poweron_coreid(core, coreid_mask);
7074ebf9693SAniket Masule }
7084ebf9693SAniket Masule 
release_core(struct venus_inst * inst)7094ebf9693SAniket Masule static int release_core(struct venus_inst *inst)
7104ebf9693SAniket Masule {
7114ebf9693SAniket Masule 	struct venus_core *core = inst->core;
7124ebf9693SAniket Masule 	unsigned int coreid_mask = 0;
7134ebf9693SAniket Masule 	int ret;
7144ebf9693SAniket Masule 
7154ebf9693SAniket Masule 	if (!inst->core_acquired)
7164ebf9693SAniket Masule 		return 0;
7174ebf9693SAniket Masule 
7184ebf9693SAniket Masule 	if (inst->clk_data.core_id & VIDC_CORE_ID_1) {
7194ebf9693SAniket Masule 		if (--core->core0_usage_count)
7204ebf9693SAniket Masule 			goto done;
7214ebf9693SAniket Masule 
7224ebf9693SAniket Masule 		coreid_mask = VIDC_CORE_ID_1;
7234ebf9693SAniket Masule 	}
7244ebf9693SAniket Masule 
7254ebf9693SAniket Masule 	if (inst->clk_data.core_id & VIDC_CORE_ID_2) {
7264ebf9693SAniket Masule 		if (--core->core1_usage_count)
7274ebf9693SAniket Masule 			goto done;
7284ebf9693SAniket Masule 
7294ebf9693SAniket Masule 		coreid_mask |= VIDC_CORE_ID_2;
7304ebf9693SAniket Masule 	}
7314ebf9693SAniket Masule 
7324ebf9693SAniket Masule 	ret = poweroff_coreid(core, coreid_mask);
7334ebf9693SAniket Masule 	if (ret)
7344ebf9693SAniket Masule 		return ret;
7354ebf9693SAniket Masule 
7364ebf9693SAniket Masule done:
7374ebf9693SAniket Masule 	inst->clk_data.core_id = VIDC_CORE_ID_DEFAULT;
7384ebf9693SAniket Masule 	inst->core_acquired = false;
7394ebf9693SAniket Masule 	return 0;
7404ebf9693SAniket Masule }
7414ebf9693SAniket Masule 
coreid_power_v4(struct venus_inst * inst,int on)7424ebf9693SAniket Masule static int coreid_power_v4(struct venus_inst *inst, int on)
7434ebf9693SAniket Masule {
7444ebf9693SAniket Masule 	struct venus_core *core = inst->core;
7454ebf9693SAniket Masule 	int ret;
7464ebf9693SAniket Masule 
7474ebf9693SAniket Masule 	if (legacy_binding)
7484ebf9693SAniket Masule 		return 0;
7494ebf9693SAniket Masule 
7504ebf9693SAniket Masule 	if (on == POWER_ON) {
7514ebf9693SAniket Masule 		ret = decide_core(inst);
7524ebf9693SAniket Masule 		if (ret)
7534ebf9693SAniket Masule 			return ret;
7544ebf9693SAniket Masule 
7554ebf9693SAniket Masule 		mutex_lock(&core->lock);
7564ebf9693SAniket Masule 		ret = acquire_core(inst);
7574ebf9693SAniket Masule 		mutex_unlock(&core->lock);
7584ebf9693SAniket Masule 	} else {
7594ebf9693SAniket Masule 		mutex_lock(&core->lock);
7604ebf9693SAniket Masule 		ret = release_core(inst);
7614ebf9693SAniket Masule 		mutex_unlock(&core->lock);
7624ebf9693SAniket Masule 	}
7634ebf9693SAniket Masule 
7644ebf9693SAniket Masule 	return ret;
7654ebf9693SAniket Masule }
7664ebf9693SAniket Masule 
vdec_get_v4(struct device * dev)7677482a983SStanimir Varbanov static int vdec_get_v4(struct device *dev)
7687482a983SStanimir Varbanov {
7697482a983SStanimir Varbanov 	struct venus_core *core = dev_get_drvdata(dev);
7707482a983SStanimir Varbanov 
7717482a983SStanimir Varbanov 	if (!legacy_binding)
7727482a983SStanimir Varbanov 		return 0;
7737482a983SStanimir Varbanov 
7747482a983SStanimir Varbanov 	return vcodec_clks_get(core, dev, core->vcodec0_clks,
7757482a983SStanimir Varbanov 			       core->res->vcodec0_clks);
7767482a983SStanimir Varbanov }
7777482a983SStanimir Varbanov 
vdec_put_v4(struct device * dev)7787482a983SStanimir Varbanov static void vdec_put_v4(struct device *dev)
7797482a983SStanimir Varbanov {
7807482a983SStanimir Varbanov 	struct venus_core *core = dev_get_drvdata(dev);
7817482a983SStanimir Varbanov 	unsigned int i;
7827482a983SStanimir Varbanov 
7837482a983SStanimir Varbanov 	if (!legacy_binding)
7847482a983SStanimir Varbanov 		return;
7857482a983SStanimir Varbanov 
7867482a983SStanimir Varbanov 	for (i = 0; i < core->res->vcodec_clks_num; i++)
7877482a983SStanimir Varbanov 		core->vcodec0_clks[i] = NULL;
7887482a983SStanimir Varbanov }
7897482a983SStanimir Varbanov 
vdec_power_v4(struct device * dev,int on)7907482a983SStanimir Varbanov static int vdec_power_v4(struct device *dev, int on)
7917482a983SStanimir Varbanov {
7927482a983SStanimir Varbanov 	struct venus_core *core = dev_get_drvdata(dev);
7937482a983SStanimir Varbanov 	int ret;
7947482a983SStanimir Varbanov 
7957482a983SStanimir Varbanov 	if (!legacy_binding)
7967482a983SStanimir Varbanov 		return 0;
7977482a983SStanimir Varbanov 
7987482a983SStanimir Varbanov 	ret = vcodec_control_v4(core, VIDC_CORE_ID_1, true);
7997482a983SStanimir Varbanov 	if (ret)
8007482a983SStanimir Varbanov 		return ret;
8017482a983SStanimir Varbanov 
8027482a983SStanimir Varbanov 	if (on == POWER_ON)
8037482a983SStanimir Varbanov 		ret = vcodec_clks_enable(core, core->vcodec0_clks);
8047482a983SStanimir Varbanov 	else
8057482a983SStanimir Varbanov 		vcodec_clks_disable(core, core->vcodec0_clks);
8067482a983SStanimir Varbanov 
8077482a983SStanimir Varbanov 	vcodec_control_v4(core, VIDC_CORE_ID_1, false);
8087482a983SStanimir Varbanov 
8097482a983SStanimir Varbanov 	return ret;
8107482a983SStanimir Varbanov }
8117482a983SStanimir Varbanov 
venc_get_v4(struct device * dev)8127482a983SStanimir Varbanov static int venc_get_v4(struct device *dev)
8137482a983SStanimir Varbanov {
8147482a983SStanimir Varbanov 	struct venus_core *core = dev_get_drvdata(dev);
8157482a983SStanimir Varbanov 
8167482a983SStanimir Varbanov 	if (!legacy_binding)
8177482a983SStanimir Varbanov 		return 0;
8187482a983SStanimir Varbanov 
8197482a983SStanimir Varbanov 	return vcodec_clks_get(core, dev, core->vcodec1_clks,
8207482a983SStanimir Varbanov 			       core->res->vcodec1_clks);
8217482a983SStanimir Varbanov }
8227482a983SStanimir Varbanov 
venc_put_v4(struct device * dev)8237482a983SStanimir Varbanov static void venc_put_v4(struct device *dev)
8247482a983SStanimir Varbanov {
8257482a983SStanimir Varbanov 	struct venus_core *core = dev_get_drvdata(dev);
8267482a983SStanimir Varbanov 	unsigned int i;
8277482a983SStanimir Varbanov 
8287482a983SStanimir Varbanov 	if (!legacy_binding)
8297482a983SStanimir Varbanov 		return;
8307482a983SStanimir Varbanov 
8317482a983SStanimir Varbanov 	for (i = 0; i < core->res->vcodec_clks_num; i++)
8327482a983SStanimir Varbanov 		core->vcodec1_clks[i] = NULL;
8337482a983SStanimir Varbanov }
8347482a983SStanimir Varbanov 
venc_power_v4(struct device * dev,int on)8357482a983SStanimir Varbanov static int venc_power_v4(struct device *dev, int on)
8367482a983SStanimir Varbanov {
8377482a983SStanimir Varbanov 	struct venus_core *core = dev_get_drvdata(dev);
8387482a983SStanimir Varbanov 	int ret;
8397482a983SStanimir Varbanov 
8407482a983SStanimir Varbanov 	if (!legacy_binding)
8417482a983SStanimir Varbanov 		return 0;
8427482a983SStanimir Varbanov 
8437482a983SStanimir Varbanov 	ret = vcodec_control_v4(core, VIDC_CORE_ID_2, true);
8447482a983SStanimir Varbanov 	if (ret)
8457482a983SStanimir Varbanov 		return ret;
8467482a983SStanimir Varbanov 
8477482a983SStanimir Varbanov 	if (on == POWER_ON)
8487482a983SStanimir Varbanov 		ret = vcodec_clks_enable(core, core->vcodec1_clks);
8497482a983SStanimir Varbanov 	else
8507482a983SStanimir Varbanov 		vcodec_clks_disable(core, core->vcodec1_clks);
8517482a983SStanimir Varbanov 
8527482a983SStanimir Varbanov 	vcodec_control_v4(core, VIDC_CORE_ID_2, false);
8537482a983SStanimir Varbanov 
8547482a983SStanimir Varbanov 	return ret;
8557482a983SStanimir Varbanov }
8567482a983SStanimir Varbanov 
vcodec_domains_get(struct venus_core * core)85708b1cf47SBryan O'Donoghue static int vcodec_domains_get(struct venus_core *core)
8587482a983SStanimir Varbanov {
8599a538b83SRajendra Nayak 	int ret;
8609a538b83SRajendra Nayak 	struct device **opp_virt_dev;
86108b1cf47SBryan O'Donoghue 	struct device *dev = core->dev;
8627482a983SStanimir Varbanov 	const struct venus_resources *res = core->res;
8637482a983SStanimir Varbanov 	struct device *pd;
8647482a983SStanimir Varbanov 	unsigned int i;
8657482a983SStanimir Varbanov 
8667482a983SStanimir Varbanov 	if (!res->vcodec_pmdomains_num)
8679a538b83SRajendra Nayak 		goto skip_pmdomains;
8687482a983SStanimir Varbanov 
8697482a983SStanimir Varbanov 	for (i = 0; i < res->vcodec_pmdomains_num; i++) {
8707482a983SStanimir Varbanov 		pd = dev_pm_domain_attach_by_name(dev,
8717482a983SStanimir Varbanov 						  res->vcodec_pmdomains[i]);
8720f6e8d8cSTang Bin 		if (IS_ERR_OR_NULL(pd))
873*9649d26dSHans Verkuil 			return pd ? PTR_ERR(pd) : -ENODATA;
8747482a983SStanimir Varbanov 		core->pmdomains[i] = pd;
8757482a983SStanimir Varbanov 	}
8767482a983SStanimir Varbanov 
8779a538b83SRajendra Nayak skip_pmdomains:
8781d95af02SStanimir Varbanov 	if (!core->res->opp_pmdomain)
8797482a983SStanimir Varbanov 		return 0;
8809a538b83SRajendra Nayak 
8819a538b83SRajendra Nayak 	/* Attach the power domain for setting performance state */
8820394360eSYangtao Li 	ret = devm_pm_opp_attach_genpd(dev, res->opp_pmdomain, &opp_virt_dev);
8830394360eSYangtao Li 	if (ret)
8849a538b83SRajendra Nayak 		goto opp_attach_err;
8859a538b83SRajendra Nayak 
8869a538b83SRajendra Nayak 	core->opp_pmdomain = *opp_virt_dev;
8879a538b83SRajendra Nayak 	core->opp_dl_venus = device_link_add(dev, core->opp_pmdomain,
8889a538b83SRajendra Nayak 					     DL_FLAG_RPM_ACTIVE |
8899a538b83SRajendra Nayak 					     DL_FLAG_PM_RUNTIME |
8909a538b83SRajendra Nayak 					     DL_FLAG_STATELESS);
8919a538b83SRajendra Nayak 	if (!core->opp_dl_venus) {
8929a538b83SRajendra Nayak 		ret = -ENODEV;
8930394360eSYangtao Li 		goto opp_attach_err;
8949a538b83SRajendra Nayak 	}
8959a538b83SRajendra Nayak 
8969a538b83SRajendra Nayak 	return 0;
8979a538b83SRajendra Nayak 
8989a538b83SRajendra Nayak opp_attach_err:
8999a538b83SRajendra Nayak 	for (i = 0; i < res->vcodec_pmdomains_num; i++) {
9009a538b83SRajendra Nayak 		if (IS_ERR_OR_NULL(core->pmdomains[i]))
9019a538b83SRajendra Nayak 			continue;
9029a538b83SRajendra Nayak 		dev_pm_domain_detach(core->pmdomains[i], true);
9039a538b83SRajendra Nayak 	}
904a76f43a4SStanimir Varbanov 
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 {
9107482a983SStanimir Varbanov 	const struct venus_resources *res = core->res;
9117482a983SStanimir Varbanov 	unsigned int i;
9127482a983SStanimir Varbanov 
9137482a983SStanimir Varbanov 	if (!res->vcodec_pmdomains_num)
9149a538b83SRajendra Nayak 		goto skip_pmdomains;
9157482a983SStanimir Varbanov 
9167482a983SStanimir Varbanov 	for (i = 0; i < res->vcodec_pmdomains_num; i++) {
9177482a983SStanimir Varbanov 		if (IS_ERR_OR_NULL(core->pmdomains[i]))
9187482a983SStanimir Varbanov 			continue;
9197482a983SStanimir Varbanov 		dev_pm_domain_detach(core->pmdomains[i], true);
9207482a983SStanimir Varbanov 	}
9219a538b83SRajendra Nayak 
9229a538b83SRajendra Nayak skip_pmdomains:
9239a538b83SRajendra Nayak 	if (!core->has_opp_table)
9249a538b83SRajendra Nayak 		return;
9259a538b83SRajendra Nayak 
9269a538b83SRajendra Nayak 	if (core->opp_dl_venus)
9279a538b83SRajendra Nayak 		device_link_del(core->opp_dl_venus);
9287482a983SStanimir Varbanov }
9297482a983SStanimir Varbanov 
core_resets_reset(struct venus_core * core)9303bca4358SStanimir Varbanov static int core_resets_reset(struct venus_core *core)
9313bca4358SStanimir Varbanov {
9323bca4358SStanimir Varbanov 	const struct venus_resources *res = core->res;
933999267d0SColin Ian King 	unsigned int i;
9343bca4358SStanimir Varbanov 	int ret;
9353bca4358SStanimir Varbanov 
9363bca4358SStanimir Varbanov 	if (!res->resets_num)
9373bca4358SStanimir Varbanov 		return 0;
9383bca4358SStanimir Varbanov 
9393bca4358SStanimir Varbanov 	for (i = 0; i < res->resets_num; i++) {
9403bca4358SStanimir Varbanov 		ret = reset_control_assert(core->resets[i]);
9413bca4358SStanimir Varbanov 		if (ret)
9423bca4358SStanimir Varbanov 			goto err;
9433bca4358SStanimir Varbanov 
9443bca4358SStanimir Varbanov 		usleep_range(150, 250);
9453bca4358SStanimir Varbanov 		ret = reset_control_deassert(core->resets[i]);
9463bca4358SStanimir Varbanov 		if (ret)
9473bca4358SStanimir Varbanov 			goto err;
9483bca4358SStanimir Varbanov 	}
9493bca4358SStanimir Varbanov 
9503bca4358SStanimir Varbanov err:
9513bca4358SStanimir Varbanov 	return ret;
9523bca4358SStanimir Varbanov }
9533bca4358SStanimir Varbanov 
core_resets_get(struct venus_core * core)9543bca4358SStanimir Varbanov static int core_resets_get(struct venus_core *core)
9553bca4358SStanimir Varbanov {
9563bca4358SStanimir Varbanov 	struct device *dev = core->dev;
9573bca4358SStanimir Varbanov 	const struct venus_resources *res = core->res;
958999267d0SColin Ian King 	unsigned int i;
9593bca4358SStanimir Varbanov 	int ret;
9603bca4358SStanimir Varbanov 
9613bca4358SStanimir Varbanov 	if (!res->resets_num)
9623bca4358SStanimir Varbanov 		return 0;
9633bca4358SStanimir Varbanov 
9643bca4358SStanimir Varbanov 	for (i = 0; i < res->resets_num; i++) {
9653bca4358SStanimir Varbanov 		core->resets[i] =
9663bca4358SStanimir Varbanov 			devm_reset_control_get_exclusive(dev, res->resets[i]);
9673bca4358SStanimir Varbanov 		if (IS_ERR(core->resets[i])) {
9683bca4358SStanimir Varbanov 			ret = PTR_ERR(core->resets[i]);
9693bca4358SStanimir Varbanov 			return ret;
9703bca4358SStanimir Varbanov 		}
9713bca4358SStanimir Varbanov 	}
9723bca4358SStanimir Varbanov 
9733bca4358SStanimir Varbanov 	return 0;
9743bca4358SStanimir Varbanov }
9753bca4358SStanimir Varbanov 
core_get_v4(struct venus_core * core)97608b1cf47SBryan O'Donoghue static int core_get_v4(struct venus_core *core)
9777482a983SStanimir Varbanov {
97808b1cf47SBryan O'Donoghue 	struct device *dev = core->dev;
9797482a983SStanimir Varbanov 	const struct venus_resources *res = core->res;
9807482a983SStanimir Varbanov 	int ret;
9817482a983SStanimir Varbanov 
9827482a983SStanimir Varbanov 	ret = core_clks_get(core);
9837482a983SStanimir Varbanov 	if (ret)
9847482a983SStanimir Varbanov 		return ret;
9857482a983SStanimir Varbanov 
9867482a983SStanimir Varbanov 	if (!res->vcodec_pmdomains_num)
9877482a983SStanimir Varbanov 		legacy_binding = true;
9887482a983SStanimir Varbanov 
9897482a983SStanimir Varbanov 	dev_info(dev, "%s legacy binding\n", legacy_binding ? "" : "non");
9907482a983SStanimir Varbanov 
9917482a983SStanimir Varbanov 	ret = vcodec_clks_get(core, dev, core->vcodec0_clks, res->vcodec0_clks);
9927482a983SStanimir Varbanov 	if (ret)
9937482a983SStanimir Varbanov 		return ret;
9947482a983SStanimir Varbanov 
9957482a983SStanimir Varbanov 	ret = vcodec_clks_get(core, dev, core->vcodec1_clks, res->vcodec1_clks);
9967482a983SStanimir Varbanov 	if (ret)
9977482a983SStanimir Varbanov 		return ret;
9987482a983SStanimir Varbanov 
9993bca4358SStanimir Varbanov 	ret = core_resets_get(core);
10003bca4358SStanimir Varbanov 	if (ret)
10013bca4358SStanimir Varbanov 		return ret;
10023bca4358SStanimir Varbanov 
10037482a983SStanimir Varbanov 	if (legacy_binding)
10047482a983SStanimir Varbanov 		return 0;
10057482a983SStanimir Varbanov 
10060394360eSYangtao Li 	ret = devm_pm_opp_set_clkname(dev, "core");
10070394360eSYangtao Li 	if (ret)
10080394360eSYangtao Li 		return ret;
10099a538b83SRajendra Nayak 
10101d95af02SStanimir Varbanov 	ret = vcodec_domains_get(core);
10111d95af02SStanimir Varbanov 	if (ret)
10121d95af02SStanimir Varbanov 		return ret;
10131d95af02SStanimir Varbanov 
10149a538b83SRajendra Nayak 	if (core->res->opp_pmdomain) {
10150394360eSYangtao Li 		ret = devm_pm_opp_of_add_table(dev);
10169a538b83SRajendra Nayak 		if (!ret) {
10179a538b83SRajendra Nayak 			core->has_opp_table = true;
10189a538b83SRajendra Nayak 		} else if (ret != -ENODEV) {
10199a538b83SRajendra Nayak 			dev_err(dev, "invalid OPP table in device tree\n");
10207482a983SStanimir Varbanov 			return ret;
10219a538b83SRajendra Nayak 		}
10229a538b83SRajendra Nayak 	}
10239a538b83SRajendra Nayak 
10247482a983SStanimir Varbanov 	return 0;
10257482a983SStanimir Varbanov }
10267482a983SStanimir Varbanov 
core_put_v4(struct venus_core * core)102708b1cf47SBryan O'Donoghue static void core_put_v4(struct venus_core *core)
10287482a983SStanimir Varbanov {
10297482a983SStanimir Varbanov 	if (legacy_binding)
10307482a983SStanimir Varbanov 		return;
10317482a983SStanimir Varbanov 
103208b1cf47SBryan O'Donoghue 	vcodec_domains_put(core);
10337482a983SStanimir Varbanov }
10347482a983SStanimir Varbanov 
core_power_v4(struct venus_core * core,int on)103508b1cf47SBryan O'Donoghue static int core_power_v4(struct venus_core *core, int on)
10367482a983SStanimir Varbanov {
103708b1cf47SBryan O'Donoghue 	struct device *dev = core->dev;
1038a76f43a4SStanimir Varbanov 	struct device *pmctrl = core->pmdomains[0];
10397482a983SStanimir Varbanov 	int ret = 0;
10407482a983SStanimir Varbanov 
10419a538b83SRajendra Nayak 	if (on == POWER_ON) {
1042a76f43a4SStanimir Varbanov 		if (pmctrl) {
1043f6bf35eeSMauro Carvalho Chehab 			ret = pm_runtime_resume_and_get(pmctrl);
1044a76f43a4SStanimir Varbanov 			if (ret < 0) {
1045a76f43a4SStanimir Varbanov 				return ret;
1046a76f43a4SStanimir Varbanov 			}
1047a76f43a4SStanimir Varbanov 		}
1048a76f43a4SStanimir Varbanov 
10493bca4358SStanimir Varbanov 		ret = core_resets_reset(core);
10503bca4358SStanimir Varbanov 		if (ret) {
10513bca4358SStanimir Varbanov 			if (pmctrl)
10523bca4358SStanimir Varbanov 				pm_runtime_put_sync(pmctrl);
10533bca4358SStanimir Varbanov 			return ret;
10543bca4358SStanimir Varbanov 		}
10553bca4358SStanimir Varbanov 
10567482a983SStanimir Varbanov 		ret = core_clks_enable(core);
1057a76f43a4SStanimir Varbanov 		if (ret < 0 && pmctrl)
1058a76f43a4SStanimir Varbanov 			pm_runtime_put_sync(pmctrl);
10599a538b83SRajendra Nayak 	} else {
10609a538b83SRajendra Nayak 		/* Drop the performance state vote */
10619a538b83SRajendra Nayak 		if (core->opp_pmdomain)
10629a538b83SRajendra Nayak 			dev_pm_opp_set_rate(dev, 0);
10639a538b83SRajendra Nayak 
10647482a983SStanimir Varbanov 		core_clks_disable(core);
1065a76f43a4SStanimir Varbanov 
10663bca4358SStanimir Varbanov 		ret = core_resets_reset(core);
10673bca4358SStanimir Varbanov 
1068a76f43a4SStanimir Varbanov 		if (pmctrl)
1069a76f43a4SStanimir Varbanov 			pm_runtime_put_sync(pmctrl);
10709a538b83SRajendra Nayak 	}
10717482a983SStanimir Varbanov 
10727482a983SStanimir Varbanov 	return ret;
10737482a983SStanimir Varbanov }
10747482a983SStanimir Varbanov 
calculate_inst_freq(struct venus_inst * inst,unsigned long filled_len)10757482a983SStanimir Varbanov static unsigned long calculate_inst_freq(struct venus_inst *inst,
10767482a983SStanimir Varbanov 					 unsigned long filled_len)
10777482a983SStanimir Varbanov {
10783cfe5815SDikshita Agarwal 	unsigned long vpp_freq_per_mb = 0, vpp_freq = 0, vsp_freq = 0;
10797482a983SStanimir Varbanov 	u32 fps = (u32)inst->fps;
10807482a983SStanimir Varbanov 	u32 mbs_per_sec;
10817482a983SStanimir Varbanov 
1082b57cf6a0SMansur Alisha Shaik 	mbs_per_sec = load_per_instance(inst);
10837482a983SStanimir Varbanov 
1084d33a9441SStanimir Varbanov 	if (inst->state != INST_START)
1085d33a9441SStanimir Varbanov 		return 0;
1086d33a9441SStanimir Varbanov 
108714442321SMansur Alisha Shaik 	if (inst->session_type == VIDC_SESSION_TYPE_ENC) {
10883cfe5815SDikshita Agarwal 		vpp_freq_per_mb = inst->flags & VENUS_LOW_POWER ?
10893cfe5815SDikshita Agarwal 			inst->clk_data.low_power_freq :
10903cfe5815SDikshita Agarwal 			inst->clk_data.vpp_freq;
10913cfe5815SDikshita Agarwal 
10923cfe5815SDikshita Agarwal 		vpp_freq = mbs_per_sec * vpp_freq_per_mb;
109314442321SMansur Alisha Shaik 	} else {
109414442321SMansur Alisha Shaik 		vpp_freq = mbs_per_sec * inst->clk_data.vpp_freq;
109514442321SMansur Alisha Shaik 	}
109614442321SMansur Alisha Shaik 
10977482a983SStanimir Varbanov 	/* 21 / 20 is overhead factor */
10987482a983SStanimir Varbanov 	vpp_freq += vpp_freq / 20;
1099aa603389SStanimir Varbanov 	vsp_freq = mbs_per_sec * inst->clk_data.vsp_freq;
11007482a983SStanimir Varbanov 
11017482a983SStanimir Varbanov 	/* 10 / 7 is overhead factor */
11027482a983SStanimir Varbanov 	if (inst->session_type == VIDC_SESSION_TYPE_ENC)
11037482a983SStanimir Varbanov 		vsp_freq += (inst->controls.enc.bitrate * 10) / 7;
11047482a983SStanimir Varbanov 	else
11057482a983SStanimir Varbanov 		vsp_freq += ((fps * filled_len * 8) * 10) / 7;
11067482a983SStanimir Varbanov 
11077482a983SStanimir Varbanov 	return max(vpp_freq, vsp_freq);
11087482a983SStanimir Varbanov }
11097482a983SStanimir Varbanov 
load_scale_v4(struct venus_inst * inst)11107482a983SStanimir Varbanov static int load_scale_v4(struct venus_inst *inst)
11117482a983SStanimir Varbanov {
11127482a983SStanimir Varbanov 	struct venus_core *core = inst->core;
11137482a983SStanimir Varbanov 	const struct freq_tbl *table = core->res->freq_tbl;
11147482a983SStanimir Varbanov 	unsigned int num_rows = core->res->freq_tbl_size;
11157482a983SStanimir Varbanov 	struct device *dev = core->dev;
11167482a983SStanimir Varbanov 	unsigned long freq = 0, freq_core1 = 0, freq_core2 = 0;
11177482a983SStanimir Varbanov 	unsigned long filled_len = 0;
111891f2b7d2SMansur Alisha Shaik 	int i, ret = 0;
11197482a983SStanimir Varbanov 
11207482a983SStanimir Varbanov 	for (i = 0; i < inst->num_input_bufs; i++)
11217482a983SStanimir Varbanov 		filled_len = max(filled_len, inst->payloads[i]);
11227482a983SStanimir Varbanov 
11237482a983SStanimir Varbanov 	if (inst->session_type == VIDC_SESSION_TYPE_DEC && !filled_len)
112491f2b7d2SMansur Alisha Shaik 		return ret;
11257482a983SStanimir Varbanov 
11267482a983SStanimir Varbanov 	freq = calculate_inst_freq(inst, filled_len);
11277482a983SStanimir Varbanov 	inst->clk_data.freq = freq;
11287482a983SStanimir Varbanov 
11297482a983SStanimir Varbanov 	mutex_lock(&core->lock);
11307482a983SStanimir Varbanov 	list_for_each_entry(inst, &core->instances, list) {
11317482a983SStanimir Varbanov 		if (inst->clk_data.core_id == VIDC_CORE_ID_1) {
11327482a983SStanimir Varbanov 			freq_core1 += inst->clk_data.freq;
11337482a983SStanimir Varbanov 		} else if (inst->clk_data.core_id == VIDC_CORE_ID_2) {
11347482a983SStanimir Varbanov 			freq_core2 += inst->clk_data.freq;
11357482a983SStanimir Varbanov 		} else if (inst->clk_data.core_id == VIDC_CORE_ID_3) {
11367482a983SStanimir Varbanov 			freq_core1 += inst->clk_data.freq;
11377482a983SStanimir Varbanov 			freq_core2 += inst->clk_data.freq;
11387482a983SStanimir Varbanov 		}
11397482a983SStanimir Varbanov 	}
11407482a983SStanimir Varbanov 
11417482a983SStanimir Varbanov 	freq = max(freq_core1, freq_core2);
11427482a983SStanimir Varbanov 
1143bcf6b264SMansur Alisha Shaik 	if (freq > table[0].freq) {
1144799926a1SMansur Alisha Shaik 		dev_dbg(dev, VDBGL "requested clock rate: %lu scaling clock rate : %lu\n",
11457482a983SStanimir Varbanov 			freq, table[0].freq);
1146799926a1SMansur Alisha Shaik 
1147799926a1SMansur Alisha Shaik 		freq = table[0].freq;
11487482a983SStanimir Varbanov 		goto set_freq;
11497482a983SStanimir Varbanov 	}
11507482a983SStanimir Varbanov 
11517482a983SStanimir Varbanov 	for (i = num_rows - 1 ; i >= 0; i--) {
11527482a983SStanimir Varbanov 		if (freq <= table[i].freq) {
11537482a983SStanimir Varbanov 			freq = table[i].freq;
11547482a983SStanimir Varbanov 			break;
11557482a983SStanimir Varbanov 		}
11567482a983SStanimir Varbanov 	}
11577482a983SStanimir Varbanov 
11587482a983SStanimir Varbanov set_freq:
11597482a983SStanimir Varbanov 
11607482a983SStanimir Varbanov 	ret = core_clks_set_rate(core, freq);
11617482a983SStanimir Varbanov 	if (ret) {
11627482a983SStanimir Varbanov 		dev_err(dev, "failed to set clock rate %lu (%d)\n",
11637482a983SStanimir Varbanov 			freq, ret);
116491f2b7d2SMansur Alisha Shaik 		goto exit;
11657482a983SStanimir Varbanov 	}
11667482a983SStanimir Varbanov 
11677482a983SStanimir Varbanov 	ret = load_scale_bw(core);
11687482a983SStanimir Varbanov 	if (ret) {
11697482a983SStanimir Varbanov 		dev_err(dev, "failed to set bandwidth (%d)\n",
11707482a983SStanimir Varbanov 			ret);
117191f2b7d2SMansur Alisha Shaik 		goto exit;
11727482a983SStanimir Varbanov 	}
11737482a983SStanimir Varbanov 
117491f2b7d2SMansur Alisha Shaik exit:
117591f2b7d2SMansur Alisha Shaik 	mutex_unlock(&core->lock);
117691f2b7d2SMansur Alisha Shaik 	return ret;
11777482a983SStanimir Varbanov }
11787482a983SStanimir Varbanov 
11797482a983SStanimir Varbanov static const struct venus_pm_ops pm_ops_v4 = {
11807482a983SStanimir Varbanov 	.core_get = core_get_v4,
11817482a983SStanimir Varbanov 	.core_put = core_put_v4,
11827482a983SStanimir Varbanov 	.core_power = core_power_v4,
11837482a983SStanimir Varbanov 	.vdec_get = vdec_get_v4,
11847482a983SStanimir Varbanov 	.vdec_put = vdec_put_v4,
11857482a983SStanimir Varbanov 	.vdec_power = vdec_power_v4,
11867482a983SStanimir Varbanov 	.venc_get = venc_get_v4,
11877482a983SStanimir Varbanov 	.venc_put = venc_put_v4,
11887482a983SStanimir Varbanov 	.venc_power = venc_power_v4,
11894ebf9693SAniket Masule 	.coreid_power = coreid_power_v4,
11907482a983SStanimir Varbanov 	.load_scale = load_scale_v4,
11917482a983SStanimir Varbanov };
11927482a983SStanimir Varbanov 
venus_pm_get(enum hfi_version version)11937482a983SStanimir Varbanov const struct venus_pm_ops *venus_pm_get(enum hfi_version version)
11947482a983SStanimir Varbanov {
11957482a983SStanimir Varbanov 	switch (version) {
11967482a983SStanimir Varbanov 	case HFI_VERSION_1XX:
11977482a983SStanimir Varbanov 	default:
11987482a983SStanimir Varbanov 		return &pm_ops_v1;
11997482a983SStanimir Varbanov 	case HFI_VERSION_3XX:
12007482a983SStanimir Varbanov 		return &pm_ops_v3;
12017482a983SStanimir Varbanov 	case HFI_VERSION_4XX:
1202f24afa95SBryan O'Donoghue 	case HFI_VERSION_6XX:
12037482a983SStanimir Varbanov 		return &pm_ops_v4;
12047482a983SStanimir Varbanov 	}
12057482a983SStanimir Varbanov 
12067482a983SStanimir Varbanov 	return NULL;
12077482a983SStanimir Varbanov }
1208