On Thu, Sep 24, 2026 at 03:51:59AM +0800, Xizhe Tang wrote:
> A Panther Lake eDP panel that advertises VRR in EDID but runs at a fixed
> refresh rate has received an Adaptive-Sync SDP since commit 6a1712052859
> ("drm/i915/dp: Enable AS SDP whenever VRR is possible or PR !async").
> On this panel the first modeset at boot is vertically streaked.
>
> intel_vrr_possible() is only crtc_state->vrr.flipline != 0. Fixed-refresh
> timings program flipline too:
>
> intel_vrr_compute_fixed_rr_timings():
> /* For fixed rr, vmin = vmax = flipline */
> crtc_state->vrr.flipline = crtc_state->vrr.vmin;
>
> intel_vrr_compute_config() takes that path when VRR is not actually
> enabled (uapi.vrr_enabled is false, or vmin == vmax). Then
> intel_dp_needs_as_sdp() is true with `vrr: no, fixed rr: yes`, and
> intel_dp_compute_as_sdp() programs DP_AS_SDP_AVT_FIXED_VTOTAL.
>
> Gate the terminal condition on the states that consume the SDP:
> crtc_state->vrr.enable (VRR) or crtc_state->cmrr.enable (CMRR / FAVT).
> Leave the Panel Replay aux-less-ALPM early-return from the same commit
> unchanged.
>
> CMRR is still hard-disabled (is_cmrr_frac_required() has "|| true"), so
> cmrr.enable stays false today and the OR is a no-op versus v1 at fixed
> refresh. intel_vrr_compute_cmrr_timings() sets cmrr.enable without
> vrr.enable; the OR keeps the FAVT branch reachable when CMRR is re-enabled.
>
> This is a no-op while VRR is actually active. It does not fix Adaptive
> Sync = Always corruption, nor the non-atomic SDP update named by the
> #FIXME above intel_dp_compute_as_sdp(). Trailer is Link:, not Closes:.
>
> Tested on LENOVO 21VG (PTL eDP, 8086:b080), v7.2.6-200.fc44.x86_64,
> rebuilding only xe.ko with this hunk:
>
> Adaptive Sync = Never (Tested-by): vrr: no, fixed rr: yes,
> infoframes enabled: 0x6 (no BIT(3)), zero Adaptive-Sync SDP, panel
> clean. This boot: six s2idle suspend/resume cycles, all clean.
>
> Adaptive Sync = Always (not Tested-by): vrr: yes, vmin 2016 / vmax 8064,
> infoframes enabled: 0xe, Adaptive-Sync SDP still sent. Panel
> appearance on Always is not claimed.
>
> CMRR / FAVT: not tested.
>
> On the same panel, Adaptive Sync = Never, first modeset, drm.debug=0xe:
>
> 7.1.13 (clean): infoframes enabled: 0x4 (VSC only)
> 7.2.4 (streaked): infoframes enabled: 0xc (VSC + AS SDP,
> operation mode 1 = DP_AS_SDP_AVT_FIXED_VTOTAL)
>
> Later dumps of those boots are 0x6 vs 0xe; each non-zero bad mask is
> good | BIT(3).
>
> Changes in v2:
> - OR crtc_state->cmrr.enable so CMRR still gets AS SDP (v1 review).
> At fixed refresh v2 matches v1.
> v1: https://lore.kernel.org/r/[email protected]
>
> Link: https://gitlab.freedesktop.org/drm/xe/kernel/-/work_items/9252
> Fixes: 6a1712052859 ("drm/i915/dp: Enable AS SDP whenever VRR is possible or
> PR !async")
> Cc: [email protected] # 7.2.x
> Signed-off-by: Xizhe Tang <[email protected]>
> Tested-by: Xizhe Tang <[email protected]> # v7.2.6, PTL eDP, Adaptive
> Sync=Never
> ---
> drivers/gpu/drm/i915/display/intel_dp.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/i915/display/intel_dp.c
> b/drivers/gpu/drm/i915/display/intel_dp.c
> --- a/drivers/gpu/drm/i915/display/intel_dp.c
> +++ b/drivers/gpu/drm/i915/display/intel_dp.c
> @@ -3115,8 +3115,9 @@ static bool intel_dp_needs_as_sdp(struct intel_dp
> *intel_dp,
> if (intel_psr_needs_alpm_aux_less(intel_dp, crtc_state) &&
> !intel_psr_pr_async_video_timing_supported(intel_dp))
> return true;
>
> - return intel_vrr_possible(crtc_state);
> + return crtc_state->vrr.enable ||
> + crtc_state->cmrr.enable;
The real problem is that intel_vrr_possible() no longer does what
it says on the tin. I think we have three different things
intel_vrr_possible() gets used for currently:
- intel_dp_needs_as_sdp() actually wants to know whether variable VRR
timings are possible or not, and it wants to know that without
actually looking at uapi.vrr_enabled in order to avoid changes to
the guardband when uapi.vrr_enabled changes
- _intel_psr_min_set_context_latency() might want to know whether we
could end up using the VRR timing generator or not. Not 100% sure
about this one though
- everything in intel_vrr.c just wants to know whether we should program
the VRR timing generator registers or not. These are the only places
where the current intel_vrr_possible() actually looks correct, albeit
with a bad function name
> }
>
> static void intel_dp_compute_as_sdp(struct intel_dp *intel_dp,
> --
> 2.47.0
--
Ville Syrjälä
Intel