Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save kwilczynski/9ddc8a5169e4f54293dec1359956b420 to your computer and use it in GitHub Desktop.

Select an option

Save kwilczynski/9ddc8a5169e4f54293dec1359956b420 to your computer and use it in GitHub Desktop.
amd_pmc: skip LPS0 handler on MINISFORUM MS-S1 MAX (firmware only implements Microsoft LPS0 _DSM via SMI; OS_HINT hangs s2idle)
From: Helmut Januschka <helmut@januschka.com>
Subject: [PATCH] platform/x86/amd/pmc: firmware-handled LPS0 quirk for MINISFORUM MS-S1 MAX
The MINISFORUM MS-S1 MAX (SHWSA, Strix Halo) ships firmware whose LPS0
PEP device only implements the Microsoft _DSM UUID; its entry/exit
functions trap into SMM (port 0xB2, 0xEA/0xEB) and perform the platform
sleep handshake there. The AMD _DSM UUID advertises no entry/exit
functions at all (function mask 0x3).
When amd_pmc additionally sends OS_HINT, s2idle never resumes: with both
the firmware SMI path and OS_HINT active every suspend hangs, and with
OS_HINT alone (Microsoft _DSM suppressed) the machine hangs within a few
cycles. Suspend is reliable only when the firmware path runs exclusively,
which matches what the vendor validated for Windows Modern Standby.
Add a DMI quirk for this board: amd_pmc registers metrics-only LPS0
hooks that start SMU logging before suspend and dump it on resume,
without ever sending OS_HINT. Firmware handles the sleep handshake on
its own and s0ix_stats/smu_fw_info stay usable for diagnosing sleep
depth (measured: the firmware path never enters S0i3 and sends no SMU
hint itself).
Signed-off-by: Helmut Januschka <helmut@januschka.com>
---
--- a/drivers/platform/x86/amd/pmc/pmc-quirks.c
+++ b/drivers/platform/x86/amd/pmc/pmc-quirks.c
@@ -19,6 +19,7 @@
u32 s2idle_bug_mmio;
bool spurious_8042;
bool need_suspend_delay;
+ bool no_lps0;
};
static struct quirk_entry quirk_s2idle_bug = {
@@ -38,6 +39,10 @@
.need_suspend_delay = true,
};
+static struct quirk_entry quirk_no_lps0 = {
+ .no_lps0 = true,
+};
+
static const struct dmi_system_id fwbug_list[] = {
{
.ident = "L14 Gen2 AMD",
@@ -360,6 +365,14 @@
DMI_MATCH(DMI_BOARD_NAME, "WUJIE Series-X5SP4NAG"),
}
},
+ {
+ .ident = "MINISFORUM MS-S1 MAX",
+ .driver_data = &quirk_no_lps0,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Micro Computer (HK) Tech Limited"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "MS-S1 MAX"),
+ }
+ },
{}
};
@@ -403,6 +416,11 @@
return dev->quirks && dev->quirks->need_suspend_delay;
}
+bool amd_pmc_quirk_no_lps0(struct amd_pmc_dev *dev)
+{
+ return dev->quirks && dev->quirks->no_lps0;
+}
+
void amd_pmc_quirks_init(struct amd_pmc_dev *dev)
{
const struct dmi_system_id *dmi_id;
--- a/drivers/platform/x86/amd/pmc/pmc.c
+++ b/drivers/platform/x86/amd/pmc/pmc.c
@@ -849,6 +849,27 @@
amd_pmc_process_restore_quirks(pdev);
}
+static void amd_pmc_s2idle_prepare_metrics_only(void)
+{
+ amd_pmc_setup_smu_logging(&pmc);
+}
+
+static void amd_pmc_s2idle_restore_metrics_only(void)
+{
+ amd_pmc_dump_data(&pmc);
+ amd_pmc_validate_deepest(&pmc);
+}
+
+/*
+ * The firmware on some boards performs the sleep handshake itself via the
+ * Microsoft LPS0 _DSM (SMM); sending OS_HINT as well makes resume hang.
+ * Collect SMU metrics around suspend without sending OS_HINT.
+ */
+static struct acpi_s2idle_dev_ops amd_pmc_s2idle_metrics_ops = {
+ .prepare = amd_pmc_s2idle_prepare_metrics_only,
+ .restore = amd_pmc_s2idle_restore_metrics_only,
+};
+
static struct acpi_s2idle_dev_ops amd_pmc_s2idle_dev_ops = {
.prepare = amd_pmc_s2idle_prepare,
.check = amd_pmc_s2idle_check,
@@ -931,11 +952,16 @@
platform_set_drvdata(pdev, dev);
if (IS_ENABLED(CONFIG_SUSPEND)) {
- err = acpi_register_lps0_dev(&amd_pmc_s2idle_dev_ops);
- if (err)
- dev_warn(dev->dev, "failed to register LPS0 sleep handler, expect increased power consumption\n");
if (!disable_workarounds)
amd_pmc_quirks_init(dev);
+ if (amd_pmc_quirk_no_lps0(dev)) {
+ dev_info(dev->dev, "platform firmware handles LPS0, registering metrics-only sleep handler\n");
+ err = acpi_register_lps0_dev(&amd_pmc_s2idle_metrics_ops);
+ } else {
+ err = acpi_register_lps0_dev(&amd_pmc_s2idle_dev_ops);
+ }
+ if (err)
+ dev_warn(dev->dev, "failed to register LPS0 sleep handler, expect increased power consumption\n");
}
amd_pmc_dbgfs_register(dev);
@@ -965,7 +991,9 @@
struct amd_pmc_dev *dev = platform_get_drvdata(pdev);
if (IS_ENABLED(CONFIG_SUSPEND))
- acpi_unregister_lps0_dev(&amd_pmc_s2idle_dev_ops);
+ acpi_unregister_lps0_dev(amd_pmc_quirk_no_lps0(dev) ?
+ &amd_pmc_s2idle_metrics_ops :
+ &amd_pmc_s2idle_dev_ops);
amd_pmc_dbgfs_unregister(dev);
pci_dev_put(dev->rdev);
if (IS_ENABLED(CONFIG_AMD_MP2_STB))
--- a/drivers/platform/x86/amd/pmc/pmc.h
+++ b/drivers/platform/x86/amd/pmc/pmc.h
@@ -167,6 +167,7 @@
void amd_pmc_process_restore_quirks(struct amd_pmc_dev *dev);
bool amd_pmc_quirk_need_suspend_delay(struct amd_pmc_dev *dev);
+bool amd_pmc_quirk_no_lps0(struct amd_pmc_dev *dev);
void amd_pmc_quirks_init(struct amd_pmc_dev *dev);
void amd_mp2_stb_init(struct amd_pmc_dev *dev);
void amd_mp2_stb_deinit(struct amd_pmc_dev *dev);

MS-S1 MAX: why s2idle hangs on Linux, and the workaround

Machine: MINISFORUM MS-S1 MAX (board SHWSA, Ryzen AI MAX+ 395 / Strix Halo), BIOS 1.11 (SHWSA_STXH_1.11_260828A). The bug was already there on 1.09. Kernel used for debugging: 7.2.8, but nothing here is version-specific.

The problem

Suspend (s2idle) with a stock kernel never comes back. Fans stop, the power LED pulses, and then nothing wakes it - not the RTC alarm, not the keyboard, not a short press of the power button. Only holding the power button helps. pm_trace shows the last thing that ran was the tail end of device suspend (device_suspend_noirq); no resume callback ever executes.

What the firmware actually implements

The LPS0 device lives in SSDT21 (device PEP, HID AMDI000B, _CID PNP0D80, full disassembly attached). Its _DSM supports two interfaces:

The AMD UUID (e3f32452-febc-43ce-9039-932122d37721) returns function mask 0x03. That's just "query" and "get device constraints" - the entry/exit and screen on/off functions that Linux's AMD s2idle path wants (functions 2-5) simply aren't there.

The Microsoft UUID (11e00d56-ce64-47ce-837b-1f898f9aa461) returns mask 0x1F9, i.e. the full Modern Standby set. Its entry/exit functions write 0xEA / 0xEB to SMI port 0xB2 (OperationRegion OSMI at SystemIO 0xB2, with an MSIN latch) and the actual sleep handshake happens inside SMM. See the excerpt file for the exact ASL.

So the board was clearly validated for Windows Modern Standby and nothing else. On top of that, Linux's amd_pmc driver sends the SMU an OS_HINT message on every s2idle entry - meaning the power controller gets told "we're going to sleep" twice, once by the kernel and once by SMM.

What was tested

All on the same machine and BIOS:

  • Stock: Microsoft _DSM active plus amd_pmc OS_HINT. Hangs on every suspend; a 15 second test is enough.
  • amd_pmc blacklisted, firmware path only: rock solid. Survived a 4h46m overnight s2idle with working RTC and keyboard wake, fans off.
  • OS_HINT only (Microsoft _DSM suppressed with a test patch): survives one or two short cycles, then hangs. SMU reports Last S0i3 Status: Unknown/Fail either way.

The firmware path has to run exclusively. The OS_HINT path is broken on this firmware even without the SMI handshake in the mix.

Sleep depth

A follow-up build registers metrics-only LPS0 hooks (SMU LOG_START before suspend, LOG_DUMP after, still no OS_HINT). After a clean 45 second cycle:

Table Version: 3
Hint Count: 0
Last S0i3 Status: Unknown/Fail
Time (in us) in S0i3: 0

Two conclusions. The SMM handshake never sends the SMU hint itself, and the SoC never enters S0i3 on the firmware-only path. Sleep works and is quiet, but it's shallow. Windows presumably reaches S0i3 through its PEP driver, so a working deep-sleep sequence must exist on this hardware - the ordering between the hint and the SMI handshake is likely what matters.

The SMU also rejects the STB (Smart Trace Buffer) S2D address query ("SMU cmd failed. err: 0xff"), so that debugging avenue is closed.

The workaround

The attached patch adds a DMI quirk to amd_pmc: on this board the driver still binds (debugfs, SMU metrics keep working) but registers metrics-only sleep hooks and never sends OS_HINT. Firmware handles sleep by itself. Without a patched kernel, module_blacklist=amd_pmc on the command line does the same job minus the metrics.

One unrelated find from the same debugging session: an external GenesysLogic USB2 hub (05e3:0610) comes out of s2idle with corrupt state (repeating "clear tt" -71 errors, then -110 and gone until a power cycle). Fixed with usbcore.quirks=05e3:0610:b (reset instead of resume). Not a MINISFORUM problem.

Side note for anyone running the amd-s2idle diagnostic tool: it flags a missing MSFT0201 ACPI device on this machine. The IVRS table advertises the HID (UID 1, devid 0x60) but the ACPI namespace never defines the device.

Notes for a firmware fix (SHWSA / MS-S1 MAX BIOS)

Companion to ANALYSIS-and-support-case.md. Everything below refers to the _DSM of device PEP (HID AMDI000B) in SSDT21 of BIOS 1.11, see the attached disassembly. Line references are from SSDT21-LPS0-PEP-disassembly.dsl.

What Linux actually calls, in order

Suspend entry (drivers/acpi/x86/s2idle.c, acpi_s2idle_prepare_late):

  1. AMD UUID function 4 (screen off) - skipped, not in mask 0x03
  2. MS UUID function 3 (screen off) - your Case(0x03), no-op
  3. AMD UUID function 2 (entry) - skipped, not in mask 0x03
  4. MS UUID function 7 (MS entry) - your Case(0x07): MSIN=1, SMIE=0xEA
  5. MS UUID function 5 (entry) - your Case(0x05): no-op (MSIN already 1)
  6. amd_pmc driver sends SMU OS_HINT - mailbox message, after the SMI

Resume, mirrored (acpi_s2idle_restore_early):

  1. amd_pmc driver sends OS_HINT (resume) - FIRST, before any _DSM
  2. AMD UUID function 3 (exit) - skipped
  3. MS UUID function 6 (exit) - your Case(0x06), no-op
  4. MS UUID function 9 (turn on display)
  5. MS UUID function 8 (MS exit) - MSIN=0, SMIE=0xEB
  6. MS UUID function 4 (screen on) - also clears EC0.MSCM / SMIE=0xEB path

So with an unmodified Linux kernel the box gets the 0xEA SMM handshake AND an SMU OS_HINT on entry, and on wake the OS_HINT resume message arrives before the 0xEB SMM handshake has run. In that configuration the machine never resumes. With OS_HINT alone (we suppressed the Microsoft path for testing) it survives one or two cycles and then hangs as well. Only the SMM-handshake-without-OS_HINT combination is stable, which is what our published kernel quirk enforces.

Windows evidently copes - its AMD PEP driver also talks to the SMU - so a working ordering exists on this silicon. The difference is in what the SMM handler and PMFW on this board expect.

Option A (the real fix): make the platform tolerate OS_HINT

Whatever the SMM 0xEA handler arms for wake appears to break once the SMU has also seen an OS_HINT from the OS (and the OS_HINT path alone is broken too). Suggested places to look:

  • the 0xEA/0xEB SMI handler's interaction with the SMU sleep-entry message (double-entry bookkeeping, hint count),
  • the wake path: with OS_HINT active, wakeup sources (RTC, GPIO 58 -> XHC0, power button GPIO 0) no longer bring the SoC back, which smells like the wake interrupt routing is torn down for Modern Standby and only the SMM exit path restores it.

Verification is easy on a stock Linux kernel: 'Hint Count' in /sys/kernel/debug/amd_pmc/smu_fw_info must be nonzero after a cycle and the machine must wake from RTC. Right now 'Hint Count' stays 0 on the working path (firmware never hints the SMU itself) and S0i3 residency is always 0, i.e. the board never reaches deep sleep under Linux at all.

Option B (additionally): implement the AMD UUID functions

The AMD interface currently advertises mask 0x03 (query + constraints only). Linux prefers it on AMD hardware; with functions 2-5 implemented the stock kernel uses the native path and the Microsoft/SMM branch stays Windows-only. Sketch in the style of the existing ASL - reuse the same SMM backend:

If ((Arg0 == ToUUID ("e3f32452-febc-43ce-9039-932122d37721")))
{
    Switch (ToInteger (Arg2))
    {
        Case (Zero)
        {
            Return (Buffer (One) { 0x3F })   // functions 0-5
        }
        Case (One)  { Return (DEVL) }        // unchanged
        Case (0x02)                          // entry
        {
            If ((MSIN == Zero)) { MSIN = One;  SMIE = 0xEA }
            Return (Zero)
        }
        Case (0x03)                          // exit
        {
            If ((MSIN == One))  { MSIN = Zero; SMIE = 0xEB }
            Return (Zero)
        }
        Case (0x04) { Return (Zero) }        // screen off
        Case (0x05)                          // screen on
        {
            If ((\_SB.PCI0.SBRG.EC0.MSCM == One))
            {
                \_SB.PCI0.SBRG.EC0.MSCM = Zero
            }
            Return (Zero)
        }
    }
}

Note the ordering difference this buys on resume: Linux calls AMD exit (function 3) BEFORE the driver-level restore work finishes only in the _DSM sequence - but amd_pmc's OS_HINT resume message still comes first. So Option B without Option A does not fix the hang: Linux will then run both the AMD entry SMI and OS_HINT. B is worthwhile for correctness and screen notifications, but A is the fix.

Small cleanups while in there

  • IVRS advertises ACPI HID MSFT0201 (UID 1, devid 0x60) but the namespace never defines that device. Either define it or drop the IVRS entry; the mismatch trips AMD's amd-s2idle diagnostics.
  • _SB.PCI0.GPP9.DEV0 is referenced but never defined ("ACPI BIOS Error (bug): Could not resolve symbol" on every boot).

How we would validate a test BIOS

  1. Flash, boot a stock Linux kernel (no quirks, amd_pmc loaded).
  2. python3 -m amd_debug.s2idle test --count 10 --duration 60 (or plain rtcwake -m mem -s 60, ten times).
  3. Pass criteria: every cycle resumes; Hint Count increments; 'Time (in us) in S0i3' nonzero; RTC, USB keyboard, and power button all wake the box; no hub/EC fallout after resume.
  4. Overnight soak with the same checks in the morning.

We are happy to test candidate BIOS builds on real hardware.

}
Method (_DSM, 4, Serialized) // _DSM: Device-Specific Method
{
CreateDWordField (Arg0, Zero, UID0)
M460 (" OEM-ASL-\\_SB.PEP._DSM (UUID 0x%X, 0x%X, 0x%X)\n", UID0, Arg1, Arg2, Zero, Zero, Zero)
If ((Arg0 == ToUUID ("e3f32452-febc-43ce-9039-932122d37721") /* Unknown UUID */))
{
Switch (ToInteger (Arg2))
{
Case (Zero)
{
Switch (ToInteger (Arg1))
{
Case (Zero)
{
M460 (" Return (Buffer (1) {0x03})\n", Zero, Zero, Zero, Zero, Zero, Zero)
Return (Buffer (One)
{
0x03 // .
})
}
Case (One)
{
M460 (" Return (Buffer (1) {0x03})\n", Zero, Zero, Zero, Zero, Zero, Zero)
Return (Buffer (One)
{
0x03 // .
})
}
Default
{
M460 (" Return (Buffer (1) {0x00})\n", Zero, Zero, Zero, Zero, Zero, Zero)
Return (Buffer (One)
{
0x00 // .
})
}
}
}
Case (One)
{
DEVL [One] = SizeOf (DEVL [0x02])
M460 (" OEM-ASL-DEVL[Count] = %d\n", DerefOf (DEVL [One]), Zero, Zero, Zero, Zero, Zero)
If (CondRefOf (\P4D3))
{
If ((\P4D3 != 0x55))
{
M460 (" Case1 P4D3 : USB4 PCIe 0/1 RP D3 supported\n", Zero, Zero, Zero, Zero, Zero, Zero)
MPEP (One, "\\_SB.PCI0.GPP0", Zero, 0x03)
MPEP (One, "\\_SB.PCI0.GPP1", Zero, 0x03)
}
}
If (CondRefOf (\P1D3))
{
If ((\P1D3 != 0x55))
{
M460 (" Case1 P1D3 : IntGPPA D3 supported\n", Zero, Zero, Zero, Zero, Zero, Zero)
MPEP (One, "\\_SB.PCI0.GPPA", Zero, 0x03)
}
}
If (CondRefOf (\P3D3))
{
If ((\P3D3 != 0x55))
{
M460 (" Case1 P3D3 : IntGPPC D3 supported\n", Zero, Zero, Zero, Zero, Zero, Zero)
MPEP (One, "\\_SB.PCI0.GPPC", Zero, 0x03)
}
}
If (CondRefOf (\F0D3))
{
If ((\F0D3 != 0x04))
{
M460 (" Case1 F0D3 : IntGPPA iGPU D3 supported\n", Zero, Zero, Zero, Zero, Zero, Zero)
MPEP (Zero, "\\_SB.PCI0.GPPA.VGA", Zero, Zero)
}
}
If (CondRefOf (\F1D3))
{
If ((\F1D3 != 0x04))
{
M460 (" Case1 F1D3 : IntGPPA Display HD audio D3 supported\n", Zero, Zero, Zero, Zero, Zero, Zero)
MPEP (Zero, "\\_SB.PCI0.GPPA.HDAU", Zero, Zero)
}
}
If (CondRefOf (\F3D3))
{
If ((\F3D3 != 0x04))
{
M460 (" Case1 F3D3 : IntGPPA XHCI 1 D3 supported\n", Zero, Zero, Zero, Zero, Zero, Zero)
MPEP (Zero, "\\_SB.PCI0.GPPA.XHC1", Zero, Zero)
}
}
If (CondRefOf (\F5D3))
{
If ((\F5D3 != 0x04))
{
M460 (" Case1 F5D3 : IntGPPA ACP D3 supported\n", Zero, Zero, Zero, Zero, Zero, Zero)
MPEP (Zero, "\\_SB.PCI0.GPPA.ACP", Zero, Zero)
}
}
If (CondRefOf (\F6D3))
{
If ((\F6D3 != 0x04))
{
M460 (" Case1 F6D3 : IntGPPA Azalia D3 supported\n", Zero, Zero, Zero, Zero, Zero, Zero)
MPEP (Zero, "\\_SB.PCI0.GPPA.AZAL", Zero, Zero)
}
}
If (CondRefOf (\G3D3))
{
If ((\G3D3 != 0x04))
{
M460 (" Case1 G3D3 : IntGPPC XHCI 0/3/4 D3 supported\n", Zero, Zero, Zero, Zero, Zero, Zero)
MPEP (Zero, "\\_SB.PCI0.GPPC.XHC0", Zero, Zero)
MPEP (Zero, "\\_SB.PCI0.GPPC.XHC3", Zero, Zero)
MPEP (Zero, "\\_SB.PCI0.GPPC.XHC4", Zero, Zero)
}
}
If (CondRefOf (\G5D3))
{
If ((\G5D3 != 0x04))
{
M460 (" Case1 G5D3 : IntGPPC CIO 0/1 D3 supported\n", Zero, Zero, Zero, Zero, Zero, Zero)
MPEP (Zero, "\\_SB.PCI0.GPPC.NHI0", Zero, Zero)
MPEP (Zero, "\\_SB.PCI0.GPPC.NHI1", Zero, Zero)
}
}
If (CondRefOf (\H0D3))
{
If ((\H0D3 != 0x04))
{
M460 (" Case1 H0D3 : USB4 PCIe 0/1 EP D3 supported\n", Zero, Zero, Zero, Zero, Zero, Zero)
MPEP (Zero, "\\_SB.PCI0.GPP0.SWUS", Zero, Zero)
MPEP (Zero, "\\_SB.PCI0.GPP1.SWUS", Zero, Zero)
}
}
ToInteger (M453, Local7)
If ((Local7 != Zero))
{
M460 (" OEM-ASL-DEVL:\n", Zero, Zero, Zero, Zero, Zero, Zero)
Local1 = DerefOf (DEVL [One])
Local0 = Zero
While ((Local0 < Local1))
{
Local2 = DerefOf (DerefOf (DerefOf (DEVL [0x02]) [Local0]
) [Zero])
Local3 = DerefOf (DerefOf (DerefOf (DEVL [0x02]) [Local0]
) [One])
Local4 = DerefOf (DerefOf (DerefOf (DEVL [0x02]) [Local0]
) [0x02])
Local5 = DerefOf (DerefOf (DerefOf (DEVL [0x02]) [Local0]
) [0x03])
M460 (" %d - %d %S %d %d\n", ToInteger (Local0), Local2, Local3, Local4, Local5, Zero)
Local0++
}
}
M460 (" Return (DEVL)\n", Zero, Zero, Zero, Zero, Zero, Zero)
Return (DEVL) /* \_SB_.PEP_.DEVL */
}
Default
{
M460 (" Return (0x00)\n", Zero, Zero, Zero, Zero, Zero, Zero)
Return (Zero)
}
}
}
ElseIf ((Arg0 == ToUUID ("11e00d56-ce64-47ce-837b-1f898f9aa461") /* Unknown UUID */))
{
Switch (ToInteger (Arg2))
{
Case (Zero)
{
Switch (ToInteger (Arg1))
{
Case (Zero)
{
M460 (" Return (Buffer (2) {0xF9, 0x01})\n", Zero, Zero, Zero, Zero, Zero, Zero)
Return (Buffer (0x02)
{
0xF9, 0x01 // ..
})
}
Default
{
M460 (" Return (Buffer (1) {0x00})\n", Zero, Zero, Zero, Zero, Zero, Zero)
Return (Buffer (One)
{
0x00 // .
})
}
}
}
Case (0x03)
{
M000 (0x3E03)
M460 (" Return (0x00)\n", Zero, Zero, Zero, Zero, Zero, Zero)
Return (Zero)
}
Case (0x04)
{
M000 (0x3E04)
M460 (" Return (0x00)\n", Zero, Zero, Zero, Zero, Zero, Zero)
If ((\_SB.PCI0.SBRG.EC0.MSCM == One))
{
\_SB.PCI0.SBRG.EC0.MSCM = Zero
}
If ((MSIN == One))
{
MSIN = Zero
SMIE = 0xEB
}
Return (Zero)
}
Case (0x05)
{
If ((MSIN == Zero))
{
MSIN = One
SMIE = 0xEA
}
M000 (0x3E05)
M460 (" Return (0x00)\n", Zero, Zero, Zero, Zero, Zero, Zero)
Return (Zero)
}
Case (0x06)
{
M000 (0x3E06)
M460 (" Return (0x00)\n", Zero, Zero, Zero, Zero, Zero, Zero)
Return (Zero)
}
Case (0x07)
{
/*
* Intel ACPI Component Architecture
* AML/ASL+ Disassembler version 20251212 (64-bit version)
* Copyright (c) 2000 - 2025 Intel Corporation
*
* Disassembling to symbolic ASL+ operators
*
* Disassembly of ssdt-SSDT21.dat
*
* Original Table Header:
* Signature "SSDT"
* Length 0x00001716 (5910)
* Revision 0x02
* Checksum 0xEA
* OEM ID "AMD"
* OEM Table ID "UPEP"
* OEM Revision 0x00000001 (1)
* Compiler ID "INTL"
* Compiler Version 0x20230331 (539165489)
*/
DefinitionBlock ("", "SSDT", 2, "AMD", "UPEP", 0x00000001)
{
External (_SB_.PCI0, DeviceObj)
External (_SB_.PCI0.SBRG.EC0_.MSCM, IntObj)
External (F0D3, IntObj)
External (F1D3, IntObj)
External (F3D3, IntObj)
External (F5D3, IntObj)
External (F6D3, IntObj)
External (G3D3, IntObj)
External (G5D3, IntObj)
External (H0D3, IntObj)
External (M000, MethodObj) // 1 Arguments
External (M037, DeviceObj)
External (M045, MethodObj) // 0 Arguments
External (M046, IntObj)
External (M047, IntObj)
External (M050, DeviceObj)
External (M051, DeviceObj)
External (M052, DeviceObj)
External (M053, DeviceObj)
External (M054, DeviceObj)
External (M055, DeviceObj)
External (M056, DeviceObj)
External (M057, DeviceObj)
External (M058, DeviceObj)
External (M059, DeviceObj)
External (M062, DeviceObj)
External (M068, DeviceObj)
External (M069, DeviceObj)
External (M070, DeviceObj)
External (M071, DeviceObj)
External (M072, DeviceObj)
External (M074, DeviceObj)
External (M075, DeviceObj)
External (M076, DeviceObj)
External (M077, DeviceObj)
External (M078, DeviceObj)
External (M079, DeviceObj)
External (M080, DeviceObj)
External (M081, DeviceObj)
External (M082, FieldUnitObj)
External (M083, FieldUnitObj)
External (M084, FieldUnitObj)
External (M085, FieldUnitObj)
External (M086, FieldUnitObj)
External (M087, FieldUnitObj)
External (M088, FieldUnitObj)
External (M089, FieldUnitObj)
External (M090, FieldUnitObj)
External (M091, FieldUnitObj)
External (M092, FieldUnitObj)
External (M093, FieldUnitObj)
External (M094, FieldUnitObj)
External (M095, FieldUnitObj)
External (M096, FieldUnitObj)
External (M097, FieldUnitObj)
External (M098, FieldUnitObj)
External (M099, FieldUnitObj)
External (M100, FieldUnitObj)
External (M101, FieldUnitObj)
External (M102, FieldUnitObj)
External (M103, FieldUnitObj)
External (M104, FieldUnitObj)
External (M105, FieldUnitObj)
External (M106, FieldUnitObj)
External (M107, FieldUnitObj)
External (M108, FieldUnitObj)
External (M109, FieldUnitObj)
External (M110, FieldUnitObj)
External (M115, BuffObj)
External (M116, BuffFieldObj)
External (M117, BuffFieldObj)
External (M118, BuffFieldObj)
External (M119, BuffFieldObj)
External (M120, BuffFieldObj)
External (M122, FieldUnitObj)
External (M127, DeviceObj)
External (M128, FieldUnitObj)
External (M131, FieldUnitObj)
External (M132, FieldUnitObj)
External (M133, FieldUnitObj)
External (M134, FieldUnitObj)
External (M135, FieldUnitObj)
External (M136, FieldUnitObj)
External (M220, FieldUnitObj)
External (M221, FieldUnitObj)
External (M226, FieldUnitObj)
External (M227, DeviceObj)
External (M229, FieldUnitObj)
External (M231, FieldUnitObj)
External (M233, FieldUnitObj)
External (M235, FieldUnitObj)
External (M23A, FieldUnitObj)
External (M251, FieldUnitObj)
External (M280, FieldUnitObj)
External (M290, FieldUnitObj)
External (M29A, FieldUnitObj)
External (M310, FieldUnitObj)
External (M31C, FieldUnitObj)
External (M320, FieldUnitObj)
External (M321, FieldUnitObj)
External (M322, FieldUnitObj)
External (M323, FieldUnitObj)
External (M324, FieldUnitObj)
External (M325, FieldUnitObj)
External (M326, FieldUnitObj)
External (M327, FieldUnitObj)
External (M328, FieldUnitObj)
External (M329, DeviceObj)
External (M32A, DeviceObj)
External (M32B, DeviceObj)
External (M32C, DeviceObj)
External (M330, DeviceObj)
External (M331, FieldUnitObj)
External (M378, FieldUnitObj)
External (M379, FieldUnitObj)
External (M380, FieldUnitObj)
External (M381, FieldUnitObj)
External (M382, FieldUnitObj)
External (M383, FieldUnitObj)
External (M384, FieldUnitObj)
External (M385, FieldUnitObj)
External (M386, FieldUnitObj)
External (M387, FieldUnitObj)
External (M388, FieldUnitObj)
External (M389, FieldUnitObj)
External (M390, FieldUnitObj)
External (M391, FieldUnitObj)
External (M392, FieldUnitObj)
External (M404, BuffObj)
External (M408, MutexObj)
External (M414, FieldUnitObj)
External (M444, FieldUnitObj)
External (M449, FieldUnitObj)
External (M453, FieldUnitObj)
External (M454, FieldUnitObj)
External (M455, FieldUnitObj)
External (M456, FieldUnitObj)
External (M457, FieldUnitObj)
External (M460, MethodObj) // 7 Arguments
External (M4C0, FieldUnitObj)
External (M4F0, FieldUnitObj)
External (M610, FieldUnitObj)
External (M620, FieldUnitObj)
External (M631, FieldUnitObj)
External (M652, FieldUnitObj)
External (P1D3, IntObj)
External (P3D3, IntObj)
External (P4D3, IntObj)
External (WLD3, IntObj)
Scope (\_SB.PCI0)
{
Name (_DEP, Package (0x01) // _DEP: Dependencies
{
\_SB.PEP
})
}
Scope (\)
{
Name (SLX4, 0x55)
Name (NVD3, 0x55)
Name (LOD3, 0x55)
Name (SDD3, 0x00)
}
Scope (\_SB)
{
OperationRegion (OSMI, SystemIO, 0xB2, One)
Field (OSMI, ByteAcc, NoLock, Preserve)
{
SMIE, 8
}
Name (MSIN, Zero)
Device (PEP)
{
Name (_HID, "AMDI000B") // _HID: Hardware ID
Name (_CID, EisaId ("PNP0D80") /* Windows-compatible System Power Management Controller */) // _CID: Compatible ID
Name (_UID, One) // _UID: Unique ID
Name (DEVL, Package (0x03)
{
Zero,
Zero,
Package (0x43)
{
Package (0x04)
{
Zero,
"\\_SB.PCI0.GPP0",
Zero,
Zero
},
Package (0x04)
{
Zero,
"\\_SB.PCI0.GPP1",
Zero,
Zero
},
Package (0x04)
{
One,
"\\_SB.PCI0.GPP6",
0x02,
One
},
Package (0x04)
{
One,
"\\_SB.PCI0.GPP7",
0x02,
One
},
Package (0x04)
{
One,
"\\_SB.PCI0.GPP9",
Zero,
0x03
},
Package (0x04)
{
One,
"\\_SB.PCI0.GP10",
0x02,
One
},
Package (0x04)
{
Zero,
"\\_SB.PCI0.GPPA",
Zero,
Zero
},
Package (0x04)
{
Zero,
"\\_SB.PCI0.GPPB",
Zero,
Zero
},
Package (0x04)
{
Zero,
"\\_SB.PCI0.GPPC",
Zero,
Zero
},
Package (0x04)
{
One,
"\\_SB.PCI0.GPP0.SWUS",
Zero,
0x03
},
Package (0x04)
{
One,
"\\_SB.PCI0.GPP1.SWUS",
Zero,
0x03
},
Package (0x04)
{
One,
"\\_SB.PCI0.GPP5.WLAN",
Zero,
0x03
},
Package (0x04)
{
One,
"\\_SB.PCI0.GPP6.NVME",
Zero,
0x03
},
Package (0x04)
{
One,
"\\_SB.PCI0.GPP7.NVME",
Zero,
0x03
},
Package (0x04)
{
One,
"\\_SB.PCI0.GP10.NVME",
Zero,
0x03
},
Package (0x04)
{
One,
"\\_SB.PCI0.GP10.PXSX",
Zero,
0x03
},
Package (0x04)
{
One,
"\\_SB.PCI0.GPP9.DEV0",
Zero,
0x03
},
Package (0x04)
{
One,
"\\_SB.PCI0.GPP4.RTL1",
Zero,
0x03
},
Package (0x04)
{
One,
"\\_SB.PCI0.GPP3.RTL2",
Zero,
0x03
},
Package (0x04)
{
One,
"\\_SB.PCI0.GPPA.VGA",
Zero,
0x03
},
Package (0x04)
{
One,
"\\_SB.PCI0.GPPA.HDAU",
Zero,
0x03
},
Package (0x04)
{
One,
"\\_SB.PCI0.GPPA.XHC1",
Zero,
0x03
},
Package (0x04)
{
One,
"\\_SB.PCI0.GPPA.ACP",
Zero,
0x03
},
Package (0x04)
{
One,
"\\_SB.PCI0.GPPA.AZAL",
Zero,
0x03
},
Package (0x04)
{
One,
"\\_SB.PCI0.GPPB.IPU",
Zero,
0x03
},
Package (0x04)
{
One,
"\\_SB.PCI0.GPPC.XHC0",
Zero,
0x03
},
Package (0x04)
{
One,
"\\_SB.PCI0.GPPC.XHC3",
Zero,
0x03
},
Package (0x04)
{
One,
"\\_SB.PCI0.GPPC.XHC4",
Zero,
0x03
},
Package (0x04)
{
One,
"\\_SB.PCI0.GPPC.NHI0",
Zero,
0x03
},
Package (0x04)
{
One,
"\\_SB.PCI0.GPPC.NHI1",
Zero,
0x03
},
Package (0x04)
{
One,
"\\_SB.FUR0",
Zero,
0x03
},
Package (0x04)
{
One,
"\\_SB.FUR1",
Zero,
0x03
},
Package (0x04)
{
One,
"\\_SB.FUR2",
Zero,
0x03
},
Package (0x04)
{
One,
"\\_SB.FUR3",
Zero,
0x03
},
Package (0x04)
{
One,
"\\_SB.I2CC.NFC1",
Zero,
0x03
},
Package (0x04)
{
One,
"\\_SB.PLTF.C000",
One,
0x03
},
Package (0x04)
{
One,
"\\_SB.PLTF.C001",
One,
0x03
},
Package (0x04)
{
One,
"\\_SB.PLTF.C002",
One,
0x03
},
Package (0x04)
{
One,
"\\_SB.PLTF.C003",
One,
0x03
},
Package (0x04)
{
One,
"\\_SB.PLTF.C004",
One,
0x03
},
Package (0x04)
{
One,
"\\_SB.PLTF.C005",
One,
0x03
},
Package (0x04)
{
One,
"\\_SB.PLTF.C006",
One,
0x03
},
Package (0x04)
{
One,
"\\_SB.PLTF.C007",
One,
0x03
},
Package (0x04)
{
One,
"\\_SB.PLTF.C008",
One,
0x03
},
Package (0x04)
{
One,
"\\_SB.PLTF.C009",
One,
0x03
},
Package (0x04)
{
One,
"\\_SB.PLTF.C00A",
One,
0x03
},
Package (0x04)
{
One,
"\\_SB.PLTF.C00B",
One,
0x03
},
Package (0x04)
{
One,
"\\_SB.PLTF.C00C",
One,
0x03
},
Package (0x04)
{
One,
"\\_SB.PLTF.C00D",
One,
0x03
},
Package (0x04)
{
One,
"\\_SB.PLTF.C00E",
One,
0x03
},
Package (0x04)
{
One,
"\\_SB.PLTF.C00F",
One,
0x03
},
Package (0x04)
{
One,
"\\_SB.PLTF.C010",
One,
0x03
},
Package (0x04)
{
One,
"\\_SB.PLTF.C011",
One,
0x03
},
Package (0x04)
{
One,
"\\_SB.PLTF.C012",
One,
0x03
},
Package (0x04)
{
One,
"\\_SB.PLTF.C013",
One,
0x03
},
Package (0x04)
{
One,
"\\_SB.PLTF.C014",
One,
0x03
},
Package (0x04)
{
One,
"\\_SB.PLTF.C015",
One,
0x03
},
Package (0x04)
{
One,
"\\_SB.PLTF.C016",
One,
0x03
},
Package (0x04)
{
One,
"\\_SB.PLTF.C017",
One,
0x03
},
Package (0x04)
{
One,
"\\_SB.PLTF.C018",
One,
0x03
},
Package (0x04)
{
One,
"\\_SB.PLTF.C019",
One,
0x03
},
Package (0x04)
{
One,
"\\_SB.PLTF.C01A",
One,
0x03
},
Package (0x04)
{
One,
"\\_SB.PLTF.C01B",
One,
0x03
},
Package (0x04)
{
One,
"\\_SB.PLTF.C01C",
One,
0x03
},
Package (0x04)
{
One,
"\\_SB.PLTF.C01D",
One,
0x03
},
Package (0x04)
{
One,
"\\_SB.PLTF.C01E",
One,
0x03
},
Package (0x04)
{
One,
"\\_SB.PLTF.C01F",
One,
0x03
}
}
})
Method (_STA, 0, NotSerialized) // _STA: Status
{
If (M045 ())
{
M460 (" OEM-ASL-\\_SB.PEP._STA = 0xF\n", Zero, Zero, Zero, Zero, Zero, Zero)
Return (0x0F)
}
Else
{
M460 (" OEM-ASL-\\_SB.PEP._STA = 0x0\n", Zero, Zero, Zero, Zero, Zero, Zero)
Return (Zero)
}
}
Method (MPEP, 4, NotSerialized)
{
Local1 = DerefOf (DEVL [One])
Local0 = Zero
While ((Local0 < Local1))
{
If ((DerefOf (DerefOf (DerefOf (DEVL [0x02]) [Local0]
) [One]) == Arg1))
{
DerefOf (DerefOf (DEVL [0x02]) [Local0]) [Zero]
= Arg0
DerefOf (DerefOf (DEVL [0x02]) [Local0]) [0x02]
= Arg2
DerefOf (DerefOf (DEVL [0x02]) [Local0]) [0x03]
= Arg3
Break
}
Local0++
}
}
Method (_DSM, 4, Serialized) // _DSM: Device-Specific Method
{
CreateDWordField (Arg0, Zero, UID0)
M460 (" OEM-ASL-\\_SB.PEP._DSM (UUID 0x%X, 0x%X, 0x%X)\n", UID0, Arg1, Arg2, Zero, Zero, Zero)
If ((Arg0 == ToUUID ("e3f32452-febc-43ce-9039-932122d37721") /* Unknown UUID */))
{
Switch (ToInteger (Arg2))
{
Case (Zero)
{
Switch (ToInteger (Arg1))
{
Case (Zero)
{
M460 (" Return (Buffer (1) {0x03})\n", Zero, Zero, Zero, Zero, Zero, Zero)
Return (Buffer (One)
{
0x03 // .
})
}
Case (One)
{
M460 (" Return (Buffer (1) {0x03})\n", Zero, Zero, Zero, Zero, Zero, Zero)
Return (Buffer (One)
{
0x03 // .
})
}
Default
{
M460 (" Return (Buffer (1) {0x00})\n", Zero, Zero, Zero, Zero, Zero, Zero)
Return (Buffer (One)
{
0x00 // .
})
}
}
}
Case (One)
{
DEVL [One] = SizeOf (DEVL [0x02])
M460 (" OEM-ASL-DEVL[Count] = %d\n", DerefOf (DEVL [One]), Zero, Zero, Zero, Zero, Zero)
If (CondRefOf (\P4D3))
{
If ((\P4D3 != 0x55))
{
M460 (" Case1 P4D3 : USB4 PCIe 0/1 RP D3 supported\n", Zero, Zero, Zero, Zero, Zero, Zero)
MPEP (One, "\\_SB.PCI0.GPP0", Zero, 0x03)
MPEP (One, "\\_SB.PCI0.GPP1", Zero, 0x03)
}
}
If (CondRefOf (\P1D3))
{
If ((\P1D3 != 0x55))
{
M460 (" Case1 P1D3 : IntGPPA D3 supported\n", Zero, Zero, Zero, Zero, Zero, Zero)
MPEP (One, "\\_SB.PCI0.GPPA", Zero, 0x03)
}
}
If (CondRefOf (\P3D3))
{
If ((\P3D3 != 0x55))
{
M460 (" Case1 P3D3 : IntGPPC D3 supported\n", Zero, Zero, Zero, Zero, Zero, Zero)
MPEP (One, "\\_SB.PCI0.GPPC", Zero, 0x03)
}
}
If (CondRefOf (\F0D3))
{
If ((\F0D3 != 0x04))
{
M460 (" Case1 F0D3 : IntGPPA iGPU D3 supported\n", Zero, Zero, Zero, Zero, Zero, Zero)
MPEP (Zero, "\\_SB.PCI0.GPPA.VGA", Zero, Zero)
}
}
If (CondRefOf (\F1D3))
{
If ((\F1D3 != 0x04))
{
M460 (" Case1 F1D3 : IntGPPA Display HD audio D3 supported\n", Zero, Zero, Zero, Zero, Zero, Zero)
MPEP (Zero, "\\_SB.PCI0.GPPA.HDAU", Zero, Zero)
}
}
If (CondRefOf (\F3D3))
{
If ((\F3D3 != 0x04))
{
M460 (" Case1 F3D3 : IntGPPA XHCI 1 D3 supported\n", Zero, Zero, Zero, Zero, Zero, Zero)
MPEP (Zero, "\\_SB.PCI0.GPPA.XHC1", Zero, Zero)
}
}
If (CondRefOf (\F5D3))
{
If ((\F5D3 != 0x04))
{
M460 (" Case1 F5D3 : IntGPPA ACP D3 supported\n", Zero, Zero, Zero, Zero, Zero, Zero)
MPEP (Zero, "\\_SB.PCI0.GPPA.ACP", Zero, Zero)
}
}
If (CondRefOf (\F6D3))
{
If ((\F6D3 != 0x04))
{
M460 (" Case1 F6D3 : IntGPPA Azalia D3 supported\n", Zero, Zero, Zero, Zero, Zero, Zero)
MPEP (Zero, "\\_SB.PCI0.GPPA.AZAL", Zero, Zero)
}
}
If (CondRefOf (\G3D3))
{
If ((\G3D3 != 0x04))
{
M460 (" Case1 G3D3 : IntGPPC XHCI 0/3/4 D3 supported\n", Zero, Zero, Zero, Zero, Zero, Zero)
MPEP (Zero, "\\_SB.PCI0.GPPC.XHC0", Zero, Zero)
MPEP (Zero, "\\_SB.PCI0.GPPC.XHC3", Zero, Zero)
MPEP (Zero, "\\_SB.PCI0.GPPC.XHC4", Zero, Zero)
}
}
If (CondRefOf (\G5D3))
{
If ((\G5D3 != 0x04))
{
M460 (" Case1 G5D3 : IntGPPC CIO 0/1 D3 supported\n", Zero, Zero, Zero, Zero, Zero, Zero)
MPEP (Zero, "\\_SB.PCI0.GPPC.NHI0", Zero, Zero)
MPEP (Zero, "\\_SB.PCI0.GPPC.NHI1", Zero, Zero)
}
}
If (CondRefOf (\H0D3))
{
If ((\H0D3 != 0x04))
{
M460 (" Case1 H0D3 : USB4 PCIe 0/1 EP D3 supported\n", Zero, Zero, Zero, Zero, Zero, Zero)
MPEP (Zero, "\\_SB.PCI0.GPP0.SWUS", Zero, Zero)
MPEP (Zero, "\\_SB.PCI0.GPP1.SWUS", Zero, Zero)
}
}
ToInteger (M453, Local7)
If ((Local7 != Zero))
{
M460 (" OEM-ASL-DEVL:\n", Zero, Zero, Zero, Zero, Zero, Zero)
Local1 = DerefOf (DEVL [One])
Local0 = Zero
While ((Local0 < Local1))
{
Local2 = DerefOf (DerefOf (DerefOf (DEVL [0x02]) [Local0]
) [Zero])
Local3 = DerefOf (DerefOf (DerefOf (DEVL [0x02]) [Local0]
) [One])
Local4 = DerefOf (DerefOf (DerefOf (DEVL [0x02]) [Local0]
) [0x02])
Local5 = DerefOf (DerefOf (DerefOf (DEVL [0x02]) [Local0]
) [0x03])
M460 (" %d - %d %S %d %d\n", ToInteger (Local0), Local2, Local3, Local4, Local5, Zero)
Local0++
}
}
M460 (" Return (DEVL)\n", Zero, Zero, Zero, Zero, Zero, Zero)
Return (DEVL) /* \_SB_.PEP_.DEVL */
}
Default
{
M460 (" Return (0x00)\n", Zero, Zero, Zero, Zero, Zero, Zero)
Return (Zero)
}
}
}
ElseIf ((Arg0 == ToUUID ("11e00d56-ce64-47ce-837b-1f898f9aa461") /* Unknown UUID */))
{
Switch (ToInteger (Arg2))
{
Case (Zero)
{
Switch (ToInteger (Arg1))
{
Case (Zero)
{
M460 (" Return (Buffer (2) {0xF9, 0x01})\n", Zero, Zero, Zero, Zero, Zero, Zero)
Return (Buffer (0x02)
{
0xF9, 0x01 // ..
})
}
Default
{
M460 (" Return (Buffer (1) {0x00})\n", Zero, Zero, Zero, Zero, Zero, Zero)
Return (Buffer (One)
{
0x00 // .
})
}
}
}
Case (0x03)
{
M000 (0x3E03)
M460 (" Return (0x00)\n", Zero, Zero, Zero, Zero, Zero, Zero)
Return (Zero)
}
Case (0x04)
{
M000 (0x3E04)
M460 (" Return (0x00)\n", Zero, Zero, Zero, Zero, Zero, Zero)
If ((\_SB.PCI0.SBRG.EC0.MSCM == One))
{
\_SB.PCI0.SBRG.EC0.MSCM = Zero
}
If ((MSIN == One))
{
MSIN = Zero
SMIE = 0xEB
}
Return (Zero)
}
Case (0x05)
{
If ((MSIN == Zero))
{
MSIN = One
SMIE = 0xEA
}
M000 (0x3E05)
M460 (" Return (0x00)\n", Zero, Zero, Zero, Zero, Zero, Zero)
Return (Zero)
}
Case (0x06)
{
M000 (0x3E06)
M460 (" Return (0x00)\n", Zero, Zero, Zero, Zero, Zero, Zero)
Return (Zero)
}
Case (0x07)
{
If ((MSIN == Zero))
{
MSIN = One
SMIE = 0xEA
}
M000 (0x3E07)
M460 (" Return (0x00)\n", Zero, Zero, Zero, Zero, Zero, Zero)
Return (Zero)
}
Case (0x08)
{
If ((MSIN == One))
{
MSIN = Zero
SMIE = 0xEB
}
M000 (0x3E08)
M460 (" Return (0x00)\n", Zero, Zero, Zero, Zero, Zero, Zero)
Return (Zero)
}
Default
{
M460 (" Return (0x00)\n", Zero, Zero, Zero, Zero, Zero, Zero)
Return (Zero)
}
}
}
Else
{
M460 (" Return (Buffer (1) {0x00})\n", Zero, Zero, Zero, Zero, Zero, Zero)
Return (Buffer (One)
{
0x00 // .
})
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment