|
@@ -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);
|
|
|
-
|
|
|
- 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;
|
|
|
- }
|
|
|
+ /* 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;
|
|
|
|
|
|
- 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);
|