├── README.md
└── ruv.py
/README.md:
--------------------------------------------------------------------------------
1 | # Ryzen-5800x3d-linux-undervolting
2 | A Python script to use Ryzen SMU for Linux PBO tuning of Ryzen 5800x3d CPU. Mostly needed for Ryzen 5800x3d undervolting.
3 | # What is it ?
4 | This is a linux implementation of the PBO2 undevolting tool used to undervolt Ryzen CPUs in Windows. More info on how to do it in Windows is here: https://github.com/PrimeO7/How-to-undervolt-AMD-RYZEN-5800X3D-Guide-with-PBO2-Tuner
5 | # How to use it ?
6 | 1. Clone this repository: https://github.com/leogx9r/ryzen_smu and install the Ryzen SMU driver that makes comunication with Ryzen SMU (System Management Unit) possible
7 | ```pwsh
8 | git clone https://github.com/leogx9r/ryzen_smu
9 | cd ryzen_smu
10 | sudo make dkms-install
11 | ```
12 | Now make a reboot. The dkms-install should make a new module into you system called "ryzen_smu". It will autostart next time you reboot your system. Without it the provided Python script will not function.
13 | 2. When you have the driver installed and functioning clone this repository and start the undervolting tool.
14 | ```pwsh
15 | git clone https://github.com/svenlange2/Ryzen-5800x3d-linux-undervolting.git
16 | cd Ryzen-5800x3d-linux-undervolting
17 | sudo python3 ruv.py
18 | ```
19 | You should see this output:
20 | ```pwsh
21 | usage: ruv.py [-h] [-l] [-o OFFSET] [-c CORECOUNT] [-r]
22 |
23 | PBO undervolt for Ryzen 5800X3D processor
24 |
25 | optional arguments:
26 | -h, --help show this help message and exit
27 | -l, --list List curve offsets
28 | -o OFFSET, --offset OFFSET
29 | Set curve offset
30 | -c CORECOUNT, --corecount CORECOUNT
31 | Set offset to cores [0..corecount]
32 | -r, --reset Reset offsets to 0
33 | ```
34 |
35 | 3. The tool gives you ability to see and write the PBO curve offsets on the fly. The corecount enables writing the offset to all the hardware cpu cores. On 5800x3d you have 8 cores (other 8 are virtual hyperthreading counterparts). So in my case Ill use it like this:
36 |
37 | ```pwsh
38 | sudo python3 ruv.py -c 8 -o -30
39 | Core 0 set to: -30 readback:-30
40 | Core 1 set to: -30 readback:-30
41 | Core 2 set to: -30 readback:-30
42 | Core 3 set to: -30 readback:-30
43 | Core 4 set to: -30 readback:-30
44 | Core 5 set to: -30 readback:-30
45 | Core 6 set to: -30 readback:-30
46 | Core 7 set to: -30 readback:-30
47 | ```
48 |
49 | The "readback" in the response indicates what value was stored in the registers. I found out that if ill try to push it further than -30 it will allways read back -30 so there is a hardware limit to the number. All offsets will reset on reboot so install this commandline as a service to automate things at reboots.
50 | The offsets need to be negative as we want to undervolt the CPU.
51 |
--------------------------------------------------------------------------------
/ruv.py:
--------------------------------------------------------------------------------
1 | #!/bin/python
2 |
3 | import os
4 | import struct
5 | import argparse
6 | from time import sleep
7 |
8 | FS_PATH = "/sys/kernel/ryzen_smu_drv/"
9 |
10 | VER_PATH = FS_PATH + "version"
11 | SMU_ARGS = FS_PATH + "smu_args"
12 | MP1_CMD = FS_PATH + "mp1_smu_cmd"
13 |
14 |
15 | def is_root():
16 | return os.getenv("SUDO_USER") is not None or os.geteuid() == 0
17 |
18 |
19 | def driver_loaded():
20 | return os.path.isfile(VER_PATH)
21 |
22 |
23 | def read_file(file, size):
24 | with open(file, "rb") as fp:
25 | result = fp.read(size)
26 | return result
27 |
28 |
29 | def write_file(file, data):
30 | with open(file, "wb") as fp:
31 | return fp.write(data)
32 |
33 |
34 | def read_file32(file):
35 | result = read_file(file, 4)
36 | return struct.unpack(" 2**31:
109 | value = value - 2**32
110 | return value
111 |
112 |
113 | def set_core_offset(core_id, value):
114 | smu_command(0x35, ((core_id & 8) << 5 | core_id & 7) << 20 | value & 0xFFFF)
115 |
116 |
117 | if not is_root():
118 | print("Script must be run with root privileges.")
119 | quit(1)
120 |
121 | if not driver_loaded():
122 | print("The driver doesn't seem to be loaded.")
123 | quit(1)
124 |
125 |
126 | parser = argparse.ArgumentParser(
127 | description="PBO undervolt for Ryzen 5800X3D processor"
128 | )
129 | parser.add_argument("-l", "--list", action="store_true", help="List curve offsets")
130 | parser.add_argument("-o", "--offset", type=int, help="Set curve offset")
131 | parser.add_argument(
132 | "-c", "--corecount", default=1, type=int, help="Set offset to cores [0..corecount]"
133 | )
134 | parser.add_argument("-r", "--reset", action="store_true", help="Reset offsets to 0")
135 |
136 |
137 | args = parser.parse_args()
138 | cc = 1
139 | if args.corecount:
140 | cc = args.corecount
141 |
142 | if args.list:
143 | for c in range(0, cc):
144 | print("Core {}: {}".format(c, get_core_offset(c)))
145 | quit()
146 | if args.reset:
147 | smu_command(0x36, 0)
148 | print("Offsets set to 0 on all cores!")
149 | quit()
150 | if args.offset:
151 | for c in range(0, cc):
152 | if args.offset >= 0:
153 | print("Offset needs to be negative!")
154 | quit(1)
155 |
156 | set_core_offset(c, args.offset)
157 | print(
158 | "Core {} set to: {} readback: {}".format(c, args.offset, get_core_offset(c))
159 | )
160 | else:
161 | parser.print_help()
162 |
--------------------------------------------------------------------------------