diff --git a/.gitignore b/.gitignore index 5509140f..2276a02d 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ *.DS_Store +.vscode/ diff --git a/README.md b/README.md index e5155327..319b0b75 100644 --- a/README.md +++ b/README.md @@ -7,24 +7,28 @@ Overclocking suite for Horizon OS (HOS) running on Atmosphere CFW. **DISCLAIMER: USE AT YOUR OWN RISK!** -- Overclocking in general will shorten the lifespan of some hardware components. - -- Due to HorizonOS design, instabilities from unsafe RAM clocks may cause filesystem corruption. **Always make backup before usage.** +- Overclocking in general will shorten the lifespan of some hardware components. **YOU ARE RESPONSIBLE for any problem or potential damage** if unsafe frequencies are ENABLED in sys-clk-OC. Issues like asking for bypassing limit will BE IGNORED OR CLOSED WITHOUT REPLY. +- Due to HorizonOS design, instabilities from unsafe RAM clocks may cause filesystem corruption. **Always make backup before enabling DRAM OC.** ## Features - Erista variant (HAC-001) - - CPU Overclock - - Safe: 1785 MHz - - Unsafe (due to the limit of board power draw or power IC): - - Enable "Allow Unsafe Frequencies" in overlay to unlock frequencies up to 2091 MHz - - See [README for sys-clk-OC](https://github.com/KazushiMe/Switch-OC-Suite/blob/master/Source/sys-clk-OC/README.md) + - CPU Overclock (Safe: 1785 MHz) +
Unsafe - - DRAM Overclock - - Safe: 1862.4 MHz - - Unsafe: - - DRAM bus overvolting + - Due to the limit of board power draw or power IC + - Unlockable frequencies up to 2091 MHz + - See [README for sys-clk-OC](https://github.com/KazushiMe/Switch-OC-Suite/blob/master/Source/sys-clk-OC/README.md) + +
+ + - DRAM Overclock (Safe: 1862.4 MHz) +
Unsafe + + - Up to 2131 MHz with DRAM bus overvolting depending on your DRAM chip + +
- Modded sys-clk and ReverseNX-RT - CPU & GPU frequency governor (Experimental) @@ -33,16 +37,21 @@ Overclocking suite for Horizon OS (HOS) running on Atmosphere CFW. - Sync ReverseNX Mode - Mariko variant (HAC-001-01, HDH-001, HEG-001) - - CPU / GPU Overclock - - Safe: 1963 / 998 MHz - - Unsafe (due to the limit of board power draw or power IC): - - Enable "Allow Unsafe Frequencies" in overlay to unlock frequencies up to 2397 / 1305 MHz - - See [README for sys-clk-OC](https://github.com/KazushiMe/Switch-OC-Suite/blob/master/Source/sys-clk-OC/README.md) + - CPU / GPU Overclock (Safe: 1963 / 998 MHz) +
Unsafe - - DRAM Overclock - - Safe: 1996.8 MHz with built-in timing adjustment - - Unsafe: - - [DRAM bus overvolting](https://gist.github.com/KazushiMe/6bb0fcbefe0e03b1274079522516d56d). + - Due to the limit of board power draw or power IC + - Unlockable frequencies up to 2397 / 1305 MHz or 2295 / 1267 MHz + - See [README for sys-clk-OC](https://github.com/KazushiMe/Switch-OC-Suite/blob/master/Source/sys-clk-OC/README.md) + +
+ + - DRAM Overclock (Safe: 1996.8 MHz) +
Unsafe + + - [DRAM bus overvolting](https://gist.github.com/KazushiMe/6bb0fcbefe0e03b1274079522516d56d). + +
- Modded sys-clk and ReverseNX-RT - Auto CPU Boost @@ -59,8 +68,7 @@ Overclocking suite for Horizon OS (HOS) running on Atmosphere CFW. - CPU & GPU frequency governor (Experimental) - Adjust frequency based on load. Might decrease power draw but can introduce stutters. Can be turned off for specific titles. -- Fast-charging (0.5A/2A) toggle, set charge limit (20% - 100%) - - Hoag (Switch Lite) cannot use the fast-charging toggle feature for now [#56](https://github.com/KazushiMe/Switch-OC-Suite/issues/56). +- Setting charge limit (20% - 100%) - Long-term use of charge limit may render the battery gauge inaccurate. Performing full cycles could help recalibration, or try [battery_desync_fix_nx](https://github.com/CTCaer/battery_desync_fix_nx). - Global profile @@ -101,23 +109,25 @@ Overclocking suite for Horizon OS (HOS) running on Atmosphere CFW.
Deprecated: patching sysmodules manually - This method is only served as reference as it could damage your MMC file system if not handled properly. - Patched sysmodules would be persistent until pcv or ptm was updated in new HOS (normally in `x.0.0`). + - This method is only served as reference as it could damage your MMC file system if not handled properly. - Tools: - - Lockpick_RCM - - TegraExplorer - - [hactool](https://github.com/SciresM/hactool) - - [nx2elf](https://github.com/shuffle2/nx2elf) - - elf2nso from [switch-tools](https://github.com/switchbrew/switch-tools/) - - [hacpack](https://github.com/The-4n/hacPack) + - Patched sysmodules would be persistent until pcv or ptm was updated in new HOS (normally in `x.0.0`). + + - Tools: + - Lockpick_RCM + - TegraExplorer + - [hactool](https://github.com/SciresM/hactool) + - [nx2elf](https://github.com/shuffle2/nx2elf) + - elf2nso from [switch-tools](https://github.com/switchbrew/switch-tools/) + - [hacpack](https://github.com/The-4n/hacPack) 1. Dump `prod.keys` with Lockpick_RCM 2. Dump HOS firmware with TegraExplorer 3. Configure and run `test_patch.sh` to generate patched pcv & ptm sysmodules in nca 4. Replace nca in `SYSTEM:/Contents/registered/` with TegraExplorer 5. `ValidateAcidSignature()` should be stubbed to allow unsigned sysmodules to load (a.k.a. `loader_patch`) +
diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/customize.cpp b/Source/Atmosphere/stratosphere/loader/source/oc/customize.cpp index 41731e13..7caf1f54 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/customize.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/customize.cpp @@ -20,29 +20,34 @@ namespace ams::ldr::oc { volatile CustomizeTable C = { /* DRAM Timing: - * AUTO_ADJ_MARIKO_SAFE: Auto adjust timings for LPDDR4 ≤3733 Mbps specs, 8Gb density (Default). - * AUTO_ADJ_MARIKO_4266: Auto adjust timings for LPDDR4X 4266 Mbps specs, 8Gb density. + * AUTO_ADJ_MARIKO_SAFE_NO_ADJ_ERISTA: Auto adjust timings for Mariko LPDDR4X ≤3733 Mbps specs, 8Gb density; No timing adjustment for Erista. (Default) + * AUTO_ADJ_MARIKO_4266_NO_ADJ_ERISTA: Auto adjust timings for Mariko LPDDR4X 4266 Mbps specs, 8Gb density; No timing adjustments for Erista. + * NO_ADJ_ALL: No timing adjustment for both Erista and Mariko. Might achieve better performance on Mariko but lower maximum frequency is expected. */ -.mtcConf = AUTO_ADJ_MARIKO_SAFE, +.mtcConf = AUTO_ADJ_MARIKO_SAFE_NO_ADJ_ERISTA, /* Mariko CPU: * - Max Clock in kHz: * Default: 1785000 - * >= 2397000 will enable overvolting (> 1120 mV) - * - Boost Clock in kHz: - * Default: 1785000 - * Boost clock will be applied when applications request higher CPU frequency for quicker loading. - * - Max Voltage in mV: - * Default voltage: 1120 + * 2397000 might be unreachable for some SoCs. */ .marikoCpuMaxClock = 2397000, +/* - Boost Clock in kHz: + * 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. + */ .marikoCpuBoostClock = 1785000, +/* - Max Voltage in mV: + * Default voltage: 1120 + */ .marikoCpuMaxVolt = 1235, /* Mariko GPU: * - Max Clock in kHz: * Default: 921600 * NVIDIA Maximum: 1267200 + * 1305600 might be unreachable for some SoCs. */ .marikoGpuMaxClock = 1305600, @@ -54,17 +59,22 @@ volatile CustomizeTable C = { * - Graphical glitches * - System instabilities * - NAND corruption - * Timings from auto-adjustment have been tested safe for up to 1996.8 MHz for all DRAM chips. */ .marikoEmcMaxClock = 1996800, +/* - RAM Voltage in uV + * Range: 600'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, /* Erista CPU: * Not tested but enabled by default. - * - Enable Overclock * - Max Voltage in mV */ -.eristaCpuOCEnabled= 1, -.eristaCpuMaxVolt = 1257, +.eristaCpuMaxVolt = 1235, /* Erista EMC: * - RAM Clock in kHz @@ -73,13 +83,14 @@ volatile CustomizeTable C = { * - Graphical glitches * - System instabilities * - NAND corruption - * - RAM Voltage in uV + */ +.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 * Not enabled by default. */ -.eristaEmcMaxClock = 1862400, .eristaEmcVolt = 0, }; diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/customize.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/customize.hpp index f9f417d8..f80f87cd 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/customize.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/customize.hpp @@ -16,29 +16,30 @@ #pragma once -#define CUST_REV 2 +#define CUST_REV 3 -#include "oc_suite_common.hpp" +#include "oc_common.hpp" namespace ams::ldr::oc { #include "mtc_timing_table.hpp" enum MtcConfig { - AUTO_ADJ_MARIKO_SAFE = 0, - AUTO_ADJ_MARIKO_4266 = 1, + AUTO_ADJ_MARIKO_SAFE_NO_ADJ_ERISTA = 0, + AUTO_ADJ_MARIKO_4266_NO_ADJ_ERISTA = 1, + NO_ADJ_ALL = 2, }; typedef struct __attribute__((packed)) CustomizeTable { u8 cust[4] = {'C', 'U', 'S', 'T'}; u16 custRev = CUST_REV; - u16 mtcConf = AUTO_ADJ_MARIKO_SAFE; + u16 mtcConf = AUTO_ADJ_MARIKO_SAFE_NO_ADJ_ERISTA; u32 marikoCpuMaxClock; u32 marikoCpuBoostClock; u32 marikoCpuMaxVolt; u32 marikoGpuMaxClock; u32 marikoEmcMaxClock; - u32 eristaCpuOCEnabled; + u32 marikoEmcVolt; u32 eristaCpuMaxVolt; u32 eristaEmcMaxClock; u32 eristaEmcVolt; diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/oc_suite_common.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/oc_common.hpp similarity index 93% rename from Source/Atmosphere/stratosphere/loader/source/oc/oc_suite_common.hpp rename to Source/Atmosphere/stratosphere/loader/source/oc/oc_common.hpp index bf14ed01..3982885b 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/oc_suite_common.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/oc_common.hpp @@ -22,7 +22,7 @@ #define LOGGING(fmt, ...) ((void)0) #define CRASH(msg, ...) { ams::diag::AbortImpl(msg, __PRETTY_FUNCTION__, "", 0); __builtin_unreachable(); } #else - #include "oc_suite_test.hpp" + #include "oc_test.hpp" #endif #include "customize.hpp" @@ -39,8 +39,9 @@ namespace ams::ldr { R_DEFINE_ERROR_RESULT(InvalidGpuDvfs, 1008); R_DEFINE_ERROR_RESULT(InvalidGpuFreqMaxPattern, 1009); R_DEFINE_ERROR_RESULT(InvalidGpuPllEntry, 1010); - R_DEFINE_ERROR_RESULT(UninitializedPatcher, 1011); - R_DEFINE_ERROR_RESULT(UnsuccessfulPatcher, 1012); + R_DEFINE_ERROR_RESULT(InvalidRegulatorEntry, 1011); + R_DEFINE_ERROR_RESULT(UninitializedPatcher, 1012); + R_DEFINE_ERROR_RESULT(UnsuccessfulPatcher, 1013); } namespace ams::ldr::oc { diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/oc_suite.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/oc_loader.hpp similarity index 95% rename from Source/Atmosphere/stratosphere/loader/source/oc/oc_suite.hpp rename to Source/Atmosphere/stratosphere/loader/source/oc/oc_loader.hpp index 97cb5188..e0445818 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/oc_suite.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/oc_loader.hpp @@ -16,6 +16,6 @@ #pragma once -#include "oc_suite_common.hpp" +#include "oc_common.hpp" #include "pcv/pcv.hpp" #include "ptm/ptm.hpp" diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/oc_suite_test.cpp b/Source/Atmosphere/stratosphere/loader/source/oc/oc_test.cpp similarity index 99% rename from Source/Atmosphere/stratosphere/loader/source/oc/oc_suite_test.cpp rename to Source/Atmosphere/stratosphere/loader/source/oc/oc_test.cpp index eb470090..61486d5f 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/oc_suite_test.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/oc_test.cpp @@ -15,8 +15,8 @@ */ #ifndef ATMOSPHERE_IS_STRATOSPHERE -#include "oc_suite_test.hpp" -#include "oc_suite.hpp" +#include "oc_test.hpp" +#include "oc_loader.hpp" void* loadExec(const char* file_loc, size_t* out_size) { FILE* fp = fopen(file_loc, "rb"); diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/oc_suite_test.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/oc_test.hpp similarity index 100% rename from Source/Atmosphere/stratosphere/loader/source/oc/oc_suite_test.hpp rename to Source/Atmosphere/stratosphere/loader/source/oc/oc_test.hpp diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.cpp b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.cpp index ce67ed13..19a6fa84 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.cpp @@ -33,7 +33,8 @@ void SafetyCheck() { if (C.custRev != CUST_REV || C.marikoCpuMaxVolt >= 1300 || C.eristaCpuMaxVolt >= 1300 || - (C.eristaEmcVolt && (C.eristaEmcVolt < 600'000 || C.eristaEmcVolt > 1250'000))) + (C.eristaEmcVolt && (C.eristaEmcVolt < 600'000 || C.eristaEmcVolt > 1250'000)) || + (C.marikoEmcVolt && (C.marikoEmcVolt < 600'000 || C.marikoEmcVolt > 650'000))) { CRASH("Triggered"); } diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.hpp index 00976a80..01143df4 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.hpp @@ -16,7 +16,7 @@ #pragma once -#include "../oc_suite_common.hpp" +#include "../oc_common.hpp" namespace ams::ldr::oc::pcv { @@ -88,6 +88,33 @@ typedef struct __attribute__((packed)) dvfs_rail { u32 unk_2[11]; } dvfs_rail; +typedef struct __attribute__((packed)) regulator { + u64 id; + const char* name; + u32 type; + union { + struct { + u32 volt_reg; + u32 step_uv; + u32 min_uv; + u32 default_uv; + u32 max_uv; + u32 unk_0[2]; + } type_1; + struct { + u32 unk_0; + u32 step_uv; + u32 unk_1; + u32 min_uv; + u32 max_uv; + u32 unk_2; + u32 default_uv; + } type_2_3; + }; + u32 unk_x[60]; +} regulator; +static_assert(sizeof(regulator) == 0x120); + constexpr u32 CpuClkOSLimit = 1785'000; constexpr u32 MemClkOSLimit = 1600'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 ea378233..acc68cf9 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_erista.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_erista.cpp @@ -27,11 +27,20 @@ Result CpuFreqCvbTable(u32* ptr) { bool validated = std::memcmp(cpu_cvb_table_head, CpuCvbTableDefault, sizeof(CpuCvbTableDefault)) == 0; R_UNLESS(validated, ldr::ResultInvalidCpuDvfs()); - if (!C.eristaCpuOCEnabled) - R_SKIP(); - std::memcpy(reinterpret_cast(new_start), CpuCvbTableAppend, sizeof(CpuCvbTableAppend)); + // Patch CPU max volt in existing and appended CPU dvfs table + if (C.eristaCpuMaxVolt) { + size_t table_size = sizeof(CpuCvbTableAppend) / sizeof(cpu_freq_cvb_table_t); + cpu_freq_cvb_table_t* entry = new_start; + for (size_t i = 0; i < table_size; i++) { + if (entry->cvb_dfll_param.c0 == CpuVoltL4T) { + PatchOffset(reinterpret_cast(&(entry->cvb_dfll_param.c0)), C.eristaCpuMaxVolt * 1000); + } + entry++; + } + } + R_SUCCEED(); } diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_erista.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_erista.hpp index f01fe4de..1bf329ae 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_erista.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_erista.hpp @@ -40,10 +40,12 @@ constexpr cpu_freq_cvb_table_t CpuCvbTableDefault[] = { { 1785000, { 1227500 }, { 5100873, -279186, 4747 } }, }; +constexpr u32 CpuVoltL4T = 1235'000; + constexpr cpu_freq_cvb_table_t CpuCvbTableAppend[] = { - { 1887000, { 1235000 }, { 5100873, -279186, 4747 } }, - { 1963500, { 1235000 }, { 5100873, -279186, 4747 } }, - { 2091000, { 1235000 }, { 5100873, -279186, 4747 } }, + { 1887000, { CpuVoltL4T }, { 5100873, -279186, 4747 } }, + { 1963500, { CpuVoltL4T }, { 5100873, -279186, 4747 } }, + { 2091000, { CpuVoltL4T }, { 5100873, -279186, 4747 } }, }; constexpr u32 CpuMinVolts[] = { 950, 850, 825, 810 }; 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 f03da3d8..97b9ec56 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.cpp @@ -149,6 +149,9 @@ void MemMtcTableAutoAdjust(MarikoMtcTable* table, const MarikoMtcTable* ref) { * you'd better calculate timings yourself rather than relying on following algorithm. */ + if (C.mtcConf == NO_ADJ_ALL) + return; + #define ADJUST_PROP(TARGET, REF) \ (u32)(std::ceil(REF + ((C.marikoEmcMaxClock-MemClkOSAlt)*(TARGET-REF))/(MemClkOSLimit-MemClkOSAlt))) @@ -186,7 +189,7 @@ void MemMtcTableAutoAdjust(MarikoMtcTable* table, const MarikoMtcTable* ref) { ADJUST_PARAM_TABLE(table, la_scale_regs.mc_ptsa_grant_decrement, ref); /* Timings that are available in or can be derived from LPDDR4X datasheet or TRM */ - const bool use_4266_spec = C.mtcConf == AUTO_ADJ_MARIKO_4266; + const bool use_4266_spec = C.mtcConf == AUTO_ADJ_MARIKO_4266_NO_ADJ_ERISTA; // tCK_avg (average clock period) in ns const double tCK_avg = 1000'000. / C.marikoEmcMaxClock; // tRPpb (row precharge time per bank) in ns @@ -368,6 +371,29 @@ Result MemFreqMax(u32* ptr) { R_SUCCEED(); } +Result MemVoltHandler(u32* ptr) { + u32 emc_uv = C.marikoEmcVolt; + if (!emc_uv) + R_SKIP(); + + regulator* entry = reinterpret_cast(reinterpret_cast(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()); + + 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 patches[] = { { "CPU Freq Vdd", &CpuFreqVdd, 1, nullptr, CpuClkOSLimit }, @@ -380,6 +406,7 @@ void Patch(uintptr_t mapped_nso, size_t nso_size) { { "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 } }; for (uintptr_t ptr = mapped_nso; diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.hpp index 032a71b9..46c23175 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.hpp @@ -115,13 +115,9 @@ constexpr emc_dvb_dvfs_table_t EmcDvbTableDefault[] = { { 1600000, { 675, 650, 637, } }, }; -constexpr emc_dvb_dvfs_table_t EmcDvbTableReplaced[] = { - { 1862400, { 675, 650, 637, } }, - { 2133000, { 700, 675, 650, } }, -}; - constexpr u32 MemClkOSAlt = 1331'200; constexpr u32 MemClkPllmLimit = 2133'000'000; +constexpr u32 MemVoltDefault = 600'000; constexpr u32 MTC_TABLE_REV = 3; diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/ptm/ptm.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/ptm/ptm.hpp index 38d6fb8d..72360e44 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/ptm/ptm.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/ptm/ptm.hpp @@ -16,7 +16,7 @@ #pragma once -#include "../oc_suite_common.hpp" +#include "../oc_common.hpp" namespace ams::ldr::oc::ptm { diff --git a/Source/loaderConfigurator/ldr_config.py b/Source/loaderConfigurator/ldr_config_old.py similarity index 100% rename from Source/loaderConfigurator/ldr_config.py rename to Source/loaderConfigurator/ldr_config_old.py diff --git a/Source/sys-clk-OC/common/include/cpp_util.hpp b/Source/sys-clk-OC/common/include/cpp_util.hpp new file mode 100644 index 00000000..34e5621f --- /dev/null +++ b/Source/sys-clk-OC/common/include/cpp_util.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include + +template +class ScopeGuard { +public: + ScopeGuard(F&& f) + : f(f), engaged(true) {}; + + ~ScopeGuard() { + if (engaged) + f(); + }; + + ScopeGuard(ScopeGuard&& rhs) + : f(std::move(rhs.f)) {}; + + void dismiss() { engaged = false; } + +private: + F f; + bool engaged; +}; + +struct MakeScopeExit { + template + ScopeGuard operator+=(F&& f) { + return ScopeGuard(std::move(f)); + }; +}; + +#define STRING_CAT2(x, y) x##y +#define STRING_CAT(x, y) STRING_CAT2(x, y) +#define SCOPE_GUARD MakeScopeExit() += [&]() __attribute__((always_inline)) +#define SCOPE_EXIT auto STRING_CAT(scope_exit_, __LINE__) = SCOPE_GUARD \ No newline at end of file diff --git a/Source/sys-clk-OC/common/include/sysclk.h b/Source/sys-clk-OC/common/include/sysclk.h index dfa7c6ec..d278083e 100644 --- a/Source/sys-clk-OC/common/include/sysclk.h +++ b/Source/sys-clk-OC/common/include/sysclk.h @@ -11,6 +11,7 @@ #pragma once #ifdef __cplusplus +#include "cpp_util.hpp" extern "C" { #endif diff --git a/Source/sys-clk-OC/common/include/sysclk/i2c.h b/Source/sys-clk-OC/common/include/sysclk/i2c.h index 8e6038f2..d5c2ea66 100644 --- a/Source/sys-clk-OC/common/include/sysclk/i2c.h +++ b/Source/sys-clk-OC/common/include/sysclk/i2c.h @@ -14,14 +14,34 @@ float I2c_Max17050_GetBatteryCurrent(); const u8 MAX17050_CURRENT_REG = 0x0A; -// Max77812 Mariko-specific buck converter -typedef enum I2c_Max77812_Volt_Type { +// Buck Converter +typedef enum I2c_BuckConverter_Reg { + I2c_Max77620_SD1VOLT_REG = 0x16, + I2c_Max77621_VOLT_REG = 0x00, I2c_Max77812_CPUVOLT_REG = 0x26, I2c_Max77812_GPUVOLT_REG = 0x23, - I2c_Max77812_MEMVOLT_REG = 0x25, -} I2c_Max77812_Volt_Type; + I2c_Max77812_MEMVOLT_REG = 0x25, // Master 3 (GPU 1 + 2, DRAM 3, CPU 4) +} I2c_BuckConverter_Reg; -u32 I2c_Max77812_GetMVOUT(I2c_Max77812_Volt_Type type); +typedef struct I2c_BuckConverter_Domain { + I2cDevice device; + I2c_BuckConverter_Reg reg; + u8 volt_mask; + u32 uv_step; + u32 uv_min; + u32 uv_max; + u8 por_val; +} I2c_BuckConverter_Domain; + +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, 0x7F, 12500, 600000, 1250000, }; +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 = { I2cDevice_Max77812_2, I2c_Max77812_MEMVOLT_REG, 0xFF, 5000, 250000, 650000, 0x78 }; + +u32 I2c_BuckConverter_GetMvOut(const I2c_BuckConverter_Domain* domain); +Result I2c_BuckConverter_SetMvOut(const I2c_BuckConverter_Domain* domain, u32 mvolt); // Bq24193 Battery management u32 I2c_Bq24193_Convert_Raw_mA(u8 raw); diff --git a/Source/sys-clk-OC/common/src/i2c.c b/Source/sys-clk-OC/common/src/i2c.c index cef2d94c..115c9e76 100644 --- a/Source/sys-clk-OC/common/src/i2c.c +++ b/Source/sys-clk-OC/common/src/i2c.c @@ -83,24 +83,58 @@ float I2c_Max17050_GetBatteryCurrent() { return (s16)val * (1.5625 / (SenseResistor * CGain)); } -u32 I2c_Max77812_GetMVOUT(I2c_Max77812_Volt_Type type) { - u8 reg = (u8)type; +u32 I2c_BuckConverter_MultiplierToMvOut(const I2c_BuckConverter_Domain* domain, u8 multiplier) { + return (domain->uv_min + domain->uv_step * multiplier) / 1000; +} - const u32 MIN_MV = 250; - const u32 MV_STEP = 5; - const u8 RESET_VAL = 0x78; +u8 I2c_BuckConverter_MvOutToMultiplier(const I2c_BuckConverter_Domain* domain, u32 mvolt) { + u32 uvolt = mvolt * 1000; + if (uvolt < domain->uv_min) + uvolt = domain->uv_min; + if (uvolt > domain->uv_max) + uvolt = domain->uv_max; - u8 val = RESET_VAL; - // Retry 3 times if received RESET_VAL + return (uvolt - domain->uv_min) / domain->uv_step; +} + +u32 I2c_BuckConverter_GetMvOut(const I2c_BuckConverter_Domain* domain) { + u8 val; + Result res; + // Retry 3 times if failed or received POR value for (int i = 0; i < 3; i++) { - if (I2cRead_OutU8(I2cDevice_Max77812_2, reg, &val)) - return 0u; - if (val != RESET_VAL) - break; - svcSleepThread(10); + res = I2cRead_OutU8(domain->device, domain->reg, &val); + if (R_FAILED(res) || (domain->por_val && val == domain->por_val)) { + svcSleepThread(1000); + continue; + } + return I2c_BuckConverter_MultiplierToMvOut(domain, val & domain->volt_mask); } + return 0u; +} - return val * MV_STEP + MIN_MV; +Result I2c_BuckConverter_SetMvOut(const I2c_BuckConverter_Domain* domain, u32 mvolt) { + u8 val; + Result res = I2cRead_OutU8(domain->device, domain->reg, &val); + if (R_FAILED(res)) + return res; + + u8 multiplier = I2c_BuckConverter_MvOutToMultiplier(domain, mvolt); + val &= ~domain->volt_mask; + val |= multiplier & domain->volt_mask; + + res = I2cSet_U8(domain->device, domain->reg, val); + if (R_FAILED(res)) + return res; + + svcSleepThread(1000); + u8 new_val; + res = I2cRead_OutU8(domain->device, domain->reg, &new_val); + if (R_FAILED(res)) + return res; + if (new_val != val) + return -1; + + return 0; } u8 I2c_Bq24193_Convert_mA_Raw(u32 ma) { diff --git a/Source/sys-clk-OC/overlay/src/ui/gui/misc_gui.cpp b/Source/sys-clk-OC/overlay/src/ui/gui/misc_gui.cpp index 3c71a5db..99a1512c 100644 --- a/Source/sys-clk-OC/overlay/src/ui/gui/misc_gui.cpp +++ b/Source/sys-clk-OC/overlay/src/ui/gui/misc_gui.cpp @@ -65,7 +65,6 @@ void MiscGui::listUI() addConfigToggle(SysClkConfigValue_AutoCPUBoost); } - addConfigToggle(SysClkConfigValue_AllowUnsafeFrequencies); addConfigToggle(SysClkConfigValue_SyncReverseNXMode); addConfigToggle(SysClkConfigValue_GovernorExperimental); @@ -86,7 +85,7 @@ void MiscGui::listUI() uint32_t current_ma = val * 100; this->configList->values[SysClkConfigValue_ChargingCurrentLimit] = current_ma; - snprintf(chargingCurrentBarDesc, sizeof(chargingCurrentBarDesc), "Battery Charging Current: %lu mA", this->configList->values[SysClkConfigValue_ChargingCurrentLimit]); + snprintf(chargingCurrentBarDesc, sizeof(chargingCurrentBarDesc), "Battery Charging Current: %lu mA (Now: %+.2f mA)", this->configList->values[SysClkConfigValue_ChargingCurrentLimit], this->i2cInfo->batCurrent); this->chargingCurrentHeader->setText(chargingCurrentBarDesc); Result rc = sysclkIpcSetConfigValues(this->configList); @@ -109,7 +108,7 @@ void MiscGui::listUI() } this->configList->values[SysClkConfigValue_ChargingLimitPercentage] = val; - snprintf(chargingLimitBarDesc, sizeof(chargingLimitBarDesc), "Battery Charging Limit: %lu%% (%u%%)", this->configList->values[SysClkConfigValue_ChargingLimitPercentage], this->batteryChargePerc); + snprintf(chargingLimitBarDesc, sizeof(chargingLimitBarDesc), "Battery Charging Limit: %lu%% (Now: %u%%)", this->configList->values[SysClkConfigValue_ChargingLimitPercentage], this->batteryChargePerc); this->chargingLimitHeader->setText(chargingLimitBarDesc); this->chargingLimitBar->setIcon(PsmGetBatteryStateIcon(this->chargeInfo)); @@ -144,13 +143,11 @@ void MiscGui::listUI() this->listElement->addItem(this->backlightToggle); // Info - if (this->isMariko) { - this->listElement->addItem(new tsl::elm::CategoryHeader("Info")); - this->listElement->addItem(new tsl::elm::CustomDrawer([this](tsl::gfx::Renderer *renderer, s32 x, s32 y, s32 w, s32 h) { - renderer->drawString(this->infoNames, false, x, y + 20, SMALL_TEXT_SIZE, DESC_COLOR); - renderer->drawString(this->infoVals, false, x + 120, y + 20, SMALL_TEXT_SIZE, VALUE_COLOR); - }), SMALL_TEXT_SIZE * 12 + 20); - } + this->listElement->addItem(new tsl::elm::CategoryHeader("Info")); + this->listElement->addItem(new tsl::elm::CustomDrawer([this](tsl::gfx::Renderer *renderer, s32 x, s32 y, s32 w, s32 h) { + renderer->drawString(this->infoNames, false, x, y + 20, SMALL_TEXT_SIZE, DESC_COLOR); + renderer->drawString(this->infoVals, false, x + 120, y + 20, SMALL_TEXT_SIZE, VALUE_COLOR); + }), SMALL_TEXT_SIZE * 12 + 20); } void MiscGui::refresh() { @@ -175,16 +172,14 @@ void MiscGui::refresh() { this->backlightToggle->setState(lblstatus); this->chargingCurrentBar->setProgress(this->configList->values[SysClkConfigValue_ChargingCurrentLimit] / 100); - snprintf(chargingCurrentBarDesc, sizeof(chargingCurrentBarDesc), "Battery Charging Current: %lu mA", this->configList->values[SysClkConfigValue_ChargingCurrentLimit]); + snprintf(chargingCurrentBarDesc, sizeof(chargingCurrentBarDesc), "Battery Charging Current: %lu mA (Now: %+.2f mA)", this->configList->values[SysClkConfigValue_ChargingCurrentLimit], this->i2cInfo->batCurrent); this->chargingCurrentHeader->setText(chargingCurrentBarDesc); this->chargingLimitBar->setProgress(this->configList->values[SysClkConfigValue_ChargingLimitPercentage]); - snprintf(chargingLimitBarDesc, sizeof(chargingLimitBarDesc), "Battery Charging Limit: %lu%% (%u%%)", this->configList->values[SysClkConfigValue_ChargingLimitPercentage], this->batteryChargePerc); + snprintf(chargingLimitBarDesc, sizeof(chargingLimitBarDesc), "Battery Charging Limit: %lu%% (Now: %u%%)", this->configList->values[SysClkConfigValue_ChargingLimitPercentage], this->batteryChargePerc); this->chargingLimitHeader->setText(chargingLimitBarDesc); - if (this->isMariko) { - I2cGetInfo(this->i2cInfo); - UpdateInfo(this->infoVals, sizeof(this->infoVals)); - } + I2cGetInfo(this->i2cInfo); + UpdateInfo(this->infoVals, sizeof(this->infoVals)); } } diff --git a/Source/sys-clk-OC/overlay/src/ui/gui/misc_gui.h b/Source/sys-clk-OC/overlay/src/ui/gui/misc_gui.h index c10a5346..8f106401 100644 --- a/Source/sys-clk-OC/overlay/src/ui/gui/misc_gui.h +++ b/Source/sys-clk-OC/overlay/src/ui/gui/misc_gui.h @@ -32,9 +32,9 @@ class MiscGui : public BaseMenuGui protected: typedef struct { float batCurrent; - u32 cpuVolt = 620; - u32 gpuVolt = 610; - u32 dramVolt = 600; + u32 cpuVolt; + u32 gpuVolt; + u32 dramVolt; } I2cInfo; void PsmUpdate(uint32_t dispatchId = 0) @@ -57,11 +57,12 @@ class MiscGui : public BaseMenuGui { i2cInitialize(); - i2cInfo->batCurrent = I2c_Max17050_GetBatteryCurrent(); + float batCurrent = I2c_Max17050_GetBatteryCurrent(); + i2cInfo->batCurrent = std::abs(batCurrent) < 10. ? 0. : batCurrent; - i2cInfo->cpuVolt = I2c_Max77812_GetMVOUT(I2c_Max77812_CPUVOLT_REG); - i2cInfo->gpuVolt = I2c_Max77812_GetMVOUT(I2c_Max77812_GPUVOLT_REG); - i2cInfo->dramVolt = I2c_Max77812_GetMVOUT(I2c_Max77812_MEMVOLT_REG); + i2cInfo->cpuVolt = I2c_BuckConverter_GetMvOut(isMariko ? &I2c_Mariko_CPU : &I2c_Erista_CPU); + i2cInfo->gpuVolt = I2c_BuckConverter_GetMvOut(isMariko ? &I2c_Mariko_GPU : &I2c_Erista_GPU); + i2cInfo->dramVolt = I2c_BuckConverter_GetMvOut(isMariko ? &I2c_Mariko_DRAM : &I2c_Erista_DRAM); I2c_Bq24193_GetFastChargeCurrentLimit(reinterpret_cast(&(chargeInfo->ChargeCurrentLimit))); @@ -78,16 +79,13 @@ class MiscGui : public BaseMenuGui if (chargeInfo->ChargeVoltageLimit) snprintf(chargeVoltLimit, sizeof(chargeVoltLimit), ", %umV", chargeInfo->ChargeVoltageLimit); - char chargWattsInfo[50] = ""; + char chargWattsInfo[30] = ""; if (chargeInfo->ChargerType) snprintf(chargWattsInfo, sizeof(chargWattsInfo), " %.1fV/%.1fA (%.1fW)", chargerVoltLimit, chargerCurrLimit, chargerOutWatts); char batCurInfo[30] = ""; - if (std::abs(i2cInfo->batCurrent) < 10) - snprintf(batCurInfo, sizeof(batCurInfo), "0mA"); - else - snprintf(batCurInfo, sizeof(batCurInfo), "%+.2fmA (%+.2fW)", - i2cInfo->batCurrent, i2cInfo->batCurrent * (float)chargeInfo->VoltageAvg / 1000'000); + snprintf(batCurInfo, sizeof(batCurInfo), "%+.2fmA (%+.2fW)", + i2cInfo->batCurrent, i2cInfo->batCurrent * (float)chargeInfo->VoltageAvg / 1000'000); snprintf(out, outsize, "%s%s\n" @@ -155,10 +153,21 @@ class MiscGui : public BaseMenuGui I2cInfo* i2cInfo; LblBacklightSwitchStatus lblstatus = LblBacklightSwitchStatus_Disabled; - const char* infoNames = "Charger:\nBattery:\nCurrent Limit:\nCharging Limit:\nRaw Charge:\nBattery Age:\nPower Role:\nCurrent Flow:\n\nCPU Volt:\nGPU Volt:\nDRAM Volt:"; + const char* infoNames = + "Charger:\n"\ + "Battery:\n"\ + "Current Limit:\n"\ + "Charging Limit:\n"\ + "Raw Charge:\n"\ + "Battery Age:\n"\ + "Power Role:\n"\ + "Current Flow:\n\n"\ + "CPU Volt:\n"\ + "GPU Volt:\n"\ + "DRAM Volt:"; char infoVals[300] = ""; - char chargingLimitBarDesc[40] = ""; - char chargingCurrentBarDesc[45] = ""; + char chargingLimitBarDesc[50] = ""; + char chargingCurrentBarDesc[60] = ""; u32 batteryChargePerc = 0; u8 frameCounter = 60; }; diff --git a/Source/sys-clk-OC/sysmodule/src/file_utils.cpp b/Source/sys-clk-OC/sysmodule/src/file_utils.cpp index 95338f23..7351cb11 100644 --- a/Source/sys-clk-OC/sysmodule/src/file_utils.cpp +++ b/Source/sys-clk-OC/sysmodule/src/file_utils.cpp @@ -185,11 +185,14 @@ void FileUtils::Exit() void FileUtils::ParseLoaderKip() { const char* dirs[] = { "/", "/atmosphere/", "/atmosphere/kips/", "/bootloader/" }; char* full_path = new char[0x200]; + SCOPE_EXIT { delete[] full_path; }; + for (auto const& dir : dirs) { struct dirent *entry = NULL; DIR *dp = opendir(dir); if (!dp) continue; + SCOPE_EXIT { closedir(dp); }; while ((entry = readdir(dp))) { if (entry->d_type != DT_REG) @@ -219,18 +222,15 @@ void FileUtils::ParseLoaderKip() { continue; if (R_SUCCEEDED(CustParser(full_path, filesize))) { - LogLine("Parsed cust config from %s, maxMemFreq: %u MHz, boostCpuFreq: %u MHz", + LogLine("Parsed cust config from \"%s\", maxMemFreq: %u MHz, boostCpuFreq: %u MHz", full_path, Clocks::maxMemFreq / 1'000'000, Clocks::boostCpuFreq / 1'000'000 ); - delete[] full_path; return; } } - closedir(dp); } - delete[] full_path; } Result FileUtils::CustParser(const char* filepath, size_t filesize) { @@ -245,17 +245,17 @@ Result FileUtils::CustParser(const char* filepath, size_t filesize) { FILE* fp = fopen(filepath, "r"); if (!fp) return ParseError_OpenReadFailed; + SCOPE_EXIT { fclose(fp); }; constexpr uint8_t KIP_MAGIC[] = {'K', 'I', 'P', '1', 'L', 'o', 'a', 'd', 'e', 'r'}; constexpr size_t BLOCK_SIZE = 0x1000; char* tmp_block = new char[BLOCK_SIZE]; + SCOPE_EXIT { delete[] tmp_block; }; fread(tmp_block, sizeof(char), BLOCK_SIZE, fp); - if (memcmp(KIP_MAGIC, tmp_block, sizeof(KIP_MAGIC))) { - delete[] tmp_block; + if (memcmp(KIP_MAGIC, tmp_block, sizeof(KIP_MAGIC))) return ParseError_WrongKipMagic; - } CustTable table {}; @@ -274,23 +274,15 @@ Result FileUtils::CustParser(const char* filepath, size_t filesize) { } found: - delete[] tmp_block; - - if (!cust_pos) { - fclose(fp); + if (!cust_pos) return ParseError_CustNotFound; - } memset(reinterpret_cast(&table), 0, sizeof(CustTable)); fsetpos(fp, &cust_pos); - if (!fread(reinterpret_cast(&table), 1, sizeof(CustTable), fp)) { - fclose(fp); + if (!fread(reinterpret_cast(&table), 1, sizeof(CustTable), fp)) return ParseError_OpenReadFailed; - } - fclose(fp); - - if (table.custRev != 2) + if (table.custRev != CUST_REV) return ParseError_WrongCustRev; if (Clocks::GetIsMariko()) { @@ -298,6 +290,11 @@ Result FileUtils::CustParser(const char* filepath, size_t filesize) { Clocks::boostCpuFreq = table.marikoCpuBoostClock * 1000; if (table.marikoEmcMaxClock) Clocks::maxMemFreq = table.marikoEmcMaxClock * 1000; + if (table.marikoEmcVolt && table.marikoEmcVolt >= 600'000 && table.marikoEmcVolt <= 650'000) { + u32 mvolt = table.marikoEmcVolt / 1000; + Result res = I2c_BuckConverter_SetMvOut(&I2c_Mariko_DRAM, mvolt); + LogLine("Set EMC volt to %u mV: %s", mvolt, R_FAILED(res) ? "Failed" : "OK"); + } } else { if (table.eristaEmcMaxClock) Clocks::maxMemFreq = table.eristaEmcMaxClock * 1000; @@ -335,6 +332,7 @@ Result FileUtils::mkdir_p(const char* dirpath) { size_t path_len = strnlen(dirpath, 0x1000); char* path_copy = new char[path_len]; + SCOPE_EXIT { delete[] path_copy; }; memcpy(path_copy, dirpath, path_len); char* p = path_copy; while (*p) { @@ -344,7 +342,7 @@ Result FileUtils::mkdir_p(const char* dirpath) { if (R_FAILED(mkdir_wrapper(path_copy))) { res = -1; - goto end; + return res; } *p = '/'; @@ -355,7 +353,5 @@ Result FileUtils::mkdir_p(const char* dirpath) { if (R_FAILED(mkdir_wrapper(path_copy))) res = -1; - end: - delete[] path_copy; return res; } diff --git a/Source/sys-clk-OC/sysmodule/src/file_utils.h b/Source/sys-clk-OC/sysmodule/src/file_utils.h index b2ec0c00..1e76832a 100644 --- a/Source/sys-clk-OC/sysmodule/src/file_utils.h +++ b/Source/sys-clk-OC/sysmodule/src/file_utils.h @@ -38,6 +38,7 @@ class FileUtils static void ParseLoaderKip(); static Result mkdir_p(const char* dirpath); protected: + static const uint16_t CUST_REV = 3; typedef struct CustTable { uint8_t cust[4] = {'C', 'U', 'S', 'T'}; uint16_t custRev; @@ -47,7 +48,7 @@ class FileUtils uint32_t marikoCpuMaxVolt; uint32_t marikoGpuMaxClock; uint32_t marikoEmcMaxClock; - uint32_t eristaCpuOCEnable; + uint32_t marikoEmcVolt; uint32_t eristaCpuMaxVolt; uint32_t eristaEmcMaxClock; uint32_t eristaEmcVolt;