From: Atharva Tiwari <atharvatiwarilinuxdev@gmail.com>
Cc: "Atharva Tiwari" <atharvatiwarilinuxdev@gmail.com>,
"Andre Eikmeyer" <dev@deq.rocks>,
"Bjorn Helgaas" <bhelgaas@google.com>,
"Thomas Gleixner" <tglx@kernel.org>,
"Ingo Molnar" <mingo@redhat.com>,
"Borislav Petkov" <bp@alien8.de>,
"Dave Hansen" <dave.hansen@linux.intel.com>,
x86@kernel.org (maintainer:X86 ARCHITECTURE (32-BIT AND 64-BIT)),
"H. Peter Anvin" <hpa@zytor.com>,
"Alex Deucher" <alexander.deucher@amd.com>,
"Christian König" <christian.koenig@amd.com>,
"David Airlie" <airlied@gmail.com>,
"Simona Vetter" <simona@ffwll.ch>,
"Harry Wentland" <harry.wentland@amd.com>,
"Leo Li" <sunpeng.li@amd.com>,
"Rodrigo Siqueira" <siqueira@igalia.com>,
"Kenneth Feng" <kenneth.feng@amd.com>,
"Hans de Goede" <hansg@kernel.org>,
"Ilpo Järvinen" <ilpo.jarvinen@linux.intel.com>,
linux-pci@vger.kernel.org (open list:PCI SUBSYSTEM),
linux-kernel@vger.kernel.org (open list:X86 ARCHITECTURE (32-BIT
AND 64-BIT)),
amd-gfx@lists.freedesktop.org (open list:RADEON and AMDGPU DRM
DRIVERS), dri-devel@lists.freedesktop.org (open list:DRM DRIVERS),
platform-driver-x86@vger.kernel.org (open list:X86 PLATFORM
DRIVERS)
Subject: [PATCH 01/13] platform/apple-gmux: Fix power for MMIO systems
Date: Sat, 24 Oct 2026 23:59:37 -0400 [thread overview]
Message-ID: <20261025040046.1602-2-atharvatiwarilinuxdev@gmail.com> (raw)
In-Reply-To: <20261025040046.1602-1-atharvatiwarilinuxdev@gmail.com>
Currently The dGPU on MMIO Systems, dies when we write the gmux values
to turn off the gpu.
On most systems we can just write PWG1 (link-training method) and the
dGPU comes up, then we write a MMIO variable, and run PWG3
(link-retraing method), to stablize the dGPU.
But on 16,1 and 16,4 this dosent work, instead we have to use PWRD
method, which turns off the entire bridge, and completely messes the
pci config, so we can't use pci to traverse through it. we save the
entire bridge using ACPI addresses then we run PWRD(1) to turn off
the bridge, then we write gmux states, and resume we do the vice
versa, but here we dont need to retrain the link and write the
MMIO variable.
Co-developed-by: Andre Eikmeyer <dev@deq.rocks>
Signed-off-by: Andre Eikmeyer <dev@deq.rocks>
Signed-off-by: Atharva Tiwari <atharvatiwarilinuxdev@gmail.com>
---
drivers/platform/x86/apple-gmux.c | 177 ++++++++++++++++++++++++++++--
1 file changed, 170 insertions(+), 7 deletions(-)
diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c
index 9c728ac4e..4e8786a5e 100644
--- a/drivers/platform/x86/apple-gmux.c
+++ b/drivers/platform/x86/apple-gmux.c
@@ -22,6 +22,7 @@
#include <linux/pci.h>
#include <linux/vga_switcheroo.h>
#include <linux/debugfs.h>
+#include <linux/dmi.h>
#include <acpi/video.h>
#include <asm/io.h>
@@ -65,6 +66,11 @@ struct apple_gmux_data {
struct backlight_device *bdev;
+ /* power handling data */
+ struct pci_dev *discrete_pdev;
+ bool uses_pwrd;
+ enum apple_gmux_type type;
+
/* switcheroo data */
acpi_handle dhandle;
int gpe;
@@ -502,23 +508,171 @@ static int gmux_switch_ddc(enum vga_switcheroo_client_id id)
/**
* DOC: Power control
*
- * gmux is able to cut power to the discrete GPU. It automatically takes care
+ * gmux is able to cut power to the discrete GPU. On most
+ * Systems the gmux automatically takes care
* of the correct sequence to tear down and bring up the power rails for
* core voltage, VRAM and PCIe.
+ *
+ * But on most MMIO Systems, we have to PCIE link-train the discrete GPU after
+ * power on, we can do that using PWG1 and then to stablize we write to
+ * 0x8C340 and then link-train the PCIE link again (this time using PWG3).
+ *
+ * But on MacBookPro16,1 and MacBookPro16,4, the PWG1 method does not work
+ * instead we have to use PWRD method, which turns off the entire bridge and
+ * messes up the PCI config, so we can't use pci_upstream_bridge to traverse
+ * through the bridge, so we use ACPI addresses to save/restore bridges.
+ *
+ * NOTE: Communication to these bridges (not the dGPU/HDA) in any form
+ * when the bridge is off, will result in CPU CATERR.
*/
+static int gmux_save_restore_pci(acpi_handle parent_handle, const char *name,
+ bool save, acpi_handle *out_handle)
+{
+ acpi_status status;
+ acpi_handle handle;
+ struct acpi_device *adev;
+ struct device *dev;
+ struct pci_dev *pdev;
+
+ if (name) {
+ status = acpi_get_handle(parent_handle, name, &handle);
+ if (ACPI_FAILURE(status))
+ return -EIO;
+
+ if (out_handle)
+ *out_handle = handle;
+ } else
+ handle = parent_handle;
+
+ adev = acpi_fetch_acpi_dev(handle);
+ if (!adev)
+ return -EIO;
+
+ dev = acpi_get_first_physical_node(adev);
+ if (!dev || !dev_is_pci(dev))
+ return -EIO;
+
+ pdev = to_pci_dev(dev);
+
+ if (save) {
+ pci_save_state(pdev);
+ pdev->current_state = PCI_D3cold;
+ } else {
+ pdev->current_state = PCI_D0;
+ pci_restore_state(pdev);
+ }
+ return 0;
+}
+
static int gmux_set_discrete_state(struct apple_gmux_data *gmux_data,
enum vga_switcheroo_state state)
{
reinit_completion(&gmux_data->powerchange_done);
+ acpi_handle discrete_handle = ACPI_HANDLE(&gmux_data->discrete_pdev->dev);
+ acpi_status status;
+ unsigned long long result;
+
+ if (!discrete_handle)
+ return -ENODEV;
if (state == VGA_SWITCHEROO_ON) {
- gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 1);
- gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 3);
+ if (gmux_data->type == APPLE_GMUX_TYPE_MMIO) {
+ u16 vendor;
+ int i;
+
+ gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 2);
+ msleep(100);
+ gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 3);
+
+ if (gmux_data->uses_pwrd) {
+ acpi_handle handle;
+
+ status = acpi_execute_simple_method(discrete_handle, "PWRD", 0);
+ if (ACPI_FAILURE(status))
+ return -EIO;
+
+ if (gmux_save_restore_pci(NULL, "\\_SB_.PCI0.PEG0", 0, &handle))
+ return -EIO;
+
+ if (gmux_save_restore_pci(handle, "EGP0", 0, &handle))
+ return -EIO;
+
+ if (gmux_save_restore_pci(handle, "EGP1", 0, &handle))
+ return -EIO;
+
+ if (gmux_save_restore_pci(handle, "GFX0", 0, NULL))
+ return -EIO;
+
+ if (gmux_save_restore_pci(handle, "HDAU", 0, NULL))
+ return -EIO;
+ } else {
+ status = acpi_evaluate_integer(discrete_handle,
+ "PWG1", NULL, &result);
+ if (ACPI_FAILURE(status) || result)
+ return -EIO;
+ }
+
+ for (i = 0; i < 1000; i++) {
+ pci_read_config_word(gmux_data->discrete_pdev,
+ PCI_VENDOR_ID, &vendor);
+ if (vendor != 0xffff)
+ break;
+ msleep(1);
+ }
+ if (vendor == 0xffff)
+ return -ETIMEDOUT;
+
+ if (!gmux_data->uses_pwrd) {
+ void __iomem *bar = pci_iomap(gmux_data->discrete_pdev, 0, 0);
+
+ if (!bar)
+ return -ENOMEM;
+
+ iowrite32(ioread32(bar + 0x8c340) & 0x3fffffff, bar + 0x8c340);
+ pci_iounmap(gmux_data->discrete_pdev, bar);
+
+ status = acpi_evaluate_integer(discrete_handle,
+ "PWG3", NULL, &result);
+ if (ACPI_FAILURE(status) || result)
+ return -EIO;
+ }
+ } else {
+ gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 1);
+ gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 3);
+ }
pr_debug("Discrete card powered up\n");
} else {
- gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 1);
- gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 0);
+ if (gmux_data->type == APPLE_GMUX_TYPE_MMIO) {
+ if (gmux_data->uses_pwrd) {
+ acpi_handle parent_handle = discrete_handle;
+ bool saved_hda = false;
+
+ while (ACPI_SUCCESS(acpi_get_parent(parent_handle,
+ &parent_handle))) {
+ if (!saved_hda) {
+ if (!gmux_save_restore_pci(parent_handle,
+ "HDAU", true, NULL)) {
+ saved_hda = true;
+ pci_save_state(gmux_data->discrete_pdev);
+ gmux_data->discrete_pdev->current_state =
+ PCI_D3cold;
+ }
+ }
+ if (gmux_save_restore_pci(parent_handle, NULL, true, NULL))
+ break;
+ }
+ status = acpi_execute_simple_method(discrete_handle, "PWRD", 1);
+ if (ACPI_FAILURE(status))
+ return -EIO;
+ }
+ gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 1);
+ mdelay(10);
+ gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 0);
+ } else {
+ gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 1);
+ gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 0);
+ }
pr_debug("Discrete card powered down\n");
}
@@ -552,10 +706,15 @@ static enum vga_switcheroo_client_id gmux_get_client_id(struct pci_dev *pdev)
else if (pdev->vendor == PCI_VENDOR_ID_NVIDIA &&
pdev->device == 0x0863)
return VGA_SWITCHEROO_IGD;
- else
+ else {
+ if (apple_gmux_data->discrete_pdev != pdev) {
+ pci_dev_put(apple_gmux_data->discrete_pdev);
+ apple_gmux_data->discrete_pdev = pci_dev_get(pdev);
+ }
return VGA_SWITCHEROO_DIS;
-}
+ }
+}
static const struct vga_switcheroo_handler gmux_handler_no_ddc = {
.switchto = gmux_switchto,
.power_state = gmux_set_power_state,
@@ -803,6 +962,9 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
if (!gmux_data)
return -ENOMEM;
pnp_set_drvdata(pnp, gmux_data);
+ gmux_data->type = type;
+ gmux_data->uses_pwrd = (dmi_match(DMI_PRODUCT_NAME, "MacBookPro16,1") ||
+ dmi_match(DMI_PRODUCT_NAME, "MacBookPro16,4"));
switch (type) {
case APPLE_GMUX_TYPE_MMIO:
@@ -993,6 +1155,7 @@ static void gmux_remove(struct pnp_dev *pnp)
gmux_fini_debugfs(gmux_data);
vga_switcheroo_unregister_handler();
+ pci_dev_put(gmux_data->discrete_pdev);
gmux_disable_interrupts(gmux_data);
if (gmux_data->gpe >= 0) {
acpi_disable_gpe(NULL, gmux_data->gpe);
--
2.55.0
next prev parent reply other threads:[~2026-10-25 4:01 UTC|newest]
Thread overview: 26+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-25 3:59 [PATCH 00/13] Fixes for apple-gmux and runtime support Atharva Tiwari
2026-10-25 3:59 ` Atharva Tiwari [this message]
2026-10-25 4:49 ` [PATCH 01/13] platform/apple-gmux: Fix power for MMIO systems sashiko-bot
2026-10-25 3:59 ` [PATCH 02/13] PCI: Disable pcie port and access on D3 on specific amd devices Atharva Tiwari
2026-10-25 4:34 ` sashiko-bot
2026-10-25 3:59 ` [PATCH 03/13] platform/apple-gmux: Fix MMIO interface Atharva Tiwari
2026-10-25 4:27 ` sashiko-bot
2026-10-25 3:59 ` [PATCH 04/13] platform/apple-gmux: Fix Interrupts for MMIO systems Atharva Tiwari
2026-10-25 4:39 ` sashiko-bot
2026-10-25 3:59 ` [PATCH 05/13] platform/apple-gmux: Write switch state to EFI on MMIO devices Atharva Tiwari
2026-10-25 4:36 ` sashiko-bot
2026-10-25 3:59 ` [PATCH 06/13] platform/apple-gmux: Add parameter to configure boot gpu Atharva Tiwari
2026-10-25 4:33 ` sashiko-bot
2026-10-25 3:59 ` [PATCH 07/13] platform/apple-gmux: Add check to detect FSS Atharva Tiwari
2026-10-25 3:59 ` [PATCH 08/13] platform/apple-gmux: Add documentation about iMacs Atharva Tiwari
2026-10-25 4:37 ` sashiko-bot
2026-10-25 3:59 ` [PATCH 09/13] drm/amdgpu: Add Apple GMUX runtime PM support Atharva Tiwari
2026-10-25 5:56 ` sashiko-bot
2026-10-25 3:59 ` [PATCH 10/13] drm/amdgpu: Catch register access while GMUX keeps the GPU off Atharva Tiwari
2026-10-25 4:40 ` sashiko-bot
2026-10-25 3:59 ` [PATCH 11/13] drm/amd/display: Refuse DP AUX " Atharva Tiwari
2026-10-25 4:41 ` sashiko-bot
2026-10-25 3:59 ` [PATCH 12/13] drm/amdgpu: Skip AC/DC notification while the GPU is runtime suspended Atharva Tiwari
2026-10-25 4:43 ` sashiko-bot
2026-10-25 3:59 ` [PATCH 13/13] drm/amd/display: Skip panel power savings on eDP links without a panel Atharva Tiwari
2026-10-25 4:30 ` sashiko-bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261025040046.1602-2-atharvatiwarilinuxdev@gmail.com \
--to=atharvatiwarilinuxdev@gmail.com \
--cc=airlied@gmail.com \
--cc=alexander.deucher@amd.com \
--cc=amd-gfx@lists.freedesktop.org \
--cc=bhelgaas@google.com \
--cc=bp@alien8.de \
--cc=christian.koenig@amd.com \
--cc=dave.hansen@linux.intel.com \
--cc=dev@deq.rocks \
--cc=dri-devel@lists.freedesktop.org \
--cc=hansg@kernel.org \
--cc=harry.wentland@amd.com \
--cc=hpa@zytor.com \
--cc=ilpo.jarvinen@linux.intel.com \
--cc=kenneth.feng@amd.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=mingo@redhat.com \
--cc=platform-driver-x86@vger.kernel.org \
--cc=simona@ffwll.ch \
--cc=siqueira@igalia.com \
--cc=sunpeng.li@amd.com \
--cc=tglx@kernel.org \
--cc=x86@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox