- pages: Drop cust v2 support; Show update time in download section
- oc_loader: Separate Vddq and Vdd2 DRAM voltage for Mariko - sys-clk-OC: Fix wrong regulator ID; Auto CPU Boost for Erista
This commit is contained in:
@@ -51,9 +51,9 @@ volatile CustomizeTable C = {
|
||||
*/
|
||||
.marikoGpuMaxClock = 1305600,
|
||||
|
||||
/* Mariko EMC:
|
||||
/* Mariko EMC(RAM):
|
||||
* - RAM Clock in kHz:
|
||||
* Values should be > 1600000, and divided evenly by 9600.
|
||||
* Values should be ≥ 1600000, and divided evenly by 9600.
|
||||
* [WARNING]
|
||||
* RAM overclock could be UNSTABLE if timing parameters are not suitable for your DRAM:
|
||||
* - Graphical glitches
|
||||
@@ -61,21 +61,21 @@ volatile CustomizeTable C = {
|
||||
* - NAND corruption
|
||||
*/
|
||||
.marikoEmcMaxClock = 1996800,
|
||||
/* - RAM Voltage in uV
|
||||
* Range: 600'000 to 650'000 uV
|
||||
/* - EMC Vddq (Mariko Only) Voltage in uV
|
||||
* Range: 550'000 to 650'000 uV
|
||||
* Value should be divided evenly by 5'000
|
||||
* Default: 600'000
|
||||
* Not enabled by default.
|
||||
* This will not work without sys-clk-OC.
|
||||
*/
|
||||
.marikoEmcVolt = 0,
|
||||
.marikoEmcVddqVolt = 0,
|
||||
|
||||
/* Erista CPU:
|
||||
* - Max Voltage in mV
|
||||
*/
|
||||
.eristaCpuMaxVolt = 1235,
|
||||
|
||||
/* Erista EMC:
|
||||
/* Erista EMC(RAM):
|
||||
* - RAM Clock in kHz
|
||||
* [WARNING]
|
||||
* RAM overclock could be UNSTABLE if timing parameters are not suitable for your DRAM:
|
||||
@@ -84,13 +84,14 @@ volatile CustomizeTable C = {
|
||||
* - NAND corruption
|
||||
*/
|
||||
.eristaEmcMaxClock = 1862400,
|
||||
/* - RAM Voltage in uV
|
||||
* Range: 600'000 to 1250'000 uV
|
||||
* Value should be divided evenly by 12'500
|
||||
* Default(HOS): 1125'000
|
||||
/* - EMC Vddq (Erista Only) and RAM Vdd2 Voltage in uV
|
||||
* Range: 1100'000 to 1250'000 uV
|
||||
* Erista Default(HOS): 1125'000 (bootloader: 1100'000)
|
||||
* Mariko Default: 1100'000 (It will not work without sys-clk-OC.)
|
||||
* Value should be divided evenly by 12'500.
|
||||
* Not enabled by default.
|
||||
*/
|
||||
.eristaEmcVolt = 0,
|
||||
.commonEmcMemVolt = 0,
|
||||
};
|
||||
|
||||
}
|
||||
@@ -39,10 +39,10 @@ typedef struct __attribute__((packed)) CustomizeTable {
|
||||
u32 marikoCpuMaxVolt;
|
||||
u32 marikoGpuMaxClock;
|
||||
u32 marikoEmcMaxClock;
|
||||
u32 marikoEmcVolt;
|
||||
u32 marikoEmcVddqVolt;
|
||||
u32 eristaCpuMaxVolt;
|
||||
u32 eristaEmcMaxClock;
|
||||
u32 eristaEmcVolt;
|
||||
u32 commonEmcMemVolt;
|
||||
} CustomizeTable;
|
||||
|
||||
extern volatile CustomizeTable C;
|
||||
|
||||
@@ -42,6 +42,7 @@ namespace ams::ldr {
|
||||
R_DEFINE_ERROR_RESULT(InvalidRegulatorEntry, 1011);
|
||||
R_DEFINE_ERROR_RESULT(UninitializedPatcher, 1012);
|
||||
R_DEFINE_ERROR_RESULT(UnsuccessfulPatcher, 1013);
|
||||
R_DEFINE_ERROR_RESULT(SafetyCheckFailure, 1014);
|
||||
}
|
||||
|
||||
namespace ams::ldr::oc {
|
||||
|
||||
@@ -29,14 +29,85 @@ Result MemFreqPllmLimit(u32* ptr) {
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result MemVoltHandler(u32* ptr) {
|
||||
// ptr value might be default_uv or max_uv
|
||||
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)),
|
||||
};
|
||||
|
||||
constexpr u32 uv_step = 12'500;
|
||||
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->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_SUCCEED();
|
||||
};
|
||||
|
||||
regulator* entry = nullptr;
|
||||
for (auto& i : entries) {
|
||||
if (R_SUCCEEDED(validator(i)))
|
||||
entry = i;
|
||||
}
|
||||
|
||||
R_UNLESS(entry, ldr::ResultInvalidRegulatorEntry());
|
||||
|
||||
u32 emc_uv = C.commonEmcMemVolt;
|
||||
if (!emc_uv)
|
||||
R_SKIP();
|
||||
|
||||
if (emc_uv % uv_step)
|
||||
emc_uv = emc_uv / uv_step * uv_step; // rounding
|
||||
|
||||
PatchOffset(ptr, emc_uv);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void SafetyCheck() {
|
||||
if (C.custRev != CUST_REV ||
|
||||
C.marikoCpuMaxVolt > 1300 ||
|
||||
C.eristaCpuMaxVolt > 1300 ||
|
||||
(C.eristaEmcVolt && (C.eristaEmcVolt < 600'000 || C.eristaEmcVolt > 1250'000)) ||
|
||||
(C.marikoEmcVolt && (C.marikoEmcVolt < 600'000 || C.marikoEmcVolt > 650'000)))
|
||||
{
|
||||
if (C.custRev != CUST_REV)
|
||||
CRASH("Triggered");
|
||||
|
||||
struct sValidator {
|
||||
volatile u32 value;
|
||||
u32 min;
|
||||
u32 max;
|
||||
bool value_required = false;
|
||||
|
||||
Result check() {
|
||||
if (!value_required && !value)
|
||||
R_SUCCEED();
|
||||
|
||||
if (min && value < min)
|
||||
R_THROW(ldr::ResultSafetyCheckFailure());
|
||||
if (max && value > max)
|
||||
R_THROW(ldr::ResultSafetyCheckFailure());
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
};
|
||||
|
||||
sValidator validators[] = {
|
||||
{ C.marikoCpuMaxClock, 1785'000, 3000'000 },
|
||||
{ C.marikoCpuBoostClock, 1020'000, 3000'000, true },
|
||||
{ C.marikoCpuMaxVolt, 1100, 1300 },
|
||||
{ C.marikoGpuMaxClock, 768'000, 1536'000 },
|
||||
{ C.marikoEmcMaxClock, 1600'000, 2400'000 },
|
||||
{ C.marikoEmcVddqVolt, 550'000, 650'000 },
|
||||
{ C.eristaCpuMaxVolt, 1100, 1300 },
|
||||
{ C.eristaEmcMaxClock, 1600'000, 2400'000 },
|
||||
{ C.commonEmcMemVolt, 1100'000, 1250'000 },
|
||||
};
|
||||
|
||||
printf("marikoCpuMaxClock: %u\n", C.marikoCpuMaxClock);
|
||||
|
||||
for (auto& i : validators) {
|
||||
if (R_FAILED(i.check()))
|
||||
CRASH("Triggered");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -117,11 +117,12 @@ static_assert(sizeof(regulator) == 0x120);
|
||||
|
||||
constexpr u32 CpuClkOSLimit = 1785'000;
|
||||
|
||||
constexpr u32 MemClkOSLimit = 1600'000;
|
||||
constexpr u32 EmcClkOSLimit = 1600'000;
|
||||
|
||||
#define R_SKIP() R_SUCCEED()
|
||||
|
||||
Result MemFreqPllmLimit(u32* ptr);
|
||||
Result MemVoltHandler(u32* ptr); // Used for Erista MEM Vdd2 + EMC Vddq or Mariko MEM Vdd2
|
||||
|
||||
template<typename Table>
|
||||
Result MemMtcTableClone(Table* des, Table* src) {
|
||||
|
||||
@@ -72,7 +72,7 @@ Result MemFreqMtcTable(u32* ptr) {
|
||||
R_UNLESS(table_list[i]->rev == MTC_TABLE_REV, ldr::ResultInvalidMtcTable());
|
||||
}
|
||||
|
||||
if (C.eristaEmcMaxClock <= MemClkOSLimit)
|
||||
if (C.eristaEmcMaxClock <= EmcClkOSLimit)
|
||||
R_SKIP();
|
||||
|
||||
// Make room for new mtc table, discarding useless 40.8 MHz table
|
||||
@@ -86,7 +86,7 @@ Result MemFreqMtcTable(u32* ptr) {
|
||||
}
|
||||
|
||||
Result MemFreqMax(u32* ptr) {
|
||||
if (C.eristaEmcMaxClock <= MemClkOSLimit)
|
||||
if (C.eristaEmcMaxClock <= EmcClkOSLimit)
|
||||
R_SKIP();
|
||||
|
||||
PatchOffset(ptr, C.eristaEmcMaxClock);
|
||||
@@ -94,27 +94,13 @@ Result MemFreqMax(u32* ptr) {
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result MemVoltHandler(u32* ptr) {
|
||||
u32 emc_uv = C.eristaEmcVolt;
|
||||
if (!emc_uv)
|
||||
R_SKIP();
|
||||
|
||||
constexpr u32 uv_step = 12'500;
|
||||
if (emc_uv % uv_step)
|
||||
emc_uv = emc_uv / uv_step * uv_step; // rounding
|
||||
|
||||
PatchOffset(ptr, emc_uv);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void Patch(uintptr_t mapped_nso, size_t nso_size) {
|
||||
PatcherEntry<u32> patches[] = {
|
||||
{ "CPU Freq Table", &CpuFreqCvbTable, 1, nullptr, CpuClkOSLimit },
|
||||
{ "CPU Volt Limit", &CpuVoltRange, 0, &CpuMaxVoltPatternFn },
|
||||
{ "MEM Freq Mtc", &MemFreqMtcTable, 0, nullptr, MemClkOSLimit },
|
||||
{ "MEM Freq Max", &MemFreqMax, 0, nullptr, MemClkOSLimit },
|
||||
{ "MEM Freq PLLM", &MemFreqPllmLimit, 2, nullptr, MemClkPllmLimit },
|
||||
{ "MEM Freq Mtc", &MemFreqMtcTable, 0, nullptr, EmcClkOSLimit },
|
||||
{ "MEM Freq Max", &MemFreqMax, 0, nullptr, EmcClkOSLimit },
|
||||
{ "MEM Freq PLLM", &MemFreqPllmLimit, 2, nullptr, EmcClkPllmLimit },
|
||||
{ "MEM Volt", &MemVoltHandler, 2, nullptr, MemVoltHOS },
|
||||
};
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ inline bool CpuMaxVoltPatternFn(u32* ptr32) {
|
||||
}
|
||||
|
||||
constexpr u32 MemVoltHOS = 1125'000;
|
||||
constexpr u32 MemClkPllmLimit = 1866'000'000;
|
||||
constexpr u32 EmcClkPllmLimit = 1866'000'000;
|
||||
|
||||
constexpr u32 MTC_TABLE_REV = 7;
|
||||
|
||||
|
||||
@@ -153,7 +153,7 @@ void MemMtcTableAutoAdjust(MarikoMtcTable* table, const MarikoMtcTable* ref) {
|
||||
return;
|
||||
|
||||
#define ADJUST_PROP(TARGET, REF) \
|
||||
(u32)(std::ceil(REF + ((C.marikoEmcMaxClock-MemClkOSAlt)*(TARGET-REF))/(MemClkOSLimit-MemClkOSAlt)))
|
||||
(u32)(std::ceil(REF + ((C.marikoEmcMaxClock-EmcClkOSAlt)*(TARGET-REF))/(EmcClkOSLimit-EmcClkOSAlt)))
|
||||
|
||||
#define ADJUST_PARAM(TARGET, REF) \
|
||||
TARGET = ADJUST_PROP(TARGET, REF);
|
||||
@@ -319,7 +319,7 @@ Result MemFreqMtcTable(u32* ptr) {
|
||||
R_UNLESS(table_list[i]->rev == MTC_TABLE_REV, ldr::ResultInvalidMtcTable());
|
||||
}
|
||||
|
||||
if (C.marikoEmcMaxClock <= MemClkOSLimit)
|
||||
if (C.marikoEmcMaxClock <= EmcClkOSLimit)
|
||||
R_SKIP();
|
||||
|
||||
MarikoMtcTable *table_alt = table_list[1], *table_max = table_list[0];
|
||||
@@ -349,7 +349,7 @@ Result MemFreqDvbTable(u32* ptr) {
|
||||
bool validated = std::memcmp(mem_dvb_table_head, EmcDvbTableDefault, sizeof(EmcDvbTableDefault)) == 0;
|
||||
R_UNLESS(validated, ldr::ResultInvalidDvbTable());
|
||||
|
||||
if (C.marikoEmcMaxClock <= MemClkOSLimit)
|
||||
if (C.marikoEmcMaxClock <= EmcClkOSLimit)
|
||||
R_SKIP();
|
||||
|
||||
if (C.marikoEmcMaxClock <= 1862400) {
|
||||
@@ -364,25 +364,30 @@ Result MemFreqDvbTable(u32* ptr) {
|
||||
}
|
||||
|
||||
Result MemFreqMax(u32* ptr) {
|
||||
if (C.marikoEmcMaxClock <= MemClkOSLimit)
|
||||
if (C.marikoEmcMaxClock <= EmcClkOSLimit)
|
||||
R_SKIP();
|
||||
|
||||
PatchOffset(ptr, C.marikoEmcMaxClock);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result MemVoltHandler(u32* ptr) {
|
||||
Result EmcVddqVolt(u32* ptr) {
|
||||
regulator* entry = reinterpret_cast<regulator *>(reinterpret_cast<u8 *>(ptr) - offsetof(regulator, type_2_3.default_uv));
|
||||
|
||||
constexpr u32 uv_step = 5'000;
|
||||
constexpr u32 uv_min = 250'000;
|
||||
|
||||
if (entry->id != 2 || entry->type != 3 ||
|
||||
entry->type_2_3.step_uv != uv_step ||
|
||||
entry->type_2_3.min_uv != uv_min)
|
||||
R_THROW(ldr::ResultInvalidRegulatorEntry());
|
||||
auto validator = [entry]() {
|
||||
R_UNLESS(entry->id == 2, ldr::ResultInvalidRegulatorEntry());
|
||||
R_UNLESS(entry->type == 3, ldr::ResultInvalidRegulatorEntry());
|
||||
R_UNLESS(entry->type_2_3.step_uv == uv_step, ldr::ResultInvalidRegulatorEntry());
|
||||
R_UNLESS(entry->type_2_3.min_uv == uv_min, ldr::ResultInvalidRegulatorEntry());
|
||||
R_SUCCEED();
|
||||
};
|
||||
|
||||
R_TRY(validator());
|
||||
|
||||
u32 emc_uv = C.marikoEmcVolt;
|
||||
u32 emc_uv = C.marikoEmcVddqVolt;
|
||||
if (!emc_uv)
|
||||
R_SKIP();
|
||||
|
||||
@@ -402,11 +407,12 @@ void Patch(uintptr_t mapped_nso, size_t nso_size) {
|
||||
{ "GPU Freq Table", &GpuFreqCvbTable, 1, nullptr, GpuClkOfficial },
|
||||
{ "GPU Freq Asm", &GpuFreqMaxAsm, 2, &GpuMaxClockPatternFn },
|
||||
{ "GPU Freq PLL", &GpuFreqPllLimit, 1, nullptr, GpuClkPllLimit },
|
||||
{ "MEM Freq Mtc", &MemFreqMtcTable, 0, nullptr, MemClkOSLimit },
|
||||
{ "MEM Freq Dvb", &MemFreqDvbTable, 1, nullptr, MemClkOSLimit },
|
||||
{ "MEM Freq Max", &MemFreqMax, 0, nullptr, MemClkOSLimit },
|
||||
{ "MEM Freq PLLM", &MemFreqPllmLimit, 2, nullptr, MemClkPllmLimit },
|
||||
{ "MEM Volt", &MemVoltHandler, 2, nullptr, MemVoltDefault }
|
||||
{ "MEM Freq Mtc", &MemFreqMtcTable, 0, nullptr, EmcClkOSLimit },
|
||||
{ "MEM Freq Dvb", &MemFreqDvbTable, 1, nullptr, EmcClkOSLimit },
|
||||
{ "MEM Freq Max", &MemFreqMax, 0, nullptr, EmcClkOSLimit },
|
||||
{ "MEM Freq PLLM", &MemFreqPllmLimit, 2, nullptr, EmcClkPllmLimit },
|
||||
{ "MEM Vddq", &EmcVddqVolt, 2, nullptr, EmcVddqDefault },
|
||||
{ "MEM Vdd2", &MemVoltHandler, 2, nullptr, MemVdd2Default }
|
||||
};
|
||||
|
||||
for (uintptr_t ptr = mapped_nso;
|
||||
|
||||
@@ -115,9 +115,10 @@ constexpr emc_dvb_dvfs_table_t EmcDvbTableDefault[] = {
|
||||
{ 1600000, { 675, 650, 637, } },
|
||||
};
|
||||
|
||||
constexpr u32 MemClkOSAlt = 1331'200;
|
||||
constexpr u32 MemClkPllmLimit = 2133'000'000;
|
||||
constexpr u32 MemVoltDefault = 600'000;
|
||||
constexpr u32 EmcClkOSAlt = 1331'200;
|
||||
constexpr u32 EmcClkPllmLimit = 2133'000'000;
|
||||
constexpr u32 EmcVddqDefault = 600'000;
|
||||
constexpr u32 MemVdd2Default = 1100'000;
|
||||
|
||||
constexpr u32 MTC_TABLE_REV = 3;
|
||||
|
||||
|
||||
@@ -65,6 +65,7 @@ bool PtmTablePatternFn(u32* ptr) {
|
||||
|
||||
void Patch(uintptr_t mapped_nso, size_t nso_size) {
|
||||
#ifdef ATMOSPHERE_IS_STRATOSPHERE
|
||||
// Ptm patcher is disabled for Erista
|
||||
bool isMariko = (spl::GetSocType() == spl::SocType_Mariko);
|
||||
if (!isMariko)
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user