diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/customize.cpp b/Source/Atmosphere/stratosphere/loader/source/oc/customize.cpp index b5645dca..96156a2b 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/customize.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/customize.cpp @@ -77,7 +77,7 @@ volatile CustomizeTable C = { * - System instabilities * - NAND corruption */ -.marikoEmcMaxClock = 1996800, +.marikoEmcMaxClock = 2131200, /* - EMC Vddq (Mariko Only) Voltage in uV * Range: 550'000 to 650'000 uV * Value should be divided evenly by 5'000 @@ -89,6 +89,10 @@ volatile CustomizeTable C = { .marikoGpuUV = 0, +.ramTimingPresetOne = 2, + +.ramTimingPresetTwo = 2, + /* Advanced Settings: * - Erista CPU DVFS Table: */ diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/customize.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/customize.hpp index 11122781..1c434210 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/customize.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/customize.hpp @@ -26,10 +26,11 @@ namespace ams::ldr::oc { #include "mtc_timing_table.hpp" enum MtcConfig: u32 { - AUTO_ADJ_SAFE_MARIKO_ONLY = 0, - AUTO_ADJ_4266_MARIKO_ONLY = 1, - NO_ADJ_ALL = 2, - CUSTOMIZED_ALL = 3, + AUTO_ADJ_SAFE_MARIKO = 0, + AUTO_ADJ_PERF_MARIKO = 1, + CUSTOM_ADJ_MARIKO = 2, + NO_ADJ_ALL = 3, + CUSTOMIZED_ALL = 4, }; using CustomizeCpuDvfsTable = pcv::cvb_entry_t[pcv::DvfsTableEntryLimit]; @@ -52,6 +53,8 @@ typedef struct CustomizeTable { u32 marikoEmcMaxClock; u32 marikoEmcVddqVolt; u32 marikoGpuUV; + u32 ramTimingPresetOne; + u32 ramTimingPresetTwo; CustomizeCpuDvfsTable eristaCpuDvfsTable; CustomizeCpuDvfsTable marikoCpuDvfsTable; CustomizeGpuDvfsTable eristaGpuDvfsTable; diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.cpp b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.cpp index c556063d..a00e5e4f 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.cpp @@ -102,7 +102,7 @@ void SafetyCheck() { { C.eristaCpuMaxVolt, 1100, 1300 }, { C.eristaEmcMaxClock, 1600'000, 2400'000 }, { C.marikoCpuMaxVolt, 1100, 1300 }, - { C.marikoEmcMaxClock, 1600'000, 2800'000 }, + { C.marikoEmcMaxClock, 1600'000, 2400'000 }, { C.marikoEmcVddqVolt, 550'000, 650'000 }, { eristaCpuDvfsMaxFreq, 1785'000, 3000'000 }, { marikoCpuDvfsMaxFreq, 1785'000, 3000'000 }, diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.cpp b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.cpp index ebf9b8c1..c906e14f 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.cpp @@ -82,6 +82,14 @@ Result GpuFreqPllLimit(u32* ptr) { R_SUCCEED(); } +const std::array tRCD_values = {18, 17, 16, 15, 14, 13}; +const std::array tRP_values = {18, 17, 16, 15, 14, 13}; +const std::array tRAS_values = {42, 39, 36, 35, 34, 33}; + +const std::array tRRD_values = {10, 7.5, 6, 4, 2}; +const std::array tFAW_values = {40, 30, 24, 16, 8}; +const std::array tRTP_values = {7.5, 7.5, 6, 6, 5}; + void MemMtcTableAutoAdjust(MarikoMtcTable* table, const MarikoMtcTable* ref) { /* Official Tegra X1 TRM, sign up for nvidia developer program (free) to download: * https://developer.nvidia.com/embedded/dlc/tegra-x1-technical-reference-manual @@ -100,11 +108,11 @@ void MemMtcTableAutoAdjust(MarikoMtcTable* table, const MarikoMtcTable* ref) { * you'd better calculate timings yourself rather than relying on following algorithm. */ - if (C.mtcConf != AUTO_ADJ_SAFE_MARIKO_ONLY && C.mtcConf != AUTO_ADJ_4266_MARIKO_ONLY) + if (C.mtcConf != AUTO_ADJ_SAFE_MARIKO && C.mtcConf != AUTO_ADJ_PERF_MARIKO) return; #define ADJUST_PROP(TARGET, REF) \ - (u32)(std::ceil(REF + ((C.marikoEmcMaxClock-EmcClkOSAlt)*(TARGET-REF))/(EmcClkOSLimit-EmcClkOSAlt))) + (u32)(std::ceil( 0.65 * C.mtcConf * (REF + ((C.marikoEmcMaxClock-EmcClkOSAlt)*(TARGET-REF))/(EmcClkOSLimit-EmcClkOSAlt)))) #define ADJUST_PARAM(TARGET, REF) \ TARGET = ADJUST_PROP(TARGET, REF); @@ -121,34 +129,39 @@ void MemMtcTableAutoAdjust(MarikoMtcTable* table, const MarikoMtcTable* ref) { TABLE->shadow_regs_ca_train.PARAM = VALUE; \ TABLE->shadow_regs_rdwr_train.PARAM = VALUE; - ADJUST_PARAM_ALL_REG(table, emc_r2w, ref); - ADJUST_PARAM_ALL_REG(table, emc_w2r, ref); - ADJUST_PARAM_ALL_REG(table, emc_r2p, ref); - ADJUST_PARAM_ALL_REG(table, emc_w2p, ref); - ADJUST_PARAM_ALL_REG(table, emc_trtm, ref); - ADJUST_PARAM_ALL_REG(table, emc_twtm, ref); - ADJUST_PARAM_ALL_REG(table, emc_tratm, ref); - ADJUST_PARAM_ALL_REG(table, emc_twatm, ref); + ADJUST_PARAM_ALL_REG(table, emc_r2w, ref); //0x140 0x4f0 0x880 + ADJUST_PARAM_ALL_REG(table, emc_w2r, ref); //0x144 0x4f4 0x884 + //ADJUST_PARAM_ALL_REG(table, emc_r2p, ref); //0x148 0x4f8 0x888 + //ADJUST_PARAM_ALL_REG(table, emc_w2p, ref); //0x14c 0x4fc 0x88c + ADJUST_PARAM_ALL_REG(table, emc_trtm, ref); //0x158 0x508 0x898 + ADJUST_PARAM_ALL_REG(table, emc_twtm, ref); //0x15c 0x50c 0x89c + ADJUST_PARAM_ALL_REG(table, emc_tratm, ref); //0x160 0x510 0x8a0 + ADJUST_PARAM_ALL_REG(table, emc_twatm, ref); //0x164 0x514 0x8a4 - ADJUST_PARAM_ALL_REG(table, emc_rw2pden, ref); + ADJUST_PARAM_ALL_REG(table, emc_rw2pden, ref); //0x1fc 0x5ac 0x93c - ADJUST_PARAM_ALL_REG(table, emc_tclkstop, ref); + ADJUST_PARAM_ALL_REG(table, emc_tclkstop, ref); //0x22c 0x5dc 0x96c - ADJUST_PARAM_ALL_REG(table, emc_pmacro_dll_cfg_2, ref); // EMC_DLL_CFG_2_0: level select for VDDA? + ADJUST_PARAM_ALL_REG(table, emc_pmacro_dll_cfg_2, ref); // EMC_DLL_CFG_2_0: level select for VDDA? //0x380 0x730 0xac0 - ADJUST_PARAM_TABLE(table, la_scale_regs.mc_mll_mpcorer_ptsa_rate, ref); - ADJUST_PARAM_TABLE(table, la_scale_regs.mc_ptsa_grant_decrement, ref); + ADJUST_PARAM_TABLE(table, la_scale_regs.mc_mll_mpcorer_ptsa_rate, ref); //0xfa4 + ADJUST_PARAM_TABLE(table, la_scale_regs.mc_ptsa_grant_decrement, ref); //0xfac + + #define MAX(A, B) std::max(A, B) + #define MIN(A, B) std::min(A, B) /* Timings that are available in or can be derived from LPDDR4X datasheet or TRM */ - const bool use_4266_spec = C.mtcConf == AUTO_ADJ_4266_MARIKO_ONLY; + + const u32 TIMING_PRIM_PRESET = C.ramTimingPresetOne; + const u32 TIMING_SECOND_PRESET = C.ramTimingPresetTwo; // tCK_avg (average clock period) in ns const double tCK_avg = 1000'000. / C.marikoEmcMaxClock; // tRPpb (row precharge time per bank) in ns - const u32 tRPpb = 18; + const u32 tRPpb = !TIMING_PRIM_PRESET ? 18 : tRP_values[TIMING_PRIM_PRESET-1]; // tRPab (row precharge time all banks) in ns - const u32 tRPab = 21; + const u32 tRPab = !TIMING_PRIM_PRESET ? 21 : tRPpb + 3; // tRAS (row active time) in ns - const u32 tRAS = 42; + const u32 tRAS = !TIMING_PRIM_PRESET ? 42 : tRAS_values[TIMING_PRIM_PRESET-1]; // tRC (ACTIVATE-ACTIVATE command period same bank) in ns const u32 tRC = tRPpb + tRAS; // tRFCab (refresh cycle time all banks) in ns for 8Gb density @@ -156,9 +169,9 @@ void MemMtcTableAutoAdjust(MarikoMtcTable* table, const MarikoMtcTable* ref) { // tRFCpb (refresh cycle time per bank) in ns for 8Gb density const u32 tRFCpb = 140; // tRCD (RAS-CAS delay) in ns - const u32 tRCD = 18; + const u32 tRCD = !TIMING_PRIM_PRESET ? 18 : tRCD_values[TIMING_PRIM_PRESET-1]; // tRRD (Active bank-A to Active bank-B) in ns - const double tRRD = use_4266_spec ? 7.5 : 10.; + const double tRRD = !TIMING_SECOND_PRESET ? 10. : tRRD_values[TIMING_SECOND_PRESET-1]; // tREFpb (average refresh interval per bank) in ns for 8Gb density const u32 tREFpb = 488; // tREFab (average refresh interval all 8 banks) in ns for 8Gb density @@ -170,62 +183,92 @@ void MemMtcTableAutoAdjust(MarikoMtcTable* table, const MarikoMtcTable* ref) { // 1600 MHz: 5894, but N' set to 6176 (~4.8% margin) const u32 REFRESH = u32(std::ceil((double(tREFpb) * C.marikoEmcMaxClock / numOfRows * 1.048 / 2 - 64))) / 4 * 4; // tPDEX2WR, tPDEX2RD (timing delay from exiting powerdown mode to a write/read command) in ns - const u32 tPDEX2 = 10; + //const u32 tPDEX2 = 10; // [Guessed] tACT2PDEN (timing delay from an activate, MRS or EMRS command to power-down entry) in ns const u32 tACT2PDEN = 14; + // Additional time after t XP hasexpired until the MRR commandmay be issued + const double tMRRI = tRCD + 3 * tCK_avg; + // Exit power-down to next valid command delay + const double tXP = 7.5; + // tPDEX2WR, tPDEX2RD (timing delay from exiting powerdown mode to a write/read command) in ns + //const u32 tPDEX2 = 10; + // tPDEX2MRR (timing delay from exiting powerdown mode to MRR command) in ns + const double tPDEX2MRR = tXP + tMRRI; // [Guessed] tPDEX2MRR (timing delay from exiting powerdown mode to MRR command) in ns - const double tPDEX2MRR = 28.75; + //const double tPDEX2MRR = 28.75; // [Guessed] tCKE2PDEN (timing delay from turning off CKE to power-down entry) in ns const double tCKE2PDEN = 8.5; // tXSR (SELF REFRESH exit to next valid command delay) in ns const double tXSR = tRFCab + 7.5; // tCKE (minimum CKE high pulse width) in ns - const u32 tCKE = 8; + const double tCKE = 7.5; + // Delay from valid command to CKE input LOW in ns + const double tCMDCKE = MAX(1.75, 3*tCK_avg); // tCKELPD (minimum CKE low pulse width in SELF REFRESH) in ns const u32 tCKELPD = 15; // [Guessed] tPD (minimum CKE low pulse width in power-down mode) in ns const double tPD = 7.5; // tFAW (Four-bank Activate Window) in ns - const u32 tFAW = use_4266_spec ? 30 : 40; + const u32 tFAW = !TIMING_SECOND_PRESET ? 40 : tFAW_values[TIMING_SECOND_PRESET-1]; - #define GET_CYCLE_CEIL(PARAM) u32(std::ceil(double(PARAM) / tCK_avg)) + // Internal READ-to-PRE-CHARGE command delay in ns + const double tRTP = !TIMING_SECOND_PRESET ? 7.5 : tRTP_values[TIMING_SECOND_PRESET-1]; + const u32 WL = 10; + const u32 BL = 16; + // write-to-precharge time for commands to the same bank in cycles + const double WTP = WL + BL/2 + 1 + std::ceil(18/tCK_avg); - WRITE_PARAM_ALL_REG(table, emc_rc, GET_CYCLE_CEIL(tRC)); - WRITE_PARAM_ALL_REG(table, emc_rfc, GET_CYCLE_CEIL(tRFCab)); - WRITE_PARAM_ALL_REG(table, emc_rfcpb, GET_CYCLE_CEIL(tRFCpb)); - WRITE_PARAM_ALL_REG(table, emc_ras, GET_CYCLE_CEIL(tRAS)); - WRITE_PARAM_ALL_REG(table, emc_rp, GET_CYCLE_CEIL(tRPpb)); - WRITE_PARAM_ALL_REG(table, emc_rd_rcd, GET_CYCLE_CEIL(tRCD)); - WRITE_PARAM_ALL_REG(table, emc_wr_rcd, GET_CYCLE_CEIL(tRCD)); - WRITE_PARAM_ALL_REG(table, emc_rrd, GET_CYCLE_CEIL(tRRD)); - WRITE_PARAM_ALL_REG(table, emc_refresh, REFRESH); - WRITE_PARAM_ALL_REG(table, emc_pre_refresh_req_cnt, REFRESH / 4); - WRITE_PARAM_ALL_REG(table, emc_pdex2wr, GET_CYCLE_CEIL(tPDEX2)); - WRITE_PARAM_ALL_REG(table, emc_pdex2rd, GET_CYCLE_CEIL(tPDEX2)); - WRITE_PARAM_ALL_REG(table, emc_act2pden,GET_CYCLE_CEIL(tACT2PDEN)); - WRITE_PARAM_ALL_REG(table, emc_cke2pden,GET_CYCLE_CEIL(tCKE2PDEN)); - WRITE_PARAM_ALL_REG(table, emc_pdex2mrr,GET_CYCLE_CEIL(tPDEX2MRR)); - WRITE_PARAM_ALL_REG(table, emc_txsr, GET_CYCLE_CEIL(tXSR)); - WRITE_PARAM_ALL_REG(table, emc_txsrdll, GET_CYCLE_CEIL(tXSR)); - WRITE_PARAM_ALL_REG(table, emc_tcke, GET_CYCLE_CEIL(tCKE)); - WRITE_PARAM_ALL_REG(table, emc_tckesr, GET_CYCLE_CEIL(tCKELPD)); - WRITE_PARAM_ALL_REG(table, emc_tpd, GET_CYCLE_CEIL(tPD)); - WRITE_PARAM_ALL_REG(table, emc_tfaw, GET_CYCLE_CEIL(tFAW)); - WRITE_PARAM_ALL_REG(table, emc_trpab, GET_CYCLE_CEIL(tRPab)); - WRITE_PARAM_ALL_REG(table, emc_trefbw, REFRESH + 64); + // Valid Clock requirement before CKE Input HIGH in ns + const double tCKCKEH = MAX(1.75, 3*tCK_avg); - constexpr u32 MC_ARB_DIV = 4; // ? - table->burst_mc_regs.mc_emem_arb_timing_rcd = std::ceil(GET_CYCLE_CEIL(tRCD) / MC_ARB_DIV - 2); - table->burst_mc_regs.mc_emem_arb_timing_rp = std::ceil(GET_CYCLE_CEIL(tRPpb) / MC_ARB_DIV - 1); - table->burst_mc_regs.mc_emem_arb_timing_rc = std::ceil(std::max(GET_CYCLE_CEIL(tRC), GET_CYCLE_CEIL(tRAS)+GET_CYCLE_CEIL(tRPpb)) / MC_ARB_DIV); - table->burst_mc_regs.mc_emem_arb_timing_ras = std::ceil(GET_CYCLE_CEIL(tRAS) / MC_ARB_DIV - 2); - table->burst_mc_regs.mc_emem_arb_timing_faw = std::ceil(GET_CYCLE_CEIL(tFAW) / MC_ARB_DIV - 1); - table->burst_mc_regs.mc_emem_arb_timing_rrd = std::ceil(GET_CYCLE_CEIL(tRRD) / MC_ARB_DIV - 1); - table->burst_mc_regs.mc_emem_arb_timing_rap2pre = std::ceil(table->burst_regs.emc_r2p / MC_ARB_DIV); - table->burst_mc_regs.mc_emem_arb_timing_wap2pre = std::ceil(table->burst_regs.emc_w2p / MC_ARB_DIV); - table->burst_mc_regs.mc_emem_arb_timing_r2w = std::ceil(table->burst_regs.emc_r2w / MC_ARB_DIV + 1); - table->burst_mc_regs.mc_emem_arb_timing_w2r = std::ceil(table->burst_regs.emc_w2r / MC_ARB_DIV + 1); - table->burst_mc_regs.mc_emem_arb_timing_rfcpb = std::ceil(GET_CYCLE_CEIL(tRFCpb) / MC_ARB_DIV + 1); // ? + #define GET_CYCLE_CEIL(PARAM) C.mtcConf ? u32(std::ceil(double(PARAM) / 1.2* tCK_avg)) : u32(std::ceil(double(PARAM) / tCK_avg)) + + WRITE_PARAM_ALL_REG(table, emc_rc, GET_CYCLE_CEIL(tRC)); //0x124 + WRITE_PARAM_ALL_REG(table, emc_rfc, GET_CYCLE_CEIL(tRFCab)); //0x128 + WRITE_PARAM_ALL_REG(table, emc_rfcpb, GET_CYCLE_CEIL(tRFCpb)); //0x12c + WRITE_PARAM_ALL_REG(table, emc_ras, GET_CYCLE_CEIL(tRAS)); //0x138 + WRITE_PARAM_ALL_REG(table, emc_rp, GET_CYCLE_CEIL(tRPpb)); //0x13c + WRITE_PARAM_ALL_REG(table, emc_r2p, GET_CYCLE_CEIL(tRTP)); + WRITE_PARAM_ALL_REG(table, emc_w2p, WTP); + WRITE_PARAM_ALL_REG(table, emc_rd_rcd, GET_CYCLE_CEIL(tRCD)); //0x170 + WRITE_PARAM_ALL_REG(table, emc_wr_rcd, GET_CYCLE_CEIL(tRCD)); //0x174 + WRITE_PARAM_ALL_REG(table, emc_rrd, GET_CYCLE_CEIL(tRRD)); //0x178 + WRITE_PARAM_ALL_REG(table, emc_refresh, REFRESH); //0x1dc + WRITE_PARAM_ALL_REG(table, emc_pre_refresh_req_cnt, REFRESH / 4); //0x1e4 + WRITE_PARAM_ALL_REG(table, emc_pdex2wr, GET_CYCLE_CEIL(tXP)); //0x1e8 + WRITE_PARAM_ALL_REG(table, emc_pdex2rd, GET_CYCLE_CEIL(tXP)); //0x1ec + WRITE_PARAM_ALL_REG(table, emc_pchg2pden, GET_CYCLE_CEIL(tCMDCKE)); + WRITE_PARAM_ALL_REG(table, emc_act2pden,GET_CYCLE_CEIL(tACT2PDEN)); //0x1f4 + WRITE_PARAM_ALL_REG(table, emc_ar2pden, GET_CYCLE_CEIL(tCMDCKE)); + //WRITE_PARAM_ALL_REG(table, emc_rw2pden, RTPDEN); + WRITE_PARAM_ALL_REG(table, emc_txsr, MIN(GET_CYCLE_CEIL(tXSR), (u32)0x3fe)); //0x20c + WRITE_PARAM_ALL_REG(table, emc_txsrdll, MIN(GET_CYCLE_CEIL(tXSR), (u32)0x3fe)); //0x210 + WRITE_PARAM_ALL_REG(table, emc_tcke, GET_CYCLE_CEIL(tCKE)); //0x214 + WRITE_PARAM_ALL_REG(table, emc_tfaw, GET_CYCLE_CEIL(tFAW)); //0x220 + WRITE_PARAM_ALL_REG(table, emc_trpab, GET_CYCLE_CEIL(tRPab)); //0x224 + WRITE_PARAM_ALL_REG(table, emc_tclkstable, GET_CYCLE_CEIL(tCKCKEH)); + WRITE_PARAM_ALL_REG(table, emc_trefbw, REFRESH + 64); //0x234 + WRITE_PARAM_ALL_REG(table, emc_pdex2mrr,GET_CYCLE_CEIL(tPDEX2MRR)); //0x208 + WRITE_PARAM_ALL_REG(table, emc_cke2pden,GET_CYCLE_CEIL(tCKE2PDEN)); //0x200 + WRITE_PARAM_ALL_REG(table, emc_tckesr, GET_CYCLE_CEIL(tCKELPD)); //0x218 + WRITE_PARAM_ALL_REG(table, emc_tpd, GET_CYCLE_CEIL(tPD)); //0x21c + + constexpr u32 MC_ARB_DIV = 4; // Guessed + constexpr u32 SFA = 2; // Guessed + table->burst_mc_regs.mc_emem_arb_timing_rcd = std::ceil(GET_CYCLE_CEIL(tRCD) / MC_ARB_DIV) - 2; //0xf30 + table->burst_mc_regs.mc_emem_arb_timing_rp = std::ceil(GET_CYCLE_CEIL(tRPpb) / MC_ARB_DIV) - 1 + SFA; //0xf34 + table->burst_mc_regs.mc_emem_arb_timing_rc = std::ceil(std::max(GET_CYCLE_CEIL(tRC), GET_CYCLE_CEIL(tRAS)+GET_CYCLE_CEIL(tRPpb)) / MC_ARB_DIV) - 1; //0xf38 + table->burst_mc_regs.mc_emem_arb_timing_ras = std::ceil(GET_CYCLE_CEIL(tRAS) / MC_ARB_DIV) - 2; //0xf3c + table->burst_mc_regs.mc_emem_arb_timing_faw = std::ceil(GET_CYCLE_CEIL(tFAW) / MC_ARB_DIV) - 1; //0xf40 + table->burst_mc_regs.mc_emem_arb_timing_rrd = std::ceil(GET_CYCLE_CEIL(tRRD) / MC_ARB_DIV) - 1; //0xf44 + table->burst_mc_regs.mc_emem_arb_timing_rap2pre = std::ceil(table->burst_regs.emc_r2p / MC_ARB_DIV); //0xf48 + table->burst_mc_regs.mc_emem_arb_timing_wap2pre = std::ceil(table->burst_regs.emc_w2p / MC_ARB_DIV); //0xf4c + //table->burst_mc_regs.mc_emem_arb_timing_r2r = std::ceil(table->burst_regs.emc_rext / MC_ARB_DIV) - 1 + SFA; + //table->burst_mc_regs.mc_emem_arb_timing_w2w = std::ceil(table->burst_regs.emc_wext / MC_ARB_DIV) - 1 + SFA; + table->burst_mc_regs.mc_emem_arb_timing_r2w = std::ceil(table->burst_regs.emc_r2w / MC_ARB_DIV) - 1 + SFA; //0xf58 + table->burst_mc_regs.mc_emem_arb_timing_w2r = std::ceil(table->burst_regs.emc_w2r / MC_ARB_DIV) - 1 + SFA; //0xf60 + table->burst_mc_regs.mc_emem_arb_timing_rfcpb = std::ceil(GET_CYCLE_CEIL(tRFCpb) / MC_ARB_DIV); //0xf64 + //table->burst_mc_regs.mc_emem_arb_timing_ccdmw = std::ceil(tCCDMW / MC_ARB_DIV) -1 + SFA; } void MemMtcPllmbDivisor(MarikoMtcTable* table) { @@ -310,9 +353,12 @@ Result MemFreqDvbTable(u32* ptr) { if (C.marikoEmcMaxClock <= 1862400) { std::memcpy(new_start, default_end, sizeof(emc_dvb_dvfs_table_t)); - } else { + } else if (C.marikoEmcMaxClock <= 2131200){ emc_dvb_dvfs_table_t oc_table = { 2131200, { 700, 675, 650, } }; std::memcpy(new_start, &oc_table, sizeof(emc_dvb_dvfs_table_t)); + } else { + emc_dvb_dvfs_table_t oc_table = { 2400000, { 730, 705, 680, } }; + std::memcpy(new_start, &oc_table, sizeof(emc_dvb_dvfs_table_t)); } new_start->freq = C.marikoEmcMaxClock; diff --git a/Source/sys-clk-OC/sysmodule/src/file_utils.h b/Source/sys-clk-OC/sysmodule/src/file_utils.h index 476b342b..48ef19b6 100644 --- a/Source/sys-clk-OC/sysmodule/src/file_utils.h +++ b/Source/sys-clk-OC/sysmodule/src/file_utils.h @@ -57,6 +57,8 @@ typedef struct CustTable { u32 marikoEmcMaxClock; u32 marikoEmcVddqVolt; u32 marikoGpuUV; + u32 ramTimingPresetOne; + u32 ramTimingPresetTwo; CustomizeCpuDvfsTable eristaCpuDvfsTable; CustomizeCpuDvfsTable marikoCpuDvfsTable; CustomizeGpuDvfsTable eristaGpuDvfsTable; diff --git a/pages/dist/main.js b/pages/dist/main.js index 01acd25f..3a2fddcc 100644 --- a/pages/dist/main.js +++ b/pages/dist/main.js @@ -1 +1 @@ -var __awaiter=this&&this.__awaiter||function(e,t,i,a){return new(i||(i=Promise))((function(s,l){function r(e){try{o(a.next(e))}catch(e){l(e)}}function n(e){try{o(a.throw(e))}catch(e){l(e)}}function o(e){var t;e.done?s(e.value):(t=e.value,t instanceof i?t:new i((function(e){e(t)}))).then(r,n)}o((a=a.apply(e,t||[])).next())}))};const CUST_REV=4,CUST_REV_ADV=5;var CustPlatform;!function(e){e[e.Undefined=0]="Undefined",e[e.Erista=1]="Erista",e[e.Mariko=2]="Mariko",e[e.All=3]="All"}(CustPlatform||(CustPlatform={}));class CustEntry{constructor(e,t,i,a,s,l,r=[0,1e6],n=1,o=!0){this.id=e,this.name=t,this.platform=i,this.size=a,this.desc=s,this.defval=l,this.step=n,this.zeroable=o,this.min=r[0],this.max=r[1]}validate(){let e=new ErrorToolTip(this.id).clear();return Number.isNaN(this.value)||void 0===this.value?(e.setMsg("Invalid value: Not a number").show(),!1):!(!this.zeroable||0!=this.value)||(this.valuethis.max?(e.setMsg(`Expected range: [${this.min}, ${this.max}], got ${this.value}.`).show(),!1):this.value%this.step==0||(e.setMsg(`${this.value} % ${this.step} ≠ 0`).show(),!1))}getInputElement(){return document.getElementById(this.id)}updateValueFromElement(){var e;this.value=Number(null===(e=this.getInputElement())||void 0===e?void 0:e.value)}isAvailableFor(e){return e===CustPlatform.Undefined||this.platform===e||this.platform===CustPlatform.All}createElement(){let e=this.getInputElement();if(!e){let t=document.createElement("div");t.classList.add("grid","cust-element"),e=document.createElement("input"),e.min=String(this.zeroable?0:this.min),e.max=String(this.max),e.id=this.id,e.type="number",e.step=String(this.step);let i=document.createElement("label");i.setAttribute("for",this.id),i.innerHTML=this.name,i.appendChild(e),t.appendChild(i);let a=document.createElement("blockquote");a.innerHTML="
    "+this.desc.map((e=>`
  • ${e}
  • `)).join("")+"
",a.setAttribute("for",this.id),t.appendChild(a),document.getElementById("config-list-basic").appendChild(t),new ErrorToolTip(this.id).addChangeListener()}e.value=String(this.value)}setElementValue(){this.getInputElement().value=String(this.value)}setElementDefaultValue(){this.getInputElement().value=String(this.defval)}removeElement(){let e=this.getInputElement();e&&e.parentElement.parentElement.remove()}showElement(){let e=this.getInputElement();e&&e.parentElement.parentElement.style.removeProperty("display")}hideElement(){let e=this.getInputElement();e&&e.parentElement.parentElement.style.setProperty("display","none")}}class AdvEntry extends CustEntry{createElement(){let e=this.getInputElement();if(!e){let t=document.createElement("div");t.classList.add("grid","cust-element"),e=document.createElement("input"),e.min=String(this.zeroable?0:this.min),e.max=String(this.max),e.id=this.id,e.type="number",e.step=String(this.step);let i=document.createElement("label");i.setAttribute("for",this.id),i.innerHTML=this.name,i.appendChild(e),t.appendChild(i);let a=document.createElement("blockquote");a.innerHTML="
    "+this.desc.map((e=>`
  • ${e}
  • `)).join("")+"
",a.setAttribute("for",this.id),t.appendChild(a),document.getElementById("config-list-advanced").appendChild(t),new ErrorToolTip(this.id).addChangeListener()}e.value=String(this.value)}}var CustTable=[new CustEntry("mtcConf","DRAM Timing",CustPlatform.Mariko,4,["0: AUTO_ADJ_MARIKO_SAFE: Auto adjust timings for LPDDR4 ≤3733 Mbps specs, 8Gb density. (Default)","1: AUTO_ADJ_MARIKO_4266: Auto adjust timings for LPDDR4X 4266 Mbps specs, 8Gb density.","2: NO_ADJ_ALL: No timing adjustment for both Erista and Mariko. Might achieve better performance on Mariko but lower maximum frequency is expected."],0,[0,2],1),new CustEntry("commonCpuBoostClock","Boost Clock in kHz",CustPlatform.All,4,["System default: 1785000","Boost clock will be applied when applications request higher CPU frequency for quicker loading.","This will be set regardless of whether sys-clk is enabled."],1785e3,[102e4,3e6],1,!1),new CustEntry("commonEmcMemVolt","EMC Vddq (Erista Only) & RAM Vdd2 Voltage in uV",CustPlatform.All,4,["Acceptable range: 1100000 ≤ x ≤ 1250000, and it should be divided evenly by 12500.","Erista Default (HOS): 1125000 (bootloader: 1100000)","Mariko Default: 1100000 (It will not work without sys-clk-OC)","Not enabled by default"],0,[11e5,125e4],12500),new CustEntry("eristaCpuMaxVolt","Erista CPU Max Voltage in mV",CustPlatform.Erista,4,["Acceptable range: 1100 ≤ x ≤ 1300","L4T Default: 1235"],1235,[1100,1300],1),new CustEntry("eristaEmcMaxClock","Erista RAM Max Clock in kHz",CustPlatform.Erista,4,["Values should be ≥ 1600000, and divided evenly by 3200.","WARNING: RAM overclock could be UNSTABLE if timing parameters are not suitable for your DRAM"],1862400,[16e5,24e5],3200),new CustEntry("marikoCpuMaxVolt","Mariko CPU Max Voltage in mV",CustPlatform.Mariko,4,["System default: 1120","Acceptable range: 1100 ≤ x ≤ 1300"],1235,[1100,1300],5),new CustEntry("marikoEmcMaxClock","Mariko RAM Max Clock in kHz",CustPlatform.Mariko,4,["Values should be ≥ 1600000, and divided evenly by 3200.","WARNING: RAM overclock could be UNSTABLE if timing parameters are not suitable for your DRAM."],1996800,[16e5,2665600],3200),new CustEntry("marikoEmcVddqVolt","EMC Vddq (Mariko Only) Voltage in uV",CustPlatform.Mariko,4,["Acceptable range: 550000 ≤ x ≤ 650000","Value should be divided evenly by 5000","Default: 600000","Not enabled by default.","This will not work without sys-clk-OC."],0,[55e4,65e4],5e3)],AdvTable=[new AdvEntry("marikoGpuUV","Enable Mariko GPU Undervolt",CustPlatform.Mariko,4,["Undervolt Mariko GPU","Your GPU might not withstand undervolt and may not work properly","Can hang your console, or crash games","0 : Default Table","1 : SLT Table","2 : HiOPT Table (Might not work on your device"],0,[0,2],1)];class ErrorToolTip{constructor(e,t){this.id=e,this.msg=t,this.id=e,this.element=document.getElementById(e),t&&this.setMsg(t)}setMsg(e){return this.msg=e,this}show(){var e,t,i,a,s,l;return null===(e=this.element)||void 0===e||e.setAttribute("aria-invalid","true"),this.msg&&(null===(t=this.element)||void 0===t||t.setAttribute("title",this.msg),null===(a=null===(i=this.element)||void 0===i?void 0:i.parentElement)||void 0===a||a.setAttribute("data-tooltip",this.msg),null===(l=null===(s=this.element)||void 0===s?void 0:s.parentElement)||void 0===l||l.setAttribute("data-placement","top")),this}clear(){var e,t,i,a,s,l;return null===(e=this.element)||void 0===e||e.removeAttribute("aria-invalid"),null===(t=this.element)||void 0===t||t.removeAttribute("title"),null===(a=null===(i=this.element)||void 0===i?void 0:i.parentElement)||void 0===a||a.removeAttribute("data-tooltip"),null===(l=null===(s=this.element)||void 0===s?void 0:s.parentElement)||void 0===l||l.removeAttribute("data-placement"),this}addChangeListener(){var e;null===(e=this.element)||void 0===e||e.addEventListener("change",(e=>{let t=CustTable.filter((e=>e.id===this.id))[0];t.value=Number(this.element.value),t.validate()}))}}class CustStorage{constructor(){this.storage={},this.key="last_saved"}updateFromTable(){CustTable.forEach((e=>{var t;if(e.updateValueFromElement(),!e.validate())throw null===(t=e.getInputElement())||void 0===t||t.focus(),new Error(`Invalid ${e.name}`)})),AdvTable.forEach((e=>{var t;if(e.updateValueFromElement(),!e.validate())throw null===(t=e.getInputElement())||void 0===t||t.focus(),new Error(`Invalid ${e.name}`)})),this.storage={};let e=Object.fromEntries(CustTable.map((e=>[e.id,e.value])));Object.keys(e).forEach((t=>this.storage[t]=e[t])),e=Object.fromEntries(AdvTable.map((e=>[e.id,e.value]))),Object.keys(e).forEach((t=>this.storage[t]=e[t]))}setTable(){let e=Object.keys(this.storage);e.forEach((e=>CustTable.filter((t=>t.id==e))[0].value=this.storage[e])),e.forEach((e=>AdvTable.filter((t=>t.id==e))[0].value=this.storage[e])),CustTable.filter((t=>!e.includes(t.id))).forEach((e=>e.value=e.defval)),AdvTable.filter((t=>!e.includes(t.id))).forEach((e=>e.value=e.defval)),CustTable.forEach((e=>{var t;if(!e.validate())throw null===(t=e.getInputElement())||void 0===t||t.focus(),new Error(`Invalid ${e.name}`);e.setElementValue()})),AdvTable.forEach((e=>{var t;if(!e.validate())throw null===(t=e.getInputElement())||void 0===t||t.focus(),new Error(`Invalid ${e.name}`);e.setElementValue()}))}save(){localStorage.setItem(this.key,JSON.stringify(this.storage))}load(){let e=localStorage.getItem(this.key);if(!e)return null;let t=JSON.parse(e),i=CustTable.map((e=>e.id)),a=Object.keys(t).filter((e=>!i.includes(e)));return a.length&&console.log(`Ignored: ${a}`),Object.keys(t).filter((e=>i.includes(e))).forEach((e=>this.storage[e]=t[e])),i=AdvTable.map((e=>e.id)),a=Object.keys(t).filter((e=>!i.includes(e))),a.length&&console.log(`Ignored: ${a}`),Object.keys(t).filter((e=>i.includes(e))).forEach((e=>this.storage[e]=t[e])),this.storage}}class Cust{constructor(){this.storage=new CustStorage,this.magic=1414747459,this.magicLen=4,this.mapper={2:{get:e=>this.view.getUint16(e,!0),set:(e,t)=>this.view.setUint16(e,t,!0)},4:{get:e=>this.view.getUint32(e,!0),set:(e,t)=>this.view.setUint32(e,t,!0)}}}findMagicOffset(){this.view=new DataView(this.buffer);for(let e=0;e{var t,i;if(!e.offset)throw null===(t=e.getInputElement())||void 0===t||t.focus(),new Error(`Failed to get offset for ${e.name}`);let a=this.mapper[e.size];if(!a)throw null===(i=e.getInputElement())||void 0===i||i.focus(),new Error(`Unknown size at ${e.name}`);a.set(e.offset,e.value)};CustTable.forEach(e),5==this.rev&&AdvTable.forEach(e),this.storage.save();let t=document.createElement("a");t.href=window.URL.createObjectURL(new Blob([this.buffer],{type:"application/octet-stream"})),t.download="loader.kip",t.click(),this.toggleLoadLastSavedBtn(!0)}removeHTMLForm(){CustTable.forEach((e=>e.removeElement()))}toggleLoadLastSavedBtn(e){let t=document.getElementById("load_saved");e?(t.addEventListener("click",(()=>{this.storage.load()&&this.storage.setTable()})),t.style.removeProperty("display"),t.removeAttribute("disabled")):t.style.setProperty("display","none")}createHTMLForm(){var e;CustTable.forEach((e=>e.createElement()));let t=document.createElement("p");t.innerHTML="Advanced configuration",null===(e=document.getElementById("config-list-advanced"))||void 0===e||e.appendChild(t),AdvTable.forEach((e=>e.createElement()));let i=document.getElementById("load_default");i.removeAttribute("disabled"),i.addEventListener("click",(()=>{CustTable.forEach((e=>e.setElementDefaultValue()))})),this.toggleLoadLastSavedBtn(null!==this.storage.load());let a=document.getElementById("save");a.removeAttribute("disabled"),a.addEventListener("click",(()=>{try{this.save()}catch(e){console.error(e),alert(e)}}))}initCustTabs(){const e=Array.from(document.querySelectorAll('nav[role="tablist"] > button'));e.forEach((t=>{t.removeAttribute("disabled");let i=Number(t.getAttribute("data-platform"));t.addEventListener("click",(a=>{const s=["outline"];t.classList.remove(...s),e.filter((e=>e!=t)).forEach((e=>e.classList.add(...s))),CustTable.forEach((e=>{e.isAvailableFor(i)?e.showElement():e.hideElement()}))}))}))}parse(){let e=this.beginOffset+this.magicLen;if(this.rev=this.mapper[4].get(e),4!=this.rev&&5!=this.rev)throw new Error(`Unsupported custRev, expected: 4 or 5, got ${this.rev}`);e+=4,document.getElementById("cust_rev").innerHTML=`Cust v${this.rev} is loaded.`;let t=t=>{var i;t.offset=e;let a=this.mapper[t.size];if(!a)throw null===(i=t.getInputElement())||void 0===i||i.focus(),new Error(`Unknown size at ${t}`);t.value=a.get(e),e+=t.size,t.validate()};CustTable.forEach(t),5==this.rev&&AdvTable.forEach(t)}load(e){try{this.buffer=e,this.findMagicOffset(),this.removeHTMLForm(),this.parse(),this.initCustTabs(),this.createHTMLForm()}catch(e){console.error(e),alert(e)}}}class ReleaseAsset{constructor(e){this.downloadUrl=e.browser_download_url,this.updatedAt=e.updated_at}}class ReleaseInfo{constructor(){this.ocLatestApi="https://api.github.com/repos/hanai3Bi/Switch-OC-Suite/releases/latest"}load(){return __awaiter(this,void 0,void 0,(function*(){try{this.parseOcResponse(yield this.responseFromApi(this.ocLatestApi).catch())}catch(e){console.error(e),alert(e)}}))}responseFromApi(e){return __awaiter(this,void 0,void 0,(function*(){const t=yield fetch(e,{method:"GET",headers:{Accept:"application/json"}});if(t.ok)return yield t.json();throw new Error(`Failed to connect to "${e}": ${t.status}`)}))}parseOcResponse(e){this.ocVer=e.tag_name,this.amsVer=this.ocVer.split(".").slice(0,3).join("."),this.loaderKipAsset=new ReleaseAsset(e.assets.filter((e=>e.name.endsWith("loader.kip")))[0]),this.sdOutZipAsset=new ReleaseAsset(e.assets.filter((e=>e.name.endsWith(".zip")))[0]),this.amsUrl=`https://github.com/Atmosphere-NX/Atmosphere/releases/tags/${this.amsVer}`}}class DownloadSection{constructor(){this.element=document.getElementById("download_btn_grid")}load(){return __awaiter(this,void 0,void 0,(function*(){for(;!this.isVisible();)yield new Promise((e=>setTimeout(e,1e3)));const e=new ReleaseInfo;yield e.load(),this.update("loader_kip_btn",`loader.kip ${e.ocVer}
${e.loaderKipAsset.updatedAt}`,e.loaderKipAsset.downloadUrl),this.update("sdout_zip_btn",`SdOut.zip ${e.ocVer}
${e.sdOutZipAsset.updatedAt}`,e.sdOutZipAsset.downloadUrl),this.update("ams_btn",`Atmosphere-NX ${e.amsVer}`,e.amsUrl)}))}isVisible(){let e=this.element.getBoundingClientRect();return e.top>0&&e.left>0&&e.bottom-e.height<(window.innerHeight||document.documentElement.clientHeight)&&e.right-e.width<(window.innerWidth||document.documentElement.clientWidth)}update(e,t,i){let a=document.getElementById(e);a.innerHTML=t,a.removeAttribute("aria-busy"),a.setAttribute("href",i)}}const fileInput=document.getElementById("file");fileInput.addEventListener("change",(e=>{var t=new Cust;if(!e.target||!e.target.files)return;let i=new FileReader;i.readAsArrayBuffer(e.target.files[0]),i.onloadend=e=>{e.target.readyState==FileReader.DONE&&t.load(e.target.result)}})),addEventListener("DOMContentLoaded",(e=>__awaiter(this,void 0,void 0,(function*(){yield(new DownloadSection).load()})))); +var __awaiter=this&&this.__awaiter||function(e,t,i,a){return new(i||(i=Promise))((function(s,r){function l(e){try{o(a.next(e))}catch(e){r(e)}}function n(e){try{o(a.throw(e))}catch(e){r(e)}}function o(e){var t;e.done?s(e.value):(t=e.value,t instanceof i?t:new i((function(e){e(t)}))).then(l,n)}o((a=a.apply(e,t||[])).next())}))};const CUST_REV=4,CUST_REV_ADV=5;var CustPlatform;!function(e){e[e.Undefined=0]="Undefined",e[e.Erista=1]="Erista",e[e.Mariko=2]="Mariko",e[e.All=3]="All"}(CustPlatform||(CustPlatform={}));class CustEntry{constructor(e,t,i,a,s,r,l=[0,1e6],n=1,o=!0){this.id=e,this.name=t,this.platform=i,this.size=a,this.desc=s,this.defval=r,this.step=n,this.zeroable=o,this.min=l[0],this.max=l[1]}validate(){let e=new ErrorToolTip(this.id).clear();return Number.isNaN(this.value)||void 0===this.value?(e.setMsg("Invalid value: Not a number").show(),!1):!(!this.zeroable||0!=this.value)||(this.valuethis.max?(e.setMsg(`Expected range: [${this.min}, ${this.max}], got ${this.value}.`).show(),!1):this.value%this.step==0||(e.setMsg(`${this.value} % ${this.step} ≠ 0`).show(),!1))}getInputElement(){return document.getElementById(this.id)}updateValueFromElement(){var e;this.value=Number(null===(e=this.getInputElement())||void 0===e?void 0:e.value)}isAvailableFor(e){return e===CustPlatform.Undefined||this.platform===e||this.platform===CustPlatform.All}createElement(){let e=this.getInputElement();if(!e){let t=document.createElement("div");t.classList.add("grid","cust-element"),e=document.createElement("input"),e.min=String(this.zeroable?0:this.min),e.max=String(this.max),e.id=this.id,e.type="number",e.step=String(this.step);let i=document.createElement("label");i.setAttribute("for",this.id),i.innerHTML=this.name,i.appendChild(e),t.appendChild(i);let a=document.createElement("blockquote");a.innerHTML="
    "+this.desc.map((e=>`
  • ${e}
  • `)).join("")+"
",a.setAttribute("for",this.id),t.appendChild(a),document.getElementById("config-list-basic").appendChild(t),new ErrorToolTip(this.id).addChangeListener()}e.value=String(this.value)}setElementValue(){this.getInputElement().value=String(this.value)}setElementDefaultValue(){this.getInputElement().value=String(this.defval)}removeElement(){let e=this.getInputElement();e&&e.parentElement.parentElement.remove()}showElement(){let e=this.getInputElement();e&&e.parentElement.parentElement.style.removeProperty("display")}hideElement(){let e=this.getInputElement();e&&e.parentElement.parentElement.style.setProperty("display","none")}}class AdvEntry extends CustEntry{createElement(){let e=this.getInputElement();if(!e){let t=document.createElement("div");t.classList.add("grid","cust-element"),e=document.createElement("input"),e.min=String(this.zeroable?0:this.min),e.max=String(this.max),e.id=this.id,e.type="number",e.step=String(this.step);let i=document.createElement("label");i.setAttribute("for",this.id),i.innerHTML=this.name,i.appendChild(e),t.appendChild(i);let a=document.createElement("blockquote");a.innerHTML="
    "+this.desc.map((e=>`
  • ${e}
  • `)).join("")+"
",a.setAttribute("for",this.id),t.appendChild(a),document.getElementById("config-list-advanced").appendChild(t),new ErrorToolTip(this.id).addChangeListener()}e.value=String(this.value)}}var CustTable=[new CustEntry("mtcConf","DRAM Timing",CustPlatform.Mariko,4,["0: AUTO_ADJ_MARIKO_SAFE: Auto adjust timings for LPDDR4 ≤3733 Mbps specs, 8Gb density. (Default)","1: AUTO_ADJ_MARIKO_4266: Auto adjust timings for LPDDR4X 4266 Mbps specs, 8Gb density.","2: NO_ADJ_ALL: No timing adjustment for both Erista and Mariko. Might achieve better performance on Mariko but lower maximum frequency is expected."],0,[0,2],1),new CustEntry("commonCpuBoostClock","Boost Clock in kHz",CustPlatform.All,4,["System default: 1785000","Boost clock will be applied when applications request higher CPU frequency for quicker loading.","This will be set regardless of whether sys-clk is enabled."],1785e3,[102e4,3e6],1,!1),new CustEntry("commonEmcMemVolt","EMC Vddq (Erista Only) & RAM Vdd2 Voltage in uV",CustPlatform.All,4,["Acceptable range: 1100000 ≤ x ≤ 1250000, and it should be divided evenly by 12500.","Erista Default (HOS): 1125000 (bootloader: 1100000)","Mariko Default: 1100000 (It will not work without sys-clk-OC)","Not enabled by default"],0,[11e5,125e4],12500),new CustEntry("eristaCpuMaxVolt","Erista CPU Max Voltage in mV",CustPlatform.Erista,4,["Acceptable range: 1100 ≤ x ≤ 1300","L4T Default: 1235"],1235,[1100,1300],1),new CustEntry("eristaEmcMaxClock","Erista RAM Max Clock in kHz",CustPlatform.Erista,4,["Values should be ≥ 1600000, and divided evenly by 3200.","WARNING: RAM overclock could be UNSTABLE if timing parameters are not suitable for your DRAM"],1862400,[16e5,24e5],3200),new CustEntry("marikoCpuMaxVolt","Mariko CPU Max Voltage in mV",CustPlatform.Mariko,4,["System default: 1120","Acceptable range: 1100 ≤ x ≤ 1300"],1235,[1100,1300],5),new CustEntry("marikoEmcMaxClock","Mariko RAM Max Clock in kHz",CustPlatform.Mariko,4,["Values should be ≥ 1600000, and divided evenly by 3200.","WARNING: RAM overclock could be UNSTABLE if timing parameters are not suitable for your DRAM."],1996800,[16e5,2665600],3200),new CustEntry("marikoEmcVddqVolt","EMC Vddq (Mariko Only) Voltage in uV",CustPlatform.Mariko,4,["Acceptable range: 550000 ≤ x ≤ 650000","Value should be divided evenly by 5000","Default: 600000","Not enabled by default.","This will not work without sys-clk-OC."],0,[55e4,65e4],5e3)],AdvTable=[new AdvEntry("marikoGpuUV","Enable Mariko GPU Undervolt",CustPlatform.Mariko,4,["Undervolt Mariko GPU","Your GPU might not withstand undervolt and may not work properly","Can hang your console, or crash games","0 : Default Table","1 : SLT Table","2 : HiOPT Table (If your speedo is not good, higher gpu freq will not work)"],0,[0,2],1),new AdvEntry("ramTimingPresetOne","Primary RAM Timing Preset",CustPlatform.Mariko,4,["WARNING: Unstable timings can corrupt your nand","Select Timing Preset for both AUTO_ADJ and CUSTOM_ADJ","Values are : tRCD - tRP - tRAS (tRC = tRP + tRAS)","0 : Do Not Adjust (CUST_ADJ only)","1 : 19 - 19 - 44","2 : 18 - 18 - 42 (Default timing)","3 : 17 - 17 - 39","4 : 16 - 16 - 36","5 : 15 - 15 - 35","6 : 14 - 14 - 34","7 : 13 - 13 - 33"],0,[0,7],1),new AdvEntry("ramTimingPresetTwo","Secondary RAM Timing Preset",CustPlatform.Mariko,4,["WARNING: Unstable timings can corrupt your nand","Secondary Timing Preset for both AUTO_ADJ and CUSTOM_ADJ","Values are : tRRD - tFAW - tRTP","0 : Do Not Adjust (CUST_ADJ only)","1 : 12 - 48 - 10","2 : 10 - 40 - 7.5 (Default timing) (3733 specs)","3 : 7.5 - 30 - 7.5 (4266 specs)","4 : 6 - 24 - 6","5 : 4 - 16 - 6","6 : 2 - 8 - 5"],0,[0,6],1)];class ErrorToolTip{constructor(e,t){this.id=e,this.msg=t,this.id=e,this.element=document.getElementById(e),t&&this.setMsg(t)}setMsg(e){return this.msg=e,this}show(){var e,t,i,a,s,r;return null===(e=this.element)||void 0===e||e.setAttribute("aria-invalid","true"),this.msg&&(null===(t=this.element)||void 0===t||t.setAttribute("title",this.msg),null===(a=null===(i=this.element)||void 0===i?void 0:i.parentElement)||void 0===a||a.setAttribute("data-tooltip",this.msg),null===(r=null===(s=this.element)||void 0===s?void 0:s.parentElement)||void 0===r||r.setAttribute("data-placement","top")),this}clear(){var e,t,i,a,s,r;return null===(e=this.element)||void 0===e||e.removeAttribute("aria-invalid"),null===(t=this.element)||void 0===t||t.removeAttribute("title"),null===(a=null===(i=this.element)||void 0===i?void 0:i.parentElement)||void 0===a||a.removeAttribute("data-tooltip"),null===(r=null===(s=this.element)||void 0===s?void 0:s.parentElement)||void 0===r||r.removeAttribute("data-placement"),this}addChangeListener(){var e;null===(e=this.element)||void 0===e||e.addEventListener("change",(e=>{let t=CustTable.filter((e=>e.id===this.id))[0];t.value=Number(this.element.value),t.validate()}))}}class CustStorage{constructor(){this.storage={},this.key="last_saved"}updateFromTable(){CustTable.forEach((e=>{var t;if(e.updateValueFromElement(),!e.validate())throw null===(t=e.getInputElement())||void 0===t||t.focus(),new Error(`Invalid ${e.name}`)})),AdvTable.forEach((e=>{var t;if(e.updateValueFromElement(),!e.validate())throw null===(t=e.getInputElement())||void 0===t||t.focus(),new Error(`Invalid ${e.name}`)})),this.storage={};let e=Object.fromEntries(CustTable.map((e=>[e.id,e.value])));Object.keys(e).forEach((t=>this.storage[t]=e[t])),e=Object.fromEntries(AdvTable.map((e=>[e.id,e.value]))),Object.keys(e).forEach((t=>this.storage[t]=e[t]))}setTable(){let e=Object.keys(this.storage);e.forEach((e=>CustTable.filter((t=>t.id==e))[0].value=this.storage[e])),e.forEach((e=>AdvTable.filter((t=>t.id==e))[0].value=this.storage[e])),CustTable.filter((t=>!e.includes(t.id))).forEach((e=>e.value=e.defval)),AdvTable.filter((t=>!e.includes(t.id))).forEach((e=>e.value=e.defval)),CustTable.forEach((e=>{var t;if(!e.validate())throw null===(t=e.getInputElement())||void 0===t||t.focus(),new Error(`Invalid ${e.name}`);e.setElementValue()})),AdvTable.forEach((e=>{var t;if(!e.validate())throw null===(t=e.getInputElement())||void 0===t||t.focus(),new Error(`Invalid ${e.name}`);e.setElementValue()}))}save(){localStorage.setItem(this.key,JSON.stringify(this.storage))}load(){let e=localStorage.getItem(this.key);if(!e)return null;let t=JSON.parse(e),i=CustTable.map((e=>e.id)),a=Object.keys(t).filter((e=>!i.includes(e)));return a.length&&console.log(`Ignored: ${a}`),Object.keys(t).filter((e=>i.includes(e))).forEach((e=>this.storage[e]=t[e])),i=AdvTable.map((e=>e.id)),a=Object.keys(t).filter((e=>!i.includes(e))),a.length&&console.log(`Ignored: ${a}`),Object.keys(t).filter((e=>i.includes(e))).forEach((e=>this.storage[e]=t[e])),this.storage}}class Cust{constructor(){this.storage=new CustStorage,this.magic=1414747459,this.magicLen=4,this.mapper={2:{get:e=>this.view.getUint16(e,!0),set:(e,t)=>this.view.setUint16(e,t,!0)},4:{get:e=>this.view.getUint32(e,!0),set:(e,t)=>this.view.setUint32(e,t,!0)}}}findMagicOffset(){this.view=new DataView(this.buffer);for(let e=0;e{var t,i;if(!e.offset)throw null===(t=e.getInputElement())||void 0===t||t.focus(),new Error(`Failed to get offset for ${e.name}`);let a=this.mapper[e.size];if(!a)throw null===(i=e.getInputElement())||void 0===i||i.focus(),new Error(`Unknown size at ${e.name}`);a.set(e.offset,e.value)};CustTable.forEach(e),5==this.rev&&AdvTable.forEach(e),this.storage.save();let t=document.createElement("a");t.href=window.URL.createObjectURL(new Blob([this.buffer],{type:"application/octet-stream"})),t.download="loader.kip",t.click(),this.toggleLoadLastSavedBtn(!0)}removeHTMLForm(){CustTable.forEach((e=>e.removeElement()))}toggleLoadLastSavedBtn(e){let t=document.getElementById("load_saved");e?(t.addEventListener("click",(()=>{this.storage.load()&&this.storage.setTable()})),t.style.removeProperty("display"),t.removeAttribute("disabled")):t.style.setProperty("display","none")}createHTMLForm(){var e;CustTable.forEach((e=>e.createElement()));let t=document.createElement("p");t.innerHTML="Advanced configuration",null===(e=document.getElementById("config-list-advanced"))||void 0===e||e.appendChild(t),AdvTable.forEach((e=>e.createElement()));let i=document.getElementById("load_default");i.removeAttribute("disabled"),i.addEventListener("click",(()=>{CustTable.forEach((e=>e.setElementDefaultValue()))})),this.toggleLoadLastSavedBtn(null!==this.storage.load());let a=document.getElementById("save");a.removeAttribute("disabled"),a.addEventListener("click",(()=>{try{this.save()}catch(e){console.error(e),alert(e)}}))}initCustTabs(){const e=Array.from(document.querySelectorAll('nav[role="tablist"] > button'));e.forEach((t=>{t.removeAttribute("disabled");let i=Number(t.getAttribute("data-platform"));t.addEventListener("click",(a=>{const s=["outline"];t.classList.remove(...s),e.filter((e=>e!=t)).forEach((e=>e.classList.add(...s))),CustTable.forEach((e=>{e.isAvailableFor(i)?e.showElement():e.hideElement()}))}))}))}parse(){let e=this.beginOffset+this.magicLen;if(this.rev=this.mapper[4].get(e),4!=this.rev&&5!=this.rev)throw new Error(`Unsupported custRev, expected: 4 or 5, got ${this.rev}`);e+=4,document.getElementById("cust_rev").innerHTML=`Cust v${this.rev} is loaded.`;let t=t=>{var i;t.offset=e;let a=this.mapper[t.size];if(!a)throw null===(i=t.getInputElement())||void 0===i||i.focus(),new Error(`Unknown size at ${t}`);t.value=a.get(e),e+=t.size,t.validate()};CustTable.forEach(t),5==this.rev&&AdvTable.forEach(t)}load(e){try{this.buffer=e,this.findMagicOffset(),this.removeHTMLForm(),this.parse(),this.initCustTabs(),this.createHTMLForm()}catch(e){console.error(e),alert(e)}}}class ReleaseAsset{constructor(e){this.downloadUrl=e.browser_download_url,this.updatedAt=e.updated_at}}class ReleaseInfo{constructor(){this.ocLatestApi="https://api.github.com/repos/hanai3Bi/Switch-OC-Suite/releases/latest"}load(){return __awaiter(this,void 0,void 0,(function*(){try{this.parseOcResponse(yield this.responseFromApi(this.ocLatestApi).catch())}catch(e){console.error(e),alert(e)}}))}responseFromApi(e){return __awaiter(this,void 0,void 0,(function*(){const t=yield fetch(e,{method:"GET",headers:{Accept:"application/json"}});if(t.ok)return yield t.json();throw new Error(`Failed to connect to "${e}": ${t.status}`)}))}parseOcResponse(e){this.ocVer=e.tag_name,this.amsVer=this.ocVer.split(".").slice(0,3).join("."),this.loaderKipAsset=new ReleaseAsset(e.assets.filter((e=>e.name.endsWith("loader.kip")))[0]),this.sdOutZipAsset=new ReleaseAsset(e.assets.filter((e=>e.name.endsWith(".zip")))[0]),this.amsUrl=`https://github.com/Atmosphere-NX/Atmosphere/releases/tags/${this.amsVer}`}}class DownloadSection{constructor(){this.element=document.getElementById("download_btn_grid")}load(){return __awaiter(this,void 0,void 0,(function*(){for(;!this.isVisible();)yield new Promise((e=>setTimeout(e,1e3)));const e=new ReleaseInfo;yield e.load(),this.update("loader_kip_btn",`loader.kip ${e.ocVer}
${e.loaderKipAsset.updatedAt}`,e.loaderKipAsset.downloadUrl),this.update("sdout_zip_btn",`SdOut.zip ${e.ocVer}
${e.sdOutZipAsset.updatedAt}`,e.sdOutZipAsset.downloadUrl),this.update("ams_btn",`Atmosphere-NX ${e.amsVer}`,e.amsUrl)}))}isVisible(){let e=this.element.getBoundingClientRect();return e.top>0&&e.left>0&&e.bottom-e.height<(window.innerHeight||document.documentElement.clientHeight)&&e.right-e.width<(window.innerWidth||document.documentElement.clientWidth)}update(e,t,i){let a=document.getElementById(e);a.innerHTML=t,a.removeAttribute("aria-busy"),a.setAttribute("href",i)}}const fileInput=document.getElementById("file");fileInput.addEventListener("change",(e=>{var t=new Cust;if(!e.target||!e.target.files)return;let i=new FileReader;i.readAsArrayBuffer(e.target.files[0]),i.onloadend=e=>{e.target.readyState==FileReader.DONE&&t.load(e.target.result)}})),addEventListener("DOMContentLoaded",(e=>__awaiter(this,void 0,void 0,(function*(){yield(new DownloadSection).load()})))); diff --git a/pages/src/main.ts b/pages/src/main.ts index 6c9ca90b..1337d507 100644 --- a/pages/src/main.ts +++ b/pages/src/main.ts @@ -162,9 +162,10 @@ var CustTable: Array = [ "DRAM Timing", CustPlatform.Mariko, 4, - ["0: AUTO_ADJ_MARIKO_SAFE: Auto adjust timings for LPDDR4 ≤3733 Mbps specs, 8Gb density. (Default)", - "1: AUTO_ADJ_MARIKO_4266: Auto adjust timings for LPDDR4X 4266 Mbps specs, 8Gb density.", - "2: NO_ADJ_ALL: No timing adjustment for both Erista and Mariko. Might achieve better performance on Mariko but lower maximum frequency is expected."], + ["0: AUTO_ADJ_SAFE_MARIKO: Auto adjust timings for LPDDR4 ≤3733 Mbps specs, 8Gb density. (Default)", + "1: AUTO_ADJ_PERF_MARIKO: Auto adjust with tightened timings for best performance", + "2: CUSTOM_ADJ_MARIKO: Basically same as NO_ADJ_ALL, with only core timing adjustments (Use advanced config)", + "3: NO_ADJ_ALL: No timing adjustment for both Erista and Mariko. Might achieve better performance on Mariko but lower maximum frequency is expected."], 0, [0, 2], 1 @@ -236,7 +237,7 @@ var CustTable: Array = [ ["Values should be ≥ 1600000, and divided evenly by 3200.", "WARNING: RAM overclock could be UNSTABLE if timing parameters are not suitable for your DRAM."], 1996_800, - [1600_000, 2665_600], + [1600_000, 2400_600], 3200, ), new CustEntry( @@ -271,6 +272,43 @@ var AdvTable: Array = [ [0,2], 1, ), + new AdvEntry( + "ramTimingPresetOne", + "Primary RAM Timing Preset", + CustPlatform.Mariko, + 4, + ["WARNING: Unstable timings can corrupt your nand", + "Select Timing Preset for both AUTO_ADJ and CUSTOM_ADJ", + "Values are : tRCD - tRP - tRAS (tRC = tRP + tRAS)", + "0 : Do Not Adjust (CUST_ADJ only)", + "1 : 18 - 18 - 42 (Default timing)", + "2 : 17 - 17 - 39", + "3 : 16 - 16 - 36", + "4 : 15 - 15 - 35", + "5 : 14 - 14 - 34", + "6 : 13 - 13 - 33"], + 1, + [0,6], + 1, + ), + new AdvEntry( + "ramTimingPresetTwo", + "Secondary RAM Timing Preset", + CustPlatform.Mariko, + 4, + ["WARNING: Unstable timings can corrupt your nand", + "Secondary Timing Preset for both AUTO_ADJ and CUSTOM_ADJ", + "Values are : tRRD - tFAW - tRTP", + "0 : Do Not Adjust (CUST_ADJ only)", + "1 : 10 - 40 - 7.5 (Default timing) (3733 specs)", + "2 : 7.5 - 30 - 7.5 (4266 specs)", + "3 : 6 - 24 - 6", + "4 : 4 - 16 - 6", + "5 : 2 - 8 - 5",], + 1, + [0,5], + 1, + ) ]; class ErrorToolTip {