From fc2226ea259de19deb94ebada4472c60bc2d89cd Mon Sep 17 00:00:00 2001 From: Dhaval Patel Date: Tue, 21 Sep 2021 14:35:18 -0700 Subject: [PATCH] disp: msm: reset lm blend stages for missing vsync MDSS INTF HW block does not generate vsync if controller turns off the link clock prematurely. This leads to frame trigger timeout and SDE driver triggers the retire fence after 84ms to recover gracefully. A client may switch source pipe from one CTL path to another CTL path based on delayed retire fence. It can lead to other ctl path hang. This can be resolved by resetting the lm blend stages for each missing vsync frame trigger. Change-Id: I5a6ed03afbdad83d8fd6decc593d39e04bef62e4 Signed-off-by: Dhaval Patel --- msm/sde/sde_crtc.c | 6 ++-- msm/sde/sde_encoder.c | 59 ++++++++-------------------------- msm/sde/sde_encoder.h | 5 +-- msm/sde/sde_encoder_phys.h | 7 ++++ msm/sde/sde_encoder_phys_vid.c | 14 +++++++- 5 files changed, 38 insertions(+), 53 deletions(-) diff --git a/msm/sde/sde_crtc.c b/msm/sde/sde_crtc.c index 9580f3159f..4e977940b9 100644 --- a/msm/sde/sde_crtc.c +++ b/msm/sde/sde_crtc.c @@ -3979,7 +3979,7 @@ int sde_crtc_reset_hw(struct drm_crtc *crtc, struct drm_crtc_state *old_state, continue; if (sde_encoder_get_intf_mode(encoder) == INTF_MODE_VIDEO) - sde_encoder_kickoff(encoder, false, true); + sde_encoder_kickoff(encoder, true); } /* panic the device if VBIF is not in good state */ @@ -4086,7 +4086,7 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc, if (encoder->crtc != crtc) continue; - sde_encoder_kickoff(encoder, false, true); + sde_encoder_kickoff(encoder, true); } sde_crtc->kickoff_in_progress = false; @@ -7061,7 +7061,7 @@ void __sde_crtc_static_cache_read_work(struct kthread_work *work) sde_plane_ctl_flush(plane, ctl, true); /* kickoff encoder and wait for VBLANK */ - sde_encoder_kickoff(drm_enc, false, false); + sde_encoder_kickoff(drm_enc, false); sde_encoder_wait_for_event(drm_enc, MSM_ENC_VBLANK); SDE_EVT32(DRMID(crtc), SDE_EVTLOG_FUNC_EXIT); diff --git a/msm/sde/sde_encoder.c b/msm/sde/sde_encoder.c index eae48d797e..16ca653405 100644 --- a/msm/sde/sde_encoder.c +++ b/msm/sde/sde_encoder.c @@ -3225,6 +3225,19 @@ void sde_encoder_helper_phys_disable(struct sde_encoder_phys *phys_enc, ctl->ops.clear_pending_flush(ctl); } +void sde_encoder_helper_phys_reset(struct sde_encoder_phys *phys_enc) +{ + struct sde_hw_ctl *ctl = phys_enc->hw_ctl; + struct sde_ctl_flush_cfg cfg; + + ctl->ops.reset(ctl); + sde_encoder_helper_reset_mixers(phys_enc, NULL); + ctl->ops.get_pending_flush(ctl, &cfg); + SDE_EVT32(DRMID(phys_enc->parent), cfg.pending_flush_mask); + ctl->ops.trigger_flush(ctl); + ctl->ops.trigger_start(ctl); +} + static enum sde_intf sde_encoder_get_intf(struct sde_mdss_cfg *catalog, enum sde_intf_type type, u32 controller_id) { @@ -4357,47 +4370,7 @@ end: return ret; } -/** - * _sde_encoder_reset_ctl_hw - reset h/w configuration for all ctl's associated - * with the specified encoder, and unstage all pipes from it - * @encoder: encoder pointer - * Returns: 0 on success - */ -static int _sde_encoder_reset_ctl_hw(struct drm_encoder *drm_enc) -{ - struct sde_encoder_virt *sde_enc; - struct sde_encoder_phys *phys; - unsigned int i; - int rc = 0; - - if (!drm_enc) { - SDE_ERROR("invalid encoder\n"); - return -EINVAL; - } - - sde_enc = to_sde_encoder_virt(drm_enc); - - SDE_ATRACE_BEGIN("encoder_release_lm"); - SDE_DEBUG_ENC(sde_enc, "\n"); - - for (i = 0; i < sde_enc->num_phys_encs; i++) { - phys = sde_enc->phys_encs[i]; - if (!phys) - continue; - - SDE_EVT32(DRMID(drm_enc), phys->intf_idx - INTF_0); - - rc = sde_encoder_helper_reset_mixers(phys, NULL); - if (rc) - SDE_EVT32(DRMID(drm_enc), rc, SDE_EVTLOG_ERROR); - } - - SDE_ATRACE_END("encoder_release_lm"); - return rc; -} - -void sde_encoder_kickoff(struct drm_encoder *drm_enc, bool is_error, - bool config_changed) +void sde_encoder_kickoff(struct drm_encoder *drm_enc, bool config_changed) { struct sde_encoder_virt *sde_enc; struct sde_encoder_phys *phys; @@ -4412,10 +4385,6 @@ void sde_encoder_kickoff(struct drm_encoder *drm_enc, bool is_error, SDE_DEBUG_ENC(sde_enc, "\n"); - /* create a 'no pipes' commit to release buffers on errors */ - if (is_error) - _sde_encoder_reset_ctl_hw(drm_enc); - if (sde_enc->delay_kickoff) { u32 loop_count = 20; u32 sleep = DELAY_KICKOFF_POLL_TIMEOUT_US / loop_count; diff --git a/msm/sde/sde_encoder.h b/msm/sde/sde_encoder.h index b253377c04..6c7604a837 100644 --- a/msm/sde/sde_encoder.h +++ b/msm/sde/sde_encoder.h @@ -325,12 +325,9 @@ void sde_encoder_trigger_kickoff_pending(struct drm_encoder *encoder); * sde_encoder_kickoff - trigger a double buffer flip of the ctl path * (i.e. ctl flush and start) immediately. * @encoder: encoder pointer - * @is_error: whether the current commit needs to be aborted and replaced - * with a 'safe' commit * @config_changed: if true new configuration is applied on the control path */ -void sde_encoder_kickoff(struct drm_encoder *encoder, bool is_error, - bool config_changed); +void sde_encoder_kickoff(struct drm_encoder *encoder, bool config_changed); /** * sde_encoder_wait_for_event - Waits for encoder events diff --git a/msm/sde/sde_encoder_phys.h b/msm/sde/sde_encoder_phys.h index 94e813e53a..740b649684 100644 --- a/msm/sde/sde_encoder_phys.h +++ b/msm/sde/sde_encoder_phys.h @@ -804,6 +804,13 @@ static inline bool sde_encoder_phys_needs_single_flush( void sde_encoder_helper_phys_disable(struct sde_encoder_phys *phys_enc, struct sde_encoder_phys_wb *wb_enc); +/** + * sde_encoder_helper_phys_reset - helper function to reset virt encoder + * if vsync is missing on phys encoder + * @phys_enc: Pointer to physical encoder structure + */ +void sde_encoder_helper_phys_reset(struct sde_encoder_phys *phys_enc); + /** * sde_encoder_helper_setup_misr - helper function to setup misr * @phys_enc: Pointer to physical encoder structure diff --git a/msm/sde/sde_encoder_phys_vid.c b/msm/sde/sde_encoder_phys_vid.c index c854703965..d8a800c353 100644 --- a/msm/sde/sde_encoder_phys_vid.c +++ b/msm/sde/sde_encoder_phys_vid.c @@ -920,6 +920,18 @@ static int sde_encoder_phys_vid_wait_for_vblank( return _sde_encoder_phys_vid_wait_for_vblank(phys_enc, true); } +static int sde_encoder_phys_vid_wait_for_commit_done( + struct sde_encoder_phys *phys_enc) +{ + int rc; + + rc = _sde_encoder_phys_vid_wait_for_vblank(phys_enc, true); + if (rc) + sde_encoder_helper_phys_reset(phys_enc); + + return rc; +} + static int sde_encoder_phys_vid_wait_for_vblank_no_notify( struct sde_encoder_phys *phys_enc) { @@ -1310,7 +1322,7 @@ static void sde_encoder_phys_vid_init_ops(struct sde_encoder_phys_ops *ops) ops->destroy = sde_encoder_phys_vid_destroy; ops->get_hw_resources = sde_encoder_phys_vid_get_hw_resources; ops->control_vblank_irq = sde_encoder_phys_vid_control_vblank_irq; - ops->wait_for_commit_done = sde_encoder_phys_vid_wait_for_vblank; + ops->wait_for_commit_done = sde_encoder_phys_vid_wait_for_commit_done; ops->wait_for_vblank = sde_encoder_phys_vid_wait_for_vblank_no_notify; ops->wait_for_tx_complete = sde_encoder_phys_vid_wait_for_vblank; ops->irq_control = sde_encoder_phys_vid_irq_control;