HOWTO undervolt the AMD RX 4XX and RX 5XX GPUs
You may or may not to manually adjust the clockspeeds on AMD GPUs and you can do it fairly easily if you are using the amdgpu
driver on GNU/Linux.
Contents
Kernel parameters required
You need to add amdgpu.ppfeaturemask=0xfffd7fff
to your kernel command-line to enable "overdrive" so you can manually fool around with GPU clocks. It is also possible to use amdgpu.ppfeaturemask=0xffffffff
but that higher setting causes artifacts on many cards (mainly RX 470/570). Booting with this will make a special file called /sys/class/drm/card0/device/pp_od_clk_voltage
appear. You can write values to this file and activate them.
HOWTO do it yourself - the manual labor way
Changing the clocks and voltages for individual GPU states
s maxpstate GPU-clock voltate
will change the GPU clock for a specific p-state.m max-memory-pstate memory-clock memory-voltate
to change the memory clock for a p-state.
There are eight (0-7) GPU clock states and two (0-1) OR three (0-2) memory states on AMD RX GPUs.
This example changes the values for the highest CPU core and memory states:
Shell command: |
echo "s 7 1209 900" > /sys/class/drm/card0/device/pp_od_clk_voltage
echo "m 2 1850 850" > /sys/class/drm/card0/device/pp_od_clk_voltage |
The first line would set a maximum pstate of 7, set MHz to 1209 and a 900mV voltage. The second line would set the maximum memory pstate to 2, memory clock to 1850 and voltage to 850.
You can activate the settings written by writing c
to pp_od_clk_voltage
:
Shell command: |
echo "c" > /sys/class/drm/card0/device/pp_od_clk_voltage
|
You can re-set to default settings by writing r
:
Shell command: |
echo "r" > /sys/class/drm/card0/device/pp_od_clk_voltage
|
You can force your card to only use selected GPU pstates by sending whole numbers to pp_dpm_sclk
:
Shell command: |
echo "5 6 7" > /sys/class/drm/card0/device/pp_dpm_sclk
|
You can look at your /sys/class/drm/card0/device/pp_od_clk_voltage
with cat and see what you have available:
Shell command: |
cat /sys/class/drm/card0/device/pp_od_clk_voltage
|
This will give you an output like this:
OD_SCLK: 0: 300MHz 800mV 1: 466MHz 818mV 2: 751MHz 824mV 3: 1019MHz 950mV 4: 1074MHz 1000mV 5: 1126MHz 1050mV 6: 1169MHz 1093mV 7: 1242MHz 1150mV OD_MCLK: 0: 300MHz 800mV 1: 1650MHz 1000mV OD_RANGE: SCLK: 300MHz 2000MHz MCLK: 300MHz 2100MHz VDDC: 800mV 1175mV
Putting it all together
Here is an example of a complete underclock of a RX 580 done with a script file:
echo "manual" > /sys/class/drm/card0/device/power_dpm_force_performance_level echo 125000000 > /sys/class/hwmon/hwmon3/power1_cap echo "s 0 300 750" > /sys/class/drm/card0/device/pp_od_clk_voltage echo "s 1 600 769" > /sys/class/drm/card0/device/pp_od_clk_voltage echo "s 2 918 912" > /sys/class/drm/card0/device/pp_od_clk_voltage echo "s 3 1167 1075" > /sys/class/drm/card0/device/pp_od_clk_voltage echo "s 4 1239 1075" > /sys/class/drm/card0/device/pp_od_clk_voltage echo "s 5 1282 1075" > /sys/class/drm/card0/device/pp_od_clk_voltage echo "s 6 1326 1075" > /sys/class/drm/card0/device/pp_od_clk_voltage echo "s 7 1366 1075" > /sys/class/drm/card0/device/pp_od_clk_voltage echo "m 0 300 750" > /sys/class/drm/card0/device/pp_od_clk_voltage echo "m 1 1000 800" > /sys/class/drm/card0/device/pp_od_clk_voltage echo "m 2 2000 875" > /sys/class/drm/card0/device/pp_od_clk_voltage echo "c" > /sys/class/drm/card0/device/pp_od_clk_voltage
And here's an example for the RX 570:
echo "manual" > /sys/class/drm/card0/device/power_dpm_force_performance_level echo "s 3 1100 940" > /sys/class/drm/card0/device/pp_od_clk_voltage echo "s 4 1150 960" > /sys/class/drm/card0/device/pp_od_clk_voltage echo "s 5 1200 980" > /sys/class/drm/card0/device/pp_od_clk_voltage echo "s 6 1250 1000" > /sys/class/drm/card0/device/pp_od_clk_voltage echo "s 7 1300 1020" > /sys/class/drm/card0/device/pp_od_clk_voltage echo "m 2 1800 850" > /sys/class/drm/card0/device/pp_od_clk_voltage echo "c" > /sys/class/drm/card0/device/pp_od_clk_voltage
A script like that, once created, would be activated on each boot by making a simple systemd service script:
[Unit] Description=Change GPU clocks [Service] Type=oneshot ExecStart=/usr/local/bin/Set_GPU_Settings.sh RemainAfterExit=yes [Install] WantedBy=multi-user.target
Run systemctl daemon-reload
then systemctl enable tunegpu.service
to activate.