Compare commits
60 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
86a2800e6e | ||
|
|
13550fbc20 | ||
|
|
187d6d6422 | ||
|
|
060178aea6 | ||
|
|
715577a644 | ||
|
|
45332444ec | ||
|
|
fd3808fd82 | ||
|
|
e13e2b1f41 | ||
|
|
6b26aa5574 | ||
|
|
13f422fa29 | ||
|
|
fa66a09b04 | ||
|
|
5d9c7acc52 | ||
|
|
52076a0191 | ||
|
|
08936d9466 | ||
|
|
45ed9afb04 | ||
|
|
1358b10616 | ||
|
|
e9f5f59ddf | ||
|
|
67be6d9120 | ||
|
|
749fd385ce | ||
|
|
65927cffce | ||
|
|
10bcf4542d | ||
|
|
8bc1aee110 | ||
|
|
ca4b132f25 | ||
|
|
afeee4937c | ||
|
|
66308b152b | ||
|
|
72dfdb53fc | ||
|
|
ee730ca68e | ||
|
|
2d0a2c4f6d | ||
|
|
8411a14b26 | ||
|
|
99e9270314 | ||
|
|
58488f7f48 | ||
|
|
c2238eb070 | ||
|
|
4271efb4a7 | ||
|
|
fd9e5a2e08 | ||
|
|
4587b01152 | ||
|
|
fae0fa5d5f | ||
|
|
059fe40339 | ||
|
|
a617a7398a | ||
|
|
2f092f7955 | ||
|
|
003854d2bb | ||
|
|
f49e1a80a0 | ||
|
|
16ea883fa8 | ||
|
|
f787ed7fd8 | ||
|
|
63c7fb211d | ||
|
|
52e13f5e1e | ||
|
|
797bcf79a2 | ||
|
|
0d227cfb82 | ||
|
|
3010c915a7 | ||
|
|
196933a6b3 | ||
|
|
bfc93c6238 | ||
|
|
6d284d9c2b | ||
|
|
7384404ac1 | ||
|
|
35de44d3fa | ||
|
|
1b07df5f08 | ||
|
|
34e1f39510 | ||
|
|
ef830ce3f6 | ||
|
|
d7e22b3ccc | ||
|
|
d6c2ddf2ea | ||
|
|
b4627ad171 | ||
|
|
381a1eafc4 |
@@ -56,6 +56,7 @@ It enables advanced CPU, GPU, and RAM tuning with user-friendly configuration to
|
||||
|
||||
```
|
||||
kip1=atmosphere/kips/hoc.kip
|
||||
secmon=atmosphere/exosphere.bin
|
||||
```
|
||||
|
||||
*(No changes needed if using fusee.)*
|
||||
|
||||
@@ -37,8 +37,6 @@ volatile CustomizeTable C = {
|
||||
|
||||
.commonEmcMemVolt = 1175000, /* LPDDR4(X) JEDEC Specification */
|
||||
.eristaEmcMaxClock = 1600000, /* Maximum HB-MGCH ram rating */
|
||||
.eristaEmcMaxClock1 = 1600000,
|
||||
.eristaEmcMaxClock2 = 1600000,
|
||||
|
||||
/* Available: 66MHz step rate, 100MHz step rate, 133MHz step rate and jedec. */
|
||||
/* Jedec freqs are 1333MHz, 1600MHz, 1866MHz, 2133MHz, 2400MHz, 2666MHz, 2933MHz, 3200MHz. */
|
||||
@@ -47,7 +45,7 @@ volatile CustomizeTable C = {
|
||||
.marikoEmcMaxClock = 2133000, /* 1866MHz @ 1866tWRL is guaranteed to work on all Mariko units */
|
||||
.marikoEmcVddqVolt = 600000,
|
||||
|
||||
.emcDvbShift = 0,
|
||||
.emcDvbShift = 0,
|
||||
.marikoSocVmax = 0, /* 0 = stock limits (1450 - 1597 is 1050mV, 1598-1708 is 1025mV, 1709+ is 1000mV). */
|
||||
|
||||
/* Primary. */
|
||||
@@ -84,37 +82,21 @@ 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
|
||||
*/
|
||||
|
||||
.mem_burst_read_latency = RL_1600,
|
||||
.mem_burst_write_latency = WL_1600,
|
||||
|
||||
.eristaCpuUV = 0,
|
||||
.eristaCpuVmin = 800,
|
||||
.eristaCpuUV = 0,
|
||||
.eristaCpuVmin = 800,
|
||||
.eristaCpuMaxVolt = 1200,
|
||||
/* Unlocks up to 2397 Mhz CPU, usage is not recommended. */
|
||||
.eristaCpuUnlock = DISABLED,
|
||||
.eristaCpuUnlock = DISABLED,
|
||||
|
||||
.marikoCpuUVLow = 0, // No undervolt
|
||||
.marikoCpuUVLow = 0, // No undervolt
|
||||
.marikoCpuUVHigh = 0, // No undervolt
|
||||
|
||||
.tableConf = TBREAK_1683,
|
||||
.marikoCpuLowVmin = 620,
|
||||
.tableConf = TBREAK_1683,
|
||||
.marikoCpuLowVmin = 620,
|
||||
.marikoCpuHighVmin = 750,
|
||||
|
||||
/* 1120mV is NVIDIA rating */
|
||||
.marikoCpuMaxVolt = 1120,
|
||||
.marikoCpuMaxVolt = 1120,
|
||||
|
||||
/* Supported values: 1963500, 2091000, 2193000, 2295000, 2397000, 2499000, 2601000, 2703000. */
|
||||
/* 1963500 is official rating of T214/Mariko, fully safe. */
|
||||
@@ -125,29 +107,24 @@ volatile CustomizeTable C = {
|
||||
/* 2703000 is potentially dangerous and not advised. */
|
||||
.marikoCpuMaxClock = 1963500,
|
||||
|
||||
.eristaCpuBoostClock = 1785000, // Default boost clock
|
||||
.marikoCpuBoostClock = 1963500, // Default boost clock
|
||||
.eristaCpuBoostClock = 1785000, /* Default boost clock */
|
||||
.marikoCpuBoostClock = 1963500, /* Default boost clock */
|
||||
|
||||
.eristaGpuUV = 0,
|
||||
.eristaGpuUV = 0,
|
||||
.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) */
|
||||
/* You can overwrite auto with any voltage (in mv) of your choice - offset will not be applied. */
|
||||
|
||||
.eristaGpuVoltArray = {
|
||||
AUTO /* 76 */,
|
||||
AUTO /* 115 */,
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#define CUST_REV 3
|
||||
#define KIP_VERSION 230
|
||||
#define CUST_REV 4
|
||||
#define KIP_VERSION 240
|
||||
|
||||
#include "oc_common.hpp"
|
||||
#include "pcv/pcv_common.hpp"
|
||||
@@ -30,8 +30,8 @@ namespace ams::ldr::hoc {
|
||||
|
||||
enum TableConfig: u32 {
|
||||
DEFAULT_TABLE = 1,
|
||||
TBREAK_1581 = 2,
|
||||
TBREAK_1683 = 3,
|
||||
TBREAK_1581 = 2,
|
||||
TBREAK_1683 = 3,
|
||||
EXTREME_TABLE = 4,
|
||||
};
|
||||
|
||||
@@ -42,19 +42,6 @@ enum StepMode: u32 {
|
||||
StepMode_133MHz = 3,
|
||||
};
|
||||
|
||||
/*
|
||||
* Read:
|
||||
* 2133RL = 40
|
||||
* 1866RL = 36
|
||||
* 1600RL = 32
|
||||
* 1331RL = 28
|
||||
* Write:
|
||||
* 2133WL = 18
|
||||
* 1866WL = 16
|
||||
* 1600WL = 14
|
||||
* 1331WL = 12
|
||||
*/
|
||||
|
||||
enum ReadLatency: u32 {
|
||||
RL_2133 = 40,
|
||||
RL_1866 = 36,
|
||||
@@ -74,11 +61,8 @@ using CustomizeGpuDvfsTable = pcv::cvb_entry_t[pcv::DvfsTableEntryLimit];
|
||||
static_assert(sizeof(CustomizeCpuDvfsTable) == sizeof(CustomizeGpuDvfsTable));
|
||||
static_assert(sizeof(CustomizeCpuDvfsTable) == sizeof(pcv::cvb_entry_t) * pcv::DvfsTableEntryLimit);
|
||||
|
||||
constexpr uint32_t ERISTA_MTC_MAGIC = 0x43544D45; // EMTC
|
||||
constexpr uint32_t MARIKO_MTC_MAGIC = 0x43544D4D; // MMTC
|
||||
|
||||
struct CustomizeTable {
|
||||
u8 cust[4] = {'C', 'U', 'S', 'T'};
|
||||
u8 cust[4] = {'C', 'U', 'S', 'T'};
|
||||
u32 custRev = CUST_REV;
|
||||
u32 kipVersion = KIP_VERSION;
|
||||
|
||||
@@ -86,8 +70,6 @@ struct CustomizeTable {
|
||||
|
||||
u32 commonEmcMemVolt;
|
||||
u32 eristaEmcMaxClock;
|
||||
u32 eristaEmcMaxClock1;
|
||||
u32 eristaEmcMaxClock2;
|
||||
|
||||
StepMode stepMode;
|
||||
u32 marikoEmcMaxClock;
|
||||
@@ -113,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;
|
||||
@@ -137,12 +116,11 @@ struct CustomizeTable {
|
||||
|
||||
u32 marikoGpuUV;
|
||||
u32 marikoGpuVmin;
|
||||
u32 marikoGpuBootVolt;
|
||||
u32 marikoGpuVmax;
|
||||
|
||||
u32 commonGpuVoltOffset;
|
||||
|
||||
u32 gpuSpeedo;
|
||||
|
||||
u32 eristaGpuVoltArray[27];
|
||||
u32 marikoGpuVoltArray[24];
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -18,6 +18,6 @@
|
||||
|
||||
namespace ams::ldr::hoc::pcv::erista {
|
||||
|
||||
void CalculateTimings(double tCK_avg);
|
||||
void CalculateTimings(double tCK_avg, u32 freq);
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -66,27 +66,32 @@ namespace ams::ldr::hoc {
|
||||
size_t maximum_patched_count = 0;
|
||||
patternFn pattern_search_fn = nullptr;
|
||||
Pointer value_search;
|
||||
|
||||
size_t patched_count = 0;
|
||||
|
||||
Result Apply(Pointer* ptr) {
|
||||
Result Apply(Pointer *ptr) {
|
||||
Result res = patcher_fn(ptr);
|
||||
if (R_SUCCEEDED(res))
|
||||
if (R_SUCCEEDED(res)) {
|
||||
patched_count++;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
Result SearchAndApply(Pointer* ptr) {
|
||||
Result SearchAndApply(Pointer *ptr) {
|
||||
bool searchOk = false;
|
||||
if (pattern_search_fn) {
|
||||
if (pattern_search_fn(ptr)) searchOk = true;
|
||||
if (pattern_search_fn(ptr)) {
|
||||
searchOk = true;
|
||||
}
|
||||
} else {
|
||||
if (value_search == *(ptr)) searchOk = true;
|
||||
if (value_search == *(ptr)) {
|
||||
searchOk = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (searchOk)
|
||||
if (searchOk) {
|
||||
return Apply(ptr);
|
||||
}
|
||||
|
||||
R_THROW(ldr::ResultUnsuccessfulPatcher());
|
||||
}
|
||||
@@ -94,8 +99,9 @@ namespace ams::ldr::hoc {
|
||||
Result CheckResult() {
|
||||
R_UNLESS(patched_count > 0, ldr::ResultUnsuccessfulPatcher());
|
||||
|
||||
if (maximum_patched_count)
|
||||
if (maximum_patched_count) {
|
||||
R_UNLESS(patched_count <= maximum_patched_count, ldr::ResultUnsuccessfulPatcher());
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
@@ -22,20 +22,20 @@
|
||||
|
||||
namespace ams::ldr::hoc::pcv {
|
||||
|
||||
Result MemFreqPllmLimit(u32* ptr) {
|
||||
clk_pll_param* entry = reinterpret_cast<clk_pll_param *>(ptr);
|
||||
Result MemFreqPllmLimit(u32 *ptr) {
|
||||
clk_pll_param *entry = reinterpret_cast<clk_pll_param *>(ptr);
|
||||
R_UNLESS(entry->freq == entry->vco_max, ldr::ResultInvalidMemPllmEntry());
|
||||
|
||||
// Double the max clk simply
|
||||
u32 max_clk = entry->freq * 2;
|
||||
entry->freq = max_clk;
|
||||
u32 max_clk = entry->freq * 2;
|
||||
entry->freq = max_clk;
|
||||
entry->vco_max = max_clk;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result MemVoltHandler(u32* ptr) {
|
||||
Result MemVoltHandler(u32 *ptr) {
|
||||
// ptr value might be default_uv or max_uv
|
||||
regulator* entries[2] = {
|
||||
regulator *entries[2] = {
|
||||
reinterpret_cast<regulator *>(reinterpret_cast<u8 *>(ptr) - offsetof(regulator, type_1.default_uv)),
|
||||
reinterpret_cast<regulator *>(reinterpret_cast<u8 *>(ptr) - offsetof(regulator, type_1.max_uv)),
|
||||
};
|
||||
@@ -44,16 +44,16 @@ namespace ams::ldr::hoc::pcv {
|
||||
constexpr u32 uv_min = 600'000;
|
||||
|
||||
auto validator = [](regulator* entry) {
|
||||
R_UNLESS(entry->id == 1, ldr::ResultInvalidRegulatorEntry());
|
||||
R_UNLESS(entry->type == 1, ldr::ResultInvalidRegulatorEntry());
|
||||
R_UNLESS(entry->id == 1, ldr::ResultInvalidRegulatorEntry());
|
||||
R_UNLESS(entry->type == 1, ldr::ResultInvalidRegulatorEntry());
|
||||
R_UNLESS(entry->type_1.volt_reg == 0x17, ldr::ResultInvalidRegulatorEntry());
|
||||
R_UNLESS(entry->type_1.step_uv == uv_step, ldr::ResultInvalidRegulatorEntry());
|
||||
R_UNLESS(entry->type_1.min_uv == uv_min, ldr::ResultInvalidRegulatorEntry());
|
||||
R_UNLESS(entry->type_1.step_uv == uv_step, ldr::ResultInvalidRegulatorEntry());
|
||||
R_UNLESS(entry->type_1.min_uv == uv_min, ldr::ResultInvalidRegulatorEntry());
|
||||
R_SUCCEED();
|
||||
};
|
||||
|
||||
regulator* entry = nullptr;
|
||||
for (auto& i : entries) {
|
||||
regulator *entry = nullptr;
|
||||
for (auto &i : entries) {
|
||||
if (R_SUCCEEDED(validator(i))) {
|
||||
entry = i;
|
||||
}
|
||||
@@ -76,24 +76,25 @@ namespace ams::ldr::hoc::pcv {
|
||||
}
|
||||
|
||||
void SafetyCheck() {
|
||||
// if (C.custRev != CUST_REV)
|
||||
// CRASH("Triggered");
|
||||
|
||||
struct sValidator {
|
||||
volatile u32 value;
|
||||
u32 min;
|
||||
u32 max;
|
||||
bool value_required = false;
|
||||
u32 panic;
|
||||
bool value_required = false;
|
||||
|
||||
Result check() {
|
||||
if (!value_required && !value)
|
||||
if (!value_required && !value) {
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
if (min && value < min)
|
||||
if (min && value < min) {
|
||||
R_THROW(ldr::ResultSafetyCheckFailure());
|
||||
if (max && value > max)
|
||||
}
|
||||
|
||||
if (max && value > max) {
|
||||
R_THROW(ldr::ResultSafetyCheckFailure());
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
@@ -102,28 +103,24 @@ namespace ams::ldr::hoc::pcv {
|
||||
u32 eristaCpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaCpuDvfsTable)->freq);
|
||||
u32 marikoCpuDvfsMaxFreq;
|
||||
if (C.marikoCpuUVHigh) {
|
||||
marikoCpuDvfsMaxFreq = static_cast<u32>(
|
||||
GetDvfsTableLastEntry(C.marikoCpuDvfsTableSLT)->freq
|
||||
);
|
||||
marikoCpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.marikoCpuDvfsTableSLT)->freq);
|
||||
} else {
|
||||
marikoCpuDvfsMaxFreq = static_cast<u32>(
|
||||
GetDvfsTableLastEntry(C.marikoCpuDvfsTable)->freq
|
||||
);
|
||||
marikoCpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.marikoCpuDvfsTable)->freq);
|
||||
}
|
||||
u32 eristaGpuDvfsMaxFreq;
|
||||
switch (C.eristaGpuUV) {
|
||||
case 0:
|
||||
eristaGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaGpuDvfsTable)->freq);
|
||||
break;
|
||||
case 1:
|
||||
eristaGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaGpuDvfsTableSLT)->freq);
|
||||
break;
|
||||
case 2:
|
||||
eristaGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaGpuDvfsTableHiOPT)->freq);
|
||||
break;
|
||||
default:
|
||||
eristaGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaGpuDvfsTable)->freq);
|
||||
break;
|
||||
case 0:
|
||||
eristaGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaGpuDvfsTable)->freq);
|
||||
break;
|
||||
case 1:
|
||||
eristaGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaGpuDvfsTableSLT)->freq);
|
||||
break;
|
||||
case 2:
|
||||
eristaGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaGpuDvfsTableHiOPT)->freq);
|
||||
break;
|
||||
default:
|
||||
eristaGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaGpuDvfsTable)->freq);
|
||||
break;
|
||||
}
|
||||
|
||||
u32 marikoGpuDvfsMaxFreq;
|
||||
@@ -142,22 +139,21 @@ namespace ams::ldr::hoc::pcv {
|
||||
break;
|
||||
}
|
||||
|
||||
using namespace ams::ldr::hoc::pcv;
|
||||
sValidator validators[] = {
|
||||
{ C.eristaCpuBoostClock, 1020'000, 2397'000, true, panic::Cpu },
|
||||
{ C.marikoCpuBoostClock, 1020'000, 2703'000, true, panic::Cpu },
|
||||
{ C.eristaCpuMaxVolt, 1000, 1260, false, panic::Cpu },
|
||||
{ C.marikoCpuMaxVolt, 1000, 1200, false, panic::Cpu },
|
||||
{ eristaCpuDvfsMaxFreq, 1785'000, 2397'000, false, panic::Cpu },
|
||||
{ marikoCpuDvfsMaxFreq, 1785'000, 2703'000, false, panic::Cpu },
|
||||
{ C.commonEmcMemVolt, 912'500, 1350'000, false, panic::Emc }, // Official burst vmax for the RAMs is 1500mV
|
||||
{ GET_MAX_OF_ARR(erista::maxEmcClocks), 1600'000, 2600'000, false, panic::Emc },
|
||||
{ C.marikoEmcMaxClock, 1600'000, 3500'000, false, panic::Emc },
|
||||
{ C.marikoEmcVddqVolt, 400'000, 750'000, false, panic::Emc },
|
||||
{ C.marikoSocVmax, 1000, 1200, false, panic::Emc },
|
||||
{ eristaGpuDvfsMaxFreq, 768'000, 1152'000, false, panic::Gpu },
|
||||
{ marikoGpuDvfsMaxFreq, 768'000, 1536'000, false, panic::Gpu },
|
||||
{ C.marikoGpuVmax, 800, 960, false, panic::Gpu },
|
||||
{ C.eristaCpuBoostClock, 1020'000, 2397'000, panic::Cpu, true },
|
||||
{ C.marikoCpuBoostClock, 1020'000, 2703'000, panic::Cpu, true },
|
||||
{ C.eristaCpuMaxVolt, 1000, 1260, panic::Cpu, },
|
||||
{ C.marikoCpuMaxVolt, 1000, 1200, panic::Cpu, },
|
||||
{ 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 */
|
||||
{ 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, },
|
||||
{ eristaGpuDvfsMaxFreq, 768'000, 1152'000, panic::Gpu, },
|
||||
{ marikoGpuDvfsMaxFreq, 768'000, 1536'000, panic::Gpu, },
|
||||
{ C.marikoGpuVmax, 800, 960, panic::Gpu, },
|
||||
};
|
||||
|
||||
for (auto &v : validators) {
|
||||
|
||||
@@ -118,34 +118,34 @@ namespace ams::ldr::hoc::pcv {
|
||||
cvb_entry_t *customize_table;
|
||||
if (isMariko) {
|
||||
switch (C.marikoGpuUV) {
|
||||
case 0:
|
||||
customize_table = const_cast<cvb_entry_t *>(C.marikoGpuDvfsTable);
|
||||
break;
|
||||
case 1:
|
||||
customize_table = const_cast<cvb_entry_t *>(C.marikoGpuDvfsTableSLT);
|
||||
break;
|
||||
case 2:
|
||||
customize_table = const_cast<cvb_entry_t *>(C.marikoGpuDvfsTableHiOPT);
|
||||
break;
|
||||
default:
|
||||
customize_table = const_cast<cvb_entry_t *>(C.marikoGpuDvfsTable);
|
||||
break;
|
||||
}
|
||||
case 0:
|
||||
customize_table = const_cast<cvb_entry_t *>(C.marikoGpuDvfsTable);
|
||||
break;
|
||||
case 1:
|
||||
customize_table = const_cast<cvb_entry_t *>(C.marikoGpuDvfsTableSLT);
|
||||
break;
|
||||
case 2:
|
||||
customize_table = const_cast<cvb_entry_t *>(C.marikoGpuDvfsTableHiOPT);
|
||||
break;
|
||||
default:
|
||||
customize_table = const_cast<cvb_entry_t *>(C.marikoGpuDvfsTable);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (C.eristaGpuUV) {
|
||||
case 0:
|
||||
customize_table = const_cast<cvb_entry_t *>(C.eristaGpuDvfsTable);
|
||||
break;
|
||||
case 1:
|
||||
customize_table = const_cast<cvb_entry_t *>(C.eristaGpuDvfsTableSLT);
|
||||
break;
|
||||
case 2:
|
||||
customize_table = const_cast<cvb_entry_t *>(C.eristaGpuDvfsTableHiOPT);
|
||||
break;
|
||||
default:
|
||||
customize_table = const_cast<cvb_entry_t *>(C.eristaGpuDvfsTable);
|
||||
break;
|
||||
}
|
||||
case 0:
|
||||
customize_table = const_cast<cvb_entry_t *>(C.eristaGpuDvfsTable);
|
||||
break;
|
||||
case 1:
|
||||
customize_table = const_cast<cvb_entry_t *>(C.eristaGpuDvfsTableSLT);
|
||||
break;
|
||||
case 2:
|
||||
customize_table = const_cast<cvb_entry_t *>(C.eristaGpuDvfsTableHiOPT);
|
||||
break;
|
||||
default:
|
||||
customize_table = const_cast<cvb_entry_t *>(C.eristaGpuDvfsTable);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
size_t default_entry_count = GetDvfsTableEntryCount(default_table);
|
||||
@@ -195,26 +195,6 @@ namespace ams::ldr::hoc::pcv {
|
||||
Result MemFreqPllmLimit(u32 *ptr);
|
||||
Result MemVoltHandler(u32 *ptr); // Used for Erista MEM Vdd2 + EMC Vddq or Mariko MEM Vdd2
|
||||
|
||||
template <typename T>
|
||||
Result MemMtcCustomizeTable(T *dst, T *src) {
|
||||
constexpr u32 mtc_magic = std::is_same_v<T, MarikoMtcTable> ? MARIKO_MTC_MAGIC : ERISTA_MTC_MAGIC;
|
||||
R_UNLESS(src->rev == mtc_magic, ldr::ResultInvalidMtcMagic());
|
||||
|
||||
constexpr u32 ZERO_VAL = UINT32_MAX;
|
||||
// Skip params from dvfs_ver to clock_src;
|
||||
for (size_t offset = offsetof(T, clk_src_emc); offset < sizeof(T); offset += sizeof(u32)) {
|
||||
u32 *src_ent = reinterpret_cast<u32 *>(reinterpret_cast<size_t>(src) + offset);
|
||||
u32 *dst_ent = reinterpret_cast<u32 *>(reinterpret_cast<size_t>(dst) + offset);
|
||||
u32 src_val = *src_ent;
|
||||
|
||||
if (src_val){
|
||||
PATCH_OFFSET(dst_ent, src_val == ZERO_VAL ? 0 : src_val);
|
||||
}
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
};
|
||||
|
||||
void SafetyCheck();
|
||||
void Patch(uintptr_t mapped_nso, size_t nso_size);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -38,14 +38,14 @@ namespace ams::ldr::hoc::pcv {
|
||||
};
|
||||
static_assert(sizeof(cvb_entry_t) == 0x38);
|
||||
|
||||
struct cvb_cpu_dfll_data {
|
||||
struct CvbCpuDfllData {
|
||||
u32 tune0_low;
|
||||
u32 tune0_high;
|
||||
u32 tune1_low;
|
||||
u32 tune1_high;
|
||||
unsigned int tune_high_min_millivolts;
|
||||
unsigned int tune_high_margin_millivolts;
|
||||
unsigned long dvco_calibration_max;
|
||||
u32 tune_high_min_millivolts;
|
||||
u32 tune_high_margin_millivolts;
|
||||
u64 dvco_calibration_max;
|
||||
};
|
||||
|
||||
struct __attribute__((packed)) div_nmp {
|
||||
@@ -115,6 +115,25 @@ namespace ams::ldr::hoc::pcv {
|
||||
};
|
||||
static_assert(sizeof(regulator) == 0x120);
|
||||
|
||||
struct __attribute__((packed)) CvbMeta {
|
||||
u64 socType;
|
||||
CvbCpuDfllData dfllData; /* Maybe? */
|
||||
u32 unkZero2[6];
|
||||
u32 unkMagic;
|
||||
u32 unkZero3;
|
||||
u32 highVmin;
|
||||
u32 unkStepMaybe;
|
||||
u32 vmin;
|
||||
u32 unkZero4[3];
|
||||
u32 pllMinMilliVolts;
|
||||
u32 vmax;
|
||||
u32 unkScale2;
|
||||
u32 speedoScale;
|
||||
u32 voltageScale;
|
||||
u32 unkZero5;
|
||||
};
|
||||
static_assert(sizeof(CvbMeta) == 0x78);
|
||||
|
||||
constexpr u32 CpuClkOSLimit = 1785'000;
|
||||
constexpr u32 GpuClkOsLimit = 921'600;
|
||||
constexpr u32 EmcClkOSLimit = 1600'000;
|
||||
@@ -126,11 +145,11 @@ namespace ams::ldr::hoc::pcv {
|
||||
constexpr size_t DvfsTableEntryLimit = DvfsTableEntryCount - 1;
|
||||
|
||||
template<typename T>
|
||||
size_t GetDvfsTableEntryCount(T* table_head) {
|
||||
size_t GetDvfsTableEntryCount(T *table_head) {
|
||||
using NT = std::remove_const_t<std::remove_volatile_t<T>>;
|
||||
|
||||
auto is_empty = [](NT* entry) {
|
||||
uint8_t* m = reinterpret_cast<uint8_t *>(entry);
|
||||
u8 *m = reinterpret_cast<u8 *>(entry);
|
||||
for (size_t i = 0; i < sizeof(NT); i++) {
|
||||
if (*(m + i)) {
|
||||
return false;
|
||||
@@ -139,7 +158,7 @@ namespace ams::ldr::hoc::pcv {
|
||||
return true;
|
||||
};
|
||||
|
||||
NT* table = const_cast<NT *>(table_head);
|
||||
NT *table = const_cast<NT *>(table_head);
|
||||
size_t count = 0;
|
||||
while (count < DvfsTableEntryLimit) {
|
||||
if (is_empty(table++)) {
|
||||
@@ -151,10 +170,10 @@ namespace ams::ldr::hoc::pcv {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* GetDvfsTableLastEntry(T* table_head) {
|
||||
T *GetDvfsTableLastEntry(T *table_head) {
|
||||
using NT = std::remove_const_t<std::remove_volatile_t<T>>;
|
||||
|
||||
NT* table = const_cast<NT *>(table_head);
|
||||
NT *table = const_cast<NT *>(table_head);
|
||||
size_t count = GetDvfsTableEntryCount(table_head);
|
||||
if (!count) {
|
||||
return nullptr;
|
||||
|
||||
@@ -18,6 +18,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"
|
||||
@@ -66,11 +67,12 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
}
|
||||
|
||||
Result CpuVoltDfll(u32* ptr) {
|
||||
cvb_cpu_dfll_data *entry = reinterpret_cast<cvb_cpu_dfll_data *>(ptr);
|
||||
R_UNLESS(entry->tune0_low == 0xFFEAD0FF, ldr::ResultInvalidCpuVoltDfllEntry());
|
||||
R_UNLESS(entry->tune0_high == 0x0, ldr::ResultInvalidCpuVoltDfllEntry());
|
||||
R_UNLESS(entry->tune1_low == 0x0, ldr::ResultInvalidCpuVoltDfllEntry());
|
||||
R_UNLESS(entry->tune1_high == 0x0, ldr::ResultInvalidCpuVoltDfllEntry());
|
||||
CvbCpuDfllData *entry = reinterpret_cast<CvbCpuDfllData *>(ptr);
|
||||
|
||||
R_UNLESS(entry->tune0_low == 0xFFEAD0FF, ldr::ResultInvalidCpuVoltDfllEntry());
|
||||
R_UNLESS(entry->tune0_high == 0x0, ldr::ResultInvalidCpuVoltDfllEntry());
|
||||
R_UNLESS(entry->tune1_low == 0x0, ldr::ResultInvalidCpuVoltDfllEntry());
|
||||
R_UNLESS(entry->tune1_high == 0x0, ldr::ResultInvalidCpuVoltDfllEntry());
|
||||
|
||||
if (!C.eristaCpuUV) {
|
||||
R_SKIP();
|
||||
@@ -100,6 +102,7 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
@@ -121,10 +124,10 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
}
|
||||
|
||||
if (C.eristaGpuVmin) {
|
||||
PATCH_OFFSET(ptr , C.eristaGpuVmin);
|
||||
PATCH_OFFSET(ptr + 3, C.eristaGpuVmin);
|
||||
PATCH_OFFSET(ptr + 6, C.eristaGpuVmin);
|
||||
PATCH_OFFSET(ptr + 9, C.eristaGpuVmin);
|
||||
PATCH_OFFSET(ptr, C.eristaGpuVmin);
|
||||
PATCH_OFFSET(ptr + 3, C.eristaGpuVmin);
|
||||
PATCH_OFFSET(ptr + 6, C.eristaGpuVmin);
|
||||
PATCH_OFFSET(ptr + 9, C.eristaGpuVmin);
|
||||
PATCH_OFFSET(ptr + 12, C.eristaGpuVmin);
|
||||
}
|
||||
|
||||
@@ -134,17 +137,13 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
Result GpuFreqMaxAsm(u32 *ptr32) {
|
||||
// Check if both two instructions match the pattern
|
||||
u32 ins1 = *ptr32, ins2 = *(ptr32 + 1);
|
||||
if (!(asm_compare_no_rd(ins1, GpuAsmPattern[0]) && asm_compare_no_rd(ins2, GpuAsmPattern[1])))
|
||||
if (!(asm_compare_no_rd(ins1, GpuAsmPattern[0]) && asm_compare_no_rd(ins2, GpuAsmPattern[1]))) {
|
||||
R_THROW(ldr::ResultInvalidGpuFreqMaxPattern());
|
||||
}
|
||||
|
||||
// Both instructions should operate on the same register
|
||||
u8 rd = asm_get_rd(ins1);
|
||||
if (rd != asm_get_rd(ins2))
|
||||
R_THROW(ldr::ResultInvalidGpuFreqMaxPattern());
|
||||
|
||||
/* Verify the limit. */
|
||||
/* TODO: Make this a little bit cleaner at some point. */
|
||||
if (AsmGetImm16(ins1) != (GpuClkOsLimit & 0xFFFF) || AsmGetImm16(ins2) != (GpuClkOsLimit >> 16)) {
|
||||
if (rd != asm_get_rd(ins2)) {
|
||||
R_THROW(ldr::ResultInvalidGpuFreqMaxPattern());
|
||||
}
|
||||
|
||||
@@ -163,10 +162,13 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
max_clock = GetDvfsTableLastEntry(C.eristaGpuDvfsTable)->freq;
|
||||
break;
|
||||
}
|
||||
|
||||
u32 asm_patch[2] = {
|
||||
asm_set_rd(asm_set_imm16(GpuAsmPattern[0], max_clock), rd),
|
||||
asm_set_rd(asm_set_imm16(GpuAsmPattern[1], max_clock >> 16), rd)};
|
||||
PATCH_OFFSET(ptr32, asm_patch[0]);
|
||||
asm_set_rd(asm_set_imm16(GpuAsmPattern[1], max_clock >> 16), rd)
|
||||
};
|
||||
|
||||
PATCH_OFFSET(ptr32, asm_patch[0]);
|
||||
PATCH_OFFSET(ptr32 + 1, asm_patch[1]);
|
||||
|
||||
R_SUCCEED();
|
||||
@@ -210,9 +212,11 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
}
|
||||
|
||||
u32 trefbw = refresh_raw + 0x40;
|
||||
trefbw = MIN(trefbw, static_cast<u32>(0x3FFF));
|
||||
trefbw = MIN(trefbw, static_cast<u32>(0x3FFF));
|
||||
|
||||
CalculateTimings(tCK_avg);
|
||||
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, 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));
|
||||
@@ -239,7 +243,6 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
WRITE_PARAM_ALL_REG(table, emc_refresh, refresh_raw);
|
||||
WRITE_PARAM_ALL_REG(table, emc_pre_refresh_req_cnt, refresh_raw / 4);
|
||||
WRITE_PARAM_ALL_REG(table, emc_trefbw, trefbw);
|
||||
const u32 dyn_self_ref_control = (static_cast<u32>(7605.0 / tCK_avg) + 260) | (table->burst_regs.emc_dyn_self_ref_control & 0xffff0000);
|
||||
WRITE_PARAM_ALL_REG(table, emc_dyn_self_ref_control, dyn_self_ref_control);
|
||||
WRITE_PARAM_ALL_REG(table, emc_pdex2wr, pdex2rw);
|
||||
WRITE_PARAM_ALL_REG(table, emc_pdex2rd, pdex2rw);
|
||||
@@ -274,22 +277,20 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
// WRITE_PARAM_ALL_REG(table, emc_rdv_early_mask, rdv);
|
||||
// WRITE_PARAM_ALL_REG(table, emc_rdv_mask, rdv + 2);
|
||||
// WRITE_PARAM_ALL_REG(table, emc_tr_rdv, rdv);
|
||||
// ams::ldr::hoc::pcv::mariko::CalculateMrw2();
|
||||
// table->emc_mrw2 = (table->emc_mrw2 & ~0xFFu) | static_cast<u32>(mrw2);
|
||||
// table->dram_timings.rl = RL;
|
||||
|
||||
/* This needs some clean up. */
|
||||
constexpr double MC_ARB_DIV = 4.0;
|
||||
constexpr u32 MC_ARB_SFA = 2;
|
||||
constexpr u32 MC_ARB_SFA = 2;
|
||||
|
||||
table->burst_mc_regs.mc_emem_arb_cfg = table->rate_khz / (33.3 * 1000) / MC_ARB_DIV;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_rcd = CEIL(GET_CYCLE_CEIL(tRCD) / MC_ARB_DIV) - 2;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_rp = CEIL(GET_CYCLE_CEIL(tRPpb) / MC_ARB_DIV) - 1;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_rc = CEIL(GET_CYCLE_CEIL(tRC) / MC_ARB_DIV) - 1;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_ras = CEIL(GET_CYCLE_CEIL(tRAS) / MC_ARB_DIV) - 2;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_faw = CEIL(GET_CYCLE_CEIL(tFAW) / MC_ARB_DIV) - 1;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_rrd = CEIL(GET_CYCLE_CEIL(tRRD) / MC_ARB_DIV) - 1;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_rfcpb = CEIL(GET_CYCLE_CEIL(tRFCpb) / MC_ARB_DIV) - 1;
|
||||
table->burst_mc_regs.mc_emem_arb_cfg = table->rate_khz / (33.3 * 1000) / MC_ARB_DIV;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_rcd = CEIL(GET_CYCLE_CEIL(tRCD) / MC_ARB_DIV) - 2;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_rp = CEIL(GET_CYCLE_CEIL(tRPpb) / MC_ARB_DIV) - 1;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_rc = CEIL(GET_CYCLE_CEIL(tRC) / MC_ARB_DIV) - 1;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_ras = CEIL(GET_CYCLE_CEIL(tRAS) / MC_ARB_DIV) - 2;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_faw = CEIL(GET_CYCLE_CEIL(tFAW) / MC_ARB_DIV) - 1;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_rrd = CEIL(GET_CYCLE_CEIL(tRRD) / MC_ARB_DIV) - 1;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_rfcpb = CEIL(GET_CYCLE_CEIL(tRFCpb) / MC_ARB_DIV) - 1;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_rap2pre = CEIL(tR2P / MC_ARB_DIV);
|
||||
table->burst_mc_regs.mc_emem_arb_timing_wap2pre = CEIL(tW2P / MC_ARB_DIV) + MC_ARB_SFA;
|
||||
|
||||
@@ -325,8 +326,8 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
table->la_scale_regs.mc_ptsa_grant_decrement = grant_decrement;
|
||||
|
||||
constexpr u32 MaskHigh = 0xFF00FFFF;
|
||||
constexpr u32 Mask2 = 0xFFFFFF00;
|
||||
constexpr u32 Mask3 = 0xFF00FF00;
|
||||
constexpr u32 Mask2 = 0xFFFFFF00;
|
||||
constexpr u32 Mask3 = 0xFF00FF00;
|
||||
|
||||
const u32 allowance1 = static_cast<u32>(0x32000 / (table->rate_khz / 0x3E8)) & 0xFF;
|
||||
const u32 allowance2 = static_cast<u32>(0x9C40 / (table->rate_khz / 0x3E8)) & 0xFF;
|
||||
@@ -354,71 +355,182 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
table->la_scale_regs.mc_latency_allowance_hc_1 = (table->la_scale_regs.mc_latency_allowance_hc_1 & Mask2) | allowance1;
|
||||
table->la_scale_regs.mc_latency_allowance_vi2_0 = (table->la_scale_regs.mc_latency_allowance_vi2_0 & Mask2) | allowance1;
|
||||
|
||||
table->dram_timings.t_rp = tRFCpb;
|
||||
table->dram_timings.t_rp = tRFCpb;
|
||||
table->dram_timings.t_rfc = tRFCab;
|
||||
table->emc_cfg_2 = 0x11083D;
|
||||
table->min_volt = (u32)std::min(static_cast<s32>(1050), 900 + C.emcDvbShift * 25);
|
||||
table->emc_cfg_2 = 0x11083D;
|
||||
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 +562,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 +628,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 +644,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);
|
||||
|
||||
@@ -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;
|
||||
@@ -140,13 +140,24 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
MtcTableIndex index;
|
||||
};
|
||||
|
||||
constexpr MtcDramIndex mtcIndexTable[] = {
|
||||
const inline MtcDramIndex mtcIndexTable[] = {
|
||||
{ ICOSA_4GB_SAMSUNG_K4F6E304HB_MGCH, T210SdevEmcDvfsTableS4gb01, },
|
||||
{ ICOSA_4GB_MICRON_MT53B512M32D2NP_062_WTC, T210SdevEmcDvfsTableS4gb01, },
|
||||
{ ICOSA_6GB_SAMSUNG_K4FHE3D4HM_MGCH, T210SdevEmcDvfsTableS6gb01, },
|
||||
{ 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);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -50,15 +50,18 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
R_THROW(ldr::ResultInvalidGpuDvfs());
|
||||
}
|
||||
|
||||
if (!C.marikoGpuVmin) {
|
||||
R_SKIP();
|
||||
}
|
||||
|
||||
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.marikoGpuBootVolt) {
|
||||
PATCH_OFFSET(ptr - 3, C.marikoGpuBootVolt);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
@@ -94,23 +97,29 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
}
|
||||
|
||||
Result CpuVoltDVFS(u32 *ptr) {
|
||||
if (MatchesPattern(ptr, cpuVoltagePatchOffsets, cpuVoltagePatchValues)) {
|
||||
if (C.marikoCpuLowVmin) {
|
||||
PATCH_OFFSET(ptr, C.marikoCpuLowVmin);
|
||||
}
|
||||
CvbMeta *cpuCvbMeta = reinterpret_cast<CvbMeta *>(reinterpret_cast<u8 *>(ptr) - offsetof(CvbMeta, vmin));
|
||||
|
||||
if (C.marikoCpuHighVmin) {
|
||||
PATCH_OFFSET(ptr - 2, C.marikoCpuHighVmin);
|
||||
}
|
||||
R_UNLESS(cpuCvbMeta->highVmin == CpuHighVminOfficial, ldr::ResultInvalidCpuMinVolt());
|
||||
R_UNLESS(cpuCvbMeta->unkStepMaybe == 38, ldr::ResultInvalidCpuMinVolt());
|
||||
R_UNLESS(cpuCvbMeta->vmax == CpuVoltOfficial, ldr::ResultInvalidCpuMinVolt());
|
||||
R_UNLESS(cpuCvbMeta->unkScale2 == 1000, ldr::ResultInvalidCpuMinVolt());
|
||||
R_UNLESS(cpuCvbMeta->speedoScale == 100, ldr::ResultInvalidCpuMinVolt());
|
||||
R_UNLESS(cpuCvbMeta->voltageScale == 1000, ldr::ResultInvalidCpuMinVolt());
|
||||
R_UNLESS(cpuCvbMeta->unkZero5 == 0, ldr::ResultInvalidCpuMinVolt());
|
||||
|
||||
if (C.marikoCpuMaxVolt) {
|
||||
PATCH_OFFSET(ptr + 5, C.marikoCpuMaxVolt);
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
if (C.marikoCpuLowVmin) {
|
||||
PATCH_OFFSET(&(cpuCvbMeta->vmin), C.marikoCpuLowVmin);
|
||||
}
|
||||
|
||||
R_THROW(ldr::ResultInvalidCpuMinVolt());
|
||||
if (C.marikoCpuHighVmin) {
|
||||
PATCH_OFFSET(&(cpuCvbMeta->highVmin), C.marikoCpuHighVmin);
|
||||
}
|
||||
|
||||
if (C.marikoCpuMaxVolt) {
|
||||
PATCH_OFFSET(&(cpuCvbMeta->vmax), C.marikoCpuMaxVolt);
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result CpuVoltThermals(u32 *ptr) {
|
||||
@@ -134,80 +143,80 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
}
|
||||
|
||||
Result CpuVoltDfll(u32 *ptr) {
|
||||
cvb_cpu_dfll_data *entry = reinterpret_cast<cvb_cpu_dfll_data *>(ptr);
|
||||
CvbCpuDfllData *entry = reinterpret_cast<CvbCpuDfllData *>(ptr);
|
||||
|
||||
R_UNLESS(entry->tune0_low == 0xFFCF, ldr::ResultInvalidCpuVoltDfllEntry());
|
||||
R_UNLESS(entry->tune0_high == 0x0, ldr::ResultInvalidCpuVoltDfllEntry());
|
||||
R_UNLESS(entry->tune1_low == 0x12207FF, ldr::ResultInvalidCpuVoltDfllEntry());
|
||||
R_UNLESS(entry->tune0_low == 0xFFCF, ldr::ResultInvalidCpuVoltDfllEntry());
|
||||
R_UNLESS(entry->tune0_high == 0x0, ldr::ResultInvalidCpuVoltDfllEntry());
|
||||
R_UNLESS(entry->tune1_low == 0x12207FF, ldr::ResultInvalidCpuVoltDfllEntry());
|
||||
R_UNLESS(entry->tune1_high == 0x3FFF7FF, ldr::ResultInvalidCpuVoltDfllEntry());
|
||||
|
||||
switch (C.marikoCpuUVLow) {
|
||||
case 1:
|
||||
PATCH_OFFSET(&(entry->tune0_low), 0xffa0);
|
||||
PATCH_OFFSET(&(entry->tune0_low), 0xffa0);
|
||||
PATCH_OFFSET(&(entry->tune0_high), 0xffff);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21107ff);
|
||||
PATCH_OFFSET(&(entry->tune1_high), 0);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21107ff);
|
||||
PATCH_OFFSET(&(entry->tune1_high), 0x0);
|
||||
break;
|
||||
case 2:
|
||||
PATCH_OFFSET(&(entry->tune0_high), 0xffdf);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21107ff);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21107ff);
|
||||
PATCH_OFFSET(&(entry->tune1_high), 0x27207ff);
|
||||
break;
|
||||
case 3:
|
||||
PATCH_OFFSET(&(entry->tune0_low), 0xffdf);
|
||||
PATCH_OFFSET(&(entry->tune0_low), 0xffdf);
|
||||
PATCH_OFFSET(&(entry->tune0_high), 0xffdf);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21107ff);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21107ff);
|
||||
PATCH_OFFSET(&(entry->tune1_high), 0x27307ff);
|
||||
break;
|
||||
case 4:
|
||||
PATCH_OFFSET(&(entry->tune0_low), 0xffff);
|
||||
PATCH_OFFSET(&(entry->tune0_low), 0xffff);
|
||||
PATCH_OFFSET(&(entry->tune0_high), 0xffdf);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21107ff);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21107ff);
|
||||
PATCH_OFFSET(&(entry->tune1_high), 0x27407ff);
|
||||
break;
|
||||
case 5:
|
||||
PATCH_OFFSET(&(entry->tune0_high), 0xffdf);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21607ff);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21607ff);
|
||||
PATCH_OFFSET(&(entry->tune1_high), 0x27707ff);
|
||||
break;
|
||||
case 6:
|
||||
PATCH_OFFSET(&(entry->tune0_high), 0xffdf);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21607ff);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21607ff);
|
||||
PATCH_OFFSET(&(entry->tune1_high), 0x27807ff);
|
||||
break;
|
||||
case 7:
|
||||
PATCH_OFFSET(&(entry->tune0_high), 0xdfff);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21607ff);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21607ff);
|
||||
PATCH_OFFSET(&(entry->tune1_high), 0x27b07ff);
|
||||
break;
|
||||
case 8:
|
||||
PATCH_OFFSET(&(entry->tune0_low), 0xdfff);
|
||||
PATCH_OFFSET(&(entry->tune0_low), 0xdfff);
|
||||
PATCH_OFFSET(&(entry->tune0_high), 0xdfff);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21707ff);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21707ff);
|
||||
PATCH_OFFSET(&(entry->tune1_high), 0x27b07ff);
|
||||
break;
|
||||
case 9:
|
||||
PATCH_OFFSET(&(entry->tune0_low), 0xdfff);
|
||||
PATCH_OFFSET(&(entry->tune0_low), 0xdfff);
|
||||
PATCH_OFFSET(&(entry->tune0_high), 0xdfff);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21707ff);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21707ff);
|
||||
PATCH_OFFSET(&(entry->tune1_high), 0x27c07ff);
|
||||
break;
|
||||
case 10:
|
||||
PATCH_OFFSET(&(entry->tune0_low), 0xdfff);
|
||||
PATCH_OFFSET(&(entry->tune0_low), 0xdfff);
|
||||
PATCH_OFFSET(&(entry->tune0_high), 0xdfff);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21707ff);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21707ff);
|
||||
PATCH_OFFSET(&(entry->tune1_high), 0x27d07ff);
|
||||
break;
|
||||
case 11:
|
||||
PATCH_OFFSET(&(entry->tune0_low), 0xdfff);
|
||||
PATCH_OFFSET(&(entry->tune0_low), 0xdfff);
|
||||
PATCH_OFFSET(&(entry->tune0_high), 0xdfff);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21707ff);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21707ff);
|
||||
PATCH_OFFSET(&(entry->tune1_high), 0x27e07ff);
|
||||
break;
|
||||
case 12:
|
||||
PATCH_OFFSET(&(entry->tune0_low), 0xdfff);
|
||||
PATCH_OFFSET(&(entry->tune0_low), 0xdfff);
|
||||
PATCH_OFFSET(&(entry->tune0_high), 0xdfff);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21707ff);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21707ff);
|
||||
PATCH_OFFSET(&(entry->tune1_high), 0x27f07ff);
|
||||
break;
|
||||
default:
|
||||
@@ -216,7 +225,7 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
|
||||
switch (C.marikoCpuUVHigh) {
|
||||
case 1:
|
||||
PATCH_OFFSET(&(entry->tune1_high), 0);
|
||||
PATCH_OFFSET(&(entry->tune1_high), 0x0);
|
||||
PATCH_OFFSET(&(entry->tune0_high), 0xffff);
|
||||
break;
|
||||
case 2:
|
||||
@@ -301,7 +310,7 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
asm_set_rd(asm_set_imm16(GpuAsmPattern[1], max_clock >> 16), rd)
|
||||
};
|
||||
|
||||
PATCH_OFFSET(ptr32, asm_patch[0]);
|
||||
PATCH_OFFSET(ptr32, asm_patch[0]);
|
||||
PATCH_OFFSET(ptr32 + 1, asm_patch[1]);
|
||||
|
||||
R_SUCCEED();
|
||||
@@ -366,7 +375,7 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
}
|
||||
|
||||
u32 trefbw = refresh_raw + 0x40;
|
||||
trefbw = MIN(trefbw, static_cast<u32>(0x3FFF));
|
||||
trefbw = MIN(trefbw, static_cast<u32>(0x3FFF));
|
||||
|
||||
const u32 dyn_self_ref_control = (static_cast<u32>(7605.0 / tCK_avg) + 260) | (table->burst_regs.emc_dyn_self_ref_control & 0xffff0000);
|
||||
|
||||
@@ -629,14 +638,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:
|
||||
@@ -758,10 +767,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);
|
||||
|
||||
@@ -769,6 +774,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()))) {
|
||||
@@ -796,9 +805,9 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
R_SKIP();
|
||||
}
|
||||
|
||||
u32 max0 = 1050;
|
||||
u32 max1 = 1025;
|
||||
u32 max2 = 1000;
|
||||
s32 max0 = 1050;
|
||||
s32 max1 = 1025;
|
||||
s32 max2 = 1000;
|
||||
s32 voltAdd = 25 * C.emcDvbShift;
|
||||
|
||||
if (C.marikoSocVmax && C.marikoSocVmax > 1000) {
|
||||
@@ -807,11 +816,17 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
max2 = C.marikoSocVmax;
|
||||
}
|
||||
|
||||
auto DvbVolt = [&](u32 zero, u32 one, u32 two) {
|
||||
return std::array<u32, 3>{
|
||||
std::min((u32)((s32)zero + voltAdd), max0),
|
||||
std::min((u32)((s32)one + voltAdd), max1),
|
||||
std::min((u32)((s32)two + voltAdd), max2)
|
||||
constexpr s32 MinVolt = 637;
|
||||
|
||||
auto ClampVolt = [&](s32 value, s32 max) {
|
||||
return std::clamp(value + voltAdd, MinVolt, max);
|
||||
};
|
||||
|
||||
auto DvbVolt = [&](s32 zero, s32 one, s32 two) {
|
||||
return std::array<s32, 3>{
|
||||
ClampVolt(zero, max0),
|
||||
ClampVolt(one, max1),
|
||||
ClampVolt(two, max2)
|
||||
};
|
||||
};
|
||||
|
||||
@@ -819,32 +834,53 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
static_cast<u32>((v)[0]), \
|
||||
static_cast<u32>((v)[1]), \
|
||||
static_cast<u32>((v)[2])
|
||||
DvbEntry emcDvbTableNew[] = {
|
||||
{ 204000, { 637, 637, 637, }, },
|
||||
{ 1331200, { 650, 637, 637, }, },
|
||||
{ 1600000, { 675, 650, 637, }, },
|
||||
{ 1866000, { DVB(DvbVolt( 700, 675, 650)) }, },
|
||||
{ 2133000, { DVB(DvbVolt( 725, 700, 675)) }, },
|
||||
{ 2400000, { DVB(DvbVolt( 750, 725, 700)) }, },
|
||||
{ 2666000, { DVB(DvbVolt( 850, 825, 800)) }, },
|
||||
{ 2933000, { DVB(DvbVolt( 950, 925, 900)) }, },
|
||||
{ 3200000, { DVB(DvbVolt(1050, 1025, 1000)) }, },
|
||||
{ 0xFFFFFFFF, { }, },
|
||||
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)) }, },
|
||||
{ ~0u, { }, },
|
||||
};
|
||||
#undef DVB
|
||||
DvbEntry emcDvbTableOc[newEmcList.size()];
|
||||
|
||||
u32 j = MtcTableCountDefault;
|
||||
for (u32 i = MtcTableCountDefault; i < newEmcList.size(); ++i) {
|
||||
if (newEmcList[i] >= emcDvbTableNew[j].freq && newEmcList[i] < emcDvbTableNew[j + 1].freq) {
|
||||
emcDvbTableNew[j].freq = newEmcList[i];
|
||||
++j;
|
||||
} else {
|
||||
break;
|
||||
u32 bracketIndex = 0;
|
||||
for (u32 i = 0; i < newEmcList.size(); ++i) {
|
||||
while (newEmcList[i] >= emcDvbOcTableBrackets[bracketIndex + 1].freq) {
|
||||
++bracketIndex;
|
||||
}
|
||||
|
||||
emcDvbTableOc[i].freq = newEmcList[i];
|
||||
std::memcpy(emcDvbTableOc[i].volt, emcDvbOcTableBrackets[bracketIndex].volt, sizeof(emcDvbTableOc[i].volt));
|
||||
}
|
||||
|
||||
std::memset(mem_dvb_table_head, 0, sizeof(EmcDvbTableDefault));
|
||||
std::memcpy(mem_dvb_table_head, &emcDvbTableNew, sizeof(emcDvbTableNew));
|
||||
std::memcpy(mem_dvb_table_head, &emcDvbTableOc, sizeof(emcDvbTableOc));
|
||||
|
||||
/* Max dvfs entry is 32, but HOS doesn't seem to boot if exact freq doesn't exist in dvb table,
|
||||
reason why it's like this
|
||||
|
||||
@@ -48,11 +48,11 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
{ },
|
||||
};
|
||||
|
||||
constexpr u32 CpuClkOfficial = 1963'500;
|
||||
constexpr u32 CpuVoltOfficial = 1120;
|
||||
constexpr u32 CpuVminOfficial = 620;
|
||||
|
||||
constexpr u32 CpuTune0Low = 0xFFCF;
|
||||
constexpr u32 CpuClkOfficial = 1963'500;
|
||||
constexpr u32 CpuVoltOfficial = 1120;
|
||||
constexpr u32 CpuHighVminOfficial = 850;
|
||||
constexpr u32 CpuVminOfficial = 620;
|
||||
constexpr u32 CpuTune0Low = 0xFFCF;
|
||||
|
||||
static const u32 cpuVoltagePatchValues[] = { 850, 38, 1120, 1000, 100, 1000, 0 };
|
||||
static const s32 cpuVoltagePatchOffsets[] = { -2, -1, 5, 6, 7, 8, 9 };
|
||||
@@ -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;
|
||||
@@ -230,7 +228,7 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
MtcTableIndex index;
|
||||
};
|
||||
|
||||
constexpr MtcDramIndex mtcIndexTable[] = {
|
||||
const inline MtcDramIndex mtcIndexTable[] = {
|
||||
{ HOAG_4GB_HYNIX_H9HCNNNBKMMLXR_NEE, T210b0SdevEmcDvfsTableH1y4gb01, },
|
||||
{ AULA_4GB_HYNIX_H9HCNNNBKMMLXR_NEE, T210b0SdevEmcDvfsTableH1y4gb01, },
|
||||
{ IOWA_4GB_HYNIX_H9HCNNNBKMMLXR_NEE, T210b0SdevEmcDvfsTableH1y4gb01, },
|
||||
|
||||
@@ -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.
@@ -76,13 +76,12 @@ typedef enum {
|
||||
HocClkConfigValue_MarikoMiddleFreqs,
|
||||
|
||||
KipConfigValue_custRev,
|
||||
KipConfigValue_KipVersion,
|
||||
// KipConfigValue_mtcConf,
|
||||
KipConfigValue_hpMode,
|
||||
|
||||
KipConfigValue_commonEmcMemVolt,
|
||||
KipConfigValue_eristaEmcMaxClock,
|
||||
KipConfigValue_eristaEmcMaxClock1,
|
||||
KipConfigValue_eristaEmcMaxClock2,
|
||||
|
||||
KipConfigValue_stepMode,
|
||||
KipConfigValue_marikoEmcMaxClock,
|
||||
@@ -115,9 +114,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 +134,10 @@ typedef enum {
|
||||
|
||||
KipConfigValue_marikoGpuUV,
|
||||
KipConfigValue_marikoGpuVmin,
|
||||
KipConfigValue_marikoGpuBootVolt,
|
||||
KipConfigValue_marikoGpuVmax,
|
||||
|
||||
KipConfigValue_commonGpuVoltOffset,
|
||||
KipConfigValue_gpuSpeedo,
|
||||
|
||||
KipConfigValue_g_volt_76800,
|
||||
KipConfigValue_g_volt_153600,
|
||||
@@ -295,6 +291,8 @@ static inline const char* hocclkFormatConfigValue(HocClkConfigValue val, bool pr
|
||||
// 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 +302,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 +359,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 +402,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";
|
||||
@@ -566,14 +555,13 @@ static inline uint64_t hocclkValidConfigValue(HocClkConfigValue val, uint64_t in
|
||||
case HocClkConfigValue_GPUSchedulingMethod:
|
||||
case HocClkConfigValue_MarikoMiddleFreqs:
|
||||
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 +587,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 +602,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:
|
||||
@@ -690,6 +676,6 @@ static inline uint64_t hocclkValidConfigValue(HocClkConfigValue val, uint64_t in
|
||||
return ((input >= 800) && (input <= 1325));
|
||||
|
||||
default:
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -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.0 # 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)
|
||||
|
||||
#---------------------------------------------------------------------------------------
|
||||
|
||||
Binary file not shown.
@@ -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;
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
*/
|
||||
|
||||
|
||||
#include "ult_ext.h"
|
||||
#include "app_profile_gui.h"
|
||||
|
||||
#include "../format.h"
|
||||
|
||||
@@ -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();
|
||||
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 = 10;
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
};
|
||||
|
||||
|
||||
@@ -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), }
|
||||
@@ -77,10 +79,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 +95,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 +350,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();
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
537
Source/hoc-clk/overlay/src/ui/gui/config_info_strings.cpp
Normal file
537
Source/hoc-clk/overlay/src/ui/gui/config_info_strings.cpp
Normal file
@@ -0,0 +1,537 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) Souldbminer, Lightos_ and Horizon OC Contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config_info_strings.h"
|
||||
|
||||
std::vector<std::string> ConfigInfoStrings(HocClkConfigValue val, bool isMariko, bool isHoag)
|
||||
{
|
||||
switch (val)
|
||||
{
|
||||
case HocClkConfigValue_PollingIntervalMs:
|
||||
return {
|
||||
"The interval (in milliseconds) where clocks are applied, temperatures and voltages are polled and logs are written (if enabled).",
|
||||
"Higher values may cause more delay between changing a setting and it taking effect, and lower values may increase sysmodule memory usage",
|
||||
"Default: 300ms"
|
||||
};
|
||||
|
||||
case HocClkConfigValue_RamDisplayUnit:
|
||||
return {
|
||||
"The unit used when displaying RAM frequency values.",
|
||||
"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"
|
||||
};
|
||||
|
||||
case HocClkConfigValue_RAMVoltDisplayMode:
|
||||
return {
|
||||
"The method used to display RAM voltage values.",
|
||||
"Options:",
|
||||
"- VDD2 - Display VDD2 voltage",
|
||||
"- VDDQ - Display VDDQ voltage",
|
||||
"Default: VDD2"
|
||||
};
|
||||
|
||||
case HocClkConfigValue_EnableExperimentalSettings:
|
||||
return {
|
||||
"When enabled, shows settings that are still being tested and may be unstable or not work at all.",
|
||||
"Use with caution and report any issues to the developers."
|
||||
};
|
||||
|
||||
case HocClkConfigValue_MarikoMiddleFreqs:
|
||||
return {
|
||||
"Allows usage of frequencies stepped by 38.4MHz instead of 76.8MHz below 1228MHz GPU clock",
|
||||
"Default: OFF"
|
||||
};
|
||||
|
||||
case HocClkConfigValue_LiveCpuUv:
|
||||
return {
|
||||
"Allows changing CPU undervolt settings without a reboot",
|
||||
"Default: OFF"
|
||||
};
|
||||
|
||||
case HocClkConfigValue_GPUSchedulingMethod:
|
||||
return {
|
||||
"Method used for GPU scheduling override",
|
||||
"Options:",
|
||||
"- INI: override via system_settings.ini",
|
||||
"- NV Service: override via nvservices sysmodule (experimental)",
|
||||
"Default: INI"
|
||||
};
|
||||
|
||||
case HocClkConfigValue_MemoryFrequencyMeasurementMode:
|
||||
return {
|
||||
"How the RAM real frequency is measured",
|
||||
"Options:",
|
||||
"- PLL: Measure from PLLMB and PLLM (more accurate)",
|
||||
"- Actmon: Measure from Actmon (less accurate)",
|
||||
"Default: PLL"
|
||||
};
|
||||
|
||||
case HocClkConfigValue_BatteryChargeCurrent:
|
||||
return {
|
||||
"Overrides the charge current to the battery. Use with caution!",
|
||||
isHoag ? "Default: 1664 mA" : "2048 mA"
|
||||
};
|
||||
|
||||
case HocClkConfigValue_AulaDisplayColorPreset:
|
||||
return {
|
||||
"Current display color preset. Default is Basic",
|
||||
"Options:",
|
||||
"- Saturated: Based on Vivid but over-saturated.",
|
||||
"- Washed: Washed out colors.",
|
||||
"- Basic: Real natural profile.",
|
||||
"- Natural: Not actually natural.. Extra saturation.",
|
||||
"- Vivid: Saturated.",
|
||||
"Default: Do not override"
|
||||
};
|
||||
|
||||
case HocClkConfigValue_CpuGovernorMinimumFreq:
|
||||
return {
|
||||
"The minimum frequency that the CPU governor will allow.",
|
||||
"Default: 612MHz"
|
||||
};
|
||||
|
||||
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.",
|
||||
"This feature conflicts with FPSLocker's feature that does the same thing.",
|
||||
"Default: OFF"
|
||||
};
|
||||
|
||||
case HocClkConfigValue_MaxDisplayClockH:
|
||||
return {
|
||||
"The maximum display clock frequency in handheld mode (in Hz).",
|
||||
"Warning: Changing this value may cause instability or display damage.",
|
||||
"Default: 60 Hz"
|
||||
};
|
||||
|
||||
case HocClkConfigValue_DisplayVoltage:
|
||||
return {
|
||||
"The voltage supplied to the display panel (in mV).",
|
||||
"Warning: Changing this value may cause instability.",
|
||||
"Default: 1200mV"
|
||||
};
|
||||
|
||||
case HocClkConfigValue_UncappedClocks:
|
||||
if(isMariko) {
|
||||
return {
|
||||
"When enabled, disables clock cappings",
|
||||
"Warning: Enabling this may cause damage to your device without a proper undervolt. Use with caution!",
|
||||
"Clock cappings:",
|
||||
"- Handheld:",
|
||||
" - GPU (HiOPT): 614 MHz",
|
||||
" - GPU (HiOPT - 15mV): 691 MHz",
|
||||
" - GPU (High UV): 768 MHz",
|
||||
"- USB Charger",
|
||||
" - GPU (HiOPT): 844 MHz",
|
||||
" - GPU (HiOPT - 15mV): 921 MHz",
|
||||
" - GPU (High UV): 998 MHz",
|
||||
"- PD Charger / Docked:",
|
||||
" - No capping applied",
|
||||
"Default: OFF"
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
"When enabled, disables clock cappings",
|
||||
"Warning: Enabling this may cause damage to your device without a proper undervolt. Use with caution!",
|
||||
"Clock cappings:",
|
||||
"- Handheld:",
|
||||
" - GPU: 460 MHz",
|
||||
" - CPU: 1581 MHz",
|
||||
"- USB Charger",
|
||||
" - GPU: 768 MHz",
|
||||
"- PD Charger / Docked:",
|
||||
" - No capping applied",
|
||||
"Default: OFF"
|
||||
};
|
||||
}
|
||||
|
||||
case HocClkConfigValue_ThermalThrottle:
|
||||
return {
|
||||
"If enabled, Resets to stock clocks after the threshold is applied",
|
||||
"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.",
|
||||
"Default: 70°C"
|
||||
};
|
||||
|
||||
case KipConfigValue_emcDvbShift:
|
||||
return {
|
||||
"Each level adds/removes 25mV from the SOC Voltage table",
|
||||
"Consoles are bracketed by SoC Speedo. The brackets are as follows:",
|
||||
" - Speedo 1487-1598: Bracket 0",
|
||||
" - Speedo 1598-1709: Bracket 1",
|
||||
" - Speedo 1709-1820: Bracket 2",
|
||||
"Default: 0"
|
||||
};
|
||||
|
||||
case KipConfigValue_marikoSocVmax:
|
||||
return {
|
||||
"The maximum available SOC Voltage that the DVB-adjusted table can use",
|
||||
"Default: Do not override"
|
||||
};
|
||||
|
||||
case KipConfigValue_hpMode:
|
||||
return {
|
||||
"When enabled, disables RAM powerdown. Helps with latency significantly",
|
||||
"Default: OFF"
|
||||
};
|
||||
|
||||
case KipConfigValue_commonEmcMemVolt:
|
||||
return {
|
||||
"RAM VDD2 voltage",
|
||||
"Increasing this WILL NOT increase your maximum frequency, but may help with timing reduction.",
|
||||
"Undervolting RAM is pointless and may hurt performance and stability",
|
||||
"Default: 1175 mV"
|
||||
};
|
||||
|
||||
case KipConfigValue_marikoEmcVddqVolt:
|
||||
return {
|
||||
"RAM VDDQ voltage",
|
||||
"Increasing this may help, but the default value is usually good enough.",
|
||||
"Undervolting RAM is pointless and may hurt performance and stability",
|
||||
"Default: 600 mV"
|
||||
};
|
||||
|
||||
case KipConfigValue_stepMode:
|
||||
return {
|
||||
"The step that RAM clocks take.",
|
||||
"Options (with examples):",
|
||||
" - 66MHz - 66 MHz step (ex. 1600, 1666, 1733, etc.)",
|
||||
" - 100MHz - 100 MHz step (ex. 1600, 1700, 1800, etc.)",
|
||||
" - 133MHz - 66 MHz step (ex. 1600, 1733, 1866, etc.)",
|
||||
" - JEDEC:",
|
||||
" - 1600, 1866, 1996, 2133, 2400, 2666, 2933 and 3200 MHz are used",
|
||||
"The RAM max clock will always be available regardless of the step mode, but the intermediate frequencies will be limited by the selected step mode.",
|
||||
"This setting does not affect performance and the option you choose mostly is based on your personal taste",
|
||||
"33 MHz step mode is not possible due to certain limitations of Horizon OS",
|
||||
"Default: 66 MHz",
|
||||
};
|
||||
|
||||
case KipConfigValue_marikoEmcMaxClock:
|
||||
return {
|
||||
"The maximum RAM frequency available.",
|
||||
"Higher frequencies may cause instability, so increase this gradually and test for stability.",
|
||||
"Default: 2133 MHz"
|
||||
};
|
||||
|
||||
case KipConfigValue_eristaEmcMaxClock:
|
||||
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)"
|
||||
};
|
||||
|
||||
case KipConfigValue_t1_tRCD:
|
||||
return {
|
||||
"RAS-to-CAS delay",
|
||||
"Default: 0"
|
||||
};
|
||||
|
||||
case KipConfigValue_t2_tRP:
|
||||
return {
|
||||
"Row precharge time",
|
||||
"Default: 0"
|
||||
};
|
||||
|
||||
case KipConfigValue_t3_tRAS:
|
||||
return {
|
||||
"Row active time",
|
||||
"Default: 0"
|
||||
};
|
||||
|
||||
case KipConfigValue_t4_tRRD:
|
||||
return {
|
||||
"Row refresh time",
|
||||
"Default: 0"
|
||||
};
|
||||
|
||||
case KipConfigValue_t5_tRFC:
|
||||
return {
|
||||
"Refresh Cycle Time",
|
||||
"Default: 0"
|
||||
};
|
||||
|
||||
case KipConfigValue_t6_tRTW:
|
||||
return {
|
||||
"Read To Write (High bracket)",
|
||||
"Default: 0"
|
||||
};
|
||||
|
||||
case KipConfigValue_t7_tWTR:
|
||||
return {
|
||||
"Write To Read (High bracket)",
|
||||
"Default: 0"
|
||||
};
|
||||
|
||||
case KipConfigValue_t8_tREFI:
|
||||
return {
|
||||
"Refresh command interval",
|
||||
"Default: 0"
|
||||
};
|
||||
|
||||
case KipConfigValue_timingEmcTbreak:
|
||||
return {
|
||||
"Frequency where t6 and t7 break between the low and high brackets",
|
||||
"Example:",
|
||||
"Tbreak is set to 1866 MHz, and t6Low is set to 4 and t6High is set to 2. At frequencies below 1866 MHz, t6 will be 4, and at frequencies above 1866 MHz, t6 will be 2.",
|
||||
"Default: Disabled"
|
||||
};
|
||||
|
||||
case KipConfigValue_low_t6_tRTW:
|
||||
return {
|
||||
"Read To Write (Low bracket)",
|
||||
"Default: 0"
|
||||
};
|
||||
|
||||
case KipConfigValue_low_t7_tWTR:
|
||||
return {
|
||||
"Write To Read (Low bracket)",
|
||||
"Default: 0"
|
||||
};
|
||||
case KipConfigValue_t2_tRP_cap:
|
||||
return {
|
||||
"Cap for t2 when 1333WL is used.",
|
||||
"The default value is sufficient for most RAMs but some may need a lower value",
|
||||
"Default: 2"
|
||||
};
|
||||
|
||||
case KipConfigValue_t6_tRTW_fine_tune:
|
||||
return {
|
||||
"Fine-tunes the raw calculation of t6",
|
||||
"Default: 0"
|
||||
};
|
||||
|
||||
case KipConfigValue_t7_tWTR_fine_tune:
|
||||
return {
|
||||
"Fine-tunes the raw calculation of t7",
|
||||
"Default: 0"
|
||||
};
|
||||
|
||||
case KipConfigValue_write_latency_1333:
|
||||
case KipConfigValue_write_latency_1600:
|
||||
case KipConfigValue_write_latency_1866:
|
||||
case KipConfigValue_write_latency_2133:
|
||||
case KipConfigValue_read_latency_1333:
|
||||
case KipConfigValue_read_latency_1600:
|
||||
case KipConfigValue_read_latency_1866:
|
||||
case KipConfigValue_read_latency_2133:
|
||||
return {
|
||||
"Latency bracket settings",
|
||||
"Example:",
|
||||
"If 1333 is set to 2000 MHz, 1600 set to 2500 MHz, 1866 set to 2766 MHz and 2133 set to 2933 MHz:",
|
||||
"Frequencies below 2000 MHz use 1333, 2033-2500 MHz use 1600, 2533-2766 MHz use 1866 and 2800-2933 MHz use 2133. ",
|
||||
"Either of these can be omitted and it will work (say you set 1333 to -, then <2000 MHz will use 1600 latency)",
|
||||
"If all of these parameters are omitted the latency will automatically be calculated as follows:",
|
||||
"1633-1866 MHz - 1866 WRL",
|
||||
"1900+ MHz - 2133 WRL",
|
||||
"These properties apply for both write and read latencies, and you can mix-and-match the brackets if necessary",
|
||||
"Default: -"
|
||||
};
|
||||
case KipConfigValue_marikoCpuUVLow:
|
||||
return {
|
||||
"The CPU UV level used before tBreak",
|
||||
"Default: 0"
|
||||
};
|
||||
|
||||
case KipConfigValue_marikoCpuUVHigh:
|
||||
return {
|
||||
"The CPU UV level used after tBreak",
|
||||
"Default: 0"
|
||||
};
|
||||
|
||||
case KipConfigValue_tableConf:
|
||||
return {
|
||||
"The current UV table used. The tbreaks are as follows:",
|
||||
"1581 MHz tBreak and 1683 MHz tBreak use their respective tBreaks",
|
||||
"The other tables use 1581 MHz as tBreak",
|
||||
"The \"Default\" table does not contain frequencies past 1963 MHz and may not undervolt correctly"
|
||||
};
|
||||
|
||||
case KipConfigValue_marikoCpuLowVmin:
|
||||
return {
|
||||
"The CPU vmin used before tBreak",
|
||||
"Default: 620 mV"
|
||||
};
|
||||
|
||||
case KipConfigValue_marikoCpuHighVmin:
|
||||
return {
|
||||
"The CPU vmin used after tBreak",
|
||||
"Default: 750 mV"
|
||||
};
|
||||
|
||||
|
||||
case KipConfigValue_marikoCpuMaxVolt:
|
||||
return {
|
||||
"The maximum voltage that the CPU can use",
|
||||
"Change this setting with caution!",
|
||||
"Default: 1120 mV"
|
||||
};
|
||||
|
||||
case KipConfigValue_marikoCpuMaxClock:
|
||||
return {
|
||||
"The maximum available CPU clock",
|
||||
"Default: 1963 MHz"
|
||||
};
|
||||
|
||||
case KipConfigValue_marikoCpuBoostClock:
|
||||
return {
|
||||
"The clock used for the CPU in \"boost mode\"",
|
||||
"Default: 1963 MHz"
|
||||
};
|
||||
|
||||
case KipConfigValue_eristaCpuUV:
|
||||
return {
|
||||
"CPU undervolt level",
|
||||
"Default: 0"
|
||||
};
|
||||
|
||||
case KipConfigValue_eristaCpuUnlock:
|
||||
return {
|
||||
"Unlock unsafe CPU clocks",
|
||||
"Default: OFF"
|
||||
};
|
||||
|
||||
case KipConfigValue_eristaCpuVmin:
|
||||
return {
|
||||
"Minimum CPU voltage",
|
||||
"Default: 825 mV"
|
||||
};
|
||||
|
||||
case KipConfigValue_eristaCpuMaxVolt:
|
||||
return {
|
||||
"Maximum CPU voltage",
|
||||
"Default: 1235 mV"
|
||||
};
|
||||
|
||||
case HocClkConfigValue_EristaMaxCpuClock:
|
||||
return {
|
||||
"The maximum available CPU clock",
|
||||
"Default: 1785 MHz"
|
||||
};
|
||||
|
||||
case KipConfigValue_eristaCpuBoostClock:
|
||||
return {
|
||||
"The clock used for the CPU in \"boost mode\"",
|
||||
"Default: 1785 MHz"
|
||||
};
|
||||
|
||||
case HocClkConfigValue_OverwriteBoostMode:
|
||||
return {
|
||||
"If enabled, profiles can override the boost mode setting",
|
||||
"Default: OFF"
|
||||
};
|
||||
|
||||
case KipConfigValue_marikoGpuUV:
|
||||
return {
|
||||
"GPU undervolt level",
|
||||
"Options:",
|
||||
" - HiOPT: L4T Custom HiOPT table",
|
||||
" - HiOPT - 15mV: L4T Custom HiOPT table with a 15mV offset",
|
||||
" - High UV: The highest undervolt table, recommended",
|
||||
"Default: HiOPT"
|
||||
};
|
||||
|
||||
case KipConfigValue_marikoGpuVmin:
|
||||
return {
|
||||
"Minimum GPU voltage",
|
||||
"Note: DVFS may change this value when the RAM clock is changed if the DVFS mode is set to PCV Hijack",
|
||||
"Default: 610 mV"
|
||||
};
|
||||
|
||||
case KipConfigValue_marikoGpuVmax:
|
||||
return {
|
||||
"Maximum GPU voltage",
|
||||
"Default: 800 mV"
|
||||
};
|
||||
|
||||
case HocClkConfigValue_DVFSMode:
|
||||
return {
|
||||
"The mode used for GPU DVFS",
|
||||
"Adjusts GPU vmin when RAM clock is changed due to a higher requirement",
|
||||
"Options:",
|
||||
"- Disabled: disabled...",
|
||||
"- PCV Hijack: hijack PCV for override",
|
||||
"Default: PCV Hijack"
|
||||
};
|
||||
|
||||
case HocClkConfigValue_DVFSOffset:
|
||||
return {
|
||||
"The offset added/subtracted to the GPU vmin when the RAM clock is changed due to a higher requirement in PCV Hijack mode",
|
||||
"Default: 0 mV (Disabled)"
|
||||
};
|
||||
|
||||
case KipConfigValue_eristaGpuUV:
|
||||
return {
|
||||
"GPU undervolt level",
|
||||
"Options:",
|
||||
" - HiOPT: L4T Custom HiOPT table",
|
||||
" - HiOPT - 15mV: L4T Custom HiOPT table with a 15mV offset",
|
||||
" - High UV: The highest undervolt table, recommended",
|
||||
"Default: HiOPT"
|
||||
};
|
||||
|
||||
case KipConfigValue_eristaGpuVmin:
|
||||
return {
|
||||
"Minimum GPU voltage",
|
||||
"Default: 810 mV (812mV as erista is stepped by 6.5mV instead of 5mV)"
|
||||
};
|
||||
|
||||
case KipConfigValue_commonGpuVoltOffset:
|
||||
return {
|
||||
"The offset added/subtracted to all AUTO GPU voltages",
|
||||
"Default: 0 mV (Disabled)"
|
||||
};
|
||||
|
||||
case HocClkConfigValue_GPUScheduling:
|
||||
return {
|
||||
"The scheduling method used for GPU clocks",
|
||||
"Options:",
|
||||
"- Do Not Override: Do not override existing scheduling mode",
|
||||
"- Disabled: Disables GPU scheduling, 99.7% GPU max load",
|
||||
"- 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 {};
|
||||
}
|
||||
}
|
||||
23
Source/hoc-clk/overlay/src/ui/gui/config_info_strings.h
Normal file
23
Source/hoc-clk/overlay/src/ui/gui/config_info_strings.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) Souldbminer, Lightos_ and Horizon OC Contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
#include "misc_gui.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
std::vector<std::string> ConfigInfoStrings(HocClkConfigValue val, bool isMariko, bool isHoag);
|
||||
@@ -25,6 +25,7 @@
|
||||
*/
|
||||
|
||||
|
||||
#include "ult_ext.h"
|
||||
#include "freq_choice_gui.h"
|
||||
|
||||
#include "../format.h"
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ult_ext.h"
|
||||
#include "../format.h"
|
||||
#include "fatal_gui.h"
|
||||
#include "global_override_gui.h"
|
||||
|
||||
88
Source/hoc-clk/overlay/src/ui/gui/info_gui.cpp
Normal file
88
Source/hoc-clk/overlay/src/ui/gui/info_gui.cpp
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) Souldbminer, Lightos_ and Horizon OC Contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "info_gui.h"
|
||||
#include "ult_ext.h"
|
||||
#include <sstream>
|
||||
|
||||
InfoGui::InfoGui(std::string title, std::vector<std::string> strings)
|
||||
: m_title(std::move(title)), m_strings(std::move(strings)) {}
|
||||
|
||||
static constexpr s32 TEXT_SIZE = 16;
|
||||
static constexpr s32 LINE_H = 22;
|
||||
static constexpr s32 PARA_GAP = 10;
|
||||
static constexpr s32 MARGIN_L = 20;
|
||||
static constexpr s32 MARGIN_R = 35;
|
||||
|
||||
static std::vector<std::string> wrapText(const std::string& text, s32 maxWidth)
|
||||
{
|
||||
constexpr float CHAR_W = 10.0f;
|
||||
|
||||
// Preserve leading whitespace as an indent prefix for wrapped continuation lines.
|
||||
std::string indent;
|
||||
for (char c : text) {
|
||||
if (c == ' ') indent += ' ';
|
||||
else break;
|
||||
}
|
||||
|
||||
std::vector<std::string> lines;
|
||||
std::istringstream ss(text);
|
||||
std::string word, line = indent; // seed with indent so first word inherits it
|
||||
bool first = true;
|
||||
while (ss >> word) {
|
||||
std::string candidate = (first && !indent.empty()) ? indent + word
|
||||
: line.empty() ? word
|
||||
: line + " " + word;
|
||||
first = false;
|
||||
if (static_cast<s32>(candidate.size() * CHAR_W) <= maxWidth)
|
||||
line = std::move(candidate);
|
||||
else {
|
||||
if (!line.empty() && line != indent) lines.push_back(line);
|
||||
line = indent + word;
|
||||
}
|
||||
}
|
||||
if (!line.empty() && line != indent) lines.push_back(line);
|
||||
if (lines.empty()) lines.emplace_back("");
|
||||
return lines;
|
||||
}
|
||||
|
||||
void InfoGui::listUI()
|
||||
{
|
||||
this->listElement->addItem(new tsl::elm::CategoryHeader(m_title));
|
||||
|
||||
const s32 maxWidth = tsl::cfg::FramebufferWidth - MARGIN_L - MARGIN_R;
|
||||
|
||||
for (const auto& para : m_strings) {
|
||||
for (const auto& lineText : wrapText(para, maxWidth)) {
|
||||
auto* d = new FocusableDrawer(
|
||||
[lineText](tsl::gfx::Renderer* r, s32 x, s32 y, s32 w, s32 h) {
|
||||
r->drawString((lineText + "\n").c_str(), false,
|
||||
x + MARGIN_L, y + LINE_H - 5,
|
||||
TEXT_SIZE, tsl::style::color::ColorText);
|
||||
});
|
||||
d->setBoundaries(0, 0, tsl::cfg::FramebufferWidth, LINE_H);
|
||||
this->listElement->addItem(d, LINE_H);
|
||||
}
|
||||
|
||||
// paragraph gap
|
||||
auto* gap = new tsl::elm::CustomDrawer(
|
||||
[](tsl::gfx::Renderer*, s32, s32, s32, s32) {});
|
||||
gap->setBoundaries(0, 0, tsl::cfg::FramebufferWidth, PARA_GAP);
|
||||
this->listElement->addItem(gap, PARA_GAP);
|
||||
}
|
||||
}
|
||||
33
Source/hoc-clk/overlay/src/ui/gui/info_gui.h
Normal file
33
Source/hoc-clk/overlay/src/ui/gui/info_gui.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) Souldbminer, Lightos_ and Horizon OC Contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
#include "base_menu_gui.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class InfoGui : public BaseMenuGui
|
||||
{
|
||||
public:
|
||||
InfoGui(std::string title, std::vector<std::string> strings);
|
||||
~InfoGui() = default;
|
||||
void listUI() override;
|
||||
|
||||
private:
|
||||
std::string m_title;
|
||||
std::vector<std::string> m_strings;
|
||||
};
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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; }
|
||||
};
|
||||
@@ -17,7 +17,9 @@
|
||||
*/
|
||||
|
||||
#include "misc_gui.h"
|
||||
#include "ult_ext.h"
|
||||
#include "fatal_gui.h"
|
||||
#include "config_info_strings.h"
|
||||
#include "../format.h"
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
@@ -60,7 +62,6 @@ class RamLatenciesSubmenuGui;
|
||||
class CpuSubmenuGui;
|
||||
class GpuSubmenuGui;
|
||||
class GpuCustomTableSubmenuGui;
|
||||
class RamTableEditor;
|
||||
class ExperimentalSettingsSubMenuGui;
|
||||
|
||||
MiscGui::MiscGui()
|
||||
@@ -88,7 +89,24 @@ MiscGui::~MiscGui()
|
||||
|
||||
void MiscGui::addConfigToggle(HocClkConfigValue configVal, const char* altName, bool kip) {
|
||||
const char* configName = altName ? altName : hocclkFormatConfigValue(configVal, true);
|
||||
tsl::elm::ToggleListItem* toggle = new tsl::elm::ToggleListItem(configName, this->configList->values[configVal]);
|
||||
auto infoStrings = ConfigInfoStrings(configVal, IsMariko(), IsHoag());
|
||||
|
||||
struct YAwareToggle : tsl::elm::ToggleListItem {
|
||||
std::vector<std::string> m_info;
|
||||
std::string m_title;
|
||||
YAwareToggle(const char* text, bool state, std::string title, std::vector<std::string> info)
|
||||
: tsl::elm::ToggleListItem(text, state), m_info(std::move(info)), m_title(std::move(title)) {}
|
||||
bool onClick(u64 keys) override {
|
||||
if (!m_info.empty() && (keys & HidNpadButton_Y) && !(keys & ~HidNpadButton_Y)) {
|
||||
tsl::changeTo<InfoGui>(m_title, m_info);
|
||||
return true;
|
||||
}
|
||||
return tsl::elm::ToggleListItem::onClick(keys);
|
||||
}
|
||||
};
|
||||
|
||||
auto* toggle = new YAwareToggle(configName, this->configList->values[configVal],
|
||||
configName, std::move(infoStrings));
|
||||
if (!kip)
|
||||
toggle->setTextColor(tsl::Color(120, 235, 255, 255));
|
||||
toggle->setStateChangedListener([this, configVal, kip](bool state) {
|
||||
@@ -106,9 +124,13 @@ void MiscGui::addConfigToggle(HocClkConfigValue configVal, const char* altName,
|
||||
}
|
||||
|
||||
void MiscGui::addConfigTrackbar(HocClkConfigValue configVal, const char* altName, const ValueRange& range, bool kip) {
|
||||
auto infoStrings = ConfigInfoStrings(configVal, IsMariko(), IsHoag());
|
||||
struct IndexedBar : tsl::elm::NamedStepTrackBar {
|
||||
IndexedBar(const char* label, const ValueRange& r)
|
||||
: tsl::elm::NamedStepTrackBar("", {""}, true, label) {
|
||||
std::vector<std::string> m_info;
|
||||
std::string m_title;
|
||||
IndexedBar(const char* label, const ValueRange& r, std::string title, std::vector<std::string> info)
|
||||
: tsl::elm::NamedStepTrackBar("", {""}, true, label),
|
||||
m_info(std::move(info)), m_title(std::move(title)) {
|
||||
m_stepDescriptions.clear();
|
||||
u32 numSteps = (r.max - r.min) / r.step + 1;
|
||||
for (u32 i = 0; i < numSteps; i++) {
|
||||
@@ -120,9 +142,17 @@ void MiscGui::addConfigTrackbar(HocClkConfigValue configVal, const char* altName
|
||||
m_numSteps = (u8)m_stepDescriptions.size();
|
||||
m_selection = m_stepDescriptions[0];
|
||||
}
|
||||
bool handleInput(u64 keysDown, u64 keysHeld, const HidTouchState& touchPos,
|
||||
HidAnalogStickState leftJoyStick, HidAnalogStickState rightJoyStick) override {
|
||||
if (!m_info.empty() && (keysDown & HidNpadButton_Y) && !(keysDown & ~HidNpadButton_Y)) {
|
||||
tsl::changeTo<InfoGui>(m_title, m_info);
|
||||
return true;
|
||||
}
|
||||
return tsl::elm::NamedStepTrackBar::handleInput(keysDown, keysHeld, touchPos, leftJoyStick, rightJoyStick);
|
||||
}
|
||||
};
|
||||
const char* name = altName ? altName : hocclkFormatConfigValue(configVal, true);
|
||||
auto* bar = new IndexedBar(name, range);
|
||||
auto* bar = new IndexedBar(name, range, name, std::move(infoStrings));
|
||||
u32 cur = (u32)this->configList->values[configVal];
|
||||
u16 curStep = 0;
|
||||
if (cur >= range.min && cur <= range.max && range.step > 0 && (cur - range.min) % range.step == 0)
|
||||
@@ -141,7 +171,25 @@ void MiscGui::addMappedConfigTrackbar(HocClkConfigValue configVal, const char* a
|
||||
std::vector<u32> vals,
|
||||
std::initializer_list<std::string> names, bool kip) {
|
||||
const char* name = altName ? altName : hocclkFormatConfigValue(configVal, true);
|
||||
auto* bar = new tsl::elm::NamedStepTrackBar("", names, true, name);
|
||||
auto infoStrings = ConfigInfoStrings(configVal, IsMariko(), IsHoag());
|
||||
|
||||
struct YAwareTrackBar : tsl::elm::NamedStepTrackBar {
|
||||
std::vector<std::string> m_info;
|
||||
std::string m_title;
|
||||
YAwareTrackBar(const char* label, std::initializer_list<std::string> steps, std::string title, std::vector<std::string> info)
|
||||
: tsl::elm::NamedStepTrackBar("", steps, true, label),
|
||||
m_info(std::move(info)), m_title(std::move(title)) {}
|
||||
bool handleInput(u64 keysDown, u64 keysHeld, const HidTouchState& touchPos,
|
||||
HidAnalogStickState leftJoyStick, HidAnalogStickState rightJoyStick) override {
|
||||
if (!m_info.empty() && (keysDown & HidNpadButton_Y) && !(keysDown & ~HidNpadButton_Y)) {
|
||||
tsl::changeTo<InfoGui>(m_title, m_info);
|
||||
return true;
|
||||
}
|
||||
return tsl::elm::NamedStepTrackBar::handleInput(keysDown, keysHeld, touchPos, leftJoyStick, rightJoyStick);
|
||||
}
|
||||
};
|
||||
|
||||
auto* bar = new YAwareTrackBar(name, names, name, std::move(infoStrings));
|
||||
u32 cur = (u32)this->configList->values[configVal];
|
||||
u16 curIdx = 0;
|
||||
for (u16 i = 0; i < (u16)vals.size(); i++) {
|
||||
@@ -170,6 +218,7 @@ void MiscGui::addConfigButton(HocClkConfigValue configVal,
|
||||
bool kip)
|
||||
{
|
||||
const char* configName = altName ? altName : hocclkFormatConfigValue(configVal, true);
|
||||
auto infoStrings = ConfigInfoStrings(configVal, IsMariko(), IsHoag());
|
||||
|
||||
tsl::elm::ListItem* listItem = new tsl::elm::ListItem(configName);
|
||||
if (!kip)
|
||||
@@ -203,8 +252,14 @@ void MiscGui::addConfigButton(HocClkConfigValue configVal,
|
||||
ValueThresholds thresholdsCopy = (thresholds ? *thresholds : ValueThresholds{});
|
||||
|
||||
listItem->setClickListener(
|
||||
[this, configVal, range, categoryName, thresholdsCopy, labels, showDefaultValue, kip](u64 keys)
|
||||
[this, configVal, range, categoryName, thresholdsCopy, labels, showDefaultValue, kip,
|
||||
infoStrings = std::move(infoStrings), configName = std::string(configName)](u64 keys)
|
||||
{
|
||||
if (!infoStrings.empty() && (keys & HidNpadButton_Y) && !(keys & ~HidNpadButton_Y)) {
|
||||
tsl::changeTo<InfoGui>(configName, infoStrings);
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((keys & HidNpadButton_A) == 0)
|
||||
return false;
|
||||
|
||||
@@ -287,6 +342,8 @@ void MiscGui::addConfigButtonS(HocClkConfigValue configVal,
|
||||
const char* subText,
|
||||
bool kip)
|
||||
{
|
||||
const char* configName = altName ? altName : hocclkFormatConfigValue(configVal, true);
|
||||
auto infoStrings = ConfigInfoStrings(configVal, IsMariko(), IsHoag());
|
||||
tsl::elm::ListItem* listItem = new tsl::elm::ListItem("");
|
||||
if (!kip)
|
||||
listItem->setTextColor(tsl::Color(120, 235, 255, 255));
|
||||
@@ -321,8 +378,14 @@ void MiscGui::addConfigButtonS(HocClkConfigValue configVal,
|
||||
ValueThresholds thresholdsCopy = (thresholds ? *thresholds : ValueThresholds{});
|
||||
|
||||
listItem->setClickListener(
|
||||
[this, configVal, range, categoryName, thresholdsCopy, labels, showDefaultValue, kip](u64 keys)
|
||||
[this, configVal, range, categoryName, thresholdsCopy, labels, showDefaultValue, kip,
|
||||
infoStrings = std::move(infoStrings), configName = std::string(configName)](u64 keys)
|
||||
{
|
||||
if (!infoStrings.empty() && (keys & HidNpadButton_Y) && !(keys & ~HidNpadButton_Y)) {
|
||||
tsl::changeTo<InfoGui>(configName, infoStrings);
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((keys & HidNpadButton_A) == 0)
|
||||
return false;
|
||||
|
||||
@@ -410,6 +473,7 @@ void MiscGui::addFreqButton(HocClkConfigValue configVal,
|
||||
const std::map<uint32_t, std::string>& labels)
|
||||
{
|
||||
const char* configName = altName ? altName : hocclkFormatConfigValue(configVal, true);
|
||||
auto infoStrings = ConfigInfoStrings(configVal, IsMariko(), IsHoag());
|
||||
|
||||
tsl::elm::ListItem* listItem = new tsl::elm::ListItem(configName);
|
||||
|
||||
@@ -419,8 +483,14 @@ void MiscGui::addFreqButton(HocClkConfigValue configVal,
|
||||
listItem->setValue(valueText);
|
||||
|
||||
listItem->setClickListener(
|
||||
[this, configVal, module, labels](u64 keys)
|
||||
[this, configVal, module, labels,
|
||||
infoStrings = std::move(infoStrings), configName = std::string(configName)](u64 keys)
|
||||
{
|
||||
if (!infoStrings.empty() && (keys & HidNpadButton_Y) && !(keys & ~HidNpadButton_Y)) {
|
||||
tsl::changeTo<InfoGui>(configName, infoStrings);
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((keys & HidNpadButton_A) == 0)
|
||||
return false;
|
||||
|
||||
@@ -478,13 +548,16 @@ 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);
|
||||
renderer->drawString("don't require a reboot to apply!", false, x + 20, y + 50, 18, tsl::style::color::ColorText);
|
||||
renderer->drawString("You can also press \ue0e3 to show", false, x + 20, y + 70, 18, tsl::style::color::ColorText);
|
||||
renderer->drawString("information about each setting.", false, x + 20, y + 90, 18, tsl::style::color::ColorText);
|
||||
|
||||
});
|
||||
rebootSetWarning->setBoundaries(0, 0, tsl::cfg::FramebufferWidth, 70);
|
||||
rebootSetWarning->setBoundaries(0, 0, tsl::cfg::FramebufferWidth, 110);
|
||||
this->listElement->addItem(rebootSetWarning);
|
||||
|
||||
tsl::elm::ListItem* sysmoduleSettingsSubMenu = new tsl::elm::ListItem("General Settings");
|
||||
@@ -587,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 = {
|
||||
@@ -615,7 +688,7 @@ protected:
|
||||
false
|
||||
|
||||
);
|
||||
|
||||
|
||||
addConfigButton(
|
||||
HocClkConfigValue_PollingIntervalMs,
|
||||
"Polling Interval",
|
||||
@@ -647,7 +720,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("Experimental Settings"));
|
||||
this->listElement->addItem(new CompactCategoryHeader("Experimental Settings"));
|
||||
ValueThresholds thresholdsDisabled(0, 0);
|
||||
if(IsMariko()) {
|
||||
addConfigToggle(HocClkConfigValue_MarikoMiddleFreqs, nullptr, true);
|
||||
@@ -783,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 = {
|
||||
@@ -824,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) {
|
||||
@@ -849,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",
|
||||
@@ -871,7 +952,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("Safety Settings"));
|
||||
this->listElement->addItem(new CompactCategoryHeader("Safety Settings"));
|
||||
addConfigToggle(HocClkConfigValue_UncappedClocks, nullptr);
|
||||
addConfigToggle(HocClkConfigValue_ThermalThrottle, nullptr);
|
||||
addConfigToggle(HocClkConfigValue_HandheldTDP, nullptr);
|
||||
@@ -931,8 +1012,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"});
|
||||
@@ -974,7 +1055,7 @@ protected:
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
addConfigToggle(KipConfigValue_hpMode, "HP Mode", true);
|
||||
|
||||
std::map<uint32_t, std::string> emc_voltage_label = {
|
||||
@@ -986,7 +1067,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",
|
||||
@@ -1000,12 +1081,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,
|
||||
@@ -1024,20 +1106,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),
|
||||
@@ -1091,19 +1204,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) {
|
||||
@@ -1138,7 +1252,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));
|
||||
@@ -1219,11 +1333,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"});
|
||||
@@ -1237,10 +1484,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++) {
|
||||
@@ -1275,35 +1529,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,
|
||||
@@ -1350,7 +1606,12 @@ protected:
|
||||
tsl::elm::ListItem* item = new tsl::elm::ListItem(label);
|
||||
item->setValue(makeValueText(currentVal));
|
||||
|
||||
item->setClickListener([this, tierIdx, thisKey, keysArr](u64 keys) -> bool {
|
||||
item->setClickListener([this, tierIdx, thisKey, keysArr, label](u64 keys) -> bool {
|
||||
auto infoStrings = ConfigInfoStrings(thisKey, IsMariko(), IsHoag());
|
||||
if (!infoStrings.empty() && (keys & HidNpadButton_Y) && !(keys & ~HidNpadButton_Y)) {
|
||||
tsl::changeTo<InfoGui>(std::string(label), infoStrings);
|
||||
return true;
|
||||
}
|
||||
if ((keys & HidNpadButton_A) == 0)
|
||||
return false;
|
||||
|
||||
@@ -1358,7 +1619,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 {
|
||||
@@ -1476,11 +1737,213 @@ 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 + 52;
|
||||
const s32 gw = w - 64;
|
||||
const s32 gy = y + 14;
|
||||
const s32 gh = 54;
|
||||
const s32 th = gh / 3;
|
||||
const s32 axisY = gy + gh;
|
||||
|
||||
auto tierY = [&](int i) -> s32 { return gy + gh - i * th; };
|
||||
// Fixed ruler: 1600 MHz (left) → 3300 MHz (right)
|
||||
constexpr uint32_t kRMin = 1600000u, kRMax = 3300000u;
|
||||
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 pix = 2;
|
||||
const s32 charH = 3 * pix;
|
||||
const s32 charW = 5 * pix;
|
||||
const s32 charGap = 1;
|
||||
|
||||
auto drawSidewaysMHz = [&](uint32_t mhz, s32 cx, s32 startY, const tsl::Color& c) {
|
||||
char buf[8];
|
||||
snprintf(buf, sizeof(buf), "%u", mhz);
|
||||
s32 originX = 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)) continue;
|
||||
renderer->drawRect(originX + (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);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
@@ -1504,7 +1967,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));
|
||||
@@ -1566,7 +2029,7 @@ protected:
|
||||
true
|
||||
);
|
||||
|
||||
|
||||
|
||||
std::vector<NamedValue> maxClkOptions = {
|
||||
NamedValue("1963 MHz", 1963500),
|
||||
NamedValue("2091 MHz", 2091000),
|
||||
@@ -1688,78 +2151,6 @@ protected:
|
||||
}
|
||||
};
|
||||
|
||||
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() { }
|
||||
@@ -1771,7 +2162,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),
|
||||
@@ -1853,6 +2244,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(
|
||||
@@ -1910,7 +2302,6 @@ protected:
|
||||
false
|
||||
);
|
||||
|
||||
if (IsMariko()) {
|
||||
std::vector<NamedValue> dvfsOffset = {
|
||||
NamedValue("-80 mV", 0xFFFFFFB0),
|
||||
NamedValue("-75 mV", 0xFFFFFFB5),
|
||||
@@ -1953,7 +2344,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) {
|
||||
@@ -1981,7 +2371,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);
|
||||
@@ -2242,8 +2632,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);
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <vector>
|
||||
#include "freq_choice_gui.h"
|
||||
#include "value_choice_gui.h"
|
||||
#include "info_gui.h"
|
||||
class MiscGui : public BaseMenuGui
|
||||
{
|
||||
public:
|
||||
@@ -32,7 +33,7 @@ public:
|
||||
~MiscGui();
|
||||
void listUI() override;
|
||||
void refresh() override;
|
||||
|
||||
|
||||
protected:
|
||||
HocClkConfigValueList* configList;
|
||||
std::map<HocClkConfigValue, tsl::elm::ListItem*> configButtons;
|
||||
@@ -43,7 +44,7 @@ protected:
|
||||
std::set<HocClkConfigValue> configButtonSKeys;
|
||||
std::map<HocClkConfigValue, std::string> configButtonSSubtext;
|
||||
std::set<HocClkConfigValue> emcClockConfigs;
|
||||
|
||||
|
||||
void addConfigToggle(HocClkConfigValue configVal, const char* altName, bool kip = false);
|
||||
void addConfigTrackbar(HocClkConfigValue configVal, const char* altName, const ValueRange& range, bool kip = true);
|
||||
void addMappedConfigTrackbar(HocClkConfigValue configVal, const char* altName,
|
||||
@@ -74,8 +75,8 @@ protected:
|
||||
HocClkModule module,
|
||||
const std::map<uint32_t, std::string>& labels = {});
|
||||
void updateConfigToggles();
|
||||
|
||||
|
||||
tsl::elm::ToggleListItem* enabledToggle;
|
||||
u8 frameCounter = 60;
|
||||
bool shouldSaveKip = false;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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:
|
||||
@@ -95,6 +117,18 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class FocusableDrawer : public tsl::elm::CustomDrawer {
|
||||
public:
|
||||
template<typename... Args>
|
||||
FocusableDrawer(Args&&... args) : tsl::elm::CustomDrawer(std::forward<Args>(args)...) {
|
||||
m_isItem = true;
|
||||
}
|
||||
Element* requestFocus(Element*, tsl::FocusDirection) override {
|
||||
return this;
|
||||
}
|
||||
void drawHighlight(tsl::gfx::Renderer*) override {}
|
||||
};
|
||||
|
||||
class HideableCustomDrawer : public tsl::elm::Element {
|
||||
private:
|
||||
bool visible;
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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.0
|
||||
KIP_VERSION := 230
|
||||
CUST_REV := 3
|
||||
TARGET_VERSION := 2.4.0
|
||||
KIP_VERSION := 240
|
||||
CUST_REV := 4
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
#include <registers.h>
|
||||
#include <battery.h>
|
||||
#include "../display/display_refresh_rate.hpp"
|
||||
#include <rgltr.h>
|
||||
#include <notification.h>
|
||||
|
||||
#include "board.hpp"
|
||||
@@ -49,6 +48,7 @@
|
||||
#include "../tsensor/aotag.hpp"
|
||||
#include "../hos/integrations.hpp"
|
||||
#include "../file/file_utils.hpp"
|
||||
#include "../hos/rgltr.h"
|
||||
namespace board {
|
||||
|
||||
u64 clkVirtAddr, dsiVirtAddr, apbVirtAddr, fuseVirtAddr;
|
||||
@@ -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;
|
||||
}
|
||||
@@ -135,12 +134,12 @@ namespace board {
|
||||
rc = tmp451Initialize();
|
||||
ASSERT_RESULT_OK(rc, "tmp451Initialize");
|
||||
|
||||
rc = rgltrInitialize();
|
||||
ASSERT_RESULT_OK(rc, "rgltrInitialize");
|
||||
|
||||
rc = pmdmntInitialize();
|
||||
ASSERT_RESULT_OK(rc, "pmdmntInitialize");
|
||||
|
||||
rc = rgltrInitialize();
|
||||
ASSERT_RESULT_OK(rc, "rgltrInitialize");
|
||||
|
||||
rc = QueryMemoryMapping(&clkVirtAddr, 0x60006000, 0x1000);
|
||||
ASSERT_RESULT_OK(rc, "QueryMemoryMapping (clk)");
|
||||
|
||||
@@ -194,6 +193,7 @@ namespace board {
|
||||
display::Initialize(&cfg);
|
||||
|
||||
CacheDfllData();
|
||||
CacheGpuVoltTable();
|
||||
}
|
||||
|
||||
void Exit() {
|
||||
@@ -205,7 +205,7 @@ namespace board {
|
||||
|
||||
apmExtExit();
|
||||
psmExit();
|
||||
|
||||
rgltrExit();
|
||||
if (HOSSVC_HAS_TC) {
|
||||
tcExit();
|
||||
}
|
||||
@@ -220,7 +220,6 @@ namespace board {
|
||||
|
||||
pwmChannelSessionClose(&iCon);
|
||||
pwmExit();
|
||||
rgltrExit();
|
||||
batteryInfoExit();
|
||||
pmdmntExit();
|
||||
nvExit();
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#include "../soc/pllmb.hpp"
|
||||
#include "../file/config.hpp"
|
||||
#include "../soc/gm20b.hpp"
|
||||
#include "../file/config.hpp"
|
||||
namespace board {
|
||||
#define MIDDLE_FREQ_TABLE_START_POINT 1228800000
|
||||
static u32 currentInjectedHz = 0;
|
||||
@@ -75,6 +76,14 @@ namespace board {
|
||||
ASSERT_RESULT_OK(pcvSetClockRate(moduleID, hz), "pcvSetClockRate");
|
||||
}
|
||||
|
||||
void HandleCpuUv()
|
||||
{
|
||||
if (board::GetSocType() == HocClkSocType_Erista)
|
||||
board::SetDfllTunings(config::GetConfigValue(KipConfigValue_eristaCpuUV), 0, 1581000000); // Erista tbreak is always 1581MHz
|
||||
else
|
||||
board::SetDfllTunings(config::GetConfigValue(KipConfigValue_marikoCpuUVLow), config::GetConfigValue(KipConfigValue_marikoCpuUVHigh), board::CalculateTbreak(config::GetConfigValue(KipConfigValue_tableConf)));
|
||||
}
|
||||
|
||||
void SetHz(HocClkModule module, u32 hz) {
|
||||
Result rc = 0;
|
||||
bool usesGovenor = module > HocClkModule_MEM;
|
||||
@@ -116,7 +125,9 @@ namespace board {
|
||||
PcvSetHz(GetPcvModule(module), pcvHz);
|
||||
}
|
||||
}
|
||||
|
||||
if(config::GetConfigValue(HocClkConfigValue_LiveCpuUv) && module == HocClkModule_CPU) {
|
||||
HandleCpuUv();
|
||||
}
|
||||
if (useGm20b) {
|
||||
gm20b::setClock(hz / 1000);
|
||||
currentInjectedHz = hz;
|
||||
|
||||
@@ -44,7 +44,8 @@ namespace board {
|
||||
u32 GetRealHz(HocClkModule module);
|
||||
void GetFreqList(HocClkModule module, u32 *outList, u32 maxCount, u32 *outCount);
|
||||
u32 GetHighestDockedDisplayRate();
|
||||
|
||||
void HandleCpuUv();
|
||||
|
||||
void ResetToStock();
|
||||
void ResetToStockDisplay();
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
#include <switch.h>
|
||||
#include <pwm.h>
|
||||
#include <cmath>
|
||||
#include <rgltr.h>
|
||||
|
||||
namespace board {
|
||||
|
||||
|
||||
@@ -22,13 +22,13 @@
|
||||
#include <memmem.h>
|
||||
#include <registers.h>
|
||||
#include <cstring>
|
||||
#include <rgltr.h>
|
||||
#include <battery.h>
|
||||
#include "board.hpp"
|
||||
#include "board_freq.hpp"
|
||||
#include "board_volt.hpp"
|
||||
#include "../file/file_utils.hpp"
|
||||
|
||||
#include "../i2c/i2cDrv.h"
|
||||
#include "../hos/rgltr.h"
|
||||
namespace board {
|
||||
|
||||
GpuVoltData voltData = {};
|
||||
@@ -50,7 +50,8 @@ namespace board {
|
||||
u32 tune1_high;
|
||||
};
|
||||
|
||||
EristaCpuUvEntry eristaCpuUvTable[5] = {
|
||||
EristaCpuUvEntry eristaCpuUvTable[6] = {
|
||||
{0xFFEAD0FF, 0x0},
|
||||
{0xffff, 0x27007ff},
|
||||
{0xefff, 0x27407ff},
|
||||
{0xdfff, 0x27807ff},
|
||||
@@ -135,19 +136,16 @@ 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-1].tune0;
|
||||
*tune1_ptr = eristaCpuUvTable[levelLow-1].tune1;
|
||||
} else {
|
||||
*tune0_ptr = 0x0;
|
||||
*tune1_ptr = 0x0;
|
||||
}
|
||||
}
|
||||
// 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 {
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,60 +212,47 @@ namespace board {
|
||||
PcvPowerDomainId_Max77812_Dram = 0x3A000005, // vddq
|
||||
} PowerDomainId;
|
||||
*/
|
||||
/*
|
||||
Note: I think Nintendo's I2C driver (or my driver, but it looks correct to me)
|
||||
*/
|
||||
u32 GetVoltage(HocClkVoltage voltage) {
|
||||
RgltrSession session;
|
||||
Result rc = 0;
|
||||
u32 out = 0;
|
||||
BatteryChargeInfo info;
|
||||
|
||||
RgltrSession s;
|
||||
switch (voltage) {
|
||||
case HocClkVoltage_SOC:
|
||||
rc = rgltrOpenSession(&session, PcvPowerDomainId_Max77620_Sd0);
|
||||
ASSERT_RESULT_OK(rc, "rgltrOpenSession")
|
||||
rgltrGetVoltage(&session, &out);
|
||||
rgltrCloseSession(&session);
|
||||
out = I2c_BuckConverter_GetUvOut(&I2c_SOC);
|
||||
break;
|
||||
case HocClkVoltage_EMCVDD2:
|
||||
rc = rgltrOpenSession(&session, PcvPowerDomainId_Max77620_Sd1);
|
||||
ASSERT_RESULT_OK(rc, "rgltrOpenSession")
|
||||
rgltrGetVoltage(&session, &out);
|
||||
rgltrCloseSession(&session);
|
||||
out = I2c_BuckConverter_GetUvOut(&I2c_VDD2);
|
||||
break;
|
||||
case HocClkVoltage_CPU:
|
||||
if (GetSocType() == HocClkSocType_Mariko) {
|
||||
rc = rgltrOpenSession(&session, PcvPowerDomainId_Max77621_Cpu);
|
||||
if(GetSocType() == HocClkSocType_Mariko) {
|
||||
out = I2c_BuckConverter_GetUvOut(&I2c_Mariko_CPU);
|
||||
} else {
|
||||
rc = rgltrOpenSession(&session, PcvPowerDomainId_Max77812_Cpu);
|
||||
rgltrOpenSession(&s, PcvPowerDomainId_Max77621_Cpu);
|
||||
rgltrGetVoltage(&s, &out);
|
||||
rgltrCloseSession(&s);
|
||||
}
|
||||
ASSERT_RESULT_OK(rc, "rgltrOpenSession")
|
||||
rgltrGetVoltage(&session, &out);
|
||||
rgltrCloseSession(&session);
|
||||
break;
|
||||
case HocClkVoltage_GPU:
|
||||
if (GetSocType() == HocClkSocType_Mariko) {
|
||||
rc = rgltrOpenSession(&session, PcvPowerDomainId_Max77621_Gpu);
|
||||
if(GetSocType() == HocClkSocType_Mariko) {
|
||||
out = I2c_BuckConverter_GetUvOut(&I2c_Mariko_GPU);
|
||||
} else {
|
||||
rc = rgltrOpenSession(&session, PcvPowerDomainId_Max77812_Gpu);
|
||||
}
|
||||
ASSERT_RESULT_OK(rc, "rgltrOpenSession")
|
||||
rgltrGetVoltage(&session, &out);
|
||||
rgltrCloseSession(&session);
|
||||
rgltrOpenSession(&s, PcvPowerDomainId_Max77621_Gpu);
|
||||
rgltrGetVoltage(&s, &out);
|
||||
rgltrCloseSession(&s);
|
||||
}
|
||||
break;
|
||||
case HocClkVoltage_EMCVDDQ:
|
||||
if (GetSocType() == HocClkSocType_Mariko) {
|
||||
rc = rgltrOpenSession(&session, PcvPowerDomainId_Max77812_Dram);
|
||||
ASSERT_RESULT_OK(rc, "rgltrOpenSession")
|
||||
rgltrGetVoltage(&session, &out);
|
||||
rgltrCloseSession(&session);
|
||||
if(GetSocType() == HocClkSocType_Mariko) {
|
||||
out = I2c_BuckConverter_GetUvOut(&I2c_Mariko_DRAM_VDDQ);
|
||||
} else {
|
||||
out = GetVoltage(HocClkVoltage_EMCVDD2); // VDD2 and VDDQ are always connected to the same rail on Erista
|
||||
out = I2c_BuckConverter_GetUvOut(&I2c_VDD2);
|
||||
}
|
||||
break;
|
||||
case HocClkVoltage_Display:
|
||||
rc = rgltrOpenSession(&session, PcvPowerDomainId_Max77620_Ldo0);
|
||||
ASSERT_RESULT_OK(rc, "rgltrOpenSession")
|
||||
rgltrGetVoltage(&session, &out);
|
||||
rgltrCloseSession(&session);
|
||||
out = I2c_BuckConverter_GetUvOut(&I2c_Display);
|
||||
break;
|
||||
case HocClkVoltage_Battery:
|
||||
batteryInfoGetChargeInfo(&info);
|
||||
@@ -373,8 +358,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));
|
||||
@@ -393,7 +378,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;
|
||||
}
|
||||
@@ -436,43 +421,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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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,17 @@ 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;
|
||||
}
|
||||
config::SetConfigValues(&configValues, true);
|
||||
// This function cannot do anything at the moment. The capabilities will be expanded in the next release
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -29,7 +29,7 @@ namespace integrations {
|
||||
bool gSharedMemoryUsed = false;
|
||||
Handle gRemoteSharedMemory = 1;
|
||||
u64 gPrevTid = 0;
|
||||
|
||||
u8 resolutionLookup = 0;
|
||||
bool CheckSaltyNXPort() {
|
||||
Handle saltysd;
|
||||
|
||||
@@ -129,6 +129,7 @@ namespace integrations {
|
||||
if (gPrevTid != tid) {
|
||||
gNxFps = nullptr;
|
||||
gPrevTid = tid;
|
||||
resolutionLookup = 0;
|
||||
}
|
||||
|
||||
if (!gNxFps) {
|
||||
@@ -137,8 +138,15 @@ namespace integrations {
|
||||
}
|
||||
|
||||
if (gNxFps) {
|
||||
gNxFps->renderCalls[0].calls = 0xFFFF;
|
||||
svcSleepThread(10*1000);
|
||||
if (!resolutionLookup) {
|
||||
gNxFps->renderCalls[0].calls = 0xFFFF;
|
||||
resolutionLookup = 1;
|
||||
return 0;
|
||||
} else if (resolutionLookup == 1) {
|
||||
if (gNxFps->renderCalls[0].calls != 0xFFFF) resolutionLookup = 2;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
return gNxFps->renderCalls[0].height == 0 ? gNxFps->viewportCalls[0].height : gNxFps->renderCalls[0].height;
|
||||
}
|
||||
return 0;
|
||||
|
||||
@@ -63,4 +63,4 @@ Result rgltrCancelVoltageRequest(RgltrSession* session) {
|
||||
|
||||
void rgltrCloseSession(RgltrSession* session) {
|
||||
serviceClose(&session->s);
|
||||
}
|
||||
}
|
||||
@@ -29,4 +29,4 @@ Result rgltrOpenSession(RgltrSession* session_out, PowerDomainId module_id);
|
||||
|
||||
Result rgltrGetVoltage(RgltrSession* session, u32* out_volt);
|
||||
|
||||
void rgltrCloseSession(RgltrSession* session);
|
||||
void rgltrCloseSession(RgltrSession* session);
|
||||
@@ -103,6 +103,10 @@ u32 I2c_BuckConverter_MultiplierToMvOut(const I2c_BuckConverter_Domain* domain,
|
||||
return (domain->uv_min + domain->uv_step * multiplier) / 1000;
|
||||
}
|
||||
|
||||
u32 I2c_BuckConverter_MultiplierToUvOut(const I2c_BuckConverter_Domain* domain, u8 multiplier) {
|
||||
return domain->uv_min + domain->uv_step * multiplier;
|
||||
}
|
||||
|
||||
u8 I2c_BuckConverter_MvOutToMultiplier(const I2c_BuckConverter_Domain* domain, u32 mvolt) {
|
||||
u32 uvolt = mvolt * 1000;
|
||||
if (uvolt < domain->uv_min)
|
||||
@@ -129,6 +133,22 @@ u32 I2c_BuckConverter_GetMvOut(const I2c_BuckConverter_Domain* domain) {
|
||||
return I2c_BuckConverter_MultiplierToMvOut(domain, val & domain->volt_mask);
|
||||
}
|
||||
|
||||
u32 I2c_BuckConverter_GetUvOut(const I2c_BuckConverter_Domain* domain) {
|
||||
u8 val;
|
||||
// Retry 5 times if received POR value
|
||||
for (int i = 0; i < 5; i++) {
|
||||
if (R_FAILED(I2cRead_OutU8(domain->device, domain->reg, &val)))
|
||||
return 0u;
|
||||
|
||||
// Wait 1us
|
||||
svcSleepThread(1E3);
|
||||
|
||||
if (!domain->por_val || val != domain->por_val)
|
||||
break;
|
||||
}
|
||||
return I2c_BuckConverter_MultiplierToUvOut(domain, val & domain->volt_mask);
|
||||
}
|
||||
|
||||
Result I2c_BuckConverter_SetMvOut(const I2c_BuckConverter_Domain* domain, u32 mvolt) {
|
||||
u8 val;
|
||||
Result res = I2cRead_OutU8(domain->device, domain->reg, &val);
|
||||
|
||||
@@ -21,6 +21,7 @@ const u8 MAX17050_CURRENT_REG = 0x0A;
|
||||
|
||||
// Buck Converter
|
||||
typedef enum I2c_BuckConverter_Reg {
|
||||
I2c_Max77620_SD0VOLT_REG = 0x16,
|
||||
I2c_Max77620_SD1VOLT_REG = 0x17, // Used for Erista DDR VDDQ+VDD2 / Mariko VDD2
|
||||
I2c_Max77620_LDO0VOLT_REG = 0x23, // Used for Erista DDR VDDQ+VDD2 / Mariko VDD2
|
||||
I2c_Max77621_VOLT_REG = 0x00,
|
||||
@@ -39,16 +40,17 @@ typedef struct I2c_BuckConverter_Domain {
|
||||
u8 por_val;
|
||||
} I2c_BuckConverter_Domain;
|
||||
|
||||
const I2c_BuckConverter_Domain I2c_SOC = { I2cDevice_Max77620Pmic, I2c_Max77620_SD0VOLT_REG, 0x7F, 12500, 600000, 1400000, };
|
||||
const I2c_BuckConverter_Domain I2c_VDD2 = { I2cDevice_Max77620Pmic, I2c_Max77620_SD1VOLT_REG, 0x7F, 12500, 600000, 1350000, };
|
||||
const I2c_BuckConverter_Domain I2c_Display = { I2cDevice_Max77620Pmic, I2c_Max77620_LDO0VOLT_REG, 0x3F, 25000, 800000, 1325000, };
|
||||
const I2c_BuckConverter_Domain I2c_Erista_CPU = { I2cDevice_Max77621Cpu, I2c_Max77621_VOLT_REG, 0x7F, 6250, 606250, 1400000, };
|
||||
const I2c_BuckConverter_Domain I2c_Erista_GPU = { I2cDevice_Max77621Gpu, I2c_Max77621_VOLT_REG, 0x7F, 6250, 606250, 1400000, };
|
||||
const I2c_BuckConverter_Domain I2c_Erista_DRAM = { I2cDevice_Max77620Pmic, I2c_Max77620_SD1VOLT_REG, 0x3F, 12500, 600000, 1250000, };
|
||||
const I2c_BuckConverter_Domain I2c_Display = { I2cDevice_Max77620Pmic, I2c_Max77620_LDO0VOLT_REG, 0x7F, 25000, 800000, 1325000, };
|
||||
const I2c_BuckConverter_Domain I2c_Mariko_CPU = { I2cDevice_Max77812_2, I2c_Max77812_CPUVOLT_REG, 0xFF, 5000, 250000, 1525000, 0x78 };
|
||||
const I2c_BuckConverter_Domain I2c_Mariko_GPU = { I2cDevice_Max77812_2, I2c_Max77812_GPUVOLT_REG, 0xFF, 5000, 250000, 1525000, 0x78 };
|
||||
const I2c_BuckConverter_Domain I2c_Mariko_DRAM_VDDQ = { I2cDevice_Max77812_2, I2c_Max77812_MEMVOLT_REG, 0xFF, 5000, 250000, 700000, 0x78 };
|
||||
const I2c_BuckConverter_Domain I2c_Mariko_DRAM_VDD2 = { I2cDevice_Max77620Pmic, I2c_Max77620_SD1VOLT_REG, 0x7F, 12500, 600000, 1250000, };
|
||||
|
||||
u32 I2c_BuckConverter_GetMvOut(const I2c_BuckConverter_Domain* domain);
|
||||
u32 I2c_BuckConverter_GetUvOut(const I2c_BuckConverter_Domain* domain);
|
||||
Result I2c_BuckConverter_SetMvOut(const I2c_BuckConverter_Domain* domain, u32 mvolt);
|
||||
|
||||
// Bq24193 Battery management
|
||||
|
||||
@@ -185,7 +185,23 @@ namespace clockManager {
|
||||
if (module == HocClkModule_GPU && board::GetSocType() == HocClkSocType_Mariko) {
|
||||
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] == freqs[i] + kStep) {
|
||||
kMax = freqs[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (kMax == 0) {
|
||||
for (u32 i = 0; i < count; i++) {
|
||||
if (freqs[i] > kMax)
|
||||
kMax = freqs[i];
|
||||
}
|
||||
}
|
||||
|
||||
for (u32 f = kPcvStep; f <= kMax && gFreqTable[module].count < HOCCLK_FREQ_LIST_MAX; f += kStep) {
|
||||
if (f % kPcvStep != 0) {
|
||||
@@ -221,6 +237,52 @@ namespace clockManager {
|
||||
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 +293,27 @@ namespace clockManager {
|
||||
fileUtils::LogLine("[mgr] count = %u", gFreqTable[module].count);
|
||||
}
|
||||
|
||||
void HandleSafetyFeatures()
|
||||
bool HandleSafetyFeatures()
|
||||
{
|
||||
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;
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (board::GetPowerMw(HocClkPowerSensor_Avg) < -(int)config::GetConfigValue(HocClkConfigValue_HandheldTDPLimit)) {
|
||||
ResetToStockClocks();
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (((tmp451TempSoc() / 1000) > (int)config::GetConfigValue(HocClkConfigValue_ThermalThrottleThreshold)) && config::GetConfigValue(HocClkConfigValue_ThermalThrottle)) {
|
||||
ResetToStockClocks();
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void HandleMiscFeatures()
|
||||
{
|
||||
@@ -267,6 +330,9 @@ namespace clockManager {
|
||||
|
||||
if(board::GetConsoleType() == HocClkConsoleType_Aula)
|
||||
AulaDisplay::SetDisplayColorMode((AulaColorMode)config::GetConfigValue(HocClkConfigValue_AulaDisplayColorPreset));
|
||||
if(config::GetConfigValue(HocClkConfigValue_LiveCpuUv)) {
|
||||
board::HandleCpuUv();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -299,17 +365,10 @@ namespace clockManager {
|
||||
}
|
||||
}
|
||||
|
||||
void HandleCpuUv()
|
||||
{
|
||||
if (board::GetSocType() == HocClkSocType_Erista)
|
||||
board::SetDfllTunings(config::GetConfigValue(KipConfigValue_eristaCpuUV), 0, 1581000000); // Erista tbreak is always 1581MHz
|
||||
else
|
||||
board::SetDfllTunings(config::GetConfigValue(KipConfigValue_marikoCpuUVLow), config::GetConfigValue(KipConfigValue_marikoCpuUVHigh), board::CalculateTbreak(config::GetConfigValue(KipConfigValue_tableConf)));
|
||||
}
|
||||
|
||||
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];
|
||||
@@ -441,7 +500,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);
|
||||
}
|
||||
|
||||
@@ -452,15 +511,11 @@ namespace clockManager {
|
||||
gContext.stable.freqs[module] = nearestHz;
|
||||
}
|
||||
|
||||
if (module == HocClkModule_CPU && config::GetConfigValue(HocClkConfigValue_LiveCpuUv)) {
|
||||
HandleCpuUv();
|
||||
}
|
||||
|
||||
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 {
|
||||
@@ -494,7 +549,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();
|
||||
}
|
||||
@@ -711,11 +766,11 @@ namespace clockManager {
|
||||
|
||||
bool isBoost = apmExtIsBoostMode(mode);
|
||||
|
||||
HandleSafetyFeatures();
|
||||
bool shouldSkipClockSet = HandleSafetyFeatures();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
34
build_noexo.sh
Normal file
34
build_noexo.sh
Normal 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
|
||||
BIN
dist/atmosphere/contents/00FF0000636C6BFF/exefs.nsp
vendored
BIN
dist/atmosphere/contents/00FF0000636C6BFF/exefs.nsp
vendored
Binary file not shown.
BIN
dist/atmosphere/exosphere.bin
vendored
BIN
dist/atmosphere/exosphere.bin
vendored
Binary file not shown.
BIN
dist/atmosphere/kips/hoc.kip
vendored
BIN
dist/atmosphere/kips/hoc.kip
vendored
Binary file not shown.
BIN
dist/switch/.overlays/Horizon-OC-Monitor.ovl
vendored
BIN
dist/switch/.overlays/Horizon-OC-Monitor.ovl
vendored
Binary file not shown.
BIN
dist/switch/.overlays/horizon-oc-overlay.ovl
vendored
BIN
dist/switch/.overlays/horizon-oc-overlay.ovl
vendored
Binary file not shown.
Reference in New Issue
Block a user