SkatterBencher #77: Raspberry Pi 5 Overclocked to 3000 MHz
We overclock the Raspberry Pi 5 single-board computer to 3000 MHz with the 52pi Ice Tower cooler and modified firmware.
3 GHz is the highest frequency I can achieve with my Raspberry Pi 5. I wrote my own hardware telemetry script, hacked the firmware, and hooked up the EVC2 to get the most out of the Pi. In today’s video, I show you how to undervolt and overclock the Raspberry Pi 5. I cover three distinct overclocking strategies, ranging from pretty simple to quite advanced:
- First, we increase the clock frequency and operating voltage of the ARM cores.
- Second, we upgrade our cooling and increase the VideoCore frequency.
- Lastly, we try to work around the voltage limitations to get to 3 GHz.
However, before we jump into overclocking, let us quickly review the hardware and software used for this guide.
Table of Contents
Raspberry Pi 5: Introduction
The Raspberry Pi 5 is a single-board computer featuring a Broadcom BCM2712 SoC and, for the first time, an RP-1 southbridge chip for I/O connectivity. Nowadays, the Raspberry Pi is primarily catering to industrial applications, however it also attracts technology enthusiasts and educators.
The BCM2712 is a 16nm SoC succeeding the BCM2711 of the Raspberry Pi 4. It’s built around a quad-core Arm Cortex-A76 (with ARMv8-A ISA) CPU cluster, with a base frequency of 1.5 GHz and a turbo frequency of up to 2.4 GHz. The core cluster has 512KB per-core L2 caches and a 2MB shared L3 cache. Furthermore, the SoC also integrates an improved 12-core VideoCore VII GPU.
A 32-bit LPDDR4X memory interface provides up to 17GB/s of memory bandwidth, while x1 and x4 PCI Express interfaces support high-bandwidth external peripherals. On Raspberry Pi 5 the latter is used to connect to the Raspberry Pi RP1 south bridge, which provides the bulk of the external-facing I/O functionality. Lastly, the SDIO provides a 100MB/s connection for the SD card which is the typical storage used for the Raspberry Pi. All these parts of the SoC are connected via a 128-bit AMBA data bus running at the VideoCore frequency.
Raspberry Pi 5: Platform Overview
The system we’re overclocking today consists of the following hardware.
Item | SKU | Price (USD) |
SBC | Raspberry Pi 5 8GB | 80 |
CPU Cooling | Argon Neo 5 52Pi Ice-Tower CPU Cooler ElmorLabs UPF | 19 16 10 |
Storage | RICELEE microSD 64GB | 13 |
Power Supply | Raspberry Pi 27W USB-C Power Supply | 14 |
Raspberry Pi 5: Benchmark Software
We use Ubuntu 23.10 64-bit and the following benchmark applications to measure performance and ensure system stability.
BENCHMARK | LINK |
Geekbench 6 (Arm Preview) | https://www.geekbench.com/preview/ |
AI Benchmark | https://pypi.org/project/ai-benchmark/ |
7-Zip | https://www.7-zip.org/ |
Sysbench | https://github.com/akopytov/sysbench |
KCBench | https://gitlab.com/knurd42/kcbench |
HWBOT Prime | https://github.com/frederikcolardyn/hwbotprime |
Openarena | https://community.hwbot.org/topic/80520-guide-3d-benchmarking-with-openarena/ |
Passmark | https://www.passmark.com/products/pt_linux/download.php |
S-tui | https://github.com/amanusk/s-tui |
Telemetry Monitoring & Logging
In addition to the benchmark software tools, we also need hardware telemetry tools to evaluate bottlenecks and operating frequencies and voltages. On Windows systems, I rely on HWiNFO for telemetry data. However, on Linux, it’s a bit more difficult to get reliable information. Especially for the Raspberry Pi.
The most reliable telemetry is available through a command line tool provided by the SoC manufacturer, Broadcom, called vcgencmd. This tool communicates with the VideoCore IP block using a UART protocol.
With the help of ChatGPT, CoPilot, Gemini, and my brother, I put together a small Python script that gathers all relevant Raspberry Pi 5 telemetry such as frequencies, voltages, and temperatures, and outputs it both in the command terminal and an easy-to-use CSV file.
You can download the script from my GitHub page if you want to have a closer look.
Raspberry Pi 5: Stock Performance
Before starting overclocking, we must check the system performance at default settings. The default operating frequencies for the Raspberry Pi 5 are as follows.
- Arm: 2400 MHz (min: 1500 MHz)
- GPU/Core: 910 MHz (min: 500 MHz)
- V3D: 960 MHz (min: 500 MHz)
- ISP: 910 MHz (min: 500 MHz)
- HEVC: 910 MHz (min: 500 MHz)
- SDRAM: 4267 MHz (LPDDR4X-4267)
- UART: 44 MHz
- EMMC: 200 MHz
- Pixel: 148 MHz
- HDMI: 648 MHz
Here is the benchmark performance at stock:
- Geekbench 6 Single: 768 points
- Geekbench 6 Single: 1,569 points
- AI Benchmark: 272 points
- 7-Zip: 10,891 points mips
- Sysbench 1T: 2,726 events/sec
- Sysbench: 4T: 10,837.5 events/sec
- KCBench: 1,105.02 sec
- HWBOT Prime 0.8.3: 4,474.31 points
- Openarena: 49.0 fps
- PassMark CPU: 2,213 marks
- PassMark Memory: 1,258 marks
When running the S-TUI Stability Test, the average Arm clock is 2398 MHz with 0.896 volts. The average SoC temperature is 73 degrees Celsius. The average Arm core power consumption is 5.44 watts.
Now it’s time to increase the frequency and, hopefully, also increase the performance!
OC Strategy #1: ARM frequency
In our first overclocking strategy, we will simply increase the operating frequency and voltage of the Arm cores. Overclocking on Raspberry Pi is actually very simple: you just have to add a few lines to a text file. Let’s have a closer look.
Config.txt
Overclocking is done by setting the boot parameters in a config.txt file which is located in the boot folder of the storage device. The easiest way is to simply add the lines to the config file, however, a fancier and cleaner way is to add your overclocking settings as a txt file in the same folder and then include that text file with the config.txt.
That’s how I do it for my overclocking guide: I have a text file for each OC Strategy, and comment in or out the appropriate file depending on the settings I want to use.
You can modify the files either on the Raspberry Pi itself or by plugging the SD card into another computer. I’ll show how it works at the end of this overclocking strategy.
Frequency Configuration
The Raspberry Pi 5 actually supports quite a bit of overclocking as it offers parameter adjustment for several clock domains:
- arm_freq & arm_freq_min for the arm cores
- gpu_freq & gpu_freq_min for the VideoCore (GPU), including the GPU, 3D engine, ISP, and hardware video blocks.
- core_freq & core_freq_min for the VideoCore (GPU) and the data bus connecting the Arm cores, memory controller, and other blocks.
- v3d_freq & v3d_freq_min for the VideoCore 3D engine. This can be set independent of the core_freq.
- isp_freq & isp_freq_min for the image signal pipeline block.
- hevc_freq & hevc_freq_min for the hardware video block
The three most relevant clock frequencies for this overclocking guide are the Arm, core, and V3D. Unfortunately, unlike with the first Raspberry Pi versions, there’s no way to set the memory frequency.
The arm core frequency was limited to 3 GHz when the Pi 5 launched in October 2023. However, following a Github issue from March 9th, Raspberry Pi firmware engineers unlocked the frequency in newer firmware versions
The VideoCore, ISP, and HEVC clocks are linked together. The operating frequency will be the highest among the three configured domains. The V3D engine will run at the same frequency if you set the gpu_freq parameter. However, if you don’t set gpu_freq or set the v3d_freq directly, it will operate at an independent frequency.
Configuring the “freq” parameter sets the frequency upper bound of the voltage/frequency curve. Likewise, “freq_min” sets the lower bound of the v/f curve. You can force the frequency to the upper bound value by using the force_turbo=1 parameter. Furthermore, you can enforce the maximum turbo frequency from boot by setting the initial_turbo=1 parameter.
BCM2712 Dynamic Voltage Frequency (DVF)
One of the more interesting aspects of the Raspberry Pi 5 overclocking is its dynamic voltage frequency curve or DVF. This technology enables dynamic adjustment of the voltage (and thus power consumption) depending on the operating frequency.
Each BCM2712 chip has a unique base voltage (Vpred) from the factory. This base voltage is added to a fixed DVF slope which increases with operating frequency. I think you can get Vpred information by running the sudo vcgencmd get_config int command. However, the value changes slightly every boot, and it’s not entirely clear to me how it impacts the V/F curve. Perhaps it’s the predicted voltage required for the default maximum turbo frequency of 2400 MHz.
Using our telemetry tool, we can map the Arm core’s voltage-frequency curve. We find that the minimum voltage is 720mV for 1500 MHz and below, then increases gradually to almost 887mV at 2400 MHz. The 720mV is a firmware-defined lower limit of the SoC voltage. As explained by a Raspberry Pi firmware engineer, below 720mV the SRAM cache becomes unstable. This is a very common challenge with silicon chips.
When we increase the upper limit of the arm frequency to 2800 MHz, without adding voltage, we find that the voltage also increases to 944 mV. That’s useful information because it means we can increase the frequency without worrying too much about the voltage.
Voltage Configuration
The Raspberry Pi 5 offers two ways to manually configure the voltage: over_voltage and over_voltage_delta.
Over_voltage is the traditional method of setting the voltage as it simply sets a fixed voltage. The over_voltage parameter ranges from -16 to +8, where +8 sets the voltage to 1.0V. I could only undervolt to -5 which sets the operating voltage to 760 mV.
Over_voltage_delta is a much more modern method of adjusting the voltage configuration as it offsets the V/F curve. Interestingly, the voltage offset can be both positive and negative, thus enabling undervolting opportunities for those looking to save power.
As we increase the operating voltage, we find there’s also an upper limit to the voltage: 1V. This limit is enforced regardless of which over-voltage method is used.
For this overclocking strategy, we use an over voltage delta of 25mV and a maximum Arm core frequency of 2900 MHz.
Config Settings & Benchmark Results
Open the Ubuntu terminal
- Type sudo nano /boot/firmware/config.txt and add the following lines
- [overclocking_strategies]
- Include ocs1.txt
- Write the file using control+o, then exit using control+x
- Type sudo nano /boot/firmware/ocs1.txt and add the following lines
- arm_freq=2900
- over_voltage_delta=25000
- Write the file using control+o, then exit the file using control+x
Then reboot the Pi.
We rerun the benchmarks and check the performance increase compared to the default operation.
- Geekbench 6 Single: +10.94%
- Geekbench 6 Single: +2.74%
- AI Benchmark: +7.74%
- 7-Zip: +9.73%
- Sysbench 1T: +20.78%
- Sysbench: 4T: +20.88%
- KCBench: +2.98%
- HWBOT Prime 0.8.3: +8.95%
- Openarena: +6.12%
- Passmark CPU: +10.94%
- Passmark Memory: +12.80%
Increasing the frequency by almost 21% increases the performance across the board. However, only in Sysbench, do we see linear performance scaling. The performance of other benchmarks improves between 3% and 13%.
When running the S-TUI Stability Test, the average Arm clock is 2636 MHz with 0.980 volts. The average SoC temperature is 83.2 degrees Celsius. The average Arm core power consumption is 7.58 watts.
OC Strategy #2: Cooling
From the stress test in our previous overclocking strategy, we see that the operating temperature is a limiting factor for our overclock. So, for this overclocking strategy, I switch to a more powerful heatsink and I also increase the operating frequency of the VideoCore.
Temperature Limit
Just like any other SoC on the market, the BCM2712 has a firmware-defined maximum operating temperature. For the Raspberry Pi 5, the thermal throttling kicks in starting from 80 degrees Celsius with the maximum allowed operating temperature being 85 degrees Celsius.
The initial throttling behavior is pretty benign as the frequency drops by only a few dozen MHz. However, as we continue to operate at the thermal limit, the frequency throttling becomes more severe until eventually the Arm turbo boost is disabled, and the frequency drops all the way to the base clock of 1500 MHz.
While there’s no way to override the maximum allowed temperature, we can further restrict it by using the temp_limit parameter.
VideoCore Frequency
The Raspberry Pi 5 SoC architecture can be separated into two major parts: the cluster of arm CPU cores and the VideoCore VPU/GPU. In our previous overclocking strategy, we overclocked the former, but in this strategy, we also want to increase the latter.
The VideoCore frequency is tied to a variety of IP blocks on our SoC, including the V3D engine, the image signaling processor, the HEVC hardware video block, the AMBA data bus, and the VideoCore L2 cache. Of these IP blocks, only the V3D engine can run at its independent frequency.
For this overclocking strategy, I’m primarily interested in increasing the data bus frequency connecting the VideoCore with the Arm cluster and the memory subsystem. For this, we can use the gpu_freq parameter and increase it to its maximum stable frequency. In my case, that was 1100 MHz. Then, I still manually limit the v3d frequency to its default of 960 MHz.
Config Settings & Benchmark Results
Open the Ubuntu terminal
- Type sudo nano /boot/firmware/config.txt and add the following lines
- Include ocs2.txt
- Write the file using control+o, then exit the file using control+x
- Type sudo nano /boot/firmware/ocs2.txt and add the following lines
- arm_freq=2900
- gpu_freq=1100
- v3d_freq=960
- over_voltage_delta=25000
- Write the file using control+o, then exit the file using control+x
Then reboot the Pi.
We run the benchmarks and check the performance increase compared to the default operation.
- Geekbench 6 Single: +14.06%
- Geekbench 6 Single: +11.98%
- AI Benchmark: +8.82%
- 7-Zip: +13.24%
- Sysbench 1T: +20.95%
- Sysbench: 4T: +21.62%
- KCBench: +2.05%
- HWBOT Prime 0.8.3: +9.18%
- Openarena: +1.63%
- Passmark CPU: +14.01%
- Passmark Memory: +14.15%
By increasing the VideoCore frequency from 910 to 1100 MHz, we see a further increase in performance across all benchmark applications as the geomean performance improvement is about 3 percentage points.
When running the S-TUI Stability Test, the average Arm clock is 2895 MHz with 1.00 volts. The average SoC temperature is 72.6 degrees Celsius. The average Arm core power consumption is 7.99 watts.
OC Strategy #3: Firmware Voltage Limitation
In our third overclocking strategy, we work around the firmware voltage limitation. However, that’s easier said than done, because the voltage configuration is handled in multiple places. Let’s dig into the details.
Artificial Voltage Limits
As I mentioned earlier on, the Broadcom SoC has a dynamic voltage frequency technology that scales the operating frequency and voltage according to a predefined voltage/frequency curve. In addition to the dynamic scaling, the V/F curve also has an upper and lower limit for the operating voltage. In the case of the Raspberry Pi 5, the upper limit is 1V and the lower limit is 720mV.
This behavior is very typical for a modern SoC. Enthusiasts overclocking AMD, Intel, and NVIDIA chips are all too familiar with this kind of artificial limitation. Typically, these limits are enforced in one or multiple ways:
- It can be software enforced through system drivers
- It can be firmware-enforced by the SoC through BIOS or microcode
- It can be firmware-enforced by the voltage regulator
- It can even be hardware-enforced on the PCB!
Just like I do with other overclocking guides, let’s have a look and see if we can work around these limitations. Let’s start with the firmware.
Firmware Voltage Limitation
As said, we’re all too familiar with artificial overclocking and overvoltage limitations governed by the firmware code of the power management unit in the name of device security. This is no different with the Raspberry Pi 5. A Raspberry Pi community member by the name of Jonatron explains this very well in a blog post titled “Beating Jeff’s 3.14 Ghz Raspberry Pi 5.”
To make a long story short, the first three boot stages of the Raspberry Pi include BOOTROM, bootsys, and bootmain. BOOTROM is on-chip code that holds the secure keys. If secure mode is enabled, it will verify the signatures of the second-stage bootloaders: bootsys, and bootmain. Bootsys verifies if the SPI EEPROM signature matches the customer key in the OTP. If it does, then it will execute the bootmain, which is also signed.
The multiple levels of signatures effectively prevent us from simply modifying the Raspberry Pi 5 firmware and flashing custom firmware. This is similar to how we can no longer flash our custom NVIDIA VGA BIOSes.
However, as a root Linux user on Raspberry Pi, we have full access to system memory, including the memory used by the VideoCore IP. The VideoCore is actually responsible for initializing the Raspberry Pi device. So, in theory, we could modify the firmware code at runtime.
Finding the 1V Firmware Limit with Ghidra
Since I’ve never done this type of workaround before, I was eager to learn how it works. Here’s the process I followed.
First, I downloaded the firmware with the removed 3 GHz limitation. Then, I pull apart the firmware using the RPI Eeprom Tools Python tools.
git clone https://github.com/info-beamer/rpi-eeprom-tools
pip install pycryptodome
mkdir extract
python .\pi-eeprom-extract .\pieeprom.bin ./extract
Next, we install the Ghidra disassembly tool.
- Download and install Java JDK 21 64-bit
- Download and extract Ghidra 11.1.2
Ghidra will disassemble the binary code and piece together a higher-level, more readable code. For that, we need a “language” file that will help with translation. While Ghidra does not have official support for the Broadcom VideoCore VII, fortunately, there are VideoCore IV architecture support files available. So, we need to pull those into our Ghidra folder.
- Git clone or copy the language files into the .\Ghidra\Processors\VideoCore folder
Now we can open Ghidra by running ghidraRun.bat, create a new project, import the bootmain file, and select the VC4 language. Next, double-click the Bootmain file and let the software analyze the code. Now, we’re ready to search for our firmware-imposed voltage limit. After the analysis is complete, we can search the program for any strings or code. In this case, we search for “set-voltage” and look for a function outside the global namespace. We find the function 3fc4c6f2.
This function appears to govern the voltage configuration. While it’s not very easy to read, we can spot two variables: iVar1 and iVar2. If we follow the functions that define these two variables, we find that iVar1 returns 1000 and iVar2 returns 720.
- iVar1 = FUN_3fc491e8(); >> returns 0x3e8 = 1000
- iVar2 = FUN_3fc493e8(); >> returns 0x2d0 = 720
720 stands for 720mV and represents the minimum voltage for the SoC. 1000 is the 1V upper limit of the voltage.
Adjusting the Voltage Limit at Runtime
The next step is to figure out how to update the voltage limit.
As mentioned, the bootmain is signed. So, we can’t just change the value and put together custom firmware. But we can try changing the value at runtime. For this purpose, we memory map the VideoCore memory which is stored in the system memory. Then, we can update the value stored in the function, flush the VideoCore cache, and hopefully our Raspberry Pi doesn’t go up in flames.
Again, with the help of CoPilot, ChatGPT, and Gemini, I put together a Python script to do this. The script does three things:
- It verifies the voltage limit value (0x3e8) at the target address (0x3fc491e8) to ensure we adjust the right function
- If the value matches, it updates the value to 0x480 which represents 1200 mV
- Lastly, it flushes the VideoCore cache
The final thing is to check if whether the modification actually worked. We can simply load up our Python telemetry script and run the stress test. We observe two key things:
- The measure_volts arm command returns 1200, which matches our expectation
- The PMIC telemetry VDD_CORE_V output reads 1.099 V.
What appears to happen is that we successfully lifted the firmware voltage limitation, thus allowing the DVF algorithm to request higher than 1.0V. However, the PMIC also has a voltage limit. That limit prevents voltage output higher than 1.1V. We’ll discuss this in the next OC Strategy.
Further Overclocking, Extra Cooling, & Bootup Service
The final piece of the puzzle is increasing our overclock. To keep things short: I further increased the arm frequency to 3000 MHz and the V3D frequency to 1200 MHz.
The additional voltage was too much for my small tower heatsink, so I added an additional fan to cool the heatsink. A quick shout out ElmorLabs for providing the UPF and making it easy to use a standard computer fan.
A key issue with the overvoltage approach of this overclocking strategy is that we can only increase the voltage after the system has booted. However, the frequency is set during boot. While we might be able to run 3 GHz with the increased voltage, we can’t boot at 3 GHz.
Again, we turn to Jonatron’s blog for guidance. They explain we can create a service that configures a lower frequency as soon as possible during the boot process. Then, at runtime, we can increase the frequency after unlocking the voltage.
Here’s how you create this service:
Create the service to limit the CPU frequency in /lib/systemd/system/slowcpu.service (Github)
Add a file in /bin/ called slowcpu (Github)
Then enable the system service: sudo systemctl enable slowcpu.service
This will limit the frequency to 2500 MHz as early as possible.
When you’ve worked around the voltage limitation, you can use the following command to set the frequency back to 3000 MHz.
echo 3000000 | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_max_freq
Config Settings & Benchmark Results
Open the Ubuntu terminal
- sudo nano /boot/firmware/config.txt and add the following lines
- Include ocs3.txt
- Write the file using control+o, then exit the file using control+x
- Type sudo nano /boot/firmware/ocs1.txt and add the following lines
- arm_freq=3000
- gpu_freq=1100
- v3d_freq=1200
- over_voltage_delta=25000
- Write the file using control+o, then exit the file using control+x
Then reboot the Pi. When you’re back in the operating system:
- Type sudo python3 vlimit_override.py
- Type echo 3000000 | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_max_freq
We rerun the benchmarks and check the performance increase compared to the default operation.
- Geekbench 6 Single: +18.10%
- Geekbench 6 Single: +13.26%
- AI Benchmark: /
- 7-Zip: +16.98%
- Sysbench 1T: +25.16%
- Sysbench: 4T: +16.95%
- KCBench: +2.49%
- HWBOT Prime 0.8.3: +9.20%
- Openarena: +8.78%
- PassMark CPU: /
- PassMark Memory: +17.81%
In this overclocking strategy, we’ve increased the Arm core frequency by 25%, the VideoCore frequency by 21%, and the V3D frequency by 25%. The performance uplift is noticeable across most benchmarks and peaks at +25.16% for Sysbench 1T. However, we also find our overclocked Pi is not stable for two benchmarks. We’ll talk about that in the next segment.
When running the S-TUI Stability Test, the average Arm clock is 2995 MHz with 1.10 volts. The average SoC temperature is 59.8 degrees Celsius. The average Arm core power consumption is 11.03 watts.
OC Strategy #X: PMIC & Further Discussion
In this segment, we further dig into the voltage limitation and discuss some of the remaining overclocking challenges. As we saw in the previous overclocking strategy: even though we worked around the firmware voltage limitation, the maximum operating voltage is still 1.1V. Let’s have a closer look at the PMIC to see what’s going on.
Renesas DA9091 PMIC
The Renesas DA9091 is a general-purpose power management IC or PMIC suitable for the supply of complete systems in low-cost single-board computing applications. The input voltage is supplied directly from the USB at 5.0 V. It integrates over-voltage, over-temperature, and over-current protections. It also features an i2c-compatible interface.
The PMIC integrates a high-performance multi-phase CPU buck converter, seven single-phase buck converters, a current-limited power switch, two general-purpose LDOs, and a low-voltage LDO.
VBUCK1 Buck1 output voltage (3V7_SYS rail) 3.7 V
VBUCK2 Buck2 output voltage (3V3_SYS rail) 3.3 V
VBUCK3 Buck3 output voltage (1V8_SYS rail) 1.8 V
VBUCK4 Buck4 output voltage (DDR_VDD2 rail) 1.1 V
VBUCK5 Buck5 output voltage (DDR_VDDQ rail) 0.6 V
VBUCK6 Buck6 output voltage (1V1_SYS rail) 1.1 V
VBUCK7 Buck7 output voltage (0V8_SOC rail) 0.8 V
VBUCK8 Buck8 output voltage (VDD_CORE rail) 0.8 V
VLDO1 LDO1 output voltage (3V3_DAC rail) 3.3 V
VLDO2 LDO2 output voltage (3V3_AUD rail) 3.3 V
VLDO3 LDO3 output voltage (0V8_AON rail) 0.8 V
Buck8 provides the voltage output for our SoC. It’s a 4-phase buck converter that supplies up to 15 A continuous and 18 A peak current. The output voltage is programmable between 0.5 V and 1.1 V.
Accessing the DA9091 PMIC I2C interface
The PMIC is software-controlled through registers accessed via the i2c interface. As regular viewers of this channel know very well, for many overclocking projects we rely on the I2C interface to work around voltage limitations using the ElmorLabs EVC2.
The first challenge is to identify the relevant I2C pins: SDA for data and SCL for the clock. This was quite a challenge because those pins are not directly exposed on the PMIC. They are hidden underneath the package! However, sometimes the I2C pins are also exposed on the PCB. So, I called upon Elmor’s expertise to search for the I2C pins.
How did we identify these pins? By trial and error and using two tools: our Python telemetry script and an oscilloscope.
Essentially, while the Raspberry Pi is running, we check each exposed pin for either a clock or data signal. Since the telemetry Python script calls PMIC data, when the script is running the data bus is much busier than when idle. After about 15 minutes of probing around, Elmor identified test points TP40 and TP41 on the back of the Raspberry Pi 5 PCB as the PMIC’s SCL and SDA pins respectively.
Now that we have access to the PMIC’s I2C interface, it’s time to explore the registers.
Relevant DA9091 PMIC Registers
Unfortunately, the DA9091 I2C register information is not public information and the full PMIC datasheet is also confidential. So, I won’t be able to share the full document. However, I can share the relevant PMIC registers for our purpose.
Register | Address | Description |
BUCK1_VOUT | 0x00007026 | 0x00 – 0x8C: 2.8V 0x8D – 0xEF: 2.800 V + 0.010 V * (BUCK1_VOUT -140) 0xF0 – 0xFF: 3.8 V |
BUCK2_VOUT | 0x00007039 | 0x00 – 0x8C: 2.8V 0x8D – 0xEF: 2.800 V + 0.010 V * (BUCK2_VOUT -140) 0xF0 – 0xFF: 3.8 V |
BUCK3_VOUT | 0x0000704C | 0x00: 1.4V 0x01 – 0x3B: 1.400 V + 0.010 V * BUCK3_VOUT 0x3C – 0xFF: 2.0 V |
BUCK4_VOUT | 0x0000705F | 0x00: 0.3 V 0x01 – 0xEF: 0.300 V + 0.005 V * BUCK5_VOUT 0xF0 – 0xFF: 1.5 V |
BUCK5_VOUT | 0x00007072 | 0x00: 0.3 V 0x01 – 0xEF: 0.300 V + 0.005 V * BUCK5_VOUT 0xF0 – 0xFF: 1.5 V |
BUCK6_VOUT | 0x00007085 | 0x00: 0.3 V 0x01 – 0xEF: 0.300 V + 0.005 V * BUCK6_VOUT 0xF0 – 0xFF: 1.5 V |
BUCK7_VOUT | 0x00007098 | 0x00: 0.3 V 0x01 – 0xEF: 0.300 V + 0.005 V * BUCK7_VOUT 0xF0 – 0xFF: 1.5 V |
BUCK8_VOUT | 0x000070AC | 0x00 – 0x27: Reserved 0x28: 0.5 V 0x29 – 0x9F: 0.500 V + 0.005 V * (BUCK8_VOUT -40) 0xA0: 1.1 V 0xA1 – 0xFF: Reserved |
LDO1_VOUT_RANGE | 0x0000B000 | 0x0: 2.38 V to 3.01 V 0x1: 2.98 V to 3.61 V |
LDO1_VOUT_SEL | 0x0000B001 | when VOUT_RANGE = 0 0x00: 2.38 V 0x00 – 0x1F: 2.38 V + 10mV * VOUT_SEL 0x20: 2.70 V 0x21 – 0x3E: 2.38 V + 10mV * VOUT_SEL 0x3F: 3.01 V when VOUT_RANGE = 1 0x00: 2.98 V 0x00 – 0x1F: 2.98 V + 10mV * VOUT_SEL 0x20: 3.30 V 0x21 – 0x3E: 2.98 V + 10mV * VOUT_SEL 0x3F: 3.61 V |
LDO2_VOUT_RANGE | 0x0000B400 | 0x0: 2.38 V to 3.01 V 0x1: 2.98 V to 3.61 V |
LDO2_VOUT_SEL | 0x0000B401 | when VOUT_RANGE = 0 0x00: 2.38 V 0x00 – 0x1F: 2.38 V + 10mV * VOUT_SEL 0x20: 2.70 V 0x21 – 0x3E: 2.38 V + 10mV * VOUT_SEL 0x3F: 3.01 V when VOUT_RANGE = 1 0x00: 2.98 V 0x00 – 0x1F: 2.98 V + 10mV * VOUT_SEL 0x20: 3.30 V 0x21 – 0x3E: 2.98 V + 10mV * VOUT_SEL 0x3F: 3.61 V |
LDO3_SEL_VOUT | 0x0000B800 | 0x00: 0.63 V 0x01 – 0x3E: 0.63 V + SEL_VOUT * 0.01 V 0x3F: 1.26 V |
Communicating with ElmorLabs EVC2
Let’s start communicating with the PMIC using the ElmorLabs EVC2.
First things first: let’s solder wires to TP40 (SCL), TP41 (SDA), and GND. Then connect the wires to an available header on the ElmorLabs EVC2 device. Now, let’s open the EVC2 software.
Here we browse to the header which connects to the Raspberry Pi PMIC. We click on ‘Find Devices’ and read the output message which says “DEV SCAN OK Found 1 addresses: 38.” That means the EVC2 found a device on address 0x38. Coincidentally, that’s the default address referenced in the PMIC datasheet.
Then, in the Read/Write segment, we switch to SMBus mode and use the following parameters to read out the BUCK8_VOUT (0x000070AC) information:
Address: 38
Command: AC70
Length: 2
This command returns 0x54 which translates to 84 in decimal. If we use the formula provided in the register description, we find that the voltage should be: 0.5V + 0.005V * (84-40) = 0.72V, or 720mV. That’s the expected value when the Raspberry Pi sits idle!
We can also try writing a value. However, keep in mind that the SoC still communicates with the PMIC. So, any value we write will be overwritten by the dynamic voltage-frequency algorithm. But, we can try using the over_voltage parameter! So, let’s set over_voltage=8 and run the S-TUI stress test. If we now read the BUCK8_VOUT (0x000070AC) register, it returns 0x8C. That translates into 0.5V + 0.005V * (140-40) = 1.0V, exactly what we expect based on this chip’s V/F curve.
Now, let’s override this value by using the following EVC2 command parameters:
Address: 38
Command: AC70
Length: 2
Data: 9E
Length: 1
9Eh = 158d => 0.5V + 0.005V * (158-40) = 1.09V
We can verify this value was written correctly by immediately clicking Read.
As a sanity check, we can also verify the settings with our telemetry script. We find that:
- The measure_volts arm command returns 1000, which matches our expectation given the firmware voltage limit is 1V
- The PMIC telemetry VDD_CORE_V output reads approximately 1.092 V.
Now that we know our I2C communication works as expected, let’s get on to the next step.In our case, we’re trying to increase the voltage out for BUCK8. We can immediately see a problem: the register is only defined up to 1.1V. Furthermore, we find can also write higher values to the register and read back our configured value. Unfortunately, while the register is programmed to a higher value, if we check the PMIC telemetry using our Python script, we find that the voltage output is still 1.1V.
The likely issue is that there’s another undocumented (and perhaps unprogrammable) register defining the voltage output limit. Without access to that register, we cannot override the 1.1V limitation using the I2C interface.
Stress Testing & Stability
As you likely noticed from the previous overclocking strategy, even though our 3 GHz overclock passes the S-TUI stress test, it fails two benchmarks: AI Benchmark and PassMark. These two benchmarks have in common that they have tests that use NEON instructions.
If we have a closer look at the PassMark benchmark, we find that the benchmark crashes specifically at the NEON sub-test. Furthermore, we find that it crashes also at lower frequencies even though it passes 2.9 GHz without the firmware voltage workaround.
If we track the current, voltage, and power of the VDD_core during the workload, we find that the NEON subtest is significantly more power-intensive than any other benchmark. We can see peak current exceeding 15 amps and the power consumption exceeding 18 watts.
When the benchmark crashes, the Raspberry Pi shuts down, and we can’t even communicate with the PMIC unless we manually press the power button. This suggests the instability is not caused by too high frequency, but perhaps some other mechanism such as over-current or over-temperature protection. Based on the voltage telemetry provided by the Python script, it doesn’t seem like it’s an under-volt issue. However, unfortunately, the PMIC debug options are not available at the moment.
So, for now, I can’t diagnose the root cause of this shutdown behavior.
Raspberry Pi 5: Conclusion
Alright, let us wrap this up.
I had the Raspberry Pi 5 on my overclocking to-do list for quite a while. I overclocked the original Raspberry Pi a long time ago and it was a lot of fun. While this modern Raspberry Pi still supports overclocking, it’s severely more restricted than before.
Not only was the maximum operating arm CPU frequency limited to 3 GHz with the initial firmware, but we also lack memory overclocking capabilities. Furthermore, the SoC operating voltage is limited not only by the firmware but also by the PMIC.
I understand and appreciate the risks associated with enabling overclocking and overvolting, but as a hardware enthusiast, I’d still like to explore the chip or device limitations. Unfortunately, the Raspberry Pi follows the industry trend by artificially limiting its capabilities.
However, that’s not to say I didn’t have a lot of fun with this project. In contrary! I learned a lot throughout this journey, including putting together the telemetry monitoring script, working with Ghidra to explore the firmware, and hooking up the EVC2 to communicate with the PMIC.
I still have some ideas on how to move further with my Raspberry Pi 5 overclocking experiment. But that will be for another video.
Anyway, that’s all for today. I want to thank my Patreon supporters for supporting my work. . If you have any questions or comments, please drop them in the comment section below.
Until the next time!
Jeff Geerling
How did I not find this post in all my testing for my 3.4 GHz overclocks?! This is even more in-depth than I could’ve ever expected, and would’ve probably saved me a dozen hours of testing, to confirm some suspicions based on what I was seeing.
Ah well, now I have a new blog to subscribe to. Nice work on this, and maybe we can convince Raspberry Pi to work with Renesas on a little more OC-friendly PMIC for the next Pi 😀
Pieter
Thanks for the kind words!
A beefier PMIC would certainly be welcome :). The RPI5 PMIC is rated up to 15A continuous and 18A peak current, so at 1.1V that would be 16.5W continuous and 19.8W peak.
In my testing, I found that whenever the power consumption (as measured by multiplying pmic_read_adc VDD_CORE_V and VDD_CORE_A) got close to 20W (regardless of frequency), the PI would just shut down. I suspect it’s due to a PMIC safety kicking in.
Did you also see that kind of behavior?