diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/customize.cpp b/Source/Atmosphere/stratosphere/loader/source/oc/customize.cpp index b20780da..0b8c957d 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/customize.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/customize.cpp @@ -56,7 +56,13 @@ volatile CustomizeTable C = { * - System instabilities * - NAND corruption */ -.eristaEmcMaxClock = 2240000, + +.eristaEmcClock1 = 1862400, // Lowest + +.eristaEmcClock2 = 1996800, // Middle + +.eristaEmcClock3 = 2132640, // Highest + /* Mariko CPU: * - Max Voltage in mV: diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/customize.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/customize.hpp index ab14c69e..83083e0c 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/customize.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/customize.hpp @@ -50,7 +50,9 @@ u32 commonCpuBoostClock; u32 commonEmcMemVolt; u32 eristaCpuMaxVolt; - u32 eristaEmcMaxClock; + u32 eristaEmcClock1; + u32 eristaEmcClock2; + u32 eristaEmcClock3; u32 marikoCpuMaxVolt; u32 marikoEmcMaxClock; u32 marikoEmcVddqVolt; diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/mtc_timing_value.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/mtc_timing_value.hpp index b6057757..3a942530 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/mtc_timing_value.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/mtc_timing_value.hpp @@ -155,9 +155,9 @@ // p78 The first valid data is available RL × t CK + t DQSCK + t DQSQ //const u32 QUSE = RL + CEIL(tDQSCK_min/tCK_avg + tDQSQ); - namespace pcv::erista { + namespace pcv::erista { // TODO: Adjust timings properly for all freqs // tCK_avg (average clock period) in ns - const double tCK_avg = 1000'000. / C.eristaEmcMaxClock; + const double tCK_avg = 1000'000. / C.eristaEmcClock3; // Write Latency const u32 WL = 14 + C.mem_burst_latency; @@ -178,7 +178,7 @@ // {REFRESH, REFRESH_LO} = max[(tREF/#_of_rows) / (emc_clk_period) - 64, (tREF/#_of_rows) / (emc_clk_period) * 97%] // emc_clk_period = dram_clk / 2; // 1600 MHz: 5894, but N' set to 6176 (~4.8% margin) - const u32 REFRESH = MIN((u32)65472, u32(std::ceil((double(tREFpb) * C.eristaEmcMaxClock / numOfRows * 1.048 / 2 - 64))) / 4 * 4); + const u32 REFRESH = MIN((u32)65472, u32(std::ceil((double(tREFpb) * C.eristaEmcClock3 / numOfRows * 1.048 / 2 - 64))) / 4 * 4); const u32 REFBW = MIN((u32)65536, REFRESH+64); // Write With Auto Precharge to to Power-Down Entry diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.cpp b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.cpp index 5451ec02..63292326 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.cpp @@ -161,7 +161,7 @@ void SafetyCheck() { { C.commonCpuBoostClock, 1020'000, 3000'000, true }, { C.commonEmcMemVolt, 1100'000, 1500'000 }, // Official burst vmax for the RAMs { C.eristaCpuMaxVolt, 1100, 1300 }, - { C.eristaEmcMaxClock, 1600'000, 2600'200 }, + { C.eristaEmcClock3, 1600'000, 2600'200 }, { C.marikoCpuMaxVolt, 1100, 1300 }, { C.marikoEmcMaxClock, 1600'000, 3500'000 }, { C.marikoEmcVddqVolt, 550'000, 700'000 }, diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_erista.cpp b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_erista.cpp index 43c80156..13367515 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_erista.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_erista.cpp @@ -246,7 +246,7 @@ { u32 khz_list[] = {1600000, 1331200, 1065600, 800000, 665600, 408000, 204000, 102000, 68000, 40800}; u32 khz_list_size = sizeof(khz_list) / sizeof(u32); - + // Generate list for mtc table pointers EristaMtcTable *table_list[khz_list_size]; for (u32 i = 0; i < khz_list_size; i++) @@ -256,32 +256,49 @@ R_UNLESS(table_list[i]->rate_khz == khz_list[i], ldr::ResultInvalidMtcTable()); R_UNLESS(table_list[i]->rev == MTC_TABLE_REV, ldr::ResultInvalidMtcTable()); } - - if (C.eristaEmcMaxClock <= EmcClkOSLimit) + + if (C.eristaEmcClock1 <= EmcClkOSLimit || + C.eristaEmcClock2 <= EmcClkOSLimit || + C.eristaEmcClock3 <= EmcClkOSLimit) R_SKIP(); - - // Make room for new mtc table, discarding useless 40.8 MHz table - // 40800 overwritten by 68000, ..., 1331200 overwritten by 1600000, leaving table_list[0] not overwritten - for (u32 i = khz_list_size - 1; i > 0; i--) - std::memcpy(static_cast(table_list[i]), static_cast(table_list[i - 1]), sizeof(EristaMtcTable)); - + + // Make room for three new mtc tables, discarding useless 40.8, 68.0, and 102 MHz tables + for (u32 i = khz_list_size - 1; i > 2; i--) + std::memcpy(static_cast(table_list[i]), + static_cast(table_list[i - 3]), + sizeof(EristaMtcTable)); + + // Adjust all three new tables MemMtcTableAutoAdjust(table_list[0]); - PATCH_OFFSET(ptr, C.eristaEmcMaxClock); - + MemMtcTableAutoAdjust(table_list[1]); + MemMtcTableAutoAdjust(table_list[2]); + + // Patch pointers for 3 custom clocks + u32 *patch_ptr1 = ptr; + u32 *patch_ptr2 = ptr - sizeof(EristaMtcTable) / sizeof(u32); + u32 *patch_ptr3 = ptr - 2 * (sizeof(EristaMtcTable) / sizeof(u32)); + + if (C.eristaEmcClock3 > EmcClkOSLimit) + PATCH_OFFSET(patch_ptr1, C.eristaEmcClock3); + if (C.eristaEmcClock2 > EmcClkOSLimit) + PATCH_OFFSET(patch_ptr2, C.eristaEmcClock2); + if (C.eristaEmcClock3 > EmcClkOSLimit) + PATCH_OFFSET(patch_ptr3, C.eristaEmcClock1); + // Handle customize table replacement // if (C.mtcConf == CUSTOMIZED_ALL) { // MemMtcCustomizeTable(table_list[0], const_cast(C.eristaMtcTable)); //} - + R_SUCCEED(); - } - + } + Result MemFreqMax(u32 *ptr) { - if (C.eristaEmcMaxClock <= EmcClkOSLimit) + if (C.eristaEmcClock3 <= EmcClkOSLimit) R_SKIP(); - PATCH_OFFSET(ptr, C.eristaEmcMaxClock); + PATCH_OFFSET(ptr, C.eristaEmcClock3); R_SUCCEED(); }