Pārlūkot izejas kodu

Merge "msm: camera: tfe: Handle sof monotonic boot time stamp" into camera-kernel.lnx.4.0

Camera Software Integration 4 gadi atpakaļ
vecāks
revīzija
10729c8cf2

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

@@ -4690,41 +4690,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;
 }
@@ -1669,16 +1671,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;
@@ -1701,33 +1723,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;
 }
@@ -3142,6 +3192,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,