Files
Horizon-OC/Source/sys-clk/sysmodule/src/clock_manager.cpp
souldbminersmwc e781e67b43 sysclk: rework governor
now should work in more games and behave more like a schedutil (slow rampdown, fast rampup)

fixes issues in Kirby and the Forgotten Land
2026-03-11 19:03:46 -04:00

1174 lines
49 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* 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 <http://www.gnu.org/licenses/>.
*
*/
/* --------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
* 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 "clock_manager.h"
#include <cstring>
#include "file_utils.h"
#include "board.h"
#include "process_management.h"
#include "errors.h"
#include "ipc_service.h"
#include "kip.h"
#include <i2c.h>
#include "notification.h"
#include <display_refresh_rate.h>
#include <cstring>
#include <cstdio>
#include <crc32.h>
#define HOSPPC_HAS_BOOST (hosversionAtLeast(7,0,0))
// governor constants
#define POLL_NS = 5'000'000; // 5 ms governor poll rate
#define DOWN_HOLD_TICKS = 10; // 50 ms how long to in POLL_NS to hold while ramping down
#define STEP_UTIL = 900; // multiplier for step calculations
bool isGpuGovernorEnabled = false;
bool isCpuGovernorEnabled = false;
bool lastGpuGovernorState = false;
bool lastCpuGovernorState = false;
bool hasChanged = true;
ClockManager *ClockManager::instance = NULL;
Thread cpuGovernorTHREAD;
Thread gpuGovernorTHREAD;
u32 initialConfigValues[SysClkConfigValue_EnumMax]; // initial config. used for safety checks
bool kipAvailable = false;
bool isCpuGovernorInBoostMode = false;
ClockManager *ClockManager::GetInstance()
{
return instance;
}
void ClockManager::Exit()
{
if (instance)
{
delete instance;
}
}
void ClockManager::Initialize()
{
if (!instance)
{
instance = new ClockManager();
}
}
ClockManager::ClockManager()
{
this->config = Config::CreateDefault();
this->context = new SysClkContext;
this->context->applicationId = 0;
this->context->profile = SysClkProfile_Handheld;
for (unsigned int module = 0; module < SysClkModule_EnumMax; module++)
{
this->context->freqs[module] = 0;
this->context->realFreqs[module] = 0;
this->context->overrideFreqs[module] = 0;
this->RefreshFreqTableRow((SysClkModule)module);
}
this->running = false;
this->lastTempLogNs = 0;
this->lastCsvWriteNs = 0;
this->sysDockIntegration = new SysDockIntegration;
memset(&initialConfigValues, 0, sizeof(initialConfigValues));
this->GetKipData();
threadCreate(
&cpuGovernorTHREAD,
ClockManager::CpuGovernorThread,
this,
NULL,
0x2000,
0x3F,
-2
);
threadCreate(
&gpuGovernorTHREAD,
ClockManager::GovernorThread,
this,
NULL,
0x2000,
0x3F,
-2
);
threadStart(&cpuGovernorTHREAD);
threadStart(&gpuGovernorTHREAD);
for(int i = 0; i < HorizonOCSpeedo_EnumMax; i++) {
this->context->speedos[i] = Board::getSpeedo((HorizonOCSpeedo)i);
this->context->iddq[i] = Board::getIDDQ((HorizonOCSpeedo)i);
}
this->context->dramID = Board::GetDramID();
this->context->isDram8GB = Board::IsDram8GB();
Board::SetGpuSchedulingMode((GpuSchedulingMode)this->config->GetConfigValue(HorizonOCConfigValue_GPUScheduling), (GpuSchedulingOverrideMethod)this->config->GetConfigValue(HorizonOCConfigValue_GPUSchedulingMethod));
this->context->gpuSchedulingMode = (GpuSchedulingMode)this->config->GetConfigValue(HorizonOCConfigValue_GPUScheduling);
this->context->isSysDockInstalled = this->sysDockIntegration->getCurrentSysDockState();
}
ClockManager::~ClockManager()
{
threadClose(&cpuGovernorTHREAD);
threadClose(&gpuGovernorTHREAD);
delete this->config;
delete this->context;
}
SysClkContext ClockManager::GetCurrentContext()
{
std::scoped_lock lock{this->contextMutex};
return *this->context;
}
Config *ClockManager::GetConfig()
{
return this->config;
}
void ClockManager::SetRunning(bool running)
{
this->running = running;
}
bool ClockManager::Running()
{
return this->running;
}
void ClockManager::GetFreqList(SysClkModule module, std::uint32_t *list, std::uint32_t maxCount, std::uint32_t *outCount)
{
ASSERT_ENUM_VALID(SysClkModule, module);
*outCount = std::min(maxCount, this->freqTable[module].count);
memcpy(list, &this->freqTable[module].list[0], *outCount * sizeof(this->freqTable[0].list[0]));
}
bool ClockManager::IsAssignableHz(SysClkModule module, std::uint32_t hz)
{
switch (module)
{
case SysClkModule_CPU:
return hz >= 500000000;
case SysClkModule_MEM:
return hz >= 665600000;
default:
return true;
}
}
std::uint32_t ClockManager::GetMaxAllowedHz(SysClkModule module, SysClkProfile profile)
{
if (this->config->GetConfigValue(HocClkConfigValue_UncappedClocks))
{
return ~0; // Integer limit, uncapped clocks ON
}
else
{
if (module == SysClkModule_GPU)
{
if (profile < SysClkProfile_HandheldCharging)
{
switch(Board::GetSocType()) {
case SysClkSocType_Erista:
return 460800000;
case SysClkSocType_Mariko:
switch(this->config->GetConfigValue(KipConfigValue_marikoGpuUV)) {
case 0:
return 614400000;
case 1:
return 691200000;
case 2:
return 768000000;
default:
return 614400000;
}
default:
return 460800000;
}
}
else if (profile <= SysClkProfile_HandheldChargingUSB)
{
switch(Board::GetSocType()) {
case SysClkSocType_Erista:
return 768000000;
case SysClkSocType_Mariko:
switch(this->config->GetConfigValue(KipConfigValue_marikoGpuUV)) {
case 0:
return 844800000;
case 1:
return 921600000;
case 2:
return 998400000;
default:
return 844800000;
}
default:
return 768000000;
}
}
} else if(module == SysClkModule_CPU) {
if(profile < SysClkProfile_HandheldCharging && Board::GetSocType() == SysClkSocType_Erista) {
return 1581000000;
} else {
return ~0;
}
}
}
return 0;
}
std::uint32_t ClockManager::GetNearestHz(SysClkModule module, std::uint32_t inHz, std::uint32_t maxHz)
{
std::uint32_t *freqs = &this->freqTable[module].list[0];
size_t count = this->freqTable[module].count - 1;
size_t i = 0;
while (i < count)
{
if (maxHz > 0 && freqs[i] >= maxHz)
{
break;
}
if (inHz <= ((std::uint64_t)freqs[i] + freqs[i + 1]) / 2)
{
break;
}
i++;
}
return freqs[i];
}
bool ClockManager::ConfigIntervalTimeout(SysClkConfigValue intervalMsConfigValue, std::uint64_t ns, std::uint64_t *lastLogNs)
{
std::uint64_t logInterval = this->GetConfig()->GetConfigValue(intervalMsConfigValue) * 1000000ULL;
bool shouldLog = logInterval && ((ns - *lastLogNs) > logInterval);
if (shouldLog)
{
*lastLogNs = ns;
}
return shouldLog;
}
void ClockManager::RefreshFreqTableRow(SysClkModule module)
{
std::scoped_lock lock{this->contextMutex};
std::uint32_t freqs[SYSCLK_FREQ_LIST_MAX];
std::uint32_t count;
FileUtils::LogLine("[mgr] %s freq list refresh", Board::GetModuleName(module, true));
Board::GetFreqList(module, &freqs[0], SYSCLK_FREQ_LIST_MAX, &count);
std::uint32_t *hz = &this->freqTable[module].list[0];
this->freqTable[module].count = 0;
for (std::uint32_t i = 0; i < count; i++)
{
if (!this->IsAssignableHz(module, freqs[i]))
{
continue;
}
*hz = freqs[i];
FileUtils::LogLine("[mgr] %02u - %u - %u.%u MHz", this->freqTable[module].count, *hz, *hz / 1000000, *hz / 100000 - *hz / 1000000 * 10);
this->freqTable[module].count++;
hz++;
}
FileUtils::LogLine("[mgr] count = %u", this->freqTable[module].count);
}
u32 ClockManager::SchedutilTargetHz(u32 util, u32 tableMaxHz) {
u64 hz = (u64)tableMaxHz * util / STEP_UTIL;
return (u32)(std::min(hz, static_cast<u64>(tableMaxHz)));
}
u32 ClockManager::TableIndexForHz(const FreqTable& table, u32 targetHz) { // must pass in a freqTable as tables are different for cpu/gpu
for (u32 i = 0; i < table.count; i++)
if (this->freqTable.list[i] >= targetHz)
return i;
return table.count - 1;
}
u32 ClockManager::ResolveTargetHz(ClockManager* mgr, SysClkModule module) {
u32 hz = mgr->context->overrideFreqs[module];
if (!hz)
hz = mgr->config->GetAutoClockHz(
mgr->context->applicationId, module,
mgr->context->profile, false);
if (!hz)
hz = mgr->config->GetAutoClockHz(
GLOBAL_PROFILE_ID, module,
mgr->context->profile, false);
return hz;
}
void ClockManager::CpuGovernorThread(void* arg) {
ClockManager* mgr = static_cast<ClockManager*>(arg);
u32 downHoldRemaining = 0;
u32 lastHz = 0;
for (;;) {
if (!mgr->running || !isCpuGovernorEnabled) {
downHoldRemaining = 0;
lastHz = 0;
continue;
}
u32 mode = 0;
Result rc = apmExtGetCurrentPerformanceConfiguration(&mode);
if (R_SUCCEEDED(rc) && apmExtIsBoostMode(mode)) {
isCpuGovernorInBoostMode = true;
downHoldRemaining = 0;
lastHz = 0;
continue; // TODO: figure out a way to get boost clock easily and set it instead of just skipping the governor
} else if(!apmExtIsBoostMode(mode)) {
isCpuGovernorInBoostMode = false;
}
auto& table = mgr->freqTable[SysClkModule_CPU];
if (table.count == 0)
continue;
std::scoped_lock lock{mgr->contextMutex};
u32 cpuLoad = Board::GetPartLoad(HocClkPartLoad_CPUMax);
u32 tableMaxHz = table.list[table.count - 1];
u32 desiredHz = ClockManager::SchedutilTargetHz(cpuLoad, tableMaxHz);
u32 targetHz = ClockManager::ResolveTargetHz(mgr, SysClkModule_CPU);
u32 maxHz = mgr->GetMaxAllowedHz(SysClkModule_CPU, mgr->context->profile);
if (targetHz && desiredHz > targetHz)
desiredHz = targetHz;
if (maxHz && desiredHz > maxHz)
desiredHz = maxHz;
u32 newHz = table.list[ClockManager::TableIndexForHz(table, desiredHz)];
// ramp up fast, go down slow
bool goingDown = (lastHz != 0) && (newHz < lastHz);
if (!goingDown)
downHoldRemaining = 0;
else if (downHoldRemaining == 0)
downHoldRemaining = DOWN_HOLD_TICKS;
if (downHoldRemaining > 0)
downHoldRemaining--;
if ((!goingDown || (downHoldRemaining == 0)) && mgr->IsAssignableHz(SysClkModule_CPU, newHz)) {
Board::SetHz(SysClkModule_CPU, newHz);
mgr->context->freqs[SysClkModule_CPU] = newHz;
lastHz = newHz;
}
svcSleepThread(POLL_NS);
}
}
void ClockManager::GovernorThread(void* arg) {
ClockManager* mgr = static_cast<ClockManager*>(arg);
u32 downHoldRemaining = 0;
u32 lastHz = 0;
for (;;) {
if (!mgr->running || !isGpuGovernorEnabled) {
downHoldRemaining = 0;
lastHz = 0;
continue;
}
auto& table = mgr->freqTable[SysClkModule_GPU];
if (table.count == 0)
continue;
std::scoped_lock lock{mgr->contextMutex};
u32 gpuLoad = Board::GetPartLoad(HocClkPartLoad_GPU);
u32 tableMaxHz = table.list[table.count - 1];
u32 desiredHz = ClockManager::SchedutilTargetHz(gpuLoad, tableMaxHz);
u32 targetHz = ClockManager::ResolveTargetHz(mgr, SysClkModule_GPU);
u32 maxHz = mgr->GetMaxAllowedHz(SysClkModule_GPU, mgr->context->profile);
if (targetHz && desiredHz > targetHz)
desiredHz = targetHz;
if (maxHz && desiredHz > maxHz)
desiredHz = maxHz;
u32 newHz = table.list[ClockManager::TableIndexForHz(table, desiredHz)];
bool goingDown = (lastHz != 0) && (newHz < lastHz);
if (!goingDown)
downHoldRemaining = 0;
else if (downHoldRemaining == 0)
downHoldRemaining = DOWN_HOLD_TICKS;
if (downHoldRemaining > 0)
downHoldRemaining--;
if ((!goingDown || (downHoldRemaining == 0)) && mgr->IsAssignableHz(SysClkModule_GPU, newHz)) {
Board::SetHz(SysClkModule_GPU, newHz);
mgr->context->freqs[SysClkModule_GPU] = newHz;
lastHz = newHz;
}
svcSleepThread(POLL_NS);
}
}
GovernorState ClockManager::GetEffectiveGovernorState(GovernorState appState, GovernorState tempState)
{
if (tempState == GovernorState_Disabled)
{
return GovernorState_Disabled;
}
if (tempState != GovernorState_DoNotOverride)
{
return tempState;
}
return appState;
}
void ClockManager::HandleSafetyFeatures() {
AppletOperationMode opMode = appletGetOperationMode();
if(this->config->GetConfigValue(HocClkConfigValue_HandheldTDP) && opMode == AppletOperationMode_Handheld) {
if(Board::GetConsoleType() == HorizonOCConsoleType_Hoag) {
if(Board::GetPowerMw(SysClkPowerSensor_Avg) < -(int)this->config->GetConfigValue(HocClkConfigValue_LiteTDPLimit)) {
ResetToStockClocks();
return;
}
} else {
if(Board::GetPowerMw(SysClkPowerSensor_Avg) < -(int)this->config->GetConfigValue(HocClkConfigValue_HandheldTDPLimit)) {
ResetToStockClocks();
return;
}
}
}
if(((tmp451TempSoc() / 1000) > (int)this->config->GetConfigValue(HocClkConfigValue_ThermalThrottleThreshold)) && this->config->GetConfigValue(HocClkConfigValue_ThermalThrottle)) {
ResetToStockClocks();
return;
}
}
void ClockManager::HandleMiscFeatures() {
if(this->config->GetConfigValue(HorizonOCConfigValue_BatteryChargeCurrent)) {
I2c_Bq24193_SetFastChargeCurrentLimit(this->config->GetConfigValue(HorizonOCConfigValue_BatteryChargeCurrent));
}
}
void ClockManager::HandleGovernor(uint32_t targetHz) {
GovernorState appGovernorState = (GovernorState)targetHz;
u32 tempTargetHz = this->context->overrideFreqs[HorizonOCModule_Governor];
if (!tempTargetHz)
{
tempTargetHz = this->config->GetAutoClockHz(this->context->applicationId, HorizonOCModule_Governor, this->context->profile, true);
if(!tempTargetHz)
tempTargetHz = this->config->GetAutoClockHz(GLOBAL_PROFILE_ID, HorizonOCModule_Governor, this->context->profile, true);
}
GovernorState tempGovernorState = (GovernorState)tempTargetHz;
GovernorState effectiveState = this->GetEffectiveGovernorState(appGovernorState, tempGovernorState);
bool newCpuGovernorState = (effectiveState == GovernorState_Enabled_CpuGpu || effectiveState == GovernorState_Enabled_Cpu);
bool newGpuGovernorState = (effectiveState == GovernorState_Enabled_CpuGpu || effectiveState == GovernorState_Enabled_Gpu);
isCpuGovernorEnabled = newCpuGovernorState;
isGpuGovernorEnabled = newGpuGovernorState;
if(newCpuGovernorState == false && lastCpuGovernorState == true) {
svcSleepThread(50'000'000); // thread syncing. probably a cleaner way to do this but hey, it works!
Board::ResetToStockCpu();
}
if(newGpuGovernorState == false && lastGpuGovernorState == true) {
svcSleepThread(50'000'000);
Board::ResetToStockGpu();
}
if(newCpuGovernorState != lastCpuGovernorState || newGpuGovernorState != lastGpuGovernorState) {
FileUtils::LogLine("[mgr] Governor state changed: CPU %s, GPU %s", newCpuGovernorState ? "enabled" : "disabled", newGpuGovernorState ? "enabled" : "disabled");
lastCpuGovernorState = newCpuGovernorState;
lastGpuGovernorState = newGpuGovernorState;
}
}
void ClockManager::DVFSBeforeSet(u32 targetHz) {
s32 dvfsOffset = this->config->GetConfigValue(HorizonOCConfigValue_DVFSOffset);
u32 vmin = Board::GetMinimumGpuVoltage(targetHz / 1000000) + dvfsOffset;
Board::PcvHijackDvfs(vmin);
/* Update the voltage. */
if (I2c_BuckConverter_GetMvOut(&I2c_Mariko_GPU) < vmin) {
I2c_BuckConverter_SetMvOut(&I2c_Mariko_GPU, vmin);
}
this->context->voltages[HocClkVoltage_GPU] = vmin * 1000;
}
void ClockManager::DVFSAfterSet(u32 targetHz) {
s32 dvfsOffset = this->config->GetConfigValue(HorizonOCConfigValue_DVFSOffset);
dvfsOffset = std::max(dvfsOffset, -50);
u32 vmin = Board::GetMinimumGpuVoltage(targetHz / 1000000) + dvfsOffset;
Board::PcvHijackDvfs(vmin);
targetHz = this->context->overrideFreqs[SysClkModule_GPU];
if (!targetHz)
{
targetHz = this->config->GetAutoClockHz(this->context->applicationId, SysClkModule_GPU, this->context->profile, false);
if(!targetHz)
targetHz = this->config->GetAutoClockHz(GLOBAL_PROFILE_ID, SysClkModule_GPU, this->context->profile, false);
}
u32 maxHz = this->GetMaxAllowedHz(SysClkModule_GPU, this->context->profile);
u32 nearestHz = this->GetNearestHz(SysClkModule_GPU, targetHz, maxHz);
if(targetHz) {
Board::SetHz(SysClkModule_GPU, ~0);
Board::SetHz(SysClkModule_GPU, nearestHz);
}
}
void ClockManager::HandleCpuUv() {
if(Board::GetSocType() == SysClkSocType_Erista)
Board::SetCpuUvLevel(this->config->GetConfigValue(KipConfigValue_eristaCpuUV), 0, 1581000000);
else
Board::SetCpuUvLevel(this->config->GetConfigValue(KipConfigValue_marikoCpuUVLow), this->config->GetConfigValue(KipConfigValue_marikoCpuUVHigh), Board::CalculateTbreak(this->config->GetConfigValue(KipConfigValue_tableConf)));
}
void ClockManager::DVFSReset() {
if (Board::GetSocType() == SysClkSocType_Mariko && this->config->GetConfigValue(HorizonOCConfigValue_DVFSMode) == DVFSMode_Hijack) {
Board::PcvHijackDvfs(0);
u32 targetHz = this->context->overrideFreqs[SysClkModule_GPU];
if (!targetHz) {
targetHz = this->config->GetAutoClockHz(this->context->applicationId, SysClkModule_GPU, this->context->profile, false);
if(!targetHz) {
targetHz = this->config->GetAutoClockHz(GLOBAL_PROFILE_ID, SysClkModule_GPU, this->context->profile, false);
}
}
u32 maxHz = this->GetMaxAllowedHz(SysClkModule_GPU, this->context->profile);
u32 nearestHz = this->GetNearestHz(SysClkModule_GPU, targetHz, maxHz);
Board::SetHz(SysClkModule_GPU, ~0);
if(targetHz) {
Board::SetHz(SysClkModule_GPU, nearestHz);
} else {
Board::ResetToStockGpu();
}
}
}
void ClockManager::HandleFreqReset(SysClkModule module, bool isBoost) {
switch (module)
{
case SysClkModule_CPU:
if(!(isBoost || (this->config->GetConfigValue(HocClkConfigValue_OverwriteBoostMode) && isBoost)))
Board::ResetToStockCpu();
if(this->config->GetConfigValue(HorizonOCConfigValue_LiveCpuUv)) {
if(Board::GetSocType() == SysClkSocType_Erista)
Board::SetCpuUvLevel(this->config->GetConfigValue(KipConfigValue_eristaCpuUV), 0, 1581000000);
else
Board::SetCpuUvLevel(this->config->GetConfigValue(KipConfigValue_marikoCpuUVLow), this->config->GetConfigValue(KipConfigValue_marikoCpuUVHigh), Board::CalculateTbreak(this->config->GetConfigValue(KipConfigValue_tableConf)));
}
break;
case SysClkModule_GPU:
Board::ResetToStockGpu();
break;
case SysClkModule_MEM:
Board::ResetToStockMem();
DVFSReset();
default:
break;
}
}
void ClockManager::SetClocks(bool isBoost) {
std::uint32_t targetHz = 0;
std::uint32_t maxHz = 0;
std::uint32_t nearestHz = 0;
if(isBoost && !this->config->GetConfigValue(HocClkConfigValue_OverwriteBoostMode)) {
u32 boostFreq = Board::GetHz(SysClkModule_CPU);
if (boostFreq / 1000000 > 1785) {
Board::SetHz(SysClkModule_CPU, boostFreq);
}
return; // Return if we are't overwriting boost mode
}
bool returnRaw = false; // Return a value scaled to MHz instead of raw value
for (unsigned int module = 0; module < SysClkModule_EnumMax; module++)
{
u32 oldHz = Board::GetHz((SysClkModule)module); // Get Old hz (used primarily for DVFS Logic)
if(module > SysClkModule_MEM)
returnRaw = true;
else
returnRaw = false;
targetHz = this->context->overrideFreqs[module];
if (!targetHz)
{
targetHz = this->config->GetAutoClockHz(this->context->applicationId, (SysClkModule)module, this->context->profile, returnRaw);
if(!targetHz)
targetHz = this->config->GetAutoClockHz(GLOBAL_PROFILE_ID, (SysClkModule)module, this->context->profile, returnRaw);
}
if(module == HorizonOCModule_Governor) {
HandleGovernor(targetHz);
}
if(module == HorizonOCModule_Display && this->config->GetConfigValue(HorizonOCConfigValue_OverwriteRefreshRate) && Board::GetConsoleType() != HorizonOCConsoleType_Hoag) {
if(targetHz)
Board::SetHz(HorizonOCModule_Display, targetHz);
else
Board::ResetToStockDisplay();
}
// Skip GPU and CPU if governors handle them
if(module > SysClkModule_MEM) {
continue;
}
bool noCPU = isCpuGovernorEnabled;
bool noGPU = isGpuGovernorEnabled;
if(noCPU && module == SysClkModule_CPU)
continue;
if(noGPU && module == SysClkModule_GPU)
continue;
if (targetHz)
{
maxHz = this->GetMaxAllowedHz((SysClkModule)module, this->context->profile);
nearestHz = this->GetNearestHz((SysClkModule)module, targetHz, maxHz);
if (nearestHz != this->context->freqs[module]) {
FileUtils::LogLine(
"[mgr] %s clock set : %u.%u MHz (target = %u.%u MHz)",
Board::GetModuleName((SysClkModule)module, true),
nearestHz / 1000000, nearestHz / 100000 - nearestHz / 1000000 * 10,
targetHz / 1000000, targetHz / 100000 - targetHz / 1000000 * 10
);
if(module == SysClkModule_MEM && Board::GetSocType() == SysClkSocType_Mariko && targetHz > oldHz && this->config->GetConfigValue(HorizonOCConfigValue_DVFSMode) == DVFSMode_Hijack) {
DVFSBeforeSet(targetHz);
}
Board::SetHz((SysClkModule)module, nearestHz);
this->context->freqs[module] = nearestHz;
if(module == SysClkModule_CPU && (this->config->GetConfigValue(HorizonOCConfigValue_LiveCpuUv))) {
HandleCpuUv();
}
if(module == SysClkModule_MEM && Board::GetSocType() == SysClkSocType_Mariko && targetHz < oldHz && this->config->GetConfigValue(HorizonOCConfigValue_DVFSMode) == DVFSMode_Hijack) {
DVFSAfterSet(targetHz);
}
}
} else {
HandleFreqReset((SysClkModule)module, isBoost);
}
}
}
void ClockManager::Tick()
{
std::scoped_lock lock{this->contextMutex};
std::uint32_t mode = 0;
Result rc = apmExtGetCurrentPerformanceConfiguration(&mode);
ASSERT_RESULT_OK(rc, "apmExtGetCurrentPerformanceConfiguration");
bool isBoost = apmExtIsBoostMode(mode);
HandleSafetyFeatures();
if (this->RefreshContext() || this->config->Refresh())
{
HandleMiscFeatures();
SetClocks(isBoost);
}
}
void ClockManager::ResetToStockClocks() {
Board::ResetToStockCpu();
if(this->config->GetConfigValue(HorizonOCConfigValue_LiveCpuUv))
{
if(Board::GetSocType() == SysClkSocType_Erista)
Board::SetCpuUvLevel(this->config->GetConfigValue(KipConfigValue_eristaCpuUV), 0, 1581000000);
else
Board::SetCpuUvLevel(this->config->GetConfigValue(KipConfigValue_marikoCpuUVLow), this->config->GetConfigValue(KipConfigValue_marikoCpuUVHigh), Board::CalculateTbreak(this->config->GetConfigValue(KipConfigValue_tableConf)));
}
Board::ResetToStockGpu();
}
void ClockManager::WaitForNextTick()
{
if(!(Board::GetHz(SysClkModule_MEM) < 665000000))
svcSleepThread(this->GetConfig()->GetConfigValue(SysClkConfigValue_PollingIntervalMs) * 1000000ULL);
else
svcSleepThread(5000 * 1000000ULL); // 5 seconds in sleep mode
}
bool ClockManager::RefreshContext()
{
bool hasChanged = false;
std::uint32_t mode = 0;
Result rc = apmExtGetCurrentPerformanceConfiguration(&mode);
ASSERT_RESULT_OK(rc, "apmExtGetCurrentPerformanceConfiguration");
std::uint64_t applicationId = ProcessManagement::GetCurrentApplicationId();
if (applicationId != this->context->applicationId)
{
FileUtils::LogLine("[mgr] TitleID change: %016lX", applicationId);
this->context->applicationId = applicationId;
hasChanged = true;
}
SysClkProfile profile = Board::GetProfile();
if (profile != this->context->profile)
{
FileUtils::LogLine("[mgr] Profile change: %s", Board::GetProfileName(profile, true));
this->context->profile = profile;
hasChanged = true;
}
// restore clocks to stock values on app or profile change
if (hasChanged)
{
Board::ResetToStock();
if (Board::GetSocType() == SysClkSocType_Mariko && this->config->GetConfigValue(HorizonOCConfigValue_DVFSMode) == DVFSMode_Hijack) {
Board::PcvHijackDvfs(0);
Board::SetHz(SysClkModule_GPU, ~0);
Board::ResetToStockGpu();
}
this->WaitForNextTick();
}
std::uint32_t hz = 0;
for (unsigned int module = 0; module < SysClkModule_EnumMax; module++)
{
hz = Board::GetHz((SysClkModule)module);
if (hz != 0 && hz != this->context->freqs[module])
{
FileUtils::LogLine("[mgr] %s clock change: %u.%u MHz", Board::GetModuleName((SysClkModule)module, true), hz / 1000000, hz / 100000 - hz / 1000000 * 10);
this->context->freqs[module] = hz;
hasChanged = true;
}
hz = this->GetConfig()->GetOverrideHz((SysClkModule)module);
if (hz != this->context->overrideFreqs[module])
{
if (hz)
{
FileUtils::LogLine("[mgr] %s override change: %u.%u MHz", Board::GetModuleName((SysClkModule)module, true), hz / 1000000, hz / 100000 - hz / 1000000 * 10);
}
this->context->overrideFreqs[module] = hz;
hasChanged = true;
}
}
std::uint64_t ns = armTicksToNs(armGetSystemTick());
// temperatures do not and should not force a refresh, hasChanged untouched
std::uint32_t millis = 0;
bool shouldLogTemp = this->ConfigIntervalTimeout(SysClkConfigValue_TempLogIntervalMs, ns, &this->lastTempLogNs);
for (unsigned int sensor = 0; sensor < SysClkThermalSensor_EnumMax; sensor++)
{
millis = Board::GetTemperatureMilli((SysClkThermalSensor)sensor);
if (shouldLogTemp)
{
FileUtils::LogLine("[mgr] %s temp: %u.%u °C", Board::GetThermalSensorName((SysClkThermalSensor)sensor, true), millis / 1000, (millis - millis / 1000 * 1000) / 100);
}
this->context->temps[sensor] = millis;
}
// power stats do not and should not force a refresh, hasChanged untouched
std::int32_t mw = 0;
bool shouldLogPower = this->ConfigIntervalTimeout(SysClkConfigValue_PowerLogIntervalMs, ns, &this->lastPowerLogNs);
for (unsigned int sensor = 0; sensor < SysClkPowerSensor_EnumMax; sensor++)
{
mw = Board::GetPowerMw((SysClkPowerSensor)sensor);
if (shouldLogPower)
{
FileUtils::LogLine("[mgr] Power %s: %d mW", Board::GetPowerSensorName((SysClkPowerSensor)sensor, false), mw);
}
this->context->power[sensor] = mw;
}
// real freqs do not and should not force a refresh, hasChanged untouched
std::uint32_t realHz = 0;
bool shouldLogFreq = this->ConfigIntervalTimeout(SysClkConfigValue_FreqLogIntervalMs, ns, &this->lastFreqLogNs);
for (unsigned int module = 0; module < SysClkModule_EnumMax; module++)
{
realHz = Board::GetRealHz((SysClkModule)module);
if (shouldLogFreq)
{
FileUtils::LogLine("[mgr] %s real freq: %u.%u MHz", Board::GetModuleName((SysClkModule)module, true), realHz / 1000000, realHz / 100000 - realHz / 1000000 * 10);
}
this->context->realFreqs[module] = realHz;
}
// ram load do not and should not force a refresh, hasChanged untouched
for (unsigned int loadSource = 0; loadSource < SysClkPartLoad_EnumMax; loadSource++)
{
this->context->partLoad[loadSource] = Board::GetPartLoad((SysClkPartLoad)loadSource);
}
for (unsigned int voltageSource = 0; voltageSource < HocClkVoltage_EnumMax; voltageSource++)
{
this->context->voltages[voltageSource] = Board::GetVoltage((HocClkVoltage)voltageSource);
}
if (this->ConfigIntervalTimeout(SysClkConfigValue_CsvWriteIntervalMs, ns, &this->lastCsvWriteNs))
{
FileUtils::WriteContextToCsv(this->context);
}
// this->context->maxDisplayFreq = Board::GetHighestDockedDisplayRate();
u32 targetHz = this->context->overrideFreqs[HorizonOCModule_Display];
if (!targetHz)
{
targetHz = this->config->GetAutoClockHz(this->context->applicationId, HorizonOCModule_Display, this->context->profile, true);
if(!targetHz)
targetHz = this->config->GetAutoClockHz(GLOBAL_PROFILE_ID, HorizonOCModule_Display, this->context->profile, true);
}
if(targetHz && this->context->realFreqs[HorizonOCModule_Display] > targetHz && this->context->profile != SysClkProfile_Docked)
this->context->realFreqs[HorizonOCModule_Display] = targetHz; // clean up display real freqs, should probably be moved to the real freqs loop?
if(Board::GetConsoleType() != HorizonOCConsoleType_Hoag)
Board::SetDisplayRefreshDockedState(this->context->profile == SysClkProfile_Docked);
return hasChanged;
}
void ClockManager::SetKipData() {
// TODO: figure out if this REALLY causes issues (i doubt it)
// if(Board::GetSocType() == SysClkSocType_Mariko) {
// if(R_FAILED(I2c_BuckConverter_SetMvOut(&I2c_Mariko_DRAM_VDDQ, this->config->GetConfigValue(KipConfigValue_marikoEmcVddqVolt) / 1000))) {
// FileUtils::LogLine("[clock_manager] Failed set i2c vddq");
// writeNotification("Horizon OC\nFailed to write I2C\nwhile setting vddq");
// }
// }
CustomizeTable table;
FILE* fp;
fp = fopen("sdmc:/atmosphere/kips/hoc.kip", "r");
if (fp == NULL) {
writeNotification("Horizon OC\nKip opening failed");
kipAvailable = false;
return;
} else {
kipAvailable = true;
fclose(fp);
}
if (!cust_read_and_cache("sdmc:/atmosphere/kips/hoc.kip", &table)) {
FileUtils::LogLine("[clock_manager] Failed to read KIP file");
writeNotification("Horizon OC\nKip read failed");
return;
}
CUST_WRITE_FIELD_BATCH(&table, custRev, this->config->GetConfigValue(KipConfigValue_custRev));
// CUST_WRITE_FIELD_BATCH(&table, mtcConf, this->config->GetConfigValue(KipConfigValue_mtcConf));
CUST_WRITE_FIELD_BATCH(&table, hpMode, this->config->GetConfigValue(KipConfigValue_hpMode));
CUST_WRITE_FIELD_BATCH(&table, commonEmcMemVolt, this->config->GetConfigValue(KipConfigValue_commonEmcMemVolt));
CUST_WRITE_FIELD_BATCH(&table, eristaEmcMaxClock, this->config->GetConfigValue(KipConfigValue_eristaEmcMaxClock));
CUST_WRITE_FIELD_BATCH(&table, eristaEmcMaxClock1, this->config->GetConfigValue(KipConfigValue_eristaEmcMaxClock1));
CUST_WRITE_FIELD_BATCH(&table, eristaEmcMaxClock2, this->config->GetConfigValue(KipConfigValue_eristaEmcMaxClock2));
CUST_WRITE_FIELD_BATCH(&table, marikoEmcMaxClock, this->config->GetConfigValue(KipConfigValue_marikoEmcMaxClock));
CUST_WRITE_FIELD_BATCH(&table, marikoEmcVddqVolt, this->config->GetConfigValue(KipConfigValue_marikoEmcVddqVolt));
CUST_WRITE_FIELD_BATCH(&table, emcDvbShift, this->config->GetConfigValue(KipConfigValue_emcDvbShift));
CUST_WRITE_FIELD_BATCH(&table, t1_tRCD, this->config->GetConfigValue(KipConfigValue_t1_tRCD));
CUST_WRITE_FIELD_BATCH(&table, t2_tRP, this->config->GetConfigValue(KipConfigValue_t2_tRP));
CUST_WRITE_FIELD_BATCH(&table, t3_tRAS, this->config->GetConfigValue(KipConfigValue_t3_tRAS));
CUST_WRITE_FIELD_BATCH(&table, t4_tRRD, this->config->GetConfigValue(KipConfigValue_t4_tRRD));
CUST_WRITE_FIELD_BATCH(&table, t5_tRFC, this->config->GetConfigValue(KipConfigValue_t5_tRFC));
CUST_WRITE_FIELD_BATCH(&table, t6_tRTW, this->config->GetConfigValue(KipConfigValue_t6_tRTW));
CUST_WRITE_FIELD_BATCH(&table, t7_tWTR, this->config->GetConfigValue(KipConfigValue_t7_tWTR));
CUST_WRITE_FIELD_BATCH(&table, t8_tREFI, this->config->GetConfigValue(KipConfigValue_t8_tREFI));
CUST_WRITE_FIELD_BATCH(&table, mem_burst_read_latency, this->config->GetConfigValue(KipConfigValue_mem_burst_read_latency));
CUST_WRITE_FIELD_BATCH(&table, mem_burst_write_latency, this->config->GetConfigValue(KipConfigValue_mem_burst_write_latency));
CUST_WRITE_FIELD_BATCH(&table, eristaCpuUV, this->config->GetConfigValue(KipConfigValue_eristaCpuUV));
CUST_WRITE_FIELD_BATCH(&table, eristaCpuVmin, this->config->GetConfigValue(KipConfigValue_eristaCpuVmin));
CUST_WRITE_FIELD_BATCH(&table, eristaCpuMaxVolt, this->config->GetConfigValue(KipConfigValue_eristaCpuMaxVolt));
CUST_WRITE_FIELD_BATCH(&table, eristaCpuUnlock, this->config->GetConfigValue(KipConfigValue_eristaCpuUnlock));
CUST_WRITE_FIELD_BATCH(&table, marikoCpuUVLow, this->config->GetConfigValue(KipConfigValue_marikoCpuUVLow));
CUST_WRITE_FIELD_BATCH(&table, marikoCpuUVHigh, this->config->GetConfigValue(KipConfigValue_marikoCpuUVHigh));
CUST_WRITE_FIELD_BATCH(&table, tableConf, this->config->GetConfigValue(KipConfigValue_tableConf));
CUST_WRITE_FIELD_BATCH(&table, marikoCpuLowVmin, this->config->GetConfigValue(KipConfigValue_marikoCpuLowVmin));
CUST_WRITE_FIELD_BATCH(&table, marikoCpuHighVmin, this->config->GetConfigValue(KipConfigValue_marikoCpuHighVmin));
CUST_WRITE_FIELD_BATCH(&table, marikoCpuMaxVolt, this->config->GetConfigValue(KipConfigValue_marikoCpuMaxVolt));
CUST_WRITE_FIELD_BATCH(&table, marikoCpuMaxClock, this->config->GetConfigValue(KipConfigValue_marikoCpuMaxClock));
CUST_WRITE_FIELD_BATCH(&table, eristaCpuBoostClock, this->config->GetConfigValue(KipConfigValue_eristaCpuBoostClock));
CUST_WRITE_FIELD_BATCH(&table, marikoCpuBoostClock, this->config->GetConfigValue(KipConfigValue_marikoCpuBoostClock));
CUST_WRITE_FIELD_BATCH(&table, eristaGpuUV, this->config->GetConfigValue(KipConfigValue_eristaGpuUV));
CUST_WRITE_FIELD_BATCH(&table, eristaGpuVmin, this->config->GetConfigValue(KipConfigValue_eristaGpuVmin));
CUST_WRITE_FIELD_BATCH(&table, marikoGpuUV, this->config->GetConfigValue(KipConfigValue_marikoGpuUV));
CUST_WRITE_FIELD_BATCH(&table, marikoGpuVmin, this->config->GetConfigValue(KipConfigValue_marikoGpuVmin));
CUST_WRITE_FIELD_BATCH(&table, marikoGpuVmax, this->config->GetConfigValue(KipConfigValue_marikoGpuVmax));
CUST_WRITE_FIELD_BATCH(&table, commonGpuVoltOffset, this->config->GetConfigValue(KipConfigValue_commonGpuVoltOffset));
CUST_WRITE_FIELD_BATCH(&table, gpuSpeedo, this->config->GetConfigValue(KipConfigValue_gpuSpeedo));
for (int i = 0; i < 24; i++) {
table.marikoGpuVoltArray[i] = this->config->GetConfigValue((SysClkConfigValue)(KipConfigValue_g_volt_76800 + i));
}
for (int i = 0; i < 27; i++) {
table.eristaGpuVoltArray[i] = this->config->GetConfigValue((SysClkConfigValue)(KipConfigValue_g_volt_e_76800 + i));
}
CUST_WRITE_FIELD_BATCH(&table, t6_tRTW_fine_tune, this->config->GetConfigValue(KipConfigValue_t6_tRTW_fine_tune));
CUST_WRITE_FIELD_BATCH(&table, t7_tWTR_fine_tune, this->config->GetConfigValue(KipConfigValue_t7_tWTR_fine_tune));
if (!cust_write_table("sdmc:/atmosphere/kips/hoc.kip", &table)) {
FileUtils::LogLine("[clock_manager] Failed to write KIP file");
writeNotification("Horizon OC\nKip write failed");
}
SysClkConfigValueList configValues;
this->config->GetConfigValues(&configValues);
configValues.values[KipCrc32] = (u64)checksum_file("sdmc:/atmosphere/kips/hoc.kip"); // write checksum
if (this->config->SetConfigValues(&configValues, false)) {
FileUtils::LogLine("[clock_manager] Successfully loaded KIP data into config");
} else {
FileUtils::LogLine("[clock_manager] Warning: Failed to set config values from KIP");
writeNotification("Horizon OC\nKip config set failed");
}
}
// I know this is very hacky, but the config system in the sysmodule doesn't really support writing
void ClockManager::GetKipData() {
FILE* fp;
if(this->config->Refresh()) {
fp = fopen("sdmc:/atmosphere/kips/hoc.kip", "r");
if (fp == NULL) {
writeNotification("Horizon OC\nKip opening failed");
kipAvailable = false;
return;
} else {
kipAvailable = true;
fclose(fp);
}
SysClkConfigValueList configValues;
this->config->GetConfigValues(&configValues);
CustomizeTable table;
if (!cust_read_and_cache("sdmc:/atmosphere/kips/hoc.kip", &table)) {
FileUtils::LogLine("[clock_manager] Failed to read KIP file for GetKipData");
writeNotification("Horizon OC\nKip read failed");
return;
}
if((u64)checksum_file("sdmc:/atmosphere/kips/hoc.kip") != this->config->GetConfigValue(KipCrc32) && !this->config->GetConfigValue(HocClkConfigValue_IsFirstLoad)) {
SetKipData();
writeNotification("Horizon OC\nKIP has been updated");
writeNotification("Horizon OC\nPlease reboot your console");
writeNotification("Horizon OC\nto complete the update");
return;
}
if(this->config->GetConfigValue(HocClkConfigValue_IsFirstLoad) == true) {
configValues.values[HocClkConfigValue_IsFirstLoad] = (u64)false;
writeNotification("Horizon OC has been installed");
}
static bool writeBootConfigValues = true;
configValues.values[KipCrc32] = (u64)checksum_file("sdmc:/atmosphere/kips/hoc.kip"); // write checksum
if(writeBootConfigValues) {
writeBootConfigValues = false;
// initialConfigValues[KipConfigValue_mtcConf] = cust_get_mtc_conf(&table);
initialConfigValues[KipConfigValue_hpMode] = cust_get_hp_mode(&table);
initialConfigValues[KipConfigValue_commonEmcMemVolt] = cust_get_common_emc_volt(&table);
initialConfigValues[KipConfigValue_eristaEmcMaxClock] = cust_get_erista_emc_max(&table);
initialConfigValues[KipConfigValue_eristaEmcMaxClock1] = cust_get_erista_emc_max1(&table);
initialConfigValues[KipConfigValue_eristaEmcMaxClock2] = cust_get_erista_emc_max2(&table);
initialConfigValues[KipConfigValue_marikoEmcMaxClock] = cust_get_mariko_emc_max(&table);
initialConfigValues[KipConfigValue_marikoEmcVddqVolt] = cust_get_mariko_emc_vddq(&table);
initialConfigValues[KipConfigValue_emcDvbShift] = cust_get_emc_dvb_shift(&table);
initialConfigValues[KipConfigValue_t1_tRCD] = cust_get_tRCD(&table);
initialConfigValues[KipConfigValue_t2_tRP] = cust_get_tRP(&table);
initialConfigValues[KipConfigValue_t3_tRAS] = cust_get_tRAS(&table);
initialConfigValues[KipConfigValue_t4_tRRD] = cust_get_tRRD(&table);
initialConfigValues[KipConfigValue_t5_tRFC] = cust_get_tRFC(&table);
initialConfigValues[KipConfigValue_t6_tRTW] = cust_get_tRTW(&table);
initialConfigValues[KipConfigValue_t7_tWTR] = cust_get_tWTR(&table);
initialConfigValues[KipConfigValue_t8_tREFI] = cust_get_tREFI(&table);
initialConfigValues[KipConfigValue_mem_burst_read_latency] = cust_get_burst_read_lat(&table);
initialConfigValues[KipConfigValue_mem_burst_write_latency] = cust_get_burst_write_lat(&table);
initialConfigValues[KipConfigValue_eristaCpuUV] = cust_get_erista_cpu_uv(&table);
initialConfigValues[KipConfigValue_eristaCpuVmin] = cust_get_eristaCpuVmin(&table);
initialConfigValues[KipConfigValue_eristaCpuMaxVolt] = cust_get_erista_cpu_max_volt(&table);
initialConfigValues[KipConfigValue_eristaCpuUnlock] = cust_get_eristaCpuUnlock(&table);
initialConfigValues[KipConfigValue_marikoCpuUVLow] = cust_get_mariko_cpu_uv_low(&table);
initialConfigValues[KipConfigValue_marikoCpuUVHigh] = cust_get_mariko_cpu_uv_high(&table);
initialConfigValues[KipConfigValue_tableConf] = cust_get_table_conf(&table);
initialConfigValues[KipConfigValue_marikoCpuLowVmin] = cust_get_mariko_cpu_low_vmin(&table);
initialConfigValues[KipConfigValue_marikoCpuHighVmin] = cust_get_mariko_cpu_high_vmin(&table);
initialConfigValues[KipConfigValue_marikoCpuMaxVolt] = cust_get_mariko_cpu_max_volt(&table);
initialConfigValues[KipConfigValue_marikoCpuMaxClock] = cust_get_marikoCpuMaxClock(&table);
initialConfigValues[KipConfigValue_eristaCpuBoostClock] = cust_get_erista_cpu_boost(&table);
initialConfigValues[KipConfigValue_marikoCpuBoostClock] = cust_get_mariko_cpu_boost(&table);
initialConfigValues[KipConfigValue_eristaGpuUV] = cust_get_erista_gpu_uv(&table);
initialConfigValues[KipConfigValue_eristaGpuVmin] = cust_get_erista_gpu_vmin(&table);
initialConfigValues[KipConfigValue_marikoGpuUV] = cust_get_mariko_gpu_uv(&table);
initialConfigValues[KipConfigValue_marikoGpuVmin] = cust_get_mariko_gpu_vmin(&table);
initialConfigValues[KipConfigValue_marikoGpuVmax] = cust_get_mariko_gpu_vmax(&table);
initialConfigValues[KipConfigValue_commonGpuVoltOffset] = cust_get_common_gpu_offset(&table);
initialConfigValues[KipConfigValue_gpuSpeedo] = cust_get_gpu_speedo(&table);
initialConfigValues[KipConfigValue_t6_tRTW_fine_tune] = cust_get_tRTW_fine_tune(&table);
initialConfigValues[KipConfigValue_t7_tWTR_fine_tune] = cust_get_tWTR_fine_tune(&table);
}
// configValues.values[KipConfigValue_mtcConf] = cust_get_mtc_conf(&table);
configValues.values[KipConfigValue_hpMode] = cust_get_hp_mode(&table);
configValues.values[KipConfigValue_commonEmcMemVolt] = cust_get_common_emc_volt(&table);
configValues.values[KipConfigValue_eristaEmcMaxClock] = cust_get_erista_emc_max(&table);
configValues.values[KipConfigValue_eristaEmcMaxClock1] = cust_get_erista_emc_max1(&table);
configValues.values[KipConfigValue_eristaEmcMaxClock2] = cust_get_erista_emc_max2(&table);
configValues.values[KipConfigValue_marikoEmcMaxClock] = cust_get_mariko_emc_max(&table);
configValues.values[KipConfigValue_marikoEmcVddqVolt] = cust_get_mariko_emc_vddq(&table);
configValues.values[KipConfigValue_emcDvbShift] = cust_get_emc_dvb_shift(&table);
configValues.values[KipConfigValue_t1_tRCD] = cust_get_tRCD(&table);
configValues.values[KipConfigValue_t2_tRP] = cust_get_tRP(&table);
configValues.values[KipConfigValue_t3_tRAS] = cust_get_tRAS(&table);
configValues.values[KipConfigValue_t4_tRRD] = cust_get_tRRD(&table);
configValues.values[KipConfigValue_t5_tRFC] = cust_get_tRFC(&table);
configValues.values[KipConfigValue_t6_tRTW] = cust_get_tRTW(&table);
configValues.values[KipConfigValue_t7_tWTR] = cust_get_tWTR(&table);
configValues.values[KipConfigValue_t8_tREFI] = cust_get_tREFI(&table);
configValues.values[KipConfigValue_mem_burst_read_latency] = cust_get_burst_read_lat(&table);
configValues.values[KipConfigValue_mem_burst_write_latency] = cust_get_burst_write_lat(&table);
configValues.values[KipConfigValue_eristaCpuUV] = cust_get_erista_cpu_uv(&table);
configValues.values[KipConfigValue_eristaCpuVmin] = cust_get_eristaCpuVmin(&table);
configValues.values[KipConfigValue_eristaCpuMaxVolt] = cust_get_erista_cpu_max_volt(&table);
configValues.values[KipConfigValue_eristaCpuUnlock] = cust_get_eristaCpuUnlock(&table);
configValues.values[KipConfigValue_marikoCpuUVLow] = cust_get_mariko_cpu_uv_low(&table);
configValues.values[KipConfigValue_marikoCpuUVHigh] = cust_get_mariko_cpu_uv_high(&table);
configValues.values[KipConfigValue_tableConf] = cust_get_table_conf(&table);
configValues.values[KipConfigValue_marikoCpuLowVmin] = cust_get_mariko_cpu_low_vmin(&table);
configValues.values[KipConfigValue_marikoCpuHighVmin] = cust_get_mariko_cpu_high_vmin(&table);
configValues.values[KipConfigValue_marikoCpuMaxVolt] = cust_get_mariko_cpu_max_volt(&table);
configValues.values[KipConfigValue_marikoCpuMaxClock] = cust_get_marikoCpuMaxClock(&table);
configValues.values[KipConfigValue_eristaCpuBoostClock] = cust_get_erista_cpu_boost(&table);
configValues.values[KipConfigValue_marikoCpuBoostClock] = cust_get_mariko_cpu_boost(&table);
configValues.values[KipConfigValue_eristaGpuUV] = cust_get_erista_gpu_uv(&table);
configValues.values[KipConfigValue_eristaGpuVmin] = cust_get_erista_gpu_vmin(&table);
configValues.values[KipConfigValue_marikoGpuUV] = cust_get_mariko_gpu_uv(&table);
configValues.values[KipConfigValue_marikoGpuVmin] = cust_get_mariko_gpu_vmin(&table);
configValues.values[KipConfigValue_marikoGpuVmax] = cust_get_mariko_gpu_vmax(&table);
configValues.values[KipConfigValue_commonGpuVoltOffset] = cust_get_common_gpu_offset(&table);
configValues.values[KipConfigValue_gpuSpeedo] = Board::getSpeedo(HorizonOCSpeedo_GPU); // cust_get_gpu_speedo(&table);
for (int i = 0; i < 24; i++) {
configValues.values[KipConfigValue_g_volt_76800 + i] = cust_get_mariko_gpu_volt(&table, i);
initialConfigValues[KipConfigValue_g_volt_76800 + i] = cust_get_mariko_gpu_volt(&table, i);
}
for (int i = 0; i < 27; i++) {
configValues.values[KipConfigValue_g_volt_e_76800 + i] = cust_get_erista_gpu_volt(&table, i);
initialConfigValues[KipConfigValue_g_volt_e_76800 + i] = cust_get_erista_gpu_volt(&table, i);
}
configValues.values[KipConfigValue_t7_tWTR_fine_tune] = cust_get_tWTR_fine_tune(&table);
configValues.values[KipConfigValue_t6_tRTW_fine_tune] = cust_get_tRTW_fine_tune(&table);
// if(cust_get_cust_rev(&table) == KIP_CUST_REV)
// return;
if (sizeof(SysClkConfigValueList) <= sizeof(configValues)) {
if (this->config->SetConfigValues(&configValues, false)) {
FileUtils::LogLine("[clock_manager] Successfully loaded KIP data into config");
} else {
FileUtils::LogLine("[clock_manager] Warning: Failed to set config values from KIP");
writeNotification("Horizon OC\nKip config set failed");
}
} else {
FileUtils::LogLine("[clock_manager] Error: Config value list buffer size mismatch");
writeNotification("Horizon OC\nConfig Buffer Mismatch");
}
} else {
FileUtils::LogLine("[clock_manager] Config refresh error in GetKipData!");
writeNotification("Horizon OC\nConfig refresh failed");
}
}