diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/customize.cpp b/Source/Atmosphere/stratosphere/loader/source/oc/customize.cpp index 8458b469..55e43b7e 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/customize.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/customize.cpp @@ -1,8 +1,10 @@ /* - * Copyright (c) Souldbminer and Horizon OC Contributors + * Copyright (C) Switch-OC-Suite * * Copyright (c) 2023 hanai3Bi - * + * + * Copyright (c) Souldbminer 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. @@ -89,7 +91,6 @@ volatile CustomizeTable C = { .marikoGpuUV = 0, - .eristaCpuUV = 0, .eristaGpuUV = 0, @@ -119,22 +120,22 @@ volatile CustomizeTable C = { // Ensure the voltages actually increase or stay the sameot .marikoGpuVoltArray = { - 610 /* 76 */, - 610 /* 153 */, - 610 /* 230 */, - 610 /* 307 */, - 610 /* 384 */, - 610 /* 460 */, - 610 /* 537 */, - 610 /* 614 */, - 610 /* 691 */, - 610 /* 768 */, - 620 /* 844 */, - 640 /* 921 */, - 675 /* 998 */, - 710 /* 1075 */, - 735 /* 1152 */, - 785 /* 1228 (Only safe if GPU Scheduling is on)*/, + 610 /* 76 */, + 610 /* 153 */, + 610 /* 230 */, + 610 /* 307 */, + 610 /* 384 */, + 610 /* 460 */, + 610 /* 537 */, + 610 /* 614 */, + 610 /* 691 */, + 610 /* 768 */, + 620 /* 844 */, + 640 /* 921 */, + 675 /* 998 */, + 710 /* 1075 */, + 735 /* 1152 */, + 785 /* 1228 */, 0 /* 1267 (Disabled by default) */, 0 /* 1305 (Disabled by default) */, 0 /* 1344 (Disabled by default) */, @@ -329,7 +330,7 @@ volatile CustomizeTable C = { }, .marikoGpuDvfsTableSLT = { - { 76800, {}, { 590000, } }, + { 76800, {}, { 590000, } }, { 153600, {}, { 590000, } }, { 230400, {}, { 590000, } }, { 307200, {}, { 590000, } }, @@ -348,21 +349,21 @@ volatile CustomizeTable C = { // { 1267200, {}, { 1308155, -13694, -867, 0, 3681, 559 } }, }, .marikoGpuDvfsTableHiOPT = { - { 76800, {}, { 590000, } }, - { 153600, {}, { 590000, } }, - { 230400, {}, { 590000, } }, - { 307200, {}, { 590000, } }, - { 384000, {}, { 590000, } }, - { 460800, {}, { 590000, } }, - { 537600, {}, { 590000, } }, - { 614400, {}, { 590000, } }, - { 691200, {}, { 838712, -7304, -552, 119, -3750, -2 } }, - { 768000, {}, { 880210, -7955, -584, 0, -2849, 39 } }, - { 844800, {}, { 926398, -8892, -602, -60, -384, -93 } }, - { 921600, {}, { 970060, -10108, -614, -179, 1508, -13 } }, - { 998400, {}, { 1065665, -16075, -497, -179, 3213, 9 } }, - { 1075200, {}, { 1132576, -16093, -648, 0, 1077, 40 } }, - { 1152000, {}, { 1180029, -14534, -830, 0, 1469, 110 } }, + { 76800, {}, { 590000, } }, + { 153600, {}, { 590000, } }, + { 230400, {}, { 590000, } }, + { 307200, {}, { 590000, } }, + { 384000, {}, { 590000, } }, + { 460800, {}, { 590000, } }, + { 537600, {}, { 590000, } }, + { 614400, {}, { 590000, } }, + { 691200, {}, { 838712, -7304, -552, 119, -3750, -2 } }, + { 768000, {}, { 880210, -7955, -584, 0, -2849, 39 } }, + { 844800, {}, { 926398, -8892, -602, -60, -384, -93 } }, + { 921600, {}, { 970060, -10108, -614, -179, 1508, -13 } }, + { 998400, {}, { 1065665, -16075, -497, -179, 3213, 9 } }, + { 1075200, {}, { 1132576, -16093, -648, 0, 1077, 40 } }, + { 1152000, {}, { 1180029, -14534, -830, 0, 1469, 110 } }, { 1228800, {}, { 1248293, -16383, -859, 0, 3722, 313 } }, // { 1267200, {}, { 1286399, -17475, -867, 0, 3681, 559 } }, }, @@ -392,21 +393,21 @@ volatile CustomizeTable C = { }, .marikoGpuDvfsTableUv3UnsafeFreqs = { - { 76800, {}, { 590000, } }, - { 153600, {}, { 590000, } }, - { 230400, {}, { 590000, } }, - { 307200, {}, { 590000, } }, - { 384000, {}, { 590000, } }, - { 460800, {}, { 590000, } }, - { 537600, {}, { 590000, } }, - { 614400, {}, { 590000, } }, - { 691200, {}, { 838712, -7304, -552, 119, -3750, -2 } }, - { 768000, {}, { 880210, -7955, -584, 0, -2849, 39 } }, - { 844800, {}, { 926398, -8892, -602, -60, -384, -93 } }, - { 921600, {}, { 970060, -10108, -614, -179, 1508, -13 } }, - { 998400, {}, { 1065665, -16075, -497, -179, 3213, 9 } }, - { 1075200, {}, { 1132576, -16093, -648, 0, 1077, 40 } }, - { 1152000, {}, { 1180029, -14534, -830, 0, 1469, 110 } }, + { 76800, {}, { 590000, } }, + { 153600, {}, { 590000, } }, + { 230400, {}, { 590000, } }, + { 307200, {}, { 590000, } }, + { 384000, {}, { 590000, } }, + { 460800, {}, { 590000, } }, + { 537600, {}, { 590000, } }, + { 614400, {}, { 590000, } }, + { 691200, {}, { 838712, -7304, -552, 119, -3750, -2 } }, + { 768000, {}, { 880210, -7955, -584, 0, -2849, 39 } }, + { 844800, {}, { 926398, -8892, -602, -60, -384, -93 } }, + { 921600, {}, { 970060, -10108, -614, -179, 1508, -13 } }, + { 998400, {}, { 1065665, -16075, -497, -179, 3213, 9 } }, + { 1075200, {}, { 1132576, -16093, -648, 0, 1077, 40 } }, + { 1152000, {}, { 1180029, -14534, -830, 0, 1469, 110 } }, { 1228800, {}, { 1248293, -16383, -859, 0, 3722, 313 } }, { 1267200, {}, { 1286399, -17475, -867, 0, 3681, 559 } }, { 1305600, {}, { 1286399, -17475, -867, 0, 3681, 559 } }, @@ -476,4 +477,4 @@ volatile CustomizeTable C = { }, }; -} \ No newline at end of file +} diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/customize.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/customize.hpp index 703ea2b0..a68ed15b 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/customize.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/customize.hpp @@ -1,8 +1,10 @@ /* - * Copyright (c) Souldbminer and Horizon OC Contributors + * Copyright (C) Switch-OC-Suite * * Copyright (c) 2023 hanai3Bi - * + * + * Copyright (c) Souldbminer 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. @@ -19,34 +21,36 @@ #pragma once #define CUST_REV 11 - + #include "oc_common.hpp" #include "pcv/pcv_common.hpp" - + namespace ams::ldr::oc { - + #include "mtc_timing_table.hpp" - + enum MtcConfig: u32 { AUTO_ADJ_ALL = 0, CUSTOM_ADJ_ALL = 1, NO_ADJ_ALL = 2, - + CUSTOMIZED_ALL = 4, + AUTO_ADJ = 5, }; - + using CustomizeCpuDvfsTable = pcv::cvb_entry_t[pcv::DvfsTableEntryLimit]; using CustomizeGpuDvfsTable = pcv::cvb_entry_t[pcv::DvfsTableEntryLimit]; static_assert(sizeof(CustomizeCpuDvfsTable) == sizeof(CustomizeGpuDvfsTable)); static_assert(sizeof(CustomizeCpuDvfsTable) == sizeof(pcv::cvb_entry_t) * pcv::DvfsTableEntryLimit); - + constexpr uint32_t ERISTA_MTC_MAGIC = 0x43544D45; // EMTC constexpr uint32_t MARIKO_MTC_MAGIC = 0x43544D4D; // MMTC - + typedef struct CustomizeTable { u8 cust[4] = {'C', 'U', 'S', 'T'}; u32 custRev = CUST_REV; - u32 mtcConf = AUTO_ADJ_ALL; + u32 mtcConfErista = AUTO_ADJ; + u32 mtcConfMariko = AUTO_ADJ_ALL; // TODO: Fix mariko and merge into mtcConf u32 commonCpuBoostClock; u32 commonEmcMemVolt; u32 eristaCpuMaxVolt; @@ -56,20 +60,20 @@ u32 marikoEmcVddqVolt; u32 marikoCpuUV; u32 marikoGpuUV; - + u32 eristaCpuUV; u32 eristaGpuUV; - + u32 enableMarikoGpuUnsafeFreqs; u32 enableEristaGpuUnsafeFreqs; - + u32 enableMarikoCpuUnsafeFreqs; u32 enableEristaCpuUnsafeFreqs; - + u32 commonGpuVoltOffset; - + u32 marikoEmcDvbShift; - + // advanced config u32 t1_tRCD; u32 t2_tRP; @@ -80,10 +84,10 @@ u32 t7_tWTR; u32 t8_tREFI; u32 mem_burst_latency; - + u32 marikoGpuVoltArray[24]; u32 eristaGpuVoltArray[14]; - + u32 marikoCpuVmin; u32 eristaGpuVmin; @@ -93,12 +97,12 @@ CustomizeCpuDvfsTable eristaCpuDvfsTable; CustomizeCpuDvfsTable marikoCpuDvfsTable; CustomizeCpuDvfsTable marikoCpuDvfsTableSLT; - + CustomizeGpuDvfsTable eristaGpuDvfsTable; CustomizeGpuDvfsTable eristaGpuDvfsTableSLT; CustomizeGpuDvfsTable eristaGpuDvfsTableHigh; - - + + CustomizeGpuDvfsTable marikoGpuDvfsTable; CustomizeGpuDvfsTable marikoGpuDvfsTableSLT; CustomizeGpuDvfsTable marikoGpuDvfsTableHiOPT; @@ -108,14 +112,14 @@ CustomizeGpuDvfsTable marikoGpuDvfsTableUv3UnsafeFreqs; CustomizeCpuDvfsTable marikoCpuDvfsTableUnsafeFreqs; CustomizeCpuDvfsTable eristaCpuDvfsTableUnsafeFreqs; - + } CustomizeTable; //static_assert(sizeof(CustomizeTable) == sizeof(u8) * 4 + sizeof(u32) * 10 + sizeof(CustomizeCpuDvfsTable) * 5 + sizeof(void*) * 2); //static_assert(sizeof(CustomizeTable) == 7000); - + extern volatile CustomizeTable C; - + //extern volatile EristaMtcTable EristaMtcTablePlaceholder; //extern volatile MarikoMtcTable MarikoMtcTablePlaceholder; - - } \ No newline at end of file + + } 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 e6dfc69e..8f0ca68d 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/mtc_timing_value.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/mtc_timing_value.hpp @@ -1,6 +1,4 @@ /* - * Copyright (c) Souldbminer & Horizon OC Contributors - * * Copyright (c) 2023 hanai3Bi * * This program is free software; you can redistribute it and/or modify it @@ -23,35 +21,35 @@ #pragma once #include "oc_common.hpp" - + namespace ams::ldr::oc { #define MAX(A, B) std::max(A, B) #define MIN(A, B) std::min(A, B) #define CEIL(A) std::ceil(A) #define FLOOR(A) std::floor(A) - + //Preset One const std::array tRCD_values = {18, 17, 16, 15, 14, 13, 12, 11}; const std::array tRP_values = {18, 17, 16, 15, 14, 13, 12, 11}; const std::array tRAS_values = {42, 36, 34, 32, 30, 28, 26, 24, 22, 20}; - + // Preset Two const std::array tRRD_values = {10, 7.5, 6, 5, 4, 3, 2, 1}; const std::array tFAW_values = {40, 30, 24, 16, 12}; - + // Preset Three const std::array tWR_values = {18, 15, 15, 12, 12, 8}; // TODO: identify what exactly eos tRTW even is (is it even real?) const std::array tRTP_values = {7.5, 7.5, 6, 6, 4, 4}; - + // Preset Four const std::array tRFC_values = {140, 120, 100, 80, 70, 60}; - + // Preset Five const std::array tWTR_values = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1}; - + // Preset Six const std::array tREFpb_values = {488, 976, 1952, 3256, 9999, 9999}; - + // const u32 TIMING_PRESET_ONE = C.ramTimingPresetOne; // const u32 TIMING_PRESET_TWO = C.ramTimingPresetTwo; const u32 TIMING_PRESET_THREE = 0; @@ -59,138 +57,137 @@ // const u32 TIMING_PRESET_FIVE = C.ramTimingPresetFive; // const u32 TIMING_PRESET_SIX = C.ramTimingPresetSix; // const u32 TIMING_PRESET_SEVEN = C.ramTimingPresetSeven; - + // Burst Length const u32 BL = 16; - + // tRFCpb (refresh cycle time per bank) in ns for 8Gb density const u32 tRFCpb = !C.t5_tRFC ? 140 : tRFC_values[C.t5_tRFC-1]; - + // tRFCab (refresh cycle time all banks) in ns for 8Gb density const u32 tRFCab = !C.t5_tRFC ? 280 : 2*tRFCpb; - + // tRAS (row active time) in ns const u32 tRAS = !C.t3_tRAS ? 42 : tRAS_values[C.t3_tRAS-1]; - + // tRPpb (row precharge time per bank) in ns const u32 tRPpb = !C.t2_tRP ? 18 : tRP_values[C.t2_tRP-1]; - + // tRPab (row precharge time all banks) in ns const u32 tRPab = !C.t2_tRP ? 21 : tRPpb + 3; - + // tRC (ACTIVATE-ACTIVATE command period same bank) in ns const u32 tRC = tRPpb + tRAS; - const u32 tRTW = !C.t6_tRTW ? 10 : tWTR_values[C.t6_tRTW-1]; // DQS output access time from CK_t/CK_c - const double tDQSCK_min = 1.5; + const double tDQSCK_min = 1.5; // TODO: Fix/remove for mariko if needed // DQS output access time from CK_t/CK_c - const double tDQSCK_max = 3.5; + const double tDQSCK_max = 3.5; // TODO: Fix/remove for mariko if needed // Write preamble (tCK) - const double tWPRE = 1.8; + const double tWPRE = 1.8; // TODO: Fix/remove for mariko if needed // Read postamble (tCK) - const double tRPST = 0.4; + const double tRPST = 0.4; // TODO: Fix/remove for mariko if needed // WRITE command to first DQS transition(max) (tCK) - const double tDQSS_max = 1.25; + const double tDQSS_max = 1.25; // TODO: Fix/remove for mariko if needed // DQ-to-DQS offset(max) (ns) - const double tDQS2DQ_max = 0.8; + const double tDQS2DQ_max = 0.8; // TODO: Fix/remove for mariko if needed // DQS_t, DQS_c to DQ skew total, per group, per access (DBI Disabled) - const double tDQSQ = 0.18; - + const double tDQSQ = 0.18; // TODO: Fix/remove for mariko if needed + // Write-to-Read delay const u32 tWTR = !C.t7_tWTR ? 10 : tWTR_values[C.t7_tWTR-1]; - + // Internal READ-to-PRE-CHARGE command delay in ns const double tRTP = !TIMING_PRESET_THREE ? 7.5 : tRTP_values[TIMING_PRESET_THREE-1]; - + // write recovery time const u32 tWR = !TIMING_PRESET_THREE ? 18 : tWR_values[TIMING_PRESET_THREE-1]; - + // Read to refresh delay const u32 tR2REF = tRTP + tRPpb; - + // tRCD (RAS-CAS delay) in ns const u32 tRCD = !C.t1_tRCD ? 18 : tRCD_values[C.t1_tRCD-1]; - + // tRRD (Active bank-A to Active bank-B) in ns const double tRRD = !C.t4_tRRD ? 10. : tRRD_values[C.t4_tRRD-1]; - + // tREFpb (average refresh interval per bank) in ns for 8Gb density const u32 tREFpb = !C.t8_tREFI ? 488 : tREFpb_values[C.t8_tREFI-1]; // tREFab (average refresh interval all 8 banks) in ns for 8Gb density // const u32 tREFab = tREFpb * 8; - + // tPDEX2WR, tPDEX2RD (timing delay from exiting powerdown mode to a write/read command) in ns // const u32 tPDEX2 = 10; // Exit power-down to next valid command delay const double tXP = 10; - + // Delay from valid command to CKE input LOW in ns - const double tCMDCKE = 1.75; - + const double tCMDCKE = 1.75; // TODO: Fix/remove for mariko if needed + // tACT2PDEN (timing delay from an activate, MRS or EMRS command to power-down entry) in ns // Valid clock and CS requirement after CKE input LOW after MRW command - const u32 tMRWCKEL = 14; - + const u32 tMRWCKEL = 14; // TODO: Fix/remove for mariko if needed + // Valid CS requirement after CKE input LOW - const double tCKELCS = 5; - + const double tCKELCS = 5; // TODO: Fix/remove for mariko if needed + // Valid CS requirement before CKE input HIGH - const double tCSCKEH = 1.75; - + const double tCSCKEH = 1.75; // TODO: Fix/remove for mariko if needed + // tXSR (SELF REFRESH exit to next valid command delay) in ns const double tXSR = tRFCab + 7.5; - + // tCKE (minimum pulse width(HIGH and LOW pulse width)) in ns - const double tCKE = 7.5; - + const double tCKE = 7.5; // TODO: Fix/remove for mariko if needed + // Minimum self refresh time (entry to exit) const u32 tSR = 15; - + // tFAW (Four-bank Activate Window) in ns const u32 tFAW = 40;// !TIMING_PRESET_TWO ? 40 : tFAW_values[TIMING_PRESET_TWO-1]; TOGO - + // Valid Clock requirement before CKE Input HIGH in ns - const double tCKCKEH = 1.75; - + const double tCKCKEH = 1.75; // TODO: Fix/remove for mariko if needed + // p78 The first valid data is available RL × t CK + t DQSCK + t DQSQ //const u32 QUSE = RL + CEIL(tDQSCK_min/tCK_avg + tDQSQ); - + namespace pcv::erista { // tCK_avg (average clock period) in ns const double tCK_avg = 1000'000. / C.eristaEmcMaxClock; - + // Write Latency const u32 WL = 14 + C.mem_burst_latency; // Read Latency const u32 RL = 32 - C.mem_burst_latency; - + // minimum number of cycles from any read command to any write command, irrespective of bank - const u32 R2W = CEIL (RL + CEIL(tDQSCK_max/tCK_avg) + BL/2 - WL + tWPRE + FLOOR(tRPST)) + 6; - + // const u32 R2W = CEIL (RL + CEIL(tDQSCK_max/tCK_avg) + BL/2 - WL + tWPRE + FLOOR(tRPST)) + 6; + // Delay Time From WRITE-to-READ - const u32 W2R = WL + BL/2 + 1 + CEIL(tWTR/tCK_avg) - 6; - + // const u32 W2R = WL + BL/2 + 1 + CEIL(tWTR/tCK_avg) - 6; + // write-to-precharge time for commands to the same bank in cycles - const u32 WTP = WL + BL/2 + 1 + CEIL(tWR/tCK_avg) - 8; - - // #_of_rows per die for 8Gb density - const u32 numOfRows = 65536; + // const u32 WTP = WL + BL/2 + 1 + CEIL(tWR/tCK_avg) - 8; + + // #_of_rows per die for 16Gb density + const u32 numOfRows = 131072; // {REFRESH, REFRESH_LO} = max[(tREF/#_of_rows) / (emc_clk_period) - 64, (tREF/#_of_rows) / (emc_clk_period) * 97%] // emc_clk_period = dram_clk / 2; // 1600 MHz: 5894, but N' set to 6176 (~4.8% margin) const u32 REFRESH = MIN((u32)65472, u32(std::ceil((double(tREFpb) * C.eristaEmcMaxClock / numOfRows * 1.048 / 2 - 64))) / 4 * 4); const u32 REFBW = MIN((u32)65536, REFRESH+64); - + // Write With Auto Precharge to to Power-Down Entry - const u32 WTPDEN = WTP + 1 + CEIL(tDQSS_max/tCK_avg) + CEIL(tDQS2DQ_max/tCK_avg) + 6; - + // const u32 WTPDEN = WTP + 1 + CEIL(tDQSS_max/tCK_avg) + CEIL(tDQS2DQ_max/tCK_avg) + 6; + // Additional time after t XP hasexpired until the MRR commandmay be issued - const double tMRRI = tRCD + 3 * tCK_avg; - + // const double tMRRI = tRCD + 3 * tCK_avg; + // tPDEX2MRR (timing delay from exiting powerdown mode to MRR command) in ns - const double tPDEX2MRR = tXP + tMRRI; + // const double tPDEX2MRR = tXP + tMRRI; } namespace pcv::mariko { // tCK_avg (average clock period) in ns @@ -199,28 +196,28 @@ const u32 WL = 14 + C.mem_burst_latency; // Read Latency const u32 RL = 32 - C.mem_burst_latency; - + // minimum number of cycles from any read command to any write command, irrespective of bank const u32 R2W = WL + BL/2 + 1 + CEIL(tRTW/tCK_avg); - + // Delay Time From WRITE-to-READ const u32 W2R = WL + BL/2 + 1 + CEIL(tWTR/tCK_avg); - + // write-to-precharge time for commands to the same bank in cycles const u32 WTP = WL + BL/2 + 1 + CEIL(tWR/tCK_avg); - + // Read-To-MRW delay const u32 RTM = RL + BL/2 + CEIL(tDQSCK_max/tCK_avg) + FLOOR(tRPST) + CEIL(7.5/tCK_avg); - + // Write-To-MRW/MRR delay const u32 WTM = WL + 1 + BL/2 + CEIL(7.5/tCK_avg); - + // Read With AP-To-MRW/MRR delay const u32 RATM = RTM + CEIL(tRTP/tCK_avg) - 8; - + // Write With AP-To-MRW/MRR delay const u32 WATM = WTM + CEIL(tWR/tCK_avg); - + // #_of_rows per die for 8Gb density const u32 numOfRows = 65536; // {REFRESH, REFRESH_LO} = max[(tREF/#_of_rows) / (emc_clk_period) - 64, (tREF/#_of_rows) / (emc_clk_period) * 97%] @@ -228,15 +225,14 @@ // 1600 MHz: 5894, but N' set to 6176 (~4.8% margin) const u32 REFRESH = MIN((u32)65472, u32(std::ceil((double(tREFpb) * C.marikoEmcMaxClock / numOfRows * 1.048 / 2 - 64))) / 4 * 4); const u32 REFBW = MIN((u32)65536, REFRESH+64); - + // Write With Auto Precharge to to Power-Down Entry const u32 WTPDEN = WTP + 1 + CEIL(tDQSS_max/tCK_avg) + CEIL(tDQS2DQ_max/tCK_avg) + 6; - + // Additional time after t XP hasexpired until the MRR commandmay be issued const double tMRRI = tRCD + 3 * tCK_avg; - + // tPDEX2MRR (timing delay from exiting powerdown mode to MRR command) in ns const double tPDEX2MRR = tXP + tMRRI; } } - \ No newline at end of file diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/oc_common.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/oc_common.hpp index 9d87124b..e7d22931 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/oc_common.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/oc_common.hpp @@ -1,8 +1,8 @@ /* + * Copyright (C) Switch-OC-Suite + * * Copyright (c) Souldbminer and Horizon OC Contributors * - * Copyright (c) 2023 hanai3Bi - * * 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. diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/oc_loader.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/oc_loader.hpp index 66361b6e..76af1b60 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/oc_loader.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/oc_loader.hpp @@ -1,8 +1,8 @@ /* + * Copyright (C) Switch-OC-Suite + * * Copyright (c) Souldbminer and Horizon OC Contributors * - * Copyright (c) 2023 hanai3Bi - * * 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. diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/oc_test.cpp b/Source/Atmosphere/stratosphere/loader/source/oc/oc_test.cpp index f80e0b15..443275a3 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/oc_test.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/oc_test.cpp @@ -1,8 +1,8 @@ /* + * Copyright (C) Switch-OC-Suite + * * Copyright (c) Souldbminer and Horizon OC Contributors * - * Copyright (c) 2023 hanai3Bi - * * 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. diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/oc_test.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/oc_test.hpp index b59b8c34..557266a5 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/oc_test.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/oc_test.hpp @@ -1,8 +1,8 @@ /* + * Copyright (C) Switch-OC-Suite + * * Copyright (c) Souldbminer and Horizon OC Contributors * - * Copyright (c) 2023 hanai3Bi - * * 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. @@ -78,4 +78,4 @@ typedef struct UnitTest { } } UnitTest; -#endif \ No newline at end of file +#endif diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.cpp b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.cpp index 00d7744e..0512f442 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.cpp @@ -1,8 +1,10 @@ /* - * Copyright (c) Souldbminer and Horizon OC Contributors + * Copyright (C) Switch-OC-Suite * * Copyright (c) 2023 hanai3Bi - * + * + * Copyright (c) Souldbminer 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. @@ -125,11 +127,11 @@ void SafetyCheck() { eristaGpuDvfsMaxFreq = static_cast(GetDvfsTableLastEntry(C.eristaGpuDvfsTableHigh)->freq); break; case 3: - if(C.enableEristaGpuUnsafeFreqs) + if(C.enableEristaGpuUnsafeFreqs) { eristaGpuDvfsMaxFreq = static_cast(GetDvfsTableLastEntry(C.eristaGpuDvfsTableUv3UnsafeFreqs)->freq); - } - else + } + else { eristaGpuDvfsMaxFreq = static_cast(GetDvfsTableLastEntry(C.eristaGpuDvfsTable)->freq); } @@ -141,30 +143,30 @@ void SafetyCheck() { u32 marikoGpuDvfsMaxFreq; switch (C.marikoGpuUV) { - case 0: + case 0: marikoGpuDvfsMaxFreq = static_cast(GetDvfsTableLastEntry(C.marikoGpuDvfsTable)->freq); break; - case 1: + case 1: marikoGpuDvfsMaxFreq = static_cast(GetDvfsTableLastEntry(C.marikoGpuDvfsTableSLT)->freq); break; - case 2: + case 2: marikoGpuDvfsMaxFreq = static_cast(GetDvfsTableLastEntry(C.marikoGpuDvfsTableHiOPT)->freq); break; case 3: - if(C.enableMarikoGpuUnsafeFreqs) + if(C.enableMarikoGpuUnsafeFreqs) { marikoGpuDvfsMaxFreq = static_cast(GetDvfsTableLastEntry(C.marikoGpuDvfsTableUv3UnsafeFreqs)->freq); - } - else + } + else { marikoGpuDvfsMaxFreq = static_cast(GetDvfsTableLastEntry(C.marikoGpuDvfsTable)->freq); } break; - default: + default: marikoGpuDvfsMaxFreq = static_cast(GetDvfsTableLastEntry(C.marikoGpuDvfsTable)->freq); break; } - + sValidator validators[] = { { C.commonCpuBoostClock, 1020'000, 3000'000, true }, { C.commonEmcMemVolt, 1100'000, 1500'000 }, // Official burst vmax for the RAMs @@ -196,4 +198,4 @@ void Patch(uintptr_t mapped_nso, size_t nso_size) { #endif } -} \ No newline at end of file +} diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.hpp index 9579be2d..7760fccc 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.hpp @@ -1,8 +1,10 @@ /* - * Copyright (c) Souldbminer and Horizon OC Contributors + * Copyright (C) Switch-OC-Suite * * Copyright (c) 2023 hanai3Bi * + * Copyright (c) Souldbminer 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. @@ -48,7 +50,7 @@ namespace ams::ldr::oc::pcv {1963500, {1675751, -38635, 27}, {1120000}}, {}, }; - + constexpr int gpuVmax = 750; constexpr int gpuVmin = 610; @@ -190,7 +192,7 @@ namespace ams::ldr::oc::pcv }; constexpr int gpuVmin = 810; - + constexpr u32 CpuVoltOfficial = 1235; constexpr u32 CpuVoltL4T = 1235'000; @@ -347,11 +349,11 @@ namespace ams::ldr::oc::pcv customize_table = const_cast(C.marikoGpuDvfsTableHiOPT); break; case 3: - if(C.enableMarikoGpuUnsafeFreqs) + if(C.enableMarikoGpuUnsafeFreqs) { customize_table = const_cast(C.marikoGpuDvfsTableUv3UnsafeFreqs); - } - else + } + else { customize_table = const_cast(C.marikoGpuDvfsTable); } @@ -375,11 +377,11 @@ namespace ams::ldr::oc::pcv customize_table = const_cast(C.eristaGpuDvfsTableHigh); break; case 3: - if(C.enableEristaGpuUnsafeFreqs) + if(C.enableEristaGpuUnsafeFreqs) { customize_table = const_cast(C.eristaGpuDvfsTableUv3UnsafeFreqs); - } - else + } + else { customize_table = const_cast(C.eristaGpuDvfsTable); } 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 4193c3b6..3dfcfe1f 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_common.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_common.hpp @@ -1,8 +1,8 @@ /* + * Copyright (C) Switch-OC-Suite + * * Copyright (c) Souldbminer and Horizon OC Contributors * - * Copyright (c) 2023 hanai3Bi - * * 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. @@ -19,7 +19,7 @@ #pragma once namespace ams::ldr::oc::pcv { - + typedef struct cvb_coefficients { s32 c0 = 0; s32 c1 = 0; @@ -28,14 +28,14 @@ s32 c4 = 0; s32 c5 = 0; } cvb_coefficients; - + typedef struct cvb_entry_t { u64 freq; cvb_coefficients cvb_dfll_param; cvb_coefficients cvb_pll_param; } cvb_entry_t; static_assert(sizeof(cvb_entry_t) == 0x38); - + typedef struct cvb_cpu_dfll_data { u32 tune0_low; u32 tune0_high; @@ -45,12 +45,12 @@ unsigned int tune_high_margin_millivolts; 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; @@ -62,7 +62,7 @@ u8 override_divm_shift; u8 override_divp_shift; } div_nmp; - + typedef struct __attribute__((packed)) clk_pll_param { u32 freq; u32 input_min; @@ -78,7 +78,7 @@ u32 unk_1[4]; void (*unk_fn)(u64* unk_struct); // set_defaults? } clk_pll_param; - + typedef struct __attribute__((packed)) dvfs_rail { u32 id; u32 unk_0[5]; @@ -90,7 +90,7 @@ u32 max_mv; u32 unk_2[11]; } dvfs_rail; - + typedef struct __attribute__((packed)) regulator { u64 id; const char* name; @@ -117,21 +117,21 @@ u32 unk_x[60]; } regulator; static_assert(sizeof(regulator) == 0x120); - + constexpr u32 CpuClkOSLimit = 1785'000; - + constexpr u32 EmcClkOSLimit = 1600'000; - + #define R_SKIP() R_SUCCEED() - + // Count 32 / Index 31 is reserved to be empty constexpr size_t DvfsTableEntryCount = 32; constexpr size_t DvfsTableEntryLimit = DvfsTableEntryCount - 1; - + template size_t GetDvfsTableEntryCount(T* table_head) { using NT = std::remove_const_t>; - + auto is_empty = [](NT* entry) { uint8_t* m = reinterpret_cast(entry); for (size_t i = 0; i < sizeof(NT); i++) { @@ -140,7 +140,7 @@ } return true; }; - + NT* table = const_cast(table_head); size_t count = 0; while (count < DvfsTableEntryLimit) { @@ -151,11 +151,11 @@ } return DvfsTableEntryLimit; } - + template T* GetDvfsTableLastEntry(T* table_head) { using NT = std::remove_const_t>; - + NT* table = const_cast(table_head); size_t count = GetDvfsTableEntryCount(table_head); if (!count) { @@ -164,5 +164,5 @@ size_t index = count - 1; return table + index; } - - } \ No newline at end of file + + } 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 e16864b3..16bb85b8 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_erista.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_erista.cpp @@ -1,8 +1,10 @@ /* - * Copyright (c) Souldbminer and Horizon OC Contributors + * Copyright (C) Switch-OC-Suite * * Copyright (c) 2023 hanai3Bi * + * Copyright (c) Souldbminer 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. @@ -18,17 +20,16 @@ #include "pcv.hpp" #include "../mtc_timing_value.hpp" - - namespace ams::ldr::oc::pcv::erista - { + + namespace ams::ldr::oc::pcv::erista { Result CpuFreqVdd(u32* ptr) { dvfs_rail* entry = reinterpret_cast(reinterpret_cast(ptr) - offsetof(dvfs_rail, freq)); - + R_UNLESS(entry->id == 1, ldr::ResultInvalidCpuFreqVddEntry()); R_UNLESS(entry->min_mv == 250'000, ldr::ResultInvalidCpuFreqVddEntry()); R_UNLESS(entry->step_mv == 5000, ldr::ResultInvalidCpuFreqVddEntry()); R_UNLESS(entry->max_mv == 1525'000, ldr::ResultInvalidCpuFreqVddEntry()); - + if (C.eristaCpuUV) { if(!C.enableEristaCpuUnsafeFreqs) { PATCH_OFFSET(ptr, GetDvfsTableLastEntry(C.eristaCpuDvfsTable)->freq); @@ -38,27 +39,24 @@ } else { PATCH_OFFSET(ptr, GetDvfsTableLastEntry(C.eristaCpuDvfsTable)->freq); } - + R_SUCCEED(); } - Result GpuVmin(u32 *ptr) - { + Result GpuVmin(u32 *ptr) { if (!C.eristaGpuVmin) R_SKIP(); PATCH_OFFSET(ptr, (int)C.eristaGpuVmin); R_SUCCEED(); } - Result CpuVoltRange(u32 *ptr) - { + Result CpuVoltRange(u32 *ptr) { u32 min_volt_got = *(ptr - 1); - for (const auto &mv : CpuMinVolts) - { + for (const auto &mv : CpuMinVolts) { if (min_volt_got != mv) continue; - + if (!C.eristaCpuMaxVolt) R_SKIP(); - + PATCH_OFFSET(ptr, C.eristaCpuMaxVolt); R_SUCCEED(); } @@ -66,7 +64,7 @@ } Result CpuVoltDfll(u32* ptr) { cvb_cpu_dfll_data *entry = reinterpret_cast(ptr); - + // R_UNLESS(entry->tune0_low == 0x0000FFCF, ldr::ResultInvalidCpuVoltDfllEntry()); // R_UNLESS(entry->tune0_high == 0x00000000, ldr::ResultInvalidCpuVoltDfllEntry()); // R_UNLESS(entry->tune1_low == 0x012207FF, ldr::ResultInvalidCpuVoltDfllEntry()); @@ -101,25 +99,23 @@ break; default: break; - } + } R_SUCCEED(); } - - Result GpuFreqMaxAsm(u32 *ptr32) - { + + 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]))) R_THROW(ldr::ResultInvalidGpuFreqMaxPattern()); - + // Both instructions should operate on the same register u8 rd = asm_get_rd(ins1); if (rd != asm_get_rd(ins2)) R_THROW(ldr::ResultInvalidGpuFreqMaxPattern()); - + u32 max_clock; - switch (C.eristaGpuUV) - { + switch (C.eristaGpuUV) { case 0: max_clock = GetDvfsTableLastEntry(C.eristaGpuDvfsTable)->freq; break; @@ -130,12 +126,9 @@ max_clock = GetDvfsTableLastEntry(C.eristaGpuDvfsTableHigh)->freq; break; case 3: - if(C.enableEristaGpuUnsafeFreqs) - { + if(C.enableEristaGpuUnsafeFreqs) { max_clock = GetDvfsTableLastEntry(C.eristaGpuDvfsTableUv3UnsafeFreqs)->freq; - } - else - { + } else { max_clock = GetDvfsTableLastEntry(C.eristaGpuDvfsTable)->freq; } break; @@ -148,48 +141,42 @@ asm_set_rd(asm_set_imm16(asm_pattern[1], max_clock >> 16), rd)}; PATCH_OFFSET(ptr32, asm_patch[0]); PATCH_OFFSET(ptr32 + 1, asm_patch[1]); - + R_SUCCEED(); } - - Result GpuFreqPllLimit(u32 *ptr) - { + + Result GpuFreqPllLimit(u32 *ptr) { clk_pll_param *entry = reinterpret_cast(ptr); - + // All zero except for freq - for (size_t i = 1; i < sizeof(clk_pll_param) / sizeof(u32); i++) - { + for (size_t i = 1; i < sizeof(clk_pll_param) / sizeof(u32); i++) { R_UNLESS(*(ptr + i) == 0, ldr::ResultInvalidGpuPllEntry()); } - + // Double the max clk simply u32 max_clk = entry->freq * 2; entry->freq = max_clk; R_SUCCEED(); } - - void MemMtcTableAutoAdjust(EristaMtcTable *table) - { - if (C.mtcConf != AUTO_ADJ_ALL) + + void MemMtcTableAutoAdjust(EristaMtcTable *table) { + if (C.mtcConfErista != AUTO_ADJ) return; - + #define WRITE_PARAM_ALL_REG(TABLE, PARAM, VALUE) \ TABLE->burst_regs.PARAM = VALUE; \ TABLE->shadow_regs_ca_train.PARAM = VALUE; \ TABLE->shadow_regs_quse_train.PARAM = VALUE; \ TABLE->shadow_regs_rdwr_train.PARAM = VALUE; - + #define GET_CYCLE_CEIL(PARAM) u32(CEIL(double(PARAM) / tCK_avg)) - + WRITE_PARAM_ALL_REG(table, emc_rc, GET_CYCLE_CEIL(tRC)); WRITE_PARAM_ALL_REG(table, emc_rfc, GET_CYCLE_CEIL(tRFCab)); WRITE_PARAM_ALL_REG(table, emc_rfcpb, GET_CYCLE_CEIL(tRFCpb)); WRITE_PARAM_ALL_REG(table, emc_ras, GET_CYCLE_CEIL(tRAS)); WRITE_PARAM_ALL_REG(table, emc_rp, GET_CYCLE_CEIL(tRPpb)); - WRITE_PARAM_ALL_REG(table, emc_r2w, R2W); - WRITE_PARAM_ALL_REG(table, emc_w2r, W2R); WRITE_PARAM_ALL_REG(table, emc_r2p, GET_CYCLE_CEIL(tRTP)); - WRITE_PARAM_ALL_REG(table, emc_w2p, WTP); WRITE_PARAM_ALL_REG(table, emc_rd_rcd, GET_CYCLE_CEIL(tRCD)); WRITE_PARAM_ALL_REG(table, emc_wr_rcd, GET_CYCLE_CEIL(tRCD)); WRITE_PARAM_ALL_REG(table, emc_rrd, GET_CYCLE_CEIL(tRRD)); @@ -197,26 +184,15 @@ WRITE_PARAM_ALL_REG(table, emc_pre_refresh_req_cnt, REFRESH / 4); WRITE_PARAM_ALL_REG(table, emc_pdex2wr, GET_CYCLE_CEIL(tXP)); WRITE_PARAM_ALL_REG(table, emc_pdex2rd, GET_CYCLE_CEIL(tXP)); - WRITE_PARAM_ALL_REG(table, emc_pchg2pden, GET_CYCLE_CEIL(tCMDCKE)); - WRITE_PARAM_ALL_REG(table, emc_act2pden, GET_CYCLE_CEIL(tMRWCKEL)); - WRITE_PARAM_ALL_REG(table, emc_ar2pden, GET_CYCLE_CEIL(tCMDCKE)); - WRITE_PARAM_ALL_REG(table, emc_rw2pden, WTPDEN); - WRITE_PARAM_ALL_REG(table, emc_cke2pden, GET_CYCLE_CEIL(tCKELCS)); - WRITE_PARAM_ALL_REG(table, emc_pdex2cke, GET_CYCLE_CEIL(tCSCKEH)); - WRITE_PARAM_ALL_REG(table, emc_pdex2mrr, GET_CYCLE_CEIL(tPDEX2MRR)); WRITE_PARAM_ALL_REG(table, emc_txsr, MIN(GET_CYCLE_CEIL(tXSR), (u32)0x3fe)); WRITE_PARAM_ALL_REG(table, emc_txsrdll, MIN(GET_CYCLE_CEIL(tXSR), (u32)0x3fe)); - WRITE_PARAM_ALL_REG(table, emc_tcke, GET_CYCLE_CEIL(tCKE)); WRITE_PARAM_ALL_REG(table, emc_tckesr, GET_CYCLE_CEIL(tSR)); - WRITE_PARAM_ALL_REG(table, emc_tpd, GET_CYCLE_CEIL(tCKE)); WRITE_PARAM_ALL_REG(table, emc_tfaw, GET_CYCLE_CEIL(tFAW)); WRITE_PARAM_ALL_REG(table, emc_trpab, GET_CYCLE_CEIL(tRPab)); - WRITE_PARAM_ALL_REG(table, emc_tclkstable, GET_CYCLE_CEIL(tCKCKEH)); - WRITE_PARAM_ALL_REG(table, emc_tclkstop, GET_CYCLE_CEIL(tCKE) + 8); WRITE_PARAM_ALL_REG(table, emc_trefbw, REFBW); - + #define WRITE_PARAM_BURST_MC_REG(TABLE, PARAM, VALUE) TABLE->burst_mc_regs.PARAM = VALUE; - + constexpr u32 MC_ARB_DIV = 4; constexpr u32 MC_ARB_SFA = 2; table->burst_mc_regs.mc_emem_arb_timing_rcd = CEIL(GET_CYCLE_CEIL(tRCD) / MC_ARB_DIV) - 2; @@ -225,143 +201,66 @@ table->burst_mc_regs.mc_emem_arb_timing_ras = CEIL(GET_CYCLE_CEIL(tRAS) / MC_ARB_DIV) - 2; table->burst_mc_regs.mc_emem_arb_timing_faw = CEIL(GET_CYCLE_CEIL(tFAW) / MC_ARB_DIV) - 1; table->burst_mc_regs.mc_emem_arb_timing_rrd = CEIL(GET_CYCLE_CEIL(tRRD) / MC_ARB_DIV) - 1; - table->burst_mc_regs.mc_emem_arb_timing_rap2pre = CEIL(GET_CYCLE_CEIL(tRTP) / MC_ARB_DIV); - table->burst_mc_regs.mc_emem_arb_timing_wap2pre = CEIL(WTP / MC_ARB_DIV); + //table->burst_mc_regs.mc_emem_arb_timing_rap2pre = CEIL(GET_CYCLE_CEIL(tRTP) / MC_ARB_DIV); + //table->burst_mc_regs.mc_emem_arb_timing_wap2pre = CEIL(WTP / MC_ARB_DIV); // table->burst_mc_regs.mc_emem_arb_timing_r2r = CEIL(table->burst_regs.emc_rext / MC_ARB_DIV) - 1 + MC_ARB_SFA; // table->burst_mc_regs.mc_emem_arb_timing_w2w = CEIL(table->burst_regs.emc_wext / MC_ARB_DIV) - 1 + MC_ARB_SFA; - table->burst_mc_regs.mc_emem_arb_timing_r2w = CEIL(R2W / MC_ARB_DIV) - 1 + MC_ARB_SFA; - table->burst_mc_regs.mc_emem_arb_timing_w2r = CEIL(W2R / MC_ARB_DIV) - 1 + MC_ARB_SFA; + // table->burst_mc_regs.mc_emem_arb_timing_r2w = CEIL(R2W / MC_ARB_DIV) - 1 + MC_ARB_SFA; + // table->burst_mc_regs.mc_emem_arb_timing_w2r = CEIL(W2R / MC_ARB_DIV) - 1 + MC_ARB_SFA; table->burst_mc_regs.mc_emem_arb_timing_rfcpb = CEIL(GET_CYCLE_CEIL(tRFCpb) / MC_ARB_DIV); // table->burst_mc_regs.mc_emem_arb_timing_ccdmw = CEIL(tCCDMW / MC_ARB_DIV) -1 + MC_ARB_SFA; } - - void MemMtcTableCustomAdjust(EristaMtcTable *table) - { - if (C.mtcConf != CUSTOM_ADJ_ALL) - return; - - constexpr u32 MC_ARB_DIV = 4; - constexpr u32 MC_ARB_SFA = 2; - - WRITE_PARAM_ALL_REG(table, emc_rc, GET_CYCLE_CEIL(tRC)); - WRITE_PARAM_ALL_REG(table, emc_ras, GET_CYCLE_CEIL(tRAS)); - WRITE_PARAM_ALL_REG(table, emc_rp, GET_CYCLE_CEIL(tRPpb)); - WRITE_PARAM_ALL_REG(table, emc_trpab, GET_CYCLE_CEIL(tRPab)); - WRITE_PARAM_ALL_REG(table, emc_rd_rcd, GET_CYCLE_CEIL(tRCD)); - WRITE_PARAM_ALL_REG(table, emc_wr_rcd, GET_CYCLE_CEIL(tRCD)); - WRITE_PARAM_ALL_REG(table, emc_pdex2mrr, GET_CYCLE_CEIL(tPDEX2MRR)); - - 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_rc = CEIL(GET_CYCLE_CEIL(tRC) / MC_ARB_DIV - 1); - table->burst_mc_regs.mc_emem_arb_timing_rp = CEIL(GET_CYCLE_CEIL(tRPpb) / MC_ARB_DIV - 1 + MC_ARB_SFA); - table->burst_mc_regs.mc_emem_arb_timing_ras = CEIL(GET_CYCLE_CEIL(tRAS) / MC_ARB_DIV - 2); - - WRITE_PARAM_ALL_REG(table, emc_tfaw, GET_CYCLE_CEIL(tFAW)); - WRITE_PARAM_ALL_REG(table, emc_rrd, GET_CYCLE_CEIL(tRRD)); - - table->burst_mc_regs.mc_emem_arb_timing_faw = CEIL(GET_CYCLE_CEIL(tFAW) / MC_ARB_DIV) - 1; - table->burst_mc_regs.mc_emem_arb_timing_rrd = CEIL(GET_CYCLE_CEIL(tRRD) / MC_ARB_DIV) - 1; - - - WRITE_PARAM_ALL_REG(table, emc_r2p, GET_CYCLE_CEIL(tRTP)); - WRITE_PARAM_ALL_REG(table, emc_w2p, WTP); - WRITE_PARAM_ALL_REG(table, emc_rw2pden, WTPDEN); - - table->burst_mc_regs.mc_emem_arb_timing_rap2pre = CEIL(GET_CYCLE_CEIL(tRTP) / MC_ARB_DIV); - table->burst_mc_regs.mc_emem_arb_timing_wap2pre = CEIL(WTP / MC_ARB_DIV); - - - WRITE_PARAM_ALL_REG(table, emc_rfc, GET_CYCLE_CEIL(tRFCab)); - WRITE_PARAM_ALL_REG(table, emc_rfcpb, GET_CYCLE_CEIL(tRFCpb)); - WRITE_PARAM_ALL_REG(table, emc_txsr, MIN(GET_CYCLE_CEIL(tXSR), (u32)0x3fe)); - WRITE_PARAM_ALL_REG(table, emc_txsrdll, MIN(GET_CYCLE_CEIL(tXSR), (u32)0x3fe)); - - table->burst_mc_regs.mc_emem_arb_timing_rfcpb = CEIL(GET_CYCLE_CEIL(tRFCpb) / MC_ARB_DIV); - - - WRITE_PARAM_ALL_REG(table, emc_w2r, W2R); - - table->burst_mc_regs.mc_emem_arb_timing_w2r = CEIL(W2R / MC_ARB_DIV) - 1 + MC_ARB_SFA; - - WRITE_PARAM_ALL_REG(table, emc_refresh, REFRESH); - WRITE_PARAM_ALL_REG(table, emc_pre_refresh_req_cnt, REFRESH / 4); - WRITE_PARAM_ALL_REG(table, emc_trefbw, REFBW); - WRITE_PARAM_ALL_REG(table, emc_r2w, R2W); - WRITE_PARAM_ALL_REG(table, emc_w2r, W2R); - WRITE_PARAM_ALL_REG(table, emc_w2p, WTP); - WRITE_PARAM_ALL_REG(table, emc_rw2pden, WTPDEN); - - table->burst_mc_regs.mc_emem_arb_timing_wap2pre = CEIL(WTP / MC_ARB_DIV); - table->burst_mc_regs.mc_emem_arb_timing_r2w = CEIL(R2W / MC_ARB_DIV) - 1 + MC_ARB_SFA; - table->burst_mc_regs.mc_emem_arb_timing_w2r = CEIL(W2R / MC_ARB_DIV) - 1 + MC_ARB_SFA; - - u32 DA_TURNS = 0; - DA_TURNS |= u8(table->burst_mc_regs.mc_emem_arb_timing_r2w / 2) << 16; // R2W TURN - DA_TURNS |= u8(table->burst_mc_regs.mc_emem_arb_timing_w2r / 2) << 24; // W2R TURN - WRITE_PARAM_BURST_MC_REG(table, mc_emem_arb_da_turns, DA_TURNS); - u32 DA_COVERS = 0; - u8 R_COVER = (table->burst_mc_regs.mc_emem_arb_timing_rap2pre + table->burst_mc_regs.mc_emem_arb_timing_rp + table->burst_mc_regs.mc_emem_arb_timing_rcd) / 2; - u8 W_COVER = (table->burst_mc_regs.mc_emem_arb_timing_wap2pre + table->burst_mc_regs.mc_emem_arb_timing_rp + table->burst_mc_regs.mc_emem_arb_timing_rcd) / 2; - DA_COVERS |= (u8)(table->burst_mc_regs.mc_emem_arb_timing_rc / 2); // RC COVER - DA_COVERS |= (R_COVER << 8); // RCD_R COVER - DA_COVERS |= (W_COVER << 16); // RCD_W COVER - WRITE_PARAM_BURST_MC_REG(table, mc_emem_arb_da_covers, DA_COVERS); - } - - Result MemFreqMtcTable(u32 *ptr) - { + + Result MemFreqMtcTable(u32 *ptr) { u32 khz_list[] = {1600000, 1331200, 1065600, 800000, 665600, 408000, 204000, 102000, 68000, 40800}; u32 khz_list_size = sizeof(khz_list) / sizeof(u32); - + // Generate list for mtc table pointers EristaMtcTable *table_list[khz_list_size]; - for (u32 i = 0; i < khz_list_size; i++) - { + for (u32 i = 0; i < khz_list_size; i++) { u8 *table = reinterpret_cast(ptr) - offsetof(EristaMtcTable, rate_khz) - i * sizeof(EristaMtcTable); 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()); } - + if (C.eristaEmcMaxClock <= EmcClkOSLimit) R_SKIP(); - + // Make room for new mtc table, discarding useless 40.8 MHz table // 40800 overwritten by 68000, ..., 1331200 overwritten by 1600000, leaving table_list[0] not overwritten for (u32 i = khz_list_size - 1; i > 0; i--) std::memcpy(static_cast(table_list[i]), static_cast(table_list[i - 1]), sizeof(EristaMtcTable)); - + MemMtcTableAutoAdjust(table_list[0]); PATCH_OFFSET(ptr, C.eristaEmcMaxClock); - + // Handle customize table replacement // if (C.mtcConf == CUSTOMIZED_ALL) { // MemMtcCustomizeTable(table_list[0], const_cast(C.eristaMtcTable)); //} - + R_SUCCEED(); } - - Result MemFreqMax(u32 *ptr) - { + + Result MemFreqMax(u32 *ptr) { if (C.eristaEmcMaxClock <= EmcClkOSLimit) R_SKIP(); - + PATCH_OFFSET(ptr, C.eristaEmcMaxClock); - + R_SUCCEED(); } - - void Patch(uintptr_t mapped_nso, size_t nso_size) - { + + void Patch(uintptr_t mapped_nso, size_t nso_size) { 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 Vdd", &CpuFreqVdd, 1, nullptr, CpuClkOSLimit }, {"CPU Freq Table", CpuFreqCvbTable, 1, nullptr, CpuCvbDefaultMaxFreq}, - { "CPU Volt Limit", &CpuVoltRange, 13, nullptr, CpuVoltOfficial }, - { "CPU Volt Dfll", &CpuVoltDfll, 1, nullptr, 0xFFEAD0FF }, + {"CPU Volt Limit", &CpuVoltRange, 13, nullptr, CpuVoltOfficial }, + {"CPU Volt Dfll", &CpuVoltDfll, 1, nullptr, 0xFFEAD0FF }, {"GPU Freq Table", GpuFreqCvbTable, 1, nullptr, GpuCvbDefaultMaxFreq}, {"GPU Freq Asm", &GpuFreqMaxAsm, 2, &GpuMaxClockPatternFn}, {"GPU Freq PLL", &GpuFreqPllLimit, 1, nullptr, GpuClkPllLimit}, @@ -371,25 +270,22 @@ {"MEM Volt", &MemVoltHandler, 2, nullptr, MemVoltHOS}, {"GPU Vmin", &GpuVmin, 0, nullptr, gpuVmin}, }; - + for (uintptr_t ptr = mapped_nso; ptr <= mapped_nso + nso_size - sizeof(EristaMtcTable); - ptr += sizeof(u32)) - { + ptr += sizeof(u32)) { u32 *ptr32 = reinterpret_cast(ptr); - for (auto &entry : patches) - { + for (auto &entry : patches) { if (R_SUCCEEDED(entry.SearchAndApply(ptr32))) break; } } - - for (auto &entry : patches) - { + + for (auto &entry : patches) { LOGGING("%s Count: %zu", entry.description, entry.patched_count); if (R_FAILED(entry.CheckResult())) CRASH(entry.description); } } - - } \ No newline at end of file + + } 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 1fa71784..471577ce 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.cpp @@ -1,8 +1,10 @@ /* - * Copyright (c) Souldbminer and Horizon OC Contributors + * Copyright (C) Switch-OC-Suite * * Copyright (c) 2023 hanai3Bi - * + * + * Copyright (c) Souldbminer 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. @@ -18,9 +20,9 @@ #include "pcv.hpp" #include "../mtc_timing_value.hpp" - + namespace ams::ldr::oc::pcv::mariko { - + Result GpuVmin(u32 *ptr) { if (!C.marikoGpuVmin) @@ -39,12 +41,12 @@ Result GpuVmax(u32 *ptr) Result CpuFreqVdd(u32* ptr) { dvfs_rail* entry = reinterpret_cast(reinterpret_cast(ptr) - offsetof(dvfs_rail, freq)); - + R_UNLESS(entry->id == 1, ldr::ResultInvalidCpuFreqVddEntry()); R_UNLESS(entry->min_mv == 250'000, ldr::ResultInvalidCpuFreqVddEntry()); R_UNLESS(entry->step_mv == 5000, ldr::ResultInvalidCpuFreqVddEntry()); R_UNLESS(entry->max_mv == 1525'000, ldr::ResultInvalidCpuFreqVddEntry()); - + if (C.marikoCpuUV) { if(!C.enableMarikoCpuUnsafeFreqs) { PATCH_OFFSET(ptr, GetDvfsTableLastEntry(C.marikoCpuDvfsTableSLT)->freq); @@ -54,19 +56,19 @@ Result GpuVmax(u32 *ptr) } else { PATCH_OFFSET(ptr, GetDvfsTableLastEntry(C.marikoCpuDvfsTable)->freq); } - + R_SUCCEED(); } - + Result CpuVoltRange(u32* ptr) { u32 min_volt_got = *(ptr - 1); for (const auto& mv : CpuMinVolts) { if (min_volt_got != mv) continue; - + if (!C.marikoCpuMaxVolt) R_SKIP(); - + PATCH_OFFSET(ptr, C.marikoCpuMaxVolt); // Patch vmin for slt if (C.marikoCpuUV) { @@ -76,16 +78,16 @@ Result GpuVmax(u32 *ptr) if (*(ptr-1) == 620) { PATCH_OFFSET((ptr-1), 600); } - + } R_SUCCEED(); } R_THROW(ldr::ResultInvalidCpuMinVolt()); } - + Result CpuVoltDfll(u32* ptr) { cvb_cpu_dfll_data *entry = reinterpret_cast(ptr); - + R_UNLESS(entry->tune0_low == 0x0000FFCF, ldr::ResultInvalidCpuVoltDfllEntry()); R_UNLESS(entry->tune0_high == 0x00000000, ldr::ResultInvalidCpuVoltDfllEntry()); R_UNLESS(entry->tune1_low == 0x012207FF, ldr::ResultInvalidCpuVoltDfllEntry()); @@ -143,43 +145,43 @@ Result GpuVmax(u32 *ptr) break; default: break; - } + } R_SUCCEED(); } - + 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]))) R_THROW(ldr::ResultInvalidGpuFreqMaxPattern()); - + // Both instructions should operate on the same register u8 rd = asm_get_rd(ins1); if (rd != asm_get_rd(ins2)) R_THROW(ldr::ResultInvalidGpuFreqMaxPattern()); - + u32 max_clock; switch(C.marikoGpuUV) { - case 0: + case 0: max_clock = GetDvfsTableLastEntry(C.marikoGpuDvfsTable)->freq; break; - case 1: + case 1: max_clock = GetDvfsTableLastEntry(C.marikoGpuDvfsTableSLT)->freq; break; - case 2: + case 2: max_clock = GetDvfsTableLastEntry(C.marikoGpuDvfsTableHiOPT)->freq; break; case 3: - if(C.enableMarikoGpuUnsafeFreqs) + if(C.enableMarikoGpuUnsafeFreqs) { max_clock = GetDvfsTableLastEntry(C.marikoGpuDvfsTableUv3UnsafeFreqs)->freq; - } - else + } + else { max_clock = GetDvfsTableLastEntry(C.marikoGpuDvfsTable)->freq; } break; - default: + default: max_clock = GetDvfsTableLastEntry(C.marikoGpuDvfsTable)->freq; break; } @@ -189,24 +191,24 @@ Result GpuVmax(u32 *ptr) }; PATCH_OFFSET(ptr32, asm_patch[0]); PATCH_OFFSET(ptr32 + 1, asm_patch[1]); - + R_SUCCEED(); } - + Result GpuFreqPllLimit(u32* ptr) { clk_pll_param* entry = reinterpret_cast(ptr); - + // All zero except for freq for (size_t i = 1; i < sizeof(clk_pll_param) / sizeof(u32); i++) { R_UNLESS(*(ptr + i) == 0, ldr::ResultInvalidGpuPllEntry()); } - + // Double the max clk simply u32 max_clk = entry->freq * 2; entry->freq = max_clk; R_SUCCEED(); } - + void MemMtcTableAutoAdjust(MarikoMtcTable* table, const MarikoMtcTable* ref) { /* Official Tegra X1 TRM, sign up for nvidia developer program (free) to download: * https://developer.nvidia.com/embedded/dlc/tegra-x1-technical-reference-manual @@ -224,36 +226,36 @@ Result GpuVmax(u32 *ptr) * If you have access to LPDDR4(X) specs or datasheets (from manufacturers or Google), * you'd better calculate timings yourself rather than relying on following algorithm. */ - - if (C.mtcConf != AUTO_ADJ_ALL) + + if (C.mtcConfMariko != AUTO_ADJ_ALL) return; - + // scale with linear interpolation #define ADJUST_PROP(TARGET, REF) \ (u32)(CEIL((REF + ((C.marikoEmcMaxClock-EmcClkOSAlt)*(TARGET-REF))/(EmcClkOSLimit-EmcClkOSAlt)))) - + #define ADJUST_PARAM(TARGET, REF) \ TARGET = ADJUST_PROP(TARGET, REF); - + #define ADJUST_PARAM_TABLE(TABLE, PARAM, REF) ADJUST_PARAM(TABLE->PARAM, REF->PARAM) - + // Burst Register #define ADJUST_PARAM_ALL_REG(TABLE, PARAM, REF) \ ADJUST_PARAM_TABLE(TABLE, burst_regs.PARAM, REF) \ ADJUST_PARAM_TABLE(TABLE, shadow_regs_ca_train.PARAM, REF) \ ADJUST_PARAM_TABLE(TABLE, shadow_regs_rdwr_train.PARAM, REF) - - #define WRITE_PARAM_BURST_REG(TABLE, PARAM, VALUE) TABLE->burst_regs.PARAM = VALUE; + + #define WRITE_PARAM_BURST_REG(TABLE, PARAM, VALUE) TABLE->burst_regs.PARAM = VALUE; #define WRITE_PARAM_CA_TRAIN_REG(TABLE, PARAM, VALUE) TABLE->shadow_regs_ca_train.PARAM = VALUE; - #define WRITE_PARAM_RDWR_TRAIN_REG(TABLE, PARAM, VALUE) TABLE->shadow_regs_rdwr_train.PARAM = VALUE; - + #define WRITE_PARAM_RDWR_TRAIN_REG(TABLE, PARAM, VALUE) TABLE->shadow_regs_rdwr_train.PARAM = VALUE; + #define WRITE_PARAM_ALL_REG(TABLE, PARAM, VALUE) \ WRITE_PARAM_BURST_REG(TABLE, PARAM, VALUE) \ WRITE_PARAM_CA_TRAIN_REG(TABLE, PARAM, VALUE) \ WRITE_PARAM_RDWR_TRAIN_REG(TABLE, PARAM, VALUE) - + #define GET_CYCLE_CEIL(PARAM) u32(CEIL(double(PARAM) / tCK_avg)) - + WRITE_PARAM_ALL_REG(table, emc_rc, GET_CYCLE_CEIL(tRC)); WRITE_PARAM_ALL_REG(table, emc_rfc, GET_CYCLE_CEIL(tRFCab)); WRITE_PARAM_ALL_REG(table, emc_rfcpb, GET_CYCLE_CEIL(tRFCpb)); @@ -293,22 +295,22 @@ Result GpuVmax(u32 *ptr) //WRITE_PARAM_ALL_REG(table, emc_tclkstable, GET_CYCLE_CEIL(tCKCKEH)); WRITE_PARAM_ALL_REG(table, emc_tclkstop, GET_CYCLE_CEIL(tCKE) + 8); WRITE_PARAM_ALL_REG(table, emc_trefbw, REFBW); - + ADJUST_PARAM_ALL_REG(table, emc_dyn_self_ref_control, ref); - - + + #define CLEAR_BIT(BITS, HIGH, LOW) \ BITS = BITS & ~( ((1u << HIGH) << 1u) - (1u << LOW) ); - + #define ADJUST(TARGET) (u32)CEIL(TARGET * (C.marikoEmcMaxClock / EmcClkOSLimit)) #define ADJUST_INVERSE(TARGET) (u32)(TARGET * (EmcClkOSLimit / 1000) / (C.marikoEmcMaxClock / 1000)) - + // Burst MC Regs #define WRITE_PARAM_BURST_MC_REG(TABLE, PARAM, VALUE) TABLE->burst_mc_regs.PARAM = VALUE; - + constexpr u32 MC_ARB_DIV = 4; constexpr u32 MC_ARB_SFA = 2; - + WRITE_PARAM_BURST_MC_REG(table, mc_emem_arb_cfg, C.marikoEmcMaxClock / (33.3 * 1000) / MC_ARB_DIV); //CYCLES_PER_UPDATE: The number of mcclk cycles per deadline timer update WRITE_PARAM_BURST_MC_REG(table, mc_emem_arb_timing_rcd, CEIL(GET_CYCLE_CEIL(tRCD) / MC_ARB_DIV) - 2) WRITE_PARAM_BURST_MC_REG(table, mc_emem_arb_timing_rp, CEIL(GET_CYCLE_CEIL(tRPpb) / MC_ARB_DIV) - 1 + MC_ARB_SFA) @@ -322,7 +324,7 @@ Result GpuVmax(u32 *ptr) WRITE_PARAM_BURST_MC_REG(table, mc_emem_arb_timing_r2w, CEIL((R2W) / MC_ARB_DIV) - 1 + MC_ARB_SFA) WRITE_PARAM_BURST_MC_REG(table, mc_emem_arb_timing_w2r, CEIL((W2R) / MC_ARB_DIV) - 1 + MC_ARB_SFA) WRITE_PARAM_BURST_MC_REG(table, mc_emem_arb_timing_rfcpb, CEIL(GET_CYCLE_CEIL(tRFCpb) / MC_ARB_DIV)) - + u32 DA_TURNS = 0; DA_TURNS |= u8(table->burst_mc_regs.mc_emem_arb_timing_r2w / 2) << 16; //R2W TURN DA_TURNS |= u8(table->burst_mc_regs.mc_emem_arb_timing_w2r / 2) << 24; //W2R TURN @@ -334,26 +336,26 @@ Result GpuVmax(u32 *ptr) DA_COVERS |= (R_COVER << 8); //RCD_R COVER DA_COVERS |= (W_COVER << 16); //RCD_W COVER WRITE_PARAM_BURST_MC_REG(table, mc_emem_arb_da_covers, DA_COVERS); - + CLEAR_BIT(table->burst_mc_regs.mc_emem_arb_misc0, 7, 0); table->burst_mc_regs.mc_emem_arb_misc0 |= u8(table->burst_mc_regs.mc_emem_arb_timing_rc + 1); //BC2AA_HOLDOFF CLEAR_BIT(table->burst_mc_regs.mc_emem_arb_misc0, 14, 8); table->burst_mc_regs.mc_emem_arb_misc0 |= u8((ADJUST(0x24) << 8)); //PRIORITY_INVERSION_THRESHOLD CLEAR_BIT(table->burst_mc_regs.mc_emem_arb_misc0, 20, 16); table->burst_mc_regs.mc_emem_arb_misc0 |= u8((ADJUST(12) << 16)); //PRIORITY_INVERSION_ISO_THRESHOLD - + // updown registers #define ADJUST_PARAM_LA_SCALE_REG(TABLE, PARAM) \ TABLE->la_scale_regs.PARAM = ADJUST(TABLE->la_scale_regs.PARAM) - + #define ADJUST_PARAM_LA_SCALE_REG_HI(TABLE, PARAM, VALUE) \ CLEAR_BIT(TABLE->la_scale_regs.PARAM, 23, 16) \ TABLE->la_scale_regs.PARAM |= VALUE << 16 - + #define ADJUST_PARAM_LA_SCALE_REG_LO(TABLE, PARAM, VALUE) \ CLEAR_BIT(TABLE->la_scale_regs.PARAM, 7, 0) \ TABLE->la_scale_regs.PARAM |= VALUE - + u8 LA = ADJUST_INVERSE(128); //0x80 ADJUST_PARAM_LA_SCALE_REG(table, mc_mll_mpcorer_ptsa_rate); //208 ADJUST_PARAM_LA_SCALE_REG(table, mc_ptsa_grant_decrement); //4611 @@ -375,7 +377,7 @@ Result GpuVmax(u32 *ptr) ADJUST_PARAM_LA_SCALE_REG_HI(table, mc_latency_allowance_nvdec_0, LA); ADJUST_PARAM_LA_SCALE_REG_HI(table, mc_latency_allowance_vic_0, LA); ADJUST_PARAM_LA_SCALE_REG_HI(table, mc_latency_allowance_isp2_1, LA); - + ADJUST_PARAM_LA_SCALE_REG_LO(table, mc_latency_allowance_hc_0, ADJUST_INVERSE(0x16)); ADJUST_PARAM_LA_SCALE_REG_LO(table, mc_latency_allowance_hc_1, LA); ADJUST_PARAM_LA_SCALE_REG_LO(table, mc_latency_allowance_gpu_0, ADJUST_INVERSE(0x19)); @@ -383,27 +385,27 @@ Result GpuVmax(u32 *ptr) ADJUST_PARAM_LA_SCALE_REG_LO(table, mc_latency_allowance_vic_0, ADJUST_INVERSE(0x1d)); ADJUST_PARAM_LA_SCALE_REG_LO(table, mc_latency_allowance_vi2_0, LA); ADJUST_PARAM_LA_SCALE_REG_LO(table, mc_latency_allowance_isp2_1, LA); - + //Spread Spectrum Control table->pllm_ss_ctrl1 = 0x0b55fe01; table->pllm_ss_ctrl2 = 0x10170b55; table->pllmb_ss_ctrl1 = 0x0b55fe01; table->pllmb_ss_ctrl2 = 0x10170b55; - + table->dram_timings.t_rp = tRPpb; table->dram_timings.t_rfc = tRFCab; //table->dram_timings.rl = 32; - + table->emc_cfg_2 = 0x0011083d; } - + void MemMtcTableCustomAdjust(MarikoMtcTable* table) { - if (C.mtcConf != CUSTOM_ADJ_ALL) + if (C.mtcConfMariko != CUSTOM_ADJ_ALL) return; - + constexpr u32 MC_ARB_DIV = 4; constexpr u32 MC_ARB_SFA = 2; - + WRITE_PARAM_ALL_REG(table, emc_rc, GET_CYCLE_CEIL(tRC)); WRITE_PARAM_ALL_REG(table, emc_ras, GET_CYCLE_CEIL(tRAS)); WRITE_PARAM_ALL_REG(table, emc_rp, GET_CYCLE_CEIL(tRPpb)); @@ -411,43 +413,43 @@ Result GpuVmax(u32 *ptr) WRITE_PARAM_ALL_REG(table, emc_rd_rcd, GET_CYCLE_CEIL(tRCD)); WRITE_PARAM_ALL_REG(table, emc_wr_rcd, GET_CYCLE_CEIL(tRCD)); WRITE_PARAM_ALL_REG(table, emc_pdex2mrr,GET_CYCLE_CEIL(tPDEX2MRR)); - + 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_rc = CEIL(GET_CYCLE_CEIL(tRC) / MC_ARB_DIV) - 1; table->burst_mc_regs.mc_emem_arb_timing_rp = CEIL(GET_CYCLE_CEIL(tRPpb) / MC_ARB_DIV) - 1 + MC_ARB_SFA; table->burst_mc_regs.mc_emem_arb_timing_ras = CEIL(GET_CYCLE_CEIL(tRAS) / MC_ARB_DIV) - 2; - - + + WRITE_PARAM_ALL_REG(table, emc_tfaw, GET_CYCLE_CEIL(tFAW)); WRITE_PARAM_ALL_REG(table, emc_rrd, GET_CYCLE_CEIL(tRRD)); - + table->burst_mc_regs.mc_emem_arb_timing_faw = CEIL(GET_CYCLE_CEIL(tFAW) / MC_ARB_DIV) - 1; table->burst_mc_regs.mc_emem_arb_timing_rrd = CEIL(GET_CYCLE_CEIL(tRRD) / MC_ARB_DIV) - 1; - + WRITE_PARAM_ALL_REG(table, emc_r2p, GET_CYCLE_CEIL(tRTP)); WRITE_PARAM_ALL_REG(table, emc_w2p, WTP); WRITE_PARAM_ALL_REG(table, emc_tratm, RATM); WRITE_PARAM_ALL_REG(table, emc_twatm, WATM); WRITE_PARAM_ALL_REG(table, emc_rw2pden, WTPDEN); - + table->burst_mc_regs.mc_emem_arb_timing_rap2pre = CEIL(GET_CYCLE_CEIL(tRTP) / MC_ARB_DIV); table->burst_mc_regs.mc_emem_arb_timing_wap2pre = CEIL(WTP / MC_ARB_DIV); - + WRITE_PARAM_ALL_REG(table, emc_rfc, GET_CYCLE_CEIL(tRFCab)); WRITE_PARAM_ALL_REG(table, emc_rfcpb, GET_CYCLE_CEIL(tRFCpb)); WRITE_PARAM_ALL_REG(table, emc_txsr, MIN(GET_CYCLE_CEIL(tXSR), (u32)0x3fe)); WRITE_PARAM_ALL_REG(table, emc_txsrdll, MIN(GET_CYCLE_CEIL(tXSR), (u32)0x3fe)); - + table->burst_mc_regs.mc_emem_arb_timing_rfcpb = CEIL(GET_CYCLE_CEIL(tRFCpb) / MC_ARB_DIV); - + WRITE_PARAM_ALL_REG(table, emc_w2r, W2R); - + table->burst_mc_regs.mc_emem_arb_timing_w2r = CEIL(W2R / MC_ARB_DIV) - 1 + MC_ARB_SFA; - + WRITE_PARAM_ALL_REG(table, emc_refresh, REFRESH); WRITE_PARAM_ALL_REG(table, emc_pre_refresh_req_cnt, REFRESH / 4); WRITE_PARAM_ALL_REG(table, emc_trefbw, REFBW); - + WRITE_PARAM_ALL_REG(table, emc_r2w, R2W); WRITE_PARAM_ALL_REG(table, emc_w2r, W2R); WRITE_PARAM_ALL_REG(table, emc_w2p, WTP); @@ -456,11 +458,11 @@ Result GpuVmax(u32 *ptr) WRITE_PARAM_ALL_REG(table, emc_tratm, RATM); WRITE_PARAM_ALL_REG(table, emc_twatm, WATM); WRITE_PARAM_ALL_REG(table, emc_rw2pden, WTPDEN); - + table->burst_mc_regs.mc_emem_arb_timing_wap2pre = CEIL(WTP / MC_ARB_DIV); table->burst_mc_regs.mc_emem_arb_timing_r2w = CEIL(R2W / MC_ARB_DIV) - 1 + MC_ARB_SFA; table->burst_mc_regs.mc_emem_arb_timing_w2r = CEIL(W2R / MC_ARB_DIV) - 1 + MC_ARB_SFA; - + u32 DA_TURNS = 0; DA_TURNS |= u8(table->burst_mc_regs.mc_emem_arb_timing_r2w / 2) << 16; //R2W TURN DA_TURNS |= u8(table->burst_mc_regs.mc_emem_arb_timing_w2r / 2) << 24; //W2R TURN @@ -473,7 +475,7 @@ Result GpuVmax(u32 *ptr) DA_COVERS |= (W_COVER << 16); //RCD_W COVER WRITE_PARAM_BURST_MC_REG(table, mc_emem_arb_da_covers, DA_COVERS); } - + void MemMtcPllmbDivisor(MarikoMtcTable* table) { // Calculate DIVM and DIVN (clock divisors) // Common PLL oscillator is 38.4 MHz @@ -482,11 +484,11 @@ Result GpuVmax(u32 *ptr) u8 numerator : 4; u8 denominator : 4; } pllmb_div; - + constexpr pllmb_div div[] = { {3, 4}, {2, 3}, {1, 2}, {1, 3}, {1, 4}, {0, 2} }; - + constexpr u32 pll_osc_in = 38'400; u32 divm {}, divn {}; const u32 remainder = C.marikoEmcMaxClock % pll_osc_in; @@ -498,15 +500,15 @@ Result GpuVmax(u32 *ptr) break; } } - + table->pllmb_divm = divm; table->pllmb_divn = divn; } - + Result MemFreqMtcTable(u32* ptr) { u32 khz_list[] = { 1600000, 1331200, 204000 }; u32 khz_list_size = sizeof(khz_list) / sizeof(u32); - + // Generate list for mtc table pointers MarikoMtcTable* table_list[khz_list_size]; for (u32 i = 0; i < khz_list_size; i++) { @@ -515,13 +517,13 @@ Result GpuVmax(u32 *ptr) R_UNLESS(table_list[i]->rate_khz == khz_list[i], ldr::ResultInvalidMtcTable()); R_UNLESS(table_list[i]->rev == MTC_TABLE_REV, ldr::ResultInvalidMtcTable()); } - + if (C.marikoEmcMaxClock <= EmcClkOSLimit) R_SKIP(); - + MarikoMtcTable *table_alt = table_list[1], *table_max = table_list[0]; MarikoMtcTable *tmp = new MarikoMtcTable; - + // Copy unmodified 1600000 table to tmp std::memcpy(reinterpret_cast(tmp), reinterpret_cast(table_max), sizeof(MarikoMtcTable)); // Adjust max freq mtc timing parameters with reference to 1331200 table @@ -530,35 +532,35 @@ Result GpuVmax(u32 *ptr) MemMtcPllmbDivisor(table_max); // Overwrite 13312000 table with unmodified 1600000 table copied back std::memcpy(reinterpret_cast(table_alt), reinterpret_cast(tmp), sizeof(MarikoMtcTable)); - + delete tmp; - + PATCH_OFFSET(ptr, C.marikoEmcMaxClock); - + // Handle customize table replacement //if (C.mtcConf == CUSTOMIZED_ALL) { // MemMtcCustomizeTable(table_list[0], reinterpret_cast(reinterpret_cast(C.marikoMtcTable))); // } - + 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; - + // 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; R_UNLESS(validated, ldr::ResultInvalidDvbTable()); - + if (C.marikoEmcMaxClock <= EmcClkOSLimit) R_SKIP(); - + int32_t voltAdd = 25*C.marikoEmcDvbShift; - + #define DVB_VOLT(zero, one, two) std::min(zero+voltAdd, 1050), std::min(one+voltAdd, 1025), std::min(two+voltAdd, 1000), - + if (C.marikoEmcMaxClock < 1862400) { std::memcpy(new_start, default_end, sizeof(emc_dvb_dvfs_table_t)); } else if (C.marikoEmcMaxClock < 2131200){ @@ -582,44 +584,44 @@ Result GpuVmax(u32 *ptr) } new_start->freq = C.marikoEmcMaxClock; /* 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 - */ - + reason why it's like this + */ + R_SUCCEED(); } - + Result MemFreqMax(u32* ptr) { if (C.marikoEmcMaxClock <= EmcClkOSLimit) R_SKIP(); - + PATCH_OFFSET(ptr, C.marikoEmcMaxClock); R_SUCCEED(); } - + Result I2cSet_U8(I2cDevice dev, u8 reg, u8 val) { struct { u8 reg; u8 val; } __attribute__((packed)) cmd; - + I2cSession _session; Result res = i2cOpenSession(&_session, dev); if (R_FAILED(res)) return res; - + cmd.reg = reg; cmd.val = val; res = i2csessionSendAuto(&_session, &cmd, sizeof(cmd), I2cTransactionOption_All); i2csessionClose(&_session); return res; } - + Result EmcVddqVolt(u32* ptr) { regulator* entry = reinterpret_cast(reinterpret_cast(ptr) - offsetof(regulator, type_2_3.default_uv)); - + constexpr u32 uv_step = 5'000; constexpr u32 uv_min = 250'000; - + auto validator = [entry]() { R_UNLESS(entry->id == 2, ldr::ResultInvalidRegulatorEntry()); R_UNLESS(entry->type == 3, ldr::ResultInvalidRegulatorEntry()); @@ -627,29 +629,29 @@ Result GpuVmax(u32 *ptr) 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) emc_uv = (emc_uv + uv_step - 1) / uv_step * uv_step; // rounding - + PATCH_OFFSET(ptr, emc_uv); - + i2cInitialize(); I2cSet_U8(I2cDevice_Max77812_2, 0x25, (emc_uv - uv_min) / uv_step); i2cExit(); - + R_SUCCEED(); } - + void Patch(uintptr_t mapped_nso, size_t nso_size) { 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 }, @@ -667,7 +669,7 @@ Result GpuVmax(u32 *ptr) { "GPU Vmin", &GpuVmin, 0, nullptr, gpuVmin}, { "GPU Vmax", &GpuVmax, 0, nullptr, gpuVmax}, }; - + for (uintptr_t ptr = mapped_nso; ptr <= mapped_nso + nso_size - sizeof(MarikoMtcTable); ptr += sizeof(u32)) @@ -678,12 +680,12 @@ Result GpuVmax(u32 *ptr) break; } } - + for (auto& entry : patches) { LOGGING("%s Count: %zu", entry.description, entry.patched_count); if (R_FAILED(entry.CheckResult())) CRASH(entry.description); } } - - } \ No newline at end of file + + } diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/ptm/ptm.cpp b/Source/Atmosphere/stratosphere/loader/source/oc/ptm/ptm.cpp index d63c0244..99b626b6 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/ptm/ptm.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/ptm/ptm.cpp @@ -1,8 +1,8 @@ /* + * Copyright (C) Switch-OC-Suite + * * Copyright (c) Souldbminer and Horizon OC Contributors * - * Copyright (c) 2023 hanai3Bi - * * 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. diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/ptm/ptm.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/ptm/ptm.hpp index e1d262b6..d2acbcf1 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/ptm/ptm.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/ptm/ptm.hpp @@ -1,8 +1,8 @@ /* + * Copyright (C) Switch-OC-Suite + * * Copyright (c) Souldbminer and Horizon OC Contributors * - * Copyright (c) 2023 hanai3Bi - * * 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. @@ -44,4 +44,4 @@ constexpr u32 memPtmClamp = 1065'600'000; void Patch(uintptr_t mapped_nso, size_t nso_size); -} \ No newline at end of file +}