Просмотр исходного кода

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

qctecmdr 4 лет назад
Родитель
Сommit
5e96441e58
6 измененных файлов с 105 добавлено и 77 удалено
  1. 4 53
      msm/msm_atomic.c
  2. 23 0
      msm/sde/sde_encoder.c
  3. 9 0
      msm/sde/sde_encoder.h
  4. 20 0
      msm/sde/sde_encoder_phys.h
  5. 47 23
      msm/sde/sde_encoder_phys_wb.c
  6. 2 1
      msm/sde/sde_kms.c

+ 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