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:

committed by
Gerrit - the friendly Code Review server

parent
363aadd666
commit
bceea4e1fe
@@ -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, ¶ms))
|
if (sde_encoder_prepare_for_kickoff(encoder, ¶ms))
|
||||||
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);
|
||||||
|
@@ -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
|
||||||
|
@@ -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,
|
||||||
|
@@ -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
|
||||||
|
@@ -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
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user