On Wed, 2026-09-02 at 12:25 -0400, Jake Steinman wrote:
> On display version 20+ the extended fast wake time is programmed in
> ALPM_CTL and the IO buffer wake in PSR2_CTL.
> intel_alpm_compute_params()
> derives both from precharge + preamble + PHY wake + tFW exit latency
> (42 us here); the IO buffer wake only differs when
> io_buffer_wake_time
> is larger than the precharge, which is not the case on this panel. So
> both end up on the same number of scanlines, 11 on this mode.
>
> On the Dell XPS 16 DA16260 (Panther Lake, LG panel with sink OUI
> 00:22:b9, 3200x2000@120, 4 x 2.7 Gbps, DSC) equal values make every
> ALPM
> link wake fail: the sink sets the Link CRC error bit in
> DP_PSR_ERROR_STATUS within ~25 ms of it being cleared, on every wake,
> for
> as long as PSR2 is active. Changing the two fields at runtime shows
> that
> the relation between them matters, not the absolute time:
>
> fast wake 11 / IO wake 11 -> CRC error on every wake
> fast wake 12 / IO wake 11 -> clean
> fast wake 40 / IO wake 40 -> CRC error on every wake
> fast wake 40 / IO wake 20 -> clean
> fast wake 11 / IO wake 20 -> CRC error on every wake
>
> The fast wake sequence has to start strictly before the IO buffer
> wake.
> With the current values PSR2 on this panel only looked usable because
> the constant wake failures kept forcing the sink to resync.
>
> Make fast_wake_lines strictly greater than io_wake_lines on display
> 20+,
> or, when already at the maximum, put the IO buffer wake one line
> below
> it. Use the larger of the two in the vblank and guardband checks,
> which
> so far only looked at the IO buffer wake on display 20+.
Thank you for the patch. Have you tried increasing vblank/guardband
alone? Addition to vblank and guardband your change is also affecting
how PSR2/ALPM is configured.
>
> This is one of the two machines behind the eDP Panel Replay quirk in
> intel_quirks.c (Dell XPS 14 DA14260 / XPS 16 DA16260). The change
> does
> not make Panel Replay or PSR2 selective updates work there on its
> own:
> with the wake fixed the panel still never receives a selective update
> (sink 0x200a stays at PSR_STATE only) while the PSR2 engine sits in
> SU_STANDBY and consumes the TRANS_PUSH frame change events. That is
> reported separately on intel-gfx.
Your change is conflicting with the spec. It might be a trace to the
actual problem. Please note that io wake time can be >= fast_wake_time
and these formulas are directly taken from our hw spec.
io_wake_time = max(precharge, io_buffer_wake_time(crtc_state))
+ preamble + phy_wake + tfw_exit_latency;
fast_wake_time = precharge + preamble + phy_wake +
tfw_exit_latency;
Have you tried fiddling with the fast wake sync pulse count? See
driver/gpu/drm/i915/display/intel_dp_auc.c:intel_dp_aux_fw_sync_len.
We could consider using something like in this patch as a quirk if it
solves your problem.
BR,
Jouni Högander
>
> Link:
> https://lore.kernel.org/intel-gfx/[email protected]/
> Link: https://gitlab.freedesktop.org/drm/xe/kernel/-/issues/7521
> Link: https://gitlab.freedesktop.org/drm/xe/kernel/-/work_items/7682
> Cc: Jouni Högander <[email protected]>
> Cc: Animesh Manna <[email protected]>
> Cc: Ville Syrjälä <[email protected]>
> Cc: Jani Nikula <[email protected]>
> Cc: [email protected]
> Cc: [email protected]
> Signed-off-by: Jake Steinman <[email protected]>
> ---
> diff --git a/drivers/gpu/drm/i915/display/intel_alpm.c
> b/drivers/gpu/drm/i915/display/intel_alpm.c
> index f138376..c244273 100644
> --- a/drivers/gpu/drm/i915/display/intel_alpm.c
> +++ b/drivers/gpu/drm/i915/display/intel_alpm.c
> @@ -238,8 +238,29 @@ bool intel_alpm_compute_params(struct intel_dp
> *intel_dp,
> io_wake_lines = fast_wake_lines = max_wake_lines;
>
> /* According to Bspec lower limit should be set as 7 lines.
> */
> - crtc_state->alpm_state.io_wake_lines = max(io_wake_lines,
> 7);
> - crtc_state->alpm_state.fast_wake_lines =
> max(fast_wake_lines, 7);
> + io_wake_lines = max(io_wake_lines, 7);
> + fast_wake_lines = max(fast_wake_lines, 7);
> +
> + /*
> + * On display 20+ the extended fast wake sequence programmed
> in
> + * ALPM_CTL has to start strictly before the IO buffer wake
> programmed
> + * in PSR2_CTL. Both are derived from the same precharge,
> preamble,
> + * PHY wake and tFW exit latency above, so they normally end
> up on the
> + * same number of lines. With equal values the
> + * LG panel (sink OUI 00:22:b9) in the Dell XPS 14/16
> DA14260/DA16260
> + * reports a Link CRC error on every link wake. One extra
> fast wake
> + * line is enough to fix it; when we are already at the
> maximum keep
> + * the IO buffer wake one line below the fast wake instead.
> + */
> + if (DISPLAY_VER(display) >= 20 && fast_wake_lines <=
> io_wake_lines) {
> + if (io_wake_lines < max_wake_lines)
> + fast_wake_lines = io_wake_lines + 1;
> + else
> + io_wake_lines = fast_wake_lines - 1;
> + }
> +
> + crtc_state->alpm_state.io_wake_lines = io_wake_lines;
> + crtc_state->alpm_state.fast_wake_lines = fast_wake_lines;
>
> return true;
> }
> diff --git a/drivers/gpu/drm/i915/display/intel_psr.c
> b/drivers/gpu/drm/i915/display/intel_psr.c
> index c0933dd..ec80a2e 100644
> --- a/drivers/gpu/drm/i915/display/intel_psr.c
> +++ b/drivers/gpu/drm/i915/display/intel_psr.c
> @@ -1443,7 +1443,8 @@ static bool wake_lines_fit_into_vblank(struct
> intel_dp *intel_dp,
> wake_lines = DISPLAY_VER(display) < 20 ?
> psr2_block_count_lines(crtc_state-
> >alpm_state.io_wake_lines,
> crtc_state-
> >alpm_state.fast_wake_lines) :
> - crtc_state->alpm_state.io_wake_lines;
> + max(crtc_state->alpm_state.io_wake_lines,
> + crtc_state->alpm_state.fast_wake_lines);
>
> /*
> * Guardband has not been computed yet, so we conservatively
> check if the
> @@ -4556,7 +4557,8 @@ void intel_psr_compute_config_late(struct
> intel_dp *intel_dp,
> wake_lines = DISPLAY_VER(display) < 20 ?
> psr2_block_count_lines(crtc_state-
> >alpm_state.io_wake_lines,
> crtc_state-
> >alpm_state.fast_wake_lines) :
> - crtc_state->alpm_state.io_wake_lines;
> + max(crtc_state-
> >alpm_state.io_wake_lines,
> + crtc_state-
> >alpm_state.fast_wake_lines);
> else
> wake_lines = 0;
>
> @@ -4612,7 +4614,8 @@ int intel_psr_min_guardband(struct
> intel_crtc_state *crtc_state)
> wake_lines = DISPLAY_VER(display) < 20 ?
> psr2_block_count_lines(crtc_state-
> >alpm_state.io_wake_lines,
> crtc_state-
> >alpm_state.fast_wake_lines) :
> - crtc_state->alpm_state.io_wake_lines;
> + max(crtc_state-
> >alpm_state.io_wake_lines,
> + crtc_state-
> >alpm_state.fast_wake_lines);
> else
> return 0;
>