Skip to content

Commit

Permalink
media: venus: Enable low power setting for encoder
Browse files Browse the repository at this point in the history
Set the FW to run in low power for encoder
to accommodate more session without losing much on quality.

Signed-off-by: Dikshita Agarwal <dikshita@codeaurora.org>
Signed-off-by: Stanimir Varbanov <stanimir.varbanov@linaro.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
  • Loading branch information
Dikshita Agarwal authored and mchehab committed Jun 2, 2021
1 parent 51bb398 commit 3cfe581
Show file tree
Hide file tree
Showing 8 changed files with 167 additions and 35 deletions.
6 changes: 6 additions & 0 deletions drivers/media/platform/qcom/venus/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -292,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)
Expand All @@ -315,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
*
Expand Down Expand Up @@ -444,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)
Expand Down
2 changes: 2 additions & 0 deletions drivers/media/platform/qcom/venus/helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -1627,6 +1627,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;
}
Expand Down
10 changes: 7 additions & 3 deletions drivers/media/platform/qcom/venus/hfi_helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
16 changes: 16 additions & 0 deletions drivers/media/platform/qcom/venus/hfi_platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 4 additions & 0 deletions drivers/media/platform/qcom/venus/hfi_platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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
28 changes: 20 additions & 8 deletions drivers/media/platform/qcom/venus/hfi_platform_v4.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 *
Expand Down Expand Up @@ -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,
};
28 changes: 20 additions & 8 deletions drivers/media/platform/qcom/venus/hfi_platform_v6.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 *
Expand Down Expand Up @@ -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;
Expand All @@ -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,
Expand Down
108 changes: 92 additions & 16 deletions drivers/media/platform/qcom/venus/pm_helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -523,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);
Expand All @@ -542,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);
Expand Down Expand Up @@ -574,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)
Expand All @@ -590,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)
Expand Down Expand Up @@ -1005,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;

Expand All @@ -1014,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;
Expand Down

0 comments on commit 3cfe581

Please sign in to comment.