From nobody Fri Sep 25 23:53:49 2026 Received: from sirius.syn-flut.de (sirius.syn-flut.de [94.125.25.230]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D5E7F43E06C for ; Mon, 7 Sep 2026 08:38:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=94.125.25.230 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788770305; cv=none; b=L7/6dmyQpuswb1L8cmoeW9unj/ex666tFWXta++nweDwtV5ZEdg9azYvw83tdCS8PHY39bYxsaJENcLm3X+55U5BSQNFV2Pxxw/axsci4tAb5n6Imr2CUfT4wpV1KKx3XFesaF4gFPu5CkNKelwHhMDG8F2Y5smspvVyNixnO6U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788770305; c=relaxed/simple; bh=xygLG76U0h94SDRfK2YHSUeetGedPykra6eCxmuqrkk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=l3q55HPqSaDvJ6Aiv84Ujyux6z7PWy62T+YnNqPaCvNMQ9rOoKWnKbJB6HsTp36KdGkJoeo1ScPRFFX6jtGmiB8SU/564sQ7WGUANcljPrW+zWNcbJd+5rwGouGOgZkKmjv3EGma0OctEv20VS6la2fHkGFuXAVnMdjHRvdWWJI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=kait2en.org; spf=pass smtp.mailfrom=kait2en.org; dkim=pass (2048-bit key) header.d=kait2en.org header.i=@kait2en.org header.b=D2VBVzHw; arc=none smtp.client-ip=94.125.25.230 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=kait2en.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=kait2en.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kait2en.org header.i=@kait2en.org header.b="D2VBVzHw" Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id C8ADB14032D; Mon, 07 Sep 2026 10:38:11 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kait2en.org; s=dkim; t=1788770294; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=rGVy4LdSYtb6djDFSbxfe1Wr7YV8BFvvYCIThCOYRTA=; b=D2VBVzHw5230cLgemWIY1yoxhReWZ2glJx2FSsLIQ47YnqKqEdFOlbIV4lrYgNGtbL+hKQ TvCi4v3T2GxIrT5S1qQ0NunRvRiEC6RBxtJaY3UYHnNO0NuqoIVObYLX0f1B1ZMmfoHO3X kDaHx5PbomWcy+NBv7qomM+YILUEx5WKzKBfrWzs8EVwhHzk3q1wImTQ+Ov9X0ckg9m8AW GhIccfm30V2ekvTH/vNQbANJnbjvEio/NGe0qqYKE1+leXuXzAjuiX86icB9rj95ji9vEa /L+94/2DkHSQenCNlci7IWgG0iutmKjH7PtHXxxhT8sCpHIZ4FSifI0Y/C6hTA== From: Alexander Fischer To: intel-gfx@lists.freedesktop.org Cc: intel-xe@lists.freedesktop.org, dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, Lukas Wunner , Jani Nikula , Rodrigo Vivi , Joonas Lahtinen , Tvrtko Ursulin , David Airlie , Simona Vetter , =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= , =?UTF-8?q?Andr=C3=A9=20Eikmeyer?= , Yossef Osman , Alexander Fischer Subject: [PATCH v2] drm/i915/psr: enable PSR on Apple T2 eDP panels Date: Mon, 7 Sep 2026 10:37:53 +0200 Message-ID: <20260907083753.41393-1-alexander.fischer@kait2en.org> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260829161622.11396-1-alexander.fischer@kait2en.org> References: <20260829161622.11396-1-alexander.fischer@kait2en.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-Last-TLS-Session-Version: TLSv1.3 Commit 1035f4a65f58 ("drm/i915: Disable PSR in Apple panels") disabled PSR on all Apple sinks until i915 gained the required panel handling. An AUX trace on a MacBookPro16,2 running macOS 15.7.7 shows the following writes when the panel is powered on: DPCD 0x321 =3D 0x3c DPCD 0x4d2 =3D 0x01 DPCD 0x4d1 =3D 0x03 DPCD 0x170 =3D 0x01 (DP_PSR_ENABLE without CRC verification) Five seconds later, a write of 0x01 to DPCD 0x4d4 occurs between the BanksiaTcon FIFOEnter() and SRDEnter() events. This register is the vendor trigger for entering self refresh. With the three setup writes, CRC verification disabled, and the 0x4d4 trigger added to i915's existing PSR enable sequence, the tested panels enter PSR1. Implement this handling as an i915 DPCD quirk. Limit it to Apple-OUI eDP sinks on systems containing an Apple T2. All other Apple sinks retain the existing NO_PSR quirk. Override the VBT PSR flag for matching panels because Apple leaves it clear. The same sink-side protocol may also be present on T1 and Apple silicon systems, but leave those systems unchanged until it has been tested with their display drivers. Tested on MacBookPro15,1, MacBookPro15,2, MacBookPro16,1, MacBookPro16,2 and MacBookAir9,1, covering four panel device IDs. All five enter PSR1 after boot and across suspend/resume, report DP_PSR_SINK_ACTIVE_SINK_SYNCED, and show no sink errors. Tested-by: Andr=C3=A9 Eikmeyer Tested-by: Yossef Osman Signed-off-by: Alexander Fischer --- Changes in v2: - Use pci_dev_present() instead of pci_get_device()/pci_dev_put(), which also drops the local PCI_DEVICE_ID define (Lukas Wunner) drivers/gpu/drm/i915/display/intel_psr.c | 28 +++++++++++++++++++-- drivers/gpu/drm/i915/display/intel_quirks.c | 28 +++++++++++++++++++++ drivers/gpu/drm/i915/display/intel_quirks.h | 1 + 3 files changed, 55 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i91= 5/display/intel_psr.c index f490beb66..4e902aa76 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -228,6 +228,9 @@ static bool psr_global_enabled(struct intel_dp *intel_d= p) =20 switch (intel_dp->psr.debug & I915_PSR_DEBUG_MODE_MASK) { case I915_PSR_DEBUG_DEFAULT: + if (intel_has_dpcd_quirk(intel_dp, QUIRK_APPLE_PSR_HANDSHAKE)) + return true; + return intel_dp_is_edp(intel_dp) ? connector->panel.vbt.psr.enable : true; case I915_PSR_DEBUG_DISABLE: @@ -663,7 +666,8 @@ static void _psr_init_dpcd(struct intel_dp *intel_dp, s= truct intel_connector *co drm_dbg_kms(display->drm, "eDP panel supports PSR version %x\n", connector->dp.psr_caps.dpcd[0]); =20 - if (drm_dp_has_quirk(&intel_dp->desc, DP_DPCD_QUIRK_NO_PSR)) { + if (drm_dp_has_quirk(&intel_dp->desc, DP_DPCD_QUIRK_NO_PSR) && + !intel_has_dpcd_quirk(intel_dp, QUIRK_APPLE_PSR_HANDSHAKE)) { drm_dbg_kms(display->drm, "PSR support not currently available for this panel\n"); return; @@ -803,19 +807,36 @@ static void _panel_replay_enable_sink(struct intel_dp= *intel_dp, drm_dp_dpcd_writeb(&intel_dp->aux, PANEL_REPLAY_CONFIG3, panel_replay_con= fig_3); } =20 +/* Undocumented Apple eDP sink registers */ +#define APPLE_PSR_SETUP_1 0x321 +#define APPLE_PSR_SETUP_2 0x4d2 +#define APPLE_PSR_SETUP_3 0x4d1 +#define APPLE_PSR_TRIGGER 0x4d4 + +static void psr_apple_prepare_sink(struct intel_dp *intel_dp) +{ + drm_dp_dpcd_writeb(&intel_dp->aux, APPLE_PSR_SETUP_1, 0x3c); + drm_dp_dpcd_writeb(&intel_dp->aux, APPLE_PSR_SETUP_2, 0x01); + drm_dp_dpcd_writeb(&intel_dp->aux, APPLE_PSR_SETUP_3, 0x03); +} + static void _psr_enable_sink(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state) { struct intel_display *display =3D to_intel_display(intel_dp); + bool apple_psr =3D intel_has_dpcd_quirk(intel_dp, QUIRK_APPLE_PSR_HANDSHA= KE); u8 val =3D 0; =20 + if (apple_psr) + psr_apple_prepare_sink(intel_dp); + if (crtc_state->has_sel_update) { val |=3D DP_PSR_ENABLE_PSR2 | DP_PSR_IRQ_HPD_WITH_CRC_ERRORS; } else { if (intel_dp->psr.link_standby) val |=3D DP_PSR_MAIN_LINK_ACTIVE; =20 - if (DISPLAY_VER(display) >=3D 8) + if (DISPLAY_VER(display) >=3D 8 && !apple_psr) val |=3D DP_PSR_CRC_VERIFICATION; } =20 @@ -831,6 +852,9 @@ static void _psr_enable_sink(struct intel_dp *intel_dp, =20 val |=3D DP_PSR_ENABLE; drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG, val); + + if (apple_psr) + drm_dp_dpcd_writeb(&intel_dp->aux, APPLE_PSR_TRIGGER, 0x01); } =20 static void intel_psr_enable_sink(struct intel_dp *intel_dp, diff --git a/drivers/gpu/drm/i915/display/intel_quirks.c b/drivers/gpu/drm/= i915/display/intel_quirks.c index 33245f44c..e859eeca7 100644 --- a/drivers/gpu/drm/i915/display/intel_quirks.c +++ b/drivers/gpu/drm/i915/display/intel_quirks.c @@ -9,6 +9,7 @@ =20 #include "intel_display_core.h" #include "intel_display_types.h" +#include "intel_dp.h" #include "intel_quirks.h" =20 static void intel_set_quirk(struct intel_display *display, enum intel_quir= k_id quirk) @@ -100,6 +101,25 @@ static void quirk_disable_psr2(struct intel_display *d= isplay) drm_info(display->drm, "PSR2 support not currently available for this set= up, applying disable PSR2 quirk\n"); } =20 +static void quirk_apple_psr_handshake(struct intel_dp *intel_dp) +{ + static const struct pci_device_id t2_ids[] =3D { + /* Apple T2 */ + {PCI_DEVICE(PCI_VENDOR_ID_APPLE, 0x1801)}, + {} + }; + struct intel_display *display =3D to_intel_display(intel_dp); + + if (!intel_dp_is_edp(intel_dp)) + return; + + if (!pci_dev_present(t2_ids)) + return; + + intel_set_dpcd_quirk(intel_dp, QUIRK_APPLE_PSR_HANDSHAKE); + drm_info(display->drm, "Applying Apple PSR handshake quirk\n"); +} + struct intel_quirk { int device; int subsystem_vendor; @@ -286,6 +306,14 @@ static const struct intel_dpcd_quirk intel_dpcd_quirks= [] =3D { .sink_oui =3D SINK_OUI(0x00, 0x22, 0xb9), .hook =3D quirk_disable_edp_panel_replay, }, + /* Apple T2 eDP panels */ + { + .device =3D DEVICE_ID_ANY, + .subsystem_vendor =3D PCI_ANY_ID, + .subsystem_device =3D PCI_ANY_ID, + .sink_oui =3D SINK_OUI(0x00, 0x10, 0xfa), + .hook =3D quirk_apple_psr_handshake, + }, }; =20 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 970a4fe52..7b863d408 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_APPLE_PSR_HANDSHAKE, }; =20 void intel_init_quirks(struct intel_display *display); base-commit: 496ff8213a2d2e1e5b1c8efe8b55e1dcdc3e3f8f --=20 2.55.0