diff --git a/msm/sde/sde_crtc.c b/msm/sde/sde_crtc.c index d562e46c5f..3b9e3ee7be 100644 --- a/msm/sde/sde_crtc.c +++ b/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) + + if (sde_crtc->cache_state != CACHE_STATE_FRAME_WRITE) return; - ctl = mixer->hw_ctl; + 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 (!drm_enc) { + SDE_ERROR("invalid encoder\n"); + return; + } SDE_EVT32(DRMID(crtc), SDE_EVTLOG_FUNC_ENTRY); - if (sde_crtc->cache_state != CACHE_STATE_FRAME_WRITE || - !ctl->ops.trigger_flush) - return; - 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); } diff --git a/msm/sde/sde_encoder.c b/msm/sde/sde_encoder.c index 117f452805..f44b8d887d 100644 --- a/msm/sde/sde_encoder.c +++ b/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++) { diff --git a/msm/sde/sde_encoder.h b/msm/sde/sde_encoder.h index bcde2bada5..504094fffc 100644 --- a/msm/sde/sde_encoder.h +++ b/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