diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.cpp b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.cpp index 10d2f1a1..3b29b705 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.cpp @@ -173,11 +173,14 @@ namespace ams::ldr::hoc::pcv { void Patch(uintptr_t mapped_nso, size_t nso_size) { #ifdef ATMOSPHERE_IS_STRATOSPHERE SafetyCheck(); + bool isMariko = (spl::GetSocType() == spl::SocType_Mariko); - if (isMariko) + if (isMariko) { mariko::Patch(mapped_nso, nso_size); - else + } else { erista::Patch(mapped_nso, nso_size); + } + #endif } diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.hpp index 6b82fe10..faa857b2 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.hpp @@ -22,253 +22,12 @@ #include "../oc_common.hpp" #include "pcv_common.hpp" +#include "pcv_erista.hpp" +#include "pcv_mariko.hpp" +#include "pcv_asm.hpp" namespace ams::ldr::hoc::pcv { - namespace mariko { - constexpr cvb_entry_t CpuCvbTableDefault[] = { - { 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 u32 CpuClkOfficial = 1963'500; - constexpr u32 CpuVoltOfficial = 1120; - constexpr u32 CpuVminOfficial = 620; - - 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"); - - static const u32 cpuVoltThermalData[] = { 620, 1120, 20000, 620, 1120, 70000, 950, 1132, 0, 950, 1227, 0 }; - - static const u32 allowedCpuMaxFrequencies[] = { 1'963'500, 2'091'000, 2'193'000, 2'295'000, 2'397'000, 2'499'000, 2'601'000, 2'703'000, }; - - 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 GpuClkPllMax = 1300'000'000; - constexpr u32 GpuClkPllLimit = 2'600'000; - constexpr u32 GpuVminOfficial = 610; - - static const u32 gpuDVFSPattern[] = { 1050, 1000, 100, 1000, 10, }; - static const u32 gpuVoltThermalPattern[] = { 800, 1120, 0, 610, 1120, 20000, 610, 1120, 30000, 610, 1120, 50000, 610, 1120, 70000, 610, 1120, 90000, }; - static_assert(sizeof(gpuVoltThermalPattern) == 72, "Invalid gpuVoltThermalPattern"); - - /* 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 auto AsmGetImm16 = [](u32 ins) { - return static_cast((ins >> 5) & 0xFFFF); - }; - - 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 { - static u32 maxEmcClocks[] = { C.eristaEmcMaxClock2, C.eristaEmcMaxClock1, C.eristaEmcMaxClock, }; - #define GET_MAX_OF_ARR(ARR) (*std::max_element(ARR, ARR + std::size(ARR))) - - 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 CpuVoltOfficial = 1227; - - constexpr u32 CpuVminOfficial = 825; - - constexpr u32 CpuVoltL4T = 1257'000; - - static const u32 cpuVoltDvfsPattern[] = { 1227, 1000, 100, 1000, 0 }; - static_assert(sizeof(cpuVoltDvfsPattern) == 0x14, "invalid cpuVoltDvfsPattern size"); - - static const u32 cpuVoltageThermalPattern[] = { 950, 1132, 0, 950, 1227, 0, 825, 1227, 15000, 825, 1170, 60000, 825, 1132, 80000 }; - static_assert(sizeof(cpuVoltageThermalPattern) == 0x3c, "invalid cpuVoltageThermalPattern size"); - - constexpr u32 GpuClkPllLimit = 2'600'000; - constexpr u32 GpuClkPllMax = 921'600'000; - constexpr u32 GpuVminOfficial = 810; - - constexpr u16 CpuMinVolts[] = { 950, 850, 825, 810 }; - - inline bool CpuMaxVoltPatternFn(u32* ptr32) { - u32 val = *ptr32; - return (val == 1132 || val == 1170 || val == 1227); - } - - static const u32 gpuVoltDvfsPattern[] = { 810, 1150, 1000, 100, 1000, 10, }; - static_assert(sizeof(gpuVoltDvfsPattern) == (sizeof(u32) * 6), "Invalid gpuVoltDvfsPattern"); - - static const u32 gpuVoltThermalPattern[] = { 950, 1132, 0, 810, 1132, 15000, 810, 1132, 30000, 810, 1132, 50000, 810, 1132, 70000, 810, 1132, 105000 }; - static_assert(sizeof(gpuVoltThermalPattern) == 0x48, "invalid gpuVoltageThermalPattern size"); - - /* 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 auto AsmGetImm16 = [](u32 ins) { - return static_cast((ins >> 5) & 0xFFFF); - }; - - 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 EmcClkMinFreq = 40800; /* 40.8 MHz table only exists on erista. */ - constexpr u32 EmcClkPllmLimit = 1866'000'000; - - constexpr u32 MTC_TABLE_REV = 7; - - void Patch(uintptr_t mapped_nso, size_t nso_size); - } - inline auto MatchesPattern = [](u32 *base, const auto &offsets, const auto &values) { for (size_t i = 0; i < std::size(values); ++i) { if (*(base + offsets[i]) != values[i]) { diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_asm.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_asm.hpp new file mode 100644 index 00000000..bf6d0b1d --- /dev/null +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_asm.hpp @@ -0,0 +1,47 @@ +/* + * Copyright (C) Switch-OC-Suite + * + * Copyright (c) 2023 hanai3Bi + * + * Copyright (c) Souldbminer, Lightos_ and Horizon OC Contributors + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "../oc_common.hpp" + +namespace ams::ldr::hoc::pcv { + + 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 auto AsmGetImm16 = [](u32 ins) { + return static_cast((ins >> 5) & 0xFFFF); + }; + +} diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_erista.cpp b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_erista.cpp index 96ae3e4e..9ee2612e 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_erista.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_erista.cpp @@ -134,7 +134,7 @@ namespace ams::ldr::hoc::pcv::erista { Result GpuFreqMaxAsm(u32 *ptr32) { // Check if both two instructions match the pattern u32 ins1 = *ptr32, ins2 = *(ptr32 + 1); - if (!(asm_compare_no_rd(ins1, asm_pattern[0]) && asm_compare_no_rd(ins2, asm_pattern[1]))) + if (!(asm_compare_no_rd(ins1, GpuAsmPattern[0]) && asm_compare_no_rd(ins2, GpuAsmPattern[1]))) R_THROW(ldr::ResultInvalidGpuFreqMaxPattern()); // Both instructions should operate on the same register @@ -142,6 +142,12 @@ namespace ams::ldr::hoc::pcv::erista { if (rd != asm_get_rd(ins2)) R_THROW(ldr::ResultInvalidGpuFreqMaxPattern()); + /* Verify the limit. */ + /* TODO: Make this a little bit cleaner at some point. */ + if (AsmGetImm16(ins1) != (GpuClkOsLimit & 0xFFFF) || AsmGetImm16(ins2) != (GpuClkOsLimit >> 16)) { + R_THROW(ldr::ResultInvalidGpuFreqMaxPattern()); + } + u32 max_clock; switch (C.eristaGpuUV) { case 0: @@ -158,8 +164,8 @@ namespace ams::ldr::hoc::pcv::erista { break; } u32 asm_patch[2] = { - asm_set_rd(asm_set_imm16(asm_pattern[0], max_clock), rd), - asm_set_rd(asm_set_imm16(asm_pattern[1], max_clock >> 16), rd)}; + asm_set_rd(asm_set_imm16(GpuAsmPattern[0], max_clock), rd), + asm_set_rd(asm_set_imm16(GpuAsmPattern[1], max_clock >> 16), rd)}; PATCH_OFFSET(ptr32, asm_patch[0]); PATCH_OFFSET(ptr32 + 1, asm_patch[1]); diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_erista.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_erista.hpp new file mode 100644 index 00000000..35dd3326 --- /dev/null +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_erista.hpp @@ -0,0 +1,120 @@ +/* + * Copyright (C) Switch-OC-Suite + * + * Copyright (c) 2023 hanai3Bi + * + * Copyright (c) Souldbminer, Lightos_ and Horizon OC Contributors + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "../oc_common.hpp" +#include "pcv_common.hpp" +#include "pcv_asm.hpp" + +namespace ams::ldr::hoc::pcv::erista { + + static u32 maxEmcClocks[] = { C.eristaEmcMaxClock2, C.eristaEmcMaxClock1, C.eristaEmcMaxClock, }; + #define GET_MAX_OF_ARR(ARR) (*std::max_element(ARR, ARR + std::size(ARR))) + + 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 CpuVoltOfficial = 1227; + + constexpr u32 CpuVminOfficial = 825; + + constexpr u32 CpuVoltL4T = 1257'000; + + static const u32 cpuVoltDvfsPattern[] = { 1227, 1000, 100, 1000, 0 }; + static_assert(sizeof(cpuVoltDvfsPattern) == 0x14, "invalid cpuVoltDvfsPattern size"); + + static const u32 cpuVoltageThermalPattern[] = { 950, 1132, 0, 950, 1227, 0, 825, 1227, 15000, 825, 1170, 60000, 825, 1132, 80000 }; + static_assert(sizeof(cpuVoltageThermalPattern) == 0x3c, "invalid cpuVoltageThermalPattern size"); + + constexpr u32 GpuClkPllLimit = 2'600'000; + constexpr u32 GpuClkPllMax = 921'600'000; + constexpr u32 GpuVminOfficial = 810; + + constexpr u16 CpuMinVolts[] = { 950, 850, 825, 810 }; + + static const u32 gpuVoltDvfsPattern[] = { 810, 1150, 1000, 100, 1000, 10, }; + static_assert(sizeof(gpuVoltDvfsPattern) == (sizeof(u32) * 6), "Invalid gpuVoltDvfsPattern"); + + static const u32 gpuVoltThermalPattern[] = { 950, 1132, 0, 810, 1132, 15000, 810, 1132, 30000, 810, 1132, 50000, 810, 1132, 70000, 810, 1132, 105000 }; + static_assert(sizeof(gpuVoltThermalPattern) == 0x48, "invalid gpuVoltageThermalPattern size"); + + /* 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 GpuAsmPattern[] = { 0x52820000, 0x72A001C0 }; + + inline bool GpuMaxClockPatternFn(u32 *ptr32) { + return asm_compare_no_rd(*ptr32, GpuAsmPattern[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 EmcClkMinFreq = 40800; /* 40.8 MHz table only exists on erista. */ + constexpr u32 EmcClkPllmLimit = 1866'000'000; + + constexpr u32 MTC_TABLE_REV = 7; + + 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 98b8d4b2..6e9313f5 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.cpp @@ -268,7 +268,7 @@ namespace ams::ldr::hoc::pcv::mariko { Result GpuFreqMaxAsm(u32 *ptr32) { // Check if both two instructions match the pattern u32 ins1 = *ptr32, ins2 = *(ptr32 + 1); - if (!(asm_compare_no_rd(ins1, asm_pattern[0]) && asm_compare_no_rd(ins2, asm_pattern[1]))) { + if (!(asm_compare_no_rd(ins1, GpuAsmPattern[0]) && asm_compare_no_rd(ins2, GpuAsmPattern[1]))) { R_THROW(ldr::ResultInvalidGpuFreqMaxPattern()); } @@ -301,8 +301,8 @@ namespace ams::ldr::hoc::pcv::mariko { } u32 asm_patch[2] = { - asm_set_rd(asm_set_imm16(asm_pattern[0], max_clock), rd), - asm_set_rd(asm_set_imm16(asm_pattern[1], max_clock >> 16), rd) + asm_set_rd(asm_set_imm16(GpuAsmPattern[0], max_clock), rd), + asm_set_rd(asm_set_imm16(GpuAsmPattern[1], max_clock >> 16), rd) }; PATCH_OFFSET(ptr32, asm_patch[0]); diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.hpp new file mode 100644 index 00000000..4c57bf1c --- /dev/null +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.hpp @@ -0,0 +1,129 @@ +/* + * Copyright (C) Switch-OC-Suite + * + * Copyright (c) 2023 hanai3Bi + * + * Copyright (c) Souldbminer, Lightos_ and Horizon OC Contributors + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "../oc_common.hpp" +#include "pcv_common.hpp" +#include "pcv_asm.hpp" + +namespace ams::ldr::hoc::pcv::mariko { + + constexpr cvb_entry_t CpuCvbTableDefault[] = { + { 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 u32 CpuClkOfficial = 1963'500; + constexpr u32 CpuVoltOfficial = 1120; + constexpr u32 CpuVminOfficial = 620; + + 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"); + + static const u32 cpuVoltThermalData[] = { 620, 1120, 20000, 620, 1120, 70000, 950, 1132, 0, 950, 1227, 0 }; + + static const u32 allowedCpuMaxFrequencies[] = { 1'963'500, 2'091'000, 2'193'000, 2'295'000, 2'397'000, 2'499'000, 2'601'000, 2'703'000, }; + + 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 GpuClkPllMax = 1300'000'000; + constexpr u32 GpuClkPllLimit = 2'600'000; + constexpr u32 GpuVminOfficial = 610; + + static const u32 gpuDVFSPattern[] = { 1050, 1000, 100, 1000, 10, }; + static const u32 gpuVoltThermalPattern[] = { 800, 1120, 0, 610, 1120, 20000, 610, 1120, 30000, 610, 1120, 50000, 610, 1120, 70000, 610, 1120, 90000, }; + static_assert(sizeof(gpuVoltThermalPattern) == 72, "Invalid gpuVoltThermalPattern"); + + /* 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 GpuAsmPattern[] = { 0x52820000, 0x72A001C0 }; + + inline bool GpuMaxClockPatternFn(u32 *ptr32) { + return asm_compare_no_rd(*ptr32, GpuAsmPattern[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); + +}