This commit is contained in:
souldbminersmwc
2026-05-19 16:22:06 -04:00
8 changed files with 166 additions and 186 deletions

View File

@@ -98,6 +98,7 @@ volatile CustomizeTable C = {
* 1331WL = 12 * 1331WL = 12
*/ */
/* Erista only. */
.mem_burst_read_latency = RL_1600, .mem_burst_read_latency = RL_1600,
.mem_burst_write_latency = WL_1600, .mem_burst_write_latency = WL_1600,
@@ -113,6 +114,7 @@ volatile CustomizeTable C = {
.tableConf = TBREAK_1683, .tableConf = TBREAK_1683,
.marikoCpuLowVmin = 620, .marikoCpuLowVmin = 620,
.marikoCpuHighVmin = 750, .marikoCpuHighVmin = 750,
/* 1120mV is NVIDIA rating */ /* 1120mV is NVIDIA rating */
.marikoCpuMaxVolt = 1120, .marikoCpuMaxVolt = 1120,
@@ -125,17 +127,15 @@ volatile CustomizeTable C = {
/* 2703000 is potentially dangerous and not advised. */ /* 2703000 is potentially dangerous and not advised. */
.marikoCpuMaxClock = 1963500, .marikoCpuMaxClock = 1963500,
.eristaCpuBoostClock = 1785000, // Default boost clock .eristaCpuBoostClock = 1785000, /* Default boost clock */
.marikoCpuBoostClock = 1963500, // Default boost clock .marikoCpuBoostClock = 1963500, /* Default boost clock */
.eristaGpuUV = 0, .eristaGpuUV = 0,
.eristaGpuVmin = 810, .eristaGpuVmin = 810,
.marikoGpuUV = 0, .marikoGpuUV = 0,
/* Vmin past 795mV won't work due boot voltage being 800mV. */ /* Vmin past 795mV won't work due boot voltage being 800mV. */
.marikoGpuVmin = 610, .marikoGpuVmin = 610,
.marikoGpuVmax = 800, .marikoGpuVmax = 800,
.commonGpuVoltOffset = 0, .commonGpuVoltOffset = 0,
@@ -147,7 +147,6 @@ volatile CustomizeTable C = {
/* AUTO: Voltage is optimally chosen; with commonGpuVoltOffset applied. */ /* 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) */ /* 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. */ /* You can overwrite auto with any voltage (in mv) of your choice - offset will not be applied. */
.eristaGpuVoltArray = { .eristaGpuVoltArray = {
AUTO /* 76 */, AUTO /* 76 */,
AUTO /* 115 */, AUTO /* 115 */,

View File

@@ -42,19 +42,6 @@ enum StepMode: u32 {
StepMode_133MHz = 3, StepMode_133MHz = 3,
}; };
/*
* Read:
* 2133RL = 40
* 1866RL = 36
* 1600RL = 32
* 1331RL = 28
* Write:
* 2133WL = 18
* 1866WL = 16
* 1600WL = 14
* 1331WL = 12
*/
enum ReadLatency: u32 { enum ReadLatency: u32 {
RL_2133 = 40, RL_2133 = 40,
RL_1866 = 36, RL_1866 = 36,
@@ -74,9 +61,6 @@ using CustomizeGpuDvfsTable = pcv::cvb_entry_t[pcv::DvfsTableEntryLimit];
static_assert(sizeof(CustomizeCpuDvfsTable) == sizeof(CustomizeGpuDvfsTable)); static_assert(sizeof(CustomizeCpuDvfsTable) == sizeof(CustomizeGpuDvfsTable));
static_assert(sizeof(CustomizeCpuDvfsTable) == sizeof(pcv::cvb_entry_t) * pcv::DvfsTableEntryLimit); 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 { struct CustomizeTable {
u8 cust[4] = {'C', 'U', 'S', 'T'}; u8 cust[4] = {'C', 'U', 'S', 'T'};
u32 custRev = CUST_REV; u32 custRev = CUST_REV;

View File

@@ -66,27 +66,32 @@ namespace ams::ldr::hoc {
size_t maximum_patched_count = 0; size_t maximum_patched_count = 0;
patternFn pattern_search_fn = nullptr; patternFn pattern_search_fn = nullptr;
Pointer value_search; Pointer value_search;
size_t patched_count = 0; size_t patched_count = 0;
Result Apply(Pointer* ptr) { Result Apply(Pointer *ptr) {
Result res = patcher_fn(ptr); Result res = patcher_fn(ptr);
if (R_SUCCEEDED(res)) if (R_SUCCEEDED(res)) {
patched_count++; patched_count++;
}
return res; return res;
} }
Result SearchAndApply(Pointer* ptr) { Result SearchAndApply(Pointer *ptr) {
bool searchOk = false; bool searchOk = false;
if (pattern_search_fn) { if (pattern_search_fn) {
if (pattern_search_fn(ptr)) searchOk = true; if (pattern_search_fn(ptr)) {
searchOk = true;
}
} else { } else {
if (value_search == *(ptr)) searchOk = true; if (value_search == *(ptr)) {
searchOk = true;
}
} }
if (searchOk) if (searchOk) {
return Apply(ptr); return Apply(ptr);
}
R_THROW(ldr::ResultUnsuccessfulPatcher()); R_THROW(ldr::ResultUnsuccessfulPatcher());
} }
@@ -94,8 +99,9 @@ namespace ams::ldr::hoc {
Result CheckResult() { Result CheckResult() {
R_UNLESS(patched_count > 0, ldr::ResultUnsuccessfulPatcher()); 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_UNLESS(patched_count <= maximum_patched_count, ldr::ResultUnsuccessfulPatcher());
}
R_SUCCEED(); R_SUCCEED();
} }

View File

@@ -22,8 +22,8 @@
namespace ams::ldr::hoc::pcv { namespace ams::ldr::hoc::pcv {
Result MemFreqPllmLimit(u32* ptr) { Result MemFreqPllmLimit(u32 *ptr) {
clk_pll_param* entry = reinterpret_cast<clk_pll_param *>(ptr); clk_pll_param *entry = reinterpret_cast<clk_pll_param *>(ptr);
R_UNLESS(entry->freq == entry->vco_max, ldr::ResultInvalidMemPllmEntry()); R_UNLESS(entry->freq == entry->vco_max, ldr::ResultInvalidMemPllmEntry());
// Double the max clk simply // Double the max clk simply
@@ -33,9 +33,9 @@ namespace ams::ldr::hoc::pcv {
R_SUCCEED(); R_SUCCEED();
} }
Result MemVoltHandler(u32* ptr) { Result MemVoltHandler(u32 *ptr) {
// ptr value might be default_uv or max_uv // 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.default_uv)),
reinterpret_cast<regulator *>(reinterpret_cast<u8 *>(ptr) - offsetof(regulator, type_1.max_uv)), reinterpret_cast<regulator *>(reinterpret_cast<u8 *>(ptr) - offsetof(regulator, type_1.max_uv)),
}; };
@@ -52,8 +52,8 @@ namespace ams::ldr::hoc::pcv {
R_SUCCEED(); R_SUCCEED();
}; };
regulator* entry = nullptr; regulator *entry = nullptr;
for (auto& i : entries) { for (auto &i : entries) {
if (R_SUCCEEDED(validator(i))) { if (R_SUCCEEDED(validator(i))) {
entry = i; entry = i;
} }
@@ -76,24 +76,25 @@ namespace ams::ldr::hoc::pcv {
} }
void SafetyCheck() { void SafetyCheck() {
// if (C.custRev != CUST_REV)
// CRASH("Triggered");
struct sValidator { struct sValidator {
volatile u32 value; volatile u32 value;
u32 min; u32 min;
u32 max; u32 max;
bool value_required = false;
u32 panic; u32 panic;
bool value_required = false;
Result check() { Result check() {
if (!value_required && !value) if (!value_required && !value) {
R_SUCCEED(); R_SUCCEED();
}
if (min && value < min) if (min && value < min) {
R_THROW(ldr::ResultSafetyCheckFailure()); R_THROW(ldr::ResultSafetyCheckFailure());
if (max && value > max) }
if (max && value > max) {
R_THROW(ldr::ResultSafetyCheckFailure()); R_THROW(ldr::ResultSafetyCheckFailure());
}
R_SUCCEED(); R_SUCCEED();
} }
@@ -102,13 +103,9 @@ namespace ams::ldr::hoc::pcv {
u32 eristaCpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaCpuDvfsTable)->freq); u32 eristaCpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaCpuDvfsTable)->freq);
u32 marikoCpuDvfsMaxFreq; u32 marikoCpuDvfsMaxFreq;
if (C.marikoCpuUVHigh) { if (C.marikoCpuUVHigh) {
marikoCpuDvfsMaxFreq = static_cast<u32>( marikoCpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.marikoCpuDvfsTableSLT)->freq);
GetDvfsTableLastEntry(C.marikoCpuDvfsTableSLT)->freq
);
} else { } else {
marikoCpuDvfsMaxFreq = static_cast<u32>( marikoCpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.marikoCpuDvfsTable)->freq);
GetDvfsTableLastEntry(C.marikoCpuDvfsTable)->freq
);
} }
u32 eristaGpuDvfsMaxFreq; u32 eristaGpuDvfsMaxFreq;
switch (C.eristaGpuUV) { switch (C.eristaGpuUV) {
@@ -142,22 +139,21 @@ namespace ams::ldr::hoc::pcv {
break; break;
} }
using namespace ams::ldr::hoc::pcv;
sValidator validators[] = { sValidator validators[] = {
{ C.eristaCpuBoostClock, 1020'000, 2397'000, true, panic::Cpu }, { C.eristaCpuBoostClock, 1020'000, 2397'000, panic::Cpu, true },
{ C.marikoCpuBoostClock, 1020'000, 2703'000, true, panic::Cpu }, { C.marikoCpuBoostClock, 1020'000, 2703'000, panic::Cpu, true },
{ C.eristaCpuMaxVolt, 1000, 1260, false, panic::Cpu }, { C.eristaCpuMaxVolt, 1000, 1260, panic::Cpu, },
{ C.marikoCpuMaxVolt, 1000, 1200, false, panic::Cpu }, { C.marikoCpuMaxVolt, 1000, 1200, panic::Cpu, },
{ eristaCpuDvfsMaxFreq, 1785'000, 2397'000, false, panic::Cpu }, { eristaCpuDvfsMaxFreq, 1785'000, 2397'000, panic::Cpu, },
{ marikoCpuDvfsMaxFreq, 1785'000, 2703'000, false, panic::Cpu }, { marikoCpuDvfsMaxFreq, 1785'000, 2703'000, panic::Cpu, },
{ C.commonEmcMemVolt, 912'500, 1350'000, false, panic::Emc }, // Official burst vmax for the RAMs is 1500mV { C.commonEmcMemVolt, 912'500, 1350'000, panic::Emc, }, /* Official vmax for the RAMs is 1400-1500mV */
{ GET_MAX_OF_ARR(erista::maxEmcClocks), 1600'000, 2600'000, false, panic::Emc }, { GET_MAX_OF_ARR(erista::maxEmcClocks), 1600'000, 2600'000, panic::Emc, },
{ C.marikoEmcMaxClock, 1600'000, 3500'000, false, panic::Emc }, { C.marikoEmcMaxClock, 1600'000, 3500'000, panic::Emc, },
{ C.marikoEmcVddqVolt, 400'000, 750'000, false, panic::Emc }, { C.marikoEmcVddqVolt, 400'000, 750'000, panic::Emc, },
{ C.marikoSocVmax, 1000, 1200, false, panic::Emc }, { C.marikoSocVmax, 1000, 1200, panic::Emc, },
{ eristaGpuDvfsMaxFreq, 768'000, 1152'000, false, panic::Gpu }, { eristaGpuDvfsMaxFreq, 768'000, 1152'000, panic::Gpu, },
{ marikoGpuDvfsMaxFreq, 768'000, 1536'000, false, panic::Gpu }, { marikoGpuDvfsMaxFreq, 768'000, 1536'000, panic::Gpu, },
{ C.marikoGpuVmax, 800, 960, false, panic::Gpu }, { C.marikoGpuVmax, 800, 960, panic::Gpu, },
}; };
for (auto &v : validators) { for (auto &v : validators) {

View File

@@ -195,26 +195,6 @@ namespace ams::ldr::hoc::pcv {
Result MemFreqPllmLimit(u32 *ptr); Result MemFreqPllmLimit(u32 *ptr);
Result MemVoltHandler(u32 *ptr); // Used for Erista MEM Vdd2 + EMC Vddq or Mariko MEM Vdd2 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 SafetyCheck();
void Patch(uintptr_t mapped_nso, size_t nso_size); void Patch(uintptr_t mapped_nso, size_t nso_size);

View File

@@ -145,11 +145,11 @@ namespace ams::ldr::hoc::pcv {
constexpr size_t DvfsTableEntryLimit = DvfsTableEntryCount - 1; constexpr size_t DvfsTableEntryLimit = DvfsTableEntryCount - 1;
template<typename T> 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>>; using NT = std::remove_const_t<std::remove_volatile_t<T>>;
auto is_empty = [](NT* entry) { 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++) { for (size_t i = 0; i < sizeof(NT); i++) {
if (*(m + i)) { if (*(m + i)) {
return false; return false;
@@ -158,7 +158,7 @@ namespace ams::ldr::hoc::pcv {
return true; return true;
}; };
NT* table = const_cast<NT *>(table_head); NT *table = const_cast<NT *>(table_head);
size_t count = 0; size_t count = 0;
while (count < DvfsTableEntryLimit) { while (count < DvfsTableEntryLimit) {
if (is_empty(table++)) { if (is_empty(table++)) {
@@ -170,10 +170,10 @@ namespace ams::ldr::hoc::pcv {
} }
template<typename T> template<typename T>
T* GetDvfsTableLastEntry(T* table_head) { T *GetDvfsTableLastEntry(T *table_head) {
using NT = std::remove_const_t<std::remove_volatile_t<T>>; 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); size_t count = GetDvfsTableEntryCount(table_head);
if (!count) { if (!count) {
return nullptr; return nullptr;

View File

@@ -136,17 +136,13 @@ namespace ams::ldr::hoc::pcv::erista {
Result GpuFreqMaxAsm(u32 *ptr32) { Result GpuFreqMaxAsm(u32 *ptr32) {
// Check if both two instructions match the pattern // Check if both two instructions match the pattern
u32 ins1 = *ptr32, ins2 = *(ptr32 + 1); 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()); R_THROW(ldr::ResultInvalidGpuFreqMaxPattern());
}
// Both instructions should operate on the same register // Both instructions should operate on the same register
u8 rd = asm_get_rd(ins1); u8 rd = asm_get_rd(ins1);
if (rd != asm_get_rd(ins2)) 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)) {
R_THROW(ldr::ResultInvalidGpuFreqMaxPattern()); R_THROW(ldr::ResultInvalidGpuFreqMaxPattern());
} }
@@ -165,6 +161,7 @@ namespace ams::ldr::hoc::pcv::erista {
max_clock = GetDvfsTableLastEntry(C.eristaGpuDvfsTable)->freq; max_clock = GetDvfsTableLastEntry(C.eristaGpuDvfsTable)->freq;
break; break;
} }
u32 asm_patch[2] = { u32 asm_patch[2] = {
asm_set_rd(asm_set_imm16(GpuAsmPattern[0], max_clock), rd), asm_set_rd(asm_set_imm16(GpuAsmPattern[0], max_clock), rd),
asm_set_rd(asm_set_imm16(GpuAsmPattern[1], max_clock >> 16), rd) asm_set_rd(asm_set_imm16(GpuAsmPattern[1], max_clock >> 16), rd)
@@ -279,11 +276,9 @@ namespace ams::ldr::hoc::pcv::erista {
// WRITE_PARAM_ALL_REG(table, emc_rdv_early_mask, rdv); // 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_rdv_mask, rdv + 2);
// WRITE_PARAM_ALL_REG(table, emc_tr_rdv, rdv); // 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->emc_mrw2 = (table->emc_mrw2 & ~0xFFu) | static_cast<u32>(mrw2);
// table->dram_timings.rl = RL; // table->dram_timings.rl = RL;
/* This needs some clean up. */
constexpr double MC_ARB_DIV = 4.0; constexpr double MC_ARB_DIV = 4.0;
constexpr u32 MC_ARB_SFA = 2; constexpr u32 MC_ARB_SFA = 2;

View File

@@ -837,10 +837,30 @@ namespace ams::ldr::hoc::pcv::mariko {
{ 1600000, { 675, 650, 637, }, }, { 1600000, { 675, 650, 637, }, },
{ 1866000, { DVB(DvbVolt( 700, 675, 650)) }, }, { 1866000, { DVB(DvbVolt( 700, 675, 650)) }, },
{ 2133000, { DVB(DvbVolt( 725, 700, 675)) }, }, { 2133000, { DVB(DvbVolt( 725, 700, 675)) }, },
{ 2400000, { DVB(DvbVolt( 750, 725, 700)) }, }, { 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)) }, }, { 2666000, { DVB(DvbVolt( 850, 825, 800)) }, },
{ 2933000, { DVB(DvbVolt( 950, 925, 900)) }, }, { 2700000, { DVB(DvbVolt( 860, 835, 810)) }, },
{ 3200000, { DVB(DvbVolt(1050, 1025, 1000)) }, }, { 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, { }, }, { ~0u, { }, },
}; };
#undef DVB #undef DVB