* [PATCH 0/2] drm/amdgpu: wake a powered-off dGPU on a dock hotplug notify
@ 2026-10-29 15:14 Mike Lothian
2026-10-29 15:14 ` [PATCH 1/2] drm/amdgpu: runtime resume dGPU on ACPI notify from its own node Mike Lothian
2026-10-29 15:14 ` [PATCH 2/2] drm/amdgpu: handle broken dGPU hotplug GPE on ASUS ROG Strix G513QY Mike Lothian
0 siblings, 2 replies; 6+ messages in thread
From: Mike Lothian @ 2026-10-29 15:14 UTC (permalink / raw)
To: amd-gfx, alexander.deucher, christian.koenig
Cc: superm1, dri-devel, linux-acpi, linux-kernel
On an ASUS ROG Strix G513QY the USB-C DP alt mode lanes are driven by the Navi 22, and the firmware signals a dock being attached with Notify(<dGPU node>, 0x81) from a level triggered GPE. Nothing in the kernel listens on the dGPU's own ACPI node, so with the dGPU in D3cold the notify is lost, no hotplug reaches userspace and the external displays stay dark
1/2 adds a notify handler on the dGPU's ACPI companion for BOCO devices that requests a runtime resume. Runtime resume already re-detects every link and sends the hotplug event
2/2 handles a board where the firmware method cannot deliver the notify at all. The G513QY's CPM table notifies \_SB.PCI0.GPP0.VGA, which does not exist because the dGPU sits behind an on-package PCIe switch, so _L05 aborts with AE_NOT_FOUND. On a DMI match, and only if that path does not resolve, amdgpu takes over the GPE and does what the notify would have done
Tested on a G513QY with a USB-C dock: with both patches and no table override the displays come up after the dGPU has been left in D3cold, and the _L05 errors are gone. 2/2 is only a DMI entry and a handler, so other boards sharing the CPM table can be added to the list
The patches were written with Claude Code assistance, as the Assisted-by tags say
Mike Lothian (2):
drm/amdgpu: runtime resume dGPU on ACPI notify from its own node
drm/amdgpu: handle broken dGPU hotplug GPE on ASUS ROG Strix G513QY
drivers/gpu/drm/amd/amdgpu/amdgpu.h | 4 +
drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c | 132 +++++++++++++++++++++++
2 files changed, 136 insertions(+)
--
2.56.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 1/2] drm/amdgpu: runtime resume dGPU on ACPI notify from its own node
2026-10-29 15:14 [PATCH 0/2] drm/amdgpu: wake a powered-off dGPU on a dock hotplug notify Mike Lothian
@ 2026-10-29 15:14 ` Mike Lothian
2026-10-29 15:20 ` Mario Limonciello
2026-10-29 15:14 ` [PATCH 2/2] drm/amdgpu: handle broken dGPU hotplug GPE on ASUS ROG Strix G513QY Mike Lothian
1 sibling, 1 reply; 6+ messages in thread
From: Mike Lothian @ 2026-10-29 15:14 UTC (permalink / raw)
To: amd-gfx, alexander.deucher, christian.koenig
Cc: superm1, dri-devel, linux-acpi, linux-kernel
On BOCO platforms the SBIOS can signal a display hotplug on a powered
off dGPU by notifying the dGPU's ACPI node. On the ASUS ROG Strix G513QY
the USB-C DP alt mode lanes are driven by the Navi 22, and the CPM
D3cold table handles the HPD GPE with only:
Method (_L05) { Notify (\_SB.PCI0.GPP0.VGA, 0x81) }
Nothing in Linux listens on that node: ATIF is bound to the iGPU and the
dGPU node is not an ACPI video bus. If the dGPU is in D3cold when a dock
is attached it stays off, no hotplug reaches userspace, the external
displays stay dark, and the level-triggered GPE keeps firing until the
dock is removed.
Install an ACPI device notify handler on the dGPU's companion when BOCO
is used, and request a runtime resume on 0x81. Runtime resume already
re-detects all links and sends a hotplug event, so the new displays are
picked up; the device autosuspends again if nothing is enabled.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Mike Lothian <mike@fireburn.co.uk>
---
drivers/gpu/drm/amd/amdgpu/amdgpu.h | 1 +
drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c | 31 ++++++++++++++++++++++++
2 files changed, 32 insertions(+)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index 7974f9b7944f..deb63122828d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -641,6 +641,7 @@ struct amdgpu_device {
bool need_swiotlb;
bool accel_working;
struct notifier_block acpi_nb;
+ bool acpi_dgpu_notify;
struct notifier_block pm_nb;
struct amdgpu_i2c_chan *i2c_bus[AMDGPU_MAX_I2C_BUS];
struct debugfs_blob_wrapper debugfs_vbios_blob;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
index 7f5abb03be1b..a4041f90b374 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
@@ -1280,6 +1280,23 @@ static int amdgpu_acpi_event(struct notifier_block *nb,
return amdgpu_atif_handler(adev, entry);
}
+/*
+ * On BOCO platforms the SBIOS signals display hotplug on a powered-off dGPU
+ * (e.g. USB-C DP alt mode HPD wired to the dGPU) with Notify(<dGPU>, 0x81)
+ * on the dGPU's own ACPI node. Nothing else listens there, so wake the
+ * device; runtime resume re-detects all links and sends a hotplug event.
+ */
+static void amdgpu_acpi_dgpu_notify(acpi_handle handle, u32 event, void *data)
+{
+ struct amdgpu_device *adev = data;
+
+ if (event != ACPI_VIDEO_NOTIFY_PROBE)
+ return;
+
+ dev_dbg(adev->dev, "ACPI notify 0x%x, requesting runtime resume\n", event);
+ pm_request_resume(adev->dev);
+}
+
/* Call all ACPI methods here */
/**
* amdgpu_acpi_init - init driver acpi support
@@ -1325,6 +1342,14 @@ int amdgpu_acpi_init(struct amdgpu_device *adev)
adev->acpi_nb.notifier_call = amdgpu_acpi_event;
register_acpi_notifier(&adev->acpi_nb);
+ if (!(adev->flags & AMD_IS_APU) && ACPI_COMPANION(adev->dev) &&
+ adev->pm.rpm_mode == AMDGPU_RUNPM_BOCO)
+ adev->acpi_dgpu_notify =
+ !acpi_dev_install_notify_handler(ACPI_COMPANION(adev->dev),
+ ACPI_DEVICE_NOTIFY,
+ amdgpu_acpi_dgpu_notify,
+ adev);
+
return 0;
}
@@ -1344,6 +1369,12 @@ void amdgpu_acpi_get_backlight_caps(struct amdgpu_dm_backlight_caps *caps)
*/
void amdgpu_acpi_fini(struct amdgpu_device *adev)
{
+ if (adev->acpi_dgpu_notify) {
+ acpi_dev_remove_notify_handler(ACPI_COMPANION(adev->dev),
+ ACPI_DEVICE_NOTIFY,
+ amdgpu_acpi_dgpu_notify);
+ adev->acpi_dgpu_notify = false;
+ }
unregister_acpi_notifier(&adev->acpi_nb);
}
--
2.56.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 2/2] drm/amdgpu: handle broken dGPU hotplug GPE on ASUS ROG Strix G513QY
2026-10-29 15:14 [PATCH 0/2] drm/amdgpu: wake a powered-off dGPU on a dock hotplug notify Mike Lothian
2026-10-29 15:14 ` [PATCH 1/2] drm/amdgpu: runtime resume dGPU on ACPI notify from its own node Mike Lothian
@ 2026-10-29 15:14 ` Mike Lothian
2026-10-29 15:24 ` Mario Limonciello
1 sibling, 1 reply; 6+ messages in thread
From: Mike Lothian @ 2026-10-29 15:14 UTC (permalink / raw)
To: amd-gfx, alexander.deucher, christian.koenig
Cc: superm1, dri-devel, linux-acpi, linux-kernel
The AMD CPM D3cold table on the G513QY (BIOS 335) handles the dGPU
hotplug GPE with:
Method (_L05) { Notify (\_SB.PCI0.GPP0.VGA, 0x81) }
On this board the Navi 22 sits behind its on-package PCIe switch, so
the dGPU node is \_SB.PCI0.GPP0.SWUS.SWDS.VGA_ and every hotplug on the
USB-C DP alt mode port while the dGPU is in D3cold logs:
ACPI BIOS Error (bug): Could not resolve symbol [\_SB.PCI0.GPP0.VGA], AE_NOT_FOUND
ACPI Error: Aborting method \_GPE._L05 due to previous error (AE_NOT_FOUND)
ACPI Error: AE_NOT_FOUND, while evaluating GPE method [_L05]
The notify is lost, the dGPU stays powered off and the external
displays stay dark. Masking the GPE (acpi_mask_gpe=0x05), the usual
workaround, removes the errors but also the hotplug.
On boards listed in a DMI table, and only when the notify target does
not resolve, install a handler for the GPE in place of the _Lxx method.
It requests a runtime resume of the dGPU, which re-detects all links and
sends a hotplug event, and re-arms the level-triggered GPE from a
delayed work so it cannot storm while the dGPU powers up. If the
firmware is fixed, or the path is supplied by an SSDT override, the
firmware method is left in charge.
Other boards using the same CPM table may need adding to the list.
Link: https://forum.endeavouros.com/t/boots-into-black-screen-unresponsive-amd/49430
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Mike Lothian <mike@fireburn.co.uk>
---
drivers/gpu/drm/amd/amdgpu/amdgpu.h | 3 +
drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c | 103 ++++++++++++++++++++++-
2 files changed, 105 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index deb63122828d..d8a7fea8be9a 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -642,6 +642,9 @@ struct amdgpu_device {
bool accel_working;
struct notifier_block acpi_nb;
bool acpi_dgpu_notify;
+ bool acpi_hpd_gpe_installed;
+ u32 acpi_hpd_gpe;
+ struct delayed_work acpi_hpd_gpe_work;
struct notifier_block pm_nb;
struct amdgpu_i2c_chan *i2c_bus[AMDGPU_MAX_I2C_BUS];
struct debugfs_blob_wrapper debugfs_vbios_blob;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
index a4041f90b374..182791f4cc86 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
@@ -25,6 +25,7 @@
#include <linux/pci.h>
#include <linux/acpi.h>
#include <linux/backlight.h>
+#include <linux/dmi.h>
#include <linux/slab.h>
#include <linux/xarray.h>
#include <linux/power_supply.h>
@@ -1297,6 +1298,103 @@ static void amdgpu_acpi_dgpu_notify(acpi_handle handle, u32 event, void *data)
pm_request_resume(adev->dev);
}
+/*
+ * Some AMD CPM D3cold tables handle the dGPU hotplug GPE with
+ * Notify(\_SB.PCI0.GPP0.VGA, 0x81), but on boards where the dGPU sits behind
+ * an on-package PCIe switch the node is \_SB.PCI0.GPP0.SWUS.SWDS.VGA_, so the
+ * _Lxx method aborts with AE_NOT_FOUND and the dGPU is never woken. On those
+ * boards take over the GPE and do what the notify would have done.
+ */
+struct amdgpu_acpi_hpd_gpe_quirk {
+ const char *notify_path;
+ u32 gpe;
+};
+
+static const struct amdgpu_acpi_hpd_gpe_quirk g513qy_hpd_gpe = {
+ .notify_path = "\\_SB.PCI0.GPP0.VGA",
+ .gpe = 0x05,
+};
+
+static const struct dmi_system_id amdgpu_acpi_hpd_gpe_quirks[] = {
+ {
+ .ident = "ASUS ROG Strix G513QY",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+ DMI_MATCH(DMI_BOARD_NAME, "G513QY"),
+ },
+ .driver_data = (void *)&g513qy_hpd_gpe,
+ },
+ {}
+};
+
+/* GPE handlers run in interrupt context; the GPE stays disabled until the work re-arms it */
+static u32 amdgpu_acpi_hpd_gpe_handler(acpi_handle gpe_device, u32 gpe, void *data)
+{
+ struct amdgpu_device *adev = data;
+
+ pm_request_resume(adev->dev);
+ schedule_delayed_work(&adev->acpi_hpd_gpe_work, msecs_to_jiffies(500));
+
+ return 0;
+}
+
+/*
+ * Re-arm after a delay: the GPE is level triggered and may stay asserted
+ * while the dGPU powers up, so this bounds the rate at which it refires.
+ */
+static void amdgpu_acpi_hpd_gpe_work(struct work_struct *work)
+{
+ struct amdgpu_device *adev =
+ container_of(work, struct amdgpu_device, acpi_hpd_gpe_work.work);
+
+ acpi_finish_gpe(NULL, adev->acpi_hpd_gpe);
+}
+
+static void amdgpu_acpi_hpd_gpe_init(struct amdgpu_device *adev)
+{
+ const struct amdgpu_acpi_hpd_gpe_quirk *quirk;
+ const struct dmi_system_id *id;
+ acpi_handle handle;
+
+ id = dmi_first_match(amdgpu_acpi_hpd_gpe_quirks);
+ if (!id)
+ return;
+ quirk = id->driver_data;
+
+ /* Firmware (or a table override) already provides the notify target */
+ if (ACPI_SUCCESS(acpi_get_handle(NULL, quirk->notify_path, &handle)))
+ return;
+
+ adev->acpi_hpd_gpe = quirk->gpe;
+ INIT_DELAYED_WORK(&adev->acpi_hpd_gpe_work, amdgpu_acpi_hpd_gpe_work);
+ if (ACPI_FAILURE(acpi_install_gpe_handler(NULL, quirk->gpe,
+ ACPI_GPE_LEVEL_TRIGGERED,
+ amdgpu_acpi_hpd_gpe_handler,
+ adev)))
+ return;
+ if (ACPI_FAILURE(acpi_enable_gpe(NULL, quirk->gpe))) {
+ acpi_remove_gpe_handler(NULL, quirk->gpe,
+ amdgpu_acpi_hpd_gpe_handler);
+ return;
+ }
+
+ adev->acpi_hpd_gpe_installed = true;
+ dev_info(adev->dev, "handling dGPU hotplug GPE 0x%02x (%s missing)\n",
+ quirk->gpe, quirk->notify_path);
+}
+
+static void amdgpu_acpi_hpd_gpe_fini(struct amdgpu_device *adev)
+{
+ if (!adev->acpi_hpd_gpe_installed)
+ return;
+
+ acpi_disable_gpe(NULL, adev->acpi_hpd_gpe);
+ cancel_delayed_work_sync(&adev->acpi_hpd_gpe_work);
+ acpi_remove_gpe_handler(NULL, adev->acpi_hpd_gpe,
+ amdgpu_acpi_hpd_gpe_handler);
+ adev->acpi_hpd_gpe_installed = false;
+}
+
/* Call all ACPI methods here */
/**
* amdgpu_acpi_init - init driver acpi support
@@ -1343,12 +1441,14 @@ int amdgpu_acpi_init(struct amdgpu_device *adev)
register_acpi_notifier(&adev->acpi_nb);
if (!(adev->flags & AMD_IS_APU) && ACPI_COMPANION(adev->dev) &&
- adev->pm.rpm_mode == AMDGPU_RUNPM_BOCO)
+ adev->pm.rpm_mode == AMDGPU_RUNPM_BOCO) {
adev->acpi_dgpu_notify =
!acpi_dev_install_notify_handler(ACPI_COMPANION(adev->dev),
ACPI_DEVICE_NOTIFY,
amdgpu_acpi_dgpu_notify,
adev);
+ amdgpu_acpi_hpd_gpe_init(adev);
+ }
return 0;
}
@@ -1369,6 +1469,7 @@ void amdgpu_acpi_get_backlight_caps(struct amdgpu_dm_backlight_caps *caps)
*/
void amdgpu_acpi_fini(struct amdgpu_device *adev)
{
+ amdgpu_acpi_hpd_gpe_fini(adev);
if (adev->acpi_dgpu_notify) {
acpi_dev_remove_notify_handler(ACPI_COMPANION(adev->dev),
ACPI_DEVICE_NOTIFY,
--
2.56.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 1/2] drm/amdgpu: runtime resume dGPU on ACPI notify from its own node
2026-10-29 15:14 ` [PATCH 1/2] drm/amdgpu: runtime resume dGPU on ACPI notify from its own node Mike Lothian
@ 2026-10-29 15:20 ` Mario Limonciello
2026-10-29 16:05 ` Alex Deucher
0 siblings, 1 reply; 6+ messages in thread
From: Mario Limonciello @ 2026-10-29 15:20 UTC (permalink / raw)
To: Mike Lothian, amd-gfx, alexander.deucher, christian.koenig
Cc: dri-devel, linux-acpi, linux-kernel
On 10/29/26 10:14, Mike Lothian wrote:
> On BOCO platforms the SBIOS can signal a display hotplug on a powered
> off dGPU by notifying the dGPU's ACPI node. On the ASUS ROG Strix G513QY
> the USB-C DP alt mode lanes are driven by the Navi 22, and the CPM
> D3cold table handles the HPD GPE with only:
>
> Method (_L05) { Notify (\_SB.PCI0.GPP0.VGA, 0x81) }
>
> Nothing in Linux listens on that node: ATIF is bound to the iGPU and the
> dGPU node is not an ACPI video bus. If the dGPU is in D3cold when a dock
> is attached it stays off, no hotplug reaches userspace, the external
> displays stay dark, and the level-triggered GPE keeps firing until the
> dock is removed.
>
> Install an ACPI device notify handler on the dGPU's companion when BOCO
> is used, and request a runtime resume on 0x81. Runtime resume already
> re-detects all links and sends a hotplug event, so the new displays are
> picked up; the device autosuspends again if nothing is enabled.
>
> Assisted-by: Claude:claude-opus-5-5
> Signed-off-by: Mike Lothian <mike@fireburn.co.uk>
> ---
> drivers/gpu/drm/amd/amdgpu/amdgpu.h | 1 +
> drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c | 31 ++++++++++++++++++++++++
> 2 files changed, 32 insertions(+)
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> index 7974f9b7944f..deb63122828d 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> @@ -641,6 +641,7 @@ struct amdgpu_device {
> bool need_swiotlb;
> bool accel_working;
> struct notifier_block acpi_nb;
> + bool acpi_dgpu_notify;
> struct notifier_block pm_nb;
> struct amdgpu_i2c_chan *i2c_bus[AMDGPU_MAX_I2C_BUS];
> struct debugfs_blob_wrapper debugfs_vbios_blob;
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
> index 7f5abb03be1b..a4041f90b374 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
> @@ -1280,6 +1280,23 @@ static int amdgpu_acpi_event(struct notifier_block *nb,
> return amdgpu_atif_handler(adev, entry);
> }
>
> +/*
> + * On BOCO platforms the SBIOS signals display hotplug on a powered-off dGPU
Although your system is a BOCO platform; I do think this same thing for
this signaling to wakeup could apply to a BACO system too.
> + * (e.g. USB-C DP alt mode HPD wired to the dGPU) with Notify(<dGPU>, 0x81)
> + * on the dGPU's own ACPI node. Nothing else listens there, so wake the
> + * device; runtime resume re-detects all links and sends a hotplug event.
> + */
> +static void amdgpu_acpi_dgpu_notify(acpi_handle handle, u32 event, void *data)
> +{
> + struct amdgpu_device *adev = data;
> +
> + if (event != ACPI_VIDEO_NOTIFY_PROBE)
> + return;
> +
> + dev_dbg(adev->dev, "ACPI notify 0x%x, requesting runtime resume\n", event);
> + pm_request_resume(adev->dev);
> +}
> +
> /* Call all ACPI methods here */
> /**
> * amdgpu_acpi_init - init driver acpi support
> @@ -1325,6 +1342,14 @@ int amdgpu_acpi_init(struct amdgpu_device *adev)
> adev->acpi_nb.notifier_call = amdgpu_acpi_event;
> register_acpi_notifier(&adev->acpi_nb);
>
> + if (!(adev->flags & AMD_IS_APU) && ACPI_COMPANION(adev->dev) &&
> + adev->pm.rpm_mode == AMDGPU_RUNPM_BOCO)
I'd install the notifier for BACO as well.
> + adev->acpi_dgpu_notify =
> + !acpi_dev_install_notify_handler(ACPI_COMPANION(adev->dev),
> + ACPI_DEVICE_NOTIFY,
> + amdgpu_acpi_dgpu_notify,
> + adev);
> +
> return 0;
> }
>
> @@ -1344,6 +1369,12 @@ void amdgpu_acpi_get_backlight_caps(struct amdgpu_dm_backlight_caps *caps)
> */
> void amdgpu_acpi_fini(struct amdgpu_device *adev)
> {
> + if (adev->acpi_dgpu_notify) {
> + acpi_dev_remove_notify_handler(ACPI_COMPANION(adev->dev),
> + ACPI_DEVICE_NOTIFY,
> + amdgpu_acpi_dgpu_notify);
> + adev->acpi_dgpu_notify = false;
> + }
> unregister_acpi_notifier(&adev->acpi_nb);
> }
>
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 2/2] drm/amdgpu: handle broken dGPU hotplug GPE on ASUS ROG Strix G513QY
2026-10-29 15:14 ` [PATCH 2/2] drm/amdgpu: handle broken dGPU hotplug GPE on ASUS ROG Strix G513QY Mike Lothian
@ 2026-10-29 15:24 ` Mario Limonciello
0 siblings, 0 replies; 6+ messages in thread
From: Mario Limonciello @ 2026-10-29 15:24 UTC (permalink / raw)
To: Mike Lothian, amd-gfx, alexander.deucher, christian.koenig,
Rafael J. Wysocki
Cc: dri-devel, linux-acpi, linux-kernel
+Rafael
On 10/29/26 10:14, Mike Lothian wrote:
> The AMD CPM D3cold table on the G513QY (BIOS 335) handles the dGPU
> hotplug GPE with:
>
> Method (_L05) { Notify (\_SB.PCI0.GPP0.VGA, 0x81) }
>
> On this board the Navi 22 sits behind its on-package PCIe switch, so
> the dGPU node is \_SB.PCI0.GPP0.SWUS.SWDS.VGA_ and every hotplug on the
> USB-C DP alt mode port while the dGPU is in D3cold logs:
>
> ACPI BIOS Error (bug): Could not resolve symbol [\_SB.PCI0.GPP0.VGA], AE_NOT_FOUND
> ACPI Error: Aborting method \_GPE._L05 due to previous error (AE_NOT_FOUND)
> ACPI Error: AE_NOT_FOUND, while evaluating GPE method [_L05]
>
> The notify is lost, the dGPU stays powered off and the external
> displays stay dark. Masking the GPE (acpi_mask_gpe=0x05), the usual
> workaround, removes the errors but also the hotplug.
>
> On boards listed in a DMI table, and only when the notify target does
> not resolve, install a handler for the GPE in place of the _Lxx method.
> It requests a runtime resume of the dGPU, which re-detects all links and
> sends a hotplug event, and re-arms the level-triggered GPE from a
> delayed work so it cannot storm while the dGPU powers up. If the
> firmware is fixed, or the path is supplied by an SSDT override, the
> firmware method is left in charge.
>
> Other boards using the same CPM table may need adding to the list.
>
> Link: https://forum.endeavouros.com/t/boots-into-black-screen-unresponsive-amd/49430
> Assisted-by: Claude:claude-opus-5-5
> Signed-off-by: Mike Lothian <mike@fireburn.co.uk>
Can you please post an acpidump to a kernel bugzilla or drm bug
associated with this issue?
This generally feels like an ACPI interpreter issue to me.
> ---
> drivers/gpu/drm/amd/amdgpu/amdgpu.h | 3 +
> drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c | 103 ++++++++++++++++++++++-
> 2 files changed, 105 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> index deb63122828d..d8a7fea8be9a 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> @@ -642,6 +642,9 @@ struct amdgpu_device {
> bool accel_working;
> struct notifier_block acpi_nb;
> bool acpi_dgpu_notify;
> + bool acpi_hpd_gpe_installed;
> + u32 acpi_hpd_gpe;
> + struct delayed_work acpi_hpd_gpe_work;
> struct notifier_block pm_nb;
> struct amdgpu_i2c_chan *i2c_bus[AMDGPU_MAX_I2C_BUS];
> struct debugfs_blob_wrapper debugfs_vbios_blob;
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
> index a4041f90b374..182791f4cc86 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
> @@ -25,6 +25,7 @@
> #include <linux/pci.h>
> #include <linux/acpi.h>
> #include <linux/backlight.h>
> +#include <linux/dmi.h>
> #include <linux/slab.h>
> #include <linux/xarray.h>
> #include <linux/power_supply.h>
> @@ -1297,6 +1298,103 @@ static void amdgpu_acpi_dgpu_notify(acpi_handle handle, u32 event, void *data)
> pm_request_resume(adev->dev);
> }
>
> +/*
> + * Some AMD CPM D3cold tables handle the dGPU hotplug GPE with
> + * Notify(\_SB.PCI0.GPP0.VGA, 0x81), but on boards where the dGPU sits behind
> + * an on-package PCIe switch the node is \_SB.PCI0.GPP0.SWUS.SWDS.VGA_, so the
> + * _Lxx method aborts with AE_NOT_FOUND and the dGPU is never woken. On those
> + * boards take over the GPE and do what the notify would have done.
> + */
> +struct amdgpu_acpi_hpd_gpe_quirk {
> + const char *notify_path;
> + u32 gpe;
> +};
> +
> +static const struct amdgpu_acpi_hpd_gpe_quirk g513qy_hpd_gpe = {
> + .notify_path = "\\_SB.PCI0.GPP0.VGA",
> + .gpe = 0x05,
> +};
> +
> +static const struct dmi_system_id amdgpu_acpi_hpd_gpe_quirks[] = {
> + {
> + .ident = "ASUS ROG Strix G513QY",
> + .matches = {
> + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
> + DMI_MATCH(DMI_BOARD_NAME, "G513QY"),
> + },
> + .driver_data = (void *)&g513qy_hpd_gpe,
> + },
> + {}
> +};
> +
> +/* GPE handlers run in interrupt context; the GPE stays disabled until the work re-arms it */
> +static u32 amdgpu_acpi_hpd_gpe_handler(acpi_handle gpe_device, u32 gpe, void *data)
> +{
> + struct amdgpu_device *adev = data;
> +
> + pm_request_resume(adev->dev);
> + schedule_delayed_work(&adev->acpi_hpd_gpe_work, msecs_to_jiffies(500));
> +
> + return 0;
> +}
> +
> +/*
> + * Re-arm after a delay: the GPE is level triggered and may stay asserted
> + * while the dGPU powers up, so this bounds the rate at which it refires.
> + */
> +static void amdgpu_acpi_hpd_gpe_work(struct work_struct *work)
> +{
> + struct amdgpu_device *adev =
> + container_of(work, struct amdgpu_device, acpi_hpd_gpe_work.work);
> +
> + acpi_finish_gpe(NULL, adev->acpi_hpd_gpe);
> +}
> +
> +static void amdgpu_acpi_hpd_gpe_init(struct amdgpu_device *adev)
> +{
> + const struct amdgpu_acpi_hpd_gpe_quirk *quirk;
> + const struct dmi_system_id *id;
> + acpi_handle handle;
> +
> + id = dmi_first_match(amdgpu_acpi_hpd_gpe_quirks);
> + if (!id)
> + return;
> + quirk = id->driver_data;
> +
> + /* Firmware (or a table override) already provides the notify target */
> + if (ACPI_SUCCESS(acpi_get_handle(NULL, quirk->notify_path, &handle)))
> + return;
> +
> + adev->acpi_hpd_gpe = quirk->gpe;
> + INIT_DELAYED_WORK(&adev->acpi_hpd_gpe_work, amdgpu_acpi_hpd_gpe_work);
> + if (ACPI_FAILURE(acpi_install_gpe_handler(NULL, quirk->gpe,
> + ACPI_GPE_LEVEL_TRIGGERED,
> + amdgpu_acpi_hpd_gpe_handler,
> + adev)))
> + return;
> + if (ACPI_FAILURE(acpi_enable_gpe(NULL, quirk->gpe))) {
> + acpi_remove_gpe_handler(NULL, quirk->gpe,
> + amdgpu_acpi_hpd_gpe_handler);
> + return;
> + }
> +
> + adev->acpi_hpd_gpe_installed = true;
> + dev_info(adev->dev, "handling dGPU hotplug GPE 0x%02x (%s missing)\n",
> + quirk->gpe, quirk->notify_path);
> +}
> +
> +static void amdgpu_acpi_hpd_gpe_fini(struct amdgpu_device *adev)
> +{
> + if (!adev->acpi_hpd_gpe_installed)
> + return;
> +
> + acpi_disable_gpe(NULL, adev->acpi_hpd_gpe);
> + cancel_delayed_work_sync(&adev->acpi_hpd_gpe_work);
> + acpi_remove_gpe_handler(NULL, adev->acpi_hpd_gpe,
> + amdgpu_acpi_hpd_gpe_handler);
> + adev->acpi_hpd_gpe_installed = false;
> +}
> +
> /* Call all ACPI methods here */
> /**
> * amdgpu_acpi_init - init driver acpi support
> @@ -1343,12 +1441,14 @@ int amdgpu_acpi_init(struct amdgpu_device *adev)
> register_acpi_notifier(&adev->acpi_nb);
>
> if (!(adev->flags & AMD_IS_APU) && ACPI_COMPANION(adev->dev) &&
> - adev->pm.rpm_mode == AMDGPU_RUNPM_BOCO)
> + adev->pm.rpm_mode == AMDGPU_RUNPM_BOCO) {
> adev->acpi_dgpu_notify =
> !acpi_dev_install_notify_handler(ACPI_COMPANION(adev->dev),
> ACPI_DEVICE_NOTIFY,
> amdgpu_acpi_dgpu_notify,
> adev);
> + amdgpu_acpi_hpd_gpe_init(adev);
> + }
>
> return 0;
> }
> @@ -1369,6 +1469,7 @@ void amdgpu_acpi_get_backlight_caps(struct amdgpu_dm_backlight_caps *caps)
> */
> void amdgpu_acpi_fini(struct amdgpu_device *adev)
> {
> + amdgpu_acpi_hpd_gpe_fini(adev);
> if (adev->acpi_dgpu_notify) {
> acpi_dev_remove_notify_handler(ACPI_COMPANION(adev->dev),
> ACPI_DEVICE_NOTIFY,
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 1/2] drm/amdgpu: runtime resume dGPU on ACPI notify from its own node
2026-10-29 15:20 ` Mario Limonciello
@ 2026-10-29 16:05 ` Alex Deucher
0 siblings, 0 replies; 6+ messages in thread
From: Alex Deucher @ 2026-10-29 16:05 UTC (permalink / raw)
To: Mario Limonciello
Cc: Mike Lothian, amd-gfx, alexander.deucher, christian.koenig,
dri-devel, linux-acpi, linux-kernel
On Thu, Oct 29, 2026 at 11:26 AM Mario Limonciello <superm1@kernel.org> wrote:
>
> On 10/29/26 10:14, Mike Lothian wrote:
> > On BOCO platforms the SBIOS can signal a display hotplug on a powered
> > off dGPU by notifying the dGPU's ACPI node. On the ASUS ROG Strix G513QY
> > the USB-C DP alt mode lanes are driven by the Navi 22, and the CPM
> > D3cold table handles the HPD GPE with only:
> >
> > Method (_L05) { Notify (\_SB.PCI0.GPP0.VGA, 0x81) }
> >
> > Nothing in Linux listens on that node: ATIF is bound to the iGPU and the
> > dGPU node is not an ACPI video bus. If the dGPU is in D3cold when a dock
> > is attached it stays off, no hotplug reaches userspace, the external
> > displays stay dark, and the level-triggered GPE keeps firing until the
> > dock is removed.
> >
> > Install an ACPI device notify handler on the dGPU's companion when BOCO
> > is used, and request a runtime resume on 0x81. Runtime resume already
> > re-detects all links and sends a hotplug event, so the new displays are
> > picked up; the device autosuspends again if nothing is enabled.
> >
> > Assisted-by: Claude:claude-opus-5-5
> > Signed-off-by: Mike Lothian <mike@fireburn.co.uk>
> > ---
> > drivers/gpu/drm/amd/amdgpu/amdgpu.h | 1 +
> > drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c | 31 ++++++++++++++++++++++++
> > 2 files changed, 32 insertions(+)
> >
> > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> > index 7974f9b7944f..deb63122828d 100644
> > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> > @@ -641,6 +641,7 @@ struct amdgpu_device {
> > bool need_swiotlb;
> > bool accel_working;
> > struct notifier_block acpi_nb;
> > + bool acpi_dgpu_notify;
> > struct notifier_block pm_nb;
> > struct amdgpu_i2c_chan *i2c_bus[AMDGPU_MAX_I2C_BUS];
> > struct debugfs_blob_wrapper debugfs_vbios_blob;
> > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
> > index 7f5abb03be1b..a4041f90b374 100644
> > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
> > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
> > @@ -1280,6 +1280,23 @@ static int amdgpu_acpi_event(struct notifier_block *nb,
> > return amdgpu_atif_handler(adev, entry);
> > }
> >
> > +/*
> > + * On BOCO platforms the SBIOS signals display hotplug on a powered-off dGPU
>
> Although your system is a BOCO platform; I do think this same thing for
> this signaling to wakeup could apply to a BACO system too.
>
I would doubt it. In the BOCO case, the OEM has a mux on the HPD pins
and redirects them to the EC when the dGPU is powered off. For BACO,
in most cases that is just PCIe add in board so there is no way to
redirect the HPD pins.
@Mike Lothian does your system have ATIF? This is already code to
handle this. It sounds like it's just registering the wrong ACPI
node. You should be able to use the existing handler.
Alex
> > + * (e.g. USB-C DP alt mode HPD wired to the dGPU) with Notify(<dGPU>, 0x81)
> > + * on the dGPU's own ACPI node. Nothing else listens there, so wake the
> > + * device; runtime resume re-detects all links and sends a hotplug event.
> > + */
> > +static void amdgpu_acpi_dgpu_notify(acpi_handle handle, u32 event, void *data)
> > +{
> > + struct amdgpu_device *adev = data;
> > +
> > + if (event != ACPI_VIDEO_NOTIFY_PROBE)
> > + return;
> > +
> > + dev_dbg(adev->dev, "ACPI notify 0x%x, requesting runtime resume\n", event);
> > + pm_request_resume(adev->dev);
> > +}
> > +
> > /* Call all ACPI methods here */
> > /**
> > * amdgpu_acpi_init - init driver acpi support
> > @@ -1325,6 +1342,14 @@ int amdgpu_acpi_init(struct amdgpu_device *adev)
> > adev->acpi_nb.notifier_call = amdgpu_acpi_event;
> > register_acpi_notifier(&adev->acpi_nb);
> >
> > + if (!(adev->flags & AMD_IS_APU) && ACPI_COMPANION(adev->dev) &&
> > + adev->pm.rpm_mode == AMDGPU_RUNPM_BOCO)
>
> I'd install the notifier for BACO as well.
> > + adev->acpi_dgpu_notify =
> > + !acpi_dev_install_notify_handler(ACPI_COMPANION(adev->dev),
> > + ACPI_DEVICE_NOTIFY,
> > + amdgpu_acpi_dgpu_notify,
> > + adev);
> > +
> > return 0;
> > }
> >
> > @@ -1344,6 +1369,12 @@ void amdgpu_acpi_get_backlight_caps(struct amdgpu_dm_backlight_caps *caps)
> > */
> > void amdgpu_acpi_fini(struct amdgpu_device *adev)
> > {
> > + if (adev->acpi_dgpu_notify) {
> > + acpi_dev_remove_notify_handler(ACPI_COMPANION(adev->dev),
> > + ACPI_DEVICE_NOTIFY,
> > + amdgpu_acpi_dgpu_notify);
> > + adev->acpi_dgpu_notify = false;
> > + }
> > unregister_acpi_notifier(&adev->acpi_nb);
> > }
> >
>
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-10-29 16:05 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-29 15:14 [PATCH 0/2] drm/amdgpu: wake a powered-off dGPU on a dock hotplug notify Mike Lothian
2026-10-29 15:14 ` [PATCH 1/2] drm/amdgpu: runtime resume dGPU on ACPI notify from its own node Mike Lothian
2026-10-29 15:20 ` Mario Limonciello
2026-10-29 16:05 ` Alex Deucher
2026-10-29 15:14 ` [PATCH 2/2] drm/amdgpu: handle broken dGPU hotplug GPE on ASUS ROG Strix G513QY Mike Lothian
2026-10-29 15:24 ` Mario Limonciello
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®