Przeglądaj źródła

disp: msm: sde: fix vblank wait after cache read mode update

This change fixes the vblank wait after system cache read mode
update. Without this change the wait does not happen since there is
no pending kickoff. This change uses encoder api to flush the
configuration and explicitly waits for vblank.

Change-Id: I8942f9b638e784c8fd9b5df33a9ccc7087a5eaef
Signed-off-by: Abhijit Kulkarni <[email protected]>
Abhijit Kulkarni 4 lat temu
rodzic
commit
3db847b7bf
3 zmienionych plików z 39 dodań i 29 usunięć
  1. 18 19
      msm/sde/sde_crtc.c
  2. 18 9
      msm/sde/sde_encoder.c
  3. 3 1
      msm/sde/sde_encoder.h

+ 18 - 19
msm/sde/sde_crtc.c

@@ -3654,7 +3654,7 @@ int sde_crtc_reset_hw(struct drm_crtc *crtc, struct drm_crtc_state *old_state,
 			continue;
 
 		if (sde_encoder_get_intf_mode(encoder) == INTF_MODE_VIDEO)
-			sde_encoder_kickoff(encoder, false);
+			sde_encoder_kickoff(encoder, false, true);
 	}
 
 	/* panic the device if VBIF is not in good state */
@@ -3760,7 +3760,7 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc,
 		if (encoder->crtc != crtc)
 			continue;
 
-		sde_encoder_kickoff(encoder, false);
+		sde_encoder_kickoff(encoder, false, true);
 	}
 
 	/* store the event after frame trigger */
@@ -6397,35 +6397,34 @@ void __sde_crtc_static_cache_read_work(struct kthread_work *work)
 	struct sde_crtc *sde_crtc = container_of(work, struct sde_crtc,
 			static_cache_read_work.work);
 	struct drm_crtc *crtc;
-	struct msm_kms *kms;
-	struct msm_drm_private *priv = NULL;
-	struct sde_crtc_mixer *mixer;
-	struct sde_hw_ctl *ctl;
+	struct drm_encoder *enc, *drm_enc = NULL;
 
 	if (!sde_crtc)
 		return;
 
 	crtc = &sde_crtc->base;
-	priv = crtc->dev->dev_private;
-	kms = priv->kms;
-	mixer = sde_crtc->mixers;
-	if (!mixer)
-		return;
 
-	ctl = mixer->hw_ctl;
+	if (sde_crtc->cache_state != CACHE_STATE_FRAME_WRITE)
+		return;
 
-	SDE_EVT32(DRMID(crtc), SDE_EVTLOG_FUNC_ENTRY);
+	drm_for_each_encoder_mask(enc, crtc->dev, crtc->state->encoder_mask) {
+		drm_enc = enc;
+		if (sde_encoder_in_clone_mode(drm_enc))
+			return;
+	}
 
-	if (sde_crtc->cache_state != CACHE_STATE_FRAME_WRITE ||
-			!ctl->ops.trigger_flush)
+	if (!drm_enc) {
+		SDE_ERROR("invalid encoder\n");
 		return;
+	}
+
+	SDE_EVT32(DRMID(crtc), SDE_EVTLOG_FUNC_ENTRY);
 
 	sde_crtc_static_img_control(crtc, CACHE_STATE_FRAME_READ, false);
 
-	/* flush with previous commit flush bits & wait till frame done */
-	ctl->ops.trigger_flush(ctl);
-	if (kms->funcs->wait_for_crtc_commit_done)
-		kms->funcs->wait_for_crtc_commit_done(kms, crtc);
+	/* kickoff encoder with previous configuration and wait for VBLANK */
+	sde_encoder_kickoff(drm_enc, false, false);
+	sde_encoder_wait_for_event(drm_enc, MSM_ENC_VBLANK);
 
 	SDE_EVT32(DRMID(crtc), SDE_EVTLOG_FUNC_EXIT);
 }

+ 18 - 9
msm/sde/sde_encoder.c

@@ -3196,10 +3196,13 @@ int sde_encoder_idle_request(struct drm_encoder *drm_enc)
  * drm_enc: Pointer to drm encoder structure
  * phys: Pointer to physical encoder structure
  * extra_flush: Additional bit mask to include in flush trigger
+ * config_changed: if true new config is applied, avoid increment of retire
+ *	count if false
  */
 static inline void _sde_encoder_trigger_flush(struct drm_encoder *drm_enc,
 		struct sde_encoder_phys *phys,
-		struct sde_ctl_flush_cfg *extra_flush)
+		struct sde_ctl_flush_cfg *extra_flush,
+		bool config_changed)
 {
 	struct sde_hw_ctl *ctl;
 	unsigned long lock_flags;
@@ -3238,7 +3241,7 @@ static inline void _sde_encoder_trigger_flush(struct drm_encoder *drm_enc,
 	/* update pending counts and trigger kickoff ctl flush atomically */
 	spin_lock_irqsave(&sde_enc->enc_spinlock, lock_flags);
 
-	if (phys->ops.is_master && phys->ops.is_master(phys))
+	if (phys->ops.is_master && phys->ops.is_master(phys) && config_changed)
 		atomic_inc(&phys->pending_retire_fence_cnt);
 
 	pend_ret_fence_cnt = atomic_read(&phys->pending_retire_fence_cnt);
@@ -3402,8 +3405,11 @@ void sde_encoder_helper_hw_reset(struct sde_encoder_phys *phys_enc)
  *	use cases that require visibility into multiple physical encoders at
  *	a time.
  * sde_enc: Pointer to virtual encoder structure
+ * config_changed: if true new config is applied. Avoid regdma_flush and
+ *	incrementing the retire count if false.
  */
-static void _sde_encoder_kickoff_phys(struct sde_encoder_virt *sde_enc)
+static void _sde_encoder_kickoff_phys(struct sde_encoder_virt *sde_enc,
+		bool config_changed)
 {
 	struct sde_hw_ctl *ctl;
 	uint32_t i;
@@ -3445,9 +3451,10 @@ static void _sde_encoder_kickoff_phys(struct sde_encoder_virt *sde_enc)
 
 		if (!phys->ops.needs_single_flush ||
 				!phys->ops.needs_single_flush(phys)) {
-			if (ctl->ops.reg_dma_flush)
+			if (config_changed && ctl->ops.reg_dma_flush)
 				ctl->ops.reg_dma_flush(ctl, is_regdma_blocking);
-			_sde_encoder_trigger_flush(&sde_enc->base, phys, 0x0);
+			_sde_encoder_trigger_flush(&sde_enc->base, phys, 0x0,
+					config_changed);
 		} else if (ctl->ops.get_pending_flush) {
 			ctl->ops.get_pending_flush(ctl, &pending_flush);
 		}
@@ -3456,10 +3463,11 @@ static void _sde_encoder_kickoff_phys(struct sde_encoder_virt *sde_enc)
 	/* for split flush, combine pending flush masks and send to master */
 	if (pending_flush.pending_flush_mask && sde_enc->cur_master) {
 		ctl = sde_enc->cur_master->hw_ctl;
-		if (ctl->ops.reg_dma_flush)
+		if (config_changed && ctl->ops.reg_dma_flush)
 			ctl->ops.reg_dma_flush(ctl, is_regdma_blocking);
 		_sde_encoder_trigger_flush(&sde_enc->base, sde_enc->cur_master,
-						&pending_flush);
+						&pending_flush,
+						config_changed);
 	}
 
 	/* update pending_kickoff_cnt AFTER flush but before trigger start */
@@ -4052,7 +4060,8 @@ static int _sde_encoder_reset_ctl_hw(struct drm_encoder *drm_enc)
 	return rc;
 }
 
-void sde_encoder_kickoff(struct drm_encoder *drm_enc, bool is_error)
+void sde_encoder_kickoff(struct drm_encoder *drm_enc, bool is_error,
+		bool config_changed)
 {
 	struct sde_encoder_virt *sde_enc;
 	struct sde_encoder_phys *phys;
@@ -4072,7 +4081,7 @@ void sde_encoder_kickoff(struct drm_encoder *drm_enc, bool is_error)
 		_sde_encoder_reset_ctl_hw(drm_enc);
 
 	/* All phys encs are ready to go, trigger the kickoff */
-	_sde_encoder_kickoff_phys(sde_enc);
+	_sde_encoder_kickoff_phys(sde_enc, config_changed);
 
 	/* allow phys encs to handle any post-kickoff business */
 	for (i = 0; i < sde_enc->num_phys_encs; i++) {

+ 3 - 1
msm/sde/sde_encoder.h

@@ -335,8 +335,10 @@ void sde_encoder_trigger_kickoff_pending(struct drm_encoder *encoder);
  * @encoder:	encoder pointer
  * @is_error:	whether the current commit needs to be aborted and replaced
  *		with a 'safe' commit
+ * @config_changed: if true new configuration is applied on the control path
  */
-void sde_encoder_kickoff(struct drm_encoder *encoder, bool is_error);
+void sde_encoder_kickoff(struct drm_encoder *encoder, bool is_error,
+		bool config_changed);
 
 /**
  * sde_encoder_wait_for_event - Waits for encoder events