linux-ptl

This commit is contained in:
Ryan Hughes committed 2026-05-08 01:04:51 -04:00
1 parent f5c8c1a97b
commit 6df117702c
10 files changed
+3

No files matched your search

@@ -0,0 +1,3 @@
{
"source": "local"
}
@@ -0,0 +1,43 @@
From 849489b94fe35172a4fea6e09acabacd273d8993 Mon Sep 17 00:00:00 2001
From: TsaiGaggery <gaggery.tsai@intel.com>
Date: Wed, 11 Mar 2026 14:21:39 -0700
Subject: [PATCH 17/17] ASoC: SDCA: Fix NULL pointer dereference in
sdca_jack_process()
Add NULL guard for card and card->snd_card before dereferencing.
During card teardown, component->card can be NULL when an IRQ fires.
---
sound/soc/sdca/sdca_jack.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/sound/soc/sdca/sdca_jack.c b/sound/soc/sdca/sdca_jack.c
index 605514f02045..04ff391aa7bc 100644
--- a/sound/soc/sdca/sdca_jack.c
+++ b/sound/soc/sdca/sdca_jack.c
@@ -37,13 +37,21 @@ int sdca_jack_process(struct sdca_interrupt *interrupt)
struct device *dev = interrupt->dev;
struct snd_soc_component *component = interrupt->component;
struct snd_soc_card *card = component->card;
- struct rw_semaphore *rwsem = &card->snd_card->controls_rwsem;
+ struct rw_semaphore *rwsem;
struct jack_state *state = interrupt->priv;
- struct snd_kcontrol *kctl = state->kctl;
+ struct snd_kcontrol *kctl;
struct snd_ctl_elem_value *ucontrol __free(kfree) = NULL;
unsigned int reg, val;
int ret;
+ if (!card || !card->snd_card) {
+ dev_dbg(dev, "card not yet bound, deferring jack event\n");
+ return -ENODEV;
+ }
+
+ rwsem = &card->snd_card->controls_rwsem;
+ kctl = state->kctl;
+
guard(rwsem_write)(rwsem);
if (!kctl) {
--
2.43.0
@@ -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
+++ b/drivers/gpu/drm/i915/display/intel_psr.c
@@ -700,8 +700,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.
*/
- connector->dp.psr_caps.su_support = y_req &&
+ connector->dp.psr_caps.su_support =
+ (y_req || connector->dp.psr_caps.dpcd[0] ==
+ DP_PSR2_WITH_Y_COORD_ET_SUPPORTED) &&
intel_alpm_aux_wake_supported(intel_dp);
drm_dbg_kms(display->drm, "PSR2 %ssupported\n",
connector->dp.psr_caps.su_support ? "" : "not ");
@@ -0,0 +1,39 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Gaggery Tsai <gaggery.tsai@intel.com>
Date: Tue, 28 Apr 2026 15:00:00 -0500
Subject: [PATCH] drm/i915/alpm: limit Panel Replay ALPM programming to PR
Linux 7 already carries the Panel Replay/PSR selective-update
granularity fixes from the old linux-ptl 0020 patch. Keep only the
remaining ALPM fix: avoid programming PR-specific ALPM controls when
Panel Replay is not active, and use the common helper for aux-less ALPM
selection.
Signed-off-by: Gaggery Tsai <gaggery.tsai@intel.com>
---
drivers/gpu/drm/i915/display/intel_alpm.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git 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
+++ b/drivers/gpu/drm/i915/display/intel_alpm.c
@@ -317,7 +317,7 @@ static void lnl_alpm_configure(struct intel_dp *intel_dp,
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 (crtc_state->link_off_after_as_sdp_when_pr_active)
@@ -432,8 +432,8 @@ void intel_alpm_enable_sink(struct intel_dp *intel_dp,
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);
@@ -0,0 +1,37 @@
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
@@ -1708,13 +1708,7 @@ 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, conn_state, adjusted_mode);
if (entry_setup_frames >= 0) {
crtc_state->entry_setup_frames = entry_setup_frames;
@@ -0,0 +1,198 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Gaggery Tsai <gaggery.tsai@intel.com>
Date: Tue, 28 Apr 2026 16:10:00 -0500
Subject: [PATCH] drm/i915: use TRANS_PUSH frame changes for Panel Replay
Panel Replay Selective Update requires a software-triggered Frame Change
event via TRANS_PUSH to send dirty regions to the panel. Cursor updates
can skip the normal VRR push path, so the panel may not receive cursor
position changes under Panel Replay SU.
Backport the upstream TRANS_PUSH frame-change flow for display 20+,
but keep it limited to Panel Replay for linux-ptl. Plain PSR2 must keep
using the old CURSURFLIVE frame-change path so systems still boot when
Panel Replay is disabled with xe.enable_panel_replay=0.
Signed-off-by: Gaggery Tsai <gaggery.tsai@intel.com>
---
drivers/gpu/drm/i915/display/intel_crtc.c | 4 +++-
drivers/gpu/drm/i915/display/intel_display_device.h | 1 +
drivers/gpu/drm/i915/display/intel_psr.c | 20 +++++++++++++++++---
drivers/gpu/drm/i915/display/intel_psr.h | 1 +
drivers/gpu/drm/i915/display/intel_vrr.c | 35 +++++++++++++++++++++++++++++------
drivers/gpu/drm/i915/display/intel_vrr.h | 1 +
drivers/gpu/drm/i915/display/intel_vrr_regs.h | 1 +
7 files changed, 53 insertions(+), 10 deletions(-)
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
@@ -747,7 +747,9 @@ void intel_pipe_update_end(struct intel_atomic_state *state,
* push to affect the next frame instead of the current frame,
* 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 ||
+ (intel_psr_use_trans_push(new_crtc_state) &&
+ !new_crtc_state->vrr.enable))
intel_vrr_send_push(NULL, new_crtc_state);
local_irq_enable();
diff --git a/drivers/gpu/drm/i915/display/intel_display_device.h b/drivers/gpu/drm/i915/display/intel_display_device.h
--- a/drivers/gpu/drm/i915/display/intel_display_device.h
+++ b/drivers/gpu/drm/i915/display/intel_display_device.h
@@ -186,6 +186,7 @@ struct intel_display_platforms {
#define HAS_PSR(__display) (DISPLAY_INFO(__display)->has_psr)
#define HAS_PSR_HW_TRACKING(__display) (DISPLAY_INFO(__display)->has_psr_hw_tracking)
#define HAS_PSR2_SEL_FETCH(__display) (DISPLAY_VER(__display) >= 12)
+#define HAS_PSR_TRANS_PUSH_FRAME_CHANGE(__display) (DISPLAY_VER(__display) >= 20)
#define HAS_SAGV(__display) (DISPLAY_VER(__display) >= 9 && \
!(__display)->platform.broxton && !(__display)->platform.geminilake)
#define HAS_TRANSCODER(__display, trans) ((DISPLAY_RUNTIME_INFO(__display)->cpu_transcoder_mask & \
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
@@ -2130,5 +2130,8 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp,
intel_alpm_configure(intel_dp, crtc_state);
+
+ if (intel_psr_use_trans_push(crtc_state))
+ intel_vrr_psr_frame_change_enable(crtc_state);
}
static bool psr_interrupt_error_check(struct intel_dp *intel_dp)
@@ -2522,10 +2525,12 @@ void intel_psr_trigger_frame_change_event(struct intel_dsb *dsb,
const struct intel_crtc_state *crtc_state =
intel_pre_commit_crtc_state(state, crtc);
struct intel_display *display = to_intel_display(crtc);
- if (crtc_state->has_psr)
- intel_de_write_dsb(display, dsb,
- CURSURFLIVE(display, crtc->pipe), 0);
+ if (!crtc_state->has_psr || intel_psr_use_trans_push(crtc_state))
+ return;
+
+ intel_de_write_dsb(display, dsb,
+ CURSURFLIVE(display, crtc->pipe), 0);
}
/**
@@ -4615,3 +4620,10 @@ int intel_psr_min_guardband(struct intel_crtc_state *crtc_state)
return psr_min_guardband;
}
+
+bool intel_psr_use_trans_push(const struct intel_crtc_state *crtc_state)
+{
+ struct intel_display *display = to_intel_display(crtc_state);
+
+ return HAS_PSR_TRANS_PUSH_FRAME_CHANGE(display) && crtc_state->has_panel_replay;
+}
diff --git a/drivers/gpu/drm/i915/display/intel_psr.h b/drivers/gpu/drm/i915/display/intel_psr.h
--- a/drivers/gpu/drm/i915/display/intel_psr.h
+++ b/drivers/gpu/drm/i915/display/intel_psr.h
@@ -80,5 +80,6 @@ bool intel_psr_needs_alpm_aux_less(struct intel_dp *intel_dp,
void intel_psr_compute_config_late(struct intel_dp *intel_dp,
struct intel_crtc_state *crtc_state);
int intel_psr_min_guardband(struct intel_crtc_state *crtc_state);
+bool intel_psr_use_trans_push(const struct intel_crtc_state *crtc_state);
#endif /* __INTEL_PSR_H__ */
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
@@ -688,21 +688,40 @@ intel_vrr_dcb_reset(const struct intel_crtc_state *old_crtc_state,
intel_de_write(display, PIPEDMC_DCB_BALANCE_RESET(pipe), 0);
}
+static u32 trans_vrr_push(const struct intel_crtc_state *crtc_state,
+ bool send_push)
+{
+ struct intel_display *display = to_intel_display(crtc_state);
+ u32 trans_vrr_push = 0;
+
+ if (intel_vrr_always_use_vrr_tg(display) ||
+ crtc_state->vrr.enable)
+ trans_vrr_push |= TRANS_PUSH_EN;
+
+ if (send_push)
+ trans_vrr_push |= TRANS_PUSH_SEND;
+
+ if (intel_psr_use_trans_push(crtc_state))
+ trans_vrr_push |= LNL_TRANS_PUSH_PSR_PR_EN;
+
+ return trans_vrr_push;
+}
+
void intel_vrr_send_push(struct intel_dsb *dsb,
const struct intel_crtc_state *crtc_state)
{
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 && !intel_psr_use_trans_push(crtc_state))
return;
if (dsb)
intel_dsb_nonpost_start(dsb);
intel_de_write_dsb(display, dsb,
TRANS_PUSH(display, cpu_transcoder),
- TRANS_PUSH_EN | TRANS_PUSH_SEND);
+ trans_vrr_push(crtc_state, true));
if (dsb)
intel_dsb_nonpost_end(dsb);
@@ -888,7 +907,8 @@ static void intel_vrr_tg_enable(const struct intel_crtc_state *crtc_state,
enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
u32 vrr_ctl;
- intel_de_write(display, TRANS_PUSH(display, cpu_transcoder), TRANS_PUSH_EN);
+ intel_de_write(display, TRANS_PUSH(display, cpu_transcoder),
+ trans_vrr_push(crtc_state, false));
vrr_ctl = VRR_CTL_VRR_ENABLE | trans_vrr_ctl(crtc_state);
@@ -919,1 +939,2 @@ static void intel_vrr_tg_disable(const struct intel_crtc_state *old_crtc_state)
- intel_de_write(display, TRANS_PUSH(display, cpu_transcoder), 0);
+ intel_de_rmw(display, TRANS_PUSH(display, cpu_transcoder),
+ TRANS_PUSH_EN, 0);
@@ -970,6 +991,15 @@ void intel_vrr_transcoder_disable(const struct intel_crtc_state *old_crtc_state)
intel_vrr_tg_disable(old_crtc_state);
}
+void intel_vrr_psr_frame_change_enable(const struct intel_crtc_state *crtc_state)
+{
+ struct intel_display *display = to_intel_display(crtc_state);
+ enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
+
+ intel_de_write(display, TRANS_PUSH(display, cpu_transcoder),
+ trans_vrr_push(crtc_state, false));
+}
+
bool intel_vrr_is_fixed_rr(const struct intel_crtc_state *crtc_state)
{
return crtc_state->vrr.flipline &&
diff --git a/drivers/gpu/drm/i915/display/intel_vrr.h b/drivers/gpu/drm/i915/display/intel_vrr.h
--- a/drivers/gpu/drm/i915/display/intel_vrr.h
+++ b/drivers/gpu/drm/i915/display/intel_vrr.h
@@ -30,5 +30,6 @@ void intel_vrr_dcb_increment_flip_count(struct intel_crtc_state *crtc_state,
bool intel_vrr_is_push_sent(const struct intel_crtc_state *crtc_state);
void intel_vrr_disable(const struct intel_crtc_state *old_crtc_state);
+void intel_vrr_psr_frame_change_enable(const struct intel_crtc_state *crtc_state);
void intel_vrr_get_config(struct intel_crtc_state *crtc_state);
int intel_vrr_vmax_vtotal(const struct intel_crtc_state *crtc_state);
int intel_vrr_vmin_vtotal(const struct intel_crtc_state *crtc_state);
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
@@ -163,6 +163,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)
@@ -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
@@ -1189,6 +1189,8 @@ static void tgl_psr2_disable_dc3co(struct intel_dp *intel_dp)
intel_display_power_set_target_dc_state(display, DC_STATE_EN_UPTO_DC6);
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)
{
@@ -1203,6 +1205,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);
@@ -4615,2 +4624,29 @@ int intel_psr_min_guardband(struct intel_crtc_state *crtc_state)
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);
+ }
+}
@@ -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);
}
+273
View File
@@ -0,0 +1,273 @@
# Maintainer: Gaggory Tsai <gaggery.tsai@intel.com> Spencer Bull <Spencer.Bull@Dell.com>
# Based on Arch Linux linux package by Jan Alexander Steffens (heftig)
pkgbase=linux-ptl
pkgver=7.0.3.arch1
pkgrel=2
pkgdesc='Linux with Panther Lake hardware backports (SDCA audio, PSR2, Panel Replay SU)'
url='https://github.com/archlinux/linux'
arch=(
x86_64
)
license=(GPL-2.0-only)
makedepends=(
bc
cpio
gettext
libelf
pahole
perl
python
tar
xz
)
options=(
!debug
!strip
)
_srcname=linux-${pkgver%.*}
_srctag=v${pkgver%.*}-${pkgver##*.}
source=(
https://cdn.kernel.org/pub/linux/kernel/v${pkgver%%.*}.x/${_srcname}.tar.{xz,sign}
$url/releases/download/$_srctag/linux-$_srctag.patch.zst{,.sig}
0017-ASoC-SDCA-Fix-NULL-pointer-dereference-in-sdca_jack_.patch
0019-drm-i915-psr-accept-early-transport-for-psr2.patch
0020-drm-i915-alpm-limit-pr-alpm-to-panel-replay.patch
0022-drm-i915-psr-allow-psr-with-vrr-on-ptl.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=(
ABAF11C65A2970B130ABE3C479BE3E4300411886 # Linus Torvalds
647F28654894E3BD457199BE38DBBDC86092693E # Greg Kroah-Hartman
83BC8889351B5DEBBB68416EB8AC08600F108CDF # Jan Alexander Steffens (heftig)
)
b2sums=('SKIP'
'SKIP'
'SKIP'
'SKIP'
'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP')
b2sums_x86_64=('9742088ab0381d8196046e42e8acb4ce01ea77461fada77dc90d197e859631e73b06ead4d512f15ab619b33ebad7bca58a10d4506d66916a99c40f9f52708a53')
# https://www.kernel.org/pub/linux/kernel/v7.x/sha256sums.asc
sha256sums=('0bedadbf5788693ddebbcc913c893f1a97349af79ddde7144c2a80b401959f1c'
'SKIP'
'SKIP'
'SKIP'
'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP')
export KBUILD_BUILD_HOST=archlinux
export KBUILD_BUILD_USER=$pkgbase
export KBUILD_BUILD_TIMESTAMP="$(date -Ru${SOURCE_DATE_EPOCH:+d @$SOURCE_DATE_EPOCH})"
prepare() {
cd $_srcname
echo "Setting version..."
echo "-$pkgrel" > localversion.10-pkgrel
echo "${pkgbase#linux}" > localversion.20-pkgname
local src
for src in "${source[@]}"; do
src="${src%%::*}"
src="${src##*/}"
src="${src%.zst}"
[[ $src = *.patch ]] || continue
echo "Applying patch $src..."
patch -Np1 < "../$src"
done
echo "Setting config..."
cp ../config.$CARCH .config
make olddefconfig
diff -u ../config.$CARCH .config || :
make -s kernelrelease > version
echo "Prepared $pkgbase version $(<version)"
}
build() {
cd $_srcname
make all
make -C tools/bpf/bpftool vmlinux.h feature-clang-bpf-co-re=1
}
_package() {
pkgdesc="The $pkgdesc kernel and modules"
depends=(
coreutils
initramfs
kmod
sof-firmware
)
optdepends=(
"$pkgbase-headers: headers and scripts for building modules"
'linux-firmware: firmware images needed for some devices'
'scx-scheds: to use sched-ext schedulers'
'wireless-regdb: to set the correct wireless channels of your country'
)
provides=(
KSMBD-MODULE
NTSYNC-MODULE
VIRTUALBOX-GUEST-MODULES
WIREGUARD-MODULE
)
replaces=(
virtualbox-guest-modules-arch
wireguard-arch
)
cd $_srcname
local modulesdir="$pkgdir/usr/lib/modules/$(<version)"
echo "Installing boot image..."
# systemd expects to find the kernel here to allow hibernation
# https://github.com/systemd/systemd/commit/edda44605f06a41fb86b7ab8128dcf99161d2344
install -Dm644 "$(make -s image_name)" "$modulesdir/vmlinuz"
# Used by mkinitcpio to name the kernel
echo "$pkgbase" | install -Dm644 /dev/stdin "$modulesdir/pkgbase"
echo "Installing modules..."
ZSTD_CLEVEL=19 make INSTALL_MOD_PATH="$pkgdir/usr" INSTALL_MOD_STRIP=1 \
DEPMOD=/doesnt/exist modules_install # Suppress depmod
# remove build link
rm "$modulesdir"/build
}
_package-headers() {
pkgdesc="Headers and scripts for building modules for the $pkgdesc kernel"
depends=(pahole)
provides=(LINUX-HEADERS)
cd $_srcname
local builddir="$pkgdir/usr/lib/modules/$(<version)/build"
local karch
case $CARCH in
x86_64) karch=x86 ;;
*) echo "Unknown CARCH $CARCH"; exit 1 ;;
esac
echo "Installing build files..."
install -Dt "$builddir" -m644 .config Makefile Module.symvers System.map \
localversion.* version vmlinux tools/bpf/bpftool/vmlinux.h
install -Dt "$builddir/kernel" -m644 kernel/Makefile
install -Dt "$builddir/arch/$karch" -m644 arch/$karch/Makefile
cp -t "$builddir" -a scripts
ln -srt "$builddir" "$builddir/scripts/gdb/vmlinux-gdb.py"
if [[ $(scripts/config -s CONFIG_HAVE_STACK_VALIDATION) = y ]]; then
install -Dt "$builddir/tools/objtool" tools/objtool/objtool
fi
if [[ $(scripts/config -s CONFIG_DEBUG_INFO_BTF_MODULES) = y ]]; then
install -Dt "$builddir/tools/bpf/resolve_btfids" tools/bpf/resolve_btfids/resolve_btfids
fi
echo "Installing headers..."
cp -t "$builddir" -a include
cp -t "$builddir/arch/$karch" -a arch/$karch/include
install -Dt "$builddir/arch/$karch/kernel" -m644 arch/$karch/kernel/asm-offsets.s
install -Dt "$builddir/drivers/md" -m644 drivers/md/*.h
install -Dt "$builddir/net/mac80211" -m644 net/mac80211/*.h
# https://bugs.archlinux.org/task/13146
install -Dt "$builddir/drivers/media/i2c" -m644 drivers/media/i2c/msp3400-driver.h
# https://bugs.archlinux.org/task/20402
install -Dt "$builddir/drivers/media/usb/dvb-usb" -m644 drivers/media/usb/dvb-usb/*.h
install -Dt "$builddir/drivers/media/dvb-frontends" -m644 drivers/media/dvb-frontends/*.h
install -Dt "$builddir/drivers/media/tuners" -m644 drivers/media/tuners/*.h
# https://bugs.archlinux.org/task/71392
install -Dt "$builddir/drivers/iio/common/hid-sensors" -m644 drivers/iio/common/hid-sensors/*.h
echo "Installing KConfig files..."
find . -name 'Kconfig*' -exec install -Dm644 {} "$builddir/{}" \;
echo "Installing Rust files..."
if [[ $(scripts/config -s CONFIG_RUST) = y ]]; then
install -Dt "$builddir/rust" -m644 rust/*.rmeta
install -Dt "$builddir/rust" rust/*.so
fi
echo "Installing unstripped VDSO..."
make INSTALL_MOD_PATH="$pkgdir/usr" vdso_install \
link= # Suppress build-id symlinks
echo "Removing unneeded architectures..."
local arch
for arch in "$builddir"/arch/*/; do
[[ $arch = */$karch/ ]] && continue
echo "Removing $(basename "$arch")"
rm -r "$arch"
done
echo "Removing documentation..."
rm -r "$builddir/Documentation"
echo "Removing broken symlinks..."
find -L "$builddir" -type l -printf 'Removing %P\n' -delete
echo "Removing loose objects..."
find "$builddir" -type f -name '*.o' -printf 'Removing %P\n' -delete
echo "Stripping build tools..."
local file
while read -rd '' file; do
case "$(file -Sib "$file")" in
application/x-sharedlib\;*) # Libraries (.so)
strip -v $STRIP_SHARED "$file" ;;
application/x-archive\;*) # Libraries (.a)
strip -v $STRIP_STATIC "$file" ;;
application/x-executable\;*) # Binaries
strip -v $STRIP_BINARIES "$file" ;;
application/x-pie-executable\;*) # Relocatable binaries
strip -v $STRIP_SHARED "$file" ;;
esac
done < <(find "$builddir" -type f -perm -u+x ! -name vmlinux -print0)
echo "Stripping vmlinux..."
strip -v $STRIP_STATIC "$builddir/vmlinux"
echo "Adding symlink..."
mkdir -p "$pkgdir/usr/src"
ln -sr "$builddir" "$pkgdir/usr/src/$pkgbase"
}
_package-docs() {
pkgdesc="Documentation for the $pkgdesc kernel"
cd $_srcname
local builddir="$pkgdir/usr/lib/modules/$(<version)/build"
echo "Installing documentation..."
local src dst
while read -rd '' src; do
dst="${src#Documentation/}"
dst="$builddir/Documentation/${dst#output/}"
install -Dm644 "$src" "$dst"
done < <(find Documentation -name '.*' -prune -o ! -type d -print0)
echo "Adding symlink..."
mkdir -p "$pkgdir/usr/share/doc"
ln -sr "$builddir/Documentation" "$pkgdir/usr/share/doc/$pkgbase"
}
pkgname=(
"$pkgbase"
"$pkgbase-headers"
)
for _p in "${pkgname[@]}"; do
eval "package_$_p() {
$(declare -f "_package${_p#$pkgbase}")
_package${_p#$pkgbase}
}"
done
# vim:set ts=8 sts=2 sw=2 et:
File diff suppressed because it is too large. Load diff