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 <veeras@codeaurora.org>
This commit is contained in:
Veera Sundaram Sankaran
2019-11-22 15:27:32 -08:00
committed by Gerrit - the friendly Code Review server
parent 363aadd666
commit bceea4e1fe
7 changed files with 48 additions and 18 deletions

View File

@@ -3527,7 +3527,7 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc,
struct msm_drm_private *priv; struct msm_drm_private *priv;
struct sde_kms *sde_kms; struct sde_kms *sde_kms;
struct sde_crtc_state *cstate; struct sde_crtc_state *cstate;
bool is_error = false, reset_req; bool is_error = false;
unsigned long flags; unsigned long flags;
enum sde_crtc_idle_pc_state idle_pc_state; enum sde_crtc_idle_pc_state idle_pc_state;
struct sde_encoder_kickoff_params params = { 0 }; struct sde_encoder_kickoff_params params = { 0 };
@@ -3539,7 +3539,6 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc,
dev = crtc->dev; dev = crtc->dev;
sde_crtc = to_sde_crtc(crtc); sde_crtc = to_sde_crtc(crtc);
sde_kms = _sde_crtc_get_kms(crtc); sde_kms = _sde_crtc_get_kms(crtc);
reset_req = false;
if (!sde_kms || !sde_kms->dev || !sde_kms->dev->dev_private) { if (!sde_kms || !sde_kms->dev || !sde_kms->dev->dev_private) {
SDE_ERROR("invalid argument\n"); 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, params.affected_displays = _sde_crtc_get_displays_affected(crtc,
crtc->state); crtc->state);
if (sde_encoder_prepare_for_kickoff(encoder, &params)) if (sde_encoder_prepare_for_kickoff(encoder, &params))
reset_req = true; sde_crtc->needs_hw_reset = true;
if (idle_pc_state != IDLE_PC_NONE) if (idle_pc_state != IDLE_PC_NONE)
sde_encoder_control_idle_pc(encoder, 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 * Optionally attempt h/w recovery if any errors were detected while
* preparing for the kickoff * preparing for the kickoff
*/ */
if (reset_req) { if (sde_crtc->needs_hw_reset) {
sde_crtc->frame_trigger_mode = params.frame_trigger_mode; sde_crtc->frame_trigger_mode = params.frame_trigger_mode;
if (sde_crtc->frame_trigger_mode if (sde_crtc->frame_trigger_mode
!= FRAME_DONE_WAIT_POSTED_START && != FRAME_DONE_WAIT_POSTED_START &&
sde_crtc_reset_hw(crtc, old_state, sde_crtc_reset_hw(crtc, old_state,
params.recovery_events_enabled)) params.recovery_events_enabled))
is_error = true; is_error = true;
sde_crtc->needs_hw_reset = false;
} }
sde_crtc_calc_fps(sde_crtc); sde_crtc_calc_fps(sde_crtc);

View File

@@ -252,6 +252,7 @@ struct sde_crtc_misr_info {
* @ltm_hist_en : flag to indicate whether LTM hist is enabled or not * @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_buffer_lock : muttx to protect ltm_buffers allcation and free
* @ltm_lock : Spinlock to protect ltm buffer_cnt, hist_en and ltm lists * @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 sde_crtc {
struct drm_crtc base; struct drm_crtc base;
@@ -330,6 +331,7 @@ struct sde_crtc {
struct drm_msm_ltm_cfg_param ltm_cfg; struct drm_msm_ltm_cfg_param ltm_cfg;
struct mutex ltm_buffer_lock; struct mutex ltm_buffer_lock;
spinlock_t ltm_lock; spinlock_t ltm_lock;
bool needs_hw_reset;
}; };
#define to_sde_crtc(x) container_of(x, struct sde_crtc, base) #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); 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 * sde_crtc_reset_hw - attempt hardware reset on errors
* @crtc: Pointer to DRM crtc instance * @crtc: Pointer to DRM crtc instance

View File

@@ -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_virt *sde_enc = to_sde_encoder_virt(drm_enc);
struct sde_encoder_phys *phys; 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 any phys needs reset, reset all phys, in-order */
if (needs_hw_reset) 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); _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; 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_virt *sde_enc;
struct sde_encoder_phys *phys; struct sde_encoder_phys *phys;
int i, rc = 0; int i, rc = 0, ret = 0;
struct sde_hw_ctl *ctl; struct sde_hw_ctl *ctl;
if (!drm_enc) { if (!drm_enc) {
SDE_ERROR("invalid encoder\n"); SDE_ERROR("invalid encoder\n");
return; return -EINVAL;
} }
sde_enc = to_sde_encoder_virt(drm_enc); 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) if (phys && phys->ops.prepare_commit)
phys->ops.prepare_commit(phys); phys->ops.prepare_commit(phys);
if (phys->enable_state == SDE_ENC_ERR_NEEDS_HW_RESET)
ret = -ETIMEDOUT;
if (phys && phys->hw_ctl) { if (phys && phys->hw_ctl) {
ctl = 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, sde_enc->cur_master->connector->base.id,
rc); rc);
} }
return ret;
} }
void sde_encoder_helper_setup_misr(struct sde_encoder_phys *phys_enc, void sde_encoder_helper_setup_misr(struct sde_encoder_phys *phys_enc,

View File

@@ -430,7 +430,7 @@ void sde_encoder_destroy(struct drm_encoder *drm_enc);
* atomic commit, before any registers are written * atomic commit, before any registers are written
* @drm_enc: Pointer to previously created drm encoder structure * @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 * 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); 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 * sde_encoder_uidle_enable - control enable/disable of uidle
* @drm_enc: Pointer to drm encoder structure * @drm_enc: Pointer to drm encoder structure

View File

@@ -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, void sde_encoder_helper_get_pp_line_count(struct drm_encoder *drm_enc,
struct sde_hw_pp_vsync_info *info); 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 * sde_encoder_helper_trigger_flush - control flush helper function
* This helper function may be optionally specified by physical * This helper function may be optionally specified by physical

View File

@@ -1625,7 +1625,7 @@ wait_for_idle:
SDE_ERROR("pp:%d failed wait_for_idle: %d\n", SDE_ERROR("pp:%d failed wait_for_idle: %d\n",
phys_enc->hw_pp->idx - PINGPONG_0, rc); phys_enc->hw_pp->idx - PINGPONG_0, rc);
if (phys_enc->enable_state == SDE_ENC_ERR_NEEDS_HW_RESET) 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; return rc;
@@ -1729,6 +1729,8 @@ static void sde_encoder_phys_cmd_prepare_commit(
> (KICKOFF_TIMEOUT_MS * USEC_PER_MSEC)) { > (KICKOFF_TIMEOUT_MS * USEC_PER_MSEC)) {
SDE_ERROR_CMDENC(cmd_enc, SDE_ERROR_CMDENC(cmd_enc,
"disable autorefresh failed\n"); "disable autorefresh failed\n");
phys_enc->enable_state = SDE_ENC_ERR_NEEDS_HW_RESET;
break; break;
} }

View File

@@ -885,7 +885,12 @@ static void sde_kms_prepare_commit(struct msm_kms *kms,
if (encoder->crtc != crtc) if (encoder->crtc != crtc)
continue; 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);
}
} }
} }