disp: msm: sde: enable support to get accurate vsync timestamp

From MDSS 8.x, vsync timestamp counter register is added in all the
interfaces. Add interface to get the vsync counter and use the global
qtmr reference counter to get the counter delta. This can be used
with reference to the curret ktime to deduce the accurate vsync
timestamp. This utility is intended to be used for setting the vblank
and retire fence timestamps which would be notified to user-mode.

Change-Id: I608a284c035cda50053eedbb311f1f54b3d3d557
Signed-off-by: Veera Sundaram Sankaran <veeras@codeaurora.org>
This commit is contained in:
Veera Sundaram Sankaran
2020-09-21 12:52:04 -07:00
parent 9ad90a834d
commit b554f01a10
6 changed files with 113 additions and 0 deletions

View File

@@ -146,6 +146,73 @@ void sde_encoder_uidle_enable(struct drm_encoder *drm_enc, bool enable)
}
}
ktime_t sde_encoder_calc_last_vsync_timestamp(struct drm_encoder *drm_enc)
{
struct sde_encoder_virt *sde_enc;
struct sde_encoder_phys *cur_master;
u64 vsync_counter, qtmr_counter, hw_diff, hw_diff_ns, frametime_ns;
ktime_t tvblank, cur_time;
struct intf_status intf_status = {0};
u32 fps;
sde_enc = to_sde_encoder_virt(drm_enc);
cur_master = sde_enc->cur_master;
fps = sde_encoder_get_fps(drm_enc);
if (!cur_master || !cur_master->hw_intf || !fps
|| !cur_master->hw_intf->ops.get_vsync_timestamp
|| (!sde_encoder_check_curr_mode(drm_enc, MSM_DISPLAY_CMD_MODE)
&& !sde_encoder_check_curr_mode(drm_enc, MSM_DISPLAY_VIDEO_MODE)))
return 0;
/*
* avoid calculation and rely on ktime_get, if programmable fetch is enabled
* as the HW VSYNC timestamp will be updated at panel vsync and not at MDP VSYNC
*/
if (cur_master->hw_intf->ops.get_status) {
cur_master->hw_intf->ops.get_status(cur_master->hw_intf, &intf_status);
if (intf_status.is_prog_fetch_en)
return 0;
}
vsync_counter = cur_master->hw_intf->ops.get_vsync_timestamp(cur_master->hw_intf);
qtmr_counter = arch_timer_read_counter();
cur_time = ktime_get_ns();
/* check for counter rollover between the two timestamps [56 bits] */
if (qtmr_counter < vsync_counter) {
hw_diff = (0xffffffffffffff - vsync_counter) + qtmr_counter;
SDE_EVT32(DRMID(drm_enc), vsync_counter >> 32, vsync_counter,
qtmr_counter >> 32, qtmr_counter, hw_diff,
fps, SDE_EVTLOG_FUNC_CASE1);
} else {
hw_diff = qtmr_counter - vsync_counter;
}
hw_diff_ns = DIV_ROUND_UP(hw_diff * 1000 * 10, 192); /* 19.2 MHz clock */
frametime_ns = DIV_ROUND_UP(1000000000, fps);
/* avoid setting timestamp, if diff is more than one vsync */
if (ktime_compare(hw_diff_ns, frametime_ns) > 0) {
tvblank = 0;
SDE_EVT32(DRMID(drm_enc), vsync_counter >> 32, vsync_counter,
qtmr_counter >> 32, qtmr_counter, ktime_to_us(hw_diff_ns),
fps, SDE_EVTLOG_ERROR);
} else {
tvblank = ktime_sub_ns(cur_time, hw_diff_ns);
}
SDE_DEBUG_ENC(sde_enc,
"vsync:%llu, qtmr:%llu, diff_ns:%llu, ts:%llu, cur_ts:%llu, fps:%d\n",
vsync_counter, qtmr_counter, ktime_to_us(hw_diff_ns),
ktime_to_us(tvblank), ktime_to_us(cur_time), fps);
SDE_EVT32_VERBOSE(DRMID(drm_enc), hw_diff >> 32, hw_diff, ktime_to_us(hw_diff_ns),
ktime_to_us(tvblank), ktime_to_us(cur_time), fps, SDE_EVTLOG_FUNC_CASE2);
return tvblank;
}
static void _sde_encoder_pm_qos_add_request(struct drm_encoder *drm_enc)
{
struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);