diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index 570d2ba0e484..2c58913ef1f3 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -43,6 +43,8 @@ /* Max CSI Rx irq error count threshold value */ #define CAM_IFE_CSID_MAX_IRQ_ERROR_COUNT 100 +static int cam_ife_csid_reset_regs( + struct cam_ife_csid_hw *csid_hw, bool reset_hw); static int cam_ife_csid_is_ipp_ppp_format_supported( uint32_t in_format) { @@ -419,7 +421,7 @@ static int cam_ife_csid_global_reset(struct cam_ife_csid_hw *csid_hw) const struct cam_ife_csid_reg_offset *csid_reg; int rc = 0; uint32_t val = 0, i; - uint32_t status; + unsigned long flags; soc_info = &csid_hw->hw_info->soc_info; csid_reg = csid_hw->csid_info->csid_reg; @@ -434,6 +436,8 @@ static int cam_ife_csid_global_reset(struct cam_ife_csid_hw *csid_hw) CAM_DBG(CAM_ISP, "CSID:%d Csid reset", csid_hw->hw_intf->hw_idx); + spin_lock_irqsave(&csid_hw->hw_info->hw_lock, flags); + /* Mask all interrupts */ cam_io_w_mb(0, soc_info->reg_map[0].mem_base + csid_reg->csi2_reg->csid_csi2_rx_irq_mask_addr); @@ -481,6 +485,8 @@ static int cam_ife_csid_global_reset(struct cam_ife_csid_hw *csid_hw) cam_io_w_mb(1, soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_irq_cmd_addr); + spin_unlock_irqrestore(&csid_hw->hw_info->hw_lock, flags); + cam_io_w_mb(0x80, soc_info->reg_map[0].mem_base + csid_hw->csid_info->csid_reg->csi2_reg->csid_csi2_rx_cfg1_addr); @@ -497,37 +503,14 @@ static int cam_ife_csid_global_reset(struct cam_ife_csid_hw *csid_hw) cam_io_w_mb(0x2, soc_info->reg_map[0].mem_base + csid_reg->rdi_reg[i]->csid_rdi_cfg0_addr); - /* perform the top CSID HW registers reset */ - cam_io_w_mb(csid_reg->cmn_reg->csid_rst_stb, - soc_info->reg_map[0].mem_base + - csid_reg->cmn_reg->csid_rst_strobes_addr); + /* reset HW regs first, then SW */ + rc = cam_ife_csid_reset_regs(csid_hw, true); + if (rc < 0) + goto end; + rc = cam_ife_csid_reset_regs(csid_hw, false); + if (rc < 0) + goto end; - rc = readl_poll_timeout(soc_info->reg_map[0].mem_base + - csid_reg->cmn_reg->csid_top_irq_status_addr, - status, (status & 0x1) == 0x1, - CAM_IFE_CSID_TIMEOUT_SLEEP_US, CAM_IFE_CSID_TIMEOUT_ALL_US); - if (rc < 0) { - CAM_ERR(CAM_ISP, "CSID:%d csid_reset fail rc = %d", - csid_hw->hw_intf->hw_idx, rc); - rc = -ETIMEDOUT; - } - - /* perform the SW registers reset */ - cam_io_w_mb(csid_reg->cmn_reg->csid_reg_rst_stb, - soc_info->reg_map[0].mem_base + - csid_reg->cmn_reg->csid_rst_strobes_addr); - - rc = readl_poll_timeout(soc_info->reg_map[0].mem_base + - csid_reg->cmn_reg->csid_top_irq_status_addr, - status, (status & 0x1) == 0x1, - CAM_IFE_CSID_TIMEOUT_SLEEP_US, CAM_IFE_CSID_TIMEOUT_ALL_US); - if (rc < 0) { - CAM_ERR(CAM_ISP, "CSID:%d csid_reset fail rc = %d", - csid_hw->hw_intf->hw_idx, rc); - rc = -ETIMEDOUT; - } - - usleep_range(3000, 3010); val = cam_io_r_mb(soc_info->reg_map[0].mem_base + csid_reg->csi2_reg->csid_csi2_rx_irq_mask_addr); if (val != 0) @@ -536,6 +519,7 @@ static int cam_ife_csid_global_reset(struct cam_ife_csid_hw *csid_hw) csid_hw->error_irq_count = 0; csid_hw->prev_boot_timestamp = 0; +end: return rc; } @@ -655,7 +639,7 @@ static int cam_ife_csid_path_reset(struct cam_ife_csid_hw *csid_hw, return -EINVAL; } - init_completion(complete); + reinit_completion(complete); reset_strb_val = csid_reg->cmn_reg->path_rst_stb_all; /* Reset the corresponding ife csid path */ @@ -1240,6 +1224,8 @@ static int cam_ife_csid_enable_hw(struct cam_ife_csid_hw *csid_hw) if (rc) goto disable_soc; + spin_lock_irqsave(&csid_hw->hw_info->hw_lock, flags); + /* clear all interrupts */ cam_io_w_mb(1, soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_top_irq_clear_addr); @@ -1271,6 +1257,8 @@ static int cam_ife_csid_enable_hw(struct cam_ife_csid_hw *csid_hw) cam_io_w_mb(1, soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_irq_cmd_addr); + spin_unlock_irqrestore(&csid_hw->hw_info->hw_lock, flags); + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_hw_version_addr); CAM_DBG(CAM_ISP, "CSID:%d CSID HW version: 0x%x", @@ -1564,7 +1552,7 @@ static int cam_ife_csid_enable_csi2( } } - /*Enable the CSI2 rx inerrupts */ + /*Enable the CSI2 rx interrupts */ val = CSID_CSI2_RX_INFO_RST_DONE | CSID_CSI2_RX_ERROR_TG_FIFO_OVERFLOW | CSID_CSI2_RX_ERROR_LANE0_FIFO_OVERFLOW | @@ -3093,6 +3081,7 @@ int cam_ife_csid_reset(void *hw_priv, csid_hw = (struct cam_ife_csid_hw *)csid_hw_info->core_info; reset = (struct cam_csid_reset_cfg_args *)reset_args; + mutex_lock(&csid_hw->hw_info->hw_mutex); switch (reset->reset_type) { case CAM_IFE_CSID_RESET_GLOBAL: rc = cam_ife_csid_global_reset(csid_hw); @@ -3106,6 +3095,7 @@ int cam_ife_csid_reset(void *hw_priv, rc = -EINVAL; break; } + mutex_unlock(&csid_hw->hw_info->hw_mutex); return rc; } @@ -3230,43 +3220,86 @@ end: return rc; } -static int cam_ife_csid_reset_retain_sw_reg( - struct cam_ife_csid_hw *csid_hw) +static int cam_ife_csid_reset_regs( + struct cam_ife_csid_hw *csid_hw, bool reset_hw) { int rc = 0; - uint32_t status; const struct cam_ife_csid_reg_offset *csid_reg = csid_hw->csid_info->csid_reg; struct cam_hw_soc_info *soc_info; + uint32_t val = 0; + unsigned long flags; soc_info = &csid_hw->hw_info->soc_info; + + reinit_completion(&csid_hw->csid_top_complete); + + spin_lock_irqsave(&csid_hw->hw_info->hw_lock, flags); + /* clear the top interrupt first */ cam_io_w_mb(1, soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_top_irq_clear_addr); cam_io_w_mb(1, soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_irq_cmd_addr); - cam_io_w_mb(csid_reg->cmn_reg->csid_rst_stb, + if (reset_hw) { + /* enable top reset complete IRQ */ + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_mask_addr); + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_irq_cmd_addr); + } + + /* perform the top CSID registers reset */ + val = reset_hw ? csid_reg->cmn_reg->csid_rst_stb : + csid_reg->cmn_reg->csid_reg_rst_stb; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_rst_strobes_addr); - rc = readl_poll_timeout(soc_info->reg_map[0].mem_base + - csid_reg->cmn_reg->csid_top_irq_status_addr, - status, (status & 0x1) == 0x1, - CAM_IFE_CSID_TIMEOUT_SLEEP_US, CAM_IFE_CSID_TIMEOUT_ALL_US); - if (rc < 0) { - CAM_ERR(CAM_ISP, "CSID:%d csid_reset fail rc = %d", - csid_hw->hw_intf->hw_idx, rc); + + /* + * for SW reset, we enable the IRQ after since the mask + * register has been reset + */ + if (!reset_hw) { + /* enable top reset complete IRQ */ + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_mask_addr); + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_irq_cmd_addr); + } + + spin_unlock_irqrestore(&csid_hw->hw_info->hw_lock, flags); + CAM_DBG(CAM_ISP, "CSID reset start"); + rc = wait_for_completion_timeout(&csid_hw->csid_top_complete, + msecs_to_jiffies(IFE_CSID_TIMEOUT)); + if (rc <= 0) { + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_status_addr); + if (val & 0x1) { + /* clear top reset IRQ */ + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_clear_addr); + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_irq_cmd_addr); + CAM_DBG(CAM_ISP, "CSID:%d %s reset completed %d", + csid_hw->hw_intf->hw_idx, + reset_hw ? "hw" : "sw", + rc); + rc = 0; + goto end; + } + CAM_ERR(CAM_ISP, "CSID:%d csid_reset %s fail rc = %d", + csid_hw->hw_intf->hw_idx, reset_hw ? "hw" : "sw", rc); rc = -ETIMEDOUT; + goto end; } else { - CAM_DBG(CAM_ISP, "CSID:%d hw reset completed %d", - csid_hw->hw_intf->hw_idx, rc); + CAM_DBG(CAM_ISP, "CSID:%d %s reset completed %d", + csid_hw->hw_intf->hw_idx, reset_hw ? "hw" : "sw", rc); rc = 0; } - cam_io_w_mb(1, soc_info->reg_map[0].mem_base + - csid_reg->cmn_reg->csid_top_irq_clear_addr); - cam_io_w_mb(1, soc_info->reg_map[0].mem_base + - csid_reg->cmn_reg->csid_irq_cmd_addr); +end: return rc; } @@ -3351,9 +3384,9 @@ int cam_ife_csid_init_hw(void *hw_priv, break; } - rc = cam_ife_csid_reset_retain_sw_reg(csid_hw); + rc = cam_ife_csid_reset_regs(csid_hw, true); if (rc < 0) - CAM_ERR(CAM_ISP, "CSID: Failed in SW reset"); + CAM_ERR(CAM_ISP, "CSID: Failed in HW reset"); if (rc) cam_ife_csid_disable_hw(csid_hw); @@ -3830,7 +3863,11 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) } } + spin_lock_irqsave(&csid_hw->hw_info->hw_lock, flags); /* clear */ + cam_io_w_mb(irq_status_top, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_clear_addr); + cam_io_w_mb(irq_status_rx, soc_info->reg_map[0].mem_base + csid_reg->csi2_reg->csid_csi2_rx_irq_clear_addr); if (csid_reg->cmn_reg->num_pix) @@ -3860,6 +3897,8 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) cam_io_w_mb(1, soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_irq_cmd_addr); + spin_unlock_irqrestore(&csid_hw->hw_info->hw_lock, flags); + CAM_DBG(CAM_ISP, "irq_status_top = 0x%x", irq_status_top); CAM_DBG(CAM_ISP, "irq_status_rx = 0x%x", irq_status_rx); CAM_DBG(CAM_ISP, "irq_status_ipp = 0x%x", irq_status_ipp); @@ -3871,6 +3910,11 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) "irq_status_udi0= 0x%x irq_status_udi1= 0x%x irq_status_udi2= 0x%x", irq_status_udi[0], irq_status_udi[1], irq_status_udi[2]); + if (irq_status_top & CSID_TOP_IRQ_DONE) { + CAM_DBG(CAM_ISP, "csid top reset complete"); + complete(&csid_hw->csid_top_complete); + } + if (irq_status_rx & BIT(csid_reg->csi2_reg->csi2_rst_done_shift_val)) { CAM_DBG(CAM_ISP, "csi rx reset complete"); complete(&csid_hw->csid_csi2_complete); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h index 863aec341899..4c2ac18089af 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h @@ -40,6 +40,7 @@ #define CSID_CSI2_RX_ERROR_TG_FIFO_OVERFLOW BIT(26) #define CSID_CSI2_RX_INFO_RST_DONE BIT(27) +#define CSID_TOP_IRQ_DONE BIT(0) #define CSID_PATH_INFO_RST_DONE BIT(1) #define CSID_PATH_ERROR_FIFO_OVERFLOW BIT(2) #define CSID_PATH_INFO_SUBSAMPLED_EOF BIT(3)