diff --git a/msm/msm_atomic.c b/msm/msm_atomic.c index 1d1447b54b..56dff6b289 100644 --- a/msm/msm_atomic.c +++ b/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); diff --git a/msm/sde/sde_encoder.c b/msm/sde/sde_encoder.c index ccf0fdeb41..7633a3af8b 100644 --- a/msm/sde/sde_encoder.c +++ b/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) diff --git a/msm/sde/sde_encoder.h b/msm/sde/sde_encoder.h index bdc8fadd00..17aec63fcd 100644 --- a/msm/sde/sde_encoder.h +++ b/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. diff --git a/msm/sde/sde_encoder_phys.h b/msm/sde/sde_encoder_phys.h index f653bbe7f2..283b75d8e4 100644 --- a/msm/sde/sde_encoder_phys.h +++ b/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 diff --git a/msm/sde/sde_encoder_phys_wb.c b/msm/sde/sde_encoder_phys_wb.c index 6b377fc63f..4de9be9b7a 100644 --- a/msm/sde/sde_encoder_phys_wb.c +++ b/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); } /** diff --git a/msm/sde/sde_kms.c b/msm/sde/sde_kms.c index a46077cb2d..239e5dfb59 100644 --- a/msm/sde/sde_kms.c +++ b/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