From 95930746d287e5a6a30ff445b1900ac897383cf5 Mon Sep 17 00:00:00 2001
From: Lightos1 <124387232+Lightos1@users.noreply.github.com>
Date: Sat, 21 Mar 2026 16:44:32 +0100
Subject: [PATCH 1/8] Merge temp and power into sensor
---
.../sysmodule/src/board/board_power.cpp | 46 -------------------
.../sysmodule/src/board/board_power.hpp | 35 --------------
.../{board_temp.cpp => board_sensor.cpp} | 13 ++++++
.../{board_temp.hpp => board_sensor.hpp} | 1 +
4 files changed, 14 insertions(+), 81 deletions(-)
delete mode 100644 Source/rewrite-hoc-clk/sysmodule/src/board/board_power.cpp
delete mode 100644 Source/rewrite-hoc-clk/sysmodule/src/board/board_power.hpp
rename Source/rewrite-hoc-clk/sysmodule/src/board/{board_temp.cpp => board_sensor.cpp} (86%)
rename Source/rewrite-hoc-clk/sysmodule/src/board/{board_temp.hpp => board_sensor.hpp} (96%)
diff --git a/Source/rewrite-hoc-clk/sysmodule/src/board/board_power.cpp b/Source/rewrite-hoc-clk/sysmodule/src/board/board_power.cpp
deleted file mode 100644
index a0701043..00000000
--- a/Source/rewrite-hoc-clk/sysmodule/src/board/board_power.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (c) Souldbminer, Lightos_ and Horizon OC Contributors
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- */
-
-/* --------------------------------------------------------------------------
- * "THE BEER-WARE LICENSE" (Revision 42):
- * , ,
- * wrote this file. As long as you retain this notice you can do whatever you
- * want with this stuff. If you meet any of us some day, and you think this
- * stuff is worth it, you can buy us a beer in return. - The sys-clk authors
- * --------------------------------------------------------------------------
- */
-
-#include
-#include
-#include
-
-namespace board {
-
- u32 GetPowerMw(SysClkPowerSensor sensor) {
- switch (sensor) {
- case SysClkPowerSensor_Now:
- return max17050PowerNow();
- case SysClkPowerSensor_Avg:
- return max17050PowerAvg();
- default:
- ASSERT_ENUM_VALID(SysClkPowerSensor, sensor);
- }
-
- return 0;
- }
-
-}
diff --git a/Source/rewrite-hoc-clk/sysmodule/src/board/board_power.hpp b/Source/rewrite-hoc-clk/sysmodule/src/board/board_power.hpp
deleted file mode 100644
index 2d0f2616..00000000
--- a/Source/rewrite-hoc-clk/sysmodule/src/board/board_power.hpp
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) Souldbminer, Lightos_ and Horizon OC Contributors
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- */
-
-/* --------------------------------------------------------------------------
- * "THE BEER-WARE LICENSE" (Revision 42):
- * , ,
- * wrote this file. As long as you retain this notice you can do whatever you
- * want with this stuff. If you meet any of us some day, and you think this
- * stuff is worth it, you can buy us a beer in return. - The sys-clk authors
- * --------------------------------------------------------------------------
- */
-
-#pragma once
-#include
-#include
-
-namespace board {
-
- u32 GetPowerMw(SysClkPowerSensor sensor)
-
-}
diff --git a/Source/rewrite-hoc-clk/sysmodule/src/board/board_temp.cpp b/Source/rewrite-hoc-clk/sysmodule/src/board/board_sensor.cpp
similarity index 86%
rename from Source/rewrite-hoc-clk/sysmodule/src/board/board_temp.cpp
rename to Source/rewrite-hoc-clk/sysmodule/src/board/board_sensor.cpp
index d102241a..955a1b38 100644
--- a/Source/rewrite-hoc-clk/sysmodule/src/board/board_temp.cpp
+++ b/Source/rewrite-hoc-clk/sysmodule/src/board/board_sensor.cpp
@@ -58,4 +58,17 @@ namespace board {
return std::max(0, millis);
}
+ u32 GetPowerMw(SysClkPowerSensor sensor) {
+ switch (sensor) {
+ case SysClkPowerSensor_Now:
+ return max17050PowerNow();
+ case SysClkPowerSensor_Avg:
+ return max17050PowerAvg();
+ default:
+ ASSERT_ENUM_VALID(SysClkPowerSensor, sensor);
+ }
+
+ return 0;
+ }
+
}
diff --git a/Source/rewrite-hoc-clk/sysmodule/src/board/board_temp.hpp b/Source/rewrite-hoc-clk/sysmodule/src/board/board_sensor.hpp
similarity index 96%
rename from Source/rewrite-hoc-clk/sysmodule/src/board/board_temp.hpp
rename to Source/rewrite-hoc-clk/sysmodule/src/board/board_sensor.hpp
index 71b02d3d..03415b96 100644
--- a/Source/rewrite-hoc-clk/sysmodule/src/board/board_temp.hpp
+++ b/Source/rewrite-hoc-clk/sysmodule/src/board/board_sensor.hpp
@@ -31,5 +31,6 @@
namespace board {
u32 GetTemperatureMilli(SysClkThermalSensor sensor);
+ u32 GetPowerMw(SysClkPowerSensor sensor)
}
From 3896c89a5cb618b83e2d84de457fe23e89aa9c03 Mon Sep 17 00:00:00 2001
From: Lightos1 <124387232+Lightos1@users.noreply.github.com>
Date: Sat, 21 Mar 2026 16:54:07 +0100
Subject: [PATCH 2/8] Revert "Fix typo"
This reverts commit 9afd3d44bda75515a97f4320ce400db92142bf4f, reversing
changes made to 95930746d287e5a6a30ff445b1900ac897383cf5.
---
Source/sys-clk/sysmodule/src/clock_manager.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Source/sys-clk/sysmodule/src/clock_manager.cpp b/Source/sys-clk/sysmodule/src/clock_manager.cpp
index db8f8062..d8180d10 100644
--- a/Source/sys-clk/sysmodule/src/clock_manager.cpp
+++ b/Source/sys-clk/sysmodule/src/clock_manager.cpp
@@ -566,7 +566,7 @@ void ClockManager::VRRThread(void* arg) {
if(++tick > 50) {
Board::SetHz(HorizonOCModule_Display, maxDisplay);
tick = 0;
- svcSleepThread(25'000'000);
+ svcSleepThread(50'000'000);
}
svcSleepThread(POLL_NS);
From f46d0a714b06bdb451cf735f073118288eda26cb Mon Sep 17 00:00:00 2001
From: Lightos1 <124387232+Lightos1@users.noreply.github.com>
Date: Sat, 21 Mar 2026 16:56:10 +0100
Subject: [PATCH 3/8] actually fix the typo
---
Source/rewrite-hoc-clk/sysmodule/src/board/board_sensor.hpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Source/rewrite-hoc-clk/sysmodule/src/board/board_sensor.hpp b/Source/rewrite-hoc-clk/sysmodule/src/board/board_sensor.hpp
index 03415b96..ec95e1ac 100644
--- a/Source/rewrite-hoc-clk/sysmodule/src/board/board_sensor.hpp
+++ b/Source/rewrite-hoc-clk/sysmodule/src/board/board_sensor.hpp
@@ -31,6 +31,6 @@
namespace board {
u32 GetTemperatureMilli(SysClkThermalSensor sensor);
- u32 GetPowerMw(SysClkPowerSensor sensor)
+ u32 GetPowerMw(SysClkPowerSensor sensor);
}
From 3d5147a6e227398812065fffc1338c0fd638e7c1 Mon Sep 17 00:00:00 2001
From: Lightos1 <124387232+Lightos1@users.noreply.github.com>
Date: Sat, 21 Mar 2026 17:01:50 +0100
Subject: [PATCH 4/8] merge pcv hijacking into voltage code
---
.../sysmodule/src/board/board_ram_oc_dvfs.cpp | 202 ------------------
.../sysmodule/src/board/board_ram_oc_dvfs.hpp | 49 -----
.../sysmodule/src/board/board_volt.cpp | 171 +++++++++++++++
.../sysmodule/src/board/board_volt.hpp | 16 ++
4 files changed, 187 insertions(+), 251 deletions(-)
delete mode 100644 Source/rewrite-hoc-clk/sysmodule/src/board/board_ram_oc_dvfs.cpp
delete mode 100644 Source/rewrite-hoc-clk/sysmodule/src/board/board_ram_oc_dvfs.hpp
diff --git a/Source/rewrite-hoc-clk/sysmodule/src/board/board_ram_oc_dvfs.cpp b/Source/rewrite-hoc-clk/sysmodule/src/board/board_ram_oc_dvfs.cpp
deleted file mode 100644
index cda16f4b..00000000
--- a/Source/rewrite-hoc-clk/sysmodule/src/board/board_ram_oc_dvfs.cpp
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright (c) Souldbminer, Lightos_ and Horizon OC Contributors
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- */
-
-/* --------------------------------------------------------------------------
- * "THE BEER-WARE LICENSE" (Revision 42):
- * , ,
- * wrote this file. As long as you retain this notice you can do whatever you
- * want with this stuff. If you meet any of us some day, and you think this
- * stuff is worth it, you can buy us a beer in return. - The sys-clk authors
- * --------------------------------------------------------------------------
- */
-
-#include
-#include
-#include "../file_utils.h"
-#include
-#include "board_ram_oc_dvfs.hpp"
-
-namespace board {
-
- GpuVoltData voltData = {};
-
- Handle GetPcvHandle() {
- constexpr u64 PcvID = 0x10000000000001a;
- u64 processIDList[80]{};
- s32 processCount = 0;
- Handle handle = INVALID_HANDLE;
-
- DebugEventInfo debugEvent{};
-
- /* Get all running processes. */
- Result resultGetProcessList = svcGetProcessList(&processCount, processIDList, std::size(processIDList));
- if (R_FAILED(resultGetProcessList)) {
- return INVALID_HANDLE;
- }
-
- /* Try to find pcv. */
- for (int i = 0; i < processCount; ++i) {
- if (handle != INVALID_HANDLE) {
- svcCloseHandle(handle);
- handle = INVALID_HANDLE;
- }
-
- /* Try to debug process, if it fails, try next process. */
- Result resultSvcDebugProcess = svcDebugActiveProcess(&handle, processIDList[i]);
- if (R_FAILED(resultSvcDebugProcess)) {
- continue;
- }
-
- /* Try to get a debug event. */
- Result resultDebugEvent = svcGetDebugEvent(&debugEvent, handle);
- if (R_SUCCEEDED(resultDebugEvent)) {
- if (debugEvent.info.create_process.program_id == PcvID) {
- return handle;
- }
- }
- }
-
- /* Failed to get handle. */
- return INVALID_HANDLE;
- }
-
- void CacheGpuVoltTable() {
- UnkRegulator reg = {
- .voltageMinUV = 600000,
- .voltageStep = 12500,
- .voltageMax = 1400000,
- };
-
- Handle handle = GetPcvHandle();
- if (handle == INVALID_HANDLE) {
- FileUtils::LogLine("[dvfs] Invalid handle!");
- return;
- }
-
- MemoryInfo memoryInfo = {};
- u64 address = 0;
- u32 pageInfo = 0;
- constexpr u32 PageSize = 0x1000;
- u8 buffer[PageSize];
-
- /* Loop until failure. */
- while (true) {
- /* Find pcv heap. */
- while (true) {
- Result resultProcessMemory = svcQueryDebugProcessMemory(&memoryInfo, &pageInfo, handle, address);
- address = memoryInfo.addr + memoryInfo.size;
-
- if (R_FAILED(resultProcessMemory) || !address) {
- svcCloseHandle(handle);
- FileUtils::LogLine("[dvfs] Failed to get process data. %u", R_DESCRIPTION(resultProcessMemory));
- handle = INVALID_HANDLE;
- return;
- }
-
- if (memoryInfo.size && (memoryInfo.perm & 3) == 3 && static_cast(memoryInfo.type) == 0x4) {
- /* Found valid memory. */
- break;
- }
- }
-
- for (u64 base = 0; base < memoryInfo.size; base += PageSize) {
- u32 memorySize = std::min(memoryInfo.size, static_cast(PageSize));
- if (R_FAILED(svcReadDebugProcessMemory(buffer, handle, base + memoryInfo.addr, memorySize))) {
- break;
- }
-
- u8 *resultFindReg = static_cast(memmem_impl(buffer, sizeof(buffer), ®, sizeof(reg)));
- u32 index = resultFindReg - buffer;
-
- if (!resultFindReg) {
- continue;
- }
-
- /* Assuming mariko. */
- const u32 vmax = 800;
- constexpr u32 VoltageTableOffset = 312;
- if (!std::memcmp(&buffer[index + VoltageTableOffset], &vmax, sizeof(vmax))) {
- std::memcpy(voltData.voltTable, &buffer[index + VoltageTableOffset], sizeof(voltData.voltTable));
- voltData.voltTableAddress = base + memoryInfo.addr + VoltageTableOffset + index;
- }
-
- svcCloseHandle(handle);
- handle = INVALID_HANDLE;
- return;
- }
- }
-
- svcCloseHandle(handle);
- handle = INVALID_HANDLE;
- return;
- }
-
- void PcvHijackGpuVolts(u32 vmin) {
- u32 table[192];
- static_assert(sizeof(table) == sizeof(voltData.voltTable));
- std::memcpy(table, voltData.voltTable, sizeof(voltData.voltTable));
-
- if (voltData.ramVmin == vmin) {
- return;
- }
-
- for (u32 i = 0; i < std::size(table); ++i) {
- if (table[i] && table[i] <= vmin) {
- table[i] = vmin;
- }
- }
-
- Handle handle = GetPcvHandle();
- if (handle == INVALID_HANDLE) {
- FileUtils::LogLine("Invalid handle!");
- return;
- }
-
- Result rc = svcWriteDebugProcessMemory(handle, table, voltData.dvfsAddress, sizeof(table));
-
- if (R_SUCCEEDED(rc)) {
- voltData.ramVmin = vmin;
- }
-
- svcCloseHandle(handle);
- FileUtils::LogLine("[dvfs] voltage set to %u mV", vmin);
- }
-
- u32 GetMinimumVmin(u32 freqMhz, u32 bracket) {
- static const u32 ramTable[][22] = {
- { 2133, 2200, 2266, 2300, 2366, 2400, 2433, 2466, 2533, 2566, 2600, 2633, 2700, 2733, 2766, 2833, 2866, 2900, 2933, 3033, 3066, 3100, },
- { 2300, 2366, 2433, 2466, 2533, 2566, 2633, 2700, 2733, 2800, 2833, 2900, 2933, 2966, 3033, 3066, 3100, 3133, 3166, 3200, 3233, 3266, },
- { 2433, 2466, 2533, 2600, 2666, 2733, 2766, 2800, 2833, 2866, 2933, 2966, 3033, 3066, 3100, 3133, 3166, 3200, 3233, 3300, 3333, 3366, },
- { 2500, 2533, 2600, 2633, 2666, 2733, 2800, 2866, 2900, 2966, 3033, 3100, 3166, 3200, 3233, 3266, 3300, 3333, 3366, 3400, 3400, 3400, },
- };
-
- static const u32 gpuVoltArray[] = { 590, 600, 610, 620, 630, 640, 650, 660, 670, 680, 690, 700, 710, 720, 730, 740, 750, 760, 770, 780, 790, 800, };
-
- if (freqMhz <= 1600) {
- return 0;
- }
-
- for (u32 i = 0; std::size(gpuDvfsArray) < 22; ++i) {
- if (freqMhz <= ramTable[bracket][i]) {
- return gpuVoltArray[i];
- }
- }
-
- return gpuVoltArray[std::size(gpuVoltArray) - 1];
- }
-
-}
diff --git a/Source/rewrite-hoc-clk/sysmodule/src/board/board_ram_oc_dvfs.hpp b/Source/rewrite-hoc-clk/sysmodule/src/board/board_ram_oc_dvfs.hpp
deleted file mode 100644
index d61a4b5b..00000000
--- a/Source/rewrite-hoc-clk/sysmodule/src/board/board_ram_oc_dvfs.hpp
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) Souldbminer, Lightos_ and Horizon OC Contributors
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- */
-
-/* --------------------------------------------------------------------------
- * "THE BEER-WARE LICENSE" (Revision 42):
- * , ,
- * wrote this file. As long as you retain this notice you can do whatever you
- * want with this stuff. If you meet any of us some day, and you think this
- * stuff is worth it, you can buy us a beer in return. - The sys-clk authors
- * --------------------------------------------------------------------------
- */
-
-#pragma once
-#include
-
-namespace board {
-
- struct GpuVoltData {
- u32 voltTable[6][32] = {};
- u64 voltTableAddress;
- u32 ramVmin;
- };
-
- /* TODO: Find out what component this actually targets. */
- struct UnkRegulator {
- u32 voltageMinUV;
- u32 voltageStep;
- u32 voltageMax;
- }
-
- void CacheGpuVoltTable();
- void PcvHijackGpuVolts(u32 vmin);
- u32 GetMinimumVmin(u32 freqMhz, u32 bracket);
-
-}
diff --git a/Source/rewrite-hoc-clk/sysmodule/src/board/board_volt.cpp b/Source/rewrite-hoc-clk/sysmodule/src/board/board_volt.cpp
index 8be8b891..8ddeae99 100644
--- a/Source/rewrite-hoc-clk/sysmodule/src/board/board_volt.cpp
+++ b/Source/rewrite-hoc-clk/sysmodule/src/board/board_volt.cpp
@@ -26,10 +26,16 @@
#include
#include
+#include
+#include
#include "board.hpp"
+#include "board_volt.hpp"
+#include "../file_utils.h"
namespace board {
+ GpuVoltData voltData = {};
+
/*
* Switch Power domains (max77620):
* Name | Usage | uV step | uV min | uV default | uV max | Init
@@ -135,4 +141,169 @@ namespace board {
return out > 0 ? out : 0;
}
+ Handle GetPcvHandle() {
+ constexpr u64 PcvID = 0x10000000000001a;
+ u64 processIDList[80]{};
+ s32 processCount = 0;
+ Handle handle = INVALID_HANDLE;
+
+ DebugEventInfo debugEvent{};
+
+ /* Get all running processes. */
+ Result resultGetProcessList = svcGetProcessList(&processCount, processIDList, std::size(processIDList));
+ if (R_FAILED(resultGetProcessList)) {
+ return INVALID_HANDLE;
+ }
+
+ /* Try to find pcv. */
+ for (int i = 0; i < processCount; ++i) {
+ if (handle != INVALID_HANDLE) {
+ svcCloseHandle(handle);
+ handle = INVALID_HANDLE;
+ }
+
+ /* Try to debug process, if it fails, try next process. */
+ Result resultSvcDebugProcess = svcDebugActiveProcess(&handle, processIDList[i]);
+ if (R_FAILED(resultSvcDebugProcess)) {
+ continue;
+ }
+
+ /* Try to get a debug event. */
+ Result resultDebugEvent = svcGetDebugEvent(&debugEvent, handle);
+ if (R_SUCCEEDED(resultDebugEvent)) {
+ if (debugEvent.info.create_process.program_id == PcvID) {
+ return handle;
+ }
+ }
+ }
+
+ /* Failed to get handle. */
+ return INVALID_HANDLE;
+ }
+
+ void CacheGpuVoltTable() {
+ UnkRegulator reg = {
+ .voltageMinUV = 600000,
+ .voltageStep = 12500,
+ .voltageMax = 1400000,
+ };
+
+ Handle handle = GetPcvHandle();
+ if (handle == INVALID_HANDLE) {
+ FileUtils::LogLine("[dvfs] Invalid handle!");
+ return;
+ }
+
+ MemoryInfo memoryInfo = {};
+ u64 address = 0;
+ u32 pageInfo = 0;
+ constexpr u32 PageSize = 0x1000;
+ u8 buffer[PageSize];
+
+ /* Loop until failure. */
+ while (true) {
+ /* Find pcv heap. */
+ while (true) {
+ Result resultProcessMemory = svcQueryDebugProcessMemory(&memoryInfo, &pageInfo, handle, address);
+ address = memoryInfo.addr + memoryInfo.size;
+
+ if (R_FAILED(resultProcessMemory) || !address) {
+ svcCloseHandle(handle);
+ FileUtils::LogLine("[dvfs] Failed to get process data. %u", R_DESCRIPTION(resultProcessMemory));
+ handle = INVALID_HANDLE;
+ return;
+ }
+
+ if (memoryInfo.size && (memoryInfo.perm & 3) == 3 && static_cast(memoryInfo.type) == 0x4) {
+ /* Found valid memory. */
+ break;
+ }
+ }
+
+ for (u64 base = 0; base < memoryInfo.size; base += PageSize) {
+ u32 memorySize = std::min(memoryInfo.size, static_cast(PageSize));
+ if (R_FAILED(svcReadDebugProcessMemory(buffer, handle, base + memoryInfo.addr, memorySize))) {
+ break;
+ }
+
+ u8 *resultFindReg = static_cast(memmem_impl(buffer, sizeof(buffer), ®, sizeof(reg)));
+ u32 index = resultFindReg - buffer;
+
+ if (!resultFindReg) {
+ continue;
+ }
+
+ /* Assuming mariko. */
+ const u32 vmax = 800;
+ constexpr u32 VoltageTableOffset = 312;
+ if (!std::memcmp(&buffer[index + VoltageTableOffset], &vmax, sizeof(vmax))) {
+ std::memcpy(voltData.voltTable, &buffer[index + VoltageTableOffset], sizeof(voltData.voltTable));
+ voltData.voltTableAddress = base + memoryInfo.addr + VoltageTableOffset + index;
+ }
+
+ svcCloseHandle(handle);
+ handle = INVALID_HANDLE;
+ return;
+ }
+ }
+
+ svcCloseHandle(handle);
+ handle = INVALID_HANDLE;
+ return;
+ }
+
+ void PcvHijackGpuVolts(u32 vmin) {
+ u32 table[192];
+ static_assert(sizeof(table) == sizeof(voltData.voltTable));
+ std::memcpy(table, voltData.voltTable, sizeof(voltData.voltTable));
+
+ if (voltData.ramVmin == vmin) {
+ return;
+ }
+
+ for (u32 i = 0; i < std::size(table); ++i) {
+ if (table[i] && table[i] <= vmin) {
+ table[i] = vmin;
+ }
+ }
+
+ Handle handle = GetPcvHandle();
+ if (handle == INVALID_HANDLE) {
+ FileUtils::LogLine("Invalid handle!");
+ return;
+ }
+
+ Result rc = svcWriteDebugProcessMemory(handle, table, voltData.dvfsAddress, sizeof(table));
+
+ if (R_SUCCEEDED(rc)) {
+ voltData.ramVmin = vmin;
+ }
+
+ svcCloseHandle(handle);
+ FileUtils::LogLine("[dvfs] voltage set to %u mV", vmin);
+ }
+
+ u32 GetMinimumGpuVmin(u32 freqMhz, u32 bracket) {
+ static const u32 ramTable[][22] = {
+ { 2133, 2200, 2266, 2300, 2366, 2400, 2433, 2466, 2533, 2566, 2600, 2633, 2700, 2733, 2766, 2833, 2866, 2900, 2933, 3033, 3066, 3100, },
+ { 2300, 2366, 2433, 2466, 2533, 2566, 2633, 2700, 2733, 2800, 2833, 2900, 2933, 2966, 3033, 3066, 3100, 3133, 3166, 3200, 3233, 3266, },
+ { 2433, 2466, 2533, 2600, 2666, 2733, 2766, 2800, 2833, 2866, 2933, 2966, 3033, 3066, 3100, 3133, 3166, 3200, 3233, 3300, 3333, 3366, },
+ { 2500, 2533, 2600, 2633, 2666, 2733, 2800, 2866, 2900, 2966, 3033, 3100, 3166, 3200, 3233, 3266, 3300, 3333, 3366, 3400, 3400, 3400, },
+ };
+
+ static const u32 gpuVoltArray[] = { 590, 600, 610, 620, 630, 640, 650, 660, 670, 680, 690, 700, 710, 720, 730, 740, 750, 760, 770, 780, 790, 800, };
+
+ if (freqMhz <= 1600) {
+ return 0;
+ }
+
+ for (u32 i = 0; i < std::size(gpuDvfsArray); ++i) {
+ if (freqMhz <= ramTable[bracket][i]) {
+ return gpuVoltArray[i];
+ }
+ }
+
+ return gpuVoltArray[std::size(gpuVoltArray) - 1];
+ }
+
}
diff --git a/Source/rewrite-hoc-clk/sysmodule/src/board/board_volt.hpp b/Source/rewrite-hoc-clk/sysmodule/src/board/board_volt.hpp
index 64e9872b..09c2da50 100644
--- a/Source/rewrite-hoc-clk/sysmodule/src/board/board_volt.hpp
+++ b/Source/rewrite-hoc-clk/sysmodule/src/board/board_volt.hpp
@@ -30,6 +30,22 @@
namespace board {
+ struct GpuVoltData {
+ u32 voltTable[6][32] = {};
+ u64 voltTableAddress;
+ u32 ramVmin;
+ };
+
+ /* TODO: Find out what component this actually targets. */
+ struct UnkRegulator {
+ u32 voltageMinUV;
+ u32 voltageStep;
+ u32 voltageMax;
+ };
+
u32 GetVoltage(HocClkVoltage voltage);
+ void CacheGpuVoltTable();
+ void PcvHijackGpuVolts(u32 vmin);
+ u32 GetMinimumGpuVmin(u32 freqMhz, u32 bracket);
}
From a697cac43c2a2109bf3390db4b0f3fa0450ab6a5 Mon Sep 17 00:00:00 2001
From: Lightos1 <124387232+Lightos1@users.noreply.github.com>
Date: Sat, 21 Mar 2026 17:03:46 +0100
Subject: [PATCH 5/8] Add message to assertion
---
Source/rewrite-hoc-clk/sysmodule/src/board/board_volt.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Source/rewrite-hoc-clk/sysmodule/src/board/board_volt.cpp b/Source/rewrite-hoc-clk/sysmodule/src/board/board_volt.cpp
index 8ddeae99..5533594e 100644
--- a/Source/rewrite-hoc-clk/sysmodule/src/board/board_volt.cpp
+++ b/Source/rewrite-hoc-clk/sysmodule/src/board/board_volt.cpp
@@ -254,7 +254,7 @@ namespace board {
void PcvHijackGpuVolts(u32 vmin) {
u32 table[192];
- static_assert(sizeof(table) == sizeof(voltData.voltTable));
+ static_assert(sizeof(table) == sizeof(voltData.voltTable), "Invalid gpu voltage table size!");
std::memcpy(table, voltData.voltTable, sizeof(voltData.voltTable));
if (voltData.ramVmin == vmin) {
From 3b907d3ca0a7a9ea6dcfc053881864aca05c752a Mon Sep 17 00:00:00 2001
From: Lightos1 <124387232+Lightos1@users.noreply.github.com>
Date: Sat, 21 Mar 2026 17:37:52 +0100
Subject: [PATCH 6/8] Add live tuning adjustment to rewrite
---
.../sysmodule/src/board/board.cpp | 16 +---
.../sysmodule/src/board/board_volt.cpp | 91 +++++++++++++++++++
.../sysmodule/src/board/board_volt.hpp | 12 +++
3 files changed, 106 insertions(+), 13 deletions(-)
diff --git a/Source/rewrite-hoc-clk/sysmodule/src/board/board.cpp b/Source/rewrite-hoc-clk/sysmodule/src/board/board.cpp
index 4cafe2d3..906a6bb8 100644
--- a/Source/rewrite-hoc-clk/sysmodule/src/board/board.cpp
+++ b/Source/rewrite-hoc-clk/sysmodule/src/board/board.cpp
@@ -33,7 +33,7 @@
#include "board.hpp"
#include "board_fuse.hpp"
#include "board_load.hpp"
-#include "board_ram_oc_dvfs.hpp"
+#include "board_volt.hpp"
#include "board_misc.hpp"
namespace board {
@@ -114,7 +114,7 @@ namespace board {
ASSERT_RESULT_OK(rc, "pmdmntInitialize");
StartGpuLoad(nvCheck, fd);
- /* TODO: Add back fan. */
+
StartMiscThread(pwmCheck)
batteryInfoInitialize();
@@ -140,17 +140,7 @@ namespace board {
DisplayRefresh_Initialize(&cfg);
}
- // rc = svcQueryMemoryMapping(&cldvfs, &cldvfs_temp, CLDVFS_REGION_BASE, CLDVFS_REGION_SIZE);
- // ASSERT_RESULT_OK(rc, "svcQueryMemoryMapping (cldvfs)");
-
- // if (socType == SysClkSocType_Erista) {
- // cachedEristaUvLowTune0 = *(u32*) (cldvfs + CL_DVFS_TUNE0_0);
- // cachedEristaUvLowTune1 = *(u32*) (cldvfs + CL_DVFS_TUNE1_0);
- // } else {
- // SetHz(SysClkModule_CPU, 1785000000);
- // cachedMarikoUvHighTune0 = *(u32*) (cldvfs + CL_DVFS_TUNE0_0);
- // ResetToStockCpu();
- // }
+ CacheDfllData();
}
void Exit() {
diff --git a/Source/rewrite-hoc-clk/sysmodule/src/board/board_volt.cpp b/Source/rewrite-hoc-clk/sysmodule/src/board/board_volt.cpp
index 5533594e..4a97c6df 100644
--- a/Source/rewrite-hoc-clk/sysmodule/src/board/board_volt.cpp
+++ b/Source/rewrite-hoc-clk/sysmodule/src/board/board_volt.cpp
@@ -27,14 +27,105 @@
#include
#include
#include
+#include
#include
#include "board.hpp"
+#include "board_freq.hpp"
#include "board_volt.hpp"
#include "../file_utils.h"
namespace board {
GpuVoltData voltData = {};
+ u64 cldvfs;
+ CpuDfllData cachedTune;
+
+ void CacheDfllData() {
+ u64 temp;
+ rc = svcQueryMemoryMapping(&cldvfs, &temp, CLDVFS_REGION_BASE, CLDVFS_REGION_SIZE);
+ ASSERT_RESULT_OK(rc, "svcQueryMemoryMapping (cldvfs)");
+
+ if (GetSocType() == SysClkSocType_Erista) {
+ cachedTune.tune0Low = *static_cast(cldvfs + CL_DVFS_TUNE0_0);
+ cachedTune.tune1Low = *static_cast(cldvfs + CL_DVFS_TUNE1_0);
+ } else {
+ SetHz(SysClkModule_CPU, 1785000000);
+ cachedTune.tune0High = *static_cast(cldvfs + CL_DVFS_TUNE0_0);
+ ResetToStockCpu();
+ }
+ }
+
+ /* TODO: clean up this code. */
+ void SetDfllTunings(u32 levelLow, u32 levelHigh, u32 tbreakPoint) {
+ u32* tune0_ptr = static_cast(cldvfs + CL_DVFS_TUNE0_0);
+ u32* tune1_ptr = static_cast(cldvfs + CL_DVFS_TUNE1_0);
+ if (GetSocType() == SysClkSocType_Mariko) {
+ if (GetHz(SysClkModule_CPU) < tbreakPoint && (levelLow || levelHigh)) {
+ if (levelLow) {
+ *tune0_ptr = marikoCpuUvLow[levelLow-1].tune0_low;
+ *tune1_ptr = marikoCpuUvLow[levelLow-1].tune1_low;
+ }
+ return;
+ } else {
+ if (levelLow) {
+ *tune0_ptr = marikoCpuUvLow[levelLow-1].tune0_low;
+ *tune1_ptr = marikoCpuUvLow[levelLow-1].tune1_low;
+ }
+ if (levelHigh) {
+ *tune0_ptr = marikoCpuUvHigh[levelHigh-1].tune0_high;
+ *tune1_ptr = marikoCpuUvHigh[levelHigh-1].tune1_high;
+ }
+ return;
+ }
+ if (GetHz(SysClkModule_CPU) < tbreakPoint || (!levelLow)) { // account for tbreak
+ *tune0_ptr = 0xCFFF;
+ *tune1_ptr = 0xFF072201;
+ return;
+ } else if (GetHz(SysClkModule_CPU) >= tbreakPoint || (!levelHigh)) {
+ *tune0_ptr = cachedTune.tune0High; // per console?
+ *tune1_ptr = 0xFFF7FF3F;
+ return;
+ }
+ } else {
+ if (GetHz(SysClkModule_CPU) < tbreakPoint || (!levelLow)) { // account for tbreak
+ *tune0_ptr = cachedTune.tune0Low; // I think each erista has a different tune0/tune1?
+ *tune1_ptr = cachedTune.tune1Low;
+ return;
+ } else {
+ if (levelLow) {
+ *tune0_ptr = eristaCpuUvTable[levelLow-1].tune0;
+ *tune1_ptr = eristaCpuUvTable[levelLow-1].tune1;
+ } else {
+ *tune0_ptr = 0x0;
+ *tune1_ptr = 0x0;
+ }
+ }
+ }
+ }
+
+ /*
+ enum TableConfig: u32 {
+ DEFAULT_TABLE = 1,
+ TBREAK_1581 = 2,
+ TBREAK_1683 = 3,
+ EXTREME_TABLE = 4,
+ };
+ */
+ u32 CalculateTbreak(u32 table) {
+ if (GetSocType() == SysClkSocType_Erista) {
+ return 1581000000;
+ } else {
+ switch (table) {
+ case 1 ... 2:
+ case 4:
+ return 1581000000;
+ case 3:
+ return 1683000000;
+ default:
+ return 1581000000;
+ }
+ }
+ }
/*
* Switch Power domains (max77620):
diff --git a/Source/rewrite-hoc-clk/sysmodule/src/board/board_volt.hpp b/Source/rewrite-hoc-clk/sysmodule/src/board/board_volt.hpp
index 09c2da50..9bed0117 100644
--- a/Source/rewrite-hoc-clk/sysmodule/src/board/board_volt.hpp
+++ b/Source/rewrite-hoc-clk/sysmodule/src/board/board_volt.hpp
@@ -43,6 +43,18 @@ namespace board {
u32 voltageMax;
};
+ struct CpuDfllData {
+ u32 tune0Low;
+ u32 tune0High;
+ u32 tune1Low;
+ u32 tune1High;
+ // u32 tune_high_min_millivolts;
+ // u32 tune_high_margin_millivolts;
+ // u64 dvco_calibration_max;
+ };
+
+ void CacheDfllData();
+ u32 CalculateTbreak();
u32 GetVoltage(HocClkVoltage voltage);
void CacheGpuVoltTable();
void PcvHijackGpuVolts(u32 vmin);
From 5d7a77074b19b015130b1d777d730bb81a8a1e82 Mon Sep 17 00:00:00 2001
From: Lightos1 <124387232+Lightos1@users.noreply.github.com>
Date: Sat, 21 Mar 2026 17:44:01 +0100
Subject: [PATCH 7/8] actually add uv tuning values... clean this code up
---
.../sysmodule/src/board/board_volt.cpp | 53 +++++++++++++++++++
1 file changed, 53 insertions(+)
diff --git a/Source/rewrite-hoc-clk/sysmodule/src/board/board_volt.cpp b/Source/rewrite-hoc-clk/sysmodule/src/board/board_volt.cpp
index 4a97c6df..d1c8b886 100644
--- a/Source/rewrite-hoc-clk/sysmodule/src/board/board_volt.cpp
+++ b/Source/rewrite-hoc-clk/sysmodule/src/board/board_volt.cpp
@@ -40,6 +40,59 @@ namespace board {
u64 cldvfs;
CpuDfllData cachedTune;
+ /* ... This really needs some cleanup... */
+ namespace {
+ struct EristaCpuUvEntry {
+ u32 tune0;
+ u32 tune1;
+ } EristaCpuUvEntry;
+
+ struct MarikoCpuUvEntry {
+ u32 tune0_low;
+ u32 tune0_high;
+ u32 tune1_low;
+ u32 tune1_high;
+ } MarikoCpuUvEntry;
+
+ EristaCpuUvEntry eristaCpuUvTable[5] = {
+ {0xffff, 0x27007ff},
+ {0xefff, 0x27407ff},
+ {0xdfff, 0x27807ff},
+ {0xdfdf, 0x27a07ff},
+ {0xcfdf, 0x37007ff},
+ };
+
+ MarikoCpuUvEntry marikoCpuUvLow[12] = {
+ {0xffa0, 0xffff, 0x21107ff, 0},
+ {0x0, 0xffdf, 0x21107ff, 0x27207ff},
+ {0xffdf, 0xffdf, 0x21107ff, 0x27307ff},
+ {0xffff, 0xffdf, 0x21107ff, 0x27407ff},
+ {0x0, 0xffdf, 0x21607ff, 0x27707ff},
+ {0x0, 0xffdf, 0x21607ff, 0x27807ff},
+ {0x0, 0xdfff, 0x21607ff, 0x27b07ff},
+ {0xdfff, 0xdfff, 0x21707ff, 0x27b07ff},
+ {0xdfff, 0xdfff, 0x21707ff, 0x27c07ff},
+ {0xdfff, 0xdfff, 0x21707ff, 0x27d07ff},
+ {0xdfff, 0xdfff, 0x21707ff, 0x27e07ff},
+ {0xdfff, 0xdfff, 0x21707ff, 0x27f07ff},
+ };
+
+ MarikoCpuUvEntry marikoCpuUvHigh[12] = {
+ {0x0, 0xffff, 0, 0},
+ {0x0, 0xffdf, 0, 0x27207ff},
+ {0x0, 0xffdf, 0, 0x27307ff},
+ {0x0, 0xffdf, 0, 0x27407ff},
+ {0x0, 0xffdf, 0, 0x27707ff},
+ {0x0, 0xffdf, 0, 0x27807ff},
+ {0x0, 0xdfff, 0, 0x27b07ff},
+ {0x0, 0xdfff, 0, 0x27c07ff},
+ {0x0, 0xdfff, 0, 0x27d07ff},
+ {0x0, 0xdfff, 0, 0x27e07ff},
+ {0x0, 0xdfff, 0, 0x27f07ff},
+ {0x0, 0xdfff, 0, 0x27f07ff},
+ };
+ }
+
void CacheDfllData() {
u64 temp;
rc = svcQueryMemoryMapping(&cldvfs, &temp, CLDVFS_REGION_BASE, CLDVFS_REGION_SIZE);
From e625e4251a9a87f39034fc4948544ebcfcf5f586 Mon Sep 17 00:00:00 2001
From: Lightos1 <124387232+Lightos1@users.noreply.github.com>
Date: Sat, 21 Mar 2026 18:02:05 +0100
Subject: [PATCH 8/8] add sched off code to rewrite
---
.../sysmodule/src/board/board_load.cpp | 44 +++++++++++++++++++
.../sysmodule/src/board/board_load.hpp | 1 +
2 files changed, 45 insertions(+)
diff --git a/Source/rewrite-hoc-clk/sysmodule/src/board/board_load.cpp b/Source/rewrite-hoc-clk/sysmodule/src/board/board_load.cpp
index 73e7cc5f..1c495c04 100644
--- a/Source/rewrite-hoc-clk/sysmodule/src/board/board_load.cpp
+++ b/Source/rewrite-hoc-clk/sysmodule/src/board/board_load.cpp
@@ -31,6 +31,7 @@
#include
#include
#include "board_misc.hpp"
+#include
namespace board {
@@ -130,4 +131,47 @@ namespace board {
threadClose(&cpuCore2Thread);
}
+ namespace {
+ constexpr u32 NVschedCtrlEnable = 0x00000601;
+ constexpr u32 NVschedCtrlDisable = 0x00000602;
+ }
+
+ void SetGpuSchedulingMode(GpuSchedulingMode mode, GpuSchedulingOverrideMethod method, Result nvCheckSched, u32 fd2) {
+ if (R_FAILED(nvCheckSched) && method == GpuSchedulingOverrideMethod_NvService) {
+ return;
+ }
+
+ u32 temp;
+ bool enabled = false;
+ switch (mode) {
+ case GpuSchedulingMode_DoNotOverride: break;
+ case GpuSchedulingMode_Disabled:
+ if (method == GpuSchedulingOverrideMethod_NvService) {
+ nvIoctl(fd2, NVschedCtrlDisable, &temp);
+ } else {
+ enabled = false;
+ }
+ break;
+ case GpuSchedulingMode_Enabled:
+ if (method == GpuSchedulingOverrideMethod_NvService) {
+ nvIoctl(fd2, NVschedCtrlEnable, &temp);
+ } else {
+ enabled = true;
+ }
+ break;
+ default:
+ ASSERT_ENUM_VALID(GpuSchedulingMode, mode);
+ }
+
+ if (method == GpuSchedulingOverrideMethod_Ini) {
+ constexpr const char *IniPath = "sdmc:/atmosphere/config/system_settings.ini";
+ constexpr const char *Section = "am.gpu";
+ constexpr const char *Key = "gpu_scheduling_enabled";
+
+ const char *value = enabled ? "u8!0x1" : "u8!0x0";
+
+ ini_puts(Section, Key, value, IniPath);
+ }
+ }
+
}
diff --git a/Source/rewrite-hoc-clk/sysmodule/src/board/board_load.hpp b/Source/rewrite-hoc-clk/sysmodule/src/board/board_load.hpp
index a46fa7b7..6f830738 100644
--- a/Source/rewrite-hoc-clk/sysmodule/src/board/board_load.hpp
+++ b/Source/rewrite-hoc-clk/sysmodule/src/board/board_load.hpp
@@ -32,5 +32,6 @@ namespace board {
void StartLoad(Result nvCheck, u32 fd);
void ExitLoad();
u32 GetPartLoad();
+ void SetGpuSchedulingMode(GpuSchedulingMode mode, GpuSchedulingOverrideMethod method, Result nvCheckSched, u32 fd2);
}