Re: [RFC v1 0/2] platform/x86/amd: Add AMD DPTCi driver for TDP control in devices without vendor-specific controls

From: Antheas Kapenekakis

Date: Tue Mar 03 2026 - 18:48:22 EST


On Tue, 3 Mar 2026 at 22:51, Armin Wolf <W_Armin@xxxxxx> wrote:
>
> Am 03.03.26 um 20:34 schrieb Antheas Kapenekakis:
>
> > On Tue, 3 Mar 2026 at 20:27, Armin Wolf <W_Armin@xxxxxx> wrote:
> >> Am 03.03.26 um 20:16 schrieb Antheas Kapenekakis:
> >>
> >>> On Tue, 3 Mar 2026 at 19:59, Mario Limonciello <superm1@xxxxxxxxxx> wrote:
> >>>> A high level question - why aren't these vendors implementing PMF? It's
> >>>> 1000% less work to enable PMF. All the values that match the design get
> >>>> stored in BIOS, driver pulls the information and uses it.
> >>> From my understanding they do not implement anything and just use
> >>> ryzenadj with their windows vendor software.
> >> Do they implement a WMI ACPI device called "AOD"? AFAIK this WMI device
> >> is used by the Ryzen Master utility, so it could also allow users to change
> >> the TDP limits in a reasonable safe way.
> >>
> >> If they indeed only use ryzenadj, then shame on them.
> > From my understanding, Ryzen Master has not been updated in a while. I
> > was not aware of the AOD device. Moreover, it was my understanding
> > that Ryzen Master hardcoded write and lookup addresses.
>
> AFAIK someone on the Phoronix forums has found out that Ryzen Master uses
> the AOD WMI device, at least on some platforms.
>
> > From a quick lookup in my dump repository [2] it seems like not all of
> > them feature an AOD device. See below for an AI assisted compilation.
> >
> > The good thing with this interface is that it handles rerouting to
> > different mailbox addresses per generation, which makes implementation
> > straightforward.
>
> Yes, but the WMI interface also signals what kinds of settings are supported
> on a given device, as well as limits and step sizes. We would however require
> some input from AMD to figure out how to properly use it. Otherwise i can run
> some test to figure out the underlying interface.
>
> On devices without the AOD device, using the ALIB interface indeed seems to be
> the least dangerous way.

Seems like the AOD device just does clock tuning, but clocks are
locked on these devices and boost is enough to exceed the thermal
envelope. So I would not consider it a replacement in any case.
Perhaps there's some potential for desktop CPUs, but that's not my
area.

Antheas

> Thanks,
> Armin Wolf
>
> > Antheas
> >
> > [2] https://github.com/hhd-dev/hwinfo
> >
> > The following devices have an AOD device:
> > Asus Z13 2025 AMD (AMDT=0x02, AMDI* HIDs)
> > Legion_5_15ACH6H AMD Ryzen 5000
> > Legion_Slim_5_14APH8 AMD
> > Legion_Slim_7_16APH8 AMD
> > ally_x AMD Ryzen Z1 Extreme
> > aokzoe a1x AMD
> > ayaneo_3 AMD
> > ayaneo_flip_kb AMD
> > legion_go AMD (multiple ACPI versions)
> > one xplayer AMD
> > onexplayer f1pro AMD (AMDT=0x02, AMDI* HIDs)
> > orangepi_neo AMD
> > xbox_ally_x AMD Ryzen Z1 Extreme
> >
> > The following do not:
> > ayaneo_airplus
> > ayaneo_kun
> > ayaneo_slide
> > gpd_win4
> > gpd_win4_2024
> > gpd_win4_8840u
> > gpd_winmini
> > legion_go_s
> > loki_max
> > onexpalyer_fly
> > onexplayer x1
> > onexplayer x1 mini
> > onexplayer_mini_pro
> > rog_ally
> > win_max_2_hx370
> > xbox_ally
> >
> >> Thanks,
> >> Armin Wolf
> >>
> >>>> Same approach for Windows and Linux.
> >>>>
> >>>> More comments below.
> >>>>
> >>>> On 3/3/26 12:17 PM, Antheas Kapenekakis wrote:
> >>>>> Many AMD-based handheld PCs (GPD, AYANEO, OneXPlayer, AOKZOE, OrangePi)
> >>>>> ship with the AGESA ALIB method at \_SB.ALIB, which accepts Function 0x0C
> >>>>> (the Dynamic Power and Thermal Configuration Interface, DPTCi). This
> >>>>> allows software to adjust APU power and thermal parameters at runtime:
> >>>>> STAPM limit, fast/slow PPT limits, skin-temperature TDP limit, slow/STAPM
> >>>>> time constants, and the thermal control target.
> >>>>>
> >>>>> Until now userspace has reached this interface through the acpi_call out-
> >>>>> of-tree module or ryzenadj, which carry no ABI guarantees and no per-device
> >>>>> safety limits. This driver replaces that with a proper in-kernel
> >>>>> implementation that:
> >>>>>
> >>>>> * Exposes all seven parameters through the firmware-attributes sysfs ABI,
> >>>>> so that standard tools (fwupd, systemd-bios-vendor, etc.) can enumerate
> >>>> What is systemd-bios-vendor? I guess I'm not familiar with this and a
> >>>> quick web search didn't turn anything obvious up.
> >>> I used some AI assistance to compile this from my userspace
> >>> implementation and the ASEGA pdf from the AMD site. I need to go
> >>> through _everything_ before this moves to non-RFC. Same with
> >>> copyright year. I focused on the implementation doing the things I
> >>> want it to do for now.
> >>>
> >>>>> and modify them without device-specific knowledge.
> >>>>>
> >>>>> * Enforces tiered per-device and per-SoC limits. The default "device"
> >>>>> mode restricts writes to a curated safe range (smin..smax) derived from
> >>>>> the device's thermal design.
> >>>> Can you please elaborate where you got all these numbers from? I don't
> >>>> know if they're accurate or not. Someone would probably need to cross
> >>>> reference them to be sure.
> >>> Trial and error, research, references from Windows, etc. All of the
> >>> devices in this driver have been tested with a userspace
> >>> implementation using the same limits for ppt/sppt/fppt. Nobody has
> >>> complained about them. To be honest, I usually do not set tctl slow
> >>> and fast time limits, so those are referenced from the Legion Go and
> >>> for tctl I go lower than what manufacturers usually set. Users like
> >>> tctl because some of them like their device to stay cooler.
> >>>
> >>> The big idea for this driver is to allow locking /dev/mem and ACPI.
> >>> Other than the legion go fan curves, and the Zotac Zone driver which
> >>> needs a cleanup, everything else is handled in the kernel now.
> >>>
> >>> But this approach works fine for the Zotac Zone as they seem to be
> >>> using a very simple WMI shim.
> >>>
> >>>>> An "expanded" mode exposes the full
> >>>>> hardware-validated range. An optional CONFIG_AMD_DPTC_EXTENDED Kconfig
> >>>>> adds "soc" (raw ALIB_PARAMS envelope) and "unbound" tiers for advanced
> >>>>> use. The active tier is itself a firmware-attribute, switchable at
> >>>>> runtime.
> >>>>>
> >>>>> * Stages values and commits them atomically in a single ALIB call,
> >>>>> matching the protocol's intended bulk-update semantics. A save_settings
> >>>>> attribute (per firmware-attributes ABI) controls whether writes commit
> >>>>> immediately ("single" mode) or are held until an explicit "save".
> >>>>>
> >>>>> * When in "single" mode, re-applies staged values after system resume,
> >>>>> so suspend/resume cycles do not silently revert to firmware defaults.
> >>>> This isn't the only interface for setting power limits. How do you make
> >>>> sure that the EC for example isn't stepping on toes on these designs?
> >>> For the DMI matched devices it is not. For the ones that are not
> >>> matched, the driver does not autoload and needs a kconfig parameter to
> >>> even load.
> >>>
> >>> OneXPlayer is a bit more complex with their turbo button doing TDP
> >>> swaps but turbo takeover in oxpec takes care of that and then you are
> >>> supposed use ryzenadj.
> >>>
> >>>> I /guess/ it always will need to be opt-in a device by device basis.
> >>>>
> >>>> What happens if the vendor enables PMF in a BIOS update? How does this
> >>>> avoid conflicts?
> >>> Some manufacturers enable pmf without implementing the tables. From my
> >>> understanding none of them implement pmf with limits. If a
> >>> manufacturer wants to move to pmf, we can amend the DMI entry with a
> >>> bios match. However, from my understanding, there is no TDP slider
> >>> equivalent for PMF.
> >>>
> >>>>> Device limits are supplied for GPD Win Mini / Win 4 / Win 5 / Win Max 2 /
> >>>>> Duo / Pocket 4, OrangePi NEO-01, AOKZOE A1/A2, OneXPlayer F1/2/X1/G1,
> >>>>> and numerous AYANEO models. The SoC table covers Ryzen 5000, 6000, 7040,
> >>>>> 8000, Z1, AI 9 HX 370, and the Ryzen AI MAX series.
> >>>>>
> >>>>> Tested on a GPD Win 5 (Ryzen AI MAX+ 395). Confirmed with ryzenadj -i
> >>>>> that committed values are applied to hardware, and that fast/slow PPT
> >>>>> limits are honoured under a full-CPU stress load.
> >>>>>
> >>>>> @Mario: can you suggest a CC list for V2? Thanks. Even if not merged, this
> >>>>> driver is still good for downstream use.
> >>>> You should include Shyam (AMD), Denis and Derek (community).
> >>> Sure.
> >>>
> >>>>> ---
> >>>>> Usage
> >>>>> -----
> >>>>>
> >>>>> List all exposed attributes (read-only, no root required):
> >>>>>
> >>>>> $ fwupdmgr get-bios-settings
> >>>>>
> >>>>> This enumerates every attribute under /sys/class/firmware-attributes/,
> >>>>> including current_value, default_value, min_value, max_value, and
> >>>>> display_name for each DPTCi parameter.
> >>>> AFAIK - fwupd doesn't understand "save_settings" today
> >>> Yes, I do not expect it to even allow writing, but at least you can
> >>> preview the values which is useful. And from what I saw defaults are
> >>> not shown either.
> >>>
> >>> Antheas
> >>>
> >>>>> Sysfs direct usage
> >>>>> ------------------
> >>>>>
> >>>>> All paths are under:
> >>>>>
> >>>>> ATTR=/sys/class/firmware-attributes/amd_dptc/attributes
> >>>>>
> >>>>> Inspect a parameter (no root needed):
> >>>>>
> >>>>> $ cat $ATTR/stapm_limit/{display_name,min_value,max_value,default_value,current_value}
> >>>>> Sustained TDP (mW)
> >>>>> 4000
> >>>>> 85000
> >>>>> 25000
> >>>>> <- empty: nothing staged yet
> >>>>>
> >>>>> Stage values (held in memory, not yet sent to firmware):
> >>>>>
> >>>>> $ echo 25000 | sudo tee $ATTR/stapm_limit/current_value
> >>>>> $ echo 40000 | sudo tee $ATTR/fast_limit/current_value
> >>>>> $ echo 27000 | sudo tee $ATTR/slow_limit/current_value
> >>>>> $ echo 25000 | sudo tee $ATTR/skin_limit/current_value
> >>>>> $ echo 85 | sudo tee $ATTR/temp_target/current_value
> >>>>>
> >>>>> Commit all staged values in one ALIB call:
> >>>>>
> >>>>> $ echo save | sudo tee $ATTR/save_settings
> >>>>>
> >>>>> Switch to auto-commit (each write commits immediately):
> >>>>>
> >>>>> $ echo single | sudo tee $ATTR/save_settings
> >>>>>
> >>>>> Return to bulk mode:
> >>>>>
> >>>>> $ echo bulk | sudo tee $ATTR/save_settings
> >>>>>
> >>>>> Clear a staged value without committing:
> >>>>>
> >>>>> $ echo | sudo tee $ATTR/stapm_limit/current_value
> >>>>>
> >>>>> Query or change the active limit tier (device/expanded/soc/unbound):
> >>>>>
> >>>>> $ cat $ATTR/limit_mode/possible_values
> >>>>> device;expanded;soc;unbound
> >>>>> $ echo expanded | sudo tee $ATTR/limit_mode/current_value
> >>>>>
> >>>>> Switching tiers clears all staged values (old values may fall outside the
> >>>>> new range). Stages and commits must be redone after a mode switch.
> >>>>>
> >>>>> Antheas Kapenekakis (2):
> >>>>> Documentation: firmware-attributes: generalize save_settings entry
> >>>>> platform/x86/amd: Add AMD DPTCi driver
> >>>>>
> >>>>> .../testing/sysfs-class-firmware-attributes | 41 +-
> >>>>> MAINTAINERS | 6 +
> >>>>> drivers/platform/x86/amd/Kconfig | 27 +
> >>>>> drivers/platform/x86/amd/Makefile | 2 +
> >>>>> drivers/platform/x86/amd/dptc.c | 1325 +++++++++++++++++
> >>>>> 5 files changed, 1386 insertions(+), 15 deletions(-)
> >>>>> create mode 100644 drivers/platform/x86/amd/dptc.c
> >>>>>
> >>>>>
> >>>>> base-commit: c89ce241c1909d2c2bdde88334c33f3000d364fb
>