diff --git a/drivers/gpu/drm/i915/display/intel_alpm.c b/drivers/gpu/drm/i915/display/intel_alpm.c index a6838e0fd3aa..0a33a89975bc 100644 --- a/drivers/gpu/drm/i915/display/intel_alpm.c +++ b/drivers/gpu/drm/i915/display/intel_alpm.c @@ -404,6 +404,29 @@ static u32 intel_pr_as_sdp_skip_frames(struct intel_dp *intel_dp) REG_FIELD_MAX(PR_ALPM_CTL_AS_SDP_SKIP_FRAMES_MASK)); } +/* + * Whether periodic AS SDP transmission (AS SDP skip frames) will be programmed + * for this Panel Replay config. The skip counter needs the AS SDP to keep + * flowing during PR active, which is incompatible with DC3co, so this is used + * to keep DC3co disabled while skip frames is enabled. + */ +bool intel_alpm_pr_as_sdp_skip_frames_enabled(struct intel_dp *intel_dp, + const struct intel_crtc_state *crtc_state) +{ + struct intel_display *display = to_intel_display(intel_dp); + + /* + * The AS SDP skip frames field only exists on Xe3p_LPD+. Periodic AS SDP + * drives the panel down to its minimum refresh rate on its own, so it is + * only used when VRR is not actively driving the refresh rate. + */ + if (DISPLAY_VER(display) < 35 || !intel_dp->as_sdp_supported || + !crtc_state->has_panel_replay || crtc_state->vrr.enable) + return false; + + return intel_pr_as_sdp_skip_frames(intel_dp) > 0; +} + static void lnl_alpm_configure(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state) { diff --git a/drivers/gpu/drm/i915/display/intel_alpm.h b/drivers/gpu/drm/i915/display/intel_alpm.h index 1cf70668ab1b..328920027f1c 100644 --- a/drivers/gpu/drm/i915/display/intel_alpm.h +++ b/drivers/gpu/drm/i915/display/intel_alpm.h @@ -34,6 +34,8 @@ bool intel_alpm_aux_wake_supported(struct intel_dp *intel_dp); bool intel_alpm_aux_less_wake_supported(struct intel_dp *intel_dp); bool intel_alpm_is_alpm_aux_less(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state); +bool intel_alpm_pr_as_sdp_skip_frames_enabled(struct intel_dp *intel_dp, + const struct intel_crtc_state *crtc_state); void intel_alpm_disable(struct intel_dp *intel_dp); bool intel_alpm_get_error(struct intel_dp *intel_dp); void intel_alpm_lobf_compute_config_late(struct intel_dp *intel_dp, diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c index 0ebec6e0c240..1b60ce2dd00c 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.c +++ b/drivers/gpu/drm/i915/display/intel_display_power.c @@ -10,6 +10,7 @@ #include #include +#include "intel_alpm.h" #include "intel_backlight_regs.h" #include "intel_cdclk.h" #include "intel_clock_gating.h" @@ -488,6 +489,14 @@ void intel_display_power_dc3co_compute(struct intel_atomic_state *state) if (crtc_state->has_sel_update) trigger |= DC3CO_TRIGGER_PSR2; + /* + * Periodic AS SDP (skip frames) needs the AS SDP to keep flowing during + * PR active, which is incompatible with DC3co. Keep DC3co disabled while + * skip frames is enabled. + */ + if (intel_alpm_pr_as_sdp_skip_frames_enabled(intel_dp, crtc_state)) + trigger = DC3CO_TRIGGER_NONE; + done: intel_display_power_dc3co_update(display, trigger); }