17482a983SStanimir Varbanov // SPDX-License-Identifier: GPL-2.0
27482a983SStanimir Varbanov /*
37482a983SStanimir Varbanov * Copyright (C) 2019 Linaro Ltd.
47482a983SStanimir Varbanov *
57482a983SStanimir Varbanov * Author: Stanimir Varbanov <stanimir.varbanov@linaro.org>
67482a983SStanimir Varbanov */
77482a983SStanimir Varbanov #include <linux/clk.h>
87482a983SStanimir Varbanov #include <linux/interconnect.h>
97482a983SStanimir Varbanov #include <linux/iopoll.h>
107482a983SStanimir Varbanov #include <linux/kernel.h>
117482a983SStanimir Varbanov #include <linux/pm_domain.h>
129a538b83SRajendra Nayak #include <linux/pm_opp.h>
137482a983SStanimir Varbanov #include <linux/pm_runtime.h>
143bca4358SStanimir Varbanov #include <linux/reset.h>
157482a983SStanimir Varbanov #include <linux/types.h>
167482a983SStanimir Varbanov #include <media/v4l2-mem2mem.h>
177482a983SStanimir Varbanov
187482a983SStanimir Varbanov #include "core.h"
194ebf9693SAniket Masule #include "hfi_parser.h"
207482a983SStanimir Varbanov #include "hfi_venus_io.h"
217482a983SStanimir Varbanov #include "pm_helpers.h"
22aa603389SStanimir Varbanov #include "hfi_platform.h"
237482a983SStanimir Varbanov
247482a983SStanimir Varbanov static bool legacy_binding;
257482a983SStanimir Varbanov
core_clks_get(struct venus_core * core)267482a983SStanimir Varbanov static int core_clks_get(struct venus_core *core)
277482a983SStanimir Varbanov {
287482a983SStanimir Varbanov const struct venus_resources *res = core->res;
297482a983SStanimir Varbanov struct device *dev = core->dev;
307482a983SStanimir Varbanov unsigned int i;
317482a983SStanimir Varbanov
327482a983SStanimir Varbanov for (i = 0; i < res->clks_num; i++) {
337482a983SStanimir Varbanov core->clks[i] = devm_clk_get(dev, res->clks[i]);
347482a983SStanimir Varbanov if (IS_ERR(core->clks[i]))
357482a983SStanimir Varbanov return PTR_ERR(core->clks[i]);
367482a983SStanimir Varbanov }
377482a983SStanimir Varbanov
387482a983SStanimir Varbanov return 0;
397482a983SStanimir Varbanov }
407482a983SStanimir Varbanov
core_clks_enable(struct venus_core * core)417482a983SStanimir Varbanov static int core_clks_enable(struct venus_core *core)
427482a983SStanimir Varbanov {
437482a983SStanimir Varbanov const struct venus_resources *res = core->res;
44c22b1a29SDikshita Agarwal const struct freq_tbl *freq_tbl = core->res->freq_tbl;
45c22b1a29SDikshita Agarwal unsigned int freq_tbl_size = core->res->freq_tbl_size;
46c22b1a29SDikshita Agarwal unsigned long freq;
477482a983SStanimir Varbanov unsigned int i;
487482a983SStanimir Varbanov int ret;
497482a983SStanimir Varbanov
50c22b1a29SDikshita Agarwal if (!freq_tbl)
51c22b1a29SDikshita Agarwal return -EINVAL;
52c22b1a29SDikshita Agarwal
53c22b1a29SDikshita Agarwal freq = freq_tbl[freq_tbl_size - 1].freq;
54c22b1a29SDikshita Agarwal
557482a983SStanimir Varbanov for (i = 0; i < res->clks_num; i++) {
56c22b1a29SDikshita Agarwal if (IS_V6(core)) {
57c22b1a29SDikshita Agarwal ret = clk_set_rate(core->clks[i], freq);
58c22b1a29SDikshita Agarwal if (ret)
59c22b1a29SDikshita Agarwal goto err;
60c22b1a29SDikshita Agarwal }
61c22b1a29SDikshita Agarwal
627482a983SStanimir Varbanov ret = clk_prepare_enable(core->clks[i]);
637482a983SStanimir Varbanov if (ret)
647482a983SStanimir Varbanov goto err;
657482a983SStanimir Varbanov }
667482a983SStanimir Varbanov
677482a983SStanimir Varbanov return 0;
687482a983SStanimir Varbanov err:
697482a983SStanimir Varbanov while (i--)
707482a983SStanimir Varbanov clk_disable_unprepare(core->clks[i]);
717482a983SStanimir Varbanov
727482a983SStanimir Varbanov return ret;
737482a983SStanimir Varbanov }
747482a983SStanimir Varbanov
core_clks_disable(struct venus_core * core)757482a983SStanimir Varbanov static void core_clks_disable(struct venus_core *core)
767482a983SStanimir Varbanov {
777482a983SStanimir Varbanov const struct venus_resources *res = core->res;
787482a983SStanimir Varbanov unsigned int i = res->clks_num;
797482a983SStanimir Varbanov
807482a983SStanimir Varbanov while (i--)
817482a983SStanimir Varbanov clk_disable_unprepare(core->clks[i]);
827482a983SStanimir Varbanov }
837482a983SStanimir Varbanov
core_clks_set_rate(struct venus_core * core,unsigned long freq)847482a983SStanimir Varbanov static int core_clks_set_rate(struct venus_core *core, unsigned long freq)
857482a983SStanimir Varbanov {
867482a983SStanimir Varbanov int ret;
877482a983SStanimir Varbanov
889a538b83SRajendra Nayak ret = dev_pm_opp_set_rate(core->dev, freq);
897482a983SStanimir Varbanov if (ret)
907482a983SStanimir Varbanov return ret;
917482a983SStanimir Varbanov
927482a983SStanimir Varbanov ret = clk_set_rate(core->vcodec0_clks[0], freq);
937482a983SStanimir Varbanov if (ret)
947482a983SStanimir Varbanov return ret;
957482a983SStanimir Varbanov
967482a983SStanimir Varbanov ret = clk_set_rate(core->vcodec1_clks[0], freq);
977482a983SStanimir Varbanov if (ret)
987482a983SStanimir Varbanov return ret;
997482a983SStanimir Varbanov
1007482a983SStanimir Varbanov return 0;
1017482a983SStanimir Varbanov }
1027482a983SStanimir Varbanov
vcodec_clks_get(struct venus_core * core,struct device * dev,struct clk ** clks,const char * const * id)1037482a983SStanimir Varbanov static int vcodec_clks_get(struct venus_core *core, struct device *dev,
1047482a983SStanimir Varbanov struct clk **clks, const char * const *id)
1057482a983SStanimir Varbanov {
1067482a983SStanimir Varbanov const struct venus_resources *res = core->res;
1077482a983SStanimir Varbanov unsigned int i;
1087482a983SStanimir Varbanov
1097482a983SStanimir Varbanov for (i = 0; i < res->vcodec_clks_num; i++) {
1107482a983SStanimir Varbanov if (!id[i])
1117482a983SStanimir Varbanov continue;
1127482a983SStanimir Varbanov clks[i] = devm_clk_get(dev, id[i]);
1137482a983SStanimir Varbanov if (IS_ERR(clks[i]))
1147482a983SStanimir Varbanov return PTR_ERR(clks[i]);
1157482a983SStanimir Varbanov }
1167482a983SStanimir Varbanov
1177482a983SStanimir Varbanov return 0;
1187482a983SStanimir Varbanov }
1197482a983SStanimir Varbanov
vcodec_clks_enable(struct venus_core * core,struct clk ** clks)1207482a983SStanimir Varbanov static int vcodec_clks_enable(struct venus_core *core, struct clk **clks)
1217482a983SStanimir Varbanov {
1227482a983SStanimir Varbanov const struct venus_resources *res = core->res;
1237482a983SStanimir Varbanov unsigned int i;
1247482a983SStanimir Varbanov int ret;
1257482a983SStanimir Varbanov
1267482a983SStanimir Varbanov for (i = 0; i < res->vcodec_clks_num; i++) {
1277482a983SStanimir Varbanov ret = clk_prepare_enable(clks[i]);
1287482a983SStanimir Varbanov if (ret)
1297482a983SStanimir Varbanov goto err;
1307482a983SStanimir Varbanov }
1317482a983SStanimir Varbanov
1327482a983SStanimir Varbanov return 0;
1337482a983SStanimir Varbanov err:
1347482a983SStanimir Varbanov while (i--)
1357482a983SStanimir Varbanov clk_disable_unprepare(clks[i]);
1367482a983SStanimir Varbanov
1377482a983SStanimir Varbanov return ret;
1387482a983SStanimir Varbanov }
1397482a983SStanimir Varbanov
vcodec_clks_disable(struct venus_core * core,struct clk ** clks)1407482a983SStanimir Varbanov static void vcodec_clks_disable(struct venus_core *core, struct clk **clks)
1417482a983SStanimir Varbanov {
1427482a983SStanimir Varbanov const struct venus_resources *res = core->res;
1437482a983SStanimir Varbanov unsigned int i = res->vcodec_clks_num;
1447482a983SStanimir Varbanov
1457482a983SStanimir Varbanov while (i--)
1467482a983SStanimir Varbanov clk_disable_unprepare(clks[i]);
1477482a983SStanimir Varbanov }
1487482a983SStanimir Varbanov
load_per_instance(struct venus_inst * inst)1497482a983SStanimir Varbanov static u32 load_per_instance(struct venus_inst *inst)
1507482a983SStanimir Varbanov {
1517482a983SStanimir Varbanov u32 mbs;
1527482a983SStanimir Varbanov
1537482a983SStanimir Varbanov if (!inst || !(inst->state >= INST_INIT && inst->state < INST_STOP))
1547482a983SStanimir Varbanov return 0;
1557482a983SStanimir Varbanov
1567482a983SStanimir Varbanov mbs = (ALIGN(inst->width, 16) / 16) * (ALIGN(inst->height, 16) / 16);
1577482a983SStanimir Varbanov
1587482a983SStanimir Varbanov return mbs * inst->fps;
1597482a983SStanimir Varbanov }
1607482a983SStanimir Varbanov
load_per_type(struct venus_core * core,u32 session_type)1617482a983SStanimir Varbanov static u32 load_per_type(struct venus_core *core, u32 session_type)
1627482a983SStanimir Varbanov {
1637482a983SStanimir Varbanov struct venus_inst *inst = NULL;
1647482a983SStanimir Varbanov u32 mbs_per_sec = 0;
1657482a983SStanimir Varbanov
1667482a983SStanimir Varbanov list_for_each_entry(inst, &core->instances, list) {
1677482a983SStanimir Varbanov if (inst->session_type != session_type)
1687482a983SStanimir Varbanov continue;
1697482a983SStanimir Varbanov
1707482a983SStanimir Varbanov mbs_per_sec += load_per_instance(inst);
1717482a983SStanimir Varbanov }
1727482a983SStanimir Varbanov
1737482a983SStanimir Varbanov return mbs_per_sec;
1747482a983SStanimir Varbanov }
1757482a983SStanimir Varbanov
mbs_to_bw(struct venus_inst * inst,u32 mbs,u32 * avg,u32 * peak)1767482a983SStanimir Varbanov static void mbs_to_bw(struct venus_inst *inst, u32 mbs, u32 *avg, u32 *peak)
1777482a983SStanimir Varbanov {
1787482a983SStanimir Varbanov const struct venus_resources *res = inst->core->res;
1797482a983SStanimir Varbanov const struct bw_tbl *bw_tbl;
1807482a983SStanimir Varbanov unsigned int num_rows, i;
1817482a983SStanimir Varbanov
1827482a983SStanimir Varbanov *avg = 0;
1837482a983SStanimir Varbanov *peak = 0;
1847482a983SStanimir Varbanov
1857482a983SStanimir Varbanov if (mbs == 0)
1867482a983SStanimir Varbanov return;
1877482a983SStanimir Varbanov
1887482a983SStanimir Varbanov if (inst->session_type == VIDC_SESSION_TYPE_ENC) {
1897482a983SStanimir Varbanov num_rows = res->bw_tbl_enc_size;
1907482a983SStanimir Varbanov bw_tbl = res->bw_tbl_enc;
1917482a983SStanimir Varbanov } else if (inst->session_type == VIDC_SESSION_TYPE_DEC) {
1927482a983SStanimir Varbanov num_rows = res->bw_tbl_dec_size;
1937482a983SStanimir Varbanov bw_tbl = res->bw_tbl_dec;
1947482a983SStanimir Varbanov } else {
1957482a983SStanimir Varbanov return;
1967482a983SStanimir Varbanov }
1977482a983SStanimir Varbanov
1987482a983SStanimir Varbanov if (!bw_tbl || num_rows == 0)
1997482a983SStanimir Varbanov return;
2007482a983SStanimir Varbanov
2017482a983SStanimir Varbanov for (i = 0; i < num_rows; i++) {
2027bf28a21SVikash Garodia if (i != 0 && mbs > bw_tbl[i].mbs_per_sec)
2037482a983SStanimir Varbanov break;
2047482a983SStanimir Varbanov
2057482a983SStanimir Varbanov if (inst->dpb_fmt & HFI_COLOR_FORMAT_10_BIT_BASE) {
2067482a983SStanimir Varbanov *avg = bw_tbl[i].avg_10bit;
2077482a983SStanimir Varbanov *peak = bw_tbl[i].peak_10bit;
2087482a983SStanimir Varbanov } else {
2097482a983SStanimir Varbanov *avg = bw_tbl[i].avg;
2107482a983SStanimir Varbanov *peak = bw_tbl[i].peak;
2117482a983SStanimir Varbanov }
2127482a983SStanimir Varbanov }
2137482a983SStanimir Varbanov }
2147482a983SStanimir Varbanov
load_scale_bw(struct venus_core * core)2157482a983SStanimir Varbanov static int load_scale_bw(struct venus_core *core)
2167482a983SStanimir Varbanov {
2177482a983SStanimir Varbanov struct venus_inst *inst = NULL;
2187482a983SStanimir Varbanov u32 mbs_per_sec, avg, peak, total_avg = 0, total_peak = 0;
2197482a983SStanimir Varbanov
2207482a983SStanimir Varbanov list_for_each_entry(inst, &core->instances, list) {
2217482a983SStanimir Varbanov mbs_per_sec = load_per_instance(inst);
2227482a983SStanimir Varbanov mbs_to_bw(inst, mbs_per_sec, &avg, &peak);
2237482a983SStanimir Varbanov total_avg += avg;
2247482a983SStanimir Varbanov total_peak += peak;
2257482a983SStanimir Varbanov }
2267482a983SStanimir Varbanov
227eff5ce02SMansur Alisha Shaik /*
228eff5ce02SMansur Alisha Shaik * keep minimum bandwidth vote for "video-mem" path,
229eff5ce02SMansur Alisha Shaik * so that clks can be disabled during vdec_session_release().
230eff5ce02SMansur Alisha Shaik * Actual bandwidth drop will be done during device supend
231eff5ce02SMansur Alisha Shaik * so that device can power down without any warnings.
232eff5ce02SMansur Alisha Shaik */
233eff5ce02SMansur Alisha Shaik
234eff5ce02SMansur Alisha Shaik if (!total_avg && !total_peak)
235eff5ce02SMansur Alisha Shaik total_avg = kbps_to_icc(1000);
236eff5ce02SMansur Alisha Shaik
2378c91dc08SStanimir Varbanov dev_dbg(core->dev, VDBGL "total: avg_bw: %u, peak_bw: %u\n",
2387482a983SStanimir Varbanov total_avg, total_peak);
2397482a983SStanimir Varbanov
2407482a983SStanimir Varbanov return icc_set_bw(core->video_path, total_avg, total_peak);
2417482a983SStanimir Varbanov }
2427482a983SStanimir Varbanov
load_scale_v1(struct venus_inst * inst)2437482a983SStanimir Varbanov static int load_scale_v1(struct venus_inst *inst)
2447482a983SStanimir Varbanov {
2457482a983SStanimir Varbanov struct venus_core *core = inst->core;
2467482a983SStanimir Varbanov const struct freq_tbl *table = core->res->freq_tbl;
2477482a983SStanimir Varbanov unsigned int num_rows = core->res->freq_tbl_size;
2487482a983SStanimir Varbanov unsigned long freq = table[0].freq;
2497482a983SStanimir Varbanov struct device *dev = core->dev;
2507482a983SStanimir Varbanov u32 mbs_per_sec;
2517482a983SStanimir Varbanov unsigned int i;
25291f2b7d2SMansur Alisha Shaik int ret = 0;
2537482a983SStanimir Varbanov
25491f2b7d2SMansur Alisha Shaik mutex_lock(&core->lock);
2557482a983SStanimir Varbanov mbs_per_sec = load_per_type(core, VIDC_SESSION_TYPE_ENC) +
2567482a983SStanimir Varbanov load_per_type(core, VIDC_SESSION_TYPE_DEC);
2577482a983SStanimir Varbanov
2587482a983SStanimir Varbanov if (mbs_per_sec > core->res->max_load)
2597482a983SStanimir Varbanov dev_warn(dev, "HW is overloaded, needed: %d max: %d\n",
2607482a983SStanimir Varbanov mbs_per_sec, core->res->max_load);
2617482a983SStanimir Varbanov
2627482a983SStanimir Varbanov if (!mbs_per_sec && num_rows > 1) {
2637482a983SStanimir Varbanov freq = table[num_rows - 1].freq;
2647482a983SStanimir Varbanov goto set_freq;
2657482a983SStanimir Varbanov }
2667482a983SStanimir Varbanov
2677482a983SStanimir Varbanov for (i = 0; i < num_rows; i++) {
2687482a983SStanimir Varbanov if (mbs_per_sec > table[i].load)
2697482a983SStanimir Varbanov break;
2707482a983SStanimir Varbanov freq = table[i].freq;
2717482a983SStanimir Varbanov }
2727482a983SStanimir Varbanov
2737482a983SStanimir Varbanov set_freq:
2747482a983SStanimir Varbanov
2757482a983SStanimir Varbanov ret = core_clks_set_rate(core, freq);
2767482a983SStanimir Varbanov if (ret) {
2777482a983SStanimir Varbanov dev_err(dev, "failed to set clock rate %lu (%d)\n",
2787482a983SStanimir Varbanov freq, ret);
27991f2b7d2SMansur Alisha Shaik goto exit;
2807482a983SStanimir Varbanov }
2817482a983SStanimir Varbanov
2827482a983SStanimir Varbanov ret = load_scale_bw(core);
2837482a983SStanimir Varbanov if (ret) {
2847482a983SStanimir Varbanov dev_err(dev, "failed to set bandwidth (%d)\n",
2857482a983SStanimir Varbanov ret);
28691f2b7d2SMansur Alisha Shaik goto exit;
2877482a983SStanimir Varbanov }
2887482a983SStanimir Varbanov
28991f2b7d2SMansur Alisha Shaik exit:
29091f2b7d2SMansur Alisha Shaik mutex_unlock(&core->lock);
29191f2b7d2SMansur Alisha Shaik return ret;
2927482a983SStanimir Varbanov }
2937482a983SStanimir Varbanov
core_get_v1(struct venus_core * core)29408b1cf47SBryan O'Donoghue static int core_get_v1(struct venus_core *core)
2957482a983SStanimir Varbanov {
29632158871SStanimir Varbanov int ret;
29732158871SStanimir Varbanov
29832158871SStanimir Varbanov ret = core_clks_get(core);
29932158871SStanimir Varbanov if (ret)
30032158871SStanimir Varbanov return ret;
30132158871SStanimir Varbanov
3020394360eSYangtao Li ret = devm_pm_opp_set_clkname(core->dev, "core");
3030394360eSYangtao Li if (ret)
3040394360eSYangtao Li return ret;
30532158871SStanimir Varbanov
30632158871SStanimir Varbanov return 0;
30732158871SStanimir Varbanov }
30832158871SStanimir Varbanov
core_put_v1(struct venus_core * core)30932158871SStanimir Varbanov static void core_put_v1(struct venus_core *core)
31032158871SStanimir Varbanov {
3117482a983SStanimir Varbanov }
3127482a983SStanimir Varbanov
core_power_v1(struct venus_core * core,int on)31308b1cf47SBryan O'Donoghue static int core_power_v1(struct venus_core *core, int on)
3147482a983SStanimir Varbanov {
3157482a983SStanimir Varbanov int ret = 0;
3167482a983SStanimir Varbanov
3177482a983SStanimir Varbanov if (on == POWER_ON)
3187482a983SStanimir Varbanov ret = core_clks_enable(core);
3197482a983SStanimir Varbanov else
3207482a983SStanimir Varbanov core_clks_disable(core);
3217482a983SStanimir Varbanov
3227482a983SStanimir Varbanov return ret;
3237482a983SStanimir Varbanov }
3247482a983SStanimir Varbanov
3257482a983SStanimir Varbanov static const struct venus_pm_ops pm_ops_v1 = {
3267482a983SStanimir Varbanov .core_get = core_get_v1,
32732158871SStanimir Varbanov .core_put = core_put_v1,
3287482a983SStanimir Varbanov .core_power = core_power_v1,
3297482a983SStanimir Varbanov .load_scale = load_scale_v1,
3307482a983SStanimir Varbanov };
3317482a983SStanimir Varbanov
3327482a983SStanimir Varbanov static void
vcodec_control_v3(struct venus_core * core,u32 session_type,bool enable)3337482a983SStanimir Varbanov vcodec_control_v3(struct venus_core *core, u32 session_type, bool enable)
3347482a983SStanimir Varbanov {
3357482a983SStanimir Varbanov void __iomem *ctrl;
3367482a983SStanimir Varbanov
3377482a983SStanimir Varbanov if (session_type == VIDC_SESSION_TYPE_DEC)
338ff2a7013SBryan O'Donoghue ctrl = core->wrapper_base + WRAPPER_VDEC_VCODEC_POWER_CONTROL;
3397482a983SStanimir Varbanov else
340ff2a7013SBryan O'Donoghue ctrl = core->wrapper_base + WRAPPER_VENC_VCODEC_POWER_CONTROL;
3417482a983SStanimir Varbanov
3427482a983SStanimir Varbanov if (enable)
3437482a983SStanimir Varbanov writel(0, ctrl);
3447482a983SStanimir Varbanov else
3457482a983SStanimir Varbanov writel(1, ctrl);
3467482a983SStanimir Varbanov }
3477482a983SStanimir Varbanov
vdec_get_v3(struct device * dev)3487482a983SStanimir Varbanov static int vdec_get_v3(struct device *dev)
3497482a983SStanimir Varbanov {
3507482a983SStanimir Varbanov struct venus_core *core = dev_get_drvdata(dev);
3517482a983SStanimir Varbanov
3527482a983SStanimir Varbanov return vcodec_clks_get(core, dev, core->vcodec0_clks,
3537482a983SStanimir Varbanov core->res->vcodec0_clks);
3547482a983SStanimir Varbanov }
3557482a983SStanimir Varbanov
vdec_power_v3(struct device * dev,int on)3567482a983SStanimir Varbanov static int vdec_power_v3(struct device *dev, int on)
3577482a983SStanimir Varbanov {
3587482a983SStanimir Varbanov struct venus_core *core = dev_get_drvdata(dev);
3597482a983SStanimir Varbanov int ret = 0;
3607482a983SStanimir Varbanov
3617482a983SStanimir Varbanov vcodec_control_v3(core, VIDC_SESSION_TYPE_DEC, true);
3627482a983SStanimir Varbanov
3637482a983SStanimir Varbanov if (on == POWER_ON)
3647482a983SStanimir Varbanov ret = vcodec_clks_enable(core, core->vcodec0_clks);
3657482a983SStanimir Varbanov else
3667482a983SStanimir Varbanov vcodec_clks_disable(core, core->vcodec0_clks);
3677482a983SStanimir Varbanov
3687482a983SStanimir Varbanov vcodec_control_v3(core, VIDC_SESSION_TYPE_DEC, false);
3697482a983SStanimir Varbanov
3707482a983SStanimir Varbanov return ret;
3717482a983SStanimir Varbanov }
3727482a983SStanimir Varbanov
venc_get_v3(struct device * dev)3737482a983SStanimir Varbanov static int venc_get_v3(struct device *dev)
3747482a983SStanimir Varbanov {
3757482a983SStanimir Varbanov struct venus_core *core = dev_get_drvdata(dev);
3767482a983SStanimir Varbanov
3777482a983SStanimir Varbanov return vcodec_clks_get(core, dev, core->vcodec1_clks,
3787482a983SStanimir Varbanov core->res->vcodec1_clks);
3797482a983SStanimir Varbanov }
3807482a983SStanimir Varbanov
venc_power_v3(struct device * dev,int on)3817482a983SStanimir Varbanov static int venc_power_v3(struct device *dev, int on)
3827482a983SStanimir Varbanov {
3837482a983SStanimir Varbanov struct venus_core *core = dev_get_drvdata(dev);
3847482a983SStanimir Varbanov int ret = 0;
3857482a983SStanimir Varbanov
3867482a983SStanimir Varbanov vcodec_control_v3(core, VIDC_SESSION_TYPE_ENC, true);
3877482a983SStanimir Varbanov
3887482a983SStanimir Varbanov if (on == POWER_ON)
3897482a983SStanimir Varbanov ret = vcodec_clks_enable(core, core->vcodec1_clks);
3907482a983SStanimir Varbanov else
3917482a983SStanimir Varbanov vcodec_clks_disable(core, core->vcodec1_clks);
3927482a983SStanimir Varbanov
3937482a983SStanimir Varbanov vcodec_control_v3(core, VIDC_SESSION_TYPE_ENC, false);
3947482a983SStanimir Varbanov
3957482a983SStanimir Varbanov return ret;
3967482a983SStanimir Varbanov }
3977482a983SStanimir Varbanov
3987482a983SStanimir Varbanov static const struct venus_pm_ops pm_ops_v3 = {
3997482a983SStanimir Varbanov .core_get = core_get_v1,
40032158871SStanimir Varbanov .core_put = core_put_v1,
4017482a983SStanimir Varbanov .core_power = core_power_v1,
4027482a983SStanimir Varbanov .vdec_get = vdec_get_v3,
4037482a983SStanimir Varbanov .vdec_power = vdec_power_v3,
4047482a983SStanimir Varbanov .venc_get = venc_get_v3,
4057482a983SStanimir Varbanov .venc_power = venc_power_v3,
4067482a983SStanimir Varbanov .load_scale = load_scale_v1,
4077482a983SStanimir Varbanov };
4087482a983SStanimir Varbanov
vcodec_control_v4(struct venus_core * core,u32 coreid,bool enable)4097482a983SStanimir Varbanov static int vcodec_control_v4(struct venus_core *core, u32 coreid, bool enable)
4107482a983SStanimir Varbanov {
4117482a983SStanimir Varbanov void __iomem *ctrl, *stat;
4127482a983SStanimir Varbanov u32 val;
4137482a983SStanimir Varbanov int ret;
4147482a983SStanimir Varbanov
415ec9a652eSJagadeesh Kona if (IS_V6(core))
416ec9a652eSJagadeesh Kona return dev_pm_genpd_set_hwmode(core->pmdomains->pd_devs[coreid], !enable);
417ec9a652eSJagadeesh Kona else if (coreid == VIDC_CORE_ID_1) {
418ff2a7013SBryan O'Donoghue ctrl = core->wrapper_base + WRAPPER_VCODEC0_MMCC_POWER_CONTROL;
419ff2a7013SBryan O'Donoghue stat = core->wrapper_base + WRAPPER_VCODEC0_MMCC_POWER_STATUS;
4207482a983SStanimir Varbanov } else {
421ff2a7013SBryan O'Donoghue ctrl = core->wrapper_base + WRAPPER_VCODEC1_MMCC_POWER_CONTROL;
422ff2a7013SBryan O'Donoghue stat = core->wrapper_base + WRAPPER_VCODEC1_MMCC_POWER_STATUS;
4237482a983SStanimir Varbanov }
4247482a983SStanimir Varbanov
4257482a983SStanimir Varbanov if (enable) {
4267482a983SStanimir Varbanov writel(0, ctrl);
4277482a983SStanimir Varbanov
4287482a983SStanimir Varbanov ret = readl_poll_timeout(stat, val, val & BIT(1), 1, 100);
4297482a983SStanimir Varbanov if (ret)
4307482a983SStanimir Varbanov return ret;
4317482a983SStanimir Varbanov } else {
4327482a983SStanimir Varbanov writel(1, ctrl);
4337482a983SStanimir Varbanov
4347482a983SStanimir Varbanov ret = readl_poll_timeout(stat, val, !(val & BIT(1)), 1, 100);
4357482a983SStanimir Varbanov if (ret)
4367482a983SStanimir Varbanov return ret;
4377482a983SStanimir Varbanov }
4387482a983SStanimir Varbanov
4397482a983SStanimir Varbanov return 0;
4407482a983SStanimir Varbanov }
4417482a983SStanimir Varbanov
poweroff_coreid(struct venus_core * core,unsigned int coreid_mask)4427482a983SStanimir Varbanov static int poweroff_coreid(struct venus_core *core, unsigned int coreid_mask)
4437482a983SStanimir Varbanov {
4447482a983SStanimir Varbanov int ret;
4457482a983SStanimir Varbanov
4467482a983SStanimir Varbanov if (coreid_mask & VIDC_CORE_ID_1) {
4477482a983SStanimir Varbanov ret = vcodec_control_v4(core, VIDC_CORE_ID_1, true);
4487482a983SStanimir Varbanov if (ret)
4497482a983SStanimir Varbanov return ret;
4507482a983SStanimir Varbanov
4517482a983SStanimir Varbanov vcodec_clks_disable(core, core->vcodec0_clks);
4527482a983SStanimir Varbanov
453ec9a652eSJagadeesh Kona if (!IS_V6(core)) {
4547482a983SStanimir Varbanov ret = vcodec_control_v4(core, VIDC_CORE_ID_1, false);
4557482a983SStanimir Varbanov if (ret)
4567482a983SStanimir Varbanov return ret;
457ec9a652eSJagadeesh Kona }
4587482a983SStanimir Varbanov
459693c301aSUlf Hansson ret = pm_runtime_put_sync(core->pmdomains->pd_devs[1]);
4607482a983SStanimir Varbanov if (ret < 0)
4617482a983SStanimir Varbanov return ret;
4627482a983SStanimir Varbanov }
4637482a983SStanimir Varbanov
4647482a983SStanimir Varbanov if (coreid_mask & VIDC_CORE_ID_2) {
4657482a983SStanimir Varbanov ret = vcodec_control_v4(core, VIDC_CORE_ID_2, true);
4667482a983SStanimir Varbanov if (ret)
4677482a983SStanimir Varbanov return ret;
4687482a983SStanimir Varbanov
4697482a983SStanimir Varbanov vcodec_clks_disable(core, core->vcodec1_clks);
4707482a983SStanimir Varbanov
471ec9a652eSJagadeesh Kona if (!IS_V6(core)) {
4727482a983SStanimir Varbanov ret = vcodec_control_v4(core, VIDC_CORE_ID_2, false);
4737482a983SStanimir Varbanov if (ret)
4747482a983SStanimir Varbanov return ret;
475ec9a652eSJagadeesh Kona }
4767482a983SStanimir Varbanov
477693c301aSUlf Hansson ret = pm_runtime_put_sync(core->pmdomains->pd_devs[2]);
4787482a983SStanimir Varbanov if (ret < 0)
4797482a983SStanimir Varbanov return ret;
4807482a983SStanimir Varbanov }
4817482a983SStanimir Varbanov
4827482a983SStanimir Varbanov return 0;
4837482a983SStanimir Varbanov }
4847482a983SStanimir Varbanov
poweron_coreid(struct venus_core * core,unsigned int coreid_mask)4857482a983SStanimir Varbanov static int poweron_coreid(struct venus_core *core, unsigned int coreid_mask)
4867482a983SStanimir Varbanov {
4877482a983SStanimir Varbanov int ret;
4887482a983SStanimir Varbanov
4897482a983SStanimir Varbanov if (coreid_mask & VIDC_CORE_ID_1) {
490693c301aSUlf Hansson ret = pm_runtime_get_sync(core->pmdomains->pd_devs[1]);
4917482a983SStanimir Varbanov if (ret < 0)
4927482a983SStanimir Varbanov return ret;
4937482a983SStanimir Varbanov
494ec9a652eSJagadeesh Kona if (!IS_V6(core)) {
4957482a983SStanimir Varbanov ret = vcodec_control_v4(core, VIDC_CORE_ID_1, true);
4967482a983SStanimir Varbanov if (ret)
4977482a983SStanimir Varbanov return ret;
498ec9a652eSJagadeesh Kona }
4997482a983SStanimir Varbanov
5007482a983SStanimir Varbanov ret = vcodec_clks_enable(core, core->vcodec0_clks);
5017482a983SStanimir Varbanov if (ret)
5027482a983SStanimir Varbanov return ret;
5037482a983SStanimir Varbanov
5047482a983SStanimir Varbanov ret = vcodec_control_v4(core, VIDC_CORE_ID_1, false);
5057482a983SStanimir Varbanov if (ret < 0)
5067482a983SStanimir Varbanov return ret;
5077482a983SStanimir Varbanov }
5087482a983SStanimir Varbanov
5097482a983SStanimir Varbanov if (coreid_mask & VIDC_CORE_ID_2) {
510693c301aSUlf Hansson ret = pm_runtime_get_sync(core->pmdomains->pd_devs[2]);
5117482a983SStanimir Varbanov if (ret < 0)
5127482a983SStanimir Varbanov return ret;
5137482a983SStanimir Varbanov
514ec9a652eSJagadeesh Kona if (!IS_V6(core)) {
5157482a983SStanimir Varbanov ret = vcodec_control_v4(core, VIDC_CORE_ID_2, true);
5167482a983SStanimir Varbanov if (ret)
5177482a983SStanimir Varbanov return ret;
518ec9a652eSJagadeesh Kona }
5197482a983SStanimir Varbanov
5207482a983SStanimir Varbanov ret = vcodec_clks_enable(core, core->vcodec1_clks);
5217482a983SStanimir Varbanov if (ret)
5227482a983SStanimir Varbanov return ret;
5237482a983SStanimir Varbanov
5247482a983SStanimir Varbanov ret = vcodec_control_v4(core, VIDC_CORE_ID_2, false);
5257482a983SStanimir Varbanov if (ret < 0)
5267482a983SStanimir Varbanov return ret;
5277482a983SStanimir Varbanov }
5287482a983SStanimir Varbanov
5297482a983SStanimir Varbanov return 0;
5307482a983SStanimir Varbanov }
5317482a983SStanimir Varbanov
power_save_mode_enable(struct venus_inst * inst,bool enable)5323cfe5815SDikshita Agarwal static inline int power_save_mode_enable(struct venus_inst *inst,
5333cfe5815SDikshita Agarwal bool enable)
5343cfe5815SDikshita Agarwal {
5353cfe5815SDikshita Agarwal struct venc_controls *enc_ctr = &inst->controls.enc;
5363cfe5815SDikshita Agarwal const u32 ptype = HFI_PROPERTY_CONFIG_VENC_PERF_MODE;
5373cfe5815SDikshita Agarwal u32 venc_mode;
5383cfe5815SDikshita Agarwal int ret = 0;
5393cfe5815SDikshita Agarwal
5403cfe5815SDikshita Agarwal if (inst->session_type != VIDC_SESSION_TYPE_ENC)
5413cfe5815SDikshita Agarwal return 0;
5423cfe5815SDikshita Agarwal
5433cfe5815SDikshita Agarwal if (enc_ctr->bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CQ)
5443cfe5815SDikshita Agarwal enable = false;
5453cfe5815SDikshita Agarwal
5463cfe5815SDikshita Agarwal venc_mode = enable ? HFI_VENC_PERFMODE_POWER_SAVE :
5473cfe5815SDikshita Agarwal HFI_VENC_PERFMODE_MAX_QUALITY;
5483cfe5815SDikshita Agarwal
5493cfe5815SDikshita Agarwal ret = hfi_session_set_property(inst, ptype, &venc_mode);
5503cfe5815SDikshita Agarwal if (ret)
5513cfe5815SDikshita Agarwal return ret;
5523cfe5815SDikshita Agarwal
5533cfe5815SDikshita Agarwal inst->flags = enable ? inst->flags | VENUS_LOW_POWER :
5543cfe5815SDikshita Agarwal inst->flags & ~VENUS_LOW_POWER;
5553cfe5815SDikshita Agarwal
5563cfe5815SDikshita Agarwal return ret;
5573cfe5815SDikshita Agarwal }
5583cfe5815SDikshita Agarwal
move_core_to_power_save_mode(struct venus_core * core,u32 core_id)5593cfe5815SDikshita Agarwal static int move_core_to_power_save_mode(struct venus_core *core,
5603cfe5815SDikshita Agarwal u32 core_id)
5613cfe5815SDikshita Agarwal {
5623cfe5815SDikshita Agarwal struct venus_inst *inst = NULL;
5633cfe5815SDikshita Agarwal
5643cfe5815SDikshita Agarwal mutex_lock(&core->lock);
5653cfe5815SDikshita Agarwal list_for_each_entry(inst, &core->instances, list) {
5663cfe5815SDikshita Agarwal if (inst->clk_data.core_id == core_id &&
5673cfe5815SDikshita Agarwal inst->session_type == VIDC_SESSION_TYPE_ENC)
5683cfe5815SDikshita Agarwal power_save_mode_enable(inst, true);
5693cfe5815SDikshita Agarwal }
5703cfe5815SDikshita Agarwal mutex_unlock(&core->lock);
5713cfe5815SDikshita Agarwal return 0;
5723cfe5815SDikshita Agarwal }
5733cfe5815SDikshita Agarwal
5744ebf9693SAniket Masule static void
min_loaded_core(struct venus_inst * inst,u32 * min_coreid,u32 * min_load,bool low_power)5753cfe5815SDikshita Agarwal min_loaded_core(struct venus_inst *inst, u32 *min_coreid, u32 *min_load, bool low_power)
5764ebf9693SAniket Masule {
5774ebf9693SAniket Masule u32 mbs_per_sec, load, core1_load = 0, core2_load = 0;
5784ebf9693SAniket Masule u32 cores_max = core_num_max(inst);
5794ebf9693SAniket Masule struct venus_core *core = inst->core;
5804ebf9693SAniket Masule struct venus_inst *inst_pos;
5814ebf9693SAniket Masule unsigned long vpp_freq;
5824ebf9693SAniket Masule u32 coreid;
5834ebf9693SAniket Masule
5844ebf9693SAniket Masule mutex_lock(&core->lock);
5854ebf9693SAniket Masule
5864ebf9693SAniket Masule list_for_each_entry(inst_pos, &core->instances, list) {
5874ebf9693SAniket Masule if (inst_pos == inst)
5884ebf9693SAniket Masule continue;
589e0eb3481SMansur Alisha Shaik
590e0eb3481SMansur Alisha Shaik if (inst_pos->state != INST_START)
591e0eb3481SMansur Alisha Shaik continue;
592e0eb3481SMansur Alisha Shaik
5933cfe5815SDikshita Agarwal if (inst->session_type == VIDC_SESSION_TYPE_DEC)
594aa603389SStanimir Varbanov vpp_freq = inst_pos->clk_data.vpp_freq;
5953cfe5815SDikshita Agarwal else if (inst->session_type == VIDC_SESSION_TYPE_ENC)
596b1f9bb80SMansur Alisha Shaik vpp_freq = low_power ? inst_pos->clk_data.low_power_freq :
597b1f9bb80SMansur Alisha Shaik inst_pos->clk_data.vpp_freq;
5983cfe5815SDikshita Agarwal else
5993cfe5815SDikshita Agarwal continue;
6003cfe5815SDikshita Agarwal
6014ebf9693SAniket Masule coreid = inst_pos->clk_data.core_id;
6024ebf9693SAniket Masule
6034ebf9693SAniket Masule mbs_per_sec = load_per_instance(inst_pos);
6044ebf9693SAniket Masule load = mbs_per_sec * vpp_freq;
6054ebf9693SAniket Masule
6064ebf9693SAniket Masule if ((coreid & VIDC_CORE_ID_3) == VIDC_CORE_ID_3) {
6074ebf9693SAniket Masule core1_load += load / 2;
6084ebf9693SAniket Masule core2_load += load / 2;
6094ebf9693SAniket Masule } else if (coreid & VIDC_CORE_ID_1) {
6104ebf9693SAniket Masule core1_load += load;
6114ebf9693SAniket Masule } else if (coreid & VIDC_CORE_ID_2) {
6124ebf9693SAniket Masule core2_load += load;
6134ebf9693SAniket Masule }
6144ebf9693SAniket Masule }
6154ebf9693SAniket Masule
6164ebf9693SAniket Masule *min_coreid = core1_load <= core2_load ?
6174ebf9693SAniket Masule VIDC_CORE_ID_1 : VIDC_CORE_ID_2;
6184ebf9693SAniket Masule *min_load = min(core1_load, core2_load);
6194ebf9693SAniket Masule
6204ebf9693SAniket Masule if (cores_max < VIDC_CORE_ID_2 || core->res->vcodec_num < 2) {
6214ebf9693SAniket Masule *min_coreid = VIDC_CORE_ID_1;
6224ebf9693SAniket Masule *min_load = core1_load;
6234ebf9693SAniket Masule }
6244ebf9693SAniket Masule
6254ebf9693SAniket Masule mutex_unlock(&core->lock);
6264ebf9693SAniket Masule }
6274ebf9693SAniket Masule
decide_core(struct venus_inst * inst)6284ebf9693SAniket Masule static int decide_core(struct venus_inst *inst)
6294ebf9693SAniket Masule {
6304ebf9693SAniket Masule const u32 ptype = HFI_PROPERTY_CONFIG_VIDEOCORES_USAGE;
6314ebf9693SAniket Masule struct venus_core *core = inst->core;
6323cfe5815SDikshita Agarwal u32 min_coreid, min_load, cur_inst_load;
6333cfe5815SDikshita Agarwal u32 min_lp_coreid, min_lp_load, cur_inst_lp_load;
6344ebf9693SAniket Masule struct hfi_videocores_usage_type cu;
6354ebf9693SAniket Masule unsigned long max_freq;
6363cfe5815SDikshita Agarwal int ret = 0;
6374ebf9693SAniket Masule
6384ebf9693SAniket Masule if (legacy_binding) {
6394ebf9693SAniket Masule if (inst->session_type == VIDC_SESSION_TYPE_DEC)
6404ebf9693SAniket Masule cu.video_core_enable_mask = VIDC_CORE_ID_1;
6414ebf9693SAniket Masule else
6424ebf9693SAniket Masule cu.video_core_enable_mask = VIDC_CORE_ID_2;
6434ebf9693SAniket Masule
6444ebf9693SAniket Masule goto done;
6454ebf9693SAniket Masule }
6464ebf9693SAniket Masule
6474ebf9693SAniket Masule if (inst->clk_data.core_id != VIDC_CORE_ID_DEFAULT)
6484ebf9693SAniket Masule return 0;
6494ebf9693SAniket Masule
6503cfe5815SDikshita Agarwal cur_inst_load = load_per_instance(inst);
6513cfe5815SDikshita Agarwal cur_inst_load *= inst->clk_data.vpp_freq;
6523cfe5815SDikshita Agarwal /*TODO : divide this inst->load by work_route */
6533cfe5815SDikshita Agarwal
6543cfe5815SDikshita Agarwal cur_inst_lp_load = load_per_instance(inst);
6553cfe5815SDikshita Agarwal cur_inst_lp_load *= inst->clk_data.low_power_freq;
6563cfe5815SDikshita Agarwal /*TODO : divide this inst->load by work_route */
6573cfe5815SDikshita Agarwal
6584ebf9693SAniket Masule max_freq = core->res->freq_tbl[0].freq;
6594ebf9693SAniket Masule
6603cfe5815SDikshita Agarwal min_loaded_core(inst, &min_coreid, &min_load, false);
6613cfe5815SDikshita Agarwal min_loaded_core(inst, &min_lp_coreid, &min_lp_load, true);
6624ebf9693SAniket Masule
6633cfe5815SDikshita Agarwal if (cur_inst_load + min_load <= max_freq) {
6643cfe5815SDikshita Agarwal inst->clk_data.core_id = min_coreid;
6653cfe5815SDikshita Agarwal cu.video_core_enable_mask = min_coreid;
6663cfe5815SDikshita Agarwal } else if (cur_inst_lp_load + min_load <= max_freq) {
6673cfe5815SDikshita Agarwal /* Move current instance to LP and return */
6683cfe5815SDikshita Agarwal inst->clk_data.core_id = min_coreid;
6693cfe5815SDikshita Agarwal cu.video_core_enable_mask = min_coreid;
6703cfe5815SDikshita Agarwal power_save_mode_enable(inst, true);
6713cfe5815SDikshita Agarwal } else if (cur_inst_lp_load + min_lp_load <= max_freq) {
6723cfe5815SDikshita Agarwal /* Move all instances to LP mode and return */
6733cfe5815SDikshita Agarwal inst->clk_data.core_id = min_lp_coreid;
6743cfe5815SDikshita Agarwal cu.video_core_enable_mask = min_lp_coreid;
6753cfe5815SDikshita Agarwal move_core_to_power_save_mode(core, min_lp_coreid);
6763cfe5815SDikshita Agarwal } else {
6773cfe5815SDikshita Agarwal dev_warn(core->dev, "HW can't support this load");
6784ebf9693SAniket Masule return -EINVAL;
6794ebf9693SAniket Masule }
6804ebf9693SAniket Masule
6814ebf9693SAniket Masule done:
6823cfe5815SDikshita Agarwal ret = hfi_session_set_property(inst, ptype, &cu);
6833cfe5815SDikshita Agarwal if (ret)
6843cfe5815SDikshita Agarwal return ret;
6853cfe5815SDikshita Agarwal
6863cfe5815SDikshita Agarwal return ret;
6874ebf9693SAniket Masule }
6884ebf9693SAniket Masule
acquire_core(struct venus_inst * inst)6894ebf9693SAniket Masule static int acquire_core(struct venus_inst *inst)
6904ebf9693SAniket Masule {
6914ebf9693SAniket Masule struct venus_core *core = inst->core;
6924ebf9693SAniket Masule unsigned int coreid_mask = 0;
6934ebf9693SAniket Masule
6944ebf9693SAniket Masule if (inst->core_acquired)
6954ebf9693SAniket Masule return 0;
6964ebf9693SAniket Masule
6974ebf9693SAniket Masule inst->core_acquired = true;
6984ebf9693SAniket Masule
6994ebf9693SAniket Masule if (inst->clk_data.core_id & VIDC_CORE_ID_1) {
7004ebf9693SAniket Masule if (core->core0_usage_count++)
7014ebf9693SAniket Masule return 0;
7024ebf9693SAniket Masule
7034ebf9693SAniket Masule coreid_mask = VIDC_CORE_ID_1;
7044ebf9693SAniket Masule }
7054ebf9693SAniket Masule
7064ebf9693SAniket Masule if (inst->clk_data.core_id & VIDC_CORE_ID_2) {
7074ebf9693SAniket Masule if (core->core1_usage_count++)
7084ebf9693SAniket Masule return 0;
7094ebf9693SAniket Masule
7104ebf9693SAniket Masule coreid_mask |= VIDC_CORE_ID_2;
7114ebf9693SAniket Masule }
7124ebf9693SAniket Masule
7134ebf9693SAniket Masule return poweron_coreid(core, coreid_mask);
7144ebf9693SAniket Masule }
7154ebf9693SAniket Masule
release_core(struct venus_inst * inst)7164ebf9693SAniket Masule static int release_core(struct venus_inst *inst)
7174ebf9693SAniket Masule {
7184ebf9693SAniket Masule struct venus_core *core = inst->core;
7194ebf9693SAniket Masule unsigned int coreid_mask = 0;
7204ebf9693SAniket Masule int ret;
7214ebf9693SAniket Masule
7224ebf9693SAniket Masule if (!inst->core_acquired)
7234ebf9693SAniket Masule return 0;
7244ebf9693SAniket Masule
7254ebf9693SAniket Masule if (inst->clk_data.core_id & VIDC_CORE_ID_1) {
7264ebf9693SAniket Masule if (--core->core0_usage_count)
7274ebf9693SAniket Masule goto done;
7284ebf9693SAniket Masule
7294ebf9693SAniket Masule coreid_mask = VIDC_CORE_ID_1;
7304ebf9693SAniket Masule }
7314ebf9693SAniket Masule
7324ebf9693SAniket Masule if (inst->clk_data.core_id & VIDC_CORE_ID_2) {
7334ebf9693SAniket Masule if (--core->core1_usage_count)
7344ebf9693SAniket Masule goto done;
7354ebf9693SAniket Masule
7364ebf9693SAniket Masule coreid_mask |= VIDC_CORE_ID_2;
7374ebf9693SAniket Masule }
7384ebf9693SAniket Masule
7394ebf9693SAniket Masule ret = poweroff_coreid(core, coreid_mask);
7404ebf9693SAniket Masule if (ret)
7414ebf9693SAniket Masule return ret;
7424ebf9693SAniket Masule
7434ebf9693SAniket Masule done:
7444ebf9693SAniket Masule inst->clk_data.core_id = VIDC_CORE_ID_DEFAULT;
7454ebf9693SAniket Masule inst->core_acquired = false;
7464ebf9693SAniket Masule return 0;
7474ebf9693SAniket Masule }
7484ebf9693SAniket Masule
coreid_power_v4(struct venus_inst * inst,int on)7494ebf9693SAniket Masule static int coreid_power_v4(struct venus_inst *inst, int on)
7504ebf9693SAniket Masule {
7514ebf9693SAniket Masule struct venus_core *core = inst->core;
7524ebf9693SAniket Masule int ret;
7534ebf9693SAniket Masule
7544ebf9693SAniket Masule if (legacy_binding)
7554ebf9693SAniket Masule return 0;
7564ebf9693SAniket Masule
7574ebf9693SAniket Masule if (on == POWER_ON) {
7584ebf9693SAniket Masule ret = decide_core(inst);
7594ebf9693SAniket Masule if (ret)
7604ebf9693SAniket Masule return ret;
7614ebf9693SAniket Masule
7624ebf9693SAniket Masule mutex_lock(&core->lock);
7634ebf9693SAniket Masule ret = acquire_core(inst);
7644ebf9693SAniket Masule mutex_unlock(&core->lock);
7654ebf9693SAniket Masule } else {
7664ebf9693SAniket Masule mutex_lock(&core->lock);
7674ebf9693SAniket Masule ret = release_core(inst);
7684ebf9693SAniket Masule mutex_unlock(&core->lock);
7694ebf9693SAniket Masule }
7704ebf9693SAniket Masule
7714ebf9693SAniket Masule return ret;
7724ebf9693SAniket Masule }
7734ebf9693SAniket Masule
vdec_get_v4(struct device * dev)7747482a983SStanimir Varbanov static int vdec_get_v4(struct device *dev)
7757482a983SStanimir Varbanov {
7767482a983SStanimir Varbanov struct venus_core *core = dev_get_drvdata(dev);
7777482a983SStanimir Varbanov
7787482a983SStanimir Varbanov if (!legacy_binding)
7797482a983SStanimir Varbanov return 0;
7807482a983SStanimir Varbanov
7817482a983SStanimir Varbanov return vcodec_clks_get(core, dev, core->vcodec0_clks,
7827482a983SStanimir Varbanov core->res->vcodec0_clks);
7837482a983SStanimir Varbanov }
7847482a983SStanimir Varbanov
vdec_put_v4(struct device * dev)7857482a983SStanimir Varbanov static void vdec_put_v4(struct device *dev)
7867482a983SStanimir Varbanov {
7877482a983SStanimir Varbanov struct venus_core *core = dev_get_drvdata(dev);
7887482a983SStanimir Varbanov unsigned int i;
7897482a983SStanimir Varbanov
7907482a983SStanimir Varbanov if (!legacy_binding)
7917482a983SStanimir Varbanov return;
7927482a983SStanimir Varbanov
7937482a983SStanimir Varbanov for (i = 0; i < core->res->vcodec_clks_num; i++)
7947482a983SStanimir Varbanov core->vcodec0_clks[i] = NULL;
7957482a983SStanimir Varbanov }
7967482a983SStanimir Varbanov
vdec_power_v4(struct device * dev,int on)7977482a983SStanimir Varbanov static int vdec_power_v4(struct device *dev, int on)
7987482a983SStanimir Varbanov {
7997482a983SStanimir Varbanov struct venus_core *core = dev_get_drvdata(dev);
8007482a983SStanimir Varbanov int ret;
8017482a983SStanimir Varbanov
8027482a983SStanimir Varbanov if (!legacy_binding)
8037482a983SStanimir Varbanov return 0;
8047482a983SStanimir Varbanov
8057482a983SStanimir Varbanov ret = vcodec_control_v4(core, VIDC_CORE_ID_1, true);
8067482a983SStanimir Varbanov if (ret)
8077482a983SStanimir Varbanov return ret;
8087482a983SStanimir Varbanov
8097482a983SStanimir Varbanov if (on == POWER_ON)
8107482a983SStanimir Varbanov ret = vcodec_clks_enable(core, core->vcodec0_clks);
8117482a983SStanimir Varbanov else
8127482a983SStanimir Varbanov vcodec_clks_disable(core, core->vcodec0_clks);
8137482a983SStanimir Varbanov
8147482a983SStanimir Varbanov vcodec_control_v4(core, VIDC_CORE_ID_1, false);
8157482a983SStanimir Varbanov
8167482a983SStanimir Varbanov return ret;
8177482a983SStanimir Varbanov }
8187482a983SStanimir Varbanov
venc_get_v4(struct device * dev)8197482a983SStanimir Varbanov static int venc_get_v4(struct device *dev)
8207482a983SStanimir Varbanov {
8217482a983SStanimir Varbanov struct venus_core *core = dev_get_drvdata(dev);
8227482a983SStanimir Varbanov
8237482a983SStanimir Varbanov if (!legacy_binding)
8247482a983SStanimir Varbanov return 0;
8257482a983SStanimir Varbanov
8267482a983SStanimir Varbanov return vcodec_clks_get(core, dev, core->vcodec1_clks,
8277482a983SStanimir Varbanov core->res->vcodec1_clks);
8287482a983SStanimir Varbanov }
8297482a983SStanimir Varbanov
venc_put_v4(struct device * dev)8307482a983SStanimir Varbanov static void venc_put_v4(struct device *dev)
8317482a983SStanimir Varbanov {
8327482a983SStanimir Varbanov struct venus_core *core = dev_get_drvdata(dev);
8337482a983SStanimir Varbanov unsigned int i;
8347482a983SStanimir Varbanov
8357482a983SStanimir Varbanov if (!legacy_binding)
8367482a983SStanimir Varbanov return;
8377482a983SStanimir Varbanov
8387482a983SStanimir Varbanov for (i = 0; i < core->res->vcodec_clks_num; i++)
8397482a983SStanimir Varbanov core->vcodec1_clks[i] = NULL;
8407482a983SStanimir Varbanov }
8417482a983SStanimir Varbanov
venc_power_v4(struct device * dev,int on)8427482a983SStanimir Varbanov static int venc_power_v4(struct device *dev, int on)
8437482a983SStanimir Varbanov {
8447482a983SStanimir Varbanov struct venus_core *core = dev_get_drvdata(dev);
8457482a983SStanimir Varbanov int ret;
8467482a983SStanimir Varbanov
8477482a983SStanimir Varbanov if (!legacy_binding)
8487482a983SStanimir Varbanov return 0;
8497482a983SStanimir Varbanov
8507482a983SStanimir Varbanov ret = vcodec_control_v4(core, VIDC_CORE_ID_2, true);
8517482a983SStanimir Varbanov if (ret)
8527482a983SStanimir Varbanov return ret;
8537482a983SStanimir Varbanov
8547482a983SStanimir Varbanov if (on == POWER_ON)
8557482a983SStanimir Varbanov ret = vcodec_clks_enable(core, core->vcodec1_clks);
8567482a983SStanimir Varbanov else
8577482a983SStanimir Varbanov vcodec_clks_disable(core, core->vcodec1_clks);
8587482a983SStanimir Varbanov
8597482a983SStanimir Varbanov vcodec_control_v4(core, VIDC_CORE_ID_2, false);
8607482a983SStanimir Varbanov
8617482a983SStanimir Varbanov return ret;
8627482a983SStanimir Varbanov }
8637482a983SStanimir Varbanov
vcodec_domains_get(struct venus_core * core)86408b1cf47SBryan O'Donoghue static int vcodec_domains_get(struct venus_core *core)
8657482a983SStanimir Varbanov {
8669a538b83SRajendra Nayak int ret;
8679a538b83SRajendra Nayak struct device **opp_virt_dev;
86808b1cf47SBryan O'Donoghue struct device *dev = core->dev;
8697482a983SStanimir Varbanov const struct venus_resources *res = core->res;
870693c301aSUlf Hansson struct dev_pm_domain_attach_data vcodec_data = {
871693c301aSUlf Hansson .pd_names = res->vcodec_pmdomains,
872693c301aSUlf Hansson .num_pd_names = res->vcodec_pmdomains_num,
873693c301aSUlf Hansson .pd_flags = PD_FLAG_NO_DEV_LINK,
874693c301aSUlf Hansson };
8757482a983SStanimir Varbanov
8767482a983SStanimir Varbanov if (!res->vcodec_pmdomains_num)
8779a538b83SRajendra Nayak goto skip_pmdomains;
8787482a983SStanimir Varbanov
879*3b019409SDikshita Agarwal ret = devm_pm_domain_attach_list(dev, &vcodec_data, &core->pmdomains);
880693c301aSUlf Hansson if (ret < 0)
881693c301aSUlf Hansson return ret;
8827482a983SStanimir Varbanov
8839a538b83SRajendra Nayak skip_pmdomains:
8841d95af02SStanimir Varbanov if (!core->res->opp_pmdomain)
8857482a983SStanimir Varbanov return 0;
8869a538b83SRajendra Nayak
8879a538b83SRajendra Nayak /* Attach the power domain for setting performance state */
8880394360eSYangtao Li ret = devm_pm_opp_attach_genpd(dev, res->opp_pmdomain, &opp_virt_dev);
8890394360eSYangtao Li if (ret)
8909a538b83SRajendra Nayak goto opp_attach_err;
8919a538b83SRajendra Nayak
8929a538b83SRajendra Nayak core->opp_pmdomain = *opp_virt_dev;
8939a538b83SRajendra Nayak core->opp_dl_venus = device_link_add(dev, core->opp_pmdomain,
8949a538b83SRajendra Nayak DL_FLAG_RPM_ACTIVE |
8959a538b83SRajendra Nayak DL_FLAG_PM_RUNTIME |
8969a538b83SRajendra Nayak DL_FLAG_STATELESS);
8979a538b83SRajendra Nayak if (!core->opp_dl_venus) {
8989a538b83SRajendra Nayak ret = -ENODEV;
8990394360eSYangtao Li goto opp_attach_err;
9009a538b83SRajendra Nayak }
9019a538b83SRajendra Nayak
9029a538b83SRajendra Nayak return 0;
9039a538b83SRajendra Nayak
9049a538b83SRajendra Nayak opp_attach_err:
9059a538b83SRajendra Nayak return ret;
9067482a983SStanimir Varbanov }
9077482a983SStanimir Varbanov
vcodec_domains_put(struct venus_core * core)90808b1cf47SBryan O'Donoghue static void vcodec_domains_put(struct venus_core *core)
9097482a983SStanimir Varbanov {
9109a538b83SRajendra Nayak if (!core->has_opp_table)
9119a538b83SRajendra Nayak return;
9129a538b83SRajendra Nayak
9139a538b83SRajendra Nayak if (core->opp_dl_venus)
9149a538b83SRajendra Nayak device_link_del(core->opp_dl_venus);
9157482a983SStanimir Varbanov }
9167482a983SStanimir Varbanov
core_resets_reset(struct venus_core * core)9173bca4358SStanimir Varbanov static int core_resets_reset(struct venus_core *core)
9183bca4358SStanimir Varbanov {
9193bca4358SStanimir Varbanov const struct venus_resources *res = core->res;
920999267d0SColin Ian King unsigned int i;
9213bca4358SStanimir Varbanov int ret;
9223bca4358SStanimir Varbanov
9233bca4358SStanimir Varbanov if (!res->resets_num)
9243bca4358SStanimir Varbanov return 0;
9253bca4358SStanimir Varbanov
9263bca4358SStanimir Varbanov for (i = 0; i < res->resets_num; i++) {
9273bca4358SStanimir Varbanov ret = reset_control_assert(core->resets[i]);
9283bca4358SStanimir Varbanov if (ret)
9293bca4358SStanimir Varbanov goto err;
9303bca4358SStanimir Varbanov
9313bca4358SStanimir Varbanov usleep_range(150, 250);
9323bca4358SStanimir Varbanov ret = reset_control_deassert(core->resets[i]);
9333bca4358SStanimir Varbanov if (ret)
9343bca4358SStanimir Varbanov goto err;
9353bca4358SStanimir Varbanov }
9363bca4358SStanimir Varbanov
9373bca4358SStanimir Varbanov err:
9383bca4358SStanimir Varbanov return ret;
9393bca4358SStanimir Varbanov }
9403bca4358SStanimir Varbanov
core_resets_get(struct venus_core * core)9413bca4358SStanimir Varbanov static int core_resets_get(struct venus_core *core)
9423bca4358SStanimir Varbanov {
9433bca4358SStanimir Varbanov struct device *dev = core->dev;
9443bca4358SStanimir Varbanov const struct venus_resources *res = core->res;
945999267d0SColin Ian King unsigned int i;
9463bca4358SStanimir Varbanov int ret;
9473bca4358SStanimir Varbanov
9483bca4358SStanimir Varbanov if (!res->resets_num)
9493bca4358SStanimir Varbanov return 0;
9503bca4358SStanimir Varbanov
9513bca4358SStanimir Varbanov for (i = 0; i < res->resets_num; i++) {
9523bca4358SStanimir Varbanov core->resets[i] =
9533bca4358SStanimir Varbanov devm_reset_control_get_exclusive(dev, res->resets[i]);
9543bca4358SStanimir Varbanov if (IS_ERR(core->resets[i])) {
9553bca4358SStanimir Varbanov ret = PTR_ERR(core->resets[i]);
9563bca4358SStanimir Varbanov return ret;
9573bca4358SStanimir Varbanov }
9583bca4358SStanimir Varbanov }
9593bca4358SStanimir Varbanov
9603bca4358SStanimir Varbanov return 0;
9613bca4358SStanimir Varbanov }
9623bca4358SStanimir Varbanov
core_get_v4(struct venus_core * core)96308b1cf47SBryan O'Donoghue static int core_get_v4(struct venus_core *core)
9647482a983SStanimir Varbanov {
96508b1cf47SBryan O'Donoghue struct device *dev = core->dev;
9667482a983SStanimir Varbanov const struct venus_resources *res = core->res;
9677482a983SStanimir Varbanov int ret;
9687482a983SStanimir Varbanov
9697482a983SStanimir Varbanov ret = core_clks_get(core);
9707482a983SStanimir Varbanov if (ret)
9717482a983SStanimir Varbanov return ret;
9727482a983SStanimir Varbanov
9737482a983SStanimir Varbanov if (!res->vcodec_pmdomains_num)
9747482a983SStanimir Varbanov legacy_binding = true;
9757482a983SStanimir Varbanov
9767482a983SStanimir Varbanov dev_info(dev, "%s legacy binding\n", legacy_binding ? "" : "non");
9777482a983SStanimir Varbanov
9787482a983SStanimir Varbanov ret = vcodec_clks_get(core, dev, core->vcodec0_clks, res->vcodec0_clks);
9797482a983SStanimir Varbanov if (ret)
9807482a983SStanimir Varbanov return ret;
9817482a983SStanimir Varbanov
9827482a983SStanimir Varbanov ret = vcodec_clks_get(core, dev, core->vcodec1_clks, res->vcodec1_clks);
9837482a983SStanimir Varbanov if (ret)
9847482a983SStanimir Varbanov return ret;
9857482a983SStanimir Varbanov
9863bca4358SStanimir Varbanov ret = core_resets_get(core);
9873bca4358SStanimir Varbanov if (ret)
9883bca4358SStanimir Varbanov return ret;
9893bca4358SStanimir Varbanov
9907482a983SStanimir Varbanov if (legacy_binding)
9917482a983SStanimir Varbanov return 0;
9927482a983SStanimir Varbanov
9930394360eSYangtao Li ret = devm_pm_opp_set_clkname(dev, "core");
9940394360eSYangtao Li if (ret)
9950394360eSYangtao Li return ret;
9969a538b83SRajendra Nayak
9971d95af02SStanimir Varbanov ret = vcodec_domains_get(core);
9981d95af02SStanimir Varbanov if (ret)
9991d95af02SStanimir Varbanov return ret;
10001d95af02SStanimir Varbanov
10019a538b83SRajendra Nayak if (core->res->opp_pmdomain) {
10020394360eSYangtao Li ret = devm_pm_opp_of_add_table(dev);
10039a538b83SRajendra Nayak if (!ret) {
10049a538b83SRajendra Nayak core->has_opp_table = true;
10059a538b83SRajendra Nayak } else if (ret != -ENODEV) {
10069a538b83SRajendra Nayak dev_err(dev, "invalid OPP table in device tree\n");
10077482a983SStanimir Varbanov return ret;
10089a538b83SRajendra Nayak }
10099a538b83SRajendra Nayak }
10109a538b83SRajendra Nayak
10117482a983SStanimir Varbanov return 0;
10127482a983SStanimir Varbanov }
10137482a983SStanimir Varbanov
core_put_v4(struct venus_core * core)101408b1cf47SBryan O'Donoghue static void core_put_v4(struct venus_core *core)
10157482a983SStanimir Varbanov {
10167482a983SStanimir Varbanov if (legacy_binding)
10177482a983SStanimir Varbanov return;
10187482a983SStanimir Varbanov
101908b1cf47SBryan O'Donoghue vcodec_domains_put(core);
10207482a983SStanimir Varbanov }
10217482a983SStanimir Varbanov
core_power_v4(struct venus_core * core,int on)102208b1cf47SBryan O'Donoghue static int core_power_v4(struct venus_core *core, int on)
10237482a983SStanimir Varbanov {
102408b1cf47SBryan O'Donoghue struct device *dev = core->dev;
1025693c301aSUlf Hansson struct device *pmctrl = core->pmdomains ?
1026693c301aSUlf Hansson core->pmdomains->pd_devs[0] : NULL;
10277482a983SStanimir Varbanov int ret = 0;
10287482a983SStanimir Varbanov
10299a538b83SRajendra Nayak if (on == POWER_ON) {
1030a76f43a4SStanimir Varbanov if (pmctrl) {
1031f6bf35eeSMauro Carvalho Chehab ret = pm_runtime_resume_and_get(pmctrl);
1032a76f43a4SStanimir Varbanov if (ret < 0) {
1033a76f43a4SStanimir Varbanov return ret;
1034a76f43a4SStanimir Varbanov }
1035a76f43a4SStanimir Varbanov }
1036a76f43a4SStanimir Varbanov
10373bca4358SStanimir Varbanov ret = core_resets_reset(core);
10383bca4358SStanimir Varbanov if (ret) {
10393bca4358SStanimir Varbanov if (pmctrl)
10403bca4358SStanimir Varbanov pm_runtime_put_sync(pmctrl);
10413bca4358SStanimir Varbanov return ret;
10423bca4358SStanimir Varbanov }
10433bca4358SStanimir Varbanov
10447482a983SStanimir Varbanov ret = core_clks_enable(core);
1045a76f43a4SStanimir Varbanov if (ret < 0 && pmctrl)
1046a76f43a4SStanimir Varbanov pm_runtime_put_sync(pmctrl);
10479a538b83SRajendra Nayak } else {
10489a538b83SRajendra Nayak /* Drop the performance state vote */
10499a538b83SRajendra Nayak if (core->opp_pmdomain)
10509a538b83SRajendra Nayak dev_pm_opp_set_rate(dev, 0);
10519a538b83SRajendra Nayak
10527482a983SStanimir Varbanov core_clks_disable(core);
1053a76f43a4SStanimir Varbanov
10543bca4358SStanimir Varbanov ret = core_resets_reset(core);
10553bca4358SStanimir Varbanov
1056a76f43a4SStanimir Varbanov if (pmctrl)
1057a76f43a4SStanimir Varbanov pm_runtime_put_sync(pmctrl);
10589a538b83SRajendra Nayak }
10597482a983SStanimir Varbanov
10607482a983SStanimir Varbanov return ret;
10617482a983SStanimir Varbanov }
10627482a983SStanimir Varbanov
calculate_inst_freq(struct venus_inst * inst,unsigned long filled_len)10637482a983SStanimir Varbanov static unsigned long calculate_inst_freq(struct venus_inst *inst,
10647482a983SStanimir Varbanov unsigned long filled_len)
10657482a983SStanimir Varbanov {
10663cfe5815SDikshita Agarwal unsigned long vpp_freq_per_mb = 0, vpp_freq = 0, vsp_freq = 0;
10677482a983SStanimir Varbanov u32 fps = (u32)inst->fps;
10687482a983SStanimir Varbanov u32 mbs_per_sec;
10697482a983SStanimir Varbanov
1070b57cf6a0SMansur Alisha Shaik mbs_per_sec = load_per_instance(inst);
10717482a983SStanimir Varbanov
1072d33a9441SStanimir Varbanov if (inst->state != INST_START)
1073d33a9441SStanimir Varbanov return 0;
1074d33a9441SStanimir Varbanov
107514442321SMansur Alisha Shaik if (inst->session_type == VIDC_SESSION_TYPE_ENC) {
10763cfe5815SDikshita Agarwal vpp_freq_per_mb = inst->flags & VENUS_LOW_POWER ?
10773cfe5815SDikshita Agarwal inst->clk_data.low_power_freq :
10783cfe5815SDikshita Agarwal inst->clk_data.vpp_freq;
10793cfe5815SDikshita Agarwal
10803cfe5815SDikshita Agarwal vpp_freq = mbs_per_sec * vpp_freq_per_mb;
108114442321SMansur Alisha Shaik } else {
108214442321SMansur Alisha Shaik vpp_freq = mbs_per_sec * inst->clk_data.vpp_freq;
108314442321SMansur Alisha Shaik }
108414442321SMansur Alisha Shaik
10857482a983SStanimir Varbanov /* 21 / 20 is overhead factor */
10867482a983SStanimir Varbanov vpp_freq += vpp_freq / 20;
1087aa603389SStanimir Varbanov vsp_freq = mbs_per_sec * inst->clk_data.vsp_freq;
10887482a983SStanimir Varbanov
10897482a983SStanimir Varbanov /* 10 / 7 is overhead factor */
10907482a983SStanimir Varbanov if (inst->session_type == VIDC_SESSION_TYPE_ENC)
10917482a983SStanimir Varbanov vsp_freq += (inst->controls.enc.bitrate * 10) / 7;
10927482a983SStanimir Varbanov else
10937482a983SStanimir Varbanov vsp_freq += ((fps * filled_len * 8) * 10) / 7;
10947482a983SStanimir Varbanov
10957482a983SStanimir Varbanov return max(vpp_freq, vsp_freq);
10967482a983SStanimir Varbanov }
10977482a983SStanimir Varbanov
load_scale_v4(struct venus_inst * inst)10987482a983SStanimir Varbanov static int load_scale_v4(struct venus_inst *inst)
10997482a983SStanimir Varbanov {
11007482a983SStanimir Varbanov struct venus_core *core = inst->core;
11017482a983SStanimir Varbanov const struct freq_tbl *table = core->res->freq_tbl;
11027482a983SStanimir Varbanov unsigned int num_rows = core->res->freq_tbl_size;
11037482a983SStanimir Varbanov struct device *dev = core->dev;
11047482a983SStanimir Varbanov unsigned long freq = 0, freq_core1 = 0, freq_core2 = 0;
11057482a983SStanimir Varbanov unsigned long filled_len = 0;
110691f2b7d2SMansur Alisha Shaik int i, ret = 0;
11077482a983SStanimir Varbanov
11087482a983SStanimir Varbanov for (i = 0; i < inst->num_input_bufs; i++)
11097482a983SStanimir Varbanov filled_len = max(filled_len, inst->payloads[i]);
11107482a983SStanimir Varbanov
11117482a983SStanimir Varbanov if (inst->session_type == VIDC_SESSION_TYPE_DEC && !filled_len)
111291f2b7d2SMansur Alisha Shaik return ret;
11137482a983SStanimir Varbanov
11147482a983SStanimir Varbanov freq = calculate_inst_freq(inst, filled_len);
11157482a983SStanimir Varbanov inst->clk_data.freq = freq;
11167482a983SStanimir Varbanov
11177482a983SStanimir Varbanov mutex_lock(&core->lock);
11187482a983SStanimir Varbanov list_for_each_entry(inst, &core->instances, list) {
11197482a983SStanimir Varbanov if (inst->clk_data.core_id == VIDC_CORE_ID_1) {
11207482a983SStanimir Varbanov freq_core1 += inst->clk_data.freq;
11217482a983SStanimir Varbanov } else if (inst->clk_data.core_id == VIDC_CORE_ID_2) {
11227482a983SStanimir Varbanov freq_core2 += inst->clk_data.freq;
11237482a983SStanimir Varbanov } else if (inst->clk_data.core_id == VIDC_CORE_ID_3) {
11247482a983SStanimir Varbanov freq_core1 += inst->clk_data.freq;
11257482a983SStanimir Varbanov freq_core2 += inst->clk_data.freq;
11267482a983SStanimir Varbanov }
11277482a983SStanimir Varbanov }
11287482a983SStanimir Varbanov
11297482a983SStanimir Varbanov freq = max(freq_core1, freq_core2);
11307482a983SStanimir Varbanov
1131bcf6b264SMansur Alisha Shaik if (freq > table[0].freq) {
1132799926a1SMansur Alisha Shaik dev_dbg(dev, VDBGL "requested clock rate: %lu scaling clock rate : %lu\n",
11337482a983SStanimir Varbanov freq, table[0].freq);
1134799926a1SMansur Alisha Shaik
1135799926a1SMansur Alisha Shaik freq = table[0].freq;
11367482a983SStanimir Varbanov goto set_freq;
11377482a983SStanimir Varbanov }
11387482a983SStanimir Varbanov
11397482a983SStanimir Varbanov for (i = num_rows - 1 ; i >= 0; i--) {
11407482a983SStanimir Varbanov if (freq <= table[i].freq) {
11417482a983SStanimir Varbanov freq = table[i].freq;
11427482a983SStanimir Varbanov break;
11437482a983SStanimir Varbanov }
11447482a983SStanimir Varbanov }
11457482a983SStanimir Varbanov
11467482a983SStanimir Varbanov set_freq:
11477482a983SStanimir Varbanov
11487482a983SStanimir Varbanov ret = core_clks_set_rate(core, freq);
11497482a983SStanimir Varbanov if (ret) {
11507482a983SStanimir Varbanov dev_err(dev, "failed to set clock rate %lu (%d)\n",
11517482a983SStanimir Varbanov freq, ret);
115291f2b7d2SMansur Alisha Shaik goto exit;
11537482a983SStanimir Varbanov }
11547482a983SStanimir Varbanov
11557482a983SStanimir Varbanov ret = load_scale_bw(core);
11567482a983SStanimir Varbanov if (ret) {
11577482a983SStanimir Varbanov dev_err(dev, "failed to set bandwidth (%d)\n",
11587482a983SStanimir Varbanov ret);
115991f2b7d2SMansur Alisha Shaik goto exit;
11607482a983SStanimir Varbanov }
11617482a983SStanimir Varbanov
116291f2b7d2SMansur Alisha Shaik exit:
116391f2b7d2SMansur Alisha Shaik mutex_unlock(&core->lock);
116491f2b7d2SMansur Alisha Shaik return ret;
11657482a983SStanimir Varbanov }
11667482a983SStanimir Varbanov
11677482a983SStanimir Varbanov static const struct venus_pm_ops pm_ops_v4 = {
11687482a983SStanimir Varbanov .core_get = core_get_v4,
11697482a983SStanimir Varbanov .core_put = core_put_v4,
11707482a983SStanimir Varbanov .core_power = core_power_v4,
11717482a983SStanimir Varbanov .vdec_get = vdec_get_v4,
11727482a983SStanimir Varbanov .vdec_put = vdec_put_v4,
11737482a983SStanimir Varbanov .vdec_power = vdec_power_v4,
11747482a983SStanimir Varbanov .venc_get = venc_get_v4,
11757482a983SStanimir Varbanov .venc_put = venc_put_v4,
11767482a983SStanimir Varbanov .venc_power = venc_power_v4,
11774ebf9693SAniket Masule .coreid_power = coreid_power_v4,
11787482a983SStanimir Varbanov .load_scale = load_scale_v4,
11797482a983SStanimir Varbanov };
11807482a983SStanimir Varbanov
venus_pm_get(enum hfi_version version)11817482a983SStanimir Varbanov const struct venus_pm_ops *venus_pm_get(enum hfi_version version)
11827482a983SStanimir Varbanov {
11837482a983SStanimir Varbanov switch (version) {
11847482a983SStanimir Varbanov case HFI_VERSION_1XX:
11857482a983SStanimir Varbanov default:
11867482a983SStanimir Varbanov return &pm_ops_v1;
11877482a983SStanimir Varbanov case HFI_VERSION_3XX:
11887482a983SStanimir Varbanov return &pm_ops_v3;
11897482a983SStanimir Varbanov case HFI_VERSION_4XX:
1190f24afa95SBryan O'Donoghue case HFI_VERSION_6XX:
11917482a983SStanimir Varbanov return &pm_ops_v4;
11927482a983SStanimir Varbanov }
11937482a983SStanimir Varbanov
11947482a983SStanimir Varbanov return NULL;
11957482a983SStanimir Varbanov }
1196