msm: vidc: Add support for runtime input CR

Clients send input buffer Compression Ratio through V4L2
buffer. Driver makes use of it while voting for bus BW.

CRs-Fixed: 2012520
Change-Id: I88da9396e98c2e081d1e16c3b1445b14c0ad4528
Signed-off-by: Praneeth Paladugu <ppaladug@codeaurora.org>
diff --git a/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c b/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c
index a7b1852..1eaec58 100644
--- a/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c
+++ b/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c
@@ -565,32 +565,21 @@
 	 */
 	/* Encoder Parameters */
 
-	enum hal_video_codec standard;
-	int width, height, fps;
-	enum hal_uncompressed_format dpb_color_format;
-	enum hal_uncompressed_format original_color_format;
+	int width, height, fps, dpb_bpp, lcu_per_frame, lcu_size,
+		vertical_tile_width, colocated_bytes_per_lcu, bitrate,
+		ref_overlap_bw_factor;
+	enum hal_uncompressed_format dpb_color_format, original_color_format;
 	bool dpb_compression_enabled, original_compression_enabled,
-		two_stage_encoding, low_power, rotation, cropping_or_scaling;
+		work_mode_1, low_power, rotation, cropping_or_scaling,
+		b_frames_enabled = false;
 	fp_t dpb_compression_factor, original_compression_factor,
-		qsmmu_bw_overhead_factor;
-	bool b_frames_enabled;
-
-	/* Derived Parameters */
-	int lcu_size;
-	enum gop {
-		GOP_IBBP,
-		GOP_IPPP,
-	} gop;
-	unsigned long bitrate;
-	fp_t bins_to_bit_factor, chroma_luma_factor_dpb, one_frame_bw_dpb,
-		 chroma_luma_factor_original, one_frame_bw_original,
-		 line_buffer_size_per_lcu, line_buffer_size, line_buffer_bw,
-		 bw_increase_p, bw_increase_b;
-	int collocated_mv_per_lcu, max_transaction_size,
-		search_window_size_vertical_p, search_window_factor_p,
-		search_window_factor_bw_p,
-		search_window_size_vertical_b, search_window_factor_b,
-		search_window_factor_bw_b;
+		input_compression_factor, qsmmu_bw_overhead_factor,
+		ref_y_bw_factor, ref_cb_cr_bw_factor, ten_bpc_bpp_factor,
+		bw_for_1x_8bpc, dpb_bw_for_1x, ref_cb_cr_read,
+		bins_to_bit_factor, ref_y_read,	ten_bpc_packing_factor,
+		dpb_write_factor, ref_overlap_bw;
+	fp_t integer_part, frac_part;
+	unsigned long ret = 0;
 
 	/* Output paramaters */
 	struct {
@@ -599,27 +588,41 @@
 			original_write, dpb_read, dpb_write, total;
 	} ddr = {0};
 
-	unsigned long ret = 0;
-	fp_t integer_part, frac_part;
 
 	/* Encoder Parameters setup */
+	ten_bpc_packing_factor = FP(1, 67, 1000);
+	ten_bpc_bpp_factor = FP(1, 1, 4);
+	rotation = false;
+	cropping_or_scaling = false;
+	vertical_tile_width = 960;
+	ref_y_bw_factor = FP(1, 30, 100);
+	ref_cb_cr_bw_factor = FP(1, 50, 100);
+	dpb_write_factor = FP(1, 8, 100);
 
-	standard = d->codec;
+
+	/* Derived Parameters */
+	lcu_size = d->lcu_size;
+	fps = d->fps;
+	b_frames_enabled = d->b_frames_enabled;
 	width = max(d->input_width, BASELINE_DIMENSIONS.width);
 	height = max(d->input_height, BASELINE_DIMENSIONS.height);
+	bitrate = __lut(width, height, fps)->bitrate;
+	lcu_per_frame = DIV_ROUND_UP(width, lcu_size) *
+		DIV_ROUND_UP(height, lcu_size);
 
 	dpb_color_format = HAL_COLOR_FORMAT_NV12_UBWC;
 	original_color_format = d->num_formats >= 1 ?
 		d->color_formats[0] : HAL_UNUSED_COLOR;
 
-	fps = d->fps;
+	dpb_bpp = d->num_formats >= 1 ? __bpp(d->color_formats[0]) : INT_MAX;
 
 	dpb_compression_enabled = __ubwc(dpb_color_format);
 	original_compression_enabled = __ubwc(original_color_format);
 
-	two_stage_encoding = false;
+	work_mode_1 = d->work_mode == VIDC_WORK_MODE_1;
 	low_power = d->power_mode == VIDC_POWER_LOW;
-	b_frames_enabled = false;
+	bins_to_bit_factor = work_mode_1 ?
+		FP_INT(0) : FP_INT(4);
 
 	/*
 	 * Convert Q16 number into Integer and Fractional part upto 2 places.
@@ -636,96 +639,84 @@
 
 	dpb_compression_factor = FP(integer_part, frac_part, 100);
 
-	original_compression_factor = dpb_compression_factor;
+	integer_part = d->input_cr >> 16;
+	frac_part =
+		((d->input_cr - (integer_part * 65536)) * 100) >> 16;
 
-	rotation = false;
-	cropping_or_scaling = false;
+	input_compression_factor = FP(integer_part, frac_part, 100);
 
-	/* Derived Parameters */
-	lcu_size = 16;
-	gop = b_frames_enabled ? GOP_IBBP : GOP_IPPP;
-	bitrate = __lut(width, height, fps)->bitrate;
-	bins_to_bit_factor = FP(1, 6, 10);
+	original_compression_factor =
+		original_compression_enabled ? d->use_dpb_read ?
+			dpb_compression_factor : input_compression_factor :
+		FP_ONE;
 
-	/*
-	 * FIXME: Minor color format related hack: a lot of the derived params
-	 * depend on the YUV bitdepth as a variable.  However, we don't have
-	 * appropriate enums defined yet (hence no support).  As a result omit
-	 * a lot of the checks (which should look like the snippet below) in
-	 * favour of hardcoding.
-	 *      dpb_color_format == YUV420 ? 0.5 :
-	 *      dpb_color_format == YUV422 ? 1.0 : 2.0
-	 * Similar hacks are annotated inline in code with the string "CF hack"
-	 * for documentation purposes.
-	 */
-	chroma_luma_factor_dpb = FP(0, 1, 2);
-	one_frame_bw_dpb = fp_mult(FP_ONE + chroma_luma_factor_dpb,
-			fp_div(FP_INT(width * height * fps),
-				FP_INT(1000 * 1000)));
-
-	chroma_luma_factor_original = FP(0, 1, 2); /* XXX: CF hack */
-	one_frame_bw_original = fp_mult(FP_ONE + chroma_luma_factor_original,
-			fp_div(FP_INT(width * height * fps),
-				FP_INT(1000 * 1000)));
-
-	line_buffer_size_per_lcu = FP_ZERO;
-	if (lcu_size == 16)
-		line_buffer_size_per_lcu = FP_INT(128) + fp_mult(FP_INT(256),
-					FP_ONE /*XXX: CF hack */);
-	else
-		line_buffer_size_per_lcu = FP_INT(192) + fp_mult(FP_INT(512),
-					FP_ONE /*XXX: CF hack */);
-
-	line_buffer_size = fp_div(
-			fp_mult(FP_INT(width / lcu_size),
-				line_buffer_size_per_lcu),
-			FP_INT(1024));
-	line_buffer_bw = fp_mult(line_buffer_size,
-			fp_div(FP_INT((height / lcu_size /
-				(two_stage_encoding ? 2 : 1) - 1) * fps),
-				FP_INT(1000)));
-
-	collocated_mv_per_lcu = lcu_size == 16 ? 16 : 64;
-	max_transaction_size = 256;
-
-	search_window_size_vertical_p = low_power ? 32 :
-					b_frames_enabled ? 80 :
-					width > 2048 ? 64 : 48;
-	search_window_factor_p = search_window_size_vertical_p * 2 / lcu_size;
-	search_window_factor_bw_p = !two_stage_encoding ?
-		search_window_size_vertical_p * 2 / lcu_size + 1 :
-		(search_window_size_vertical_p * 2 / lcu_size + 2) / 2;
-	bw_increase_p = fp_mult(one_frame_bw_dpb,
-			FP_INT(search_window_factor_bw_p - 1) / 3);
-
-	search_window_size_vertical_b = 48;
-	search_window_factor_b = search_window_size_vertical_b * 2 / lcu_size;
-	search_window_factor_bw_b = !two_stage_encoding ?
-		search_window_size_vertical_b * 2 / lcu_size + 1 :
-		(search_window_size_vertical_b * 2 / lcu_size + 2) / 2;
-	bw_increase_b = fp_mult(one_frame_bw_dpb,
-			FP_INT((search_window_factor_bw_b - 1) / 3));
-
-	/* Output parameters for DDR */
 	ddr.vsp_read = fp_mult(fp_div(FP_INT(bitrate), FP_INT(8)),
 			bins_to_bit_factor);
 	ddr.vsp_write = ddr.vsp_read + fp_div(FP_INT(bitrate), FP_INT(8));
 
-	ddr.collocated_read = fp_div(FP_INT(DIV_ROUND_UP(width, lcu_size) *
-			DIV_ROUND_UP(height, lcu_size) *
-			collocated_mv_per_lcu * fps), FP_INT(1000 * 1000));
+	colocated_bytes_per_lcu = lcu_size == 16 ? 16 :
+				lcu_size == 32 ? 64 : 256;
+
+	ddr.collocated_read = FP_INT(lcu_per_frame *
+			colocated_bytes_per_lcu * fps / bps(1));
+
 	ddr.collocated_write = ddr.collocated_read;
 
+	ddr.line_buffer_read = FP_INT(16 * lcu_per_frame * fps / bps(1));
+
 	ddr.line_buffer_write = ddr.line_buffer_read;
 
-	ddr.original_read = fp_div(one_frame_bw_original,
-			original_compression_factor);
+	bw_for_1x_8bpc = fp_div(FP_INT(width * height), FP_INT(32 * 8));
+
+	bw_for_1x_8bpc = fp_mult(bw_for_1x_8bpc,
+		fp_div(FP_INT(256 * 30), FP_INT(1000 * 1000)));
+
+	dpb_bw_for_1x = dpb_bpp == 8 ? bw_for_1x_8bpc :
+		fp_mult(bw_for_1x_8bpc, fp_mult(ten_bpc_packing_factor,
+			ten_bpc_bpp_factor));
+
+	ddr.original_read = fp_div(fp_mult(FP(1, 50, 100), dpb_bw_for_1x),
+		input_compression_factor);
+
 	ddr.original_write = FP_ZERO;
 
-	ddr.dpb_read = FP_ZERO;
+	ref_y_bw_factor =
+		width == vertical_tile_width ? FP_INT(1) : ref_y_bw_factor;
 
-	ddr.dpb_read = fp_div(ddr.dpb_read, dpb_compression_factor);
-	ddr.dpb_write = fp_div(one_frame_bw_dpb, dpb_compression_factor);
+	ref_y_read = fp_mult(ref_y_bw_factor, dpb_bw_for_1x);
+
+	ref_y_read = fp_div(ref_y_read, dpb_compression_factor);
+
+	ref_y_read =
+		b_frames_enabled ? fp_mult(ref_y_read, FP_INT(2)) : ref_y_read;
+
+	ref_cb_cr_read = fp_mult(ref_cb_cr_bw_factor, dpb_bw_for_1x);
+
+	ref_cb_cr_read = fp_div(ref_cb_cr_read, dpb_compression_factor);
+
+	ref_cb_cr_read =
+		b_frames_enabled ? fp_mult(ref_cb_cr_read, FP_INT(2)) :
+					ref_cb_cr_read;
+
+	ref_cb_cr_read = fp_div(ref_cb_cr_read, FP_INT(2));
+
+	ddr.dpb_write = fp_mult(dpb_write_factor, dpb_bw_for_1x);
+
+	ddr.dpb_write = fp_mult(ddr.dpb_write, FP(1, 50, 100));
+
+	ddr.dpb_write = fp_div(ddr.dpb_write, input_compression_factor);
+
+	ref_overlap_bw_factor =
+		width <= vertical_tile_width ? FP_INT(0) : FP_INT(1);
+
+	ref_overlap_bw = fp_mult(ddr.dpb_write, ref_overlap_bw_factor);
+
+	ref_overlap_bw = fp_div(ref_overlap_bw, dpb_write_factor);
+
+	ref_overlap_bw = fp_mult(ref_overlap_bw,
+		(dpb_write_factor - FP_INT(1)));
+
+	ddr.dpb_read = ref_y_read + ref_cb_cr_read + ref_overlap_bw;
 
 	ddr.total = ddr.vsp_read + ddr.vsp_write +
 		ddr.collocated_read + ddr.collocated_write +
@@ -739,7 +730,6 @@
 	if (debug) {
 		struct dump dump[] = {
 		{"ENCODER PARAMETERS", "", DUMP_HEADER_MAGIC},
-		{"standard", "%#x", standard},
 		{"width", "%d", width},
 		{"height", "%d", height},
 		{"DPB format", "%#x", dpb_color_format},
@@ -748,8 +738,8 @@
 		{"DPB compression enable", "%d", dpb_compression_enabled},
 		{"original compression enable", "%d",
 			original_compression_enabled},
-		{"two stage encoding", "%d", two_stage_encoding},
 		{"low power mode", "%d", low_power},
+		{"Work Mode", "%d", work_mode_1},
 		{"DPB compression factor", DUMP_FP_FMT,
 			dpb_compression_factor},
 		{"original compression factor", DUMP_FP_FMT,
@@ -759,44 +749,21 @@
 
 		{"DERIVED PARAMETERS", "", DUMP_HEADER_MAGIC},
 		{"LCU size", "%d", lcu_size},
-		{"GOB pattern", "%d", gop},
 		{"bitrate (Mbit/sec)", "%lu", bitrate},
 		{"bins to bit factor", DUMP_FP_FMT, bins_to_bit_factor},
-		{"B-frames enabled", "%d", b_frames_enabled},
-		{"search window size vertical (B)", "%d",
-			search_window_size_vertical_b},
-		{"search window factor (B)", "%d", search_window_factor_b},
-		{"search window factor BW (B)", "%d",
-			search_window_factor_bw_b},
-		{"bw increase (MB/s) (B)", DUMP_FP_FMT, bw_increase_b},
-		{"search window size vertical (P)", "%d",
-			search_window_size_vertical_p},
-		{"search window factor (P)", "%d", search_window_factor_p},
-		{"search window factor BW (P)", "%d",
-			search_window_factor_bw_p},
-		{"bw increase (MB/s) (P)", DUMP_FP_FMT, bw_increase_p},
-		{"chroma/luma factor DPB", DUMP_FP_FMT,
-			chroma_luma_factor_dpb},
-		{"one frame BW DPB (MB/s)", DUMP_FP_FMT, one_frame_bw_dpb},
-		{"chroma/Luma factor original", DUMP_FP_FMT,
-			chroma_luma_factor_original},
-		{"one frame BW original (MB/s)", DUMP_FP_FMT,
-			one_frame_bw_original},
-		{"line buffer size per LCU", DUMP_FP_FMT,
-			line_buffer_size_per_lcu},
-		{"line buffer size (KB)", DUMP_FP_FMT, line_buffer_size},
-		{"line buffer BW (MB/s)", DUMP_FP_FMT, line_buffer_bw},
-		{"collocated MVs per LCU", "%d", collocated_mv_per_lcu},
 
 		{"INTERMEDIATE B/W DDR", "", DUMP_HEADER_MAGIC},
+		{"ref_y_read", DUMP_FP_FMT, ref_y_read},
+		{"ref_cb_cr_read", DUMP_FP_FMT, ref_cb_cr_read},
+		{"ref_overlap_bw", DUMP_FP_FMT, ref_overlap_bw},
 		{"VSP read", DUMP_FP_FMT, ddr.vsp_read},
-		{"VSP read", DUMP_FP_FMT, ddr.vsp_write},
+		{"VSP write", DUMP_FP_FMT, ddr.vsp_write},
 		{"collocated read", DUMP_FP_FMT, ddr.collocated_read},
-		{"collocated read", DUMP_FP_FMT, ddr.collocated_write},
+		{"collocated write", DUMP_FP_FMT, ddr.collocated_write},
 		{"line buffer read", DUMP_FP_FMT, ddr.line_buffer_read},
-		{"line buffer read", DUMP_FP_FMT, ddr.line_buffer_write},
+		{"line buffer write", DUMP_FP_FMT, ddr.line_buffer_write},
 		{"original read", DUMP_FP_FMT, ddr.original_read},
-		{"original read", DUMP_FP_FMT, ddr.original_write},
+		{"original write", DUMP_FP_FMT, ddr.original_write},
 		{"DPB read", DUMP_FP_FMT, ddr.dpb_read},
 		{"DPB write", DUMP_FP_FMT, ddr.dpb_write},
 		};
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
index e5d1576..a08f282 100644
--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -1140,6 +1140,12 @@
 			buffreq->buffer[10].buffer_type =
 				HAL_BUFFER_INTERNAL_PERSIST_1;
 			break;
+		case HFI_BUFFER_COMMON_INTERNAL_RECON:
+			memcpy(&buffreq->buffer[11], hfi_buf_req,
+			sizeof(struct hfi_buffer_requirements));
+			buffreq->buffer[11].buffer_type =
+				HAL_BUFFER_INTERNAL_RECON;
+			break;
 		default:
 			dprintk(VIDC_ERR,
 			"hal_process_sess_get_prop_buf_req: bad_buffer_type: %d\n",
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index bc4b280..de45678 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -2362,6 +2362,7 @@
 			rc = -EINVAL;
 			goto exit;
 		}
+		inst->clk_data.opb_fourcc = f->fmt.pix_mp.pixelformat;
 		memcpy(&inst->fmts[fmt->type], fmt,
 				sizeof(struct msm_vidc_format));
 
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 1b931ee..854aa0a 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -442,6 +442,7 @@
 	struct msm_vidc_inst *inst = instance;
 	int rc = 0, i = 0;
 	struct buf_queue *q = NULL;
+	u32 cr = 0;
 
 	if (!inst || !inst->core || !b || !valid_v4l2_buffer(b, inst)) {
 		dprintk(VIDC_ERR, "%s: invalid params, inst %pK\n",
@@ -453,8 +454,16 @@
 		b->m.planes[i].m.fd = b->m.planes[i].reserved[0];
 		b->m.planes[i].data_offset = b->m.planes[i].reserved[1];
 	}
+
 	msm_comm_qbuf_cache_operations(inst, b);
 
+	/* Compression ratio is valid only for Encoder YUV buffers. */
+	if (inst->session_type == MSM_VIDC_ENCODER &&
+			b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		cr = b->m.planes[0].reserved[2];
+		msm_comm_update_input_cr(inst, b->index, cr);
+	}
+
 	q = msm_comm_get_vb2q(inst, b->type);
 	if (!q) {
 		dprintk(VIDC_ERR,
@@ -712,7 +721,6 @@
 		rc = set_buffer_count(inst, bufreq->buffer_count_min_host,
 			bufreq->buffer_count_actual, HAL_BUFFER_INPUT);
 		}
-
 		break;
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: {
 		buffer_type = msm_comm_get_hal_output_buffer(inst);
@@ -1494,6 +1502,7 @@
 
 	INIT_MSM_VIDC_LIST(&inst->scratchbufs);
 	INIT_MSM_VIDC_LIST(&inst->freqs);
+	INIT_MSM_VIDC_LIST(&inst->input_crs);
 	INIT_MSM_VIDC_LIST(&inst->persistbufs);
 	INIT_MSM_VIDC_LIST(&inst->pending_getpropq);
 	INIT_MSM_VIDC_LIST(&inst->outputbufs);
@@ -1605,6 +1614,8 @@
 	DEINIT_MSM_VIDC_LIST(&inst->outputbufs);
 	DEINIT_MSM_VIDC_LIST(&inst->registeredbufs);
 	DEINIT_MSM_VIDC_LIST(&inst->eosbufs);
+	DEINIT_MSM_VIDC_LIST(&inst->freqs);
+	DEINIT_MSM_VIDC_LIST(&inst->input_crs);
 
 	kfree(inst);
 	inst = NULL;
@@ -1634,6 +1645,8 @@
 
 	msm_comm_free_freq_table(inst);
 
+	msm_comm_free_input_cr_table(inst);
+
 	if (msm_comm_release_scratch_buffers(inst, false))
 		dprintk(VIDC_ERR,
 			"Failed to release scratch buffers\n");
@@ -1699,6 +1712,8 @@
 	DEINIT_MSM_VIDC_LIST(&inst->outputbufs);
 	DEINIT_MSM_VIDC_LIST(&inst->registeredbufs);
 	DEINIT_MSM_VIDC_LIST(&inst->eosbufs);
+	DEINIT_MSM_VIDC_LIST(&inst->freqs);
+	DEINIT_MSM_VIDC_LIST(&inst->input_crs);
 
 	mutex_destroy(&inst->sync_lock);
 	mutex_destroy(&inst->bufq[CAPTURE_PORT].lock);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
index 6b09a54..ba14ea9 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
@@ -19,6 +19,9 @@
 #define MSM_VIDC_MIN_UBWC_COMPLEXITY_FACTOR (1 << 16)
 #define MSM_VIDC_MAX_UBWC_COMPLEXITY_FACTOR (4 << 16)
 
+#define MSM_VIDC_MIN_UBWC_COMPRESSION_RATIO (1 << 16)
+#define MSM_VIDC_MAX_UBWC_COMPRESSION_RATIO (5 << 16)
+
 static inline unsigned long int get_ubwc_compression_ratio(
 	struct ubwc_cr_stats_info_type ubwc_stats_info)
 {
@@ -90,36 +93,56 @@
 	mutex_unlock(&inst->reconbufs.lock);
 }
 
-static int fill_recon_stats(struct msm_vidc_inst *inst,
+static int fill_dynamic_stats(struct msm_vidc_inst *inst,
 	struct vidc_bus_vote_data *vote_data)
 {
-	struct recon_buf *binfo;
-	u32 CR = 0, min_cf = MSM_VIDC_MIN_UBWC_COMPLEXITY_FACTOR,
-		max_cf = MSM_VIDC_MAX_UBWC_COMPLEXITY_FACTOR;
+	struct recon_buf *binfo, *nextb;
+	struct vidc_input_cr_data *temp, *next;
+	u32 min_cf = 0, max_cf = 0;
+	u32 min_input_cr = 0, max_input_cr = 0, min_cr = 0, max_cr = 0;
 
 	mutex_lock(&inst->reconbufs.lock);
-	list_for_each_entry(binfo, &inst->reconbufs.list, list) {
-		CR = max(CR, binfo->CR);
+	list_for_each_entry_safe(binfo, nextb, &inst->reconbufs.list, list) {
+		min_cr = min(min_cr, binfo->CR);
+		max_cr = max(max_cr, binfo->CR);
 		min_cf = min(min_cf, binfo->CF);
 		max_cf = max(max_cf, binfo->CF);
 	}
 	mutex_unlock(&inst->reconbufs.lock);
 
+	mutex_lock(&inst->input_crs.lock);
+	list_for_each_entry_safe(temp, next, &inst->input_crs.list, list) {
+		min_input_cr = min(min_input_cr, temp->input_cr);
+		max_input_cr = max(max_input_cr, temp->input_cr);
+	}
+	mutex_unlock(&inst->input_crs.lock);
+
 	/* Sanitize CF values from HW . */
 	max_cf = min_t(u32, max_cf, MSM_VIDC_MAX_UBWC_COMPLEXITY_FACTOR);
 	min_cf = max_t(u32, min_cf, MSM_VIDC_MIN_UBWC_COMPLEXITY_FACTOR);
+	max_cr = min_t(u32, max_cr, MSM_VIDC_MAX_UBWC_COMPRESSION_RATIO);
+	min_cr = max_t(u32, min_cr, MSM_VIDC_MIN_UBWC_COMPRESSION_RATIO);
+	max_input_cr = min_t(u32,
+		max_input_cr, MSM_VIDC_MAX_UBWC_COMPRESSION_RATIO);
+	min_input_cr = max_t(u32,
+		min_input_cr, MSM_VIDC_MIN_UBWC_COMPRESSION_RATIO);
 
-	vote_data->compression_ratio = CR;
+	vote_data->compression_ratio = min_cr;
 	vote_data->complexity_factor = max_cf;
+	vote_data->input_cr = min_input_cr;
 	vote_data->use_dpb_read = false;
+
+	/* Check if driver can vote for lower bus BW */
 	if (inst->clk_data.load <= inst->clk_data.load_norm) {
+		vote_data->compression_ratio = max_cr;
 		vote_data->complexity_factor = min_cf;
+		vote_data->input_cr = max_input_cr;
 		vote_data->use_dpb_read = true;
 	}
 
-	dprintk(VIDC_DBG,
-		"Compression Ratio = %d Complexity Factor = %d\n",
-			vote_data->compression_ratio,
+	dprintk(VIDC_PROF,
+		"Input CR = %d Recon CR = %d Complexity Factor = %d\n",
+			vote_data->input_cr, vote_data->compression_ratio,
 			vote_data->complexity_factor);
 
 	return 0;
@@ -198,6 +221,9 @@
 				max(inst->prop.height[CAPTURE_PORT],
 				inst->prop.height[OUTPUT_PORT]);
 		vote_data[i].lcu_size = codec == V4L2_PIX_FMT_HEVC ? 32 : 16;
+		vote_data[i].b_frames_enabled =
+			msm_comm_g_ctrl_for_id(inst,
+				V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES) != 0;
 
 		if (inst->clk_data.operating_rate)
 			vote_data[i].fps =
@@ -227,7 +253,7 @@
 			vote_data[i].num_formats = 2;
 		}
 		vote_data[i].work_mode = inst->clk_data.work_mode;
-		fill_recon_stats(inst, &vote_data[i]);
+		fill_dynamic_stats(inst, &vote_data[i]);
 
 		if (core->resources.sys_cache_res_set)
 			vote_data[i].use_sys_cache = true;
@@ -356,10 +382,15 @@
 
 	if (!found) {
 		temp = kzalloc(sizeof(*temp), GFP_KERNEL);
+		if (!temp) {
+			dprintk(VIDC_WARN, "%s: malloc failure.\n", __func__);
+			goto exit;
+		}
 		temp->freq = freq;
 		temp->device_addr = device_addr;
 		list_add_tail(&temp->list, &inst->freqs.list);
 	}
+exit:
 	mutex_unlock(&inst->freqs.lock);
 }
 
@@ -415,6 +446,48 @@
 	mutex_unlock(&inst->freqs.lock);
 }
 
+void msm_comm_free_input_cr_table(struct msm_vidc_inst *inst)
+{
+	struct vidc_input_cr_data *temp, *next;
+
+	mutex_lock(&inst->input_crs.lock);
+	list_for_each_entry_safe(temp, next, &inst->input_crs.list, list) {
+		list_del(&temp->list);
+		kfree(temp);
+	}
+	INIT_LIST_HEAD(&inst->input_crs.list);
+	mutex_unlock(&inst->input_crs.lock);
+}
+
+void msm_comm_update_input_cr(struct msm_vidc_inst *inst,
+	u32 index, u32 cr)
+{
+	struct vidc_input_cr_data *temp, *next;
+	bool found = false;
+
+	mutex_lock(&inst->input_crs.lock);
+	list_for_each_entry_safe(temp, next, &inst->input_crs.list, list) {
+		if (temp->index == index) {
+			temp->input_cr = cr;
+			found = true;
+			break;
+		}
+	}
+
+	if (!found) {
+		temp = kzalloc(sizeof(*temp), GFP_KERNEL);
+		if (!temp)  {
+			dprintk(VIDC_WARN, "%s: malloc failure.\n", __func__);
+			goto exit;
+		}
+		temp->index = index;
+		temp->input_cr = cr;
+		list_add_tail(&temp->list, &inst->input_crs.list);
+	}
+exit:
+	mutex_unlock(&inst->input_crs.lock);
+}
+
 static unsigned long msm_vidc_max_freq(struct msm_vidc_core *core)
 {
 	struct allowed_clock_rates_table *allowed_clks_tbl = NULL;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_clocks.h b/drivers/media/platform/msm/vidc/msm_vidc_clocks.h
index 705cb7c..707f034 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_clocks.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_clocks.h
@@ -33,6 +33,9 @@
 int msm_vidc_decide_core_and_power_mode(struct msm_vidc_inst *inst);
 void msm_vidc_clear_freq_entry(struct msm_vidc_inst *inst,
 	u32 device_addr);
+void msm_comm_free_input_cr_table(struct msm_vidc_inst *inst);
+void msm_comm_update_input_cr(struct msm_vidc_inst *inst, u32 index,
+	u32 cr);
 void update_recon_stats(struct msm_vidc_inst *inst,
 	struct recon_stats_type *recon_stats);
 #endif
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 48afa0b..f5793d4 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -4769,8 +4769,7 @@
 		return 0;
 	}
 
-	if (!list_empty(&inst->reconbufs.list))
-		msm_comm_release_recon_buffers(inst);
+	msm_comm_release_recon_buffers(inst);
 
 	for (i = 0; i < internal_buf->buffer_count_actual; i++) {
 		binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index 6511029..57dfd52 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -144,6 +144,12 @@
 	unsigned long freq;
 };
 
+struct vidc_input_cr_data {
+	struct list_head list;
+	u32 index;
+	u32 input_cr;
+};
+
 struct recon_buf {
 	struct list_head list;
 	u32 buffer_index;
@@ -327,6 +333,7 @@
 	struct msm_vidc_format fmts[MAX_PORT_NUM];
 	struct buf_queue bufq[MAX_PORT_NUM];
 	struct msm_vidc_list freqs;
+	struct msm_vidc_list input_crs;
 	struct msm_vidc_list scratchbufs;
 	struct msm_vidc_list persistbufs;
 	struct msm_vidc_list pending_getpropq;
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index fbd3b02..e854b43 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -1345,11 +1345,13 @@
 	int output_height, output_width;
 	int compression_ratio;
 	int complexity_factor;
+	int input_cr;
 	bool use_dpb_read;
 	unsigned int lcu_size;
 	enum msm_vidc_power_mode power_mode;
 	enum hal_work_mode work_mode;
 	bool use_sys_cache;
+	bool b_frames_enabled;
 };
 
 struct vidc_clk_scale_data {