浏览代码

msm: camera: isp: csid hw register reset with IRQ

CSID hw register reset is done with the the help of
IRQ to make sure it is reset every time before we start
a new session.

CRs-Fixed: 2563958
Change-Id: I33c870003eb1e99d458b7650b5b3218f61cccd3b
Signed-off-by: Tejas Prajapati <[email protected]>
Tejas Prajapati 5 年之前
父节点
当前提交
809c56ef16

+ 96 - 52
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);
-
-	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);

+ 1 - 0
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)