disp: msm: sde: update retire-fence with precise vsync timestamp
Retire fence for frames are signaled based on vsync. Use the HW vsync timestamp counter to calculate the precise vsync timestamp and update the retire fence signal timestamp. This will offset all IRQ and SW delays and sends the precise timestamp. Avoid calculating the timestamp on error or panel dead events and set the current ktime for those cases. Change-Id: Ic762f7cd6daead9c8fdcb0f8aad6386cf980407d Signed-off-by: Veera Sundaram Sankaran <veeras@codeaurora.org>
This commit is contained in:
@@ -2279,7 +2279,7 @@ static void _sde_crtc_dest_scaler_setup(struct drm_crtc *crtc)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sde_crtc_frame_event_cb(void *data, u32 event)
|
static void sde_crtc_frame_event_cb(void *data, u32 event, ktime_t ts)
|
||||||
{
|
{
|
||||||
struct drm_crtc *crtc = (struct drm_crtc *)data;
|
struct drm_crtc *crtc = (struct drm_crtc *)data;
|
||||||
struct sde_crtc *sde_crtc;
|
struct sde_crtc *sde_crtc;
|
||||||
@@ -2349,9 +2349,9 @@ static void sde_crtc_frame_event_cb(void *data, u32 event)
|
|||||||
}
|
}
|
||||||
|
|
||||||
fevent->event = event;
|
fevent->event = event;
|
||||||
|
fevent->ts = ts;
|
||||||
fevent->crtc = crtc;
|
fevent->crtc = crtc;
|
||||||
fevent->connector = cb_data->connector;
|
fevent->connector = cb_data->connector;
|
||||||
fevent->ts = ktime_get();
|
|
||||||
kthread_queue_work(&priv->event_thread[crtc_id].worker, &fevent->work);
|
kthread_queue_work(&priv->event_thread[crtc_id].worker, &fevent->work);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -3225,7 +3225,7 @@ void sde_encoder_register_vblank_callback(struct drm_encoder *drm_enc,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void sde_encoder_register_frame_event_callback(struct drm_encoder *drm_enc,
|
void sde_encoder_register_frame_event_callback(struct drm_encoder *drm_enc,
|
||||||
void (*frame_event_cb)(void *, u32 event),
|
void (*frame_event_cb)(void *, u32 event, ktime_t ts),
|
||||||
struct drm_crtc *crtc)
|
struct drm_crtc *crtc)
|
||||||
{
|
{
|
||||||
struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
|
struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
|
||||||
@@ -3252,14 +3252,16 @@ static void sde_encoder_frame_done_callback(
|
|||||||
struct sde_encoder_phys *ready_phys, u32 event)
|
struct sde_encoder_phys *ready_phys, u32 event)
|
||||||
{
|
{
|
||||||
struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
|
struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
|
||||||
|
struct sde_kms *sde_kms = sde_encoder_get_kms(&sde_enc->base);
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
bool trigger = true;
|
bool trigger = true;
|
||||||
bool is_cmd_mode = false;
|
bool is_cmd_mode = false;
|
||||||
enum sde_rm_topology_name topology = SDE_RM_TOPOLOGY_NONE;
|
enum sde_rm_topology_name topology = SDE_RM_TOPOLOGY_NONE;
|
||||||
|
ktime_t ts = 0;
|
||||||
|
|
||||||
if (!drm_enc || !sde_enc->cur_master) {
|
if (!sde_kms || !sde_enc->cur_master) {
|
||||||
SDE_ERROR("invalid param: drm_enc %pK, cur_master %pK\n",
|
SDE_ERROR("invalid param: sde_kms %pK, cur_master %pK\n",
|
||||||
drm_enc, drm_enc ? sde_enc->cur_master : 0);
|
sde_kms, sde_enc->cur_master);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3268,6 +3270,19 @@ static void sde_encoder_frame_done_callback(
|
|||||||
if (sde_encoder_check_curr_mode(drm_enc, MSM_DISPLAY_CMD_MODE))
|
if (sde_encoder_check_curr_mode(drm_enc, MSM_DISPLAY_CMD_MODE))
|
||||||
is_cmd_mode = true;
|
is_cmd_mode = true;
|
||||||
|
|
||||||
|
/* get precise vsync timestamp for retire fence, if precise vsync timestamp is enabled */
|
||||||
|
if (sde_kms->catalog->has_precise_vsync_ts
|
||||||
|
&& (event & SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE)
|
||||||
|
&& (!(event & (SDE_ENCODER_FRAME_EVENT_ERROR | SDE_ENCODER_FRAME_EVENT_PANEL_DEAD))))
|
||||||
|
ts = sde_encoder_calc_last_vsync_timestamp(drm_enc);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get current ktime for other events and when precise timestamp is not
|
||||||
|
* available for retire-fence
|
||||||
|
*/
|
||||||
|
if (!ts)
|
||||||
|
ts = ktime_get();
|
||||||
|
|
||||||
if (event & (SDE_ENCODER_FRAME_EVENT_DONE
|
if (event & (SDE_ENCODER_FRAME_EVENT_DONE
|
||||||
| SDE_ENCODER_FRAME_EVENT_ERROR
|
| SDE_ENCODER_FRAME_EVENT_ERROR
|
||||||
| SDE_ENCODER_FRAME_EVENT_PANEL_DEAD) && is_cmd_mode) {
|
| SDE_ENCODER_FRAME_EVENT_PANEL_DEAD) && is_cmd_mode) {
|
||||||
@@ -3301,15 +3316,13 @@ static void sde_encoder_frame_done_callback(
|
|||||||
if (trigger) {
|
if (trigger) {
|
||||||
if (sde_enc->crtc_frame_event_cb)
|
if (sde_enc->crtc_frame_event_cb)
|
||||||
sde_enc->crtc_frame_event_cb(
|
sde_enc->crtc_frame_event_cb(
|
||||||
&sde_enc->crtc_frame_event_cb_data,
|
&sde_enc->crtc_frame_event_cb_data, event, ts);
|
||||||
event);
|
|
||||||
for (i = 0; i < sde_enc->num_phys_encs; i++)
|
for (i = 0; i < sde_enc->num_phys_encs; i++)
|
||||||
atomic_add_unless(&sde_enc->frame_done_cnt[i],
|
atomic_add_unless(&sde_enc->frame_done_cnt[i],
|
||||||
-1, 0);
|
-1, 0);
|
||||||
}
|
}
|
||||||
} else if (sde_enc->crtc_frame_event_cb) {
|
} else if (sde_enc->crtc_frame_event_cb) {
|
||||||
sde_enc->crtc_frame_event_cb(
|
sde_enc->crtc_frame_event_cb(&sde_enc->crtc_frame_event_cb_data, event, ts);
|
||||||
&sde_enc->crtc_frame_event_cb_data, event);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -226,7 +226,7 @@ struct sde_encoder_virt {
|
|||||||
struct dentry *debugfs_root;
|
struct dentry *debugfs_root;
|
||||||
struct mutex enc_lock;
|
struct mutex enc_lock;
|
||||||
atomic_t frame_done_cnt[MAX_PHYS_ENCODERS_PER_VIRTUAL];
|
atomic_t frame_done_cnt[MAX_PHYS_ENCODERS_PER_VIRTUAL];
|
||||||
void (*crtc_frame_event_cb)(void *data, u32 event);
|
void (*crtc_frame_event_cb)(void *data, u32 event, ktime_t ts);
|
||||||
struct sde_kms_frame_event_cb_data crtc_frame_event_cb_data;
|
struct sde_kms_frame_event_cb_data crtc_frame_event_cb_data;
|
||||||
|
|
||||||
struct sde_rsc_client *rsc_client;
|
struct sde_rsc_client *rsc_client;
|
||||||
@@ -300,7 +300,7 @@ void sde_encoder_register_vblank_callback(struct drm_encoder *encoder,
|
|||||||
* @crtc: pointer to drm_crtc object interested in frame events
|
* @crtc: pointer to drm_crtc object interested in frame events
|
||||||
*/
|
*/
|
||||||
void sde_encoder_register_frame_event_callback(struct drm_encoder *encoder,
|
void sde_encoder_register_frame_event_callback(struct drm_encoder *encoder,
|
||||||
void (*cb)(void *, u32), struct drm_crtc *crtc);
|
void (*cb)(void *, u32, ktime_t), struct drm_crtc *crtc);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sde_encoder_get_rsc_client - gets the rsc client state for primary
|
* sde_encoder_get_rsc_client - gets the rsc client state for primary
|
||||||
|
Reference in New Issue
Block a user