Merge "msm: camera: isp: Enable RDI and DS4/DS16 support in VFE" into msm-4.9
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c
index 366ac8a..bf4d174 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c
@@ -106,6 +106,7 @@
 	struct list_head                th_list_head[CAM_IRQ_PRIORITY_MAX];
 	uint32_t                        hdl_idx;
 	rwlock_t                        rw_lock;
+	struct cam_irq_th_payload       th_payload;
 };
 
 int cam_irq_controller_deinit(void **irq_controller)
@@ -118,11 +119,13 @@
 			&controller->evt_handler_list_head,
 			struct cam_irq_evt_handler, list_node);
 		list_del_init(&evt_handler->list_node);
+		kfree(evt_handler->evt_bit_mask_arr);
 		kfree(evt_handler);
 	}
 
-	kfree(controller->irq_register_arr);
+	kfree(controller->th_payload.evt_status_arr);
 	kfree(controller->irq_status_arr);
+	kfree(controller->irq_register_arr);
 	kfree(controller);
 	*irq_controller = NULL;
 	return 0;
@@ -166,6 +169,16 @@
 		rc = -ENOMEM;
 		goto status_alloc_error;
 	}
+
+	controller->th_payload.evt_status_arr =
+		kzalloc(register_info->num_registers * sizeof(uint32_t),
+		GFP_KERNEL);
+	if (!controller->th_payload.evt_status_arr) {
+		CDBG("Failed to allocate BH payload bit mask Arr\n");
+		rc = -ENOMEM;
+		goto evt_mask_alloc_error;
+	}
+
 	controller->name = name;
 
 	CDBG("num_registers: %d\n", register_info->num_registers);
@@ -206,6 +219,8 @@
 
 	return rc;
 
+evt_mask_alloc_error:
+	kfree(controller->irq_status_arr);
 status_alloc_error:
 	kfree(controller->irq_register_arr);
 reg_alloc_error:
@@ -415,9 +430,10 @@
 	struct list_head               *th_list_head)
 {
 	struct cam_irq_evt_handler     *evt_handler = NULL;
-	struct cam_irq_th_payload       th_payload;
+	struct cam_irq_th_payload      *th_payload = &controller->th_payload;
 	bool                            is_irq_match;
 	int                             rc = -EINVAL;
+	int                             i;
 
 	CDBG("Enter\n");
 
@@ -433,10 +449,14 @@
 
 		CDBG("match found\n");
 
-		cam_irq_th_payload_init(&th_payload);
-		th_payload.handler_priv   = evt_handler->handler_priv;
-		th_payload.num_registers  = controller->num_registers;
-		th_payload.evt_status_arr = controller->irq_status_arr;
+		cam_irq_th_payload_init(th_payload);
+		th_payload->handler_priv  = evt_handler->handler_priv;
+		th_payload->num_registers = controller->num_registers;
+		for (i = 0; i < controller->num_registers; i++) {
+			th_payload->evt_status_arr[i] =
+				controller->irq_status_arr[i] &
+				evt_handler->evt_bit_mask_arr[i];
+		}
 
 		/*
 		 * irq_status_arr[0] is dummy argument passed. the entire
@@ -445,8 +465,7 @@
 		if (evt_handler->top_half_handler)
 			rc = evt_handler->top_half_handler(
 				controller->irq_status_arr[0],
-				(void *)&th_payload);
-
+				(void *)th_payload);
 
 		if (!rc && evt_handler->bottom_half_handler) {
 			CDBG("Enqueuing bottom half\n");
@@ -454,7 +473,7 @@
 				evt_handler->bottom_half_enqueue_func(
 					evt_handler->bottom_half,
 					evt_handler->handler_priv,
-					th_payload.evt_payload_priv,
+					th_payload->evt_payload_priv,
 					evt_handler->bottom_half_handler);
 			}
 		}
@@ -465,9 +484,10 @@
 
 irqreturn_t cam_irq_controller_handle_irq(int irq_num, void *priv)
 {
-	struct cam_irq_controller      *controller  = priv;
-	int i, j;
-	bool need_th_processing[CAM_IRQ_PRIORITY_MAX] = {false};
+	struct cam_irq_controller  *controller  = priv;
+	bool         need_th_processing[CAM_IRQ_PRIORITY_MAX] = {false};
+	int          i;
+	int          j;
 
 	if (!controller)
 		return IRQ_NONE;
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.h
index 2f88a8b..1990c51 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.h
@@ -103,7 +103,6 @@
 	struct cam_irq_th_payload *th_payload) {
 	th_payload->handler_priv = NULL;
 	th_payload->evt_payload_priv = NULL;
-	th_payload->evt_status_arr = NULL;
 }
 
 typedef int (*CAM_IRQ_HANDLER_TOP_HALF)(uint32_t evt_id,
@@ -215,4 +214,4 @@
  */
 irqreturn_t cam_irq_controller_handle_irq(int irq_num, void *priv);
 
-#endif /*_CAM_IRQ_CONTROLLER_H_ */
+#endif /* _CAM_IRQ_CONTROLLER_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c
index 488a00b..739a1e7 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c
@@ -23,6 +23,7 @@
 #include "cam_vfe_core.h"
 #include "cam_vfe_bus.h"
 #include "cam_vfe_top.h"
+#include "cam_ife_hw_mgr.h"
 
 #undef CDBG
 #define CDBG(fmt, args...) pr_debug(fmt, ##args)
@@ -35,11 +36,16 @@
 	0x0000007C,
 };
 
-static uint32_t top_irq_reg_mask[CAM_IFE_IRQ_REGISTERS_MAX] = {
-	0x7803FDFF,
+static uint32_t camif_irq_reg_mask[CAM_IFE_IRQ_REGISTERS_MAX] = {
+	0x0003FD1F,
 	0x0FFF7EB3,
 };
 
+static uint32_t rdi_irq_reg_mask[CAM_IFE_IRQ_REGISTERS_MAX] = {
+	0x780000e0,
+	0x00000000,
+};
+
 static uint32_t top_reset_irq_reg_mask[CAM_IFE_IRQ_REGISTERS_MAX] = {
 	0x80000000,
 	0x00000000,
@@ -440,11 +446,21 @@
 
 	mutex_lock(&vfe_hw->hw_mutex);
 	if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_IN) {
-		isp_res->irq_handle = cam_irq_controller_subscribe_irq(
-			core_info->vfe_irq_controller, CAM_IRQ_PRIORITY_2,
-			top_irq_reg_mask, &core_info->irq_payload,
-			cam_vfe_irq_top_half, NULL,
-			isp_res->tasklet_info, cam_tasklet_enqueue_cmd);
+		if (isp_res->res_id == CAM_ISP_HW_VFE_IN_CAMIF)
+			isp_res->irq_handle = cam_irq_controller_subscribe_irq(
+				core_info->vfe_irq_controller,
+				CAM_IRQ_PRIORITY_2,
+				camif_irq_reg_mask, &core_info->irq_payload,
+				cam_vfe_irq_top_half, cam_ife_mgr_do_tasklet,
+				isp_res->tasklet_info, cam_tasklet_enqueue_cmd);
+		else
+			isp_res->irq_handle = cam_irq_controller_subscribe_irq(
+				core_info->vfe_irq_controller,
+				CAM_IRQ_PRIORITY_2,
+				rdi_irq_reg_mask, &core_info->irq_payload,
+				cam_vfe_irq_top_half, cam_ife_mgr_do_tasklet,
+				isp_res->tasklet_info, cam_tasklet_enqueue_cmd);
+
 		if (isp_res->irq_handle > 0)
 			rc = core_info->vfe_top->hw_ops.start(
 				core_info->vfe_top->top_priv, isp_res,
@@ -456,7 +472,7 @@
 			core_info->vfe_irq_controller, CAM_IRQ_PRIORITY_1,
 			bus_irq_reg_mask, &core_info->irq_payload,
 			core_info->vfe_bus->top_half_handler,
-			NULL,
+			cam_ife_mgr_do_tasklet_buf_done,
 			isp_res->tasklet_info, cam_tasklet_enqueue_cmd);
 		if (isp_res->irq_handle > 0)
 			rc = core_info->vfe_bus->start_resource(isp_res);
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.h
index 92e322b..94b4cf0 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.h
@@ -43,7 +43,7 @@
 	struct cam_isp_reg_val_pair      *vbif_settings;
 };
 
-#define CAM_VFE_EVT_MAX                    128
+#define CAM_VFE_EVT_MAX                    256
 
 struct cam_vfe_hw_core_info {
 	struct cam_vfe_hw_info             *vfe_hw_info;
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c
index 48b0363..21494b5 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c
@@ -26,6 +26,8 @@
 #undef CDBG
 #define CDBG(fmt, args...) pr_debug(fmt, ##args)
 
+#define FRAME_BASED_EN 0
+
 static uint32_t irq_reg_offset[CAM_IFE_BUS_IRQ_REGISTERS_MAX] = {
 	0x0000205C,
 	0x00002060,
@@ -649,6 +651,11 @@
 		wm_res->res_priv;
 	struct cam_vfe_bus_ver2_common_data        *common_data =
 		rsrc_data->common_data;
+	uint32_t                                    width;
+	uint32_t                                    height;
+	uint32_t                                    pack_fmt;
+	uint32_t                                    stride;
+	uint32_t                                    en_cfg;
 
 	CDBG("WM res %d width = %d, height = %d\n", rsrc_data->index,
 		rsrc_data->width, rsrc_data->height);
@@ -657,22 +664,39 @@
 	CDBG("WM res %d stride = %d, burst len = %d\n",
 		rsrc_data->index, rsrc_data->width, 0xf);
 
-	cam_io_w_mb(0,
-		common_data->mem_base + rsrc_data->hw_regs->header_addr);
-	cam_io_w_mb(0,
-		common_data->mem_base + rsrc_data->hw_regs->header_cfg);
-	cam_io_w_mb(0,
-		common_data->mem_base + rsrc_data->hw_regs->frame_inc);
-	cam_io_w_mb(rsrc_data->width,
+	cam_io_w_mb(0, common_data->mem_base + rsrc_data->hw_regs->header_addr);
+	cam_io_w_mb(0, common_data->mem_base + rsrc_data->hw_regs->header_cfg);
+	cam_io_w_mb(0, common_data->mem_base + rsrc_data->hw_regs->frame_inc);
+	cam_io_w(0xf, common_data->mem_base + rsrc_data->hw_regs->burst_limit);
+
+	if (rsrc_data->index < 3) {
+		width = rsrc_data->width * 5/4;
+		height = 1;
+		pack_fmt = 0x0;
+		stride = rsrc_data->width * 5/4;
+		en_cfg = 0x3;
+	} else if (rsrc_data->index < 5) {
+		width = rsrc_data->width;
+		height = rsrc_data->height;
+		pack_fmt = 0xE;
+		stride = rsrc_data->width;
+		en_cfg = 0x1;
+	} else {
+		width = rsrc_data->width * 4;
+		height = rsrc_data->height / 2;
+		pack_fmt = 0x0;
+		stride = rsrc_data->width * 4;
+		en_cfg = 0x1;
+	}
+
+	cam_io_w_mb(width,
 		common_data->mem_base + rsrc_data->hw_regs->buffer_width_cfg);
-	cam_io_w(rsrc_data->height,
+	cam_io_w(height,
 		common_data->mem_base + rsrc_data->hw_regs->buffer_height_cfg);
-	cam_io_w(0xe,
+	cam_io_w(pack_fmt,
 		common_data->mem_base + rsrc_data->hw_regs->packer_cfg);
-	cam_io_w(rsrc_data->width,
+	cam_io_w(stride,
 		common_data->mem_base + rsrc_data->hw_regs->stride);
-	cam_io_w(0xf,
-		common_data->mem_base + rsrc_data->hw_regs->burst_limit);
 
 	cam_io_w(0xFFFFFFFF, common_data->mem_base +
 		rsrc_data->hw_regs->irq_subsample_pattern);
@@ -680,9 +704,9 @@
 		rsrc_data->hw_regs->irq_subsample_period);
 
 	cam_io_w(0xFFFFFFFF,
-	 common_data->mem_base + rsrc_data->hw_regs->framedrop_pattern);
+		common_data->mem_base + rsrc_data->hw_regs->framedrop_pattern);
 	cam_io_w(0x0,
-	 common_data->mem_base + rsrc_data->hw_regs->framedrop_period);
+		common_data->mem_base + rsrc_data->hw_regs->framedrop_period);
 
 	/* UBWC registers */
 	switch (rsrc_data->format) {
@@ -702,10 +726,16 @@
 	}
 
 	/* Enable WM */
-	cam_io_w_mb(0x1,
-		common_data->mem_base + rsrc_data->hw_regs->cfg);
-	CDBG("enable WM red %d offset 0x%x val 0x%x\n", rsrc_data->index,
-		(uint32_t) rsrc_data->hw_regs->cfg, 0x1);
+	cam_io_w_mb(en_cfg, common_data->mem_base + rsrc_data->hw_regs->cfg);
+
+	CDBG("WM res %d width = %d, height = %d\n", rsrc_data->index,
+		width, height);
+	CDBG("WM res %d pk_fmt = %d\n", rsrc_data->index,
+		pack_fmt & PACKER_FMT_MAX);
+	CDBG("WM res %d stride = %d, burst len = %d\n",
+		rsrc_data->index, stride, 0xf);
+	CDBG("enable WM res %d offset 0x%x val 0x%x\n", rsrc_data->index,
+		(uint32_t) rsrc_data->hw_regs->cfg, en_cfg);
 
 	wm_res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING;
 
@@ -754,14 +784,22 @@
 	int rc = CAM_VFE_IRQ_STATUS_ERR;
 	struct cam_isp_resource_node          *wm_res = wm_node;
 	struct cam_vfe_bus_irq_evt_payload    *evt_payload = evt_payload_priv;
-	struct cam_vfe_bus_ver2_wm_resource_data *rsrc_data = wm_res->res_priv;
-	uint32_t  *cam_ife_irq_regs = evt_payload->irq_reg_val;
+	struct cam_vfe_bus_ver2_wm_resource_data *rsrc_data =
+		(wm_res == NULL) ? NULL : wm_res->res_priv;
+	uint32_t  *cam_ife_irq_regs;
 	uint32_t   status_reg;
 
-	status_reg = cam_ife_irq_regs[CAM_IFE_IRQ_BUS_REG_STATUS0];
+	if (!evt_payload || !rsrc_data)
+		return rc;
 
-	if (status_reg & BIT(rsrc_data->index))
+	cam_ife_irq_regs = evt_payload->irq_reg_val;
+	status_reg = cam_ife_irq_regs[CAM_IFE_IRQ_BUS_REG_STATUS1];
+
+	if (status_reg & BIT(rsrc_data->index)) {
+		cam_ife_irq_regs[CAM_IFE_IRQ_BUS_REG_STATUS1] &=
+			~BIT(rsrc_data->index);
 		rc = CAM_VFE_IRQ_STATUS_SUCCESS;
+	}
 
 	if (rc == CAM_VFE_IRQ_STATUS_SUCCESS)
 		cam_vfe_bus_put_evt_payload(evt_payload->core_info,
@@ -974,9 +1012,6 @@
 	 * Individual Comp_Grp Subscribe IRQ can be done here once
 	 * dynamic IRQ enable support is added.
 	 */
-	cam_io_w_mb(0x00001F70, common_data->mem_base + 0x2044);
-	cam_io_w_mb(0x000FFFE7, common_data->mem_base + 0x2048);
-	cam_io_w_mb(0x000000FF, common_data->mem_base + 0x204c);
 
 	cam_io_w_mb(rsrc_data->composite_mask, common_data->mem_base +
 		rsrc_data->hw_regs->comp_mask);
@@ -1051,10 +1086,15 @@
 	struct cam_isp_resource_node          *comp_grp = handler_priv;
 	struct cam_vfe_bus_irq_evt_payload    *evt_payload = evt_payload_priv;
 	struct cam_vfe_bus_ver2_comp_grp_data *rsrc_data = comp_grp->res_priv;
-	uint32_t  *cam_ife_irq_regs = evt_payload->irq_reg_val;
-	uint32_t   status_reg;
-	uint32_t   comp_err_reg;
-	uint32_t   dual_comp_grp;
+	uint32_t                              *cam_ife_irq_regs;
+	uint32_t                               status_reg;
+	uint32_t                               comp_err_reg;
+	uint32_t                               comp_grp_id;
+
+	if (!evt_payload)
+		return rc;
+
+	cam_ife_irq_regs = evt_payload->irq_reg_val;
 
 	CDBG("comp grp type %d\n", rsrc_data->comp_grp_type);
 	switch (rsrc_data->comp_grp_type) {
@@ -1064,7 +1104,7 @@
 	case CAM_VFE_BUS_VER2_COMP_GRP_3:
 	case CAM_VFE_BUS_VER2_COMP_GRP_4:
 	case CAM_VFE_BUS_VER2_COMP_GRP_5:
-		dual_comp_grp = (rsrc_data->comp_grp_type -
+		comp_grp_id = (rsrc_data->comp_grp_type -
 			CAM_VFE_BUS_VER2_COMP_GRP_0);
 
 		/* Check for Regular composite error */
@@ -1086,12 +1126,15 @@
 			break;
 		}
 
-		/* Regular Composite SUCCESS*/
-		if (status_reg & BIT(dual_comp_grp + 5))
+		/* Regular Composite SUCCESS */
+		if (status_reg & BIT(comp_grp_id + 5)) {
+			cam_ife_irq_regs[CAM_IFE_IRQ_BUS_REG_STATUS0] &=
+				~BIT(comp_grp_id + 5);
 			rc = CAM_VFE_IRQ_STATUS_SUCCESS;
+		}
 
 		CDBG("status reg = 0x%x, bit index = %d\n",
-			status_reg, (dual_comp_grp + 5));
+			status_reg, (comp_grp_id + 5));
 		break;
 
 	case CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0:
@@ -1100,7 +1143,7 @@
 	case CAM_VFE_BUS_VER2_COMP_GRP_DUAL_3:
 	case CAM_VFE_BUS_VER2_COMP_GRP_DUAL_4:
 	case CAM_VFE_BUS_VER2_COMP_GRP_DUAL_5:
-		dual_comp_grp = (rsrc_data->comp_grp_type -
+		comp_grp_id = (rsrc_data->comp_grp_type -
 			CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0);
 
 		/* Check for DUAL composite error */
@@ -1122,12 +1165,14 @@
 			break;
 		}
 
-		/* DUAL Composite SUCCESS*/
-		if (status_reg & BIT(dual_comp_grp))
+		/* DUAL Composite SUCCESS */
+		if (status_reg & BIT(comp_grp_id)) {
+			cam_ife_irq_regs[CAM_IFE_IRQ_BUS_REG_STATUS2] &=
+				~BIT(comp_grp_id + 5);
 			rc = CAM_VFE_IRQ_STATUS_SUCCESS;
+		}
 
 		break;
-
 	default:
 		rc = CAM_VFE_IRQ_STATUS_ERR;
 		break;
@@ -1302,7 +1347,9 @@
 static int cam_vfe_bus_start_vfe_out(struct cam_isp_resource_node *vfe_out)
 {
 	int rc = 0, i;
-	struct cam_vfe_bus_ver2_vfe_out_data *rsrc_data = vfe_out->res_priv;
+	struct cam_vfe_bus_ver2_vfe_out_data  *rsrc_data = vfe_out->res_priv;
+	struct cam_vfe_bus_ver2_common_data   *common_data =
+		rsrc_data->common_data;
 
 	CDBG("Start resource index %d\n", rsrc_data->out_type);
 
@@ -1312,6 +1359,11 @@
 		return -EACCES;
 	}
 
+	/* Enable IRQ Mask */
+	cam_io_w_mb(0x00001F70, common_data->mem_base + 0x2044);
+	cam_io_w_mb(0x000FFFE7, common_data->mem_base + 0x2048);
+	cam_io_w_mb(0x000000FF, common_data->mem_base + 0x204c);
+
 	for (i = 0; i < rsrc_data->num_wm; i++)
 		rc = cam_vfe_bus_start_wm(rsrc_data->wm_res[i]);
 
@@ -1335,12 +1387,6 @@
 	cam_io_w_mb(0x0, rsrc_data->common_data->mem_base + 0x00002080);
 	/* BUS_WR_INPUT_IF_ADDR_SYNC_NO_SYNC */
 	cam_io_w_mb(0xFFFFF, rsrc_data->common_data->mem_base + 0x00002084);
-	/* no clock gating at bus input */
-	cam_io_w_mb(0xFFFFF, rsrc_data->common_data->mem_base + 0x0000200C);
-	/*  BUS_WR_PWR_ISO_CFG */
-	cam_io_w_mb(0x0, rsrc_data->common_data->mem_base + 0x000020CC);
-	/*  BUS_WR_TEST_BUS_CTRL */
-	cam_io_w_mb(0x0, rsrc_data->common_data->mem_base + 0x0000211C);
 	/*  BUS_WR_INPUT_IF_ADDR_SYNC_0 */
 	cam_io_w_mb(0x0, rsrc_data->common_data->mem_base + 0x00002088);
 	cam_io_w_mb(0x0, rsrc_data->common_data->mem_base + 0x0000208c);
@@ -1351,6 +1397,12 @@
 	cam_io_w_mb(0x0, rsrc_data->common_data->mem_base + 0x000020a0);
 	cam_io_w_mb(0x0, rsrc_data->common_data->mem_base + 0x000020a4);
 
+	/* no clock gating at bus input */
+	cam_io_w_mb(0xFFFFF, rsrc_data->common_data->mem_base + 0x0000200C);
+
+	/* BUS_WR_TEST_BUS_CTRL */
+	cam_io_w_mb(0x0, rsrc_data->common_data->mem_base + 0x0000211C);
+
 	return rc;
 }
 
@@ -1400,7 +1452,7 @@
 			rsrc_data->comp_grp, evt_payload_priv);
 	} else {
 		rc = rsrc_data->wm_res[0]->bottom_half_handler(
-			rsrc_data->comp_grp, evt_payload_priv);
+			rsrc_data->wm_res[0], evt_payload_priv);
 	}
 
 	return rc;
@@ -1449,6 +1501,7 @@
 	struct cam_vfe_bus_irq_evt_payload  **evt_payload)
 {
 	if (list_empty(&bus_priv->free_payload_list)) {
+		*evt_payload = NULL;
 		pr_err("No free payload\n");
 		return -ENODEV;
 	}
@@ -1463,6 +1516,16 @@
 	struct cam_vfe_bus_irq_evt_payload     **evt_payload)
 {
 	struct cam_vfe_bus_ver2_priv         *bus_priv = NULL;
+	uint32_t  *cam_ife_irq_regs = (*evt_payload)->irq_reg_val;
+	uint32_t   status_reg0, status_reg1;
+
+	status_reg0 = cam_ife_irq_regs[CAM_IFE_IRQ_BUS_REG_STATUS0];
+	status_reg1 = cam_ife_irq_regs[CAM_IFE_IRQ_BUS_REG_STATUS1];
+
+	if (status_reg0 || status_reg1) {
+		CDBG("status0 0x%x status1 0x%x\n", status_reg0, status_reg1);
+		return 0;
+	}
 
 	if (!core_info) {
 		pr_err("Invalid param core_info NULL");
@@ -1489,6 +1552,7 @@
 	struct cam_vfe_bus                    *bus_info;
 	struct cam_vfe_bus_ver2_priv          *bus_priv;
 	struct cam_irq_controller_reg_info    *reg_info;
+	uint32_t                               irq_mask;
 
 	handler_priv = th_payload->handler_priv;
 	core_info    = handler_priv->core_info;
@@ -1517,8 +1581,10 @@
 			(uint64_t)handler_priv->core_info);
 
 	for (i = 0; i < CAM_IFE_BUS_IRQ_REGISTERS_MAX; i++) {
-		evt_payload->irq_reg_val[i] = cam_io_r(handler_priv->mem_base +
-			irq_reg_offset[i]);
+		irq_mask = cam_io_r(handler_priv->mem_base +
+			irq_reg_offset[i] - (0xC * 2));
+		evt_payload->irq_reg_val[i] = irq_mask &
+			cam_io_r(handler_priv->mem_base + irq_reg_offset[i]);
 		CDBG("irq_status%d = 0x%x\n", i, evt_payload->irq_reg_val[i]);
 	}
 	for (i = 0; i <= CAM_IFE_IRQ_BUS_REG_STATUS2; i++) {
@@ -1546,7 +1612,7 @@
 	struct cam_isp_hw_get_buf_update         *update_buf;
 	struct cam_vfe_bus_ver2_vfe_out_data     *vfe_out_data = NULL;
 	struct cam_vfe_bus_ver2_wm_resource_data *wm_data = NULL;
-	uint32_t  reg_val_pair[6];
+	uint32_t  reg_val_pair[8];
 	uint32_t i, size = 0;
 
 	/*
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/Makefile b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/Makefile
index 56dc513..0a94746 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/Makefile
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/Makefile
@@ -7,4 +7,4 @@
 ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/include
 ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include
 
-obj-$(CONFIG_SPECTRA_CAMERA) += cam_vfe_top.o cam_vfe_top_ver2.o cam_vfe_camif_ver2.o
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_vfe_top.o cam_vfe_top_ver2.o cam_vfe_camif_ver2.o cam_vfe_rdi.o
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c
index ff56115..3f3c2a3 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c
@@ -124,7 +124,7 @@
 	cam_io_w_mb(0x1, rsrc_data->mem_base +
 			rsrc_data->camif_reg->irq_subsample_pattern);
 
-	/* epoch config with 20 line  */
+	/* epoch config with 20 line */
 	cam_io_w_mb(0x00140014,
 		rsrc_data->mem_base + rsrc_data->camif_reg->epoch_irq);
 
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c
new file mode 100644
index 0000000..5f77a7c
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c
@@ -0,0 +1,189 @@
+/* Copyright (c) 2017, 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
+
+#include <linux/slab.h>
+#include "cam_vfe_rdi.h"
+#include "cam_isp_hw_mgr_intf.h"
+#include "cam_vfe_hw_intf.h"
+#include "cam_io_util.h"
+
+#undef CDBG
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+
+struct cam_vfe_mux_rdi_data {
+	void __iomem                                *mem_base;
+	struct cam_hw_intf                          *hw_intf;
+	struct cam_vfe_top_ver2_reg_offset_common   *common_reg;
+
+	enum cam_isp_hw_sync_mode          sync_mode;
+};
+
+int cam_vfe_rdi_ver2_acquire_resource(
+	struct cam_isp_resource_node  *rdi_res,
+	void                          *acquire_param)
+{
+	struct cam_vfe_mux_rdi_data   *rdi_data;
+	struct cam_vfe_acquire_args   *acquire_data;
+
+	rdi_data     = (struct cam_vfe_mux_rdi_data *)rdi_res->res_priv;
+	acquire_data = (struct cam_vfe_acquire_args *)acquire_param;
+
+	rdi_data->sync_mode   = acquire_data->vfe_in.sync_mode;
+
+	return 0;
+}
+
+static int cam_vfe_rdi_resource_start(
+	struct cam_isp_resource_node  *rdi_res)
+{
+	struct cam_vfe_mux_rdi_data   *rsrc_data;
+	int                            rc = 0;
+
+	if (!rdi_res) {
+		pr_err("Error! Invalid input arguments\n");
+		return -EINVAL;
+	}
+
+	if (rdi_res->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) {
+		pr_err("Error! Invalid rdi res res_state:%d\n",
+			rdi_res->res_state);
+		return -EINVAL;
+	}
+
+	rsrc_data = (struct cam_vfe_mux_rdi_data  *)rdi_res->res_priv;
+	rdi_res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING;
+
+	/* Reg Update */
+	cam_io_w_mb(0x2, rsrc_data->mem_base + 0x4AC);
+
+	CDBG("Exit\n");
+
+	return rc;
+}
+
+
+static int cam_vfe_rdi_resource_stop(
+	struct cam_isp_resource_node        *rdi_res)
+{
+	struct cam_vfe_mux_rdi_data           *rdi_priv;
+	int rc = 0;
+
+	if (!rdi_res) {
+		pr_err("Error! Invalid input arguments\n");
+		return -EINVAL;
+	}
+
+	if (rdi_res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED ||
+		rdi_res->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE)
+		return 0;
+
+	rdi_priv = (struct cam_vfe_mux_rdi_data *)rdi_res->res_priv;
+
+	if (rdi_res->res_state == CAM_ISP_RESOURCE_STATE_STREAMING)
+		rdi_res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED;
+
+
+	return rc;
+}
+
+int cam_vfe_rdi_process_cmd(void *priv,
+	uint32_t cmd_type, void *cmd_args, uint32_t arg_size)
+{
+	int rc = -EINVAL;
+
+	if (!priv || !cmd_args) {
+		pr_err("Error! Invalid input arguments\n");
+		return -EINVAL;
+	}
+
+	switch (cmd_type) {
+	default:
+		pr_err("Error! unsupported RDI process command:%d\n", cmd_type);
+		break;
+	}
+
+	return rc;
+}
+
+static int cam_vfe_rdi_handle_irq_top_half(uint32_t evt_id,
+	struct cam_irq_th_payload *th_payload)
+{
+	return -EPERM;
+}
+
+static int cam_vfe_rdi_handle_irq_bottom_half(void *handler_priv,
+	void *evt_payload_priv)
+{
+	int                                  ret = CAM_VFE_IRQ_STATUS_ERR;
+	struct cam_isp_resource_node        *rdi_node;
+	struct cam_vfe_mux_rdi_data         *rdi_priv;
+	struct cam_vfe_top_irq_evt_payload  *payload;
+	uint32_t                             irq_status0;
+
+	if (!handler_priv || !evt_payload_priv)
+		return ret;
+
+	rdi_node = handler_priv;
+	rdi_priv = rdi_node->res_priv;
+	payload = evt_payload_priv;
+	irq_status0 = payload->irq_reg_val[CAM_IFE_IRQ_CAMIF_REG_STATUS0];
+
+	CDBG("event ID:%d\n", payload->evt_id);
+	CDBG("irq_status_0 = %x\n", irq_status0);
+
+	switch (payload->evt_id) {
+	case CAM_ISP_HW_EVENT_SOF:
+		if (irq_status0 & 0x8000000)
+			ret = CAM_VFE_IRQ_STATUS_SUCCESS;
+		break;
+	case CAM_ISP_HW_EVENT_REG_UPDATE:
+		if (irq_status0 & 0x20)
+			ret = CAM_VFE_IRQ_STATUS_SUCCESS;
+		break;
+	default:
+		break;
+	}
+
+	CDBG("returing status = %d\n", ret);
+	return ret;
+}
+
+int cam_vfe_rdi_ver2_init(
+	struct cam_hw_intf            *hw_intf,
+	struct cam_hw_soc_info        *soc_info,
+	void                          *rdi_hw_info,
+	struct cam_isp_resource_node  *rdi_node)
+{
+	struct cam_vfe_mux_rdi_data     *rdi_priv = NULL;
+
+	rdi_priv = kzalloc(sizeof(struct cam_vfe_mux_rdi_data),
+			GFP_KERNEL);
+	if (!rdi_priv) {
+		CDBG("Error! Failed to alloc for rdi_priv\n");
+		return -ENOMEM;
+	}
+
+	rdi_node->res_priv = rdi_priv;
+
+	rdi_priv->mem_base   = soc_info->reg_map[VFE_CORE_BASE_IDX].mem_base;
+	rdi_priv->hw_intf    = hw_intf;
+
+	rdi_node->start = cam_vfe_rdi_resource_start;
+	rdi_node->stop  = cam_vfe_rdi_resource_stop;
+	rdi_node->top_half_handler = cam_vfe_rdi_handle_irq_top_half;
+	rdi_node->bottom_half_handler = cam_vfe_rdi_handle_irq_bottom_half;
+
+	return 0;
+}
+
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.h
new file mode 100644
index 0000000..967cec3
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.h
@@ -0,0 +1,46 @@
+/* Copyright (c) 2017, 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_VFE_RDI_H_
+#define _CAM_VFE_RDI_H_
+
+#include "cam_isp_hw.h"
+#include "cam_vfe_top.h"
+
+struct cam_vfe_rdi_ver2_reg {
+	uint32_t     reg_update_cmd;
+};
+
+struct cam_vfe_rdi_reg_data {
+	uint32_t     reg_update_irq_mask;
+};
+
+struct cam_vfe_rdi_ver2_hw_info {
+	struct cam_vfe_top_ver2_reg_offset_common   *common_reg;
+	struct cam_vfe_rdi_ver2_reg               *rdi_reg;
+	struct cam_vfe_rdi_reg_data               *reg_data;
+};
+
+int cam_vfe_rdi_ver2_acquire_resource(
+	struct cam_isp_resource_node  *rdi_res,
+	void                          *acquire_param);
+
+int cam_vfe_rdi_process_cmd(void *priv,
+	uint32_t cmd_type, void *cmd_args, uint32_t arg_size);
+
+int cam_vfe_rdi_ver2_init(
+	struct cam_hw_intf            *hw_intf,
+	struct cam_hw_soc_info        *soc_info,
+	void                          *rdi_hw_info,
+	struct cam_isp_resource_node  *rdi_node);
+
+#endif /* _CAM_VFE_RDI_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c
index 4fa5e98..cbddf01 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c
@@ -118,8 +118,12 @@
 
 	if (cdm_args->res->res_id == CAM_ISP_HW_VFE_IN_CAMIF)
 		reg_val_pair[1] = BIT(0);
-	else
-		reg_val_pair[1] = BIT(cdm_args->res->res_id + 1);
+	else {
+		uint32_t rdi_num = cdm_args->res->res_id -
+			CAM_ISP_HW_VFE_IN_RDI0;
+		/* RDI reg_update starts at BIT 1, so add 1 */
+		reg_val_pair[1] = BIT(rdi_num + 1);
+	}
 
 	cdm_util_ops->cdm_write_regrandom(cdm_args->cmd_buf_addr,
 		1, reg_val_pair);
@@ -132,13 +136,13 @@
 int cam_vfe_top_get_hw_caps(void *device_priv,
 	void *get_hw_cap_args, uint32_t arg_size)
 {
-	return 0;
+	return -EPERM;
 }
 
 int cam_vfe_top_init_hw(void *device_priv,
 	void *init_hw_args, uint32_t arg_size)
 {
-	return 0;
+	return -EPERM;
 }
 
 int cam_vfe_top_reset(void *device_priv,
@@ -304,13 +308,13 @@
 int cam_vfe_top_read(void *device_priv,
 	void *read_args, uint32_t arg_size)
 {
-	return -ENODEV;
+	return -EPERM;
 }
 
 int cam_vfe_top_write(void *device_priv,
 	void *write_args, uint32_t arg_size)
 {
-	return -ENODEV;
+	return -EPERM;
 }
 
 int cam_vfe_top_process_cmd(void *device_priv, uint32_t cmd_type,
@@ -387,7 +391,10 @@
 			/* set the RDI resource id */
 			top_priv->mux_rsrc[i].res_id =
 				CAM_ISP_HW_VFE_IN_RDI0 + j;
-			top_priv->mux_rsrc[i].res_priv = NULL;
+			rc = cam_vfe_rdi_ver2_init(hw_intf, soc_info,
+				NULL, &top_priv->mux_rsrc[i]);
+			if (rc)
+				goto deinit_resources;
 			j++;
 		}
 	}
@@ -410,6 +417,7 @@
 
 	return rc;
 
+deinit_resources:
 err_mux_init:
 	kfree(vfe_top->top_priv);
 err_alloc_priv:
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h
index 24301d7..1038721 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h
@@ -14,6 +14,7 @@
 #define _CAM_VFE_TOP_VER2_H_
 
 #include "cam_vfe_camif_ver2.h"
+#include "cam_vfe_rdi.h"
 
 #define CAM_VFE_TOP_VER2_MUX_MAX 4