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