Răsfoiți Sursa

disp: msm: sde: delay cwb done wait for last frame

Commit Ifa100424733 ("disp: msm: sde: delay
encoder disable for clone mode") delays the CWB
encoder disable but it is also skipping the CWB
disable flush. That can cause the underrun on dp
display if it uses the same 3d_merge HW block. This
change reverts the portion of original code and
only delays the last cwb frame done wait. It still
keep the last CWB frame done wait as it is if crtc
is also moving to inactive state.

Change-Id: I3461188a35197f2925899ceea7ef705adf00a398
Signed-off-by: Dhaval Patel <[email protected]>
Dhaval Patel 4 ani în urmă
părinte
comite
8d6fea832e

+ 4 - 53
msm/msm_atomic.c

@@ -142,50 +142,16 @@ static void msm_atomic_wait_for_commit_done(
 	}
 }
 
-static bool
-msm_disable_outputs_for_clone_conn(struct drm_device *dev,
-		struct drm_atomic_state *old_state)
-{
-	struct drm_connector *connector;
-	struct drm_connector_state *old_conn_state;
-	struct drm_crtc_state *old_crtc_state;
-	struct drm_crtc *crtc = NULL;
-	int i;
-	bool clone_state = false;
-
-	for_each_old_connector_in_state(old_state, connector,
-			old_conn_state, i) {
-
-		if (!old_conn_state->crtc)
-			continue;
-
-		old_crtc_state = drm_atomic_get_old_crtc_state(old_state,
-							old_conn_state->crtc);
-		if (!old_crtc_state->active ||
-		    !old_conn_state->crtc->state->connectors_changed ||
-		    (!_msm_seamless_for_conn(connector, old_conn_state,
-				 false) && (connector->connector_type !=
-						DRM_MODE_CONNECTOR_VIRTUAL)))
-			return false;
-
-		if (crtc)
-			clone_state = (crtc == old_conn_state->crtc)
-				? true : false;
-
-		crtc = old_conn_state->crtc;
-	}
-
-	return clone_state;
-}
-
 static void
-msm_disable_connector_outputs(struct drm_device *dev,
-		struct drm_atomic_state *old_state)
+msm_disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
 {
 	struct drm_connector *connector;
 	struct drm_connector_state *old_conn_state;
+	struct drm_crtc *crtc;
+	struct drm_crtc_state *old_crtc_state;
 	int i;
 
+	SDE_ATRACE_BEGIN("msm_disable");
 	for_each_old_connector_in_state(old_state, connector,
 			old_conn_state, i) {
 		const struct drm_encoder_helper_funcs *funcs;
@@ -238,18 +204,6 @@ msm_disable_connector_outputs(struct drm_device *dev,
 
 		drm_bridge_post_disable(encoder->bridge);
 	}
-}
-
-static void
-msm_disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
-{
-	struct drm_crtc *crtc;
-	struct drm_crtc_state *old_crtc_state;
-	int i;
-
-	SDE_ATRACE_BEGIN("msm_disable");
-	if (!msm_disable_outputs_for_clone_conn(dev, old_state))
-		msm_disable_connector_outputs(dev, old_state);
 
 	for_each_old_crtc_in_state(old_state, crtc, old_crtc_state, i) {
 		const struct drm_crtc_helper_funcs *funcs;
@@ -568,9 +522,6 @@ static void complete_commit(struct msm_commit *c)
 
 	kms->funcs->complete_commit(kms, state);
 
-	if (msm_disable_outputs_for_clone_conn(dev, state))
-		msm_disable_connector_outputs(dev, state);
-
 	drm_atomic_state_put(state);
 
 	commit_destroy(c);

+ 23 - 0
msm/sde/sde_encoder.c

@@ -756,6 +756,29 @@ bool sde_encoder_in_clone_mode(struct drm_encoder *drm_enc)
 	return false;
 }
 
+bool sde_encoder_is_cwb_disabling(struct drm_encoder *drm_enc,
+	struct drm_crtc *crtc)
+{
+	struct sde_encoder_virt *sde_enc;
+	int i;
+
+	if (!drm_enc)
+		return false;
+
+	sde_enc = to_sde_encoder_virt(drm_enc);
+	if (sde_enc->disp_info.intf_type != DRM_MODE_CONNECTOR_VIRTUAL)
+		return false;
+
+	for (i = 0; i < sde_enc->num_phys_encs; i++) {
+		struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
+
+		if (sde_encoder_phys_is_cwb_disabling(phys, crtc))
+			return true;
+	}
+
+	return false;
+}
+
 static int _sde_encoder_atomic_check_phys_enc(struct sde_encoder_virt *sde_enc,
 	struct drm_crtc_state *crtc_state,
 	struct drm_connector_state *conn_state)

+ 9 - 0
msm/sde/sde_encoder.h

@@ -495,6 +495,15 @@ void sde_encoder_recovery_events_handler(struct drm_encoder *encoder,
  */
 bool sde_encoder_in_clone_mode(struct drm_encoder *enc);
 
+/*
+ * sde_encoder_is_cwb_disabling - check if cwb encoder disable is pending
+ * @drm_enc:    Pointer to drm encoder structure
+ * @drm_crtc:    Pointer to drm crtc structure
+ * @Return: true if cwb encoder disable is pending
+ */
+bool sde_encoder_is_cwb_disabling(struct drm_encoder *drm_enc,
+	struct drm_crtc *drm_crtc);
+
 /**
  * sde_encoder_is_primary_display - checks if underlying display is primary
  *     display or not.

+ 20 - 0
msm/sde/sde_encoder_phys.h

@@ -641,6 +641,26 @@ static inline enum sde_3d_blend_mode sde_encoder_helper_get_3d_blend_mode(
 	return BLEND_3D_NONE;
 }
 
+/**
+ * sde_encoder_phys_is_cwb_disabling - Check if CWB encoder attached to this
+ *	 CRTC and it is in SDE_ENC_DISABLING state.
+ * @phys_enc: Pointer to physical encoder structure
+ * @crtc: drm crtc
+ * @Return: true if cwb encoder is in disabling state
+ */
+static inline bool sde_encoder_phys_is_cwb_disabling(
+	struct sde_encoder_phys *phys, struct drm_crtc *crtc)
+{
+	struct sde_encoder_phys_wb *wb_enc;
+
+	if (!phys || !phys->in_clone_mode ||
+				phys->enable_state != SDE_ENC_DISABLING)
+		return false;
+
+	wb_enc = container_of(phys, struct sde_encoder_phys_wb, base);
+	return (wb_enc->crtc == crtc) ? true : false;
+}
+
 /**
  * sde_encoder_helper_split_config - split display configuration helper function
  *	This helper function may be used by physical encoders to configure

+ 47 - 23
msm/sde/sde_encoder_phys_wb.c

@@ -1074,7 +1074,8 @@ static void _sde_encoder_phys_wb_frame_done_helper(void *arg, bool frame_error)
 	SDE_DEBUG("[wb:%d,%u]\n", hw_wb->idx - WB_0, wb_enc->frame_count);
 
 	/* don't notify upper layer for internal commit */
-	if (phys_enc->enable_state == SDE_ENC_DISABLING)
+	if (phys_enc->enable_state == SDE_ENC_DISABLING &&
+			!phys_enc->in_clone_mode)
 		goto complete;
 
 	if (phys_enc->parent_ops.handle_frame_done &&
@@ -1272,6 +1273,31 @@ static bool _sde_encoder_phys_wb_is_idle(
 
 	return ret;
 }
+static void _sde_encoder_phys_wb_reset_state(
+		struct sde_encoder_phys *phys_enc)
+{
+	struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
+
+	/*
+	 * frame count and kickoff count are only used for debug purpose. Frame
+	 * count can be more than kickoff count at the end of disable call due
+	 * to extra frame_done wait. It does not cause any issue because
+	 * frame_done wait is based on retire_fence count. Leaving these
+	 * counters for debugging purpose.
+	 */
+	if (wb_enc->frame_count != wb_enc->kickoff_count) {
+		SDE_EVT32(DRMID(phys_enc->parent), WBID(wb_enc),
+			wb_enc->kickoff_count, wb_enc->frame_count,
+			phys_enc->in_clone_mode);
+		wb_enc->frame_count = wb_enc->kickoff_count;
+	}
+
+	phys_enc->enable_state = SDE_ENC_DISABLED;
+	wb_enc->crtc = NULL;
+	phys_enc->hw_cdm = NULL;
+	phys_enc->hw_ctl = NULL;
+	phys_enc->in_clone_mode = false;
+}
 
 static int _sde_encoder_phys_wb_wait_for_commit_done(
 		struct sde_encoder_phys *phys_enc, bool is_disable)
@@ -1358,7 +1384,17 @@ skip_wait:
 static int sde_encoder_phys_wb_wait_for_commit_done(
 		struct sde_encoder_phys *phys_enc)
 {
-	return _sde_encoder_phys_wb_wait_for_commit_done(phys_enc, false);
+	int rc;
+
+	if (phys_enc->enable_state == SDE_ENC_DISABLING &&
+			phys_enc->in_clone_mode) {
+		rc = _sde_encoder_phys_wb_wait_for_commit_done(phys_enc, true);
+		_sde_encoder_phys_wb_reset_state(phys_enc);
+	} else {
+		rc = _sde_encoder_phys_wb_wait_for_commit_done(phys_enc, false);
+	}
+
+	return rc;
 }
 
 static int sde_encoder_phys_wb_wait_for_tx_complete(
@@ -1625,7 +1661,9 @@ static void sde_encoder_phys_wb_disable(struct sde_encoder_phys *phys_enc)
 	SDE_DEBUG("[wait_for_done: wb:%d, frame:%u, kickoff:%u]\n",
 			hw_wb->idx - WB_0, wb_enc->frame_count,
 			wb_enc->kickoff_count);
-	_sde_encoder_phys_wb_wait_for_commit_done(phys_enc, true);
+
+	if (!phys_enc->in_clone_mode || !wb_enc->crtc->state->active)
+		_sde_encoder_phys_wb_wait_for_commit_done(phys_enc, true);
 
 	if (!phys_enc->hw_ctl || !phys_enc->parent ||
 			!phys_enc->sde_kms || !wb_enc->fb_disable) {
@@ -1633,11 +1671,14 @@ static void sde_encoder_phys_wb_disable(struct sde_encoder_phys *phys_enc)
 		goto exit;
 	}
 
-	/* avoid reset frame for CWB */
 	if (phys_enc->in_clone_mode) {
 		_sde_encoder_phys_wb_setup_cwb(phys_enc, false);
 		_sde_encoder_phys_wb_update_cwb_flush(phys_enc, false);
-		phys_enc->in_clone_mode = false;
+		phys_enc->enable_state = SDE_ENC_DISABLING;
+
+		if (wb_enc->crtc->state->active)
+			return;
+
 		goto exit;
 	}
 
@@ -1670,24 +1711,7 @@ static void sde_encoder_phys_wb_disable(struct sde_encoder_phys *phys_enc)
 	sde_encoder_phys_wb_irq_ctrl(phys_enc, false);
 
 exit:
-	/*
-	 * frame count and kickoff count are only used for debug purpose. Frame
-	 * count can be more than kickoff count at the end of disable call due
-	 * to extra frame_done wait. It does not cause any issue because
-	 * frame_done wait is based on retire_fence count. Leaving these
-	 * counters for debugging purpose.
-	 */
-	if (wb_enc->frame_count != wb_enc->kickoff_count) {
-		SDE_EVT32(DRMID(phys_enc->parent), WBID(wb_enc),
-			wb_enc->kickoff_count, wb_enc->frame_count,
-			phys_enc->in_clone_mode);
-		wb_enc->frame_count = wb_enc->kickoff_count;
-	}
-
-	phys_enc->enable_state = SDE_ENC_DISABLED;
-	wb_enc->crtc = NULL;
-	phys_enc->hw_cdm = NULL;
-	phys_enc->hw_ctl = NULL;
+	_sde_encoder_phys_wb_reset_state(phys_enc);
 }
 
 /**

+ 2 - 1
msm/sde/sde_kms.c

@@ -1557,7 +1557,8 @@ static void sde_kms_wait_for_commit_done(struct msm_kms *kms,
 
 	SDE_ATRACE_BEGIN("sde_kms_wait_for_commit_done");
 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
-		if (encoder->crtc != crtc)
+		if (encoder->crtc != crtc &&
+				!sde_encoder_is_cwb_disabling(encoder, crtc))
 			continue;
 		/*
 		 * Wait for post-flush if necessary to delay before