linux-ptl: [EXPERIMENTAL] enable Panel Replay Selective Update with cursor fix (#77)
* linux-ptl: add package with audio, wifi, and Panel Replay SU patches
Adds the linux-ptl Omarchy package for Panther Lake (PTL) hardware.
The stock Arch linux kernel on PTL is missing: SDCA audio class
driver backports, an iwlwifi generation-data fix, and Panel Replay
SU enablement + cursor-lag workaround. Ship them in this package
until they land upstream and Arch picks them up.
Patch sets
==========
Audio (SDCA backports on 6.19.10)
0001-0005, 0007-0008, 0010, 0012-0014, 0017
Cirrus CS35L57 amps and SDCA jack on Dell XPS OLED require the
SDCA class driver plus a NULL-pointer fix (0017). Without these
the sound card never registers. 0006/0009/0011/0015/0016 from the
full upstream series are already in 6.19.10 stable and not needed.
WiFi
0018-wifi-iwlwifi-mld-correctly-set-wifi-generation-data.patch
Backport from wifi-next to fix wifi generation data reporting on
Intel AX/BE radios in PTL.
Display (PSR2 + Panel Replay SU)
0019-drm-i915-psr-accept-early-transport-for-psr2.patch
0020-drm-i915-psr-fix-su-granularity-source-for-psr2.patch
0022-drm-i915-psr-allow-psr-with-vrr-on-ptl.patch
Enable PSR2 Early Transport and fix the SU-granularity DPCD
source so PSR2 is not rejected at compute_config on OLED
panels (LGD 2880x1800 etc). Also allow PSR with VRR on PTL.
0026-drm-i915-psr-handle-Panel-Replay-full-line-SU-granul.patch
PR SU can advertise X granularity = 0xFFFF (full-line).
Without this the modulo check rejects PR SU.
0027-drm-i915-trans-push-frame-change-for-panel-replay.patch
Program TRANS_PUSH Frame Change path so PR SU cursor/plane
updates actually trigger selective updates.
0028-drm-i915-psr-exit-Panel-Replay-for-ALPM-lag.patch
Workaround for the LGD OLED panel (Dell XPS 14 DA14260,
sink OUI 00:22:b9). PR ALPM AUX-Less wake/sleep cycling on
this panel cannot resume selective updates at frame rate,
producing ~15 Hz visible motion from a 120 Hz source.
The workaround exits PR in frontbuffer_flush() and uses the
existing dc3co_work delayed_work as a 50 ms idle timer.
During continuous motion the timer is re-armed by each flush,
so the link stays awake and motion is smooth; after 50 ms of
genuine idle, dc3co_work fires and PR re-activates with ALPM
for power savings.
Compared to a per-commit exit/re-enter approach (earlier
revision of this PR), the delayed re-entry keeps video and
animation playback smooth: per-commit cycling pays the panel's
wake-to-display latency on every frame, which is visible as
playback stutter. 50 ms was chosen empirically against 100 ms
and 200 ms on the same device; 50 ms gives the best idle and
cursor-motion power while remaining subjectively identical in
smoothness to the longer delays.
Power on Dell XPS 14 OLED (LGD 2880x1800 @ 120 Hz, battery,
brightness 268/512, 10-run averaged idle):
PR SU + delayed-re-entry WA : 3268 mW (smooth)
PR SU stock (cursor laggy) : 3384 mW
PR SU + WA 100 ms : 3436 mW
PR SU + WA 200 ms : 3484 mW
PSR2 : 4060 mW (baseline)
config.x86_64 changes
=====================
Required for the kernel to boot cleanly on this hardware:
CONFIG_PINCTRL_INTEL_PLATFORM=y (was =m)
Without this the PTL GPIO controller is a late-loaded module
and early probe of CS35L57 audio amps (spk-id-gpios) and the
I2C touchpad time out with EPROBE_DEFER / -110 ETIMEDOUT.
CONFIG_VFAT_FS=y, CONFIG_FAT_FS=y, CONFIG_MSDOS_FS=y,
CONFIG_NLS_ISO8859_1=y (all were =m)
Required for the ESP /boot to mount in the initramfs / UKI
boot flow. Without these the box drops to emergency mode.
CONFIG_RUST is disabled in this package because Arch Rust 1.94.1
is too new for kernel 6.19.x Rust code.
* Backport DisplayID adaptive sync VRR parsing
* add vrr patch
* fix linux-ptl patch indentation
* linux-ptl: renumber DisplayID VRR patch
---------
Co-authored-by: Gaggery Tsai <gaggery.tsai@gmail.com>
Co-authored-by: Spencer Bull <Spencer.Bull@Dell.com>
This commit is contained in:
co-authored by
Gaggery Tsai
Spencer Bull
parent
dc78c66c1f
commit
49214baae5
@@ -0,0 +1,19 @@
|
||||
diff -ruN a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c
|
||||
--- a/drivers/gpu/drm/i915/display/intel_psr.c 2026-04-06 23:05:21.088563236 -0700
|
||||
+++ b/drivers/gpu/drm/i915/display/intel_psr.c 2026-04-06 23:05:32.080081783 -0700
|
||||
@@ -716,8 +716,14 @@
|
||||
* To support PSR version 02h and PSR version 03h without
|
||||
* Y-coordinate requirement panels we would need to enable
|
||||
* GTC first.
|
||||
+ *
|
||||
+ * Early Transport (version 04h) implies Y-coordinate
|
||||
+ * support. Accept it without explicit Y-coordinate
|
||||
+ * requirement bit.
|
||||
*/
|
||||
- intel_dp->psr.sink_psr2_support = y_req &&
|
||||
+ intel_dp->psr.sink_psr2_support =
|
||||
+ (y_req || intel_dp->psr_dpcd[0] ==
|
||||
+ DP_PSR2_WITH_Y_COORD_ET_SUPPORTED) &&
|
||||
intel_alpm_aux_wake_supported(intel_dp);
|
||||
drm_dbg_kms(display->drm, "PSR2 %ssupported\n",
|
||||
intel_dp->psr.sink_psr2_support ? "" : "not ");
|
||||
@@ -0,0 +1,56 @@
|
||||
diff -ruN a/drivers/gpu/drm/i915/display/intel_alpm.c b/drivers/gpu/drm/i915/display/intel_alpm.c
|
||||
--- a/drivers/gpu/drm/i915/display/intel_alpm.c 2026-04-06 22:15:28.734440462 -0700
|
||||
+++ b/drivers/gpu/drm/i915/display/intel_alpm.c 2026-04-06 22:16:30.831931436 -0700
|
||||
@@ -317,7 +317,7 @@
|
||||
ALPM_CTL_AUX_LESS_SLEEP_HOLD_TIME_50_SYMBOLS |
|
||||
ALPM_CTL_AUX_LESS_WAKE_TIME(crtc_state->alpm_state.aux_less_wake_lines);
|
||||
|
||||
- if (intel_dp->as_sdp_supported) {
|
||||
+ if (intel_dp->as_sdp_supported && crtc_state->has_panel_replay) {
|
||||
u32 pr_alpm_ctl = PR_ALPM_CTL_ADAPTIVE_SYNC_SDP_POSITION_T1;
|
||||
|
||||
if (intel_dp->pr_dpcd[INTEL_PR_DPCD_INDEX(DP_PANEL_REPLAY_CAP_CAPABILITY)] &
|
||||
@@ -432,8 +432,8 @@
|
||||
|
||||
val = DP_ALPM_ENABLE | DP_ALPM_LOCK_ERROR_IRQ_HPD_ENABLE;
|
||||
|
||||
- if (crtc_state->has_panel_replay || (crtc_state->has_lobf &&
|
||||
- intel_alpm_aux_less_wake_supported(intel_dp)))
|
||||
+ if (intel_psr_needs_alpm_aux_less(intel_dp, crtc_state) ||
|
||||
+ (crtc_state->has_lobf && intel_alpm_aux_less_wake_supported(intel_dp)))
|
||||
val |= DP_ALPM_MODE_AUX_LESS;
|
||||
|
||||
drm_dp_dpcd_writeb(&intel_dp->aux, DP_RECEIVER_ALPM_CONFIG, val);
|
||||
diff -ruN a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c
|
||||
--- a/drivers/gpu/drm/i915/display/intel_psr.c 2026-04-06 22:15:28.733325868 -0700
|
||||
+++ b/drivers/gpu/drm/i915/display/intel_psr.c 2026-04-06 23:05:46.639364241 -0700
|
||||
@@ -498,7 +498,8 @@
|
||||
{
|
||||
u8 su_capability = 0;
|
||||
|
||||
- if (intel_dp->psr.sink_panel_replay_su_support) {
|
||||
+ if (intel_dp->psr.sink_panel_replay_su_support &&
|
||||
+ panel_replay_global_enabled(intel_dp)) {
|
||||
if (drm_dp_dpcd_read_byte(&intel_dp->aux,
|
||||
DP_PANEL_REPLAY_CAP_CAPABILITY,
|
||||
&su_capability) < 0)
|
||||
@@ -513,7 +514,8 @@
|
||||
static unsigned int
|
||||
intel_dp_get_su_x_granularity_offset(struct intel_dp *intel_dp)
|
||||
{
|
||||
- return intel_dp->psr.sink_panel_replay_su_support ?
|
||||
+ return (intel_dp->psr.sink_panel_replay_su_support &&
|
||||
+ panel_replay_global_enabled(intel_dp)) ?
|
||||
DP_PANEL_REPLAY_CAP_X_GRANULARITY :
|
||||
DP_PSR2_SU_X_GRANULARITY;
|
||||
}
|
||||
@@ -521,7 +523,8 @@
|
||||
static unsigned int
|
||||
intel_dp_get_su_y_granularity_offset(struct intel_dp *intel_dp)
|
||||
{
|
||||
- return intel_dp->psr.sink_panel_replay_su_support ?
|
||||
+ return (intel_dp->psr.sink_panel_replay_su_support &&
|
||||
+ panel_replay_global_enabled(intel_dp)) ?
|
||||
DP_PANEL_REPLAY_CAP_Y_GRANULARITY :
|
||||
DP_PSR2_SU_Y_GRANULARITY;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Gaggery Tsai <gaggery.tsai@intel.com>
|
||||
Date: Tue, 8 Apr 2026 15:00:00 -0700
|
||||
Subject: [PATCH] drm/i915/psr: Allow PSR with VRR on Panther Lake
|
||||
|
||||
The blanket VRR rejection in _psr_compute_config() prevents PSR2
|
||||
from coexisting with VRR on all platforms. On Panther Lake (PTL,
|
||||
DISPLAY_VER 30), PSR2 + VRR has been tested and works correctly.
|
||||
|
||||
The existing Wa_16011303918 in intel_psr2_config_valid() already
|
||||
handles the Alderlake-P stepping-specific VRR incompatibility.
|
||||
|
||||
Remove the blanket check to allow PSR2 + VRR on platforms where
|
||||
no specific workaround applies.
|
||||
|
||||
Signed-off-by: Gaggery Tsai <gaggery.tsai@intel.com>
|
||||
---
|
||||
drivers/gpu/drm/i915/display/intel_psr.c | 6 ------
|
||||
1 file changed, 6 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c
|
||||
--- a/drivers/gpu/drm/i915/display/intel_psr.c
|
||||
+++ b/drivers/gpu/drm/i915/display/intel_psr.c
|
||||
@@ -1712,12 +1712,6 @@ static bool _psr_compute_config(struct intel_dp *intel_dp,
|
||||
if (!CAN_PSR(intel_dp) || !display->params.enable_psr)
|
||||
return false;
|
||||
|
||||
- /*
|
||||
- * Currently PSR doesn't work reliably with VRR enabled.
|
||||
- */
|
||||
- if (crtc_state->vrr.enable)
|
||||
- return false;
|
||||
-
|
||||
entry_setup_frames = intel_psr_entry_setup_frames(intel_dp, adjusted_mode);
|
||||
if (entry_setup_frames >= 0) {
|
||||
intel_dp->psr.entry_setup_frames = entry_setup_frames;
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
From: Gaggery Tsai <gaggery.tsai@intel.com>
|
||||
Date: Thu, 10 Apr 2026 00:00:00 -0700
|
||||
Subject: [PATCH] drm/i915/psr: handle Panel Replay full-line SU granularity
|
||||
|
||||
Panel Replay SU reports X granularity = 0xFFFF meaning full-line.
|
||||
Without this, psr2_granularity_check() rejects PR SU because
|
||||
2880 % 65535 != 0.
|
||||
|
||||
Signed-off-by: Gaggery Tsai <gaggery.tsai@intel.com>
|
||||
---
|
||||
drivers/gpu/drm/i915/display/intel_psr.c | 9 ++++++++-
|
||||
1 file changed, 8 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c
|
||||
--- a/drivers/gpu/drm/i915/display/intel_psr.c
|
||||
+++ b/drivers/gpu/drm/i915/display/intel_psr.c
|
||||
@@ -1326,9 +1326,17 @@
|
||||
const int crtc_hdisplay = crtc_state->hw.adjusted_mode.crtc_hdisplay;
|
||||
const int crtc_vdisplay = crtc_state->hw.adjusted_mode.crtc_vdisplay;
|
||||
u16 y_granularity = 0;
|
||||
+ u16 w_granularity = intel_dp->psr.su_w_granularity;
|
||||
+
|
||||
+ /*
|
||||
+ * Panel Replay SU can report 0xFFFF meaning full-line granularity.
|
||||
+ * Substitute crtc_hdisplay so the modulo check passes.
|
||||
+ */
|
||||
+ if (w_granularity == 0xFFFF)
|
||||
+ w_granularity = crtc_hdisplay;
|
||||
|
||||
/* PSR2 HW only send full lines so we only need to validate the width */
|
||||
- if (crtc_hdisplay % intel_dp->psr.su_w_granularity)
|
||||
+ if (crtc_hdisplay % w_granularity)
|
||||
return false;
|
||||
|
||||
if (crtc_vdisplay % intel_dp->psr.su_y_granularity)
|
||||
@@ -0,0 +1,60 @@
|
||||
From: Gaggery Tsai <gaggery.tsai@intel.com>
|
||||
Date: Thu, 10 Apr 2026 10:00:00 -0700
|
||||
Subject: [PATCH] drm/i915: send TRANS_PUSH Frame Change for Panel Replay cursor updates
|
||||
|
||||
Panel Replay Selective Update requires a software-triggered Frame
|
||||
Change event via TRANS_PUSH to send dirty regions to the panel.
|
||||
Cursor updates (legacy_cursor_update) skip TRANS_PUSH_SEND, so the
|
||||
panel never receives cursor position changes under Panel Replay SU.
|
||||
|
||||
Fix by sending TRANS_PUSH with LNL_TRANS_PUSH_PSR_PR_EN for cursor
|
||||
updates when Panel Replay is active.
|
||||
|
||||
Signed-off-by: Gaggery Tsai <gaggery.tsai@intel.com>
|
||||
---
|
||||
diff --git a/drivers/gpu/drm/i915/display/intel_vrr_regs.h b/drivers/gpu/drm/i915/display/intel_vrr_regs.h
|
||||
--- a/drivers/gpu/drm/i915/display/intel_vrr_regs.h
|
||||
+++ b/drivers/gpu/drm/i915/display/intel_vrr_regs.h
|
||||
@@ -97,6 +97,7 @@
|
||||
#define TRANS_PUSH(display, trans) _MMIO_TRANS2((display), (trans), _TRANS_PUSH_A)
|
||||
#define TRANS_PUSH_EN REG_BIT(31)
|
||||
#define TRANS_PUSH_SEND REG_BIT(30)
|
||||
+#define LNL_TRANS_PUSH_PSR_PR_EN REG_BIT(16)
|
||||
|
||||
#define _TRANS_VRR_VSYNC_A 0x60078
|
||||
#define TRANS_VRR_VSYNC(display, trans) _MMIO_TRANS2((display), (trans), _TRANS_VRR_VSYNC_A)
|
||||
diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c b/drivers/gpu/drm/i915/display/intel_crtc.c
|
||||
--- a/drivers/gpu/drm/i915/display/intel_crtc.c
|
||||
+++ b/drivers/gpu/drm/i915/display/intel_crtc.c
|
||||
@@ -732,7 +732,8 @@
|
||||
* which would cause the next frame to terminate already at vmin
|
||||
* vblank start instead of vmax vblank start.
|
||||
*/
|
||||
- if (!state->base.legacy_cursor_update)
|
||||
+ if (!state->base.legacy_cursor_update ||
|
||||
+ new_crtc_state->has_panel_replay)
|
||||
intel_vrr_send_push(NULL, new_crtc_state);
|
||||
|
||||
local_irq_enable();
|
||||
diff --git a/drivers/gpu/drm/i915/display/intel_vrr.c b/drivers/gpu/drm/i915/display/intel_vrr.c
|
||||
--- a/drivers/gpu/drm/i915/display/intel_vrr.c
|
||||
+++ b/drivers/gpu/drm/i915/display/intel_vrr.c
|
||||
@@ -597,7 +597,7 @@
|
||||
struct intel_display *display = to_intel_display(crtc_state);
|
||||
enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
|
||||
|
||||
- if (!crtc_state->vrr.enable)
|
||||
+ if (!crtc_state->vrr.enable && !crtc_state->has_panel_replay)
|
||||
return;
|
||||
|
||||
if (dsb)
|
||||
@@ -605,7 +605,8 @@
|
||||
|
||||
intel_de_write_dsb(display, dsb,
|
||||
TRANS_PUSH(display, cpu_transcoder),
|
||||
- TRANS_PUSH_EN | TRANS_PUSH_SEND);
|
||||
+ TRANS_PUSH_EN | TRANS_PUSH_SEND |
|
||||
+ (crtc_state->has_panel_replay ? LNL_TRANS_PUSH_PSR_PR_EN : 0));
|
||||
|
||||
if (dsb)
|
||||
intel_dsb_nonpost_end(dsb);
|
||||
@@ -0,0 +1,116 @@
|
||||
From: Gaggery Tsai <gaggery.tsai@intel.com>
|
||||
Date: Thu, 17 Apr 2026 10:30:00 -0700
|
||||
Subject: [PATCH] drm/i915/psr: exit Panel Replay during updates to work around ALPM lag
|
||||
|
||||
Panel Replay ALPM AUX-Less wake/sleep cycling cannot resume selective
|
||||
updates at frame rate on the LGD OLED panel in the Dell XPS 14
|
||||
DA14260. The panel's internal timing engine appears to need a
|
||||
per-frame timing beacon to resume quickly after ALPM sleep; without
|
||||
it, the source commits at 120 Hz but visible frames land around
|
||||
15 Hz.
|
||||
|
||||
Work around by temporarily exiting Panel Replay in
|
||||
frontbuffer_flush() before each frame update. Re-entry into PR (with
|
||||
ALPM) is deferred by 50 ms via dc3co_work so that during continuous
|
||||
motion the link stays on (cursor/video smooth), and PR re-engages
|
||||
after 50 ms of no further updates (idle power savings preserved).
|
||||
|
||||
The delay was chosen empirically:
|
||||
|
||||
| Delay | Idle (10x avg) | Cursor motion (3x avg) |
|
||||
|--------|----------------|------------------------|
|
||||
| 50 ms | 3268 mW | 8749 mW |
|
||||
| 100 ms | 3436 mW | 9088 mW |
|
||||
| 200 ms | 3484 mW | 9104 mW |
|
||||
| stock | 3384 mW | ~15 Hz visible lag |
|
||||
| PSR2 | 4060 mW | 9191 mW |
|
||||
|
||||
50 ms gives the best idle and cursor-motion power while remaining
|
||||
subjectively identical in smoothness to longer delays.
|
||||
|
||||
Repurpose the existing dc3co_work delayed_work as the re-entry timer:
|
||||
each frontbuffer_flush cancels+rearms it to 50 ms, and the work
|
||||
handler calls intel_psr_activate() when it fires.
|
||||
|
||||
Signed-off-by: Gaggery Tsai <gaggery.tsai@intel.com>
|
||||
---
|
||||
drivers/gpu/drm/i915/display/intel_frontbuffer.c | 1 +
|
||||
drivers/gpu/drm/i915/display/intel_psr.c | 33 ++++++++++++++++++
|
||||
drivers/gpu/drm/i915/display/intel_psr.h | 1 +
|
||||
3 files changed, 35 insertions(+)
|
||||
|
||||
--- a/drivers/gpu/drm/i915/display/intel_frontbuffer.c
|
||||
+++ b/drivers/gpu/drm/i915/display/intel_frontbuffer.c
|
||||
@@ -97,6 +97,7 @@ static void frontbuffer_flush(struct intel_display *display,
|
||||
might_sleep();
|
||||
intel_td_flush(display);
|
||||
intel_drrs_flush(display, frontbuffer_bits);
|
||||
+ intel_psr_panel_replay_exit(display);
|
||||
intel_psr_flush(display, frontbuffer_bits, origin);
|
||||
intel_fbc_flush(display, frontbuffer_bits, origin);
|
||||
}
|
||||
--- a/drivers/gpu/drm/i915/display/intel_psr.h
|
||||
+++ b/drivers/gpu/drm/i915/display/intel_psr.h
|
||||
@@ -40,6 +40,7 @@ int intel_psr_debug_set(struct intel_dp *intel_dp, u64 value);
|
||||
void intel_psr_invalidate(struct intel_display *display,
|
||||
unsigned frontbuffer_bits,
|
||||
enum fb_op_origin origin);
|
||||
+void intel_psr_panel_replay_exit(struct intel_display *display);
|
||||
void intel_psr_flush(struct intel_display *display,
|
||||
unsigned frontbuffer_bits,
|
||||
enum fb_op_origin origin);
|
||||
--- a/drivers/gpu/drm/i915/display/intel_psr.c
|
||||
+++ b/drivers/gpu/drm/i915/display/intel_psr.c
|
||||
@@ -1217,6 +1217,8 @@ static void tgl_psr2_enable_dc3co(struct intel_dp *intel_dp)
|
||||
psr2_program_idle_frames(intel_dp, psr_compute_idle_frames(intel_dp));
|
||||
}
|
||||
|
||||
+static void intel_psr_activate(struct intel_dp *intel_dp);
|
||||
+
|
||||
static void tgl_dc3co_disable_work(struct work_struct *work)
|
||||
{
|
||||
struct intel_dp *intel_dp =
|
||||
@@ -1227,6 +1229,13 @@ static void tgl_dc3co_disable_work(struct work_struct *work)
|
||||
if (delayed_work_pending(&intel_dp->psr.dc3co_work))
|
||||
goto unlock;
|
||||
|
||||
+ /* Panel Replay ALPM cursor-lag workaround re-activation path. */
|
||||
+ if (intel_dp->psr.panel_replay_enabled &&
|
||||
+ intel_dp->psr.enabled && !intel_dp->psr.active) {
|
||||
+ intel_psr_activate(intel_dp);
|
||||
+ goto unlock;
|
||||
+ }
|
||||
+
|
||||
tgl_psr2_disable_dc3co(intel_dp);
|
||||
unlock:
|
||||
mutex_unlock(&intel_dp->psr.lock);
|
||||
@@ -4593,2 +4593,29 @@ u8 intel_psr_needed_vblank_count_for_frontbuffer_flush(struct intel_display *dis
|
||||
return psr_min_guardband;
|
||||
}
|
||||
+
|
||||
+/*
|
||||
+ * intel_psr_panel_replay_exit - exit Panel Replay during frontbuffer activity
|
||||
+ *
|
||||
+ * Exits PR on frontbuffer flush and arms dc3co_work with a 50 ms
|
||||
+ * delay. Each subsequent flush cancels and rearms the timer. When it
|
||||
+ * finally fires, tgl_dc3co_disable_work re-activates PR.
|
||||
+ */
|
||||
+void intel_psr_panel_replay_exit(struct intel_display *display)
|
||||
+{
|
||||
+ struct intel_encoder *encoder;
|
||||
+
|
||||
+ for_each_intel_encoder_with_psr(display->drm, encoder) {
|
||||
+ struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
|
||||
+
|
||||
+ mutex_lock(&intel_dp->psr.lock);
|
||||
+ if (intel_dp->psr.panel_replay_enabled &&
|
||||
+ intel_dp->psr.sel_update_enabled) {
|
||||
+ if (intel_dp->psr.active)
|
||||
+ intel_psr_exit(intel_dp);
|
||||
+ mod_delayed_work(display->wq.unordered,
|
||||
+ &intel_dp->psr.dc3co_work,
|
||||
+ msecs_to_jiffies(50));
|
||||
+ }
|
||||
+ mutex_unlock(&intel_dp->psr.lock);
|
||||
+ }
|
||||
+}
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spencer Bull <spencer.bull@dell.com>
|
||||
Date: Mon, 30 Mar 2026 23:30:00 +0000
|
||||
Subject: [PATCH] drm/edid: populate monitor range from DisplayID adaptive sync
|
||||
|
||||
Some eDP OLED panels advertise a VRR range only via the DisplayID 2.x
|
||||
Adaptive Sync data block. In that case `display_info.monitor_range`
|
||||
stays at 0/0 because DRM currently only fills it from the legacy EDID
|
||||
monitor range descriptor.
|
||||
|
||||
Intel's VRR capability path consumes `display_info.monitor_range`
|
||||
directly, so the connector ends up with `vrr_capable=0` despite EDID
|
||||
advertising Adaptive Sync.
|
||||
|
||||
Backfill `monitor_range` from the DisplayID 2.x Adaptive Sync data
|
||||
block when the legacy descriptor did not provide a range.
|
||||
---
|
||||
drivers/gpu/drm/drm_displayid_internal.h | 1 +
|
||||
drivers/gpu/drm/drm_edid.c | 50 ++++++++++++++++++++++++++++++++++------
|
||||
2 files changed, 43 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/drm_displayid_internal.h
|
||||
+++ b/drivers/gpu/drm/drm_displayid_internal.h
|
||||
@@ -67,6 +67,7 @@
|
||||
#define DATA_BLOCK_2_TILED_DISPLAY_TOPOLOGY 0x28
|
||||
#define DATA_BLOCK_2_CONTAINER_ID 0x29
|
||||
#define DATA_BLOCK_2_TYPE_10_FORMULA_TIMING 0x2a
|
||||
+#define DATA_BLOCK_2_ADAPTIVE_SYNC 0x2b
|
||||
#define DATA_BLOCK_2_VENDOR_SPECIFIC 0x7e
|
||||
#define DATA_BLOCK_2_CTA_DISPLAY_ID 0x81
|
||||
|
||||
--- a/drivers/gpu/drm/drm_edid.c
|
||||
+++ b/drivers/gpu/drm/drm_edid.c
|
||||
@@ -6527,6 +6527,46 @@
|
||||
info->monitor_range.min_vfreq, info->monitor_range.max_vfreq);
|
||||
}
|
||||
|
||||
+#define DISPLAYID_ADAPTIVE_SYNC_DESC_SIZE 6
|
||||
+
|
||||
+static void drm_update_displayid_adaptive_sync_range(struct drm_connector *connector,
|
||||
+ const struct displayid_block *block)
|
||||
+{
|
||||
+ struct drm_monitor_range_info *range = &connector->display_info.monitor_range;
|
||||
+ const u8 *data = (const u8 *)(block + 1);
|
||||
+ u16 best_min = 0, best_max = 0;
|
||||
+ unsigned int best_span = 0;
|
||||
+ int i;
|
||||
+
|
||||
+ if (block->rev != 0 || block->num_bytes < DISPLAYID_ADAPTIVE_SYNC_DESC_SIZE ||
|
||||
+ block->num_bytes % DISPLAYID_ADAPTIVE_SYNC_DESC_SIZE)
|
||||
+ return;
|
||||
+
|
||||
+ for (i = 0; i < block->num_bytes; i += DISPLAYID_ADAPTIVE_SYNC_DESC_SIZE) {
|
||||
+ const u8 *desc = &data[i];
|
||||
+ u16 min_vfreq = desc[2];
|
||||
+ u16 max_vfreq = ((((u16)desc[4]) & 0x3) << 8) | desc[3];
|
||||
+ unsigned int span;
|
||||
+
|
||||
+ max_vfreq += 1;
|
||||
+ if (!min_vfreq || max_vfreq <= min_vfreq)
|
||||
+ continue;
|
||||
+
|
||||
+ span = max_vfreq - min_vfreq;
|
||||
+ if (span <= best_span)
|
||||
+ continue;
|
||||
+
|
||||
+ best_min = min_vfreq;
|
||||
+ best_max = max_vfreq;
|
||||
+ best_span = span;
|
||||
+ }
|
||||
+
|
||||
+ if (best_span) {
|
||||
+ range->min_vfreq = best_min;
|
||||
+ range->max_vfreq = best_max;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static void drm_parse_vesa_mso_data(struct drm_connector *connector,
|
||||
const struct displayid_block *block)
|
||||
{
|
||||
@@ -6648,26 +6688,41 @@
|
||||
{
|
||||
struct drm_display_info *info = &connector->display_info;
|
||||
const struct displayid_block *block;
|
||||
+ bool displayid_base_logged = false;
|
||||
struct displayid_iter iter;
|
||||
|
||||
displayid_iter_edid_begin(drm_edid, &iter);
|
||||
displayid_iter_for_each(block, &iter) {
|
||||
+ /*
|
||||
+ * Primary use is a DisplayID base section property, but later
|
||||
+ * blocks may still carry useful metadata like adaptive sync ranges.
|
||||
+ */
|
||||
+ if (!displayid_base_logged) {
|
||||
+ drm_dbg_kms(connector->dev,
|
||||
+ "[CONNECTOR:%d:%s] DisplayID extension version 0x%02x, primary use 0x%02x\n",
|
||||
+ connector->base.id, connector->name,
|
||||
+ displayid_version(&iter),
|
||||
+ displayid_primary_use(&iter));
|
||||
+ if (displayid_version(&iter) == DISPLAY_ID_STRUCTURE_VER_20 &&
|
||||
+ (displayid_primary_use(&iter) == PRIMARY_USE_HEAD_MOUNTED_VR ||
|
||||
+ displayid_primary_use(&iter) == PRIMARY_USE_HEAD_MOUNTED_AR))
|
||||
+ info->non_desktop = true;
|
||||
+
|
||||
+ displayid_base_logged = true;
|
||||
+ }
|
||||
+
|
||||
+ if (!info->monitor_range.min_vfreq && !info->monitor_range.max_vfreq &&
|
||||
+ block->tag == DATA_BLOCK_2_ADAPTIVE_SYNC)
|
||||
+ drm_update_displayid_adaptive_sync_range(connector, block);
|
||||
+ }
|
||||
+
|
||||
+ if (info->monitor_range.min_vfreq && info->monitor_range.max_vfreq)
|
||||
drm_dbg_kms(connector->dev,
|
||||
- "[CONNECTOR:%d:%s] DisplayID extension version 0x%02x, primary use 0x%02x\n",
|
||||
+ "[CONNECTOR:%d:%s] DisplayID adaptive sync refresh rate range is %d Hz - %d Hz\n",
|
||||
connector->base.id, connector->name,
|
||||
- displayid_version(&iter),
|
||||
- displayid_primary_use(&iter));
|
||||
- if (displayid_version(&iter) == DISPLAY_ID_STRUCTURE_VER_20 &&
|
||||
- (displayid_primary_use(&iter) == PRIMARY_USE_HEAD_MOUNTED_VR ||
|
||||
- displayid_primary_use(&iter) == PRIMARY_USE_HEAD_MOUNTED_AR))
|
||||
- info->non_desktop = true;
|
||||
-
|
||||
- /*
|
||||
- * We're only interested in the base section here, no need to
|
||||
- * iterate further.
|
||||
- */
|
||||
- break;
|
||||
- }
|
||||
+ info->monitor_range.min_vfreq,
|
||||
+ info->monitor_range.max_vfreq);
|
||||
+
|
||||
displayid_iter_end(&iter);
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
|
||||
pkgbase=linux-ptl
|
||||
pkgver=6.19.10.arch1
|
||||
pkgrel=1
|
||||
pkgdesc='Linux with Panther Lake hardware backports (SDCA audio, WiFi 7)'
|
||||
pkgrel=3
|
||||
pkgdesc='Linux with Panther Lake hardware backports (SDCA audio, WiFi 7, PSR2, Panel Replay SU)'
|
||||
url='https://github.com/archlinux/linux'
|
||||
arch=(
|
||||
x86_64
|
||||
@@ -43,6 +43,13 @@ source=(
|
||||
0014-ASoC-SDCA-Limit-values-user-can-write-to-Selected-Mo.patch
|
||||
0017-ASoC-SDCA-Fix-NULL-pointer-dereference-in-sdca_jack_.patch
|
||||
0018-wifi-iwlwifi-mld-correctly-set-wifi-generation-data.patch
|
||||
0019-drm-i915-psr-accept-early-transport-for-psr2.patch
|
||||
0020-drm-i915-psr-fix-su-granularity-source-for-psr2.patch
|
||||
0022-drm-i915-psr-allow-psr-with-vrr-on-ptl.patch
|
||||
0026-drm-i915-psr-handle-Panel-Replay-full-line-SU-granul.patch
|
||||
0027-drm-i915-trans-push-frame-change-for-panel-replay.patch
|
||||
0028-drm-i915-psr-exit-Panel-Replay-for-ALPM-lag.patch
|
||||
0029-drm-edid-populate-monitor-range-from-displayid-adaptive-sync.patch
|
||||
)
|
||||
source_x86_64=(config.x86_64)
|
||||
validpgpkeys=(
|
||||
@@ -55,8 +62,9 @@ b2sums=('f91cdd0b8727ce50ba286b321e85f394ff7e2eff27cde6e6e85e8abfc627b2b069bb567
|
||||
'9632ace64efb38ee784d731ea85aeb285f0c3db486112122c17059c359c490a54c6ef7cd9d1d1cdecc8ae1d43df94536890b83a6671c1166a6b2148308f1baf3'
|
||||
'SKIP'
|
||||
'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP'
|
||||
'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP')
|
||||
b2sums_x86_64=('0fe195286246b83f0859f79dd2f6c633f5370057aa6afad4525309822ade855f7f6ebcfb01109786313c9331ad61d667b0257ecc7b7f239d2f962c9d34f0b10d')
|
||||
'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP'
|
||||
'SKIP' 'SKIP' 'SKIP' 'SKIP')
|
||||
b2sums_x86_64=('9742088ab0381d8196046e42e8acb4ce01ea77461fada77dc90d197e859631e73b06ead4d512f15ab619b33ebad7bca58a10d4506d66916a99c40f9f52708a53')
|
||||
|
||||
# https://www.kernel.org/pub/linux/kernel/v6.x/sha256sums.asc
|
||||
sha256sums=('466d441a0ea5e04b7023618b7b201bfd60effab225f806fd41ce663484395a1c'
|
||||
@@ -64,7 +72,8 @@ sha256sums=('466d441a0ea5e04b7023618b7b201bfd60effab225f806fd41ce663484395a1c'
|
||||
'96410b474e9b3efc2e03e5bb8e3819f41313e943f2157c215094668200cb069d'
|
||||
'SKIP'
|
||||
'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP'
|
||||
'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP')
|
||||
'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP'
|
||||
'SKIP' 'SKIP' 'SKIP' 'SKIP')
|
||||
|
||||
export KBUILD_BUILD_HOST=archlinux
|
||||
export KBUILD_BUILD_USER=$pkgbase
|
||||
|
||||
@@ -5202,7 +5202,7 @@ CONFIG_PINCTRL_BAYTRAIL=y
|
||||
CONFIG_PINCTRL_CHERRYVIEW=y
|
||||
CONFIG_PINCTRL_LYNXPOINT=m
|
||||
CONFIG_PINCTRL_INTEL=y
|
||||
CONFIG_PINCTRL_INTEL_PLATFORM=m
|
||||
CONFIG_PINCTRL_INTEL_PLATFORM=y
|
||||
CONFIG_PINCTRL_ALDERLAKE=m
|
||||
CONFIG_PINCTRL_BROXTON=m
|
||||
CONFIG_PINCTRL_CANNONLAKE=m
|
||||
@@ -11316,9 +11316,9 @@ CONFIG_UDF_FS=m
|
||||
#
|
||||
# DOS/FAT/EXFAT/NT Filesystems
|
||||
#
|
||||
CONFIG_FAT_FS=m
|
||||
CONFIG_MSDOS_FS=m
|
||||
CONFIG_VFAT_FS=m
|
||||
CONFIG_FAT_FS=y
|
||||
CONFIG_MSDOS_FS=y
|
||||
CONFIG_VFAT_FS=y
|
||||
CONFIG_FAT_DEFAULT_CODEPAGE=437
|
||||
CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
|
||||
CONFIG_FAT_DEFAULT_UTF8=y
|
||||
@@ -11567,7 +11567,7 @@ CONFIG_NLS_ISO8859_8=m
|
||||
CONFIG_NLS_CODEPAGE_1250=m
|
||||
CONFIG_NLS_CODEPAGE_1251=m
|
||||
CONFIG_NLS_ASCII=y
|
||||
CONFIG_NLS_ISO8859_1=m
|
||||
CONFIG_NLS_ISO8859_1=y
|
||||
CONFIG_NLS_ISO8859_2=m
|
||||
CONFIG_NLS_ISO8859_3=m
|
||||
CONFIG_NLS_ISO8859_4=m
|
||||
|
||||
Reference in New Issue
Block a user