57 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
souldbminersmwc
3af3ad4a68 hocclk: fix clock reset bug 2026-05-27 20:51:44 -04:00
souldbminersmwc
d1308e0251 hocclk: add auto cpu ram oc 2026-05-27 19:32:56 -04:00
souldbminersmwc
e48cab36b7 hocclk: remove handheld TDP 2026-05-27 16:21:56 -04:00
souldbminersmwc
b2ba7354cd Update base_gui.cpp 2026-05-27 16:12:43 -04:00
souldbminersmwc
4f0e890e01 hocclk: fix pcv patch 38.4mhz clock bug 2026-05-27 15:59:05 -04:00
souldbminersmwc
86a2800e6e hocclk: fix compile error 2026-05-26 20:35:51 -04:00
souldbminersmwc
13550fbc20 hocclk: improve DVFS curve 2026-05-26 20:35:07 -04:00
souldbminersmwc
187d6d6422 Update board_volt.cpp 2026-05-26 19:51:04 -04:00
Souldbminer
060178aea6 Merge pull request #85 from Horizon-OC/erista-dvfs
WIP Erista dvfs
2026-05-26 19:50:31 -04:00
souldbminersmwc
715577a644 Update board_volt.cpp 2026-05-26 19:50:09 -04:00
souldbminersmwc
45332444ec wip erista dvfs 2026-05-26 19:44:46 -04:00
souldbminersmwc
fd3808fd82 Update misc_gui.cpp 2026-05-26 19:19:17 -04:00
souldbminersmwc
e13e2b1f41 hocclk: improve logo position 2026-05-26 19:15:07 -04:00
souldbminersmwc
6b26aa5574 hocclk: improve ui
yes i did vibecode this, no i don't care
2026-05-26 19:05:53 -04:00
souldbminersmwc
13f422fa29 hocclk: overlay logo 2026-05-26 16:10:13 -04:00
souldbminersmwc
fa66a09b04 hocclk: add timing tbreak graph 2026-05-25 16:00:23 -04:00
souldbminersmwc
5d9c7acc52 hocclk: add latency graph 2026-05-25 15:52:53 -04:00
souldbminersmwc
52076a0191 reapply erista mrf changes 2026-05-25 15:18:36 -04:00
Souldbminer
08936d9466 Merge pull request #84 from Horizon-OC/erista-mrf-shit
erista mrf
2026-05-25 15:02:40 -04:00
souldbminersmwc
45ed9afb04 Merge remote-tracking branch 'origin/main' into erista-mrf-shit 2026-05-25 15:01:52 -04:00
souldbminersmwc
1358b10616 hocclk: lower default 2026-05-25 14:55:52 -04:00
souldbminersmwc
e9f5f59ddf ldr: add some comments 2026-05-25 13:28:58 -04:00
souldbminersmwc
67be6d9120 ldr: fix patch 2026-05-25 13:18:32 -04:00
Lightos1
749fd385ce revert erista mrf changes 2026-05-24 21:30:05 +02:00
Lightos1
65927cffce Revert "Update misc_gui.cpp"
This reverts commit fae0fa5d5f.
2026-05-24 21:21:00 +02:00
souldbminersmwc
10bcf4542d hocclk: fix safety features 2026-05-24 12:34:37 -04:00
Lightos1
8bc1aee110 add back comment 2026-05-24 16:46:28 +02:00
Lightos1
ca4b132f25 add initial garbage erista shit 2026-05-24 16:45:31 +02:00
souldbminersmwc
afeee4937c Update horizon-oc-overlay.ovl 2026-05-23 20:09:35 -04:00
souldbminersmwc
66308b152b hocclk: kip migration 2026-05-23 20:07:28 -04:00
souldbminersmwc
72dfdb53fc hocclk: fix small issue 2026-05-23 19:45:47 -04:00
souldbminersmwc
ee730ca68e all: add mariko gpu boot voltage patch 2026-05-23 19:43:54 -04:00
souldbminersmwc
2d0a2c4f6d hocclk: fix edge case with middle freqs 2026-05-23 16:40:04 -04:00
souldbminersmwc
8411a14b26 hocclk: fix ui issue 2026-05-22 17:50:36 -04:00
souldbminersmwc
99e9270314 hocclk: add erista gpu workaround 2026-05-22 17:48:21 -04:00
souldbminersmwc
58488f7f48 chore: add no exosphere build scripts 2026-05-22 17:40:49 -04:00
souldbminersmwc
c2238eb070 hocclk: perfect migration between kip versions 2026-05-22 16:48:48 -04:00
souldbminersmwc
4271efb4a7 hocclk/ldr: add kip migration skeleton 2026-05-22 16:35:56 -04:00
souldbminersmwc
fd9e5a2e08 add more docs and warnings 2026-05-22 16:16:06 -04:00
souldbminersmwc
4587b01152 hocclk: minor configurator changes 2026-05-22 16:13:16 -04:00
souldbminersmwc
fae0fa5d5f Update misc_gui.cpp 2026-05-22 16:10:18 -04:00
souldbminersmwc
059fe40339 hocclk: update configurator for new features 2026-05-22 16:10:12 -04:00
Lightos1
a617a7398a Implement Mariko-style MRF for erista
There is heavy code duplication because I'm lazy, but loader needs to be
refactored anyway at some point and this "works" for now.
2026-05-22 21:57:32 +02:00
50 changed files with 1439 additions and 569 deletions

View File

@@ -35,10 +35,8 @@ volatile CustomizeTable C = {
/* Disables RAM powerdown */
.hpMode = DISABLED,
.commonEmcMemVolt = 1175000, /* LPDDR4(X) JEDEC Specification */
.eristaEmcMaxClock = 1600000, /* Maximum HB-MGCH ram rating */
.eristaEmcMaxClock1 = 1600000,
.eristaEmcMaxClock2 = 1600000,
.commonEmcMemVolt = 1175000, /* LPDDR4(X) JEDEC Specification */
.eristaEmcMaxClock = 1600000, /* Maximum HB-MGCH ram rating */
/* Available: 66MHz step rate, 100MHz step rate, 133MHz step rate and jedec. */
/* Jedec freqs are 1333MHz, 1600MHz, 1866MHz, 2133MHz, 2400MHz, 2666MHz, 2933MHz, 3200MHz. */
@@ -84,24 +82,6 @@ volatile CustomizeTable C = {
/* 2133 */ 0,
},
/* You can mix and match different latencies if needed */
/*
* Read:
* 2133RL = 40
* 1866RL = 36
* 1600RL = 32
* 1331RL = 28
* Write:
* 2133WL = 18
* 1866WL = 16
* 1600WL = 14
* 1331WL = 12
*/
/* Erista only. */
.mem_burst_read_latency = RL_1600,
.mem_burst_write_latency = WL_1600,
.eristaCpuUV = 0,
.eristaCpuVmin = 800,
.eristaCpuMaxVolt = 1200,
@@ -134,15 +114,13 @@ volatile CustomizeTable C = {
.eristaGpuVmin = 810,
.marikoGpuUV = 0,
/* Vmin past 795mV won't work due boot voltage being 800mV. */
/* Vmin past 795mV won't work due boot voltage being 800mV (can be adjusted though). */
.marikoGpuVmin = 610,
.marikoGpuBootVolt = 800, /* Used during boot and when temp is <20°C */
.marikoGpuVmax = 800,
.commonGpuVoltOffset = 0,
/* Speedo is automatically set by hoc-clk on first boot */
.gpuSpeedo = 1450,
/* Setting DEACTIVATED_GPU_FREQ on any freq will disable it and all freqs greater than it. (the latter is a bug :/) */
/* AUTO: Voltage is optimally chosen; with commonGpuVoltOffset applied. */
/* AUTO only works up to 1305 GPU on Mariko and 998 GPU on Erista (it is reccomended to manually set your 998MHz voltage though) */

View File

@@ -20,8 +20,8 @@
#pragma once
#define CUST_REV 3
#define KIP_VERSION 231
#define CUST_REV 4
#define KIP_VERSION 240
#include "oc_common.hpp"
#include "pcv/pcv_common.hpp"
@@ -70,8 +70,6 @@ struct CustomizeTable {
u32 commonEmcMemVolt;
u32 eristaEmcMaxClock;
u32 eristaEmcMaxClock1;
u32 eristaEmcMaxClock2;
StepMode stepMode;
u32 marikoEmcMaxClock;
@@ -97,9 +95,6 @@ struct CustomizeTable {
u32 readLatency[4];
u32 writeLatency[4];
u32 mem_burst_read_latency;
u32 mem_burst_write_latency;
u32 eristaCpuUV;
u32 eristaCpuVmin;
u32 eristaCpuMaxVolt;
@@ -121,12 +116,11 @@ struct CustomizeTable {
u32 marikoGpuUV;
u32 marikoGpuVmin;
u32 marikoGpuBootVolt;
u32 marikoGpuVmax;
u32 commonGpuVoltOffset;
u32 gpuSpeedo;
u32 eristaGpuVoltArray[27];
u32 marikoGpuVoltArray[24];

View File

@@ -18,8 +18,80 @@
namespace ams::ldr::hoc::pcv::erista {
void CalculateTimings(double tCK_avg) {
tR2W = FLOOR(FLOOR((5.0 / tCK_avg) + ((FLOOR(48.0 / WL) - 0.478) * 3.0)) / 1.501) + RL - (C.t6_tRTW * 3) + finetRTW;
void SwitchLatency(volatile u32 &latency, u32 index, u32 latencyStep) {
latency += index * latencyStep;
}
static s32 GetMaxLatencyIndex(volatile u32 *latencyArray, u32 latencySize) {
s32 maxIndex = -1;
for (u32 i = 0; i < latencySize; ++i) {
if (latencyArray[i]) {
maxIndex = i;
}
}
return maxIndex;
}
void AutoLatency(volatile u32 &latency, u32 freq, u32 latencyStep) {
if (freq > 1600'000 && freq <= 1866'000) { /* 1866tRWL */
latency += latencyStep * 2;
} else { /* 2133tRWL */
latency += latencyStep * 3;
}
}
void HandleLatency(u32 freq, volatile u32 &latency, volatile u32 *latencyArray, u32 indexMax, u32 latencyStep) {
for (u32 i = 0; i <= indexMax; ++i) {
if (latencyArray[i] != 0 && freq <= latencyArray[i]) {
SwitchLatency(latency, i, latencyStep);
return;
}
}
SwitchLatency(latency, indexMax, latencyStep);
}
void HandleLatency(u32 freq) {
static s32 rlIndexMax = GetMaxLatencyIndex(C.readLatency, std::size(C.readLatency));
static s32 wlIndexMax = GetMaxLatencyIndex(C.writeLatency, std::size(C.writeLatency));
constexpr u32 ReadLatencyStep = 4;
constexpr u32 WriteLatencyStep = 2;
bool autoLatencyRead = false, autoLatencyWrite = false;
if (rlIndexMax == -1) {
AutoLatency(RL, freq, ReadLatencyStep);
autoLatencyRead = true;
}
if (wlIndexMax == -1) {
AutoLatency(WL, freq, WriteLatencyStep);
autoLatencyWrite = true;
}
if (autoLatencyRead && autoLatencyWrite) {
return;
}
if (!autoLatencyRead) {
HandleLatency(freq, RL, C.readLatency, rlIndexMax, ReadLatencyStep);
}
if (!autoLatencyWrite) {
HandleLatency(freq, WL, C.writeLatency, wlIndexMax, WriteLatencyStep);
}
}
void CalculateTimings(double tCK_avg, u32 freq) {
RL = RL_1331;
WL = WL_1331;
HandleLatency(freq);
tR2P = CEIL((RL * 0.426) - 2.0);
tR2W = FLOOR(FLOOR((5.0 / tCK_avg) + ((FLOOR(48.0 / WL) - 0.478) * 3.0)) / 1.501) + RL - (C.t6_tRTW * 3) + finetRTW;
tW2P = (CEIL(WL * 1.7303) * 2) - 5;
tWTPDEN = CEIL(((1.803 / tCK_avg) + MAX(RL + (2.694 / tCK_avg), static_cast<double>(tW2P))) + (BL / 2));
tW2R = FLOOR(MAX((5.020 / tCK_avg) + 1.130, WL - MAX(-CEIL(0.258 * (WL - RL)), 1.964)) * 1.964) + WL - CEIL(tWTR / tCK_avg) + finetWTR;

View File

@@ -18,6 +18,6 @@
namespace ams::ldr::hoc::pcv::erista {
void CalculateTimings(double tCK_avg);
void CalculateTimings(double tCK_avg, u32 freq);
}

View File

@@ -46,7 +46,7 @@ namespace ams::ldr::hoc::pcv::mariko {
}
void AutoLatency(volatile u32 &latency, u32 freq, u32 latencyStep) {
if (freq > 1600'000 && freq <= 1866'000) { /* 1866tRWL */
if (freq > 1600'000 && freq <= 1862'400) { /* 1866tRWL */
latency += latencyStep * 2;
} else { /* 2133tRWL */
latency += latencyStep * 3;

View File

@@ -33,10 +33,6 @@ namespace ams::ldr::hoc {
/* Burst latency, not to be confused with base latency (tWRL). */
const u32 BL = 16;
/* Base latency for read and write (tWRL). */
const u32 RL = C.mem_burst_read_latency;
const u32 WL = C.mem_burst_write_latency;
/* Precharge to Precharge Delay. (tCK) */
const u32 tPPD = 4;
@@ -87,11 +83,14 @@ namespace ams::ldr::hoc {
const u32 tFAW = static_cast<u32>(tRRD * 4.0);
const double tRPab = tRPpb + 3;
const u32 tR2P = CEIL((RL * 0.426) - 2.0);
inline u32 RL;
inline u32 WL;
inline u32 tR2P;
inline u32 tR2W;
inline u32 rext;
const u32 tW2P = (CEIL(WL * 1.7303) * 2) - 5;
inline u32 tW2P;
inline u32 tWTPDEN;
inline u32 tW2R;

View File

@@ -147,7 +147,7 @@ namespace ams::ldr::hoc::pcv {
{ eristaCpuDvfsMaxFreq, 1785'000, 2397'000, panic::Cpu, },
{ marikoCpuDvfsMaxFreq, 1785'000, 2703'000, panic::Cpu, },
{ C.commonEmcMemVolt, 912'500, 1350'000, panic::Emc, }, /* Official vmax for the RAMs is 1400-1500mV */
{ GET_MAX_OF_ARR(erista::maxEmcClocks), 1600'000, 2600'000, panic::Emc, },
{ C.eristaEmcMaxClock, 1600'000, 2600'000, panic::Emc, },
{ C.marikoEmcMaxClock, 1600'000, 3500'000, panic::Emc, },
{ C.marikoEmcVddqVolt, 400'000, 750'000, panic::Emc, },
{ C.marikoSocVmax, 1000, 1200, panic::Emc, },

View File

@@ -24,7 +24,7 @@
namespace ams::ldr::hoc::pcv {
constexpr u32 NopIns = 0x1f2003d5;
constexpr u32 NopIns = 0xD503201F;
template <typename Compare>
u32 *ScanAssembly(u32 *ptr, u32 scanLimit, u32 pattern, Compare comp) {
@@ -76,6 +76,30 @@ namespace ams::ldr::hoc::pcv {
SF | Op | S | | RM | Cond | 0 | 0 | Rn | Rd
31 | 30 | 29 | 28 27 26 25 24 23 | 20 19 18 17 16 | 15 14 13 12 | 11 | 10 | 9 8 7 6 5 | 4 3 2 1 0
*/
inline auto AsmCbzCompareOpcodeOnly = [](u32 ins1, u32 ins2) {
return ((ins1 ^ ins2) >> 24) == 0;
};
inline auto AsmBlCompareOpcodeOnly = [](u32 ins1, u32 ins2) {
return ((ins1 ^ ins2) >> 26) == 0;
};
inline bool AsmComparePrologue(u32 ins1, u32 ins2, u32 ins3, u32 cmp1, u32 cmp2, u32 cmp3) {
constexpr u32 StpImmMask = ~((((1u << 7) - 1u) << 15));
bool firstMatch = (ins1 & StpImmMask) == (cmp1 & StpImmMask);
constexpr u32 StpRegsImmMask = ~(((1u << 5) - 1u) |(((1u << 5) - 1u) << 10) | (((1u << 7) - 1u) << 15));
bool secondMatch = (ins2 & StpRegsImmMask) == (cmp2 & StpRegsImmMask);
constexpr u32 MovMask = ~((1u << 5) - 1u);
bool thirdMatch = (ins3 & MovMask) == (cmp3 & MovMask);
return firstMatch && secondMatch && thirdMatch;
}
inline auto AsmCompareCselNoReg = [](u32 ins1, u32 ins2) {
constexpr u32 ClearReg = ~(((1 << 10) - 1) | (((1 << 5) - 1) << 16));
return ((ins1 & ClearReg) ^ (ins2 & ClearReg)) == 0;

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
@@ -18,6 +20,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <vector>
#include "pcv.hpp"
#include "../mtc_timing_value.hpp"
#include "../erista/calculate_timings_erista.hpp"
@@ -215,7 +218,7 @@ namespace ams::ldr::hoc::pcv::erista {
const u32 dyn_self_ref_control = (static_cast<u32>(7605.0 / tCK_avg) + 260) | (table->burst_regs.emc_dyn_self_ref_control & 0xffff0000);
CalculateTimings(tCK_avg);
CalculateTimings(tCK_avg, table->rate_khz);
WRITE_PARAM_ALL_REG(table, emc_rd_rcd, GET_CYCLE_CEIL(tRCD));
WRITE_PARAM_ALL_REG(table, emc_wr_rcd, GET_CYCLE_CEIL(tRCD));
@@ -360,65 +363,176 @@ namespace ams::ldr::hoc::pcv::erista {
table->min_volt = std::clamp(900 + (C.emcDvbShift * 25), 900, 1050);
}
/* Probably more intuitive to point to 40800 rather than 1600000, but oh well. */
Result MemFreqMtcTable(u32 *ptr) {
u32 khz_list[] = { 40800, 68000, 102000, 204000, 408000, 665600, 800000, 1065600, 1331200, 1600000 };
std::sort(maxEmcClocks, maxEmcClocks + std::size(maxEmcClocks));
u32 khz_list_size = std::size(khz_list);
namespace {
std::vector<u32> newEmcList;
u32 *nsoStart;
}
// Generate list for mtc table pointers
EristaMtcTable *table_list[khz_list_size];
for (u32 i = 0; i < khz_list_size; i++) {
u32 mtcIndex = khz_list_size - 1 - i;
u8 *table = reinterpret_cast<u8 *>(ptr) - offsetof(EristaMtcTable, rate_khz) - i * sizeof(EristaMtcTable);
table_list[mtcIndex] = reinterpret_cast<EristaMtcTable *>(table);
R_UNLESS(table_list[mtcIndex]->rate_khz == khz_list[mtcIndex], ldr::ResultInvalidMtcTable());
R_UNLESS(table_list[mtcIndex]->rev == MTC_TABLE_REV, ldr::ResultInvalidMtcTable());
/* The silicon instructs; the children obey... */
void MtcGenerateFreqTables() {
newEmcList.clear();
newEmcList.reserve(DvfsTableEntryCount);
newEmcList.insert(newEmcList.end(), std::begin(EmcListDefault), std::end(EmcListDefault));
if (C.eristaEmcMaxClock <= EmcClkOSLimit) {
return;
}
if (GET_MAX_OF_ARR(maxEmcClocks) <= EmcClkOSLimit) {
/* This is scuffed, but Eristas step rate is... weird? */
/* 1766MHz seems to cause crashes with other freqs near it... why is anyones guess... */
u32 freqsLow[] = { 1633000, 1666000, 1700000, 1733000, 1800000, 1833000, 1862400, };
constexpr size_t freqsLowSize = std::size(freqsLow);
for (size_t i = 0; i < freqsLowSize; ++i) {
if (freqsLow[i] <= C.eristaEmcMaxClock) {
newEmcList.push_back(freqsLow[i]);
} else {
break;
}
}
if (C.eristaEmcMaxClock <= freqsLow[freqsLowSize - 1]) {
return;
}
/* High range. */
constexpr u32 StepRate = 38400;
while (newEmcList.back() + StepRate < C.eristaEmcMaxClock) {
newEmcList.push_back(newEmcList.back() + StepRate);
}
if (newEmcList.back() != C.eristaEmcMaxClock) {
newEmcList.push_back(static_cast<u32>(C.eristaEmcMaxClock));
}
constexpr u32 PllmToggleFrequency = 19200;
/* A step of 19.2khz will cause hangs, crashes and other weirdness. */
/* Why? ¯\_(ツ)_/¯ */
if (C.eristaEmcMaxClock - newEmcList[newEmcList.size() - 2] <= PllmToggleFrequency) {
newEmcList.erase(newEmcList.begin() + newEmcList.size() - 2);
}
newEmcList.resize(std::min(newEmcList.size(), DvfsTableEntryLimit));
}
/* TODO: Template this */
Result VerifyMtcTable(EristaMtcTable *tableStart, u32 expectedFreq) {
R_UNLESS(tableStart->rate_khz == expectedFreq, ldr::ResultInvalidMtcTable());
R_UNLESS(tableStart->rev == MTC_TABLE_REV, ldr::ResultInvalidMtcTable());
R_SUCCEED();
}
/* TODO: Template this */
Result MtcValidateAllTables(EristaMtcTable *tableStart, const u32 *validationList, u32 tableCount) {
for (u32 i = 0; i < tableCount; ++i) {
R_TRY(VerifyMtcTable(&tableStart[i], validationList[i]));
}
R_SUCCEED();
}
/* TODO: Put this into common. */
DramId GetDramId() {
u64 id64;
splGetConfig(SplConfigItem_DramId, &id64);
return static_cast<DramId>(id64);
}
MtcTableIndex GetMtcDramIndex(DramId dramId) {
for (u32 i = 0; i < std::size(mtcIndexTable); ++i) {
if (mtcIndexTable[i].dramId == dramId) {
return mtcIndexTable[i].index;
}
}
return MtcTableIndex_Invalid;
}
NORETURN void AbortInvalidMtc(const char *crashMsg) {
panic::SmcError(panic::Emc);
CRASH(crashMsg);
}
u32 GetMtcOffset(MtcTableIndex index) {
if (index < T210SdevEmcDvfsTableS6gb01) {
return index * erista::MtcFullTableSize;
}
/* Account for the weird in between mariko table. */
return index * erista::MtcFullTableSize + mariko::MtcFullTableSize;
}
void PrepareMtcMemoryRegion(u8 *firstTable, EristaMtcTable *usedTable) {
memmove(firstTable, usedTable, erista::MtcFullTableSize);
/* Clear all other tables. */
/* The used table is excluded. */
constexpr size_t RemainingRegionSize = (mariko::MtcFullTableSize) * (mariko::MtcFullTableCount) + (erista::MtcFullTableSize * (erista::MtcFullTableCount - 1));
memset(firstTable + erista::MtcFullTableSize, 0, RemainingRegionSize);
}
void MtcExtendTables(EristaMtcTable *table) {
for (u32 i = erista::MtcTableCountDefault; i < newEmcList.size(); ++i) {
std::memcpy(&table[i], &table[i - 1], sizeof(EristaMtcTable));
table[i].rate_khz = newEmcList[i];
}
}
Result MemFreqMtcTable(u32 *ptr) {
static const DramId dramId = [] {
DramId id = GetDramId();
return id;
}();
static const MtcTableIndex mtcIndex = [] {
MtcTableIndex idx = GetMtcDramIndex(dramId);
/* If for some reason this happens, there is no chance of recovering this. */
if (idx == MtcTableIndex_Invalid) {
AbortInvalidMtc("Invalid dramId");
}
return idx;
}();
static const u32 mtcOffset = GetMtcOffset(mtcIndex);
constexpr u32 StartAdjustment = offsetof(EristaMtcTable, rate_khz) + sizeof(EristaMtcTable) * (erista::MtcTableCountDefault - 1);
u8 *startPtr = reinterpret_cast<u8 *>(ptr) - StartAdjustment;
EristaMtcTable *table = reinterpret_cast<EristaMtcTable *>(startPtr + mtcOffset);
R_TRY(MtcValidateAllTables(table, EmcListDefault, EmcListSizeDefault));
PrepareMtcMemoryRegion(startPtr, table);
table = reinterpret_cast<EristaMtcTable *>(startPtr);
if (R_FAILED(MtcValidateAllTables(table, EmcListDefault, EmcListSizeDefault))) {
AbortInvalidMtc("Failed mtc validation");
}
if (C.eristaEmcMaxClock <= EmcClkOSLimit) {
R_SKIP();
}
/* If we oc ram at all, tables are always shifted by at least 1. */
u32 tableShifts = 1;
for (u32 i = 0; i < std::size(maxEmcClocks) - 1; ++i) {
/* Duplicated mtc tables may cause pcv to not select frequencies properly, causing issues. */
if (maxEmcClocks[i] != maxEmcClocks[i + 1] && maxEmcClocks[i] > EmcClkOSLimit) {
++tableShifts;
} else {
maxEmcClocks[i] = 0;
}
MtcExtendTables(table);
if (R_FAILED(MtcValidateAllTables(table, newEmcList.data(), newEmcList.size()))) {
AbortInvalidMtc("Failed mtc validation");
}
/* Erista has extra, useless mtc tables, such as 40.8 Mhz, overwrite them to make room for oc freqs. */
/* More than 3 tables can be overwritten, but 3 is plenty. */
std::memmove(table_list[0], table_list[tableShifts], sizeof(EristaMtcTable) * (khz_list_size - tableShifts));
/* Since we're not scaling r/w latency properly on Erista, we first overwrite the tables with the 1600 MHz table before scaling it. */
for (u32 i = 0; i < tableShifts; ++i) {
std::memcpy(table_list[khz_list_size - i - 1], table_list[khz_list_size - tableShifts - 1], sizeof(EristaMtcTable));
}
for (u32 i = tableShifts, j = 0; i > 0 && j < std::size(maxEmcClocks); ++j) {
if (!maxEmcClocks[j]) {
continue;
}
table_list[khz_list_size - i]->rate_khz = maxEmcClocks[j];
MemMtcTableAutoAdjust(table_list[khz_list_size - i]);
--i;
for (u32 i = erista::MtcTableCountDefault; i < newEmcList.size(); ++i) {
MemMtcTableAutoAdjust(&table[i]);
}
R_SUCCEED();
}
Result MemFreqMax(u32 *ptr) {
if (GET_MAX_OF_ARR(maxEmcClocks) <= EmcClkOSLimit) {
if (C.eristaEmcMaxClock <= EmcClkOSLimit) {
R_SKIP();
}
PATCH_OFFSET(ptr, GET_MAX_OF_ARR(maxEmcClocks));
PATCH_OFFSET(ptr, C.eristaEmcMaxClock);
R_SUCCEED();
}
@@ -450,7 +564,58 @@ namespace ams::ldr::hoc::pcv::erista {
// R_SUCCEED();
// }
Result MemMtcTableAsm(u32 *ptr) {
/* This is a mess but the compiler made this painful to patch so we must do it this way */
constexpr s32 GoodAdrpOffset = -1;
constexpr s32 GoodMovOffset = -7;
constexpr s32 GoodBlOffset = 1;
constexpr u32 MtcGoodBlOpcode = 0x97fe6cfc;
constexpr u32 MtcBadBlOpcode0 = 0x97ffae64; // bl nn::pcv::GetHardwareType
constexpr u32 MtcBadBlOpcode1 = 0x940036d5; // bl nn::pcv::GetHardwareType
constexpr u32 MtcBadAdrpAsm = 0xd00000a1; // adrp x1, s_ModuleResetStatus_
constexpr s32 MtcBadBlOffset0 = 2;
constexpr s32 MtcBadBlOffset1 = -1;
constexpr s32 MtcBadAdrpOffset = 1;
/* Ensure we don't dereference memory before nso start. */
R_UNLESS(ptr + GoodMovOffset >= nsoStart, ldr::ResultInvalidMtcTablePattern());
/* Check for GetHardwareType asm and skip if it is found */
/* The pattern will match on the first time, but the location is bad, so it must be skipped */
if(AsmCompareAdrpNoImm(*(ptr + MtcBadAdrpOffset), MtcBadAdrpAsm) && AsmBlCompareOpcodeOnly(*(ptr + MtcBadBlOffset0), MtcBadBlOpcode0) && AsmBlCompareOpcodeOnly(*(ptr + MtcBadBlOffset1), MtcBadBlOpcode1)) {
R_SKIP();
}
/* We don't check for matching register because both registers must be x0 in order to pass the previous checks. */
/* 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);
R_UNLESS(AsmBlCompareOpcodeOnly(bl, MtcGoodBlOpcode), ldr::ResultInvalidMtcTablePattern());
/* Check for the mov that actually sets the mtc table count. */
u32 mov = *(ptr + GoodMovOffset);
R_UNLESS(asm_compare_no_rd(mov, MtcMovAsm), ldr::ResultInvalidMtcTablePattern());
/* Patch out the count of the mov to our custom mtc table amount*/
u32 movCountPatch = asm_set_rd(asm_set_imm16(MtcMovAsm, newEmcList.size()), asm_get_rd(mov));
PATCH_OFFSET(ptr + GoodMovOffset, movCountPatch);
R_SUCCEED();
}
void Patch(uintptr_t mapped_nso, size_t nso_size) {
nsoStart = reinterpret_cast<u32 *>(mapped_nso);
MtcGenerateFreqTables();
u32 CpuCvbDefaultMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(CpuCvbTableDefault)->freq);
u32 GpuCvbDefaultMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(GpuCvbTableDefault)->freq);
@@ -465,10 +630,11 @@ namespace ams::ldr::hoc::pcv::erista {
{"GPU Freq Asm", &GpuFreqMaxAsm, 2, &GpuMaxClockPatternFn },
{"GPU PLL Max", & GpuFreqPllMax, 1, nullptr, GpuClkPllMax },
// {"GPU PLL Limit", &GpuFreqPllLimit, 4, nullptr, GpuClkPllLimit },
{"MEM Freq Mtc", &MemFreqMtcTable, 0, nullptr, EmcClkOSLimit },
{"MEM Freq Mtc", &MemFreqMtcTable, 1, nullptr, EmcClkOSLimit },
{"MEM Freq Max", &MemFreqMax, 0, nullptr, EmcClkOSLimit },
{"MEM Freq PLLM", &MemFreqPllmLimit, 2, nullptr, EmcClkPllmLimit },
{"MEM Volt", &MemVoltHandler, 2, nullptr, MemVoltHOS },
{"MEM Table Asm", &MemMtcTableAsm, 4, &MemMtcGetGetTablePatternFn },
};
for (uintptr_t ptr = mapped_nso; ptr <= mapped_nso + nso_size - sizeof(EristaMtcTable); ptr += sizeof(u32)) {
@@ -480,9 +646,12 @@ namespace ams::ldr::hoc::pcv::erista {
}
}
// ViewLog();
for (auto &entry : patches) {
LOGGING("%s Count: %zu", entry.description, entry.patched_count);
LOGGING("%s Count: %zu\n", entry.description, entry.patched_count);
if (R_FAILED(entry.CheckResult())) {
// ViewLog();
panic::SmcError(panic::Patch);
CRASH(entry.description);

View File

@@ -26,9 +26,6 @@
namespace ams::ldr::hoc::pcv::erista {
static u32 maxEmcClocks[] = { C.eristaEmcMaxClock2, C.eristaEmcMaxClock1, C.eristaEmcMaxClock, };
#define GET_MAX_OF_ARR(ARR) (*std::max_element(ARR, ARR + std::size(ARR)))
constexpr cvb_entry_t CpuCvbTableDefault[] = {
// CPU_PLL_CVB_TABLE_ODN
{ 204000, {721094}, { } },
@@ -109,8 +106,11 @@ namespace ams::ldr::hoc::pcv::erista {
{ },
};
constexpr u32 EmcListDefault[] = { 40800, 68000, 102000, 204000, 408000, 665600, 800000, 1065600, 1331200, 1600000, };
constexpr u32 EmcListSizeDefault = std::size(EmcListDefault);
constexpr u32 EmcListEndDefault = EmcListSizeDefault - 1;
constexpr u32 MemVoltHOS = 1125'000;
constexpr u32 EmcClkMinFreq = 40800; /* 40.8 MHz table only exists on erista. */
constexpr u32 EmcClkPllmLimit = 1866'000'000;
constexpr u32 MTC_TABLE_REV = 7;
@@ -147,6 +147,17 @@ namespace ams::ldr::hoc::pcv::erista {
{ ICOSA_4GB_HYNIX_H9HCNNNBPUMLHR_NLE, T210SdevEmcDvfsTableH4gb01, },
};
constexpr u32 MtcBrAsm = 0xD61F0140;
constexpr u32 MtcMovAsm = 0x52800148;
constexpr u32 MtcAdrpAsm = 0xD0000081;
constexpr u32 MtcBlIns = 0x97ffae64;
constexpr u32 MtcAddAsm = 0x91131821;
ALWAYS_INLINE bool MemMtcGetGetTablePatternFn(u32 *ptr) {
/* This builds an address that gets returned, so the register must be x0 by convention. */
return AsmCompareAddNoImm12(*ptr, MtcAddAsm);
}
void Patch(uintptr_t mapped_nso, size_t nso_size);
}
}

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,15 +52,17 @@ namespace ams::ldr::hoc::pcv::mariko {
R_THROW(ldr::ResultInvalidGpuDvfs());
}
if (!C.marikoGpuVmin) {
R_SKIP();
if (C.marikoGpuBootVolt) {
PATCH_OFFSET(ptr - 3, C.marikoGpuBootVolt);
}
PATCH_OFFSET(ptr, C.marikoGpuVmin);
PATCH_OFFSET(ptr + 3, C.marikoGpuVmin);
PATCH_OFFSET(ptr + 6, C.marikoGpuVmin);
PATCH_OFFSET(ptr + 9, C.marikoGpuVmin);
PATCH_OFFSET(ptr + 12, C.marikoGpuVmin);
if (C.marikoGpuVmin) {
PATCH_OFFSET(ptr, C.marikoGpuVmin);
PATCH_OFFSET(ptr + 3, C.marikoGpuVmin);
PATCH_OFFSET(ptr + 6, C.marikoGpuVmin);
PATCH_OFFSET(ptr + 9, C.marikoGpuVmin);
PATCH_OFFSET(ptr + 12, C.marikoGpuVmin);
}
R_SUCCEED();
}
@@ -635,14 +639,14 @@ namespace ams::ldr::hoc::pcv::mariko {
}
void MtcGenerateFreqTables() {
if (C.marikoEmcMaxClock <= EmcClkOSLimit) {
return;
}
newEmcList.clear();
newEmcList.reserve(DvfsTableEntryCount);
newEmcList.insert(newEmcList.end(), std::begin(EmcListDefault), std::end(EmcListDefault));
if (C.marikoEmcMaxClock <= EmcClkOSLimit) {
return;
}
u32 stepRate = 0;
switch (C.stepMode) {
case StepMode_66MHz:
@@ -764,10 +768,6 @@ namespace ams::ldr::hoc::pcv::mariko {
MarikoMtcTable *table = reinterpret_cast<MarikoMtcTable *>(startPtr + mtcOffset);
R_TRY(MtcValidateAllTables(table, EmcListDefault, EmcListSizeDefault));
if (C.marikoEmcMaxClock <= EmcClkOSLimit) {
R_SKIP();
}
PrepareMtcMemoryRegion(startPtr, table);
table = reinterpret_cast<MarikoMtcTable *>(startPtr);
@@ -775,6 +775,10 @@ namespace ams::ldr::hoc::pcv::mariko {
AbortInvalidMtc("Failed mtc validation");
}
if (C.marikoEmcMaxClock <= EmcClkOSLimit) {
R_SKIP();
}
MtcExtendTables(table);
if (R_FAILED(MtcValidateAllTables(table, newEmcList.data(), newEmcList.size()))) {
@@ -834,33 +838,33 @@ namespace ams::ldr::hoc::pcv::mariko {
DvbEntry emcDvbOcTableBrackets[] = {
{ 204000, { 637, 637, 637, }, },
{ 1331200, { 650, 637, 637, }, },
{ 1600000, { 675, 650, 637, }, },
{ 1866000, { DVB(DvbVolt( 700, 675, 650)) }, },
{ 2133000, { DVB(DvbVolt( 725, 700, 675)) }, },
{ 2246000, { DVB(DvbVolt( 750, 725, 700)) }, },
{ 2400000, { DVB(DvbVolt( 775, 750, 725)) }, },
{ 2466000, { DVB(DvbVolt( 800, 775, 750)) }, },
{ 2533000, { DVB(DvbVolt( 810, 785, 760)) }, },
{ 2566000, { DVB(DvbVolt( 820, 795, 770)) }, },
{ 2600000, { DVB(DvbVolt( 830, 805, 780)) }, },
{ 2633000, { DVB(DvbVolt( 840, 815, 790)) }, },
{ 2666000, { DVB(DvbVolt( 850, 825, 800)) }, },
{ 2700000, { DVB(DvbVolt( 860, 835, 810)) }, },
{ 2733000, { DVB(DvbVolt( 870, 845, 820)) }, },
{ 2766000, { DVB(DvbVolt( 880, 855, 830)) }, },
{ 2800000, { DVB(DvbVolt( 895, 865, 840)) }, },
{ 2833000, { DVB(DvbVolt( 900, 875, 850)) }, },
{ 2866000, { DVB(DvbVolt( 910, 885, 860)) }, },
{ 2900000, { DVB(DvbVolt( 920, 895, 870)) }, },
{ 2933000, { DVB(DvbVolt( 950, 905, 880)) }, },
{ 2966000, { DVB(DvbVolt( 960, 915, 890)) }, },
{ 3000000, { DVB(DvbVolt( 970, 925, 900)) }, },
{ 3033000, { DVB(DvbVolt( 980, 940, 910)) }, },
{ 3066000, { DVB(DvbVolt(1000, 955, 920)) }, },
{ 3100000, { DVB(DvbVolt(1010, 990, 930)) }, },
{ 3133000, { DVB(DvbVolt(1025, 1005, 940)) }, },
{ 3166000, { DVB(DvbVolt(1035, 1015, 950)) }, },
{ 3200000, { DVB(DvbVolt(1050, 1025, 960)) }, },
{ 1600000, { 675, 650, 637, }, },
{ 1866000, { DVB(DvbVolt( 700, 675, 650)) }, },
{ 2000000, { DVB(DvbVolt( 712, 687, 662)) }, },
{ 2133000, { DVB(DvbVolt( 725, 700, 675)) }, },
{ 2200000, { DVB(DvbVolt( 737, 712, 687)) }, },
{ 2266000, { DVB(DvbVolt( 750, 725, 700)) }, },
{ 2333000, { DVB(DvbVolt( 762, 737, 712)) }, },
{ 2400000, { DVB(DvbVolt( 775, 750, 725)) }, },
{ 2433000, { DVB(DvbVolt( 787, 762, 737)) }, },
{ 2466000, { DVB(DvbVolt( 800, 775, 750)) }, },
{ 2533000, { DVB(DvbVolt( 812, 787, 762)) }, },
{ 2566000, { DVB(DvbVolt( 825, 800, 775)) }, },
{ 2600000, { DVB(DvbVolt( 837, 812, 787)) }, },
{ 2666000, { DVB(DvbVolt( 850, 825, 800)) }, },
{ 2700000, { DVB(DvbVolt( 875, 850, 825)) }, },
{ 2733000, { DVB(DvbVolt( 887, 862, 837)) }, },
{ 2766000, { DVB(DvbVolt( 912, 887, 862)) }, },
{ 2800000, { DVB(DvbVolt( 925, 900, 875)) }, },
{ 2833000, { DVB(DvbVolt( 937, 912, 887)) }, },
{ 2900000, { DVB(DvbVolt( 950, 925, 900)) }, },
{ 2933000, { DVB(DvbVolt( 962, 937, 912)) }, },
{ 3000000, { DVB(DvbVolt( 975, 950, 925)) }, },
{ 3033000, { DVB(DvbVolt( 987, 962, 937)) }, },
{ 3100000, { DVB(DvbVolt(1000, 975, 950)) }, },
{ 3133000, { DVB(DvbVolt(1025, 1000, 975)) }, },
{ 3166000, { DVB(DvbVolt(1037, 1012, 987)) }, },
{ 3200000, { DVB(DvbVolt(1050, 1025, 1000)) }, },
{ ~0u, { }, },
};
#undef DVB

View File

@@ -148,8 +148,6 @@ namespace ams::ldr::hoc::pcv::mariko {
constexpr u32 EmcListDefault[] = { 204000, 1331200, 1600000, };
constexpr u32 EmcListSizeDefault = std::size(EmcListDefault);
constexpr u32 EmcListEndDefault = EmcListSizeDefault - 1;
constexpr u32 EmcRateStep = 33'000;
constexpr u32 EmcRateStepScale = 33'200;
constexpr u32 EmcClkOSAlt = 1331'200;
constexpr u32 EmcClkPllmLimit = 2133'000'000;

View File

@@ -84,7 +84,7 @@ namespace ams::ldr::hoc::ptm {
switch (entry->cpu_freq_1) {
case cpuPtmBoost:
cpuPtmBoostPatch.Apply(entry);
R_DISCARD(cpuPtmBoostPatch.Apply(entry));
break;
case cpuPtmDefault:
case cpuPtmDevOC:
@@ -99,7 +99,7 @@ namespace ams::ldr::hoc::ptm {
case memPtmAlt:
case memPtmClamp:
if (isMariko) {
memPtmPatch.Apply(entry);
R_DISCARD(memPtmPatch.Apply(entry));
}
break;
default:
@@ -109,13 +109,15 @@ namespace ams::ldr::hoc::ptm {
}
LOGGING("%s Count: %zu", cpuPtmBoostPatch.description, cpuPtmBoostPatch.patched_count);
if (R_FAILED(cpuPtmBoostPatch.CheckResult()))
if (R_FAILED(cpuPtmBoostPatch.CheckResult())) {
CRASH(cpuPtmBoostPatch.description);
}
if (isMariko) {
LOGGING("%s Count: %zu", memPtmPatch.description, memPtmPatch.patched_count);
if (R_FAILED(memPtmPatch.CheckResult()))
if (R_FAILED(memPtmPatch.CheckResult())) {
CRASH(memPtmPatch.description);
}
}
}

Binary file not shown.

View File

@@ -46,11 +46,6 @@ typedef enum {
HocClkConfigValue_ThermalThrottle,
HocClkConfigValue_ThermalThrottleThreshold,
HocClkConfigValue_HandheldTDP,
HocClkConfigValue_HandheldTDPLimit,
HocClkConfigValue_LiteTDPLimit,
HocClkConfigValue_BatteryChargeCurrent,
HocClkConfigValue_OverwriteRefreshRate,
@@ -74,15 +69,18 @@ typedef enum {
HocClkConfigValue_AulaDisplayColorPreset,
HocClkConfigValue_MarikoMiddleFreqs,
HocClkConfigValue_AutoRAMCPUOverclock,
HocClkConfigValue_AutoRamCpuCpuOCFreq,
HocClkConfigValue_AutoRamCpuRamOCThreshold,
KipConfigValue_custRev,
KipConfigValue_KipVersion,
// KipConfigValue_mtcConf,
KipConfigValue_hpMode,
KipConfigValue_commonEmcMemVolt,
KipConfigValue_eristaEmcMaxClock,
KipConfigValue_eristaEmcMaxClock1,
KipConfigValue_eristaEmcMaxClock2,
KipConfigValue_stepMode,
KipConfigValue_marikoEmcMaxClock,
@@ -115,9 +113,6 @@ typedef enum {
KipConfigValue_write_latency_1866,
KipConfigValue_write_latency_2133,
KipConfigValue_mem_burst_read_latency,
KipConfigValue_mem_burst_write_latency,
KipConfigValue_eristaCpuUV,
KipConfigValue_eristaCpuVmin,
KipConfigValue_eristaCpuMaxVolt,
@@ -138,10 +133,10 @@ typedef enum {
KipConfigValue_marikoGpuUV,
KipConfigValue_marikoGpuVmin,
KipConfigValue_marikoGpuBootVolt,
KipConfigValue_marikoGpuVmax,
KipConfigValue_commonGpuVoltOffset,
KipConfigValue_gpuSpeedo,
KipConfigValue_g_volt_76800,
KipConfigValue_g_volt_153600,
@@ -239,15 +234,6 @@ static inline const char* hocclkFormatConfigValue(HocClkConfigValue val, bool pr
case HocClkConfigValue_ThermalThrottleThreshold:
return pretty ? "Thermal Throttle Threshold" : "thermal_throttle_threshold";
case HocClkConfigValue_HandheldTDP:
return pretty ? "Handheld TDP" : "handheld_tdp";
case HocClkConfigValue_HandheldTDPLimit:
return pretty ? "Handheld TDP Limit" : "tdp_limit";
case HocClkConfigValue_LiteTDPLimit:
return pretty ? "Handheld TDP Limit" : "tdp_limit_l";
case HocClkConfigValue_BatteryChargeCurrent:
return pretty ? "Battery Charge Current" : "bat_charge_current";
@@ -292,9 +278,19 @@ static inline const char* hocclkFormatConfigValue(HocClkConfigValue val, bool pr
return pretty ? "Aula Display Color Preset" : "aula_color_preset";
case HocClkConfigValue_MarikoMiddleFreqs:
return pretty ? "Mariko Middle Clocks" : "mariko_middle_freqs";
case HocClkConfigValue_AutoRAMCPUOverclock:
return pretty ? "Auto High RAM CPU OC" : "auto_high_ram_cpu_oc";
case HocClkConfigValue_AutoRamCpuCpuOCFreq:
return pretty ? "Auto High RAM CPU OC Freq" : "auto_ram_cpu_cpu_oc_freq";
case HocClkConfigValue_AutoRamCpuRamOCThreshold:
return pretty ? "Auto High RAM CPU OC RAM Threshold" : "auto_ram_cpu_ram_oc_threshold";
// KIP config values
case KipConfigValue_custRev:
return pretty ? "Custom Revision" : "kip_cust_rev";
case KipConfigValue_KipVersion:
return pretty ? "KIP Version" : "kip_version";
// case KipConfigValue_mtcConf:
// return pretty ? "MTC Config" : "kip_mtc_conf";
case KipConfigValue_hpMode:
@@ -304,11 +300,7 @@ static inline const char* hocclkFormatConfigValue(HocClkConfigValue val, bool pr
case KipConfigValue_commonEmcMemVolt:
return pretty ? "Common EMC/MEM Voltage" : "common_emc_mem_volt";
case KipConfigValue_eristaEmcMaxClock:
return pretty ? "Erista EMC Max Clock 1" : "erista_emc_max_clock";
case KipConfigValue_eristaEmcMaxClock1:
return pretty ? "Erista EMC Max Clock 2" : "erista_emc_max_clock1";
case KipConfigValue_eristaEmcMaxClock2:
return pretty ? "Erista EMC Max Clock 3" : "erista_emc_max_clock2";
return pretty ? "Erista EMC Max Clock" : "erista_emc_max_clock2";
case KipConfigValue_stepMode:
return pretty ? "Step Mode:" : "step_mode";
case KipConfigValue_marikoEmcMaxClock:
@@ -365,11 +357,6 @@ static inline const char* hocclkFormatConfigValue(HocClkConfigValue val, bool pr
case KipConfigValue_write_latency_2133:
return pretty ? "2133 Write Latency" : "write_latency_2133";
case KipConfigValue_mem_burst_read_latency:
return pretty ? "Memory Burst Read Latency" : "mem_burst_read_latency";
case KipConfigValue_mem_burst_write_latency:
return pretty ? "Memory Burst Write Latency" : "mem_burst_write_latency";
// CPU Erista
case KipConfigValue_eristaCpuUV:
return pretty ? "Erista CPU Undervolt" : "erista_cpu_uv";
@@ -413,13 +400,13 @@ static inline const char* hocclkFormatConfigValue(HocClkConfigValue val, bool pr
return pretty ? "Mariko GPU Undervolt" : "mariko_gpu_uv";
case KipConfigValue_marikoGpuVmin:
return pretty ? "Mariko GPU Vmin" : "mariko_gpu_vmin";
case KipConfigValue_marikoGpuBootVolt:
return pretty ? "Mariko GPU Boot Voltage" : "mariko_gpu_boot_volt";
case KipConfigValue_marikoGpuVmax:
return pretty ? "Mariko GPU Vmax" : "mariko_gpu_vmax";
case KipConfigValue_commonGpuVoltOffset:
return pretty ? "Common GPU Voltage Offset" : "common_gpu_volt_offset";
case KipConfigValue_gpuSpeedo:
return pretty ? "GPU Speedo" : "gpu_speedo";
// Mariko GPU voltages (24)
case KipConfigValue_g_volt_76800: return pretty ? "Mariko GPU Volt 76 MHz" : "g_volt_76800";
@@ -515,16 +502,16 @@ static inline uint64_t hocclkDefaultConfigValue(HocClkConfigValue val)
return 1963ULL;
case HocClkConfigValue_ThermalThrottle:
case HocClkConfigValue_HandheldTDP:
case HocClkConfigValue_IsFirstLoad:
case HocClkConfigValue_DVFSMode:
case HocClkConfigValue_AutoRAMCPUOverclock:
return 1ULL;
case HocClkConfigValue_AutoRamCpuCpuOCFreq:
return 1683000ULL;
case HocClkConfigValue_AutoRamCpuRamOCThreshold:
return 2133000ULL;
case HocClkConfigValue_ThermalThrottleThreshold:
return 70ULL;
case HocClkConfigValue_HandheldTDPLimit:
return 9600ULL; // 8600mW will trigger on erista stock, so raise it a bit
case HocClkConfigValue_LiteTDPLimit:
return 6400ULL; // 0.5C
case HocClkConfigValue_CpuGovernorMinimumFreq:
return 612000000ULL; // 612MHz
case HocClkConfigValue_MaxDisplayClockH:
@@ -545,8 +532,6 @@ static inline uint64_t hocclkValidConfigValue(HocClkConfigValue val, uint64_t in
case HocClkConfigValue_EristaMaxCpuClock:
case HocClkConfigValue_MarikoMaxCpuClock:
case HocClkConfigValue_ThermalThrottleThreshold:
case HocClkConfigValue_HandheldTDPLimit:
case HocClkConfigValue_LiteTDPLimit:
case HocClkConfigValue_PollingIntervalMs:
case HocClkConfigValue_MaxDisplayClockH:
return input > 0;
@@ -558,22 +543,21 @@ static inline uint64_t hocclkValidConfigValue(HocClkConfigValue val, uint64_t in
case HocClkConfigValue_UncappedClocks:
case HocClkConfigValue_OverwriteBoostMode:
case HocClkConfigValue_ThermalThrottle:
case HocClkConfigValue_HandheldTDP:
case HocClkConfigValue_OverwriteRefreshRate:
case HocClkConfigValue_IsFirstLoad:
case HocClkConfigValue_EnableExperimentalSettings:
case HocClkConfigValue_LiveCpuUv:
case HocClkConfigValue_GPUSchedulingMethod:
case HocClkConfigValue_MarikoMiddleFreqs:
case HocClkConfigValue_AutoRAMCPUOverclock:
return (input & 0x1) == input;
case KipConfigValue_KipVersion:
case KipConfigValue_custRev:
// case KipConfigValue_mtcConf:
case KipConfigValue_hpMode:
case KipConfigValue_commonEmcMemVolt:
case KipConfigValue_eristaEmcMaxClock:
case KipConfigValue_eristaEmcMaxClock1:
case KipConfigValue_eristaEmcMaxClock2:
case KipConfigValue_stepMode:
case KipConfigValue_marikoEmcMaxClock:
case KipConfigValue_marikoEmcVddqVolt:
@@ -599,8 +583,6 @@ static inline uint64_t hocclkValidConfigValue(HocClkConfigValue val, uint64_t in
case KipConfigValue_write_latency_1600:
case KipConfigValue_write_latency_1866:
case KipConfigValue_write_latency_2133:
case KipConfigValue_mem_burst_read_latency:
case KipConfigValue_mem_burst_write_latency:
case KipConfigValue_eristaCpuUV:
case KipConfigValue_eristaCpuMaxVolt:
case KipConfigValue_marikoCpuUVLow:
@@ -616,9 +598,9 @@ static inline uint64_t hocclkValidConfigValue(HocClkConfigValue val, uint64_t in
case KipConfigValue_eristaGpuVmin:
case KipConfigValue_marikoGpuUV:
case KipConfigValue_marikoGpuVmin:
case KipConfigValue_marikoGpuBootVolt:
case KipConfigValue_marikoGpuVmax:
case KipConfigValue_commonGpuVoltOffset:
case KipConfigValue_gpuSpeedo:
case KipConfigValue_g_volt_76800:
case KipConfigValue_g_volt_153600:
case KipConfigValue_g_volt_230400:
@@ -683,6 +665,8 @@ static inline uint64_t hocclkValidConfigValue(HocClkConfigValue val, uint64_t in
case HocClkConfigValue_MemoryFrequencyMeasurementMode:
case HocClkConfigValue_RamDisplayUnit:
case HocClkConfigValue_AulaDisplayColorPreset:
case HocClkConfigValue_AutoRamCpuCpuOCFreq:
case HocClkConfigValue_AutoRamCpuRamOCThreshold:
return true;
case HocClkConfigValue_BatteryChargeCurrent:
return ((input >= 1024) && (input <= 3072)) || !input;
@@ -690,6 +674,6 @@ static inline uint64_t hocclkValidConfigValue(HocClkConfigValue val, uint64_t in
return ((input >= 800) && (input <= 1325));
default:
return false;
return true;
}
}

View File

@@ -22,12 +22,12 @@ BUILD := build
OUTDIR := out
RESOURCES := res
SOURCES := src src/ui/gui src/ui/elements ../common/src ../common/src/client
DATA := data
DATA := data ../assets
INCLUDES := ../common/include
EXEFS_SRC := exefs_src
IS_MINIMAL := 0
APP_TITLE := Horizon OC Gaea
APP_TITLE := Horizon OC
NO_ICON := 1
@@ -39,7 +39,7 @@ include ${TOPDIR}/lib/libultrahand/ultrahand.mk
# version control constants
#---------------------------------------------------------------------------------
#TARGET_VERSION := $(shell git describe --dirty --always --tags)
APP_VERSION := 2.3.1 # ensure to set KIP_VERSION and CUST_REV in sysmodule Makefile when updating this
APP_VERSION := 2.4.0 # ensure to set KIP_VERSION and CUST_REV in sysmodule Makefile when updating this
TARGET_VERSION := $(APP_VERSION)
#---------------------------------------------------------------------------------
@@ -166,6 +166,11 @@ $(OUTPUT).elf: $(OFILES)
@echo $(notdir $<)
@$(bin2o)
%.rgba.o : %.rgba
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
-include $(DEPENDS)
#---------------------------------------------------------------------------------------

View File

@@ -28,20 +28,21 @@
#pragma once
#include <tesla.hpp>
#include "../gui/base_gui.h"
class BaseGui;
static constexpr u16 HOC_HEADER_HEIGHT = 287;
// Bottom edge of the drawn box: 106 + TOP_Y_OFFSET(15) + 156 = 277
static constexpr u16 HOC_BOX_BOTTOM = 277;
class BaseFrame : public tsl::elm::HeaderOverlayFrame
{
public:
BaseFrame(BaseGui* gui) : tsl::elm::HeaderOverlayFrame(234) {
BaseFrame(BaseGui* gui, u16 headerHeight = HOC_HEADER_HEIGHT) : tsl::elm::HeaderOverlayFrame(headerHeight) {
this->gui = gui;
}
void draw(tsl::gfx::Renderer* renderer) override
{
tsl::elm::HeaderOverlayFrame::draw(renderer);
this->gui->preDraw(renderer);
}
void draw(tsl::gfx::Renderer* renderer) override;
protected:
BaseGui* gui;

View File

@@ -25,6 +25,7 @@
*/
#include "ult_ext.h"
#include "app_profile_gui.h"
#include "../format.h"
@@ -303,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

@@ -25,20 +25,38 @@
*/
#include "base_gui.h"
#include "../elements/base_frame.h"
void BaseFrame::draw(tsl::gfx::Renderer* renderer) {
tsl::elm::HeaderOverlayFrame::draw(renderer);
this->gui->preDraw(renderer);
}
#include <tesla.hpp>
#include <math.h>
#define LOGO_Y_REAL 65
#define LOGO_X 20
#define LOGO_Y 50
#define LOGO_Y 60
#define LOGO_LABEL_FONT_SIZE 45
#define VERSION_X (LOGO_X + 250)
#define TEXT_Y 57
#define LOGO_IMG_W 50
#define LOGO_IMG_H 50
#define LOGO_IMG_PAD 8
#define LOGO_TEXT_X (LOGO_X + LOGO_IMG_W + LOGO_IMG_PAD)
#define VERSION_X (LOGO_TEXT_X + 185)
#define VERSION_Y (LOGO_Y - 40)
#define VERSION_FONT_SIZE 15
extern "C" {
extern const u8 hoc_rgba[];
extern const u32 hoc_rgba_size;
}
std::string getVersionString() {
char buf[0x100] = "";
Result rc = hocclkIpcGetVersionString(buf, sizeof(buf));
@@ -48,10 +66,10 @@ std::string getVersionString() {
return std::string(buf);
}
static constexpr tsl::Color dynamicLogoRGB1 = tsl::Color(0, 15, 3, 15);
static constexpr tsl::Color dynamicLogoRGB2 = tsl::Color(0, 8, 1, 15);
static constexpr tsl::Color STATIC_GREEN = tsl::Color(0, 15, 0, 15);
const std::string name = "Horizon OC Gaea";
static constexpr tsl::Color dynamicLogoRGB1 = tsl::Color( 7, 15, 15, 15);
static constexpr tsl::Color dynamicLogoRGB2 = tsl::Color( 2, 8, 11, 15);
static constexpr tsl::Color STATIC_TEAL = tsl::Color( 7, 15, 15, 15);
const std::string name = " Horizon OC";
static s32 drawDynamicUltraText(
tsl::gfx::Renderer* renderer,
@@ -67,7 +85,6 @@ static s32 drawDynamicUltraText(
const u64 currentTime_ns = armTicksToNs(armGetSystemTick());
const double timeNow = static_cast<double>(currentTime_ns) / 1e9;
const double timeBase = fmod(timeNow, cycleDuration);
const double waveScale = 2.0 * M_PI / cycleDuration;
@@ -76,7 +93,7 @@ static s32 drawDynamicUltraText(
char letter = name[i];
if (letter == '\0') break;
double phase = waveScale * (timeBase + i * 0.12);
double phase = waveScale * (timeNow + i * 0.12);
double raw = cos(phase);
double n = (raw + 1.0) * 0.5;
@@ -87,13 +104,13 @@ static s32 drawDynamicUltraText(
double brightness = 0.75 + glow * 0.25;
u8 r = static_cast<u8>(
(dynamicLogoRGB1.r + (dynamicLogoRGB2.r - dynamicLogoRGB1.r) * blend) * brightness
((int)dynamicLogoRGB1.r + ((int)dynamicLogoRGB2.r - (int)dynamicLogoRGB1.r) * blend) * brightness
);
u8 g = static_cast<u8>(
(dynamicLogoRGB1.g + (dynamicLogoRGB2.g - dynamicLogoRGB1.g) * blend) * brightness
((int)dynamicLogoRGB1.g + ((int)dynamicLogoRGB2.g - (int)dynamicLogoRGB1.g) * blend) * brightness
);
u8 b = static_cast<u8>(
(dynamicLogoRGB1.b + (dynamicLogoRGB2.b - dynamicLogoRGB1.b) * blend) * brightness
((int)dynamicLogoRGB1.b + ((int)dynamicLogoRGB2.b - (int)dynamicLogoRGB1.b) * blend) * brightness
);
r = std::clamp<u8>(r, 0, 15);
@@ -121,19 +138,37 @@ static s32 drawDynamicUltraText(
}
void BaseGui::preDraw(tsl::gfx::Renderer* renderer) {
renderer->drawBitmap(LOGO_X, LOGO_Y_REAL - LOGO_LABEL_FONT_SIZE, LOGO_IMG_W, LOGO_IMG_H, hoc_rgba);
drawDynamicUltraText(
renderer,
LOGO_X,
LOGO_Y,
LOGO_TEXT_X,
TEXT_Y,
LOGO_LABEL_FONT_SIZE,
STATIC_GREEN,
STATIC_TEAL,
false
);
static const std::string versionStr = "Version " + getVersionString() + " \"Gaea\"";
static constexpr tsl::Color versionColor(9, 9, 9, 15);
static constexpr s32 vx = LOGO_TEXT_X + 15;
static constexpr s32 vy = TEXT_Y + 18;
static constexpr s32 fs = 15;
static constexpr s32 skew = 3;
static constexpr s32 passes = 25;
for (s32 i = 0; i < passes; i++) {
s32 sliceY = (vy - fs) + i * fs / passes;
s32 sliceH = fs / passes + 1;
s32 xOff = skew - (skew * i / (passes - 1));
renderer->enableScissoring(0, sliceY, tsl::cfg::FramebufferWidth, sliceH);
renderer->drawString(versionStr.c_str(), false, vx + xOff, vy, fs, versionColor);
renderer->disableScissoring();
}
}
tsl::elm::Element* BaseGui::createUI()
{
BaseFrame* rootFrame = new BaseFrame(this);
BaseFrame* rootFrame = new BaseFrame(this, this->headerHeight());
rootFrame->setContent(this->baseUI());
return rootFrame;
}

View File

@@ -28,6 +28,7 @@
#pragma once
#include <tesla.hpp>
#include "../elements/base_frame.h"
#include <fstream>
#include <vector>
#include <string>
@@ -46,6 +47,7 @@ class BaseGui : public tsl::Gui
tsl::elm::Element* createUI() override;
virtual tsl::elm::Element* baseUI() = 0;
virtual void refresh() {}
virtual u16 headerHeight() const { return HOC_HEADER_HEIGHT; }
private:
};

View File

@@ -29,6 +29,8 @@
#include "fatal_gui.h"
#include "../format.h"
#define TOP_Y_OFFSET 15
// Cache hardware model to avoid repeated syscalls
BaseMenuGui::BaseMenuGui() : tempColors{ tsl::Color(0), tsl::Color(0), tsl::Color(0), tsl::Color(0), tsl::Color(0), tsl::Color(0), tsl::Color(0), }
@@ -55,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};
@@ -77,10 +87,10 @@ void BaseMenuGui::preDraw(tsl::gfx::Renderer* renderer) {
static u32 maxProfileValueWidth = renderer->getTextDimensions("USB Charger", false, SMALL_TEXT_SIZE).first; // longest word
u32 y = 91;
u32 y = 91 + TOP_Y_OFFSET;
// === TOP SECTION ===
renderer->drawRoundedRect(14, 70-1, 420, 30+2, 12.0f, renderer->aWithOpacity(tsl::tableBGColor));
renderer->drawRoundedRect(14, 70-1 + TOP_Y_OFFSET, 420, 30+2, 12.0f, renderer->aWithOpacity(tsl::tableBGColor));
// App ID - use pre-formatted string
renderer->drawString(labels[0], false, positions[0], y, SMALL_TEXT_SIZE, tsl::sectionTextColor);
@@ -93,7 +103,7 @@ void BaseMenuGui::preDraw(tsl::gfx::Renderer* renderer) {
y += 38; // Direct assignment instead of += 38
// === MAIN DATA SECTION ===
renderer->drawRoundedRect(14, 106, 420, 156, 10.0f, renderer->aWithOpacity(tsl::tableBGColor));
renderer->drawRoundedRect(14, 106 + TOP_Y_OFFSET, 420, 156, 10.0f, renderer->aWithOpacity(tsl::tableBGColor));
// === FREQUENCY SECTION ===
// Labels first (better cache locality)
@@ -348,7 +358,6 @@ void BaseMenuGui::refresh()
tsl::elm::Element* BaseMenuGui::baseUI()
{
auto* list = new tsl::elm::List();
list->addItem(new tsl::elm::CustomDrawer([](tsl::gfx::Renderer*, s32, s32, s32, s32) {}), 35); // add a bit of space
this->listElement = list;
this->listUI();

View File

@@ -84,6 +84,7 @@ class BaseMenuGui : public BaseGui
tsl::elm::Element* baseUI() override;
void refresh() override;
virtual void listUI() = 0;
u16 headerHeight() const override { return HOC_BOX_BOTTOM + 9; }
private:
char displayStrings[48][32]; // Pre-formatted display strings

View File

@@ -35,6 +35,7 @@ std::vector<std::string> ConfigInfoStrings(HocClkConfigValue val, bool isMariko,
"Options:",
"- MHz: Megahertz (e.g. 1600 MHz)",
"- MT/s: MegaTransfers per second (e.g. 3200 MT/s)",
"- MHz and MT/s: Display in both MHz and MT/s",
"Default: MHz"
};
@@ -97,8 +98,8 @@ std::vector<std::string> ConfigInfoStrings(HocClkConfigValue val, bool isMariko,
"- Washed: Washed out colors.",
"- Basic: Real natural profile.",
"- Natural: Not actually natural.. Extra saturation.",
"- Vivid: Saturated.",
"Default: Do not override"
"- Vivid: Saturated.",
"Default: Do not override"
};
case HocClkConfigValue_CpuGovernorMinimumFreq:
@@ -110,7 +111,9 @@ std::vector<std::string> ConfigInfoStrings(HocClkConfigValue val, bool isMariko,
case HocClkConfigValue_OverwriteRefreshRate:
return {
"Controls the availability of display refresh rate features.",
"When enabled, allows changing the display refresh rate and using display refresh rate related features."
"When enabled, allows changing the display refresh rate and using display refresh rate related features.",
"This feature conflicts with FPSLocker's feature that does the same thing.",
"Default: OFF"
};
case HocClkConfigValue_MaxDisplayClockH:
@@ -167,19 +170,6 @@ std::vector<std::string> ConfigInfoStrings(HocClkConfigValue val, bool isMariko,
"Default: ON",
};
case HocClkConfigValue_HandheldTDP:
return {
"If enabled, Resets to stock clocks when power consumption is above the threshold in handheld mode",
"Default: ON",
};
case HocClkConfigValue_HandheldTDPLimit:
case HocClkConfigValue_LiteTDPLimit:
return {
"The power consumption threshold (in mW) for resetting to stock clocks in handheld mode when Handheld TDP is enabled.",
isHoag ? "Default: 6400mW" : "Default: 9600mW"
};
case HocClkConfigValue_ThermalThrottleThreshold:
return {
"The temperature threshold (in °C) for resetting to stock clocks when Thermal Throttle is enabled.",
@@ -224,7 +214,7 @@ std::vector<std::string> ConfigInfoStrings(HocClkConfigValue val, bool isMariko,
"Default: 600 mV"
};
case KipConfigValue_stepMode:
case KipConfigValue_stepMode:
return {
"The step that RAM clocks take.",
"Options (with examples):",
@@ -247,8 +237,6 @@ std::vector<std::string> ConfigInfoStrings(HocClkConfigValue val, bool isMariko,
};
case KipConfigValue_eristaEmcMaxClock:
case KipConfigValue_eristaEmcMaxClock1:
case KipConfigValue_eristaEmcMaxClock2:
return {
"The RAM frequency used in the particular slot. Higher frequencies may cause instability, so increase this gradually and test for stability.",
"Default: Disabled (1600 MHz)"
@@ -360,19 +348,6 @@ std::vector<std::string> ConfigInfoStrings(HocClkConfigValue val, bool isMariko,
"These properties apply for both write and read latencies, and you can mix-and-match the brackets if necessary",
"Default: -"
};
case KipConfigValue_mem_burst_read_latency:
return {
"The read latency for the ram",
"Default: 1600 RL"
};
case KipConfigValue_mem_burst_write_latency:
return {
"The write latency for the ram",
"Default: 1600 WL"
};
case KipConfigValue_marikoCpuUVLow:
return {
"The CPU UV level used before tBreak",
@@ -460,6 +435,23 @@ std::vector<std::string> ConfigInfoStrings(HocClkConfigValue val, bool isMariko,
"The clock used for the CPU in \"boost mode\"",
"Default: 1785 MHz"
};
case HocClkConfigValue_AutoRAMCPUOverclock:
return {
"When enabled, automatically raises the CPU clock to the configured OC frequency when RAM clock meets or exceeds the threshold to meet the increased voltage requirement.",
"Default: ON"
};
case HocClkConfigValue_AutoRamCpuCpuOCFreq:
return {
"The CPU clock (in MHz) applied when Auto High RAM CPU OC is enabled and the RAM threshold is met.",
"Default: 1683 MHz"
};
case HocClkConfigValue_AutoRamCpuRamOCThreshold:
return {
"The RAM clock threshold (in MHz) at or above which the Auto High RAM CPU OC will activate.",
"Default: 2133MHz"
};
case HocClkConfigValue_OverwriteBoostMode:
return {
@@ -489,7 +481,7 @@ std::vector<std::string> ConfigInfoStrings(HocClkConfigValue val, bool isMariko,
"Maximum GPU voltage",
"Default: 800 mV"
};
case HocClkConfigValue_DVFSMode:
return {
"The mode used for GPU DVFS",
@@ -537,7 +529,12 @@ std::vector<std::string> ConfigInfoStrings(HocClkConfigValue val, bool isMariko,
"- Enabled: Enables GPU scheduling, 96.5% GPU max load",
"Default: Do not override"
};
case KipConfigValue_marikoGpuBootVolt:
return {
"The voltage supplied to the GPU during boot and when the temperature is below 20°C (in mV).",
"Warning: Changing this value may cause instability.",
"Default: 800mV"
};
default:
return {};
}

View File

@@ -25,6 +25,7 @@
*/
#include "ult_ext.h"
#include "freq_choice_gui.h"
#include "../format.h"

View File

@@ -16,6 +16,7 @@
*
*/
#include "ult_ext.h"
#include "../format.h"
#include "fatal_gui.h"
#include "global_override_gui.h"

View File

@@ -32,6 +32,14 @@
#include "global_override_gui.h"
#include "misc_gui.h"
#include "about_gui.h"
#include "ult_ext.h"
tsl::elm::Element* MainGui::baseUI() {
auto* list = new BoxClippedList();
this->listElement = list;
this->listUI();
return list;
}
void MainGui::listUI()
{

View File

@@ -34,6 +34,8 @@ class MainGui : public BaseMenuGui
public:
MainGui() {}
~MainGui() {}
tsl::elm::Element* baseUI() override;
void listUI() override;
void refresh() override;
u16 headerHeight() const override { return HOC_HEADER_HEIGHT - 25; }
};

View File

@@ -17,6 +17,7 @@
*/
#include "misc_gui.h"
#include "ult_ext.h"
#include "fatal_gui.h"
#include "config_info_strings.h"
#include "../format.h"
@@ -61,7 +62,6 @@ class RamLatenciesSubmenuGui;
class CpuSubmenuGui;
class GpuSubmenuGui;
class GpuCustomTableSubmenuGui;
class RamTableEditor;
class ExperimentalSettingsSubMenuGui;
MiscGui::MiscGui()
@@ -548,7 +548,7 @@ void MiscGui::listUI()
ValueThresholds thresholdsDisabled(0, 0);
std::vector<NamedValue> noNamedValues = {};
this->listElement->addItem(new tsl::elm::CategoryHeader("Settings"));
this->listElement->addItem(new CompactCategoryHeader("Settings"));
tsl::elm::CustomDrawer* rebootSetWarning = new tsl::elm::CustomDrawer([](tsl::gfx::Renderer *renderer, s32 x, s32 y, s32 w, s32 h) {
renderer->drawString("\uE150 Settings marked in blue", false, x + 20, y + 30, 18, tsl::style::color::ColorText);
@@ -660,7 +660,7 @@ protected:
void listUI() override {
Result rc = hocclkIpcGetConfigValues(this->configList);
if (R_FAILED(rc)) [[unlikely]] { FatalGui::openWithResultCode("hocclkIpcGetConfigValues", rc); return; }
this->listElement->addItem(new tsl::elm::CategoryHeader("General Settings"));
this->listElement->addItem(new CompactCategoryHeader("General Settings"));
ValueThresholds thresholdsDisabled(0, 0);
std::vector<NamedValue> ramVoltDispModes = {
@@ -688,7 +688,7 @@ protected:
false
);
addConfigButton(
HocClkConfigValue_PollingIntervalMs,
"Polling Interval",
@@ -720,12 +720,12 @@ protected:
void listUI() override {
Result rc = hocclkIpcGetConfigValues(this->configList);
if (R_FAILED(rc)) [[unlikely]] { FatalGui::openWithResultCode("hocclkIpcGetConfigValues", rc); return; }
this->listElement->addItem(new tsl::elm::CategoryHeader("Experimental Settings"));
this->listElement->addItem(new CompactCategoryHeader("Experimental Settings"));
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),
@@ -856,7 +856,7 @@ protected:
void listUI() override {
Result rc = hocclkIpcGetConfigValues(this->configList);
if (R_FAILED(rc)) [[unlikely]] { FatalGui::openWithResultCode("hocclkIpcGetConfigValues", rc); return; }
this->listElement->addItem(new tsl::elm::CategoryHeader("Governor Settings"));
this->listElement->addItem(new CompactCategoryHeader("Governor Settings"));
ValueThresholds thresholdsDisabled(0, 0);
std::vector<NamedValue> GovernorMinHz = {
@@ -897,7 +897,7 @@ protected:
if(!this->context)
return;
this->listElement->addItem(new tsl::elm::CategoryHeader("Display Settings"));
this->listElement->addItem(new CompactCategoryHeader("Display Settings"));
addConfigToggle(HocClkConfigValue_OverwriteRefreshRate, nullptr);
if(!this->context->isUsingRetroSuper) {
tsl::elm::CustomDrawer* warningText = new tsl::elm::CustomDrawer([](tsl::gfx::Renderer *renderer, s32 x, s32 y, s32 w, s32 h) {
@@ -922,6 +922,14 @@ protected:
);
}
if(!IsAula()) {
tsl::elm::CustomDrawer* warningTextDV = new tsl::elm::CustomDrawer([](tsl::gfx::Renderer *renderer, s32 x, s32 y, s32 w, s32 h) {
renderer->drawString("\uE150 Adjust the display voltage", false, x + 20, y + 30, 18, tsl::style::color::ColorText);
renderer->drawString("with caution to avoid damage", false, x + 20, y + 50, 18, tsl::style::color::ColorText);
renderer->drawString("to your display panel! ", false, x + 20, y + 70, 18, tsl::style::color::ColorText);
renderer->drawString("Proceed at your own risk!", false, x + 20, y + 90, 18, tsl::style::color::ColorText);
});
warningTextDV->setBoundaries(0, 0, tsl::cfg::FramebufferWidth, 110);
this->listElement->addItem(warningTextDV);
addConfigButton(
HocClkConfigValue_DisplayVoltage,
"Display Voltage",
@@ -944,37 +952,11 @@ protected:
void listUI() override {
Result rc = hocclkIpcGetConfigValues(this->configList);
if (R_FAILED(rc)) [[unlikely]] { FatalGui::openWithResultCode("hocclkIpcGetConfigValues", rc); return; }
this->listElement->addItem(new tsl::elm::CategoryHeader("Safety Settings"));
this->listElement->addItem(new CompactCategoryHeader("Safety Settings"));
addConfigToggle(HocClkConfigValue_UncappedClocks, nullptr);
addConfigToggle(HocClkConfigValue_ThermalThrottle, nullptr);
addConfigToggle(HocClkConfigValue_HandheldTDP, nullptr);
#if IS_MINIMAL == 0
std::map<uint32_t, std::string> labels_pwr_l = {
{6400, "Official Rating"}
};
if(IsHoag()) {
ValueThresholds tdpThresholdsLite(6400, 7500);
addConfigButton(
HocClkConfigValue_LiteTDPLimit,
"TDP Threshold",
ValueRange(4000, 8000, 100, "mW", 1),
"Power",
&tdpThresholdsLite,
labels_pwr_l
);
} else {
ValueThresholds tdpThresholds(9600, 11000);
addConfigButton(
HocClkConfigValue_HandheldTDPLimit,
"TDP Threshold",
ValueRange(8000, 12000, 100, "mW", 1),
"Power",
&tdpThresholds
);
}
ValueThresholds throttleThresholds(70, 80);
addConfigButton(
HocClkConfigValue_ThermalThrottleThreshold,
@@ -1004,8 +986,8 @@ protected:
this->listElement->addItem(new tsl::elm::CategoryHeader("RAM Settings"));
this->listElement->addItem(new CompactCategoryHeader("RAM Settings"));
addMappedConfigTrackbar(KipConfigValue_emcDvbShift, "DVB Shift",
{0xFFFFFFFCu, 0xFFFFFFFDu, 0xFFFFFFFEu, 0xFFFFFFFFu, 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u},
{"-4", "-3", "-2", "-1", " 0", "1", "2", "3", "4", "5", "6", "7", "8"});
@@ -1047,7 +1029,7 @@ protected:
true
);
}
addConfigToggle(KipConfigValue_hpMode, "HP Mode", true);
std::map<uint32_t, std::string> emc_voltage_label = {
@@ -1059,7 +1041,7 @@ protected:
{1250000, "Unsafe Max"},
};
ValueThresholds vdd2Thresholds(IsMariko() ? 1212500 : 1237500, 1250000);
ValueThresholds vdd2Thresholds(IsMariko() ? 1212500 : 1237500, IsMariko() ? 1250000 : 1275000);
addConfigButton(
KipConfigValue_commonEmcMemVolt,
"RAM VDD2 Voltage",
@@ -1073,12 +1055,13 @@ protected:
);
if(IsMariko()) {
ValueThresholds vddqThresholds(675000, 725000);
addConfigButton(
KipConfigValue_marikoEmcVddqVolt,
"RAM VDDQ Voltage",
ValueRange(400000, 700000, 5000, "mV", 1000),
ValueRange(400000, 750000, 5000, "mV", 1000),
"RAM VDDQ Voltage",
&thresholdsDisabled,
&vddqThresholds,
{},
{},
false,
@@ -1097,20 +1080,51 @@ protected:
addConfigButton(KipConfigValue_stepMode, "Step Mode", ValueRange(0, 0, 2, "", 0), "Step Mode", &thresholdsDisabled, {}, stepMode, false, true);
}
std::vector<NamedValue> emcMaxClock = { };
RamDisplayUnit unit = (RamDisplayUnit)this->configList->values[HocClkConfigValue_RamDisplayUnit];
if (IsErista()) {
tsl::elm::ListItem* freqSubmenu = new tsl::elm::ListItem("RAM Frequency Editor");
freqSubmenu->setClickListener([](u64 keys) {
if (keys & HidNpadButton_A) {
tsl::changeTo<RamTableEditor>();
return true;
}
return false;
});
freqSubmenu->setValue(R_ARROW);
this->listElement->addItem(freqSubmenu);
emcMaxClock = {
NamedValue("Disabled", 1600000),
NamedValue("1633 MHz", 1633000),
NamedValue("1666 MHz", 1666000),
NamedValue("1700 MHz", 1700000),
NamedValue("1733 MHz", 1733000),
// NamedValue("1766 MHz", 1766000),
NamedValue("1800 MHz", 1800000),
NamedValue("1833 MHz", 1833000),
NamedValue("1862 MHz", 1862400, "JEDEC."),
NamedValue("1881 MHz", 1881600),
NamedValue("1900 MHz", 1900800),
NamedValue("1920 MHz", 1920000),
NamedValue("1939 MHz", 1939200),
NamedValue("1958 MHz", 1958400),
NamedValue("1977 MHz", 1977600),
NamedValue("1996 MHz", 1996800, "JEDEC."),
NamedValue("2016 MHz", 2016000),
NamedValue("2035 MHz", 2035200),
NamedValue("2054 MHz", 2054400),
NamedValue("2073 MHz", 2073600),
NamedValue("2092 MHz", 2092800),
NamedValue("2112 MHz", 2112000),
NamedValue("2131 MHz", 2131200, "JEDEC."),
NamedValue("2150 MHz", 2150400),
NamedValue("2169 MHz", 2169600),
NamedValue("2188 MHz", 2188800),
NamedValue("2208 MHz", 2208000),
NamedValue("2227 MHz", 2227200),
NamedValue("2246 MHz", 2246400),
NamedValue("2265 MHz", 2265600),
NamedValue("2284 MHz", 2284800),
NamedValue("2304 MHz", 2304000),
NamedValue("2323 MHz", 2323200),
NamedValue("2342 MHz", 2342400),
NamedValue("2361 MHz", 2361600),
NamedValue("2380 MHz", 2380800),
NamedValue("2400 MHz", 2400000, "JEDEC."),
};
} else {
RamDisplayUnit unit = (RamDisplayUnit)this->configList->values[HocClkConfigValue_RamDisplayUnit];
std::vector<NamedValue> marikoMaxEmcClock = {
emcMaxClock = {
NamedValue("1600 MHz", 1600000),
NamedValue("1633 MHz", 1633000),
NamedValue("1666 MHz", 1666000),
@@ -1164,19 +1178,20 @@ protected:
NamedValue("3233 MHz", 3233000, "High speedo needed!"),
NamedValue("3266 MHz", 3266000, "High speedo needed!"),
NamedValue("3300 MHz", 3300000, "High speedo needed!"),
// NamedValue("3333MHz (Needs extreme Speedo/PLL)", 3333000),
// NamedValue("3366MHz (Needs extreme Speedo/PLL)", 3366000),
// NamedValue("3400MHz (Needs extreme Speedo/PLL)", 3400000),
// NamedValue("3433MHz (Needs ridiculous Speedo/PLL)", 3433000),
// NamedValue("3466MHz (Needs ridiculous Speedo/PLL)", 3466000),
// NamedValue("3500MHz (Needs ridiculous Speedo/PLL)", 3500000),
};
for (auto& nv : marikoMaxEmcClock)
nv.name = formatMemClockKhzLabel(nv.value, unit);
addConfigButton(KipConfigValue_marikoEmcMaxClock, "Ram Max Clock", ValueRange(0, 1, 1, "", 1), "Ram Max Clock", &thresholdsDisabled, {}, marikoMaxEmcClock, false, true);
}
for (auto& nv : emcMaxClock) {
if (nv.name != "Disabled") {
nv.name = formatMemClockKhzLabel(nv.value, unit);
}
}
if (IsMariko()) {
addConfigButton(KipConfigValue_marikoEmcMaxClock, "Ram Max Clock", ValueRange(0, 1, 1, "", 1), "Ram Max Clock", &thresholdsDisabled, {}, emcMaxClock, false, true);
} else {
addConfigButton(KipConfigValue_eristaEmcMaxClock, "Ram Max Clock", ValueRange(0, 1, 1, "", 1), "Ram Max Clock", &thresholdsDisabled, {}, emcMaxClock, false, true);
}
tsl::elm::ListItem* latenciesSubmenu = new tsl::elm::ListItem("RAM Latency Editor");
latenciesSubmenu->setClickListener([](u64 keys) {
@@ -1211,7 +1226,7 @@ protected:
void listUI() override {
Result rc = hocclkIpcGetConfigValues(this->configList);
if (R_FAILED(rc)) [[unlikely]] { FatalGui::openWithResultCode("hocclkIpcGetConfigValues", rc); return; }
this->listElement->addItem(new tsl::elm::CategoryHeader("Memory Timings"));
this->listElement->addItem(new CompactCategoryHeader("Memory Timings"));
addConfigTrackbar(KipConfigValue_t1_tRCD, "t1 tRCD", ValueRange(0, 7, 1));
addConfigTrackbar(KipConfigValue_t2_tRP, "t2 tRP", ValueRange(0, 7, 1));
@@ -1292,11 +1307,144 @@ protected:
}
ValueThresholds thresholdsDisabled(0, 0);
this->listElement->addItem(new tsl::elm::CategoryHeader("Advanced"));
addConfigButton(KipConfigValue_timingEmcTbreak, "RAM-Timing tBreak", ValueRange(0, 1, 1, "", 1), "tBreak", &thresholdsDisabled, {}, timingTbreakFreqs, false, true);
addConfigTrackbar(KipConfigValue_low_t6_tRTW, "Low t6 tRTW", ValueRange(0, 9, 1));
addConfigTrackbar(KipConfigValue_low_t7_tWTR, "Low t7 tWTR", ValueRange(0, 9, 1));
addConfigTrackbar(KipConfigValue_t2_tRP_cap, "1333WL t2 RP Cap", ValueRange(0, 8, 1));
this->listElement->addItem(new CompactCategoryHeader("Advanced"));
if(IsMariko()) {
// tBreak / low-high timing graph (live, reads config each frame)
{
HocClkConfigValueList* cfgPtr = this->configList;
auto* tbreakGraph = new tsl::elm::CustomDrawer(
[cfgPtr](tsl::gfx::Renderer* renderer, s32 x, s32 y, s32 w, s32 h) {
const s32 t6 = (s32)cfgPtr->values[KipConfigValue_t6_tRTW];
const s32 t7 = (s32)cfgPtr->values[KipConfigValue_t7_tWTR];
const s32 lt6 = (s32)cfgPtr->values[KipConfigValue_low_t6_tRTW];
const s32 lt7 = (s32)cfgPtr->values[KipConfigValue_low_t7_tWTR];
const s32 t2c = (s32)cfgPtr->values[KipConfigValue_t2_tRP_cap];
const uint32_t tbk = (uint32_t)cfgPtr->values[KipConfigValue_timingEmcTbreak];
const tsl::Color cT6 = tsl::Color(4, 14, 15, 15);
const tsl::Color cT7 = tsl::Color(15, 9, 2, 15);
const tsl::Color cT2 = tsl::Color(12, 4, 15, 15);
const tsl::Color cAxis = tsl::Color(5, 5, 5, 15);
const tsl::Color cTbk = tsl::Color(7, 7, 7, 10);
const s32 gx = x + 52;
const s32 gw = w - 64;
const s32 gy = y + 14;
const s32 gh = 72;
const s32 axisY = gy + gh;
// Y: value 0 = bottom, value 9 = top
auto valY = [&](s32 v) -> s32 { return axisY - v * gh / 9; };
constexpr uint32_t kRMin = 1600000u, kRMax = 3300000u;
auto freqX = [&](uint32_t kHz) -> s32 {
if (kHz <= kRMin) return gx;
if (kHz >= kRMax) return gx + gw;
return gx + (s32)((uint64_t)(kHz - kRMin) * (uint32_t)gw / (kRMax - kRMin));
};
// Y-axis guide lines at 0, 3, 6, 9
for (int v : {0, 3, 6, 9}) {
char buf[4]; snprintf(buf, sizeof(buf), "%d", v);
renderer->drawString(buf, false, x + 4, valY(v) + 5, 12, cAxis);
renderer->drawRect(gx, valY(v), gw, 1, tsl::Color(3, 3, 3, 15));
}
renderer->drawRect(gx, gy, 1, gh + 1, cAxis);
renderer->drawRect(gx, axisY, gw, 1, cAxis);
// tBreak vertical divider
if (tbk != 0) {
s32 tx = freqX(tbk);
renderer->drawRect(tx, gy, 1, gh, cTbk);
}
// Step line: lowVal below tBreak, hiVal at/above tBreak
auto drawTimingLine = [&](s32 lowVal, s32 hiVal, const tsl::Color& c) {
if (tbk == 0 || tbk <= kRMin) {
s32 yy = valY(hiVal) + 1;
renderer->drawRect(gx, yy, gw, 2, c);
renderer->drawCircle(gx, yy + 1, 3, true, c);
renderer->drawCircle(gx + gw - 1, yy + 1, 3, true, c);
} else {
s32 tx = freqX(tbk);
s32 yLow = valY(lowVal) + 1;
s32 yHi = valY(hiVal) + 1;
renderer->drawRect(gx, yLow, tx - gx, 2, c);
renderer->drawRect(tx, yHi, gx + gw - tx, 2, c);
if (yLow != yHi) {
s32 topY = yLow < yHi ? yLow : yHi;
s32 botY = yLow > yHi ? yLow : yHi;
renderer->drawRect(tx, topY, 2, botY - topY + 2, c);
}
renderer->drawCircle(gx, yLow + 1, 3, true, c);
renderer->drawCircle(tx, yLow + 1, 3, true, c);
renderer->drawCircle(tx, yHi + 1, 3, true, c);
renderer->drawCircle(gx + gw - 1, yHi + 1, 3, true, c);
}
};
drawTimingLine(lt6, t6, cT6);
drawTimingLine(lt7, t7, cT7);
// t2 tRP cap: constant line
s32 yT2 = valY(t2c) + 1;
renderer->drawRect(gx, yT2, gw, 2, cT2);
renderer->drawCircle(gx, yT2 + 1, 3, true, cT2);
renderer->drawCircle(gx + gw - 1, yT2 + 1, 3, true, cT2);
// X-axis ruler with sideways bitmap-font labels
static const uint8_t kDigBmp[10][5] = {
{7,5,5,5,7},{6,2,2,2,7},{7,1,7,4,7},{7,1,3,1,7},{5,5,7,1,1},
{7,4,7,1,7},{7,4,7,5,7},{7,1,1,2,2},{7,5,7,5,7},{7,5,7,1,7},
};
const s32 pix = 2, charH = 3*pix, charW = 5*pix, charGap = 1;
auto drawSidewaysMHz = [&](uint32_t mhz, s32 cx, s32 startY, const tsl::Color& c) {
char buf[8]; snprintf(buf, sizeof(buf), "%u", mhz);
s32 ox = cx - charW / 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);
for (int r = 0; r < 5; r++)
for (int col = 0; col < 3; col++)
if ((kDigBmp[d][r] >> (2-col)) & 1)
renderer->drawRect(ox + (4-r)*pix, cy + col*pix, pix, pix, 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);
}
// Legend
s32 ly = y + h - 14;
renderer->drawRect(gx, ly, 14, 3, cT6);
renderer->drawString("t6 tRTW", false, gx + 17, ly + 5, 12, cT6);
renderer->drawRect(gx + 80, ly, 14, 3, cT7);
renderer->drawString("t7 tWTR", false, gx + 97, ly + 5, 12, cT7);
renderer->drawRect(gx + 165, ly, 14, 3, cT2);
renderer->drawString("t2 cap", false, gx + 182, ly + 5, 12, cT2);
}
);
tbreakGraph->setBoundaries(0, 0, tsl::cfg::FramebufferWidth, 150);
this->listElement->addItem(tbreakGraph);
}
addConfigButton(KipConfigValue_timingEmcTbreak, "RAM-Timing tBreak", ValueRange(0, 1, 1, "", 1), "tBreak", &thresholdsDisabled, {}, timingTbreakFreqs, false, true);
addConfigTrackbar(KipConfigValue_low_t6_tRTW, "Low t6 tRTW", ValueRange(0, 9, 1));
addConfigTrackbar(KipConfigValue_low_t7_tWTR, "Low t7 tWTR", ValueRange(0, 9, 1));
{
auto* spacer = new tsl::elm::CustomDrawer([](tsl::gfx::Renderer*, s32, s32, s32, s32){});
spacer->setBoundaries(0, 0, tsl::cfg::FramebufferWidth, 8);
this->listElement->addItem(spacer);
}
addConfigTrackbar(KipConfigValue_t2_tRP_cap, "1333WL t2 RP Cap", ValueRange(0, 8, 1));
}
addMappedConfigTrackbar(KipConfigValue_t6_tRTW_fine_tune, "t6 tRTW Fine Tune",
{0xFFFFFFFEu, 0xFFFFFFFFu, 0u, 1u, 2u},
{"-2", "-1", " 0", "+1", "+2"});
@@ -1310,10 +1458,17 @@ class RamLatenciesSubmenuGui : public MiscGui {
public:
RamLatenciesSubmenuGui() { }
tsl::elm::Element* baseUI() override {
auto* list = new TopAnchoredList();
this->listElement = list;
this->listUI();
return list;
}
protected:
void normalizeLatencies(const HocClkConfigValue keysArr[4]) {
uint32_t maxClock = (uint32_t)this->configList->values[KipConfigValue_marikoEmcMaxClock];
uint32_t maxClock = IsMariko() ? (uint32_t)this->configList->values[KipConfigValue_marikoEmcMaxClock] : (uint32_t)this->configList->values[KipConfigValue_eristaEmcMaxClock];
uint32_t vals[4];
for (int i = 0; i < 4; i++) {
@@ -1348,35 +1503,37 @@ protected:
void listUI() override {
ValueThresholds thresholdsDisabled(0, 0);
if (IsErista()) {
std::vector<NamedValue> rlLabels = { NamedValue("1333 RL", 28), NamedValue("1600 RL", 32), NamedValue("1866 RL", 36), NamedValue("2133 RL", 40) };
std::vector<NamedValue> wlLabels = { NamedValue("1333 WL", 12), NamedValue("1600 WL", 14), NamedValue("1866 WL", 16), NamedValue("2133 WL", 18) };
addConfigButton(KipConfigValue_mem_burst_read_latency, "Read Latency", ValueRange(0, 6, 1, "", 0), "Read Latency", &thresholdsDisabled, {}, rlLabels, false, true);
addConfigButton(KipConfigValue_mem_burst_write_latency, "Write Latency", ValueRange(0, 6, 1, "", 0), "Write Latency", &thresholdsDisabled, {}, wlLabels, false, true);
return;
}
Result rc = hocclkIpcGetConfigValues(this->configList);
if (R_FAILED(rc)) [[unlikely]] {
FatalGui::openWithResultCode("hocclkIpcGetConfigValues", rc);
return;
}
uint32_t maxClock = (uint32_t)this->configList->values[KipConfigValue_marikoEmcMaxClock];
uint32_t maxClock = IsMariko() ? (uint32_t)this->configList->values[KipConfigValue_marikoEmcMaxClock] : (uint32_t)this->configList->values[KipConfigValue_eristaEmcMaxClock];
RamDisplayUnit unit = (RamDisplayUnit)this->configList->values[HocClkConfigValue_RamDisplayUnit];
static const std::vector<uint32_t> kFreqOptions = {
1633000, 1666000, 1700000, 1733000, 1766000, 1800000,
1833000, 1866000, 1900000, 1933000, 1966000, 1996800, 2000000,
2033000, 2066000, 2100000, 2133000, 2166000, 2200000, 2233000,
2266000, 2300000, 2333000, 2366000, 2400000, 2433000, 2466000,
2500000, 2533000, 2566000, 2600000, 2633000, 2666000, 2700000,
2733000, 2766000, 2800000, 2833000, 2866000, 2900000, 2933000,
2966000, 3000000, 3033000, 3066000, 3100000, 3133000, 3166000,
3200000, 3233000, 3266000, 3300000,
};
static std::vector<uint32_t> kFreqOptions = { };
if (IsMariko()) {
kFreqOptions = {
1633000, 1666000, 1700000, 1733000, 1766000, 1800000,
1833000, 1866000, 1900000, 1933000, 1966000, 1996800, 2000000,
2033000, 2066000, 2100000, 2133000, 2166000, 2200000, 2233000,
2266000, 2300000, 2333000, 2366000, 2400000, 2433000, 2466000,
2500000, 2533000, 2566000, 2600000, 2633000, 2666000, 2700000,
2733000, 2766000, 2800000, 2833000, 2866000, 2900000, 2933000,
2966000, 3000000, 3033000, 3066000, 3100000, 3133000, 3166000,
3200000, 3233000, 3266000, 3300000,
};
} else {
kFreqOptions = {
1633000, 1666000, 1700000, 1733000, 1800000,
1833000, 1862400, 1881600, 1900800, 1920000, 1939200,
1958400, 1977600, 1996800, 2016000, 2035200, 2054400,
2073600, 2092800, 2112000, 2131200, 2150400, 2169600,
2188800, 2208000, 2227200, 2246400, 2265600, 2284800,
2304000, 2323200, 2342400, 2361600, 2380800, 2400000,
};
}
static const HocClkConfigValue kLatencyRKeys[4] = {
KipConfigValue_read_latency_1333,
@@ -1436,7 +1593,7 @@ protected:
for (int i = 0; i < 4; i++)
vals[i] = (uint32_t)this->configList->values[keysArr[i]];
uint32_t maxClock = (uint32_t)this->configList->values[KipConfigValue_marikoEmcMaxClock];
uint32_t maxClock = IsMariko() ? (uint32_t)this->configList->values[KipConfigValue_marikoEmcMaxClock] : (uint32_t)this->configList->values[KipConfigValue_eristaEmcMaxClock];
RamDisplayUnit unit = (RamDisplayUnit)this->configList->values[HocClkConfigValue_RamDisplayUnit];
auto resolveVal = [maxClock](uint32_t v) -> uint32_t {
@@ -1554,11 +1711,224 @@ protected:
this->configNamedValues[thisKey] = buildNamedValues(tierIdx);
};
this->listElement->addItem(new tsl::elm::CategoryHeader("Read Latency"));
this->listElement->addItem(new CompactCategoryHeader("Latency Graph"));
{
HocClkConfigValueList* cfgPtr = this->configList;
bool mariko = IsMariko();
auto* graph = new tsl::elm::CustomDrawer(
[cfgPtr, mariko](tsl::gfx::Renderer* renderer, s32 x, s32 y, s32 w, s32 h) {
static const HocClkConfigValue kR[4] = {
KipConfigValue_read_latency_1333, KipConfigValue_read_latency_1600,
KipConfigValue_read_latency_1866, KipConfigValue_read_latency_2133,
};
static const HocClkConfigValue kW[4] = {
KipConfigValue_write_latency_1333, KipConfigValue_write_latency_1600,
KipConfigValue_write_latency_1866, KipConfigValue_write_latency_2133,
};
uint32_t capMax = mariko
? (uint32_t)cfgPtr->values[KipConfigValue_marikoEmcMaxClock]
: (uint32_t)cfgPtr->values[KipConfigValue_eristaEmcMaxClock];
uint32_t rv[4], wv[4];
for (int i = 0; i < 4; i++) {
rv[i] = (uint32_t)cfgPtr->values[kR[i]];
wv[i] = (uint32_t)cfgPtr->values[kW[i]];
if (rv[i] == 0xFFFFFFFFu) rv[i] = capMax;
if (wv[i] == 0xFFFFFFFFu) wv[i] = capMax;
}
const tsl::Color cRead = tsl::Color(4, 14, 15, 15);
const tsl::Color cWrite = tsl::Color(15, 9, 2, 15);
const tsl::Color cMerge = tsl::Color(5, 15, 4, 15);
const tsl::Color cAxis = tsl::Color(5, 5, 5, 15);
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; };
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;
return gx + (s32)((uint64_t)(kHz - kRMin) * (uint32_t)gw / (kRMax - kRMin));
};
const char* tierLabels[4] = {"1333", "1600", "1866", "2133"};
for (int i = 0; i < 4; i++) {
renderer->drawString(tierLabels[i], false, x + 4, tierY(i) + 5, 12, cAxis);
renderer->drawRect(gx, tierY(i), gw, 1, cAxis);
}
renderer->drawRect(gx, gy, 1, gh + 1, cAxis);
renderer->drawRect(gx, axisY, gw, 1, cAxis);
struct LatSeg { int tier; uint32_t start, end; };
auto buildSegs = [&](const uint32_t* vals) -> std::vector<LatSeg> {
struct Pt { int tier; uint32_t freq; };
Pt pts[4]; int n = 0;
for (int i = 0; i < 4; i++)
if (vals[i] != 0) pts[n++] = {i, vals[i]};
if (n == 0) return {};
std::vector<LatSeg> segs;
uint32_t prev = kRMin;
for (int k = 0; k < n; k++) {
if (pts[k].freq > prev)
segs.push_back({pts[k].tier, prev, pts[k].freq});
prev = pts[k].freq;
}
if (prev < kRMax)
segs.push_back({pts[n-1].tier, prev, kRMax});
return segs;
};
auto rSegs = buildSegs(rv);
auto wSegs = buildSegs(wv);
auto drawSeriesSegs = [&](const std::vector<LatSeg>& segs,
const std::vector<LatSeg>& other,
const tsl::Color& c, s32 yOff)
{
for (const auto& seg : segs) {
s32 ty = tierY(seg.tier) + yOff;
s32 tyMrg = tierY(seg.tier);
struct Iv { uint32_t s, e; };
Iv ovlp[4]; int no = 0;
for (const auto& os : other) {
if (os.tier != seg.tier) continue;
uint32_t s = seg.start > os.start ? seg.start : os.start;
uint32_t e = seg.end < os.end ? seg.end : os.end;
if (s < e) ovlp[no++] = {s, e};
}
for (int a = 1; a < no; a++)
for (int b = a; b > 0 && ovlp[b-1].s > ovlp[b].s; b--)
{ auto t = ovlp[b]; ovlp[b] = ovlp[b-1]; ovlp[b-1] = t; }
uint32_t cur = seg.start;
for (int oi = 0; oi < no; oi++) {
if (cur < ovlp[oi].s) {
s32 x0 = freqX(cur), x1 = freqX(ovlp[oi].s);
if (x1 > x0) renderer->drawRect(x0, ty, x1-x0, 2, c);
}
s32 x0 = freqX(ovlp[oi].s), x1 = freqX(ovlp[oi].e);
if (x1 > x0) renderer->drawRect(x0, tyMrg, x1-x0, 2, cMerge);
cur = ovlp[oi].e;
}
if (cur < seg.end) {
s32 x0 = freqX(cur), x1 = freqX(seg.end);
if (x1 > x0) renderer->drawRect(x0, ty, x1-x0, 2, c);
}
}
for (int k = 0; k+1 < (int)segs.size(); k++) {
if (segs[k].end != segs[k+1].start) continue;
uint32_t transFreq = segs[k].end;
bool otherHere = false;
for (int j = 0; j+1 < (int)other.size(); j++)
if (other[j].end == transFreq && other[j+1].start == transFreq)
{ otherHere = true; break; }
s32 fx = freqX(transFreq);
s32 y1 = tierY(segs[k].tier) + yOff;
s32 y2 = tierY(segs[k+1].tier) + yOff;
s32 topY = y1 < y2 ? y1 : y2;
s32 botY = y1 > y2 ? y1 : y2;
if (botY > topY)
renderer->drawRect(fx, topY, 2, botY - topY + 2, otherHere ? cMerge : c);
}
};
drawSeriesSegs(rSegs, wSegs, cRead, 0);
drawSeriesSegs(wSegs, rSegs, cWrite, 0);
static const uint8_t kDigBmp[10][5] = {
{7,5,5,5,7}, // 0
{6,2,2,2,7}, // 1
{7,1,7,4,7}, // 2
{7,1,3,1,7}, // 3
{5,5,7,1,1}, // 4
{7,4,7,1,7}, // 5
{7,4,7,5,7}, // 6
{7,1,1,2,2}, // 7
{7,5,7,5,7}, // 8
{7,5,7,1,7}, // 9
};
const s32 charGap = 1;
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 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 * (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)*pixSize, cy + col*pixSize, pixSize, pixSize, c);
}
}
}
};
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
for (int i = 0; i < 4; i++) {
s32 ty = tierY(i) + 1;
bool merged = (rv[i] != 0 && rv[i] == wv[i]);
if (merged) {
renderer->drawCircle(freqX(rv[i]), ty, 4, true, cMerge);
} else {
if (rv[i]) renderer->drawCircle(freqX(rv[i]), ty, 4, true, cRead);
if (wv[i]) renderer->drawCircle(freqX(wv[i]), ty, 4, true, cWrite);
}
}
const s32 ly = axisY + 46;
renderer->drawRect(gx, ly, 14, 3, cRead);
renderer->drawString("Read", false, gx + 17, ly + 5, 12, cRead);
renderer->drawRect(gx + 60, ly, 14, 3, cWrite);
renderer->drawString("Write", false, gx + 77, ly + 5, 12, cWrite);
renderer->drawRect(gx + 125, ly, 14, 3, cMerge);
renderer->drawString("Same", false, gx + 142, ly + 5, 12, cMerge);
}
);
graph->setBoundaries(0, 0, tsl::cfg::FramebufferWidth, 150);
this->listElement->addItem(graph);
}
this->listElement->addItem(new CompactCategoryHeader("Read Latency"));
for (int i = 0; i < 4; i++)
addLatencyRow(kTierLabels[i], i, kLatencyRKeys);
this->listElement->addItem(new tsl::elm::CategoryHeader("Write Latency"));
this->listElement->addItem(new CompactCategoryHeader("Write Latency"));
for (int i = 0; i < 4; i++)
addLatencyRow(kTierLabels[i], i, kLatencyWKeys);
}
@@ -1582,7 +1952,7 @@ protected:
ValueThresholds eCpuClockThresholds(1785000, 2091000);
ValueThresholds eCpuClockThresholdsUV(2091000, 2193000);
this->listElement->addItem(new tsl::elm::CategoryHeader("CPU Settings"));
this->listElement->addItem(new CompactCategoryHeader("CPU Settings"));
if(IsMariko()) {
addConfigTrackbar(KipConfigValue_marikoCpuUVLow, "CPU Low UV", ValueRange(0, 8, 1));
addConfigTrackbar(KipConfigValue_marikoCpuUVHigh, "CPU High UV", ValueRange(0, 12, 1));
@@ -1644,7 +2014,7 @@ protected:
true
);
std::vector<NamedValue> maxClkOptions = {
NamedValue("1963 MHz", 1963500),
NamedValue("2091 MHz", 2091000),
@@ -1678,6 +2048,24 @@ protected:
NamedValue("2601 MHz", 2601000),
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),
NamedValue("1887 MHz", 1887000),
NamedValue("1963 MHz", 1963500),
NamedValue("2091 MHz", 2091000),
NamedValue("2193 MHz", 2193000),
NamedValue("2295 MHz", 2295000),
NamedValue("2397 MHz", 2397000),
NamedValue("2499 MHz", 2499000),
NamedValue("2601 MHz", 2601000),
NamedValue("2703 MHz", 2703000),
};
addConfigButton(
KipConfigValue_marikoCpuBoostClock,
@@ -1690,6 +2078,85 @@ protected:
false,
true
);
std::vector<NamedValue> emcMaxClock = {
NamedValue("1600 MHz", 1600000),
NamedValue("1633 MHz", 1633000),
NamedValue("1666 MHz", 1666000),
NamedValue("1700 MHz", 1700000),
NamedValue("1733 MHz", 1733000),
NamedValue("1766 MHz", 1766000),
NamedValue("1800 MHz", 1800000),
NamedValue("1833 MHz", 1833000),
NamedValue("1866 MHz", 1866000, "JEDEC."),
NamedValue("1900 MHz", 1900000),
NamedValue("1933 MHz", 1933000),
NamedValue("1966 MHz", 1966000),
NamedValue("1996 MHz", 1996800, "JEDEC."),
NamedValue("2000 MHz", 2000000),
NamedValue("2033 MHz", 2033000),
NamedValue("2066 MHz", 2066000),
NamedValue("2100 MHz", 2100000),
NamedValue("2133 MHz", 2133000, "JEDEC."),
NamedValue("2166 MHz", 2166000),
NamedValue("2200 MHz", 2200000),
NamedValue("2233 MHz", 2233000),
NamedValue("2266 MHz", 2266000),
NamedValue("2300 MHz", 2300000),
NamedValue("2333 MHz", 2333000),
NamedValue("2366 MHz", 2366000),
NamedValue("2400 MHz", 2400000, "JEDEC."),
NamedValue("2433 MHz", 2433000),
NamedValue("2466 MHz", 2466000),
NamedValue("2500 MHz", 2500000),
NamedValue("2533 MHz", 2533000),
NamedValue("2566 MHz", 2566000),
NamedValue("2600 MHz", 2600000),
NamedValue("2633 MHz", 2633000),
NamedValue("2666 MHz", 2666000, "JEDEC."),
NamedValue("2700 MHz", 2700000),
NamedValue("2733 MHz", 2733000),
NamedValue("2766 MHz", 2766000),
NamedValue("2800 MHz", 2800000),
NamedValue("2833 MHz", 2833000),
NamedValue("2866 MHz", 2866000),
NamedValue("2900 MHz", 2900000),
NamedValue("2933 MHz", 2933000, "JEDEC."),
NamedValue("2966 MHz", 2966000),
NamedValue("3000 MHz", 3000000),
NamedValue("3033 MHz", 3033000),
NamedValue("3066 MHz", 3066000),
NamedValue("3100 MHz", 3100000),
NamedValue("3133 MHz", 3133000),
NamedValue("3166 MHz", 3166000),
NamedValue("3200 MHz", 3200000, "JEDEC."),
NamedValue("3233 MHz", 3233000, "High speedo needed!"),
NamedValue("3266 MHz", 3266000, "High speedo needed!"),
NamedValue("3300 MHz", 3300000, "High speedo needed!"),
};
addConfigToggle(HocClkConfigValue_AutoRAMCPUOverclock, "Auto CPU RAM OC");
addConfigButton(
HocClkConfigValue_AutoRamCpuCpuOCFreq,
"Auto CPU RAM OC CPU clock",
ValueRange(0, 0, 1, "", 1),
"CPU Clock",
&thresholdsDisabled,
{},
ClkOptionsRamOc,
false,
false
);
addConfigButton(
HocClkConfigValue_AutoRamCpuRamOCThreshold,
"Auto CPU RAM OC Threshold",
ValueRange(0, 0, 1, "", 1),
"RAM Clock",
&thresholdsDisabled,
{},
emcMaxClock,
false,
false
);
} else {
addConfigTrackbar(KipConfigValue_eristaCpuUV, "CPU UV", ValueRange(0, 5, 1));
@@ -1698,7 +2165,7 @@ protected:
addConfigButton(
KipConfigValue_eristaCpuVmin,
"CPU VMIN",
ValueRange(700, 900, 25, "mV", 1),
ValueRange(750, 900, 25, "mV", 1),
"CPU VMIN",
&thresholdsDisabled,
{},
@@ -1762,82 +2229,10 @@ protected:
);
}
addConfigToggle(HocClkConfigValue_OverwriteBoostMode, nullptr);
addConfigToggle(HocClkConfigValue_LiveCpuUv, nullptr);
}
};
class RamTableEditor : public MiscGui {
public:
RamTableEditor() { }
protected:
void listUI() override {
Result rc = hocclkIpcGetConfigValues(this->configList);
if (R_FAILED(rc)) [[unlikely]] { FatalGui::openWithResultCode("hocclkIpcGetConfigValues", rc); return; }
this->listElement->addItem(new tsl::elm::CategoryHeader("RAM Frequency Editor"));
ValueThresholds thresholdsDisabled(0, 0);
// 1600000, 1331200, 1065600, 800000, 665600, 408000, 204000
RamDisplayUnit unit = (RamDisplayUnit)this->configList->values[HocClkConfigValue_RamDisplayUnit];
this->listElement->addItem(new tsl::elm::ListItem(formatMemClockKhzLabel(665600, unit)));
this->listElement->addItem(new tsl::elm::ListItem(formatMemClockKhzLabel(800000, unit)));
this->listElement->addItem(new tsl::elm::ListItem(formatMemClockKhzLabel(1065600, unit)));
this->listElement->addItem(new tsl::elm::ListItem(formatMemClockKhzLabel(1331200, unit)));
this->listElement->addItem(new tsl::elm::ListItem(formatMemClockKhzLabel(1600000, unit)));
ValueThresholds eristaRamThresholds(2208000, 2304000);
std::vector<NamedValue> eristaMaxEmcClock = {
NamedValue("Disabled", 1600000),
NamedValue("1633 MHz", 1633000),
NamedValue("1666 MHz", 1666000),
NamedValue("1700 MHz", 1700000),
NamedValue("1733 MHz", 1733000),
NamedValue("1766 MHz", 1766000),
NamedValue("1800 MHz", 1800000),
NamedValue("1833 MHz", 1833000),
NamedValue("1862 MHz", 1862400, "JEDEC."),
NamedValue("1881 MHz", 1881600),
NamedValue("1900 MHz", 1900800),
NamedValue("1920 MHz", 1920000),
NamedValue("1939 MHz", 1939200),
NamedValue("1958 MHz", 1958400),
NamedValue("1977 MHz", 1977600),
NamedValue("1996 MHz", 1996800, "JEDEC."),
NamedValue("2016 MHz", 2016000),
NamedValue("2035 MHz", 2035200),
NamedValue("2054 MHz", 2054400),
NamedValue("2073 MHz", 2073600),
NamedValue("2092 MHz", 2092800),
NamedValue("2112 MHz", 2112000),
NamedValue("2131 MHz", 2131200, "JEDEC."),
NamedValue("2150 MHz", 2150400),
NamedValue("2169 MHz", 2169600),
NamedValue("2188 MHz", 2188800),
NamedValue("2208 MHz", 2208000),
NamedValue("2227 MHz", 2227200),
NamedValue("2246 MHz", 2246400),
NamedValue("2265 MHz", 2265600),
NamedValue("2284 MHz", 2284800),
NamedValue("2304 MHz", 2304000),
NamedValue("2323 MHz", 2323200),
NamedValue("2342 MHz", 2342400),
NamedValue("2361 MHz", 2361600),
NamedValue("2380 MHz", 2380800),
NamedValue("2400 MHz", 2400000, "JEDEC."),
};
for (auto& nv : eristaMaxEmcClock)
if (nv.name != "Disabled")
nv.name = formatMemClockKhzLabel(nv.value, unit);
addConfigButtonS(KipConfigValue_eristaEmcMaxClock, "", ValueRange(0, 1, 1, "", 1), "", &eristaRamThresholds, {}, eristaMaxEmcClock, false, A_BTN, true);
addConfigButtonS(KipConfigValue_eristaEmcMaxClock1, "", ValueRange(0, 1, 1, "", 1), "", &eristaRamThresholds, {}, eristaMaxEmcClock, false, A_BTN, true);
addConfigButtonS(KipConfigValue_eristaEmcMaxClock2, "", ValueRange(0, 1, 1, "", 1), "", &eristaRamThresholds, {}, eristaMaxEmcClock, false, A_BTN, true);
};
};
class GpuSubmenuGui : public MiscGui {
public:
GpuSubmenuGui() { }
@@ -1849,7 +2244,7 @@ protected:
ValueThresholds thresholdsDisabled(0, 0);
std::vector<NamedValue> noNamedValues = {};
this->listElement->addItem(new tsl::elm::CategoryHeader("GPU Settings"));
this->listElement->addItem(new CompactCategoryHeader("GPU Settings"));
std::vector<NamedValue> gpuUvConf = {
NamedValue("HiOPT", 0),
@@ -1931,6 +2326,7 @@ protected:
// return false;
// });
addConfigButton(KipConfigValue_marikoGpuBootVolt, "GPU Boot Volt", ValueRange(700, 800, 5, "mV", 1), "GPU Boot Voltage", &thresholdsDisabled, {}, {}, false, true);
addConfigButton(KipConfigValue_marikoGpuVmin, "GPU VMIN", ValueRange(0, 0, 0, "0", 1), "GPU VMIN", &thresholdsDisabled, {}, mGpuVoltsVmin, false, true);
ValueThresholds MgpuVmaxThresholds(805, 850);
addConfigButton(
@@ -1988,7 +2384,6 @@ protected:
false
);
if (IsMariko()) {
std::vector<NamedValue> dvfsOffset = {
NamedValue("-80 mV", 0xFFFFFFB0),
NamedValue("-75 mV", 0xFFFFFFB5),
@@ -2031,7 +2426,6 @@ protected:
);
addConfigButton(HocClkConfigValue_DVFSOffset, "GPU DVFS Offset", ValueRange(0, 12, 1, "", 0), "GPU DVFS Offset", &thresholdsDisabled, {}, dvfsOffset, false);
}
tsl::elm::ListItem* customTableSubmenu = new tsl::elm::ListItem("GPU Voltage Table");
customTableSubmenu->setClickListener([](u64 keys) {
@@ -2059,7 +2453,7 @@ protected:
return;
}
this->listElement->addItem(new tsl::elm::CategoryHeader("GPU Custom Table (mV)"));
this->listElement->addItem(new CompactCategoryHeader("GPU Custom Table (mV)"));
ValueThresholds MgpuVmaxThresholds(800, 850);
ValueThresholds EgpuVmaxThresholds(950, 975);
@@ -2320,8 +2714,6 @@ void MiscGui::refresh() {
constexpr HocClkConfigValue emcKeys[] = {
KipConfigValue_marikoEmcMaxClock,
KipConfigValue_eristaEmcMaxClock,
KipConfigValue_eristaEmcMaxClock1,
KipConfigValue_eristaEmcMaxClock2,
};
for (auto key : emcKeys) {
auto it = this->configNamedValues.find(key);

View File

@@ -17,6 +17,28 @@
#pragma once
#include <tesla.hpp>
#include "../elements/base_frame.h"
class TopAnchoredList : public tsl::elm::List {
public:
TopAnchoredList() { m_hasSetInitialFocusHack = true; }
};
class BoxClippedList : public tsl::elm::List {
public:
void draw(tsl::gfx::Renderer* renderer) override {
renderer->enableScissoring(0, HOC_BOX_BOTTOM, tsl::cfg::FramebufferWidth, tsl::cfg::FramebufferHeight - HOC_BOX_BOTTOM);
tsl::elm::List::draw(renderer);
renderer->disableScissoring();
}
};
class CompactCategoryHeader : public tsl::elm::CategoryHeader {
public:
CompactCategoryHeader(const std::string& text) : tsl::elm::CategoryHeader(text) {}
void layout(u16 parentX, u16 parentY, u16 parentWidth, u16 parentHeight) override {
this->setBoundaries(this->getX(), this->getY(), this->getWidth(), 33);
}
};
class ImageElement : public tsl::elm::ListItem {
private:

View File

@@ -16,6 +16,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "ult_ext.h"
#include "value_choice_gui.h"
#include "../format.h"
#include "fatal_gui.h"

View File

@@ -28,9 +28,9 @@ INCLUDES := ../common/include src/hos src/soc src/i2c src/util src/pwr src/ipc
EXEFS_SRC := exefs_src
LIBNAMES := minIni
# major minor patch
TARGET_VERSION := 2.3.1
KIP_VERSION := 231
CUST_REV := 3
TARGET_VERSION := 2.4.0
KIP_VERSION := 240
CUST_REV := 4
#---------------------------------------------------------------------------------
# options for code generation

View File

@@ -76,7 +76,6 @@ namespace board {
u32 hidrev = *(u32*)(apbVirtAddr + APB_MISC_GP_HIDREV);
if (((hidrev >> 4) & 0xF) >= GP_HIDREV_MAJOR_T210B01) {
gSocType = HocClkSocType_Mariko;
CacheGpuVoltTable();
} else {
gSocType = HocClkSocType_Erista;
}
@@ -194,6 +193,7 @@ namespace board {
display::Initialize(&cfg);
CacheDfllData();
CacheGpuVoltTable();
}
void Exit() {

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

@@ -19,27 +19,48 @@
#include <fuse.h>
#include "board_fuse.hpp"
#include <cstring>
#include "board.hpp"
namespace board {
void SetGpuBracket(u16 speedo, u8 &gpuBracket) {
if (speedo <= 1624) {
gpuBracket = 0;
return;
}
if(GetSocType() == HocClkSocType_Mariko) {
if (speedo <= 1624) {
gpuBracket = 0;
return;
}
if (speedo <= 1689) {
gpuBracket = 1;
return;
}
if (speedo <= 1689) {
gpuBracket = 1;
return;
}
if (speedo <= 1753) {
gpuBracket = 2;
return;
}
if (speedo <= 1753) {
gpuBracket = 2;
return;
}
/* >= 1754 */
gpuBracket = 3;
/* >= 1754 */
gpuBracket = 3;
} else {
switch(speedo) {
case 1850 ... 1925:
gpuBracket = 0;
break;
case 1926 ... 2025:
gpuBracket = 1;
break;
case 2026 ... 2100:
gpuBracket = 2;
break;
case 2101 ... 2200:
gpuBracket = 3;
break;
default:
gpuBracket = 0;
break;
}
}
}
void ReadFuses(FuseData &speedo, u64 fuseVa) {

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;
}
}
@@ -358,8 +356,8 @@ namespace board {
continue;
}
/* Assuming mariko. */
const u32 vmax = 800;
/* 800mV on Mariko, 950mV on Erista. */
u32 vmax = GetSocType() == HocClkSocType_Mariko ? 800 : 950;
constexpr u32 GpuVoltageTableOffset = 312;
if (!std::memcmp(&buffer[index + GpuVoltageTableOffset], &vmax, sizeof(vmax))) {
std::memcpy(voltData.voltTable, &buffer[index + GpuVoltageTableOffset], sizeof(voltData.voltTable));
@@ -378,7 +376,7 @@ namespace board {
}
for(int i = 0; i < (int)std::size(voltData.voltTable); ++i) {
fileUtils::LogLine("[dvfs] gpu volt %d: %u mV", i, voltData.voltTable[i]);
fileUtils::LogLine("[dvfs] gpu volt %d: %u mV", i, voltData.voltTable[0][i]);
}
return;
}
@@ -421,42 +419,65 @@ namespace board {
}
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, }, // Bracket 0
{ 2300, 2366, 2433, 2466, 2533, 2566, 2633, 2700, 2733, 2800, 2833, 2900, 2933, 2966, 3033, 3066, 3100, 3133, 3166, 3200, 3233, 3266, }, // Bracket 1
{ 2433, 2466, 2533, 2566, 2600, 2666, 2766, 2800, 2833, 2866, 2933, 2966, 3033, 3066, 3100, 3133, 3166, 3200, 3233, 3300, 3333, 3366, }, // Bracket 2
{ 2500, 2533, 2600, 2633, 2666, 2733, 2800, 2866, 2900, 2966, 3033, 3100, 3166, 3200, 3233, 3266, 3300, 3333, 3366, 3400, 3400, 3400, }, // Bracket 3
};
u32 baseVolt = 800;
if(GetSocType() == HocClkSocType_Mariko) {
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, }, // Bracket 0
{ 2300, 2366, 2433, 2466, 2533, 2566, 2633, 2700, 2733, 2800, 2833, 2900, 2933, 2966, 3033, 3066, 3100, 3133, 3166, 3200, 3233, 3266, }, // Bracket 1
{ 2433, 2466, 2533, 2566, 2600, 2666, 2766, 2800, 2833, 2866, 2933, 2966, 3033, 3066, 3100, 3133, 3166, 3200, 3233, 3300, 3333, 3366, }, // Bracket 2
{ 2500, 2533, 2600, 2633, 2666, 2733, 2800, 2866, 2900, 2966, 3033, 3100, 3166, 3200, 3233, 3266, 3300, 3333, 3366, 3400, 3400, 3400, }, // Bracket 3
};
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, };
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; // DVFS doesnt work below 1600MHz, it will just use vMin
if (bracket >= std::size(ramTable)) bracket = 0;
if (freqMhz <= 1600) return 0; // DVFS doesnt work below 1600MHz, it will just use vMin
if (bracket >= std::size(ramTable)) bracket = 0;
u32 bracketStart = ramTable[bracket][0];
u32 bracketStart = ramTable[bracket][0];
u32 rampStartVolt = (bracket == 0) ? 535 : 525; // Do not touch!
u32 rampSpan = 590 - rampStartVolt;
u32 rampStartVolt = (bracket == 0) ? 535 : 525; // Do not touch!
u32 rampSpan = 590 - rampStartVolt;
if (freqMhz >= 1633 && freqMhz < bracketStart) {
u32 raw = rampStartVolt + ((freqMhz - 1633) * rampSpan) / (bracketStart - 1633);
u32 volt = ((raw + 2) / 5) * 5;
if (volt < rampStartVolt) volt = rampStartVolt;
if (volt > 590) volt = 590;
return volt;
}
if (freqMhz >= 1633 && freqMhz < bracketStart) {
u32 raw = rampStartVolt + ((freqMhz - 1633) * rampSpan) / (bracketStart - 1633);
u32 volt = ((raw + 2) / 5) * 5;
if (volt < rampStartVolt) volt = rampStartVolt;
if (volt > 590) volt = 590;
return volt;
}
u32 baseVolt = gpuVoltArray[std::size(gpuVoltArray) - 1];
for (u32 i = 0; i < std::size(gpuVoltArray); ++i) {
if (freqMhz <= ramTable[bracket][i]) {
baseVolt = gpuVoltArray[i];
break;
baseVolt = gpuVoltArray[std::size(gpuVoltArray) - 1];
for (u32 i = 0; i < std::size(gpuVoltArray); ++i) {
if (freqMhz <= ramTable[bracket][i]) {
baseVolt = gpuVoltArray[i];
break;
}
}
} else {
struct DvfsEntry { u32 freq; u32 volt; };
static const DvfsEntry ramTable[][19] = {
{ {1733,725}, {1800,730}, {1866,735}, {1920,740}, {1958,745}, {1996,750}, {2035,755}, {2073,760}, {2112,765}, {2131,770}, {2150,775}, {2169,780}, {2188,785}, {2227,790}, {2265,795}, {2304,800}, {2342,805}, {2380,810}, {2400,815} }, // Bracket 0
{ {1733,715}, {1800,720}, {1866,725}, {1920,730}, {1958,735}, {1996,740}, {2035,745}, {2073,750}, {2112,755}, {2131,760}, {2150,765}, {2169,770}, {2188,775}, {2227,780}, {2265,785}, {2304,790}, {2342,795}, {2380,800}, {2400,805} }, // Bracket 1
{ {1733,705}, {1800,710}, {1866,715}, {1920,720}, {1958,725}, {1996,730}, {2035,735}, {2073,740}, {2112,745}, {2131,750}, {2150,755}, {2169,760}, {2188,765}, {2227,770}, {2265,775}, {2304,780}, {2342,785}, {2380,790}, {2400,795} }, // Bracket 2
{ {1733,695}, {1800,700}, {1866,705}, {1920,710}, {1958,715}, {1996,720}, {2035,725}, {2073,730}, {2112,735}, {2131,740}, {2150,745}, {2169,750}, {2188,755}, {2227,760}, {2265,765}, {2304,770}, {2342,775}, {2380,780}, {2400,785} }, // Bracket 3
};
if (freqMhz <= 1600) return 0; // DVFS doesnt work below 1600MHz, it will just use vMin
if (bracket >= std::size(ramTable)) bracket = 0;
const auto& entries = ramTable[bracket];
baseVolt = entries[std::size(entries) - 1].volt;
for (const auto& entry : entries) {
if (freqMhz <= entry.freq) {
baseVolt = entry.volt;
break;
}
}
}
return baseVolt;
}
}

View File

@@ -480,4 +480,8 @@ namespace config {
return true;
}
void DeleteKey(const char* section, const char* key) {
std::scoped_lock lock{gConfigMutex};
ini_puts(section, key, NULL, gPath.c_str());
}
}

View File

@@ -55,7 +55,8 @@ namespace config {
bool SetConfigValues(HocClkConfigValueList* configValues, bool immediate);
bool ResetConfigValue(HocClkConfigValue kval);
bool SetConfigValue(HocClkConfigValue kval, std::uint64_t value, bool immediate = true);
void DeleteKey(const char* section, const char* key);
extern uint64_t configValues[HocClkConfigValue_EnumMax];
}

View File

@@ -24,7 +24,6 @@
namespace kip {
bool kipAvailable = false;
void SetKipData()
{
// TODO: figure out if this REALLY causes issues (i doubt it)
@@ -72,11 +71,9 @@ namespace kip {
CUST_WRITE_FIELD_BATCH(&table, commonEmcMemVolt, config::GetConfigValue(KipConfigValue_commonEmcMemVolt));
CUST_WRITE_FIELD_BATCH(&table, eristaEmcMaxClock, config::GetConfigValue(KipConfigValue_eristaEmcMaxClock));
CUST_WRITE_FIELD_BATCH(&table, eristaEmcMaxClock1, config::GetConfigValue(KipConfigValue_eristaEmcMaxClock1));
CUST_WRITE_FIELD_BATCH(&table, eristaEmcMaxClock2, config::GetConfigValue(KipConfigValue_eristaEmcMaxClock2));
CUST_WRITE_FIELD_BATCH(&table, marikoEmcMaxClock, config::GetConfigValue(KipConfigValue_marikoEmcMaxClock));
CUST_WRITE_FIELD_BATCH(&table, marikoEmcVddqVolt, config::GetConfigValue(KipConfigValue_marikoEmcVddqVolt));
CUST_WRITE_FIELD_BATCH(&table, emcDvbShift, config::GetConfigValue(KipConfigValue_emcDvbShift) > 8 && config::GetConfigValue(KipConfigValue_emcDvbShift) <= 16 ? 8 : config::GetConfigValue(KipConfigValue_emcDvbShift)); // 2.2.0 -> 2.3.0 compat
CUST_WRITE_FIELD_BATCH(&table, emcDvbShift, config::GetConfigValue(KipConfigValue_emcDvbShift));
CUST_WRITE_FIELD_BATCH(&table, marikoSocVmax, config::GetConfigValue(KipConfigValue_marikoSocVmax));
CUST_WRITE_FIELD_BATCH(&table, t1_tRCD, config::GetConfigValue(KipConfigValue_t1_tRCD));
@@ -104,8 +101,6 @@ namespace kip {
CUST_WRITE_FIELD_BATCH(&table, writeLatency1866, config::GetConfigValue(KipConfigValue_write_latency_1866));
CUST_WRITE_FIELD_BATCH(&table, writeLatency2133, config::GetConfigValue(KipConfigValue_write_latency_2133));
CUST_WRITE_FIELD_BATCH(&table, mem_burst_read_latency, config::GetConfigValue(KipConfigValue_mem_burst_read_latency));
CUST_WRITE_FIELD_BATCH(&table, mem_burst_write_latency, config::GetConfigValue(KipConfigValue_mem_burst_write_latency));
CUST_WRITE_FIELD_BATCH(&table, eristaCpuUV, config::GetConfigValue(KipConfigValue_eristaCpuUV));
CUST_WRITE_FIELD_BATCH(&table, eristaCpuVmin, config::GetConfigValue(KipConfigValue_eristaCpuVmin));
CUST_WRITE_FIELD_BATCH(&table, eristaCpuMaxVolt, config::GetConfigValue(KipConfigValue_eristaCpuMaxVolt));
@@ -127,10 +122,10 @@ namespace kip {
CUST_WRITE_FIELD_BATCH(&table, marikoGpuUV, config::GetConfigValue(KipConfigValue_marikoGpuUV));
CUST_WRITE_FIELD_BATCH(&table, marikoGpuVmin, config::GetConfigValue(KipConfigValue_marikoGpuVmin));
CUST_WRITE_FIELD_BATCH(&table, marikoGpuBootVolt, config::GetConfigValue(KipConfigValue_marikoGpuBootVolt));
CUST_WRITE_FIELD_BATCH(&table, marikoGpuVmax, config::GetConfigValue(KipConfigValue_marikoGpuVmax));
CUST_WRITE_FIELD_BATCH(&table, commonGpuVoltOffset, config::GetConfigValue(KipConfigValue_commonGpuVoltOffset));
CUST_WRITE_FIELD_BATCH(&table, gpuSpeedo, config::GetConfigValue(KipConfigValue_gpuSpeedo));
for (int i = 0; i < 24; i++) {
table.marikoGpuVoltArray[i] = config::GetConfigValue((HocClkConfigValue)(KipConfigValue_g_volt_76800 + i));
@@ -153,7 +148,7 @@ namespace kip {
configValues.values[KipCrc32] = (u64)crc32::checksum_file("sdmc:/atmosphere/kips/hoc.kip"); // write checksum
if (config::SetConfigValues(&configValues, false)) {
if (config::SetConfigValues(&configValues, true)) {
fileUtils::LogLine("[kip] KIP data set. CRC32: %ld (Cust Rev %ld)", configValues.values[KipCrc32], configValues.values[KipConfigValue_custRev]);
for (u64 i = KipConfigValue_hpMode; i < HocClkConfigValue_EnumMax; i++) {
fileUtils::LogLine("%s: %ld", hocclkFormatConfigValue((HocClkConfigValue)i, false), configValues.values[i]);
@@ -196,6 +191,7 @@ namespace kip {
// }
if ((u64)crc32::checksum_file("sdmc:/atmosphere/kips/hoc.kip") != config::GetConfigValue(KipCrc32) && !config::GetConfigValue(HocClkConfigValue_IsFirstLoad)) {
MigrateKipData(cust_get_cust_rev(&table), cust_get_kip_version(&table));
SetKipData();
notification::writeNotification("Horizon OC\nKIP has been updated\nPlease reboot your console");
return;
@@ -225,15 +221,14 @@ namespace kip {
clockManager::gContext.kipVersion = kipVersion;
configValues.values[KipConfigValue_custRev] = cust_get_cust_rev(&table);
configValues.values[KipConfigValue_KipVersion] = cust_get_kip_version(&table); // Run this after the check so we can do migration process
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) > 8 && cust_get_emc_dvb_shift(&table) <= 16 ? 8 : cust_get_emc_dvb_shift(&table); // 2.2.0 -> 2.3.0 compat
configValues.values[KipConfigValue_emcDvbShift] = cust_get_emc_dvb_shift(&table);
configValues.values[KipConfigValue_marikoSocVmax] = cust_get_marikoSocVmax(&table);
configValues.values[KipConfigValue_t1_tRCD] = cust_get_tRCD(&table);
@@ -261,9 +256,6 @@ namespace kip {
configValues.values[KipConfigValue_write_latency_1866] = cust_get_write_latency_1866(&table);
configValues.values[KipConfigValue_write_latency_2133] = cust_get_write_latency_2133(&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);
@@ -283,9 +275,9 @@ namespace kip {
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_marikoGpuBootVolt] = cust_get_mariko_gpu_boot_volt(&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::GetFuseData()->gpuSpeedo; // 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);
@@ -299,7 +291,7 @@ namespace kip {
configValues.values[KipConfigValue_t6_tRTW_fine_tune] = cust_get_tRTW_fine_tune(&table);
if (sizeof(HocClkConfigValueList) <= sizeof(configValues)) {
if (config::SetConfigValues(&configValues, false)) {
if (config::SetConfigValues(&configValues, true)) {
fileUtils::LogLine("[kip] KIP loaded. CRC32: %ld (Cust Rev %ld)", configValues.values[KipCrc32], configValues.values[KipConfigValue_custRev]);
for (u64 i = KipConfigValue_hpMode; i < HocClkConfigValue_EnumMax; i++) {
fileUtils::LogLine("%s: %ld", hocclkFormatConfigValue((HocClkConfigValue)i, false), configValues.values[i]);
@@ -313,5 +305,28 @@ namespace kip {
notification::writeNotification("Horizon OC\nConfig Buffer Mismatch");
}
}
void MigrateKipData(u32 custRev, u32 version) {
HocClkConfigValueList configValues;
config::GetConfigValues(&configValues);
u32 previousVersion = configValues.values[KipConfigValue_KipVersion];
if(previousVersion < 240 && version >= 240) {
// <2.4.0 -> 2.4.0 migration
// 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");
config::DeleteKey(CONFIG_VAL_SECTION, "tdp_limit_l");
}
config::SetConfigValues(&configValues, true);
}
}

View File

@@ -26,8 +26,6 @@
#include <notification.h>
#include <crc32.h>
#pragma pack(push, 1)
namespace kip {
extern bool kipAvailable;
@@ -38,8 +36,6 @@ namespace kip {
u32 hpMode;
u32 commonEmcMemVolt;
u32 eristaEmcMaxClock;
u32 eristaEmcMaxClock1;
u32 eristaEmcMaxClock2;
u32 stepMode;
u32 marikoEmcMaxClock;
u32 marikoEmcVddqVolt;
@@ -66,9 +62,6 @@ namespace kip {
u32 readLatency1333, readLatency1600, readLatency1866, readLatency2133;
u32 writeLatency1333, writeLatency1600, writeLatency1866, writeLatency2133;
u32 mem_burst_read_latency;
u32 mem_burst_write_latency;
u32 eristaCpuUV;
u32 eristaCpuVmin;
u32 eristaCpuMaxVolt;
@@ -90,12 +83,11 @@ namespace kip {
u32 marikoGpuUV;
u32 marikoGpuVmin;
u32 marikoGpuBootVolt;
u32 marikoGpuVmax;
u32 commonGpuVoltOffset;
u32 gpuSpeedo;
u32 eristaGpuVoltArray[27];
u32 marikoGpuVoltArray[24];
@@ -105,8 +97,6 @@ namespace kip {
u32 reserved[60];
} CustomizeTable;
#pragma pack(pop)
#define CUST_MAGIC "CUST"
#define CUST_MAGIC_LEN 4
@@ -212,8 +202,6 @@ namespace kip {
static inline bool cust_set_common_emc_volt(const char* p, u32 v) { CUST_WRITE_FIELD(p, commonEmcMemVolt, v); }
static inline bool cust_set_erista_emc_max(const char* p, u32 v) { CUST_WRITE_FIELD(p, eristaEmcMaxClock, v); }
static inline bool cust_set_erista_emc_max1(const char* p, u32 v) { CUST_WRITE_FIELD(p, eristaEmcMaxClock1, v); }
static inline bool cust_set_erista_emc_max2(const char* p, u32 v) { CUST_WRITE_FIELD(p, eristaEmcMaxClock2, v); }
static inline bool cust_set_step_mode(const char* p, u32 v) { CUST_WRITE_FIELD(p, stepMode, v); }
static inline bool cust_set_mariko_emc_max(const char* p, u32 v) { CUST_WRITE_FIELD(p, marikoEmcMaxClock, v); }
static inline bool cust_set_mariko_emc_vddq(const char* p, u32 v) { CUST_WRITE_FIELD(p, marikoEmcVddqVolt, v); }
@@ -244,9 +232,6 @@ namespace kip {
static inline bool cust_set_write_latency_1866(const char* p, u32 v) { CUST_WRITE_FIELD(p, writeLatency1866, v); }
static inline bool cust_set_write_latency_2133(const char* p, u32 v) { CUST_WRITE_FIELD(p, writeLatency2133, v); }
static inline bool cust_set_burst_read_lat(const char* p, u32 v) { CUST_WRITE_FIELD(p, mem_burst_read_latency, v); }
static inline bool cust_set_burst_write_lat(const char* p, u32 v) { CUST_WRITE_FIELD(p, mem_burst_write_latency, v); }
static inline bool cust_set_erista_cpu_uv(const char* p, u32 v) { CUST_WRITE_FIELD(p, eristaCpuUV, v); }
static inline bool cust_set_eristaCpuVmin(const char* p, u32 v) { CUST_WRITE_FIELD(p, eristaCpuVmin, v); }
static inline bool cust_set_erista_cpu_max_volt(const char* p, u32 v) { CUST_WRITE_FIELD(p, eristaCpuMaxVolt, v); }
@@ -264,9 +249,9 @@ namespace kip {
static inline bool cust_set_erista_gpu_vmin(const char* p, u32 v) { CUST_WRITE_FIELD(p, eristaGpuVmin, v); }
static inline bool cust_set_mariko_gpu_uv(const char* p, u32 v) { CUST_WRITE_FIELD(p, marikoGpuUV, v); }
static inline bool cust_set_mariko_gpu_vmin(const char* p, u32 v) { CUST_WRITE_FIELD(p, marikoGpuVmin, v); }
static inline bool cust_set_mariko_gpu_boot_volt(const char* p, u32 v) { CUST_WRITE_FIELD(p, marikoGpuBootVolt, v); }
static inline bool cust_set_mariko_gpu_vmax(const char* p, u32 v) { CUST_WRITE_FIELD(p, marikoGpuVmax, v); }
static inline bool cust_set_common_gpu_offset(const char* p, u32 v) { CUST_WRITE_FIELD(p, commonGpuVoltOffset, v); }
static inline bool cust_set_gpu_speedo(const char* p, u32 v) { CUST_WRITE_FIELD(p, gpuSpeedo, v); }
static inline bool cust_set_marikoCpuMaxClock(const char* p, u32 v) { CUST_WRITE_FIELD(p, marikoCpuMaxClock, v); }
static inline bool cust_set_marikoSocVmax(const char* p, u32 v) { CUST_WRITE_FIELD(p, marikoSocVmax, v); }
@@ -301,8 +286,6 @@ namespace kip {
static inline u32 cust_get_common_emc_volt(const CustomizeTable* t) { return CUST_GET_FIELD(t, commonEmcMemVolt); }
static inline u32 cust_get_erista_emc_max(const CustomizeTable* t) { return CUST_GET_FIELD(t, eristaEmcMaxClock); }
static inline u32 cust_get_erista_emc_max1(const CustomizeTable* t) { return CUST_GET_FIELD(t, eristaEmcMaxClock1); }
static inline u32 cust_get_erista_emc_max2(const CustomizeTable* t) { return CUST_GET_FIELD(t, eristaEmcMaxClock2); }
static inline u32 cust_get_step_mode(const CustomizeTable* t) { return CUST_GET_FIELD(t, stepMode); }
static inline u32 cust_get_mariko_emc_max(const CustomizeTable* t) { return CUST_GET_FIELD(t, marikoEmcMaxClock); }
static inline u32 cust_get_mariko_emc_vddq(const CustomizeTable* t) { return CUST_GET_FIELD(t, marikoEmcVddqVolt); }
@@ -333,9 +316,6 @@ namespace kip {
static inline u32 cust_get_write_latency_1866(const CustomizeTable* t) { return CUST_GET_FIELD(t, writeLatency1866); }
static inline u32 cust_get_write_latency_2133(const CustomizeTable* t) { return CUST_GET_FIELD(t, writeLatency2133); }
static inline u32 cust_get_burst_read_lat(const CustomizeTable* t) { return CUST_GET_FIELD(t, mem_burst_read_latency); }
static inline u32 cust_get_burst_write_lat(const CustomizeTable* t) { return CUST_GET_FIELD(t, mem_burst_write_latency); }
static inline u32 cust_get_erista_cpu_uv(const CustomizeTable* t) { return CUST_GET_FIELD(t, eristaCpuUV); }
static inline u32 cust_get_eristaCpuVmin(const CustomizeTable* t) { return CUST_GET_FIELD(t, eristaCpuVmin); }
static inline u32 cust_get_erista_cpu_max_volt(const CustomizeTable* t) { return CUST_GET_FIELD(t, eristaCpuMaxVolt); }
@@ -354,9 +334,9 @@ namespace kip {
static inline u32 cust_get_erista_gpu_vmin(const CustomizeTable* t) { return CUST_GET_FIELD(t, eristaGpuVmin); }
static inline u32 cust_get_mariko_gpu_uv(const CustomizeTable* t) { return CUST_GET_FIELD(t, marikoGpuUV); }
static inline u32 cust_get_mariko_gpu_vmin(const CustomizeTable* t) { return CUST_GET_FIELD(t, marikoGpuVmin); }
static inline u32 cust_get_mariko_gpu_boot_volt(const CustomizeTable* t) { return CUST_GET_FIELD(t, marikoGpuBootVolt); }
static inline u32 cust_get_mariko_gpu_vmax(const CustomizeTable* t) { return CUST_GET_FIELD(t, marikoGpuVmax); }
static inline u32 cust_get_common_gpu_offset(const CustomizeTable* t) { return CUST_GET_FIELD(t, commonGpuVoltOffset); }
static inline u32 cust_get_gpu_speedo(const CustomizeTable* t) { return CUST_GET_FIELD(t, gpuSpeedo); }
static inline u32 cust_get_marikoCpuMaxClock(const CustomizeTable* t) { return CUST_GET_FIELD(t, marikoCpuMaxClock); }
static inline u32 cust_get_marikoSocVmax(const CustomizeTable* t) { return CUST_GET_FIELD(t, marikoSocVmax); }
@@ -500,7 +480,7 @@ namespace kip {
DECL_MARIKO_GPU_VOLT_GET(1459200, 21)
DECL_MARIKO_GPU_VOLT_GET(1497600, 22)
DECL_MARIKO_GPU_VOLT_GET(1536000, 23)
void MigrateKipData(u32 custRev, u32 version);
void SetKipData();
void GetKipData();
}

View File

@@ -182,15 +182,30 @@ namespace clockManager {
std::uint32_t *hz = &gFreqTable[module].list[0];
gFreqTable[module].count = 0;
if (module == HocClkModule_GPU && board::GetSocType() == HocClkSocType_Mariko) {
constexpr u32 kStep = 38400000;
if (module == HocClkModule_GPU && board::GetSocType() == HocClkSocType_Mariko
&& config::GetConfigValue(HocClkConfigValue_MarikoMiddleFreqs)) {
constexpr u32 kStep = 38400000;
constexpr u32 kPcvStep = 76800000;
constexpr u32 kMax = 1228800000;
u32 kMax = ~0;
for (u32 i = 0; i < count; i++) {
for (u32 j = 0; j < count; j++) {
if (freqs[j] + kStep == freqs[i]) {
if (freqs[j] < kMax) kMax = freqs[j];
break;
}
}
}
if (kMax == ~0u) {
kMax = 0;
for (u32 i = 0; i < count; 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) {
if (!config::GetConfigValue(HocClkConfigValue_MarikoMiddleFreqs))
continue;
*hz = f;
gFreqTable[module].count++;
hz++;
@@ -216,11 +231,59 @@ namespace clockManager {
return;
}
board::SetMarikoGm20bCutoff(0);
for (std::uint32_t i = 0; i < count; i++) {
if (!IsAssignableHz(module, freqs[i])) {
continue;
}
// Workaround for PCV bug involving 38.4mhz step rate on erista
if (module == HocClkModule_GPU && board::GetSocType() == HocClkSocType_Erista) {
static const struct {
u32 hz;
HocClkConfigValue kval;
} eristaGpuVoltMap[] = {
{ 76800000, KipConfigValue_g_volt_e_76800 },
{ 115200000, KipConfigValue_g_volt_e_115200 },
{ 153600000, KipConfigValue_g_volt_e_153600 },
{ 192000000, KipConfigValue_g_volt_e_192000 },
{ 230400000, KipConfigValue_g_volt_e_230400 },
{ 268800000, KipConfigValue_g_volt_e_268800 },
{ 307200000, KipConfigValue_g_volt_e_307200 },
{ 345600000, KipConfigValue_g_volt_e_345600 },
{ 384000000, KipConfigValue_g_volt_e_384000 },
{ 422400000, KipConfigValue_g_volt_e_422400 },
{ 460800000, KipConfigValue_g_volt_e_460800 },
{ 499200000, KipConfigValue_g_volt_e_499200 },
{ 537600000, KipConfigValue_g_volt_e_537600 },
{ 576000000, KipConfigValue_g_volt_e_576000 },
{ 614400000, KipConfigValue_g_volt_e_614400 },
{ 652800000, KipConfigValue_g_volt_e_652800 },
{ 691200000, KipConfigValue_g_volt_e_691200 },
{ 729600000, KipConfigValue_g_volt_e_729600 },
{ 768000000, KipConfigValue_g_volt_e_768000 },
{ 806400000, KipConfigValue_g_volt_e_806400 },
{ 844800000, KipConfigValue_g_volt_e_844800 },
{ 883200000, KipConfigValue_g_volt_e_883200 },
{ 921600000, KipConfigValue_g_volt_e_921600 },
{ 960000000, KipConfigValue_g_volt_e_960000 },
{ 998400000, KipConfigValue_g_volt_e_998400 },
{1036800000, KipConfigValue_g_volt_e_1036800 },
{1075200000, KipConfigValue_g_volt_e_1075200 },
};
bool skip = false;
for (auto& entry : eristaGpuVoltMap) {
if (entry.hz == freqs[i]) {
if (config::GetConfigValue(entry.kval) == 2000) {
skip = true;
}
break;
}
}
if (skip) continue;
}
*hz = freqs[i];
fileUtils::LogLine("[mgr] %02u - %u - %u.%u MHz", gFreqTable[module].count, *hz, *hz / 1000000, *hz / 100000 - *hz / 1000000 * 10);
@@ -231,26 +294,30 @@ namespace clockManager {
fileUtils::LogLine("[mgr] count = %u", gFreqTable[module].count);
}
void HandleSafetyFeatures()
bool HandleSafetyFeatures(bool isBoost)
{
if (config::GetConfigValue(HocClkConfigValue_HandheldTDP) && (gContext.profile != HocClkProfile_Docked)) {
if (board::GetConsoleType() == HocClkConsoleType_Hoag) {
if (board::GetPowerMw(HocClkPowerSensor_Avg) < -(int)config::GetConfigValue(HocClkConfigValue_LiteTDPLimit)) {
ResetToStockClocks();
return;
}
} else {
if (board::GetPowerMw(HocClkPowerSensor_Avg) < -(int)config::GetConfigValue(HocClkConfigValue_HandheldTDPLimit)) {
ResetToStockClocks();
return;
}
}
}
if (((tmp451TempSoc() / 1000) > (int)config::GetConfigValue(HocClkConfigValue_ThermalThrottleThreshold)) && config::GetConfigValue(HocClkConfigValue_ThermalThrottle)) {
ResetToStockClocks();
return;
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()
{
@@ -305,7 +372,7 @@ namespace clockManager {
void DVFSReset()
{
if (board::GetSocType() == HocClkSocType_Mariko && config::GetConfigValue(HocClkConfigValue_DVFSMode) == DVFSMode_Hijack) {
if (config::GetConfigValue(HocClkConfigValue_DVFSMode) == DVFSMode_Hijack) {
board::PcvHijackGpuVolts(0); // Reset to vMin
u32 targetHz = gContext.overrideFreqs[HocClkModule_GPU];
@@ -437,7 +504,7 @@ namespace clockManager {
);
// The logic MUST be done in this order otherwise you WILL get crashes
if (module == HocClkModule_MEM && board::GetSocType() == HocClkSocType_Mariko && targetHz > oldHz && config::GetConfigValue(HocClkConfigValue_DVFSMode) == DVFSMode_Hijack) {
if (module == HocClkModule_MEM && targetHz > oldHz && config::GetConfigValue(HocClkConfigValue_DVFSMode) == DVFSMode_Hijack) {
ApplyGpuDvfs(targetHz);
}
@@ -448,11 +515,11 @@ namespace clockManager {
gContext.stable.freqs[module] = nearestHz;
}
if (module == HocClkModule_MEM && board::GetSocType() == HocClkSocType_Mariko && targetHz < oldHz && config::GetConfigValue(HocClkConfigValue_DVFSMode) == DVFSMode_Hijack) {
if (module == HocClkModule_MEM && targetHz < oldHz && config::GetConfigValue(HocClkConfigValue_DVFSMode) == DVFSMode_Hijack) {
ApplyGpuDvfs(targetHz);
}
if(module == HocClkModule_MEM && board::GetSocType() == HocClkSocType_Mariko && config::GetConfigValue(HocClkConfigValue_DVFSMode) == DVFSMode_Hijack)
if(module == HocClkModule_MEM && config::GetConfigValue(HocClkConfigValue_DVFSMode) == DVFSMode_Hijack)
didHijackPcv = false;
}
} else {
@@ -486,7 +553,7 @@ namespace clockManager {
// restore clocks to stock values on app or profile change
if (hasChanged) {
board::ResetToStock();
if (board::GetSocType() == HocClkSocType_Mariko && config::GetConfigValue(HocClkConfigValue_DVFSMode) == DVFSMode_Hijack) {
if (config::GetConfigValue(HocClkConfigValue_DVFSMode) == DVFSMode_Hijack) {
board::PcvHijackGpuVolts(0);
board::ResetToStockGpu();
}
@@ -703,11 +770,11 @@ namespace clockManager {
bool isBoost = apmExtIsBoostMode(mode);
HandleSafetyFeatures();
bool shouldSkipClockSet = HandleSafetyFeatures(isBoost);
HandleMiscFeatures();
// GPU clock should always be the same unless PCV has overwriten our change, so reset it
if (RefreshContext() || config::Refresh() || board::GetRealHz(HocClkModule_GPU) != gContext.freqs[HocClkModule_GPU]) {
if ((RefreshContext() || config::Refresh() || (board::GetRealHz(HocClkModule_GPU) != gContext.freqs[HocClkModule_GPU])) && !shouldSkipClockSet) {
SetClocks(isBoost);
}
}

View File

@@ -162,6 +162,15 @@ namespace governor {
if (++cpuTick > 50) {
minHz = config::GetConfigValue(HocClkConfigValue_CpuGovernorMinimumFreq);
if (config::GetConfigValue(HocClkConfigValue_AutoRAMCPUOverclock)) {
u32 ramHz = clockManager::gContext.freqs[HocClkModule_MEM];
u32 threshold = (u32)config::GetConfigValue(HocClkConfigValue_AutoRamCpuRamOCThreshold) * 1000;
if (ramHz >= threshold) {
u32 overrideHz = (u32)config::GetConfigValue(HocClkConfigValue_AutoRamCpuCpuOCFreq) * 1000;
if (overrideHz > minHz)
minHz = overrideHz;
}
}
cpuTick = 0;
}

34
build_noexo.sh Normal file
View File

@@ -0,0 +1,34 @@
#!/bin/sh
CORES="$(nproc --all)"
SRC="Source/Atmosphere/stratosphere/loader/"
DEST="build/stratosphere/loader/"
mkdir -p "dist/atmosphere/kips/"
mkdir -p "$DEST"
echo
echo "*** Patching loader ***"
cp -vr "$SRC"/. "$DEST"/
echo
echo "CORES: $CORES"
echo
echo "*** Compiling loader ***"
cd build/stratosphere/loader || exit 1
make -j$CORES
hactool -t kip1 out/nintendo_nx_arm64_armv8a/release/loader.kip --uncompress=hoc.kip
cd ../../../ # exit
cp -v build/stratosphere/loader/hoc.kip dist/atmosphere/kips/hoc.kip
cd Source/hoc-clk/
./build.sh
cp -r dist/ ../../
cd ../../
echo "*** Compiling horizon-oc-monitor ***"
cd Source/Horizon-OC-Monitor/
make -j$CORES
cp -v Horizon-OC-Monitor.ovl ../../dist/switch/.overlays/Horizon-OC-Monitor.ovl

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.