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, 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. 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..79cce5b 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; } 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);
