brintos

brintos / linux-shallow public Read only

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