cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

pm_helpers.c (26004B)


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