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;
>  

Reply via email to