msm: vidc: Add LTR feature for H264 encoder

This change adds Long Term Reference picture
selection feature for H264 video encoder.

Change-Id: Ida957df244d8715c955afe8d809708123a94e999
Signed-off-by: Maheshwar Ajja <majja@codeaurora.org>
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c
index 89186f6..4127eeb 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c
@@ -287,6 +287,25 @@
 		return VCD_ERR_ILLEGAL_OP;
 	}
 	encoder = &ddl->codec_data.encoder;
+	if (DDL_IS_LTR_ENABLED(encoder)) {
+		DDL_MSG_HIGH("LTR enabled, mode %u count %u",
+			(u32)encoder->ltr_control.ltrmode.ltr_mode,
+			(u32)encoder->ltr_control.ltr_count);
+		status = ddl_allocate_ltr_list(&encoder->ltr_control);
+		if (status) {
+			DDL_MSG_ERROR("%s: allocate ltr list failed",
+				__func__);
+			return status;
+		} else {
+			ddl_clear_ltr_list(&encoder->ltr_control, false);
+		}
+		encoder->num_references_for_p_frame = 2;
+		encoder->ltr_control.callback_reqd = false;
+		encoder->ltr_control.curr_ltr_id = (u32)DDL_LTR_FRAME_START_ID;
+		DDL_MSG_HIGH("num_ref_for_p_frames %u, curr_ltr_id = %u",
+			(u32)encoder->num_references_for_p_frame,
+			(u32)encoder->ltr_control.curr_ltr_id);
+	}
 	status = ddl_allocate_enc_hw_buffers(ddl);
 	if (status)
 		return status;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
index 58a9329..30e3c52 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
@@ -52,6 +52,19 @@
 #define DDLCLIENT_STATE_IS(ddl, state) \
 	(state == (ddl)->client_state)
 
+#define DDL_IS_LTR_ENABLED(encoder) \
+	((encoder->ltr_control.ltrmode.ltr_mode == \
+		VCD_LTR_MODE_AUTO || \
+	encoder->ltr_control.ltrmode.ltr_mode == \
+		VCD_LTR_MODE_MANUAL) && \
+	(encoder->ltr_control.ltr_count > 0))
+
+#define DDL_IS_LTR_IN_AUTO_MODE(encoder) \
+	((encoder->ltr_control.ltrmode.ltr_mode == \
+		VCD_LTR_MODE_AUTO) && \
+	(encoder->ltr_control.ltr_count > 0) && \
+	(encoder->ltr_control.ltr_period > 0))
+
 #define DDL_DPB_OP_INIT       1
 #define DDL_DPB_OP_MARK_FREE  2
 #define DDL_DPB_OP_MARK_BUSY  3
@@ -72,6 +85,7 @@
 #define DDL_ENC_CHANGE_BITRATE    0x04
 #define DDL_ENC_CHANGE_FRAMERATE  0x08
 #define DDL_ENC_CHANGE_CIR        0x10
+#define DDL_ENC_LTR_USE_FRAME     0x20
 
 #define DDL_DEC_REQ_OUTPUT_FLUSH  0x1
 
@@ -86,6 +100,9 @@
 
 #define MDP_MIN_TILE_HEIGHT			96
 
+#define DDL_MAX_NUM_LTR_FRAMES      2
+#define DDL_LTR_FRAME_START_ID      1
+
 enum ddl_mem_area {
 	DDL_FW_MEM	= 0x0,
 	DDL_MM_MEM	= 0x1,
@@ -243,6 +260,39 @@
 	u32 seqdisp_extdump_enable;
 	u32 seq_extdump_enable;
 };
+struct ddl_ltrlist {
+	bool ltr_in_use;
+	u32 ltr_id;
+};
+struct ddl_ltr_encoding_type {
+	struct vcd_property_ltrmode_type ltrmode;
+	struct vcd_property_ltruse_type failed_use_cmd;
+	struct ddl_ltrlist *ltr_list;
+	u32 ltr_count;
+	u32 ltr_period;
+	u32 ltr_use_frames;
+	u32 curr_ltr_id;
+	u32 storing_idx;
+	u32 out_frame_cnt_to_use_this_ltr;
+	u32 out_frame_cnt_before_next_idr;
+	bool storing;
+	bool callback_reqd;
+	bool meta_data_reqd;
+	bool using;
+	bool first_ltr_use_arvd;
+	bool use_ltr_reqd;
+	bool store_for_intraframe_insertion;
+	bool pending_chg_ltr_useframes; /* True if
+		* corresponding driver context of
+		* out_frame_cnt_to_use_this_ltr
+		* is pending to be changed with
+		* client settings
+		*/
+	bool store_ltr0;
+	bool store_ltr1;
+	bool use_ltr0;
+	bool use_ltr1;
+};
 struct ddl_encoder_data{
 	struct ddl_codec_data_hdr   hdr;
 	struct vcd_property_codec   codec;
@@ -276,6 +326,7 @@
 	struct ddl_enc_buffers  hw_bufs;
 	struct ddl_yuv_buffer_size  input_buf_size;
 	struct vidc_1080p_enc_frame_info enc_frame_info;
+	struct ddl_ltr_encoding_type ltr_control;
 	u32  meta_data_enable_flag;
 	u32  suffix;
 	u32  meta_data_offset;
@@ -291,6 +342,7 @@
 	u32  num_references_for_p_frame;
 	u32  closed_gop;
 	u32  num_slices_comp;
+	bool intra_period_changed;
 	struct vcd_property_slice_delivery_info slice_delivery_info;
 	struct ddl_batch_frame_data batch_frame;
 	u32 avc_delimiter_enable;
@@ -511,4 +563,20 @@
 void ddl_vidc_decode_reset_avg_time(struct ddl_client_context *ddl);
 void ddl_calc_core_proc_time(const char *func_name, u32 index,
 		struct ddl_client_context *ddl);
+s32 ddl_encoder_ltr_control(struct ddl_client_context *ddl);
+void ddl_encoder_use_ltr_fail_callback(
+	struct ddl_client_context *ddl);
+void ddl_handle_ltr_in_framedone(struct ddl_client_context *ddl);
+s32 ddl_clear_ltr_list(struct ddl_ltr_encoding_type *ltr_control,
+	bool only_use_flag);
+s32 ddl_find_oldest_ltr_not_in_use(
+	struct ddl_ltr_encoding_type *ltr_control);
+s32 ddl_find_ltr_in_use(struct ddl_ltr_encoding_type *ltr_control);
+s32 ddl_find_ltr_from_list(struct ddl_ltr_encoding_type *ltr_control,
+	u32 ltr_id);
+s32 ddl_use_ltr_from_list(struct ddl_ltr_encoding_type *ltr_control,
+	u32 ltr_idx);
+s32 ddl_allocate_ltr_list(struct ddl_ltr_encoding_type *ltr_control);
+s32 ddl_free_ltr_list(struct ddl_ltr_encoding_type *ltr_control);
+void ddl_print_ltr_list(struct ddl_ltr_encoding_type *ltr_control);
 #endif
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h
index e6d0260..5685009 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h
@@ -154,4 +154,10 @@
 #define VIDC_SM_ERR_CONCEALMENT_INTER_SLICE_MB_COPY		2
 #define VIDC_SM_ERR_CONCEALMENT_INTRA_SLICE_COLOR_CONCEALMENT	1
 
+#define DDL_MAX_P_FRAMES_IN_INTRA_INTERVAL 0xffff
+
+#define DDL_SATURATE_P_FRAMES_IN_INTRA_INTERVAL(p_rames) \
+	(((p_rames) > (DDL_MAX_P_FRAMES_IN_INTRA_INTERVAL - 1)) ? \
+	(DDL_MAX_P_FRAMES_IN_INTRA_INTERVAL) : (p_rames))
+
 #endif
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
index 74d7aef..f5fb24f 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
@@ -410,6 +410,7 @@
 		ddl_vidc_encode_dynamic_property(ddl, false);
 		encoder->dynamic_prop_change = 0;
 		ddl_free_enc_hw_buffers(ddl);
+		ddl_free_ltr_list(&encoder->ltr_control);
 	}
 }
 
@@ -1172,3 +1173,295 @@
 	vidc_sm_set_video_core_timeout_value(
 		&ddl->shared_mem[ddl->command_channel], vidc_time_out);
 }
+
+void ddl_handle_ltr_in_framedone(struct ddl_client_context *ddl)
+{
+	struct ddl_ltr_encoding_type *ltr_control =
+		&ddl->codec_data.encoder.ltr_control;
+	DDL_MSG_LOW("%s:", __func__);
+	if (ltr_control->storing) {
+		ltr_control->ltr_list[ltr_control->storing_idx].ltr_id =
+			ltr_control->curr_ltr_id;
+		DDL_MSG_LOW("Encoder output stores LTR ID %d into entry %d",
+			ltr_control->curr_ltr_id, ltr_control->storing_idx);
+		ltr_control->meta_data_reqd = true;
+		ltr_control->storing = false;
+	}
+	ltr_control->out_frame_cnt_before_next_idr++;
+	if (ltr_control->out_frame_cnt_to_use_this_ltr) {
+		ltr_control->out_frame_cnt_to_use_this_ltr--;
+		if (!ltr_control->out_frame_cnt_to_use_this_ltr)
+			ddl_clear_ltr_list(ltr_control, true);
+	}
+}
+
+s32 ddl_encoder_ltr_control(struct ddl_client_context *ddl)
+{
+	s32 vcd_status = VCD_S_SUCCESS;
+	struct ddl_encoder_data *encoder = &ddl->codec_data.encoder;
+	struct ddl_ltr_encoding_type *ltr_ctrl = &encoder->ltr_control;
+	bool intra_period_reached = false;
+
+	DDL_MSG_LOW("%s:", __func__);
+	ddl_print_ltr_list(ltr_ctrl);
+
+	if (DDL_IS_LTR_IN_AUTO_MODE(encoder)) {
+		bool finite_i_period, infinite_i_period;
+		DDL_MSG_LOW("%s: before LTR encoding: output "\
+			"count before next IDR %d", __func__,
+			ltr_ctrl->out_frame_cnt_before_next_idr);
+		finite_i_period =
+			(DDL_MAX_P_FRAMES_IN_INTRA_INTERVAL !=
+			encoder->i_period.p_frames) &&
+			(!(ltr_ctrl->out_frame_cnt_before_next_idr %
+			(encoder->i_period.p_frames + 1)));
+		infinite_i_period =
+			((DDL_MAX_P_FRAMES_IN_INTRA_INTERVAL ==
+			encoder->i_period.p_frames) &&
+			(!ltr_ctrl->out_frame_cnt_before_next_idr));
+		if (finite_i_period || infinite_i_period) {
+			DDL_MSG_LOW("%s: Intra period reached. "\
+				"finite_i_period (%u), infinite_i_period (%u)",
+				__func__, (u32)finite_i_period,
+				(u32)infinite_i_period);
+			intra_period_reached = true;
+		}
+		if (intra_period_reached ||
+			ltr_ctrl->store_for_intraframe_insertion ||
+			encoder->intra_period_changed) {
+			ddl_clear_ltr_list(ltr_ctrl, false);
+			ltr_ctrl->out_frame_cnt_before_next_idr = 0;
+			ltr_ctrl->first_ltr_use_arvd = false;
+			ltr_ctrl->store_for_intraframe_insertion = false;
+		} else {
+			if (ltr_ctrl->first_ltr_use_arvd == false) {
+				ddl_use_ltr_from_list(ltr_ctrl, 0);
+				ltr_ctrl->out_frame_cnt_to_use_this_ltr =
+					0xFFFFFFFF;
+				ltr_ctrl->use_ltr_reqd = true;
+			}
+		}
+		if (!(ltr_ctrl->out_frame_cnt_before_next_idr %
+			ltr_ctrl->ltr_period)) {
+			s32 idx;
+			DDL_MSG_LOW("%s: reached LTR period "\
+				"out_frame_cnt_before_next_idr %d",
+				__func__, ltr_ctrl->\
+				out_frame_cnt_before_next_idr);
+			idx = ddl_find_oldest_ltr_not_in_use(
+				ltr_ctrl);
+			if (idx >= 0) {
+				ltr_ctrl->storing = true;
+				ltr_ctrl->storing_idx = idx;
+				if (idx == 0)
+					ltr_ctrl->store_ltr0 = true;
+				else if (idx == 1)
+					ltr_ctrl->store_ltr1 = true;
+			}
+		}
+	}
+	if (encoder->intra_frame_insertion) {
+		DDL_MSG_LOW("%s: I-frame insertion requested, "\
+			"delay LTR store for one frame", __func__);
+			ltr_ctrl->store_for_intraframe_insertion = true;
+	}
+	if (ltr_ctrl->pending_chg_ltr_useframes) {
+		ltr_ctrl->out_frame_cnt_to_use_this_ltr =
+			ltr_ctrl->ltr_use_frames;
+		ltr_ctrl->pending_chg_ltr_useframes = false;
+	}
+	if (ltr_ctrl->out_frame_cnt_to_use_this_ltr)
+		ltr_ctrl->use_ltr_reqd = true;
+	if (ltr_ctrl->use_ltr_reqd) {
+		s32 idx;
+		idx = ddl_find_ltr_in_use(ltr_ctrl);
+		if (idx == 0)
+			ltr_ctrl->use_ltr0 = true;
+		else if (idx == 1)
+			ltr_ctrl->use_ltr1 = true;
+		ltr_ctrl->using = true;
+		ltr_ctrl->use_ltr_reqd = false;
+	} else {
+		DDL_MSG_LOW("%s: use_ltr_reqd skipped", __func__);
+	}
+
+	return vcd_status;
+}
+
+s32 ddl_allocate_ltr_list(struct ddl_ltr_encoding_type *ltr_control)
+{
+	s32 vcd_status = VCD_S_SUCCESS;
+
+	DDL_MSG_LOW("%s: ltr_cout = %u", __func__, ltr_control->ltr_count);
+	if (!ltr_control->ltr_list) {
+		if (ltr_control->ltr_count) {
+			ltr_control->ltr_list = (struct ddl_ltrlist *)
+				kmalloc(sizeof(struct ddl_ltrlist)*
+				ltr_control->ltr_count, GFP_KERNEL);
+			if (!ltr_control->ltr_list) {
+				DDL_MSG_LOW("ddl_allocate_ltr_list failed");
+				vcd_status = VCD_ERR_ALLOC_FAIL;
+			}
+		} else {
+			DDL_MSG_LOW("%s: failed, zero LTR count", __func__);
+			vcd_status = VCD_ERR_FAIL;
+		}
+	} else {
+		DDL_MSG_LOW("WARN: ltr_list already allocated");
+	}
+
+	return vcd_status;
+}
+
+s32 ddl_free_ltr_list(struct ddl_ltr_encoding_type *ltr_control)
+{
+	s32 vcd_status = VCD_S_SUCCESS;
+
+	DDL_MSG_LOW("%s:", __func__);
+	kfree(ltr_control->ltr_list);
+	ltr_control->ltr_list = NULL;
+
+	return vcd_status;
+}
+
+s32 ddl_clear_ltr_list(struct ddl_ltr_encoding_type *ltr_control,
+	bool only_use_flag)
+{
+	s32 vcd_status = VCD_S_SUCCESS;
+	u32 i;
+
+	DDL_MSG_LOW("%s:", __func__);
+	for (i = 0; i < ltr_control->ltr_count; i++) {
+		ltr_control->ltr_list[i].ltr_in_use = false;
+		if (!only_use_flag)
+			ltr_control->ltr_list[i].ltr_id = 0;
+	}
+
+	return vcd_status;
+}
+
+s32 ddl_find_oldest_ltr_not_in_use(struct ddl_ltr_encoding_type *ltr_control)
+{
+	s32 found_idx = -1;
+	u32 i;
+
+	DDL_MSG_LOW("%s:", __func__);
+
+	if (ltr_control->ltr_list) {
+		if (ltr_control->ltr_count == 1)
+			found_idx = 0;
+		else {
+			for (i = 0; i < ltr_control->ltr_count; i++) {
+				if ((ltr_control->ltr_list[i].ltr_in_use ==
+					false) && (found_idx < 0)) {
+					found_idx = i;
+				}
+				if ((found_idx >= 0) &&
+					(ltr_control->ltr_list[i].\
+					ltr_in_use == false) &&
+					(ltr_control->ltr_list[i].ltr_id <
+					ltr_control->ltr_list[found_idx].\
+					ltr_id)) {
+					found_idx = i;
+				}
+			}
+		}
+	}
+
+	DDL_MSG_LOW("%s: found_idx = %d", __func__, found_idx);
+	return found_idx;
+}
+
+s32 ddl_find_ltr_in_use(struct ddl_ltr_encoding_type *ltr_control)
+{
+	s32 found_idx = -1;
+	u32 i;
+
+	DDL_MSG_LOW("%s:", __func__);
+
+	if (ltr_control->ltr_list) {
+		for (i = 0; i < ltr_control->ltr_count; i++) {
+			if (ltr_control->ltr_list[i].ltr_in_use == true)
+				found_idx = i;
+		}
+	}
+
+	DDL_MSG_LOW("%s: found_idx = %d", __func__, found_idx);
+	return found_idx;
+}
+
+s32 ddl_find_ltr_from_list(struct ddl_ltr_encoding_type *ltr_control,
+	u32 ltr_id)
+{
+	s32 found_idx = -1;
+	u32 i;
+
+	DDL_MSG_LOW("%s:", __func__);
+
+	if (ltr_control->ltr_list) {
+		for (i = 0; i < ltr_control->ltr_count; i++) {
+			if (ltr_control->ltr_list[i].ltr_id == ltr_id) {
+				found_idx = i;
+				break;
+			}
+		}
+	} else {
+		DDL_MSG_LOW("%s: ltr_list is NULL", __func__);
+	}
+
+	DDL_MSG_ERROR("%s: found_idx = %d", __func__, found_idx);
+	return found_idx;
+}
+
+s32 ddl_use_ltr_from_list(struct ddl_ltr_encoding_type *ltr_control,
+	u32 ltr_idx)
+{
+	s32 vcd_status = VCD_S_SUCCESS;
+	u32 i;
+
+	DDL_MSG_LOW("%s: ltr_idx = %u", __func__, ltr_idx);
+	if (ltr_idx > ltr_control->ltr_count) {
+		DDL_MSG_LOW("%s: fail, idx %d larger than "\
+			"the list array count %d", __func__,
+			ltr_idx, ltr_control->ltr_count);
+		vcd_status = VCD_ERR_FAIL;
+	} else {
+		for (i = 0; i < ltr_control->ltr_count; i++) {
+			if (i == ltr_idx)
+				ltr_control->ltr_list[ltr_idx].ltr_in_use =
+					true;
+			else
+				ltr_control->ltr_list[i].ltr_in_use = false;
+		}
+	}
+
+	return vcd_status;
+}
+
+void ddl_encoder_use_ltr_fail_callback(struct ddl_client_context *ddl)
+{
+	struct ddl_encoder_data *encoder = &(ddl->codec_data.encoder);
+	struct ddl_context *ddl_context = ddl->ddl_context;
+
+	DDL_MSG_LOW("%s: LTR use failed, callback "\
+		"requested with LTR ID %d", __func__,
+		encoder->ltr_control.failed_use_cmd.ltr_id);
+
+	ddl_context->ddl_callback(VCD_EVT_IND_INFO_LTRUSE_FAILED,
+		VCD_ERR_ILLEGAL_PARM,
+		&(encoder->ltr_control.failed_use_cmd),
+		sizeof(struct vcd_property_ltruse_type),
+		(u32 *)ddl,
+		ddl->client_data);
+}
+
+void ddl_print_ltr_list(struct ddl_ltr_encoding_type *ltr_control)
+{
+	u32 i;
+
+	for (i = 0; i < ltr_control->ltr_count; i++) {
+		DDL_MSG_LOW("%s: ltr_id: %d, ltr_in_use: %d",
+			__func__, ltr_control->ltr_list[i].ltr_id,
+			ltr_control->ltr_list[i].ltr_in_use);
+	}
+}
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
index 3c753b3..2fc8f86 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
@@ -1817,7 +1817,16 @@
 			(unsigned long) output_frame->alloc_len,
 			ION_IOC_INV_CACHES);
 	}
-	ddl_process_encoder_metadata(ddl);
+	if ((VIDC_1080P_ENCODE_FRAMETYPE_SKIPPED !=
+		encoder->enc_frame_info.enc_frame) &&
+		(VIDC_1080P_ENCODE_FRAMETYPE_NOT_CODED !=
+		encoder->enc_frame_info.enc_frame)) {
+		if (DDL_IS_LTR_ENABLED(encoder))
+			ddl_handle_ltr_in_framedone(ddl);
+		ddl_process_encoder_metadata(ddl);
+		encoder->ltr_control.meta_data_reqd = false;
+	}
+	encoder->ltr_control.using = false;
 	ddl_vidc_encode_dynamic_property(ddl, false);
 	ddl->input_frame.frm_trans_end = false;
 	input_buffer_address = ddl_context->dram_base_a.align_physical_addr +
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.c
index 97187b7..c2e01a1 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.c
@@ -76,6 +76,9 @@
 		case VCD_METADATA_QCOMFILLER:
 			skip_words = 6;
 		break;
+		case VCD_METADATA_LTR_INFO:
+			skip_words = 9;
+		break;
 		}
 	}
 	buffer += skip_words;
@@ -147,17 +150,20 @@
 		hdr_entry[DDL_METADATA_HDR_VERSION_INDEX] = 0x00000101;
 		hdr_entry[DDL_METADATA_HDR_PORT_INDEX] = 1;
 		hdr_entry[DDL_METADATA_HDR_TYPE_INDEX] = VCD_METADATA_ENC_SLICE;
+		hdr_entry = ddl_metadata_hdr_entry(ddl, VCD_METADATA_LTR_INFO);
+		hdr_entry[DDL_METADATA_HDR_VERSION_INDEX] = 0x00000101;
+		hdr_entry[DDL_METADATA_HDR_PORT_INDEX] = 1;
+		hdr_entry[DDL_METADATA_HDR_TYPE_INDEX] = VCD_METADATA_LTR_INFO;
 	}
 }
 
 static u32 ddl_supported_metadata_flag(struct ddl_client_context *ddl)
 {
 	u32 flag = 0;
+	enum vcd_codec codec =
+		ddl->codec_data.decoder.codec.codec;
 
 	if (ddl->decoding) {
-		enum vcd_codec codec =
-			ddl->codec_data.decoder.codec.codec;
-
 		flag |= (VCD_METADATA_CONCEALMB | VCD_METADATA_PASSTHROUGH |
 				VCD_METADATA_QPARRAY |
 				VCD_METADATA_SEPARATE_BUF);
@@ -169,8 +175,12 @@
 		else if (codec == VCD_CODEC_MPEG2)
 			flag |= (VCD_METADATA_USER_DATA |
 				VCD_METADATA_EXT_DATA);
-	} else
-		flag |= VCD_METADATA_ENC_SLICE;
+	} else {
+		if (codec == VCD_CODEC_H264)
+			flag |= VCD_METADATA_ENC_SLICE | VCD_METADATA_LTR_INFO;
+		else
+			flag |= VCD_METADATA_ENC_SLICE;
+	}
 	return flag;
 }
 
@@ -279,6 +289,12 @@
 		DDL_METADATA_ALIGNSIZE(size);
 		suffix += size;
 	}
+	if (flag & VCD_METADATA_LTR_INFO) {
+		size = DDL_METADATA_HDR_SIZE;
+		size += DDL_METADATA_LTR_INFO_PAYLOAD_SIZE;
+		DDL_METADATA_ALIGNSIZE(size);
+		suffix += size;
+	}
 	size = DDL_METADATA_EXTRADATANONE_SIZE;
 	DDL_METADATA_ALIGNSIZE(size);
 	suffix += (size);
@@ -510,21 +526,34 @@
 	struct ddl_encoder_data *encoder = &(ddl->codec_data.encoder);
 	struct vcd_frame_data *out_frame =
 		&(ddl->output_frame.vcd_frm);
+	u32 metadata_available = false;
 	out_frame->metadata_offset = 0;
 	out_frame->metadata_len = 0;
+	out_frame->curr_ltr_id = 0;
+	out_frame->flags &= ~(VCD_FRAME_FLAG_EXTRADATA);
 	if (!encoder->meta_data_enable_flag) {
-		out_frame->flags &= ~(VCD_FRAME_FLAG_EXTRADATA);
+		DDL_MSG_HIGH("meta_data is not enabled");
 		return;
 	}
-	if (!encoder->enc_frame_info.meta_data_exists) {
-		out_frame->flags &= ~(VCD_FRAME_FLAG_EXTRADATA);
-		return;
+	if (encoder->enc_frame_info.meta_data_exists) {
+		DDL_MSG_LOW("meta_data exists");
+		metadata_available = true;
 	}
-	DDL_MSG_LOW("%s: data_len/metadata_offset : %d/%d", __func__,
-		out_frame->data_len, encoder->meta_data_offset);
-	out_frame->metadata_offset = encoder->meta_data_offset;
-	out_frame->metadata_len = encoder->suffix;
-	out_frame->flags |= VCD_FRAME_FLAG_EXTRADATA;
+	if ((encoder->meta_data_enable_flag & VCD_METADATA_LTR_INFO) &&
+		(encoder->ltr_control.meta_data_reqd == true)) {
+		out_frame->curr_ltr_id = encoder->ltr_control.curr_ltr_id;
+		DDL_MSG_LOW("%s: increment curr_ltr_id = %d",
+			__func__, (u32)encoder->ltr_control.curr_ltr_id);
+		encoder->ltr_control.curr_ltr_id++;
+		metadata_available = true;
+	}
+	if (metadata_available) {
+		DDL_MSG_LOW("%s: data_len/metadata_offset : %d/%d", __func__,
+			out_frame->data_len, encoder->meta_data_offset);
+		out_frame->metadata_offset = encoder->meta_data_offset;
+		out_frame->metadata_len = encoder->suffix;
+		out_frame->flags |= VCD_FRAME_FLAG_EXTRADATA;
+	}
 }
 
 void ddl_process_decoder_metadata(struct ddl_client_context *ddl)
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.h
index 8cee92f..f133df6 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.h
@@ -27,6 +27,7 @@
 #define DDL_METADATA_SEI_PAYLOAD_SIZE          100
 #define DDL_METADATA_SEI_MAX                     5
 #define DDL_METADATA_VUI_PAYLOAD_SIZE          256
+#define DDL_METADATA_LTR_INFO_PAYLOAD_SIZE     (4)
 #define DDL_METADATA_PASSTHROUGH_PAYLOAD_SIZE   68
 #define DDL_METADATA_EXT_PAYLOAD_SIZE         (640)
 #define DDL_METADATA_USER_PAYLOAD_SIZE        (2048)
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
index 905e456..2e4fba1 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
@@ -163,6 +163,27 @@
 		DDL_MSG_ERROR("H264BaseLineCABAC!!");
 		return false;
 	}
+	if (DDL_IS_LTR_ENABLED(encoder)) {
+		if ((encoder->codec.codec != VCD_CODEC_H264) ||
+			(encoder->i_period.b_frames)) {
+			DDL_MSG_ERROR("%s: Only support LTR encoding "\
+				"for H264 without B frame. Current "\
+				"codec %d, B-frame %d", __func__,
+				encoder->codec.codec,
+				encoder->i_period.b_frames);
+			return false;
+		}
+		if (encoder->ltr_control.ltrmode.ltr_mode ==
+			VCD_LTR_MODE_MANUAL) {
+			DDL_MSG_ERROR("%s: Manual LTR mode not supported!",
+				__func__);
+			return false;
+		}
+		DDL_MSG_HIGH("%s: LTR: mode = %u, count = %u, period = %u",
+			__func__, (u32)encoder->ltr_control.ltrmode.ltr_mode,
+		encoder->ltr_control.ltr_count,
+		encoder->ltr_control.ltr_period);
+	}
 	return true;
 }
 
@@ -693,8 +714,9 @@
 		struct vcd_property_multi_slice *multi_slice =
 			(struct vcd_property_multi_slice *)
 				property_value;
-		DDL_MSG_HIGH("VCD_I_MULTI_SLICE eMSliceSel %d  nMSliceSize %d"
-				"Tot#of MB %d encoder->frame_size.width = %d"
+		DDL_MSG_HIGH("VCD_I_MULTI_SLICE eMSliceSel %d "\
+				"nMSliceSize %d Tot#of MB %d "\
+				"encoder->frame_size.width = %d "\
 				"encoder->frame_size.height = %d",
 				(int)multi_slice->m_slice_sel,
 				multi_slice->m_slice_size,
@@ -1123,6 +1145,41 @@
 		}
 		break;
 	}
+	case VCD_I_LTR_MODE:
+		if (sizeof(struct vcd_property_ltrmode_type) ==
+			property_hdr->sz && encoder->codec.codec ==
+			VCD_CODEC_H264) {
+			struct vcd_property_ltrmode_type *ltrmode =
+				(struct vcd_property_ltrmode_type *)
+				property_value;
+			encoder->ltr_control.ltrmode.ltr_mode =
+				ltrmode->ltr_mode;
+			DDL_MSG_HIGH("%s: set LTR mode = %u", __func__,
+				(u32)encoder->ltr_control.ltrmode.ltr_mode);
+			vcd_status = VCD_S_SUCCESS;
+		}
+	break;
+	case VCD_I_LTR_COUNT:
+		if (sizeof(struct vcd_property_ltrcount_type) ==
+			property_hdr->sz && encoder->codec.codec ==
+			VCD_CODEC_H264) {
+			struct vcd_property_ltrcount_type *ltrcount =
+				(struct vcd_property_ltrcount_type *)
+				property_value;
+			if (ltrcount->ltr_count > DDL_MAX_NUM_LTR_FRAMES) {
+				DDL_MSG_ERROR("%s: set LTR count failed. "\
+					"LTR count %u beyond maximum of %u",
+					__func__, ltrcount->ltr_count,
+					(u32)DDL_MAX_NUM_LTR_FRAMES);
+			} else {
+				encoder->ltr_control.ltr_count =
+					ltrcount->ltr_count;
+				DDL_MSG_HIGH("%s: set LTR count = %u", __func__,
+					encoder->ltr_control.ltr_count);
+				vcd_status = VCD_S_SUCCESS;
+			}
+		}
+	break;
 	case VCD_REQ_PERF_LEVEL:
 		DDL_MSG_LOW("%s: VCD_REQ_PERF_LEVEL (do nithing)", __func__);
 		vcd_status = VCD_S_SUCCESS;
@@ -1170,7 +1227,8 @@
 		break;
 	}
 	default:
-		DDL_MSG_ERROR("INVALID ID %d\n", (int)property_hdr->prop_id);
+		DDL_MSG_ERROR("%s: INVALID ID 0x%x\n", __func__,
+			(int)property_hdr->prop_id);
 		vcd_status = VCD_ERR_ILLEGAL_OP;
 		break;
 	}
@@ -1710,7 +1768,67 @@
 			vcd_status = VCD_S_SUCCESS;
 		}
 	break;
+	case VCD_I_CAPABILITY_LTR_COUNT:
+		if (sizeof(struct vcd_property_range_type) ==
+			property_hdr->sz) {
+			struct vcd_property_range_type capability_ltr_range;
+			capability_ltr_range.max = DDL_MAX_NUM_LTR_FRAMES;
+			capability_ltr_range.min = 1;
+			capability_ltr_range.step_size = 1;
+			*(struct vcd_property_range_type *)property_value =
+				capability_ltr_range;
+			DDL_MSG_HIGH("%s: capability_ltr_count = %u",
+				__func__, ((struct vcd_property_range_type *)
+				property_value)->max);
+			vcd_status = VCD_S_SUCCESS;
+		}
+	break;
+	case VCD_I_LTR_MODE:
+		if (sizeof(struct vcd_property_ltrmode_type) ==
+			property_hdr->sz) {
+			((struct vcd_property_ltrmode_type *)
+				property_value)->ltr_mode =
+				encoder->ltr_control.ltrmode.ltr_mode;
+			DDL_MSG_HIGH("%s: ltr_mode = %u", __func__,
+				(u32)(((struct vcd_property_ltrmode_type *)
+				property_value)->ltr_mode));
+			vcd_status = VCD_S_SUCCESS;
+		}
+	break;
+	case VCD_I_LTR_COUNT:
+		if (sizeof(struct vcd_property_ltrcount_type) ==
+			property_hdr->sz) {
+			struct vcd_property_ltrcount_type ltr_count;
+			ltr_count.ltr_count =
+				encoder->ltr_control.ltr_count;
+			*(struct vcd_property_ltrcount_type *)property_value =
+				ltr_count;
+			DDL_MSG_HIGH("%s: ltr_count = %u", __func__,
+				((struct vcd_property_ltrcount_type *)
+				property_value)->ltr_count);
+			vcd_status = VCD_S_SUCCESS;
+		}
+	break;
+	case VCD_I_LTR_PERIOD:
+		if (sizeof(struct vcd_property_ltrperiod_type) ==
+			property_hdr->sz) {
+			struct vcd_property_ltrperiod_type ltr_period;
+			if (!encoder->ltr_control.ltr_period)
+				ltr_period.ltr_period = 0;
+			else
+				ltr_period.ltr_period =
+			encoder->ltr_control.ltr_period - 1;
+			*(struct vcd_property_ltrperiod_type *)property_value =
+				ltr_period;
+			DDL_MSG_HIGH("%s: ltr_period = %u", __func__,
+				((struct vcd_property_ltrperiod_type *)
+				property_value)->ltr_period);
+			vcd_status = VCD_S_SUCCESS;
+		}
+	break;
 	default:
+		DDL_MSG_ERROR("%s: unknown prop_id = 0x%x", __func__,
+			property_hdr->prop_id);
 		vcd_status = VCD_ERR_ILLEGAL_OP;
 		break;
 	}
@@ -1799,6 +1917,77 @@
 		}
 	}
 	break;
+	case VCD_I_LTR_PERIOD:
+	{
+		if (sizeof(struct vcd_property_ltrperiod_type) ==
+			property_hdr->sz) {
+			struct vcd_property_ltrperiod_type *ltrperiod =
+				(struct vcd_property_ltrperiod_type *)
+				property_value;
+			encoder->ltr_control.ltr_period =
+				(ltrperiod->ltr_period == 0xFFFFFFFF) ?
+				0xFFFFFFFF : (ltrperiod->ltr_period + 1);
+			DDL_MSG_HIGH("%s: set ltr_period = %u", __func__,
+				encoder->ltr_control.ltr_period);
+			vcd_status = VCD_S_SUCCESS;
+		}
+	}
+	break;
+	case VCD_I_LTR_USE:
+	{
+		if (sizeof(struct vcd_property_ltruse_type) ==
+			property_hdr->sz) {
+			struct vcd_property_ltruse_type *ltruse =
+				(struct vcd_property_ltruse_type *)
+				property_value;
+			if (ltruse->ltr_id >= DDL_LTR_FRAME_START_ID) {
+				struct ddl_ltr_encoding_type *ltr_ctrl =
+					&encoder->ltr_control;
+				s32 idx;
+				idx = ddl_find_ltr_from_list(ltr_ctrl,
+					ltruse->ltr_id);
+				if (idx < 0) {
+					ltr_ctrl->callback_reqd = true;
+					ltr_ctrl->failed_use_cmd.ltr_id =
+						ltruse->ltr_id;
+					ltr_ctrl->failed_use_cmd.ltr_frames =
+						ltruse->ltr_frames;
+					DDL_MSG_ERROR("%s: index (%d) "\
+						"not found. Callback requested. "\
+						"ltr_id = %u, ltr_frames = %u",
+						__func__, idx, ltruse->ltr_id,
+						ltruse->ltr_frames);
+				} else {
+					ddl_use_ltr_from_list(ltr_ctrl, idx);
+					ltr_ctrl->ltr_use_frames =
+						ltruse->ltr_frames;
+					if (ltr_ctrl->using == false)
+						ltr_ctrl->\
+							out_frame_cnt_to_use_this_ltr =
+							ltruse->ltr_frames;
+					else
+						ltr_ctrl->\
+							pending_chg_ltr_useframes =
+							true;
+					ltr_ctrl->first_ltr_use_arvd = true;
+					ltr_ctrl->use_ltr_reqd = true;
+					DDL_MSG_HIGH("%s: index (%d) found. "\
+						"num frames to use this ltr_id (%u) "\
+						"is %u", __func__, idx,
+						ltruse->ltr_id, ltruse->ltr_frames);
+				}
+				dynamic_prop_change = DDL_ENC_LTR_USE_FRAME;
+				vcd_status = VCD_S_SUCCESS;
+			} else {
+				DDL_MSG_ERROR("%s: LTRUse ID %d failed. "\
+					"LTR ID starts from %d", __func__,
+					ltruse->ltr_id,
+					(u32)DDL_LTR_FRAME_START_ID);
+					vcd_status = VCD_ERR_ILLEGAL_OP;
+			}
+		}
+	}
+	break;
 	default:
 		vcd_status = VCD_ERR_ILLEGAL_OP;
 		break;
@@ -1866,6 +2055,9 @@
 	encoder->num_references_for_p_frame = DDL_MIN_NUM_REF_FOR_P_FRAME;
 	if (encoder->codec.codec == VCD_CODEC_MPEG4)
 		encoder->closed_gop = true;
+	encoder->intra_period_changed = false;
+	memset(&encoder->ltr_control, 0,
+		sizeof(struct ddl_ltr_encoding_type));
 	ddl_set_default_metadata_flag(ddl);
 	ddl_set_default_encoder_buffer_req(encoder);
 	encoder->slice_delivery_info.enable = 0;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
index 2ab02f7..62012b9 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
@@ -89,6 +89,8 @@
 #define VIDC_SM_ENC_EXT_CTRL_STREAM_RESTRICT_EN_SHFT 13
 #define VIDC_SM_ENC_EXT_CTRL_AU_DELIMITER_EN_BMSK    0x00000800
 #define VIDC_SM_ENC_EXT_CTRL_AU_DELIMITER_EN_SHFT    11
+#define VIDC_SM_ENC_EXT_CTRL_LONG_TERM_REF_ENABLE_BMSK 0x00000400
+#define VIDC_SM_ENC_EXT_CTRL_LONG_TERM_REF_ENABLE_SHFT 10
 #define VIDC_SM_ENC_EXT_CTRL_H263_CPCFC_ENABLE_BMSK  0x80
 #define VIDC_SM_ENC_EXT_CTRL_H263_CPCFC_ENABLE_SHFT  7
 #define VIDC_SM_ENC_EXT_CTRL_SPS_PPS_CONTROL_BMSK    0X100
@@ -482,7 +484,7 @@
 	u32 seq_hdr_in_band, u32 vbv_buffer_size, u32 cpcfc_enable,
 	u32 sps_pps_control, u32 closed_gop_enable,
 	u32 au_delim_enable, u32 vui_timing_info_enable,
-	u32 restrict_bitstream_enable)
+	u32 restrict_bitstream_enable, u32 ltr_enable)
 {
 	u32 enc_ctrl;
 	enc_ctrl = VIDC_SETFIELD((hec_enable) ? 1 : 0,
@@ -514,7 +516,10 @@
 			VIDC_SM_ENC_EXT_CTRL_TIMING_INFO_EN_BMSK) |
 			VIDC_SETFIELD((restrict_bitstream_enable) ? 1 : 0,
 			VIDC_SM_ENC_EXT_CTRL_STREAM_RESTRICT_EN_SHFT,
-			VIDC_SM_ENC_EXT_CTRL_STREAM_RESTRICT_EN_BMSK);
+			VIDC_SM_ENC_EXT_CTRL_STREAM_RESTRICT_EN_BMSK) |
+			VIDC_SETFIELD((ltr_enable) ? 1 : 0,
+			VIDC_SM_ENC_EXT_CTRL_LONG_TERM_REF_ENABLE_SHFT,
+			VIDC_SM_ENC_EXT_CTRL_LONG_TERM_REF_ENABLE_BMSK);
 
 	DDL_MEM_WRITE_32(shared_mem, VIDC_SM_ENC_EXT_CTRL_ADDR, enc_ctrl);
 }
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
index 51feaf9..5c0db51 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
@@ -107,7 +107,7 @@
 	enum VIDC_SM_frame_skip  frame_skip_mode, u32 seq_hdr_in_band,
 	u32 vbv_buffer_size, u32 cpcfc_enable, u32 sps_pps_control,
 	u32 closed_gop_enable, u32 au_delim_enable, u32 vui_timing_info_enable,
-	u32 restrict_bitstream_enable);
+	u32 restrict_bitstream_enable, u32 ltr_enable);
 void vidc_sm_set_encoder_param_change(struct ddl_buf_addr *shared_mem,
 	u32 bit_rate_chg, u32 frame_rate_chg, u32 i_period_chg);
 void vidc_sm_set_encoder_vop_time(struct ddl_buf_addr *shared_mem,
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
index b62a7df..d985c66 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
@@ -339,7 +339,7 @@
 {
 	struct ddl_encoder_data *encoder = &(ddl->codec_data.encoder);
 	u32 frame_rate_change = false, bit_rate_change = false;
-	u32 i_period_change = false, reset_req = false;
+	u32 reset_req = false;
 
 	if (!enable) {
 		if (encoder->dynmic_prop_change_req) {
@@ -352,6 +352,17 @@
 			encoder->dynamic_prop_change &=
 				~(DDL_ENC_REQ_IFRAME);
 		}
+		if (encoder->dynamic_prop_change & DDL_ENC_LTR_USE_FRAME) {
+			if (encoder->ltr_control.callback_reqd) {
+				DDL_MSG_ERROR("%s: LTR use failed", __func__);
+				ddl_encoder_use_ltr_fail_callback(ddl);
+				encoder->ltr_control.callback_reqd = false;
+			} else {
+				encoder->ltr_control.use_ltr_reqd = true;
+			}
+			encoder->dynamic_prop_change &=
+				~(DDL_ENC_LTR_USE_FRAME);
+		}
 		if ((encoder->dynamic_prop_change &
 			DDL_ENC_CHANGE_BITRATE)) {
 			bit_rate_change = true;
@@ -363,7 +374,7 @@
 		}
 		if ((encoder->dynamic_prop_change
 			& DDL_ENC_CHANGE_IPERIOD)) {
-			i_period_change = true;
+			encoder->intra_period_changed = true;
 			vidc_sm_set_encoder_new_i_period(
 				&ddl->shared_mem[ddl->command_channel],
 				encoder->i_period.p_frames);
@@ -395,7 +406,7 @@
 		vidc_sm_set_encoder_param_change(
 			&ddl->shared_mem[ddl->command_channel],
 			bit_rate_change, frame_rate_change,
-			i_period_change);
+			encoder->intra_period_changed);
 	}
 }
 
@@ -588,7 +599,7 @@
 	u32 index, luma[4], chroma[4], hdr_ext_control = false;
 	const u32 recon_bufs = 4;
 	u32 h263_cpfc_enable = false;
-	u32 scaled_frame_rate;
+	u32 scaled_frame_rate, ltr_enable;
 
 	ddl_vidc_encode_set_profile_level(ddl);
 	vidc_1080p_set_encode_frame_size(encoder->frame_size.width,
@@ -609,13 +620,15 @@
 		(DDL_FRAMERATE_SCALE(DDL_INITIAL_FRAME_RATE)
 		 != scaled_frame_rate))
 		h263_cpfc_enable = true;
+	ltr_enable = DDL_IS_LTR_ENABLED(encoder);
+	DDL_MSG_HIGH("ltr_enable = %u", ltr_enable);
 	vidc_sm_set_extended_encoder_control(&ddl->shared_mem
 		[ddl->command_channel], hdr_ext_control,
 		r_cframe_skip, false, 0,
 		h263_cpfc_enable, encoder->sps_pps.sps_pps_for_idr_enable_flag,
 		encoder->closed_gop, encoder->avc_delimiter_enable,
 		encoder->vui_timinginfo_enable,
-		encoder->bitstream_restrict_enable);
+		encoder->bitstream_restrict_enable, ltr_enable);
 	if (encoder->vui_timinginfo_enable) {
 		vidc_sm_set_h264_encoder_timing_info(
 			&ddl->shared_mem[ddl->command_channel],
@@ -827,6 +840,8 @@
 		ddl_vidc_encode_dynamic_property(ddl, true);
 	}
 
+	if (DDL_IS_LTR_ENABLED(encoder))
+		ddl_encoder_ltr_control(ddl);
 	vidc_1080p_set_encode_circular_intra_refresh(
 		encoder->intra_refresh.cir_mb_number);
 	ddl_vidc_encode_set_multi_slice_info(encoder);
@@ -847,6 +862,17 @@
 		encoder->intra_frame_insertion = false;
 	enc_param.input_flush = false;
 	enc_param.slice_enable = false;
+	enc_param.store_ltr0 = encoder->ltr_control.store_ltr0;
+	enc_param.store_ltr1 = encoder->ltr_control.store_ltr1;
+	enc_param.use_ltr0 = encoder->ltr_control.use_ltr0;
+	enc_param.use_ltr1 = encoder->ltr_control.use_ltr1;
+
+	encoder->intra_frame_insertion = false;
+	encoder->intra_period_changed = false;
+	encoder->ltr_control.store_ltr0 = false;
+	encoder->ltr_control.store_ltr1 = false;
+	encoder->ltr_control.use_ltr0 = false;
+	encoder->ltr_control.use_ltr1 = false;
 		vidc_sm_set_encoder_vop_time(
 			&ddl->shared_mem[ddl->command_channel], true,
 			encoder->vop_timing.vop_time_resolution,
diff --git a/drivers/video/msm/vidc/1080p/ddl/vidc.c b/drivers/video/msm/vidc/1080p/ddl/vidc.c
index b3dff14..45ec601 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vidc.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vidc.c
@@ -83,6 +83,17 @@
 #define VIDC_1080P_SI_RG10_ENCODE_SLICE_IF_ENABLE_SHFT      31
 #define VIDC_1080P_MAX_INTRA_PERIOD 0xffff
 
+#define VIDC_1080P_COMMON_CHX_RG6_I_FRAME_BMASK 0x00000001
+#define VIDC_1080P_COMMON_CHX_RG6_I_FRAME_SHIFT 0
+#define VIDC_1080P_COMMON_CHX_RG6_STORE_LTR0_BMASK 0x00000008
+#define VIDC_1080P_COMMON_CHX_RG6_STORE_LTR0_SHIFT 3
+#define VIDC_1080P_COMMON_CHX_RG6_STORE_LTR1_BMASK 0x00000010
+#define VIDC_1080P_COMMON_CHX_RG6_STORE_LTR1_SHIFT 4
+#define VIDC_1080P_COMMON_CHX_RG6_USE_LTR0_BMASK 0x00000020
+#define VIDC_1080P_COMMON_CHX_RG6_USE_LTR0_SHIFT 5
+#define VIDC_1080P_COMMON_CHX_RG6_USE_LTR1_BMASK 0x00000040
+#define VIDC_1080P_COMMON_CHX_RG6_USE_LTR1_SHIFT 6
+
 u8 *VIDC_BASE_PTR;
 
 void vidc_1080p_do_sw_reset(enum vidc_1080p_reset init_flag)
@@ -876,7 +887,8 @@
 void vidc_1080p_encode_frame_start_ch0(
 	struct vidc_1080p_enc_frame_start_param *param)
 {
-	u32 input_flush;
+	u32 input_flush = 0;
+	u32 frame_insertion = 0;
 	VIDC_HWIO_OUT(REG_695082, VIDC_1080P_RISC2HOST_CMD_EMPTY);
 	VIDC_HWIO_OUT(REG_666957, VIDC_1080P_INIT_CH_INST_ID);
 	VIDC_HWIO_OUT(REG_117192,
@@ -887,7 +899,22 @@
 		VIDC_1080P_BASE_OFFSET_SHIFT);
 	VIDC_HWIO_OUT(REG_175608, param->current_c_addr_offset >>
 		VIDC_1080P_BASE_OFFSET_SHIFT);
-	VIDC_HWIO_OUT(REG_190381, param->intra_frame);
+	frame_insertion = VIDC_SETFIELD(param->intra_frame,
+		VIDC_1080P_COMMON_CHX_RG6_I_FRAME_SHIFT,
+		VIDC_1080P_COMMON_CHX_RG6_I_FRAME_BMASK);
+	frame_insertion |= VIDC_SETFIELD(param->store_ltr0,
+		VIDC_1080P_COMMON_CHX_RG6_STORE_LTR0_SHIFT,
+		VIDC_1080P_COMMON_CHX_RG6_STORE_LTR0_BMASK);
+	frame_insertion |= VIDC_SETFIELD(param->store_ltr1,
+		VIDC_1080P_COMMON_CHX_RG6_STORE_LTR1_SHIFT,
+		VIDC_1080P_COMMON_CHX_RG6_STORE_LTR1_BMASK);
+	frame_insertion |= VIDC_SETFIELD(param->use_ltr0,
+		VIDC_1080P_COMMON_CHX_RG6_USE_LTR0_SHIFT,
+		VIDC_1080P_COMMON_CHX_RG6_USE_LTR0_BMASK);
+	frame_insertion |= VIDC_SETFIELD(param->use_ltr1,
+		VIDC_1080P_COMMON_CHX_RG6_USE_LTR1_SHIFT,
+		VIDC_1080P_COMMON_CHX_RG6_USE_LTR1_BMASK);
+	VIDC_HWIO_OUT(REG_190381, frame_insertion);
 	VIDC_HWIO_OUT(REG_889944, param->shared_mem_addr_offset);
 	input_flush = VIDC_SETFIELD(param->input_flush,
 			VIDC_1080P_SI_RG10_ENCODE_INPUT_BUFFER_FLUSH_SHFT,
@@ -905,7 +932,8 @@
 void vidc_1080p_encode_frame_start_ch1(
 	struct vidc_1080p_enc_frame_start_param *param)
 {
-	u32 input_flush;
+	u32 input_flush = 0;
+	u32 frame_insertion = 0;
 	VIDC_HWIO_OUT(REG_695082, VIDC_1080P_RISC2HOST_CMD_EMPTY);
 	VIDC_HWIO_OUT(REG_313350, VIDC_1080P_INIT_CH_INST_ID);
 	VIDC_HWIO_OUT(REG_980194,
@@ -916,7 +944,22 @@
 		VIDC_1080P_BASE_OFFSET_SHIFT);
 	VIDC_HWIO_OUT(REG_548308,  param->current_c_addr_offset >>
 		VIDC_1080P_BASE_OFFSET_SHIFT);
-	VIDC_HWIO_OUT(REG_887095, param->intra_frame);
+	frame_insertion = VIDC_SETFIELD(param->intra_frame,
+		VIDC_1080P_COMMON_CHX_RG6_I_FRAME_SHIFT,
+		VIDC_1080P_COMMON_CHX_RG6_I_FRAME_BMASK);
+	frame_insertion |= VIDC_SETFIELD(param->store_ltr0,
+		VIDC_1080P_COMMON_CHX_RG6_STORE_LTR0_SHIFT,
+		VIDC_1080P_COMMON_CHX_RG6_STORE_LTR0_BMASK);
+	frame_insertion |= VIDC_SETFIELD(param->store_ltr1,
+		VIDC_1080P_COMMON_CHX_RG6_STORE_LTR1_SHIFT,
+		VIDC_1080P_COMMON_CHX_RG6_STORE_LTR1_BMASK);
+	frame_insertion |= VIDC_SETFIELD(param->use_ltr0,
+		VIDC_1080P_COMMON_CHX_RG6_USE_LTR0_SHIFT,
+		VIDC_1080P_COMMON_CHX_RG6_USE_LTR0_BMASK);
+	frame_insertion |= VIDC_SETFIELD(param->use_ltr1,
+		VIDC_1080P_COMMON_CHX_RG6_USE_LTR1_SHIFT,
+		VIDC_1080P_COMMON_CHX_RG6_USE_LTR1_BMASK);
+	VIDC_HWIO_OUT(REG_887095, frame_insertion);
 	VIDC_HWIO_OUT(REG_652528, param->shared_mem_addr_offset);
 	input_flush = VIDC_SETFIELD(param->input_flush,
 			VIDC_1080P_SI_RG10_ENCODE_INPUT_BUFFER_FLUSH_SHFT,
diff --git a/drivers/video/msm/vidc/1080p/ddl/vidc.h b/drivers/video/msm/vidc/1080p/ddl/vidc.h
index dd4ac37..d8976bd 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vidc.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vidc.h
@@ -401,6 +401,10 @@
 	u32 intra_frame;
 	u32 input_flush;
 	u32 slice_enable;
+	u32 store_ltr0;
+	u32 store_ltr1;
+	u32 use_ltr0;
+	u32 use_ltr1;
 	enum vidc_1080p_encode encode;
 };
 struct vidc_1080p_enc_frame_info{
diff --git a/drivers/video/msm/vidc/common/enc/venc.c b/drivers/video/msm/vidc/common/enc/venc.c
index 8714a0c2..b57ef74 100644
--- a/drivers/video/msm/vidc/common/enc/venc.c
+++ b/drivers/video/msm/vidc/common/enc/venc.c
@@ -260,6 +260,9 @@
 		/* Metadata offset */
 		venc_msg->venc_msg_info.buf.metadata_offset =
 			vcd_frame_data->metadata_offset;
+		/* Current ltr id */
+		venc_msg->venc_msg_info.buf.metadata_ltrid =
+			vcd_frame_data->curr_ltr_id;
 
 		/* Decoded picture width and height */
 		venc_msg->venc_msg_info.msgdata_size =
@@ -343,6 +346,13 @@
 			VEN_MSG_PAUSE;
 		break;
 
+	case VCD_EVT_IND_INFO_LTRUSE_FAILED:
+		INFO("\n msm_vidc_enc: Sending VEN_MSG_LTRUSE_FAILED"\
+			" to client");
+		venc_msg->venc_msg_info.msgcode =
+			VEN_MSG_LTRUSE_FAILED;
+		break;
+
 	default:
 		ERR("%s() : unknown event type %u\n",
 			__func__, event);
@@ -400,6 +410,7 @@
 	case VCD_EVT_IND_OUTPUT_RECONFIG:
 	case VCD_EVT_IND_HWERRFATAL:
 	case VCD_EVT_IND_RESOURCES_LOST:
+	case VCD_EVT_IND_INFO_LTRUSE_FAILED:
 		vid_enc_lean_event(client_ctx, event, status);
 		break;
 
@@ -1777,6 +1788,143 @@
 			return -EFAULT;
 		break;
 	}
+	case VEN_IOCTL_SET_LTRMODE:
+	case VEN_IOCTL_GET_LTRMODE:
+	{
+		struct venc_ltrmode encoder_ltrmode;
+		if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
+			return -EFAULT;
+		if (cmd == VEN_IOCTL_SET_LTRMODE) {
+			DBG("VEN_IOCTL_SET_LTRMODE\n");
+			if (copy_from_user(&encoder_ltrmode, venc_msg.in,
+				sizeof(encoder_ltrmode)))
+				return -EFAULT;
+			result = vid_enc_set_get_ltrmode(client_ctx,
+				&encoder_ltrmode, true);
+		} else {
+			DBG("VEN_IOCTL_GET_LTRMODE\n");
+			result = vid_enc_set_get_ltrmode(client_ctx,
+				&encoder_ltrmode, false);
+			if (result) {
+				if (copy_to_user(venc_msg.out, &encoder_ltrmode,
+					sizeof(encoder_ltrmode)))
+					return -EFAULT;
+			}
+		}
+		if (!result) {
+			ERR("VEN_IOCTL_(G)SET_LTRMODE failed\n");
+			return -EIO;
+		}
+		break;
+	}
+	case VEN_IOCTL_SET_LTRCOUNT:
+	case VEN_IOCTL_GET_LTRCOUNT:
+	{
+		struct venc_ltrcount encoder_ltrcount;
+		if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
+			return -EFAULT;
+		if (cmd == VEN_IOCTL_SET_LTRCOUNT) {
+			DBG("VEN_IOCTL_SET_LTRCOUNT\n");
+			if (copy_from_user(&encoder_ltrcount, venc_msg.in,
+				sizeof(encoder_ltrcount)))
+				return -EFAULT;
+			result = vid_enc_set_get_ltrcount(client_ctx,
+				&encoder_ltrcount, true);
+		} else {
+			DBG("VEN_IOCTL_GET_LTRCOUNT\n");
+			result = vid_enc_set_get_ltrcount(client_ctx,
+				&encoder_ltrcount, false);
+			if (result) {
+				if (copy_to_user(venc_msg.out,
+					&encoder_ltrcount,
+					sizeof(encoder_ltrcount)))
+					return -EFAULT;
+			}
+		}
+		if (!result) {
+			ERR("VEN_IOCTL_(G)SET_LTRCOUNT failed\n");
+			return -EIO;
+		}
+		break;
+	}
+	case VEN_IOCTL_SET_LTRPERIOD:
+	case VEN_IOCTL_GET_LTRPERIOD:
+	{
+		struct venc_ltrperiod encoder_ltrperiod;
+		if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
+			return -EFAULT;
+		if (cmd == VEN_IOCTL_SET_LTRPERIOD) {
+			DBG("VEN_IOCTL_SET_LTRPERIOD\n");
+			if (copy_from_user(&encoder_ltrperiod, venc_msg.in,
+				sizeof(encoder_ltrperiod)))
+				return -EFAULT;
+			result = vid_enc_set_get_ltrperiod(client_ctx,
+				&encoder_ltrperiod, true);
+		} else {
+			DBG("VEN_IOCTL_GET_LTRPERIOD\n");
+			result = vid_enc_set_get_ltrperiod(client_ctx,
+				&encoder_ltrperiod, false);
+			if (result) {
+				if (copy_to_user(venc_msg.out,
+					&encoder_ltrperiod,
+					sizeof(encoder_ltrperiod)))
+					return -EFAULT;
+			}
+		}
+		if (!result) {
+			ERR("VEN_IOCTL_(G)SET_LTRPERIOD failed\n");
+			return -EIO;
+		}
+		break;
+	}
+	case VEN_IOCTL_GET_CAPABILITY_LTRCOUNT:
+	{
+		struct venc_range venc_capltrcount;
+		if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
+			return -EFAULT;
+			DBG("VEN_IOCTL_GET_CAPABILITY_LTRCOUNT\n");
+			result = vid_enc_get_capability_ltrcount(client_ctx,
+				&venc_capltrcount);
+			if (result) {
+				if (copy_to_user(venc_msg.out, &venc_capltrcount,
+					sizeof(venc_capltrcount)))
+					return -EFAULT;
+			} else {
+				ERR("VEN_IOCTL_GET_CAPABILITY_LTRCOUNT failed\n");
+				return -EIO;
+			}
+			break;
+	}
+	case VEN_IOCTL_SET_LTRUSE:
+	case VEN_IOCTL_GET_LTRUSE:
+	{
+		struct venc_ltruse encoder_ltruse;
+		if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
+			return -EFAULT;
+		if (cmd == VEN_IOCTL_SET_LTRUSE) {
+			DBG("VEN_IOCTL_SET_LTRUSE\n");
+			if (copy_from_user(&encoder_ltruse, venc_msg.in,
+				sizeof(encoder_ltruse)))
+				return -EFAULT;
+			result = vid_enc_set_get_ltruse(client_ctx,
+				&encoder_ltruse, true);
+		} else {
+			DBG("VEN_IOCTL_GET_LTRUSE\n");
+			result = vid_enc_set_get_ltruse(client_ctx,
+				&encoder_ltruse, false);
+			if (result) {
+				if (copy_to_user(venc_msg.out,
+					&encoder_ltruse,
+					sizeof(encoder_ltruse)))
+					return -EFAULT;
+			}
+		}
+		if (!result) {
+			ERR("VEN_IOCTL_(G)SET_LTRUSE failed\n");
+			return -EIO;
+		}
+		break;
+	}
 	case VEN_IOCTL_SET_AC_PREDICTION:
 	case VEN_IOCTL_GET_AC_PREDICTION:
 	case VEN_IOCTL_SET_RVLC:
diff --git a/drivers/video/msm/vidc/common/enc/venc_internal.c b/drivers/video/msm/vidc/common/enc/venc_internal.c
index 136d5ee..9d9fdc1 100644
--- a/drivers/video/msm/vidc/common/enc/venc_internal.c
+++ b/drivers/video/msm/vidc/common/enc/venc_internal.c
@@ -360,6 +360,42 @@
 	return true;
 }
 
+u32 vid_enc_set_get_extradata_cfg(struct video_client_ctx *client_ctx,
+		u32 *extradata_flag, u32 set_flag)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_meta_data_enable vcd_meta_data;
+	u32 vcd_status = VCD_ERR_FAIL;
+	if (!client_ctx || !extradata_flag)
+		return false;
+	vcd_property_hdr.prop_id = VCD_I_METADATA_ENABLE;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_meta_data_enable);
+	if (set_flag) {
+		DBG("vcd_set_property: VCD_I_METADATA_ENABLE = %d\n",
+			*extradata_flag);
+		vcd_meta_data.meta_data_enable_flag = *extradata_flag;
+		vcd_status = vcd_set_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &vcd_meta_data);
+		if (vcd_status) {
+			ERR("%s(): Set VCD_I_METADATA_ENABLE Failed\n",
+				__func__);
+			return false;
+		}
+	} else {
+		vcd_status = vcd_get_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &vcd_meta_data);
+		if (vcd_status) {
+			ERR("%s(): Get VCD_I_METADATA_ENABLE Failed\n",
+				__func__);
+			return false;
+		}
+		*extradata_flag = vcd_meta_data.meta_data_enable_flag;
+		DBG("vcd_get_property: VCD_I_METADATA_ENABLE = 0x%x\n",
+			(u32)*extradata_flag);
+	}
+	return true;
+}
+
 u32 vid_enc_set_get_framerate(struct video_client_ctx *client_ctx,
 		struct venc_framerate *frame_rate, u32 set_flag)
 {
@@ -2046,3 +2082,215 @@
 		return true;
 	}
 }
+
+u32 vid_enc_set_get_ltrmode(struct video_client_ctx *client_ctx,
+		struct venc_ltrmode *venc_ltrmode, u32 set_flag)
+{
+	struct vcd_property_ltrmode_type vcd_property_ltrmode;
+	struct vcd_property_hdr vcd_property_hdr;
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	if (!client_ctx || !venc_ltrmode)
+		return false;
+
+	vcd_property_hdr.prop_id = VCD_I_LTR_MODE;
+	vcd_property_hdr.sz =
+		sizeof(struct vcd_property_ltrmode_type);
+
+	if (set_flag) {
+		vcd_property_ltrmode.ltr_mode = (enum vcd_property_ltrmode)
+			venc_ltrmode->ltr_mode;
+		DBG("%s: Set ltr_mode = %u", __func__,
+			(u32)vcd_property_ltrmode.ltr_mode);
+		vcd_status = vcd_set_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &vcd_property_ltrmode);
+		if (vcd_status) {
+			ERR("%s(): Set VCD_I_LTR_MODE Failed\n",
+				__func__);
+			return false;
+		}
+	} else {
+		vcd_status = vcd_get_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &vcd_property_ltrmode);
+		if (vcd_status) {
+			ERR("%s(): Get VCD_I_LTR_MODE Failed\n",
+				__func__);
+			return false;
+		} else {
+			venc_ltrmode->ltr_mode = (unsigned long)
+				vcd_property_ltrmode.ltr_mode;
+			DBG("%s: Got ltr_mode = %u", __func__,
+				(u32)vcd_property_ltrmode.ltr_mode);
+		}
+	}
+
+	return true;
+}
+
+u32 vid_enc_set_get_ltrcount(struct video_client_ctx *client_ctx,
+		struct venc_ltrcount *venc_ltrcount, u32 set_flag)
+{
+	struct vcd_property_ltrcount_type vcd_property_ltrcount;
+	struct vcd_property_hdr vcd_property_hdr;
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	if (!client_ctx || !venc_ltrcount)
+		return false;
+
+	vcd_property_hdr.prop_id = VCD_I_LTR_COUNT;
+	vcd_property_hdr.sz =
+		sizeof(struct vcd_property_ltrcount_type);
+
+	if (set_flag) {
+		vcd_property_ltrcount.ltr_count = (u32)
+			venc_ltrcount->ltr_count;
+		DBG("%s: Set ltr_count = %u", __func__,
+			(u32)vcd_property_ltrcount.ltr_count);
+		vcd_status = vcd_set_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &vcd_property_ltrcount);
+		if (vcd_status) {
+			ERR("%s(): Set VCD_I_LTR_COUNT Failed\n",
+				__func__);
+			return false;
+		}
+	} else {
+		vcd_status = vcd_get_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &vcd_property_ltrcount);
+		if (vcd_status) {
+			ERR("%s(): Get VCD_I_LTR_COUNT Failed\n",
+				__func__);
+			return false;
+		} else {
+			venc_ltrcount->ltr_count = (unsigned long)
+				vcd_property_ltrcount.ltr_count;
+			DBG("%s: Got ltr_count = %u", __func__,
+				(u32)vcd_property_ltrcount.ltr_count);
+		}
+	}
+
+	return true;
+}
+
+u32 vid_enc_set_get_ltrperiod(struct video_client_ctx *client_ctx,
+		struct venc_ltrperiod *venc_ltrperiod, u32 set_flag)
+{
+	struct vcd_property_ltrperiod_type vcd_property_ltrperiod;
+	struct vcd_property_hdr vcd_property_hdr;
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	if (!client_ctx || !venc_ltrperiod)
+		return false;
+
+	vcd_property_hdr.prop_id = VCD_I_LTR_PERIOD;
+	vcd_property_hdr.sz =
+		sizeof(struct vcd_property_ltrperiod_type);
+
+	if (set_flag) {
+		vcd_property_ltrperiod.ltr_period = (u32)
+			venc_ltrperiod->ltr_period;
+		DBG("%s: Set ltr_period = %u", __func__,
+			(u32)vcd_property_ltrperiod.ltr_period);
+		vcd_status = vcd_set_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &vcd_property_ltrperiod);
+		if (vcd_status) {
+			ERR("%s(): Set VCD_I_LTR_PERIOD Failed\n",
+				__func__);
+			return false;
+		}
+	} else {
+		vcd_status = vcd_get_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &vcd_property_ltrperiod);
+		if (vcd_status) {
+			ERR("%s(): Get VCD_I_LTR_PERIOD Failed\n",
+				__func__);
+			return false;
+		} else {
+			venc_ltrperiod->ltr_period = (unsigned long)
+				vcd_property_ltrperiod.ltr_period;
+			DBG("%s: Got ltr_period = %u", __func__,
+				(u32)vcd_property_ltrperiod.ltr_period);
+		}
+	}
+
+	return true;
+}
+
+u32 vid_enc_set_get_ltruse(struct video_client_ctx *client_ctx,
+		struct venc_ltruse *venc_ltruse, u32 set_flag)
+{
+	struct vcd_property_ltruse_type vcd_property_ltruse;
+	struct vcd_property_hdr vcd_property_hdr;
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	if (!client_ctx || !venc_ltruse)
+		return false;
+
+	vcd_property_hdr.prop_id = VCD_I_LTR_USE;
+	vcd_property_hdr.sz =
+		sizeof(struct vcd_property_ltruse_type);
+
+	if (set_flag) {
+		vcd_property_ltruse.ltr_id = (u32)
+			venc_ltruse->ltr_id;
+		vcd_property_ltruse.ltr_frames = (u32)
+			venc_ltruse->ltr_frames;
+		DBG("%s: Set ltr_id = %u, ltr_frames = %u",
+			__func__, vcd_property_ltruse.ltr_id,
+			vcd_property_ltruse.ltr_frames);
+		vcd_status = vcd_set_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &vcd_property_ltruse);
+		if (vcd_status) {
+			ERR("%s(): Set VCD_I_LTR_USE Failed\n",
+				__func__);
+			return false;
+		}
+	} else {
+		vcd_status = vcd_get_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &vcd_property_ltruse);
+		if (vcd_status) {
+			ERR("%s(): Get VCD_I_LTR_USE Failed\n",
+				__func__);
+			return false;
+		} else {
+			venc_ltruse->ltr_id = (unsigned long)
+				vcd_property_ltruse.ltr_id;
+			venc_ltruse->ltr_frames = (unsigned long)
+				vcd_property_ltruse.ltr_frames;
+			DBG("%s: Got ltr_id = %u, ltr_frames = %u",
+				__func__, vcd_property_ltruse.ltr_id,
+				vcd_property_ltruse.ltr_frames);
+		}
+	}
+
+	return true;
+}
+
+u32 vid_enc_get_capability_ltrcount(struct video_client_ctx *client_ctx,
+		struct venc_range *venc_capltrcount)
+{
+	struct vcd_property_range_type vcd_property_range;
+	struct vcd_property_hdr vcd_property_hdr;
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	if (!client_ctx || !venc_capltrcount)
+		return false;
+
+	vcd_property_hdr.prop_id = VCD_I_CAPABILITY_LTR_COUNT;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_range_type);
+	vcd_status = vcd_get_property(client_ctx->vcd_handle,
+		&vcd_property_hdr, &vcd_property_range);
+	if (vcd_status) {
+		ERR("%s(): Get VCD_I_CAPABILITY_LTR_COUNT Failed\n",
+			__func__);
+		return false;
+	} else {
+		venc_capltrcount->min = vcd_property_range.min;
+		venc_capltrcount->max = vcd_property_range.max;
+		venc_capltrcount->step_size = vcd_property_range.step_size;
+		DBG("%s: Got min: %lu, max: %lu, step_size: %lu", __func__,
+			venc_capltrcount->min, venc_capltrcount->max,
+			venc_capltrcount->step_size);
+	}
+
+	return true;
+}
diff --git a/drivers/video/msm/vidc/common/enc/venc_internal.h b/drivers/video/msm/vidc/common/enc/venc_internal.h
index 1d32b26..397babf 100644
--- a/drivers/video/msm/vidc/common/enc/venc_internal.h
+++ b/drivers/video/msm/vidc/common/enc/venc_internal.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -155,4 +155,19 @@
 u32 vid_enc_get_curr_perf_level(struct video_client_ctx *client_ctx,
 		u32 *curr_perf_level);
 
+u32 vid_enc_set_get_ltrmode(struct video_client_ctx *client_ctx,
+		struct venc_ltrmode *encoder_ltrmode, u32 set_flag);
+
+u32 vid_enc_set_get_ltrcount(struct video_client_ctx *client_ctx,
+		struct venc_ltrcount *encoder_ltrcount, u32 set_flag);
+
+u32 vid_enc_set_get_ltrperiod(struct video_client_ctx *client_ctx,
+		struct venc_ltrperiod *encoder_ltrperiod, u32 set_flag);
+
+u32 vid_enc_get_capability_ltrcount(struct video_client_ctx *client_ctx,
+		struct venc_range *venc_capltrcount);
+
+u32 vid_enc_set_get_ltruse(struct video_client_ctx *client_ctx,
+		struct venc_ltruse *encoder_ltruse, u32 set_flag);
+
 #endif
diff --git a/drivers/video/msm/vidc/common/vcd/vcd.h b/drivers/video/msm/vidc/common/vcd/vcd.h
index 48583b7..185d811 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd.h
+++ b/drivers/video/msm/vidc/common/vcd/vcd.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -403,4 +403,7 @@
 struct vcd_transc *vcd_get_first_in_use_trans_for_clnt(
 	struct vcd_clnt_ctxt *cctxt);
 
+u32 vcd_handle_ltr_use_failed(struct vcd_clnt_ctxt *cctxt,
+	void *payload, size_t sz, u32 status);
+
 #endif
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c b/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
index 36d312d..fc5d650 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
@@ -980,6 +980,12 @@
 			vcd_handle_ind_info_output_reconfig(cctxt, status);
 			break;
 		}
+	case VCD_EVT_IND_INFO_LTRUSE_FAILED:
+		{
+			rc = vcd_handle_ltr_use_failed(cctxt,
+				payload, sz, status);
+			break;
+		}
 	default:
 		{
 			VCD_MSG_ERROR
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_sub.c b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
index 204dee4..c342191 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_sub.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
@@ -3588,3 +3588,14 @@
 	}
 	return rc;
 }
+
+u32 vcd_handle_ltr_use_failed(struct vcd_clnt_ctxt *cctxt,
+	void *payload, size_t sz, u32 status)
+{
+	u32 rc = VCD_S_SUCCESS;
+	if (payload && cctxt) {
+		cctxt->callback(VCD_EVT_IND_INFO_LTRUSE_FAILED,
+			status, payload, sz, cctxt, cctxt->client_data);
+	}
+	return rc;
+}
diff --git a/include/linux/msm_vidc_enc.h b/include/linux/msm_vidc_enc.h
index 8d191bf..6c7ceec 100644
--- a/include/linux/msm_vidc_enc.h
+++ b/include/linux/msm_vidc_enc.h
@@ -44,6 +44,7 @@
 #define VEN_MSG_PAUSE	8
 #define VEN_MSG_RESUME	9
 #define VEN_MSG_STOP_READING_MSG	10
+#define VEN_MSG_LTRUSE_FAILED 11
 
 /*Buffer flags bits masks*/
 #define VEN_BUFFLAG_EOS	0x00000001
@@ -56,6 +57,7 @@
 #define VEN_EXTRADATA_NONE          0x001
 #define VEN_EXTRADATA_QCOMFILLER    0x002
 #define VEN_EXTRADATA_SLICEINFO     0x100
+#define VEN_EXTRADATA_LTRINFO       0x200
 
 /*ENCODER CONFIGURATION CONSTANTS*/
 
@@ -472,6 +474,53 @@
 #define VEN_IOCTL_GET_PERF_LEVEL \
 	_IOR(VEN_IOCTLBASE_ENC, 53, struct venc_ioctl_msg)
 
+/*IOCTL params:SET: InputData - venc_range, OutputData - NULL.*/
+#define VEN_IOCTL_SET_CAPABILITY_LTRCOUNT \
+	_IOW(VEN_IOCTLBASE_ENC, 54, struct venc_ioctl_msg)
+/*IOCTL params:GET: InputData - NULL, OutputData - venc_range.*/
+#define VEN_IOCTL_GET_CAPABILITY_LTRCOUNT \
+	_IOR(VEN_IOCTLBASE_ENC, 55, struct venc_ioctl_msg)
+
+/*IOCTL params:SET: InputData - venc_ltrmode, OutputData - NULL.*/
+#define VEN_IOCTL_SET_LTRMODE \
+	_IOW(VEN_IOCTLBASE_ENC, 56, struct venc_ioctl_msg)
+/*IOCTL params:GET: InputData - NULL, OutputData - venc_ltrmode.*/
+#define VEN_IOCTL_GET_LTRMODE \
+	_IOR(VEN_IOCTLBASE_ENC, 57, struct venc_ioctl_msg)
+
+/*IOCTL params:SET: InputData - venc_ltrcount, OutputData - NULL.*/
+#define VEN_IOCTL_SET_LTRCOUNT \
+	_IOW(VEN_IOCTLBASE_ENC, 58, struct venc_ioctl_msg)
+/*IOCTL params:GET: InputData - NULL, OutputData - venc_ltrcount.*/
+#define VEN_IOCTL_GET_LTRCOUNT \
+	_IOR(VEN_IOCTLBASE_ENC, 59, struct venc_ioctl_msg)
+
+/*IOCTL params:SET: InputData - venc_ltrperiod, OutputData - NULL.*/
+#define VEN_IOCTL_SET_LTRPERIOD \
+	_IOW(VEN_IOCTLBASE_ENC, 60, struct venc_ioctl_msg)
+/*IOCTL params:GET: InputData - NULL, OutputData - venc_ltrperiod.*/
+#define VEN_IOCTL_GET_LTRPERIOD \
+	_IOR(VEN_IOCTLBASE_ENC, 61, struct venc_ioctl_msg)
+
+/*IOCTL params:SET: InputData - venc_ltruse, OutputData - NULL.*/
+#define VEN_IOCTL_SET_LTRUSE \
+	_IOW(VEN_IOCTLBASE_ENC, 62, struct venc_ioctl_msg)
+/*IOCTL params:GET: InputData - NULL, OutputData - venc_ltruse.*/
+#define VEN_IOCTL_GET_LTRUSE \
+	_IOR(VEN_IOCTLBASE_ENC, 63, struct venc_ioctl_msg)
+
+/*IOCTL params:SET: InputData - venc_ltrmark, OutputData - NULL.*/
+#define VEN_IOCTL_SET_LTRMARK \
+	_IOW(VEN_IOCTLBASE_ENC, 64, struct venc_ioctl_msg)
+/*IOCTL params:GET: InputData - NULL, OutputData - venc_ltrmark.*/
+#define VEN_IOCTL_GET_LTRMARK \
+	_IOR(VEN_IOCTLBASE_ENC, 65, struct venc_ioctl_msg)
+
+struct venc_range {
+	unsigned long        max;
+	unsigned long        min;
+	unsigned long        step_size;
+};
 
 struct venc_switch{
 	unsigned char	status;
@@ -506,6 +555,7 @@
  void	*clientdata;
 	unsigned long	metadata_len;
 	unsigned long	metadata_offset;
+	unsigned long	metadata_ltrid;
 };
 
 struct venc_basecfg{
@@ -631,4 +681,21 @@
 	int alignment;
 };
 
+struct venc_ltrmode {
+	unsigned long ltr_mode;
+};
+
+struct venc_ltrcount {
+	unsigned long ltr_count;
+};
+
+struct venc_ltrperiod {
+	unsigned long ltr_period;
+};
+
+struct venc_ltruse {
+	unsigned long ltr_id;
+	unsigned long ltr_frames;
+};
+
 #endif /* _MSM_VIDC_ENC_H_ */
diff --git a/include/media/msm/vcd_api.h b/include/media/msm/vcd_api.h
index ec535ce5..a6ceb4d 100644
--- a/include/media/msm/vcd_api.h
+++ b/include/media/msm/vcd_api.h
@@ -80,6 +80,7 @@
 	struct vcd_aspect_ratio aspect_ratio_info;
 	u32 metadata_len;
 	u32 metadata_offset;
+	u32 curr_ltr_id;
 };
 
 struct vcd_sequence_hdr {
diff --git a/include/media/msm/vcd_property.h b/include/media/msm/vcd_property.h
index 8bcac81..8b8f1ad 100644
--- a/include/media/msm/vcd_property.h
+++ b/include/media/msm/vcd_property.h
@@ -62,6 +62,12 @@
 #define VCD_I_ENABLE_SEC_METADATA (VCD_START_BASE + 0x2E)
 #define VCD_I_ENABLE_VUI_BITSTREAM_RESTRICT_FLAG (VCD_START_BASE + 0x2F)
 #define VCD_I_GET_CURR_PERF_LEVEL (VCD_START_BASE + 0x30)
+#define VCD_I_LTR_MODE (VCD_START_BASE + 0x31)
+#define VCD_I_LTR_COUNT (VCD_START_BASE + 0x32)
+#define VCD_I_LTR_PERIOD (VCD_START_BASE + 0x33)
+#define VCD_I_LTR_USE (VCD_START_BASE + 0x34)
+#define VCD_I_CAPABILITY_LTR_COUNT (VCD_START_BASE + 0x35)
+#define VCD_I_LTR_MARK (VCD_START_BASE + 0x36)
 
 #define VCD_START_REQ      (VCD_START_BASE + 0x1000)
 #define VCD_I_REQ_IFRAME   (VCD_START_REQ + 0x1)
@@ -119,6 +125,7 @@
 #define VCD_METADATA_VC1            0x040
 #define VCD_METADATA_PASSTHROUGH    0x080
 #define VCD_METADATA_ENC_SLICE      0x100
+#define VCD_METADATA_LTR_INFO       0x200
 
 #define VCD_METADATA_EXT_DATA       0x0800
 #define VCD_METADATA_USER_DATA      0x1000
@@ -409,4 +416,35 @@
 struct vcd_property_bitstream_restrict_enable {
 	u32 bitstream_restrict_enable_flag;
 };
+
+struct vcd_property_range_type {
+	u32 min;
+	u32 max;
+	u32 step_size;
+};
+
+enum vcd_property_ltrmode {
+	VCD_LTR_MODE_DISABLE = 0,
+	VCD_LTR_MODE_MANUAL = 1,
+	VCD_LTR_MODE_AUTO = 2,
+	VCD_LTR_MODE_MAX = 0x7fffffff
+};
+
+struct vcd_property_ltrmode_type {
+	enum vcd_property_ltrmode ltr_mode;
+};
+
+struct vcd_property_ltrcount_type {
+	u32 ltr_count;
+};
+
+struct vcd_property_ltrperiod_type {
+	u32 ltr_period;
+};
+
+struct vcd_property_ltruse_type {
+	u32 ltr_id;
+	u32 ltr_frames;
+};
+
 #endif
diff --git a/include/media/msm/vcd_status.h b/include/media/msm/vcd_status.h
index 9b67ed0..f8270c2 100644
--- a/include/media/msm/vcd_status.h
+++ b/include/media/msm/vcd_status.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -33,6 +33,7 @@
 #define VCD_EVT_IND_RESOURCES_LOST        (VCD_EVT_IND_BASE + 0x4)
 #define VCD_EVT_IND_INFO_OUTPUT_RECONFIG  (VCD_EVT_IND_BASE + 0x5)
 #define VCD_EVT_IND_INFO_FIELD_DROPPED    (VCD_EVT_IND_BASE + 0x6)
+#define VCD_EVT_IND_INFO_LTRUSE_FAILED    (VCD_EVT_IND_BASE + 0x7)
 
 #define VCD_S_SUCCESS           0x0