├── 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 | --------------------------------------------------------------------------------