Modern AMDGPU exposes one signed millivolt offset for the whole firmware-managed V/F curve.
AMD RDNA undervolting on Linux: what exists, what we can hack, and what we can visualize
Source-level analysis of Linux 7.1.5–7.1.8, 7.2-rc7, current public AMD DRM trees, and the path toward a single PenguinBurner tuning model for AMD and NVIDIA. RX 9060 and RX 9070 are the primary target. RDNA3 follows for the six-boundary experiment; RDNA2 remains a useful stock global-offset backend without the six-boundary claim.
SMU13/14 carry six offsets around five PWL zones, but stock Linux broadcasts one value to all six.
No modern AMDGPU getter enumerates the hidden V/F curve. We can sample its operating response instead.
Bottom line
Modern RDNA support is viable, but it is a different control model from NVIDIA. The shared product should be built around capabilities and typed tuning plans—not around a universal editable curve.
| Capability | NVIDIA in PenguinBurner | AMD stock 7.1.8 | AMD SMU14 experiment |
|---|---|---|---|
| Enumerate editable V/F bins | Yes | No | No |
| Independent voltage-shape control | Many frequency offsets at voltage bins | No | Six coarse boundary offsets, if PMFW accepts them |
| Whole-curve voltage offset | Not the current NVIDIA model | vo N | Keep vo N compatible |
| Observe current voltage/frequency | Yes | Yes when board/firmware exports the metrics | Same telemetry |
| Read six boundary offsets | Not applicable | Only element zero is reported | Patch can report all six |
| Read hidden base curve | Hidden NVAPI path | No public getter | Still no base-curve getter |
(frequency, voltage) coordinates. Exposing them would produce a
coarse curve-shaping control, not NVIDIA-style editing of dozens of bins.
Scope by generation
| Target | Supported stock plan | Six-boundary experiment | PenguinBurner scope |
|---|---|---|---|
| RDNA2 / inspected SMU11 paths | Global vo where the live ABI exposes it | No six-slot table found on the relevant path | Simple global-offset support only |
| RDNA3 / inspected SMU13.0.0 and 13.0.7 paths | Global vo | Six slots exist; investigate after RDNA4 | Stock support plus later experimental qualification |
| RDNA4 / SMU14.0.2 and 14.0.3 | Global vo | Six slots exist; first patch and hardware target | Primary RX 9060/9070 target |
Marketing generation is not the dispatch key. PenguinBurner must inspect the selected card's live tokens
and ranges, then advertise GLOBAL_VOLTAGE_OFFSET or the explicitly patched
ZONE_BOUNDARY_OFFSETS capability. This keeps RDNA2 inside the same adapter without forcing it
into the RDNA3/4 experiment.
Exactly what Linux 7.1.8 can do on modern AMD
This is the stock-kernel implementation target. Every item must be capability-probed on the selected PCI device; board firmware and the OverDrive feature mask remain authoritative.
1. Global voltage offset—the supported path
Confirmed upstream
The documented pp_od_clk_voltage command is vo <offset_mv>. AMDGPU describes it
as an extra offset applied to the whole V/F curve.
The generic parser sends one PP_OD_EDIT_VDDGFX_OFFSET value; the SMU13 and SMU14 handlers copy
it into every internal boundary slot. Linux 7.1.8 therefore provides one scalar—not per-point control.
# Schematic sequence; exact card path and emitted range must be discovered.
write power_dpm_force_performance_level: manual
write pp_od_clk_voltage: vo <signed millivolts inside VDDGFX_OFFSET range>
write pp_od_clk_voltage: c
read pp_od_clk_voltage # verify committed state
# Restore OverDrive state:
write pp_od_clk_voltage: r
write pp_od_clk_voltage: c
restore the performance-level policy captured before the transaction
PenguinBurner can scan progressively more-negative values, but it must use the card's reported range and read back every commit. Fixed presets such as −50/−100/−150 mV can be search seeds, never assumed-safe universal values. A crash-safe baseline, rollback, and final verification are mandatory.
pp_od_clk_voltage is created only when OverDrive is
supported and enabled. OverDrive bit 14 is not in the upstream default stable feature mask, so a missing
node may reflect the effective amdgpu.ppfeaturemask policy rather than the silicon. The files are
root-writable. PenguinBurner should diagnose both conditions, never silently edit boot parameters, and route
every write through penguin-burnerd after an explicit user action.
2. Clock, power, fan, and policy controls
| Control | 7.1.8 surface | Practical meaning |
|---|---|---|
| Graphics clock | pp_od_clk_voltage tokens emitted by the card | SMU backends differ: min/max clocks or an offset. Parse the live output. |
| Power cap | hwmon power1_cap, _min, _max | Enough to define lower-power Efficiency and higher-headroom Performance candidates when supported. |
| Fan control | hwmon PWM and optional gpu_od/fan_curve | Independent capability; never assume every board exposes the firmware curve editor. |
| DPM policy | power_dpm_force_performance_level | Manual OverDrive changes require policy coordination and restoration. |
| Recovery | OverDrive reset; separate GPU recovery machinery | Use r + c for normal rollback. A full GPU reset is escalation, not routine restore. |
What changed specifically in the 7.1.x stable updates
- 7.1.6: corrected SMU13 power-limit min/default/max calculation and power-display units. The SMU13 range fix is not the RX 9000 SMU14 fix.
- 7.1.8: standardized AMD PM's internal GPU-power sensor unit to milliwatts while preserving the legacy raw debugfs encoding.
- 7.1.8: made each
gpu_metricsread one atomic snapshot instead of a possible mixture of two samples. - 7.1.8: fixed a concurrent
pp_tableuse-after-free and stopped exposing that table on firmware-owned APUs. - 7.1.8: restored the selected UMD stable pstate after runtime resume and included DCN flip/idle correctness fixes.
None of those commits changed PP_OD_EDIT_VDDGFX_OFFSET, the six-slot broadcast, the fan ABI, or added a voltage-curve getter.
3. Telemetry available to an Auto-UV scanner
Confirmed upstream
Documented hwmon attributes include GPU voltage in0_input, GFX clock freq1_input,
memory clock, temperature, power, fan, and cap limits when the ASIC/firmware supplies them.
gpu_busy_percent, mem_busy_percent, and versioned binary gpu_metrics
add utilization and a synchronized metrics snapshot. Linux 7.1.8 specifically fixed
torn gpu_metrics reads,
which is useful for response sampling.
4. Things 7.1.8 does not expose
- No per-point editor for RDNA2, RDNA3, or RDNA4 on the modern
vopath. - No list of the firmware's base V/F points and no boundary-frequency getter.
- No public six-value setter or six-value readback for
VoltageOffsetPerZoneBoundary[]. - No guarantee that voltage telemetry exists or has the same averaging behavior on every board.
- No reason to use ROCm merely for sysfs tuning; the kernel driver owns these controls.
What 7.2 and newer public trees actually change
None of the inspected changes turn AMD into a per-point curve API. They still matter for a reliable PenguinBurner backend.
| Tree | Tuning-adjacent changes | Per-point/per-zone UV? |
|---|---|---|
| 7.1.5 → 7.1.8 | Power-unit correction, atomic gpu_metrics, pp_table safety/APU restriction, UMD state restore, display fixes. |
No change |
| 7.2-rc7 | OD parser/output hardening, corrected SMU14 power-limit range, SMU14.0.2 energy-metric fix, GFX12 queue/reset and display robustness. | No change |
| Post-7.2 AMD DRM / linux-next | Queued power-limit accounting and restoration across AC/DC changes, resume, table reload, and reset. | No public patch found |
RX 9060 uses MP1 14.0.2 and RX 9070/9070 XT uses MP1 14.0.3 in the
official hardware table.
Both dispatch through the shared smu_v14_0_2 backend, so both get the same scalar-only voltage
semantics—and both are good targets for the same carefully gated experiment.
The six-boundary SMU13/14 experiment
The driver is currently the narrowing point on the inspected SMU13/14 paths: the full OverDrive table contains six values, while the public edit path deliberately broadcasts one input and reports only slot zero. Patch SMU14 first for RX 9060/9070; treat SMU13 as a separate follow-up qualification.
What the stock handler does
Confirmed upstream
SMU14 defines PP_NUM_RTAVFS_PWL_ZONES = 5 and six
VoltageOffsetPerZoneBoundary[] entries. The
7.2-rc7 edit handler
loops over all six entries and assigns the same input[0]. Its
read path
prints only element zero. The 7.1.8 code has the same semantics.
Can we add a six-value setter?
Experiment proposal
Yes at the kernel-driver layer. Preserve vo N as the supported broadcast operation, add an
explicitly experimental command that accepts exactly six signed values, validate every element against
firmware-provided bounds, write the complete OverDrive table, commit, and read it back.
# Existing ABI remains unchanged:
vo -75 # broadcast -75 mV to B0..B5
# Illustrative private-patch syntax—not an upstream ABI:
voz -20 -30 -45 -60 -75 -85 # independently stage B0..B5
c # commit through the normal OD transaction
r # reset remains available
The token name voz is intentionally presented as a design placeholder. An upstream RFC should
let AMD maintainers choose the ABI. The important properties are atomic six-value input, unchanged legacy
behavior, per-slot validation, full readback, and an obvious experimental capability flag.
Can we add a six-value getter?
Experiment proposal
Yes. The complete SMU OverDrive table is already retrieved from firmware; the current display function
merely selects [0]. A diagnostic patch can emit B0 through B5 after a fresh table read, and the
setter can compare requested values with that firmware readback.
# Illustrative patched readback—not present in stock 7.1.8:
OD_VDDGFX_OFFSET_ZONES:
0: <signed mV at B0>
1: <signed mV at B1>
2: <signed mV at B2>
3: <signed mV at B3>
4: <signed mV at B4>
5: <signed mV at B5>
What we still have to prove on hardware
Encouraging evidence
- The firmware table truly carries six independently addressable fields.
- The full table already crosses the kernel/PMFW boundary.
- SMU14 declares advanced/full-control fields and an OD curve-offset error code.
- RX 9060 and RX 9070 share the backend to patch first.
Unknown until an RX 9000 test
- Whether PMFW accepts unequal offsets or silently normalizes them.
- Whether a hidden advanced mode is required—and how to enable it safely.
- Per-slot bounds, interpolation behavior, and persistence across reset/resume.
- Whether unequal offsets produce stable, useful curve shaping.
What AMD getters actually offer
Stock modern AMD exposes configured controls and the current operating state—not the full function the firmware uses to choose voltage at every frequency.
| Question | Best source | Answer |
|---|---|---|
| What voltage offset and OD ranges are configured? | pp_od_clk_voltage | Yes: supported tokens, state, and ranges; modern stock readback shows the scalar. |
| What clock and voltage is the GPU using now? | gpu_metrics or hwmon freq1_input + in0_input | Often, capability-dependent. Metric versions and averaging differ. |
| What are temperature, power, fan, and utilization now? | gpu_metrics, hwmon, busy-percent files | Yes when exposed; missing values must remain “unavailable.” |
| What DPM levels exist/currently apply? | pp_dpm_sclk and related files | Where supported; levels are not an absolute V/F curve. |
| What are all hidden V/F points? | No public modern ABI | No. |
| What are all six internal offsets? | Stock display function | No: only slot zero. A patch can expose all six. |
| Where are the six boundary frequencies? | No documented ABI | No safe mapping found. |
The internal SMU table also contains droop/PWL coefficients. Their presence suggests a piecewise mathematical curve, not a dense public list of 100+ points. The scaling and relationship to the six offset boundaries are not documented as a userspace ABI, so decoding them would be a separate reverse-engineering project—not something PenguinBurner should silently rely on.
How PenguinBurner can visualize an opaque AMD curve
Call it a measured operating response, not “the firmware V/F curve.” Each dot is something the GPU actually reported while a controlled workload was running.
Show
- Faint raw samples, binned median, confidence/dispersion band, and sample count.
- Stock versus current candidate and final Efficiency/Balanced/Performance overlays.
- Red markers for throttling, instability, reset, or a failed probe.
- Gaps where telemetry is missing or sample density is insufficient.
- A separate six-node offset strip when the patched capability exists.
Never imply
- That interpolation through samples is the firmware's stored curve.
- That every frequency has one deterministic voltage independent of temperature and limits.
- That B0…B5 have known MHz positions before the mapping is proven.
- That absent voltage metrics equal zero.
- That a passed workload proves universal stability.
One PenguinBurner interface for AMD and NVIDIA
Use one orchestration contract with a tagged voltage-control payload. Share identity, telemetry, lifecycle, scoring, persistence, rollback, and verification; let candidate construction remain capability-specific.
- NVML facts/controls
- hidden NVAPI V/F snapshot
- per-bin frequency offsets
- capabilities + stable device identity
- telemetry snapshot
- apply typed plan + readback
- restore captured baseline
- run/score/verify candidates
- sysfs/hwmon facts
- global offset now
- six-boundary offsets only when patched
enum VoltageControl {
PerPointCurve { points: Vec<VfOffset> }, // NVIDIA
GlobalOffset { offset_mv: i32 }, // stock modern AMD
ZoneBoundaryOffsets { offsets_mv: [i32; 6] }, // patched SMU13/14 only
None,
}
struct TuningPlan {
device_id: StablePciIdentity,
voltage: VoltageControl,
gfx_clock: Option<ClockControl>,
memory_clock: Option<ClockControl>,
power_limit: Option<PowerLimit>,
fan: Option<FanControl>,
}
trait GpuTuningBackend {
fn capabilities(&self) -> Capabilities;
fn telemetry(&self) -> TelemetrySnapshot;
fn capture_baseline(&self) -> BaselineToken;
fn apply(&self, plan: &TuningPlan) -> AppliedReadback;
fn restore(&self, baseline: &BaselineToken) -> AppliedReadback;
}
PenguinBurner design
The Rust daemon remains the only privileged writer. AMD sysfs writes, OD commit/reset, fan changes, and
recovery belong behind /run/penguin-burnerd.sock, just like NVIDIA mutations. Python and Qt
consume typed daemon capabilities; they do not open a second privileged engine.
Do not add an adapter method named simply get_curve() and fabricate AMD points. Instead expose
voltage_control.kind, optional editable controls, and a distinct measured-response series.
Profiles should persist the tagged plan, PCI identity, kernel/driver/firmware facts, ranges, captured
baseline, and verification evidence. A profile is revalidated when capabilities change.
Efficiency, Balanced, and Performance on AMD
The same three product goals remain possible without pretending AMD has NVIDIA's curve editor. PenguinBurner searches the controls the card actually exposes.
| Tier | Global voltage strategy | Clock/power strategy | Selection target |
|---|---|---|---|
| Efficiency | Most-negative verified stable scalar offset | Lower power cap and, where supported, lower clock target/offset | Best performance per watt subject to a performance floor |
| Balanced | Moderate verified negative offset | Near-stock clocks and a moderate cap | Meaningful power/temperature reduction with little performance loss |
| Performance | Mild negative or zero offset, whichever remains stable | Positive GFX control and/or higher permitted power cap | Highest verified throughput inside thermal and power guardrails |
Yes, Performance can push clocks and power upward if the card exposes those controls. Efficiency can push
them downward. A negative voltage offset does not itself lock an exact voltage; firmware continues choosing
the operating point. Search candidates should therefore be explicit tuples such as
{offset_mv, gfx_control, power_limit}, scored using measured output, energy, temperature,
throttling, and stability.
How to take the six-boundary idea upstream
First prove that PMFW accepts unequal values on RX 9060/9070. Then turn the evidence into a narrow RFC rather than asking upstream to accept an untested UI concept.
- Build the private SMU14 diagnostic patch with legacy scalar behavior, atomic six-value set, six-value get, validation, reset, and readback logs.
- Capture exact board, VBIOS, PMFW, kernel commit, OD ranges, accepted/rejected arrays, runtime telemetry, transition tests, reset/resume behavior, and recovery.
- Document the missing contract questions: slot bounds, interpolation, boundary mapping, advanced-mode requirements, and long-term ABI.
- Open a focused request in the DRM/AMD project, linking the evidence and PenguinBurner Discussion #43.
- Send the RFC/patch to amd-gfx and the current AMD PowerPlay/SWSMU and AMDGPU maintainers listed in the kernel MAINTAINERS file.
No matching public patch series or announced roadmap exposing independent
VoltageOffsetPerZoneBoundary[] values was found in mainline, drm-next, AMD staging, linux-next,
or the searched public patch queue as of the research date. That is absence of public evidence—not proof
AMD will never support it.
Primary sources
Claims above were checked against project documentation and source, not forum recipes.
- AMDGPU GPU Power/Thermal Controls, Linux 7.1Documented OverDrive commands, hwmon attributes, fan controls, power caps, and gpu_metrics.
- Linux 7.1.8 OverDrive parserThe public
votoken maps to one voltage-offset edit operation. - Linux 7.1.8 SMU14 voltage-offset handlerOne input is copied across all internal boundary entries.
- SMU14 firmware-interface definitionsFive RTAVFS PWL zones and six OverDrive curve-offset entries.
- Official AMDGPU hardware tableRX 9060 XT MP1 14.0.2; RX 9070/9070 XT MP1 14.0.3.
- Linux 7.1.8 changelogStable fixes checked for AMD power, metrics, table, resume, and display changes.
- SMU14 power-limit range correction in 7.2The main tuning-adjacent 7.2 correction for the shared RX 9000 backend.
- Inspected linux-next SMU14 backendStill scalar-broadcasting at the pinned development-tree revision.
- AMD ADLX
SetGPUVoltageWindows cross-check: Navi4+ exposes a scalar voltage offset from base voltage. - PenguinBurner Discussion #43The original AMD support and per-V/F-point API discussion this report updates.