diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/customize.cpp b/Source/Atmosphere/stratosphere/loader/source/oc/customize.cpp index 2faab95e..153c08f3 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/customize.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/customize.cpp @@ -28,7 +28,7 @@ volatile CustomizeTable C = { * NO_ADJ_ALL: No timing adjustment for both Erista and Mariko. * CUSTOMIZED_ALL: Replace with values in customized table for both Erista and Mariko. */ -.mtcConf = CUSTOM_ADJ_ALL, +.mtcConf = AUTO_ADJ_ALL, /* Common: * - Boost Clock in kHz: @@ -36,7 +36,7 @@ volatile CustomizeTable C = { * Boost clock will be applied when applications request higher CPU frequency for quicker loading. * This will be set regardless of whether sys-clk is enabled. */ -.commonCpuBoostClock = 2295000, +.commonCpuBoostClock = 1785000, /* - EMC Vddq (Erista Only) and RAM Vdd2 Voltage in uV * Range: 1100'000 to 1250'000 uV * Erista Default(HOS): 1125'000 (bootloader: 1100'000) @@ -66,7 +66,7 @@ volatile CustomizeTable C = { * - Max Voltage in mV: * Default voltage: 1120 */ -.marikoCpuMaxVolt = 1235, +.marikoCpuMaxVolt = 1120, /* Mariko EMC(RAM): * - RAM Clock in kHz: @@ -85,7 +85,7 @@ volatile CustomizeTable C = { * Not enabled by default. * This will not work without sys-clk-OC. */ -.marikoEmcVddqVolt = 640000, +.marikoEmcVddqVolt = 600000, .marikoCpuUV = 0, @@ -97,29 +97,29 @@ volatile CustomizeTable C = { .marikoCpuHighUV = 0, -.cpuMaxFreq = 1963500, +.cpuMaxFreq = 1785000, -.gpuMaxFreq = 1267200, +.gpuMaxFreq = 921600, + +.gpuVmax = 800, .marikoEmcDvbShift = 0, -.ramTimingPresetOne = 4, // T1-3 EOS +.ramTimingPresetOne = 0, // T1-3 EOS -.ramTimingPresetTwo = 2, // T4 +.ramTimingPresetTwo = 0, // T4 -.ramTimingPresetThree = 2, // Try all values from 0-6 +.ramTimingPresetThree = 0, // Try all values from 0-6 -.ramTimingPresetFour = 2, // EOS T5 +.ramTimingPresetFour = 0, // EOS T5 -.ramTimingPresetFive = 2, // EOS T7 +.ramTimingPresetFive = 0, // EOS T7 -.ramTimingPresetSix = 2, // EOS T8 +.ramTimingPresetSix = 0, // EOS T8 -.ramTimingPresetSeven = 2, - -.marikoGpuVoltArray = {635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 660, 685, 715, 745, 765, 785}, - -.marikoGpuVoltArray_RAM_OC = {635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 660, 685, 715, 745, 765, 785}, +.ramTimingPresetSeven = 0, + // +.marikoGpuVoltArray = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, @@ -207,7 +207,7 @@ volatile CustomizeTable C = { { 2601000, { 1805897, -36331, 113 }, { 1235000 } }, { 2703000, { 1857394, -37019, 113 }, { 1235000 } }, { 2805000, { 1908891, -37707, 113 }, { 1235000 } }, - { 2907000, { 1960388, -38395, 113 }, { 1250000 } }, + { 2907000, { 1960388, -38395, 113 }, { 1235000 } }, }, /* - Erista GPU DVFS Table: @@ -294,6 +294,32 @@ volatile CustomizeTable C = { { 1305600, {}, { 1163644, -12688, -648, 0, 1077, 40 } }, }, +.marikoGpuDvfsTableUv3 = { // This is for manually defined voltages, ignore the 0v, that means freq not enabled + { 76800, {}, { 0, } }, + { 153600, {}, { 0, } }, + { 230400, {}, { 0, } }, + { 307200, {}, { 0, } }, + { 384000, {}, { 0, } }, + { 460800, {}, { 0, } }, + { 537600, {}, { 0, } }, + { 614400, {}, { 0, } }, + { 691200, {}, { 0, } }, + { 768000, {}, { 0, } }, + { 844800, {}, { 0, } }, + { 921600, {}, { 0, } }, + { 998400, {}, { 0, } }, + { 1075200, {}, { 0, } }, + { 1152000, {}, { 0, } }, + { 1228800, {}, { 0, } }, + { 1267200, {}, { 0, } }, + { 1305600, {}, { 0, } }, + { 1344000, {}, { 0, } }, + { 1382400, {}, { 0, } }, + { 1420800, {}, { 0, } }, + { 1459200, {}, { 0, } }, + { 1497600, {}, { 0, } }, + { 1536000, {}, { 0, } }, +}, //.eristaMtcTable = const_cast(&EristaMtcTablePlaceholder), //.marikoMtcTable = const_cast(&MarikoMtcTablePlaceholder), .eristaCPUvMax = 1300, diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/customize.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/customize.hpp index 9389d663..a0ae51a8 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/customize.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/customize.hpp @@ -60,6 +60,7 @@ typedef struct CustomizeTable { u32 cpuMaxFreq; u32 gpuMaxFreq; + u32 gpuVmax; // advanced config u32 marikoEmcDvbShift; u32 ramTimingPresetOne; @@ -70,8 +71,7 @@ typedef struct CustomizeTable { u32 ramTimingPresetSix; u32 ramTimingPresetSeven; // - u32 marikoGpuVoltArray[18]; - u32 marikoGpuVoltArray_RAM_OC[18]; + u32 marikoGpuVoltArray[24]; CustomizeCpuDvfsTable eristaCpuDvfsTable; @@ -81,6 +81,7 @@ typedef struct CustomizeTable { CustomizeGpuDvfsTable marikoGpuDvfsTable; CustomizeGpuDvfsTable marikoGpuDvfsTableSLT; CustomizeGpuDvfsTable marikoGpuDvfsTableHiOPT; + CustomizeGpuDvfsTable marikoGpuDvfsTableUv3; //EristaMtcTable* eristaMtcTable; //MarikoMtcTable* marikoMtcTable; u32 eristaCPUvMax; diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.cpp b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.cpp index de701a67..1347e9c3 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.cpp @@ -95,6 +95,7 @@ void SafetyCheck() { u32 marikoCpuDvfsMaxFreq = static_cast(C.marikoCpuUV ? GetDvfsTableLastEntry(C.marikoCpuDvfsTableSLT)->freq : GetDvfsTableLastEntry(C.marikoCpuDvfsTable)->freq); u32 eristaGpuDvfsMaxFreq = static_cast(GetDvfsTableLastEntry(C.eristaGpuDvfsTable)->freq); u32 marikoGpuDvfsMaxFreq; + u32 temporaryMaxFreqForCalculation = C.gpuMaxFreq; switch (C.marikoGpuUV) { case 0: marikoGpuDvfsMaxFreq = static_cast(GetDvfsTableLastEntry(C.marikoGpuDvfsTable)->freq); @@ -105,6 +106,10 @@ void SafetyCheck() { case 2: marikoGpuDvfsMaxFreq = static_cast(GetDvfsTableLastEntry(C.marikoGpuDvfsTableHiOPT)->freq); break; + case 3: + marikoGpuDvfsMaxFreq = static_cast(GetDvfsTableLastEntry(C.marikoGpuDvfsTableUv3)->freq); + temporaryMaxFreqForCalculation = 1536'000; + break; default: marikoGpuDvfsMaxFreq = static_cast(GetDvfsTableLastEntry(C.marikoGpuDvfsTable)->freq); break; @@ -120,8 +125,8 @@ void SafetyCheck() { { C.marikoEmcVddqVolt, 550'000, C.marikoVDDQMax + 1 }, { eristaCpuDvfsMaxFreq, 1785'000, C.cpuMaxFreq + 1 }, { marikoCpuDvfsMaxFreq, 1785'000, C.cpuMaxFreq + 1 }, - { eristaGpuDvfsMaxFreq, 768'000, C.gpuMaxFreq + 1 }, - { marikoGpuDvfsMaxFreq, 768'000, C.gpuMaxFreq + 1 }, + { eristaGpuDvfsMaxFreq, 76'800, C.gpuMaxFreq + 1 }, + { marikoGpuDvfsMaxFreq, 76'800, temporaryMaxFreqForCalculation + 1 }, }; for (auto& i : validators) { diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.hpp index d5fef376..9d9fb3a1 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.hpp @@ -19,234 +19,297 @@ #include "../oc_common.hpp" #include "pcv_common.hpp" -namespace ams::ldr::oc::pcv { +namespace ams::ldr::oc::pcv +{ -namespace mariko { - constexpr cvb_entry_t CpuCvbTableDefault[] = { - // CPUB01_CVB_TABLE - { 204000, { 721589, -12695, 27 }, {} }, - { 306000, { 747134, -14195, 27 }, {} }, - { 408000, { 776324, -15705, 27 }, {} }, - { 510000, { 809160, -17205, 27 }, {} }, - { 612000, { 845641, -18715, 27 }, {} }, - { 714000, { 885768, -20215, 27 }, {} }, - { 816000, { 929540, -21725, 27 }, {} }, - { 918000, { 976958, -23225, 27 }, {} }, - { 1020000, { 1028021, -24725, 27 }, { 1120000 } }, - { 1122000, { 1082730, -26235, 27 }, { 1120000 } }, - { 1224000, { 1141084, -27735, 27 }, { 1120000 } }, - { 1326000, { 1203084, -29245, 27 }, { 1120000 } }, - { 1428000, { 1268729, -30745, 27 }, { 1120000 } }, - { 1581000, { 1374032, -33005, 27 }, { 1120000 } }, - { 1683000, { 1448791, -34505, 27 }, { 1120000 } }, - { 1785000, { 1527196, -36015, 27 }, { 1120000 } }, - { 1887000, { 1609246, -37515, 27 }, { 1120000 } }, - { 1963500, { 1675751, -38635, 27 }, { 1120000 } }, - { }, - }; + namespace mariko + { + constexpr cvb_entry_t CpuCvbTableDefault[] = { + // CPUB01_CVB_TABLE + {204000, {721589, -12695, 27}, {}}, + {306000, {747134, -14195, 27}, {}}, + {408000, {776324, -15705, 27}, {}}, + {510000, {809160, -17205, 27}, {}}, + {612000, {845641, -18715, 27}, {}}, + {714000, {885768, -20215, 27}, {}}, + {816000, {929540, -21725, 27}, {}}, + {918000, {976958, -23225, 27}, {}}, + {1020000, {1028021, -24725, 27}, {1120000}}, + {1122000, {1082730, -26235, 27}, {1120000}}, + {1224000, {1141084, -27735, 27}, {1120000}}, + {1326000, {1203084, -29245, 27}, {1120000}}, + {1428000, {1268729, -30745, 27}, {1120000}}, + {1581000, {1374032, -33005, 27}, {1120000}}, + {1683000, {1448791, -34505, 27}, {1120000}}, + {1785000, {1527196, -36015, 27}, {1120000}}, + {1887000, {1609246, -37515, 27}, {1120000}}, + {1963500, {1675751, -38635, 27}, {1120000}}, + {}, + }; - constexpr u16 CpuMinVolts[] = { 800, 637, 620, 610 }; + constexpr u16 CpuMinVolts[] = {800, 637, 620, 610}; - constexpr u32 CpuClkOfficial = 1963'500; - constexpr u32 CpuVoltOfficial = 1120; + constexpr u32 CpuClkOfficial = 1963'500; + constexpr u32 CpuVoltOfficial = 1120; - constexpr cvb_entry_t GpuCvbTableDefault[] = { - // GPUB01_NA_CVB_TABLE - { 76800, {}, { 610000, } }, - { 153600, {}, { 610000, } }, - { 230400, {}, { 610000, } }, - { 307200, {}, { 610000, } }, - { 384000, {}, { 610000, } }, - { 460800, {}, { 610000, } }, - { 537600, {}, { 801688, -10900, -163, 298, -10599, 162 } }, - { 614400, {}, { 824214, -5743, -452, 238, -6325, 81 } }, - { 691200, {}, { 848830, -3903, -552, 119, -4030, -2 } }, - { 768000, {}, { 891575, -4409, -584, 0, -2849, 39 } }, - { 844800, {}, { 940071, -5367, -602, -60, -63, -93 } }, - { 921600, {}, { 986765, -6637, -614, -179, 1905, -13 } }, - { 998400, {}, { 1098475, -13529, -497, -179, 3626, 9 } }, - { 1075200, {}, { 1163644, -12688, -648, 0, 1077, 40 } }, - { 1152000, {}, { 1204812, -9908, -830, 0, 1469, 110 } }, - { 1228800, {}, { 1277303, -11675, -859, 0, 3722, 313 } }, - { 1267200, {}, { 1335531, -12567, -867, 0, 3681, 559 } }, - { }, - }; + constexpr cvb_entry_t GpuCvbTableDefault[] = { + // GPUB01_NA_CVB_TABLE + {76800, {}, { + 610000, + }}, + {153600, {}, { + 610000, + }}, + {230400, {}, { + 610000, + }}, + {307200, {}, { + 610000, + }}, + {384000, {}, { + 610000, + }}, + {460800, {}, { + 610000, + }}, + {537600, {}, {801688, -10900, -163, 298, -10599, 162}}, + {614400, {}, {824214, -5743, -452, 238, -6325, 81}}, + {691200, {}, {848830, -3903, -552, 119, -4030, -2}}, + {768000, {}, {891575, -4409, -584, 0, -2849, 39}}, + {844800, {}, {940071, -5367, -602, -60, -63, -93}}, + {921600, {}, {986765, -6637, -614, -179, 1905, -13}}, + {998400, {}, {1098475, -13529, -497, -179, 3626, 9}}, + {1075200, {}, {1163644, -12688, -648, 0, 1077, 40}}, + {1152000, {}, {1204812, -9908, -830, 0, 1469, 110}}, + {1228800, {}, {1277303, -11675, -859, 0, 3722, 313}}, + {1267200, {}, {1335531, -12567, -867, 0, 3681, 559}}, + {}, + }; - constexpr u32 GpuClkPllLimit = 1300'000'000; + constexpr u32 GpuClkPllLimit = 1300'000'000; - /* GPU Max Clock asm Pattern: - * - * MOV W11, #0x1000 MOV (wide immediate) 0x1000 0xB (11) - * sf | opc | | hw | imm16 | 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 - * 0 | 1 0 | 1 0 0 1 0 1| 0 0| 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 |0 1 0 1 1 - * - * MOVK W11, #0xE, LSL#16 16 0xE 0xB (11) - * sf | opc | | hw | imm16 | 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 - * 0 | 1 1 | 1 0 0 1 0 1| 0 1| 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 |0 1 0 1 1 - */ - inline constexpr u32 asm_pattern[] = { 0x52820000, 0x72A001C0 }; - inline auto asm_compare_no_rd = [](u32 ins1, u32 ins2) { return ((ins1 ^ ins2) >> 5) == 0; }; - inline auto asm_get_rd = [](u32 ins) { return ins & ((1 << 5) - 1); }; - inline auto asm_set_rd = [](u32 ins, u8 rd) { return (ins & 0xFFFFFFE0) | (rd & 0x1F); }; - inline auto asm_set_imm16 = [](u32 ins, u16 imm) { return (ins & 0xFFE0001F) | ((imm & 0xFFFF) << 5); }; + /* GPU Max Clock asm Pattern: + * + * MOV W11, #0x1000 MOV (wide immediate) 0x1000 0xB (11) + * sf | opc | | hw | imm16 | 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 + * 0 | 1 0 | 1 0 0 1 0 1| 0 0| 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 |0 1 0 1 1 + * + * MOVK W11, #0xE, LSL#16 16 0xE 0xB (11) + * sf | opc | | hw | imm16 | 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 + * 0 | 1 1 | 1 0 0 1 0 1| 0 1| 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 |0 1 0 1 1 + */ + inline constexpr u32 asm_pattern[] = {0x52820000, 0x72A001C0}; + inline auto asm_compare_no_rd = [](u32 ins1, u32 ins2) + { return ((ins1 ^ ins2) >> 5) == 0; }; + inline auto asm_get_rd = [](u32 ins) + { return ins & ((1 << 5) - 1); }; + inline auto asm_set_rd = [](u32 ins, u8 rd) + { return (ins & 0xFFFFFFE0) | (rd & 0x1F); }; + inline auto asm_set_imm16 = [](u32 ins, u16 imm) + { return (ins & 0xFFE0001F) | ((imm & 0xFFFF) << 5); }; - inline bool GpuMaxClockPatternFn(u32* ptr32) { - return asm_compare_no_rd(*ptr32, asm_pattern[0]); - } - - constexpr emc_dvb_dvfs_table_t EmcDvbTableDefault[] = { - { 204000, { 637, 637, 637, } }, - { 408000, { 637, 637, 637, } }, - { 800000, { 637, 637, 637, } }, - { 1065600, { 637, 637, 637, } }, - { 1331200, { 650, 637, 637, } }, - { 1600000, { 675, 650, 637, } }, - }; - - 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; - - void Patch(uintptr_t mapped_nso, size_t nso_size); - -} - -namespace erista { - constexpr cvb_entry_t CpuCvbTableDefault[] = { - // CPU_PLL_CVB_TABLE_ODN - { 204000, { 721094 }, {} }, - { 306000, { 754040 }, {} }, - { 408000, { 786986 }, {} }, - { 510000, { 819932 }, {} }, - { 612000, { 852878 }, {} }, - { 714000, { 885824 }, {} }, - { 816000, { 918770 }, {} }, - { 918000, { 951716 }, {} }, - { 1020000, { 984662 }, { -2875621, 358099, -8585 } }, - { 1122000, { 1017608 }, { -52225, 104159, -2816 } }, - { 1224000, { 1050554 }, { 1076868, 8356, -727 } }, - { 1326000, { 1083500 }, { 2208191, -84659, 1240 } }, - { 1428000, { 1116446 }, { 2519460, -105063, 1611 } }, - { 1581000, { 1130000 }, { 2889664, -122173, 1834 } }, - { 1683000, { 1168000 }, { 5100873, -279186, 4747 } }, - { 1785000, { 1227500 }, { 5100873, -279186, 4747 } }, - { }, - }; - - constexpr u32 CpuVoltL4T = 1235'000; - - constexpr u16 CpuMinVolts[] = { 950, 850, 825, 810 }; - - inline bool CpuMaxVoltPatternFn(u32* ptr32) { - u32 val = *ptr32; - return (val == 1132 || val == 1170 || val == 1227); - } - - constexpr u32 GpuClkPllLimit = 921'600'000; - - /* GPU Max Clock asm Pattern: - * - * MOV W11, #0x1000 MOV (wide immediate) 0x1000 0xB (11) - * sf | opc | | hw | imm16 | 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 - * 0 | 1 0 | 1 0 0 1 0 1| 0 0| 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 |0 1 0 1 1 - * - * MOVK W11, #0xE, LSL#16 16 0xE 0xB (11) - * sf | opc | | hw | imm16 | 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 - * 0 | 1 1 | 1 0 0 1 0 1| 0 1| 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 |0 1 0 1 1 - */ - inline constexpr u32 asm_pattern[] = { 0x52820000, 0x72A001C0 }; - inline auto asm_compare_no_rd = [](u32 ins1, u32 ins2) { return ((ins1 ^ ins2) >> 5) == 0; }; - inline auto asm_get_rd = [](u32 ins) { return ins & ((1 << 5) - 1); }; - inline auto asm_set_rd = [](u32 ins, u8 rd) { return (ins & 0xFFFFFFE0) | (rd & 0x1F); }; - inline auto asm_set_imm16 = [](u32 ins, u16 imm) { return (ins & 0xFFE0001F) | ((imm & 0xFFFF) << 5); }; - - inline bool GpuMaxClockPatternFn(u32* ptr32) { - return asm_compare_no_rd(*ptr32, asm_pattern[0]); - } - - constexpr cvb_entry_t GpuCvbTableDefault[] = { - // NA_FREQ_CVB_TABLE - { 76800, { }, { 814294, 8144, -940, 808, -21583, 226 } }, - { 153600, { }, { 856185, 8144, -940, 808, -21583, 226 } }, - { 230400, { }, { 898077, 8144, -940, 808, -21583, 226 } }, - { 307200, { }, { 939968, 8144, -940, 808, -21583, 226 } }, - { 384000, { }, { 981860, 8144, -940, 808, -21583, 226 } }, - { 460800, { }, { 1023751, 8144, -940, 808, -21583, 226 } }, - { 537600, { }, { 1065642, 8144, -940, 808, -21583, 226 } }, - { 614400, { }, { 1107534, 8144, -940, 808, -21583, 226 } }, - { 691200, { }, { 1149425, 8144, -940, 808, -21583, 226 } }, - { 768000, { }, { 1191317, 8144, -940, 808, -21583, 226 } }, - { 844800, { }, { 1233208, 8144, -940, 808, -21583, 226 } }, - { 921600, { }, { 1275100, 8144, -940, 808, -21583, 226 } }, - { }, - }; - - constexpr u32 MemVoltHOS = 1125'000; - constexpr u32 EmcClkPllmLimit = 1866'000'000; - - constexpr u32 MTC_TABLE_REV = 7; - - void Patch(uintptr_t mapped_nso, size_t nso_size); -} - -template -Result CpuFreqCvbTable(u32* ptr) { - cvb_entry_t* default_table = isMariko ? (cvb_entry_t *)(&mariko::CpuCvbTableDefault) : (cvb_entry_t *)(&erista::CpuCvbTableDefault); - cvb_entry_t* customize_table = const_cast(isMariko ? (C.marikoCpuUV ? C.marikoCpuDvfsTableSLT : C.marikoCpuDvfsTable) : C.eristaCpuDvfsTable); - - u32 cpu_max_volt = isMariko ? C.marikoCpuMaxVolt : C.eristaCpuMaxVolt; - u32 cpu_freq_threshold = 1020'000; - if (isMariko) { - cpu_freq_threshold = C.marikoCpuUV ? 2193'000 : 2091'000; - } else { - cpu_freq_threshold = cpu_max_volt >= 1235 ? 1887'000 : 1428'000; - } - - size_t default_entry_count = GetDvfsTableEntryCount(default_table); - size_t default_table_size = default_entry_count * sizeof(cvb_entry_t); - size_t customize_entry_count = GetDvfsTableEntryCount(customize_table); - size_t customize_table_size = customize_entry_count * sizeof(cvb_entry_t); - - // Validate existing table - cvb_entry_t* table_free = reinterpret_cast(ptr) + 1; - void* cpu_cvb_table_head = reinterpret_cast(table_free) - default_table_size; - bool validated = std::memcmp(cpu_cvb_table_head, default_table, default_table_size) == 0; - R_UNLESS(validated, ldr::ResultInvalidCpuDvfs()); - - std::memcpy(cpu_cvb_table_head, static_cast(customize_table), customize_table_size); - - // Patch CPU max volt - if (cpu_max_volt) { - cvb_entry_t* entry = static_cast(cpu_cvb_table_head); - for (size_t i = 0; i < customize_entry_count; i++) { - if (entry->freq >= cpu_freq_threshold) { - if (isMariko) { - PATCH_OFFSET(&(entry->cvb_pll_param.c0), cpu_max_volt * 1000); - } else { - PATCH_OFFSET(&(entry->cvb_dfll_param.c0), cpu_max_volt * 1000); - } - } - entry++; + inline bool GpuMaxClockPatternFn(u32 *ptr32) + { + return asm_compare_no_rd(*ptr32, asm_pattern[0]); } + + constexpr emc_dvb_dvfs_table_t EmcDvbTableDefault[] = { + {204000, { + 637, + 637, + 637, + }}, + {408000, { + 637, + 637, + 637, + }}, + {800000, { + 637, + 637, + 637, + }}, + {1065600, { + 637, + 637, + 637, + }}, + {1331200, { + 650, + 637, + 637, + }}, + {1600000, { + 675, + 650, + 637, + }}, + }; + + 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; + + void Patch(uintptr_t mapped_nso, size_t nso_size); + } - R_SUCCEED(); -} + namespace erista + { + constexpr cvb_entry_t CpuCvbTableDefault[] = { + // CPU_PLL_CVB_TABLE_ODN + {204000, {721094}, {}}, + {306000, {754040}, {}}, + {408000, {786986}, {}}, + {510000, {819932}, {}}, + {612000, {852878}, {}}, + {714000, {885824}, {}}, + {816000, {918770}, {}}, + {918000, {951716}, {}}, + {1020000, {984662}, {-2875621, 358099, -8585}}, + {1122000, {1017608}, {-52225, 104159, -2816}}, + {1224000, {1050554}, {1076868, 8356, -727}}, + {1326000, {1083500}, {2208191, -84659, 1240}}, + {1428000, {1116446}, {2519460, -105063, 1611}}, + {1581000, {1130000}, {2889664, -122173, 1834}}, + {1683000, {1168000}, {5100873, -279186, 4747}}, + {1785000, {1227500}, {5100873, -279186, 4747}}, + {}, + }; -template -Result GpuFreqCvbTable(u32* ptr) { - cvb_entry_t* default_table = isMariko ? (cvb_entry_t *)(&mariko::GpuCvbTableDefault) : (cvb_entry_t *)(&erista::GpuCvbTableDefault); - cvb_entry_t* customize_table; - if (isMariko) { - switch (C.marikoGpuUV) { - case 0: + constexpr u32 CpuVoltL4T = 1235'000; + + constexpr u16 CpuMinVolts[] = {950, 850, 825, 810}; + + inline bool CpuMaxVoltPatternFn(u32 *ptr32) + { + u32 val = *ptr32; + return (val == 1132 || val == 1170 || val == 1227); + } + + constexpr u32 GpuClkPllLimit = 921'600'000; + + /* GPU Max Clock asm Pattern: + * + * MOV W11, #0x1000 MOV (wide immediate) 0x1000 0xB (11) + * sf | opc | | hw | imm16 | 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 + * 0 | 1 0 | 1 0 0 1 0 1| 0 0| 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 |0 1 0 1 1 + * + * MOVK W11, #0xE, LSL#16 16 0xE 0xB (11) + * sf | opc | | hw | imm16 | 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 + * 0 | 1 1 | 1 0 0 1 0 1| 0 1| 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 |0 1 0 1 1 + */ + inline constexpr u32 asm_pattern[] = {0x52820000, 0x72A001C0}; + inline auto asm_compare_no_rd = [](u32 ins1, u32 ins2) + { return ((ins1 ^ ins2) >> 5) == 0; }; + inline auto asm_get_rd = [](u32 ins) + { return ins & ((1 << 5) - 1); }; + inline auto asm_set_rd = [](u32 ins, u8 rd) + { return (ins & 0xFFFFFFE0) | (rd & 0x1F); }; + inline auto asm_set_imm16 = [](u32 ins, u16 imm) + { return (ins & 0xFFE0001F) | ((imm & 0xFFFF) << 5); }; + + inline bool GpuMaxClockPatternFn(u32 *ptr32) + { + return asm_compare_no_rd(*ptr32, asm_pattern[0]); + } + + constexpr cvb_entry_t GpuCvbTableDefault[] = { + // NA_FREQ_CVB_TABLE + {76800, {}, {814294, 8144, -940, 808, -21583, 226}}, + {153600, {}, {856185, 8144, -940, 808, -21583, 226}}, + {230400, {}, {898077, 8144, -940, 808, -21583, 226}}, + {307200, {}, {939968, 8144, -940, 808, -21583, 226}}, + {384000, {}, {981860, 8144, -940, 808, -21583, 226}}, + {460800, {}, {1023751, 8144, -940, 808, -21583, 226}}, + {537600, {}, {1065642, 8144, -940, 808, -21583, 226}}, + {614400, {}, {1107534, 8144, -940, 808, -21583, 226}}, + {691200, {}, {1149425, 8144, -940, 808, -21583, 226}}, + {768000, {}, {1191317, 8144, -940, 808, -21583, 226}}, + {844800, {}, {1233208, 8144, -940, 808, -21583, 226}}, + {921600, {}, {1275100, 8144, -940, 808, -21583, 226}}, + {}, + }; + + constexpr u32 MemVoltHOS = 1125'000; + constexpr u32 EmcClkPllmLimit = 1866'000'000; + + constexpr u32 MTC_TABLE_REV = 7; + + void Patch(uintptr_t mapped_nso, size_t nso_size); + } + + template + Result CpuFreqCvbTable(u32 *ptr) + { + cvb_entry_t *default_table = isMariko ? (cvb_entry_t *)(&mariko::CpuCvbTableDefault) : (cvb_entry_t *)(&erista::CpuCvbTableDefault); + cvb_entry_t *customize_table = const_cast(isMariko ? (C.marikoCpuUV ? C.marikoCpuDvfsTableSLT : C.marikoCpuDvfsTable) : C.eristaCpuDvfsTable); + + u32 cpu_max_volt = isMariko ? C.marikoCpuMaxVolt : C.eristaCpuMaxVolt; + u32 cpu_freq_threshold = 1020'000; + if (isMariko) + { + cpu_freq_threshold = C.marikoCpuUV ? 2193'000 : 2091'000; + } + else + { + cpu_freq_threshold = cpu_max_volt >= 1235 ? 1887'000 : 1428'000; + } + + size_t default_entry_count = GetDvfsTableEntryCount(default_table); + size_t default_table_size = default_entry_count * sizeof(cvb_entry_t); + size_t customize_entry_count = GetDvfsTableEntryCount(customize_table); + size_t customize_table_size = customize_entry_count * sizeof(cvb_entry_t); + + // Validate existing table + cvb_entry_t *table_free = reinterpret_cast(ptr) + 1; + void *cpu_cvb_table_head = reinterpret_cast(table_free) - default_table_size; + bool validated = std::memcmp(cpu_cvb_table_head, default_table, default_table_size) == 0; + R_UNLESS(validated, ldr::ResultInvalidCpuDvfs()); + + std::memcpy(cpu_cvb_table_head, static_cast(customize_table), customize_table_size); + + // Patch CPU max volt + if (cpu_max_volt) + { + cvb_entry_t *entry = static_cast(cpu_cvb_table_head); + for (size_t i = 0; i < customize_entry_count; i++) + { + if (entry->freq >= cpu_freq_threshold) + { + if (isMariko) + { + PATCH_OFFSET(&(entry->cvb_pll_param.c0), cpu_max_volt * 1000); + } + else + { + PATCH_OFFSET(&(entry->cvb_dfll_param.c0), cpu_max_volt * 1000); + } + } + entry++; + } + } + + R_SUCCEED(); + } + + template + Result GpuFreqCvbTable(u32 *ptr) + { + cvb_entry_t *default_table = isMariko ? (cvb_entry_t *)(&mariko::GpuCvbTableDefault) : (cvb_entry_t *)(&erista::GpuCvbTableDefault); + cvb_entry_t *customize_table; + if (isMariko) + { + switch (C.marikoGpuUV) + { + case 0: customize_table = const_cast(C.marikoGpuDvfsTable); break; case 1: @@ -255,75 +318,94 @@ Result GpuFreqCvbTable(u32* ptr) { case 2: customize_table = const_cast(C.marikoGpuDvfsTableHiOPT); break; + case 3: + customize_table = const_cast(C.marikoGpuDvfsTableUv3); + break; default: customize_table = const_cast(C.marikoGpuDvfsTable); break; + } } - } else { - customize_table = const_cast(C.eristaGpuDvfsTable); - } - - size_t default_entry_count = GetDvfsTableEntryCount(default_table); - size_t default_table_size = default_entry_count * sizeof(cvb_entry_t); - size_t customize_entry_count = GetDvfsTableEntryCount(customize_table); - size_t customize_table_size = customize_entry_count * sizeof(cvb_entry_t); - - // Validate existing table - cvb_entry_t* table_free = reinterpret_cast(ptr) + 1; - void* gpu_cvb_table_head = reinterpret_cast(table_free) - default_table_size; - bool validated = std::memcmp(gpu_cvb_table_head, default_table, default_table_size) == 0; - R_UNLESS(validated, ldr::ResultInvalidGpuDvfs()); - - std::memcpy(gpu_cvb_table_head, (void*)customize_table, customize_table_size); - - // Patch GPU volt - if (isMariko && C.marikoGpuUV == 3) { - cvb_entry_t* entry = static_cast(gpu_cvb_table_head); - for (size_t i = 0; i < customize_entry_count; i++) { - PATCH_OFFSET(&(entry->cvb_pll_param.c0), C.marikoGpuVoltArray[i] * 1000); - PATCH_OFFSET(&(entry->cvb_pll_param.c1), 0); - PATCH_OFFSET(&(entry->cvb_pll_param.c2), 0); - PATCH_OFFSET(&(entry->cvb_pll_param.c3), 0); - PATCH_OFFSET(&(entry->cvb_pll_param.c4), 0); - PATCH_OFFSET(&(entry->cvb_pll_param.c5), 0); - entry++; + else + { + customize_table = const_cast(C.eristaGpuDvfsTable); } - } - else if (C.commonGpuVoltOffset) { - cvb_entry_t* entry = static_cast(gpu_cvb_table_head); - for (size_t i = 0; i < customize_entry_count; i++) { - PATCH_OFFSET(&(entry->cvb_pll_param.c0), (entry->cvb_pll_param.c0 - C.commonGpuVoltOffset*1000)); - entry++; + + size_t default_entry_count = GetDvfsTableEntryCount(default_table); + size_t default_table_size = default_entry_count * sizeof(cvb_entry_t); + size_t customize_entry_count = GetDvfsTableEntryCount(customize_table); + size_t customize_table_size = customize_entry_count * sizeof(cvb_entry_t); + + // Validate existing table + cvb_entry_t *table_free = reinterpret_cast(ptr) + 1; + void *gpu_cvb_table_head = reinterpret_cast(table_free) - default_table_size; + bool validated = std::memcmp(gpu_cvb_table_head, default_table, default_table_size) == 0; + R_UNLESS(validated, ldr::ResultInvalidGpuDvfs()); + + std::memcpy(gpu_cvb_table_head, (void *)customize_table, customize_table_size); + + // Patch GPU volt + if (isMariko && C.marikoGpuUV == 3) + { + cvb_entry_t *entry = static_cast(gpu_cvb_table_head); + for (size_t i = 0; i < customize_entry_count; i++) + { + if (C.marikoGpuVoltArray[i] != 0) + { + u32 patched_voltage = C.marikoGpuVoltArray[i]; + if(patched_voltage > C.gpuVmax) { + patched_voltage = C.gpuVmax; + } + PATCH_OFFSET(&(entry->cvb_pll_param.c0), patched_voltage * 1000); + PATCH_OFFSET(&(entry->cvb_pll_param.c1), 0); + PATCH_OFFSET(&(entry->cvb_pll_param.c2), 0); + PATCH_OFFSET(&(entry->cvb_pll_param.c3), 0); + PATCH_OFFSET(&(entry->cvb_pll_param.c4), 0); + PATCH_OFFSET(&(entry->cvb_pll_param.c5), 0); + } + entry++; + } } - } - - R_SUCCEED(); -}; - -Result MemFreqPllmLimit(u32* ptr); -Result MemVoltHandler(u32* ptr); // Used for Erista MEM Vdd2 + EMC Vddq or Mariko MEM Vdd2 - -template -Result MemMtcCustomizeTable(T* dst, T* src) { - constexpr u32 mtc_magic = std::is_same_v ? MARIKO_MTC_MAGIC : ERISTA_MTC_MAGIC; - R_UNLESS(src->rev == mtc_magic, ldr::ResultInvalidMtcMagic()); - - constexpr u32 ZERO_VAL = UINT32_MAX; - // Skip params from dvfs_ver to clock_src; - for (size_t offset = offsetof(T, clk_src_emc); offset < sizeof(T); offset += sizeof(u32)) { - u32* src_ent = reinterpret_cast(reinterpret_cast(src) + offset); - u32* dst_ent = reinterpret_cast(reinterpret_cast(dst) + offset); - u32 src_val = *src_ent; - - if (src_val) { - PATCH_OFFSET(dst_ent, src_val == ZERO_VAL ? 0 : src_val); + else if (C.commonGpuVoltOffset) + { + cvb_entry_t *entry = static_cast(gpu_cvb_table_head); + for (size_t i = 0; i < customize_entry_count; i++) + { + PATCH_OFFSET(&(entry->cvb_pll_param.c0), (entry->cvb_pll_param.c0 - C.commonGpuVoltOffset * 1000)); + entry++; + } } - } - R_SUCCEED(); -}; + R_SUCCEED(); + }; -void SafetyCheck(); -void Patch(uintptr_t mapped_nso, size_t nso_size); + Result MemFreqPllmLimit(u32 *ptr); + Result MemVoltHandler(u32 *ptr); // Used for Erista MEM Vdd2 + EMC Vddq or Mariko MEM Vdd2 + + template + Result MemMtcCustomizeTable(T *dst, T *src) + { + constexpr u32 mtc_magic = std::is_same_v ? MARIKO_MTC_MAGIC : ERISTA_MTC_MAGIC; + R_UNLESS(src->rev == mtc_magic, ldr::ResultInvalidMtcMagic()); + + constexpr u32 ZERO_VAL = UINT32_MAX; + // Skip params from dvfs_ver to clock_src; + for (size_t offset = offsetof(T, clk_src_emc); offset < sizeof(T); offset += sizeof(u32)) + { + u32 *src_ent = reinterpret_cast(reinterpret_cast(src) + offset); + u32 *dst_ent = reinterpret_cast(reinterpret_cast(dst) + offset); + u32 src_val = *src_ent; + + if (src_val) + { + PATCH_OFFSET(dst_ent, src_val == ZERO_VAL ? 0 : src_val); + } + } + + R_SUCCEED(); + }; + + void SafetyCheck(); + 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 b3e2392a..adf08018 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.cpp @@ -109,6 +109,9 @@ Result GpuFreqMaxAsm(u32* ptr32) { case 2: max_clock = GetDvfsTableLastEntry(C.marikoGpuDvfsTableHiOPT)->freq; break; + case 3: + max_clock = GetDvfsTableLastEntry(C.marikoGpuDvfsTableUv3)->freq; + break; default: max_clock = GetDvfsTableLastEntry(C.marikoGpuDvfsTable)->freq; break; diff --git a/docs/main.js b/docs/main.js index 1c6e885c..34705edf 100644 --- a/docs/main.js +++ b/docs/main.js @@ -94,7 +94,7 @@ class AdvEntry extends CustEntry { } } class GpuEntry extends CustEntry { - constructor(e, t, i = CustPlatform.Mariko, n = 4, a = ["range: 610 ≤ x ≤ 1000"], r = 610, s = [610, 1e3], l = 5, o = !1) { + constructor(e, t, i = CustPlatform.Mariko, n = 4, a = ["range: 610 ≤ x ≤ 960"], r = 610, s = [610, 960], l = 5, o = !1) { super(e, t, i, n, a, r, s, l, o), this.id = e, this.name = t, this.platform = i, this.size = n, this.desc = a, this.defval = r, this.step = l, this.zeroable = o } createElement() { @@ -120,26 +120,25 @@ var CustTable = [ new CustEntry("commonCpuBoostClock", "Boost Clock in kHz", CustPlatform.All, 4, [ "System default: 1785000", "Boost clock will be applied when applications request Boost Mode via performance configuration." - ], 2091e3, [204000, 2907000], 1, !1), + ], 1785000, [204000, 2907000], 1, !1), new CustEntry("commonEmcMemVolt", "EMC Vdd2 Voltage in uV", CustPlatform.All, 4, [ "Acceptable range: 1100000 ≤ x ≤ 1250000, and it should be divided evenly by 12500.", - "Erista Default: 1125000", - "Mariko Default: 1100000", - "Official LPDDR4(X) range: 1060mV~1175mV (1100mV nominal)", - "Not enabled by default" - ], 0, [11e5, 125e4], 12500), + "Erista Default: 1175000", + "Mariko Default: 1175000", + "Official LPDDR4(X) voltage: 1175mV (1175mV nominal)" + ], 1175000, [11e5, 125e4], 12500), new CustEntry("eristaCpuMaxVolt", "Erista CPU Max Voltage in mV", CustPlatform.Erista, 4, [ "Acceptable range: 1120 ≤ x ≤ 1300", - "L4T Default: 1235" + "Default: 1235" ], 1235, [1000, 1500], 1), new CustEntry("eristaEmcMaxClock", "Erista RAM Max Clock in kHz", CustPlatform.Erista, 4, [ "Values should be ≥ 1600000, and divided evenly by 3200.", "Recommended Clocks: 1862400, 2131200 (JEDEC)", "WARNING: RAM overclock could be UNSTABLE if timing parameters are not suitable for your DRAM" - ], 1862400, [16e5, 2131200], 3200), + ], 1862400, [16e5, 2428800], 3200), new CustEntry("marikoCpuMaxVolt", "Mariko CPU Max Voltage in mV", CustPlatform.Mariko, 4, [ "System default: 1120", @@ -159,7 +158,7 @@ var CustTable = [ "Default: 600000", "Official lpddr4(x) range: 570mV~650mV (600mV nominal)", "Not enabled by default." - ], 0, [55e4, 65e4], 5e3), + ], 600000, [55e4, 65e4], 5e3), new CustEntry("marikoCpuUV", "Enable Mariko CPU Undervolt", CustPlatform.Mariko, 4, [ "Reduce CPU power draw", @@ -195,18 +194,26 @@ var CustTable = [ ], 0, [0, 12], 1), new CustEntry("cpuMaxFreq", "Maximum allowed CPU Frequency (KHz)", CustPlatform.All, 4, [ - "Default: 1963500", + "Default: 1785000", "This is the maximum frequency for the CPU you can set in sys-clk-ocs2.", "The value for this setting is capped at 2091mhz for Erista units and 2907MHz for Mariko units", "Anything above 1785MHz for Erista units and 1963MHz for Mariko units is unsafe without undervolting" - ], 1963500, [204000, 2907000], 1, !1), + ], 1785000, [204000, 2907000], 1, !1), new CustEntry("gpuMaxFreq", "Maximum allowed GPU Frequency (KHz)", CustPlatform.All, 4, [ - "Default: 1267200", + "Default: 921600", "This is the maximum frequency for the GPU you can set in sys-clk-ocs2.", "The value for this setting is capped at 998mhz for Erista units, and 1305MHz on Mariko units", - "The maximum safe value without undervolt is 844MHz for Erista units and 1152MHz for Mariko units" - ], 1152000, [76800, 1305600], 1, !1), + "The maximum safe value without undervolt is 921MHz for Erista units and 1152MHz for Mariko units", + "Higher frequencies via GPU UV3 bypass this setting" + ], 921600, [76800, 1305600], 1, !1), + + new CustEntry("gpuVmax", "Mariko Maximum allowed GPU Voltage (mV)", CustPlatform.Mariko, 4, [ + "Default: 800", + "This is the maximum voltage you can use in GPU UV3.", + "Anything above 800MV is considered UNSAFE (although it depends per frequency)" + ], 800, [480, 1000], 1, !1), + ]; var AdvTable = [ @@ -321,11 +328,17 @@ var GpuTable = [ new GpuEntry("10", "844.8"), new GpuEntry("11", "921.6"), new GpuEntry("12", "998.4"), - new GpuEntry("13", "1075.2"), - new GpuEntry("14", "1152.0"), - new GpuEntry("15", "1228.8"), - new GpuEntry("16", "1267.2"), - new GpuEntry("17", "1305.6 (UNSAFE)") + new GpuEntry("13", "1075.2", CustPlatform.Mariko), + new GpuEntry("14", "1152.0", CustPlatform.Mariko), + new GpuEntry("15", "1228.8 (UNSAFE)", CustPlatform.Mariko), + new GpuEntry("16", "1267.2 (UNSAFE)", CustPlatform.Mariko), + new GpuEntry("17", "1305.6 (UNSAFE)", CustPlatform.Mariko), + new GpuEntry("18", "1344.0 (UNSAFE)", CustPlatform.Mariko), + new GpuEntry("19", "1382.4 (UNSAFE)", CustPlatform.Mariko), + new GpuEntry("20", "1420.8 (DANGEROUS)", CustPlatform.Mariko), + new GpuEntry("21", "1459.2 (DANGEROUS)", CustPlatform.Mariko), + new GpuEntry("22", "1497.6 (DANGEROUS)", CustPlatform.Mariko), + new GpuEntry("23", "1536.0 (DANGEROUS)", CustPlatform.Mariko) ]; class ErrorToolTip {