14 Commits

Author SHA1 Message Date
souldbminersmwc
1d56ed1504 hocclk: improve ui cohesiveness 2026-05-29 16:49:00 -04:00
souldbminersmwc
a8b43a650d hocclk: fix auto ram oc on erista 2026-05-29 16:21:52 -04:00
souldbminersmwc
aaa8ec1881 Update clock_manager.cpp 2026-05-29 16:17:01 -04:00
souldbminersmwc
bc6dd1a4f6 hocclk: fix compile error 2026-05-29 16:16:23 -04:00
souldbminersmwc
532a85b593 hocclk: fix some logic issues 2026-05-29 15:51:13 -04:00
souldbminersmwc
a18efcbed7 hocclk: fix gm20b driver bug at >1305mhz 2026-05-28 20:02:33 -04:00
souldbminersmwc
e52d57a961 Update kip.cpp 2026-05-28 19:50:27 -04:00
souldbminersmwc
6093cff721 hocclk: increase erista cpu min vmin to 750mV 2026-05-28 18:47:01 -04:00
souldbminersmwc
de62e8b33d hocclk: add lower auto ram oc freqs 2026-05-28 18:44:48 -04:00
souldbminersmwc
0d7608a4d5 hocclk: fix graph for erista 2026-05-28 18:43:16 -04:00
souldbminersmwc
397d96843b hocclk: make live cpu uv non experimental on erista 2026-05-28 16:44:19 -04:00
souldbminersmwc
fd6ceaaaf1 Merge branch 'main' of https://github.com/Horizon-OC/Horizon-OC 2026-05-28 16:36:24 -04:00
souldbminersmwc
a35a3b241b hocclk: fix erista live cpu uv0 2026-05-28 16:36:21 -04:00
Lightos1
072e9e4076 ldr: improved dvb tables by b3711
Co-Authored-By: halop <4215938+halop@users.noreply.github.com
2026-05-28 19:05:21 +02:00
10 changed files with 115 additions and 82 deletions

View File

@@ -3,6 +3,8 @@
*
* Copyright (c) 2023 hanai3Bi
*
* Copyright (c) B3711
*
* Copyright (c) Souldbminer, Lightos_ and Horizon OC Contributors
*
* This program is free software; you can redistribute it and/or modify it
@@ -591,7 +593,7 @@ namespace ams::ldr::hoc::pcv::erista {
/* The correct instructions will always be x0 since the mtcTable pointer is returned. */
u32 adrp = *(ptr + GoodAdrpOffset);
R_UNLESS(AsmCompareAdrpNoImm(adrp, MtcAdrpAsm), ldr::ResultInvalidMtcTablePattern());
/* Check for the branch instruction above the cbz to ensure we are patching the right location*/
u32 bl = *(ptr + GoodBlOffset);

View File

@@ -3,6 +3,8 @@
*
* Copyright (c) 2023 hanai3Bi
*
* Copyright (c) B3711
*
* Copyright (c) Souldbminer and Horizon OC Contributors
*
* This program is free software; you can redistribute it and/or modify it
@@ -50,11 +52,10 @@ namespace ams::ldr::hoc::pcv::mariko {
R_THROW(ldr::ResultInvalidGpuDvfs());
}
if(C.marikoGpuBootVolt) {
PATCH_OFFSET(ptr - 3, C.marikoGpuBootVolt);
if (C.marikoGpuBootVolt) {
PATCH_OFFSET(ptr - 3, C.marikoGpuBootVolt);
}
if (C.marikoGpuVmin) {
PATCH_OFFSET(ptr, C.marikoGpuVmin);
PATCH_OFFSET(ptr + 3, C.marikoGpuVmin);
@@ -864,7 +865,7 @@ namespace ams::ldr::hoc::pcv::mariko {
{ 3133000, { DVB(DvbVolt(1025, 1000, 975)) }, },
{ 3166000, { DVB(DvbVolt(1037, 1012, 987)) }, },
{ 3200000, { DVB(DvbVolt(1050, 1025, 1000)) }, },
{ ~0u, { }, },
{ ~0u, { }, },
};
#undef DVB
DvbEntry emcDvbTableOc[newEmcList.size()];

View File

@@ -304,7 +304,7 @@ public:
static constexpr struct { const char* label; int shift; } kAll[] = {
{"CPU", 0}, {"GPU", 8}, {"VRR", 16}
};
int count = configList.values[HocClkConfigValue_OverwriteRefreshRate] || this->context->isUsingRetroSuper ? 3 : 2;
int count = configList.values[HocClkConfigValue_OverwriteRefreshRate] || this->context->isUsingRetroSuper || this->context->profile == HocClkProfile_Docked ? 3 : 2;
for (int i = 0; i < count; i++) {
u8 cur = (this->profileList->mhzMap[this->profile][HocClkModule_Governor] >> kAll[i].shift) & 0xFF;

View File

@@ -57,11 +57,19 @@ BaseMenuGui::~BaseMenuGui() {
// Fast preDraw - just renders pre-computed strings
void BaseMenuGui::preDraw(tsl::gfx::Renderer* renderer) {
BaseGui::preDraw(renderer);
if(!this->context) [[unlikely]] return;
if (!this->context) [[unlikely]] {
this->context = new HocClkContext;
}
Result rc = hocclkIpcGetCurrentContext(this->context);
if (R_FAILED(rc)) [[unlikely]] {
FatalGui::openWithResultCode("hocclkIpcGetCurrentContext", rc);
return;
}
// All constants pre-calculated and cached
const char* labels[] = {
"App ID", "Profile", "CPU", "GPU", "MEM", "SoC", "Board", "Skin", "Now", "Avg", "BAT", "PMIC", "Fan", IsAula() ? "OLED" : "LCD", "FPS", "RES"
"App ID", "Profile", "CPU", "GPU", "MEM", "SoC", "Board", "Skin", "Now", "Avg", "BAT", "PMIC", "Fan", IsAula() || this->context->isUsingRetroSuper ? "OLED" : "LCD", "FPS", "RES"
};
static constexpr u32 dataPositions[6] = {63-3+3, 200-1, 344-1-3, 200-1, 342-1, 321-1};

View File

@@ -724,8 +724,8 @@ protected:
ValueThresholds thresholdsDisabled(0, 0);
if(IsMariko()) {
addConfigToggle(HocClkConfigValue_MarikoMiddleFreqs, nullptr, true);
addConfigToggle(HocClkConfigValue_LiveCpuUv, nullptr);
}
addConfigToggle(HocClkConfigValue_LiveCpuUv, nullptr);
std::vector<NamedValue> gpuSchedMethodValues = {
NamedValue("INI", GpuSchedulingOverrideMethod_Ini),
NamedValue("NV Service", GpuSchedulingOverrideMethod_NvService),
@@ -1745,16 +1745,16 @@ protected:
const tsl::Color cMerge = tsl::Color(5, 15, 4, 15);
const tsl::Color cAxis = tsl::Color(5, 5, 5, 15);
const s32 gx = x + 52;
const s32 gw = w - 64;
const s32 gx = x + (mariko ? 52 : 47);
const s32 gw = w - (mariko ? 64 : 59);
const s32 gy = y + 14;
const s32 gh = 54;
const s32 th = gh / 3;
const s32 axisY = gy + gh;
auto tierY = [&](int i) -> s32 { return gy + gh - i * th; };
// Fixed ruler: 1600 MHz (left) → 3300 MHz (right)
constexpr uint32_t kRMin = 1600000u, kRMax = 3300000u;
const uint32_t kRMin = 1600000u;
const uint32_t kRMax = mariko ? 3300000u : 2400000u;
auto freqX = [&](uint32_t kHz) -> s32 {
if (kHz <= kRMin) return gx;
if (kHz >= kRMax) return gx + gw;
@@ -1856,36 +1856,47 @@ protected:
{7,5,7,5,7}, // 8
{7,5,7,1,7}, // 9
};
const s32 pix = 2;
const s32 charH = 3 * pix;
const s32 charW = 5 * pix;
const s32 charGap = 1;
auto drawSidewaysMHz = [&](uint32_t mhz, s32 cx, s32 startY, const tsl::Color& c) {
auto drawSidewaysMHz = [&](uint32_t mhz, s32 cx, s32 startY, const tsl::Color& c, s32 pixSize) {
char buf[8];
snprintf(buf, sizeof(buf), "%u", mhz);
s32 originX = cx - charW / 2;
s32 cW = 5 * pixSize;
s32 cH = 3 * pixSize;
s32 originX = cx - cW / 2;
for (int ci = 0; buf[ci]; ci++) {
int d = buf[ci] - '0';
if (d < 0 || d > 9) continue;
s32 cy = startY + ci * (charH + charGap);
s32 cy = startY + ci * (cH + charGap);
for (int r = 0; r < 5; r++) {
for (int col = 0; col < 3; col++) {
if (!((kDigBmp[d][r] >> (2 - col)) & 1)) continue;
renderer->drawRect(originX + (4-r)*pix, cy + col*pix, pix, pix, c);
renderer->drawRect(originX + (4-r)*pixSize, cy + col*pixSize, pixSize, pixSize, c);
}
}
}
};
static const uint32_t kRulerMHz[] = {
1600, 1733, 1866, 2000, 2133, 2266,
2400, 2533, 2666, 2800, 2933, 3066, 3200, 3300,
};
for (uint32_t mhz : kRulerMHz) {
s32 fx = freqX(mhz * 1000u);
renderer->drawRect(fx, axisY, 1, 4, cAxis);
drawSidewaysMHz(mhz, fx, axisY + 6, cAxis);
if (mariko) {
static const uint32_t kRulerMHz[] = {
1600, 1733, 1866, 2000, 2133, 2266,
2400, 2533, 2666, 2800, 2933, 3066, 3200, 3300,
};
for (uint32_t mhz : kRulerMHz) {
s32 fx = freqX(mhz * 1000u);
renderer->drawRect(fx, axisY, 1, 4, cAxis);
drawSidewaysMHz(mhz, fx, axisY + 6, cAxis, 2);
}
} else {
static const uint32_t kEristaRulerMHz[] = {
1600, 1666, 1733, 1800, 1866, 1933,
2000, 2066, 2133, 2200, 2266, 2333, 2400,
};
for (uint32_t mhz : kEristaRulerMHz) {
s32 fx = freqX(mhz * 1000u);
renderer->drawRect(fx, axisY, 1, 4, cAxis);
drawSidewaysMHz(mhz, fx, axisY + 6, cAxis, 2);
}
}
// Breakpoint dots
@@ -2038,6 +2049,10 @@ protected:
NamedValue("2703 MHz", 2703000),
};
std::vector<NamedValue> ClkOptionsRamOc = {
NamedValue("1122 MHz", 1122000),
NamedValue("1224 MHz", 1224000),
NamedValue("1326 MHz", 1326000),
NamedValue("1428 MHz", 1428000),
NamedValue("1581 MHz", 1581000),
NamedValue("1683 MHz", 1683000),
NamedValue("1785 MHz", 1785000),
@@ -2150,7 +2165,7 @@ protected:
addConfigButton(
KipConfigValue_eristaCpuVmin,
"CPU VMIN",
ValueRange(700, 900, 25, "mV", 1),
ValueRange(750, 900, 25, "mV", 1),
"CPU VMIN",
&thresholdsDisabled,
{},
@@ -2214,7 +2229,7 @@ protected:
);
}
addConfigToggle(HocClkConfigValue_OverwriteBoostMode, nullptr);
addConfigToggle(HocClkConfigValue_LiveCpuUv, nullptr);
}
};

View File

@@ -43,8 +43,12 @@
#include "../soc/gm20b.hpp"
#include "../file/config.hpp"
namespace board {
#define MIDDLE_FREQ_TABLE_START_POINT 1228800000
static u32 currentInjectedHz = 0;
static u32 gMarikoGm20bCutoff = 1228800000;
void SetMarikoGm20bCutoff(u32 hz) {
gMarikoGm20bCutoff = hz;
}
PcvModule GetPcvModule(HocClkModule hocclkModule) {
switch (hocclkModule) {
case HocClkModule_CPU:
@@ -97,7 +101,7 @@ namespace board {
return;
}
bool useGm20b = (module == HocClkModule_GPU) && (GetSocType() == HocClkSocType_Mariko) && (hz % 38400000 == 0) && (hz % 76800000 != 0) && hz < MIDDLE_FREQ_TABLE_START_POINT;
bool useGm20b = (module == HocClkModule_GPU) && (GetSocType() == HocClkSocType_Mariko) && (hz % 38400000 == 0) && (hz % 76800000 != 0) && hz < gMarikoGm20bCutoff;
u32 pcvHz = useGm20b ? ((hz + 76800000 - 1) / 76800000) * 76800000 : hz;

View File

@@ -39,6 +39,7 @@
namespace board {
void SetHz(HocClkModule module, u32 hz);
void SetMarikoGm20bCutoff(u32 hz);
u32 GetHz(HocClkModule module);
u32 GetRealHz(HocClkModule module);

View File

@@ -50,8 +50,17 @@ namespace board {
u32 tune1_high;
};
EristaCpuUvEntry eristaCpuUvTable[6] = {
{0xFFEAD0FF, 0x0},
EristaCpuUvEntry eristaCpuUvTableLowBracket[6] = { // <2118 CPU speedo
{0xFFEAD0FF, 0x25501d0},
{0xffff, 0x27007ff},
{0xefff, 0x27407ff},
{0xdfff, 0x27807ff},
{0xdfdf, 0x27a07ff},
{0xcfdf, 0x37007ff},
};
EristaCpuUvEntry eristaCpuUvTableHighBracket[6] = {
{0xFFEAD0FF, 0x20091d9},
{0xffff, 0x27007ff},
{0xefff, 0x27407ff},
{0xdfff, 0x27807ff},
@@ -97,10 +106,6 @@ namespace board {
if (GetSocType() == HocClkSocType_Erista) {
cachedTune.tune0Low = *reinterpret_cast<u32 *>(cldvfs + CL_DVFS_TUNE0_0);
cachedTune.tune1Low = *reinterpret_cast<u32 *>(cldvfs + CL_DVFS_TUNE1_0);
} else {
SetHz(HocClkModule_CPU, 1785000000);
cachedTune.tune0High = *reinterpret_cast<u32 *>(cldvfs + CL_DVFS_TUNE0_0);
ResetToStockCpu();
}
}
@@ -108,6 +113,7 @@ namespace board {
void SetDfllTunings(u32 levelLow, u32 levelHigh, u32 tbreakPoint) {
u32* tune0_ptr = reinterpret_cast<u32 *>(cldvfs + CL_DVFS_TUNE0_0);
u32* tune1_ptr = reinterpret_cast<u32 *>(cldvfs + CL_DVFS_TUNE1_0);
if (GetSocType() == HocClkSocType_Mariko) {
if (GetHz(HocClkModule_CPU) < tbreakPoint && (levelLow || levelHigh)) {
if (levelLow) {
@@ -136,16 +142,8 @@ namespace board {
return;
}
} else {
// if (GetHz(HocClkModule_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].tune0;
*tune1_ptr = eristaCpuUvTable[levelLow].tune1;
// } else {
// }
*tune0_ptr = fuseData.cpuSpeedo > 2118 ? eristaCpuUvTableHighBracket[levelLow].tune0 : eristaCpuUvTableLowBracket[levelLow].tune0;
*tune1_ptr = fuseData.cpuSpeedo > 2118 ? eristaCpuUvTableHighBracket[levelLow].tune1 : eristaCpuUvTableLowBracket[levelLow].tune1;
}
}

View File

@@ -316,6 +316,11 @@ namespace kip {
// add marikoGpuBootVolt with default value of 800mV
configValues.values[KipConfigValue_marikoGpuBootVolt] = 800;
// Raise min cpu vmin
if(configValues.values[KipConfigValue_eristaCpuVmin] < 750) {
configValues.values[KipConfigValue_eristaCpuVmin] = 750;
}
// delete handheld TDP config entries
config::DeleteKey(CONFIG_VAL_SECTION, "handheld_tdp");
config::DeleteKey(CONFIG_VAL_SECTION, "tdp_limit");

View File

@@ -182,27 +182,28 @@ namespace clockManager {
std::uint32_t *hz = &gFreqTable[module].list[0];
gFreqTable[module].count = 0;
if (module == HocClkModule_GPU && board::GetSocType() == HocClkSocType_Mariko && config::GetConfigValue(HocClkConfigValue_MarikoMiddleFreqs)) {
constexpr u32 kStep = 38400000;
if (module == HocClkModule_GPU && board::GetSocType() == HocClkSocType_Mariko
&& config::GetConfigValue(HocClkConfigValue_MarikoMiddleFreqs)) {
constexpr u32 kStep = 38400000;
constexpr u32 kPcvStep = 76800000;
u32 kMax = 0;
u32 kMax = ~0;
for (u32 i = 0; i < count; i++) {
for (u32 j = 0; j < count; j++) {
if (freqs[j] == freqs[i] + kStep) {
kMax = freqs[j];
if (freqs[j] + kStep == freqs[i]) {
if (freqs[j] < kMax) kMax = freqs[j];
break;
}
}
}
if (kMax == 0) {
if (kMax == ~0u) {
kMax = 0;
for (u32 i = 0; i < count; i++) {
if (freqs[i] > kMax)
kMax = freqs[i];
if (freqs[i] > kMax) kMax = freqs[i];
}
}
board::SetMarikoGm20bCutoff(kMax);
for (u32 f = kPcvStep; f <= kMax && gFreqTable[module].count < HOCCLK_FREQ_LIST_MAX; f += kStep) {
if (f % kPcvStep != 0) {
*hz = f;
@@ -230,6 +231,8 @@ namespace clockManager {
return;
}
board::SetMarikoGm20bCutoff(0);
for (std::uint32_t i = 0; i < count; i++) {
if (!IsAssignableHz(module, freqs[i])) {
continue;
@@ -291,12 +294,29 @@ namespace clockManager {
fileUtils::LogLine("[mgr] count = %u", gFreqTable[module].count);
}
bool HandleSafetyFeatures()
bool HandleSafetyFeatures(bool isBoost)
{
if (((tmp451TempSoc() / 1000) > (int)config::GetConfigValue(HocClkConfigValue_ThermalThrottleThreshold)) && config::GetConfigValue(HocClkConfigValue_ThermalThrottle)) {
ResetToStockClocks();
return true;
}
if (config::GetConfigValue(HocClkConfigValue_AutoRAMCPUOverclock) && !isBoost && !governor::isCpuGovernorEnabled && (board::GetSocType() == HocClkSocType_Mariko)) {
u32 ramHz = gContext.freqs[HocClkModule_MEM];
u32 threshold = (u32)config::GetConfigValue(HocClkConfigValue_AutoRamCpuRamOCThreshold) * 1000;
if (ramHz >= threshold) {
u32 cpuOverrideHz = (u32)config::GetConfigValue(HocClkConfigValue_AutoRamCpuCpuOCFreq) * 1000;
if (cpuOverrideHz <= gContext.freqs[HocClkModule_CPU])
return false;
u32 maxHz = GetMaxAllowedHz(HocClkModule_CPU, gContext.profile);
u32 nearestHz = GetNearestHz(HocClkModule_CPU, cpuOverrideHz, maxHz);
board::SetHz(HocClkModule_CPU, nearestHz);
gContext.freqs[HocClkModule_CPU] = nearestHz;
if (HocClkModule_CPU < HocClkModuleStable_EnumMax)
gContext.stable.freqs[HocClkModule_CPU] = nearestHz;
return true;
}
}
return false;
}
void HandleMiscFeatures()
@@ -506,27 +526,6 @@ namespace clockManager {
HandleFreqReset((HocClkModule)module, isBoost, didHijackPcv);
}
}
if (config::GetConfigValue(HocClkConfigValue_AutoRAMCPUOverclock) && !skipCpuDueToBoost && !governor::isCpuGovernorEnabled) {
u32 ramHz = gContext.freqs[HocClkModule_MEM];
u32 threshold = (u32)config::GetConfigValue(HocClkConfigValue_AutoRamCpuRamOCThreshold) * 1000;
if (ramHz >= threshold) {
u32 cpuOverrideHz = (u32)config::GetConfigValue(HocClkConfigValue_AutoRamCpuCpuOCFreq) * 1000;
if (cpuOverrideHz <= gContext.freqs[HocClkModule_CPU])
return;
maxHz = GetMaxAllowedHz(HocClkModule_CPU, gContext.profile);
nearestHz = GetNearestHz(HocClkModule_CPU, cpuOverrideHz, maxHz);
fileUtils::LogLine(
"[mgr] AutoRAMCPUOC CPU clock set : %u.%u MHz (ram = %u.%u MHz)",
nearestHz / 1000000, nearestHz / 100000 - nearestHz / 1000000 * 10,
ramHz / 1000000, ramHz / 100000 - ramHz / 1000000 * 10
);
board::SetHz(HocClkModule_CPU, nearestHz);
gContext.freqs[HocClkModule_CPU] = nearestHz;
if (HocClkModule_CPU < HocClkModuleStable_EnumMax)
gContext.stable.freqs[HocClkModule_CPU] = nearestHz;
}
}
}
bool RefreshContext()
@@ -771,7 +770,7 @@ namespace clockManager {
bool isBoost = apmExtIsBoostMode(mode);
bool shouldSkipClockSet = HandleSafetyFeatures();
bool shouldSkipClockSet = HandleSafetyFeatures(isBoost);
HandleMiscFeatures();
// GPU clock should always be the same unless PCV has overwriten our change, so reset it