浏览代码

msm: camera: isp: Support for SFE IRQ handling

Add irq controller support for the SFE core & bus interfaces.

CRs-Fixed: 2783797
Change-Id: I84c04a13fa26a9d040bab9e7ec7ba2d3061e1f76
Signed-off-by: Jigarkumar Zala <[email protected]>
Signed-off-by: Karthik Anantha Ram <[email protected]>
Jigarkumar Zala 5 年之前
父节点
当前提交
e4b180abaf

+ 59 - 8
drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_sfe_hw_intf.h

@@ -7,6 +7,7 @@
 #define _CAM_SFE_HW_INTF_H_
 
 #include "cam_isp_hw.h"
+#include "cam_isp_hw_mgr_intf.h"
 
 #define SFE_CORE_BASE_IDX           0
 #define SFE_RT_CDM_BASE_IDX         1
@@ -48,6 +49,11 @@ enum cam_sfe_bus_irq_regs {
 	CAM_SFE_BUS_IRQ_REGISTERS_MAX,
 };
 
+enum cam_sfe_bus_rd_irq_regs {
+	CAM_SFE_IRQ_BUS_RD_REG_STATUS0,
+	CAM_SFE_BUS_RD_IRQ_REGISTERS_MAX,
+};
+
 /*
  * struct cam_sfe_fe_update_args:
  *
@@ -83,33 +89,78 @@ struct cam_sfe_core_config_args {
 };
 
 /*
- * struct cam_sfe_irq_evt_payload:
+ * struct cam_sfe_top_irq_evt_payload:
  *
  * @Brief:                   This structure is used to save payload for IRQ
- *                           related to SFE resources
+ *                           related to SFE top resource
  *
  * @list:                    list_head node for the payload
  * @core_index:              Index of SFE HW that generated this IRQ event
  * @evt_id:                  IRQ event
  * @irq_reg_val:             IRQ and Error register values, read when IRQ was
  *                           handled
- * @bus_irq_val              Bus irq register status
+ * @violation_status         ccif violation status
+ * @error_type:              Identify different errors
+ * @ts:                      Timestamp
+ */
+struct cam_sfe_top_irq_evt_payload {
+	struct list_head           list;
+	uint32_t                   core_index;
+	uint32_t                   evt_id;
+	uint32_t                   irq_reg_val[CAM_SFE_IRQ_REGISTERS_MAX];
+	uint32_t                   violation_status;
+	uint32_t                   error_type;
+	struct cam_isp_timestamp   ts;
+};
+
+/*
+ * struct cam_sfe_bus_wr_irq_evt_payload:
+ *
+ * @Brief:                   This structure is used to save payload for IRQ
+ *                           BUS related to SFE resources
+ *
+ * @list:                    list_head node for the payload
+ * @core_index:              Index of SFE HW that generated this IRQ event
+ * @irq_reg_val              Bus irq register status
  * @ccif_violation_status    ccif violation status
  * @overflow_status          bus overflow status
  * @image_size_vio_sts       image size violations status
  * @error_type:              Identify different errors
+ * @evt_id:                  IRQ event
  * @ts:                      Timestamp
  */
-struct cam_sfe_irq_evt_payload {
+struct cam_sfe_bus_wr_irq_evt_payload {
 	struct list_head           list;
 	uint32_t                   core_index;
-	uint32_t                   evt_id;
-	uint32_t                   irq_reg_val[CAM_SFE_IRQ_REGISTERS_MAX];
-	uint32_t                   bus_irq_val[CAM_SFE_BUS_IRQ_REGISTERS_MAX];
+	uint32_t                   irq_reg_val[CAM_SFE_BUS_IRQ_REGISTERS_MAX];
 	uint32_t                   ccif_violation_status;
 	uint32_t                   overflow_status;
-	uint32_t                   image_size_vio_sts;
+	uint32_t                   image_size_violation_status;
 	uint32_t                   error_type;
+	uint32_t                   evt_id;
+	struct cam_isp_timestamp   ts;
+};
+
+/*
+ * struct cam_sfe_bus_rd_irq_evt_payload:
+ *
+ * @Brief:                   This structure is used to save payload for IRQ
+ *                           BUS related to SFE resources
+ *
+ * @list:                    list_head node for the payload
+ * @irq_reg_val              Bus irq register status
+ * @constraint_violation     constraint violation
+ * @error_type:              Identify different errors
+ * @evt_id:                  IRQ event
+ * @ts:                      Timestamp
+ */
+struct cam_sfe_bus_rd_irq_evt_payload {
+	struct list_head           list;
+	uint32_t                   irq_reg_val[
+		CAM_SFE_BUS_RD_IRQ_REGISTERS_MAX];
+	uint32_t                   constraint_violation;
+	uint32_t                   error_type;
+	uint32_t                   evt_id;
 	struct cam_isp_timestamp   ts;
 };
 

+ 46 - 2
drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe680.h

@@ -128,6 +128,14 @@ static struct cam_sfe_top_hw_info sfe680_top_hw_info = {
 	},
 };
 
+static struct cam_irq_register_set sfe680_bus_rd_irq_reg[1] = {
+	{
+		.mask_reg_offset   = 0x00000404,
+		.clear_reg_offset  = 0x00000408,
+		.status_reg_offset = 0x00000410,
+	},
+};
+
 static struct cam_sfe_bus_rd_hw_info sfe680_bus_rd_hw_info = {
 	.common_reg = {
 		.hw_version                   = 0x00000400,
@@ -136,6 +144,13 @@ static struct cam_sfe_bus_rd_hw_info sfe680_bus_rd_hw_info = {
 		.input_if_cmd                 = 0x00000414,
 		.test_bus_ctrl                = 0x0000042C,
 		.security_cfg                 = 0x00000420,
+		.cons_violation_status        = 0x00000434,
+		.irq_reg_info = {
+			.num_registers     = 1,
+			.irq_reg_set          = sfe680_bus_rd_irq_reg,
+			.global_clear_offset  = 0x0000040C,
+			.global_clear_bitmask = 0x00000001,
+		},
 	},
 	.num_client = 3,
 	.bus_client_reg = {
@@ -191,6 +206,14 @@ static struct cam_sfe_bus_rd_hw_info sfe680_bus_rd_hw_info = {
 	.top_irq_shift = 0x1,
 };
 
+static struct cam_irq_register_set sfe680_bus_wr_irq_reg[1] = {
+	{
+		.mask_reg_offset   = 0x00000818,
+		.clear_reg_offset  = 0x00000820,
+		.status_reg_offset = 0x00000828,
+	},
+};
+
 static struct cam_sfe_bus_wr_hw_info sfe680_bus_wr_hw_info = {
 	.common_reg = {
 		.hw_version                       = 0x00000800,
@@ -211,7 +234,13 @@ static struct cam_sfe_bus_wr_hw_info sfe680_bus_wr_hw_info = {
 		.debug_status_top_cfg             = 0x000008D4,
 		.debug_status_top                 = 0x000008D8,
 		.test_bus_ctrl                    = 0x000008DC,
-		.top_irq_mask_0                   = 0x00000818,
+		.top_irq_mask_0                   = 0x00000020,
+		.irq_reg_info = {
+			.num_registers     = 1,
+			.irq_reg_set          = sfe680_bus_wr_irq_reg,
+			.global_clear_offset  = 0x00000830,
+			.global_clear_bitmask = 0x00000001,
+		},
 	},
 	.num_client = 13,
 	.bus_client_reg = {
@@ -679,8 +708,23 @@ static struct cam_sfe_bus_wr_hw_info sfe680_bus_wr_hw_info = {
 	.top_irq_shift   = 0x0,
 };
 
+static struct cam_irq_register_set sfe680_top_irq_reg_set[1] = {
+{
+	.mask_reg_offset   = 0x00000020,
+	.clear_reg_offset  = 0x00000024,
+	.status_reg_offset = 0x00000028,
+	},
+};
+
+static struct cam_irq_controller_reg_info sfe680_top_irq_reg_info = {
+	.num_registers = 1,
+	.irq_reg_set = sfe680_top_irq_reg_set,
+	.global_clear_offset  = 0x0000001C,
+	.global_clear_bitmask = 0x00000001,
+};
+
 struct cam_sfe_hw_info cam_sfe680_hw_info = {
-	.irq_reg_info                  = NULL,
+	.irq_reg_info                  = &sfe680_top_irq_reg_info,
 
 	.bus_wr_version                = CAM_SFE_BUS_WR_VER_1_0,
 	.bus_wr_hw_info                = &sfe680_bus_wr_hw_info,

+ 26 - 9
drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_core.c

@@ -407,17 +407,28 @@ int cam_sfe_core_init(
 	struct cam_hw_intf           *hw_intf,
 	struct cam_sfe_hw_info       *sfe_hw_info)
 {
-	int rc;
+	int rc = -EINVAL;
+
+	rc = cam_irq_controller_init(drv_name,
+		CAM_SOC_GET_REG_MAP_START(soc_info, SFE_CORE_BASE_IDX),
+		sfe_hw_info->irq_reg_info, &core_info->sfe_irq_controller,
+		true);
+	if (rc) {
+		CAM_ERR(CAM_SFE, "SFE irq controller init failed");
+		return rc;
+	}
 
 	rc = cam_sfe_top_init(sfe_hw_info->top_version, soc_info, hw_intf,
-		sfe_hw_info->top_hw_info, &core_info->sfe_top);
+		sfe_hw_info->top_hw_info, core_info->sfe_irq_controller,
+		&core_info->sfe_top);
 	if (rc) {
 		CAM_ERR(CAM_SFE, "SFE top init failed rc: %d", rc);
-		return rc;
+		goto deinit_controller;
 	}
 
 	rc = cam_sfe_bus_init(sfe_hw_info->bus_wr_version, BUS_TYPE_SFE_WR,
 		soc_info, hw_intf, sfe_hw_info->bus_wr_hw_info,
+		core_info->sfe_irq_controller,
 		&core_info->sfe_bus_wr);
 	if (rc) {
 		CAM_ERR(CAM_SFE, "SFE bus wr init failed rc: %d", rc);
@@ -426,13 +437,13 @@ int cam_sfe_core_init(
 
 	rc = cam_sfe_bus_init(sfe_hw_info->bus_rd_version, BUS_TYPE_SFE_RD,
 		soc_info, hw_intf, sfe_hw_info->bus_rd_hw_info,
+		core_info->sfe_irq_controller,
 		&core_info->sfe_bus_rd);
 	if (rc) {
 		CAM_ERR(CAM_SFE, "SFE bus rd init failed rc: %d", rc);
 		goto deinit_bus_wr;
 	}
 
-	INIT_LIST_HEAD(&core_info->free_payload_list);
 	spin_lock_init(&core_info->spin_lock);
 	CAM_DBG(CAM_SFE, "SFE device [%u] INIT success",
 		hw_intf->hw_idx);
@@ -445,6 +456,11 @@ deinit_bus_wr:
 deinit_top:
 	cam_sfe_top_deinit(sfe_hw_info->top_version,
 		&core_info->sfe_top);
+deinit_controller:
+	if (cam_irq_controller_deinit(&core_info->sfe_irq_controller))
+		CAM_ERR(CAM_SFE,
+			"Error cam_irq_controller_deinit failed rc=%d", rc);
+
 	return rc;
 }
 
@@ -452,15 +468,11 @@ int cam_sfe_core_deinit(
 	struct cam_sfe_hw_core_info  *core_info,
 	struct cam_sfe_hw_info       *sfe_hw_info)
 {
-	int                rc = -EINVAL, i;
+	int                rc = -EINVAL;
 	unsigned long      flags;
 
 	spin_lock_irqsave(&core_info->spin_lock, flags);
 
-	INIT_LIST_HEAD(&core_info->free_payload_list);
-	for (i = 0; i < CAM_SFE_EVT_MAX; i++)
-		INIT_LIST_HEAD(&core_info->evt_payload[i].list);
-
 	rc = cam_sfe_bus_deinit(BUS_TYPE_SFE_RD,
 		sfe_hw_info->bus_rd_version,
 		&core_info->sfe_bus_rd);
@@ -481,6 +493,11 @@ int cam_sfe_core_deinit(
 		CAM_ERR(CAM_SFE,
 			"SFE top deinit failed rc: %d", rc);
 
+	rc = cam_irq_controller_deinit(&core_info->sfe_irq_controller);
+	if (rc)
+		CAM_ERR(CAM_SFE,
+			"Error cam_irq_controller_deinit failed rc=%d", rc);
+
 	spin_unlock_irqrestore(&core_info->spin_lock, flags);
 	return rc;
 }

+ 0 - 2
drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_core.h

@@ -34,8 +34,6 @@ struct cam_sfe_hw_core_info {
 	struct cam_sfe_bus                 *sfe_bus_rd;
 	void                               *sfe_irq_controller;
 	void                               *tasklet_info;
-	struct cam_sfe_irq_evt_payload      evt_payload[CAM_SFE_EVT_MAX];
-	struct list_head                    free_payload_list;
 	spinlock_t                          spin_lock;
 };
 

+ 3 - 2
drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus.c

@@ -14,6 +14,7 @@ int cam_sfe_bus_init(
 	struct cam_hw_soc_info        *soc_info,
 	struct cam_hw_intf            *hw_intf,
 	void                          *bus_hw_info,
+	void                          *sfe_irq_controller,
 	struct cam_sfe_bus           **sfe_bus)
 {
 	int rc = -ENODEV;
@@ -23,7 +24,7 @@ int cam_sfe_bus_init(
 		switch (bus_version) {
 		case CAM_SFE_BUS_WR_VER_1_0:
 			rc = cam_sfe_bus_wr_init(soc_info, hw_intf,
-				bus_hw_info, sfe_bus);
+				bus_hw_info, sfe_irq_controller, sfe_bus);
 			break;
 		default:
 			CAM_ERR(CAM_SFE, "Unsupported Bus WR Version 0x%x",
@@ -35,7 +36,7 @@ int cam_sfe_bus_init(
 		switch (bus_version) {
 		case CAM_SFE_BUS_RD_VER_1_0:
 			rc = cam_sfe_bus_rd_init(soc_info, hw_intf,
-				bus_hw_info, sfe_bus);
+				bus_hw_info, sfe_irq_controller, sfe_bus);
 			break;
 		default:
 			CAM_ERR(CAM_SFE, "Unsupported Bus RD Version 0x%x",

+ 263 - 13
drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_rd.c

@@ -28,7 +28,12 @@ static const char drv_name[] = "sfe_bus_rd";
 #define MAX_REG_VAL_PAIR_SIZE    \
 	(MAX_BUF_UPDATE_REG_NUM * 2 * CAM_PACKET_MAX_PLANES)
 
-#define BUS_RD_DEFAULT_LATENCY_BUF_ALLOC 512
+#define BUS_RD_DEFAULT_LATENCY_BUF_ALLOC   512
+#define CAM_SFE_BUS_RD_PAYLOAD_MAX         16
+
+static uint32_t bus_rd_error_irq_mask[1] = {
+	0x00000001,
+};
 
 enum cam_sfe_bus_rd_unpacker_format {
 	BUS_RD_UNPACKER_FMT_PLAIN_128             = 0x0,
@@ -60,7 +65,12 @@ struct cam_sfe_bus_rd_common_data {
 	struct cam_sfe_bus_rd_reg_offset_common    *common_reg;
 	uint32_t                                    io_buf_update[
 		MAX_REG_VAL_PAIR_SIZE];
-
+	void                                       *bus_irq_controller;
+	void                                       *sfe_irq_controller;
+	spinlock_t                                  spin_lock;
+	struct list_head                            free_payload_list;
+	struct cam_sfe_bus_rd_irq_evt_payload       evt_payload[
+		CAM_SFE_BUS_RD_PAYLOAD_MAX];
 	cam_hw_mgr_event_cb_func                    event_cb;
 };
 
@@ -95,7 +105,6 @@ struct cam_sfe_bus_rd_data {
 	uint32_t                           max_height;
 	struct cam_cdm_utils_ops          *cdm_util_ops;
 	void                              *priv;
-	uint32_t                           status;
 	uint32_t                           secure_mode;
 	uint32_t                           fs_sync_enable;
 	uint32_t                           fs_line_sync_en;
@@ -112,6 +121,8 @@ struct cam_sfe_bus_rd_priv {
 	struct cam_isp_resource_node  sfe_bus_rd[
 		CAM_SFE_BUS_RD_MAX];
 
+	int                                 irq_handle;
+	int                                 error_irq_handle;
 	void                               *tasklet_info;
 	uint32_t                            top_irq_shift;
 };
@@ -280,6 +291,73 @@ static int cam_sfe_bus_get_rm_idx(
 	return rm_idx;
 }
 
+static int cam_sfe_bus_rd_get_evt_payload(
+	struct cam_sfe_bus_rd_common_data      *common_data,
+	struct cam_sfe_bus_rd_irq_evt_payload **evt_payload)
+{
+	int rc = 0;
+
+	spin_lock(&common_data->spin_lock);
+
+	if (list_empty(&common_data->free_payload_list)) {
+		CAM_ERR_RATE_LIMIT(CAM_SFE,
+			"No free BUS RD event payload");
+		*evt_payload = NULL;
+		rc = -ENODEV;
+		goto done;
+	}
+
+	*evt_payload = list_first_entry(&common_data->free_payload_list,
+		struct cam_sfe_bus_rd_irq_evt_payload, list);
+	list_del_init(&(*evt_payload)->list);
+
+done:
+	spin_unlock(&common_data->spin_lock);
+	return rc;
+}
+
+static int cam_sfe_bus_rd_put_evt_payload(
+	struct cam_sfe_bus_rd_common_data       *common_data,
+	struct cam_sfe_bus_rd_irq_evt_payload  **evt_payload)
+{
+	unsigned long flags;
+
+	if (!common_data) {
+		CAM_ERR(CAM_SFE, "Invalid param common_data NULL");
+		return -EINVAL;
+	}
+
+	if (*evt_payload == NULL) {
+		CAM_ERR(CAM_SFE, "No payload to put");
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&common_data->spin_lock, flags);
+		list_add_tail(&(*evt_payload)->list,
+			&common_data->free_payload_list);
+	spin_unlock_irqrestore(&common_data->spin_lock, flags);
+
+	*evt_payload = NULL;
+
+	return 0;
+}
+
+static int cam_sfe_bus_rd_handle_irq(
+	uint32_t    evt_id,
+	struct cam_irq_th_payload *th_payload)
+{
+	struct cam_sfe_bus_rd_priv *bus_priv;
+	int rc = 0;
+
+	bus_priv = th_payload->handler_priv;
+	CAM_DBG(CAM_SFE, "Top Bus RD IRQ Received");
+
+	rc = cam_irq_controller_handle_irq(evt_id,
+		bus_priv->common_data.bus_irq_controller);
+
+	return (rc == IRQ_HANDLED) ? 0 : -EINVAL;
+}
+
 static int cam_sfe_bus_acquire_rm(
 	struct cam_sfe_bus_rd_priv             *bus_rd_priv,
 	void                                   *tasklet,
@@ -452,6 +530,99 @@ static int cam_sfe_bus_deinit_rm_resource(
 	return 0;
 }
 
+static int cam_sfe_bus_rd_handle_irq_top_half(uint32_t evt_id,
+	struct cam_irq_th_payload *th_payload)
+{
+	int i, rc = 0;
+	struct cam_sfe_bus_rd_priv *bus_priv;
+	struct cam_sfe_bus_rd_irq_evt_payload *evt_payload = NULL;
+
+	bus_priv = th_payload->handler_priv;
+	rc  = cam_sfe_bus_rd_get_evt_payload(
+		&bus_priv->common_data, &evt_payload);
+	if (rc)
+		return rc;
+
+	for (i = 0; i < th_payload->num_registers; i++) {
+		evt_payload->irq_reg_val[i] =
+			th_payload->evt_status_arr[i];
+		CAM_DBG(CAM_SFE, "SFE:%d Bus RD IRQ status_%d: 0x%x",
+			bus_priv->common_data.core_index, i,
+			th_payload->evt_status_arr[i]);
+	}
+
+	evt_payload->constraint_violation = cam_io_r_mb(
+		bus_priv->common_data.mem_base +
+		bus_priv->common_data.common_reg->cons_violation_status);
+	if (evt_payload->constraint_violation) {
+		CAM_ERR(CAM_SFE, "SFE:%d constraint violation:0x%x",
+			bus_priv->common_data.core_index,
+			evt_payload->constraint_violation);
+		cam_irq_controller_disable_irq(
+			bus_priv->common_data.bus_irq_controller,
+			 bus_priv->error_irq_handle);
+		cam_irq_controller_clear_and_mask(evt_id,
+			bus_priv->common_data.bus_irq_controller);
+	}
+
+	cam_isp_hw_get_timestamp(&evt_payload->ts);
+	th_payload->evt_payload_priv = evt_payload;
+	return 0;
+}
+
+static int cam_sfe_bus_rd_handle_irq_bottom_half(
+	void  *handler_priv, void *evt_payload_priv)
+{
+	struct cam_sfe_bus_rd_irq_evt_payload *evt_payload;
+	struct cam_sfe_bus_rd_priv            *bus_priv;
+	struct cam_sfe_bus_rd_common_data     *common_data = NULL;
+	struct cam_isp_hw_event_info           evt_info;
+	uint32_t status = 0, constraint_violation = 0;
+
+	if (!handler_priv || !evt_payload_priv)
+		return -EINVAL;
+
+	bus_priv = (struct cam_sfe_bus_rd_priv *)handler_priv;
+	evt_payload = (struct cam_sfe_bus_rd_irq_evt_payload *)evt_payload_priv;
+	common_data = &bus_priv->common_data;
+	status = evt_payload->irq_reg_val[CAM_SFE_IRQ_BUS_RD_REG_STATUS0];
+	constraint_violation = evt_payload->constraint_violation;
+	cam_sfe_bus_rd_put_evt_payload(common_data, &evt_payload);
+
+	if (status & 0x2)
+		CAM_DBG(CAM_SFE, "Received SFE:%d BUS RD RUP",
+			bus_priv->common_data.core_index);
+
+	if (status & 0x4)
+		CAM_DBG(CAM_SFE, "Received SFE:%d BUS RD0 BUF DONE",
+			bus_priv->common_data.core_index);
+
+	if (status & 0x8)
+		CAM_DBG(CAM_SFE, "Received SFE:%d BUS RD1 BUF DONE",
+			bus_priv->common_data.core_index);
+
+	if (status & 0x10)
+		CAM_DBG(CAM_SFE, "Received SFE:%d BUS RD2 BUF DONE",
+			bus_priv->common_data.core_index);
+
+	if (status & 0x1) {
+		CAM_ERR(CAM_SFE, "SFE:%d Constraint violation status:0x%x",
+			bus_priv->common_data.core_index,
+			constraint_violation);
+
+		evt_info.hw_idx = bus_priv->common_data.core_index;
+		evt_info.res_type = CAM_ISP_RESOURCE_SFE_RD;
+		evt_info.res_id = CAM_SFE_BUS_RD_MAX;
+		evt_info.err_type = CAM_SFE_IRQ_STATUS_VIOLATION;
+
+		if (common_data->event_cb)
+			common_data->event_cb(NULL,
+				CAM_ISP_HW_EVENT_ERROR, (void *)&evt_info);
+	}
+
+	return 0;
+}
+
 static int cam_sfe_bus_rd_get_secure_mode(void *priv, void *cmd_args,
 	uint32_t arg_size)
 {
@@ -639,7 +810,7 @@ static int cam_sfe_bus_start_bus_rd(
 	for (i = 0; i < rsrc_data->num_rm; i++)
 		rc = cam_sfe_bus_start_rm(rsrc_data->rm_res[i]);
 
-	/* Subscribe mask for buf_done */
+	/* TO DO Subscribe mask for buf_done */
 
 	sfe_bus_rd->res_state = CAM_ISP_RESOURCE_STATE_STREAMING;
 	return rc;
@@ -930,19 +1101,52 @@ static int cam_sfe_bus_init_hw(void *hw_priv,
 	void *init_hw_args, uint32_t arg_size)
 {
 	struct cam_sfe_bus_rd_priv    *bus_priv = hw_priv;
-	uint32_t                       sfe_top_irq_mask = 0;
 	uint32_t                       offset = 0;
 	struct cam_sfe_bus_rd_reg_offset_common  *common_reg;
+	uint32_t sfe_top_irq_mask[CAM_SFE_IRQ_REGISTERS_MAX] = {0};
 
 	if (!bus_priv) {
 		CAM_ERR(CAM_SFE, "Invalid args");
 		return -EINVAL;
 	}
 	common_reg = bus_priv->common_data.common_reg;
-	sfe_top_irq_mask = (1 << bus_priv->top_irq_shift);
-
-	/* Subscribe for error IRQs */
+	sfe_top_irq_mask[0] = (1 << bus_priv->top_irq_shift);
+
+	/* Subscribe for top IRQ */
+	bus_priv->irq_handle = cam_irq_controller_subscribe_irq(
+		bus_priv->common_data.sfe_irq_controller,
+		CAM_IRQ_PRIORITY_2,
+		sfe_top_irq_mask,
+		bus_priv,
+		cam_sfe_bus_rd_handle_irq,
+		NULL,
+		NULL,
+		NULL);
+
+	if (bus_priv->irq_handle < 1) {
+		CAM_ERR(CAM_SFE,
+			"Failed to subscribe TOP IRQ for BUS RD");
+		bus_priv->irq_handle = 0;
+		return -EFAULT;
+	}
 
+	if (bus_priv->tasklet_info != NULL) {
+		bus_priv->error_irq_handle = cam_irq_controller_subscribe_irq(
+			bus_priv->common_data.bus_irq_controller,
+			CAM_IRQ_PRIORITY_1,
+			bus_rd_error_irq_mask,
+			bus_priv,
+			cam_sfe_bus_rd_handle_irq_top_half,
+			cam_sfe_bus_rd_handle_irq_bottom_half,
+			bus_priv->tasklet_info,
+			&tasklet_bh_api);
+
+		if (bus_priv->error_irq_handle < 1) {
+			CAM_ERR(CAM_SFE, "Failed to subscribe error IRQ");
+			bus_priv->error_irq_handle = 0;
+			return -EFAULT;
+		}
+	}
 	/* BUS_RD_TEST_BUS_CTRL disabling test bus */
 	offset = common_reg->test_bus_ctrl;
 	cam_io_w_mb(0x0, bus_priv->common_data.mem_base + offset);
@@ -954,7 +1158,6 @@ static int cam_sfe_bus_deinit_hw(void *hw_priv,
 	void *deinit_hw_args, uint32_t arg_size)
 {
 	struct cam_sfe_bus_rd_priv    *bus_priv = hw_priv;
-	uint32_t                       sfe_top_irq_mask = 0;
 	int                            rc = 0;
 
 	if (!bus_priv) {
@@ -962,9 +1165,24 @@ static int cam_sfe_bus_deinit_hw(void *hw_priv,
 		return -EINVAL;
 	}
 
-	sfe_top_irq_mask = 1 << bus_priv->top_irq_shift;
+	/* Unsubscribe irqs */
+	if (bus_priv->irq_handle) {
+		rc =   cam_irq_controller_unsubscribe_irq(
+				bus_priv->common_data.sfe_irq_controller,
+				bus_priv->irq_handle);
+		if (rc)
+			CAM_ERR(CAM_SFE, "Failed to unsubscribe top irq");
+		bus_priv->irq_handle = 0;
+	}
 
-	/* Unsubscribe for err irqs */
+	if (bus_priv->error_irq_handle) {
+		rc =   cam_irq_controller_unsubscribe_irq(
+				bus_priv->common_data.bus_irq_controller,
+				bus_priv->error_irq_handle);
+		if (rc)
+			CAM_ERR(CAM_SFE, "Failed to unsubscribe error irq");
+		bus_priv->error_irq_handle = 0;
+	}
 
 	return rc;
 }
@@ -1005,6 +1223,7 @@ int cam_sfe_bus_rd_init(
 	struct cam_hw_soc_info               *soc_info,
 	struct cam_hw_intf                   *hw_intf,
 	void                                 *bus_hw_info,
+	void                                 *sfe_irq_controller,
 	struct cam_sfe_bus                  **sfe_bus)
 {
 	int i, rc = 0;
@@ -1036,7 +1255,6 @@ int cam_sfe_bus_rd_init(
 	}
 
 	sfe_bus_local->bus_priv = bus_priv;
-
 	bus_priv->num_client                    = bus_rd_hw_info->num_client;
 	bus_priv->num_bus_rd_resc               =
 		bus_rd_hw_info->num_bus_rd_resc;
@@ -1044,9 +1262,19 @@ int cam_sfe_bus_rd_init(
 	bus_priv->common_data.mem_base          =
 		CAM_SOC_GET_REG_MAP_START(soc_info, SFE_CORE_BASE_IDX);
 	bus_priv->common_data.hw_intf           = hw_intf;
+	bus_priv->common_data.sfe_irq_controller = sfe_irq_controller;
 	bus_priv->common_data.common_reg        = &bus_rd_hw_info->common_reg;
 	bus_priv->top_irq_shift                 = bus_rd_hw_info->top_irq_shift;
 
+	rc = cam_irq_controller_init(drv_name,
+		bus_priv->common_data.mem_base,
+		&bus_rd_hw_info->common_reg.irq_reg_info,
+		&bus_priv->common_data.bus_irq_controller, true);
+	if (rc) {
+		CAM_ERR(CAM_SFE, "IRQ controller init failed");
+		goto free_bus_priv;
+	}
+
 	for (i = 0; i < bus_priv->num_client; i++) {
 		rc = cam_sfe_bus_init_rm_resource(i, bus_priv, bus_hw_info,
 			&bus_priv->bus_client[i]);
@@ -1065,12 +1293,21 @@ int cam_sfe_bus_rd_init(
 		}
 	}
 
+	spin_lock_init(&bus_priv->common_data.spin_lock);
+	INIT_LIST_HEAD(&bus_priv->common_data.free_payload_list);
+	for (i = 0; i < CAM_SFE_BUS_RD_PAYLOAD_MAX; i++) {
+		INIT_LIST_HEAD(&bus_priv->common_data.evt_payload[i].list);
+		list_add_tail(&bus_priv->common_data.evt_payload[i].list,
+			&bus_priv->common_data.free_payload_list);
+	}
+
 	sfe_bus_local->hw_ops.reserve      = cam_sfe_bus_acquire_bus_rd;
 	sfe_bus_local->hw_ops.release      = cam_sfe_bus_release_bus_rd;
 	sfe_bus_local->hw_ops.start        = cam_sfe_bus_start_bus_rd;
 	sfe_bus_local->hw_ops.stop         = cam_sfe_bus_stop_bus_rd;
 	sfe_bus_local->hw_ops.init         = cam_sfe_bus_init_hw;
 	sfe_bus_local->hw_ops.deinit       = cam_sfe_bus_deinit_hw;
+	sfe_bus_local->top_half_handler    = cam_sfe_bus_rd_handle_irq;
 	sfe_bus_local->bottom_half_handler = NULL;
 	sfe_bus_local->hw_ops.process_cmd  = cam_sfe_bus_rd_process_cmd;
 
@@ -1090,6 +1327,7 @@ deinit_rm:
 	for (--i; i >= 0; i--)
 		cam_sfe_bus_deinit_rm_resource(&bus_priv->bus_client[i]);
 
+free_bus_priv:
 	kfree(sfe_bus_local->bus_priv);
 
 free_bus_local:
@@ -1103,6 +1341,7 @@ int cam_sfe_bus_rd_deinit(
 	struct cam_sfe_bus                  **sfe_bus)
 {
 	int i, rc = 0;
+	unsigned long flags;
 	struct cam_sfe_bus_rd_priv    *bus_priv = NULL;
 	struct cam_sfe_bus            *sfe_bus_local;
 
@@ -1119,6 +1358,12 @@ int cam_sfe_bus_rd_deinit(
 		goto free_bus_local;
 	}
 
+	spin_lock_irqsave(&bus_priv->common_data.spin_lock, flags);
+	INIT_LIST_HEAD(&bus_priv->common_data.free_payload_list);
+	for (i = 0; i < CAM_SFE_BUS_RD_PAYLOAD_MAX; i++)
+		INIT_LIST_HEAD(&bus_priv->common_data.evt_payload[i].list);
+	spin_unlock_irqrestore(&bus_priv->common_data.spin_lock, flags);
+
 	for (i = 0; i < bus_priv->num_client; i++) {
 		rc = cam_sfe_bus_deinit_rm_resource(&bus_priv->bus_client[i]);
 		if (rc < 0)
@@ -1133,11 +1378,16 @@ int cam_sfe_bus_rd_deinit(
 				"Deinit SFE RD failed rc=%d", rc);
 	}
 
+	rc = cam_irq_controller_deinit(
+		&bus_priv->common_data.bus_irq_controller);
+	if (rc)
+		CAM_ERR(CAM_SFE,
+			"Deinit IRQ Controller failed rc=%d", rc);
+
 	kfree(sfe_bus_local->bus_priv);
 
 free_bus_local:
 	kfree(sfe_bus_local);
-
 	*sfe_bus = NULL;
 
 	return rc;

+ 4 - 1
drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_rd.h

@@ -29,6 +29,8 @@ struct cam_sfe_bus_rd_reg_offset_common {
 	uint32_t input_if_cmd;
 	uint32_t test_bus_ctrl;
 	uint32_t security_cfg;
+	uint32_t cons_violation_status;
+	struct cam_irq_controller_reg_info irq_reg_info;
 };
 
 /*
@@ -98,6 +100,7 @@ int cam_sfe_bus_rd_init(
 	struct cam_hw_soc_info               *soc_info,
 	struct cam_hw_intf                   *hw_intf,
 	void                                 *bus_hw_info,
+	void                                 *sfe_irq_controller,
 	struct cam_sfe_bus                  **sfe_bus);
 
 /*
@@ -105,7 +108,7 @@ int cam_sfe_bus_rd_init(
  *
  * @Brief:                   Deinitialize Bus layer
  *
- * @vfe_bus:                 Pointer to sfe_bus structure to deinitialize
+ * @sfe_bus:                 Pointer to sfe_bus structure to deinitialize
  *
  * @Return:                  0: Success
  *                           Non-zero: Failure

+ 441 - 24
drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_wr.c

@@ -37,6 +37,10 @@ static const char drv_name[] = "sfe_bus_wr";
 #define MAX_REG_VAL_PAIR_SIZE    \
 	(MAX_BUF_UPDATE_REG_NUM * 2 * CAM_PACKET_MAX_PLANES)
 
+static uint32_t bus_wr_error_irq_mask[1] = {
+	0xD0000000,
+};
+
 enum cam_sfe_bus_wr_packer_format {
 	PACKER_FMT_PLAIN_128,
 	PACKER_FMT_PLAIN_8,
@@ -63,12 +67,16 @@ struct cam_sfe_bus_wr_common_data {
 	uint32_t                                    hw_version;
 	void __iomem                               *mem_base;
 	struct cam_hw_intf                         *hw_intf;
+	void                                       *sfe_irq_controller;
 	void                                       *buf_done_controller;
+	void                                       *bus_irq_controller;
 	struct cam_sfe_bus_reg_offset_common       *common_reg;
 	uint32_t                                    io_buf_update[
 		MAX_REG_VAL_PAIR_SIZE];
 	struct list_head                            free_payload_list;
 	spinlock_t                                  spin_lock;
+	struct cam_sfe_bus_wr_irq_evt_payload       evt_payload[
+		CAM_SFE_BUS_WR_PAYLOAD_MAX];
 	struct mutex                                bus_mutex;
 	uint32_t                                    secure_mode;
 	uint32_t                                    num_sec_out;
@@ -167,10 +175,9 @@ struct cam_sfe_bus_wr_priv {
 	struct list_head                    free_comp_grp;
 	struct list_head                    used_comp_grp;
 
-	//int                                 bus_irq_handle;
-	//int                                 rup_irq_handle;
-	//int                                 error_irq_handle;
-	//void                               *tasklet_info;
+	int                                 bus_irq_handle;
+	int                                 error_irq_handle;
+	void                               *tasklet_info;
 };
 
 static int cam_sfe_bus_wr_process_cmd(
@@ -235,6 +242,54 @@ static enum cam_sfe_bus_sfe_out_type
 	}
 }
 
+static int cam_sfe_bus_get_comp_sfe_out_res_id_list(
+	uint32_t comp_mask, uint32_t *out_list, int *num_out)
+{
+	int count = 0;
+
+	if (comp_mask & (1 << CAM_SFE_BUS_SFE_OUT_RDI0))
+		out_list[count++] = CAM_ISP_SFE_OUT_RES_RDI_0;
+
+	if (comp_mask & (1 << CAM_SFE_BUS_SFE_OUT_RDI1))
+		out_list[count++] = CAM_ISP_SFE_OUT_RES_RDI_1;
+
+	if (comp_mask & (1 << CAM_SFE_BUS_SFE_OUT_RDI2))
+		out_list[count++] = CAM_ISP_SFE_OUT_RES_RDI_2;
+
+	if (comp_mask & (1 << CAM_SFE_BUS_SFE_OUT_RDI3))
+		out_list[count++] = CAM_ISP_SFE_OUT_RES_RDI_3;
+
+	if (comp_mask & (1 << CAM_SFE_BUS_SFE_OUT_RDI4))
+		out_list[count++] = CAM_ISP_SFE_OUT_RES_RDI_4;
+
+	if (comp_mask & (1 << CAM_SFE_BUS_SFE_OUT_RAW_DUMP))
+		out_list[count++] = CAM_ISP_SFE_OUT_RES_RAW_DUMP;
+
+	if (comp_mask & (1 << CAM_SFE_BUS_SFE_OUT_BE_0))
+		out_list[count++] = CAM_ISP_SFE_OUT_BE_STATS_0;
+
+	if (comp_mask & (1 << CAM_SFE_BUS_SFE_OUT_BHIST_0))
+		out_list[count++] = CAM_ISP_SFE_OUT_BHIST_STATS_0;
+
+	if (comp_mask & (1 << CAM_SFE_BUS_SFE_OUT_BE_1))
+		out_list[count++] = CAM_ISP_SFE_OUT_BE_STATS_1;
+
+	if (comp_mask & (1 << CAM_SFE_BUS_SFE_OUT_BHIST_1))
+		out_list[count++] = CAM_ISP_SFE_OUT_BHIST_STATS_1;
+
+	if (comp_mask & (1 << CAM_SFE_BUS_SFE_OUT_BE_2))
+		out_list[count++] = CAM_ISP_SFE_OUT_BE_STATS_2;
+
+	if (comp_mask & (1 << CAM_SFE_BUS_SFE_OUT_BHIST_2))
+		out_list[count++] = CAM_ISP_SFE_OUT_BHIST_STATS_2;
+
+	if (comp_mask & (1 << CAM_SFE_BUS_SFE_OUT_LCR))
+		out_list[count++] = CAM_ISP_SFE_OUT_RES_LCR;
+
+	*num_out = count;
+	return 0;
+}
+
 static enum cam_sfe_bus_wr_packer_format
 	cam_sfe_bus_get_packer_fmt(uint32_t out_fmt, int wm_index)
 {
@@ -766,7 +821,9 @@ static int cam_sfe_bus_start_comp_grp(
 	if (comp_grp->res_state == CAM_ISP_RESOURCE_STATE_STREAMING)
 		return 0;
 
-	/* TO DO Enable top irq */
+	bus_irq_reg_mask[CAM_SFE_IRQ_BUS_REG_STATUS0] =
+		(0x1 << (rsrc_data->comp_grp_type +
+		rsrc_data->common_data->comp_done_shift));
 
 	CAM_DBG(CAM_SFE, "Start Done SFE:%d comp_grp:%d",
 		rsrc_data->common_data->core_index,
@@ -1073,13 +1130,73 @@ static int cam_sfe_bus_release_sfe_out(void *bus_priv, void *release_args,
 	return 0;
 }
 
+static int cam_sfe_bus_wr_get_evt_payload(
+	struct cam_sfe_bus_wr_common_data       *common_data,
+	struct cam_sfe_bus_wr_irq_evt_payload  **evt_payload)
+{
+	int rc;
+
+	spin_lock(&common_data->spin_lock);
+
+	if (!common_data->hw_init) {
+		CAM_ERR_RATE_LIMIT(CAM_SFE, "SFE:%d Bus uninitialized",
+			common_data->core_index);
+		*evt_payload = NULL;
+		rc = -EPERM;
+		goto done;
+	}
+
+	if (list_empty(&common_data->free_payload_list)) {
+		CAM_ERR_RATE_LIMIT(CAM_SFE, "No free BUS event payload");
+		*evt_payload = NULL;
+		rc = -ENODEV;
+		goto done;
+	}
+
+	*evt_payload = list_first_entry(&common_data->free_payload_list,
+		struct cam_sfe_bus_wr_irq_evt_payload, list);
+	list_del_init(&(*evt_payload)->list);
+	rc = 0;
+done:
+	spin_unlock(&common_data->spin_lock);
+	return rc;
+}
+
+static int cam_sfe_bus_wr_put_evt_payload(
+	struct cam_sfe_bus_wr_common_data      *common_data,
+	struct cam_sfe_bus_wr_irq_evt_payload **evt_payload)
+{
+	unsigned long flags;
+
+	if (!common_data) {
+		CAM_ERR(CAM_SFE, "Invalid param common_data NULL");
+		return -EINVAL;
+	}
+
+	if (*evt_payload == NULL) {
+		CAM_ERR(CAM_SFE, "No payload to put");
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&common_data->spin_lock, flags);
+	if (common_data->hw_init)
+		list_add_tail(&(*evt_payload)->list,
+			&common_data->free_payload_list);
+	spin_unlock_irqrestore(&common_data->spin_lock, flags);
+
+	*evt_payload = NULL;
+
+	CAM_DBG(CAM_SFE, "Done");
+	return 0;
+}
+
 static int cam_sfe_bus_start_sfe_out(
 	struct cam_isp_resource_node          *sfe_out)
 {
 	int rc = 0, i;
 	struct cam_sfe_bus_wr_out_data      *rsrc_data = NULL;
 	struct cam_sfe_bus_wr_common_data   *common_data = NULL;
-	uint32_t bus_irq_reg_mask[2];
+	uint32_t bus_irq_reg_mask[CAM_SFE_IRQ_REGISTERS_MAX];
 	uint32_t source_group = 0;
 
 	if (!sfe_out) {
@@ -1112,8 +1229,21 @@ static int cam_sfe_bus_start_sfe_out(
 	if (rsrc_data->is_dual && !rsrc_data->is_master)
 		goto end;
 
-	/* TO DO IRQ handling */
-
+	sfe_out->irq_handle =  cam_irq_controller_subscribe_irq(
+		common_data->buf_done_controller,
+		CAM_IRQ_PRIORITY_1,
+		bus_irq_reg_mask,
+		sfe_out,
+		sfe_out->top_half_handler,
+		sfe_out->bottom_half_handler,
+		sfe_out->tasklet_info,
+		&tasklet_bh_api);
+	if (sfe_out->irq_handle < 1) {
+		CAM_ERR(CAM_SFE, "Subscribe IRQ failed for sfe out_res: %d",
+			sfe_out->res_id);
+		sfe_out->irq_handle = 0;
+		return -EFAULT;
+	}
 end:
 	sfe_out->res_state = CAM_ISP_RESOURCE_STATE_STREAMING;
 	return rc;
@@ -1148,10 +1278,161 @@ static int cam_sfe_bus_stop_sfe_out(
 		rc = cam_sfe_bus_stop_wm(&rsrc_data->wm_res[i]);
 
 	/* TO DO any IRQ handling */
+	if (sfe_out->irq_handle) {
+		cam_irq_controller_unsubscribe_irq(
+			common_data->buf_done_controller,
+			sfe_out->irq_handle);
+		sfe_out->irq_handle = 0;
+	}
+
 	sfe_out->res_state = CAM_ISP_RESOURCE_STATE_RESERVED;
 	return rc;
 }
 
+static int cam_sfe_bus_handle_sfe_out_done_top_half(
+	uint32_t evt_id,
+	struct cam_irq_th_payload *th_payload)
+{
+	int32_t                                     rc;
+	int                                         i;
+	struct cam_isp_resource_node               *sfe_out = NULL;
+	struct cam_sfe_bus_wr_out_data             *rsrc_data = NULL;
+	struct cam_sfe_bus_wr_irq_evt_payload      *evt_payload;
+	struct cam_sfe_bus_wr_comp_grp_data        *resource_data;
+	uint32_t                                    status_0;
+
+	sfe_out = th_payload->handler_priv;
+	if (!sfe_out) {
+		CAM_ERR_RATE_LIMIT(CAM_SFE, "No resource");
+		return -ENODEV;
+	}
+
+	rsrc_data = sfe_out->res_priv;
+	resource_data = rsrc_data->comp_grp->res_priv;
+
+	CAM_DBG(CAM_SFE, "SFE:%d Bus IRQ status_0: 0x%X status_1: 0x%X",
+		rsrc_data->common_data->core_index,
+		th_payload->evt_status_arr[0],
+		th_payload->evt_status_arr[1]);
+
+	rc  = cam_sfe_bus_wr_get_evt_payload(rsrc_data->common_data,
+			&evt_payload);
+	if (rc) {
+		CAM_INFO_RATE_LIMIT(CAM_SFE,
+			"SFE:%d Bus IRQ status_0: 0x%X status_1: 0x%X",
+			rsrc_data->common_data->core_index,
+			th_payload->evt_status_arr[0],
+			th_payload->evt_status_arr[1]);
+		return rc;
+	}
+
+	cam_isp_hw_get_timestamp(&evt_payload->ts);
+
+	evt_payload->core_index = rsrc_data->common_data->core_index;
+	evt_payload->evt_id = evt_id;
+
+	for (i = 0; i < th_payload->num_registers; i++)
+		evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i];
+
+	th_payload->evt_payload_priv = evt_payload;
+
+	status_0 = th_payload->evt_status_arr[CAM_SFE_IRQ_BUS_REG_STATUS0];
+
+	if (status_0 & BIT(resource_data->comp_grp_type +
+		rsrc_data->common_data->comp_done_shift)) {
+		trace_cam_log_event("bufdone", "bufdone_IRQ",
+			status_0, resource_data->comp_grp_type);
+	}
+
+	return rc;
+}
+
+static int cam_sfe_bus_handle_comp_done_bottom_half(
+	void                *handler_priv,
+	void                *evt_payload_priv,
+	uint32_t            *comp_mask)
+{
+	int rc = CAM_SFE_IRQ_STATUS_ERR;
+	struct cam_isp_resource_node          *comp_grp = handler_priv;
+	struct cam_sfe_bus_wr_irq_evt_payload *evt_payload = evt_payload_priv;
+	struct cam_sfe_bus_wr_comp_grp_data   *rsrc_data = comp_grp->res_priv;
+	uint32_t                              *cam_ife_irq_regs;
+	uint32_t                               status_0;
+
+	if (!evt_payload)
+		return rc;
+
+	if (rsrc_data->is_dual && (!rsrc_data->is_master)) {
+		CAM_ERR(CAM_SFE, "Invalid comp_grp:%u is_master:%u",
+			rsrc_data->comp_grp_type, rsrc_data->is_master);
+		return rc;
+	}
+
+	cam_ife_irq_regs = evt_payload->irq_reg_val;
+	status_0 = cam_ife_irq_regs[CAM_SFE_IRQ_BUS_REG_STATUS0];
+
+	if (status_0 & BIT(rsrc_data->comp_grp_type +
+		rsrc_data->common_data->comp_done_shift)) {
+		evt_payload->evt_id = CAM_ISP_HW_EVENT_DONE;
+		rc = CAM_SFE_IRQ_STATUS_SUCCESS;
+	}
+
+	CAM_DBG(CAM_SFE, "SFE:%d comp_grp:%d Bus IRQ status_0: 0x%X rc:%d",
+		rsrc_data->common_data->core_index, rsrc_data->comp_grp_type,
+		status_0, rc);
+
+	*comp_mask = rsrc_data->composite_mask;
+
+	return rc;
+}
+
+static int cam_sfe_bus_handle_sfe_out_done_bottom_half(
+	void                *handler_priv,
+	void                *evt_payload_priv)
+{
+	int                                    rc = -EINVAL, num_out = 0, i = 0;
+	struct cam_isp_resource_node          *sfe_out = handler_priv;
+	struct cam_sfe_bus_wr_out_data        *rsrc_data = sfe_out->res_priv;
+	struct cam_sfe_bus_wr_irq_evt_payload *evt_payload = evt_payload_priv;
+	struct cam_isp_hw_event_info           evt_info;
+	void                                  *ctx = NULL;
+	uint32_t                               evt_id = 0, comp_mask = 0;
+	uint32_t                       out_list[CAM_SFE_BUS_SFE_OUT_MAX];
+
+	rc = cam_sfe_bus_handle_comp_done_bottom_half(
+		rsrc_data->comp_grp, evt_payload_priv, &comp_mask);
+	CAM_DBG(CAM_SFE, "SFE:%d out_type:0x%X rc:%d",
+		rsrc_data->common_data->core_index, rsrc_data->out_type,
+		rsrc_data->out_type, rc);
+
+	ctx = rsrc_data->priv;
+	memset(out_list, 0, sizeof(out_list));
+
+	switch (rc) {
+	case CAM_SFE_IRQ_STATUS_SUCCESS:
+		evt_id = evt_payload->evt_id;
+
+		evt_info.res_type = sfe_out->res_type;
+		evt_info.hw_idx   = sfe_out->hw_intf->hw_idx;
+
+		rc = cam_sfe_bus_get_comp_sfe_out_res_id_list(
+			comp_mask, out_list, &num_out);
+		for (i = 0; i < num_out; i++) {
+			evt_info.res_id = out_list[i];
+			if (rsrc_data->common_data->event_cb)
+				rsrc_data->common_data->event_cb(ctx, evt_id,
+					(void *)&evt_info);
+		}
+		break;
+	default:
+		break;
+	}
+
+	cam_sfe_bus_wr_put_evt_payload(rsrc_data->common_data, &evt_payload);
+
+	return rc;
+}
+
 static int cam_sfe_bus_init_sfe_out_resource(
 	uint32_t                              index,
 	struct cam_sfe_bus_wr_priv           *bus_priv,
@@ -1220,11 +1501,12 @@ static int cam_sfe_bus_init_sfe_out_resource(
 		return rc;
 	}
 
-	/* TO DO top & bh */
 	sfe_out->start = cam_sfe_bus_start_sfe_out;
 	sfe_out->stop = cam_sfe_bus_stop_sfe_out;
-	sfe_out->top_half_handler = NULL;
-	sfe_out->bottom_half_handler = NULL;
+	sfe_out->top_half_handler =
+		cam_sfe_bus_handle_sfe_out_done_top_half;
+	sfe_out->bottom_half_handler =
+		cam_sfe_bus_handle_sfe_out_done_bottom_half;
 	sfe_out->process_cmd = cam_sfe_bus_wr_process_cmd;
 	sfe_out->hw_intf = bus_priv->common_data.hw_intf;
 	sfe_out->irq_handle = 0;
@@ -1307,6 +1589,97 @@ static int cam_sfe_bus_wr_print_dimensions(
 	return 0;
 }
 
+static int cam_sfe_bus_wr_handle_bus_irq(uint32_t    evt_id,
+	struct cam_irq_th_payload                 *th_payload)
+{
+	struct cam_sfe_bus_wr_priv          *bus_priv;
+	int rc = 0;
+
+	bus_priv = th_payload->handler_priv;
+	rc = cam_irq_controller_handle_irq(evt_id,
+		bus_priv->common_data.bus_irq_controller);
+	return (rc == IRQ_HANDLED) ? 0 : -EINVAL;
+}
+
+static int cam_sfe_bus_wr_err_irq_top_half(uint32_t evt_id,
+	struct cam_irq_th_payload *th_payload)
+{
+
+	int i = 0, rc = 0;
+	struct cam_sfe_bus_wr_priv *bus_priv =
+		th_payload->handler_priv;
+	struct cam_sfe_bus_wr_irq_evt_payload *evt_payload;
+
+	CAM_ERR_RATE_LIMIT(CAM_ISP, "SFE:%d BUS Err IRQ",
+		bus_priv->common_data.core_index);
+
+	for (i = 0; i < th_payload->num_registers; i++) {
+		CAM_ERR_RATE_LIMIT(CAM_ISP, "SFE:%d BUS IRQ status_%d: 0x%X",
+		bus_priv->common_data.core_index, i,
+			th_payload->evt_status_arr[i]);
+	}
+	cam_irq_controller_disable_irq(
+		bus_priv->common_data.bus_irq_controller,
+		bus_priv->error_irq_handle);
+
+	rc  = cam_sfe_bus_wr_get_evt_payload(&bus_priv->common_data,
+		&evt_payload);
+	if (rc)
+		return rc;
+
+	for (i = 0; i < th_payload->num_registers; i++)
+		evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i];
+
+	evt_payload->core_index = bus_priv->common_data.core_index;
+
+	evt_payload->ccif_violation_status = cam_io_r_mb(
+		bus_priv->common_data.mem_base +
+		bus_priv->common_data.common_reg->ccif_violation_status);
+
+	evt_payload->image_size_violation_status = cam_io_r_mb(
+		bus_priv->common_data.mem_base +
+		bus_priv->common_data.common_reg->image_size_violation_status);
+
+	th_payload->evt_payload_priv = evt_payload;
+
+	return rc;
+}
+
+static int cam_sfe_bus_wr_irq_bottom_half(
+	void *handler_priv, void *evt_payload_priv)
+{
+	uint32_t status = 0;
+	struct cam_sfe_bus_wr_priv            *bus_priv = handler_priv;
+	struct cam_sfe_bus_wr_common_data     *common_data;
+	struct cam_isp_hw_event_info           evt_info;
+	struct cam_sfe_bus_wr_irq_evt_payload *evt_payload = evt_payload_priv;
+
+	if (!handler_priv || !evt_payload_priv)
+		return -EINVAL;
+
+	common_data = &bus_priv->common_data;
+
+	status = evt_payload->irq_reg_val[CAM_SFE_IRQ_BUS_REG_STATUS0];
+
+	CAM_ERR(CAM_SFE,
+		"SFE:%d status 0x%x Image Size violation status 0x%x CCIF violation status 0x%x",
+		bus_priv->common_data.core_index, status,
+		evt_payload->image_size_violation_status,
+		evt_payload->ccif_violation_status);
+
+	cam_sfe_bus_wr_put_evt_payload(common_data, &evt_payload);
+
+	evt_info.hw_idx = common_data->core_index;
+	evt_info.res_type = CAM_ISP_RESOURCE_SFE_OUT;
+	evt_info.res_id = CAM_SFE_BUS_SFE_OUT_MAX;
+	evt_info.err_type = CAM_SFE_IRQ_STATUS_VIOLATION;
+
+	if (common_data->event_cb)
+		common_data->event_cb(NULL, CAM_ISP_HW_EVENT_ERROR,
+			(void *)&evt_info);
+	return 0;
+}
+
 static int cam_sfe_bus_wr_update_wm(void *priv, void *cmd_args,
 	uint32_t arg_size)
 {
@@ -1680,6 +2053,7 @@ static int cam_sfe_bus_wr_init_hw(void *hw_priv,
 	void *init_hw_args, uint32_t arg_size)
 {
 	struct cam_sfe_bus_wr_priv    *bus_priv = hw_priv;
+	uint32_t top_irq_reg_mask[CAM_SFE_IRQ_REGISTERS_MAX] = {0};
 
 	if (!bus_priv) {
 		CAM_ERR(CAM_SFE, "Invalid args");
@@ -1689,7 +2063,42 @@ static int cam_sfe_bus_wr_init_hw(void *hw_priv,
 	if (bus_priv->common_data.hw_init)
 		return 0;
 
-	/* To Do Subscribe IRQs */
+	/* Subscribe top IRQ */
+	top_irq_reg_mask[0] = (1 << bus_priv->top_irq_shift);
+
+	bus_priv->bus_irq_handle = cam_irq_controller_subscribe_irq(
+		bus_priv->common_data.sfe_irq_controller,
+		CAM_IRQ_PRIORITY_4,
+		top_irq_reg_mask,
+		bus_priv,
+		cam_sfe_bus_wr_handle_bus_irq,
+		NULL,
+		NULL,
+		NULL);
+
+	if (bus_priv->bus_irq_handle < 1) {
+		CAM_ERR(CAM_SFE, "Failed to subscribe BUS (buf_done) IRQ");
+		bus_priv->bus_irq_handle = 0;
+		return -EFAULT;
+	}
+
+	if (bus_priv->tasklet_info != NULL) {
+		bus_priv->error_irq_handle = cam_irq_controller_subscribe_irq(
+			bus_priv->common_data.bus_irq_controller,
+			CAM_IRQ_PRIORITY_0,
+			bus_wr_error_irq_mask,
+			bus_priv,
+			cam_sfe_bus_wr_err_irq_top_half,
+			cam_sfe_bus_wr_irq_bottom_half,
+			bus_priv->tasklet_info,
+			&tasklet_bh_api);
+
+		if (bus_priv->error_irq_handle < 1) {
+			CAM_ERR(CAM_SFE, "Failed to subscribe BUS Error IRQ");
+			bus_priv->error_irq_handle = 0;
+			return -EFAULT;
+		}
+	}
 
 	/* BUS_WR_TEST_BUS_CTRL */
 	cam_io_w_mb(0x0, bus_priv->common_data.mem_base +
@@ -1787,13 +2196,13 @@ int cam_sfe_bus_wr_init(
 	struct cam_hw_soc_info               *soc_info,
 	struct cam_hw_intf                   *hw_intf,
 	void                                 *bus_hw_info,
+	void                                 *sfe_irq_controller,
 	struct cam_sfe_bus                  **sfe_bus)
 {
 	int i, rc = 0;
 	struct cam_sfe_bus_wr_priv    *bus_priv = NULL;
 	struct cam_sfe_bus            *sfe_bus_local;
 	struct cam_sfe_bus_wr_hw_info *hw_info = bus_hw_info;
-	struct cam_sfe_soc_private    *soc_private = NULL;
 
 	CAM_DBG(CAM_SFE, "Enter");
 
@@ -1805,13 +2214,6 @@ int cam_sfe_bus_wr_init(
 		goto end;
 	}
 
-	soc_private = soc_info->soc_private;
-	if (!soc_private) {
-		CAM_ERR(CAM_SFE, "Invalid soc_private");
-		rc = -ENODEV;
-		goto end;
-	}
-
 	sfe_bus_local = kzalloc(sizeof(struct cam_sfe_bus), GFP_KERNEL);
 	if (!sfe_bus_local) {
 		CAM_DBG(CAM_SFE, "Failed to alloc for sfe_bus");
@@ -1841,11 +2243,11 @@ int cam_sfe_bus_wr_init(
 	bus_priv->common_data.common_reg         = &hw_info->common_reg;
 	bus_priv->common_data.comp_done_shift    = hw_info->comp_done_shift;
 	bus_priv->common_data.hw_init            = false;
-
+	bus_priv->common_data.sfe_irq_controller = sfe_irq_controller;
 	rc = cam_cpas_get_cpas_hw_version(&bus_priv->common_data.hw_version);
 	if (rc) {
 		CAM_ERR(CAM_SFE, "Failed to get hw_version rc:%d", rc);
-		goto end;
+		goto free_bus_priv;
 	}
 
 	bus_priv->comp_grp = kzalloc((sizeof(struct cam_isp_resource_node) *
@@ -1865,6 +2267,15 @@ int cam_sfe_bus_wr_init(
 	}
 
 	mutex_init(&bus_priv->common_data.bus_mutex);
+	rc = cam_irq_controller_init(drv_name,
+		bus_priv->common_data.mem_base,
+		&hw_info->common_reg.irq_reg_info,
+		&bus_priv->common_data.bus_irq_controller,
+		false);
+	if (rc) {
+		CAM_ERR(CAM_SFE, "Init bus_irq_controller failed");
+		goto free_bus_priv;
+	}
 
 	INIT_LIST_HEAD(&bus_priv->free_comp_grp);
 	INIT_LIST_HEAD(&bus_priv->used_comp_grp);
@@ -1894,6 +2305,12 @@ int cam_sfe_bus_wr_init(
 	spin_lock_init(&bus_priv->common_data.spin_lock);
 	INIT_LIST_HEAD(&bus_priv->common_data.free_payload_list);
 
+	for (i = 0; i < CAM_SFE_BUS_WR_PAYLOAD_MAX; i++) {
+		INIT_LIST_HEAD(&bus_priv->common_data.evt_payload[i].list);
+		list_add_tail(&bus_priv->common_data.evt_payload[i].list,
+			&bus_priv->common_data.free_payload_list);
+	}
+
 	sfe_bus_local->hw_ops.reserve      = cam_sfe_bus_acquire_sfe_out;
 	sfe_bus_local->hw_ops.release      = cam_sfe_bus_release_sfe_out;
 	sfe_bus_local->hw_ops.start        = cam_sfe_bus_wr_start_hw;
@@ -1958,8 +2375,8 @@ int cam_sfe_bus_wr_deinit(
 
 	spin_lock_irqsave(&bus_priv->common_data.spin_lock, flags);
 	INIT_LIST_HEAD(&bus_priv->common_data.free_payload_list);
-	//for (i = 0; i < CAM_SFE_BUS_WR_PAYLOAD_MAX; i++)
-		//INIT_LIST_HEAD(&bus_priv->common_data.evt_payload[i].list);
+	for (i = 0; i < CAM_SFE_BUS_WR_PAYLOAD_MAX; i++)
+		INIT_LIST_HEAD(&bus_priv->common_data.evt_payload[i].list);
 	bus_priv->common_data.hw_init = false;
 	spin_unlock_irqrestore(&bus_priv->common_data.spin_lock, flags);
 

+ 3 - 1
drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_wr.h

@@ -7,7 +7,6 @@
 #ifndef _CAM_SFE_BUS_WR_H_
 #define _CAM_SFE_BUS_WR_H_
 
-#include "cam_irq_controller.h"
 #include "cam_sfe_bus.h"
 
 #define CAM_SFE_BUS_WR_MAX_CLIENTS     13
@@ -72,6 +71,7 @@ struct cam_sfe_bus_reg_offset_common {
 	uint32_t debug_status_top;
 	uint32_t test_bus_ctrl;
 	uint32_t top_irq_mask_0;
+	struct cam_irq_controller_reg_info irq_reg_info;
 };
 
 /*
@@ -154,6 +154,7 @@ struct cam_sfe_bus_wr_hw_info {
  * @soc_info:                Soc Information for the associated HW
  * @hw_intf:                 HW Interface of HW to which this resource belongs
  * @bus_hw_info:             BUS HW info that contains details of BUS registers
+ * @sfe_irq_controller:      SFE irq controller
  * @sfe_bus:                 Pointer to sfe_bus structure which will be filled
  *                           and returned on successful initialize
  *
@@ -164,6 +165,7 @@ int cam_sfe_bus_wr_init(
 	struct cam_hw_soc_info               *soc_info,
 	struct cam_hw_intf                   *hw_intf,
 	void                                 *bus_hw_info,
+	void                                 *sfe_irq_controller,
 	struct cam_sfe_bus                  **sfe_bus);
 
 /*

+ 5 - 4
drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/include/cam_sfe_bus.h

@@ -6,7 +6,6 @@
 #ifndef _CAM_SFE_BUS_H_
 #define _CAM_SFE_BUS_H_
 
-#include "cam_isp_hw.h"
 #include "cam_sfe_hw_intf.h"
 
 #define CAM_SFE_BUS_WR_VER_1_0          0x1000
@@ -50,8 +49,7 @@ enum cam_sfe_bus_type {
  * @bottom_half_handler:     Bottom Half handler function
  */
 struct cam_sfe_bus {
-	void               *bus_priv;
-
+	void                          *bus_priv;
 	struct cam_hw_ops              hw_ops;
 	CAM_IRQ_HANDLER_TOP_HALF       top_half_handler;
 	CAM_IRQ_HANDLER_BOTTOM_HALF    bottom_half_handler;
@@ -67,17 +65,20 @@ struct cam_sfe_bus {
  * @soc_info:                Soc Information for the associated HW
  * @hw_intf:                 HW Interface of HW to which this resource belongs
  * @bus_hw_info:             BUS HW info that contains details of BUS registers
+ * @sfe_irq_controller:      SFE irq controller
  * @sfe_bus:                 Pointer to sfe_bus structure which will be filled
  *                           and returned on successful initialize
  *
  * @Return:                  0: Success
  *                           Non-zero: Failure
  */
-int cam_sfe_bus_init(uint32_t      bus_version,
+int cam_sfe_bus_init(
+	uint32_t      bus_version,
 	int                            bus_type,
 	struct cam_hw_soc_info        *soc_info,
 	struct cam_hw_intf            *hw_intf,
 	void                          *bus_hw_info,
+	void                          *sfe_irq_controller,
 	struct cam_sfe_bus           **sfe_bus);
 
 /*

+ 350 - 5
drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_top/cam_sfe_top.c

@@ -7,9 +7,11 @@
 #include "cam_io_util.h"
 #include "cam_cdm_util.h"
 #include "cam_sfe_hw_intf.h"
+#include "cam_tasklet_util.h"
 #include "cam_sfe_top.h"
 #include "cam_debug_util.h"
 #include "cam_sfe_soc.h"
+#include "cam_sfe_core.h"
 
 struct cam_sfe_core_cfg {
 	uint32_t   mode_sel;
@@ -18,9 +20,12 @@ struct cam_sfe_core_cfg {
 };
 
 struct cam_sfe_top_common_data {
-	struct cam_hw_soc_info                     *soc_info;
-	struct cam_hw_intf                         *hw_intf;
-	struct cam_sfe_top_common_reg_offset       *common_reg;
+	struct cam_hw_soc_info                  *soc_info;
+	struct cam_hw_intf                      *hw_intf;
+	struct cam_sfe_top_common_reg_offset    *common_reg;
+	struct cam_irq_controller               *sfe_irq_controller;
+	struct cam_sfe_top_irq_evt_payload       evt_payload[CAM_SFE_EVT_MAX];
+	struct list_head                         free_payload_list;
 };
 
 struct cam_sfe_top_priv {
@@ -38,20 +43,45 @@ struct cam_sfe_top_priv {
 		CAM_SFE_TOP_IN_PORT_MAX];
 	struct cam_sfe_core_cfg         core_cfg;
 	uint32_t                        sfe_debug_cfg;
+	spinlock_t                      spin_lock;
 };
 
 struct cam_sfe_path_data {
 	void __iomem                             *mem_base;
 	void                                     *priv;
 	struct cam_hw_intf                       *hw_intf;
+	struct cam_sfe_top_priv                  *top_priv;
 	struct cam_sfe_top_common_reg_offset     *common_reg;
 	struct cam_sfe_modules_common_reg_offset *modules_reg;
 	struct cam_sfe_path_common_reg_data      *path_reg_data;
 	struct cam_hw_soc_info                   *soc_info;
 	uint32_t                                  min_hblank_cnt;
+	int                                       error_irq_handle;
+	int                                       sof_eof_handle;
 	cam_hw_mgr_event_cb_func                  event_cb;
 };
 
+static const char *cam_sfe_top_res_id_to_string(
+	uint32_t res_id)
+{
+	switch (res_id) {
+	case CAM_ISP_HW_SFE_IN_PIX:
+		return "PP";
+	case CAM_ISP_HW_SFE_IN_RDI0:
+		return "RDI0";
+	case CAM_ISP_HW_SFE_IN_RDI1:
+		return "RDI1";
+	case CAM_ISP_HW_SFE_IN_RDI2:
+		return "RDI2";
+	case CAM_ISP_HW_SFE_IN_RDI3:
+		return "RDI3";
+	case CAM_ISP_HW_SFE_IN_RDI4:
+		return "RDI4";
+	default:
+		return "";
+	}
+}
+
 static int cam_sfe_top_core_cfg(
 	struct cam_sfe_top_priv *top_priv,
 	void *cmd_args, uint32_t arg_size)
@@ -329,6 +359,7 @@ int cam_sfe_top_reserve(void *device_priv,
 				top_priv->in_rsrc[i].res_priv;
 			path_data->event_cb = args->event_cb;
 			path_data->priv = args->priv;
+			path_data->top_priv = top_priv;
 			CAM_DBG(CAM_SFE,
 				"SFE [%u] for rsrc: %u acquired",
 				top_priv->in_rsrc[i].hw_intf->hw_idx,
@@ -379,6 +410,244 @@ int cam_sfe_top_release(void *device_priv,
 	return 0;
 }
 
+static int cam_sfe_top_get_evt_payload(
+	struct cam_sfe_top_priv            *top_priv,
+	struct cam_sfe_top_irq_evt_payload    **evt_payload)
+{
+	int rc = 0;
+
+	spin_lock(&top_priv->spin_lock);
+	if (list_empty(&top_priv->common_data.free_payload_list)) {
+		CAM_ERR_RATE_LIMIT(CAM_ISP, "No free CAMIF LITE event payload");
+		*evt_payload = NULL;
+		rc = -ENODEV;
+		goto done;
+	}
+
+	*evt_payload = list_first_entry(
+		&top_priv->common_data.free_payload_list,
+		struct cam_sfe_top_irq_evt_payload, list);
+	list_del_init(&(*evt_payload)->list);
+
+done:
+	spin_unlock(&top_priv->spin_lock);
+	return rc;
+}
+
+static int cam_sfe_top_put_evt_payload(
+	struct cam_sfe_top_priv                *top_priv,
+	struct cam_sfe_top_irq_evt_payload    **evt_payload)
+{
+	unsigned long flags;
+
+	if (!top_priv) {
+		CAM_ERR(CAM_SFE, "Invalid param core_info NULL");
+		return -EINVAL;
+	}
+	if (*evt_payload == NULL) {
+		CAM_ERR(CAM_SFE, "No payload to put");
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&top_priv->spin_lock, flags);
+	list_add_tail(&(*evt_payload)->list,
+		&top_priv->common_data.free_payload_list);
+	*evt_payload = NULL;
+	spin_unlock_irqrestore(&top_priv->spin_lock, flags);
+
+	CAM_DBG(CAM_SFE, "Done");
+	return 0;
+}
+
+static void cam_sfe_top_print_debug_reg_info(
+	struct cam_sfe_path_data           *path_data)
+{
+	CAM_INFO(CAM_SFE,
+		"Debug0: 0x%x Debug1: 0x%x Debug2: 0x%x Debug3: 0x%x",
+		cam_io_r_mb(path_data->mem_base +
+			path_data->common_reg->top_debug_0),
+		cam_io_r_mb(path_data->mem_base +
+			path_data->common_reg->top_debug_1),
+		cam_io_r_mb(path_data->mem_base +
+			path_data->common_reg->top_debug_2),
+		cam_io_r_mb(path_data->mem_base +
+			path_data->common_reg->top_debug_3));
+	CAM_INFO(CAM_SFE,
+		"Debug4: 0x%x Debug5: 0x%x Debug6: 0x%x Debug7: 0x%x",
+		cam_io_r_mb(path_data->mem_base +
+			path_data->common_reg->top_debug_4),
+		cam_io_r_mb(path_data->mem_base +
+			path_data->common_reg->top_debug_5),
+		cam_io_r_mb(path_data->mem_base +
+			path_data->common_reg->top_debug_6),
+		cam_io_r_mb(path_data->mem_base +
+			path_data->common_reg->top_debug_7));
+	CAM_INFO(CAM_SFE,
+		"Debug8: 0x%x Debug9: 0x%x Debug10: 0x%x Debug11: 0x%x",
+		cam_io_r_mb(path_data->mem_base +
+			path_data->common_reg->top_debug_8),
+		cam_io_r_mb(path_data->mem_base +
+			path_data->common_reg->top_debug_9),
+		cam_io_r_mb(path_data->mem_base +
+			path_data->common_reg->top_debug_10),
+		cam_io_r_mb(path_data->mem_base +
+			path_data->common_reg->top_debug_11));
+}
+
+static int cam_sfe_top_handle_err_irq_top_half(
+	uint32_t evt_id,
+	struct cam_irq_th_payload *th_payload)
+{
+	int rc = 0, i;
+	uint32_t irq_status = 0;
+	void __iomem *base = NULL;
+	struct cam_sfe_top_priv            *top_priv;
+	struct cam_isp_resource_node       *res;
+	struct cam_sfe_path_data           *path_data;
+	struct cam_sfe_top_irq_evt_payload *evt_payload;
+
+	res = th_payload->handler_priv;
+	path_data = res->res_priv;
+	top_priv = path_data->priv;
+
+	CAM_DBG(CAM_SFE, "Top error IRQ Received");
+
+	irq_status = th_payload->evt_status_arr[0];
+
+	base = path_data->mem_base;
+	if (irq_status & path_data->path_reg_data->error_irq_mask) {
+		CAM_ERR(CAM_SFE,
+			"SFE Violation Detected irq_status: 0x%x",
+			irq_status);
+		cam_irq_controller_disable_irq(
+			top_priv->common_data.sfe_irq_controller,
+			path_data->error_irq_handle);
+		cam_irq_controller_clear_and_mask(evt_id,
+			top_priv->common_data.sfe_irq_controller);
+	}
+
+	rc  = cam_sfe_top_get_evt_payload(top_priv, &evt_payload);
+	if (rc)
+		return rc;
+
+	for (i = 0; i < th_payload->num_registers; i++)
+		evt_payload->irq_reg_val[i] =
+			th_payload->evt_status_arr[i];
+
+	cam_isp_hw_get_timestamp(&evt_payload->ts);
+	evt_payload->violation_status =
+	cam_io_r(base +
+		top_priv->common_data.common_reg->violation_status);
+
+	th_payload->evt_payload_priv = evt_payload;
+
+	return rc;
+}
+
+static int cam_sfe_top_handle_irq_top_half(uint32_t evt_id,
+	struct cam_irq_th_payload *th_payload)
+{
+	int rc = 0, i;
+	uint32_t irq_status = 0;
+	struct cam_sfe_top_priv             *top_priv;
+	struct cam_isp_resource_node        *res;
+	struct cam_sfe_path_data            *path_data;
+	struct cam_sfe_top_irq_evt_payload  *evt_payload;
+
+	res = th_payload->handler_priv;
+	path_data = res->res_priv;
+	top_priv = path_data->top_priv;
+
+	rc  = cam_sfe_top_get_evt_payload(top_priv, &evt_payload);
+	if (rc)
+		return rc;
+
+	irq_status = th_payload->evt_status_arr[0];
+	CAM_DBG(CAM_SFE, "SFE top irq status: 0x%x",
+			irq_status);
+	for (i = 0; i < th_payload->num_registers; i++)
+		evt_payload->irq_reg_val[i] =
+			th_payload->evt_status_arr[i];
+
+	cam_isp_hw_get_timestamp(&evt_payload->ts);
+	th_payload->evt_payload_priv = evt_payload;
+	return rc;
+}
+
+static int cam_sfe_top_handle_irq_bottom_half(
+	void *handler_priv, void *evt_payload_priv)
+{
+	int i;
+	uint32_t irq_status[CAM_SFE_IRQ_REGISTERS_MAX] = {0};
+	enum cam_sfe_hw_irq_status          ret;
+	struct cam_isp_hw_event_info        evt_info;
+	struct cam_isp_resource_node       *res = handler_priv;
+	struct cam_sfe_path_data           *path_data = res->res_priv;
+	struct cam_sfe_top_priv            *top_priv = path_data->top_priv;
+	struct cam_sfe_top_irq_evt_payload *payload = evt_payload_priv;
+
+	for (i = 0; i < CAM_SFE_IRQ_REGISTERS_MAX; i++)
+		irq_status[i] = payload->irq_reg_val[i];
+
+	evt_info.hw_idx = res->hw_intf->hw_idx;
+	evt_info.res_id = res->res_id;
+	evt_info.res_type = res->res_type;
+	evt_info.reg_val = 0;
+
+	if (irq_status[0] &
+		path_data->path_reg_data->error_irq_mask) {
+		if (irq_status[0] & 0x4000)
+			CAM_ERR(CAM_SFE, "PP VIOLATION");
+
+		if (irq_status[0] & 0x8000)
+			CAM_ERR(CAM_SFE, "DIAG VIOLATION");
+
+		if (irq_status[0] & 0x10000)
+			CAM_ERR(CAM_SFE, "LINE SMOOTH VIOLATION");
+
+		CAM_INFO(CAM_SFE, "Violation status 0x%x",
+			payload->violation_status);
+
+		evt_info.err_type = CAM_SFE_IRQ_STATUS_VIOLATION;
+		cam_sfe_top_print_debug_reg_info(path_data);
+		if (path_data->event_cb)
+			path_data->event_cb(NULL,
+				CAM_ISP_HW_EVENT_ERROR, (void *)&evt_info);
+
+		ret = CAM_SFE_IRQ_STATUS_VIOLATION;
+	}
+
+	/* To Do Debugfs entry to control the enablement */
+	if (irq_status[0] & path_data->path_reg_data->subscribe_irq_mask) {
+		if (irq_status[0] & path_data->path_reg_data->sof_irq_mask) {
+			CAM_INFO_RATE_LIMIT(CAM_SFE, "SFE:%d Received %s SOF",
+				evt_info.hw_idx,
+				cam_sfe_top_res_id_to_string(res->res_id));
+		}
+
+		if (irq_status[0] &
+			path_data->path_reg_data->eof_irq_mask) {
+			CAM_INFO_RATE_LIMIT(CAM_SFE, "SFE:%d Received %s EOF",
+				evt_info.hw_idx,
+				cam_sfe_top_res_id_to_string(res->res_id));
+		}
+		ret = CAM_SFE_IRQ_STATUS_SUCCESS;
+	}
+
+	/* To DO frame counter under debugfs */
+	CAM_DBG(CAM_SFE,
+		"SFE:%d SFE_DIAG_SENSOR_STATUS0: 0x%x SFE_DIAG_SENSOR_STATUS1: 0x%x",
+		evt_info.hw_idx,
+		cam_io_r(path_data->mem_base +
+			path_data->common_reg->diag_sensor_status_0),
+		cam_io_r(path_data->mem_base +
+			path_data->common_reg->diag_sensor_status_1));
+
+	cam_sfe_top_put_evt_payload(top_priv, &payload);
+
+	return ret;
+}
+
 int cam_sfe_top_start(
 	void *priv, void *start_args, uint32_t arg_size)
 {
@@ -387,6 +656,8 @@ int cam_sfe_top_start(
 	struct cam_isp_resource_node         *sfe_res;
 	struct cam_hw_info                   *hw_info = NULL;
 	struct cam_sfe_path_data             *path_data;
+	uint32_t   error_mask[CAM_SFE_IRQ_REGISTERS_MAX];
+	uint32_t   sof_eof_mask[CAM_SFE_IRQ_REGISTERS_MAX];
 
 	if (!priv || !start_args) {
 		CAM_ERR(CAM_SFE, "Invalid args");
@@ -421,13 +692,54 @@ int cam_sfe_top_start(
 			path_data->common_reg->core_cfg));
 
 	/* Enable debug cfg registers */
-	cam_io_w_mb(path_data->path_reg_data->top_debug_cfg_en,
+	cam_io_w(path_data->path_reg_data->top_debug_cfg_en,
 		path_data->mem_base +
 		path_data->common_reg->top_debug_cfg);
 
 	/* Enable sensor diag info */
-	/* Enable SOF & EOF IRQ based on debug flag */
+	/* TO DO - debug fs to enable*/
+	cam_io_w(path_data->path_reg_data->enable_diagnostic_hw,
+		path_data->mem_base + path_data->common_reg->diag_config);
+
+	error_mask[0] = path_data->path_reg_data->error_irq_mask;
 	/* Enable error IRQ by default */
+	if (!path_data->error_irq_handle) {
+		path_data->error_irq_handle = cam_irq_controller_subscribe_irq(
+			top_priv->common_data.sfe_irq_controller,
+			CAM_IRQ_PRIORITY_0,
+			error_mask,
+			sfe_res,
+			cam_sfe_top_handle_err_irq_top_half,
+			cam_sfe_top_handle_irq_bottom_half,
+			sfe_res->tasklet_info,
+			&tasklet_bh_api);
+
+		if (path_data->error_irq_handle < 1) {
+			CAM_ERR(CAM_SFE, "Failed to subscribe Top IRQ");
+			path_data->error_irq_handle = 0;
+			return -EFAULT;
+		}
+	}
+
+	/* TO DO define the debugfs to enable/disable sof/eof irq */
+	if (!path_data->sof_eof_handle) {
+		sof_eof_mask[0] = path_data->path_reg_data->subscribe_irq_mask;
+		path_data->sof_eof_handle = cam_irq_controller_subscribe_irq(
+			top_priv->common_data.sfe_irq_controller,
+			CAM_IRQ_PRIORITY_1,
+			sof_eof_mask,
+			sfe_res,
+			cam_sfe_top_handle_irq_top_half,
+			cam_sfe_top_handle_irq_bottom_half,
+			sfe_res->tasklet_info,
+			&tasklet_bh_api);
+
+		if (path_data->sof_eof_handle < 1) {
+			CAM_ERR(CAM_SFE, "Failed to subscribe SOF/EOF IRQ");
+			path_data->sof_eof_handle = 0;
+			return -EFAULT;
+		}
+	}
 
 	sfe_res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING;
 	return 0;
@@ -439,6 +751,7 @@ int cam_sfe_top_stop(
 	int i;
 	struct cam_sfe_top_priv       *top_priv;
 	struct cam_isp_resource_node  *sfe_res;
+	struct cam_sfe_path_data      *path_data;
 
 	if (!priv || !stop_args) {
 		CAM_ERR(CAM_SFE, "Invalid args");
@@ -447,6 +760,7 @@ int cam_sfe_top_stop(
 
 	top_priv = (struct cam_sfe_top_priv *)priv;
 	sfe_res = (struct cam_isp_resource_node *) stop_args;
+	path_data = sfe_res->res_priv;
 
 	if (sfe_res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED ||
 		sfe_res->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE)
@@ -465,6 +779,18 @@ int cam_sfe_top_stop(
 		}
 	}
 
+	if (path_data->error_irq_handle > 0) {
+		cam_irq_controller_unsubscribe_irq(
+			top_priv->common_data.sfe_irq_controller,
+			path_data->error_irq_handle);
+	}
+
+	if (path_data->sof_eof_handle > 0) {
+		cam_irq_controller_unsubscribe_irq(
+			top_priv->common_data.sfe_irq_controller,
+			path_data->sof_eof_handle);
+	}
+
 	return 0;
 }
 
@@ -473,6 +799,7 @@ int cam_sfe_top_init(
 	struct cam_hw_soc_info             *soc_info,
 	struct cam_hw_intf                 *hw_intf,
 	void                               *top_hw_info,
+	void                               *sfe_irq_controller,
 	struct cam_sfe_top                **sfe_top_ptr)
 {
 	int i, j, rc = 0;
@@ -497,6 +824,7 @@ int cam_sfe_top_init(
 	}
 
 	sfe_top->top_priv = top_priv;
+	top_priv->common_data.sfe_irq_controller = sfe_irq_controller;
 	if (sfe_top_hw_info->num_inputs > CAM_SFE_TOP_IN_PORT_MAX) {
 		CAM_ERR(CAM_SFE,
 			"Invalid number of input resources: %d max: %d",
@@ -590,6 +918,15 @@ int cam_sfe_top_init(
 	sfe_top->hw_ops.stop = cam_sfe_top_stop;
 	sfe_top->hw_ops.reserve = cam_sfe_top_reserve;
 	sfe_top->hw_ops.release = cam_sfe_top_release;
+
+	spin_lock_init(&top_priv->spin_lock);
+	INIT_LIST_HEAD(&top_priv->common_data.free_payload_list);
+	for (i = 0; i < CAM_SFE_EVT_MAX; i++) {
+		INIT_LIST_HEAD(&top_priv->common_data.evt_payload[i].list);
+		list_add_tail(&top_priv->common_data.evt_payload[i].list,
+			&top_priv->common_data.free_payload_list);
+	}
+
 	*sfe_top_ptr = sfe_top;
 
 	return rc;
@@ -625,6 +962,7 @@ int cam_sfe_top_deinit(
 	struct cam_sfe_top **sfe_top_ptr)
 {
 	int i, rc = 0;
+	unsigned long flags;
 	struct cam_sfe_top      *sfe_top;
 	struct cam_sfe_top_priv *top_priv;
 
@@ -651,6 +989,13 @@ int cam_sfe_top_deinit(
 		top_priv->common_data.hw_intf->hw_idx,
 		hw_version);
 
+	spin_lock_irqsave(&top_priv->spin_lock, flags);
+	INIT_LIST_HEAD(&top_priv->common_data.free_payload_list);
+		for (i = 0; i < CAM_SFE_EVT_MAX; i++)
+			INIT_LIST_HEAD(
+				&top_priv->common_data.evt_payload[i].list);
+	spin_unlock_irqrestore(&top_priv->spin_lock, flags);
+
 	for (i = 0; i < CAM_SFE_TOP_IN_PORT_MAX; i++) {
 		top_priv->in_rsrc[i].res_state =
 			CAM_ISP_RESOURCE_STATE_UNAVAILABLE;

+ 1 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_top/cam_sfe_top.h

@@ -93,6 +93,7 @@ int cam_sfe_top_init(
 	struct cam_hw_soc_info             *soc_info,
 	struct cam_hw_intf                 *hw_intf,
 	void                               *top_hw_info,
+	void                               *sfe_irq_controller,
 	struct cam_sfe_top                **sfe_top);
 
 int cam_sfe_top_deinit(