Browse Source

msm: camera: tfe: Handle sof monotonic boot time stamp

Modify the sof monotonic boot timestamp logic. Boot time
stamp difference between two frames should not change,
it should be same as qtime csid time stamp difference.
So modified logic to give proper boot time stamp with no
difference in the successive frames, the difference of sof
time stamp taken from qtime stamp value.
Delayed IRQ handling can lead to torn read of timestamp
register (LSB from nth frame and MSB from n+1th frame).
This change tries to detect torn read cases and corrects
timestamp close to the actual value.

CRs-Fixed: 2688271
Change-Id: I1dc75629887cfcf971d51a7dae6ea28624d272f1
Signed-off-by: Ravikishore Pampana <[email protected]>
Ravikishore Pampana 5 năm trước cách đây
mục cha
commit
1beadb140b

+ 33 - 31
drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c

@@ -4467,41 +4467,43 @@ static int cam_tfe_mgr_cmd_get_sof_timestamp(
 	struct cam_hw_intf                        *hw_intf;
 	struct cam_tfe_csid_get_time_stamp_args    csid_get_time;
 
-	list_for_each_entry(hw_mgr_res, &tfe_ctx->res_list_tfe_csid, list) {
-		for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
-			if (!hw_mgr_res->hw_res[i])
-				continue;
+	hw_mgr_res = list_first_entry(&tfe_ctx->res_list_tfe_csid,
+		struct cam_isp_hw_mgr_res, list);
+
+	for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
+		if (!hw_mgr_res->hw_res[i])
+			continue;
+
+		/*
+		 * Get the SOF time stamp from left resource only.
+		 * Left resource is master for dual tfe case and
+		 * Rdi only context case left resource only hold
+		 * the RDI resource
+		 */
 
+		hw_intf = hw_mgr_res->hw_res[i]->hw_intf;
+		if (hw_intf->hw_ops.process_cmd) {
 			/*
-			 * Get the SOF time stamp from left resource only.
-			 * Left resource is master for dual tfe case and
-			 * Rdi only context case left resource only hold
-			 * the RDI resource
+			 * Single TFE case, Get the time stamp from
+			 * available one csid hw in the context
+			 * Dual TFE case, get the time stamp from
+			 * master(left) would be sufficient
 			 */
 
-			hw_intf = hw_mgr_res->hw_res[i]->hw_intf;
-			if (hw_intf->hw_ops.process_cmd) {
-				/*
-				 * Single TFE case, Get the time stamp from
-				 * available one csid hw in the context
-				 * Dual TFE case, get the time stamp from
-				 * master(left) would be sufficient
-				 */
-
-				csid_get_time.node_res =
-					hw_mgr_res->hw_res[i];
-				rc = hw_intf->hw_ops.process_cmd(
-					hw_intf->hw_priv,
-					CAM_TFE_CSID_CMD_GET_TIME_STAMP,
-					&csid_get_time,
-					sizeof(struct
-					cam_tfe_csid_get_time_stamp_args));
-				if (!rc && (i == CAM_ISP_HW_SPLIT_LEFT)) {
-					*time_stamp =
-						csid_get_time.time_stamp_val;
-					*boot_time_stamp =
-						csid_get_time.boot_timestamp;
-				}
+			csid_get_time.node_res =
+				hw_mgr_res->hw_res[i];
+			rc = hw_intf->hw_ops.process_cmd(
+				hw_intf->hw_priv,
+				CAM_TFE_CSID_CMD_GET_TIME_STAMP,
+				&csid_get_time,
+				sizeof(struct
+				cam_tfe_csid_get_time_stamp_args));
+			if (!rc && (i == CAM_ISP_HW_SPLIT_LEFT)) {
+				*time_stamp =
+					csid_get_time.time_stamp_val;
+				*boot_time_stamp =
+					csid_get_time.boot_timestamp;
+				break;
 			}
 		}
 	}

+ 70 - 19
drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.c

@@ -345,6 +345,7 @@ static int cam_tfe_csid_global_reset(struct cam_tfe_csid_hw *csid_hw)
 		CAM_ERR(CAM_ISP, "CSID:%d IRQ value after reset rc = %d",
 			csid_hw->hw_intf->hw_idx, val);
 	csid_hw->error_irq_count = 0;
+	csid_hw->prev_boot_timestamp = 0;
 
 	return rc;
 }
@@ -998,6 +999,7 @@ static int cam_tfe_csid_disable_hw(struct cam_tfe_csid_hw *csid_hw)
 	spin_unlock_irqrestore(&csid_hw->spin_lock, flags);
 	csid_hw->hw_info->hw_state = CAM_HW_STATE_POWER_DOWN;
 	csid_hw->error_irq_count = 0;
+	csid_hw->prev_boot_timestamp = 0;
 
 	return rc;
 }
@@ -1612,16 +1614,36 @@ static int cam_tfe_csid_poll_stop_status(
 	return rc;
 }
 
+static int __cam_tfe_csid_read_timestamp(void __iomem *base,
+	uint32_t msb_offset, uint32_t lsb_offset, uint64_t *timestamp)
+{
+	uint32_t lsb, msb, tmp, torn = 0;
+
+	msb = cam_io_r_mb(base + msb_offset);
+	do {
+		tmp = msb;
+		torn++;
+		lsb = cam_io_r_mb(base + lsb_offset);
+		msb = cam_io_r_mb(base + msb_offset);
+	} while (tmp != msb);
+
+	*timestamp = msb;
+	*timestamp = (*timestamp << 32) | lsb;
+
+	return (torn > 1);
+}
+
 static int cam_tfe_csid_get_time_stamp(
 		struct cam_tfe_csid_hw   *csid_hw, void *cmd_args)
 {
-	struct cam_tfe_csid_get_time_stamp_args        *time_stamp;
+	struct cam_tfe_csid_get_time_stamp_args    *time_stamp;
 	struct cam_isp_resource_node               *res;
 	const struct cam_tfe_csid_reg_offset       *csid_reg;
 	struct cam_hw_soc_info                     *soc_info;
 	const struct cam_tfe_csid_rdi_reg_offset   *rdi_reg;
 	struct timespec64 ts;
-	uint32_t  time_32, id;
+	uint32_t  id, torn;
+	uint64_t  time_delta;
 
 	time_stamp = (struct cam_tfe_csid_get_time_stamp_args  *)cmd_args;
 	res = time_stamp->node_res;
@@ -1644,33 +1666,61 @@ static int cam_tfe_csid_get_time_stamp(
 	}
 
 	if (res->res_id == CAM_TFE_CSID_PATH_RES_IPP) {
-		time_32 = cam_io_r_mb(soc_info->reg_map[0].mem_base +
-			csid_reg->ipp_reg->csid_pxl_timestamp_curr1_sof_addr);
-		time_stamp->time_stamp_val = (uint64_t) time_32;
-		time_stamp->time_stamp_val = time_stamp->time_stamp_val << 32;
-		time_32 = cam_io_r_mb(soc_info->reg_map[0].mem_base +
-			csid_reg->ipp_reg->csid_pxl_timestamp_curr0_sof_addr);
+		torn = __cam_tfe_csid_read_timestamp(
+			soc_info->reg_map[0].mem_base,
+			csid_reg->ipp_reg->csid_pxl_timestamp_curr1_sof_addr,
+			csid_reg->ipp_reg->csid_pxl_timestamp_curr0_sof_addr,
+			&time_stamp->time_stamp_val);
 	} else {
 		id = res->res_id;
 		rdi_reg = csid_reg->rdi_reg[id];
-		time_32 = cam_io_r_mb(soc_info->reg_map[0].mem_base +
-			rdi_reg->csid_rdi_timestamp_curr1_sof_addr);
-		time_stamp->time_stamp_val = (uint64_t) time_32;
-		time_stamp->time_stamp_val = time_stamp->time_stamp_val << 32;
-
-		time_32 = cam_io_r_mb(soc_info->reg_map[0].mem_base +
-			rdi_reg->csid_rdi_timestamp_curr0_sof_addr);
+		torn = __cam_tfe_csid_read_timestamp(
+			soc_info->reg_map[0].mem_base,
+			rdi_reg->csid_rdi_timestamp_curr1_sof_addr,
+			rdi_reg->csid_rdi_timestamp_curr0_sof_addr,
+			&time_stamp->time_stamp_val);
 	}
 
-	time_stamp->time_stamp_val |= (uint64_t) time_32;
 	time_stamp->time_stamp_val = mul_u64_u32_div(
 		time_stamp->time_stamp_val,
 		CAM_TFE_CSID_QTIMER_MUL_FACTOR,
 		CAM_TFE_CSID_QTIMER_DIV_FACTOR);
 
-	ktime_get_boottime_ts64(&ts);
-	time_stamp->boot_timestamp = (uint64_t)((ts.tv_sec * 1000000000) +
-		ts.tv_nsec);
+	if (!csid_hw->prev_boot_timestamp) {
+		ktime_get_boottime_ts64(&ts);
+		time_stamp->boot_timestamp =
+			(uint64_t)((ts.tv_sec * 1000000000) +
+			ts.tv_nsec);
+		csid_hw->prev_qtimer_ts = 0;
+		CAM_DBG(CAM_ISP, "timestamp:%lld",
+			time_stamp->boot_timestamp);
+	} else {
+		time_delta = time_stamp->time_stamp_val -
+			csid_hw->prev_qtimer_ts;
+
+		if (csid_hw->prev_boot_timestamp >
+			U64_MAX - time_delta) {
+			CAM_WARN(CAM_ISP, "boottimestamp overflowed");
+			CAM_INFO(CAM_ISP,
+			"currQTimer %lx prevQTimer %lx prevBootTimer %lx torn %d",
+				time_stamp->time_stamp_val,
+				csid_hw->prev_qtimer_ts,
+				csid_hw->prev_boot_timestamp, torn);
+			return -EINVAL;
+		}
+
+		time_stamp->boot_timestamp =
+			csid_hw->prev_boot_timestamp + time_delta;
+	}
+
+	CAM_DBG(CAM_ISP,
+	"currQTimer %lx prevQTimer %lx currBootTimer %lx prevBootTimer %lx torn %d",
+		time_stamp->time_stamp_val,
+		csid_hw->prev_qtimer_ts, time_stamp->boot_timestamp,
+		csid_hw->prev_boot_timestamp, torn);
+
+	csid_hw->prev_qtimer_ts = time_stamp->time_stamp_val;
+	csid_hw->prev_boot_timestamp = time_stamp->boot_timestamp;
 
 	return 0;
 }
@@ -2997,6 +3047,7 @@ int cam_tfe_csid_hw_probe_init(struct cam_hw_intf  *csid_hw_intf,
 
 	tfe_csid_hw->csid_debug = 0;
 	tfe_csid_hw->error_irq_count = 0;
+	tfe_csid_hw->prev_boot_timestamp = 0;
 
 	rc = cam_tfe_csid_disable_soc_resources(
 		&tfe_csid_hw->hw_info->soc_info);

+ 4 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.h

@@ -387,6 +387,8 @@ struct cam_tfe_csid_path_cfg {
  * @ppi_hw_intf               interface to ppi hardware
  * @ppi_enabled               flag to specify if the hardware has ppi bridge
  *                            or not
+ * @prev_boot_timestamp       previous frame bootime stamp
+ * @prev_qtimer_ts            previous frame qtimer csid timestamp
  *
  */
 struct cam_tfe_csid_hw {
@@ -415,6 +417,8 @@ struct cam_tfe_csid_hw {
 	void                               *event_cb_priv;
 	struct cam_hw_intf                 *ppi_hw_intf[CAM_CSID_PPI_HW_MAX];
 	bool                                ppi_enable;
+	uint64_t                            prev_boot_timestamp;
+	uint64_t                            prev_qtimer_ts;
 };
 
 int cam_tfe_csid_hw_probe_init(struct cam_hw_intf  *csid_hw_intf,