From e4b180abaf756fb9e6a6094365b4d220b5ac9390 Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Tue, 28 Jul 2020 22:25:46 -0700 Subject: [PATCH] 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 Signed-off-by: Karthik Anantha Ram --- .../isp_hw/include/cam_sfe_hw_intf.h | 69 ++- .../isp_hw_mgr/isp_hw/sfe_hw/cam_sfe680.h | 48 +- .../isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_core.c | 35 +- .../isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_core.h | 2 - .../isp_hw/sfe_hw/sfe_bus/cam_sfe_bus.c | 5 +- .../isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_rd.c | 274 ++++++++++- .../isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_rd.h | 5 +- .../isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_wr.c | 465 +++++++++++++++++- .../isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_wr.h | 4 +- .../sfe_hw/sfe_bus/include/cam_sfe_bus.h | 9 +- .../isp_hw/sfe_hw/sfe_top/cam_sfe_top.c | 355 ++++++++++++- .../isp_hw/sfe_hw/sfe_top/cam_sfe_top.h | 1 + 12 files changed, 1201 insertions(+), 71 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_sfe_hw_intf.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_sfe_hw_intf.h index 55f76f30f3..c517563bdd 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_sfe_hw_intf.h +++ b/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 - * @ccif_violation_status ccif violation status - * @overflow_status bus overflow status - * @image_size_vio_sts image size violations status + * @violation_status ccif violation status * @error_type: Identify different errors * @ts: Timestamp */ -struct cam_sfe_irq_evt_payload { +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 bus_irq_val[CAM_SFE_BUS_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_bus_wr_irq_evt_payload { + struct list_head list; + uint32_t core_index; + 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; }; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe680.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe680.h index 2da1d3f35d..1821310f9b 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe680.h +++ b/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, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_core.c index ca0220c10d..8c6907f297 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_core.c +++ b/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; } diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_core.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_core.h index 349de9e7e1..b8ed146e34 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_core.h +++ b/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; }; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus.c index d713714e1d..39bf7eb4b3 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus.c +++ b/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", diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_rd.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_rd.c index f9ad59da9f..7bed7948c5 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_rd.c +++ b/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); + sfe_top_irq_mask[0] = (1 << bus_priv->top_irq_shift); - /* Subscribe for error IRQs */ + /* 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; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_rd.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_rd.h index e3dd098810..39ad21d747 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_rd.h +++ b/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 diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_wr.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_wr.c index 9dac41227e..5666b8df14 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_wr.c +++ b/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); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_wr.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_wr.h index 54ea96bb3d..1b448247ed 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_wr.h +++ b/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); /* diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/include/cam_sfe_bus.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/include/cam_sfe_bus.h index 7cac810839..00cc78689b 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/include/cam_sfe_bus.h +++ b/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); /* diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_top/cam_sfe_top.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_top/cam_sfe_top.c index a61a539fdb..e3586e65de 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_top/cam_sfe_top.c +++ b/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; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_top/cam_sfe_top.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_top/cam_sfe_top.h index c6ad175792..fc30248088 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_top/cam_sfe_top.h +++ b/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(