diff --git a/msm/sde/sde_color_processing.c b/msm/sde/sde_color_processing.c index e71a59230545..8e84eb38cf22 100644 --- a/msm/sde/sde_color_processing.c +++ b/msm/sde/sde_color_processing.c @@ -4132,7 +4132,7 @@ int sde_cp_ltm_off_event_handler(struct drm_crtc *crtc_drm, bool en, return 0; } -void sde_cp_mode_switch_prop_dirty(struct drm_crtc *crtc_drm) +void sde_cp_crtc_res_change(struct drm_crtc *crtc_drm) { struct sde_cp_node *prop_node = NULL, *n = NULL; struct sde_crtc *crtc; diff --git a/msm/sde/sde_color_processing.h b/msm/sde/sde_color_processing.h index ef943c3358df..e8542bcb8b94 100644 --- a/msm/sde/sde_color_processing.h +++ b/msm/sde/sde_color_processing.h @@ -201,10 +201,10 @@ int sde_cp_ltm_off_event_handler(struct drm_crtc *crtc_drm, bool en, struct sde_irq_callback *hist_irq); /** - * sde_cp_mode_switch_prop_dirty: API marks mode dependent features as dirty + * sde_cp_crtc_res_change: API to handle LM resolution changes * @crtc_drm: Pointer to crtc. */ -void sde_cp_mode_switch_prop_dirty(struct drm_crtc *crtc_drm); +void sde_cp_crtc_res_change(struct drm_crtc *crtc_drm); /** * sde_cp_crtc_vm_primary_handoff: Properly handoff CRTC color mode features diff --git a/msm/sde/sde_crtc.c b/msm/sde/sde_crtc.c index 275d1690350d..3123f1aab167 100644 --- a/msm/sde/sde_crtc.c +++ b/msm/sde/sde_crtc.c @@ -433,7 +433,6 @@ static bool sde_crtc_mode_fixup(struct drm_crtc *crtc, { SDE_DEBUG("\n"); - sde_cp_mode_switch_prop_dirty(crtc); if ((msm_is_mode_seamless(adjusted_mode) || (msm_is_mode_seamless_vrr(adjusted_mode) || msm_is_mode_seamless_dyn_clk(adjusted_mode))) && @@ -1113,40 +1112,49 @@ static int _sde_crtc_check_rois(struct drm_crtc *crtc, static void _sde_crtc_program_lm_output_roi(struct drm_crtc *crtc) { struct sde_crtc *sde_crtc; - struct sde_crtc_state *crtc_state; + struct sde_crtc_state *cstate; const struct sde_rect *lm_roi; struct sde_hw_mixer *hw_lm; bool right_mixer = false; + bool lm_updated = false; int lm_idx; if (!crtc) return; sde_crtc = to_sde_crtc(crtc); - crtc_state = to_sde_crtc_state(crtc->state); + cstate = to_sde_crtc_state(crtc->state); for (lm_idx = 0; lm_idx < sde_crtc->num_mixers; lm_idx++) { struct sde_hw_mixer_cfg cfg; - lm_roi = &crtc_state->lm_roi[lm_idx]; + lm_roi = &cstate->lm_roi[lm_idx]; hw_lm = sde_crtc->mixers[lm_idx].hw_lm; if (!sde_crtc->mixers_swapped) right_mixer = lm_idx % MAX_MIXERS_PER_LAYOUT; - SDE_EVT32(DRMID(crtc_state->base.crtc), lm_idx, - lm_roi->x, lm_roi->y, lm_roi->w, lm_roi->h, - right_mixer); + if (lm_roi->w != hw_lm->cfg.out_width || + lm_roi->h != hw_lm->cfg.out_height || + right_mixer != hw_lm->cfg.right_mixer) { + hw_lm->cfg.out_width = lm_roi->w; + hw_lm->cfg.out_height = lm_roi->h; + hw_lm->cfg.right_mixer = right_mixer; - hw_lm->cfg.out_width = lm_roi->w; - hw_lm->cfg.out_height = lm_roi->h; - hw_lm->cfg.right_mixer = right_mixer; + cfg.out_width = lm_roi->w; + cfg.out_height = lm_roi->h; + cfg.right_mixer = right_mixer; + cfg.flags = 0; - cfg.out_width = lm_roi->w; - cfg.out_height = lm_roi->h; - cfg.right_mixer = right_mixer; - cfg.flags = 0; - hw_lm->ops.setup_mixer_out(hw_lm, &cfg); + hw_lm->ops.setup_mixer_out(hw_lm, &cfg); + lm_updated = true; + } + + SDE_EVT32(DRMID(crtc), lm_idx, lm_roi->x, lm_roi->y, lm_roi->w, + lm_roi->h, right_mixer, lm_updated); } + + if (lm_updated) + sde_cp_crtc_res_change(crtc); } struct plane_state { @@ -1533,8 +1541,6 @@ static void _sde_crtc_blend_setup_mixer(struct drm_crtc *crtc, } } - _sde_crtc_program_lm_output_roi(crtc); - end: kfree(pstates); } @@ -2165,8 +2171,6 @@ static void _sde_crtc_dest_scaler_setup(struct drm_crtc *crtc) hw_ctl->ops.update_bitmask_mixer( hw_ctl, hw_lm->idx, 1); } - - sde_cp_mode_switch_prop_dirty(crtc); } } @@ -3901,12 +3905,63 @@ static void sde_crtc_reset(struct drm_crtc *crtc) crtc->state = &cstate->base; } +static void sde_crtc_clear_cached_mixer_cfg(struct drm_crtc *crtc) +{ + struct sde_crtc *sde_crtc = to_sde_crtc(crtc); + struct sde_hw_mixer *hw_lm; + int lm_idx; + + /* clearing lm cfg marks it dirty to force reprogramming next update */ + for (lm_idx = 0; lm_idx < sde_crtc->num_mixers; lm_idx++) { + hw_lm = sde_crtc->mixers[lm_idx].hw_lm; + hw_lm->cfg.out_width = 0; + hw_lm->cfg.out_height = 0; + } + + SDE_EVT32(DRMID(crtc)); +} + +static void sde_crtc_reset_sw_state_for_ipc(struct drm_crtc *crtc) +{ + struct sde_crtc_state *cstate = to_sde_crtc_state(crtc->state); + struct drm_plane *plane; + + /* mark planes, mixers, and other blocks dirty for next update */ + drm_atomic_crtc_for_each_plane(plane, crtc) + sde_plane_set_revalidate(plane, true); + + /* mark mixers dirty for next update */ + sde_crtc_clear_cached_mixer_cfg(crtc); + + /* mark other properties which need to be dirty for next update */ + set_bit(SDE_CRTC_DIRTY_DIM_LAYERS, cstate->dirty); + if (cstate->num_ds_enabled) + set_bit(SDE_CRTC_DIRTY_DEST_SCALER, cstate->dirty); +} + +static void sde_crtc_post_ipc(struct drm_crtc *crtc) +{ + struct sde_crtc *sde_crtc; + struct sde_crtc_state *cstate; + struct drm_encoder *encoder; + + sde_crtc = to_sde_crtc(crtc); + cstate = to_sde_crtc_state(crtc->state); + + /* restore encoder; crtc will be programmed during commit */ + drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask) + sde_encoder_virt_restore(encoder); + + /* restore UIDLE */ + sde_core_perf_crtc_update_uidle(crtc, true); + + sde_cp_crtc_post_ipc(crtc); +} + static void sde_crtc_handle_power_event(u32 event_type, void *arg) { struct drm_crtc *crtc = arg; struct sde_crtc *sde_crtc; - struct sde_crtc_state *cstate; - struct drm_plane *plane; struct drm_encoder *encoder; u32 power_on; unsigned long flags; @@ -3919,7 +3974,6 @@ static void sde_crtc_handle_power_event(u32 event_type, void *arg) return; } sde_crtc = to_sde_crtc(crtc); - cstate = to_sde_crtc_state(crtc->state); mutex_lock(&sde_crtc->crtc_lock); @@ -3927,15 +3981,6 @@ static void sde_crtc_handle_power_event(u32 event_type, void *arg) switch (event_type) { case SDE_POWER_EVENT_POST_ENABLE: - /* restore encoder; crtc will be programmed during commit */ - drm_for_each_encoder_mask(encoder, crtc->dev, - crtc->state->encoder_mask) { - sde_encoder_virt_restore(encoder); - } - - /* restore UIDLE */ - sde_core_perf_crtc_update_uidle(crtc, true); - spin_lock_irqsave(&sde_crtc->spin_lock, flags); list_for_each_entry(node, &sde_crtc->user_event_list, list) { ret = 0; @@ -3947,10 +3992,9 @@ static void sde_crtc_handle_power_event(u32 event_type, void *arg) } spin_unlock_irqrestore(&sde_crtc->spin_lock, flags); - sde_cp_crtc_post_ipc(crtc); + sde_crtc_post_ipc(crtc); break; case SDE_POWER_EVENT_PRE_DISABLE: - drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask) { /* @@ -3980,21 +4024,8 @@ static void sde_crtc_handle_power_event(u32 event_type, void *arg) sde_cp_crtc_pre_ipc(crtc); break; case SDE_POWER_EVENT_POST_DISABLE: - /* - * set revalidate flag in planes, so it will be re-programmed - * in the next frame update - */ - drm_atomic_crtc_for_each_plane(plane, crtc) - sde_plane_set_revalidate(plane, true); - + sde_crtc_reset_sw_state_for_ipc(crtc); sde_cp_crtc_suspend(crtc); - - /* reconfigure everything on next frame update */ - set_bit(SDE_CRTC_DIRTY_DIM_LAYERS, cstate->dirty); - - if (cstate->num_ds_enabled) - set_bit(SDE_CRTC_DIRTY_DEST_SCALER, cstate->dirty); - event.type = DRM_EVENT_SDE_POWER; event.length = sizeof(power_on); power_on = 0; @@ -4014,6 +4045,9 @@ static void _sde_crtc_reset(struct drm_crtc *crtc) struct sde_crtc *sde_crtc = to_sde_crtc(crtc); struct sde_crtc_state *cstate = to_sde_crtc_state(crtc->state); + /* mark mixer cfgs dirty before wiping them */ + sde_crtc_clear_cached_mixer_cfg(crtc); + memset(sde_crtc->mixers, 0, sizeof(sde_crtc->mixers)); sde_crtc->num_mixers = 0; sde_crtc->mixers_swapped = false;