mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-10 22:40:54 -04:00
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 <rpampana@codeaurora.org>
This commit is contained in:
parent
526970e73b
commit
1beadb140b
3 changed files with 107 additions and 50 deletions
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Reference in a new issue