From nobody Tue Sep 29 04:09:38 2026 Received: from bulk0.mail-out.lima-city.de (bulk0.mail-out.lima-city.de [91.216.248.212]) (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 C1BEE46AA79; Wed, 12 Aug 2026 14:48:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.216.248.212 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786546094; cv=none; b=U4OP1Dvv5Vpjz+vC/wItGG7Ul9MFpJiu33RCIartwwRuaTtbGqxQ54AfOdW0cTCV+FYSIcpZxVCABfJPkyQOMhJcZe9UTDyXVy+ll1ClS6dJCq689yjtA24RCFIeflXXDDmZnFKfvtjzLyArIC9RWjGZ+IMPBUViNrvpZrisC5I= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786546094; c=relaxed/simple; bh=79vwdvV8p9yudrSia5lQjOpCjUlE3msAERhpr9jn+Uw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ip5+IPl6sCTqbdz65dC9h9MxT+m68ysUPG++HjeT5nvCD2yLwvFckxTP60tdGkqgxxr8Ium9i8/3PK6qTYCpEcEGVtoBtJH451WCgmHMPRAIaVDbX4xj/qQlaNua5hH5hn69hDgQOMkJSvoLTmCzAp3IllL9Kh+M7HI5eoaNDak= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=deq.rocks; spf=none smtp.mailfrom=deq.rocks; dkim=pass (2048-bit key) header.d=deq.rocks header.i=@deq.rocks header.b=aYgG5EMg; arc=none smtp.client-ip=91.216.248.212 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=deq.rocks Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=deq.rocks Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=deq.rocks header.i=@deq.rocks header.b="aYgG5EMg" From: Andre Eikmeyer DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=deq.rocks; s=securedbylima-20251205; t=1786546080; bh=79vwdvV8p9yudrSia5lQjOpCjUlE3msAERhpr9jn+Uw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=aYgG5EMg9jnhxfWzBxM8uWzsJefeApzHspx9voOZPHMjsvNNv1VIvlk6OCURWRiHo Ty1wCCIJsuimQHQB3nAkLRoX3y27ytclMAmr5RBkakzc7vewiEGLKksd0lAUtXoVsd evws3iz0g2XjdzxzfzgHukX4+N69EkkGJyre8TbMbn5vMJDVO5SDlcvyW4OA3/pmpO jUnRX+EtVNkq5JVTzCTSGGZyECwr/+vrLGQif+21mZJePB3TMG4l6fbxvVk873uqBx lgUANunU2LFicHtusxKW4kkvbYb7T05pFjqYkhccxk56k1WhJ32Afj2aEn0PBnilww PJVcYKw9rtpOA== To: platform-driver-x86@vger.kernel.org, amd-gfx@lists.freedesktop.org, linux-sound@vger.kernel.org Cc: Atharva Tiwari , Hans de Goede , =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= , Alex Deucher , =?UTF-8?q?Christian=20K=C3=B6nig?= , David Airlie , Simona Vetter , Kenneth Feng , Jaroslav Kysela , Takashi Iwai , Takashi Iwai , Harry Wentland , Leo Li , dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, Andre Eikmeyer Subject: [PATCH v3 1/3] platform/x86: apple-gmux: add MacBookPro15,1 dGPU power sequence Date: Wed, 12 Aug 2026 16:47:48 +0200 Message-ID: <20260812144750.36797-2-dev@deq.rocks> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260812144750.36797-1-dev@deq.rocks> References: <20260812144221.35877-1-dev@deq.rocks> <20260812144750.36797-1-dev@deq.rocks> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Atharva Tiwari The discrete GPU on the MacBookPro15,1 does not return after the legacy GMUX power-on sequence. PCI configuration space remains inaccessible, so runtime PM cannot provide usable hybrid graphics with the integrated GPU as primary. Evaluate the firmware PWG1 and PWG3 link methods around the GMUX transition and wait for PCI configuration space before completing power-on. Keep the sequence limited to the MacBookPro15,1 and retain the existing path for every other model. This was tested on both the 2018 and 2019 MacBookPro15,1 revisions with the integrated GPU as primary. The discrete GPU transitions between DynOff and DynPwr, and external displays work across the transitions. Co-developed-by: Andre Eikmeyer Signed-off-by: Andre Eikmeyer Signed-off-by: Atharva Tiwari --- drivers/platform/x86/apple-gmux.c | 86 ++++++++++++++++++++++++++++--- 1 file changed, 80 insertions(+), 6 deletions(-) diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple= -gmux.c index 9c728ac..ccb059a 100644 --- a/drivers/platform/x86/apple-gmux.c +++ b/drivers/platform/x86/apple-gmux.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include =20 @@ -74,6 +75,8 @@ struct apple_gmux_data { enum vga_switcheroo_client_id switch_state_external; enum vga_switcheroo_state power_state; struct completion powerchange_done; + struct pci_dev *discrete_pdev; + bool use_pwg_power_sequence; =20 /* debugfs data */ u8 selected_port; @@ -82,6 +85,34 @@ struct apple_gmux_data { =20 static struct apple_gmux_data *apple_gmux_data; =20 +static int gmux_call_pwg(struct apple_gmux_data *gmux_data, + const char *method) +{ + acpi_handle handle =3D ACPI_HANDLE(&gmux_data->discrete_pdev->dev); + unsigned long long result; + acpi_status status; + + if (!handle) + return -ENODEV; + + status =3D acpi_evaluate_integer(handle, (acpi_string)method, NULL, + &result); + if (ACPI_FAILURE(status)) { + dev_err(&gmux_data->discrete_pdev->dev, + "failed to evaluate %s: %s\n", method, + acpi_format_exception(status)); + return -EIO; + } + + if (result) { + dev_err(&gmux_data->discrete_pdev->dev, + "%s failed: %llu\n", method, result); + return -EIO; + } + + return 0; +} + struct apple_gmux_config { u8 (*read8)(struct apple_gmux_data *gmux_data, int port); void (*write8)(struct apple_gmux_data *gmux_data, int port, u8 val); @@ -510,14 +541,49 @@ static int gmux_switch_ddc(enum vga_switcheroo_client= _id id) static int gmux_set_discrete_state(struct apple_gmux_data *gmux_data, enum vga_switcheroo_state state) { + int ret; + reinit_completion(&gmux_data->powerchange_done); =20 if (state =3D=3D VGA_SWITCHEROO_ON) { - gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 1); - gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 3); + if (gmux_data->use_pwg_power_sequence && + gmux_data->discrete_pdev) { + u16 vendor; + int i; + + gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 2); + msleep(100); + gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 3); + + ret =3D gmux_call_pwg(gmux_data, "PWG1"); + if (ret) + return ret; + + for (i =3D 0; i < 1000; i++) { + pci_read_config_word(gmux_data->discrete_pdev, + PCI_VENDOR_ID, &vendor); + if (vendor !=3D 0xffff) + break; + usleep_range(1000, 2000); + } + if (vendor =3D=3D 0xffff) { + dev_err(&gmux_data->discrete_pdev->dev, + "timed out waiting for PCI config space\n"); + return -ETIMEDOUT; + } + + ret =3D gmux_call_pwg(gmux_data, "PWG3"); + if (ret) + return ret; + } 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); + if (gmux_data->use_pwg_power_sequence) + usleep_range(10000, 11000); gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 0); pr_debug("Discrete card powered down\n"); } @@ -549,11 +615,16 @@ static enum vga_switcheroo_client_id gmux_get_client_= id(struct pci_dev *pdev) */ if (pdev->vendor =3D=3D PCI_VENDOR_ID_INTEL) return VGA_SWITCHEROO_IGD; - else if (pdev->vendor =3D=3D PCI_VENDOR_ID_NVIDIA && - pdev->device =3D=3D 0x0863) + if (pdev->vendor =3D=3D PCI_VENDOR_ID_NVIDIA && pdev->device =3D=3D 0x086= 3) return VGA_SWITCHEROO_IGD; - else - return VGA_SWITCHEROO_DIS; + + if (apple_gmux_data->use_pwg_power_sequence && + apple_gmux_data->discrete_pdev !=3D pdev) { + pci_dev_put(apple_gmux_data->discrete_pdev); + apple_gmux_data->discrete_pdev =3D pci_dev_get(pdev); + } + + return VGA_SWITCHEROO_DIS; } =20 static const struct vga_switcheroo_handler gmux_handler_no_ddc =3D { @@ -803,6 +874,8 @@ 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->use_pwg_power_sequence =3D type =3D=3D APPLE_GMUX_TYPE_MMIO && + dmi_match(DMI_PRODUCT_NAME, "MacBookPro15,1"); =20 switch (type) { case APPLE_GMUX_TYPE_MMIO: @@ -1009,6 +1082,7 @@ static void gmux_remove(struct pnp_dev *pnp) } else release_region(gmux_data->iostart, gmux_data->iolen); apple_gmux_data =3D NULL; + pci_dev_put(gmux_data->discrete_pdev); kfree(gmux_data); } =20 --=20 2.55.0 From nobody Tue Sep 29 04:09:38 2026 Received: from bulk0.mail-out.lima-city.de (bulk0.mail-out.lima-city.de [91.216.248.212]) (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 479FA46C4CF; Wed, 12 Aug 2026 14:48:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.216.248.212 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786546097; cv=none; b=AMnoOjtnxxtT/7NKYJV4gYbKGhtZX37jdoku5bQKg1ha0fE02pe/Ypon0HIC+mdE/hNX+pxyU3vMb4f2zgRMqgpEJ6t/JSz1YBdzidi6YQ0nKGjfyeR9jckSLjEgOdI6UCfsyC/BZ49YEIhdTdUUiB6CQJDiCwYl3lssVXBTf38= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786546097; c=relaxed/simple; bh=NHGFnHCWZzH1vnJMLGX/Fcj31gRuYYTG1RpcbvmCyR8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=XBBZlZ1PL+QYeOZ2aKt3YUNkYr8yVxZYmtE73lx+SJ2YBlPmy4GANCOPXRozq8A1Te5GZahiNrDCd1NFjIImrsMoevVKo5rZMFxWJ8KI3PwRvgCBrXXKwynU9kNlJiTXBWazE0Arbix3igeuAdJpS2p2mjEu1ibgxjjGgqZBDYk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=deq.rocks; spf=none smtp.mailfrom=deq.rocks; dkim=pass (2048-bit key) header.d=deq.rocks header.i=@deq.rocks header.b=cDMp2hft; arc=none smtp.client-ip=91.216.248.212 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=deq.rocks Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=deq.rocks Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=deq.rocks header.i=@deq.rocks header.b="cDMp2hft" From: Andre Eikmeyer DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=deq.rocks; s=securedbylima-20251205; t=1786546084; bh=NHGFnHCWZzH1vnJMLGX/Fcj31gRuYYTG1RpcbvmCyR8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=cDMp2hft0pDfT38+CiQ4hywy4zsuClGl0L0OfHh4CVCvPfsFESh/kvD7Zh2mLtGyC 6HTIkth85rUajAsYJnJuI5Mpy8mqnAW2FN/wWO+8ZW1wt0lVKTAn5fyvzH6BvKBbEo jwhL9pnkVDq5Zz0SdJaPOxAJNS4XuYs1IvtXgSZyoCpjGC2txmAIFMplCer/ZXhrnb dEZeaaKM5EQJQ4gcNSPoW7j1LoIQ98pypgnbviaNSu9Ls31ilPqHDTbUDtJoDpmU7Q alCioqTKlukCNRe8NLpaRgijR6Vxe9F74Q1F2ZfKQs4iNFDewT5MyYQ8c+wjlqjphd MUO8e7uEB0PEw== To: platform-driver-x86@vger.kernel.org, amd-gfx@lists.freedesktop.org, linux-sound@vger.kernel.org Cc: Atharva Tiwari , Hans de Goede , =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= , Alex Deucher , =?UTF-8?q?Christian=20K=C3=B6nig?= , David Airlie , Simona Vetter , Kenneth Feng , Jaroslav Kysela , Takashi Iwai , Takashi Iwai , Harry Wentland , Leo Li , dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, Andre Eikmeyer Subject: [PATCH v3 2/3] drm/amdgpu: add Apple GMUX runtime PM support Date: Wed, 12 Aug 2026 16:47:49 +0200 Message-ID: <20260812144750.36797-3-dev@deq.rocks> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260812144750.36797-1-dev@deq.rocks> References: <20260812144221.35877-1-dev@deq.rocks> <20260812144750.36797-1-dev@deq.rocks> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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. Signed-off-by: Andre Eikmeyer --- 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/amdg= pu/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 *a= dev); 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/a= md/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 #include #include +#include #include #include #include @@ -568,6 +569,22 @@ bool amdgpu_device_supports_px(struct amdgpu_device *a= dev) return false; } =20 +static const struct dmi_system_id amdgpu_gmux_runpm_dmi_table[] =3D { + { + .matches =3D { + 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 reso= urces * @@ -631,6 +648,9 @@ void amdgpu_device_detect_runtime_pm_mode(struct amdgpu= _device *adev) /* enable PX as runtime mode */ adev->pm.rpm_mode =3D AMDGPU_RUNPM_PX; dev_info(adev->dev, "Using ATPX for runtime pm\n"); + } else if (amdgpu_device_supports_gmux(adev)) { + adev->pm.rpm_mode =3D 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 =3D AMDGPU_RUNPM_BOCO; @@ -3711,7 +3731,7 @@ int amdgpu_device_init(struct amdgpu_device *adev, { struct pci_dev *pdev =3D adev->pdev; int r, i; - bool px =3D false; + bool gmux, px =3D false; u32 max_MBps; int tmp; =20 @@ -4144,13 +4164,14 @@ fence_driver_init: vga_client_register(adev->pdev, amdgpu_device_vga_set_decode); =20 px =3D amdgpu_device_supports_px(adev); + gmux =3D amdgpu_device_supports_gmux(adev); =20 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); =20 - if (px) + if (px || gmux) vga_switcheroo_init_domain_pm_ops(adev->dev, &adev->vga_pm_domain); =20 adev->pm_nb.notifier_call =3D 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; =20 amdgpu_device_ip_fini(adev); amdgpu_fence_driver_sw_fini(adev); @@ -4309,12 +4330,13 @@ void amdgpu_device_fini_sw(struct amdgpu_device *ad= ev) adev->xcp_mgr =3D NULL; =20 px =3D amdgpu_device_supports_px(adev); + gmux =3D amdgpu_device_supports_gmux(adev); =20 if (px || (!dev_is_removable(&adev->pdev->dev) && apple_gmux_detect(NULL, NULL))) vga_switcheroo_unregister_client(adev->pdev); =20 - if (px) + if (px || gmux) vga_switcheroo_fini_domain_pm_ops(adev->dev); =20 if ((adev->pdev->class >> 8) =3D=3D 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); =20 if (adev->pm.rpm_mode !=3D 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 =3D=3D 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 =3D=3D AMDGPU_RUNPM_GMUX) && + pm_runtime_suspended(dev)) return 1; =20 /* if we will not support s3 or s2i for the device @@ -2860,7 +2863,8 @@ static int amdgpu_pmops_runtime_suspend(struct device= *dev) } =20 adev->in_runpm =3D true; - if (adev->pm.rpm_mode =3D=3D AMDGPU_RUNPM_PX) + if (adev->pm.rpm_mode =3D=3D AMDGPU_RUNPM_PX || + adev->pm.rpm_mode =3D=3D AMDGPU_RUNPM_GMUX) drm_dev->switch_power_state =3D DRM_SWITCH_POWER_CHANGING; =20 /* @@ -2887,8 +2891,9 @@ static int amdgpu_pmops_runtime_suspend(struct device= *dev) if (adev->pm.rpm_mode =3D=3D AMDGPU_RUNPM_BOCO) adev->mp1_state =3D PP_MP1_STATE_NONE; =20 - if (adev->pm.rpm_mode =3D=3D AMDGPU_RUNPM_PX) { - /* Only need to handle PCI state in the driver for ATPX + if (adev->pm.rpm_mode =3D=3D AMDGPU_RUNPM_PX || + adev->pm.rpm_mode =3D=3D 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 devic= e *dev) if (!pci_device_is_present(adev->pdev)) adev->no_hw_access =3D true; =20 - if (adev->pm.rpm_mode =3D=3D AMDGPU_RUNPM_PX) { + if (adev->pm.rpm_mode =3D=3D AMDGPU_RUNPM_PX || + adev->pm.rpm_mode =3D=3D AMDGPU_RUNPM_GMUX) { drm_dev->switch_power_state =3D DRM_SWITCH_POWER_CHANGING; =20 - /* 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 devic= e *dev) } ret =3D amdgpu_device_resume(drm_dev, false); if (ret) { - if (adev->pm.rpm_mode =3D=3D AMDGPU_RUNPM_PX) + if (adev->pm.rpm_mode =3D=3D AMDGPU_RUNPM_PX || + adev->pm.rpm_mode =3D=3D AMDGPU_RUNPM_GMUX) pci_disable_device(pdev); return ret; } =20 - if (adev->pm.rpm_mode =3D=3D AMDGPU_RUNPM_PX) + if (adev->pm.rpm_mode =3D=3D AMDGPU_RUNPM_PX || + adev->pm.rpm_mode =3D=3D AMDGPU_RUNPM_GMUX) drm_dev->switch_power_state =3D DRM_SWITCH_POWER_ON; =20 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, --=20 2.55.0 From nobody Tue Sep 29 04:09:38 2026 Received: from bulk0.mail-out.lima-city.de (bulk0.mail-out.lima-city.de [91.216.248.212]) (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 CEA92468C29; Wed, 12 Aug 2026 14:48:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.216.248.212 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786546098; cv=none; b=mwWlZaZAquNQJVBJk25G3V2yEwc2apkTa+wwAQL+/NmjPHZVFhUcb7uB7BbfIw80oWP0Q1pftdn/jctFJcNWDqC0M6sNBH91CnkhNZwrFdtyiyTxpJeCLM+k/EljO8nD4IYtuuo8AbyAeSGJ1LNIYO6tMIpnffBsm9zGhAVQUAI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786546098; c=relaxed/simple; bh=Nhd5BwNT8JgJuZ2WolA1jVTq2wOYamSWOsjVsd/H9Ns=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=gY3uD5xCSPQkm1L7vLWiHBF82mZLPnCG1DgJbb3HArdgPHJxe3nm27CbgFHwXd0XA5AtRESw5VAbw3Xmw15Zu1mKoTQJe7pvFa+Wu/YXbateJZxe5iTxJ4bqoMn2vqHP0Vkvt+JYdCzqpUMURH9pLEo6nU9IQJUcsHnkJb6OzOs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=deq.rocks; spf=none smtp.mailfrom=deq.rocks; dkim=pass (2048-bit key) header.d=deq.rocks header.i=@deq.rocks header.b=G7sLTTjm; arc=none smtp.client-ip=91.216.248.212 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=deq.rocks Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=deq.rocks Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=deq.rocks header.i=@deq.rocks header.b="G7sLTTjm" From: Andre Eikmeyer DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=deq.rocks; s=securedbylima-20251205; t=1786546088; bh=Nhd5BwNT8JgJuZ2WolA1jVTq2wOYamSWOsjVsd/H9Ns=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=G7sLTTjmWZM77W1pxZTDwK11BjmuVuQOoX/qZAwHg4i3kXhejBUvyLqf0tsDq6zTT orFa1BH5G/2zLBIUZOWSdOaPgtfMuxzwrA5zvTFGU5nIAripMP630j9Ntxtxf8vSlz uXqHFdw1vY9mqIfiWykKccWOU9Qeajs+Q1/vkRBVGkFEAiSN8kgekA95Jg86A3cyhe PSO04dCWDFNpq2P7kbqCaq+c3C3F9NSTj0JgqS/uO/H/0HLBZ0nEywpROo8BpsrhaE LNaZdKTfa+5i067+x2FGRC2FMPn4PwwrZSz+Rq3saZjX030D09C70NzJF4tmKKkLR2 h3TiY1KAQD9Ew== To: platform-driver-x86@vger.kernel.org, amd-gfx@lists.freedesktop.org, linux-sound@vger.kernel.org Cc: Atharva Tiwari , Hans de Goede , =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= , Alex Deucher , =?UTF-8?q?Christian=20K=C3=B6nig?= , David Airlie , Simona Vetter , Kenneth Feng , Jaroslav Kysela , Takashi Iwai , Takashi Iwai , Harry Wentland , Leo Li , dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, Andre Eikmeyer Subject: [PATCH v3 3/3] ALSA: hda: allow direct complete with a powered-off GPU Date: Wed, 12 Aug 2026 16:47:50 +0200 Message-ID: <20260812144750.36797-4-dev@deq.rocks> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260812144750.36797-1-dev@deq.rocks> References: <20260812144221.35877-1-dev@deq.rocks> <20260812144750.36797-1-dev@deq.rocks> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The HDA controller normally needs different WAKEEN settings for runtime and system suspend, so azx_prepare() prevents direct complete. For a switcheroo audio client whose bound GPU is already runtime suspended and switched off, however, the controller is physically inaccessible and cannot signal wake events. Resuming the HDA function during system suspend also acquires its runtime PM supplier. This powers the discrete GPU back on only to suspend it again and can expose failures while restoring an otherwise unused GPU. Direct complete is allowed when the bound VGA device is both runtime suspended and reported off by vga_switcheroo. Active GPUs and HDA controllers without a switcheroo binding retain the existing WAKEEN transition. This was tested as part of the MacBookPro15,1 hybrid graphics series on both the 2018 and 2019 revisions. The discrete GPU remains powered off across system suspend when it is unused, and suspend and resume complete successfully. Reviewed-by: Takashi Iwai Signed-off-by: Andre Eikmeyer --- sound/hda/controllers/intel.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/sound/hda/controllers/intel.c b/sound/hda/controllers/intel.c index 28c55c5..194d962 100644 --- a/sound/hda/controllers/intel.c +++ b/sound/hda/controllers/intel.c @@ -334,9 +334,11 @@ enum { #ifdef SUPPORT_VGA_SWITCHEROO #define use_vga_switcheroo(chip) ((chip)->use_vga_switcheroo) #define needs_eld_notify_link(chip) ((chip)->bus.keep_power) +static bool azx_vga_is_powered_off(struct azx *chip); #else #define use_vga_switcheroo(chip) 0 #define needs_eld_notify_link(chip) false +#define azx_vga_is_powered_off(chip) false #endif =20 static const char * const driver_short_names[] =3D { @@ -1025,6 +1027,10 @@ static int azx_prepare(struct device *dev) return 0; =20 chip =3D card->private_data; + /* A positive return allows the PM core to use direct complete. */ + if (azx_vga_is_powered_off(chip)) + return 1; + chip->pm_prepared =3D 1; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); =20 @@ -1185,6 +1191,24 @@ static int azx_probe_continue(struct azx *chip); #ifdef SUPPORT_VGA_SWITCHEROO static struct pci_dev *get_bound_vga(struct pci_dev *pci); =20 +static bool azx_vga_is_powered_off(struct azx *chip) +{ + struct pci_dev *pci; + bool powered_off =3D false; + + if (!use_vga_switcheroo(container_of(chip, struct hda_intel, chip))) + return false; + + pci =3D get_bound_vga(chip->pci); + if (pci) { + powered_off =3D pm_runtime_suspended(&pci->dev) && + vga_switcheroo_get_client_state(pci) =3D=3D VGA_SWITCHEROO_OFF; + pci_dev_put(pci); + } + + return powered_off; +} + static void azx_vs_set_state(struct pci_dev *pci, enum vga_switcheroo_state state) { --=20 2.55.0