From: Andre Eikmeyer <dev@deq.rocks>
To: platform-driver-x86@vger.kernel.org,
amd-gfx@lists.freedesktop.org, linux-sound@vger.kernel.org
Cc: "Atharva Tiwari" <atharvatiwarilinuxdev@gmail.com>,
"Hans de Goede" <hansg@kernel.org>,
"Ilpo Järvinen" <ilpo.jarvinen@linux.intel.com>,
"Alex Deucher" <alexander.deucher@amd.com>,
"Christian König" <christian.koenig@amd.com>,
"David Airlie" <airlied@gmail.com>,
"Simona Vetter" <simona@ffwll.ch>,
"Kenneth Feng" <kenneth.feng@amd.com>,
"Jaroslav Kysela" <perex@perex.cz>,
"Takashi Iwai" <tiwai@suse.com>,
dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org,
"Andre Eikmeyer" <dev@deq.rocks>
Subject: [PATCH 2/3] drm/amdgpu: add Apple GMUX runtime PM support
Date: Wed, 12 Aug 2026 14:22:05 +0200 [thread overview]
Message-ID: <20260812122206.193680-3-dev@deq.rocks> (raw)
In-Reply-To: <20260812122206.193680-1-dev@deq.rocks>
Hello everyone,
The MacBookPro15,1 uses Apple GMUX to control power to the discrete GPU,
but it does not expose the ATPX or ACPI power-resource interfaces currently
recognized by amdgpu. The driver therefore leaves runtime PM disabled even
though vga_switcheroo can switch the GPU reliably.
A dedicated GMUX runtime PM mode uses the existing vga_switcheroo PM domain
to sequence GPU power. A runtime-suspended GMUX GPU can remain powered off
across system sleep, following the smart-suspend handling already used by
BOCO devices.
This allows the discrete GPU to enter D3cold while the integrated GPU is
primary and allows PRIME workloads and external displays to wake it on
demand. The model enablement is limited to the tested MacBookPro15,1.
This was tested on both the 2018 and 2019 MacBookPro15,1 revisions together
with the apple-gmux and HDA changes in this series.
Thank you for your time and consideration.
Signed-off-by: Andre Eikmeyer <dev@deq.rocks>
---
drivers/gpu/drm/amd/amdgpu/amdgpu.h | 1 +
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 34 ++++++++++++++++++----
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 30 ++++++++++++-------
drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h | 1 +
4 files changed, 49 insertions(+), 17 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index 7b09410..cc2e2e2 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -1402,6 +1402,7 @@ int amdgpu_device_mode1_reset(struct amdgpu_device *adev);
int amdgpu_device_link_reset(struct amdgpu_device *adev);
bool amdgpu_device_supports_atpx(struct amdgpu_device *adev);
bool amdgpu_device_supports_px(struct amdgpu_device *adev);
+bool amdgpu_device_supports_gmux(struct amdgpu_device *adev);
bool amdgpu_device_supports_boco(struct amdgpu_device *adev);
bool amdgpu_device_supports_smart_shift(struct amdgpu_device *adev);
int amdgpu_device_supports_baco(struct amdgpu_device *adev);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index bff3e06..bfa2b7a 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -34,6 +34,7 @@
#include <linux/slab.h>
#include <linux/iommu.h>
#include <linux/pci.h>
+#include <linux/dmi.h>
#include <linux/pci-p2pdma.h>
#include <linux/apple-gmux.h>
#include <linux/nospec.h>
@@ -568,6 +569,22 @@ bool amdgpu_device_supports_px(struct amdgpu_device *adev)
return false;
}
+static const struct dmi_system_id amdgpu_gmux_runpm_dmi_table[] = {
+ {
+ .matches = {
+ DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro15,1"),
+ },
+ },
+ { }
+};
+
+bool amdgpu_device_supports_gmux(struct amdgpu_device *adev)
+{
+ return dmi_check_system(amdgpu_gmux_runpm_dmi_table) &&
+ !dev_is_removable(&adev->pdev->dev) &&
+ apple_gmux_detect(NULL, NULL);
+}
+
/**
* amdgpu_device_supports_boco - Is the device a dGPU with ACPI power resources
*
@@ -631,6 +648,9 @@ void amdgpu_device_detect_runtime_pm_mode(struct amdgpu_device *adev)
/* enable PX as runtime mode */
adev->pm.rpm_mode = AMDGPU_RUNPM_PX;
dev_info(adev->dev, "Using ATPX for runtime pm\n");
+ } else if (amdgpu_device_supports_gmux(adev)) {
+ adev->pm.rpm_mode = AMDGPU_RUNPM_GMUX;
+ dev_info(adev->dev, "Using Apple GMUX for runtime pm\n");
} else if (amdgpu_device_supports_boco(adev)) {
/* enable boco as runtime mode */
adev->pm.rpm_mode = AMDGPU_RUNPM_BOCO;
@@ -3711,7 +3731,7 @@ int amdgpu_device_init(struct amdgpu_device *adev,
{
struct pci_dev *pdev = adev->pdev;
int r, i;
- bool px = false;
+ bool gmux, px = false;
u32 max_MBps;
int tmp;
@@ -4144,13 +4164,14 @@ fence_driver_init:
vga_client_register(adev->pdev, amdgpu_device_vga_set_decode);
px = amdgpu_device_supports_px(adev);
+ gmux = amdgpu_device_supports_gmux(adev);
if (px || (!dev_is_removable(&adev->pdev->dev) &&
- apple_gmux_detect(NULL, NULL)))
+ apple_gmux_detect(NULL, NULL)))
vga_switcheroo_register_client(adev->pdev,
- &amdgpu_switcheroo_ops, px);
+ &amdgpu_switcheroo_ops, px || gmux);
- if (px)
+ if (px || gmux)
vga_switcheroo_init_domain_pm_ops(adev->dev, &adev->vga_pm_domain);
adev->pm_nb.notifier_call = amdgpu_device_pm_notifier;
@@ -4278,7 +4299,7 @@ void amdgpu_device_fini_hw(struct amdgpu_device *adev)
void amdgpu_device_fini_sw(struct amdgpu_device *adev)
{
int i, idx;
- bool px;
+ bool gmux, px;
amdgpu_device_ip_fini(adev);
amdgpu_fence_driver_sw_fini(adev);
@@ -4309,12 +4330,13 @@ void amdgpu_device_fini_sw(struct amdgpu_device *adev)
adev->xcp_mgr = NULL;
px = amdgpu_device_supports_px(adev);
+ gmux = amdgpu_device_supports_gmux(adev);
if (px || (!dev_is_removable(&adev->pdev->dev) &&
apple_gmux_detect(NULL, NULL)))
vga_switcheroo_unregister_client(adev->pdev);
- if (px)
+ if (px || gmux)
vga_switcheroo_fini_domain_pm_ops(adev->dev);
if ((adev->pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
index 1aed121..b8d4273 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -2485,11 +2485,12 @@ retry_init:
DRM_ERROR("Creating debugfs files failed (%d).\n", ret);
if (adev->pm.rpm_mode != AMDGPU_RUNPM_NONE) {
- /* only need to skip on ATPX */
+ /* ATPX requires a full system-sleep transition. */
if (amdgpu_device_supports_px(adev))
dev_pm_set_driver_flags(ddev->dev, DPM_FLAG_NO_DIRECT_COMPLETE);
- /* we want direct complete for BOCO */
- if (amdgpu_device_supports_boco(adev))
+ /* BOCO and GMUX can remain runtime suspended across system sleep. */
+ if (amdgpu_device_supports_boco(adev) ||
+ adev->pm.rpm_mode == AMDGPU_RUNPM_GMUX)
dev_pm_set_driver_flags(ddev->dev, DPM_FLAG_SMART_PREPARE |
DPM_FLAG_SMART_SUSPEND |
DPM_FLAG_MAY_SKIP_RESUME);
@@ -2598,7 +2599,9 @@ static int amdgpu_pmops_prepare(struct device *dev)
/* Return a positive number here so
* DPM_FLAG_SMART_SUSPEND works properly
*/
- if (amdgpu_device_supports_boco(adev) && pm_runtime_suspended(dev))
+ if ((amdgpu_device_supports_boco(adev) ||
+ adev->pm.rpm_mode == AMDGPU_RUNPM_GMUX) &&
+ pm_runtime_suspended(dev))
return 1;
/* if we will not support s3 or s2i for the device
@@ -2860,7 +2863,8 @@ static int amdgpu_pmops_runtime_suspend(struct device *dev)
}
adev->in_runpm = true;
- if (adev->pm.rpm_mode == AMDGPU_RUNPM_PX)
+ if (adev->pm.rpm_mode == AMDGPU_RUNPM_PX ||
+ adev->pm.rpm_mode == AMDGPU_RUNPM_GMUX)
drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
/*
@@ -2887,8 +2891,9 @@ static int amdgpu_pmops_runtime_suspend(struct device *dev)
if (adev->pm.rpm_mode == AMDGPU_RUNPM_BOCO)
adev->mp1_state = PP_MP1_STATE_NONE;
- if (adev->pm.rpm_mode == AMDGPU_RUNPM_PX) {
- /* Only need to handle PCI state in the driver for ATPX
+ if (adev->pm.rpm_mode == AMDGPU_RUNPM_PX ||
+ adev->pm.rpm_mode == AMDGPU_RUNPM_GMUX) {
+ /* Only need to handle PCI state in the driver for ATPX and GMUX.
* PCI core handles it for _PR3.
*/
amdgpu_device_cache_pci_state(pdev);
@@ -2935,10 +2940,11 @@ static int amdgpu_pmops_runtime_resume(struct device *dev)
if (!pci_device_is_present(adev->pdev))
adev->no_hw_access = true;
- if (adev->pm.rpm_mode == AMDGPU_RUNPM_PX) {
+ if (adev->pm.rpm_mode == AMDGPU_RUNPM_PX ||
+ adev->pm.rpm_mode == AMDGPU_RUNPM_GMUX) {
drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
- /* Only need to handle PCI state in the driver for ATPX
+ /* Only need to handle PCI state in the driver for ATPX and GMUX.
* PCI core handles it for _PR3.
*/
pci_set_power_state(pdev, PCI_D0);
@@ -2958,12 +2964,14 @@ static int amdgpu_pmops_runtime_resume(struct device *dev)
}
ret = amdgpu_device_resume(drm_dev, false);
if (ret) {
- if (adev->pm.rpm_mode == AMDGPU_RUNPM_PX)
+ if (adev->pm.rpm_mode == AMDGPU_RUNPM_PX ||
+ adev->pm.rpm_mode == AMDGPU_RUNPM_GMUX)
pci_disable_device(pdev);
return ret;
}
- if (adev->pm.rpm_mode == AMDGPU_RUNPM_PX)
+ if (adev->pm.rpm_mode == AMDGPU_RUNPM_PX ||
+ adev->pm.rpm_mode == AMDGPU_RUNPM_GMUX)
drm_dev->switch_power_state = DRM_SWITCH_POWER_ON;
amdgpu_restore_umd_profile_pstate_after_runpm(adev);
diff --git a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
index 8d1b097..df24b01 100644
--- a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
+++ b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
@@ -48,6 +48,7 @@ enum amdgpu_int_thermal_type {
enum amdgpu_runpm_mode {
AMDGPU_RUNPM_NONE,
AMDGPU_RUNPM_PX,
+ AMDGPU_RUNPM_GMUX,
AMDGPU_RUNPM_BOCO,
AMDGPU_RUNPM_BACO,
AMDGPU_RUNPM_BAMACO,
--
2.55.0
next prev parent reply other threads:[~2026-08-12 12:22 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-12 12:22 [PATCH 0/3] Apple GMUX hybrid graphics support for MacBookPro15,1 Andre Eikmeyer
2026-08-12 12:22 ` [PATCH 1/3] platform/x86: apple-gmux: add MacBookPro15, 1 dGPU power sequence Andre Eikmeyer
2026-08-12 12:22 ` Andre Eikmeyer [this message]
2026-08-12 12:22 ` [PATCH 3/3] ALSA: hda: allow direct complete with a powered-off GPU Andre Eikmeyer
2026-08-12 13:45 ` Takashi Iwai
2026-08-12 13:53 ` Takashi Iwai
2026-08-12 14:03 ` [PATCH v2 " Andre Eikmeyer
2026-08-12 14:23 ` [PATCH v3 " Andre Eikmeyer
2026-08-12 14:30 ` Takashi Iwai
2026-08-12 14:04 ` [PATCH " Christian König
2026-08-12 14:42 ` [PATCH v2 0/3] Apple GMUX hybrid graphics support for MacBookPro15,1 Andre Eikmeyer
2026-08-12 14:42 ` [PATCH v2 1/3] platform/x86: apple-gmux: add MacBookPro15, 1 dGPU power sequence Andre Eikmeyer
2026-08-12 14:42 ` [PATCH v2 2/3] drm/amdgpu: add Apple GMUX runtime PM support Andre Eikmeyer
2026-08-12 14:42 ` [PATCH v2 3/3] ALSA: hda: allow direct complete with a powered-off GPU Andre Eikmeyer
2026-08-12 14:47 ` [PATCH v3 0/3] Apple GMUX hybrid graphics support for MacBookPro15,1 Andre Eikmeyer
2026-08-12 14:47 ` [PATCH v3 1/3] platform/x86: apple-gmux: add MacBookPro15, 1 dGPU power sequence Andre Eikmeyer
2026-08-12 14:47 ` [PATCH v3 2/3] drm/amdgpu: add Apple GMUX runtime PM support Andre Eikmeyer
2026-08-12 14:47 ` [PATCH v3 3/3] ALSA: hda: allow direct complete with a powered-off GPU Andre Eikmeyer
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=20260812122206.193680-3-dev@deq.rocks \
--to=dev@deq.rocks \
--cc=airlied@gmail.com \
--cc=alexander.deucher@amd.com \
--cc=amd-gfx@lists.freedesktop.org \
--cc=atharvatiwarilinuxdev@gmail.com \
--cc=christian.koenig@amd.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=hansg@kernel.org \
--cc=ilpo.jarvinen@linux.intel.com \
--cc=kenneth.feng@amd.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-sound@vger.kernel.org \
--cc=perex@perex.cz \
--cc=platform-driver-x86@vger.kernel.org \
--cc=simona@ffwll.ch \
--cc=tiwai@suse.com \
/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