From 6a851d40958e7a8535d040dc480cb592a91a421e Mon Sep 17 00:00:00 2001 From: Lightos1 <124387232+Lightos1@users.noreply.github.com> Date: Sat, 18 Apr 2026 23:00:21 +0200 Subject: [PATCH] nso start check, timing tbreak and some horrendous ui code --- .../loader/source/oc/customize.cpp | 7 ++ .../loader/source/oc/customize.hpp | 4 + .../source/oc/mariko/calculate_timings.cpp | 15 ++-- .../loader/source/oc/pcv/pcv_mariko.cpp | 25 +++++-- Source/hoc-clk/common/include/hocclk/config.h | 14 ++++ .../hoc-clk/overlay/src/ui/gui/misc_gui.cpp | 75 ++++++++++++++++++- Source/hoc-clk/sysmodule/src/kip.cpp | 7 ++ Source/hoc-clk/sysmodule/src/kip.hpp | 10 +++ 8 files changed, 143 insertions(+), 14 deletions(-) diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/customize.cpp b/Source/Atmosphere/stratosphere/loader/source/oc/customize.cpp index 24f39eac..121c5d8b 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/customize.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/customize.cpp @@ -59,8 +59,15 @@ volatile CustomizeTable C = { .t7_tWTR = 0, .t8_tREFI = 0, +/* At 1333WL, for some reason (incorrect ram timing config in mtc table?), tRP causes crashes at high reductions - 2 seems to be the most common limit. */ +/* This is a lazy workaround until I find the issue... */ .t2_tRP_cap = 2, +/* Frequency where non low timings gets used. */ +.timingEmcTbreak = DISABLED, +.low_t6_tRTW = DISABLED, +.low_t7_tWTR = DISABLED, + .readLatency = { 2133000, 2400000, diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/customize.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/customize.hpp index 19d6673d..e3e23bd7 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/customize.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/customize.hpp @@ -105,6 +105,10 @@ typedef struct CustomizeTable { u32 t2_tRP_cap; + u32 timingEmcTbreak; + u32 low_t6_tRTW; + u32 low_t7_tWTR; + u32 readLatency[4]; u32 writeLatency[4]; diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/mariko/calculate_timings.cpp b/Source/Atmosphere/stratosphere/loader/source/oc/mariko/calculate_timings.cpp index 2c6ee633..c88412d7 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/mariko/calculate_timings.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/mariko/calculate_timings.cpp @@ -146,14 +146,17 @@ namespace ams::ldr::hoc::pcv::mariko { tRAS = tRAS_values[C.t3_tRAS]; tRRD = tRRD_values[C.t4_tRRD]; tRFCpb = tRFC_values[C.t5_tRFC]; - u32 tWTR = 10 - tWTR_values[C.t7_tWTR]; + u32 tRTW = C.t6_tRTW; + u32 tWTR = 10 - tWTR_values[C.t7_tWTR]; + + if (freq < C.timingEmcTbreak) { + tRTW = C.low_t6_tRTW; + tWTR = 10 - tWTR_values[C.low_t7_tWTR]; + } + s32 finetRTW = C.fineTune_t6_tRTW; s32 finetWTR = C.fineTune_t7_tWTR; - Log("Freq: %u\n", freq); - Log("WL: %u\n", WL); - Log("tRP value: %u\n\n", tRPpb); - tRC = tRAS + tRPpb; tRFCab = tRFCpb * 2; tXSR = static_cast(tRFCab + 7.5); @@ -161,7 +164,7 @@ namespace ams::ldr::hoc::pcv::mariko { tRPab = tRPpb + 3; tR2P = CEIL((RL * 0.426) - 2.0); - tR2W = FLOOR(FLOOR((5.0 / tCK_avg) + ((FLOOR(48.0 / WL) - 0.478) * 3.0)) / 1.501) + RL - (C.t6_tRTW * 3) + finetRTW; + tR2W = FLOOR(FLOOR((5.0 / tCK_avg) + ((FLOOR(48.0 / WL) - 0.478) * 3.0)) / 1.501) + RL - (tRTW * 3) + finetRTW; tRTM = FLOOR((10.0 + RL) + (3.502 / tCK_avg)) + FLOOR(7.489 / tCK_avg); tRATM = CEIL((tRTM - 10.0) + (RL * 0.426)); 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 fbb60197..3e0b04b1 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.cpp @@ -591,7 +591,11 @@ namespace ams::ldr::hoc::pcv::mariko { } } - std::vector newEmcList; + namespace { + std::vector newEmcList; + u32 *nsoStart; + } + void MtcGenerateJedecTable() { const u32 jedecFreqs[] = { 1866000, 1996000, 2133000, 2400000, 2666000, 2933000, 3200000 }; constexpr u32 JedecFreqCount = std::size(jedecFreqs); @@ -718,6 +722,7 @@ namespace ams::ldr::hoc::pcv::mariko { static const DramId dramId = [] { DramId id = GetDramId(); + id = IOWA_4GB_SAMSUNG_K4U6E3S4AA_MGCL; return id; }(); @@ -877,29 +882,37 @@ namespace ams::ldr::hoc::pcv::mariko { } Result MemMtcTableAsm(u32 *ptr) { - u32 adrp = *(ptr - 1); + constexpr u32 AddpOffset = 1; + constexpr u32 BrOffset = 12; + constexpr u32 MovOffset = 10; + + /* Ensure we don't dereference memory before nso start. */ + R_UNLESS(ptr - BrOffset >= nsoStart, ldr::ResultInvalidMtcTable()); + + u32 adrp = *(ptr - AddpOffset); R_UNLESS(AsmCompareAdrpNoImm(adrp, MtcAdrpAsm), ldr::ResultInvalidMtcTable()); /* We don't check for matching register because both registers must be x0 in order to pass the previous checks. */ /* The correct instructions will always be x0 since the mtcTable pointer is returned. */ /* Pray this does not break. */ - u32 br = *(ptr - 12); + u32 br = *(ptr - BrOffset); R_UNLESS(AsmCompareBrNoRd(br, MtcBrAsm), ldr::ResultInvalidMtcTable()); /* Pray this does not break either. */ - u32 mov = *(ptr - 10); + u32 mov = *(ptr - MovOffset); R_UNLESS(asm_compare_no_rd(mov, MtcMovAsm), ldr::ResultInvalidMtcTable()); u8 movRd = asm_get_rd(mov); u32 movCountPatch = asm_set_rd(asm_set_imm16(MtcMovAsm, newEmcList.size()), movRd); - PATCH_OFFSET(ptr - 12, NopIns); - PATCH_OFFSET(ptr - 10, movCountPatch); + PATCH_OFFSET(ptr - BrOffset, NopIns); + PATCH_OFFSET(ptr - MovOffset, movCountPatch); R_SUCCEED(); } void Patch(uintptr_t mapped_nso, size_t nso_size) { + nsoStart = reinterpret_cast(mapped_nso); MtcGenerateFreqTables(); u32 CpuCvbDefaultMaxFreq = static_cast(GetDvfsTableLastEntry(CpuCvbTableDefault)->freq); u32 GpuCvbDefaultMaxFreq = static_cast(GetDvfsTableLastEntry(GpuCvbTableDefault)->freq); diff --git a/Source/hoc-clk/common/include/hocclk/config.h b/Source/hoc-clk/common/include/hocclk/config.h index 0ccbf01d..825caf5d 100644 --- a/Source/hoc-clk/common/include/hocclk/config.h +++ b/Source/hoc-clk/common/include/hocclk/config.h @@ -94,6 +94,10 @@ typedef enum { KipConfigValue_t7_tWTR, KipConfigValue_t8_tREFI, + KipConfigValue_timingEmcTbreak, + KipConfigValue_low_t6_tRTW, + KipConfigValue_low_t7_tWTR, + KipConfigValue_t2_tRP_cap, KipConfigValue_read_latency_1333, @@ -325,6 +329,13 @@ static inline const char* hocclkFormatConfigValue(HocClkConfigValue val, bool pr case KipConfigValue_t8_tREFI: return pretty ? "t8 - tREFI" : "t8_trefi"; + case KipConfigValue_timingEmcTbreak: + return pretty ? "Timing Emc Tbreak" : "timingEmcTbreak"; + case KipConfigValue_low_t6_tRTW: + return pretty ? "Low T6 - tRTW" : "low_t6_tRTW"; + case KipConfigValue_low_t7_tWTR: + return pretty ? "Low T7 - tWTR" : "low_t7_tWTR"; + case KipConfigValue_t2_tRP_cap: return pretty ? "t2 - trp 1333WL Cap" : "t2_tRP_cap"; @@ -563,6 +574,9 @@ static inline uint64_t hocclkValidConfigValue(HocClkConfigValue val, uint64_t in case KipConfigValue_t6_tRTW: case KipConfigValue_t7_tWTR: case KipConfigValue_t8_tREFI: + case KipConfigValue_timingEmcTbreak: + case KipConfigValue_low_t6_tRTW: + case KipConfigValue_low_t7_tWTR: case KipConfigValue_t2_tRP_cap: case KipConfigValue_read_latency_1333: case KipConfigValue_read_latency_1600: diff --git a/Source/hoc-clk/overlay/src/ui/gui/misc_gui.cpp b/Source/hoc-clk/overlay/src/ui/gui/misc_gui.cpp index 2d7cd270..086ababb 100644 --- a/Source/hoc-clk/overlay/src/ui/gui/misc_gui.cpp +++ b/Source/hoc-clk/overlay/src/ui/gui/misc_gui.cpp @@ -897,6 +897,7 @@ protected: freqSubmenu->setValue(R_ARROW); this->listElement->addItem(freqSubmenu); } else { + RamDisplayUnit unit = (RamDisplayUnit)this->configList->values[HocClkConfigValue_RamDisplayUnit]; std::vector marikoMaxEmcClock = { NamedValue("1600 MHz", 1600000), NamedValue("1633 MHz", 1633000), @@ -958,8 +959,6 @@ protected: // NamedValue("3466MHz (Needs ridiculous Speedo/PLL)", 3466000), // NamedValue("3500MHz (Needs ridiculous Speedo/PLL)", 3500000), }; - - RamDisplayUnit unit = (RamDisplayUnit)this->configList->values[HocClkConfigValue_RamDisplayUnit]; for (auto& nv : marikoMaxEmcClock) nv.name = formatMemClockKhzLabel(nv.value, unit); @@ -1031,7 +1030,79 @@ protected: NamedValue("+3", 3), }; + /* Yes this is duplicated code, yes I don't care. */ + std::vector timingTbreakFreqs = { + NamedValue("Disabled", 0), + NamedValue("1633 MHz", 1633000), + NamedValue("1666 MHz", 1666000), + NamedValue("1700 MHz", 1700000), + NamedValue("1733 MHz", 1733000), + NamedValue("1766 MHz", 1766000), + NamedValue("1800 MHz", 1800000), + NamedValue("1833 MHz", 1833000), + NamedValue("1866 MHz", 1866000, "JEDEC."), + NamedValue("1900 MHz", 1900000), + NamedValue("1933 MHz", 1933000), + NamedValue("1966 MHz", 1966000), + NamedValue("1996 MHz", 1996800, "JEDEC."), + NamedValue("2000 MHz", 2000000), + NamedValue("2033 MHz", 2033000), + NamedValue("2066 MHz", 2066000), + NamedValue("2100 MHz", 2100000), + NamedValue("2133 MHz", 2133000, "JEDEC."), + NamedValue("2166 MHz", 2166000), + NamedValue("2200 MHz", 2200000), + NamedValue("2233 MHz", 2233000), + NamedValue("2266 MHz", 2266000), + NamedValue("2300 MHz", 2300000), + NamedValue("2333 MHz", 2333000), + NamedValue("2366 MHz", 2366000), + NamedValue("2400 MHz", 2400000, "JEDEC."), + NamedValue("2433 MHz", 2433000), + NamedValue("2466 MHz", 2466000), + NamedValue("2500 MHz", 2500000), + NamedValue("2533 MHz", 2533000), + NamedValue("2566 MHz", 2566000), + NamedValue("2600 MHz", 2600000), + NamedValue("2633 MHz", 2633000), + NamedValue("2666 MHz", 2666000, "JEDEC."), + NamedValue("2700 MHz", 2700000), + NamedValue("2733 MHz", 2733000), + NamedValue("2766 MHz", 2766000), + NamedValue("2800 MHz", 2800000), + NamedValue("2833 MHz", 2833000), + NamedValue("2866 MHz", 2866000), + NamedValue("2900 MHz", 2900000), + NamedValue("2933 MHz", 2933000, "JEDEC."), + NamedValue("2966 MHz", 2966000), + NamedValue("3000 MHz", 3000000), + NamedValue("3033 MHz", 3033000), + NamedValue("3066 MHz", 3066000), + NamedValue("3100 MHz", 3100000), + NamedValue("3133 MHz", 3133000), + NamedValue("3166 MHz", 3166000), + NamedValue("3200 MHz", 3200000, "JEDEC."), + NamedValue("3233 MHz", 3233000, "High speedo needed"), + NamedValue("3266 MHz", 3266000, "High speedo needed!"), + NamedValue("3300 MHz", 3300000, "High speedo needed!"), + // NamedValue("3333MHz (Needs extreme Speedo/PLL)", 3333000), + // NamedValue("3366MHz (Needs extreme Speedo/PLL)", 3366000), + // NamedValue("3400MHz (Needs extreme Speedo/PLL)", 3400000), + // NamedValue("3433MHz (Needs ridiculous Speedo/PLL)", 3433000), + // NamedValue("3466MHz (Needs ridiculous Speedo/PLL)", 3466000), + // NamedValue("3500MHz (Needs ridiculous Speedo/PLL)", 3500000), + }; + RamDisplayUnit unit = (RamDisplayUnit)this->configList->values[HocClkConfigValue_RamDisplayUnit]; + + for (size_t i = 1; i < timingTbreakFreqs.size(); ++i) { + auto &nv = timingTbreakFreqs[i]; + nv.name = formatMemClockKhzLabel(nv.value, unit); + } + this->listElement->addItem(new tsl::elm::CategoryHeader("Advanced")); + addConfigButton(KipConfigValue_timingEmcTbreak, "RAM-Timing tBreak", ValueRange(0, 1, 1, "", 1), "tBreak", &thresholdsDisabled, {}, timingTbreakFreqs, false, true); + addConfigButton(KipConfigValue_low_t6_tRTW, "Low t6 tRTW", ValueRange(0, 10, 1, "", 1), "low tRTW", &thresholdsDisabled, {}, {}, false, true ); + addConfigButton(KipConfigValue_low_t7_tWTR, "Low t7 tWTR", ValueRange(0, 10, 1, "", 1), "low tWTR", &thresholdsDisabled, {}, {}, false, true ); addConfigButton(KipConfigValue_t2_tRP_cap, "1333WL t2 RP Cap", ValueRange(0, 8, 1, "", 1), "tRP Cap", &thresholdsDisabled, {}, {}, false, true ); addConfigButton(KipConfigValue_t6_tRTW_fine_tune, "t6 tRTW Fine Tune", ValueRange(0, 4, 1, "", 0), "tRTW Fine Tune", &thresholdsDisabled, {}, t6_tRTW_fine_tune, false, true); addConfigButton(KipConfigValue_t7_tWTR_fine_tune, "t7 tWTR Fine Tune", ValueRange(0, 6, 1, "", 0), "tWTR Fine Tune", &thresholdsDisabled, {}, t7_tWTR_fine_tune, false, true); diff --git a/Source/hoc-clk/sysmodule/src/kip.cpp b/Source/hoc-clk/sysmodule/src/kip.cpp index 6f670241..5b5b3213 100644 --- a/Source/hoc-clk/sysmodule/src/kip.cpp +++ b/Source/hoc-clk/sysmodule/src/kip.cpp @@ -71,6 +71,10 @@ namespace kip { CUST_WRITE_FIELD_BATCH(&table, t7_tWTR, config::GetConfigValue(KipConfigValue_t7_tWTR)); CUST_WRITE_FIELD_BATCH(&table, t8_tREFI, config::GetConfigValue(KipConfigValue_t8_tREFI)); CUST_WRITE_FIELD_BATCH(&table, stepMode, config::GetConfigValue(KipConfigValue_stepMode)); + + CUST_WRITE_FIELD_BATCH(&table, timingEmcTbreak, config::GetConfigValue(KipConfigValue_timingEmcTbreak)); + CUST_WRITE_FIELD_BATCH(&table, low_t6_tRTW, config::GetConfigValue(KipConfigValue_low_t6_tRTW)); + CUST_WRITE_FIELD_BATCH(&table, low_t7_tWTR, config::GetConfigValue(KipConfigValue_low_t7_tWTR)); CUST_WRITE_FIELD_BATCH(&table, t2_tRP_cap, config::GetConfigValue(KipConfigValue_t2_tRP_cap)); CUST_WRITE_FIELD_BATCH(&table, readLatency1333, config::GetConfigValue(KipConfigValue_read_latency_1333)); @@ -202,6 +206,9 @@ namespace kip { configValues.values[KipConfigValue_t8_tREFI] = cust_get_tREFI(&table); configValues.values[KipConfigValue_stepMode] = cust_get_step_mode(&table); + configValues.values[KipConfigValue_timingEmcTbreak] = cust_get_timing_emc_tbreak(&table); + configValues.values[KipConfigValue_low_t6_tRTW] = cust_get_low_t6_tRTW(&table); + configValues.values[KipConfigValue_low_t7_tWTR] = cust_get_low_t7_tWTR(&table); configValues.values[KipConfigValue_t2_tRP_cap] = cust_get_tRP_cap(&table); configValues.values[KipConfigValue_read_latency_1333] = cust_get_read_latency_1333(&table); diff --git a/Source/hoc-clk/sysmodule/src/kip.hpp b/Source/hoc-clk/sysmodule/src/kip.hpp index 460775a1..8a57f2a2 100644 --- a/Source/hoc-clk/sysmodule/src/kip.hpp +++ b/Source/hoc-clk/sysmodule/src/kip.hpp @@ -56,6 +56,10 @@ namespace kip { u32 t2_tRP_cap; + u32 timingEmcTbreak; + u32 low_t6_tRTW; + u32 low_t7_tWTR; + /* These latencies are arrays in loader, but it's easier to handle it this way in the configurator. */ u32 readLatency1333, readLatency1600, readLatency1866, readLatency2133; u32 writeLatency1333, writeLatency1600, writeLatency1866, writeLatency2133; @@ -222,6 +226,9 @@ namespace kip { static inline bool cust_set_tWTR(const char* p, u32 v) { CUST_WRITE_FIELD(p, t7_tWTR, v); } static inline bool cust_set_tREFI(const char* p, u32 v) { CUST_WRITE_FIELD(p, t8_tREFI, v); } static inline bool cust_set_tRP_cap(const char* p, u32 v) { CUST_WRITE_FIELD(p, t2_tRP_cap, v); } + static inline bool cust_set_timing_emc_tbreak(const char* p, u32 v) { CUST_WRITE_FIELD(p, timingEmcTbreak, v); } + static inline bool cust_set_low_tRTW(const char* p, u32 v) { CUST_WRITE_FIELD(p, low_t6_tRTW, v); } + static inline bool cust_set_low_tWTR(const char* p, u32 v) { CUST_WRITE_FIELD(p, low_t7_tWTR, v); } static inline bool cust_set_tRTW_fine_tune(const char* p, u32 v) { CUST_WRITE_FIELD(p, t6_tRTW_fine_tune, v); } static inline bool cust_set_tWTR_fine_tune(const char* p, u32 v) { CUST_WRITE_FIELD(p, t7_tWTR_fine_tune, v); } @@ -306,6 +313,9 @@ namespace kip { static inline u32 cust_get_tWTR(const CustomizeTable* t) { return CUST_GET_FIELD(t, t7_tWTR); } static inline u32 cust_get_tREFI(const CustomizeTable* t) { return CUST_GET_FIELD(t, t8_tREFI); } static inline u32 cust_get_tRP_cap(const CustomizeTable* t) { return CUST_GET_FIELD(t, t2_tRP_cap); } + static inline u32 cust_get_timing_emc_tbreak(const CustomizeTable* t) { return CUST_GET_FIELD(t, timingEmcTbreak); } + static inline u32 cust_get_low_t6_tRTW(const CustomizeTable* t) { return CUST_GET_FIELD(t, low_t6_tRTW); } + static inline u32 cust_get_low_t7_tWTR(const CustomizeTable* t) { return CUST_GET_FIELD(t, low_t7_tWTR); } static inline u32 cust_get_tRTW_fine_tune(const CustomizeTable* t) { return CUST_GET_FIELD(t, t6_tRTW_fine_tune); } static inline u32 cust_get_tWTR_fine_tune(const CustomizeTable* t) { return CUST_GET_FIELD(t, t7_tWTR_fine_tune); }