Files
omarchy-pkgs/pkgbuilds/edge/linux-ptl/0029-drm-edid-populate-monitor-range-from-displayid-adaptive-sync.patch
T
49214baae5 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>
2026-04-21 14:39:32 +02:00

137 lines
4.6 KiB
Diff

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