diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 30feed50a2d1..ebd00922bf3c 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1778,6 +1778,8 @@ struct intel_psr { bool irq_aux_error; /* DC3CO allowed used to control PSR configuration */ bool dc3co_allowed; + /* DC3CO disable work */ + struct delayed_work dc3co_work; u16 su_w_granularity; u16 su_y_granularity; bool source_panel_replay_support; diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 091da8341b0f..911afb9cb24e 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -1774,6 +1774,50 @@ static bool intel_psr_needs_wa_18037818876(struct intel_dp *intel_dp, !crtc_state->has_sel_update); } +static void psr2_dc3co_disable_locked(struct intel_dp *intel_dp) +{ + struct intel_display *display = to_intel_display(intel_dp); + + if (intel_dp->psr.dc3co_allowed) { + intel_dp->psr.dc3co_allowed = false; + intel_display_power_set_target_dc_state(display, DC_STATE_EN_UPTO_DC6); + psr2_program_idle_frames(intel_dp, psr_compute_idle_frames(intel_dp)); + } +} + +static void psr2_dc3co_disable_work(struct work_struct *work) +{ + struct intel_dp *intel_dp = + container_of(work, typeof(*intel_dp), psr.dc3co_work.work); + + mutex_lock(&intel_dp->psr.lock); + psr2_dc3co_disable_locked(intel_dp); + mutex_unlock(&intel_dp->psr.lock); +} + +static void +psr2_dc3co_flush_locked(struct intel_dp *intel_dp, unsigned int frontbuffer_bits) +{ + struct intel_display *display = to_intel_display(intel_dp); + + if (!intel_dp->psr.dc3co_allowed) + return; + + if (!intel_dp->psr.sel_update_enabled || + !intel_dp->psr.active) + return; + /* + * At every frontbuffer flush flip event modified delay of delayed work, + * when delayed work schedules that means display has been idle. + */ + if (!(frontbuffer_bits & + INTEL_FRONTBUFFER_ALL_MASK(intel_dp->psr.pipe))) + return; + + mod_delayed_work(display->wq.unordered, &intel_dp->psr.dc3co_work, + intel_dp->psr.dc3co_exit_delay); +} + static void intel_psr_set_non_psr_pipes(struct intel_dp *intel_dp, struct intel_crtc_state *crtc_state) @@ -2331,6 +2375,7 @@ static void intel_psr_disable_locked(struct intel_dp *intel_dp) intel_dp->psr.psr2_sel_fetch_cff_enabled = false; intel_dp->psr.active_non_psr_pipes = 0; intel_dp->psr.pkg_c_latency_used = 0; + cancel_delayed_work(&intel_dp->psr.dc3co_work); intel_dp->psr.dc3co_allowed = false; } @@ -2361,6 +2406,7 @@ void intel_psr_disable(struct intel_dp *intel_dp, mutex_unlock(&intel_dp->psr.lock); cancel_work_sync(&intel_dp->psr.work); + cancel_delayed_work_sync(&intel_dp->psr.dc3co_work); } /** @@ -2391,6 +2437,7 @@ void intel_psr_pause(struct intel_dp *intel_dp) mutex_unlock(&psr->lock); cancel_work_sync(&psr->work); + cancel_delayed_work_sync(&psr->dc3co_work); } /** @@ -2417,8 +2464,13 @@ void intel_psr_resume(struct intel_dp *intel_dp) goto out; } - if (--intel_dp->psr.pause_counter == 0) + if (--intel_dp->psr.pause_counter == 0) { intel_psr_activate(intel_dp); + /* re-arm cancelled dc3co work from pause */ + if (intel_dp->psr.dc3co_allowed) + mod_delayed_work(display->wq.unordered, &intel_dp->psr.dc3co_work, + intel_dp->psr.dc3co_exit_delay); + } out: mutex_unlock(&psr->lock); @@ -3174,6 +3226,11 @@ void intel_psr_post_plane_update(struct intel_atomic_state *state, */ intel_dp->psr.busy_frontbuffer_bits = 0; + if (intel_dp->psr.dc3co_allowed) { + mod_delayed_work(display->wq.unordered, &intel_dp->psr.dc3co_work, + intel_dp->psr.dc3co_exit_delay); + } + mutex_unlock(&psr->lock); } } @@ -3632,6 +3689,7 @@ void intel_psr_flush(struct intel_display *display, if (origin == ORIGIN_FLIP || (origin == ORIGIN_CURSOR_UPDATE && !intel_dp->psr.psr2_sel_fetch_enabled)) { + psr2_dc3co_flush_locked(intel_dp, frontbuffer_bits); goto unlock; } @@ -3690,6 +3748,7 @@ void intel_psr_init(struct intel_dp *intel_dp) intel_dp->psr.link_standby = connector->panel.vbt.psr.full_link; INIT_WORK(&intel_dp->psr.work, intel_psr_work); + INIT_DELAYED_WORK(&intel_dp->psr.dc3co_work, psr2_dc3co_disable_work); mutex_init(&intel_dp->psr.lock); }