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);