Răsfoiți Sursa

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 <[email protected]>
Veera Sundaram Sankaran 5 ani în urmă
părinte
comite
bceea4e1fe

+ 4 - 4
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, &params))
-			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);

+ 18 - 0
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

+ 10 - 5
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,

+ 7 - 1
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

+ 0 - 6
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

+ 3 - 1
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;
 		}
 

+ 6 - 1
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);
+			}
 		}
 	}