From 64910dc3d6542b1498b6c72ab5be11f958a1ccb7 Mon Sep 17 00:00:00 2001 From: Ayush Kumar Date: Fri, 11 Sep 2020 17:11:00 +0530 Subject: [PATCH] msm: camera: tfe: Change csid stop sequence during flush This change takes care of a race which we see when we halt master csid immediately and slave csid halt to follow. In some scenarios after master csid halt, slave gives violation errors. With this change we are first changing the mode of slave to master then issue halt commands to both master and slave. CRs-Fixed: 2773668 Change-Id: Iab7baa41a69b2e4e0a658c7abac29d2dcb80c289 Signed-off-by: Ayush Kumar --- drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c | 55 +++++++++++ .../isp_hw_mgr/isp_hw/include/cam_isp_hw.h | 1 + .../isp_hw/include/cam_tfe_csid_hw_intf.h | 27 ++++++ .../isp_hw/tfe_csid_hw/cam_tfe_csid_core.c | 97 ++++++++++++++++++- 4 files changed, 179 insertions(+), 1 deletion(-) diff --git a/drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c index 8aa68af8ca62..4f2c990e0faf 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c @@ -529,6 +529,48 @@ static int cam_tfe_hw_mgr_free_hw_res( return 0; } +static int cam_tfe_mgr_csid_change_halt_mode(struct list_head *halt_list, + uint32_t base_idx, enum cam_tfe_csid_halt_mode halt_mode) +{ + struct cam_isp_hw_mgr_res *hw_mgr_res; + struct cam_isp_resource_node *isp_res; + struct cam_csid_hw_halt_args halt; + struct cam_hw_intf *hw_intf; + uint32_t i; + int rc = 0; + + list_for_each_entry(hw_mgr_res, halt_list, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i] || + (hw_mgr_res->hw_res[i]->res_state != + CAM_ISP_RESOURCE_STATE_STREAMING)) + continue; + + isp_res = hw_mgr_res->hw_res[i]; + if (isp_res->hw_intf->hw_idx != base_idx) + continue; + + if ((isp_res->res_type == CAM_ISP_RESOURCE_PIX_PATH) && + (isp_res->res_id == + CAM_TFE_CSID_PATH_RES_IPP)) { + hw_intf = isp_res->hw_intf; + halt.node_res = isp_res; + halt.halt_mode = halt_mode; + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_ISP_HW_CMD_CSID_CHANGE_HALT_MODE, + &halt, + sizeof(struct cam_csid_hw_halt_args)); + if (rc) + CAM_ERR(CAM_ISP, "Halt update failed"); + break; + } + } + } + + return rc; +} + static int cam_tfe_mgr_csid_stop_hw( struct cam_tfe_hw_mgr_ctx *ctx, struct list_head *stop_list, uint32_t base_idx, uint32_t stop_cmd) @@ -2650,6 +2692,19 @@ static int cam_tfe_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) */ if (i == ctx->num_base) master_base_idx = ctx->base[0].idx; + + /*Change slave mode*/ + if (csid_halt_type == CAM_CSID_HALT_IMMEDIATELY) { + for (i = 0; i < ctx->num_base; i++) { + if (ctx->base[i].idx == master_base_idx) + continue; + cam_tfe_mgr_csid_change_halt_mode( + &ctx->res_list_tfe_csid, + ctx->base[i].idx, + CAM_TFE_CSID_HALT_MODE_INTERNAL); + } + } + CAM_DBG(CAM_ISP, "Stopping master CSID idx %d", master_base_idx); /* Stop the master CSID path first */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h index a3aef55354ea..8cec98ffeb4d 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h @@ -129,6 +129,7 @@ enum cam_isp_hw_cmd_type { CAM_ISP_HW_CMD_BLANKING_UPDATE, CAM_ISP_HW_CMD_CSID_CLOCK_DUMP, CAM_ISP_HW_CMD_TPG_CORE_CFG_CMD, + CAM_ISP_HW_CMD_CSID_CHANGE_HALT_MODE, CAM_ISP_HW_CMD_MAX, }; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_tfe_csid_hw_intf.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_tfe_csid_hw_intf.h index a665ac589311..f93c606392cb 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_tfe_csid_hw_intf.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_tfe_csid_hw_intf.h @@ -95,6 +95,33 @@ enum cam_tfe_csid_halt_cmd { CAM_TFE_CSID_HALT_MAX, }; +/** + * enum cam_tfe_csid_halt_mode_cmd - Specify the halt command type + */ +enum cam_tfe_csid_halt_mode { + CAM_TFE_CSID_HALT_MODE_INTERNAL, + CAM_TFE_CSID_HALT_MODE_GLOBAL, + CAM_TFE_CSID_HALT_MODE_MASTER, + CAM_TFE_CSID_HALT_MODE_SLAVE, + CAM_TFE_CSID_HALT_MODE_MAX, +}; + +/** + * struct cam_csid_hw_halt_args + * @halt_mode : Applicable only for PATH resources + * 0 Internal : The CSID responds to the HALT_CMD + * 1 Global : The CSID responds to the GLOBAL_HALT_CMD + * 2 Master : The CSID responds to the HALT_CMD + * 3 Slave : The CSID responds to the external halt command + * and not the HALT_CMD register + * @node_res : reource pointer array( ie cid or CSID) + * + */ +struct cam_csid_hw_halt_args { + enum cam_tfe_csid_halt_mode halt_mode; + struct cam_isp_resource_node *node_res; +}; + /** * struct cam_csid_hw_stop- stop all resources * @stop_cmd : Applicable only for PATH resources diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.c index f9325204ba72..0958b9790068 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.c @@ -1246,6 +1246,63 @@ static int cam_tfe_csid_enable_pxl_path( return 0; } +static void cam_tfe_csid_change_pxl_halt_mode( + struct cam_tfe_csid_hw *csid_hw, + struct cam_isp_resource_node *res, + enum cam_tfe_csid_halt_mode halt_mode) +{ + uint32_t val = 0; + const struct cam_tfe_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + struct cam_tfe_csid_path_cfg *path_data; + const struct cam_tfe_csid_pxl_reg_offset *pxl_reg; + bool is_ipp; + + path_data = (struct cam_tfe_csid_path_cfg *) res->res_priv; + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + + if (res->res_id >= CAM_TFE_CSID_PATH_RES_MAX) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid res id%d", + csid_hw->hw_intf->hw_idx, res->res_id); + goto end; + } + + if (res->res_state == CAM_ISP_RESOURCE_STATE_INIT_HW || + res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR(CAM_ISP, "CSID:%d Res:%d already in stopped state:%d", + csid_hw->hw_intf->hw_idx, res->res_id, res->res_state); + goto end; + } + + if (res->res_id == CAM_TFE_CSID_PATH_RES_IPP) { + is_ipp = true; + pxl_reg = csid_reg->ipp_reg; + } else { + goto end; + } + + if (res->res_state != CAM_ISP_RESOURCE_STATE_STREAMING) { + CAM_ERR(CAM_ISP, "CSID:%d %s path Res:%d Invalid state%d", + csid_hw->hw_intf->hw_idx, "IPP", + res->res_id, res->res_state); + goto end; + } + + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_irq_mask_addr); + + /* configure Halt for slave */ + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_ctrl_addr); + val &= ~0xC; + val |= (halt_mode << 2); + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_ctrl_addr); +end: + return; +} + static int cam_tfe_csid_disable_pxl_path( struct cam_tfe_csid_hw *csid_hw, struct cam_isp_resource_node *res, @@ -2088,6 +2145,41 @@ end: return rc; } +int cam_tfe_csid_halt(struct cam_tfe_csid_hw *csid_hw, + void *halt_args) +{ + struct cam_isp_resource_node *res; + struct cam_csid_hw_halt_args *csid_halt; + + if (!csid_hw || !halt_args) { + CAM_ERR(CAM_ISP, "CSID: Invalid args"); + return -EINVAL; + } + + csid_halt = (struct cam_csid_hw_halt_args *)halt_args; + + /* Change the halt mode */ + res = csid_halt->node_res; + CAM_DBG(CAM_ISP, "CSID:%d res_type %d res_id %d", + csid_hw->hw_intf->hw_idx, + res->res_type, res->res_id); + + switch (res->res_type) { + case CAM_ISP_RESOURCE_PIX_PATH: + if (res->res_id == CAM_TFE_CSID_PATH_RES_IPP) + cam_tfe_csid_change_pxl_halt_mode(csid_hw, res, + csid_halt->halt_mode); + break; + default: + CAM_ERR(CAM_ISP, "CSID:%d Invalid res type%d", + csid_hw->hw_intf->hw_idx, + res->res_type); + break; + } + + return 0; +} + static int cam_tfe_csid_stop(void *hw_priv, void *stop_args, uint32_t arg_size) { @@ -2095,7 +2187,7 @@ static int cam_tfe_csid_stop(void *hw_priv, struct cam_tfe_csid_hw *csid_hw; struct cam_hw_info *csid_hw_info; struct cam_isp_resource_node *res; - struct cam_tfe_csid_hw_stop_args *csid_stop; + struct cam_tfe_csid_hw_stop_args *csid_stop; uint32_t i; uint32_t res_mask = 0; @@ -2472,6 +2564,9 @@ static int cam_tfe_csid_process_cmd(void *hw_priv, case CAM_ISP_HW_CMD_DUMP_HW: rc = cam_tfe_csid_dump_hw(csid_hw, cmd_args); break; + case CAM_ISP_HW_CMD_CSID_CHANGE_HALT_MODE: + rc = cam_tfe_csid_halt(csid_hw, cmd_args); + break; default: CAM_ERR(CAM_ISP, "CSID:%d unsupported cmd:%d", csid_hw->hw_intf->hw_idx, cmd_type);