diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/customize.cpp b/Source/Atmosphere/stratosphere/loader/source/oc/customize.cpp index 1be77755..c46201a0 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/customize.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/customize.cpp @@ -31,6 +31,7 @@ namespace ams::ldr::hoc { volatile CustomizeTable C = { + /* Disables RAM powerdown */ .hpMode = DISABLED, @@ -39,8 +40,12 @@ volatile CustomizeTable C = { .eristaEmcMaxClock1 = 1600000, .eristaEmcMaxClock2 = 1600000, +/* Available: 66MHz step rate, 100MHz step rate and jedec. */ +/* Jedec freqs are 1333MHz, 1600MHz, 1866MHz, 2133MHz, 2400MHz, 2666MHz, 2933MHz, 3200MHz. */ +.stepMode = StepMode_66MHz, + .marikoEmcMaxClock = 1866000, /* 1866MHz @ 1866tWRL is guaranteed to work on all Mariko units */ -.marikoEmcVddqVolt = 600000, /* Micron: 600mV, other manafacturers: 640mV */ +.marikoEmcVddqVolt = 600000, .emcDvbShift = 0, // Primary @@ -54,6 +59,29 @@ 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 = { + DISABLED, + DISABLED, + DISABLED, + DISABLED, +}, + +.writeLatency = { + DISABLED, + DISABLED, + DISABLED, + DISABLED, +}, + /* You can mix and match different latencies if needed */ /* * Read: @@ -74,7 +102,7 @@ volatile CustomizeTable C = { .eristaCpuUV = 0, .eristaCpuVmin = 800, .eristaCpuMaxVolt = 1200, -/* Unlocks up to 2295 Mhz CPU, usage is not recommended. */ +/* Unlocks up to 2397 Mhz CPU, usage is not recommended. */ .eristaCpuUnlock = DISABLED, .marikoCpuUVLow = 0, // No undervolt diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/customize.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/customize.hpp index fbbd51d4..e3e23bd7 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/customize.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/customize.hpp @@ -36,6 +36,12 @@ enum TableConfig: u32 { EXTREME_TABLE = 4, }; +enum StepMode:u32 { + StepMode_66MHz = 0, + StepMode_100MHz = 1, + StepMode_Jedec = 2, +}; + /* * Read: * 2133RL = 40 @@ -82,6 +88,8 @@ typedef struct CustomizeTable { u32 eristaEmcMaxClock; u32 eristaEmcMaxClock1; u32 eristaEmcMaxClock2; + + StepMode stepMode; u32 marikoEmcMaxClock; u32 marikoEmcVddqVolt; u32 emcDvbShift; @@ -95,6 +103,15 @@ typedef struct CustomizeTable { u32 t7_tWTR; u32 t8_tREFI; + u32 t2_tRP_cap; + + u32 timingEmcTbreak; + u32 low_t6_tRTW; + u32 low_t7_tWTR; + + u32 readLatency[4]; + u32 writeLatency[4]; + u32 mem_burst_read_latency; u32 mem_burst_write_latency; diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/erista/calculate_timings_erista.cpp b/Source/Atmosphere/stratosphere/loader/source/oc/erista/calculate_timings_erista.cpp index 721c1a92..ad482924 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/erista/calculate_timings_erista.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/erista/calculate_timings_erista.cpp @@ -14,7 +14,7 @@ * along with this program. If not, see . */ -#include "../oc_common.hpp" +#include #include "../mtc_timing_value.hpp" namespace ams::ldr::hoc::pcv::erista { 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 78f8e1f3..c88412d7 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/mariko/calculate_timings.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/mariko/calculate_timings.cpp @@ -14,7 +14,7 @@ * along with this program. If not, see . */ -#include "../oc_common.hpp" +#include #include "../mtc_timing_value.hpp" #include "timing_tables.hpp" @@ -30,6 +30,73 @@ namespace ams::ldr::hoc::pcv::mariko { rext = 0x1A; } + void SwitchLatency(volatile u32 &latency, u32 index, u32 latencyStep) { + latency += index * latencyStep; + } + + static u32 GetMaxLatencyIndex(volatile u32 *latencyArray, u32 latencySize) { + u32 maxIndex = 0; + for (u32 i = 0; i < latencySize; ++i) { + if (latencyArray[i]) { + maxIndex = i; + } + } + + return maxIndex; + } + + void AutoLatency(volatile u32 &latency, u32 freq, u32 latencyStep) { + if (freq >= 1866'000 && freq < 2133000) { + latency += latencyStep * 2; + } else if (freq >= 2133'000) { + latency += latencyStep * 3; + } else { + latency += latencyStep; + } + /* 1333 latency is not possible with this config. */ + } + + void HandleLatency(u32 freq, volatile u32 &latency, volatile u32 *latencyArray, u32 indexMax, u32 latencyStep) { + for (u32 i = 0; i <= indexMax; ++i) { + if (latencyArray[i] != 0 && freq <= latencyArray[i]) { + SwitchLatency(latency, i, latencyStep); + return; + } + } + + SwitchLatency(latency, indexMax, latencyStep); + } + + void HandleLatency(u32 freq) { + static u32 rlIndexMax = GetMaxLatencyIndex(C.readLatency, std::size(C.readLatency)); + static u32 wlIndexMax = GetMaxLatencyIndex(C.writeLatency, std::size(C.writeLatency)); + constexpr u32 ReadLatencyStep = 4; + constexpr u32 WriteLatencyStep = 2; + bool autoLatencyRead = false, autoLatencyWrite = false; + + if (rlIndexMax == 0) { + AutoLatency(RL, freq, ReadLatencyStep); + autoLatencyRead = true; + } + + if (wlIndexMax == 0) { + AutoLatency(WL, freq, WriteLatencyStep); + autoLatencyWrite = true; + } + + if (autoLatencyRead && autoLatencyWrite) { + return; + } + + if (!autoLatencyRead) { + HandleLatency(freq, RL, C.readLatency, rlIndexMax, ReadLatencyStep); + } + + if (!autoLatencyWrite) { + HandleLatency(freq, WL, C.writeLatency, wlIndexMax, WriteLatencyStep); + } + } + void CalculateMrw2() { static const u8 rlMapDBI[8] = { 6, 12, 16, 22, 28, 32, 36, 40 @@ -59,8 +126,80 @@ namespace ams::ldr::hoc::pcv::mariko { mrw2 = static_cast(((rlIndex & 0x7) | ((wlIndex & 0x7) << 3) | ((0 & 0x1) << 6))); } - void CalculateTimings() { + void CalculateTimings(double tCK_avg, u32 freq) { + RL = RL_1331; + WL = WL_1331; + + HandleLatency(freq); + GetRext(); + + /* 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... */ + u32 tRPpbIndex = C.t2_tRP; + if (WL == WL_1331) { + tRPpbIndex = MIN(C.t2_tRP_cap, C.t2_tRP); + } + + tRCD = tRCD_values[C.t1_tRCD]; + tRPpb = tRP_values[tRPpbIndex]; + tRAS = tRAS_values[C.t3_tRAS]; + tRRD = tRRD_values[C.t4_tRRD]; + tRFCpb = tRFC_values[C.t5_tRFC]; + 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; + + tRC = tRAS + tRPpb; + tRFCab = tRFCpb * 2; + tXSR = static_cast(tRFCab + 7.5); + tFAW = static_cast(tRRD * 4.0); + 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 - (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)); + + rdv = RL + FLOOR((5.105 / tCK_avg) + 17.017); + qpop = rdv - 14; + quse_width = CEIL(((4.897 / tCK_avg) - FLOOR(2.538 / tCK_avg)) + 3.782); + quse = FLOOR(RL + ((5.082 / tCK_avg) + FLOOR(2.560 / tCK_avg))) - CEIL(4.820 / tCK_avg); + einput_duration = FLOOR(9.936 / tCK_avg) + 5.0 + quse_width; + einput = quse - CEIL(9.928 / tCK_avg); + u32 qrst_duration = FLOOR(8.399 - tCK_avg); + u32 qrstLow = MAX(static_cast(einput - qrst_duration - 2), static_cast(0)); + qrst = PACK_U32(qrst_duration, qrstLow); + ibdly = PACK_U32_NIBBLE_HIGH_BYTE_LOW(1, quse - qrst_duration - 2.0); + qsafe = (einput_duration + 3) + MAX(MIN(qrstLow * rdv, qrst_duration + qrst_duration), einput); + tW2P = (CEIL(WL * 1.7303) * 2) - 5; + tWTPDEN = CEIL(((1.803 / tCK_avg) + MAX(RL + (2.694 / tCK_avg), static_cast(tW2P))) + (BL / 2)); + tW2R = FLOOR(MAX((5.020 / tCK_avg) + 1.130, WL - MAX(-CEIL(0.258 * (WL - RL)), 1.964)) * 1.964) + WL - CEIL(tWTR / tCK_avg) + finetWTR; + tWTM = CEIL(WL + ((7.570 / tCK_avg) + 8.753)); + tWATM = (tWTM + (FLOOR(WL / 0.816) * 2.0)) - 4.0; + + wdv = WL; + wsv = WL - 2; + wev = 0xA + (WL - 14); + + u32 obdlyHigh = 3 / FLOOR(MIN(static_cast(2), tCK_avg * (WL - 7))); + u32 obdlyLow = MAX(WL - FLOOR((126.0 / CEIL(tCK_avg + 8.601))), 0.0); + obdly = PACK_U32_NIBBLE_HIGH_BYTE_LOW(obdlyHigh, obdlyLow); + + pdex2rw = CEIL((CEIL(12.335 - tCK_avg) + (7.430 / tCK_avg) - CEIL(tCK_avg * 11.361))); + + tCLKSTOP = FLOOR(MIN(8.488 / tCK_avg, 23.0)) + 8.0; + + u32 tMMRI = tRCD + (tCK_avg * 3); + pdex2mrr = tMMRI + 10; + CalculateMrw2(); } diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/mariko/calculate_timings.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/mariko/calculate_timings.hpp index dbf63bae..84165e07 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/mariko/calculate_timings.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/mariko/calculate_timings.hpp @@ -18,7 +18,7 @@ namespace ams::ldr::hoc::pcv::mariko { - void CalculateTimings(); + void CalculateTimings(double tCK_avg, u32 freq); } diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/mtc_timing_value.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/mtc_timing_value.hpp index b6a72cc6..1b592f0e 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/mtc_timing_value.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/mtc_timing_value.hpp @@ -111,60 +111,54 @@ namespace ams::ldr::hoc { const std::array tWTR_values = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 }; const std::array tREFpb_values = { 3900, 5850, 7800, 11700, 15600, 99999 }; - const double tCK_avg = 1000'000.0 / C.marikoEmcMaxClock; + inline u32 tRCD; + inline u32 tRPpb; + inline u32 tRAS; + inline double tRRD; + inline u32 tRFCpb; - const u32 tRCD = tRCD_values[C.t1_tRCD]; - const u32 tRPpb = tRP_values[C.t2_tRP]; - const u32 tRAS = tRAS_values[C.t3_tRAS]; - const double tRRD = tRRD_values[C.t4_tRRD]; - const u32 tRFCpb = tRFC_values[C.t5_tRFC]; - const u32 tWTR = 10 - tWTR_values[C.t7_tWTR]; - const s32 finetRTW = C.fineTune_t6_tRTW; - const s32 finetWTR = C.fineTune_t7_tWTR; + inline u32 tRC; + inline u32 tRFCab; + inline double tXSR; + inline u32 tFAW; + inline double tRPab; - const u32 tRC = tRAS + tRPpb; - const u32 tRFCab = tRFCpb * 2; - const double tXSR = static_cast(tRFCab + 7.5); - const u32 tFAW = static_cast(tRRD * 4.0); - const double tRPab = tRPpb + 3; + inline u32 RL; + inline u32 WL; - const u32 tR2P = CEIL((RL * 0.426) - 2.0); - const u32 tR2W = FLOOR(FLOOR((5.0 / tCK_avg) + ((FLOOR(48.0 / WL) - 0.478) * 3.0)) / 1.501) + RL - (C.t6_tRTW * 3) + finetRTW; - const u32 tRTM = FLOOR((10.0 + RL) + (3.502 / tCK_avg)) + FLOOR(7.489 / tCK_avg); - const u32 tRATM = CEIL((tRTM - 10.0) + (RL * 0.426)); + inline u32 tR2P; + inline u32 tR2W; + inline u32 tRTM; + inline u32 tRATM; inline u32 rext; - const u32 rdv = RL + FLOOR((5.105 / tCK_avg) + 17.017); - const u32 qpop = rdv - 14; - const u32 quse_width = CEIL(((4.897 / tCK_avg) - FLOOR(2.538 / tCK_avg)) + 3.782); - const u32 quse = FLOOR(RL + ((5.082 / tCK_avg) + FLOOR(2.560 / tCK_avg))) - CEIL(4.820 / tCK_avg); - const u32 einput_duration = FLOOR(9.936 / tCK_avg) + 5.0 + quse_width; - const u32 einput = quse - CEIL(9.928 / tCK_avg); - const u32 qrst_duration = FLOOR(8.399 - tCK_avg); - const u32 qrstLow = MAX(static_cast(einput - qrst_duration - 2), static_cast(0)); - const u32 qrst = PACK_U32(qrst_duration, qrstLow); - const u32 ibdly = PACK_U32_NIBBLE_HIGH_BYTE_LOW(1, quse - qrst_duration - 2.0); - const u32 qsafe = (einput_duration + 3) + MAX(MIN(qrstLow * rdv, qrst_duration + qrst_duration), einput); - const u32 tW2P = (CEIL(WL * 1.7303) * 2) - 5; - const u32 tWTPDEN = CEIL(((1.803 / tCK_avg) + MAX(RL + (2.694 / tCK_avg), static_cast(tW2P))) + (BL / 2)); - const u32 tW2R = FLOOR(MAX((5.020 / tCK_avg) + 1.130, WL - MAX(-CEIL(0.258 * (WL - RL)), 1.964)) * 1.964) + WL - CEIL(tWTR / tCK_avg) + finetWTR; - const u32 tWTM = CEIL(WL + ((7.570 / tCK_avg) + 8.753)); - const u32 tWATM = (tWTM + (FLOOR(WL / 0.816) * 2.0)) - 4.0; + inline u32 rdv; + inline u32 qpop; + inline u32 quse_width; + inline u32 quse; + inline u32 einput_duration; + inline u32 einput; + inline u32 qrst; + inline u32 ibdly; + inline u32 qsafe; - const u32 wdv = WL; - const u32 wsv = WL - 2; - const u32 wev = 0xA + (WL - 14); + inline u32 tW2P; + inline u32 tWTPDEN; + inline u32 tW2R; + inline u32 tWTM; + inline u32 tWATM; - const u32 obdlyHigh = 3 / FLOOR(MIN(static_cast(2), tCK_avg * (WL - 7))); - const u32 obdlyLow = MAX(WL - FLOOR((126.0 / CEIL(tCK_avg + 8.601))), 0.0); - const u32 obdly = PACK_U32_NIBBLE_HIGH_BYTE_LOW(obdlyHigh, obdlyLow); + inline u32 wdv; + inline u32 wsv; + inline u32 wev; - const u32 pdex2rw = CEIL((CEIL(12.335 - tCK_avg) + (7.430 / tCK_avg) - CEIL(tCK_avg * 11.361))); + inline u32 obdly; - const u32 tCLKSTOP = FLOOR(MIN(8.488 / tCK_avg, 23.0)) + 8.0; + inline u32 pdex2rw; - const double tMMRI = tRCD + (tCK_avg * 3); - const double pdex2mrr = tMMRI + 10; /* Do this properly? */ + inline u32 tCLKSTOP; + + inline u32 pdex2mrr; inline u8 mrw2; } diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/oc_common.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/oc_common.hpp index 2e900f72..2205c4a3 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/oc_common.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/oc_common.hpp @@ -51,6 +51,7 @@ namespace ams::ldr { R_DEFINE_ERROR_RESULT(UninitializedPatcher, 1013); R_DEFINE_ERROR_RESULT(UnsuccessfulPatcher, 1014); R_DEFINE_ERROR_RESULT(SafetyCheckFailure, 1015); + R_DEFINE_ERROR_RESULT(InvalidMtcTablePattern, 1016); } namespace ams::ldr::hoc { diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_asm.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_asm.hpp index bf6d0b1d..ac96bb19 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_asm.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_asm.hpp @@ -20,10 +20,12 @@ #pragma once -#include "../oc_common.hpp" +#include namespace ams::ldr::hoc::pcv { + constexpr u32 NopIns = 0x1f2003d5; + inline auto asm_compare_no_rd = [](u32 ins1, u32 ins2) { return ((ins1 ^ ins2) >> 5) == 0; }; @@ -44,4 +46,19 @@ namespace ams::ldr::hoc::pcv { return static_cast((ins >> 5) & 0xFFFF); }; + inline auto AsmCompareBrNoRd = [](u32 ins1, u32 ins2) { + constexpr u32 RegMask = ~(((1 << 5) - 1) << 5); + return ((ins1 & RegMask) ^ (ins2 & RegMask)) == 0; + }; + + inline auto AsmCompareAddNoImm12 = [](u32 ins1, u32 ins2) { + constexpr u32 Imm12Mask = ~(((1 << 12) - 1) << 10); + return ((ins1 & Imm12Mask) ^ (ins2 & Imm12Mask)) == 0; + }; + + inline auto AsmCompareAdrpNoImm = [](u32 ins1, u32 ins2) { + constexpr u32 ImmMask = ~((((1 << 2) - 1) << 29) | (((1 << 19) - 1) << 5)); + return ((ins1 & ImmMask) ^ (ins2 & ImmMask)) == 0; + }; + } diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_common.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_common.hpp index 2d75687a..cbd6a12f 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_common.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_common.hpp @@ -46,11 +46,6 @@ namespace ams::ldr::hoc::pcv { unsigned long dvco_calibration_max; } cvb_cpu_dfll_data; - typedef struct emc_dvb_dvfs_table_t { - u64 freq; - s32 volt[4] = {0}; - } emc_dvb_dvfs_table_t; - typedef struct __attribute__((packed)) div_nmp { u8 divn_shift; u8 divn_width; 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 35dd3326..c9b180ac 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_erista.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_erista.hpp @@ -113,7 +113,38 @@ namespace ams::ldr::hoc::pcv::erista { constexpr u32 EmcClkMinFreq = 40800; /* 40.8 MHz table only exists on erista. */ constexpr u32 EmcClkPllmLimit = 1866'000'000; - constexpr u32 MTC_TABLE_REV = 7; + constexpr u32 MTC_TABLE_REV = 7; + constexpr u32 MtcTableCountDefault = 10; + + constexpr size_t MtcFullTableSize = sizeof(EristaMtcTable) * MtcTableCountDefault; + constexpr u32 MtcFullTableCount = 3; + + /* These dramids were copied from Hekate -- see /bdk/mem/sdram.h */ + enum DramId { + ICOSA_4GB_SAMSUNG_K4F6E304HB_MGCH = 0, + ICOSA_4GB_HYNIX_H9HCNNNBPUMLHR_NLE = 1, + ICOSA_4GB_MICRON_MT53B512M32D2NP_062_WTC = 2, /* This doesn't have a table in pcv? Wtf? */ + ICOSA_6GB_SAMSUNG_K4FHE3D4HM_MGCH = 4, + ICOSA_8GB_SAMSUNG_K4FBE3D4HM_MGXX = 7, /* No table, but expected */ + }; + + enum MtcTableIndex { + T210SdevEmcDvfsTableS4gb01 = 0, /* HB-MGCH */ + T210SdevEmcDvfsTableS6gb01 = 1, /* HM-MGCH */ + T210SdevEmcDvfsTableH4gb01 = 2, /* HR-NLE */ + MtcTableIndex_Invalid = 3, + }; + + struct MtcDramIndex { + DramId dramId; + MtcTableIndex index; + }; + + constexpr MtcDramIndex mtcIndexTable[] = { + { ICOSA_4GB_SAMSUNG_K4F6E304HB_MGCH, T210SdevEmcDvfsTableS4gb01, }, + { ICOSA_6GB_SAMSUNG_K4FHE3D4HM_MGCH, T210SdevEmcDvfsTableS6gb01, }, + { ICOSA_4GB_HYNIX_H9HCNNNBPUMLHR_NLE, T210SdevEmcDvfsTableH4gb01, }, + }; void Patch(uintptr_t mapped_nso, size_t nso_size); 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 6e9313f5..3e0b04b1 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.cpp @@ -18,6 +18,7 @@ * along with this program. If not, see . */ +#include #include "pcv.hpp" #include "../mtc_timing_value.hpp" #include "../mariko/calculate_timings.hpp" @@ -53,7 +54,7 @@ namespace ams::ldr::hoc::pcv::mariko { R_SKIP(); } - PATCH_OFFSET(ptr + 0, C.marikoGpuVmin); + PATCH_OFFSET(ptr, C.marikoGpuVmin); PATCH_OFFSET(ptr + 3, C.marikoGpuVmin); PATCH_OFFSET(ptr + 6, C.marikoGpuVmin); PATCH_OFFSET(ptr + 9, C.marikoGpuVmin); @@ -349,6 +350,8 @@ namespace ams::ldr::hoc::pcv::mariko { TABLE->shadow_regs_ca_train.PARAM = VALUE; \ TABLE->shadow_regs_rdwr_train.PARAM = VALUE; + const double tCK_avg = 1000'000.0 / table->rate_khz; + #define GET_CYCLE_CEIL(PARAM) u32(CEIL(double(PARAM) / tCK_avg)) /* Ram power down */ @@ -372,7 +375,7 @@ namespace ams::ldr::hoc::pcv::mariko { const u32 dyn_self_ref_control = (static_cast(7605.0 / tCK_avg) + 260) | (table->burst_regs.emc_dyn_self_ref_control & 0xffff0000); - CalculateTimings(); + CalculateTimings(tCK_avg, table->rate_khz); WRITE_PARAM_ALL_REG(table, emc_rd_rcd, GET_CYCLE_CEIL(tRCD)); WRITE_PARAM_ALL_REG(table, emc_wr_rcd, GET_CYCLE_CEIL(tRCD)); @@ -399,7 +402,7 @@ namespace ams::ldr::hoc::pcv::mariko { WRITE_PARAM_ALL_REG(table, emc_twtm, tWTM); WRITE_PARAM_ALL_REG(table, emc_twatm, tWATM); WRITE_PARAM_ALL_REG(table, emc_rext, rext); - WRITE_PARAM_ALL_REG(table, emc_wext, (C.marikoEmcMaxClock >= 2533000) ? 0x19 : 0x16); + WRITE_PARAM_ALL_REG(table, emc_wext, (table->rate_khz >= 2533000) ? 0x19 : 0x16); WRITE_PARAM_ALL_REG(table, emc_refresh, refresh_raw); WRITE_PARAM_ALL_REG(table, emc_pre_refresh_req_cnt, refresh_raw / 4); WRITE_PARAM_ALL_REG(table, emc_trefbw, trefbw); @@ -443,7 +446,7 @@ namespace ams::ldr::hoc::pcv::mariko { constexpr double MC_ARB_DIV = 4.0; constexpr u32 MC_ARB_SFA = 2; - table->burst_mc_regs.mc_emem_arb_cfg = C.marikoEmcMaxClock / (33.3 * 1000) / MC_ARB_DIV; + table->burst_mc_regs.mc_emem_arb_cfg = table->rate_khz / (33.3 * 1000) / MC_ARB_DIV; table->burst_mc_regs.mc_emem_arb_timing_rcd = CEIL(GET_CYCLE_CEIL(tRCD) / MC_ARB_DIV) - 2; table->burst_mc_regs.mc_emem_arb_timing_rp = CEIL(GET_CYCLE_CEIL(tRPpb) / MC_ARB_DIV) - 1; table->burst_mc_regs.mc_emem_arb_timing_rc = CEIL(GET_CYCLE_CEIL(tRC) / MC_ARB_DIV) - 1; @@ -485,7 +488,7 @@ namespace ams::ldr::hoc::pcv::mariko { table->la_scale_regs.mc_mll_mpcorer_ptsa_rate = 0x115; - if (C.marikoEmcMaxClock >= 2133000) { + if (table->rate_khz >= 2133000) { table->la_scale_regs.mc_ftop_ptsa_rate = 0x1F; } else { table->la_scale_regs.mc_ftop_ptsa_rate = 0x1B; @@ -494,14 +497,14 @@ namespace ams::ldr::hoc::pcv::mariko { table->la_scale_regs.mc_ptsa_grant_decrement = 0x17ff; constexpr u32 MaskHigh = 0xFF00FFFF; - constexpr u32 Mask2 = 0xFFFFFF00; - constexpr u32 Mask3 = 0xFF00FF00; + constexpr u32 Mask2 = 0xFFFFFF00; + constexpr u32 Mask3 = 0xFF00FF00; - const u32 allowance1 = static_cast(0x32000 / (C.marikoEmcMaxClock / 0x3E8)) & 0xFF; - const u32 allowance2 = static_cast(0x9C40 / (C.marikoEmcMaxClock / 0x3E8)) & 0xFF; - const u32 allowance3 = static_cast(0xB540 / (C.marikoEmcMaxClock / 0x3E8)) & 0xFF; - const u32 allowance4 = static_cast(0x9600 / (C.marikoEmcMaxClock / 0x3E8)) & 0xFF; - const u32 allowance5 = static_cast(0x8980 / (C.marikoEmcMaxClock / 0x3E8)) & 0xFF; + const u32 allowance1 = static_cast(0x32000 / (table->rate_khz / 1000)) & 0xFF; + const u32 allowance2 = static_cast(0x9C40 / (table->rate_khz / 1000)) & 0xFF; + const u32 allowance3 = static_cast(0xB540 / (table->rate_khz / 1000)) & 0xFF; + const u32 allowance4 = static_cast(0x9600 / (table->rate_khz / 1000)) & 0xFF; + const u32 allowance5 = static_cast(0x8980 / (table->rate_khz / 1000)) & 0xFF; table->la_scale_regs.mc_latency_allowance_xusb_0 = (table->la_scale_regs.mc_latency_allowance_xusb_0 & MaskHigh) | (allowance1 << 16); table->la_scale_regs.mc_latency_allowance_xusb_1 = (table->la_scale_regs.mc_latency_allowance_xusb_1 & MaskHigh) | (allowance1 << 16); @@ -525,8 +528,8 @@ namespace ams::ldr::hoc::pcv::mariko { table->dram_timings.t_rp = tRFCpb; table->dram_timings.t_rfc = tRFCab; - table->dram_timings.rl = RL; + table->dram_timings.rl = RL; table->emc_mrw2 = (table->emc_mrw2 & ~0xFFu) | static_cast(mrw2); table->emc_cfg_2 = 0x11083D; } @@ -535,24 +538,24 @@ namespace ams::ldr::hoc::pcv::mariko { constexpr u32 PllOscInKHz = 38400; constexpr u32 PllOscHalfKHz = 19200; - double target_freq_d = static_cast(C.marikoEmcMaxClock); + double target_freq_d = static_cast(table->rate_khz); - s32 divm_candidate_half = static_cast(C.marikoEmcMaxClock / PllOscHalfKHz); + s32 divm_candidate_half = static_cast(table->rate_khz / PllOscHalfKHz); - bool remainder_check = (C.marikoEmcMaxClock - PllOscInKHz * (C.marikoEmcMaxClock / PllOscInKHz)) > (C.marikoEmcMaxClock - PllOscHalfKHz * divm_candidate_half) && static_cast(((target_freq_d / PllOscHalfKHz - divm_candidate_half - 0.5) * 8192.0)) != 0; + bool remainder_check = (table->rate_khz - PllOscInKHz * (table->rate_khz / PllOscInKHz)) > (table->rate_khz - PllOscHalfKHz * divm_candidate_half) && static_cast(((target_freq_d / PllOscHalfKHz - divm_candidate_half - 0.5) * 8192.0)) != 0; u32 divm_final = remainder_check + 1; table->pllmb_divm = divm_final; double div_step_d = static_cast(PllOscInKHz) / divm_final; - s32 divn_integer = static_cast(C.marikoEmcMaxClock / div_step_d); + s32 divn_integer = static_cast(table->rate_khz / div_step_d); table->pllmb_divn = divn_integer; u32 divn_fraction = static_cast((target_freq_d / div_step_d - divn_integer - 0.5) * 8192.0); u32 actual_freq_khz = static_cast((divn_integer + 0.5 + divn_fraction * 0.000122070312) * div_step_d); - if (C.marikoEmcMaxClock - 2366001 < 133999) { + if (table->rate_khz - 2366001 < 133999) { s32 divn_fraction_ssc = static_cast((actual_freq_khz * 0.997 / div_step_d - divn_integer - 0.5) * 8192.0); double delta_scaled = (0.3 / div_step_d + 0.3 / div_step_d) * (divn_fraction - divn_fraction_ssc); @@ -580,7 +583,7 @@ namespace ams::ldr::hoc::pcv::mariko { table->pllm_ss_cfg &= 0xBFFFFFFF; table->pllmb_ss_cfg &= 0xBFFFFFFF; - u64 pair = (static_cast(divn_fraction) << 32) | static_cast(C.marikoEmcMaxClock); + u64 pair = (static_cast(divn_fraction) << 32) | static_cast(table->rate_khz); u32 pll_misc = (table->pllm_ss_ctrl2 & 0xFFFF0000) | static_cast((pair - actual_freq_khz) >> 32); table->pllm_ss_ctrl2 = pll_misc; @@ -588,80 +591,222 @@ namespace ams::ldr::hoc::pcv::mariko { } } - Result MemFreqMtcTable(u32 *ptr) { - u32 khz_list[] = {1600000, 1331200, 204000}; - u32 khz_list_size = sizeof(khz_list) / sizeof(u32); + namespace { + std::vector newEmcList; + u32 *nsoStart; + } - // Generate list for mtc table pointers - MarikoMtcTable *table_list[khz_list_size]; - for (u32 i = 0; i < khz_list_size; i++) { - u8 *table = reinterpret_cast(ptr) - offsetof(MarikoMtcTable, rate_khz) - i * sizeof(MarikoMtcTable); - table_list[i] = reinterpret_cast(table); - R_UNLESS(table_list[i]->rate_khz == khz_list[i], ldr::ResultInvalidMtcTable()); - R_UNLESS(table_list[i]->rev == MTC_TABLE_REV, ldr::ResultInvalidMtcTable()); + void MtcGenerateJedecTable() { + const u32 jedecFreqs[] = { 1866000, 1996000, 2133000, 2400000, 2666000, 2933000, 3200000 }; + constexpr u32 JedecFreqCount = std::size(jedecFreqs); + + for (u32 i = 0; i < JedecFreqCount; ++i) { + if (jedecFreqs[i] <= C.marikoEmcMaxClock) { + newEmcList.push_back(jedecFreqs[i]); + } else { + break; + } } - if (C.marikoEmcMaxClock <= EmcClkOSLimit) + newEmcList.resize(std::min(newEmcList.size(), DvfsTableEntryLimit)); + } + + void MtcGenerateFreqTables() { + if (C.marikoEmcMaxClock <= EmcClkOSLimit) { + return; + } + + newEmcList.clear(); + newEmcList.reserve(DvfsTableEntryCount); + newEmcList.insert(newEmcList.end(), std::begin(EmcListDefault), std::end(EmcListDefault)); + + u32 stepRate = 0; + switch (C.stepMode) { + case StepMode_66MHz: + stepRate = 66667; + break; + case StepMode_100MHz: + stepRate = 100000; + break; + case StepMode_Jedec: + MtcGenerateJedecTable(); + return; + default: + stepRate = 66667; + break; + } + + constexpr u32 RoundHz = 1000; + for (u32 stepIndex = 1;; ++stepIndex) { + u32 newFreq = EmcClkOSLimit + stepIndex * stepRate; + newFreq = (newFreq / RoundHz) * RoundHz; + if (newFreq > C.marikoEmcMaxClock) { + if (newEmcList.back() != C.marikoEmcMaxClock) { + newEmcList.push_back(static_cast(C.marikoEmcMaxClock)); + } + break; + } + newEmcList.push_back(newFreq); + } + + newEmcList.resize(std::min(newEmcList.size(), DvfsTableEntryLimit)); + } + + Result VerifyMtcTable(MarikoMtcTable *tableStart, u32 expectedFreq) { + R_UNLESS(tableStart->rate_khz == expectedFreq, ldr::ResultInvalidMtcTable()); + R_UNLESS(tableStart->rev == MTC_TABLE_REV, ldr::ResultInvalidMtcTable()); + + R_SUCCEED(); + } + + Result MtcValidateAllTables(MarikoMtcTable *tableStart, const u32 *validationList, u32 tableCount) { + for (u32 i = 0; i < tableCount; ++i) { + R_UNLESS(R_SUCCEEDED(VerifyMtcTable(&tableStart[i], validationList[i])), ldr::ResultInvalidMtcTable()); + } + + R_SUCCEED(); + } + + DramId GetDramId() { + u64 id64; + splGetConfig(SplConfigItem_DramId, &id64); + return static_cast(id64); + } + + MtcTableIndex GetMtcDramIndex(DramId dramId) { + for (u32 i = 0; i < std::size(mtcIndexTable); ++i) { + if (mtcIndexTable[i].dramId == dramId) { + return mtcIndexTable[i].index; + } + } + + return MtcTableIndex_Invalid; + } + + NORETURN void AbortInvalidDramId() { + panic::SmcError(panic::Emc); + CRASH("Invalid dram id\n"); + } + + u32 GetMtcOffset(MtcTableIndex index) { + if (index < T210b0SdevEmcDvfsTableS4gb03) { + return index * mariko::MtcFullTableSize; + } + + /* There are 2 erista mtc tables between T210b0SdevEmcDvfsTableS4gb01 and T210b0SdevEmcDvfsTableS4gb03, so we have to do this adjustment. */ + return mariko::MtcFullTableSize * index + (2 * erista::MtcFullTableSize); + } + + void PrepareMtcMemoryRegion(u8 *firstTable, MarikoMtcTable *usedTable) { + memmove(firstTable, usedTable, mariko::MtcFullTableSize); + + /* Clear all other tables. */ + /* 1 erista table is excluded because it's always before firstTable. */ + /* We also exclude the used table obviously. */ + constexpr size_t RemainingRegionSize = (mariko::MtcFullTableSize) * (mariko::MtcFullTableCount - 1) + (erista::MtcFullTableSize * (erista::MtcFullTableCount - 1)); + memset(firstTable + mariko::MtcFullTableSize, 0, RemainingRegionSize); + } + + void MtcExtendTables(MarikoMtcTable *table) { + for (u32 i = mariko::MtcTableCountDefault; i < newEmcList.size(); ++i) { + std::memcpy(&table[i], &table[i - 1], sizeof(MarikoMtcTable)); + table[i].rate_khz = newEmcList[i]; + } + } + + bool patchedMtc = false; + Result MemFreqMtcTable(u32 *ptr) { + if (C.marikoEmcMaxClock <= EmcClkOSLimit || patchedMtc) { R_SKIP(); + } - MarikoMtcTable *table_alt = table_list[1], *table_max = table_list[0]; - MarikoMtcTable *tmp = new MarikoMtcTable; + static const DramId dramId = [] { + DramId id = GetDramId(); + id = IOWA_4GB_SAMSUNG_K4U6E3S4AA_MGCL; + return id; + }(); - // Copy unmodified 1600000 table to tmp - std::memcpy(reinterpret_cast(tmp), reinterpret_cast(table_max), sizeof(MarikoMtcTable)); + static const MtcTableIndex mtcIndex = [] { + MtcTableIndex idx = GetMtcDramIndex(dramId); + /* If for some reason this happens, there is no chance of recovering this. */ + if (idx == MtcTableIndex_Invalid) { + AbortInvalidDramId(); + } + return idx; + }(); - /* Adjust timings properly according to the new frequency. */ - MemMtcTableAutoAdjust(table_max); + /* Offset to dram id specific mtc table. */ + static const u32 mtcOffset = GetMtcOffset(mtcIndex); - MemMtcPllmbDivisor(table_max); - // Overwrite 13312000 table with unmodified 1600000 table copied back - std::memcpy(reinterpret_cast(table_alt), reinterpret_cast(tmp), sizeof(MarikoMtcTable)); + /* Offset from 1600MHz pointer to 204Mhz table start. */ + constexpr u32 StartAdjustment = offsetof(MarikoMtcTable, rate_khz) + sizeof(MarikoMtcTable) * 2; + u8 *startPtr = reinterpret_cast(ptr) - StartAdjustment; + MarikoMtcTable *table = reinterpret_cast(startPtr + mtcOffset); + R_UNLESS(R_SUCCEEDED(MtcValidateAllTables(table, EmcListDefault, EmcListSizeDefault)), ldr::ResultInvalidMtcTable()); - delete tmp; + table = reinterpret_cast(startPtr); - PATCH_OFFSET(ptr, C.marikoEmcMaxClock); + PrepareMtcMemoryRegion(startPtr, table); + if (R_FAILED(MtcValidateAllTables(table, EmcListDefault, EmcListSizeDefault))) { + panic::SmcError(panic::Emc); + } + + MtcExtendTables(table); + + if (R_FAILED(MtcValidateAllTables(table, newEmcList.data(), newEmcList.size()))) { + panic::SmcError(panic::Emc); + } + + for (u32 i = mariko::MtcTableCountDefault; i < newEmcList.size(); ++i) { + MemMtcTableAutoAdjust(&table[i]); + MemMtcPllmbDivisor(&table[i]); + } + + patchedMtc = true; R_SUCCEED(); } Result MemFreqDvbTable(u32 *ptr) { - emc_dvb_dvfs_table_t *default_end = reinterpret_cast(ptr); - emc_dvb_dvfs_table_t *new_start = default_end + 1; + DvbEntry *default_end = reinterpret_cast(ptr); + DvbEntry *new_start = default_end + 1; // Validate existing table void *mem_dvb_table_head = reinterpret_cast(new_start) - sizeof(EmcDvbTableDefault); - bool validated = std::memcmp(mem_dvb_table_head, EmcDvbTableDefault, sizeof(EmcDvbTableDefault)) == 0; + bool validated = std::memcmp(mem_dvb_table_head, EmcDvbTableDefault, sizeof(EmcDvbTableDefault)) == 0; R_UNLESS(validated, ldr::ResultInvalidDvbTable()); - if (C.marikoEmcMaxClock <= EmcClkOSLimit) + if (C.marikoEmcMaxClock <= EmcClkOSLimit) { R_SKIP(); - - int32_t voltAdd = 25 * C.emcDvbShift; - - #define DVB_VOLT(zero, one, two) std::min(zero + voltAdd, 1050), std::min(one + voltAdd, 1025), std::min(two + voltAdd, 1000), - - /* TODO: More fine tuned values? */ - if (C.marikoEmcMaxClock < 1862400) { - std::memcpy(new_start, default_end, sizeof(emc_dvb_dvfs_table_t)); - } else if (C.marikoEmcMaxClock < 2131200) { - emc_dvb_dvfs_table_t oc_table = {1862400, {700, 675, 650, }}; - std::memcpy(new_start, &oc_table, sizeof(emc_dvb_dvfs_table_t)); - } else if (C.marikoEmcMaxClock < 2400000) { - emc_dvb_dvfs_table_t oc_table = {2131200, { 725, 700, 675} }; - std::memcpy(new_start, &oc_table, sizeof(emc_dvb_dvfs_table_t)); - } else if (C.marikoEmcMaxClock < 2665600) { - emc_dvb_dvfs_table_t oc_table = {2400000, {DVB_VOLT(750, 725, 700)}}; - std::memcpy(new_start, &oc_table, sizeof(emc_dvb_dvfs_table_t)); - } else if (C.marikoEmcMaxClock < 2931200) { - emc_dvb_dvfs_table_t oc_table = {2665600, {DVB_VOLT(775, 750, 725)}}; - std::memcpy(new_start, &oc_table, sizeof(emc_dvb_dvfs_table_t)); - } else if (C.marikoEmcMaxClock < 3200000) { - emc_dvb_dvfs_table_t oc_table = {2931200, {DVB_VOLT(800, 775, 750)}}; - std::memcpy(new_start, &oc_table, sizeof(emc_dvb_dvfs_table_t)); - } else { - emc_dvb_dvfs_table_t oc_table = {3200000, {DVB_VOLT(800, 800, 775)}}; - std::memcpy(new_start, &oc_table, sizeof(emc_dvb_dvfs_table_t)); } - new_start->freq = C.marikoEmcMaxClock; + + s32 voltAdd = 25 * C.emcDvbShift; + #define DVB_VOLT(zero, one, two) std::min(zero + voltAdd, 1050), std::min(one + voltAdd, 1025), std::min(two + voltAdd, 1000), + DvbEntry emcDvbTableNew[] = { + { 204000, { 637, 637, 637, } }, + { 1331200, { 650, 637, 637, } }, + { 1600000, { 675, 650, 637, } }, + { 1866000, { DVB_VOLT(700, 675, 650) } }, + { 2133000, { DVB_VOLT(725, 700, 675) } }, + { 2400000, { DVB_VOLT(750, 725, 700) } }, + { 2666000, { DVB_VOLT(775, 750, 725) } }, + { 2933000, { DVB_VOLT(800, 775, 750) } }, + { 3200000, { DVB_VOLT(800, 800, 775) } }, + { 0xFFFFFFFF, { } }, + }; + + u32 j = MtcTableCountDefault; + for (u32 i = MtcTableCountDefault; i < newEmcList.size(); ++i) { + if (newEmcList[i] >= emcDvbTableNew[j].freq && newEmcList[i] < emcDvbTableNew[j + 1].freq) { + emcDvbTableNew[j].freq = newEmcList[i]; + ++j; + } else { + break; + } + } + + std::memset(mem_dvb_table_head, 0, sizeof(EmcDvbTableDefault)); + std::memcpy(mem_dvb_table_head, &emcDvbTableNew, sizeof(emcDvbTableNew)); + /* Max dvfs entry is 32, but HOS doesn't seem to boot if exact freq doesn't exist in dvb table, reason why it's like this */ @@ -670,8 +815,9 @@ namespace ams::ldr::hoc::pcv::mariko { } Result MemFreqMax(u32 *ptr) { - if (C.marikoEmcMaxClock <= EmcClkOSLimit) + if (C.marikoEmcMaxClock <= EmcClkOSLimit) { R_SKIP(); + } PATCH_OFFSET(ptr, C.marikoEmcMaxClock); R_SUCCEED(); @@ -685,12 +831,13 @@ namespace ams::ldr::hoc::pcv::mariko { I2cSession _session; Result res = i2cOpenSession(&_session, dev); - if (R_FAILED(res)) + if (R_FAILED(res)) { return res; + } cmd.reg = reg; cmd.val = val; - res = i2csessionSendAuto(&_session, &cmd, sizeof(cmd), I2cTransactionOption_All); + res = i2csessionSendAuto(&_session, &cmd, sizeof(cmd), I2cTransactionOption_All); i2csessionClose(&_session); return res; } @@ -702,21 +849,24 @@ namespace ams::ldr::hoc::pcv::mariko { constexpr u32 uv_min = 250'000; auto validator = [entry]() { - R_UNLESS(entry->id == 2, ldr::ResultInvalidRegulatorEntry()); - R_UNLESS(entry->type == 3, ldr::ResultInvalidRegulatorEntry()); + R_UNLESS(entry->id == 2, ldr::ResultInvalidRegulatorEntry()); + R_UNLESS(entry->type == 3, ldr::ResultInvalidRegulatorEntry()); R_UNLESS(entry->type_2_3.step_uv == uv_step, ldr::ResultInvalidRegulatorEntry()); - R_UNLESS(entry->type_2_3.min_uv == uv_min, ldr::ResultInvalidRegulatorEntry()); + R_UNLESS(entry->type_2_3.min_uv == uv_min, ldr::ResultInvalidRegulatorEntry()); R_SUCCEED(); }; R_TRY(validator()); u32 emc_uv = C.marikoEmcVddqVolt; - if (!emc_uv) - R_SKIP(); - if (emc_uv % uv_step) + if (!emc_uv) { + R_SKIP(); + } + + if (emc_uv % uv_step) { emc_uv = (emc_uv + uv_step - 1) / uv_step * uv_step; // rounding + } PATCH_OFFSET(ptr, emc_uv); @@ -731,28 +881,61 @@ namespace ams::ldr::hoc::pcv::mariko { return resultI2C; } + Result MemMtcTableAsm(u32 *ptr) { + 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 - BrOffset); + R_UNLESS(AsmCompareBrNoRd(br, MtcBrAsm), ldr::ResultInvalidMtcTable()); + + /* Pray this does not break either. */ + 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 - 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); PatcherEntry patches[] = { - {"CPU Freq Vdd", &CpuFreqVdd, 1, nullptr, CpuClkOSLimit}, - {"CPU Freq Table", CpuFreqCvbTable, 1, nullptr, CpuCvbDefaultMaxFreq}, - {"CPU Volt DVFS", &CpuVoltDVFS, 1, nullptr, CpuVminOfficial}, - {"CPU Volt Thermals", &CpuVoltThermals, 1, nullptr, CpuVminOfficial}, - {"CPU Volt Dfll", &CpuVoltDfll, 1, nullptr, 0x0000FFCF}, - {"GPU Volt DVFS", &GpuVoltDVFS, 1, nullptr, GpuVminOfficial}, - {"GPU Volt Thermals", &GpuVoltThermals, 1, nullptr, GpuVminOfficial}, - {"GPU Freq Table", GpuFreqCvbTable, 1, nullptr, GpuCvbDefaultMaxFreq}, - {"GPU Freq Asm", &GpuFreqMaxAsm, 2, &GpuMaxClockPatternFn}, - {"GPU PLL Max", &GpuFreqPllMax, 1, nullptr, GpuClkPllMax}, - {"GPU PLL Limit", &GpuFreqPllLimit, 4, nullptr, GpuClkPllLimit}, - {"MEM Freq Mtc", &MemFreqMtcTable, 0, nullptr, EmcClkOSLimit}, - {"MEM Freq Dvb", &MemFreqDvbTable, 1, nullptr, EmcClkOSLimit}, - {"MEM Freq Max", &MemFreqMax, 0, nullptr, EmcClkOSLimit}, - {"MEM Freq PLLM", &MemFreqPllmLimit, 2, nullptr, EmcClkPllmLimit}, - {"MEM Vddq", &EmcVddqVolt, 2, nullptr, EmcVddqDefault}, - {"MEM Vdd2", &MemVoltHandler, 2, nullptr, MemVdd2Default}, + { "CPU Freq Vdd", &CpuFreqVdd, 1, nullptr, CpuClkOSLimit }, + { "CPU Freq Table", CpuFreqCvbTable, 1, nullptr, CpuCvbDefaultMaxFreq }, + { "CPU Volt DVFS", &CpuVoltDVFS, 1, nullptr, CpuVminOfficial }, + { "CPU Volt Thermals", &CpuVoltThermals, 1, nullptr, CpuVminOfficial }, + { "CPU Volt Dfll", &CpuVoltDfll, 1, nullptr, CpuTune0Low }, + { "GPU Volt DVFS", &GpuVoltDVFS, 1, nullptr, GpuVminOfficial }, + { "GPU Volt Thermals", &GpuVoltThermals, 1, nullptr, GpuVminOfficial }, + { "GPU Freq Table", GpuFreqCvbTable, 1, nullptr, GpuCvbDefaultMaxFreq }, + { "GPU Freq Asm", &GpuFreqMaxAsm, 2, &GpuMaxClockPatternFn }, + { "GPU PLL Max", &GpuFreqPllMax, 1, nullptr, GpuClkPllMax }, + { "GPU PLL Limit", &GpuFreqPllLimit, 4, nullptr, GpuClkPllLimit }, + { "MEM Freq Mtc", &MemFreqMtcTable, 0, nullptr, EmcClkOSLimit }, + { "MEM Freq Dvb", &MemFreqDvbTable, 1, nullptr, EmcClkOSLimit }, + { "MEM Freq Max", &MemFreqMax, 0, nullptr, EmcClkOSLimit }, + { "MEM Freq PLLM", &MemFreqPllmLimit, 2, nullptr, EmcClkPllmLimit }, + { "MEM Vddq", &EmcVddqVolt, 2, nullptr, EmcVddqDefault }, + { "MEM Vdd2", &MemVoltHandler, 2, nullptr, MemVdd2Default }, + { "Mem Table Asm", &MemMtcTableAsm, 0, &MemMtcGetGetTablePatternFn }, }; for (uintptr_t ptr = mapped_nso; ptr <= mapped_nso + nso_size - sizeof(MarikoMtcTable); ptr += sizeof(u32)) { 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 4c57bf1c..033d5f42 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.hpp @@ -52,6 +52,8 @@ namespace ams::ldr::hoc::pcv::mariko { constexpr u32 CpuVoltOfficial = 1120; constexpr u32 CpuVminOfficial = 620; + constexpr u32 CpuTune0Low = 0xFFCF; + static const u32 cpuVoltagePatchValues[] = { 850, 38, 1120, 1000, 100, 1000, 0 }; static const s32 cpuVoltagePatchOffsets[] = { -2, -1, 5, 6, 7, 8, 9 }; static_assert(sizeof(cpuVoltagePatchValues) == sizeof(cpuVoltagePatchOffsets), "Invalid cpuVoltagePatch size"); @@ -108,7 +110,12 @@ namespace ams::ldr::hoc::pcv::mariko { return asm_compare_no_rd(*ptr32, GpuAsmPattern[0]); } - constexpr emc_dvb_dvfs_table_t EmcDvbTableDefault[] = { + struct DvbEntry { + u64 freq; + s32 volt[4] = {}; + }; + + constexpr DvbEntry EmcDvbTableDefault[] = { { 204000, { 637, 637, 637, } }, { 408000, { 637, 637, 637, } }, { 800000, { 637, 637, 637, } }, @@ -117,12 +124,161 @@ namespace ams::ldr::hoc::pcv::mariko { { 1600000, { 675, 650, 637, } }, }; + constexpr u32 EmcListDefault[] = { 204000, 1331200, 1600000, }; + constexpr u32 EmcListSizeDefault = std::size(EmcListDefault); + constexpr u32 EmcListEndDefault = EmcListSizeDefault - 1; + constexpr u32 EmcRateStep = 33'000; + constexpr u32 EmcRateStepScale = 33'200; + constexpr u32 EmcClkOSAlt = 1331'200; constexpr u32 EmcClkPllmLimit = 2133'000'000; constexpr u32 EmcVddqDefault = 600'000; constexpr u32 MemVdd2Default = 1100'000; - constexpr u32 MTC_TABLE_REV = 3; + constexpr u32 MTC_TABLE_REV = 3; + constexpr u32 MtcTableCountDefault = 3; + + constexpr size_t MtcFullTableSize = sizeof(MarikoMtcTable) * MtcTableCountDefault; + constexpr u32 MtcFullTableCount = 17; + + /* These dramids were copied from Hekate -- see /bdk/mem/sdram.h */ + enum DramId : u64 { + HOAG_4GB_HYNIX_H9HCNNNBKMMLXR_NEE = 3, + AULA_4GB_HYNIX_H9HCNNNBKMMLXR_NEE = 5, + IOWA_4GB_HYNIX_H9HCNNNBKMMLXR_NEE = 6, + + IOWA_4GB_SAMSUNG_K4U6E3S4AM_MGCJ = 8, + IOWA_8GB_SAMSUNG_K4UBE3D4AM_MGCJ = 9, + IOWA_4GB_HYNIX_H9HCNNNBKMMLHR_NME = 10, + IOWA_4GB_MICRON_MT53E512M32D2NP_046_WTE = 11, + + HOAG_4GB_SAMSUNG_K4U6E3S4AM_MGCJ = 12, + HOAG_8GB_SAMSUNG_K4UBE3D4AM_MGCJ = 13, + HOAG_4GB_HYNIX_H9HCNNNBKMMLHR_NME = 14, + HOAG_4GB_MICRON_MT53E512M32D2NP_046_WTE = 15, + + IOWA_4GB_SAMSUNG_K4U6E3S4AA_MGCL = 17, + IOWA_8GB_SAMSUNG_K4UBE3D4AA_MGCL = 18, + HOAG_4GB_SAMSUNG_K4U6E3S4AA_MGCL = 19, + + IOWA_4GB_SAMSUNG_K4U6E3S4AB_MGCL = 20, + HOAG_4GB_SAMSUNG_K4U6E3S4AB_MGCL = 21, + AULA_4GB_SAMSUNG_K4U6E3S4AB_MGCL = 22, + + HOAG_8GB_SAMSUNG_K4UBE3D4AA_MGCL = 23, + AULA_4GB_SAMSUNG_K4U6E3S4AA_MGCL = 24, + + IOWA_4GB_MICRON_MT53E512M32D2NP_046_WTF = 25, + HOAG_4GB_MICRON_MT53E512M32D2NP_046_WTF = 26, + AULA_4GB_MICRON_MT53E512M32D2NP_046_WTF = 27, + + AULA_8GB_SAMSUNG_K4UBE3D4AA_MGCL = 28, + + IOWA_4GB_HYNIX_H54G46CYRBX267 = 29, + HOAG_4GB_HYNIX_H54G46CYRBX267 = 30, + AULA_4GB_HYNIX_H54G46CYRBX267 = 31, + + IOWA_4GB_MICRON_MT53E512M32D1NP_046_WTB = 32, + HOAG_4GB_MICRON_MT53E512M32D1NP_046_WTB = 33, + AULA_4GB_MICRON_MT53E512M32D1NP_046_WTB = 34, + }; + + enum MtcTableIndex { + T210b0SdevEmcDvfsTableS4gb01 = 0, /* (Unused) Samsung 4Gb */ + T210b0SdevEmcDvfsTableS4gb03 = 1, /* Samsung AM-MGCJ 4Gb */ + T210b0SdevEmcDvfsTableS8gb03 = 2, /* (Unused) Samsung 4Gb */ + T210b0SdevEmcDvfsTableH4gb03 = 3, /* Hynix NME 4Gb */ + T210b0SdevEmcDvfsTableM4gb03 = 4, /* Micron WT:F 4Gb */ + T210b0SdevEmcDvfsTableS4gbY01 = 5, /* (Unused) Samsung 4Gb */ + T210b0SdevEmcDvfsTableS1y4gbY01 = 6, /* (Unused) Samsung 4Gb */ + T210b0SdevEmcDvfsTableS1y8gbY01 = 7, /* (Unused) Samsung 4Gb */ + T210b0SdevEmcDvfsTableS1y4gbX03 = 8, /* Samsung AA-MGCL 4Gb */ + T210b0SdevEmcDvfsTableS1y8gbX03 = 9, /* Samsung AA-MGCL 8Gb */ + T210b0SdevEmcDvfsTableS1y4gb01 = 10, /* (Unused) Samsung 4Gb */ + T210b0SdevEmcDvfsTableM1y4gb01 = 11, /* Micron WT:E 4Gb */ + T210b0SdevEmcDvfsTableH1y4gb01 = 12, /* Hynix NEE 4Gb */ + T210b0SdevEmcDvfsTableS1y8gb04 = 13, /* Samsung AM-MGCJ 8Gb */ + T210b0SdevEmcDvfsTableS1z4gb01 = 14, /* Samsung AB-MGCL 4Gb */ + T210b0SdevEmcDvfsTableH1a4gb01 = 15, /* Hynix x267 4Gb */ + T210b0SdevEmcDvfsTableM1a4gb01 = 16, /* Micron WT:B 8Gb */ + MtcTableIndex_Invalid = 17, + }; + + struct MtcDramIndex { + DramId dramId; + MtcTableIndex index; + }; + + constexpr MtcDramIndex mtcIndexTable[] = { + { HOAG_4GB_HYNIX_H9HCNNNBKMMLXR_NEE, T210b0SdevEmcDvfsTableH1y4gb01, }, + { AULA_4GB_HYNIX_H9HCNNNBKMMLXR_NEE, T210b0SdevEmcDvfsTableH1y4gb01, }, + { IOWA_4GB_HYNIX_H9HCNNNBKMMLXR_NEE, T210b0SdevEmcDvfsTableH1y4gb01, }, + { IOWA_4GB_SAMSUNG_K4U6E3S4AM_MGCJ, T210b0SdevEmcDvfsTableS4gb03, }, + { IOWA_8GB_SAMSUNG_K4UBE3D4AM_MGCJ, T210b0SdevEmcDvfsTableS1y8gb04, }, + { IOWA_4GB_HYNIX_H9HCNNNBKMMLHR_NME, T210b0SdevEmcDvfsTableH4gb03, }, + { IOWA_4GB_MICRON_MT53E512M32D2NP_046_WTE, T210b0SdevEmcDvfsTableM1y4gb01, }, + { HOAG_4GB_SAMSUNG_K4U6E3S4AM_MGCJ, T210b0SdevEmcDvfsTableS4gb03, }, + { HOAG_8GB_SAMSUNG_K4UBE3D4AM_MGCJ, T210b0SdevEmcDvfsTableS1y8gb04, }, + { HOAG_4GB_HYNIX_H9HCNNNBKMMLHR_NME, T210b0SdevEmcDvfsTableH4gb03, }, + { HOAG_4GB_MICRON_MT53E512M32D2NP_046_WTE, T210b0SdevEmcDvfsTableM1y4gb01, }, + { IOWA_4GB_SAMSUNG_K4U6E3S4AA_MGCL, T210b0SdevEmcDvfsTableS1y4gbX03, }, + { IOWA_8GB_SAMSUNG_K4UBE3D4AA_MGCL, T210b0SdevEmcDvfsTableS1y8gbX03, }, + { HOAG_4GB_SAMSUNG_K4U6E3S4AA_MGCL, T210b0SdevEmcDvfsTableS1y4gbX03, }, + { IOWA_4GB_SAMSUNG_K4U6E3S4AB_MGCL, T210b0SdevEmcDvfsTableS1z4gb01, }, + { HOAG_4GB_SAMSUNG_K4U6E3S4AB_MGCL, T210b0SdevEmcDvfsTableS1y8gb04, }, + { AULA_4GB_SAMSUNG_K4U6E3S4AB_MGCL, T210b0SdevEmcDvfsTableS1y8gb04, }, + { HOAG_8GB_SAMSUNG_K4UBE3D4AA_MGCL, T210b0SdevEmcDvfsTableS1y8gbX03, }, + { AULA_4GB_SAMSUNG_K4U6E3S4AA_MGCL, T210b0SdevEmcDvfsTableS1y4gbX03, }, + { IOWA_4GB_MICRON_MT53E512M32D2NP_046_WTF, T210b0SdevEmcDvfsTableM4gb03, }, + { HOAG_4GB_MICRON_MT53E512M32D2NP_046_WTF, T210b0SdevEmcDvfsTableM4gb03, }, + { AULA_4GB_MICRON_MT53E512M32D2NP_046_WTF, T210b0SdevEmcDvfsTableM4gb03, }, + { AULA_8GB_SAMSUNG_K4UBE3D4AA_MGCL, T210b0SdevEmcDvfsTableS1y8gbX03, }, + { IOWA_4GB_HYNIX_H54G46CYRBX267, T210b0SdevEmcDvfsTableH1a4gb01, }, + { HOAG_4GB_HYNIX_H54G46CYRBX267, T210b0SdevEmcDvfsTableH1a4gb01, }, + { AULA_4GB_HYNIX_H54G46CYRBX267, T210b0SdevEmcDvfsTableH1a4gb01, }, + { IOWA_4GB_MICRON_MT53E512M32D1NP_046_WTB, T210b0SdevEmcDvfsTableM1a4gb01, }, + { HOAG_4GB_MICRON_MT53E512M32D1NP_046_WTB, T210b0SdevEmcDvfsTableM1a4gb01, }, + { AULA_4GB_MICRON_MT53E512M32D1NP_046_WTB, T210b0SdevEmcDvfsTableM1a4gb01, }, + }; + + /* + 710006abfc 40 01 1f d6 br x10 + */ + + /* + 710006ac28 a0 03 00 90 adrp x0,0x71000de000 + 710006ac2c 00 80 16 91 add x0=>SdevEmcDvfsTableS4gb01,x0,#0x5a0 + */ + + /* Br */ + /* + | Z | OP | Fixed | A | M | RN | RM + 31 30 29 28 27 26 25 | 24 23 | 22 | 21 20 19 18 17 16 15 14 13 12 |11 | 10 | 9 8 7 6 5 | 4 3 2 1 0 + 1 1 0 1 0 1 1 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 Rn 0 0 0 0 0 + Z op A M Rm + */ + + /* Adrp */ + /* + OP | ImmLow | ImmHigh | RD + 31 | 30 29 28 27 26 25 24 | 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 | 4 3 2 1 0 + */ + + /* ADD (immediate) */ + /* + SF | OP | S | Fixed value | Sh | Imm12 | RN | RD + 31 | 30 | 29 | 28 27 26 25 24 23 | 22 | 21 20 19 18 17 16 15 14 13 12 11 10 | 9 8 7 6 5 | 4 3 2 1 0 + */ + + constexpr u32 MtcBrAsm = 0xD61F0140; + constexpr u32 MtcMovAsm = 0x52800068; + constexpr u32 MtcAdrpAsm = 0x900003A0; + constexpr u32 MtcAddAsm = 0x91168000; + + ALWAYS_INLINE bool MemMtcGetGetTablePatternFn(u32 *ptr) { + /* This builds an address that gets returned, so the register must be x0 by convention. */ + return AsmCompareAddNoImm12(*ptr, MtcAddAsm); + } void Patch(uintptr_t mapped_nso, size_t nso_size); diff --git a/Source/hoc-clk/common/include/hocclk/config.h b/Source/hoc-clk/common/include/hocclk/config.h index 8b3700d6..825caf5d 100644 --- a/Source/hoc-clk/common/include/hocclk/config.h +++ b/Source/hoc-clk/common/include/hocclk/config.h @@ -79,6 +79,8 @@ typedef enum { KipConfigValue_eristaEmcMaxClock, KipConfigValue_eristaEmcMaxClock1, KipConfigValue_eristaEmcMaxClock2, + + KipConfigValue_stepMode, KipConfigValue_marikoEmcMaxClock, KipConfigValue_marikoEmcVddqVolt, KipConfigValue_emcDvbShift, @@ -91,6 +93,23 @@ typedef enum { KipConfigValue_t6_tRTW, KipConfigValue_t7_tWTR, KipConfigValue_t8_tREFI, + + KipConfigValue_timingEmcTbreak, + KipConfigValue_low_t6_tRTW, + KipConfigValue_low_t7_tWTR, + + KipConfigValue_t2_tRP_cap, + + KipConfigValue_read_latency_1333, + KipConfigValue_read_latency_1600, + KipConfigValue_read_latency_1866, + KipConfigValue_read_latency_2133, + + KipConfigValue_write_latency_1333, + KipConfigValue_write_latency_1600, + KipConfigValue_write_latency_1866, + KipConfigValue_write_latency_2133, + KipConfigValue_mem_burst_read_latency, KipConfigValue_mem_burst_write_latency, @@ -283,6 +302,8 @@ static inline const char* hocclkFormatConfigValue(HocClkConfigValue val, bool pr return pretty ? "Erista EMC Max Clock 2" : "erista_emc_max_clock1"; case KipConfigValue_eristaEmcMaxClock2: return pretty ? "Erista EMC Max Clock 3" : "erista_emc_max_clock2"; + case KipConfigValue_stepMode: + return pretty ? "Step Mode:" : "step_mode"; case KipConfigValue_marikoEmcMaxClock: return pretty ? "Mariko EMC Max Clock" : "mariko_emc_max_clock"; case KipConfigValue_marikoEmcVddqVolt: @@ -307,6 +328,35 @@ static inline const char* hocclkFormatConfigValue(HocClkConfigValue val, bool pr return pretty ? "t7 - tWTR" : "t7_twtr"; 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"; + + case KipConfigValue_read_latency_1333: + return pretty ? "1333 Read Latency" : "read_latency_1333"; + case KipConfigValue_read_latency_1600: + return pretty ? "1600 Read Latency" : "read_latency_1600"; + case KipConfigValue_read_latency_1866: + return pretty ? "1866 Read Latency" : "read_latency_1866"; + case KipConfigValue_read_latency_2133: + return pretty ? "2133 Read Latency" : "read_latency_2133"; + + case KipConfigValue_write_latency_1333: + return pretty ? "1333 Write Latency" : "write_latency_1333"; + case KipConfigValue_write_latency_1600: + return pretty ? "1600 Write Latency" : "write_latency_1600"; + case KipConfigValue_write_latency_1866: + return pretty ? "1866 Write Latency" : "write_latency_1866"; + case KipConfigValue_write_latency_2133: + return pretty ? "2133 Write Latency" : "write_latency_2133"; + case KipConfigValue_mem_burst_read_latency: return pretty ? "Memory Burst Read Latency" : "mem_burst_read_latency"; case KipConfigValue_mem_burst_write_latency: @@ -512,6 +562,7 @@ static inline uint64_t hocclkValidConfigValue(HocClkConfigValue val, uint64_t in case KipConfigValue_eristaEmcMaxClock: case KipConfigValue_eristaEmcMaxClock1: case KipConfigValue_eristaEmcMaxClock2: + case KipConfigValue_stepMode: case KipConfigValue_marikoEmcMaxClock: case KipConfigValue_marikoEmcVddqVolt: case KipConfigValue_emcDvbShift: @@ -523,6 +574,18 @@ 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: + case KipConfigValue_read_latency_1866: + case KipConfigValue_read_latency_2133: + case KipConfigValue_write_latency_1333: + case KipConfigValue_write_latency_1600: + case KipConfigValue_write_latency_1866: + case KipConfigValue_write_latency_2133: case KipConfigValue_mem_burst_read_latency: case KipConfigValue_mem_burst_write_latency: case KipConfigValue_eristaCpuUV: diff --git a/Source/hoc-clk/overlay/Makefile b/Source/hoc-clk/overlay/Makefile index 2477a223..634df530 100644 --- a/Source/hoc-clk/overlay/Makefile +++ b/Source/hoc-clk/overlay/Makefile @@ -39,7 +39,7 @@ include ${TOPDIR}/lib/libultrahand/ultrahand.mk # version control constants #--------------------------------------------------------------------------------- #TARGET_VERSION := $(shell git describe --dirty --always --tags) -APP_VERSION := 1.3.0 +APP_VERSION := 2.0.0 TARGET_VERSION := $(APP_VERSION) #--------------------------------------------------------------------------------- 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 7c9f1229..086ababb 100644 --- a/Source/hoc-clk/overlay/src/ui/gui/misc_gui.cpp +++ b/Source/hoc-clk/overlay/src/ui/gui/misc_gui.cpp @@ -423,7 +423,7 @@ void MiscGui::listUI() std::vector noNamedValues = {}; this->listElement->addItem(new tsl::elm::CategoryHeader("Settings")); - + tsl::elm::CustomDrawer* rebootSetWarning = new tsl::elm::CustomDrawer([](tsl::gfx::Renderer *renderer, s32 x, s32 y, s32 w, s32 h) { renderer->drawString("\uE150 Settings marked in orange", false, x + 20, y + 30, 18, tsl::style::color::ColorText); renderer->drawString("require a reboot to apply!", false, x + 20, y + 50, 18, tsl::style::color::ColorText); @@ -554,7 +554,7 @@ protected: {}, RamDisplayUnitValues, false - + ); addConfigButton( HocClkConfigValue_PollingIntervalMs, @@ -604,7 +604,7 @@ protected: false ); - + std::vector ramRFMeasurementMethods = { NamedValue("Actmon", MemoryFrequencyMeasurementMode_Actmon), NamedValue("PLL", MemoryFrequencyMeasurementMode_PLL), @@ -724,7 +724,7 @@ public: protected: void listUI() override { ValueThresholds thresholdsDisabled(0, 0); - + BaseMenuGui::refresh(); // get latest context if(!this->context) return; @@ -876,6 +876,14 @@ protected: true ); + std::vector stepMode = { + NamedValue("66MHz", 0), + NamedValue("100MHz", 1), + NamedValue("Jedec", 2), + }; + + addConfigButton(KipConfigValue_stepMode, "Step Mode", ValueRange(0, 0, 2, "", 0), "Step Mode", &thresholdsDisabled, {}, stepMode, false, true); + if (IsErista()) { tsl::elm::ListItem* freqSubmenu = new tsl::elm::ListItem("RAM Frequency Editor"); freqSubmenu->setTextColor(tsl::Color(255, 165, 0, 255)); @@ -889,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), @@ -950,14 +959,13 @@ 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); addConfigButton(KipConfigValue_marikoEmcMaxClock, "Ram Max Clock", ValueRange(0, 1, 1, "", 1), "Ram Max Clock", &thresholdsDisabled, {}, marikoMaxEmcClock, false, true); } + tsl::elm::ListItem* latenciesSubmenu = new tsl::elm::ListItem("RAM Latency Editor"); latenciesSubmenu->setTextColor(tsl::Color(255, 165, 0, 255)); latenciesSubmenu->setClickListener([](u64 keys) { @@ -1022,7 +1030,80 @@ 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); } @@ -1033,48 +1114,252 @@ public: RamLatenciesSubmenuGui() { } protected: + + void normalizeLatencies(const HocClkConfigValue keysArr[4]) { + uint32_t maxClock = (uint32_t)this->configList->values[KipConfigValue_marikoEmcMaxClock]; + uint32_t vals[4]; + + for (int i = 0; i < 4; i++) { + vals[i] = (uint32_t)this->configList->values[keysArr[i]]; + if (vals[i] == 0xFFFFFFFFu) vals[i] = maxClock; + } + + uint32_t currentLimit = 0; + for (int i = 3; i >= 0; i--) { + if (vals[i] != 0) { + if (currentLimit != 0 && vals[i] > currentLimit) { + vals[i] = currentLimit; + } + currentLimit = vals[i]; + } + } + + uint32_t last = 0; + for (int i = 0; i < 4; i++) { + if (vals[i] == 0) continue; + + if (vals[i] < last) vals[i] = last; + if (vals[i] > maxClock) vals[i] = maxClock; + + last = vals[i]; + } + + for (int i = 0; i < 4; i++) { + this->configList->values[keysArr[i]] = vals[i]; + } + } + void listUI() override { ValueThresholds thresholdsDisabled(0, 0); - this->listElement->addItem(new tsl::elm::CategoryHeader("Memory Latencies")); + if (IsErista()) { + std::vector rlLabels = { NamedValue("1333 RL", 28), NamedValue("1600 RL", 32), NamedValue("1866 RL", 36), NamedValue("2133 RL", 40) }; + std::vector wlLabels = { NamedValue("1333 WL", 12), NamedValue("1600 WL", 14), NamedValue("1866 WL", 16), NamedValue("2133 WL", 18) }; - std::vector rlLabels = { - NamedValue("1333 RL", 28), - NamedValue("1600 RL", 32), - NamedValue("1866 RL", 36), - NamedValue("2133 RL", 40) + addConfigButton(KipConfigValue_mem_burst_read_latency, "Read Latency", ValueRange(0, 6, 1, "", 0), "Read Latency", &thresholdsDisabled, {}, rlLabels, false, true); + addConfigButton(KipConfigValue_mem_burst_write_latency, "Write Latency", ValueRange(0, 6, 1, "", 0), "Write Latency", &thresholdsDisabled, {}, wlLabels, false, true); + return; + } + + Result rc = hocclkIpcGetConfigValues(this->configList); + if (R_FAILED(rc)) [[unlikely]] { + FatalGui::openWithResultCode("hocclkIpcGetConfigValues", rc); + return; + } + + uint32_t maxClock = (uint32_t)this->configList->values[KipConfigValue_marikoEmcMaxClock]; + RamDisplayUnit unit = (RamDisplayUnit)this->configList->values[HocClkConfigValue_RamDisplayUnit]; + + static const std::vector kFreqOptions = { + 1633000, 1666000, 1700000, 1733000, 1766000, 1800000, + 1833000, 1866000, 1900000, 1933000, 1966000, 1996800, 2000000, + 2033000, 2066000, 2100000, 2133000, 2166000, 2200000, 2233000, + 2266000, 2300000, 2333000, 2366000, 2400000, 2433000, 2466000, + 2500000, 2533000, 2566000, 2600000, 2633000, 2666000, 2700000, + 2733000, 2766000, 2800000, 2833000, 2866000, 2900000, 2933000, + 2966000, 3000000, 3033000, 3066000, 3100000, 3133000, 3166000, + 3200000, 3233000, 3266000, 3300000, }; - std::vector wlLabels = { - NamedValue("1333 WL", 12), - NamedValue("1600 WL", 14), - NamedValue("1866 WL", 16), - NamedValue("2133 WL", 18) + static const HocClkConfigValue kLatencyRKeys[4] = { + KipConfigValue_read_latency_1333, + KipConfigValue_read_latency_1600, + KipConfigValue_read_latency_1866, + KipConfigValue_read_latency_2133, + }; + static const HocClkConfigValue kLatencyWKeys[4] = { + KipConfigValue_write_latency_1333, + KipConfigValue_write_latency_1600, + KipConfigValue_write_latency_1866, + KipConfigValue_write_latency_2133, }; - addConfigButton( - KipConfigValue_mem_burst_read_latency, - "Read Latency", - ValueRange(0, 6, 1, "", 0), - "Read Latency", - &thresholdsDisabled, - {}, - rlLabels, - false, - true - ); + static const char* kTierLabels[4] = { "1333 Latency Max", "1600 Latency Max", "1866 Latency Max", "2133 Latency Max" }; - addConfigButton( - KipConfigValue_mem_burst_write_latency, - "Write Latency", - ValueRange(0, 6, 1, "", 0), - "Write Latency", - &thresholdsDisabled, - {}, - wlLabels, - false, - true - ); + auto buildNamedValues = [&](int tierIdx) -> std::vector { + std::vector nv; + nv.push_back(NamedValue("-", 0u)); + if (tierIdx == 3) { + nv.push_back(NamedValue(formatMemClockKhzLabel(maxClock, unit), maxClock)); + nv.push_back(NamedValue(formatMemClockKhzLabel(maxClock, unit), 0xFFFFFFFFu)); + } else { + for (uint32_t freq : kFreqOptions) { + if (freq > maxClock) continue; + nv.push_back(NamedValue(formatMemClockKhzLabel(freq, unit), freq)); + } + nv.push_back(NamedValue(formatMemClockKhzLabel(maxClock, unit), maxClock)); + nv.push_back(NamedValue(formatMemClockKhzLabel(maxClock, unit), 0xFFFFFFFFu)); + } + return nv; + }; + + auto makeValueText = [&](uint32_t rawVal) -> std::string { + if (rawVal == 0) return "-"; + if (rawVal == 0xFFFFFFFFu) return formatMemClockKhzLabel(maxClock, unit); + return formatMemClockKhzLabel(rawVal, unit); + }; + + auto addLatencyRow = [&](const char* label, int tierIdx, const HocClkConfigValue keysArr[4]) { + HocClkConfigValue thisKey = keysArr[tierIdx]; + uint32_t currentVal = (uint32_t)this->configList->values[thisKey]; + + tsl::elm::ListItem* item = new tsl::elm::ListItem(label); + item->setTextColor(tsl::Color(255, 165, 0, 255)); + item->setValue(makeValueText(currentVal)); + + item->setClickListener([this, tierIdx, thisKey, keysArr](u64 keys) -> bool { + if ((keys & HidNpadButton_A) == 0) + return false; + + uint32_t vals[4]; + for (int i = 0; i < 4; i++) + vals[i] = (uint32_t)this->configList->values[keysArr[i]]; + + uint32_t maxClock = (uint32_t)this->configList->values[KipConfigValue_marikoEmcMaxClock]; + RamDisplayUnit unit = (RamDisplayUnit)this->configList->values[HocClkConfigValue_RamDisplayUnit]; + + auto resolveVal = [maxClock](uint32_t v) -> uint32_t { + return (v == 0xFFFFFFFFu) ? maxClock : v; + }; + + if (tierIdx == 3) { + bool maxOccupied = false; + for (int i = 0; i < 3; i++) { + if (resolveVal(vals[i]) == maxClock) { + maxOccupied = true; + break; + } + } + + std::vector opts; + opts.push_back(NamedValue("-", 0u)); + + if (!maxOccupied) { + opts.push_back(NamedValue(formatMemClockKhzLabel(maxClock, unit), maxClock)); + } + + uint32_t displayCurrent = resolveVal(vals[3]); + if (maxOccupied && displayCurrent == maxClock) { + displayCurrent = 0; + } + + tsl::changeTo( + displayCurrent, + ValueRange(0, 0, 1, "", 1), + std::string("2133 Latency Max"), + [this, thisKey, keysArr](uint32_t chosen) -> bool { + this->configList->values[thisKey] = chosen; + Result rc = hocclkIpcSetConfigValues(this->configList); + if (R_FAILED(rc)) { + FatalGui::openWithResultCode("hocclkIpcSetConfigValues", rc); + return false; + } + sendKipData(); + this->lastContextUpdate = armGetSystemTick(); + return true; + }, + ValueThresholds(), false, + std::map{}, + opts, + false, + false + ); + return true; + } + + uint32_t lowerBound = 0; + for (int i = 0; i < tierIdx; i++) { + uint32_t v = resolveVal(vals[i]); + if (v != 0 && v > lowerBound) + lowerBound = v; + } + + uint32_t upperBound = 0; + for (int i = tierIdx + 1; i < 4; i++) { + uint32_t v; + if (i == 3) { + uint32_t r = resolveVal(vals[i]); + v = (r != 0) ? maxClock : 0; + } else { + v = resolveVal(vals[i]); + } + if (v != 0 && (upperBound == 0 || v < upperBound)) + upperBound = v; + } + + std::vector opts; + opts.push_back(NamedValue("-", 0u)); + for (uint32_t freq : kFreqOptions) { + if (freq <= lowerBound) continue; + if (freq > maxClock) continue; + if (upperBound != 0 && freq >= upperBound) continue; + opts.push_back(NamedValue(formatMemClockKhzLabel(freq, unit), freq)); + } + + uint32_t displayCurrent = resolveVal(vals[tierIdx]); + bool currentInList = false; + for (auto& nv : opts) + if (nv.value == displayCurrent) { currentInList = true; break; } + if (!currentInList) displayCurrent = 0; + + tsl::changeTo( + displayCurrent, + ValueRange(0, 0, 1, "", 1), + std::string("Latency Max"), + [this, thisKey, keysArr](uint32_t chosen) -> bool { + this->configList->values[thisKey] = chosen; + normalizeLatencies(keysArr); + Result rc = hocclkIpcSetConfigValues(this->configList); + if (R_FAILED(rc)) { + FatalGui::openWithResultCode("hocclkIpcSetConfigValues", rc); + return false; + } + sendKipData(); + this->lastContextUpdate = armGetSystemTick(); + return true; + }, + ValueThresholds(), false, + std::map{}, + opts, + false, + false + ); + return true; + }); + + this->listElement->addItem(item); + this->configButtons[thisKey] = item; + this->configRanges[thisKey] = ValueRange(0, 0, 1, "", 1); + this->configNamedValues[thisKey] = buildNamedValues(tierIdx); + }; + + this->listElement->addItem(new tsl::elm::CategoryHeader("Read Latency")); + for (int i = 0; i < 4; i++) + addLatencyRow(kTierLabels[i], i, kLatencyRKeys); + + this->listElement->addItem(new tsl::elm::CategoryHeader("Write Latency")); + for (int i = 0; i < 4; i++) + addLatencyRow(kTierLabels[i], i, kLatencyWKeys); } }; @@ -1373,7 +1658,7 @@ protected: for (auto& nv : eristaMaxEmcClock) if (nv.name != "Disabled") nv.name = formatMemClockKhzLabel(nv.value, unit); - + addConfigButtonS(KipConfigValue_eristaEmcMaxClock, "", ValueRange(0, 1, 1, "", 1), "", &eristaRamThresholds, {}, eristaMaxEmcClock, false, A_BTN, true); addConfigButtonS(KipConfigValue_eristaEmcMaxClock1, "", ValueRange(0, 1, 1, "", 1), "", &eristaRamThresholds, {}, eristaMaxEmcClock, false, A_BTN, true); addConfigButtonS(KipConfigValue_eristaEmcMaxClock2, "", ValueRange(0, 1, 1, "", 1), "", &eristaRamThresholds, {}, eristaMaxEmcClock, false, A_BTN, true); diff --git a/Source/hoc-clk/sysmodule/src/kip.cpp b/Source/hoc-clk/sysmodule/src/kip.cpp index b1faabc2..5b5b3213 100644 --- a/Source/hoc-clk/sysmodule/src/kip.cpp +++ b/Source/hoc-clk/sysmodule/src/kip.cpp @@ -21,7 +21,7 @@ namespace kip { bool kipAvailable = false; - + void SetKipData() { // TODO: figure out if this REALLY causes issues (i doubt it) @@ -70,6 +70,23 @@ namespace kip { CUST_WRITE_FIELD_BATCH(&table, t6_tRTW, config::GetConfigValue(KipConfigValue_t6_tRTW)); 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)); + CUST_WRITE_FIELD_BATCH(&table, readLatency1600, config::GetConfigValue(KipConfigValue_read_latency_1600)); + CUST_WRITE_FIELD_BATCH(&table, readLatency1866, config::GetConfigValue(KipConfigValue_read_latency_1866)); + CUST_WRITE_FIELD_BATCH(&table, readLatency2133, config::GetConfigValue(KipConfigValue_read_latency_2133)); + + CUST_WRITE_FIELD_BATCH(&table, writeLatency1333, config::GetConfigValue(KipConfigValue_write_latency_1333)); + CUST_WRITE_FIELD_BATCH(&table, writeLatency1600, config::GetConfigValue(KipConfigValue_write_latency_1600)); + CUST_WRITE_FIELD_BATCH(&table, writeLatency1866, config::GetConfigValue(KipConfigValue_write_latency_1866)); + CUST_WRITE_FIELD_BATCH(&table, writeLatency2133, config::GetConfigValue(KipConfigValue_write_latency_2133)); + CUST_WRITE_FIELD_BATCH(&table, mem_burst_read_latency, config::GetConfigValue(KipConfigValue_mem_burst_read_latency)); CUST_WRITE_FIELD_BATCH(&table, mem_burst_write_latency, config::GetConfigValue(KipConfigValue_mem_burst_write_latency)); CUST_WRITE_FIELD_BATCH(&table, eristaCpuUV, config::GetConfigValue(KipConfigValue_eristaCpuUV)); @@ -166,7 +183,7 @@ namespace kip { configValues.values[HocClkConfigValue_IsFirstLoad] = (u64)false; notification::writeNotification("Horizon OC has been installed"); } - + configValues.values[KipCrc32] = (u64)crc32::checksum_file("sdmc:/atmosphere/kips/hoc.kip"); // write checksum // configValues.values[KipConfigValue_mtcConf] = cust_get_mtc_conf(&table); configValues.values[KipConfigValue_hpMode] = cust_get_hp_mode(&table); @@ -187,6 +204,23 @@ namespace kip { configValues.values[KipConfigValue_t6_tRTW] = cust_get_tRTW(&table); configValues.values[KipConfigValue_t7_tWTR] = cust_get_tWTR(&table); 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); + configValues.values[KipConfigValue_read_latency_1600] = cust_get_read_latency_1600(&table); + configValues.values[KipConfigValue_read_latency_1866] = cust_get_read_latency_1866(&table); + configValues.values[KipConfigValue_read_latency_2133] = cust_get_read_latency_2133(&table); + + configValues.values[KipConfigValue_write_latency_1333] = cust_get_write_latency_1333(&table); + configValues.values[KipConfigValue_write_latency_1600] = cust_get_write_latency_1600(&table); + configValues.values[KipConfigValue_write_latency_1866] = cust_get_write_latency_1866(&table); + configValues.values[KipConfigValue_write_latency_2133] = cust_get_write_latency_2133(&table); + configValues.values[KipConfigValue_mem_burst_read_latency] = cust_get_burst_read_lat(&table); configValues.values[KipConfigValue_mem_burst_write_latency] = cust_get_burst_write_lat(&table); diff --git a/Source/hoc-clk/sysmodule/src/kip.hpp b/Source/hoc-clk/sysmodule/src/kip.hpp index 26729fdc..8a57f2a2 100644 --- a/Source/hoc-clk/sysmodule/src/kip.hpp +++ b/Source/hoc-clk/sysmodule/src/kip.hpp @@ -30,7 +30,7 @@ namespace kip { extern bool kipAvailable; - + typedef struct { u8 cust[4]; u32 custRev; @@ -40,6 +40,7 @@ namespace kip { u32 eristaEmcMaxClock; u32 eristaEmcMaxClock1; u32 eristaEmcMaxClock2; + u32 stepMode; u32 marikoEmcMaxClock; u32 marikoEmcVddqVolt; u32 emcDvbShift; @@ -53,6 +54,16 @@ namespace kip { u32 t7_tWTR; u32 t8_tREFI; + 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; + u32 mem_burst_read_latency; u32 mem_burst_write_latency; @@ -201,6 +212,7 @@ namespace kip { static inline bool cust_set_erista_emc_max(const char* p, u32 v) { CUST_WRITE_FIELD(p, eristaEmcMaxClock, v); } static inline bool cust_set_erista_emc_max1(const char* p, u32 v) { CUST_WRITE_FIELD(p, eristaEmcMaxClock1, v); } static inline bool cust_set_erista_emc_max2(const char* p, u32 v) { CUST_WRITE_FIELD(p, eristaEmcMaxClock2, v); } + static inline bool cust_set_step_mode(const char* p, u32 v) { CUST_WRITE_FIELD(p, stepMode, v); } static inline bool cust_set_mariko_emc_max(const char* p, u32 v) { CUST_WRITE_FIELD(p, marikoEmcMaxClock, v); } static inline bool cust_set_mariko_emc_vddq(const char* p, u32 v) { CUST_WRITE_FIELD(p, marikoEmcVddqVolt, v); } static inline bool cust_set_emc_dvb_shift(const char* p, u32 v) { CUST_WRITE_FIELD(p, emcDvbShift, v); } @@ -213,8 +225,23 @@ namespace kip { static inline bool cust_set_tRTW(const char* p, u32 v) { CUST_WRITE_FIELD(p, t6_tRTW, v); } 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); } + + static inline bool cust_set_read_latency_1333(const char* p, u32 v) { CUST_WRITE_FIELD(p, readLatency1333, v); } + static inline bool cust_set_read_latency_1600(const char* p, u32 v) { CUST_WRITE_FIELD(p, readLatency1600, v); } + static inline bool cust_set_read_latency_1866(const char* p, u32 v) { CUST_WRITE_FIELD(p, readLatency1866, v); } + static inline bool cust_set_read_latency_2133(const char* p, u32 v) { CUST_WRITE_FIELD(p, readLatency2133, v); } + + static inline bool cust_set_write_latency_1333(const char* p, u32 v) { CUST_WRITE_FIELD(p, writeLatency1333, v); } + static inline bool cust_set_write_latency_1600(const char* p, u32 v) { CUST_WRITE_FIELD(p, writeLatency1600, v); } + static inline bool cust_set_write_latency_1866(const char* p, u32 v) { CUST_WRITE_FIELD(p, writeLatency1866, v); } + static inline bool cust_set_write_latency_2133(const char* p, u32 v) { CUST_WRITE_FIELD(p, writeLatency2133, v); } + static inline bool cust_set_burst_read_lat(const char* p, u32 v) { CUST_WRITE_FIELD(p, mem_burst_read_latency, v); } static inline bool cust_set_burst_write_lat(const char* p, u32 v) { CUST_WRITE_FIELD(p, mem_burst_write_latency, v); } @@ -272,6 +299,7 @@ namespace kip { static inline u32 cust_get_erista_emc_max(const CustomizeTable* t) { return CUST_GET_FIELD(t, eristaEmcMaxClock); } static inline u32 cust_get_erista_emc_max1(const CustomizeTable* t) { return CUST_GET_FIELD(t, eristaEmcMaxClock1); } static inline u32 cust_get_erista_emc_max2(const CustomizeTable* t) { return CUST_GET_FIELD(t, eristaEmcMaxClock2); } + static inline u32 cust_get_step_mode(const CustomizeTable* t) { return CUST_GET_FIELD(t, stepMode); } static inline u32 cust_get_mariko_emc_max(const CustomizeTable* t) { return CUST_GET_FIELD(t, marikoEmcMaxClock); } static inline u32 cust_get_mariko_emc_vddq(const CustomizeTable* t) { return CUST_GET_FIELD(t, marikoEmcVddqVolt); } static inline u32 cust_get_emc_dvb_shift(const CustomizeTable* t) { return CUST_GET_FIELD(t, emcDvbShift); } @@ -284,8 +312,23 @@ namespace kip { static inline u32 cust_get_tRTW(const CustomizeTable* t) { return CUST_GET_FIELD(t, t6_tRTW); } 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); } + + static inline u32 cust_get_read_latency_1333(const CustomizeTable* t) { return CUST_GET_FIELD(t, readLatency1333); } + static inline u32 cust_get_read_latency_1600(const CustomizeTable* t) { return CUST_GET_FIELD(t, readLatency1600); } + static inline u32 cust_get_read_latency_1866(const CustomizeTable* t) { return CUST_GET_FIELD(t, readLatency1866); } + static inline u32 cust_get_read_latency_2133(const CustomizeTable* t) { return CUST_GET_FIELD(t, readLatency2133); } + + static inline u32 cust_get_write_latency_1333(const CustomizeTable* t) { return CUST_GET_FIELD(t, writeLatency1333); } + static inline u32 cust_get_write_latency_1600(const CustomizeTable* t) { return CUST_GET_FIELD(t, writeLatency1600); } + static inline u32 cust_get_write_latency_1866(const CustomizeTable* t) { return CUST_GET_FIELD(t, writeLatency1866); } + static inline u32 cust_get_write_latency_2133(const CustomizeTable* t) { return CUST_GET_FIELD(t, writeLatency2133); } + static inline u32 cust_get_burst_read_lat(const CustomizeTable* t) { return CUST_GET_FIELD(t, mem_burst_read_latency); } static inline u32 cust_get_burst_write_lat(const CustomizeTable* t) { return CUST_GET_FIELD(t, mem_burst_write_latency); }