On Thu, 2026-09-03 at 20:43 -0400, Jake Steinman wrote: > The LG panel (sink OUI 00:22:b9) in the Dell XPS 14 DA14260 and XPS > 16 > DA16260 (Panther Lake) fails every ALPM link wake when the extended > fast > wake and the IO buffer wake are programmed to the same number of > scanlines, which the spec formulas produce for it (11/11 lines on > 3200x2000@120, 4 x 2.7 Gbps, DSC). 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. > > Measured with DP_PSR_ERROR_STATUS polled every 200 ms and cleared > after > each read, 15 s of PSR2 per configuration, number of polls that found > the bit set again: > > io/fast 11/11, guardband 60 (stock) 70 of 71 > io/fast 11/11, guardband 127 (full vblank) 70 of 70 > fast wake sync length 20 -> io/fast 12/12 68 of 69 > fast wake sync length 24 -> io/fast 13/13 69 of 70 > io/fast 11/12 0 of 71 > > A larger guardband or a longer fast wake sync pulse does not help, > and > moving both wake times up together does not either. The fast wake has > to start strictly before the IO buffer wake on this panel. > > Since the spec allows the IO buffer wake to be equal to or longer > than > the fast wake, keep the formulas as they are and apply the relation > as > a DPCD quirk for this panel on these two machines: one extra fast > wake > line, or the IO buffer wake one line below the fast wake when already > at the maximum. Account for the larger of the two wake times in the > vblank and guardband checks, PSR and LOBF, which only looked at the > IO > buffer wake on display 20+. > > This does not by itself make PSR2 selective updates or Panel Replay > usable on these machines; with the wake clean the panel still never > receives a selective update. That is tracked separately.
This patch doesn't help much ATM because we wont get rid of the quirk disabling selective fetch anyways. BR, Jouni Högander > > v3: also account for the fast wake in the LOBF guardband and vblank > checks (Sashiko review) > v2: quirk for the affected panel instead of a generic change (Jouni) > > Link: > https://lore.kernel.org/intel-gfx/[email protected]/ > Link: https://gitlab.freedesktop.org/drm/xe/kernel/-/issues/7521 > 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..04f61fd 100644 > --- a/drivers/gpu/drm/i915/display/intel_alpm.c > +++ b/drivers/gpu/drm/i915/display/intel_alpm.c > @@ -15,6 +15,7 @@ > #include "intel_dp.h" > #include "intel_dp_aux.h" > #include "intel_psr.h" > +#include "intel_quirks.h" > #include "intel_psr_regs.h" > #include "intel_vrr.h" > > @@ -238,8 +239,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); > + > + /* > + * 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 when > + * the extended fast wake and the IO buffer wake are > programmed to > + * the same number of lines, which the formulas above > produce for it. > + * Neither a larger guardband nor a longer fast wake sync > pulse > + * changes that; the fast wake has to start strictly before > the IO > + * buffer wake. Apply that as a quirk for this panel only. > + */ > + if (DISPLAY_VER(display) >= 20 && > + intel_has_dpcd_quirk(intel_dp, > QUIRK_ALPM_FAST_WAKE_AHEAD) && > + 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; > } > @@ -256,8 +278,9 @@ int intel_alpm_lobf_min_guardband(struct > intel_crtc_state *crtc_state) > * is applicable. Currently this information is not readily > * available in crtc_state, so max will suffice for now. > */ > - waketime_in_lines = max(crtc_state- > >alpm_state.io_wake_lines, > - crtc_state- > >alpm_state.aux_less_wake_lines); > + waketime_in_lines = max3(crtc_state- > >alpm_state.io_wake_lines, > + crtc_state- > >alpm_state.fast_wake_lines, > + crtc_state- > >alpm_state.aux_less_wake_lines); > > if (!crtc_state->has_lobf) > return 0; > @@ -314,7 +337,8 @@ void intel_alpm_lobf_compute_config_late(struct > intel_dp *intel_dp, > */ > first_sdp_position = adjusted_mode->crtc_vtotal - > adjusted_mode->crtc_vsync_start; > if (intel_alpm_aux_less_wake_supported(intel_dp)) > - waketime_in_lines = crtc_state- > >alpm_state.io_wake_lines; > + waketime_in_lines = max(crtc_state- > >alpm_state.io_wake_lines, > + crtc_state- > >alpm_state.fast_wake_lines); > else > waketime_in_lines = crtc_state- > >alpm_state.aux_less_wake_lines; > > 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; > > diff --git a/drivers/gpu/drm/i915/display/intel_quirks.c > b/drivers/gpu/drm/i915/display/intel_quirks.c > index 33245f4..a5d01ba 100644 > --- a/drivers/gpu/drm/i915/display/intel_quirks.c > +++ b/drivers/gpu/drm/i915/display/intel_quirks.c > @@ -86,6 +86,14 @@ static void quirk_edp_limit_rate_hbr2(struct > intel_display *display) > drm_info(display->drm, "Applying eDP Limit rate to HBR2 > quirk\n"); > } > > +static void quirk_alpm_fast_wake_ahead(struct intel_dp *intel_dp) > +{ > + struct intel_display *display = to_intel_display(intel_dp); > + > + intel_set_dpcd_quirk(intel_dp, QUIRK_ALPM_FAST_WAKE_AHEAD); > + drm_info(display->drm, "Applying ALPM fast wake ahead of IO > buffer wake quirk\n"); > +} > + > static void quirk_disable_edp_panel_replay(struct intel_dp > *intel_dp) > { > struct intel_display *display = to_intel_display(intel_dp); > @@ -286,6 +294,21 @@ static const struct intel_dpcd_quirk > intel_dpcd_quirks[] = { > .sink_oui = SINK_OUI(0x00, 0x22, 0xb9), > .hook = quirk_disable_edp_panel_replay, > }, > + /* Dell XPS 14 DA14260 and XPS 16 DA16260, LG panel: ALPM > link wake */ > + { > + .device = DEVICE_ID_ANY, > + .subsystem_vendor = 0x1028, > + .subsystem_device = 0x0db9, > + .sink_oui = SINK_OUI(0x00, 0x22, 0xb9), > + .hook = quirk_alpm_fast_wake_ahead, > + }, > + { > + .device = DEVICE_ID_ANY, > + .subsystem_vendor = 0x1028, > + .subsystem_device = 0x0dba, > + .sink_oui = SINK_OUI(0x00, 0x22, 0xb9), > + .hook = quirk_alpm_fast_wake_ahead, > + }, > }; > > void intel_init_quirks(struct intel_display *display) > diff --git a/drivers/gpu/drm/i915/display/intel_quirks.h > b/drivers/gpu/drm/i915/display/intel_quirks.h > index 970a4fe..8bbc2eb 100644 > --- a/drivers/gpu/drm/i915/display/intel_quirks.h > +++ b/drivers/gpu/drm/i915/display/intel_quirks.h > @@ -23,6 +23,7 @@ enum intel_quirk_id { > QUIRK_EDP_LIMIT_RATE_HBR2, > QUIRK_DISABLE_EDP_PANEL_REPLAY, > QUIRK_DISABLE_PSR2, > + QUIRK_ALPM_FAST_WAKE_AHEAD, > }; > > void intel_init_quirks(struct intel_display *display);
