diff --git a/drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c index 8aa68af8ca62..6ca6384c7e79 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c +++ b/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; } } } diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.c index f9325204ba72..5b7a03a51cef 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.c +++ b/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); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.h index d211a70c56bc..b9430e18f8cf 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.h +++ b/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,