File Index
Files and directories
Sign in
FILE

pm_helpers.c

File preview with syntax highlighting.

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