From bceea4e1feb8d4a9fa9c0a323ed49f0db9ff2b1d Mon Sep 17 00:00:00 2001 From: Veera Sundaram Sankaran Date: Fri, 22 Nov 2019 15:27:32 -0800 Subject: [PATCH] disp: msm: sde: reset ctl on autorefresh disable failure Reset MDP ctl path and DSI ctl on autorefresh disable failure. This will enable the hardware to recover from the hang. Change-Id: Ia9acc8573c22e0713179ef4f6ef604caacabfadb Signed-off-by: Veera Sundaram Sankaran --- msm/sde/sde_crtc.c | 8 ++++---- msm/sde/sde_crtc.h | 18 ++++++++++++++++++ msm/sde/sde_encoder.c | 15 ++++++++++----- msm/sde/sde_encoder.h | 8 +++++++- msm/sde/sde_encoder_phys.h | 6 ------ msm/sde/sde_encoder_phys_cmd.c | 4 +++- msm/sde/sde_kms.c | 7 ++++++- 7 files changed, 48 insertions(+), 18 deletions(-) diff --git a/msm/sde/sde_crtc.c b/msm/sde/sde_crtc.c index 8fc5a2b5c5dd..6344ce8cc8cc 100644 --- a/msm/sde/sde_crtc.c +++ b/msm/sde/sde_crtc.c @@ -3527,7 +3527,7 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc, struct msm_drm_private *priv; struct sde_kms *sde_kms; struct sde_crtc_state *cstate; - bool is_error = false, reset_req; + bool is_error = false; unsigned long flags; enum sde_crtc_idle_pc_state idle_pc_state; struct sde_encoder_kickoff_params params = { 0 }; @@ -3539,7 +3539,6 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc, dev = crtc->dev; sde_crtc = to_sde_crtc(crtc); sde_kms = _sde_crtc_get_kms(crtc); - reset_req = false; if (!sde_kms || !sde_kms->dev || !sde_kms->dev->dev_private) { SDE_ERROR("invalid argument\n"); @@ -3572,7 +3571,7 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc, params.affected_displays = _sde_crtc_get_displays_affected(crtc, crtc->state); if (sde_encoder_prepare_for_kickoff(encoder, ¶ms)) - reset_req = true; + sde_crtc->needs_hw_reset = true; if (idle_pc_state != IDLE_PC_NONE) sde_encoder_control_idle_pc(encoder, @@ -3583,13 +3582,14 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc, * Optionally attempt h/w recovery if any errors were detected while * preparing for the kickoff */ - if (reset_req) { + if (sde_crtc->needs_hw_reset) { sde_crtc->frame_trigger_mode = params.frame_trigger_mode; if (sde_crtc->frame_trigger_mode != FRAME_DONE_WAIT_POSTED_START && sde_crtc_reset_hw(crtc, old_state, params.recovery_events_enabled)) is_error = true; + sde_crtc->needs_hw_reset = false; } sde_crtc_calc_fps(sde_crtc); diff --git a/msm/sde/sde_crtc.h b/msm/sde/sde_crtc.h index 67ab431dc165..c5bbf06d685a 100644 --- a/msm/sde/sde_crtc.h +++ b/msm/sde/sde_crtc.h @@ -252,6 +252,7 @@ struct sde_crtc_misr_info { * @ltm_hist_en : flag to indicate whether LTM hist is enabled or not * @ltm_buffer_lock : muttx to protect ltm_buffers allcation and free * @ltm_lock : Spinlock to protect ltm buffer_cnt, hist_en and ltm lists + * @needs_hw_reset : Initiate a hw ctl reset */ struct sde_crtc { struct drm_crtc base; @@ -330,6 +331,7 @@ struct sde_crtc { struct drm_msm_ltm_cfg_param ltm_cfg; struct mutex ltm_buffer_lock; spinlock_t ltm_lock; + bool needs_hw_reset; }; #define to_sde_crtc(x) container_of(x, struct sde_crtc, base) @@ -494,6 +496,22 @@ static inline int sde_crtc_frame_pending(struct drm_crtc *crtc) return atomic_read(&sde_crtc->frame_pending); } +/** + * sde_crtc_set_needs_hw_reset - set hw reset flag, to handle reset during + * commit kickoff + * @crtc: Pointer to DRM crtc instance + */ +static inline void sde_crtc_set_needs_hw_reset(struct drm_crtc *crtc) +{ + struct sde_crtc *sde_crtc; + + if (!crtc) + return; + + sde_crtc = to_sde_crtc(crtc); + sde_crtc->needs_hw_reset = true; +} + /** * sde_crtc_reset_hw - attempt hardware reset on errors * @crtc: Pointer to DRM crtc instance diff --git a/msm/sde/sde_encoder.c b/msm/sde/sde_encoder.c index 779e2a39b14a..a5303cbe9f05 100644 --- a/msm/sde/sde_encoder.c +++ b/msm/sde/sde_encoder.c @@ -3891,7 +3891,7 @@ static void _sde_encoder_helper_hdr_plus_mempool_update( } } -void sde_encoder_helper_needs_hw_reset(struct drm_encoder *drm_enc) +void sde_encoder_needs_hw_reset(struct drm_encoder *drm_enc) { struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc); struct sde_encoder_phys *phys; @@ -3975,7 +3975,7 @@ int sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc, /* if any phys needs reset, reset all phys, in-order */ if (needs_hw_reset) - sde_encoder_helper_needs_hw_reset(drm_enc); + sde_encoder_needs_hw_reset(drm_enc); _sde_encoder_update_master(drm_enc, params); @@ -4177,16 +4177,16 @@ int sde_encoder_helper_reset_mixers(struct sde_encoder_phys *phys_enc, return 0; } -void sde_encoder_prepare_commit(struct drm_encoder *drm_enc) +int sde_encoder_prepare_commit(struct drm_encoder *drm_enc) { struct sde_encoder_virt *sde_enc; struct sde_encoder_phys *phys; - int i, rc = 0; + int i, rc = 0, ret = 0; struct sde_hw_ctl *ctl; if (!drm_enc) { SDE_ERROR("invalid encoder\n"); - return; + return -EINVAL; } sde_enc = to_sde_encoder_virt(drm_enc); @@ -4200,6 +4200,9 @@ void sde_encoder_prepare_commit(struct drm_encoder *drm_enc) if (phys && phys->ops.prepare_commit) phys->ops.prepare_commit(phys); + if (phys->enable_state == SDE_ENC_ERR_NEEDS_HW_RESET) + ret = -ETIMEDOUT; + if (phys && phys->hw_ctl) { ctl = phys->hw_ctl; /* @@ -4222,6 +4225,8 @@ void sde_encoder_prepare_commit(struct drm_encoder *drm_enc) sde_enc->cur_master->connector->base.id, rc); } + + return ret; } void sde_encoder_helper_setup_misr(struct sde_encoder_phys *phys_enc, diff --git a/msm/sde/sde_encoder.h b/msm/sde/sde_encoder.h index 806d050b159f..80f51fb2de3a 100644 --- a/msm/sde/sde_encoder.h +++ b/msm/sde/sde_encoder.h @@ -430,7 +430,7 @@ void sde_encoder_destroy(struct drm_encoder *drm_enc); * atomic commit, before any registers are written * @drm_enc: Pointer to previously created drm encoder structure */ -void sde_encoder_prepare_commit(struct drm_encoder *drm_enc); +int sde_encoder_prepare_commit(struct drm_encoder *drm_enc); /** * sde_encoder_update_caps_for_cont_splash - update encoder settings during @@ -514,6 +514,12 @@ void sde_encoder_control_idle_pc(struct drm_encoder *enc, bool enable); */ int sde_encoder_in_cont_splash(struct drm_encoder *enc); +/** + * sde_encoder_helper_hw_reset - hw reset helper function + * @drm_enc: Pointer to drm encoder structure + */ +void sde_encoder_needs_hw_reset(struct drm_encoder *enc); + /** * sde_encoder_uidle_enable - control enable/disable of uidle * @drm_enc: Pointer to drm encoder structure diff --git a/msm/sde/sde_encoder_phys.h b/msm/sde/sde_encoder_phys.h index 8a4eff00deb6..ca26e1f8b75c 100644 --- a/msm/sde/sde_encoder_phys.h +++ b/msm/sde/sde_encoder_phys.h @@ -535,12 +535,6 @@ void sde_encoder_phys_setup_cdm(struct sde_encoder_phys *phys_enc, void sde_encoder_helper_get_pp_line_count(struct drm_encoder *drm_enc, struct sde_hw_pp_vsync_info *info); -/** - * sde_encoder_helper_needs_hw_reset - hw reset helper function - * @drm_enc: Pointer to drm encoder structure - */ -void sde_encoder_helper_needs_hw_reset(struct drm_encoder *drm_enc); - /** * sde_encoder_helper_trigger_flush - control flush helper function * This helper function may be optionally specified by physical diff --git a/msm/sde/sde_encoder_phys_cmd.c b/msm/sde/sde_encoder_phys_cmd.c index 4d2fbb7fa5be..ecd9c896c20e 100644 --- a/msm/sde/sde_encoder_phys_cmd.c +++ b/msm/sde/sde_encoder_phys_cmd.c @@ -1625,7 +1625,7 @@ wait_for_idle: SDE_ERROR("pp:%d failed wait_for_idle: %d\n", phys_enc->hw_pp->idx - PINGPONG_0, rc); if (phys_enc->enable_state == SDE_ENC_ERR_NEEDS_HW_RESET) - sde_encoder_helper_needs_hw_reset(phys_enc->parent); + sde_encoder_needs_hw_reset(phys_enc->parent); } return rc; @@ -1729,6 +1729,8 @@ static void sde_encoder_phys_cmd_prepare_commit( > (KICKOFF_TIMEOUT_MS * USEC_PER_MSEC)) { SDE_ERROR_CMDENC(cmd_enc, "disable autorefresh failed\n"); + + phys_enc->enable_state = SDE_ENC_ERR_NEEDS_HW_RESET; break; } diff --git a/msm/sde/sde_kms.c b/msm/sde/sde_kms.c index 3ec90fe7359b..399c4e8e0c72 100644 --- a/msm/sde/sde_kms.c +++ b/msm/sde/sde_kms.c @@ -885,7 +885,12 @@ static void sde_kms_prepare_commit(struct msm_kms *kms, if (encoder->crtc != crtc) continue; - sde_encoder_prepare_commit(encoder); + if (sde_encoder_prepare_commit(encoder) == -ETIMEDOUT) { + SDE_ERROR("crtc:%d, initiating hw reset\n", + DRMID(crtc)); + sde_encoder_needs_hw_reset(encoder); + sde_crtc_set_needs_hw_reset(crtc); + } } }