rewrite everything
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
/*
|
||||
* Copyright (C) hanai3bi (meha)
|
||||
* Copyright (C) Switch-OC-Suite
|
||||
*
|
||||
* 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.
|
||||
@@ -15,71 +17,159 @@
|
||||
*/
|
||||
|
||||
#include "customize.hpp"
|
||||
|
||||
#define ENABLED 1
|
||||
#define DISABLED 0
|
||||
namespace ams::ldr::oc {
|
||||
|
||||
//volatile EristaMtcTable EristaMtcTablePlaceholder = { .rev = ERISTA_MTC_MAGIC, };
|
||||
//volatile MarikoMtcTable MarikoMtcTablePlaceholder = { .rev = MARIKO_MTC_MAGIC, };
|
||||
|
||||
volatile CustomizeTable C = {
|
||||
// --- u32 fields ---
|
||||
/* DRAM Timing:
|
||||
* AUTO_ADJ_ALL: Auto adjust timings for Mariko LPDDR4X ≤3733 Mbps specs, 8Gb density. (Default)
|
||||
* CUSTOM_ADJ_ALL: Basically same as NO_ADJ_ALL, with core timing adjustments
|
||||
* 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 = AUTO_ADJ_ALL,
|
||||
|
||||
/* Common:
|
||||
* - Boost Clock in kHz:
|
||||
* Default: 1785000
|
||||
* 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 = 1785000,
|
||||
.commonEmcMemVolt = 1175000,
|
||||
/* - 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)
|
||||
* Mariko Default: 1100'000 (It will not work without sys-clk-OC.)
|
||||
* Value should be divided evenly by 12'500.
|
||||
* Not enabled by default.
|
||||
*/
|
||||
.commonEmcMemVolt = 0,
|
||||
|
||||
/* Erista CPU:
|
||||
* - Max Voltage in mV
|
||||
* - CpuVoltL4T: 1235
|
||||
*/
|
||||
.eristaCpuMaxVolt = 1235,
|
||||
|
||||
/* Erista EMC(RAM):
|
||||
* - RAM Clock in kHz
|
||||
* [WARNING]
|
||||
* RAM overclock could be UNSTABLE if timing parameters are not suitable for your DRAM:
|
||||
* - Graphical glitches
|
||||
* - System instabilities
|
||||
* - NAND corruption
|
||||
*/
|
||||
.eristaEmcMaxClock = 1862400,
|
||||
.marikoCpuMaxVolt = 1120,
|
||||
|
||||
/* Mariko CPU:
|
||||
* - Max Voltage in mV:
|
||||
* Default voltage: 1120
|
||||
*/
|
||||
.marikoCpuMaxVolt = 1235,
|
||||
|
||||
/* Mariko EMC(RAM):
|
||||
* - RAM Clock in kHz:
|
||||
* Values should be ≥ 1600000, and divided evenly by 9600.
|
||||
* [WARNING]
|
||||
* RAM overclock could be UNSTABLE if timing parameters are not suitable for your DRAM:
|
||||
* - Graphical glitches
|
||||
* - System instabilities
|
||||
* - NAND corruption
|
||||
*/
|
||||
.marikoEmcMaxClock = 1996800,
|
||||
.marikoEmcVddqVolt = 600000,
|
||||
/* - EMC Vddq (Mariko Only) Voltage in uV
|
||||
* Range: 550'000 to 650'000 uV
|
||||
* Value should be divided evenly by 5'000
|
||||
* Default: 600'000
|
||||
* Not enabled by default.
|
||||
* This will not work without sys-clk-OC.
|
||||
*/
|
||||
.marikoEmcVddqVolt = 0,
|
||||
|
||||
.marikoCpuUV = 0,
|
||||
|
||||
.marikoGpuUV = 0,
|
||||
|
||||
.eristaCpuUV = 0,
|
||||
|
||||
.eristaGpuUV = 1,
|
||||
|
||||
.enableMarikoGpuUnsafeFreqs = DISABLED,
|
||||
|
||||
.enableEristaGpuUnsafeFreqs = DISABLED,
|
||||
|
||||
.enableMarikoCpuUnsafeFreqs = DISABLED,
|
||||
|
||||
.enableEristaCpuUnsafeFreqs = DISABLED,
|
||||
|
||||
.commonGpuVoltOffset = 0,
|
||||
.marikoCpuHighVoltOffset = 0,
|
||||
.marikoCpuHighUV = 0,
|
||||
.cpuMaxFreq = 1785000,
|
||||
.gpuMaxFreq = 921600,
|
||||
.gpuVmax = 800,
|
||||
.gpuVmin = 600,
|
||||
|
||||
.marikoEmcDvbShift = 0,
|
||||
.latency = 0,
|
||||
.BL = 16,
|
||||
.WL = 32,
|
||||
.RL = 14,
|
||||
.tRFCpb = 140,
|
||||
.tRFCab = 280,
|
||||
.tRAS = 42,
|
||||
.tRPpb = 18,
|
||||
.tRPab = 21,
|
||||
.tRC = 60,
|
||||
.tWTR = 10,
|
||||
.tWR = 18,
|
||||
.tRCD = 18,
|
||||
.tREFpb = 488,
|
||||
.tMRWCKEL = 14,
|
||||
.tSR = 15,
|
||||
.tFAW = 40,
|
||||
|
||||
// --- double fields ---
|
||||
.tR2REF = 25.5,
|
||||
.tDQSCK_min = 1.5,
|
||||
.tDQSCK_max = 3.5,
|
||||
.tWPRE = 1.8,
|
||||
.tRPST = 0.4,
|
||||
.tDQSS_max = 1.25,
|
||||
.tDQS2DQ_max = 0.8,
|
||||
.tDQSQ = 0.18,
|
||||
.tRTP = 7.5,
|
||||
.tRRD = 10.0,
|
||||
.tXP = 10.0,
|
||||
.tCMDCKE = 1.75,
|
||||
.tCKELCS = 5.0,
|
||||
.tCSCKEH = 1.75,
|
||||
.tXSR = 287.5,
|
||||
.tCKE = 7.5,
|
||||
.tCKCKEH = 1.75,
|
||||
.ramTimingPresetOne = 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},
|
||||
.ramTimingPresetTwo = 0,
|
||||
|
||||
.ramTimingPresetThree = 0,
|
||||
|
||||
.ramTimingPresetFour = 0,
|
||||
|
||||
.ramTimingPresetFive = 0,
|
||||
|
||||
.ramTimingPresetSix = 0,
|
||||
|
||||
.ramTimingPresetSeven = 0, // Sets the BL of the ram. Change to 2 to get 1866BL and set to 0 to keep the default 1600BL
|
||||
|
||||
// NOTE: These tables should NOT BE USED and are only here as placeholders. Always try and find your own optimal tables.
|
||||
|
||||
.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 */,
|
||||
0 /* 1305 (Disabled by default) */,
|
||||
0 /* 1344 (Disabled by default) */,
|
||||
0 /* 1382 (Disabled by default) */,
|
||||
0 /* 1420 (Disabled by default) */,
|
||||
0 /* 1459 (Disabled by default) */,
|
||||
0 /* 1497 (Disabled by default) */,
|
||||
0 /* 1536 (Disabled by default) */,
|
||||
|
||||
},
|
||||
|
||||
.eristaGpuVoltArray = {
|
||||
750 /* 76 */,
|
||||
750 /* 153 */,
|
||||
750 /* 230 */,
|
||||
750 /* 307 */,
|
||||
775 /* 384 */,
|
||||
800 /* 460 */,
|
||||
825 /* 537 */,
|
||||
850 /* 614 */,
|
||||
875 /* 691 */,
|
||||
900 /* 768 */,
|
||||
950 /* 844 */,
|
||||
975 /* 921 */,
|
||||
0 /* 998 (Disabled by default) */,
|
||||
0 /* 1075 (Disabled by default) */,
|
||||
0 /* 1152 (Disabled by default) */,
|
||||
},
|
||||
|
||||
/* Advanced Settings:
|
||||
* - Erista CPU DVFS Table:
|
||||
@@ -107,20 +197,23 @@ volatile CustomizeTable C = {
|
||||
{ 2091000, { 1235000 }, { 5100873, -279186, 4747 } },
|
||||
{ 2193000, { 1235000 }, { 5100873, -279186, 4747 } },
|
||||
{ 2295000, { 1235000 }, { 5100873, -279186, 4747 } },
|
||||
{ 2397000, { 1235000 }, { 5100873, -279186, 4747 } },
|
||||
{ 2499000, { 1235000 }, { 5100873, -279186, 4747 } },
|
||||
{ 2602000, { 1235000 }, { 5100873, -279186, 4747 } },
|
||||
},
|
||||
|
||||
/* - Mariko CPU DVFS Table:
|
||||
* 2397000 might not work for some SoCs.
|
||||
*/
|
||||
.marikoCpuDvfsTable = {
|
||||
{ 204000, { 721589, -12695, 27 }, { 1120000 } },
|
||||
{ 306000, { 747134, -14195, 27 }, { 1120000 } },
|
||||
{ 408000, { 776324, -15705, 27 }, { 1120000 } },
|
||||
{ 510000, { 809160, -17205, 27 }, { 1120000 } },
|
||||
{ 612000, { 845641, -18715, 27 }, { 1120000 } },
|
||||
{ 714000, { 885768, -20215, 27 }, { 1120000 } },
|
||||
{ 816000, { 929540, -21725, 27 }, { 1120000 } },
|
||||
{ 918000, { 976958, -23225, 27 }, { 1120000 } },
|
||||
{ 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 } },
|
||||
@@ -135,10 +228,205 @@ volatile CustomizeTable C = {
|
||||
{ 2091000, { 1716501, -39395, 27 }, { 1235000 } },
|
||||
{ 2193000, { 1775132, -40505, 27 }, { 1235000 } },
|
||||
{ 2295000, { 1866287, -42005, 27 }, { 1235000 } },
|
||||
{ 2397000, { 1961107, -43506, 27 }, { 1235000 } },
|
||||
//{ 2397000, { 1961107, -43506, 27 }, { 1235000 } },
|
||||
},
|
||||
|
||||
.marikoCpuDvfsTableSLT = {
|
||||
{ 204000, { 732856, -17335, 113 }, {} },
|
||||
{ 306000, { 760024, -18195, 113 }, {} },
|
||||
{ 408000, { 789258, -19055, 113 }, {} },
|
||||
{ 510000, { 789258, -19055, 113 }, {} },
|
||||
{ 612000, { 853926, -20775, 113 }, {} },
|
||||
{ 714000, { 889361, -21625, 113 }, {} },
|
||||
{ 816000, { 926862, -22485, 113 }, {} },
|
||||
{ 918000, { 966431, -23345, 113 }, {} },
|
||||
{ 1020000, { 1008066, -24205, 113 }, { 1120000 } },
|
||||
{ 1122000, { 1051768, -25065, 113 }, { 1120000 } },
|
||||
{ 1224000, { 1097537, -25925, 113 }, { 1120000 } },
|
||||
{ 1326000, { 1145373, -26785, 113 }, { 1120000 } },
|
||||
{ 1428000, { 1195276, -27645, 113 }, { 1120000 } },
|
||||
{ 1581000, { 1274006, -28935, 113 }, { 1120000 } },
|
||||
{ 1683000, { 1329076, -29795, 113 }, { 1120000 } },
|
||||
{ 1785000, { 1386213, -30655, 113 }, { 1120000 } },
|
||||
{ 1887000, { 1445416, -31515, 113 }, { 1120000 } },
|
||||
{ 1963500, { 1490873, -32155, 113 }, { 1120000 } },
|
||||
// Appending table
|
||||
{ 2091000, { 1580725, -33235, 113 }, { 1120000 } },
|
||||
{ 2193000, { 1580725, -33235, 113 }, { 1235000 } },
|
||||
{ 2295000, { 1635431, -34095, 113 }, { 1235000 } },
|
||||
{ 2397000, { 1702903, -34955, 113 }, { 1235000 } },
|
||||
},
|
||||
|
||||
/* - Erista GPU DVFS Table:
|
||||
*/
|
||||
.eristaGpuDvfsTable = {
|
||||
{ 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 } },
|
||||
// { 998400, { }, { 1316991, 8144, -940, 808, -21583, 226 } },
|
||||
// { 1075200, { }, { 1358882, 8144, -940, 808, -21583, 226 } },
|
||||
|
||||
},
|
||||
|
||||
.eristaGpuDvfsTableSLT = {
|
||||
{ 76800, { }, { 772403, 8144, -940, 808, -21583, 226 } },
|
||||
{ 153600, { }, { 814294, 8144, -940, 808, -21583, 226 } },
|
||||
{ 230400, { }, { 856186, 8144, -940, 808, -21583, 226 } },
|
||||
{ 307200, { }, { 898077, 8144, -940, 808, -21583, 226 } },
|
||||
{ 384000, { }, { 939969, 8144, -940, 808, -21583, 226 } },
|
||||
{ 460800, { }, { 981860, 8144, -940, 808, -21583, 226 } },
|
||||
{ 537600, { }, { 1023751, 8144, -940, 808, -21583, 226 } },
|
||||
{ 614400, { }, { 1065643, 8144, -940, 808, -21583, 226 } },
|
||||
{ 691200, { }, { 1107534, 8144, -940, 808, -21583, 226 } },
|
||||
{ 768000, { }, { 1149426, 8144, -940, 808, -21583, 226 } },
|
||||
{ 844800, { }, { 1191317, 8144, -940, 808, -21583, 226 } },
|
||||
{ 921600, { }, { 1233209, 8144, -940, 808, -21583, 226 } },
|
||||
// { 998400, { }, { 1275100, 8144, -940, 808, -21583, 226 } },
|
||||
// { 1075200, { }, { 1316991, 8144, -940, 808, -21583, 226 } },
|
||||
},
|
||||
|
||||
.eristaGpuDvfsTableHigh = {
|
||||
{ 76800, { }, { 730512, 8144, -940, 808, -21583, 226 } },
|
||||
{ 153600, { }, { 772403, 8144, -940, 808, -21583, 226 } },
|
||||
{ 230400, { }, { 814295, 8144, -940, 808, -21583, 226 } },
|
||||
{ 307200, { }, { 856186, 8144, -940, 808, -21583, 226 } },
|
||||
{ 384000, { }, { 898078, 8144, -940, 808, -21583, 226 } },
|
||||
{ 460800, { }, { 939969, 8144, -940, 808, -21583, 226 } },
|
||||
{ 537600, { }, { 981860, 8144, -940, 808, -21583, 226 } },
|
||||
{ 614400, { }, { 1023752, 8144, -940, 808, -21583, 226 } },
|
||||
{ 691200, { }, { 1065643, 8144, -940, 808, -21583, 226 } },
|
||||
{ 768000, { }, { 1107535, 8144, -940, 808, -21583, 226 } },
|
||||
{ 844800, { }, { 1149426, 8144, -940, 808, -21583, 226 } },
|
||||
{ 921600, { }, { 1191318, 8144, -940, 808, -21583, 226 } },
|
||||
// { 998400, { }, { 1233209, 8144, -940, 808, -21583, 226 } },
|
||||
// { 1075200, { }, { 1275100, 8144, -940, 808, -21583, 226 } },
|
||||
},
|
||||
|
||||
/* - Mariko GPU DVFS Table:
|
||||
* 1305600 might not work for some SoCs.
|
||||
*/
|
||||
.marikoGpuDvfsTable = {
|
||||
{ 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 } },
|
||||
// Appending table
|
||||
//{ 1305600, {}, { 1374130, -13725, -859, 0, 4442, 576 } },
|
||||
},
|
||||
|
||||
.marikoGpuDvfsTableSLT = {
|
||||
{ 76800, {}, { 590000, } },
|
||||
{ 153600, {}, { 590000, } },
|
||||
{ 230400, {}, { 590000, } },
|
||||
{ 307200, {}, { 590000, } },
|
||||
{ 384000, {}, { 590000, } },
|
||||
{ 460800, {}, { 795089, -11096, -163, 298, -10421, 162 } },
|
||||
{ 537600, {}, { 795089, -11096, -163, 298, -10421, 162 } },
|
||||
{ 614400, {}, { 820606, -6285, -452, 238, -6182, 81 } },
|
||||
{ 691200, {}, { 846289, -4565, -552, 119, -3958, -2 } },
|
||||
{ 768000, {}, { 888720, -5110, -584, 0, -2849, 39 } },
|
||||
{ 844800, {}, { 936634, -6089, -602, -60, -99, -93 } },
|
||||
{ 921600, {}, { 982562, -7373, -614, -179, 1797, -13 } },
|
||||
{ 998400, {}, { 1090179, -14125, -497, -179, 3518, 9 } },
|
||||
{ 1075200, {}, { 1155798, -13465, -648, 0, 1077, 40 } },
|
||||
{ 1152000, {}, { 1198568, -10904, -830, 0, 1469, 110 } },
|
||||
{ 1228800, {}, { 1269988, -12707, -859, 0, 3722, 313 } },
|
||||
{ 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 } },
|
||||
{ 1228800, {}, { 1248293, -16383, -859, 0, 3722, 313 } },
|
||||
{ 1267200, {}, { 1286399, -17475, -867, 0, 3681, 559 } },
|
||||
},
|
||||
|
||||
//.eristaMtcTable = const_cast<EristaMtcTable *>(&EristaMtcTablePlaceholder),
|
||||
//.marikoMtcTable = const_cast<MarikoMtcTable *>(&MarikoMtcTablePlaceholder),
|
||||
|
||||
// UV3 tables
|
||||
|
||||
.eristaGpuDvfsTableUv3UnsafeFreqs = {
|
||||
{ 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 } },
|
||||
{ 998400, { }, { 1316991, 8144, -940, 808, -21583, 226 } }, // UNSAFE
|
||||
{ 1075200, { }, { 1358882, 8144, -940, 808, -21583, 226 } }, // UNSAFE
|
||||
{ 1152000, { }, { 1400773, 8144, -940, 808, -21583, 226 } }, // DANGEROUS
|
||||
},
|
||||
|
||||
.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 } },
|
||||
{ 1228800, {}, { 1248293, -16383, -859, 0, 3722, 313 } },
|
||||
{ 1267200, {}, { 1286399, -17475, -867, 0, 3681, 559 } },
|
||||
{ 1305600, {}, { 1286399, -17475, -867, 0, 3681, 559 } },
|
||||
{ 1305600, {}, { 1324505, -17475, -867, 0, 3681, 559 } },
|
||||
{ 1344000, {}, { 1362611, -17475, -867, 0, 3681, 559 } },
|
||||
{ 1382400, {}, { 1400717, -17475, -867, 0, 3681, 559 } },
|
||||
{ 1420800, {}, { 1438823, -17475, -867, 0, 3681, 559 } },
|
||||
{ 1459200, {}, { 1476929, -17475, -867, 0, 3681, 559 } },
|
||||
{ 1497600, {}, { 1515035, -17475, -867, 0, 3681, 559 } },
|
||||
{ 1536000, {}, { 1553141, -17475, -867, 0, 3681, 559 } },
|
||||
},
|
||||
|
||||
.marikoCpuDvfsTableUnsafeFreqs = {
|
||||
{ 204000, { 732856, -17335, 113 }, { 1120000 } },
|
||||
{ 306000, { 760024, -18195, 113 }, { 1120000 } },
|
||||
{ 408000, { 789258, -19055, 113 }, { 1120000 } },
|
||||
@@ -170,128 +458,6 @@ volatile CustomizeTable C = {
|
||||
|
||||
},
|
||||
|
||||
/* - Erista GPU DVFS Table:
|
||||
*/
|
||||
.eristaGpuDvfsTable = {
|
||||
{ 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 } },
|
||||
{ 998400, { }, { 1316991, 8144, -940, 808, -21583, 226 } },
|
||||
},
|
||||
|
||||
/* - Mariko GPU DVFS Table:
|
||||
* 1305600 might not work for some SoCs.
|
||||
*/
|
||||
.marikoGpuDvfsTable = {
|
||||
{ 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 } },
|
||||
// Appending table
|
||||
{ 1305600, {}, { 1304130, -13725, -859, 0, 4442, 576 } },
|
||||
},
|
||||
|
||||
.marikoGpuDvfsTableSLT = {
|
||||
{ 76800, {}, { 635000, } },
|
||||
{ 153600, {}, { 635000, } },
|
||||
{ 230400, {}, { 635000, } },
|
||||
{ 307200, {}, { 635000, } },
|
||||
{ 384000, {}, { 635000, } },
|
||||
{ 460800, {}, { 635000, } },
|
||||
{ 537600, {}, { 635000, } },
|
||||
{ 614400, {}, { 635000, } },
|
||||
{ 691200, {}, { 635000, } },
|
||||
{ 768000, {}, { 635000, } },
|
||||
{ 844800, {}, { 635000, } },
|
||||
{ 921600, {}, { 635000, } },
|
||||
{ 998400, {}, { 901575, -4409, -584, 0, -2849, 39 } },
|
||||
{ 1075200, {}, { 940071, -5367, -602, -60, -63, -93 } },
|
||||
{ 1152000, {}, { 996765, -6637, -614, -179, 1905, -13 } },
|
||||
{ 1228800, {}, { 1098475, -13529, -497, -179, 3626, 9 } },
|
||||
{ 1267200, {}, { 1131060, -13109, -573, -90, 2352, 25 } },
|
||||
{ 1305600, {}, { 1163644, -12688, -648, 0, 1077, 40 } },
|
||||
},
|
||||
.marikoGpuDvfsTableHiOPT = {
|
||||
{ 76800, {}, { 550000, } },
|
||||
{ 153600, {}, { 550000, } },
|
||||
{ 230400, {}, { 550000, } },
|
||||
{ 307200, {}, { 550000, } },
|
||||
{ 384000, {}, { 550000, } },
|
||||
{ 460800, {}, { 550000, } },
|
||||
{ 537600, {}, { 550000, } },
|
||||
{ 614400, {}, { 550000, } },
|
||||
{ 691200, {}, { 550000, } },
|
||||
{ 768000, {}, { 801688, -10900, -163, 298, -10599, 162 } },
|
||||
{ 844800, {}, { 824214, -5743, -452, 238, -6325, 81 } },
|
||||
{ 921600, {}, { 848830, -3903, -552, 119, -4030, -2 } },
|
||||
{ 998400, {}, { 901575, -4409, -584, 0, -2849, 39 } },
|
||||
{ 1075200, {}, { 940071, -5367, -602, -60, -63, -93 } },
|
||||
{ 1152000, {}, { 996765, -6637, -614, -179, 1905, -13 } },
|
||||
{ 1228800, {}, { 1098475, -13529, -497, -179, 3626, 9 } },
|
||||
{ 1267200, {}, { 1131060, -13109, -573, -90, 2352, 25 } },
|
||||
{ 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<EristaMtcTable *>(&EristaMtcTablePlaceholder),
|
||||
//.marikoMtcTable = const_cast<MarikoMtcTable *>(&MarikoMtcTablePlaceholder),
|
||||
.eristaCPUvMax = 1300,
|
||||
|
||||
.marikoCPUvMax = 1235,
|
||||
|
||||
.MemVltMax = 1350000,
|
||||
|
||||
.marikoVDDQMax = 650000,
|
||||
|
||||
.marikoB3 = 179,
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
/*
|
||||
* Copyright (C) hanai3bi (meha)
|
||||
* Copyright (C) Switch-OC-Suite
|
||||
*
|
||||
* 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.
|
||||
@@ -16,7 +18,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#define CUST_REV 2
|
||||
#define CUST_REV 11
|
||||
|
||||
#include "oc_common.hpp"
|
||||
#include "pcv/pcv_common.hpp"
|
||||
@@ -43,90 +45,58 @@ constexpr uint32_t MARIKO_MTC_MAGIC = 0x43544D4D; // MMTC
|
||||
|
||||
typedef struct CustomizeTable {
|
||||
u8 cust[4] = {'C', 'U', 'S', 'T'};
|
||||
u32 custRev;
|
||||
u32 custRev = CUST_REV;
|
||||
u32 mtcConf;
|
||||
u32 commonCpuBoostClock;
|
||||
u32 commonEmcMemVolt;
|
||||
|
||||
// Erista CPU/EMC
|
||||
u32 eristaCpuMaxVolt;
|
||||
u32 eristaEmcMaxClock;
|
||||
|
||||
// Mariko CPU/EMC
|
||||
u32 marikoCpuMaxVolt;
|
||||
u32 marikoEmcMaxClock;
|
||||
u32 marikoEmcVddqVolt;
|
||||
u32 marikoCpuUV;
|
||||
u32 marikoGpuUV;
|
||||
|
||||
u32 eristaCpuUV;
|
||||
u32 eristaGpuUV;
|
||||
|
||||
u32 enableMarikoGpuUnsafeFreqs;
|
||||
u32 enableEristaGpuUnsafeFreqs;
|
||||
|
||||
u32 enableMarikoCpuUnsafeFreqs;
|
||||
u32 enableEristaCpuUnsafeFreqs;
|
||||
|
||||
u32 commonGpuVoltOffset;
|
||||
u32 marikoCpuHighVoltOffset;
|
||||
u32 marikoCpuHighUV;
|
||||
|
||||
u32 cpuMaxFreq;
|
||||
u32 gpuMaxFreq;
|
||||
u32 gpuVmax;
|
||||
u32 gpuVmin;
|
||||
|
||||
// advanced config
|
||||
u32 marikoEmcDvbShift;
|
||||
u32 ramTimingPresetOne;
|
||||
u32 ramTimingPresetTwo;
|
||||
u32 ramTimingPresetThree;
|
||||
u32 ramTimingPresetFour;
|
||||
u32 ramTimingPresetFive;
|
||||
u32 ramTimingPresetSix;
|
||||
u32 ramTimingPresetSeven;
|
||||
//
|
||||
u32 marikoGpuVoltArray[23];
|
||||
u32 eristaGpuVoltArray[15];
|
||||
|
||||
// RAM timings (u32)
|
||||
u32 latency;
|
||||
u32 BL;
|
||||
u32 WL;
|
||||
u32 RL;
|
||||
u32 tRFCpb;
|
||||
u32 tRFCab;
|
||||
u32 tRAS;
|
||||
u32 tRPpb;
|
||||
u32 tRPab;
|
||||
u32 tRC;
|
||||
u32 tWTR;
|
||||
u32 tWR;
|
||||
u32 tRCD;
|
||||
u32 tREFpb;
|
||||
u32 tMRWCKEL;
|
||||
u32 tSR;
|
||||
u32 tFAW;
|
||||
|
||||
// RAM timings (double)
|
||||
double tR2REF;
|
||||
double tDQSCK_min;
|
||||
double tDQSCK_max;
|
||||
double tWPRE;
|
||||
double tRPST;
|
||||
double tDQSS_max;
|
||||
double tDQS2DQ_max;
|
||||
double tDQSQ;
|
||||
double tRTP;
|
||||
double tRRD;
|
||||
double tXP;
|
||||
double tCMDCKE;
|
||||
double tCKELCS;
|
||||
double tCSCKEH;
|
||||
double tXSR;
|
||||
double tCKE;
|
||||
double tCKCKEH;
|
||||
|
||||
// Mariko GPU voltages
|
||||
u32 marikoGpuVoltArray[24];
|
||||
|
||||
|
||||
CustomizeCpuDvfsTable eristaCpuDvfsTable;
|
||||
CustomizeCpuDvfsTable marikoCpuDvfsTable;
|
||||
CustomizeCpuDvfsTable marikoCpuDvfsTableSLT;
|
||||
|
||||
CustomizeGpuDvfsTable eristaGpuDvfsTable;
|
||||
CustomizeGpuDvfsTable eristaGpuDvfsTableSLT;
|
||||
CustomizeGpuDvfsTable eristaGpuDvfsTableHigh;
|
||||
|
||||
|
||||
CustomizeGpuDvfsTable marikoGpuDvfsTable;
|
||||
CustomizeGpuDvfsTable marikoGpuDvfsTableSLT;
|
||||
CustomizeGpuDvfsTable marikoGpuDvfsTableHiOPT;
|
||||
CustomizeGpuDvfsTable marikoGpuDvfsTableUv3;
|
||||
//EristaMtcTable* eristaMtcTable;
|
||||
//MarikoMtcTable* marikoMtcTable;
|
||||
u32 eristaCPUvMax;
|
||||
u32 marikoCPUvMax;
|
||||
u32 MemVltMax;
|
||||
u32 marikoVDDQMax;
|
||||
u8 marikoB3;
|
||||
|
||||
CustomizeGpuDvfsTable eristaGpuDvfsTableUv3UnsafeFreqs;
|
||||
CustomizeGpuDvfsTable marikoGpuDvfsTableUv3UnsafeFreqs;
|
||||
CustomizeCpuDvfsTable marikoCpuDvfsTableUnsafeFreqs;
|
||||
} CustomizeTable;
|
||||
//static_assert(sizeof(CustomizeTable) == sizeof(u8) * 4 + sizeof(u32) * 10 + sizeof(CustomizeCpuDvfsTable) * 5 + sizeof(void*) * 2);
|
||||
//static_assert(sizeof(CustomizeTable) == 7000);
|
||||
@@ -136,4 +106,4 @@ extern volatile CustomizeTable C;
|
||||
//extern volatile EristaMtcTable EristaMtcTablePlaceholder;
|
||||
//extern volatile MarikoMtcTable MarikoMtcTablePlaceholder;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -16,84 +16,220 @@
|
||||
* from GCC preprocessor output
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#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)
|
||||
namespace pcv::erista {
|
||||
// tCK_avg (average clock period) in ns
|
||||
const double tCK_avg = 1000'000. / C.eristaEmcMaxClock;
|
||||
#include "oc_common.hpp"
|
||||
|
||||
// minimum number of cycles from any read command to any write command, irrespective of bank
|
||||
const u32 R2W = CEIL (C.RL + CEIL(C.tDQSCK_max/tCK_avg) + C.BL/2 - C.WL + C.tWPRE + FLOOR(C.tRPST)) + 6;
|
||||
|
||||
// Delay Time From WRITE-to-READ
|
||||
const u32 W2R = C.WL + C.BL/2 + 1 + CEIL(C.tWTR/tCK_avg) - 6;
|
||||
|
||||
// write-to-precharge time for commands to the same bank in cycles
|
||||
const u32 WTP = C.WL + C.BL/2 + 1 + CEIL(C.tWR/tCK_avg) - 8;
|
||||
|
||||
// #_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%]
|
||||
// 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(C.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(C.tDQSS_max/tCK_avg) + CEIL(C.tDQS2DQ_max/tCK_avg) + 6;
|
||||
|
||||
// Additional time after t XP hasexpired until the MRR commandmay be issued
|
||||
const double tMRRI = C.tRCD + 3 * tCK_avg;
|
||||
|
||||
// tPDEX2MRR (timing delay from exiting powerdown mode to MRR command) in ns
|
||||
const double tPDEX2MRR = C.tXP + tMRRI;
|
||||
}
|
||||
namespace pcv::mariko {
|
||||
// tCK_avg (average clock period) in ns
|
||||
const double tCK_avg = 1000'000. / C.marikoEmcMaxClock;
|
||||
// minimum number of cycles from any read command to any write command, irrespective of bank
|
||||
const u32 R2W = CEIL (C.RL + CEIL(C.tDQSCK_max/tCK_avg) + C.BL/2 - C.WL + C.tWPRE + FLOOR(C.tRPST));
|
||||
|
||||
// Delay Time From WRITE-to-READ
|
||||
const u32 W2R = C.WL + C.BL/2 + 1 + CEIL(C.tWTR/tCK_avg);
|
||||
|
||||
// write-to-precharge time for commands to the same bank in cycles
|
||||
const u32 WTP = C.WL + C.BL/2 + 1 + CEIL(C.tWR/tCK_avg);
|
||||
|
||||
// Read-To-MRW delay
|
||||
const u32 RTM = C.RL + C.BL/2 + CEIL(C.tDQSCK_max/tCK_avg) + FLOOR(C.tRPST) + CEIL(7.5/tCK_avg);
|
||||
|
||||
// Write-To-MRW/MRR delay
|
||||
const u32 WTM = C.WL + 1 + C.BL/2 + CEIL(7.5/tCK_avg);
|
||||
|
||||
// Read With AP-To-MRW/MRR delay
|
||||
const u32 RATM = RTM + CEIL(C.tRTP/tCK_avg) - 8;
|
||||
|
||||
// Write With AP-To-MRW/MRR delay
|
||||
const u32 WATM = WTM + CEIL(C.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%]
|
||||
// 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(C.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(C.tDQSS_max/tCK_avg) + CEIL(C.tDQS2DQ_max/tCK_avg) + 6;
|
||||
|
||||
// Additional time after t XP hasexpired until the MRR commandmay be issued
|
||||
const double tMRRI = C.tRCD + 3 * tCK_avg;
|
||||
|
||||
// tPDEX2MRR (timing delay from exiting powerdown mode to MRR command) in ns
|
||||
const double tPDEX2MRR = C.tXP + tMRRI;
|
||||
}
|
||||
}
|
||||
|
||||
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<u32, 6> tRCD_values = {18, 17, 16, 15, 14, 13};
|
||||
const std::array<u32, 6> tRP_values = {18, 17, 16, 15, 14, 13};
|
||||
const std::array<u32, 6> tRAS_values = {42, 39, 36, 34, 32, 30};
|
||||
|
||||
// Preset Two
|
||||
const std::array<double, 5> tRRD_values = {10, 7.5, 6, 4, 3};
|
||||
const std::array<double, 5> tFAW_values = {40, 30, 24, 16, 12};
|
||||
|
||||
// Preset Three
|
||||
const std::array<u32, 6> tWR_values = {18, 15, 15, 12, 12, 8};
|
||||
const std::array<double, 6> tRTP_values = {7.5, 7.5, 6, 6, 4, 4};
|
||||
|
||||
// Preset Four
|
||||
const std::array<u32, 6> tRFC_values = {140, 120, 100, 80, 70, 60};
|
||||
|
||||
// Preset Five
|
||||
const std::array<u32, 6> tWTR_values = {10, 8, 6, 4, 2, 1};
|
||||
|
||||
// Preset Six
|
||||
const std::array<u32, 5> tREFpb_values = {488, 976, 1952, 3256, 9999};
|
||||
|
||||
const u32 TIMING_PRESET_ONE = C.ramTimingPresetOne;
|
||||
const u32 TIMING_PRESET_TWO = C.ramTimingPresetTwo;
|
||||
const u32 TIMING_PRESET_THREE = C.ramTimingPresetThree;
|
||||
const u32 TIMING_PRESET_FOUR = C.ramTimingPresetFour;
|
||||
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 = !TIMING_PRESET_FOUR ? 140 : tRFC_values[TIMING_PRESET_FOUR-1];
|
||||
|
||||
// tRFCab (refresh cycle time all banks) in ns for 8Gb density
|
||||
const u32 tRFCab = !TIMING_PRESET_FOUR ? 280 : 2*tRFCpb;
|
||||
|
||||
// tRAS (row active time) in ns
|
||||
const u32 tRAS = !TIMING_PRESET_ONE ? 42 : tRAS_values[TIMING_PRESET_ONE-1];
|
||||
|
||||
// tRPpb (row precharge time per bank) in ns
|
||||
const u32 tRPpb = !TIMING_PRESET_ONE ? 18 : tRP_values[TIMING_PRESET_ONE-1];
|
||||
|
||||
// tRPab (row precharge time all banks) in ns
|
||||
const u32 tRPab = !TIMING_PRESET_ONE ? 21 : tRPpb + 3;
|
||||
|
||||
// tRC (ACTIVATE-ACTIVATE command period same bank) in ns
|
||||
const u32 tRC = tRPpb + tRAS;
|
||||
|
||||
// DQS output access time from CK_t/CK_c
|
||||
const double tDQSCK_min = 1.5;
|
||||
// DQS output access time from CK_t/CK_c
|
||||
const double tDQSCK_max = 3.5;
|
||||
// Write preamble (tCK)
|
||||
const double tWPRE = 1.8;
|
||||
// Read postamble (tCK)
|
||||
const double tRPST = 0.4;
|
||||
// WRITE command to first DQS transition(max) (tCK)
|
||||
const double tDQSS_max = 1.25;
|
||||
// DQ-to-DQS offset(max) (ns)
|
||||
const double tDQS2DQ_max = 0.8;
|
||||
// DQS_t, DQS_c to DQ skew total, per group, per access (DBI Disabled)
|
||||
const double tDQSQ = 0.18;
|
||||
|
||||
// Write-to-Read delay
|
||||
const u32 tWTR = !TIMING_PRESET_FIVE ? 10 : tWTR_values[TIMING_PRESET_FIVE-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 = !TIMING_PRESET_ONE ? 18 : tRCD_values[TIMING_PRESET_ONE-1];
|
||||
|
||||
// tRRD (Active bank-A to Active bank-B) in ns
|
||||
const double tRRD = !TIMING_PRESET_TWO ? 10. : tRRD_values[TIMING_PRESET_TWO-1];
|
||||
|
||||
// tREFpb (average refresh interval per bank) in ns for 8Gb density
|
||||
const u32 tREFpb = !TIMING_PRESET_SIX ? 488 : tREFpb_values[TIMING_PRESET_SIX-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;
|
||||
|
||||
// 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;
|
||||
|
||||
// Valid CS requirement after CKE input LOW
|
||||
const double tCKELCS = 5;
|
||||
|
||||
// Valid CS requirement before CKE input HIGH
|
||||
const double tCSCKEH = 1.75;
|
||||
|
||||
// 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;
|
||||
|
||||
// Minimum self refresh time (entry to exit)
|
||||
const u32 tSR = 15;
|
||||
|
||||
// tFAW (Four-bank Activate Window) in ns
|
||||
const u32 tFAW = !TIMING_PRESET_TWO ? 40 : tFAW_values[TIMING_PRESET_TWO-1];
|
||||
|
||||
// Valid Clock requirement before CKE Input HIGH in ns
|
||||
const double tCKCKEH = 1.75;
|
||||
|
||||
// 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 + TIMING_PRESET_SEVEN;
|
||||
// Read Latency
|
||||
const u32 RL = 32 + TIMING_PRESET_SEVEN;
|
||||
|
||||
// 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;
|
||||
|
||||
// Delay Time From WRITE-to-READ
|
||||
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;
|
||||
// {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;
|
||||
|
||||
// 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;
|
||||
}
|
||||
namespace pcv::mariko {
|
||||
// tCK_avg (average clock period) in ns
|
||||
const double tCK_avg = 1000'000. / C.marikoEmcMaxClock;
|
||||
// Write Latency
|
||||
const u32 WL = 14 + TIMING_PRESET_SEVEN;
|
||||
// Read Latency
|
||||
const u32 RL = 32 + TIMING_PRESET_SEVEN;
|
||||
|
||||
// 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));
|
||||
|
||||
// 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%]
|
||||
// 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.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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/*
|
||||
* Copyright (C) hanai3bi (meha)
|
||||
* Copyright (C) Switch-OC-Suite
|
||||
*
|
||||
* 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.
|
||||
@@ -93,9 +95,34 @@ void SafetyCheck() {
|
||||
|
||||
u32 eristaCpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaCpuDvfsTable)->freq);
|
||||
u32 marikoCpuDvfsMaxFreq = static_cast<u32>(C.marikoCpuUV ? GetDvfsTableLastEntry(C.marikoCpuDvfsTableSLT)->freq : GetDvfsTableLastEntry(C.marikoCpuDvfsTable)->freq);
|
||||
u32 eristaGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaGpuDvfsTable)->freq);
|
||||
u32 eristaGpuDvfsMaxFreq;
|
||||
switch (C.eristaGpuUV)
|
||||
{
|
||||
case 0:
|
||||
eristaGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaGpuDvfsTable)->freq);
|
||||
break;
|
||||
case 1:
|
||||
eristaGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaGpuDvfsTableSLT)->freq);
|
||||
break;
|
||||
case 2:
|
||||
eristaGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaGpuDvfsTableHigh)->freq);
|
||||
break;
|
||||
case 3:
|
||||
if(C.enableEristaGpuUnsafeFreqs)
|
||||
{
|
||||
eristaGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaGpuDvfsTableUv3UnsafeFreqs)->freq);
|
||||
}
|
||||
else
|
||||
{
|
||||
eristaGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaGpuDvfsTable)->freq);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
eristaGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaGpuDvfsTable)->freq);
|
||||
break;
|
||||
}
|
||||
|
||||
u32 marikoGpuDvfsMaxFreq;
|
||||
u32 temporaryMaxFreqForCalculation = C.gpuMaxFreq;
|
||||
switch (C.marikoGpuUV) {
|
||||
case 0:
|
||||
marikoGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.marikoGpuDvfsTable)->freq);
|
||||
@@ -106,27 +133,23 @@ void SafetyCheck() {
|
||||
case 2:
|
||||
marikoGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.marikoGpuDvfsTableHiOPT)->freq);
|
||||
break;
|
||||
case 3:
|
||||
marikoGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.marikoGpuDvfsTableUv3)->freq);
|
||||
temporaryMaxFreqForCalculation = 1536'000;
|
||||
break;
|
||||
default:
|
||||
marikoGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.marikoGpuDvfsTable)->freq);
|
||||
break;
|
||||
}
|
||||
|
||||
sValidator validators[] = {
|
||||
{ C.commonCpuBoostClock, 1020'000, C.cpuMaxFreq + 1, true },
|
||||
{ C.commonEmcMemVolt, 1000'000, C.MemVltMax + 1 },
|
||||
{ C.eristaCpuMaxVolt, 1100, C.eristaCPUvMax + 1 },
|
||||
{ C.eristaEmcMaxClock, 1600'000, 2428'800 },
|
||||
{ C.marikoCpuMaxVolt, 800, C.marikoCPUvMax + 1 },
|
||||
{ C.marikoEmcMaxClock, 1600'000, 3504'000 },
|
||||
{ C.marikoEmcVddqVolt, 550'000, C.marikoVDDQMax + 1 },
|
||||
{ eristaCpuDvfsMaxFreq, 1785'000, C.cpuMaxFreq + 1 },
|
||||
{ marikoCpuDvfsMaxFreq, 1785'000, C.cpuMaxFreq + 1 },
|
||||
{ eristaGpuDvfsMaxFreq, 76'800, C.gpuMaxFreq + 1 },
|
||||
{ marikoGpuDvfsMaxFreq, 76'800, temporaryMaxFreqForCalculation + 1 },
|
||||
{ C.commonCpuBoostClock, 1020'000, 3000'000, true },
|
||||
{ C.commonEmcMemVolt, 1100'000, 1500'000 }, // Official burst vmax for the RAMs
|
||||
{ C.eristaCpuMaxVolt, 1100, 1300 },
|
||||
{ C.eristaEmcMaxClock, 1600'000, 2600'200 },
|
||||
{ C.marikoCpuMaxVolt, 1100, 1300 },
|
||||
{ C.marikoEmcMaxClock, 1600'000, 3500'000 },
|
||||
{ C.marikoEmcVddqVolt, 550'000, 650'000 },
|
||||
{ eristaCpuDvfsMaxFreq, 1785'000, 3000'000 },
|
||||
{ marikoCpuDvfsMaxFreq, 1785'000, 3000'000 },
|
||||
{ eristaGpuDvfsMaxFreq, 768'000, 1536'000 },
|
||||
{ marikoGpuDvfsMaxFreq, 768'000, 1536'000 },
|
||||
};
|
||||
|
||||
for (auto& i : validators) {
|
||||
@@ -146,4 +169,4 @@ void Patch(uintptr_t mapped_nso, size_t nso_size) {
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
* Copyright (C) Switch-OC-Suite
|
||||
*
|
||||
* 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.
|
||||
@@ -21,234 +21,302 @@
|
||||
#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 <shift>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 <shift>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 <shift>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<bool isMariko>
|
||||
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<cvb_entry_t *>(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<cvb_entry_t *>(ptr) + 1;
|
||||
void* cpu_cvb_table_head = reinterpret_cast<u8 *>(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<void *>(customize_table), customize_table_size);
|
||||
|
||||
// Patch CPU max volt
|
||||
if (cpu_max_volt) {
|
||||
cvb_entry_t* entry = static_cast<cvb_entry_t *>(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<bool isMariko>
|
||||
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 <shift>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 <bool isMariko>
|
||||
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<cvb_entry_t *>(
|
||||
isMariko
|
||||
? (C.enableMarikoCpuUnsafeFreqs
|
||||
? C.marikoCpuDvfsTableUnsafeFreqs
|
||||
: (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 >= 1300 ? 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<cvb_entry_t *>(ptr) + 1;
|
||||
void *cpu_cvb_table_head = reinterpret_cast<u8 *>(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<void *>(customize_table), customize_table_size);
|
||||
|
||||
// Patch CPU max volt
|
||||
if (cpu_max_volt)
|
||||
{
|
||||
cvb_entry_t *entry = static_cast<cvb_entry_t *>(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 <bool isMariko>
|
||||
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<cvb_entry_t *>(C.marikoGpuDvfsTable);
|
||||
break;
|
||||
case 1:
|
||||
@@ -257,84 +325,133 @@ Result GpuFreqCvbTable(u32* ptr) {
|
||||
case 2:
|
||||
customize_table = const_cast<cvb_entry_t *>(C.marikoGpuDvfsTableHiOPT);
|
||||
break;
|
||||
case 3:
|
||||
if(C.enableMarikoGpuUnsafeFreqs)
|
||||
{
|
||||
customize_table = const_cast<cvb_entry_t *>(C.marikoGpuDvfsTableUv3UnsafeFreqs);
|
||||
}
|
||||
else
|
||||
{
|
||||
customize_table = const_cast<cvb_entry_t *>(C.marikoGpuDvfsTable);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
customize_table = const_cast<cvb_entry_t *>(C.marikoGpuDvfsTable);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
customize_table = const_cast<cvb_entry_t *>(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<cvb_entry_t *>(ptr) + 1;
|
||||
void* gpu_cvb_table_head = reinterpret_cast<u8 *>(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<cvb_entry_t *>(gpu_cvb_table_head);
|
||||
for (size_t i = 0; i < customize_entry_count; i++) {
|
||||
u32 patched_voltage = C.marikoGpuVoltArray[i];
|
||||
if (C.marikoGpuVoltArray[i] < C.gpuVmin)
|
||||
else
|
||||
{
|
||||
switch (C.eristaGpuUV)
|
||||
{
|
||||
patched_voltage = C.gpuVmin;
|
||||
case 0:
|
||||
customize_table = const_cast<cvb_entry_t *>(C.eristaGpuDvfsTable);
|
||||
break;
|
||||
case 1:
|
||||
customize_table = const_cast<cvb_entry_t *>(C.eristaGpuDvfsTableSLT);
|
||||
break;
|
||||
case 2:
|
||||
customize_table = const_cast<cvb_entry_t *>(C.eristaGpuDvfsTableHigh);
|
||||
break;
|
||||
case 3:
|
||||
if(C.enableEristaGpuUnsafeFreqs)
|
||||
{
|
||||
customize_table = const_cast<cvb_entry_t *>(C.eristaGpuDvfsTableUv3UnsafeFreqs);
|
||||
}
|
||||
else
|
||||
{
|
||||
customize_table = const_cast<cvb_entry_t *>(C.eristaGpuDvfsTable);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
customize_table = const_cast<cvb_entry_t *>(C.eristaGpuDvfsTable);
|
||||
break;
|
||||
}
|
||||
if(C.marikoGpuVoltArray[i] > C.gpuVmax) {
|
||||
patched_voltage = C.gpuVmax;
|
||||
}
|
||||
|
||||
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<cvb_entry_t *>(ptr) + 1;
|
||||
void *gpu_cvb_table_head = reinterpret_cast<u8 *>(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 (C.marikoGpuUV == 3 || C.eristaGpuUV == 1)
|
||||
{
|
||||
cvb_entry_t *entry = static_cast<cvb_entry_t *>(gpu_cvb_table_head);
|
||||
for (size_t i = 0; i < customize_entry_count; i++)
|
||||
{
|
||||
if (isMariko)
|
||||
{
|
||||
if (C.marikoGpuVoltArray[i] == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
PATCH_OFFSET(&(entry->cvb_pll_param.c0), C.marikoGpuVoltArray[i] * 1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (C.eristaGpuVoltArray[i] == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
PATCH_OFFSET(&(entry->cvb_pll_param.c0), C.eristaGpuVoltArray[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++;
|
||||
}
|
||||
|
||||
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++;
|
||||
}
|
||||
}
|
||||
else if (C.commonGpuVoltOffset) {
|
||||
cvb_entry_t* entry = static_cast<cvb_entry_t *>(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++;
|
||||
else if (C.commonGpuVoltOffset)
|
||||
{
|
||||
cvb_entry_t *entry = static_cast<cvb_entry_t *>(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();
|
||||
};
|
||||
|
||||
Result MemFreqPllmLimit(u32* ptr);
|
||||
Result MemVoltHandler(u32* ptr); // Used for Erista MEM Vdd2 + EMC Vddq or Mariko MEM Vdd2
|
||||
Result MemFreqPllmLimit(u32 *ptr);
|
||||
Result MemVoltHandler(u32 *ptr); // Used for Erista MEM Vdd2 + EMC Vddq or Mariko MEM Vdd2
|
||||
|
||||
template<typename T>
|
||||
Result MemMtcCustomizeTable(T* dst, T* src) {
|
||||
constexpr u32 mtc_magic = std::is_same_v<T, MarikoMtcTable> ? MARIKO_MTC_MAGIC : ERISTA_MTC_MAGIC;
|
||||
R_UNLESS(src->rev == mtc_magic, ldr::ResultInvalidMtcMagic());
|
||||
template <typename T>
|
||||
Result MemMtcCustomizeTable(T *dst, T *src)
|
||||
{
|
||||
constexpr u32 mtc_magic = std::is_same_v<T, MarikoMtcTable> ? 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<u32 *>(reinterpret_cast<size_t>(src) + offset);
|
||||
u32* dst_ent = reinterpret_cast<u32 *>(reinterpret_cast<size_t>(dst) + offset);
|
||||
u32 src_val = *src_ent;
|
||||
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<u32 *>(reinterpret_cast<size_t>(src) + offset);
|
||||
u32 *dst_ent = reinterpret_cast<u32 *>(reinterpret_cast<size_t>(dst) + offset);
|
||||
u32 src_val = *src_ent;
|
||||
|
||||
if (src_val) {
|
||||
PATCH_OFFSET(dst_ent, src_val == ZERO_VAL ? 0 : src_val);
|
||||
if (src_val)
|
||||
{
|
||||
PATCH_OFFSET(dst_ent, src_val == ZERO_VAL ? 0 : src_val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
};
|
||||
R_SUCCEED();
|
||||
};
|
||||
|
||||
void SafetyCheck();
|
||||
void Patch(uintptr_t mapped_nso, size_t nso_size);
|
||||
void SafetyCheck();
|
||||
void Patch(uintptr_t mapped_nso, size_t nso_size);
|
||||
|
||||
}
|
||||
|
||||
@@ -14,153 +14,153 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
namespace ams::ldr::oc::pcv {
|
||||
|
||||
typedef struct cvb_coefficients {
|
||||
s32 c0 = 0;
|
||||
s32 c1 = 0;
|
||||
s32 c2 = 0;
|
||||
s32 c3 = 0;
|
||||
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;
|
||||
u32 tune1_low;
|
||||
u32 tune1_high;
|
||||
unsigned int tune_high_min_millivolts;
|
||||
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;
|
||||
u8 divm_shift;
|
||||
u8 divm_width;
|
||||
u8 divp_shift;
|
||||
u8 divp_width;
|
||||
u8 override_divn_shift;
|
||||
u8 override_divm_shift;
|
||||
u8 override_divp_shift;
|
||||
} div_nmp;
|
||||
|
||||
typedef struct __attribute__((packed)) clk_pll_param {
|
||||
u32 freq;
|
||||
u32 input_min;
|
||||
u32 input_max;
|
||||
u32 cf_min;
|
||||
u32 cf_max;
|
||||
u32 vco_min;
|
||||
u32 vco_max;
|
||||
s32 lock_delay;
|
||||
u32 fixed_rate;
|
||||
u32 unk_0;
|
||||
struct div_nmp *div_nmp;
|
||||
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];
|
||||
u32 freq;
|
||||
u32 unk_1[8];
|
||||
u32 unk_flag;
|
||||
u32 min_mv;
|
||||
u32 step_mv;
|
||||
u32 max_mv;
|
||||
u32 unk_2[11];
|
||||
} dvfs_rail;
|
||||
|
||||
typedef struct __attribute__((packed)) regulator {
|
||||
u64 id;
|
||||
const char* name;
|
||||
u32 type;
|
||||
union {
|
||||
struct {
|
||||
u32 volt_reg;
|
||||
u32 step_uv;
|
||||
u32 min_uv;
|
||||
u32 default_uv;
|
||||
u32 max_uv;
|
||||
u32 unk_0[2];
|
||||
} type_1;
|
||||
struct {
|
||||
u32 unk_0;
|
||||
u32 step_uv;
|
||||
u32 unk_1;
|
||||
u32 min_uv;
|
||||
u32 max_uv;
|
||||
u32 unk_2;
|
||||
u32 default_uv;
|
||||
} type_2_3;
|
||||
};
|
||||
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<typename T>
|
||||
size_t GetDvfsTableEntryCount(T* table_head) {
|
||||
using NT = std::remove_const_t<std::remove_volatile_t<T>>;
|
||||
|
||||
auto is_empty = [](NT* entry) {
|
||||
uint8_t* m = reinterpret_cast<uint8_t *>(entry);
|
||||
for (size_t i = 0; i < sizeof(NT); i++) {
|
||||
if (*(m + i))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
NT* table = const_cast<NT *>(table_head);
|
||||
size_t count = 0;
|
||||
while (count < DvfsTableEntryLimit) {
|
||||
if (is_empty(table++)) {
|
||||
return count;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
return DvfsTableEntryLimit;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* GetDvfsTableLastEntry(T* table_head) {
|
||||
using NT = std::remove_const_t<std::remove_volatile_t<T>>;
|
||||
|
||||
NT* table = const_cast<NT *>(table_head);
|
||||
size_t count = GetDvfsTableEntryCount(table_head);
|
||||
if (!count) {
|
||||
return nullptr;
|
||||
}
|
||||
size_t index = count - 1;
|
||||
return table + index;
|
||||
}
|
||||
|
||||
}
|
||||
namespace ams::ldr::oc::pcv {
|
||||
|
||||
typedef struct cvb_coefficients {
|
||||
s32 c0 = 0;
|
||||
s32 c1 = 0;
|
||||
s32 c2 = 0;
|
||||
s32 c3 = 0;
|
||||
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;
|
||||
u32 tune1_low;
|
||||
u32 tune1_high;
|
||||
unsigned int tune_high_min_millivolts;
|
||||
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;
|
||||
u8 divm_shift;
|
||||
u8 divm_width;
|
||||
u8 divp_shift;
|
||||
u8 divp_width;
|
||||
u8 override_divn_shift;
|
||||
u8 override_divm_shift;
|
||||
u8 override_divp_shift;
|
||||
} div_nmp;
|
||||
|
||||
typedef struct __attribute__((packed)) clk_pll_param {
|
||||
u32 freq;
|
||||
u32 input_min;
|
||||
u32 input_max;
|
||||
u32 cf_min;
|
||||
u32 cf_max;
|
||||
u32 vco_min;
|
||||
u32 vco_max;
|
||||
s32 lock_delay;
|
||||
u32 fixed_rate;
|
||||
u32 unk_0;
|
||||
struct div_nmp *div_nmp;
|
||||
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];
|
||||
u32 freq;
|
||||
u32 unk_1[8];
|
||||
u32 unk_flag;
|
||||
u32 min_mv;
|
||||
u32 step_mv;
|
||||
u32 max_mv;
|
||||
u32 unk_2[11];
|
||||
} dvfs_rail;
|
||||
|
||||
typedef struct __attribute__((packed)) regulator {
|
||||
u64 id;
|
||||
const char* name;
|
||||
u32 type;
|
||||
union {
|
||||
struct {
|
||||
u32 volt_reg;
|
||||
u32 step_uv;
|
||||
u32 min_uv;
|
||||
u32 default_uv;
|
||||
u32 max_uv;
|
||||
u32 unk_0[2];
|
||||
} type_1;
|
||||
struct {
|
||||
u32 unk_0;
|
||||
u32 step_uv;
|
||||
u32 unk_1;
|
||||
u32 min_uv;
|
||||
u32 max_uv;
|
||||
u32 unk_2;
|
||||
u32 default_uv;
|
||||
} type_2_3;
|
||||
};
|
||||
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<typename T>
|
||||
size_t GetDvfsTableEntryCount(T* table_head) {
|
||||
using NT = std::remove_const_t<std::remove_volatile_t<T>>;
|
||||
|
||||
auto is_empty = [](NT* entry) {
|
||||
uint8_t* m = reinterpret_cast<uint8_t *>(entry);
|
||||
for (size_t i = 0; i < sizeof(NT); i++) {
|
||||
if (*(m + i))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
NT* table = const_cast<NT *>(table_head);
|
||||
size_t count = 0;
|
||||
while (count < DvfsTableEntryLimit) {
|
||||
if (is_empty(table++)) {
|
||||
return count;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
return DvfsTableEntryLimit;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* GetDvfsTableLastEntry(T* table_head) {
|
||||
using NT = std::remove_const_t<std::remove_volatile_t<T>>;
|
||||
|
||||
NT* table = const_cast<NT *>(table_head);
|
||||
size_t count = GetDvfsTableEntryCount(table_head);
|
||||
if (!count) {
|
||||
return nullptr;
|
||||
}
|
||||
size_t index = count - 1;
|
||||
return table + index;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
* Copyright (C) Switch-OC-Suite
|
||||
*
|
||||
* 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.
|
||||
@@ -18,233 +18,328 @@
|
||||
|
||||
#include "pcv.hpp"
|
||||
#include "../mtc_timing_value.hpp"
|
||||
#include "../customize.hpp"
|
||||
namespace ams::ldr::oc::pcv::erista {
|
||||
|
||||
Result CpuVoltRange(u32* ptr) {
|
||||
u32 min_volt_got = *(ptr - 1);
|
||||
for (const auto& mv : CpuMinVolts) {
|
||||
if (min_volt_got != mv)
|
||||
continue;
|
||||
namespace ams::ldr::oc::pcv::erista
|
||||
{
|
||||
|
||||
if (!C.eristaCpuMaxVolt)
|
||||
R_SKIP();
|
||||
Result CpuVoltRange(u32 *ptr)
|
||||
{
|
||||
u32 min_volt_got = *(ptr - 1);
|
||||
for (const auto &mv : CpuMinVolts)
|
||||
{
|
||||
if (min_volt_got != mv)
|
||||
continue;
|
||||
|
||||
if (!C.eristaCpuMaxVolt)
|
||||
R_SKIP();
|
||||
|
||||
PATCH_OFFSET(ptr, C.eristaCpuMaxVolt);
|
||||
R_SUCCEED();
|
||||
}
|
||||
R_THROW(ldr::ResultInvalidCpuMinVolt());
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
case 0:
|
||||
max_clock = GetDvfsTableLastEntry(C.eristaGpuDvfsTable)->freq;
|
||||
break;
|
||||
case 1:
|
||||
max_clock = GetDvfsTableLastEntry(C.eristaGpuDvfsTableSLT)->freq;
|
||||
break;
|
||||
case 2:
|
||||
max_clock = GetDvfsTableLastEntry(C.eristaGpuDvfsTableHigh)->freq;
|
||||
break;
|
||||
case 3:
|
||||
if(C.enableEristaGpuUnsafeFreqs)
|
||||
{
|
||||
max_clock = GetDvfsTableLastEntry(C.eristaGpuDvfsTableUv3UnsafeFreqs)->freq;
|
||||
}
|
||||
else
|
||||
{
|
||||
max_clock = GetDvfsTableLastEntry(C.eristaGpuDvfsTable)->freq;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
max_clock = GetDvfsTableLastEntry(C.eristaGpuDvfsTable)->freq;
|
||||
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)};
|
||||
PATCH_OFFSET(ptr32, asm_patch[0]);
|
||||
PATCH_OFFSET(ptr32 + 1, asm_patch[1]);
|
||||
|
||||
PATCH_OFFSET(ptr, C.eristaCpuMaxVolt);
|
||||
R_SUCCEED();
|
||||
}
|
||||
R_THROW(ldr::ResultInvalidCpuMinVolt());
|
||||
}
|
||||
|
||||
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 = GetDvfsTableLastEntry(C.eristaGpuDvfsTable)->freq;
|
||||
|
||||
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)
|
||||
};
|
||||
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<clk_pll_param *>(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(EristaMtcTable* table) {
|
||||
if (C.mtcConf != AUTO_ADJ_ALL)
|
||||
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(C.tRC));
|
||||
WRITE_PARAM_ALL_REG(table, emc_rfc, GET_CYCLE_CEIL(C.tRFCab));
|
||||
WRITE_PARAM_ALL_REG(table, emc_rfcpb, GET_CYCLE_CEIL(C.tRFCpb));
|
||||
WRITE_PARAM_ALL_REG(table, emc_ras, GET_CYCLE_CEIL(C.tRAS));
|
||||
WRITE_PARAM_ALL_REG(table, emc_rp, GET_CYCLE_CEIL(C.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(C.tRTP));
|
||||
WRITE_PARAM_ALL_REG(table, emc_w2p, WTP);
|
||||
WRITE_PARAM_ALL_REG(table, emc_rd_rcd, GET_CYCLE_CEIL(C.tRCD));
|
||||
WRITE_PARAM_ALL_REG(table, emc_wr_rcd, GET_CYCLE_CEIL(C.tRCD));
|
||||
WRITE_PARAM_ALL_REG(table, emc_rrd, GET_CYCLE_CEIL(C.tRRD));
|
||||
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_pdex2wr, GET_CYCLE_CEIL(C.tXP));
|
||||
WRITE_PARAM_ALL_REG(table, emc_pdex2rd, GET_CYCLE_CEIL(C.tXP));
|
||||
WRITE_PARAM_ALL_REG(table, emc_pchg2pden, GET_CYCLE_CEIL(C.tCMDCKE));
|
||||
WRITE_PARAM_ALL_REG(table, emc_act2pden, GET_CYCLE_CEIL(C.tMRWCKEL));
|
||||
WRITE_PARAM_ALL_REG(table, emc_ar2pden, GET_CYCLE_CEIL(C.tCMDCKE));
|
||||
WRITE_PARAM_ALL_REG(table, emc_rw2pden, WTPDEN);
|
||||
WRITE_PARAM_ALL_REG(table, emc_cke2pden, GET_CYCLE_CEIL(C.tCKELCS));
|
||||
WRITE_PARAM_ALL_REG(table, emc_pdex2cke, GET_CYCLE_CEIL(C.tCSCKEH));
|
||||
WRITE_PARAM_ALL_REG(table, emc_pdex2mrr, GET_CYCLE_CEIL(tPDEX2MRR));
|
||||
WRITE_PARAM_ALL_REG(table, emc_txsr, MIN(GET_CYCLE_CEIL(C.tXSR), (u32)0x3fe));
|
||||
WRITE_PARAM_ALL_REG(table, emc_txsrdll, MIN(GET_CYCLE_CEIL(C.tXSR), (u32)0x3fe));
|
||||
WRITE_PARAM_ALL_REG(table, emc_tcke, GET_CYCLE_CEIL(C.tCKE));
|
||||
WRITE_PARAM_ALL_REG(table, emc_tckesr, GET_CYCLE_CEIL(C.tSR));
|
||||
WRITE_PARAM_ALL_REG(table, emc_tpd, GET_CYCLE_CEIL(C.tCKE));
|
||||
WRITE_PARAM_ALL_REG(table, emc_tfaw, GET_CYCLE_CEIL(C.tFAW));
|
||||
WRITE_PARAM_ALL_REG(table, emc_trpab, GET_CYCLE_CEIL(C.tRPab));
|
||||
WRITE_PARAM_ALL_REG(table, emc_tclkstable, GET_CYCLE_CEIL(C.tCKCKEH));
|
||||
WRITE_PARAM_ALL_REG(table, emc_tclkstop, GET_CYCLE_CEIL(C.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(C.tRCD) / MC_ARB_DIV) - 2;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_rp = CEIL(GET_CYCLE_CEIL(C.tRPpb) / MC_ARB_DIV) - 1 + MC_ARB_SFA;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_rc = CEIL(GET_CYCLE_CEIL(C.tRC) / MC_ARB_DIV) - 1;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_ras = CEIL(GET_CYCLE_CEIL(C.tRAS) / MC_ARB_DIV) - 2;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_faw = CEIL(GET_CYCLE_CEIL(C.tFAW) / MC_ARB_DIV) - 1;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_rrd = CEIL(GET_CYCLE_CEIL(C.tRRD) / MC_ARB_DIV) - 1;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_rap2pre = CEIL(GET_CYCLE_CEIL(C.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_rfcpb = CEIL(GET_CYCLE_CEIL(C.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(C.tRC));
|
||||
WRITE_PARAM_ALL_REG(table, emc_ras, GET_CYCLE_CEIL(C.tRAS));
|
||||
WRITE_PARAM_ALL_REG(table, emc_rp, GET_CYCLE_CEIL(C.tRPpb));
|
||||
WRITE_PARAM_ALL_REG(table, emc_trpab, GET_CYCLE_CEIL(C.tRPab));
|
||||
WRITE_PARAM_ALL_REG(table, emc_rd_rcd, GET_CYCLE_CEIL(C.tRCD));
|
||||
WRITE_PARAM_ALL_REG(table, emc_wr_rcd, GET_CYCLE_CEIL(C.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(C.tRCD) / MC_ARB_DIV - 2);
|
||||
table->burst_mc_regs.mc_emem_arb_timing_rc = CEIL(GET_CYCLE_CEIL(C.tRC) / MC_ARB_DIV - 1);
|
||||
table->burst_mc_regs.mc_emem_arb_timing_rp = CEIL(GET_CYCLE_CEIL(C.tRPpb) / MC_ARB_DIV - 1 + MC_ARB_SFA);
|
||||
table->burst_mc_regs.mc_emem_arb_timing_ras = CEIL(GET_CYCLE_CEIL(C.tRAS) / MC_ARB_DIV - 2);
|
||||
|
||||
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) {
|
||||
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++) {
|
||||
u8* table = reinterpret_cast<u8 *>(ptr) - offsetof(EristaMtcTable, rate_khz) - i * sizeof(EristaMtcTable);
|
||||
table_list[i] = reinterpret_cast<EristaMtcTable *>(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<void *>(table_list[i]), static_cast<void *>(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<EristaMtcTable *>(C.eristaMtcTable));
|
||||
//}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
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) {
|
||||
u32 CpuCvbDefaultMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(CpuCvbTableDefault)->freq);
|
||||
u32 GpuCvbDefaultMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(GpuCvbTableDefault)->freq);
|
||||
|
||||
PatcherEntry<u32> patches[] = {
|
||||
{ "CPU Freq Table", CpuFreqCvbTable<false>, 1, nullptr, CpuCvbDefaultMaxFreq },
|
||||
{ "CPU Volt Limit", &CpuVoltRange, 0, &CpuMaxVoltPatternFn },
|
||||
{ "GPU Freq Table", GpuFreqCvbTable<false>, 1, nullptr, GpuCvbDefaultMaxFreq },
|
||||
{ "GPU Freq Asm", &GpuFreqMaxAsm, 2, &GpuMaxClockPatternFn },
|
||||
{ "GPU Freq PLL", &GpuFreqPllLimit, 1, nullptr, GpuClkPllLimit },
|
||||
{ "MEM Freq Mtc", &MemFreqMtcTable, 0, nullptr, EmcClkOSLimit },
|
||||
{ "MEM Freq Max", &MemFreqMax, 0, nullptr, EmcClkOSLimit },
|
||||
{ "MEM Freq PLLM", &MemFreqPllmLimit, 2, nullptr, EmcClkPllmLimit },
|
||||
{ "MEM Volt", &MemVoltHandler, 2, nullptr, MemVoltHOS },
|
||||
};
|
||||
|
||||
for (uintptr_t ptr = mapped_nso;
|
||||
ptr <= mapped_nso + nso_size - sizeof(EristaMtcTable);
|
||||
ptr += sizeof(u32))
|
||||
Result GpuFreqPllLimit(u32 *ptr)
|
||||
{
|
||||
u32* ptr32 = reinterpret_cast<u32 *>(ptr);
|
||||
for (auto& entry : patches) {
|
||||
if (R_SUCCEEDED(entry.SearchAndApply(ptr32)))
|
||||
break;
|
||||
clk_pll_param *entry = reinterpret_cast<clk_pll_param *>(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(EristaMtcTable *table)
|
||||
{
|
||||
if (C.mtcConf != AUTO_ADJ_ALL)
|
||||
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));
|
||||
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_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;
|
||||
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_rc = CEIL(GET_CYCLE_CEIL(tRC) / MC_ARB_DIV) - 1;
|
||||
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_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_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;
|
||||
|
||||
if (TIMING_PRESET_ONE)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
if (TIMING_PRESET_TWO)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
if (TIMING_PRESET_THREE)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
if (TIMING_PRESET_FOUR)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
if (TIMING_PRESET_FIVE)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
if (TIMING_PRESET_SIX)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
if (TIMING_PRESET_SEVEN)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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++)
|
||||
{
|
||||
u8 *table = reinterpret_cast<u8 *>(ptr) - offsetof(EristaMtcTable, rate_khz) - i * sizeof(EristaMtcTable);
|
||||
table_list[i] = reinterpret_cast<EristaMtcTable *>(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<void *>(table_list[i]), static_cast<void *>(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<EristaMtcTable *>(C.eristaMtcTable));
|
||||
//}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
u32 CpuCvbDefaultMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(CpuCvbTableDefault)->freq);
|
||||
u32 GpuCvbDefaultMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(GpuCvbTableDefault)->freq);
|
||||
|
||||
PatcherEntry<u32> patches[] = {
|
||||
{"CPU Freq Table", CpuFreqCvbTable<false>, 1, nullptr, CpuCvbDefaultMaxFreq},
|
||||
{"CPU Volt Limit", &CpuVoltRange, 0, &CpuMaxVoltPatternFn},
|
||||
{"GPU Freq Table", GpuFreqCvbTable<false>, 1, nullptr, GpuCvbDefaultMaxFreq},
|
||||
{"GPU Freq Asm", &GpuFreqMaxAsm, 2, &GpuMaxClockPatternFn},
|
||||
{"GPU Freq PLL", &GpuFreqPllLimit, 1, nullptr, GpuClkPllLimit},
|
||||
{"MEM Freq Mtc", &MemFreqMtcTable, 0, nullptr, EmcClkOSLimit},
|
||||
{"MEM Freq Max", &MemFreqMax, 0, nullptr, EmcClkOSLimit},
|
||||
{"MEM Freq PLLM", &MemFreqPllmLimit, 2, nullptr, EmcClkPllmLimit},
|
||||
{"MEM Volt", &MemVoltHandler, 2, nullptr, MemVoltHOS},
|
||||
};
|
||||
|
||||
for (uintptr_t ptr = mapped_nso;
|
||||
ptr <= mapped_nso + nso_size - sizeof(EristaMtcTable);
|
||||
ptr += sizeof(u32))
|
||||
{
|
||||
u32 *ptr32 = reinterpret_cast<u32 *>(ptr);
|
||||
for (auto &entry : patches)
|
||||
{
|
||||
if (R_SUCCEEDED(entry.SearchAndApply(ptr32)))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &entry : patches)
|
||||
{
|
||||
LOGGING("%s Count: %zu", entry.description, entry.patched_count);
|
||||
if (R_FAILED(entry.CheckResult()))
|
||||
CRASH(entry.description);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& entry : patches) {
|
||||
LOGGING("%s Count: %zu", entry.description, entry.patched_count);
|
||||
if (R_FAILED(entry.CheckResult()))
|
||||
CRASH(entry.description);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -18,7 +18,6 @@
|
||||
|
||||
#include "pcv.hpp"
|
||||
#include "../mtc_timing_value.hpp"
|
||||
#include "../customize.hpp"
|
||||
|
||||
namespace ams::ldr::oc::pcv::mariko {
|
||||
|
||||
@@ -31,7 +30,11 @@ Result CpuFreqVdd(u32* ptr) {
|
||||
R_UNLESS(entry->max_mv == 1525'000, ldr::ResultInvalidCpuFreqVddEntry());
|
||||
|
||||
if (C.marikoCpuUV) {
|
||||
PATCH_OFFSET(ptr, GetDvfsTableLastEntry(C.marikoCpuDvfsTableSLT)->freq);
|
||||
if(!C.enableMarikoCpuUnsafeFreqs) {
|
||||
PATCH_OFFSET(ptr, GetDvfsTableLastEntry(C.marikoCpuDvfsTableSLT)->freq);
|
||||
} else {
|
||||
PATCH_OFFSET(ptr, GetDvfsTableLastEntry(C.marikoCpuDvfsTableUnsafeFreqs)->freq);
|
||||
}
|
||||
} else {
|
||||
PATCH_OFFSET(ptr, GetDvfsTableLastEntry(C.marikoCpuDvfsTable)->freq);
|
||||
}
|
||||
@@ -108,6 +111,16 @@ Result GpuFreqMaxAsm(u32* ptr32) {
|
||||
case 2:
|
||||
max_clock = GetDvfsTableLastEntry(C.marikoGpuDvfsTableHiOPT)->freq;
|
||||
break;
|
||||
case 3:
|
||||
if(C.enableMarikoGpuUnsafeFreqs)
|
||||
{
|
||||
max_clock = GetDvfsTableLastEntry(C.marikoGpuDvfsTableUv3UnsafeFreqs)->freq;
|
||||
}
|
||||
else
|
||||
{
|
||||
max_clock = GetDvfsTableLastEntry(C.marikoGpuDvfsTable)->freq;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
max_clock = GetDvfsTableLastEntry(C.marikoGpuDvfsTable)->freq;
|
||||
break;
|
||||
@@ -183,44 +196,44 @@ void MemMtcTableAutoAdjust(MarikoMtcTable* table, const MarikoMtcTable* ref) {
|
||||
|
||||
#define GET_CYCLE_CEIL(PARAM) u32(CEIL(double(PARAM) / tCK_avg))
|
||||
|
||||
WRITE_PARAM_ALL_REG(table, emc_rc, GET_CYCLE_CEIL(C.tRC));
|
||||
WRITE_PARAM_ALL_REG(table, emc_rfc, GET_CYCLE_CEIL(C.tRFCab));
|
||||
WRITE_PARAM_ALL_REG(table, emc_rfcpb, GET_CYCLE_CEIL(C.tRFCpb));
|
||||
WRITE_PARAM_ALL_REG(table, emc_ras, GET_CYCLE_CEIL(C.tRAS));
|
||||
WRITE_PARAM_ALL_REG(table, emc_rp, GET_CYCLE_CEIL(C.tRPpb));
|
||||
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(C.tRTP));
|
||||
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_trtm, RTM);
|
||||
WRITE_PARAM_ALL_REG(table, emc_twtm, WTM);
|
||||
WRITE_PARAM_ALL_REG(table, emc_tratm, RATM);
|
||||
WRITE_PARAM_ALL_REG(table, emc_twatm, WATM);
|
||||
//WRITE_PARAM_ALL_REG(table, emc_tr2ref, GET_CYCLE_CEIL(C.tR2REF));
|
||||
WRITE_PARAM_ALL_REG(table, emc_rd_rcd, GET_CYCLE_CEIL(C.tRCD));
|
||||
WRITE_PARAM_ALL_REG(table, emc_wr_rcd, GET_CYCLE_CEIL(C.tRCD));
|
||||
WRITE_PARAM_ALL_REG(table, emc_rrd, GET_CYCLE_CEIL(C.tRRD));
|
||||
//WRITE_PARAM_ALL_REG(table, emc_tr2ref, GET_CYCLE_CEIL(tR2REF));
|
||||
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));
|
||||
WRITE_PARAM_ALL_REG(table, emc_rext, 26);
|
||||
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_pdex2wr, GET_CYCLE_CEIL(C.tXP));
|
||||
WRITE_PARAM_ALL_REG(table, emc_pdex2rd, GET_CYCLE_CEIL(C.tXP));
|
||||
WRITE_PARAM_ALL_REG(table, emc_pchg2pden, GET_CYCLE_CEIL(C.tCMDCKE));
|
||||
WRITE_PARAM_ALL_REG(table, emc_act2pden, GET_CYCLE_CEIL(C.tMRWCKEL));
|
||||
WRITE_PARAM_ALL_REG(table, emc_ar2pden, GET_CYCLE_CEIL(C.tCMDCKE));
|
||||
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(C.tCKELCS));
|
||||
//WRITE_PARAM_ALL_REG(table, emc_pdex2cke, GET_CYCLE_CEIL(C.tCSCKEH));
|
||||
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(C.tXSR), (u32)0x3fe));
|
||||
WRITE_PARAM_ALL_REG(table, emc_txsrdll, MIN(GET_CYCLE_CEIL(C.tXSR), (u32)0x3fe));
|
||||
WRITE_PARAM_ALL_REG(table, emc_tcke, GET_CYCLE_CEIL(C.tCKE) + 1);
|
||||
WRITE_PARAM_ALL_REG(table, emc_tckesr, GET_CYCLE_CEIL(C.tSR));
|
||||
WRITE_PARAM_ALL_REG(table, emc_tpd, GET_CYCLE_CEIL(C.tCKE));
|
||||
WRITE_PARAM_ALL_REG(table, emc_tfaw, GET_CYCLE_CEIL(C.tFAW));
|
||||
WRITE_PARAM_ALL_REG(table, emc_trpab, GET_CYCLE_CEIL(C.tRPab));
|
||||
//WRITE_PARAM_ALL_REG(table, emc_tclkstable, GET_CYCLE_CEIL(C.tCKCKEH));
|
||||
WRITE_PARAM_ALL_REG(table, emc_tclkstop, GET_CYCLE_CEIL(C.tCKE) + 8);
|
||||
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) + 1);
|
||||
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);
|
||||
|
||||
ADJUST_PARAM_ALL_REG(table, emc_dyn_self_ref_control, ref);
|
||||
@@ -239,18 +252,18 @@ void MemMtcTableAutoAdjust(MarikoMtcTable* table, const MarikoMtcTable* ref) {
|
||||
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(C.tRCD) / MC_ARB_DIV) - 2)
|
||||
WRITE_PARAM_BURST_MC_REG(table, mc_emem_arb_timing_rp, CEIL(GET_CYCLE_CEIL(C.tRPpb) / MC_ARB_DIV) - 1 + MC_ARB_SFA)
|
||||
WRITE_PARAM_BURST_MC_REG(table, mc_emem_arb_timing_rc, CEIL(GET_CYCLE_CEIL(C.tRC) / MC_ARB_DIV) - 1)
|
||||
WRITE_PARAM_BURST_MC_REG(table, mc_emem_arb_timing_ras, CEIL(GET_CYCLE_CEIL(C.tRAS) / MC_ARB_DIV) - 2)
|
||||
WRITE_PARAM_BURST_MC_REG(table, mc_emem_arb_timing_faw, CEIL(GET_CYCLE_CEIL(C.tFAW) / MC_ARB_DIV) - 1)
|
||||
WRITE_PARAM_BURST_MC_REG(table, mc_emem_arb_timing_rrd, CEIL(GET_CYCLE_CEIL(C.tRRD) / MC_ARB_DIV) - 1)
|
||||
WRITE_PARAM_BURST_MC_REG(table, mc_emem_arb_timing_rap2pre, CEIL(GET_CYCLE_CEIL(C.tRTP) / MC_ARB_DIV))
|
||||
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)
|
||||
WRITE_PARAM_BURST_MC_REG(table, mc_emem_arb_timing_rc, CEIL(GET_CYCLE_CEIL(tRC) / MC_ARB_DIV) - 1)
|
||||
WRITE_PARAM_BURST_MC_REG(table, mc_emem_arb_timing_ras, CEIL(GET_CYCLE_CEIL(tRAS) / MC_ARB_DIV) - 2)
|
||||
WRITE_PARAM_BURST_MC_REG(table, mc_emem_arb_timing_faw, CEIL(GET_CYCLE_CEIL(tFAW) / MC_ARB_DIV) - 1)
|
||||
WRITE_PARAM_BURST_MC_REG(table, mc_emem_arb_timing_rrd, CEIL(GET_CYCLE_CEIL(tRRD) / MC_ARB_DIV) - 1)
|
||||
WRITE_PARAM_BURST_MC_REG(table, mc_emem_arb_timing_rap2pre, CEIL(GET_CYCLE_CEIL(tRTP) / MC_ARB_DIV))
|
||||
WRITE_PARAM_BURST_MC_REG(table, mc_emem_arb_timing_wap2pre, CEIL((WTP) / MC_ARB_DIV))
|
||||
WRITE_PARAM_BURST_MC_REG(table, mc_emem_arb_timing_r2r, CEIL(table->burst_regs.emc_rext / MC_ARB_DIV) - 1 + MC_ARB_SFA)
|
||||
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(C.tRFCpb) / MC_ARB_DIV))
|
||||
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
|
||||
@@ -319,8 +332,8 @@ void MemMtcTableAutoAdjust(MarikoMtcTable* table, const MarikoMtcTable* ref) {
|
||||
table->pllmb_ss_ctrl1 = 0x0b55fe01;
|
||||
table->pllmb_ss_ctrl2 = 0x10170b55;
|
||||
|
||||
table->dram_timings.t_rp = C.tRPpb;
|
||||
table->dram_timings.t_rfc = C.tRFCab;
|
||||
table->dram_timings.t_rp = tRPpb;
|
||||
table->dram_timings.t_rfc = tRFCab;
|
||||
//table->dram_timings.rl = 32;
|
||||
|
||||
table->emc_cfg_2 = 0x0011083d;
|
||||
@@ -333,18 +346,76 @@ void MemMtcTableCustomAdjust(MarikoMtcTable* table) {
|
||||
constexpr u32 MC_ARB_DIV = 4;
|
||||
constexpr u32 MC_ARB_SFA = 2;
|
||||
|
||||
WRITE_PARAM_ALL_REG(table, emc_rc, GET_CYCLE_CEIL(C.tRC));
|
||||
WRITE_PARAM_ALL_REG(table, emc_ras, GET_CYCLE_CEIL(C.tRAS));
|
||||
WRITE_PARAM_ALL_REG(table, emc_rp, GET_CYCLE_CEIL(C.tRPpb));
|
||||
WRITE_PARAM_ALL_REG(table, emc_trpab, GET_CYCLE_CEIL(C.tRPab));
|
||||
WRITE_PARAM_ALL_REG(table, emc_rd_rcd, GET_CYCLE_CEIL(C.tRCD));
|
||||
WRITE_PARAM_ALL_REG(table, emc_wr_rcd, GET_CYCLE_CEIL(C.tRCD));
|
||||
WRITE_PARAM_ALL_REG(table, emc_pdex2mrr,GET_CYCLE_CEIL(tPDEX2MRR));
|
||||
if (TIMING_PRESET_ONE) {
|
||||
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(C.tRCD) / MC_ARB_DIV) - 2;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_rc = CEIL(GET_CYCLE_CEIL(C.tRC) / MC_ARB_DIV) - 1;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_rp = CEIL(GET_CYCLE_CEIL(C.tRPpb) / MC_ARB_DIV) - 1 + MC_ARB_SFA;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_ras = CEIL(GET_CYCLE_CEIL(C.tRAS) / MC_ARB_DIV) - 2;
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
if (TIMING_PRESET_TWO) {
|
||||
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;
|
||||
}
|
||||
|
||||
if (TIMING_PRESET_THREE) {
|
||||
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);
|
||||
}
|
||||
|
||||
if (TIMING_PRESET_FOUR) {
|
||||
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);
|
||||
}
|
||||
|
||||
if (TIMING_PRESET_FIVE) {
|
||||
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;
|
||||
}
|
||||
|
||||
if (TIMING_PRESET_SIX) {
|
||||
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);
|
||||
}
|
||||
|
||||
if (TIMING_PRESET_SEVEN) {
|
||||
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_trtm, RTM);
|
||||
WRITE_PARAM_ALL_REG(table, emc_twtm, WTM);
|
||||
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
|
||||
|
||||
74
Source/Atmosphere/stratosphere/loader/source/patch.py
Normal file
74
Source/Atmosphere/stratosphere/loader/source/patch.py
Normal file
@@ -0,0 +1,74 @@
|
||||
#!python3
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
def file_replace_str(file_path, search_replace_list):
|
||||
assert file_path
|
||||
assert search_replace_list
|
||||
with open(file_path, "r") as f:
|
||||
content = f.read()
|
||||
|
||||
for entry in search_replace_list:
|
||||
(search, replace) = entry
|
||||
if search in content:
|
||||
content = content.replace(search, replace)
|
||||
else:
|
||||
assert replace in content, f"Pattern \"{search}\" not found"
|
||||
|
||||
with open(file_path, "w") as f:
|
||||
f.write(content)
|
||||
|
||||
|
||||
dir_path = os.path.dirname(__file__)
|
||||
|
||||
os.chdir(dir_path)
|
||||
os.system("git reset --hard")
|
||||
|
||||
ldr_process_creation = os.path.join(dir_path, "ldr_process_creation.cpp")
|
||||
file_replace_str(ldr_process_creation,
|
||||
[("""#include "ldr_ro_manager.hpp"
|
||||
|
||||
namespace ams::ldr {""",
|
||||
"""#include "ldr_ro_manager.hpp"
|
||||
#include "oc/oc_loader.hpp"
|
||||
|
||||
namespace ams::ldr {"""),
|
||||
(""" NsoHeader g_nso_headers[Nso_Count];
|
||||
|
||||
Result ValidateProgramVersion(ncm::ProgramId program_id, u32 version) {""",
|
||||
""" NsoHeader g_nso_headers[Nso_Count];
|
||||
|
||||
/* Pcv/Ptm check cache. */
|
||||
bool g_is_pcv;
|
||||
bool g_is_ptm;
|
||||
|
||||
Result ValidateProgramVersion(ncm::ProgramId program_id, u32 version) {"""),
|
||||
(""" R_UNLESS(meta->aci->program_id <= meta->acid->program_id_max, ldr::ResultInvalidProgramId());
|
||||
|
||||
/* Validate the kernel capabilities. */""",
|
||||
""" R_UNLESS(meta->aci->program_id <= meta->acid->program_id_max, ldr::ResultInvalidProgramId());
|
||||
|
||||
/* Check if nca is pcv or ptm */
|
||||
g_is_pcv = meta->aci->program_id == ncm::SystemProgramId::Pcv;
|
||||
g_is_ptm = meta->aci->program_id == ncm::SystemProgramId::Ptm;
|
||||
|
||||
/* Validate the kernel capabilities. */"""),
|
||||
(""" LocateAndApplyIpsPatchesToModule(nso_header->module_id, map_address, nso_size);
|
||||
}""",
|
||||
""" LocateAndApplyIpsPatchesToModule(nso_header->module_id, map_address, nso_size);
|
||||
|
||||
/* Apply pcv and ptm patches. */
|
||||
if (g_is_pcv)
|
||||
oc::pcv::Patch(map_address, nso_size);
|
||||
if (g_is_ptm)
|
||||
oc::ptm::Patch(map_address, nso_size);
|
||||
}""")])
|
||||
|
||||
ldr_meta = os.path.join(dir_path, "ldr_meta.cpp")
|
||||
file_replace_str(ldr_meta,
|
||||
[(""" Result ValidateAcidSignature(Meta *meta) {
|
||||
/* Loader did not check signatures prior to 10.0.0. */""",
|
||||
""" Result ValidateAcidSignature(Meta *meta) {
|
||||
R_SUCCEED();
|
||||
/* Loader did not check signatures prior to 10.0.0. */""")])
|
||||
Reference in New Issue
Block a user