diff mbox series

[v2,34/34] media: iris: add power management for encoder

Message ID 1702899149-21321-35-git-send-email-quic_dikshita@quicinc.com (mailing list archive)
State Not Applicable
Headers show
Series Qualcomm video encoder and decoder driver | expand

Commit Message

Dikshita Agarwal Dec. 18, 2023, 11:32 a.m. UTC
Hardware specific power sequence include programming specific
sequence of registers. Implements this sequence for iris3.

Also, implement iris3 Encoder specific calculation for clock
and bus bandwidth which depends on hardware configuration,
codec format, resolution and frame rate.

Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
---
 .../media/platform/qcom/vcodec/iris/iris_ctrls.c   |   2 +
 .../media/platform/qcom/vcodec/iris/iris_power.c   |  15 ++--
 .../platform/qcom/vcodec/iris/platform_common.h    |   3 +
 .../platform/qcom/vcodec/iris/platform_sm8550.c    |  14 +++
 .../platform/qcom/vcodec/iris/vpu_iris3_power.c    | 100 +++++++++++++++------
 5 files changed, 103 insertions(+), 31 deletions(-)

Comments

Konrad Dybcio Dec. 19, 2023, 12:26 p.m. UTC | #1
On 18.12.2023 12:32, Dikshita Agarwal wrote:
> Hardware specific power sequence include programming specific
> sequence of registers. Implements this sequence for iris3.
> 
> Also, implement iris3 Encoder specific calculation for clock
> and bus bandwidth which depends on hardware configuration,
> codec format, resolution and frame rate.
> 
> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
> ---
[...]

> +static const struct bw_info sm8550_bw_table_enc[] = {
> +	{ 1944000, 1491000, 2693000 },	/* 3840x2160@60 */
> +	{  972000,  765000, 1366000 },	/* 3840x2160@30 */
> +	{  489600,  557000, 780000 },	/* 1920x1080@60 */
> +	{  244800,  288000, 399000 },	/* 1920x1080@30 */
> +};
can this be calculated at runtime by chance?

Konrad
diff mbox series

Patch

diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_ctrls.c b/drivers/media/platform/qcom/vcodec/iris/iris_ctrls.c
index 559b0dd..1a2e305 100644
--- a/drivers/media/platform/qcom/vcodec/iris/iris_ctrls.c
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_ctrls.c
@@ -799,6 +799,8 @@  int decide_quality_mode(struct iris_inst *inst)
 	if (mbpf <= max_hq_mbpf && mbps <= max_hq_mbps)
 		mode = MAX_QUALITY_MODE;
 
+	inst->cap[QUALITY_MODE].value = mode;
+
 	return mode;
 }
 
diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_power.c b/drivers/media/platform/qcom/vcodec/iris/iris_power.c
index 77439e3..be71751 100644
--- a/drivers/media/platform/qcom/vcodec/iris/iris_power.c
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_power.c
@@ -48,11 +48,16 @@  static int iris_vote_buses(struct iris_inst *inst)
 	vote_data->height = inp_f->fmt.pix_mp.height;
 	vote_data->fps = inst->max_rate;
 
-	if (is_linear_colorformat(out_f->fmt.pix_mp.pixelformat)) {
-		vote_data->color_formats[0] = V4L2_PIX_FMT_NV12;
-		vote_data->color_formats[1] = out_f->fmt.pix_mp.pixelformat;
-	} else {
-		vote_data->color_formats[0] = out_f->fmt.pix_mp.pixelformat;
+	if (inst->domain == ENCODER) {
+		vote_data->color_formats[0] =
+			v4l2_colorformat_to_driver(inst, inst->fmt_src->fmt.pix_mp.pixelformat);
+	} else if (inst->domain == DECODER) {
+		if (is_linear_colorformat(out_f->fmt.pix_mp.pixelformat)) {
+			vote_data->color_formats[0] = V4L2_PIX_FMT_NV12;
+			vote_data->color_formats[1] = out_f->fmt.pix_mp.pixelformat;
+		} else {
+			vote_data->color_formats[0] = out_f->fmt.pix_mp.pixelformat;
+		}
 	}
 
 	call_session_op(core, calc_bw, inst, vote_data);
diff --git a/drivers/media/platform/qcom/vcodec/iris/platform_common.h b/drivers/media/platform/qcom/vcodec/iris/platform_common.h
index 42ac662..e9b5c99 100644
--- a/drivers/media/platform/qcom/vcodec/iris/platform_common.h
+++ b/drivers/media/platform/qcom/vcodec/iris/platform_common.h
@@ -174,6 +174,7 @@  enum plat_inst_cap_type {
 	INPUT_BUF_HOST_MAX_COUNT,
 	STAGE,
 	PIPE,
+	QUALITY_MODE,
 	POC,
 	CODED_FRAMES,
 	BIT_DEPTH,
@@ -279,6 +280,8 @@  struct format_capability {
 struct platform_data {
 	const struct bus_info *bus_tbl;
 	unsigned int bus_tbl_size;
+	const struct bw_info *bw_tbl_enc;
+	unsigned int bw_tbl_enc_size;
 	const struct bw_info *bw_tbl_dec;
 	unsigned int bw_tbl_dec_size;
 	const char * const *pd_tbl;
diff --git a/drivers/media/platform/qcom/vcodec/iris/platform_sm8550.c b/drivers/media/platform/qcom/vcodec/iris/platform_sm8550.c
index 17c5856..d47c985 100644
--- a/drivers/media/platform/qcom/vcodec/iris/platform_sm8550.c
+++ b/drivers/media/platform/qcom/vcodec/iris/platform_sm8550.c
@@ -1005,6 +1005,11 @@  static struct plat_inst_cap instance_cap_data_sm8550[] = {
 		NULL,
 		set_pipe},
 
+	{QUALITY_MODE, ENC, CODECS_ALL,
+		MAX_QUALITY_MODE,
+		POWER_SAVE_MODE, 1,
+		POWER_SAVE_MODE},
+
 	{POC, DEC, H264, 0, 2, 1, 1,
 		0,
 		HFI_PROP_PIC_ORDER_CNT_TYPE},
@@ -1051,6 +1056,13 @@  static const char * const sm8550_pd_table[] = { "iris-ctl", "vcodec", NULL };
 
 static const char * const sm8550_opp_pd_table[] = { "mxc", "mmcx", NULL };
 
+static const struct bw_info sm8550_bw_table_enc[] = {
+	{ 1944000, 1491000, 2693000 },	/* 3840x2160@60 */
+	{  972000,  765000, 1366000 },	/* 3840x2160@30 */
+	{  489600,  557000, 780000 },	/* 1920x1080@60 */
+	{  244800,  288000, 399000 },	/* 1920x1080@30 */
+};
+
 static const struct bw_info sm8550_bw_table_dec[] = {
 	{ 2073600, 1608000, 2742000 },	/* 4096x2160@60 */
 	{ 1036800,  826000, 1393000 },	/* 4096x2160@30 */
@@ -1133,6 +1145,8 @@  struct platform_data sm8550_data = {
 	.clk_rst_tbl = sm8550_clk_reset_table,
 	.clk_rst_tbl_size = ARRAY_SIZE(sm8550_clk_reset_table),
 
+	.bw_tbl_enc = sm8550_bw_table_enc,
+	.bw_tbl_enc_size = ARRAY_SIZE(sm8550_bw_table_enc),
 	.bw_tbl_dec = sm8550_bw_table_dec,
 	.bw_tbl_dec_size = ARRAY_SIZE(sm8550_bw_table_dec),
 
diff --git a/drivers/media/platform/qcom/vcodec/iris/vpu_iris3_power.c b/drivers/media/platform/qcom/vcodec/iris/vpu_iris3_power.c
index 2828227..8497b84 100644
--- a/drivers/media/platform/qcom/vcodec/iris/vpu_iris3_power.c
+++ b/drivers/media/platform/qcom/vcodec/iris/vpu_iris3_power.c
@@ -11,12 +11,13 @@ 
 
 u64 iris_calc_freq_iris3(struct iris_inst *inst, u32 data_size)
 {
+	u32 operating_rate, vsp_factor_num = 1, vsp_factor_den = 1;
 	u64 vsp_cycles = 0, vpp_cycles = 0, fw_cycles = 0;
 	u64 fw_vpp_cycles = 0, bitrate = 0, freq = 0;
+	u32 vpp_cycles_per_mb, mbs_per_second;
 	u32 base_cycles = 0, fps, mbpf;
 	u32 height = 0, width = 0;
 	struct v4l2_format *inp_f;
-	u32 mbs_per_second;
 
 	inp_f = inst->fmt_src;
 	width = max(inp_f->fmt.pix_mp.width, inst->crop.width);
@@ -29,32 +30,74 @@  u64 iris_calc_freq_iris3(struct iris_inst *inst, u32 data_size)
 	fw_cycles = fps * inst->cap[MB_CYCLES_FW].value;
 	fw_vpp_cycles = fps * inst->cap[MB_CYCLES_FW_VPP].value;
 
-	vpp_cycles = mbs_per_second * inst->cap[MB_CYCLES_VPP].value /
-		inst->cap[PIPE].value;
-	vpp_cycles += max(vpp_cycles / 20, fw_vpp_cycles);
-
-	if (inst->cap[PIPE].value > 1)
-		vpp_cycles += div_u64(vpp_cycles * 59, 1000);
-
-	base_cycles = inst->cap[MB_CYCLES_VSP].value;
-	bitrate = fps * data_size * 8;
-	vsp_cycles = bitrate;
-
-	if (inst->codec == VP9) {
-		vsp_cycles = div_u64(vsp_cycles * 170, 100);
-	} else if (inst->cap[ENTROPY_MODE].value ==
-		V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC) {
-		vsp_cycles = div_u64(vsp_cycles * 135, 100);
-	} else {
-		base_cycles = 0;
-		vsp_cycles = div_u64(vsp_cycles, 2);
-	}
-	vsp_cycles = div_u64(vsp_cycles * 21, 20);
+	if (inst->domain == ENCODER) {
+		vpp_cycles_per_mb =
+			inst->cap[QUALITY_MODE].value == POWER_SAVE_MODE ?
+			inst->cap[MB_CYCLES_LP].value :
+			inst->cap[MB_CYCLES_VPP].value;
+
+		vpp_cycles = mbs_per_second * vpp_cycles_per_mb / inst->cap[PIPE].value;
+
+		if (inst->cap[B_FRAME].value > 1)
+			vpp_cycles += (vpp_cycles / 4) + (vpp_cycles / 8);
+		else if (inst->cap[B_FRAME].value)
+			vpp_cycles += vpp_cycles / 4;
+
+		vpp_cycles += max(div_u64(vpp_cycles, 20), fw_vpp_cycles);
+		if (inst->cap[PIPE].value > 1)
+			vpp_cycles += div_u64(vpp_cycles, 100);
+
+		operating_rate = inst->cap[OPERATING_RATE].value >> 16;
+		if (operating_rate > (inst->cap[FRAME_RATE].value >> 16) &&
+		    (inst->cap[FRAME_RATE].value >> 16)) {
+			vsp_factor_num = operating_rate;
+			vsp_factor_den = inst->cap[FRAME_RATE].value >> 16;
+		}
+		vsp_cycles = div_u64(((u64)inst->cap[BIT_RATE].value * vsp_factor_num),
+				     vsp_factor_den);
+
+		base_cycles = inst->cap[MB_CYCLES_VSP].value;
+		if (inst->cap[ENTROPY_MODE].value ==
+			V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC) {
+			vsp_cycles = div_u64(vsp_cycles * 135, 100);
+		} else {
+			base_cycles = 0;
+			vsp_cycles = div_u64(vsp_cycles, 2);
+		}
+		vsp_cycles = div_u64(vsp_cycles * 21, 20);
+
+		if (inst->cap[STAGE].value == STAGE_1)
+			vsp_cycles = vsp_cycles * 3;
 
-	if (inst->cap[STAGE].value == STAGE_1)
-		vsp_cycles = vsp_cycles * 3;
+		vsp_cycles += mbs_per_second * base_cycles;
+	} else if (inst->domain == DECODER) {
+		vpp_cycles = mbs_per_second * inst->cap[MB_CYCLES_VPP].value /
+			inst->cap[PIPE].value;
+		vpp_cycles += max(vpp_cycles / 20, fw_vpp_cycles);
+
+		if (inst->cap[PIPE].value > 1)
+			vpp_cycles += div_u64(vpp_cycles * 59, 1000);
+
+		base_cycles = inst->cap[MB_CYCLES_VSP].value;
+		bitrate = fps * data_size * 8;
+		vsp_cycles = bitrate;
+
+		if (inst->codec == VP9) {
+			vsp_cycles = div_u64(vsp_cycles * 170, 100);
+		} else if (inst->cap[ENTROPY_MODE].value ==
+				V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC) {
+			vsp_cycles = div_u64(vsp_cycles * 135, 100);
+		} else {
+			base_cycles = 0;
+			vsp_cycles = div_u64(vsp_cycles, 2);
+		}
+		vsp_cycles = div_u64(vsp_cycles * 21, 20);
+
+		if (inst->cap[STAGE].value == STAGE_1)
+			vsp_cycles = vsp_cycles * 3;
 
 		vsp_cycles += mbs_per_second * base_cycles;
+	}
 
 	freq = max3(vpp_cycles, vsp_cycles, fw_cycles);
 
@@ -78,8 +121,13 @@  int iris_calc_bw_iris3(struct iris_inst *inst, struct bus_vote_data *data)
 	if (mbps == 0)
 		return 0;
 
-	bw_tbl = core->platform_data->bw_tbl_dec;
-	num_rows = core->platform_data->bw_tbl_dec_size;
+	if (inst->domain == DECODER) {
+		bw_tbl = core->platform_data->bw_tbl_dec;
+		num_rows = core->platform_data->bw_tbl_dec_size;
+	} else if (inst->domain == ENCODER) {
+		bw_tbl = core->platform_data->bw_tbl_enc;
+		num_rows = core->platform_data->bw_tbl_enc_size;
+	}
 
 	if (!bw_tbl || num_rows == 0)
 		return 0;