summaryrefslogtreecommitdiffstats
path: root/drivers/media/platform/qcom/venus
diff options
context:
space:
mode:
authorMaarten Lankhorst <maarten.lankhorst@linux.intel.com>2021-07-27 12:48:17 +0200
committerMaarten Lankhorst <maarten.lankhorst@linux.intel.com>2021-07-27 12:48:17 +0200
commitca31fef11dc83e672415d5925a134749761329bd (patch)
tree8eb6a489e2d6dd117300f40ed8fc945a06bb6eee /drivers/media/platform/qcom/venus
parentdrm/plane: Move drm_plane_enable_fb_damage_clips into core (diff)
parentefi: sysfb_efi: fix build when EFI is not set (diff)
downloadlinux-ca31fef11dc83e672415d5925a134749761329bd.tar.xz
linux-ca31fef11dc83e672415d5925a134749761329bd.zip
Backmerge remote-tracking branch 'drm/drm-next' into drm-misc-next
Required bump from v5.13-rc3 to v5.14-rc3, and to pick up sysfb compilation fixes. Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Diffstat (limited to 'drivers/media/platform/qcom/venus')
-rw-r--r--drivers/media/platform/qcom/venus/core.c60
-rw-r--r--drivers/media/platform/qcom/venus/core.h7
-rw-r--r--drivers/media/platform/qcom/venus/helpers.c5
-rw-r--r--drivers/media/platform/qcom/venus/hfi_cmds.c31
-rw-r--r--drivers/media/platform/qcom/venus/hfi_cmds.h2
-rw-r--r--drivers/media/platform/qcom/venus/hfi_helper.h10
-rw-r--r--drivers/media/platform/qcom/venus/hfi_msgs.c16
-rw-r--r--drivers/media/platform/qcom/venus/hfi_msgs.h6
-rw-r--r--drivers/media/platform/qcom/venus/hfi_platform.c16
-rw-r--r--drivers/media/platform/qcom/venus/hfi_platform.h4
-rw-r--r--drivers/media/platform/qcom/venus/hfi_platform_v4.c28
-rw-r--r--drivers/media/platform/qcom/venus/hfi_platform_v6.c28
-rw-r--r--drivers/media/platform/qcom/venus/pm_helpers.c153
-rw-r--r--drivers/media/platform/qcom/venus/vdec.c6
-rw-r--r--drivers/media/platform/qcom/venus/venc.c5
15 files changed, 262 insertions, 115 deletions
diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c
index 54bac7ec14c5..91b15842c555 100644
--- a/drivers/media/platform/qcom/venus/core.c
+++ b/drivers/media/platform/qcom/venus/core.c
@@ -78,22 +78,32 @@ static const struct hfi_core_ops venus_core_ops = {
.event_notify = venus_event_notify,
};
+#define RPM_WAIT_FOR_IDLE_MAX_ATTEMPTS 10
+
static void venus_sys_error_handler(struct work_struct *work)
{
struct venus_core *core =
container_of(work, struct venus_core, work.work);
- int ret = 0;
-
- pm_runtime_get_sync(core->dev);
+ int ret, i, max_attempts = RPM_WAIT_FOR_IDLE_MAX_ATTEMPTS;
+ const char *err_msg = "";
+ bool failed = false;
+
+ ret = pm_runtime_get_sync(core->dev);
+ if (ret < 0) {
+ err_msg = "resume runtime PM";
+ max_attempts = 0;
+ failed = true;
+ }
hfi_core_deinit(core, true);
- dev_warn(core->dev, "system error has occurred, starting recovery!\n");
-
mutex_lock(&core->lock);
- while (pm_runtime_active(core->dev_dec) || pm_runtime_active(core->dev_enc))
+ for (i = 0; i < max_attempts; i++) {
+ if (!pm_runtime_active(core->dev_dec) && !pm_runtime_active(core->dev_enc))
+ break;
msleep(10);
+ }
venus_shutdown(core);
@@ -101,31 +111,55 @@ static void venus_sys_error_handler(struct work_struct *work)
pm_runtime_put_sync(core->dev);
- while (core->pmdomains[0] && pm_runtime_active(core->pmdomains[0]))
+ for (i = 0; i < max_attempts; i++) {
+ if (!core->pmdomains[0] || !pm_runtime_active(core->pmdomains[0]))
+ break;
usleep_range(1000, 1500);
+ }
hfi_reinit(core);
- pm_runtime_get_sync(core->dev);
+ ret = pm_runtime_get_sync(core->dev);
+ if (ret < 0) {
+ err_msg = "resume runtime PM";
+ failed = true;
+ }
- ret |= venus_boot(core);
- ret |= hfi_core_resume(core, true);
+ ret = venus_boot(core);
+ if (ret && !failed) {
+ err_msg = "boot Venus";
+ failed = true;
+ }
+
+ ret = hfi_core_resume(core, true);
+ if (ret && !failed) {
+ err_msg = "resume HFI";
+ failed = true;
+ }
enable_irq(core->irq);
mutex_unlock(&core->lock);
- ret |= hfi_core_init(core);
+ ret = hfi_core_init(core);
+ if (ret && !failed) {
+ err_msg = "init HFI";
+ failed = true;
+ }
pm_runtime_put_sync(core->dev);
- if (ret) {
+ if (failed) {
disable_irq_nosync(core->irq);
- dev_warn(core->dev, "recovery failed (%d)\n", ret);
+ dev_warn_ratelimited(core->dev,
+ "System error has occurred, recovery failed to %s\n",
+ err_msg);
schedule_delayed_work(&core->work, msecs_to_jiffies(10));
return;
}
+ dev_warn(core->dev, "system error has occurred (recovered)\n");
+
mutex_lock(&core->lock);
core->sys_error = false;
mutex_unlock(&core->lock);
diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h
index 745f226a523f..8df2d497d706 100644
--- a/drivers/media/platform/qcom/venus/core.h
+++ b/drivers/media/platform/qcom/venus/core.h
@@ -155,7 +155,6 @@ struct venus_core {
struct clk *vcodec1_clks[VIDC_VCODEC_CLKS_NUM_MAX];
struct icc_path *video_path;
struct icc_path *cpucfg_path;
- struct opp_table *opp_table;
bool has_opp_table;
struct device *pmdomains[VIDC_PMDOMAINS_NUM_MAX];
struct device_link *opp_dl_venus;
@@ -293,6 +292,7 @@ struct clock_data {
unsigned long freq;
unsigned long vpp_freq;
unsigned long vsp_freq;
+ unsigned long low_power_freq;
};
#define to_venus_buffer(ptr) container_of(ptr, struct venus_buffer, vb)
@@ -316,6 +316,10 @@ struct venus_ts_metadata {
struct v4l2_timecode tc;
};
+enum venus_inst_modes {
+ VENUS_LOW_POWER = BIT(0),
+};
+
/**
* struct venus_inst - holds per instance parameters
*
@@ -445,6 +449,7 @@ struct venus_inst {
unsigned int pic_struct;
bool next_buf_last;
bool drain_active;
+ enum venus_inst_modes flags;
};
#define IS_V1(core) ((core)->res->hfi_version == HFI_VERSION_1XX)
diff --git a/drivers/media/platform/qcom/venus/helpers.c b/drivers/media/platform/qcom/venus/helpers.c
index b813d6dba481..1fe6d463dc99 100644
--- a/drivers/media/platform/qcom/venus/helpers.c
+++ b/drivers/media/platform/qcom/venus/helpers.c
@@ -595,8 +595,7 @@ static int platform_get_bufreq(struct venus_inst *inst, u32 buftype,
params.dec.is_secondary_output =
inst->opb_buftype == HFI_BUFFER_OUTPUT2;
params.dec.is_interlaced =
- inst->pic_struct != HFI_INTERLACE_FRAME_PROGRESSIVE ?
- true : false;
+ inst->pic_struct != HFI_INTERLACE_FRAME_PROGRESSIVE;
} else {
params.width = inst->out_width;
params.height = inst->out_height;
@@ -1627,6 +1626,8 @@ int venus_helper_session_init(struct venus_inst *inst)
session_type);
inst->clk_data.vsp_freq = hfi_platform_get_codec_vsp_freq(version, codec,
session_type);
+ inst->clk_data.low_power_freq = hfi_platform_get_codec_lp_freq(version, codec,
+ session_type);
return 0;
}
diff --git a/drivers/media/platform/qcom/venus/hfi_cmds.c b/drivers/media/platform/qcom/venus/hfi_cmds.c
index 11a8347e5f5c..f51024786991 100644
--- a/drivers/media/platform/qcom/venus/hfi_cmds.c
+++ b/drivers/media/platform/qcom/venus/hfi_cmds.c
@@ -3,6 +3,7 @@
* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
* Copyright (C) 2017 Linaro Ltd.
*/
+#include <linux/overflow.h>
#include <linux/errno.h>
#include <linux/hash.h>
@@ -27,7 +28,7 @@ void pkt_sys_idle_indicator(struct hfi_sys_set_property_pkt *pkt, u32 enable)
{
struct hfi_enable *hfi = (struct hfi_enable *)&pkt->data[1];
- pkt->hdr.size = sizeof(*pkt) + sizeof(*hfi) + sizeof(u32);
+ pkt->hdr.size = struct_size(pkt, data, 1) + sizeof(*hfi);
pkt->hdr.pkt_type = HFI_CMD_SYS_SET_PROPERTY;
pkt->num_properties = 1;
pkt->data[0] = HFI_PROPERTY_SYS_IDLE_INDICATOR;
@@ -39,7 +40,7 @@ void pkt_sys_debug_config(struct hfi_sys_set_property_pkt *pkt, u32 mode,
{
struct hfi_debug_config *hfi;
- pkt->hdr.size = sizeof(*pkt) + sizeof(*hfi) + sizeof(u32);
+ pkt->hdr.size = struct_size(pkt, data, 1) + sizeof(*hfi);
pkt->hdr.pkt_type = HFI_CMD_SYS_SET_PROPERTY;
pkt->num_properties = 1;
pkt->data[0] = HFI_PROPERTY_SYS_DEBUG_CONFIG;
@@ -50,7 +51,7 @@ void pkt_sys_debug_config(struct hfi_sys_set_property_pkt *pkt, u32 mode,
void pkt_sys_coverage_config(struct hfi_sys_set_property_pkt *pkt, u32 mode)
{
- pkt->hdr.size = sizeof(*pkt) + sizeof(u32);
+ pkt->hdr.size = struct_size(pkt, data, 2);
pkt->hdr.pkt_type = HFI_CMD_SYS_SET_PROPERTY;
pkt->num_properties = 1;
pkt->data[0] = HFI_PROPERTY_SYS_CONFIG_COVERAGE;
@@ -116,7 +117,7 @@ void pkt_sys_power_control(struct hfi_sys_set_property_pkt *pkt, u32 enable)
{
struct hfi_enable *hfi = (struct hfi_enable *)&pkt->data[1];
- pkt->hdr.size = sizeof(*pkt) + sizeof(*hfi) + sizeof(u32);
+ pkt->hdr.size = struct_size(pkt, data, 1) + sizeof(*hfi);
pkt->hdr.pkt_type = HFI_CMD_SYS_SET_PROPERTY;
pkt->num_properties = 1;
pkt->data[0] = HFI_PROPERTY_SYS_CODEC_POWER_PLANE_CTRL;
@@ -1226,6 +1227,17 @@ pkt_session_set_property_4xx(struct hfi_session_set_property_pkt *pkt,
pkt->shdr.hdr.size += sizeof(u32) + sizeof(*hdr10);
break;
}
+ case HFI_PROPERTY_PARAM_VDEC_CONCEAL_COLOR: {
+ struct hfi_conceal_color_v4 *color = prop_data;
+ u32 *in = pdata;
+
+ color->conceal_color_8bit = *in & 0xff;
+ color->conceal_color_8bit |= ((*in >> 10) & 0xff) << 8;
+ color->conceal_color_8bit |= ((*in >> 20) & 0xff) << 16;
+ color->conceal_color_10bit = *in;
+ pkt->shdr.hdr.size += sizeof(u32) + sizeof(*color);
+ break;
+ }
case HFI_PROPERTY_CONFIG_VENC_MAX_BITRATE:
case HFI_PROPERTY_CONFIG_VDEC_POST_LOOP_DEBLOCKER:
@@ -1279,17 +1291,6 @@ pkt_session_set_property_6xx(struct hfi_session_set_property_pkt *pkt,
pkt->shdr.hdr.size += sizeof(u32) + sizeof(*cq);
break;
}
- case HFI_PROPERTY_PARAM_VDEC_CONCEAL_COLOR: {
- struct hfi_conceal_color_v4 *color = prop_data;
- u32 *in = pdata;
-
- color->conceal_color_8bit = *in & 0xff;
- color->conceal_color_8bit |= ((*in >> 10) & 0xff) << 8;
- color->conceal_color_8bit |= ((*in >> 20) & 0xff) << 16;
- color->conceal_color_10bit = *in;
- pkt->shdr.hdr.size += sizeof(u32) + sizeof(*color);
- break;
- }
default:
return pkt_session_set_property_4xx(pkt, cookie, ptype, pdata);
}
diff --git a/drivers/media/platform/qcom/venus/hfi_cmds.h b/drivers/media/platform/qcom/venus/hfi_cmds.h
index 83705e237f1c..327ed90a2788 100644
--- a/drivers/media/platform/qcom/venus/hfi_cmds.h
+++ b/drivers/media/platform/qcom/venus/hfi_cmds.h
@@ -68,7 +68,7 @@ struct hfi_sys_release_resource_pkt {
struct hfi_sys_set_property_pkt {
struct hfi_pkt_hdr hdr;
u32 num_properties;
- u32 data[1];
+ u32 data[];
};
struct hfi_sys_get_property_pkt {
diff --git a/drivers/media/platform/qcom/venus/hfi_helper.h b/drivers/media/platform/qcom/venus/hfi_helper.h
index 63cd347a62da..b0a9beb4163c 100644
--- a/drivers/media/platform/qcom/venus/hfi_helper.h
+++ b/drivers/media/platform/qcom/venus/hfi_helper.h
@@ -415,9 +415,6 @@
#define HFI_BUFFER_MODE_RING 0x1000002
#define HFI_BUFFER_MODE_DYNAMIC 0x1000003
-#define HFI_VENC_PERFMODE_MAX_QUALITY 0x1
-#define HFI_VENC_PERFMODE_POWER_SAVE 0x2
-
/*
* HFI_PROPERTY_SYS_COMMON_START
* HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET + 0x0000
@@ -848,6 +845,13 @@ struct hfi_framesize {
u32 height;
};
+#define HFI_VENC_PERFMODE_MAX_QUALITY 0x1
+#define HFI_VENC_PERFMODE_POWER_SAVE 0x2
+
+struct hfi_perf_mode {
+ u32 video_perf_mode;
+};
+
#define VIDC_CORE_ID_DEFAULT 0
#define VIDC_CORE_ID_1 1
#define VIDC_CORE_ID_2 2
diff --git a/drivers/media/platform/qcom/venus/hfi_msgs.c b/drivers/media/platform/qcom/venus/hfi_msgs.c
index a2d436d407b2..d9fde66f6fa8 100644
--- a/drivers/media/platform/qcom/venus/hfi_msgs.c
+++ b/drivers/media/platform/qcom/venus/hfi_msgs.c
@@ -251,11 +251,11 @@ sys_get_prop_image_version(struct device *dev,
req_bytes = pkt->hdr.size - sizeof(*pkt);
- if (req_bytes < VER_STR_SZ || !pkt->data[1] || pkt->num_properties > 1)
+ if (req_bytes < VER_STR_SZ || !pkt->data[0] || pkt->num_properties > 1)
/* bad packet */
return;
- img_ver = (u8 *)&pkt->data[1];
+ img_ver = pkt->data;
dev_dbg(dev, VDBGL "F/W version: %s\n", img_ver);
@@ -277,7 +277,7 @@ static void hfi_sys_property_info(struct venus_core *core,
return;
}
- switch (pkt->data[0]) {
+ switch (pkt->property) {
case HFI_PROPERTY_SYS_IMAGE_VERSION:
sys_get_prop_image_version(dev, pkt);
break;
@@ -338,7 +338,7 @@ session_get_prop_profile_level(struct hfi_msg_session_property_info_pkt *pkt,
/* bad packet */
return HFI_ERR_SESSION_INVALID_PARAMETER;
- hfi = (struct hfi_profile_level *)&pkt->data[1];
+ hfi = (struct hfi_profile_level *)&pkt->data[0];
profile_level->profile = hfi->profile;
profile_level->level = hfi->level;
@@ -355,11 +355,11 @@ session_get_prop_buf_req(struct hfi_msg_session_property_info_pkt *pkt,
req_bytes = pkt->shdr.hdr.size - sizeof(*pkt);
- if (!req_bytes || req_bytes % sizeof(*buf_req) || !pkt->data[1])
+ if (!req_bytes || req_bytes % sizeof(*buf_req) || !pkt->data[0])
/* bad packet */
return HFI_ERR_SESSION_INVALID_PARAMETER;
- buf_req = (struct hfi_buffer_requirements *)&pkt->data[1];
+ buf_req = (struct hfi_buffer_requirements *)&pkt->data[0];
if (!buf_req)
return HFI_ERR_SESSION_INVALID_PARAMETER;
@@ -391,7 +391,7 @@ static void hfi_session_prop_info(struct venus_core *core,
goto done;
}
- switch (pkt->data[0]) {
+ switch (pkt->property) {
case HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS:
memset(hprop->bufreq, 0, sizeof(hprop->bufreq));
error = session_get_prop_buf_req(pkt, hprop->bufreq);
@@ -404,7 +404,7 @@ static void hfi_session_prop_info(struct venus_core *core,
case HFI_PROPERTY_CONFIG_VDEC_ENTROPY:
break;
default:
- dev_dbg(dev, VDBGM "unknown property id:%x\n", pkt->data[0]);
+ dev_dbg(dev, VDBGM "unknown property id:%x\n", pkt->property);
return;
}
diff --git a/drivers/media/platform/qcom/venus/hfi_msgs.h b/drivers/media/platform/qcom/venus/hfi_msgs.h
index 526d9f5b487b..510513697335 100644
--- a/drivers/media/platform/qcom/venus/hfi_msgs.h
+++ b/drivers/media/platform/qcom/venus/hfi_msgs.h
@@ -113,7 +113,8 @@ struct hfi_msg_sys_ping_ack_pkt {
struct hfi_msg_sys_property_info_pkt {
struct hfi_pkt_hdr hdr;
u32 num_properties;
- u32 data[1];
+ u32 property;
+ u8 data[];
};
struct hfi_msg_session_load_resources_done_pkt {
@@ -233,7 +234,8 @@ struct hfi_msg_session_parse_sequence_header_done_pkt {
struct hfi_msg_session_property_info_pkt {
struct hfi_session_hdr_pkt shdr;
u32 num_properties;
- u32 data[1];
+ u32 property;
+ u8 data[];
};
struct hfi_msg_session_release_resources_done_pkt {
diff --git a/drivers/media/platform/qcom/venus/hfi_platform.c b/drivers/media/platform/qcom/venus/hfi_platform.c
index 8f47804e973f..f5b4e1f4764f 100644
--- a/drivers/media/platform/qcom/venus/hfi_platform.c
+++ b/drivers/media/platform/qcom/venus/hfi_platform.c
@@ -50,6 +50,22 @@ hfi_platform_get_codec_vsp_freq(enum hfi_version version, u32 codec, u32 session
return freq;
}
+unsigned long
+hfi_platform_get_codec_lp_freq(enum hfi_version version, u32 codec, u32 session_type)
+{
+ const struct hfi_platform *plat;
+ unsigned long freq = 0;
+
+ plat = hfi_platform_get(version);
+ if (!plat)
+ return 0;
+
+ if (plat->codec_lp_freq)
+ freq = plat->codec_lp_freq(session_type, codec);
+
+ return freq;
+}
+
u8 hfi_platform_num_vpp_pipes(enum hfi_version version)
{
const struct hfi_platform *plat;
diff --git a/drivers/media/platform/qcom/venus/hfi_platform.h b/drivers/media/platform/qcom/venus/hfi_platform.h
index 3819bb2b36bd..2dbe608c53af 100644
--- a/drivers/media/platform/qcom/venus/hfi_platform.h
+++ b/drivers/media/platform/qcom/venus/hfi_platform.h
@@ -43,11 +43,13 @@ struct hfi_platform_codec_freq_data {
u32 session_type;
unsigned long vpp_freq;
unsigned long vsp_freq;
+ unsigned long low_power_freq;
};
struct hfi_platform {
unsigned long (*codec_vpp_freq)(u32 session_type, u32 codec);
unsigned long (*codec_vsp_freq)(u32 session_type, u32 codec);
+ unsigned long (*codec_lp_freq)(u32 session_type, u32 codec);
void (*codecs)(u32 *enc_codecs, u32 *dec_codecs, u32 *count);
const struct hfi_plat_caps *(*capabilities)(unsigned int *entries);
u8 (*num_vpp_pipes)(void);
@@ -63,5 +65,7 @@ unsigned long hfi_platform_get_codec_vpp_freq(enum hfi_version version, u32 code
u32 session_type);
unsigned long hfi_platform_get_codec_vsp_freq(enum hfi_version version, u32 codec,
u32 session_type);
+unsigned long hfi_platform_get_codec_lp_freq(enum hfi_version version, u32 codec,
+ u32 session_type);
u8 hfi_platform_num_vpp_pipes(enum hfi_version version);
#endif
diff --git a/drivers/media/platform/qcom/venus/hfi_platform_v4.c b/drivers/media/platform/qcom/venus/hfi_platform_v4.c
index 3848bb6d7408..3f7f5277a50e 100644
--- a/drivers/media/platform/qcom/venus/hfi_platform_v4.c
+++ b/drivers/media/platform/qcom/venus/hfi_platform_v4.c
@@ -262,14 +262,14 @@ static void get_codecs(u32 *enc_codecs, u32 *dec_codecs, u32 *count)
}
static const struct hfi_platform_codec_freq_data codec_freq_data[] = {
- { V4L2_PIX_FMT_H264, VIDC_SESSION_TYPE_ENC, 675, 10 },
- { V4L2_PIX_FMT_HEVC, VIDC_SESSION_TYPE_ENC, 675, 10 },
- { V4L2_PIX_FMT_VP8, VIDC_SESSION_TYPE_ENC, 675, 10 },
- { V4L2_PIX_FMT_MPEG2, VIDC_SESSION_TYPE_DEC, 200, 10 },
- { V4L2_PIX_FMT_H264, VIDC_SESSION_TYPE_DEC, 200, 10 },
- { V4L2_PIX_FMT_HEVC, VIDC_SESSION_TYPE_DEC, 200, 10 },
- { V4L2_PIX_FMT_VP8, VIDC_SESSION_TYPE_DEC, 200, 10 },
- { V4L2_PIX_FMT_VP9, VIDC_SESSION_TYPE_DEC, 200, 10 },
+ { V4L2_PIX_FMT_H264, VIDC_SESSION_TYPE_ENC, 675, 10, 320 },
+ { V4L2_PIX_FMT_HEVC, VIDC_SESSION_TYPE_ENC, 675, 10, 320 },
+ { V4L2_PIX_FMT_VP8, VIDC_SESSION_TYPE_ENC, 675, 10, 320 },
+ { V4L2_PIX_FMT_MPEG2, VIDC_SESSION_TYPE_DEC, 200, 10, 200 },
+ { V4L2_PIX_FMT_H264, VIDC_SESSION_TYPE_DEC, 200, 10, 200 },
+ { V4L2_PIX_FMT_HEVC, VIDC_SESSION_TYPE_DEC, 200, 10, 200 },
+ { V4L2_PIX_FMT_VP8, VIDC_SESSION_TYPE_DEC, 200, 10, 200 },
+ { V4L2_PIX_FMT_VP9, VIDC_SESSION_TYPE_DEC, 200, 10, 200 },
};
static const struct hfi_platform_codec_freq_data *
@@ -311,9 +311,21 @@ static unsigned long codec_vsp_freq(u32 session_type, u32 codec)
return 0;
}
+static unsigned long codec_lp_freq(u32 session_type, u32 codec)
+{
+ const struct hfi_platform_codec_freq_data *data;
+
+ data = get_codec_freq_data(session_type, codec);
+ if (data)
+ return data->low_power_freq;
+
+ return 0;
+}
+
const struct hfi_platform hfi_plat_v4 = {
.codec_vpp_freq = codec_vpp_freq,
.codec_vsp_freq = codec_vsp_freq,
+ .codec_lp_freq = codec_lp_freq,
.codecs = get_codecs,
.capabilities = get_capabilities,
};
diff --git a/drivers/media/platform/qcom/venus/hfi_platform_v6.c b/drivers/media/platform/qcom/venus/hfi_platform_v6.c
index dd1a03911b6c..d8243b22568a 100644
--- a/drivers/media/platform/qcom/venus/hfi_platform_v6.c
+++ b/drivers/media/platform/qcom/venus/hfi_platform_v6.c
@@ -262,14 +262,14 @@ static void get_codecs(u32 *enc_codecs, u32 *dec_codecs, u32 *count)
}
static const struct hfi_platform_codec_freq_data codec_freq_data[] = {
- { V4L2_PIX_FMT_H264, VIDC_SESSION_TYPE_ENC, 675, 25 },
- { V4L2_PIX_FMT_HEVC, VIDC_SESSION_TYPE_ENC, 675, 25 },
- { V4L2_PIX_FMT_VP8, VIDC_SESSION_TYPE_ENC, 675, 60 },
- { V4L2_PIX_FMT_MPEG2, VIDC_SESSION_TYPE_DEC, 200, 25 },
- { V4L2_PIX_FMT_H264, VIDC_SESSION_TYPE_DEC, 200, 25 },
- { V4L2_PIX_FMT_HEVC, VIDC_SESSION_TYPE_DEC, 200, 25 },
- { V4L2_PIX_FMT_VP8, VIDC_SESSION_TYPE_DEC, 200, 60 },
- { V4L2_PIX_FMT_VP9, VIDC_SESSION_TYPE_DEC, 200, 60 },
+ { V4L2_PIX_FMT_H264, VIDC_SESSION_TYPE_ENC, 675, 25, 320 },
+ { V4L2_PIX_FMT_HEVC, VIDC_SESSION_TYPE_ENC, 675, 25, 320 },
+ { V4L2_PIX_FMT_VP8, VIDC_SESSION_TYPE_ENC, 675, 60, 320 },
+ { V4L2_PIX_FMT_MPEG2, VIDC_SESSION_TYPE_DEC, 200, 25, 200 },
+ { V4L2_PIX_FMT_H264, VIDC_SESSION_TYPE_DEC, 200, 25, 200 },
+ { V4L2_PIX_FMT_HEVC, VIDC_SESSION_TYPE_DEC, 200, 25, 200 },
+ { V4L2_PIX_FMT_VP8, VIDC_SESSION_TYPE_DEC, 200, 60, 200 },
+ { V4L2_PIX_FMT_VP9, VIDC_SESSION_TYPE_DEC, 200, 60, 200 },
};
static const struct hfi_platform_codec_freq_data *
@@ -311,6 +311,17 @@ static unsigned long codec_vsp_freq(u32 session_type, u32 codec)
return 0;
}
+static unsigned long codec_lp_freq(u32 session_type, u32 codec)
+{
+ const struct hfi_platform_codec_freq_data *data;
+
+ data = get_codec_freq_data(session_type, codec);
+ if (data)
+ return data->low_power_freq;
+
+ return 0;
+}
+
static u8 num_vpp_pipes(void)
{
return 4;
@@ -319,6 +330,7 @@ static u8 num_vpp_pipes(void)
const struct hfi_platform hfi_plat_v6 = {
.codec_vpp_freq = codec_vpp_freq,
.codec_vsp_freq = codec_vsp_freq,
+ .codec_lp_freq = codec_lp_freq,
.codecs = get_codecs,
.capabilities = get_capabilities,
.num_vpp_pipes = num_vpp_pipes,
diff --git a/drivers/media/platform/qcom/venus/pm_helpers.c b/drivers/media/platform/qcom/venus/pm_helpers.c
index c7e1ebec47ee..3e2345eb47f7 100644
--- a/drivers/media/platform/qcom/venus/pm_helpers.c
+++ b/drivers/media/platform/qcom/venus/pm_helpers.c
@@ -300,16 +300,15 @@ static int core_get_v1(struct venus_core *core)
if (ret)
return ret;
- core->opp_table = dev_pm_opp_set_clkname(core->dev, "core");
- if (IS_ERR(core->opp_table))
- return PTR_ERR(core->opp_table);
+ ret = devm_pm_opp_set_clkname(core->dev, "core");
+ if (ret)
+ return ret;
return 0;
}
static void core_put_v1(struct venus_core *core)
{
- dev_pm_opp_put_clkname(core->opp_table);
}
static int core_power_v1(struct venus_core *core, int on)
@@ -524,8 +523,50 @@ static int poweron_coreid(struct venus_core *core, unsigned int coreid_mask)
return 0;
}
+static inline int power_save_mode_enable(struct venus_inst *inst,
+ bool enable)
+{
+ struct venc_controls *enc_ctr = &inst->controls.enc;
+ const u32 ptype = HFI_PROPERTY_CONFIG_VENC_PERF_MODE;
+ u32 venc_mode;
+ int ret = 0;
+
+ if (inst->session_type != VIDC_SESSION_TYPE_ENC)
+ return 0;
+
+ if (enc_ctr->bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CQ)
+ enable = false;
+
+ venc_mode = enable ? HFI_VENC_PERFMODE_POWER_SAVE :
+ HFI_VENC_PERFMODE_MAX_QUALITY;
+
+ ret = hfi_session_set_property(inst, ptype, &venc_mode);
+ if (ret)
+ return ret;
+
+ inst->flags = enable ? inst->flags | VENUS_LOW_POWER :
+ inst->flags & ~VENUS_LOW_POWER;
+
+ return ret;
+}
+
+static int move_core_to_power_save_mode(struct venus_core *core,
+ u32 core_id)
+{
+ struct venus_inst *inst = NULL;
+
+ mutex_lock(&core->lock);
+ list_for_each_entry(inst, &core->instances, list) {
+ if (inst->clk_data.core_id == core_id &&
+ inst->session_type == VIDC_SESSION_TYPE_ENC)
+ power_save_mode_enable(inst, true);
+ }
+ mutex_unlock(&core->lock);
+ return 0;
+}
+
static void
-min_loaded_core(struct venus_inst *inst, u32 *min_coreid, u32 *min_load)
+min_loaded_core(struct venus_inst *inst, u32 *min_coreid, u32 *min_load, bool low_power)
{
u32 mbs_per_sec, load, core1_load = 0, core2_load = 0;
u32 cores_max = core_num_max(inst);
@@ -543,7 +584,14 @@ min_loaded_core(struct venus_inst *inst, u32 *min_coreid, u32 *min_load)
if (inst_pos->state != INST_START)
continue;
- vpp_freq = inst_pos->clk_data.vpp_freq;
+ if (inst->session_type == VIDC_SESSION_TYPE_DEC)
+ vpp_freq = inst_pos->clk_data.vpp_freq;
+ else if (inst->session_type == VIDC_SESSION_TYPE_ENC)
+ vpp_freq = low_power ? inst_pos->clk_data.vpp_freq :
+ inst_pos->clk_data.low_power_freq;
+ else
+ continue;
+
coreid = inst_pos->clk_data.core_id;
mbs_per_sec = load_per_instance(inst_pos);
@@ -575,9 +623,11 @@ static int decide_core(struct venus_inst *inst)
{
const u32 ptype = HFI_PROPERTY_CONFIG_VIDEOCORES_USAGE;
struct venus_core *core = inst->core;
- u32 min_coreid, min_load, inst_load;
+ u32 min_coreid, min_load, cur_inst_load;
+ u32 min_lp_coreid, min_lp_load, cur_inst_lp_load;
struct hfi_videocores_usage_type cu;
unsigned long max_freq;
+ int ret = 0;
if (legacy_binding) {
if (inst->session_type == VIDC_SESSION_TYPE_DEC)
@@ -591,23 +641,43 @@ static int decide_core(struct venus_inst *inst)
if (inst->clk_data.core_id != VIDC_CORE_ID_DEFAULT)
return 0;
- inst_load = load_per_instance(inst);
- inst_load *= inst->clk_data.vpp_freq;
- max_freq = core->res->freq_tbl[0].freq;
+ cur_inst_load = load_per_instance(inst);
+ cur_inst_load *= inst->clk_data.vpp_freq;
+ /*TODO : divide this inst->load by work_route */
- min_loaded_core(inst, &min_coreid, &min_load);
+ cur_inst_lp_load = load_per_instance(inst);
+ cur_inst_lp_load *= inst->clk_data.low_power_freq;
+ /*TODO : divide this inst->load by work_route */
- if ((inst_load + min_load) > max_freq) {
- dev_warn(core->dev, "HW is overloaded, needed: %u max: %lu\n",
- inst_load, max_freq);
+ max_freq = core->res->freq_tbl[0].freq;
+
+ min_loaded_core(inst, &min_coreid, &min_load, false);
+ min_loaded_core(inst, &min_lp_coreid, &min_lp_load, true);
+
+ if (cur_inst_load + min_load <= max_freq) {
+ inst->clk_data.core_id = min_coreid;
+ cu.video_core_enable_mask = min_coreid;
+ } else if (cur_inst_lp_load + min_load <= max_freq) {
+ /* Move current instance to LP and return */
+ inst->clk_data.core_id = min_coreid;
+ cu.video_core_enable_mask = min_coreid;
+ power_save_mode_enable(inst, true);
+ } else if (cur_inst_lp_load + min_lp_load <= max_freq) {
+ /* Move all instances to LP mode and return */
+ inst->clk_data.core_id = min_lp_coreid;
+ cu.video_core_enable_mask = min_lp_coreid;
+ move_core_to_power_save_mode(core, min_lp_coreid);
+ } else {
+ dev_warn(core->dev, "HW can't support this load");
return -EINVAL;
}
- inst->clk_data.core_id = min_coreid;
- cu.video_core_enable_mask = min_coreid;
-
done:
- return hfi_session_set_property(inst, ptype, &cu);
+ ret = hfi_session_set_property(inst, ptype, &cu);
+ if (ret)
+ return ret;
+
+ return ret;
}
static int acquire_core(struct venus_inst *inst)
@@ -788,7 +858,6 @@ static int venc_power_v4(struct device *dev, int on)
static int vcodec_domains_get(struct venus_core *core)
{
int ret;
- struct opp_table *opp_table;
struct device **opp_virt_dev;
struct device *dev = core->dev;
const struct venus_resources *res = core->res;
@@ -811,11 +880,9 @@ skip_pmdomains:
return 0;
/* Attach the power domain for setting performance state */
- opp_table = dev_pm_opp_attach_genpd(dev, res->opp_pmdomain, &opp_virt_dev);
- if (IS_ERR(opp_table)) {
- ret = PTR_ERR(opp_table);
+ ret = devm_pm_opp_attach_genpd(dev, res->opp_pmdomain, &opp_virt_dev);
+ if (ret)
goto opp_attach_err;
- }
core->opp_pmdomain = *opp_virt_dev;
core->opp_dl_venus = device_link_add(dev, core->opp_pmdomain,
@@ -824,13 +891,11 @@ skip_pmdomains:
DL_FLAG_STATELESS);
if (!core->opp_dl_venus) {
ret = -ENODEV;
- goto opp_dl_add_err;
+ goto opp_attach_err;
}
return 0;
-opp_dl_add_err:
- dev_pm_opp_detach_genpd(core->opp_table);
opp_attach_err:
for (i = 0; i < res->vcodec_pmdomains_num; i++) {
if (IS_ERR_OR_NULL(core->pmdomains[i]))
@@ -861,8 +926,6 @@ skip_pmdomains:
if (core->opp_dl_venus)
device_link_del(core->opp_dl_venus);
-
- dev_pm_opp_detach_genpd(core->opp_table);
}
static int core_resets_reset(struct venus_core *core)
@@ -941,45 +1004,33 @@ static int core_get_v4(struct venus_core *core)
if (legacy_binding)
return 0;
- core->opp_table = dev_pm_opp_set_clkname(dev, "core");
- if (IS_ERR(core->opp_table))
- return PTR_ERR(core->opp_table);
+ ret = devm_pm_opp_set_clkname(dev, "core");
+ if (ret)
+ return ret;
if (core->res->opp_pmdomain) {
- ret = dev_pm_opp_of_add_table(dev);
+ ret = devm_pm_opp_of_add_table(dev);
if (!ret) {
core->has_opp_table = true;
} else if (ret != -ENODEV) {
dev_err(dev, "invalid OPP table in device tree\n");
- dev_pm_opp_put_clkname(core->opp_table);
return ret;
}
}
ret = vcodec_domains_get(core);
- if (ret) {
- if (core->has_opp_table)
- dev_pm_opp_of_remove_table(dev);
- dev_pm_opp_put_clkname(core->opp_table);
+ if (ret)
return ret;
- }
return 0;
}
static void core_put_v4(struct venus_core *core)
{
- struct device *dev = core->dev;
-
if (legacy_binding)
return;
vcodec_domains_put(core);
-
- if (core->has_opp_table)
- dev_pm_opp_of_remove_table(dev);
- dev_pm_opp_put_clkname(core->opp_table);
-
}
static int core_power_v4(struct venus_core *core, int on)
@@ -990,9 +1041,8 @@ static int core_power_v4(struct venus_core *core, int on)
if (on == POWER_ON) {
if (pmctrl) {
- ret = pm_runtime_get_sync(pmctrl);
+ ret = pm_runtime_resume_and_get(pmctrl);
if (ret < 0) {
- pm_runtime_put_noidle(pmctrl);
return ret;
}
}
@@ -1026,7 +1076,7 @@ static int core_power_v4(struct venus_core *core, int on)
static unsigned long calculate_inst_freq(struct venus_inst *inst,
unsigned long filled_len)
{
- unsigned long vpp_freq = 0, vsp_freq = 0;
+ unsigned long vpp_freq_per_mb = 0, vpp_freq = 0, vsp_freq = 0;
u32 fps = (u32)inst->fps;
u32 mbs_per_sec;
@@ -1035,7 +1085,12 @@ static unsigned long calculate_inst_freq(struct venus_inst *inst,
if (inst->state != INST_START)
return 0;
- vpp_freq = mbs_per_sec * inst->clk_data.vpp_freq;
+ if (inst->session_type == VIDC_SESSION_TYPE_ENC)
+ vpp_freq_per_mb = inst->flags & VENUS_LOW_POWER ?
+ inst->clk_data.low_power_freq :
+ inst->clk_data.vpp_freq;
+
+ vpp_freq = mbs_per_sec * vpp_freq_per_mb;
/* 21 / 20 is overhead factor */
vpp_freq += vpp_freq / 20;
vsp_freq = mbs_per_sec * inst->clk_data.vsp_freq;
diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c
index ddb7cd39424e..198e47eb63f4 100644
--- a/drivers/media/platform/qcom/venus/vdec.c
+++ b/drivers/media/platform/qcom/venus/vdec.c
@@ -568,10 +568,10 @@ static int vdec_pm_get(struct venus_inst *inst)
int ret;
mutex_lock(&core->pm_lock);
- ret = pm_runtime_get_sync(dev);
+ ret = pm_runtime_resume_and_get(dev);
mutex_unlock(&core->pm_lock);
- return ret < 0 ? ret : 0;
+ return ret;
}
static int vdec_pm_put(struct venus_inst *inst, bool autosuspend)
@@ -601,7 +601,7 @@ static int vdec_pm_get_put(struct venus_inst *inst)
mutex_lock(&core->pm_lock);
if (pm_runtime_suspended(dev)) {
- ret = pm_runtime_get_sync(dev);
+ ret = pm_runtime_resume_and_get(dev);
if (ret < 0)
goto error;
diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c
index 4a7291f934b6..8dd49d4f124c 100644
--- a/drivers/media/platform/qcom/venus/venc.c
+++ b/drivers/media/platform/qcom/venus/venc.c
@@ -1205,9 +1205,9 @@ static int venc_open(struct file *file)
venus_helper_init_instance(inst);
- ret = pm_runtime_get_sync(core->dev_enc);
+ ret = pm_runtime_resume_and_get(core->dev_enc);
if (ret < 0)
- goto err_put_sync;
+ goto err_free;
ret = venc_ctrl_init(inst);
if (ret)
@@ -1252,6 +1252,7 @@ err_ctrl_deinit:
venc_ctrl_deinit(inst);
err_put_sync:
pm_runtime_put_sync(core->dev_enc);
+err_free:
kfree(inst);
return ret;
}