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;
