Compare commits
82 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e4c9ac6ee3 | ||
|
|
5d6500523b | ||
|
|
b111ccabb5 | ||
|
|
b90a67aa43 | ||
|
|
9ed72839f4 | ||
|
|
b8f50da45f | ||
|
|
1e4dada672 | ||
|
|
a943d14807 | ||
|
|
2cf437ff34 | ||
|
|
7cbccbbb5b | ||
|
|
f79af5b6f7 | ||
|
|
05af1d04ff | ||
|
|
2753646f06 | ||
|
|
2b3889c897 | ||
|
|
e01e346dea | ||
|
|
7735037ad9 | ||
|
|
b2bcd5fc3a | ||
|
|
a40ea357db | ||
|
|
7434c22772 | ||
|
|
f0eb25b88c | ||
|
|
7ec9827db5 | ||
|
|
eeca31c92e | ||
|
|
2cd736035c | ||
|
|
bc99616e43 | ||
|
|
732f27fcf6 | ||
|
|
54e8465e47 | ||
|
|
7ceb02c001 | ||
|
|
2450a348f1 | ||
|
|
7bd469939e | ||
|
|
89180359c0 | ||
|
|
4259ace5c4 | ||
|
|
d7e5c38a62 | ||
|
|
b601105998 | ||
|
|
ca07d0716f | ||
|
|
eb16df3450 | ||
|
|
b44684760d | ||
|
|
be3fc1bb84 | ||
|
|
e781e67b43 | ||
|
|
40800ffe4b | ||
|
|
4e704e59e8 | ||
|
|
06e5d5e3d1 | ||
|
|
06010d7cd6 | ||
|
|
2549cd9a71 | ||
|
|
e89e35436e | ||
|
|
f5029ee3e9 | ||
|
|
08a84e0a8b | ||
|
|
36c819de04 | ||
|
|
f62987af4b | ||
|
|
8d9b44d6ec | ||
|
|
a5babb722d | ||
|
|
bde65f094d | ||
|
|
3fa2cfabd3 | ||
|
|
b8f4d02e4f | ||
|
|
436b7feb8e | ||
|
|
8bab4dd6ee | ||
|
|
99dfea631b | ||
|
|
16501bd6a8 | ||
|
|
88201b7308 | ||
|
|
2fb680b06a | ||
|
|
fb8116107b | ||
|
|
e6b83a1db5 | ||
|
|
607a19048b | ||
|
|
0db831e0c3 | ||
|
|
863cca507d | ||
|
|
3916a252d4 | ||
|
|
1594b76851 | ||
|
|
9e14fc5241 | ||
|
|
54fd3e2fd1 | ||
|
|
2348f8dba2 | ||
|
|
f0a3dc48f9 | ||
|
|
58ad43213b | ||
|
|
4a505b7238 | ||
|
|
7c6c0e68d2 | ||
|
|
1c5b22710d | ||
|
|
75755528b1 | ||
|
|
4dadcaf574 | ||
|
|
5a88d53443 | ||
|
|
2bd5faa7d9 | ||
|
|
29cb868f50 | ||
|
|
4eb222f5aa | ||
|
|
eca6ab2297 | ||
|
|
749e5147df |
@@ -1,7 +1,7 @@
|
||||
|
||||
<div align="center">
|
||||
|
||||
<img src="assets/logo.png" alt="logo" width="350"/>
|
||||
<img src="assets/logo.png" alt="logo" width="768"/>
|
||||
|
||||
---
|
||||
|
||||
@@ -36,12 +36,12 @@ It enables advanced CPU, GPU, and RAM tuning with user-friendly configuration to
|
||||
|
||||
* **CPU:** Up to 1963MHz (Mariko) / 1785MHz (Erista)
|
||||
* **GPU:** Up to 1075MHz (Mariko) / 921MHz (Erista)
|
||||
* **RAM:** Up to 1866MHz (Mariko) / 1600MHz (Erista)
|
||||
* **RAM:** Up to 1866/2133MHz (Mariko) / 1600MHz (Erista)
|
||||
* Over/undervolting support
|
||||
* Built-in configurator
|
||||
* Compatible with most homebrew
|
||||
|
||||
> It is reccomended to read the [guide](https://rentry.co/howtoget60fps) before proceeding, as this can help you get a *significant* performance boost over the default settings, often times with less power draw and heat output
|
||||
> It is recommended to read the [guide](https://rentry.co/howtoget60fps) before proceeding, as this can help you get a *significant* performance boost over the default settings, often times with less power draw and heat output
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| 0.x | :white_check_mark: |
|
||||
| 1.x | :white_check_mark: |
|
||||
| 0.x | Not supported |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#define DISABLED 0
|
||||
#define DEACTIVATED_GPU_FREQ 2000
|
||||
#define GPU_MIN_MIN_VOLT 480000
|
||||
#define CPU_MAX_MAX_VOLT 1395000
|
||||
#define CPU_MAX_MAX_VOLT 1200000
|
||||
|
||||
namespace ams::ldr::hoc {
|
||||
|
||||
@@ -80,7 +80,7 @@ volatile CustomizeTable C = {
|
||||
.marikoCpuUVLow = 0, // No undervolt
|
||||
.marikoCpuUVHigh = 0, // No undervolt
|
||||
|
||||
.tableConf = DEFAULT_TABLE,
|
||||
.tableConf = TBREAK_1683,
|
||||
.marikoCpuLowVmin = 620,
|
||||
.marikoCpuHighVmin = 750,
|
||||
/* 1120mV is NVIDIA rating */
|
||||
@@ -122,28 +122,32 @@ volatile CustomizeTable C = {
|
||||
|
||||
.eristaGpuVoltArray = {
|
||||
AUTO /* 76 */,
|
||||
AUTO /* 115 */,
|
||||
AUTO /* 153 */,
|
||||
AUTO /* 192 */,
|
||||
AUTO /* 230 */,
|
||||
AUTO /* 269 */,
|
||||
AUTO /* 307 */,
|
||||
AUTO /* 346 */,
|
||||
AUTO /* 384 */,
|
||||
AUTO /* 422 */,
|
||||
AUTO /* 460 */,
|
||||
AUTO /* 499 */,
|
||||
AUTO /* 537 */,
|
||||
AUTO /* 576 */,
|
||||
AUTO /* 614 */,
|
||||
AUTO /* 652 */,
|
||||
AUTO /* 691 */,
|
||||
AUTO /* 729 */,
|
||||
AUTO /* 768 */,
|
||||
AUTO /* 806 */,
|
||||
AUTO /* 844 */,
|
||||
AUTO /* 883 */,
|
||||
AUTO /* 921 */,
|
||||
DEACTIVATED_GPU_FREQ /* 960 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 998 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1036 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1075 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1152 (SLT / HiOPT Only!) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1228 (HiOPT Only!) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1305 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1344 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1382 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1420 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1459 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1497 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1536 (Disabled by default) */,
|
||||
},
|
||||
|
||||
.marikoGpuVoltArray = {
|
||||
@@ -163,6 +167,7 @@ volatile CustomizeTable C = {
|
||||
AUTO /* 1075 */,
|
||||
AUTO /* 1152 (SLT / HiOPT Only!) */,
|
||||
AUTO /* 1228 (HiOPT Only!) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1267 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1305 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1344 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1382 (Disabled by default) */,
|
||||
@@ -170,14 +175,6 @@ volatile CustomizeTable C = {
|
||||
DEACTIVATED_GPU_FREQ /* 1459 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1497 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1536 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1574 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1612 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1651 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1689 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1728 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1766 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1804 (Disabled by default) */,
|
||||
|
||||
},
|
||||
|
||||
/* Advanced. */
|
||||
@@ -202,9 +199,9 @@ volatile CustomizeTable C = {
|
||||
{ 1581000, { 1130000, }, { 2889664, -122173, 1834, } },
|
||||
{ 1683000, { 1168000, }, { 5100873, -279186, 4747, } },
|
||||
{ 1785000, { 1225000, }, { 5100873, -279186, 4747, } },
|
||||
{ 1887000, { 1225000, }, { 5100873, -279186, 4747, } },
|
||||
{ 1989000, { 1227500, }, { 5100873, -279186, 4747, } },
|
||||
{ 2091000, { 1256250, }, { 5100873, -279186, 4747, } },
|
||||
// { 1887000, { 1225000, }, { 5100873, -279186, 4747, } },
|
||||
// { 1989000, { 1227500, }, { 5100873, -279186, 4747, } },
|
||||
// { 2091000, { 1256250, }, { 5100873, -279186, 4747, } },
|
||||
},
|
||||
|
||||
.eristaCpuDvfsTableSLT = {
|
||||
@@ -225,14 +222,11 @@ volatile CustomizeTable C = {
|
||||
{ 1683000, { 1168000, }, { 5100873, -279186, 4747, } },
|
||||
{ 1785000, { 1225000, }, { 5100873, -279186, 4747, } },
|
||||
{ 1887000, { 1225000, }, { 5100873, -279186, 4747, } },
|
||||
{ 1989000, { 1227500, }, { 5100873, -279186, 4747, } },
|
||||
{ 1963500, { 1227500, }, { 5100873, -279186, 4747, } },
|
||||
{ 2091000, { 1227500, }, { 5100873, -279186, 4747, } },
|
||||
{ 2193000, { 1227500, }, { 5100873, -279186, 4747, } },
|
||||
{ 2295000, { 1227500, }, { 5100873, -279186, 4747, } },
|
||||
{ 2397000, { 1395000, }, { 5100873, -279186, 4747, } },
|
||||
{ 2499000, { 1395000, }, { 6000000, -179186, 4747, } },
|
||||
{ 2601000, { 1395000, }, { 6000000, -179186, 4747, } },
|
||||
{ 2703000, { 1395000, }, { 6000000, -179186, 4747, } },
|
||||
{ 2295000, { 1256250, }, { 5100873, -279186, 4747, } },
|
||||
{ 2397000, { 1256250, }, { 5100873, -279186, 4747, } }, // Only for god speedo!
|
||||
},
|
||||
|
||||
.marikoCpuDvfsTable = {
|
||||
@@ -254,13 +248,17 @@ volatile CustomizeTable C = {
|
||||
{ 1785000, { 1527196, -36015, 27, }, { 1120000, } },
|
||||
{ 1887000, { 1609246, -37515, 27, }, { 1120000, } },
|
||||
{ 1963500, { 1675751, -38635, 27, }, { 1120000, } },
|
||||
{ 2091000, { 1716501, -39395, 27, }, { CPU_MAX_MAX_VOLT, } },
|
||||
{ 2193000, { 1775132, -40505, 27, }, { CPU_MAX_MAX_VOLT, } },
|
||||
{ 2295000, { 1866287, -42005, 27, }, { CPU_MAX_MAX_VOLT, } },
|
||||
{ 2397000, { 1961107, -43506, 27, }, { CPU_MAX_MAX_VOLT, } },
|
||||
// { 2091000, { 1716501, -39395, 27, }, { CPU_MAX_MAX_VOLT, } },
|
||||
// { 2193000, { 1775132, -40505, 27, }, { CPU_MAX_MAX_VOLT, } },
|
||||
// { 2295000, { 1866287, -42005, 27, }, { CPU_MAX_MAX_VOLT, } },
|
||||
// { 2397000, { 1961107, -43506, 27, }, { CPU_MAX_MAX_VOLT, } },
|
||||
},
|
||||
|
||||
.marikoCpuDvfsTableSLT = {
|
||||
{ 204000, { 732856, -17335, 113, }, { } },
|
||||
{ 306000, { 760024, -18195, 113, }, { } },
|
||||
{ 408000, { 789258, -19055, 113, }, { } },
|
||||
{ 510000, { 789258, -19055, 113, }, { } },
|
||||
{ 612000, { 789258, -19055, 113, }, { } },
|
||||
{ 714000, { 789258, -19055, 113, }, { } },
|
||||
{ 816000, { 789258, -19055, 113, }, { } },
|
||||
@@ -282,12 +280,13 @@ volatile CustomizeTable C = {
|
||||
{ 2499000, { 1580725, -35815, 113, }, { CPU_MAX_MAX_VOLT, } },
|
||||
{ 2601000, { 1702903, -36675, 113, }, { CPU_MAX_MAX_VOLT, } },
|
||||
{ 2703000, { 1770375, -37515, 113, }, { CPU_MAX_MAX_VOLT, } },
|
||||
{ 2805000, { 1908891, -37707, 113 }, { CPU_MAX_MAX_VOLT, } },
|
||||
{ 2907000, { 1960388, -38395, 113 }, { CPU_MAX_MAX_VOLT ,} },
|
||||
{ 3009000, { 2011885, -39083, 113 }, { CPU_MAX_MAX_VOLT ,} },
|
||||
},
|
||||
|
||||
.marikoCpuDvfsTable1581Tbreak {
|
||||
{ 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, }, { } },
|
||||
@@ -309,12 +308,13 @@ volatile CustomizeTable C = {
|
||||
{ 2499000, { 1736856, -35286, 113, }, { CPU_MAX_MAX_VOLT, } },
|
||||
{ 2601000, { 1787838, -35967, 113, }, { CPU_MAX_MAX_VOLT, } },
|
||||
{ 2703000, { 1838820, -36648, 113, }, { CPU_MAX_MAX_VOLT, } },
|
||||
{ 2805000, { 1908891, -37707, 113 }, { CPU_MAX_MAX_VOLT, } },
|
||||
{ 2907000, { 1960388, -38395, 113 }, { CPU_MAX_MAX_VOLT ,} },
|
||||
{ 3009000, { 2011885, -39083, 113 }, { CPU_MAX_MAX_VOLT ,} },
|
||||
},
|
||||
|
||||
.marikoCpuDvfsTable1683Tbreak {
|
||||
{ 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, }, { } },
|
||||
@@ -336,12 +336,13 @@ volatile CustomizeTable C = {
|
||||
{ 2499000, { 1736856, -35286, 113, }, { CPU_MAX_MAX_VOLT, } },
|
||||
{ 2601000, { 1787838, -35967, 113, }, { CPU_MAX_MAX_VOLT, } },
|
||||
{ 2703000, { 1838820, -36648, 113, }, { CPU_MAX_MAX_VOLT, } },
|
||||
{ 2805000, { 1908891, -37707, 113 }, { CPU_MAX_MAX_VOLT, } },
|
||||
{ 2907000, { 1960388, -38395, 113 }, { CPU_MAX_MAX_VOLT ,} },
|
||||
{ 3009000, { 2011885, -39083, 113 }, { CPU_MAX_MAX_VOLT ,} },
|
||||
},
|
||||
|
||||
.marikoCpuDvfsTableExtreme {
|
||||
{ 204000, { 732856, -17335, 113, }, { } },
|
||||
{ 306000, { 760024, -18195, 113, }, { } },
|
||||
{ 408000, { 789258, -19055, 113, }, { } },
|
||||
{ 510000, { 789258, -19915, 113, }, { } },
|
||||
{ 612000, { 789258, -19055, 113, }, { } },
|
||||
{ 714000, { 820558, -19915, 113, }, { } },
|
||||
{ 816000, { 853926, -20775, 113, }, { } },
|
||||
@@ -363,66 +364,91 @@ volatile CustomizeTable C = {
|
||||
{ 2499000, { 1580725, -35815, 113, }, { CPU_MAX_MAX_VOLT, } },
|
||||
{ 2601000, { 1702903, -36675, 113, }, { CPU_MAX_MAX_VOLT, } },
|
||||
{ 2703000, { 1775375, -37515, 113, }, { CPU_MAX_MAX_VOLT, } },
|
||||
{ 2805000, { 1908891, -37707, 113 }, { CPU_MAX_MAX_VOLT, } },
|
||||
{ 2907000, { 1960388, -38395, 113 }, { CPU_MAX_MAX_VOLT ,} },
|
||||
{ 3009000, { 2011885, -39083, 113 }, { CPU_MAX_MAX_VOLT ,} },
|
||||
},
|
||||
|
||||
.eristaGpuDvfsTable = {
|
||||
{ 76800, { }, { 814294, 8144, -940, 808, -21583, 226, } },
|
||||
{ 115200, { }, { 856185, 8144, -940, 808, -21583, 226, } },
|
||||
{ 153600, { }, { 856185, 8144, -940, 808, -21583, 226, } },
|
||||
{ 192000, { }, { 898077, 8144, -940, 808, -21583, 226, } },
|
||||
{ 230400, { }, { 898077, 8144, -940, 808, -21583, 226, } },
|
||||
{ 268800, { }, { 939968, 8144, -940, 808, -21583, 226, } },
|
||||
{ 307200, { }, { 939968, 8144, -940, 808, -21583, 226, } },
|
||||
{ 345600, { }, { 981860, 8144, -940, 808, -21583, 226, } },
|
||||
{ 384000, { }, { 981860, 8144, -940, 808, -21583, 226, } },
|
||||
{ 422400, { }, { 1023751, 8144, -940, 808, -21583, 226, } },
|
||||
{ 460800, { }, { 1023751, 8144, -940, 808, -21583, 226, } },
|
||||
{ 499200, { }, { 1065642, 8144, -940, 808, -21583, 226, } },
|
||||
{ 537600, { }, { 1065642, 8144, -940, 808, -21583, 226, } },
|
||||
{ 576000, { }, { 1107534, 8144, -940, 808, -21583, 226, } },
|
||||
{ 614400, { }, { 1107534, 8144, -940, 808, -21583, 226, } },
|
||||
{ 652800, { }, { 1149425, 8144, -940, 808, -21583, 226, } },
|
||||
{ 691200, { }, { 1149425, 8144, -940, 808, -21583, 226, } },
|
||||
{ 729600, { }, { 1191317, 8144, -940, 808, -21583, 226, } },
|
||||
{ 768000, { }, { 1191317, 8144, -940, 808, -21583, 226, } },
|
||||
{ 806400, { }, { 1233208, 8144, -940, 808, -21583, 226, } },
|
||||
{ 844800, { }, { 1233208, 8144, -940, 808, -21583, 226, } },
|
||||
{ 883200, { }, { 1275100, 8144, -940, 808, -21583, 226, } },
|
||||
{ 921600, { }, { 1275100, 8144, -940, 808, -21583, 226, } },
|
||||
// { 998400, { }, { 1316991, 8144, -940, 808, -21583, 226, } },
|
||||
},
|
||||
|
||||
.eristaGpuDvfsTableSLT = {
|
||||
{ 76800, { }, { 814294, 8144, -940, 0, 0, 226, } },
|
||||
{ 115200, { }, { 856185, 8144, -940, 0, 0, 226, } },
|
||||
{ 153600, { }, { 856185, 8144, -940, 0, 0, 226, } },
|
||||
{ 192000, { }, { 908077, 8144, -940, 0, 0, 226, } },
|
||||
{ 230400, { }, { 908077, 8144, -940, 0, 0, 226, } },
|
||||
{ 268800, { }, { 934968, 8144, -940, 0, 0, 226, } },
|
||||
{ 307200, { }, { 934968, 8144, -940, 0, 0, 226, } },
|
||||
{ 345600, { }, { 952860, 8144, -940, 0, 0, 226, } },
|
||||
{ 384000, { }, { 952860, 8144, -940, 0, 0, 226, } },
|
||||
{ 422400, { }, { 978751, 8144, -940, 0, 0, 226, } },
|
||||
{ 460800, { }, { 978751, 8144, -940, 0, 0, 226, } },
|
||||
{ 499200, { }, { 990642, 8144, -940, 0, 0, 226, } },
|
||||
{ 537600, { }, { 990642, 8144, -940, 0, 0, 226, } },
|
||||
{ 576000, { }, { 1017534, 8144, -940, 0, 0, 226, } },
|
||||
{ 614400, { }, { 1017534, 8144, -940, 0, 0, 226, } },
|
||||
{ 652800, { }, { 1042425, 8144, -940, 0, 0, 226, } },
|
||||
{ 691200, { }, { 1042425, 8144, -940, 0, 0, 226, } },
|
||||
{ 729600, { }, { 1066317, 8144, -940, 0, 0, 226, } },
|
||||
{ 768000, { }, { 1066317, 8144, -940, 0, 0, 226, } },
|
||||
{ 806400, { }, { 1093208, 8144, -940, 0, 0, 226, } },
|
||||
{ 844800, { }, { 1093208, 8144, -940, 0, 0, 226, } },
|
||||
{ 883200, { }, { 1118100, 8144, -940, 0, 0, 226, } },
|
||||
{ 921600, { }, { 1118100, 8144, -940, 0, 0, 226, } },
|
||||
{ 960000, { }, { 1156991, 8144, -940, 0, 0, 226, } },
|
||||
},
|
||||
|
||||
.eristaGpuDvfsTableHiOPT = {
|
||||
{ 76800, { }, { 814294, 8144, -940, 0, 0, 226, } },
|
||||
{ 115200, { }, { 856185, 8144, -940, 0, 0, 226, } },
|
||||
{ 153600, { }, { 856185, 8144, -940, 0, 0, 226, } },
|
||||
{ 192000, { }, { 908077, 8144, -940, 0, 0, 226, } },
|
||||
{ 230400, { }, { 908077, 8144, -940, 0, 0, 226, } },
|
||||
{ 268800, { }, { 934968, 8144, -940, 0, 0, 226, } },
|
||||
{ 307200, { }, { 934968, 8144, -940, 0, 0, 226, } },
|
||||
{ 345600, { }, { 952860, 8144, -940, 0, 0, 226, } },
|
||||
{ 384000, { }, { 952860, 8144, -940, 0, 0, 226, } },
|
||||
{ 422400, { }, { 978751, 8144, -940, 0, 0, 226, } },
|
||||
{ 460800, { }, { 978751, 8144, -940, 0, 0, 226, } },
|
||||
{ 499200, { }, { 990642, 8144, -940, 0, 0, 226, } },
|
||||
{ 537600, { }, { 990642, 8144, -940, 0, 0, 226, } },
|
||||
{ 576000, { }, { 1017534, 8144, -940, 0, 0, 226, } },
|
||||
{ 614400, { }, { 1017534, 8144, -940, 0, 0, 226, } },
|
||||
{ 652800, { }, { 1042425, 8144, -940, 0, 0, 226, } },
|
||||
{ 691200, { }, { 1042425, 8144, -940, 0, 0, 226, } },
|
||||
{ 729600, { }, { 1066317, 8144, -940, 0, 0, 226, } },
|
||||
{ 768000, { }, { 1066317, 8144, -940, 0, 0, 226, } },
|
||||
{ 806400, { }, { 1093208, 8144, -940, 0, 0, 226, } },
|
||||
{ 844800, { }, { 1093208, 8144, -940, 0, 0, 226, } },
|
||||
{ 883200, { }, { 1118100, 8144, -940, 0, 0, 226, } },
|
||||
{ 921600, { }, { 1118100, 8144, -940, 0, 0, 226, } },
|
||||
{ 960000, { }, { 1156991, 8144, -940, 0, 0, 226, } },
|
||||
{ 998400, { }, { 1156991, 8144, -940, 0, 0, 226, } },
|
||||
{ 1036800, { }, { } },
|
||||
{ 1075200, { }, { } },
|
||||
{ 1152000, { }, { } },
|
||||
{ 1228800, { }, { 0, 0, 0, 0, 0, 0 } },
|
||||
{ 1267200, { }, { 0, 0, 0, 0, 0, 0 } },
|
||||
{ 1344000, { }, { 0, 0, 0, 0, 0, 0 } },
|
||||
{ 1382400, { }, { 0, 0, 0, 0, 0, 0 } },
|
||||
{ 1420800, { }, { 0, 0, 0, 0, 0, 0 } },
|
||||
{ 1459200, { }, { 0, 0, 0, 0, 0, 0 } },
|
||||
{ 1497600, { }, { 0, 0, 0, 0, 0, 0 } },
|
||||
{ 1536000, { }, { 0, 0, 0, 0, 0, 0 } },
|
||||
// { 1152000, { }, { } },
|
||||
},
|
||||
|
||||
.marikoGpuDvfsTable = {
|
||||
@@ -440,9 +466,9 @@ volatile CustomizeTable C = {
|
||||
{ 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 } },
|
||||
// { 1152000, { }, { 1180029,-14534, -830, 0, 1469, 110 } },
|
||||
// { 1228800, { }, { 1248293,-16383, -859, 0, 3722, 313 } },
|
||||
// { 1267200, { }, { 1286399,-17475, -867, 0, 3681, 559 } },
|
||||
},
|
||||
|
||||
.marikoGpuDvfsTableSLT = {
|
||||
@@ -462,7 +488,7 @@ volatile CustomizeTable C = {
|
||||
{ 1075200, { }, { 1132576, -16093, -648, 0, 1077, 40 } },
|
||||
{ 1152000, { }, { 1180029, -14534, -830, 0, 1469, 110 } },
|
||||
{ 1228800, { }, { 1238293, -16383, -859, 0, 3722, 313 } },
|
||||
{ 1267200, { }, { 1276399, -17475, -867, 0, 3681, 559 } },
|
||||
// { 1267200, { }, { 1276399, -17475, -867, 0, 3681, 559 } },
|
||||
},
|
||||
|
||||
.marikoGpuDvfsTableHiOPT = {
|
||||
@@ -490,13 +516,6 @@ volatile CustomizeTable C = {
|
||||
{ 1459200, { }, { 0, 0, 0, 0, 0, 0 } },
|
||||
{ 1497600, { }, { 0, 0, 0, 0, 0, 0 } },
|
||||
{ 1536000, { }, { 0, 0, 0, 0, 0, 0 } },
|
||||
{ 1574400, { }, { 0, 0, 0, 0, 0, 0 } },
|
||||
{ 1612800, { }, { 0, 0, 0, 0, 0, 0 } },
|
||||
{ 1651200, { }, { 0, 0, 0, 0, 0, 0 } },
|
||||
{ 1689600, { }, { 0, 0, 0, 0, 0, 0 } },
|
||||
{ 1728000, { }, { 0, 0, 0, 0, 0, 0 } },
|
||||
{ 1766400, { }, { 0, 0, 0, 0, 0, 0 } },
|
||||
{ 1804800, { }, { 0, 0, 0, 0, 0, 0 } },
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
@@ -125,8 +125,8 @@ typedef struct CustomizeTable {
|
||||
|
||||
u32 gpuSpeedo;
|
||||
|
||||
u32 eristaGpuVoltArray[24];
|
||||
u32 marikoGpuVoltArray[31];
|
||||
u32 eristaGpuVoltArray[27];
|
||||
u32 marikoGpuVoltArray[24];
|
||||
|
||||
u32 fineTune_t6_tRTW;
|
||||
u32 fineTune_t7_tWTR;
|
||||
|
||||
@@ -22,153 +22,157 @@
|
||||
|
||||
namespace ams::ldr::hoc::pcv {
|
||||
|
||||
Result MemFreqPllmLimit(u32* ptr) {
|
||||
clk_pll_param* entry = reinterpret_cast<clk_pll_param *>(ptr);
|
||||
R_UNLESS(entry->freq == entry->vco_max, ldr::ResultInvalidMemPllmEntry());
|
||||
Result MemFreqPllmLimit(u32* ptr) {
|
||||
clk_pll_param* entry = reinterpret_cast<clk_pll_param *>(ptr);
|
||||
R_UNLESS(entry->freq == entry->vco_max, ldr::ResultInvalidMemPllmEntry());
|
||||
|
||||
// Double the max clk simply
|
||||
u32 max_clk = entry->freq * 2;
|
||||
entry->freq = max_clk;
|
||||
entry->vco_max = max_clk;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result MemVoltHandler(u32* ptr) {
|
||||
// ptr value might be default_uv or max_uv
|
||||
regulator* entries[2] = {
|
||||
reinterpret_cast<regulator *>(reinterpret_cast<u8 *>(ptr) - offsetof(regulator, type_1.default_uv)),
|
||||
reinterpret_cast<regulator *>(reinterpret_cast<u8 *>(ptr) - offsetof(regulator, type_1.max_uv)),
|
||||
};
|
||||
|
||||
constexpr u32 uv_step = 12'500;
|
||||
constexpr u32 uv_min = 600'000;
|
||||
|
||||
auto validator = [](regulator* entry) {
|
||||
R_UNLESS(entry->id == 1, ldr::ResultInvalidRegulatorEntry());
|
||||
R_UNLESS(entry->type == 1, ldr::ResultInvalidRegulatorEntry());
|
||||
R_UNLESS(entry->type_1.volt_reg == 0x17, ldr::ResultInvalidRegulatorEntry());
|
||||
R_UNLESS(entry->type_1.step_uv == uv_step, ldr::ResultInvalidRegulatorEntry());
|
||||
R_UNLESS(entry->type_1.min_uv == uv_min, ldr::ResultInvalidRegulatorEntry());
|
||||
// Double the max clk simply
|
||||
u32 max_clk = entry->freq * 2;
|
||||
entry->freq = max_clk;
|
||||
entry->vco_max = max_clk;
|
||||
R_SUCCEED();
|
||||
};
|
||||
|
||||
regulator* entry = nullptr;
|
||||
for (auto& i : entries) {
|
||||
if (R_SUCCEEDED(validator(i)))
|
||||
entry = i;
|
||||
}
|
||||
|
||||
R_UNLESS(entry, ldr::ResultInvalidRegulatorEntry());
|
||||
Result MemVoltHandler(u32* ptr) {
|
||||
// ptr value might be default_uv or max_uv
|
||||
regulator* entries[2] = {
|
||||
reinterpret_cast<regulator *>(reinterpret_cast<u8 *>(ptr) - offsetof(regulator, type_1.default_uv)),
|
||||
reinterpret_cast<regulator *>(reinterpret_cast<u8 *>(ptr) - offsetof(regulator, type_1.max_uv)),
|
||||
};
|
||||
|
||||
u32 emc_uv = C.commonEmcMemVolt;
|
||||
if (!emc_uv)
|
||||
R_SKIP();
|
||||
|
||||
if (emc_uv % uv_step)
|
||||
emc_uv = emc_uv / uv_step * uv_step; // rounding
|
||||
|
||||
PATCH_OFFSET(ptr, emc_uv);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void SafetyCheck() {
|
||||
// if (C.custRev != CUST_REV)
|
||||
// CRASH("Triggered");
|
||||
|
||||
struct sValidator {
|
||||
volatile u32 value;
|
||||
u32 min;
|
||||
u32 max;
|
||||
bool value_required = false;
|
||||
|
||||
Result check() {
|
||||
if (!value_required && !value)
|
||||
R_SUCCEED();
|
||||
|
||||
if (min && value < min)
|
||||
R_THROW(ldr::ResultSafetyCheckFailure());
|
||||
if (max && value > max)
|
||||
R_THROW(ldr::ResultSafetyCheckFailure());
|
||||
constexpr u32 uv_step = 12'500;
|
||||
constexpr u32 uv_min = 600'000;
|
||||
|
||||
auto validator = [](regulator* entry) {
|
||||
R_UNLESS(entry->id == 1, ldr::ResultInvalidRegulatorEntry());
|
||||
R_UNLESS(entry->type == 1, ldr::ResultInvalidRegulatorEntry());
|
||||
R_UNLESS(entry->type_1.volt_reg == 0x17, ldr::ResultInvalidRegulatorEntry());
|
||||
R_UNLESS(entry->type_1.step_uv == uv_step, ldr::ResultInvalidRegulatorEntry());
|
||||
R_UNLESS(entry->type_1.min_uv == uv_min, ldr::ResultInvalidRegulatorEntry());
|
||||
R_SUCCEED();
|
||||
};
|
||||
|
||||
regulator* entry = nullptr;
|
||||
for (auto& i : entries) {
|
||||
if (R_SUCCEEDED(validator(i))) {
|
||||
entry = i;
|
||||
}
|
||||
}
|
||||
};
|
||||
u32 eristaCpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaCpuDvfsTable)->freq);
|
||||
u32 marikoCpuDvfsMaxFreq;
|
||||
if (C.marikoCpuUVHigh) {
|
||||
marikoCpuDvfsMaxFreq = static_cast<u32>(
|
||||
GetDvfsTableLastEntry(C.marikoCpuDvfsTableSLT)->freq
|
||||
);
|
||||
} else {
|
||||
marikoCpuDvfsMaxFreq = static_cast<u32>(
|
||||
GetDvfsTableLastEntry(C.marikoCpuDvfsTable)->freq
|
||||
);
|
||||
|
||||
R_UNLESS(entry, ldr::ResultInvalidRegulatorEntry());
|
||||
|
||||
u32 emc_uv = C.commonEmcMemVolt;
|
||||
if (!emc_uv) {
|
||||
R_SKIP();
|
||||
}
|
||||
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.eristaGpuDvfsTableHiOPT)->freq);
|
||||
break;
|
||||
default:
|
||||
eristaGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaGpuDvfsTable)->freq);
|
||||
break;
|
||||
|
||||
if (emc_uv % uv_step) {
|
||||
emc_uv = emc_uv / uv_step * uv_step; // rounding
|
||||
}
|
||||
|
||||
PATCH_OFFSET(ptr, emc_uv);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
u32 marikoGpuDvfsMaxFreq;
|
||||
switch (C.marikoGpuUV) {
|
||||
void SafetyCheck() {
|
||||
// if (C.custRev != CUST_REV)
|
||||
// CRASH("Triggered");
|
||||
|
||||
struct sValidator {
|
||||
volatile u32 value;
|
||||
u32 min;
|
||||
u32 max;
|
||||
bool value_required = false;
|
||||
|
||||
Result check() {
|
||||
if (!value_required && !value)
|
||||
R_SUCCEED();
|
||||
|
||||
if (min && value < min)
|
||||
R_THROW(ldr::ResultSafetyCheckFailure());
|
||||
if (max && value > max)
|
||||
R_THROW(ldr::ResultSafetyCheckFailure());
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
};
|
||||
|
||||
u32 eristaCpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaCpuDvfsTable)->freq);
|
||||
u32 marikoCpuDvfsMaxFreq;
|
||||
if (C.marikoCpuUVHigh) {
|
||||
marikoCpuDvfsMaxFreq = static_cast<u32>(
|
||||
GetDvfsTableLastEntry(C.marikoCpuDvfsTableSLT)->freq
|
||||
);
|
||||
} else {
|
||||
marikoCpuDvfsMaxFreq = static_cast<u32>(
|
||||
GetDvfsTableLastEntry(C.marikoCpuDvfsTable)->freq
|
||||
);
|
||||
}
|
||||
u32 eristaGpuDvfsMaxFreq;
|
||||
switch (C.eristaGpuUV) {
|
||||
case 0:
|
||||
marikoGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.marikoGpuDvfsTable)->freq);
|
||||
eristaGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaGpuDvfsTable)->freq);
|
||||
break;
|
||||
case 1:
|
||||
marikoGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.marikoGpuDvfsTableSLT)->freq);
|
||||
eristaGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaGpuDvfsTableSLT)->freq);
|
||||
break;
|
||||
case 2:
|
||||
marikoGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.marikoGpuDvfsTableHiOPT)->freq);
|
||||
eristaGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaGpuDvfsTableHiOPT)->freq);
|
||||
break;
|
||||
default:
|
||||
marikoGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.marikoGpuDvfsTable)->freq);
|
||||
eristaGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaGpuDvfsTable)->freq);
|
||||
break;
|
||||
}
|
||||
|
||||
u32 marikoGpuDvfsMaxFreq;
|
||||
switch (C.marikoGpuUV) {
|
||||
case 0:
|
||||
marikoGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.marikoGpuDvfsTable)->freq);
|
||||
break;
|
||||
case 1:
|
||||
marikoGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.marikoGpuDvfsTableSLT)->freq);
|
||||
break;
|
||||
case 2:
|
||||
marikoGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.marikoGpuDvfsTableHiOPT)->freq);
|
||||
break;
|
||||
default:
|
||||
marikoGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.marikoGpuDvfsTable)->freq);
|
||||
break;
|
||||
}
|
||||
|
||||
using namespace ams::ldr::hoc::pcv;
|
||||
sValidator validators[] = {
|
||||
{ C.eristaCpuBoostClock, 1020'000, 2295'000, true },
|
||||
{ C.marikoCpuBoostClock, 1020'000, 2703'000, true },
|
||||
{ C.commonEmcMemVolt, 912'500, 1350'000 }, // Official burst vmax for the RAMs is 1500mV
|
||||
{ C.eristaCpuMaxVolt, 1000, 1260 },
|
||||
{ GET_MAX_OF_ARR(erista::maxEmcClocks), 1600'000, 2600'000 },
|
||||
{ C.marikoCpuMaxVolt, 1000, 1200 },
|
||||
{ C.marikoEmcMaxClock, 1600'000, 3500'000 },
|
||||
{ C.marikoEmcVddqVolt, 250'000, 700'000 },
|
||||
{ eristaCpuDvfsMaxFreq, 1785'000, 2295'000 },
|
||||
{ marikoCpuDvfsMaxFreq, 1785'000, 2703'000 },
|
||||
{ eristaGpuDvfsMaxFreq, 768'000, 1152'000 },
|
||||
{ marikoGpuDvfsMaxFreq, 768'000, 1536'000 },
|
||||
};
|
||||
|
||||
for (auto& i : validators) {
|
||||
if (R_FAILED(i.check())) {
|
||||
CRASH("Validation FAIL");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
using namespace ams::ldr::hoc::pcv;
|
||||
sValidator validators[] = {
|
||||
{ C.eristaCpuBoostClock, 1020'000, 3009'000, true },
|
||||
{ C.marikoCpuBoostClock, 1020'000, 3009'000, true },
|
||||
{ C.commonEmcMemVolt, 912'500, 1500'000 }, // Official burst vmax for the RAMs is 1500mV
|
||||
{ C.eristaCpuMaxVolt, 1000, 1500 },
|
||||
{ GET_MAX_OF_ARR(erista::maxEmcClocks), 1600'000, 2700'000 },
|
||||
{ C.marikoCpuMaxVolt, 1000, 1500 },
|
||||
{ C.marikoEmcMaxClock, 1600'000, 3500'000 },
|
||||
{ C.marikoEmcVddqVolt, 250'000, 1500'000 },
|
||||
{ eristaCpuDvfsMaxFreq, 1785'000, 3009'000 },
|
||||
{ marikoCpuDvfsMaxFreq, 1785'000, 3009'000 },
|
||||
{ eristaGpuDvfsMaxFreq, 768'000, 1536'000 },
|
||||
{ marikoGpuDvfsMaxFreq, 768'000, 1536'000 },
|
||||
};
|
||||
|
||||
for (auto& i : validators) {
|
||||
if (R_FAILED(i.check()))
|
||||
CRASH("Validation FAIL");
|
||||
void Patch(uintptr_t mapped_nso, size_t nso_size) {
|
||||
#ifdef ATMOSPHERE_IS_STRATOSPHERE
|
||||
SafetyCheck();
|
||||
bool isMariko = (spl::GetSocType() == spl::SocType_Mariko);
|
||||
if (isMariko)
|
||||
mariko::Patch(mapped_nso, nso_size);
|
||||
else
|
||||
erista::Patch(mapped_nso, nso_size);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void Patch(uintptr_t mapped_nso, size_t nso_size) {
|
||||
#ifdef ATMOSPHERE_IS_STRATOSPHERE
|
||||
SafetyCheck();
|
||||
bool isMariko = (spl::GetSocType() == spl::SocType_Mariko);
|
||||
if (isMariko)
|
||||
mariko::Patch(mapped_nso, nso_size);
|
||||
else
|
||||
erista::Patch(mapped_nso, nso_size);
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ namespace ams::ldr::hoc::pcv {
|
||||
|
||||
static const u32 cpuVoltThermalData[] = { 620, 1120, 20000, 620, 1120, 70000, 950, 1132, 0, 950, 1227, 0 };
|
||||
|
||||
static const u32 allowedCpuMaxFrequencies[] = { 1'963'000, 2'091'000, 2'193'000, 2'295'000, 2'397'000, 2'499'000, 2'601'000, 2'703'000, 2'805'000, 2'907'000, 3'009'000, };
|
||||
static const u32 allowedCpuMaxFrequencies[] = { 1'963'000, 2'091'000, 2'193'000, 2'295'000, 2'397'000, 2'499'000, 2'601'000, 2'703'000, };
|
||||
|
||||
constexpr cvb_entry_t GpuCvbTableDefault[] = {
|
||||
// GPUB01_NA_CVB_TABLE
|
||||
@@ -202,20 +202,14 @@ namespace ams::ldr::hoc::pcv {
|
||||
{ },
|
||||
};
|
||||
|
||||
constexpr u32 CpuVoltOfficial = 1235;
|
||||
constexpr u32 CpuVoltOfficial = 1227;
|
||||
|
||||
constexpr u32 CpuVminOfficial = 825;
|
||||
|
||||
constexpr u32 CpuVoltL4T = 1235'000;
|
||||
constexpr u16 CpuMinVolts[] = { 950, 850, 825, 810 };
|
||||
constexpr u32 CpuVoltL4T = 1257'000;
|
||||
|
||||
inline bool CpuMaxVoltPatternFn(u32* ptr32) {
|
||||
u32 val = *ptr32;
|
||||
return (val == 1132 || val == 1170 || val == 1227);
|
||||
}
|
||||
static const u32 cpuVoltDvfsPattern[] = { 1227, 1000, 100, 1000, 0 };
|
||||
static const u32 cpuVoltDvfsOffsets[] = { 5, 6, 7, 8, 9 };
|
||||
static_assert(sizeof(cpuVoltDvfsPattern) == sizeof(cpuVoltDvfsOffsets), "Invalid cpuVoltDvfsPattern");
|
||||
static_assert(sizeof(cpuVoltDvfsPattern) == 0x14, "invalid cpuVoltDvfsPattern size");
|
||||
|
||||
static const u32 cpuVoltageThermalPattern[] = { 950, 1132, 0, 950, 1227, 0, 825, 1227, 15000, 825, 1170, 60000, 825, 1132, 80000 };
|
||||
static_assert(sizeof(cpuVoltageThermalPattern) == 0x3c, "invalid cpuVoltageThermalPattern size");
|
||||
@@ -223,13 +217,19 @@ namespace ams::ldr::hoc::pcv {
|
||||
constexpr u32 GpuClkPllMax = 921'600'000;
|
||||
constexpr u32 GpuVminOfficial = 810;
|
||||
|
||||
constexpr u16 CpuMinVolts[] = { 950, 850, 825, 810 };
|
||||
|
||||
inline bool CpuMaxVoltPatternFn(u32* ptr32) {
|
||||
u32 val = *ptr32;
|
||||
return (val == 1132 || val == 1170 || val == 1227);
|
||||
}
|
||||
|
||||
static const u32 gpuVoltDvfsPattern[] = { 810, 1150, 1000, 100, 1000, 10, };
|
||||
static_assert(sizeof(gpuVoltDvfsPattern) == (sizeof(u32) * 6), "Invalid gpuVoltDvfsPattern");
|
||||
|
||||
static const u32 gpuVoltThermalPattern[] = { 950, 1132, 0, 810, 1132, 15000, 810, 1132, 30000, 810, 1132, 50000, 810, 1132, 70000, 810, 1132, 105000 };
|
||||
static_assert(sizeof(gpuVoltThermalPattern) == 0x48, "invalid gpuVoltageThermalPattern size");
|
||||
|
||||
|
||||
/* GPU Max Clock asm Pattern:
|
||||
*
|
||||
* MOV W11, #0x1000 MOV (wide immediate) 0x1000 0xB (11)
|
||||
@@ -284,6 +284,7 @@ namespace ams::ldr::hoc::pcv {
|
||||
};
|
||||
|
||||
constexpr u32 MemVoltHOS = 1125'000;
|
||||
constexpr u32 EmcClkMinFreq = 40800; /* 40.8 MHz table only exists on erista. */
|
||||
constexpr u32 EmcClkPllmLimit = 1866'000'000;
|
||||
|
||||
constexpr u32 MTC_TABLE_REV = 7;
|
||||
|
||||
@@ -16,153 +16,154 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
namespace ams::ldr::hoc::pcv {
|
||||
namespace ams::ldr::hoc::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_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_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 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 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)) 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)) 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)) 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);
|
||||
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 CpuClkOSLimit = 1785'000;
|
||||
|
||||
constexpr u32 EmcClkOSLimit = 1600'000;
|
||||
constexpr u32 EmcClkOSLimit = 1600'000;
|
||||
|
||||
#define R_SKIP() R_SUCCEED()
|
||||
#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;
|
||||
// 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>>;
|
||||
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;
|
||||
};
|
||||
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;
|
||||
}
|
||||
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>>;
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,23 +25,23 @@
|
||||
namespace ams::ldr::hoc::pcv::erista {
|
||||
|
||||
Result CpuVoltDvfs(u32 *ptr) {
|
||||
if (MatchesPattern(ptr, cpuVoltDvfsPattern, cpuVoltDvfsOffsets)) {
|
||||
if (C.eristaCpuVmin) {
|
||||
PATCH_OFFSET(ptr, C.eristaCpuVmin);
|
||||
}
|
||||
|
||||
if (C.eristaCpuUV) {
|
||||
PATCH_OFFSET(ptr - 2, C.eristaCpuVmin);
|
||||
}
|
||||
|
||||
if (C.eristaCpuMaxVolt) {
|
||||
PATCH_OFFSET(ptr + 5, C.eristaCpuMaxVolt);
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
if (std::memcmp(ptr + 5, cpuVoltDvfsPattern, sizeof(cpuVoltDvfsPattern))) {
|
||||
R_THROW(ldr::ResultInvalidCpuMinVolt());
|
||||
}
|
||||
|
||||
R_THROW(ldr::ResultInvalidCpuMinVolt());
|
||||
if (C.eristaCpuVmin) {
|
||||
PATCH_OFFSET(ptr, C.eristaCpuVmin);
|
||||
}
|
||||
|
||||
if (C.eristaCpuUV) {
|
||||
PATCH_OFFSET(ptr - 2, C.eristaCpuVmin);
|
||||
}
|
||||
|
||||
if (C.eristaCpuMaxVolt) {
|
||||
PATCH_OFFSET(ptr + 5, C.eristaCpuMaxVolt);
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result CpuVoltThermals(u32 *ptr) {
|
||||
@@ -52,7 +52,7 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
if (C.eristaCpuVmin) {
|
||||
PATCH_OFFSET( ptr, C.eristaCpuVmin);
|
||||
PATCH_OFFSET(ptr + 3, C.eristaCpuVmin);
|
||||
PATCH_OFFSET(ptr + 9, C.eristaCpuVmin);
|
||||
PATCH_OFFSET(ptr + 6, C.eristaCpuVmin);
|
||||
}
|
||||
|
||||
if (C.eristaCpuMaxVolt) {
|
||||
@@ -67,12 +67,12 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
|
||||
Result CpuVoltDfll(u32* ptr) {
|
||||
cvb_cpu_dfll_data *entry = reinterpret_cast<cvb_cpu_dfll_data *>(ptr);
|
||||
R_UNLESS(entry->tune0_low == 0xFFEAD0FF, ldr::ResultInvalidCpuVoltDfllEntry());
|
||||
R_UNLESS(entry->tune0_high == 0x0, ldr::ResultInvalidCpuVoltDfllEntry());
|
||||
R_UNLESS(entry->tune1_low == 0x0, ldr::ResultInvalidCpuVoltDfllEntry());
|
||||
R_UNLESS(entry->tune1_high == 0x0, ldr::ResultInvalidCpuVoltDfllEntry());
|
||||
R_UNLESS(entry->tune0_low == 0xFFEAD0FF, ldr::ResultInvalidCpuVoltDfllEntry());
|
||||
R_UNLESS(entry->tune0_high == 0x0, ldr::ResultInvalidCpuVoltDfllEntry());
|
||||
R_UNLESS(entry->tune1_low == 0x0, ldr::ResultInvalidCpuVoltDfllEntry());
|
||||
R_UNLESS(entry->tune1_high == 0x0, ldr::ResultInvalidCpuVoltDfllEntry());
|
||||
|
||||
if( !C.eristaCpuUV) {
|
||||
if (!C.eristaCpuUV) {
|
||||
R_SKIP();
|
||||
}
|
||||
|
||||
@@ -104,20 +104,19 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
}
|
||||
|
||||
Result GpuVoltDVFS(u32 *ptr) {
|
||||
u32 result = std::memcmp(ptr, gpuVoltDvfsPattern, sizeof(gpuVoltDvfsPattern));
|
||||
|
||||
if (result)
|
||||
if (std::memcmp(ptr, gpuVoltDvfsPattern, sizeof(gpuVoltDvfsPattern))) {
|
||||
R_THROW(ldr::ResultInvalidGpuDvfs());
|
||||
}
|
||||
|
||||
if (C.eristaGpuVmin)
|
||||
if (C.eristaGpuVmin) {
|
||||
PATCH_OFFSET(ptr, C.eristaGpuVmin);
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result GpuVoltThermals(u32 *ptr) {
|
||||
u32 result = std::memcmp(ptr - 3, gpuVoltThermalPattern, sizeof(gpuVoltThermalPattern));
|
||||
if (result) {
|
||||
if (std::memcmp(ptr - 3, gpuVoltThermalPattern, sizeof(gpuVoltThermalPattern))) {
|
||||
R_THROW(ldr::ResultInvalidGpuDvfs());
|
||||
}
|
||||
|
||||
@@ -355,44 +354,54 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
table->min_volt = std::min(static_cast<u32>(1050), 900 + C.emcDvbShift * 25);
|
||||
}
|
||||
|
||||
/* Probably more intuitive to point to 40800 rather than 1600000, but oh well. */
|
||||
Result MemFreqMtcTable(u32 *ptr) {
|
||||
if (GET_MAX_OF_ARR(maxEmcClocks) <= EmcClkOSLimit) {
|
||||
R_SKIP();
|
||||
}
|
||||
|
||||
u32 khz_list[] = {1600000, 1331200, 1065600, 800000, 665600, 408000, 204000, 102000, 68000, 40800};
|
||||
std::sort(maxEmcClocks, maxEmcClocks + std::size(maxEmcClocks), std::greater<>());
|
||||
u32 khz_list_size = sizeof(khz_list) / sizeof(u32);
|
||||
u32 khz_list[] = { 40800, 68000, 102000, 204000, 408000, 665600, 800000, 1065600, 1331200, 1600000 };
|
||||
std::sort(maxEmcClocks, maxEmcClocks + std::size(maxEmcClocks));
|
||||
u32 khz_list_size = std::size(khz_list);
|
||||
|
||||
// Generate list for mtc table pointers
|
||||
EristaMtcTable *table_list[khz_list_size];
|
||||
for (u32 i = 0; i < khz_list_size; i++) {
|
||||
u32 mtcIndex = khz_list_size - 1 - 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());
|
||||
table_list[mtcIndex] = reinterpret_cast<EristaMtcTable *>(table);
|
||||
R_UNLESS(table_list[mtcIndex]->rate_khz == khz_list[mtcIndex], ldr::ResultInvalidMtcTable());
|
||||
R_UNLESS(table_list[mtcIndex]->rev == MTC_TABLE_REV, ldr::ResultInvalidMtcTable());
|
||||
}
|
||||
|
||||
u32 additionalFreqs = 0;
|
||||
for (u32 i = 0; i < std::size(maxEmcClocks); ++i) {
|
||||
if (maxEmcClocks[i] > EmcClkOSLimit) {
|
||||
++additionalFreqs;
|
||||
/* If we oc ram at all, tables are always shifted by at least 1. */
|
||||
u32 tableShifts = 1;
|
||||
for (u32 i = 0; i < std::size(maxEmcClocks) - 1; ++i) {
|
||||
/* Duplicated mtc tables may cause pcv to not select frequencies properly, causing issues. */
|
||||
if (maxEmcClocks[i] != maxEmcClocks[i + 1] && maxEmcClocks[i] > EmcClkOSLimit) {
|
||||
++tableShifts;
|
||||
} else {
|
||||
break;
|
||||
maxEmcClocks[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Make room for new mtc table, discarding useless 40.8, 68000 and 102000 MHz table
|
||||
// 40800 overwritten by 204000, ..., 1331200 overwritten by 1600000, leaving table_list[0], table_list[1] and table_list[2] not overwritten
|
||||
for (u32 i = khz_list_size - 1; i > additionalFreqs - 1; --i) {
|
||||
std::memcpy(static_cast<void *>(table_list[i]), static_cast<void *>(table_list[i - additionalFreqs]), sizeof(EristaMtcTable));
|
||||
/* Erista has extra, useless mtc tables, such as 40.8 Mhz, overwrite them to make room for oc freqs. */
|
||||
/* More than 3 tables can be overwritten, but 3 is plenty. */
|
||||
std::memmove(table_list[0], table_list[tableShifts], sizeof(EristaMtcTable) * (khz_list_size - tableShifts));
|
||||
|
||||
/* Since we're not scaling r/w latency properly on Erista, we first overwrite the tables with the 1600 MHz table before scaling it. */
|
||||
for (u32 i = 0; i < tableShifts; ++i) {
|
||||
std::memcpy(table_list[khz_list_size - i - 1], table_list[khz_list_size - tableShifts - 1], sizeof(EristaMtcTable));
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < additionalFreqs; ++i) {
|
||||
/* Since we're not scaling latency timings properly, copy over the 1600Mhz table to get the closest timings. */
|
||||
std::memcpy(table_list[i], table_list[additionalFreqs], sizeof(EristaMtcTable));
|
||||
table_list[i]->rate_khz = maxEmcClocks[i];
|
||||
MemMtcTableAutoAdjust(table_list[i]);
|
||||
for (u32 i = tableShifts, j = 0; i > 0 && j < std::size(maxEmcClocks); ++j) {
|
||||
if (!maxEmcClocks[j]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
table_list[khz_list_size - i]->rate_khz = maxEmcClocks[j];
|
||||
MemMtcTableAutoAdjust(table_list[khz_list_size - i]);
|
||||
--i;
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
@@ -407,20 +416,6 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
Result CpuVoltRange(u32* ptr) {
|
||||
u32 min_volt_got = *(ptr - 1);
|
||||
for (const auto& mv : CpuMinVolts) {
|
||||
if (min_volt_got != mv)
|
||||
continue;
|
||||
|
||||
if (!C.eristaCpuMaxVolt)
|
||||
R_SKIP();
|
||||
|
||||
PATCH_OFFSET(ptr, C.eristaCpuMaxVolt);
|
||||
R_SUCCEED();
|
||||
}
|
||||
R_THROW(ldr::ResultInvalidCpuMinVolt());
|
||||
}
|
||||
|
||||
Result GpuFreqPllMax(u32 *ptr) {
|
||||
clk_pll_param *entry = reinterpret_cast<clk_pll_param *>(ptr);
|
||||
@@ -436,31 +431,31 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result GpuFreqPllLimit(u32 *ptr) {
|
||||
u32 prev_freq = *(ptr - 1);
|
||||
// patch out 1305MHz limit on erista, don't use this!
|
||||
// Result GpuFreqPllLimit(u32 *ptr) {
|
||||
// u32 prev_freq = *(ptr - 1);
|
||||
|
||||
if (prev_freq != 128000 && prev_freq != 1300000 && prev_freq != 76800) {
|
||||
R_THROW(ldr::ResultInvalidGpuPllEntry());
|
||||
}
|
||||
// if (prev_freq != 128000 && prev_freq != 1300000 && prev_freq != 76800) {
|
||||
// R_THROW(ldr::ResultInvalidGpuPllEntry());
|
||||
// }
|
||||
|
||||
PATCH_OFFSET(ptr, 3600000);
|
||||
// PATCH_OFFSET(ptr, 3600000);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
// R_SUCCEED();
|
||||
// }
|
||||
|
||||
void Patch(uintptr_t mapped_nso, size_t nso_size) {
|
||||
PatcherEntry<u32> patches[] = {
|
||||
{"CPU Freq Table", CpuFreqCvbTable<false>, 1, nullptr, static_cast<u32>(GetDvfsTableLastEntry(CpuCvbTableDefault)->freq)},
|
||||
{"CPU Volt DVFS", &CpuVoltDvfs, 1, nullptr, 825},
|
||||
{"CPU Volt Limit", &CpuVoltRange, 0, &CpuMaxVoltPatternFn},
|
||||
{"CPU Volt Thermals", &CpuVoltThermals, 1, nullptr, 825},
|
||||
{"CPU Volt Dfll", &CpuVoltDfll, 1, nullptr, 0xFFEAD0FF},
|
||||
{"GPU Volt DVFS", &GpuVoltDVFS, 1, nullptr, 810},
|
||||
{"GPU Volt Thermals", &GpuVoltThermals, 1, nullptr, 810},
|
||||
{"CPU Volt DVFS", &CpuVoltDvfs, 1, nullptr, CpuVminOfficial},
|
||||
{"CPU Volt Thermals", &CpuVoltThermals, 1, nullptr, CpuVminOfficial},
|
||||
{"CPU Volt Dfll", &CpuVoltDfll, 1, nullptr, 0xFFEAD0FF},
|
||||
{"GPU Volt DVFS", &GpuVoltDVFS, 1, nullptr, GpuVminOfficial},
|
||||
{"GPU Volt Thermals", &GpuVoltThermals, 1, nullptr, GpuVminOfficial},
|
||||
{"GPU Freq Table", GpuFreqCvbTable<false>, 1, nullptr, static_cast<u32>(GetDvfsTableLastEntry(GpuCvbTableDefault)->freq)},
|
||||
{"GPU Freq Asm", &GpuFreqMaxAsm, 2, &GpuMaxClockPatternFn},
|
||||
{"GPU PLL Max", &GpuFreqPllMax, 1, nullptr, GpuClkPllMax},
|
||||
{"GPU PLL Limit", &GpuFreqPllLimit, 4, nullptr, GpuClkPllLimit},
|
||||
// {"GPU PLL Limit", &GpuFreqPllLimit, 4, nullptr, GpuClkPllLimit},
|
||||
{"MEM Freq Mtc", &MemFreqMtcTable, 0, nullptr, EmcClkOSLimit},
|
||||
{"MEM Freq Max", &MemFreqMax, 0, nullptr, EmcClkOSLimit},
|
||||
{"MEM Freq PLLM", &MemFreqPllmLimit, 2, nullptr, EmcClkPllmLimit},
|
||||
|
||||
@@ -652,9 +652,8 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
|
||||
// Copy unmodified 1600000 table to tmp
|
||||
std::memcpy(reinterpret_cast<void *>(tmp), reinterpret_cast<void *>(table_max), sizeof(MarikoMtcTable));
|
||||
// Adjust max freq mtc timing parameters with reference to 1331200 table
|
||||
/* TODO: Implement mariko */
|
||||
|
||||
|
||||
/* Adjust timings properly according to the new frequency. */
|
||||
MemMtcTableAutoAdjust(table_max);
|
||||
|
||||
MemMtcPllmbDivisor(table_max);
|
||||
@@ -683,6 +682,7 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
|
||||
#define DVB_VOLT(zero, one, two) std::min(zero + voltAdd, 1050), std::min(one + voltAdd, 1025), std::min(two + voltAdd, 1000),
|
||||
|
||||
/* TODO: More fine tuned values? */
|
||||
if (C.marikoEmcMaxClock < 1862400) {
|
||||
std::memcpy(new_start, default_end, sizeof(emc_dvb_dvfs_table_t));
|
||||
} else if (C.marikoEmcMaxClock < 2131200) {
|
||||
|
||||
@@ -20,116 +20,111 @@
|
||||
|
||||
namespace ams::ldr::hoc::ptm {
|
||||
|
||||
Result CpuPtmBoost(perf_conf_entry* entry) {
|
||||
Result CpuPtmBoost(perf_conf_entry* entry) {
|
||||
#ifdef ATMOSPHERE_IS_STRATOSPHERE
|
||||
bool isMariko = (spl::GetSocType() == spl::SocType_Mariko);
|
||||
#else
|
||||
bool isMariko = true;
|
||||
#endif
|
||||
|
||||
#ifdef ATMOSPHERE_IS_STRATOSPHERE
|
||||
bool isMariko = (spl::GetSocType() == spl::SocType_Mariko);
|
||||
#else
|
||||
bool isMariko = true;
|
||||
#endif
|
||||
if (!C.eristaCpuBoostClock || !C.marikoCpuBoostClock) {
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
u32 cpuPtmBoostNew = isMariko ? C.marikoCpuBoostClock * 1000 : C.eristaCpuBoostClock * 1000;
|
||||
|
||||
PATCH_OFFSET(&(entry->cpu_freq_1), cpuPtmBoostNew);
|
||||
PATCH_OFFSET(&(entry->cpu_freq_2), cpuPtmBoostNew);
|
||||
|
||||
if (!C.eristaCpuBoostClock || !C.marikoCpuBoostClock)
|
||||
R_SUCCEED();
|
||||
|
||||
u32 cpuPtmBoostNew = isMariko ? C.marikoCpuBoostClock * 1000 : C.eristaCpuBoostClock * 1000;
|
||||
|
||||
PATCH_OFFSET(&(entry->cpu_freq_1), cpuPtmBoostNew);
|
||||
PATCH_OFFSET(&(entry->cpu_freq_2), cpuPtmBoostNew);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result MemPtm(perf_conf_entry* entry) {
|
||||
PATCH_OFFSET(&(entry->emc_freq_1), memPtmLimit);
|
||||
PATCH_OFFSET(&(entry->emc_freq_2), memPtmLimit);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
bool PtmEntryIsValid(perf_conf_entry* entry) {
|
||||
return (entry->cpu_freq_1 == entry->cpu_freq_2 &&
|
||||
entry->gpu_freq_1 == entry->gpu_freq_2 &&
|
||||
entry->emc_freq_1 == entry->emc_freq_2);
|
||||
}
|
||||
|
||||
bool PtmTablePatternFn(u32* ptr) {
|
||||
perf_conf_entry* entry = reinterpret_cast<perf_conf_entry *>(ptr);
|
||||
if (!PtmEntryIsValid(entry))
|
||||
return false;
|
||||
|
||||
return entry->cpu_freq_1 == cpuPtmDefault;
|
||||
}
|
||||
|
||||
void Patch(uintptr_t mapped_nso, size_t nso_size) {
|
||||
perf_conf_entry* confTable = nullptr;
|
||||
for (uintptr_t ptr = mapped_nso;
|
||||
ptr <= mapped_nso + nso_size - sizeof(perf_conf_entry) * entryCnt;
|
||||
ptr += sizeof(u32))
|
||||
{
|
||||
u32* ptr32 = reinterpret_cast<u32 *>(ptr);
|
||||
if (PtmTablePatternFn(ptr32)) {
|
||||
confTable = reinterpret_cast<perf_conf_entry *>(ptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!confTable) {
|
||||
CRASH("confTable not found!");
|
||||
Result MemPtm(perf_conf_entry* entry) {
|
||||
PATCH_OFFSET(&(entry->emc_freq_1), memPtmLimit);
|
||||
PATCH_OFFSET(&(entry->emc_freq_2), memPtmLimit);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
PatcherEntry<perf_conf_entry> cpuPtmBoostPatch = { "CPU Ptm Boost", &CpuPtmBoost, 2, };
|
||||
PatcherEntry<perf_conf_entry> memPtmPatch = { "MEM Ptm", &MemPtm, 16, };
|
||||
|
||||
#ifdef ATMOSPHERE_IS_STRATOSPHERE
|
||||
bool isMariko = (spl::GetSocType() == spl::SocType_Mariko);
|
||||
#else
|
||||
bool isMariko = true;
|
||||
#endif
|
||||
|
||||
|
||||
for (u32 i = 0; i < entryCnt; i++) {
|
||||
perf_conf_entry* entry = confTable + i;
|
||||
bool PtmEntryIsValid(perf_conf_entry* entry) {
|
||||
return (entry->cpu_freq_1 == entry->cpu_freq_2 && entry->gpu_freq_1 == entry->gpu_freq_2 && entry->emc_freq_1 == entry->emc_freq_2);
|
||||
}
|
||||
|
||||
bool PtmTablePatternFn(u32* ptr) {
|
||||
perf_conf_entry* entry = reinterpret_cast<perf_conf_entry *>(ptr);
|
||||
if (!PtmEntryIsValid(entry)) {
|
||||
LOGGING("@%p", &entry);
|
||||
CRASH("Invalid ptm confTable entry");
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (entry->cpu_freq_1) {
|
||||
case cpuPtmBoost:
|
||||
cpuPtmBoostPatch.Apply(entry);
|
||||
return entry->cpu_freq_1 == cpuPtmDefault;
|
||||
}
|
||||
|
||||
void Patch(uintptr_t mapped_nso, size_t nso_size) {
|
||||
perf_conf_entry* confTable = nullptr;
|
||||
for (uintptr_t ptr = mapped_nso; ptr <= mapped_nso + nso_size - sizeof(perf_conf_entry) * entryCnt; ptr += sizeof(u32)) {
|
||||
u32* ptr32 = reinterpret_cast<u32 *>(ptr);
|
||||
if (PtmTablePatternFn(ptr32)) {
|
||||
confTable = reinterpret_cast<perf_conf_entry *>(ptr);
|
||||
break;
|
||||
case cpuPtmDefault:
|
||||
case cpuPtmDevOC:
|
||||
break;
|
||||
default:
|
||||
LOGGING("%u (0x%08x) @%p", entry->cpu_freq_1, entry->conf_id, &(entry->cpu_freq_1));
|
||||
CRASH("Unknown CPU Freq");
|
||||
}
|
||||
}
|
||||
|
||||
switch (entry->emc_freq_1) {
|
||||
case memPtmLimit:
|
||||
case memPtmAlt:
|
||||
case memPtmClamp:
|
||||
if (isMariko) {
|
||||
memPtmPatch.Apply(entry);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOGGING("%u (0x%08x) @%p", entry->emc_freq_1, entry->conf_id, &(entry->emc_freq_2));
|
||||
CRASH("Unknown MEM Freq");
|
||||
if (!confTable) {
|
||||
CRASH("confTable not found!");
|
||||
}
|
||||
|
||||
PatcherEntry<perf_conf_entry> cpuPtmBoostPatch = { "CPU Ptm Boost", &CpuPtmBoost, 2, };
|
||||
PatcherEntry<perf_conf_entry> memPtmPatch = { "MEM Ptm", &MemPtm, 16, };
|
||||
|
||||
#ifdef ATMOSPHERE_IS_STRATOSPHERE
|
||||
bool isMariko = (spl::GetSocType() == spl::SocType_Mariko);
|
||||
#else
|
||||
bool isMariko = true;
|
||||
#endif
|
||||
|
||||
for (u32 i = 0; i < entryCnt; i++) {
|
||||
perf_conf_entry *entry = confTable + i;
|
||||
|
||||
if (!PtmEntryIsValid(entry)) {
|
||||
LOGGING("@%p", &entry);
|
||||
CRASH("Invalid ptm confTable entry");
|
||||
}
|
||||
|
||||
switch (entry->cpu_freq_1) {
|
||||
case cpuPtmBoost:
|
||||
cpuPtmBoostPatch.Apply(entry);
|
||||
break;
|
||||
case cpuPtmDefault:
|
||||
case cpuPtmDevOC:
|
||||
break;
|
||||
default:
|
||||
LOGGING("%u (0x%08x) @%p", entry->cpu_freq_1, entry->conf_id, &(entry->cpu_freq_1));
|
||||
CRASH("Unknown CPU Freq");
|
||||
}
|
||||
|
||||
switch (entry->emc_freq_1) {
|
||||
case memPtmLimit:
|
||||
case memPtmAlt:
|
||||
case memPtmClamp:
|
||||
if (isMariko) {
|
||||
memPtmPatch.Apply(entry);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOGGING("%u (0x%08x) @%p", entry->emc_freq_1, entry->conf_id, &(entry->emc_freq_2));
|
||||
CRASH("Unknown MEM Freq");
|
||||
}
|
||||
}
|
||||
|
||||
LOGGING("%s Count: %zu", cpuPtmBoostPatch.description, cpuPtmBoostPatch.patched_count);
|
||||
if (R_FAILED(cpuPtmBoostPatch.CheckResult()))
|
||||
CRASH(cpuPtmBoostPatch.description);
|
||||
|
||||
if (isMariko) {
|
||||
LOGGING("%s Count: %zu", memPtmPatch.description, memPtmPatch.patched_count);
|
||||
if (R_FAILED(memPtmPatch.CheckResult()))
|
||||
CRASH(memPtmPatch.description);
|
||||
}
|
||||
}
|
||||
|
||||
LOGGING("%s Count: %zu", cpuPtmBoostPatch.description, cpuPtmBoostPatch.patched_count);
|
||||
if (R_FAILED(cpuPtmBoostPatch.CheckResult()))
|
||||
CRASH(cpuPtmBoostPatch.description);
|
||||
|
||||
if (isMariko) {
|
||||
LOGGING("%s Count: %zu", memPtmPatch.description, memPtmPatch.patched_count);
|
||||
if (R_FAILED(memPtmPatch.CheckResult()))
|
||||
CRASH(memPtmPatch.description);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -22,26 +22,26 @@
|
||||
|
||||
namespace ams::ldr::hoc::ptm {
|
||||
|
||||
typedef struct {
|
||||
u32 conf_id;
|
||||
u32 cpu_freq_1; // min-max pair?
|
||||
u32 cpu_freq_2;
|
||||
u32 gpu_freq_1;
|
||||
u32 gpu_freq_2;
|
||||
u32 emc_freq_1;
|
||||
u32 emc_freq_2;
|
||||
u32 padding;
|
||||
} perf_conf_entry;
|
||||
typedef struct {
|
||||
u32 conf_id;
|
||||
u32 cpu_freq_1; // min-max pair?
|
||||
u32 cpu_freq_2;
|
||||
u32 gpu_freq_1;
|
||||
u32 gpu_freq_2;
|
||||
u32 emc_freq_1;
|
||||
u32 emc_freq_2;
|
||||
u32 padding;
|
||||
} perf_conf_entry;
|
||||
|
||||
constexpr u32 entryCnt = 16;
|
||||
constexpr u32 cpuPtmDefault = 1020'000'000;
|
||||
constexpr u32 cpuPtmDevOC = 1224'000'000;
|
||||
constexpr u32 cpuPtmBoost = 1785'000'000;
|
||||
constexpr u32 entryCnt = 16;
|
||||
constexpr u32 cpuPtmDefault = 1020'000'000;
|
||||
constexpr u32 cpuPtmDevOC = 1224'000'000;
|
||||
constexpr u32 cpuPtmBoost = 1785'000'000;
|
||||
|
||||
constexpr u32 memPtmLimit = 1600'000'000;
|
||||
constexpr u32 memPtmAlt = 1331'200'000;
|
||||
constexpr u32 memPtmClamp = 1065'600'000;
|
||||
constexpr u32 memPtmLimit = 1600'000'000;
|
||||
constexpr u32 memPtmAlt = 1331'200'000;
|
||||
constexpr u32 memPtmClamp = 1065'600'000;
|
||||
|
||||
void Patch(uintptr_t mapped_nso, size_t nso_size);
|
||||
void Patch(uintptr_t mapped_nso, size_t nso_size);
|
||||
|
||||
}
|
||||
|
||||
@@ -685,7 +685,7 @@ void Misc2(void*) {
|
||||
|
||||
void Misc3(void*) {
|
||||
const bool isUsingEOS = usingEOS();
|
||||
|
||||
|
||||
// Initialize voltage reading if needed
|
||||
bool canReadVoltages = false;
|
||||
if (!isUsingEOS && realVoltsPolling) {
|
||||
@@ -694,7 +694,7 @@ void Misc3(void*) {
|
||||
realVoltsPolling = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
do {
|
||||
mutexLock(&mutex_Misc);
|
||||
|
||||
@@ -706,7 +706,7 @@ void Misc3(void*) {
|
||||
if (R_SUCCEEDED(tcCheck)) {
|
||||
tcGetSkinTemperatureMilliC(&skin_temperaturemiliC);
|
||||
}
|
||||
|
||||
|
||||
// Fan
|
||||
if (R_SUCCEEDED(pwmCheck)) {
|
||||
double temp = 0;
|
||||
@@ -720,16 +720,21 @@ void Misc3(void*) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// GPU Load
|
||||
if (R_SUCCEEDED(nvCheck)) {
|
||||
nvIoctl(fd, NVGPU_GPU_IOCTL_PMU_GET_GPU_LOAD, &GPU_Load_u);
|
||||
}
|
||||
|
||||
|
||||
SysClkContext sysclkCTX;
|
||||
if (R_SUCCEEDED(sysclkIpcGetCurrentContext(&sysclkCTX))) {
|
||||
partLoad[SysClkPartLoad_EMC] = sysclkCTX.partLoad[SysClkPartLoad_EMC];
|
||||
}
|
||||
|
||||
mutexUnlock(&mutex_Misc);
|
||||
|
||||
|
||||
} while (!leventWait(&threadexit, 1'000'000'000)); // 1 second timeout
|
||||
|
||||
|
||||
// Cleanup voltage reading if initialized
|
||||
if (canReadVoltages) {
|
||||
rgltrExit();
|
||||
@@ -2453,4 +2458,4 @@ ALWAYS_INLINE void GetConfigSettings(ResolutionSettings* settings) {
|
||||
convertToUpper(key);
|
||||
settings->disableScreenshots = (key != "FALSE");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
248
Source/sys-clk/common/include/SaltyNX.h
Normal file
248
Source/sys-clk/common/include/SaltyNX.h
Normal file
@@ -0,0 +1,248 @@
|
||||
/*
|
||||
* Copyright (c) MasaGratoR
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "ipc.h"
|
||||
|
||||
Handle saltysd_orig;
|
||||
|
||||
Result SaltySD_Connect() {
|
||||
for (int i = 0; i < 200; i++) {
|
||||
if (!svcConnectToNamedPort(&saltysd_orig, "SaltySD"))
|
||||
return 0;
|
||||
svcSleepThread(1000*1000);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
Result SaltySD_Term()
|
||||
{
|
||||
Result ret;
|
||||
IpcCommand c;
|
||||
|
||||
ipcInitialize(&c);
|
||||
ipcSendPid(&c);
|
||||
|
||||
struct input
|
||||
{
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 zero;
|
||||
u64 reserved[2];
|
||||
} *raw;
|
||||
|
||||
raw = (input*)ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 0;
|
||||
raw->zero = 0;
|
||||
|
||||
ret = ipcDispatch(saltysd_orig);
|
||||
|
||||
if (R_SUCCEEDED(ret))
|
||||
{
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct output {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = (output*)r.Raw;
|
||||
|
||||
ret = resp->result;
|
||||
}
|
||||
|
||||
// Session terminated works too.
|
||||
svcCloseHandle(saltysd_orig);
|
||||
if (ret == 0xf601) return 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Result SaltySD_CheckIfSharedMemoryAvailable(ptrdiff_t *offset, u64 size)
|
||||
{
|
||||
Result ret = 0;
|
||||
|
||||
// Send a command
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcSendPid(&c);
|
||||
|
||||
struct input {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 size;
|
||||
u32 reserved[2];
|
||||
} *raw;
|
||||
|
||||
raw = (input*)ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 6;
|
||||
raw->size = size;
|
||||
|
||||
ret = ipcDispatch(saltysd_orig);
|
||||
|
||||
if (R_SUCCEEDED(ret)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct output {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u64 offset;
|
||||
} *resp = (output*)r.Raw;
|
||||
|
||||
ret = resp->result;
|
||||
|
||||
if (!ret)
|
||||
{
|
||||
*offset = resp->offset;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Result SaltySD_GetSharedMemoryHandle(Handle *retrieve)
|
||||
{
|
||||
Result ret = 0;
|
||||
|
||||
// Send a command
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcSendPid(&c);
|
||||
|
||||
struct input {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u32 reserved[4];
|
||||
} *raw;
|
||||
|
||||
raw = (input*)ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 7;
|
||||
|
||||
ret = ipcDispatch(saltysd_orig);
|
||||
|
||||
if (R_SUCCEEDED(ret)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct output {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u64 reserved[2];
|
||||
} *resp = (output*)r.Raw;
|
||||
|
||||
ret = resp->result;
|
||||
|
||||
if (!ret)
|
||||
{
|
||||
*retrieve = r.Handles[0];
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Result SaltySD_GetDisplayRefreshRate(uint8_t* refreshRate)
|
||||
{
|
||||
Result ret = 0;
|
||||
|
||||
// Send a command
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcSendPid(&c);
|
||||
|
||||
struct input {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 zero;
|
||||
u64 reserved;
|
||||
} *raw;
|
||||
|
||||
raw = (input*)ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 10;
|
||||
raw->zero = 0;
|
||||
|
||||
ret = ipcDispatch(saltysd_orig);
|
||||
|
||||
if (R_SUCCEEDED(ret)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct output {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u64 refreshRate;
|
||||
u64 reserved;
|
||||
} *resp = (output*)r.Raw;
|
||||
|
||||
ret = resp->result;
|
||||
|
||||
if (!ret)
|
||||
{
|
||||
*refreshRate = (uint8_t)(resp->refreshRate);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Result SaltySD_SetDisplayRefreshRate(uint8_t refreshRate)
|
||||
{
|
||||
Result ret = 0;
|
||||
|
||||
// Send a command
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcSendPid(&c);
|
||||
|
||||
struct input {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 refreshRate;
|
||||
u64 reserved;
|
||||
} *raw;
|
||||
|
||||
raw = (input*)ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 11;
|
||||
raw->refreshRate = refreshRate;
|
||||
|
||||
ret = ipcDispatch(saltysd_orig);
|
||||
|
||||
if (R_SUCCEEDED(ret)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct output {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u64 reserved[2];
|
||||
} *resp = (output*)r.Raw;
|
||||
|
||||
ret = resp->result;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -19,7 +19,6 @@
|
||||
#include <switch.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
// Battery charging flags
|
||||
typedef enum {
|
||||
BatteryFlag_NoHub = BIT(0), // Hub is disconnected
|
||||
BatteryFlag_Rail = BIT(8), // At least one Joy-con is charging from rail
|
||||
@@ -27,7 +26,6 @@ typedef enum {
|
||||
BatteryFlag_ACC = BIT(16) // Accessory
|
||||
} BatteryChargeFlags;
|
||||
|
||||
// Power Delivery Controller State (BM92T series)
|
||||
typedef enum {
|
||||
PDState_NewPDO = 1, // Received new Power Data Object
|
||||
PDState_NoPD = 2, // No Power Delivery source is detected
|
||||
@@ -47,14 +45,11 @@ typedef enum {
|
||||
ChargerType_Apple_1000mA = 8,
|
||||
ChargerType_Apple_2000mA = 9
|
||||
} BatteryChargerType;
|
||||
|
||||
// Power role (USB Power Delivery)
|
||||
typedef enum {
|
||||
PowerRole_Sink = 1, // Device is receiving power
|
||||
PowerRole_Source = 2 // Device is providing power
|
||||
} BatteryPowerRole;
|
||||
|
||||
// Complete battery charge information structure
|
||||
typedef struct {
|
||||
int32_t InputCurrentLimit; // Input (Sink) current limit in mA
|
||||
int32_t VBUSCurrentLimit; // Output (Source/VBUS/OTG) current limit in mA
|
||||
@@ -64,7 +59,7 @@ typedef struct {
|
||||
int32_t unk_x14; // Unknown field (possibly flags)
|
||||
BatteryPDControllerState PDControllerState; // PD Controller State
|
||||
int32_t BatteryTemperature; // Battery temperature in milli-Celsius
|
||||
int32_t RawBatteryCharge; // Battery charge in per cent-mille (100% = 100000)
|
||||
int32_t RawBatteryCharge; // Battery charge in percentmille
|
||||
int32_t VoltageAvg; // Average voltage in mV
|
||||
int32_t BatteryAge; // Battery health (capacity full/design) in pcm
|
||||
BatteryPowerRole PowerRole; // Current power role
|
||||
@@ -74,36 +69,27 @@ typedef struct {
|
||||
BatteryChargeFlags Flags; // Various status flags
|
||||
} BatteryChargeInfo;
|
||||
|
||||
// Helper macro to check if battery charging is enabled
|
||||
#define IS_BATTERY_CHARGING_ENABLED(info) (((info)->unk_x14 >> 8) & 1)
|
||||
|
||||
// Initialize the battery info driver
|
||||
Result batteryInfoInitialize(void);
|
||||
|
||||
// Cleanup the battery info driver
|
||||
void batteryInfoExit(void);
|
||||
|
||||
// Get complete battery charge information
|
||||
Result batteryInfoGetChargeInfo(BatteryChargeInfo *out);
|
||||
|
||||
// Get battery charge percentage (0-100)
|
||||
Result batteryInfoGetChargePercentage(u32 *out);
|
||||
|
||||
// Check if enough power is being supplied
|
||||
Result batteryInfoIsEnoughPowerSupplied(bool *out);
|
||||
|
||||
// Battery charge control functions
|
||||
Result batteryInfoEnableCharging(void);
|
||||
Result batteryInfoDisableCharging(void);
|
||||
Result batteryInfoEnableFastCharging(void);
|
||||
Result batteryInfoDisableFastCharging(void);
|
||||
|
||||
// Helper functions to get human-readable strings
|
||||
const char* batteryInfoGetChargerTypeString(BatteryChargerType type);
|
||||
const char* batteryInfoGetPowerRoleString(BatteryPowerRole role);
|
||||
const char* batteryInfoGetPDStateString(BatteryPDControllerState state);
|
||||
|
||||
// Convenience functions for common values
|
||||
static inline int batteryInfoGetTemperatureMiliCelsius(BatteryChargeInfo *info) {
|
||||
return info->BatteryTemperature;
|
||||
}
|
||||
@@ -120,7 +106,6 @@ static inline bool batteryInfoIsCharging(BatteryChargeInfo *info) {
|
||||
return IS_BATTERY_CHARGING_ENABLED(info);
|
||||
}
|
||||
|
||||
// String lookup tables
|
||||
static const char* s_chargerTypeStrings[] = {
|
||||
"None",
|
||||
"Power Delivery",
|
||||
@@ -187,7 +172,6 @@ static Result psmDisableFastBatteryCharging_internal(void) {
|
||||
return serviceDispatch(&g_psmService, 11);
|
||||
}
|
||||
|
||||
// Public API implementations
|
||||
Result batteryInfoInitialize(void) {
|
||||
if (g_batteryInfoInitialized)
|
||||
return 0;
|
||||
|
||||
@@ -15,17 +15,12 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DISPLAY_REFRESH_RATE_H
|
||||
#define DISPLAY_REFRESH_RATE_H
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Display mode structures
|
||||
typedef struct {
|
||||
uint16_t hFrontPorch;
|
||||
uint8_t hSyncWidth;
|
||||
@@ -52,7 +47,6 @@ typedef struct {
|
||||
uint8_t max;
|
||||
} MinMaxRefreshRate;
|
||||
|
||||
// Display mode information
|
||||
typedef struct {
|
||||
uint32_t unk0;
|
||||
uint32_t hActive;
|
||||
@@ -76,7 +70,6 @@ typedef struct {
|
||||
uint32_t num_modes;
|
||||
} NvdcModeDB2;
|
||||
|
||||
// PLL structures
|
||||
typedef struct {
|
||||
unsigned int PLLD_DIVM: 8;
|
||||
unsigned int reserved_1: 3;
|
||||
@@ -109,7 +102,6 @@ typedef struct {
|
||||
unsigned int reserved: 2;
|
||||
} PLLD_MISC;
|
||||
|
||||
// Configuration structure
|
||||
typedef struct {
|
||||
uint64_t clkVirtAddr;
|
||||
uint64_t dsiVirtAddr;
|
||||
@@ -132,9 +124,3 @@ uint8_t DisplayRefresh_GetDockedHighestAllowed(void);
|
||||
void DisplayRefresh_CorrectOledGamma(uint32_t refresh_rate);
|
||||
void DisplayRefresh_SetAllowedDockedRatesIPC(uint32_t refreshRates, bool is720p);
|
||||
void DisplayRefresh_Shutdown(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // DISPLAY_REFRESH_RATE_H
|
||||
756
Source/sys-clk/common/include/ipc.h
Normal file
756
Source/sys-clk/common/include/ipc.h
Normal file
@@ -0,0 +1,756 @@
|
||||
/**
|
||||
* @file ipc.h
|
||||
* @brief Inter-process communication handling
|
||||
* @author plutoo
|
||||
* @copyright libnx Authors (ISC License)
|
||||
*/
|
||||
#pragma once
|
||||
#include <switch.h>
|
||||
|
||||
/// IPC input header magic
|
||||
#define SFCI_MAGIC 0x49434653
|
||||
/// IPC output header magic
|
||||
#define SFCO_MAGIC 0x4f434653
|
||||
|
||||
/// IPC invalid object ID
|
||||
#define IPC_INVALID_OBJECT_ID UINT32_MAX
|
||||
|
||||
///@name IPC request building
|
||||
///@{
|
||||
|
||||
/// IPC command (request) structure.
|
||||
#define IPC_MAX_BUFFERS 8
|
||||
#define IPC_MAX_OBJECTS 8
|
||||
|
||||
typedef enum {
|
||||
BufferType_Normal=0, ///< Regular buffer.
|
||||
BufferType_Type1=1, ///< Allows ProcessMemory and shared TransferMemory.
|
||||
BufferType_Invalid=2,
|
||||
BufferType_Type3=3 ///< Same as Type1 except remote process is not allowed to use device-mapping.
|
||||
} BufferType;
|
||||
|
||||
typedef enum {
|
||||
BufferDirection_Send=0,
|
||||
BufferDirection_Recv=1,
|
||||
BufferDirection_Exch=2,
|
||||
} BufferDirection;
|
||||
|
||||
typedef enum {
|
||||
IpcCommandType_Invalid = 0,
|
||||
IpcCommandType_LegacyRequest = 1,
|
||||
IpcCommandType_Close = 2,
|
||||
IpcCommandType_LegacyControl = 3,
|
||||
IpcCommandType_Request = 4,
|
||||
IpcCommandType_Control = 5,
|
||||
IpcCommandType_RequestWithContext = 6,
|
||||
IpcCommandType_ControlWithContext = 7,
|
||||
} IpcCommandType;
|
||||
|
||||
typedef enum {
|
||||
DomainMessageType_Invalid = 0,
|
||||
DomainMessageType_SendMessage = 1,
|
||||
DomainMessageType_Close = 2,
|
||||
} DomainMessageType;
|
||||
|
||||
/// IPC domain message header.
|
||||
typedef struct {
|
||||
u8 Type;
|
||||
u8 NumObjectIds;
|
||||
u16 Length;
|
||||
u32 ThisObjectId;
|
||||
u32 Pad[2];
|
||||
} DomainMessageHeader;
|
||||
|
||||
/// IPC domain response header.
|
||||
typedef struct {
|
||||
u32 NumObjectIds;
|
||||
u32 Pad[3];
|
||||
} DomainResponseHeader;
|
||||
|
||||
|
||||
typedef struct {
|
||||
size_t NumSend; // A
|
||||
size_t NumRecv; // B
|
||||
size_t NumExch; // W
|
||||
const void* Buffers[IPC_MAX_BUFFERS];
|
||||
size_t BufferSizes[IPC_MAX_BUFFERS];
|
||||
BufferType BufferTypes[IPC_MAX_BUFFERS];
|
||||
|
||||
size_t NumStaticIn; // X
|
||||
size_t NumStaticOut; // C
|
||||
const void* Statics[IPC_MAX_BUFFERS];
|
||||
size_t StaticSizes[IPC_MAX_BUFFERS];
|
||||
u8 StaticIndices[IPC_MAX_BUFFERS];
|
||||
|
||||
bool SendPid;
|
||||
size_t NumHandlesCopy;
|
||||
size_t NumHandlesMove;
|
||||
Handle Handles[IPC_MAX_OBJECTS];
|
||||
|
||||
size_t NumObjectIds;
|
||||
u32 ObjectIds[IPC_MAX_OBJECTS];
|
||||
} IpcCommand;
|
||||
|
||||
/**
|
||||
* @brief Initializes an IPC command structure.
|
||||
* @param cmd IPC command structure.
|
||||
*/
|
||||
static inline void ipcInitialize(IpcCommand* cmd) {
|
||||
*cmd = (IpcCommand){};
|
||||
}
|
||||
|
||||
/// IPC buffer descriptor.
|
||||
typedef struct {
|
||||
u32 Size; ///< Size of the buffer.
|
||||
u32 Addr; ///< Lower 32-bits of the address of the buffer
|
||||
u32 Packed; ///< Packed data (including higher bits of the address)
|
||||
} IpcBufferDescriptor;
|
||||
|
||||
/// IPC static send-buffer descriptor.
|
||||
typedef struct {
|
||||
u32 Packed; ///< Packed data (including higher bits of the address)
|
||||
u32 Addr; ///< Lower 32-bits of the address
|
||||
} IpcStaticSendDescriptor;
|
||||
|
||||
/// IPC static receive-buffer descriptor.
|
||||
typedef struct {
|
||||
u32 Addr; ///< Lower 32-bits of the address of the buffer
|
||||
u32 Packed; ///< Packed data (including higher bits of the address)
|
||||
} IpcStaticRecvDescriptor;
|
||||
|
||||
/**
|
||||
* @brief Adds a buffer to an IPC command structure.
|
||||
* @param cmd IPC command structure.
|
||||
* @param buffer Address of the buffer.
|
||||
* @param size Size of the buffer.
|
||||
* @param type Buffer type.
|
||||
*/
|
||||
static inline void ipcAddSendBuffer(IpcCommand* cmd, const void* buffer, size_t size, BufferType type) {
|
||||
size_t off = cmd->NumSend;
|
||||
cmd->Buffers[off] = buffer;
|
||||
cmd->BufferSizes[off] = size;
|
||||
cmd->BufferTypes[off] = type;
|
||||
cmd->NumSend++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds a receive-buffer to an IPC command structure.
|
||||
* @param cmd IPC command structure.
|
||||
* @param buffer Address of the buffer.
|
||||
* @param size Size of the buffer.
|
||||
* @param type Buffer type.
|
||||
*/
|
||||
static inline void ipcAddRecvBuffer(IpcCommand* cmd, void* buffer, size_t size, BufferType type) {
|
||||
size_t off = cmd->NumSend + cmd->NumRecv;
|
||||
cmd->Buffers[off] = buffer;
|
||||
cmd->BufferSizes[off] = size;
|
||||
cmd->BufferTypes[off] = type;
|
||||
cmd->NumRecv++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds an exchange-buffer to an IPC command structure.
|
||||
* @param cmd IPC command structure.
|
||||
* @param buffer Address of the buffer.
|
||||
* @param size Size of the buffer.
|
||||
* @param type Buffer type.
|
||||
*/
|
||||
static inline void ipcAddExchBuffer(IpcCommand* cmd, void* buffer, size_t size, BufferType type) {
|
||||
size_t off = cmd->NumSend + cmd->NumRecv + cmd->NumExch;
|
||||
cmd->Buffers[off] = buffer;
|
||||
cmd->BufferSizes[off] = size;
|
||||
cmd->BufferTypes[off] = type;
|
||||
cmd->NumExch++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds a static-buffer to an IPC command structure.
|
||||
* @param cmd IPC command structure.
|
||||
* @param buffer Address of the buffer.
|
||||
* @param size Size of the buffer.
|
||||
* @param index Index of buffer.
|
||||
*/
|
||||
static inline void ipcAddSendStatic(IpcCommand* cmd, const void* buffer, size_t size, u8 index) {
|
||||
size_t off = cmd->NumStaticIn;
|
||||
cmd->Statics[off] = buffer;
|
||||
cmd->StaticSizes[off] = size;
|
||||
cmd->StaticIndices[off] = index;
|
||||
cmd->NumStaticIn++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds a static-receive-buffer to an IPC command structure.
|
||||
* @param cmd IPC command structure.
|
||||
* @param buffer Address of the buffer.
|
||||
* @param size Size of the buffer.
|
||||
* @param index Index of buffer.
|
||||
*/
|
||||
static inline void ipcAddRecvStatic(IpcCommand* cmd, void* buffer, size_t size, u8 index) {
|
||||
size_t off = cmd->NumStaticIn + cmd->NumStaticOut;
|
||||
cmd->Statics[off] = buffer;
|
||||
cmd->StaticSizes[off] = size;
|
||||
cmd->StaticIndices[off] = index;
|
||||
cmd->NumStaticOut++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds a smart-buffer (buffer + static-buffer pair) to an IPC command structure.
|
||||
* @param cmd IPC command structure.
|
||||
* @param pointer_buffer_size Pointer buffer size.
|
||||
* @param buffer Address of the buffer.
|
||||
* @param size Size of the buffer.
|
||||
* @param index Index of buffer.
|
||||
*/
|
||||
static inline void ipcAddSendSmart(IpcCommand* cmd, size_t pointer_buffer_size, const void* buffer, size_t size, u8 index) {
|
||||
if (pointer_buffer_size != 0 && size <= pointer_buffer_size) {
|
||||
ipcAddSendBuffer(cmd, NULL, 0, BufferType_Normal);
|
||||
ipcAddSendStatic(cmd, buffer, size, index);
|
||||
} else {
|
||||
ipcAddSendBuffer(cmd, buffer, size, BufferType_Normal);
|
||||
ipcAddSendStatic(cmd, NULL, 0, index);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds a smart-receive-buffer (buffer + static-receive-buffer pair) to an IPC command structure.
|
||||
* @param cmd IPC command structure.
|
||||
* @param pointer_buffer_size Pointer buffer size.
|
||||
* @param buffer Address of the buffer.
|
||||
* @param size Size of the buffer.
|
||||
* @param index Index of buffer.
|
||||
*/
|
||||
static inline void ipcAddRecvSmart(IpcCommand* cmd, size_t pointer_buffer_size, void* buffer, size_t size, u8 index) {
|
||||
if (pointer_buffer_size != 0 && size <= pointer_buffer_size) {
|
||||
ipcAddRecvBuffer(cmd, NULL, 0, BufferType_Normal);
|
||||
ipcAddRecvStatic(cmd, buffer, size, index);
|
||||
} else {
|
||||
ipcAddRecvBuffer(cmd, buffer, size, BufferType_Normal);
|
||||
ipcAddRecvStatic(cmd, NULL, 0, index);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tags an IPC command structure to send the PID.
|
||||
* @param cmd IPC command structure.
|
||||
*/
|
||||
static inline void ipcSendPid(IpcCommand* cmd) {
|
||||
cmd->SendPid = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds a copy-handle to be sent through an IPC command structure.
|
||||
* @param cmd IPC command structure.
|
||||
* @param h Handle to send.
|
||||
* @remark The receiving process gets a copy of the handle.
|
||||
*/
|
||||
static inline void ipcSendHandleCopy(IpcCommand* cmd, Handle h) {
|
||||
cmd->Handles[cmd->NumHandlesCopy++] = h;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds a move-handle to be sent through an IPC command structure.
|
||||
* @param cmd IPC command structure.
|
||||
* @param h Handle to send.
|
||||
* @remark The sending process loses ownership of the handle, which is transferred to the receiving process.
|
||||
*/
|
||||
static inline void ipcSendHandleMove(IpcCommand* cmd, Handle h) {
|
||||
cmd->Handles[cmd->NumHandlesCopy + cmd->NumHandlesMove++] = h;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Prepares the header of an IPC command structure.
|
||||
* @param cmd IPC command structure.
|
||||
* @param sizeof_raw Size in bytes of the raw data structure to embed inside the IPC request
|
||||
* @return Pointer to the raw embedded data structure in the request, ready to be filled out.
|
||||
*/
|
||||
static inline void* ipcPrepareHeader(IpcCommand* cmd, size_t sizeof_raw) {
|
||||
u32* buf = (u32*)armGetTls();
|
||||
size_t i;
|
||||
*buf++ = IpcCommandType_Request | (cmd->NumStaticIn << 16) | (cmd->NumSend << 20) | (cmd->NumRecv << 24) | (cmd->NumExch << 28);
|
||||
|
||||
u32* fill_in_size_later = buf;
|
||||
|
||||
if (cmd->NumStaticOut > 0) {
|
||||
*buf = (cmd->NumStaticOut + 2) << 10;
|
||||
}
|
||||
else {
|
||||
*buf = 0;
|
||||
}
|
||||
|
||||
if (cmd->SendPid || cmd->NumHandlesCopy > 0 || cmd->NumHandlesMove > 0) {
|
||||
*buf++ |= 0x80000000;
|
||||
*buf++ = (!!cmd->SendPid) | (cmd->NumHandlesCopy << 1) | (cmd->NumHandlesMove << 5);
|
||||
|
||||
if (cmd->SendPid)
|
||||
buf += 2;
|
||||
|
||||
for (i=0; i<(cmd->NumHandlesCopy + cmd->NumHandlesMove); i++)
|
||||
*buf++ = cmd->Handles[i];
|
||||
}
|
||||
else {
|
||||
buf++;
|
||||
}
|
||||
|
||||
for (i=0; i<cmd->NumStaticIn; i++, buf+=2) {
|
||||
IpcStaticSendDescriptor* desc = (IpcStaticSendDescriptor*) buf;
|
||||
|
||||
uintptr_t ptr = (uintptr_t) cmd->Statics[i];
|
||||
desc->Addr = ptr;
|
||||
desc->Packed = cmd->StaticIndices[i] | (cmd->StaticSizes[i] << 16) |
|
||||
(((ptr >> 32) & 15) << 12) | (((ptr >> 36) & 15) << 6);
|
||||
}
|
||||
|
||||
for (i=0; i<(cmd->NumSend + cmd->NumRecv + cmd->NumExch); i++, buf+=3) {
|
||||
IpcBufferDescriptor* desc = (IpcBufferDescriptor*) buf;
|
||||
desc->Size = cmd->BufferSizes[i];
|
||||
|
||||
uintptr_t ptr = (uintptr_t) cmd->Buffers[i];
|
||||
desc->Addr = ptr;
|
||||
desc->Packed = cmd->BufferTypes[i] |
|
||||
(((ptr >> 32) & 15) << 28) | ((ptr >> 36) << 2);
|
||||
}
|
||||
|
||||
u32 padding = ((16 - (((uintptr_t) buf) & 15)) & 15) / 4;
|
||||
u32* raw = (u32*) (buf + padding);
|
||||
|
||||
size_t raw_size = (sizeof_raw/4) + 4;
|
||||
buf += raw_size;
|
||||
|
||||
u16* buf_u16 = (u16*) buf;
|
||||
|
||||
for (i=0; i<cmd->NumStaticOut; i++) {
|
||||
size_t off = cmd->NumStaticIn + i;
|
||||
size_t sz = (uintptr_t) cmd->StaticSizes[off];
|
||||
|
||||
buf_u16[i] = (sz > 0xFFFF) ? 0 : sz;
|
||||
}
|
||||
|
||||
size_t u16s_size = ((2*cmd->NumStaticOut) + 3)/4;
|
||||
buf += u16s_size;
|
||||
raw_size += u16s_size;
|
||||
|
||||
*fill_in_size_later |= raw_size;
|
||||
|
||||
for (i=0; i<cmd->NumStaticOut; i++, buf+=2) {
|
||||
IpcStaticRecvDescriptor* desc = (IpcStaticRecvDescriptor*) buf;
|
||||
size_t off = cmd->NumStaticIn + i;
|
||||
|
||||
uintptr_t ptr = (uintptr_t) cmd->Statics[off];
|
||||
desc->Addr = ptr;
|
||||
desc->Packed = (ptr >> 32) | (cmd->StaticSizes[off] << 16);
|
||||
}
|
||||
|
||||
return (void*) raw;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Dispatches an IPC request.
|
||||
* @param session IPC session handle.
|
||||
* @return Result code.
|
||||
*/
|
||||
static inline Result ipcDispatch(Handle session) {
|
||||
return svcSendSyncRequest(session);
|
||||
}
|
||||
|
||||
///@}
|
||||
|
||||
///@name IPC response parsing
|
||||
///@{
|
||||
|
||||
/// IPC parsed command (response) structure.
|
||||
typedef struct {
|
||||
IpcCommandType CommandType; ///< Type of the command
|
||||
|
||||
bool HasPid; ///< true if the 'Pid' field is filled out.
|
||||
u64 Pid; ///< PID included in the response (only if HasPid is true)
|
||||
|
||||
size_t NumHandles; ///< Number of handles copied.
|
||||
Handle Handles[IPC_MAX_OBJECTS]; ///< Handles.
|
||||
bool WasHandleCopied[IPC_MAX_OBJECTS]; ///< true if the handle was moved, false if it was copied.
|
||||
|
||||
bool IsDomainRequest; ///< true if the the message is a Domain message.
|
||||
DomainMessageType InMessageType; ///< Type of the domain message.
|
||||
u32 InMessageLength; ///< Size of rawdata (for domain messages).
|
||||
u32 InThisObjectId; ///< Object ID to call the command on (for domain messages).
|
||||
size_t InNumObjectIds; ///< Number of object IDs (for domain messages).
|
||||
u32 InObjectIds[IPC_MAX_OBJECTS]; ///< Object IDs (for domain messages).
|
||||
|
||||
bool IsDomainResponse; ///< true if the the message is a Domain response.
|
||||
size_t OutNumObjectIds; ///< Number of object IDs (for domain responses).
|
||||
u32 OutObjectIds[IPC_MAX_OBJECTS]; ///< Object IDs (for domain responses).
|
||||
|
||||
size_t NumBuffers; ///< Number of buffers in the response.
|
||||
void* Buffers[IPC_MAX_BUFFERS]; ///< Pointers to the buffers.
|
||||
size_t BufferSizes[IPC_MAX_BUFFERS]; ///< Sizes of the buffers.
|
||||
BufferType BufferTypes[IPC_MAX_BUFFERS]; ///< Types of the buffers.
|
||||
BufferDirection BufferDirections[IPC_MAX_BUFFERS]; ///< Direction of each buffer.
|
||||
|
||||
size_t NumStatics; ///< Number of statics in the response.
|
||||
void* Statics[IPC_MAX_BUFFERS]; ///< Pointers to the statics.
|
||||
size_t StaticSizes[IPC_MAX_BUFFERS]; ///< Sizes of the statics.
|
||||
u8 StaticIndices[IPC_MAX_BUFFERS]; ///< Indices of the statics.
|
||||
|
||||
size_t NumStaticsOut; ///< Number of output statics available in the response.
|
||||
|
||||
void* Raw; ///< Pointer to the raw embedded data structure in the response.
|
||||
void* RawWithoutPadding; ///< Pointer to the raw embedded data structure, without padding.
|
||||
size_t RawSize; ///< Size of the raw embedded data.
|
||||
} IpcParsedCommand;
|
||||
|
||||
/**
|
||||
* @brief Parse an IPC command response into an IPC parsed command structure.
|
||||
* @param r IPC parsed command structure to fill in.
|
||||
* @return Result code.
|
||||
*/
|
||||
static inline Result ipcParse(IpcParsedCommand* r) {
|
||||
u32* buf = (u32*)armGetTls();
|
||||
u32 ctrl0 = *buf++;
|
||||
u32 ctrl1 = *buf++;
|
||||
size_t i;
|
||||
|
||||
r->IsDomainRequest = false;
|
||||
r->IsDomainResponse = false;
|
||||
|
||||
r->CommandType = (IpcCommandType) (ctrl0 & 0xffff);
|
||||
r->HasPid = false;
|
||||
r->RawSize = (ctrl1 & 0x1ff) * 4;
|
||||
r->NumHandles = 0;
|
||||
|
||||
r->NumStaticsOut = (ctrl1 >> 10) & 15;
|
||||
if (r->NumStaticsOut >> 1) r->NumStaticsOut--; // Value 2 -> Single descriptor
|
||||
if (r->NumStaticsOut >> 1) r->NumStaticsOut--; // Value 3+ -> (Value - 2) descriptors
|
||||
|
||||
if (ctrl1 & 0x80000000) {
|
||||
u32 ctrl2 = *buf++;
|
||||
|
||||
if (ctrl2 & 1) {
|
||||
r->HasPid = true;
|
||||
r->Pid = *buf++;
|
||||
r->Pid |= ((u64)(*buf++)) << 32;
|
||||
}
|
||||
|
||||
size_t num_handles_copy = ((ctrl2 >> 1) & 15);
|
||||
size_t num_handles_move = ((ctrl2 >> 5) & 15);
|
||||
|
||||
size_t num_handles = num_handles_copy + num_handles_move;
|
||||
u32* buf_after_handles = buf + num_handles;
|
||||
|
||||
if (num_handles > IPC_MAX_OBJECTS)
|
||||
num_handles = IPC_MAX_OBJECTS;
|
||||
|
||||
for (i=0; i<num_handles; i++)
|
||||
{
|
||||
r->Handles[i] = *(buf+i);
|
||||
r->WasHandleCopied[i] = (i < num_handles_copy);
|
||||
}
|
||||
|
||||
r->NumHandles = num_handles;
|
||||
buf = buf_after_handles;
|
||||
}
|
||||
|
||||
size_t num_statics = (ctrl0 >> 16) & 15;
|
||||
u32* buf_after_statics = buf + num_statics*2;
|
||||
|
||||
if (num_statics > IPC_MAX_BUFFERS)
|
||||
num_statics = IPC_MAX_BUFFERS;
|
||||
|
||||
for (i=0; i<num_statics; i++, buf+=2) {
|
||||
IpcStaticSendDescriptor* desc = (IpcStaticSendDescriptor*) buf;
|
||||
u64 packed = (u64) desc->Packed;
|
||||
|
||||
r->Statics[i] = (void*) (desc->Addr | (((packed >> 12) & 15) << 32) | (((packed >> 6) & 15) << 36));
|
||||
r->StaticSizes[i] = packed >> 16;
|
||||
r->StaticIndices[i] = packed & 63;
|
||||
}
|
||||
|
||||
r->NumStatics = num_statics;
|
||||
buf = buf_after_statics;
|
||||
|
||||
size_t num_bufs_send = (ctrl0 >> 20) & 15;
|
||||
size_t num_bufs_recv = (ctrl0 >> 24) & 15;
|
||||
size_t num_bufs_exch = (ctrl0 >> 28) & 15;
|
||||
|
||||
size_t num_bufs = num_bufs_send + num_bufs_recv + num_bufs_exch;
|
||||
r->Raw = (void*)(((uintptr_t)(buf + num_bufs*3) + 15) &~ 15);
|
||||
r->RawWithoutPadding = (void*)((uintptr_t)(buf + num_bufs*3));
|
||||
|
||||
if (num_bufs > IPC_MAX_BUFFERS)
|
||||
num_bufs = IPC_MAX_BUFFERS;
|
||||
|
||||
for (i=0; i<num_bufs; i++, buf+=3) {
|
||||
IpcBufferDescriptor* desc = (IpcBufferDescriptor*) buf;
|
||||
u64 packed = (u64) desc->Packed;
|
||||
|
||||
r->Buffers[i] = (void*) (desc->Addr | ((packed >> 28) << 32) | (((packed >> 2) & 15) << 36));
|
||||
r->BufferSizes[i] = desc->Size;
|
||||
r->BufferTypes[i] = (BufferType) (packed & 3);
|
||||
|
||||
if (i < num_bufs_send)
|
||||
r->BufferDirections[i] = BufferDirection_Send;
|
||||
else if (i < (num_bufs_send + num_bufs_recv))
|
||||
r->BufferDirections[i] = BufferDirection_Recv;
|
||||
else
|
||||
r->BufferDirections[i] = BufferDirection_Exch;
|
||||
}
|
||||
|
||||
r->NumBuffers = num_bufs;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Queries the size of an IPC pointer buffer.
|
||||
* @param session IPC session handle.
|
||||
* @param size Output variable in which to store the size.
|
||||
* @return Result code.
|
||||
*/
|
||||
static inline Result ipcQueryPointerBufferSize(Handle session, size_t *size) {
|
||||
u32* buf = (u32*)armGetTls();
|
||||
|
||||
buf[0] = IpcCommandType_Control;
|
||||
buf[1] = 8;
|
||||
buf[2] = 0;
|
||||
buf[3] = 0;
|
||||
buf[4] = SFCI_MAGIC;
|
||||
buf[5] = 0;
|
||||
buf[6] = 3;
|
||||
buf[7] = 0;
|
||||
|
||||
Result rc = ipcDispatch(session);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct ipcQueryPointerBufferSizeResponse {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u32 size;
|
||||
} *raw = (struct ipcQueryPointerBufferSizeResponse*)r.Raw;
|
||||
|
||||
rc = raw->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
*size = raw->size & 0xffff;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Closes the IPC session with proper clean up.
|
||||
* @param session IPC session handle.
|
||||
* @return Result code.
|
||||
*/
|
||||
static inline Result ipcCloseSession(Handle session) {
|
||||
u32* buf = (u32*)armGetTls();
|
||||
buf[0] = IpcCommandType_Close;
|
||||
buf[1] = 0;
|
||||
return ipcDispatch(session);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clones an IPC session.
|
||||
* @param session IPC session handle.
|
||||
* @param unk Unknown.
|
||||
* @param new_session_out Output cloned IPC session handle.
|
||||
* @return Result code.
|
||||
*/
|
||||
static inline Result ipcCloneSession(Handle session, u32 unk, Handle* new_session_out) {
|
||||
u32* buf = (u32*)armGetTls();
|
||||
|
||||
buf[0] = IpcCommandType_Control;
|
||||
buf[1] = 9;
|
||||
buf[2] = 0;
|
||||
buf[3] = 0;
|
||||
buf[4] = SFCI_MAGIC;
|
||||
buf[5] = 0;
|
||||
buf[6] = 4;
|
||||
buf[7] = 0;
|
||||
buf[8] = unk;
|
||||
|
||||
Result rc = ipcDispatch(session);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct ipcCloneSessionResponse {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *raw = (struct ipcCloneSessionResponse*)r.Raw;
|
||||
|
||||
rc = raw->result;
|
||||
|
||||
if (R_SUCCEEDED(rc) && new_session_out) {
|
||||
*new_session_out = r.Handles[0];
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
///@}
|
||||
|
||||
///@name IPC domain handling
|
||||
///@{
|
||||
|
||||
/**
|
||||
* @brief Converts an IPC session handle into a domain.
|
||||
* @param session IPC session handle.
|
||||
* @param object_id_out Output variable in which to store the object ID.
|
||||
* @return Result code.
|
||||
*/
|
||||
static inline Result ipcConvertSessionToDomain(Handle session, u32* object_id_out) {
|
||||
u32* buf = (u32*)armGetTls();
|
||||
|
||||
buf[0] = IpcCommandType_Control;
|
||||
buf[1] = 8;
|
||||
buf[4] = SFCI_MAGIC;
|
||||
buf[5] = 0;
|
||||
buf[6] = 0;
|
||||
buf[7] = 0;
|
||||
|
||||
Result rc = ipcDispatch(session);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct ipcConvertSessionToDomainResponse {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u32 object_id;
|
||||
} *raw = (struct ipcConvertSessionToDomainResponse*)r.Raw;
|
||||
|
||||
rc = raw->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
*object_id_out = raw->object_id;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds an object ID to be sent through an IPC domain command structure.
|
||||
* @param cmd IPC domain command structure.
|
||||
* @param object_id Object ID to send.
|
||||
*/
|
||||
static inline void ipcSendObjectId(IpcCommand* cmd, u32 object_id) {
|
||||
cmd->ObjectIds[cmd->NumObjectIds++] = object_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Prepares the header of an IPC command structure (domain version).
|
||||
* @param cmd IPC command structure.
|
||||
* @param sizeof_raw Size in bytes of the raw data structure to embed inside the IPC request
|
||||
* @param object_id Domain object ID.
|
||||
* @return Pointer to the raw embedded data structure in the request, ready to be filled out.
|
||||
*/
|
||||
static inline void* ipcPrepareHeaderForDomain(IpcCommand* cmd, size_t sizeof_raw, u32 object_id) {
|
||||
void* raw = ipcPrepareHeader(cmd, sizeof_raw + sizeof(DomainMessageHeader) + cmd->NumObjectIds*sizeof(u32));
|
||||
DomainMessageHeader* hdr = (DomainMessageHeader*) raw;
|
||||
u32 *object_ids = (u32*)(((uintptr_t) raw) + sizeof(DomainMessageHeader) + sizeof_raw);
|
||||
|
||||
hdr->Type = DomainMessageType_SendMessage;
|
||||
hdr->NumObjectIds = (u8)cmd->NumObjectIds;
|
||||
hdr->Length = sizeof_raw;
|
||||
hdr->ThisObjectId = object_id;
|
||||
hdr->Pad[0] = hdr->Pad[1] = 0;
|
||||
|
||||
for(size_t i = 0; i < cmd->NumObjectIds; i++)
|
||||
object_ids[i] = cmd->ObjectIds[i];
|
||||
return (void*)(((uintptr_t) raw) + sizeof(DomainMessageHeader));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Parse an IPC command request into an IPC parsed command structure (domain version).
|
||||
* @param r IPC parsed command structure to fill in.
|
||||
* @return Result code.
|
||||
*/
|
||||
static inline Result ipcParseDomainRequest(IpcParsedCommand* r) {
|
||||
Result rc = ipcParse(r);
|
||||
DomainMessageHeader *hdr;
|
||||
u32 *object_ids;
|
||||
if(R_FAILED(rc))
|
||||
return rc;
|
||||
|
||||
hdr = (DomainMessageHeader*) r->Raw;
|
||||
object_ids = (u32*)(((uintptr_t) hdr) + sizeof(DomainMessageHeader) + hdr->Length);
|
||||
r->Raw = (void*)(((uintptr_t) r->Raw) + sizeof(DomainMessageHeader));
|
||||
|
||||
r->IsDomainRequest = true;
|
||||
r->InMessageType = (DomainMessageType)(hdr->Type);
|
||||
switch (r->InMessageType) {
|
||||
case DomainMessageType_SendMessage:
|
||||
case DomainMessageType_Close:
|
||||
break;
|
||||
default:
|
||||
return MAKERESULT(Module_Libnx, LibnxError_DomainMessageUnknownType);
|
||||
}
|
||||
|
||||
r->InThisObjectId = hdr->ThisObjectId;
|
||||
r->InNumObjectIds = hdr->NumObjectIds > 8 ? 8 : hdr->NumObjectIds;
|
||||
if ((uintptr_t)object_ids + sizeof(u32) * r->InNumObjectIds - (uintptr_t)armGetTls() >= 0x100) {
|
||||
return MAKERESULT(Module_Libnx, LibnxError_DomainMessageTooManyObjectIds);
|
||||
}
|
||||
for(size_t i = 0; i < r->InNumObjectIds; i++)
|
||||
r->InObjectIds[i] = object_ids[i];
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Parse an IPC command response into an IPC parsed command structure (domain version).
|
||||
* @param r IPC parsed command structure to fill in.
|
||||
* @param sizeof_raw Size in bytes of the raw data structure.
|
||||
* @return Result code.
|
||||
*/
|
||||
static inline Result ipcParseDomainResponse(IpcParsedCommand* r, size_t sizeof_raw) {
|
||||
Result rc = ipcParse(r);
|
||||
DomainResponseHeader *hdr;
|
||||
u32 *object_ids;
|
||||
if(R_FAILED(rc))
|
||||
return rc;
|
||||
|
||||
hdr = (DomainResponseHeader*) r->Raw;
|
||||
r->Raw = (void*)(((uintptr_t) r->Raw) + sizeof(DomainResponseHeader));
|
||||
object_ids = (u32*)(((uintptr_t) r->Raw) + sizeof_raw);//Official sw doesn't align this.
|
||||
|
||||
r->IsDomainResponse = true;
|
||||
|
||||
r->OutNumObjectIds = hdr->NumObjectIds > 8 ? 8 : hdr->NumObjectIds;
|
||||
if ((uintptr_t)object_ids + sizeof(u32) * r->OutNumObjectIds - (uintptr_t)armGetTls() >= 0x100) {
|
||||
return MAKERESULT(Module_Libnx, LibnxError_DomainMessageTooManyObjectIds);
|
||||
}
|
||||
for(size_t i = 0; i < r->OutNumObjectIds; i++)
|
||||
r->OutObjectIds[i] = object_ids[i];
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Closes a domain object by ID.
|
||||
* @param session IPC session handle.
|
||||
* @param object_id ID of the object to close.
|
||||
* @return Result code.
|
||||
*/
|
||||
static inline Result ipcCloseObjectById(Handle session, u32 object_id) {
|
||||
IpcCommand c;
|
||||
DomainMessageHeader* hdr;
|
||||
|
||||
ipcInitialize(&c);
|
||||
hdr = (DomainMessageHeader*)ipcPrepareHeader(&c, sizeof(DomainMessageHeader));
|
||||
|
||||
hdr->Type = DomainMessageType_Close;
|
||||
hdr->NumObjectIds = 0;
|
||||
hdr->Length = 0;
|
||||
hdr->ThisObjectId = object_id;
|
||||
hdr->Pad[0] = hdr->Pad[1] = 0;
|
||||
|
||||
return ipcDispatch(session); // this command has no associated response
|
||||
}
|
||||
|
||||
///@}
|
||||
@@ -1,6 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ and Horizon OC Contributors
|
||||
*
|
||||
* Copyright (c) Linux 4 Tegra & Linux 4 Switch contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
@@ -522,9 +524,4 @@
|
||||
#define CL_DVFS_I2C_VDD_REG_ADDR_0 0x44
|
||||
#define CL_DVFS_I2C_STS_0 0x48
|
||||
#define CL_DVFS_INTR_STS_0 0x5C
|
||||
#define CL_DVFS_INTR_EN_0 0x60
|
||||
#define DVFS_DFLL_THROTTLE_CTRL_0 0x64
|
||||
#define DVFS_DFLL_THROTTLE_LIGHT_0 0x68
|
||||
#define DVFS_DFLL_THROTTLE_MEDIUM_0 0x6C
|
||||
#define DVFS_DFLL_THROTTLE_HEAVY_0 0x70
|
||||
#define CL_DVFS_I2C_CLK_DIVISOR_REGISTER_0 0x16C
|
||||
|
||||
@@ -34,3 +34,5 @@ void rgltrCloseSession(RgltrSession* session);
|
||||
Result rgltrGetVoltage(RgltrSession* session, u32 *out_volt);
|
||||
Result rgltrGetPowerModuleNumLimit(u32 *out);
|
||||
Result rgltrGetVoltageEnabled(RgltrSession* session, u32 *out);
|
||||
Result rgltrRequestVoltage(RgltrSession* session, u32 microvolt);
|
||||
Result rgltrCancelVoltageRequest(RgltrSession* session);
|
||||
@@ -146,11 +146,21 @@ typedef enum {
|
||||
typedef enum {
|
||||
GovernorState_DoNotOverride = 0,
|
||||
GovernorState_Disabled,
|
||||
GovernorState_Enabled_CpuGpuVrr,
|
||||
GovernorState_Enabled_CpuVrr,
|
||||
GovernorState_Enabled_GpuVrr,
|
||||
GovernorState_Enabled_CpuGpu,
|
||||
GovernorState_Enabled_Cpu,
|
||||
GovernorState_Enabled_Gpu,
|
||||
GovernorState_Enabled_Vrr,
|
||||
GovernorState_EnumMax,
|
||||
} GovernorState;
|
||||
typedef enum {
|
||||
RamDisplayMode_VDD2VDDQ = 0,
|
||||
RamDisplayMode_VDD2Usage,
|
||||
RamDisplayMode_VDDQUsage,
|
||||
RamDisplayMode_EnumMax,
|
||||
} RamDisplayMode;
|
||||
|
||||
#define SYSCLK_ENUM_VALID(n, v) ((v) < n##_EnumMax)
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@ typedef struct
|
||||
u16 iddq[HorizonOCSpeedo_EnumMax];
|
||||
GpuSchedulingMode gpuSchedulingMode;
|
||||
bool isSysDockInstalled;
|
||||
bool isSaltyNXInstalled;
|
||||
u8 maxDisplayFreq;
|
||||
u8 dramID;
|
||||
bool isDram8GB;
|
||||
|
||||
@@ -63,6 +63,10 @@ typedef enum {
|
||||
|
||||
HorizonOCConfigValue_GPUScheduling,
|
||||
HorizonOCConfigValue_GPUSchedulingMethod,
|
||||
|
||||
HorizonOCConfigValue_RAMVoltUsageDisplayMode,
|
||||
HorizonOCConfigValue_CpuGovernorMinimumFreq,
|
||||
|
||||
KipConfigValue_custRev,
|
||||
// KipConfigValue_mtcConf,
|
||||
KipConfigValue_hpMode,
|
||||
@@ -135,38 +139,34 @@ typedef enum {
|
||||
KipConfigValue_g_volt_1459200,
|
||||
KipConfigValue_g_volt_1497600,
|
||||
KipConfigValue_g_volt_1536000,
|
||||
KipConfigValue_g_volt_1574400,
|
||||
KipConfigValue_g_volt_1612800,
|
||||
KipConfigValue_g_volt_1651200,
|
||||
KipConfigValue_g_volt_1689600,
|
||||
KipConfigValue_g_volt_1728000,
|
||||
KipConfigValue_g_volt_1766400,
|
||||
KipConfigValue_g_volt_1804800,
|
||||
|
||||
KipConfigValue_g_volt_e_76800,
|
||||
KipConfigValue_g_volt_e_115200,
|
||||
KipConfigValue_g_volt_e_153600,
|
||||
KipConfigValue_g_volt_e_192000,
|
||||
KipConfigValue_g_volt_e_230400,
|
||||
KipConfigValue_g_volt_e_268800,
|
||||
KipConfigValue_g_volt_e_307200,
|
||||
KipConfigValue_g_volt_e_345600,
|
||||
KipConfigValue_g_volt_e_384000,
|
||||
KipConfigValue_g_volt_e_422400,
|
||||
KipConfigValue_g_volt_e_460800,
|
||||
KipConfigValue_g_volt_e_499200,
|
||||
KipConfigValue_g_volt_e_537600,
|
||||
KipConfigValue_g_volt_e_576000,
|
||||
KipConfigValue_g_volt_e_614400,
|
||||
KipConfigValue_g_volt_e_652800,
|
||||
KipConfigValue_g_volt_e_691200,
|
||||
KipConfigValue_g_volt_e_729600,
|
||||
KipConfigValue_g_volt_e_768000,
|
||||
KipConfigValue_g_volt_e_806400,
|
||||
KipConfigValue_g_volt_e_844800,
|
||||
KipConfigValue_g_volt_e_883200,
|
||||
KipConfigValue_g_volt_e_921600,
|
||||
KipConfigValue_g_volt_e_960000,
|
||||
KipConfigValue_g_volt_e_998400,
|
||||
KipConfigValue_g_volt_e_1036800,
|
||||
KipConfigValue_g_volt_e_1075200,
|
||||
KipConfigValue_g_volt_e_1152000,
|
||||
KipConfigValue_g_volt_e_1228800,
|
||||
KipConfigValue_g_volt_e_1267200,
|
||||
KipConfigValue_g_volt_e_1305600,
|
||||
KipConfigValue_g_volt_e_1344000,
|
||||
KipConfigValue_g_volt_e_1382400,
|
||||
KipConfigValue_g_volt_e_1420800,
|
||||
KipConfigValue_g_volt_e_1459200,
|
||||
KipConfigValue_g_volt_e_1497600,
|
||||
KipConfigValue_g_volt_e_1536000,
|
||||
|
||||
KipConfigValue_t6_tRTW_fine_tune,
|
||||
KipConfigValue_t7_tWTR_fine_tune,
|
||||
@@ -201,7 +201,7 @@ static inline const char* sysclkFormatConfigValue(SysClkConfigValue val, bool pr
|
||||
return pretty ? "Overwrite Boost Mode" : "ow_boost";
|
||||
|
||||
case HocClkConfigValue_EristaMaxCpuClock:
|
||||
return pretty ? "CPU Max Display Clock" : "cpu_max_e";
|
||||
return pretty ? "CPU Max Clock" : "cpu_max_e";
|
||||
|
||||
case HocClkConfigValue_MarikoMaxCpuClock:
|
||||
return pretty ? "CPU Max Display Clock" : "cpu_max_m";
|
||||
@@ -248,6 +248,10 @@ static inline const char* sysclkFormatConfigValue(SysClkConfigValue val, bool pr
|
||||
case HorizonOCConfigValue_EnableExperimentalSettings:
|
||||
return pretty ? "Enable Experimental Settings" : "enable_experimental_settings";
|
||||
|
||||
case HorizonOCConfigValue_RAMVoltUsageDisplayMode:
|
||||
return pretty ? "RAM Voltage / Usage Display Mode" : "ram_volt_usage_display_mode";
|
||||
case HorizonOCConfigValue_CpuGovernorMinimumFreq:
|
||||
return pretty ? "CPU Governor Minimum Frequency" : "cpu_gov_min_freq";
|
||||
// KIP config values
|
||||
case KipConfigValue_custRev:
|
||||
return pretty ? "Custom Revision" : "kip_cust_rev";
|
||||
@@ -370,41 +374,35 @@ static inline const char* sysclkFormatConfigValue(SysClkConfigValue val, bool pr
|
||||
case KipConfigValue_g_volt_1459200: return pretty ? "Mariko GPU Volt 1459 MHz" : "g_volt_1459200";
|
||||
case KipConfigValue_g_volt_1497600: return pretty ? "Mariko GPU Volt 1497 MHz" : "g_volt_1497600";
|
||||
case KipConfigValue_g_volt_1536000: return pretty ? "Mariko GPU Volt 1536 MHz" : "g_volt_1536000";
|
||||
case KipConfigValue_g_volt_1574400: return pretty ? "Mariko GPU Volt 1574 MHz" : "g_volt_1574400";
|
||||
case KipConfigValue_g_volt_1612800: return pretty ? "Mariko GPU Volt 1612 MHz" : "g_volt_1612800";
|
||||
case KipConfigValue_g_volt_1651200: return pretty ? "Mariko GPU Volt 1651 MHz" : "g_volt_1651200";
|
||||
case KipConfigValue_g_volt_1689600: return pretty ? "Mariko GPU Volt 1689 MHz" : "g_volt_1689600";
|
||||
case KipConfigValue_g_volt_1728000: return pretty ? "Mariko GPU Volt 1728 MHz" : "g_volt_1728000";
|
||||
case KipConfigValue_g_volt_1766400: return pretty ? "Mariko GPU Volt 1766 MHz" : "g_volt_1766400";
|
||||
case KipConfigValue_g_volt_1804800: return pretty ? "Mariko GPU Volt 1804 MHz" : "g_volt_1804800";
|
||||
|
||||
|
||||
// Erista GPU voltages (27)
|
||||
case KipConfigValue_g_volt_e_76800: return pretty ? "Erista GPU Volt 76 MHz" : "g_volt_e_76800";
|
||||
case KipConfigValue_g_volt_e_115200: return pretty ? "Erista GPU Volt 115 MHz" : "g_volt_e_115200";
|
||||
case KipConfigValue_g_volt_e_153600: return pretty ? "Erista GPU Volt 153 MHz" : "g_volt_e_153600";
|
||||
case KipConfigValue_g_volt_e_192000: return pretty ? "Erista GPU Volt 192 MHz" : "g_volt_e_192000";
|
||||
case KipConfigValue_g_volt_e_230400: return pretty ? "Erista GPU Volt 230 MHz" : "g_volt_e_230400";
|
||||
case KipConfigValue_g_volt_e_268800: return pretty ? "Erista GPU Volt 268 MHz" : "g_volt_e_268800";
|
||||
case KipConfigValue_g_volt_e_307200: return pretty ? "Erista GPU Volt 307 MHz" : "g_volt_e_307200";
|
||||
case KipConfigValue_g_volt_e_345600: return pretty ? "Erista GPU Volt 345 MHz" : "g_volt_e_345600";
|
||||
case KipConfigValue_g_volt_e_384000: return pretty ? "Erista GPU Volt 384 MHz" : "g_volt_e_384000";
|
||||
case KipConfigValue_g_volt_e_422400: return pretty ? "Erista GPU Volt 422 MHz" : "g_volt_e_422400";
|
||||
case KipConfigValue_g_volt_e_460800: return pretty ? "Erista GPU Volt 460 MHz" : "g_volt_e_460800";
|
||||
case KipConfigValue_g_volt_e_499200: return pretty ? "Erista GPU Volt 499 MHz" : "g_volt_e_499200";
|
||||
case KipConfigValue_g_volt_e_537600: return pretty ? "Erista GPU Volt 537 MHz" : "g_volt_e_537600";
|
||||
case KipConfigValue_g_volt_e_576000: return pretty ? "Erista GPU Volt 576 MHz" : "g_volt_e_576000";
|
||||
case KipConfigValue_g_volt_e_614400: return pretty ? "Erista GPU Volt 614 MHz" : "g_volt_e_614400";
|
||||
case KipConfigValue_g_volt_e_652800: return pretty ? "Erista GPU Volt 652 MHz" : "g_volt_e_652800";
|
||||
case KipConfigValue_g_volt_e_691200: return pretty ? "Erista GPU Volt 691 MHz" : "g_volt_e_691200";
|
||||
case KipConfigValue_g_volt_e_729600: return pretty ? "Erista GPU Volt 729 MHz" : "g_volt_e_729600";
|
||||
case KipConfigValue_g_volt_e_768000: return pretty ? "Erista GPU Volt 768 MHz" : "g_volt_e_768000";
|
||||
case KipConfigValue_g_volt_e_806400: return pretty ? "Erista GPU Volt 806 MHz" : "g_volt_e_806400";
|
||||
case KipConfigValue_g_volt_e_844800: return pretty ? "Erista GPU Volt 844 MHz" : "g_volt_e_844800";
|
||||
case KipConfigValue_g_volt_e_883200: return pretty ? "Erista GPU Volt 883 MHz" : "g_volt_e_883200";
|
||||
case KipConfigValue_g_volt_e_921600: return pretty ? "Erista GPU Volt 921 MHz" : "g_volt_e_921600";
|
||||
case KipConfigValue_g_volt_e_960000: return pretty ? "Erista GPU Volt 960 MHz" : "g_volt_e_960000";
|
||||
case KipConfigValue_g_volt_e_998400: return pretty ? "Erista GPU Volt 998 MHz" : "g_volt_e_998400";
|
||||
case KipConfigValue_g_volt_e_1036800: return pretty ? "Erista GPU Volt 1036 MHz" : "g_volt_e_1036800";
|
||||
case KipConfigValue_g_volt_e_1075200: return pretty ? "Erista GPU Volt 1075 MHz" : "g_volt_e_1075200";
|
||||
case KipConfigValue_g_volt_e_1152000: return pretty ? "Erista GPU Volt 1152 MHz" : "g_volt_e_1152000";
|
||||
case KipConfigValue_g_volt_e_1228800: return pretty ? "Erista GPU Volt 1228 MHz" : "g_volt_e_1228800";
|
||||
case KipConfigValue_g_volt_e_1267200: return pretty ? "Erista GPU Volt 1267 MHz" : "g_volt_e_1267200";
|
||||
case KipConfigValue_g_volt_e_1305600: return pretty ? "Erista GPU Volt 1305 MHz" : "g_volt_e_1305600";
|
||||
case KipConfigValue_g_volt_e_1344000: return pretty ? "Erista GPU Volt 1344 MHz" : "g_volt_e_1344000";
|
||||
case KipConfigValue_g_volt_e_1382400: return pretty ? "Erista GPU Volt 1382 MHz" : "g_volt_e_1382400";
|
||||
case KipConfigValue_g_volt_e_1420800: return pretty ? "Erista GPU Volt 1420 MHz" : "g_volt_e_1420800";
|
||||
case KipConfigValue_g_volt_e_1459200: return pretty ? "Erista GPU Volt 1459 MHz" : "g_volt_e_1459200";
|
||||
case KipConfigValue_g_volt_e_1497600: return pretty ? "Erista GPU Volt 1497 MHz" : "g_volt_e_1497600";
|
||||
case KipConfigValue_g_volt_e_1536000: return pretty ? "Erista GPU Volt 1536 MHz" : "g_volt_e_1536000";
|
||||
|
||||
case KipConfigValue_t6_tRTW_fine_tune: return pretty ? "t6 - tRTW Fine Tune" : "t6_tRTW_fine_fune";
|
||||
case KipConfigValue_t7_tWTR_fine_tune: return pretty ? "t7 - tWTR Fine Tune" : "t7_tWTR_fine_tune";
|
||||
case KipCrc32:
|
||||
@@ -426,6 +424,8 @@ static inline uint64_t sysclkDefaultConfigValue(SysClkConfigValue val)
|
||||
case SysClkConfigValue_FreqLogIntervalMs:
|
||||
case SysClkConfigValue_PowerLogIntervalMs:
|
||||
case SysClkConfigValue_CsvWriteIntervalMs:
|
||||
case HocClkConfigValue_UncappedClocks:
|
||||
case HocClkConfigValue_OverwriteBoostMode:
|
||||
case HorizonOCConfigValue_BatteryChargeCurrent:
|
||||
case HorizonOCConfigValue_OverwriteRefreshRate:
|
||||
case HorizonOCConfigValue_EnableUnsafeDisplayFreqs:
|
||||
@@ -438,11 +438,11 @@ static inline uint64_t sysclkDefaultConfigValue(SysClkConfigValue val)
|
||||
|
||||
case HocClkConfigValue_MarikoMaxCpuClock:
|
||||
return 1963ULL;
|
||||
case HocClkConfigValue_UncappedClocks:
|
||||
case HocClkConfigValue_OverwriteBoostMode:
|
||||
|
||||
case HocClkConfigValue_ThermalThrottle:
|
||||
case HocClkConfigValue_HandheldTDP:
|
||||
case HocClkConfigValue_IsFirstLoad:
|
||||
case HorizonOCConfigValue_DVFSMode:
|
||||
case HorizonOCConfigValue_EnableExperimentalSettings:
|
||||
return 1ULL;
|
||||
case HocClkConfigValue_ThermalThrottleThreshold:
|
||||
return 70ULL;
|
||||
@@ -450,6 +450,8 @@ static inline uint64_t sysclkDefaultConfigValue(SysClkConfigValue val)
|
||||
return 9600ULL; // 8600mW will trigger on erista stock, so raise it a bit
|
||||
case HocClkConfigValue_LiteTDPLimit:
|
||||
return 6400ULL; // 0.5C
|
||||
case HorizonOCConfigValue_CpuGovernorMinimumFreq:
|
||||
return 612ULL; // 612MHz
|
||||
default:
|
||||
return 0ULL;
|
||||
}
|
||||
@@ -521,6 +523,57 @@ static inline uint64_t sysclkValidConfigValue(SysClkConfigValue val, uint64_t in
|
||||
case KipConfigValue_marikoGpuVmax:
|
||||
case KipConfigValue_commonGpuVoltOffset:
|
||||
case KipConfigValue_gpuSpeedo:
|
||||
case KipConfigValue_g_volt_76800:
|
||||
case KipConfigValue_g_volt_153600:
|
||||
case KipConfigValue_g_volt_230400:
|
||||
case KipConfigValue_g_volt_307200:
|
||||
case KipConfigValue_g_volt_384000:
|
||||
case KipConfigValue_g_volt_460800:
|
||||
case KipConfigValue_g_volt_537600:
|
||||
case KipConfigValue_g_volt_614400:
|
||||
case KipConfigValue_g_volt_691200:
|
||||
case KipConfigValue_g_volt_768000:
|
||||
case KipConfigValue_g_volt_844800:
|
||||
case KipConfigValue_g_volt_921600:
|
||||
case KipConfigValue_g_volt_998400:
|
||||
case KipConfigValue_g_volt_1075200:
|
||||
case KipConfigValue_g_volt_1152000:
|
||||
case KipConfigValue_g_volt_1228800:
|
||||
case KipConfigValue_g_volt_1267200:
|
||||
case KipConfigValue_g_volt_1305600:
|
||||
case KipConfigValue_g_volt_1344000:
|
||||
case KipConfigValue_g_volt_1382400:
|
||||
case KipConfigValue_g_volt_1420800:
|
||||
case KipConfigValue_g_volt_1459200:
|
||||
case KipConfigValue_g_volt_1497600:
|
||||
case KipConfigValue_g_volt_1536000:
|
||||
case KipConfigValue_g_volt_e_76800:
|
||||
case KipConfigValue_g_volt_e_115200:
|
||||
case KipConfigValue_g_volt_e_153600:
|
||||
case KipConfigValue_g_volt_e_192000:
|
||||
case KipConfigValue_g_volt_e_230400:
|
||||
case KipConfigValue_g_volt_e_268800:
|
||||
case KipConfigValue_g_volt_e_307200:
|
||||
case KipConfigValue_g_volt_e_345600:
|
||||
case KipConfigValue_g_volt_e_384000:
|
||||
case KipConfigValue_g_volt_e_422400:
|
||||
case KipConfigValue_g_volt_e_460800:
|
||||
case KipConfigValue_g_volt_e_499200:
|
||||
case KipConfigValue_g_volt_e_537600:
|
||||
case KipConfigValue_g_volt_e_576000:
|
||||
case KipConfigValue_g_volt_e_614400:
|
||||
case KipConfigValue_g_volt_e_652800:
|
||||
case KipConfigValue_g_volt_e_691200:
|
||||
case KipConfigValue_g_volt_e_729600:
|
||||
case KipConfigValue_g_volt_e_768000:
|
||||
case KipConfigValue_g_volt_e_806400:
|
||||
case KipConfigValue_g_volt_e_844800:
|
||||
case KipConfigValue_g_volt_e_883200:
|
||||
case KipConfigValue_g_volt_e_921600:
|
||||
case KipConfigValue_g_volt_e_960000:
|
||||
case KipConfigValue_g_volt_e_998400:
|
||||
case KipConfigValue_g_volt_e_1036800:
|
||||
case KipConfigValue_g_volt_e_1075200:
|
||||
case KipConfigValue_eristaCpuVmin:
|
||||
case KipConfigValue_eristaCpuUnlock:
|
||||
case KipConfigValue_t6_tRTW_fine_tune:
|
||||
@@ -529,8 +582,12 @@ static inline uint64_t sysclkValidConfigValue(SysClkConfigValue val, uint64_t in
|
||||
case HorizonOCConfigValue_DVFSMode:
|
||||
case HorizonOCConfigValue_DVFSOffset:
|
||||
case HorizonOCConfigValue_GPUScheduling:
|
||||
case HorizonOCConfigValue_RAMVoltUsageDisplayMode:
|
||||
case HorizonOCConfigValue_CpuGovernorMinimumFreq:
|
||||
return true;
|
||||
case HorizonOCConfigValue_BatteryChargeCurrent:
|
||||
return ((input >= 1024) && (input <= 3072)) || !input;
|
||||
default:
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -29,11 +29,9 @@
|
||||
|
||||
#define MAX_REFRESH_RATE 72
|
||||
|
||||
// Configuration
|
||||
static DisplayRefreshConfig g_config = {0};
|
||||
static bool g_initialized = false;
|
||||
|
||||
// State
|
||||
static uint8_t g_dockedHighestRefreshRate = 60;
|
||||
static uint8_t g_dockedLinkRate = 10;
|
||||
static bool g_wasRetroSuperTurnedOff = false;
|
||||
@@ -41,7 +39,6 @@ static uint32_t g_lastVActive = 1080;
|
||||
static bool g_canChangeRefreshRateDocked = false;
|
||||
static uint8_t g_lastVActiveSet = 0;
|
||||
|
||||
// Refresh rate tables
|
||||
static const uint8_t g_dockedRefreshRates[] = {40, 45, 50, 55, 60, 70, 72, 75, 80, 90, 95, 100, 110, 120, 130, 140, 144, 150, 160, 165, 170, 180, 190, 200, 210, 220, 230, 240};
|
||||
// Calculate with this tool:
|
||||
|
||||
@@ -88,6 +85,7 @@ static const DockedTimings g_dockedTimings1080p[] = {
|
||||
{8, 32, 40, 108, 8, 6, 0, 528880}, //220Hz CVT-RBv2
|
||||
{8, 32, 40, 114, 8, 6, 0, 555680}, //230Hz CVT-RBv2
|
||||
{8, 32, 40, 121, 8, 6, 0, 583200}, //240Hz CVT-RBv2
|
||||
// technically you can go to 476hz, but in practice, why would you?
|
||||
};
|
||||
|
||||
static const HandheldTimings g_handheldTimingsRETRO[] = {
|
||||
@@ -100,7 +98,6 @@ static const HandheldTimings g_handheldTimingsRETRO[] = {
|
||||
|
||||
static const MinMaxRefreshRate g_handheldModeRefreshRate = {40, 80};
|
||||
|
||||
// Utility functions
|
||||
static uint8_t _getDockedRefreshRateIterator(uint32_t refreshRate) {
|
||||
for (size_t i = 0; i < sizeof(g_dockedRefreshRates) / sizeof(g_dockedRefreshRates[0]); i++) {
|
||||
if (g_dockedRefreshRates[i] == refreshRate) return i;
|
||||
@@ -553,9 +550,10 @@ bool DisplayRefresh_SetRate(uint32_t new_refreshRate) {
|
||||
if (g_config.isRetroSUPER && !g_config.isDocked) {
|
||||
return _setNvDispHandheldRefreshRate(new_refreshRate);
|
||||
}
|
||||
else if ((!g_config.isRetroSUPER && g_config.isLite) ||
|
||||
nvOpen(&fd, "/dev/nvdisp-disp1")) {
|
||||
return _setPLLDHandheldRefreshRate(new_refreshRate);
|
||||
|
||||
else if ((!g_config.isRetroSUPER && g_config.isLite) || R_FAILED(nvOpen(&fd, "/dev/nvdisp-disp1"))) {
|
||||
if (_setPLLDHandheldRefreshRate(new_refreshRate) == false)
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
struct dpaux_read {
|
||||
@@ -577,15 +575,19 @@ bool DisplayRefresh_SetRate(uint32_t new_refreshRate) {
|
||||
nvClose(fd);
|
||||
|
||||
if (rc != 0) {
|
||||
if (!g_config.isRetroSUPER) {
|
||||
return _setPLLDHandheldRefreshRate(new_refreshRate);
|
||||
} else {
|
||||
return _setNvDispHandheldRefreshRate(new_refreshRate);
|
||||
}
|
||||
if (!g_config.isRetroSUPER) {
|
||||
return _setPLLDHandheldRefreshRate(new_refreshRate);
|
||||
} else {
|
||||
return _setNvDispHandheldRefreshRate(new_refreshRate);
|
||||
}
|
||||
} else {
|
||||
return _setNvDispDockedRefreshRate(new_refreshRate);
|
||||
if(g_config.isDocked)
|
||||
return _setNvDispDockedRefreshRate(new_refreshRate);
|
||||
else
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DisplayRefresh_GetRate(uint32_t* out_refreshRate, bool internal) {
|
||||
|
||||
@@ -53,6 +53,14 @@ Result rgltrGetVoltage(RgltrSession* session, u32* out_volt) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result rgltrRequestVoltage(RgltrSession* session, u32 microvolt) {
|
||||
return serviceDispatchIn(&session->s, 5, microvolt);
|
||||
}
|
||||
|
||||
Result rgltrCancelVoltageRequest(RgltrSession* session) {
|
||||
return serviceDispatch(&session->s, 6);
|
||||
}
|
||||
|
||||
void rgltrCloseSession(RgltrSession* session) {
|
||||
serviceClose(&session->s);
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ include ${TOPDIR}/lib/libultrahand/ultrahand.mk
|
||||
# version control constants
|
||||
#---------------------------------------------------------------------------------
|
||||
#TARGET_VERSION := $(shell git describe --dirty --always --tags)
|
||||
APP_VERSION := 0.41
|
||||
APP_VERSION := 1.0.1
|
||||
TARGET_VERSION := $(APP_VERSION)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
@@ -49,7 +49,7 @@ DEFINES := -DDISABLE_IPC -DTARGET="\"$(TARGET)\"" -DTARGET_VERSION="\"$(TARGET_V
|
||||
|
||||
ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE
|
||||
|
||||
CFLAGS := -Os -Wall -flto -fdata-sections -ffunction-sections -fno-rtti -fno-common \
|
||||
CFLAGS := -O2 -Wall -flto -fdata-sections -ffunction-sections -fno-rtti -fno-common \
|
||||
$(ARCH) $(DEFINES)
|
||||
|
||||
CFLAGS += $(INCLUDE) -D__SWITCH__
|
||||
|
||||
@@ -24,7 +24,10 @@
|
||||
|
||||
tsl::elm::ListItem* SpeedoItem = NULL;
|
||||
tsl::elm::ListItem* IddqItem = NULL;
|
||||
tsl::elm::ListItem* DramModule = NULL;
|
||||
tsl::elm::ListItem* sysdockStatusItem = NULL;
|
||||
tsl::elm::ListItem* saltyNXStatusItem = NULL;
|
||||
|
||||
ImageElement* CatImage = NULL;
|
||||
HideableCategoryHeader* CatHeader = NULL;
|
||||
HideableCustomDrawer* CatSpacer = NULL;
|
||||
@@ -53,10 +56,18 @@ void AboutGui::listUI()
|
||||
new tsl::elm::ListItem("IDDQ:");
|
||||
this->listElement->addItem(IddqItem);
|
||||
|
||||
DramModule =
|
||||
new tsl::elm::ListItem("Module: ");
|
||||
this->listElement->addItem(DramModule);
|
||||
|
||||
sysdockStatusItem =
|
||||
new tsl::elm::ListItem("sys-dock status:");
|
||||
this->listElement->addItem(sysdockStatusItem);
|
||||
|
||||
saltyNXStatusItem =
|
||||
new tsl::elm::ListItem("SaltyNX status:");
|
||||
this->listElement->addItem(saltyNXStatusItem);
|
||||
|
||||
this->listElement->addItem(
|
||||
new tsl::elm::CategoryHeader("Credits")
|
||||
);
|
||||
@@ -122,7 +133,7 @@ void AboutGui::listUI()
|
||||
this->listElement->addItem(
|
||||
new tsl::elm::ListItem("Happy")
|
||||
);
|
||||
|
||||
|
||||
this->listElement->addItem(
|
||||
new tsl::elm::ListItem("Flopsider")
|
||||
);
|
||||
@@ -200,7 +211,7 @@ void AboutGui::listUI()
|
||||
CatHeader = new HideableCategoryHeader("Cat");
|
||||
CatHeader->setVisible(false);
|
||||
this->listElement->addItem(CatHeader);
|
||||
|
||||
|
||||
CatImage = new ImageElement(CAT_DATA, CAT_WIDTH, CAT_HEIGHT);
|
||||
CatImage->setVisible(false);
|
||||
this->listElement->addItem(CatImage);
|
||||
@@ -210,6 +221,49 @@ void AboutGui::listUI()
|
||||
this->listElement->addItem(CatSpacer);
|
||||
}
|
||||
|
||||
std::string AboutGui::formatRamModule() {
|
||||
switch (this->context->dramID) {
|
||||
case 0: return "HB-MGCH 4GB";
|
||||
case 4: return "HM-MGCH 6GB";
|
||||
case 7: return "HM-MGXX 8GB";
|
||||
|
||||
case 1: return "NLE";
|
||||
case 2: return "WT:C";
|
||||
|
||||
case 3:
|
||||
case 5 ... 6: return "NEE";
|
||||
|
||||
case 8:
|
||||
case 12: return "AM-MGCJ 4GB";
|
||||
case 9:
|
||||
case 13: return "AM-MGCJ 8GB";
|
||||
|
||||
case 10:
|
||||
case 14: return "NME";
|
||||
|
||||
case 11:
|
||||
case 15: return "WT:E";
|
||||
|
||||
case 17:
|
||||
case 19:
|
||||
case 24: return "AA-MGCL 4GB";
|
||||
|
||||
case 18:
|
||||
case 23:
|
||||
case 28: return "AA-MGCL 8GB";
|
||||
|
||||
case 20 ... 22: return "AB-MGCL 4GB";
|
||||
|
||||
case 25 ... 27: return "WT:F";
|
||||
|
||||
case 29 ... 31: return "x267";
|
||||
|
||||
case 32 ... 34: return "WT:B";
|
||||
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
void AboutGui::update()
|
||||
{
|
||||
BaseMenuGui::update();
|
||||
@@ -218,7 +272,8 @@ void AboutGui::update()
|
||||
void AboutGui::refresh()
|
||||
{
|
||||
BaseMenuGui::refresh();
|
||||
|
||||
std::string ramModule = formatRamModule();
|
||||
|
||||
if (!this->context)
|
||||
return;
|
||||
// Format strings once per refresh
|
||||
@@ -226,5 +281,7 @@ void AboutGui::refresh()
|
||||
sprintf(strings[1], "%u/%u/%u", this->context->iddq[HorizonOCSpeedo_CPU], this->context->iddq[HorizonOCSpeedo_GPU], this->context->iddq[HorizonOCSpeedo_SOC]);
|
||||
SpeedoItem->setValue(strings[0]);
|
||||
IddqItem->setValue(strings[1]);
|
||||
DramModule->setValue(formatRamModule());
|
||||
sysdockStatusItem->setValue(this->context->isSysDockInstalled ? "Installed" : "Not Installed");
|
||||
}
|
||||
saltyNXStatusItem->setValue(this->context->isSaltyNXInstalled ? "Installed" : "Not Installed");
|
||||
}
|
||||
|
||||
@@ -27,12 +27,15 @@ class AboutGui : public BaseMenuGui
|
||||
{
|
||||
protected:
|
||||
char strings[32][32]; // Pre-formatted strings
|
||||
|
||||
|
||||
public:
|
||||
AboutGui();
|
||||
~AboutGui();
|
||||
|
||||
|
||||
void listUI() override;
|
||||
void update() override;
|
||||
void refresh() override;
|
||||
|
||||
private:
|
||||
std::string formatRamModule();
|
||||
};
|
||||
@@ -292,7 +292,7 @@ void AppProfileGui::addProfileUI(SysClkProfile profile)
|
||||
this->addModuleListItem(profile, SysClkModule_MEM);
|
||||
#if IS_MINIMAL == 0
|
||||
ValueThresholds lcdThresholds(60, 65);
|
||||
if(!IsHoag() && configList.values[HorizonOCConfigValue_OverwriteRefreshRate]) {
|
||||
if(configList.values[HorizonOCConfigValue_OverwriteRefreshRate]) {
|
||||
if(profile != SysClkProfile_Docked) {
|
||||
this->addModuleListItemValue(profile, HorizonOCModule_Display, "Display", IsAula() ? 45 : 40, configList.values[HorizonOCConfigValue_EnableUnsafeDisplayFreqs] ? IsAula() ? 65 : 72 : 60, 1, " Hz", 1, 0, lcdThresholds);
|
||||
} else {
|
||||
@@ -360,13 +360,25 @@ void AppProfileGui::addProfileUI(SysClkProfile profile)
|
||||
NamedValue("115 Hz", 115),
|
||||
NamedValue("120 Hz", 120)
|
||||
};
|
||||
|
||||
this->addModuleListItemValue(profile, HorizonOCModule_Display, "Display", 50, 120, 1, " Hz", 1, 0, ValueThresholds(), dockedFreqsStandard);
|
||||
if(configList.values[HorizonOCConfigValue_OverwriteRefreshRate] && !IsHoag())
|
||||
this->addModuleListItemValue(profile, HorizonOCModule_Display, "Display", 50, 120, 1, " Hz", 1, 0, ValueThresholds(), dockedFreqsStandard);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
std::vector<NamedValue> governorSettingsE = {
|
||||
NamedValue("Do Not Override", GovernorState_DoNotOverride),
|
||||
NamedValue("Disabled", GovernorState_Disabled),
|
||||
NamedValue("CPU + GPU + VRR", GovernorState_Enabled_CpuGpuVrr),
|
||||
NamedValue("CPU + VRR", GovernorState_Enabled_CpuVrr),
|
||||
NamedValue("GPU + VRR", GovernorState_Enabled_GpuVrr),
|
||||
NamedValue("CPU + GPU", GovernorState_Enabled_CpuGpu),
|
||||
NamedValue("CPU", GovernorState_Enabled_Cpu),
|
||||
NamedValue("GPU", GovernorState_Enabled_Gpu),
|
||||
NamedValue("VRR", GovernorState_Enabled_Vrr),
|
||||
};
|
||||
|
||||
std::vector<NamedValue> governorSettingsH = {
|
||||
NamedValue("Do Not Override", GovernorState_DoNotOverride),
|
||||
NamedValue("Disabled", GovernorState_Disabled),
|
||||
NamedValue("CPU + GPU", GovernorState_Enabled_CpuGpu),
|
||||
@@ -374,12 +386,7 @@ void AppProfileGui::addProfileUI(SysClkProfile profile)
|
||||
NamedValue("GPU", GovernorState_Enabled_Gpu),
|
||||
};
|
||||
|
||||
std::vector<NamedValue> governorSettings = {
|
||||
NamedValue("Do Not Override", GovernorState_DoNotOverride),
|
||||
NamedValue("Disabled", GovernorState_Disabled),
|
||||
NamedValue("GPU", GovernorState_Enabled_Gpu),
|
||||
};
|
||||
this->addModuleListItemValue(profile, HorizonOCModule_Governor, "Governor", 0, 0, 1, "", 1, 0, ValueThresholds(), configList.values[HorizonOCConfigValue_EnableExperimentalSettings] ?governorSettingsE : governorSettings, false);
|
||||
this->addModuleListItemValue(profile, HorizonOCModule_Governor, "Governor", 0, 0, 1, "", 1, 0, ValueThresholds(), IsHoag() ? governorSettingsH : governorSettingsE, false);
|
||||
}
|
||||
|
||||
void AppProfileGui::listUI()
|
||||
|
||||
@@ -48,16 +48,11 @@ std::string getVersionString() {
|
||||
return std::string(buf);
|
||||
}
|
||||
|
||||
// ---------------------------------------------
|
||||
// AQUATIC BLUE COLORS (4-bit color space)
|
||||
// ---------------------------------------------
|
||||
static constexpr tsl::Color dynamicLogoRGB1 = tsl::Color(0, 4, 8, 15); // Deep ocean blue
|
||||
static constexpr tsl::Color dynamicLogoRGB2 = tsl::Color(7, 15, 15, 15); // Bright aqua cyan
|
||||
static constexpr tsl::Color STATIC_AQUA = tsl::Color(2, 10, 12, 15); // Mid aqua
|
||||
static constexpr tsl::Color dynamicLogoRGB1 = tsl::Color(0, 4, 8, 15);
|
||||
static constexpr tsl::Color dynamicLogoRGB2 = tsl::Color(7, 15, 15, 15);
|
||||
static constexpr tsl::Color STATIC_AQUA = tsl::Color(2, 10, 12, 15);
|
||||
const std::string name = "Horizon OC Zeus";
|
||||
|
||||
// ---------------------------------------------
|
||||
// FULLY ENHANCED ANIMATED LOGO EFFECT
|
||||
// ---------------------------------------------
|
||||
static s32 drawDynamicUltraText(
|
||||
tsl::gfx::Renderer* renderer,
|
||||
s32 startX,
|
||||
@@ -68,7 +63,6 @@ static s32 drawDynamicUltraText(
|
||||
{
|
||||
static constexpr double cycleDuration = 1.6;
|
||||
|
||||
const std::string name = "Horizon OC Zeus";
|
||||
s32 currentX = startX;
|
||||
|
||||
const u64 currentTime_ns = armTicksToNs(armGetSystemTick());
|
||||
@@ -89,15 +83,9 @@ static s32 drawDynamicUltraText(
|
||||
double s1 = n * n * (3.0 - 2.0 * n);
|
||||
double blend = std::clamp(s1, 0.0, 1.0);
|
||||
|
||||
// ---------------------------------------------
|
||||
// Glow Pulse (brightness modulation)
|
||||
// ---------------------------------------------
|
||||
double glow = (cos(phase * 1.5) + 1.0) * 0.5;
|
||||
double brightness = 0.75 + glow * 0.25;
|
||||
|
||||
// ---------------------------------------------
|
||||
// Color interpolation (4-bit!)
|
||||
// ---------------------------------------------
|
||||
u8 r = static_cast<u8>(
|
||||
(dynamicLogoRGB1.r + (dynamicLogoRGB2.r - dynamicLogoRGB1.r) * blend) * brightness
|
||||
);
|
||||
@@ -112,21 +100,15 @@ static s32 drawDynamicUltraText(
|
||||
g = std::clamp<u8>(g, 0, 15);
|
||||
b = std::clamp<u8>(b, 0, 15);
|
||||
|
||||
// ---------------------------------------------
|
||||
// ZEUS Lightning Flash
|
||||
// ---------------------------------------------
|
||||
bool lightning = (fmod(timeNow, 5.0) < 0.15);
|
||||
if (lightning) {
|
||||
r = std::min<u8>(r + 4, 15);
|
||||
g = std::min<u8>(g + 4, 15);
|
||||
b = std::min<u8>(b + 15, 15); // strong blue spike
|
||||
b = std::min<u8>(b + 15, 15);
|
||||
}
|
||||
|
||||
tsl::Color color(r, g, b, 15);
|
||||
|
||||
// ---------------------------------------------
|
||||
// Static Position (no vertical wobble)
|
||||
// ---------------------------------------------
|
||||
std::string ls(1, letter);
|
||||
|
||||
if (useNotificationMethod)
|
||||
@@ -138,11 +120,7 @@ static s32 drawDynamicUltraText(
|
||||
return currentX;
|
||||
}
|
||||
|
||||
// ---------------------------------------------
|
||||
// PRE-DRAW HOOK
|
||||
// ---------------------------------------------
|
||||
void BaseGui::preDraw(tsl::gfx::Renderer* renderer)
|
||||
{
|
||||
void BaseGui::preDraw(tsl::gfx::Renderer* renderer) {
|
||||
drawDynamicUltraText(
|
||||
renderer,
|
||||
LOGO_X,
|
||||
@@ -153,9 +131,6 @@ void BaseGui::preDraw(tsl::gfx::Renderer* renderer)
|
||||
);
|
||||
}
|
||||
|
||||
// ---------------------------------------------
|
||||
// UI SETUP
|
||||
// ---------------------------------------------
|
||||
tsl::elm::Element* BaseGui::createUI()
|
||||
{
|
||||
BaseFrame* rootFrame = new BaseFrame(this);
|
||||
@@ -163,9 +138,6 @@ tsl::elm::Element* BaseGui::createUI()
|
||||
return rootFrame;
|
||||
}
|
||||
|
||||
// ---------------------------------------------
|
||||
// LIVE UPDATE
|
||||
// ---------------------------------------------
|
||||
void BaseGui::update()
|
||||
{
|
||||
this->refresh();
|
||||
|
||||
@@ -58,7 +58,7 @@ void BaseMenuGui::preDraw(tsl::gfx::Renderer* renderer) {
|
||||
|
||||
// All constants pre-calculated and cached
|
||||
static constexpr const char* const labels[] = {
|
||||
"App ID", "Profile", "CPU", "GPU", "MEM", "SoC", "Board", "Skin", "Now", "Avg", "BAT", "PMIC", "FAN", "DISP"
|
||||
"App ID", "Profile", "CPU", "GPU", "MEM", "SoC", "Board", "Skin", "Now", "Avg", "BAT", "PMIC", "FAN", "DISP", "FPS"
|
||||
};
|
||||
|
||||
static constexpr u32 dataPositions[6] = {63-3+3, 200-1, 344-1-3, 200-1, 342-1, 321-1};
|
||||
@@ -74,12 +74,12 @@ void BaseMenuGui::preDraw(tsl::gfx::Renderer* renderer) {
|
||||
}
|
||||
static u32 positions[10] = {24-1, 310-labelWidths[1], 24-1, 192-labelWidths[3], 332-labelWidths[4], 24-1, 192 - labelWidths[6], 332-labelWidths[7], 192 - labelWidths[8], 332-labelWidths[9]};
|
||||
|
||||
static u32 maxProfileValueWidth = renderer->getTextDimensions("PD Charger", false, SMALL_TEXT_SIZE).first; // longest word
|
||||
static u32 maxProfileValueWidth = renderer->getTextDimensions("USB Charger", false, SMALL_TEXT_SIZE).first; // longest word
|
||||
|
||||
u32 y = 91;
|
||||
|
||||
// === TOP SECTION ===
|
||||
renderer->drawRoundedRect(14, 70-1, 420, 30+2, 15.0f, renderer->aWithOpacity(tsl::tableBGColor));
|
||||
renderer->drawRoundedRect(14, 70-1, 420, 30+2, 12.0f, renderer->aWithOpacity(tsl::tableBGColor));
|
||||
|
||||
// App ID - use pre-formatted string
|
||||
renderer->drawString(labels[0], false, positions[0], y, SMALL_TEXT_SIZE, tsl::sectionTextColor);
|
||||
@@ -89,42 +89,43 @@ void BaseMenuGui::preDraw(tsl::gfx::Renderer* renderer) {
|
||||
renderer->drawString(labels[1], false, 423 - maxProfileValueWidth - labelWidths[1] - 9, y, SMALL_TEXT_SIZE, tsl::sectionTextColor);
|
||||
renderer->drawString(displayStrings[1], false, 423 - maxProfileValueWidth, y, SMALL_TEXT_SIZE, tsl::infoTextColor);
|
||||
|
||||
y = 129; // Direct assignment instead of += 38
|
||||
y += 38; // Direct assignment instead of += 38
|
||||
|
||||
// === MAIN DATA SECTION ===
|
||||
renderer->drawRoundedRect(14, 106, 420, 156, 10.0f, renderer->aWithOpacity(tsl::tableBGColor));
|
||||
|
||||
// renderer->drawRoundedRect(14, 106, 420, 156, 10.0f, renderer->aWithOpacity(tsl::tableBGColor));
|
||||
renderer->drawRoundedRect(14, 106, 420, 136, 12.0f, renderer->aWithOpacity(tsl::tableBGColor));
|
||||
// === FREQUENCY SECTION ===
|
||||
// Labels first (better cache locality)
|
||||
renderer->drawString(labels[2], false, positions[2], y, SMALL_TEXT_SIZE, tsl::sectionTextColor);
|
||||
renderer->drawString(labels[3], false, positions[3], y, SMALL_TEXT_SIZE, tsl::sectionTextColor);
|
||||
renderer->drawString(labels[4], false, positions[4], y, SMALL_TEXT_SIZE, tsl::sectionTextColor);
|
||||
|
||||
// Current frequencies - use pre-formatted strings
|
||||
renderer->drawString(displayStrings[2], false, dataPositions[0], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // CPU
|
||||
renderer->drawString(displayStrings[3], false, dataPositions[1], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // GPU
|
||||
renderer->drawString(displayStrings[4], false, dataPositions[2], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // MEM
|
||||
|
||||
y = 149; // Direct assignment (129 + 20)
|
||||
|
||||
renderer->drawString(displayStrings[19], false, positions[2], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // CPU Usage
|
||||
renderer->drawString(displayStrings[17], false, positions[3], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // GPU Usage
|
||||
renderer->drawString(displayStrings[18], false, positions[4], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // RAM Usage
|
||||
|
||||
// === REAL FREQUENCIES ===
|
||||
renderer->drawString(displayStrings[5], false, dataPositions[0], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // CPU real
|
||||
renderer->drawString(displayStrings[6], false, dataPositions[1], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // GPU real
|
||||
renderer->drawString(displayStrings[7], false, dataPositions[2], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // MEM real
|
||||
|
||||
y = 169; // Direct assignment (149 + 20)
|
||||
// Current frequencies - use pre-formatted strings
|
||||
// renderer->drawString(displayStrings[2], false, dataPositions[0], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // CPU
|
||||
// renderer->drawString(displayStrings[3], false, dataPositions[1], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // GPU
|
||||
// renderer->drawString(displayStrings[4], false, dataPositions[2], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // MEM
|
||||
|
||||
y += 20; // Direct assignment (129 + 20)
|
||||
|
||||
renderer->drawString(displayStrings[19], false, positions[2], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // CPU Usage
|
||||
renderer->drawString(displayStrings[17], false, positions[3], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // GPU Usage
|
||||
if(configList.values[HorizonOCConfigValue_RAMVoltUsageDisplayMode] == RamDisplayMode_VDD2Usage || configList.values[HorizonOCConfigValue_RAMVoltUsageDisplayMode] == RamDisplayMode_VDDQUsage)
|
||||
renderer->drawString(displayStrings[18], false, positions[4], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // RAM Usage
|
||||
// === REAL FREQUENCIES ===
|
||||
|
||||
// y += 20; // Direct assignment (149 + 20)
|
||||
|
||||
// === VOLTAGES ===
|
||||
renderer->drawString(displayStrings[8], false, dataPositions[0], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // CPU voltage
|
||||
renderer->drawString(displayStrings[9], false, dataPositions[1], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // GPU voltage
|
||||
|
||||
renderer->drawStringWithColoredSections(displayStrings[10], false, {""}, dataPositions[5]-16, y, SMALL_TEXT_SIZE, tsl::infoTextColor, tsl::separatorColor);
|
||||
renderer->drawStringWithColoredSections(displayStrings[10], false, {""}, configList.values[HorizonOCConfigValue_RAMVoltUsageDisplayMode] == RamDisplayMode_VDD2VDDQ ? dataPositions[5]-16 : dataPositions[2], y, SMALL_TEXT_SIZE, tsl::infoTextColor, tsl::separatorColor);
|
||||
|
||||
y = 191; // Direct assignment (169 + 22)
|
||||
y += 22; // Direct assignment (169 + 22)
|
||||
|
||||
// === TEMPERATURE SECTION ===
|
||||
// Labels
|
||||
@@ -137,7 +138,7 @@ void BaseMenuGui::preDraw(tsl::gfx::Renderer* renderer) {
|
||||
renderer->drawString(displayStrings[12], false, dataPositions[1], y, SMALL_TEXT_SIZE, tempColors[SysClkThermalSensor_PCB]); // PCB
|
||||
renderer->drawString(displayStrings[13], false, dataPositions[2], y, SMALL_TEXT_SIZE, tempColors[SysClkThermalSensor_Skin]); // Skin
|
||||
|
||||
y = 211; // Direct assignment (191 + 20)
|
||||
y += 20; // Direct assignment (191 + 20)
|
||||
|
||||
renderer->drawString(displayStrings[14], false, dataPositions[0], y, SMALL_TEXT_SIZE, tsl::infoTextColor);
|
||||
|
||||
@@ -153,11 +154,11 @@ void BaseMenuGui::preDraw(tsl::gfx::Renderer* renderer) {
|
||||
renderer->drawString(labels[10], false, positions[2], y, SMALL_TEXT_SIZE, tsl::sectionTextColor);
|
||||
|
||||
renderer->drawString(displayStrings[20], false, dataPositions[0], y, SMALL_TEXT_SIZE, tempColors[HorizonOCThermalSensor_Battery]); // Battery
|
||||
if(!IsHoag()) {
|
||||
renderer->drawString(labels[13], false, positions[4], y, SMALL_TEXT_SIZE, tsl::sectionTextColor); // disp label
|
||||
|
||||
renderer->drawString(labels[13], false, positions[4], y, SMALL_TEXT_SIZE, tsl::sectionTextColor); // disp label
|
||||
|
||||
renderer->drawString(displayStrings[25], false, dataPositions[2], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // disp freq
|
||||
|
||||
renderer->drawString(displayStrings[25], false, dataPositions[2], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // disp freq
|
||||
}
|
||||
renderer->drawString(labels[12], false, positions[3], y, SMALL_TEXT_SIZE, tsl::sectionTextColor); // fan label
|
||||
|
||||
renderer->drawString(displayStrings[24], false, dataPositions[1], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // fan speed
|
||||
@@ -167,8 +168,10 @@ void BaseMenuGui::preDraw(tsl::gfx::Renderer* renderer) {
|
||||
renderer->drawString(displayStrings[21], false, dataPositions[0], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // Bat voltage
|
||||
renderer->drawString(displayStrings[23], false, positions[2] - 2, y, SMALL_TEXT_SIZE, tsl::infoTextColor); // Bat Age
|
||||
|
||||
|
||||
renderer->drawString(displayStrings[26], false, dataPositions[2], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // disp volt
|
||||
if(this->context->isSaltyNXInstalled) {
|
||||
renderer->drawString(labels[14], false, positions[4], y, SMALL_TEXT_SIZE, tsl::sectionTextColor); // FPS label
|
||||
renderer->drawString(displayStrings[26], false, dataPositions[2], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // FPS
|
||||
}
|
||||
|
||||
y+=20;
|
||||
}
|
||||
@@ -234,14 +237,19 @@ void BaseMenuGui::refresh()
|
||||
sprintf(displayStrings[8], "%.1f mV", context->voltages[HocClkVoltage_CPU] / 1000.0);
|
||||
sprintf(displayStrings[9], "%.1f mV", context->voltages[HocClkVoltage_GPU] / 1000.0);
|
||||
|
||||
// Memory voltage (handle VDD case)
|
||||
if (IsMariko()) {
|
||||
//sprintf(displayStrings[10], "%u%u mV", vddVoltageUv / 1000U, emcVoltageUv / 1000U);
|
||||
//sprintf(displayStrings[10], "%u%.1f mV", vddVoltageUv / 1000U, emcVoltageUv / 1000.0f);
|
||||
sprintf(displayStrings[10], "%u.%u%u mV", context->voltages[HocClkVoltage_EMCVDD2] / 1000U, (context->voltages[HocClkVoltage_EMCVDD2] % 1000U) / 100U, context->voltages[HocClkVoltage_EMCVDDQ_MarikoOnly] / 1000U);
|
||||
} else {
|
||||
//sprintf(displayStrings[10], "%u mV", vddVoltageUv / 1000U);
|
||||
sprintf(displayStrings[10], "%u.%u%u mV", context->voltages[HocClkVoltage_EMCVDD2] / 1000U, (context->voltages[HocClkVoltage_EMCVDD2] % 1000U) / 100U, context->voltages[HocClkVoltage_EMCVDD2] / 1000U);
|
||||
switch(configList.values[HorizonOCConfigValue_RAMVoltUsageDisplayMode]) {
|
||||
case RamDisplayMode_VDD2VDDQ:
|
||||
sprintf(displayStrings[10], "%u.%u%u mV", context->voltages[HocClkVoltage_EMCVDD2] / 1000U, (context->voltages[HocClkVoltage_EMCVDD2] % 1000U) / 100U, context->voltages[HocClkVoltage_EMCVDDQ_MarikoOnly] / 1000U);
|
||||
break;
|
||||
case RamDisplayMode_VDD2Usage:
|
||||
sprintf(displayStrings[10], "%u.%u mV", context->voltages[HocClkVoltage_EMCVDD2] / 1000U, (context->voltages[HocClkVoltage_EMCVDD2] % 1000U) / 100U);
|
||||
break;
|
||||
case RamDisplayMode_VDDQUsage:
|
||||
sprintf(displayStrings[10], "%u.%u mV", context->voltages[HocClkVoltage_EMCVDDQ_MarikoOnly] / 1000U, (context->voltages[HocClkVoltage_EMCVDDQ_MarikoOnly] % 1000U) / 100U);
|
||||
break;
|
||||
default:
|
||||
strcpy(displayStrings[10], "N/A");
|
||||
break;
|
||||
}
|
||||
|
||||
// Temperatures and pre-compute colors
|
||||
@@ -279,15 +287,20 @@ void BaseMenuGui::refresh()
|
||||
sprintf(displayStrings[24], "%u%%", context->partLoad[HocClkPartLoad_FAN]);
|
||||
|
||||
sprintf(displayStrings[25], "%u Hz", context->realFreqs[HorizonOCModule_Display]);
|
||||
|
||||
//sprintf(displayStrings[26], "%u", context->speedos[HorizonOCSpeedo_CPU]);
|
||||
|
||||
if(this->context->isSaltyNXInstalled) {
|
||||
if(context->fps == 254) {
|
||||
strcpy(displayStrings[26], "N/A");
|
||||
} else {
|
||||
memset(displayStrings[26], 0, sizeof(displayStrings[26]));
|
||||
sprintf(displayStrings[26], "%u", context->fps);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tsl::elm::Element* BaseMenuGui::baseUI()
|
||||
{
|
||||
auto* list = new tsl::elm::List();
|
||||
list->addItem(new tsl::elm::CustomDrawer([](tsl::gfx::Renderer*, s32, s32, s32, s32) {}), 50); // add a bit of space
|
||||
list->addItem(new tsl::elm::CustomDrawer([](tsl::gfx::Renderer*, s32, s32, s32, s32) {}), 10); // add a bit of space
|
||||
this->listElement = list;
|
||||
this->listUI();
|
||||
|
||||
|
||||
@@ -131,10 +131,9 @@ void FreqChoiceGui::listUI()
|
||||
// // this->configList->values[HocClkConfigValue_MarikoMaxMemClock] < mhz)
|
||||
// // continue;
|
||||
|
||||
// } else if (checkMax && IsErista()) {
|
||||
// if (moduleName == "cpu" &&
|
||||
// this->configList->values[HocClkConfigValue_EristaMaxCpuClock] < mhz)
|
||||
// continue;
|
||||
if (checkMax && IsErista())
|
||||
if (moduleName == "cpu" && this->configList->values[HocClkConfigValue_EristaMaxCpuClock] < mhz)
|
||||
continue;
|
||||
|
||||
// // if (moduleName == "gpu" &&
|
||||
// // this->configList->values[HocClkConfigValue_EristaMaxGpuClock] < mhz)
|
||||
|
||||
@@ -290,6 +290,25 @@ void GlobalOverrideGui::addModuleToggleItem(SysClkModule module)
|
||||
this->listItems[module] = toggle;
|
||||
}
|
||||
|
||||
std::vector<NamedValue> governorSettingsE = {
|
||||
NamedValue("Do Not Override", GovernorState_DoNotOverride),
|
||||
NamedValue("Disabled", GovernorState_Disabled),
|
||||
NamedValue("CPU + GPU + VRR", GovernorState_Enabled_CpuGpuVrr),
|
||||
NamedValue("CPU + VRR", GovernorState_Enabled_CpuVrr),
|
||||
NamedValue("GPU + VRR", GovernorState_Enabled_GpuVrr),
|
||||
NamedValue("CPU + GPU", GovernorState_Enabled_CpuGpu),
|
||||
NamedValue("CPU", GovernorState_Enabled_Cpu),
|
||||
NamedValue("GPU", GovernorState_Enabled_Gpu),
|
||||
NamedValue("VRR", GovernorState_Enabled_Vrr),
|
||||
};
|
||||
|
||||
std::vector<NamedValue> governorSettingsH = {
|
||||
NamedValue("Do Not Override", GovernorState_DoNotOverride),
|
||||
NamedValue("Disabled", GovernorState_Disabled),
|
||||
NamedValue("CPU + GPU", GovernorState_Enabled_CpuGpu),
|
||||
NamedValue("CPU", GovernorState_Enabled_Cpu),
|
||||
NamedValue("GPU", GovernorState_Enabled_Gpu),
|
||||
};
|
||||
|
||||
void GlobalOverrideGui::listUI()
|
||||
{
|
||||
@@ -306,24 +325,11 @@ void GlobalOverrideGui::listUI()
|
||||
this->addModuleListItem(SysClkModule_MEM);
|
||||
#if IS_MINIMAL == 0
|
||||
ValueThresholds lcdThresholds(60, 65);
|
||||
if(!IsHoag() && configList.values[HorizonOCConfigValue_OverwriteRefreshRate])
|
||||
if(configList.values[HorizonOCConfigValue_OverwriteRefreshRate] && !IsHoag())
|
||||
this->addModuleListItemValue(HorizonOCModule_Display, "Display", IsAula() ? 45 : 40, configList.values[HorizonOCConfigValue_EnableUnsafeDisplayFreqs] ? IsAula() ? 65 : 72 : 60, 1, " Hz", 1, 0, lcdThresholds);
|
||||
#endif
|
||||
|
||||
std::vector<NamedValue> governorSettingsE = {
|
||||
NamedValue("Do Not Override", GovernorState_DoNotOverride),
|
||||
NamedValue("Disabled", GovernorState_Disabled),
|
||||
NamedValue("CPU + GPU", GovernorState_Enabled_CpuGpu),
|
||||
NamedValue("CPU", GovernorState_Enabled_Cpu),
|
||||
NamedValue("GPU", GovernorState_Enabled_Gpu),
|
||||
};
|
||||
|
||||
std::vector<NamedValue> governorSettings = {
|
||||
NamedValue("Do Not Override", GovernorState_DoNotOverride),
|
||||
NamedValue("Disabled", GovernorState_Disabled),
|
||||
NamedValue("GPU", GovernorState_Enabled_Gpu),
|
||||
};
|
||||
this->addModuleListItemValue(HorizonOCModule_Governor, "Governor", 0, 0, 1, "", 1, 0, ValueThresholds(), configList.values[HorizonOCConfigValue_EnableExperimentalSettings] ?governorSettingsE : governorSettings, false);
|
||||
this->addModuleListItemValue(HorizonOCModule_Governor, "Governor", 0, 0, 1, "", 1, 0, ValueThresholds(), IsHoag() ? governorSettingsH : governorSettingsE, false);
|
||||
}
|
||||
|
||||
void GlobalOverrideGui::refresh()
|
||||
@@ -341,15 +347,8 @@ void GlobalOverrideGui::refresh()
|
||||
std::string displayText = FREQ_DEFAULT_TEXT;
|
||||
std::uint32_t currentValue = this->context->overrideFreqs[m];
|
||||
|
||||
std::vector<NamedValue> governorSettings = {
|
||||
NamedValue("Do Not Override", GovernorState_DoNotOverride),
|
||||
NamedValue("Disabled", GovernorState_Disabled),
|
||||
NamedValue("CPU + GPU", GovernorState_Enabled_CpuGpu),
|
||||
NamedValue("CPU", GovernorState_Enabled_Cpu),
|
||||
NamedValue("GPU", GovernorState_Enabled_Gpu),
|
||||
};
|
||||
|
||||
for (const auto& setting : governorSettings) {
|
||||
|
||||
for (const auto& setting : governorSettingsE) {
|
||||
if (setting.value == currentValue) {
|
||||
displayText = setting.name;
|
||||
break;
|
||||
|
||||
@@ -35,7 +35,7 @@ std::map<uint32_t, std::string> cpu_freq_label_e = {
|
||||
{1224000000, "Dev OC"},
|
||||
{1785000000, "Boost Mode & Safe Max"},
|
||||
{2091000000, "Unsafe Max"},
|
||||
{2295000000, "Absolute Max"},
|
||||
{2397000000, "Absolute Max"},
|
||||
};
|
||||
std::map<uint32_t, std::string> gpu_freq_label_e = {
|
||||
{76800000, "Boost Mode"},
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,3 @@
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright (c) Souldbminer, Lightos_ and Horizon OC Contributors
|
||||
@@ -19,12 +18,12 @@
|
||||
#pragma once
|
||||
#include "../../ipc.h"
|
||||
#include "base_menu_gui.h"
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "freq_choice_gui.h"
|
||||
#include "value_choice_gui.h"
|
||||
|
||||
class MiscGui : public BaseMenuGui
|
||||
{
|
||||
public:
|
||||
@@ -40,6 +39,8 @@ protected:
|
||||
std::map<SysClkConfigValue, std::vector<NamedValue>> configNamedValues;
|
||||
std::map<SysClkConfigValue, tsl::elm::ToggleListItem*> configToggles;
|
||||
std::map<SysClkConfigValue, std::tuple<tsl::elm::TrackBar*, tsl::elm::ListItem*, std::vector<uint64_t>>> configTrackbars;
|
||||
std::set<SysClkConfigValue> configButtonSKeys;
|
||||
std::map<SysClkConfigValue, std::string> configButtonSSubtext;
|
||||
|
||||
void addConfigToggle(SysClkConfigValue configVal, const char* altName);
|
||||
void addConfigButton(SysClkConfigValue configVal,
|
||||
@@ -50,6 +51,16 @@ protected:
|
||||
const std::map<uint32_t, std::string>& labels = {},
|
||||
const std::vector<NamedValue>& namedValues = {},
|
||||
bool showDefaultValue = true);
|
||||
|
||||
void addConfigButtonS(SysClkConfigValue configVal,
|
||||
const char* altName,
|
||||
const ValueRange& range,
|
||||
const std::string& categoryName,
|
||||
const ValueThresholds* thresholds,
|
||||
const std::map<uint32_t, std::string>& labels = {},
|
||||
const std::vector<NamedValue>& namedValues = {},
|
||||
bool showDefaultValue = true,
|
||||
const char* subText = nullptr);
|
||||
void addFreqButton(SysClkConfigValue configVal,
|
||||
const char* altName,
|
||||
SysClkModule module,
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
"main_thread_stack_size": "0x0000C000",
|
||||
"main_thread_priority": 16,
|
||||
"default_cpu_id": 3,
|
||||
"process_category": 0,
|
||||
"process_category": 1,
|
||||
"is_retail": true,
|
||||
"pool_partition": 2,
|
||||
"is_64_bit": true,
|
||||
"address_space_type": 1,
|
||||
"address_space_type": 3,
|
||||
"filesystem_access": {
|
||||
"permissions": "0xFFFFFFFFFFFFFFFF"
|
||||
},
|
||||
|
||||
@@ -276,11 +276,13 @@ void Board::Initialize()
|
||||
// threadStart(&cpuCore3Thread);
|
||||
threadStart(&miscThread);
|
||||
batteryInfoInitialize();
|
||||
FetchHardwareInfos();
|
||||
|
||||
if (hosversionAtLeast(6,0,0) && R_SUCCEEDED(pwmInitialize())) {
|
||||
pwmCheck = pwmOpenSession2(&g_ICon, 0x3D000001);
|
||||
}
|
||||
if(Board::GetConsoleType() != HorizonOCConsoleType_Hoag) {
|
||||
|
||||
if(!IsHoag()) {
|
||||
u64 clkVirtAddr, dsiVirtAddr, outsize;
|
||||
rc = svcQueryMemoryMapping(&clkVirtAddr, &outsize, 0x60006000, 0x1000);
|
||||
ASSERT_RESULT_OK(rc, "svcQueryMemoryMapping (clk)");
|
||||
@@ -292,9 +294,9 @@ void Board::Initialize()
|
||||
DisplayRefresh_Initialize(&cfg);
|
||||
}
|
||||
|
||||
FetchHardwareInfos();
|
||||
rc = svcQueryMemoryMapping(&cldvfs, &cldvfs_temp, CLDVFS_REGION_BASE, CLDVFS_REGION_SIZE);
|
||||
ASSERT_RESULT_OK(rc, "svcQueryMemoryMapping (cldvfs)");
|
||||
|
||||
if(Board::GetSocType() == SysClkSocType_Erista) {
|
||||
cachedEristaUvLowTune0 = *(u32*)(cldvfs + CL_DVFS_TUNE0_0);
|
||||
cachedEristaUvLowTune1 = *(u32*)(cldvfs + CL_DVFS_TUNE1_0);
|
||||
@@ -303,6 +305,8 @@ void Board::Initialize()
|
||||
cachedMarikoUvHighTune0 = *(u32*)(cldvfs + CL_DVFS_TUNE0_0);
|
||||
Board::ResetToStockCpu();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void Board::fuseReadSpeedos() {
|
||||
@@ -422,7 +426,7 @@ void Board::Exit()
|
||||
batteryInfoExit();
|
||||
pmdmntExit();
|
||||
nvExit();
|
||||
if(Board::GetConsoleType() != HorizonOCConsoleType_Hoag)
|
||||
if(!IsHoag())
|
||||
DisplayRefresh_Shutdown();
|
||||
}
|
||||
|
||||
@@ -457,8 +461,9 @@ SysClkProfile Board::GetProfile()
|
||||
void Board::SetHz(SysClkModule module, std::uint32_t hz)
|
||||
{
|
||||
Result rc = 0;
|
||||
if(module == HorizonOCModule_Display && Board::GetConsoleType() != HorizonOCConsoleType_Hoag) {
|
||||
DisplayRefresh_SetRate(hz);
|
||||
if(module == HorizonOCModule_Display) {
|
||||
if(!IsHoag())
|
||||
DisplayRefresh_SetRate(hz);
|
||||
return;
|
||||
}
|
||||
if(module > SysClkModule_MEM)
|
||||
@@ -496,7 +501,7 @@ std::uint32_t Board::GetHz(SysClkModule module)
|
||||
std::uint32_t hz = 0;
|
||||
|
||||
if(module == HorizonOCModule_Display) {
|
||||
if(Board::GetConsoleType() != HorizonOCConsoleType_Hoag)
|
||||
if(!IsHoag())
|
||||
DisplayRefresh_GetRate(&hz, false);
|
||||
else
|
||||
hz = 60;
|
||||
@@ -536,7 +541,7 @@ std::uint32_t Board::GetRealHz(SysClkModule module)
|
||||
case SysClkModule_MEM:
|
||||
return t210ClkMemFreq();
|
||||
case HorizonOCModule_Display:
|
||||
if(Board::GetConsoleType() != HorizonOCConsoleType_Hoag)
|
||||
if(!IsHoag())
|
||||
DisplayRefresh_GetRate(&hz, false);
|
||||
else
|
||||
hz = 60;
|
||||
@@ -734,9 +739,8 @@ void Board::ResetToStockGpu()
|
||||
}
|
||||
|
||||
void Board::ResetToStockDisplay() {
|
||||
if(Board::GetConsoleType() != HorizonOCConsoleType_Hoag) {
|
||||
if(!IsHoag())
|
||||
DisplayRefresh_SetRate(60);
|
||||
}
|
||||
}
|
||||
|
||||
u8 Board::GetHighestDockedDisplayRate() {
|
||||
@@ -1249,7 +1253,6 @@ MarikoCpuUvEntry marikoCpuUvHigh[12] = {
|
||||
{0x0, 0xdfff, 0, 0x27f07ff},
|
||||
};
|
||||
void Board::SetCpuUvLevel(u32 levelLow, u32 levelHigh, u32 tbreakPoint) {
|
||||
|
||||
u32* tune0_ptr = (u32*)(cldvfs + CL_DVFS_TUNE0_0);
|
||||
u32* tune1_ptr = (u32*)(cldvfs + CL_DVFS_TUNE1_0);
|
||||
if(Board::GetSocType() == SysClkSocType_Mariko) {
|
||||
@@ -1318,4 +1321,8 @@ u32 Board::CalculateTbreak(u32 table) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool Board::IsHoag() {
|
||||
return Board::GetConsoleType() == HorizonOCConsoleType_Hoag;
|
||||
}
|
||||
@@ -68,6 +68,7 @@ class Board
|
||||
static void SetDisplayRefreshDockedState(bool docked);
|
||||
static void SetCpuUvLevel(u32 levelLow, u32 levelHigh, u32 tbreakPoint);
|
||||
static u32 CalculateTbreak(u32 table);
|
||||
static bool IsHoag();
|
||||
protected:
|
||||
static void FetchHardwareInfos();
|
||||
static PcvModule GetPcvModule(SysClkModule sysclkModule);
|
||||
|
||||
@@ -40,20 +40,27 @@
|
||||
#include <cstdio>
|
||||
#include <crc32.h>
|
||||
|
||||
|
||||
#define HOSPPC_HAS_BOOST (hosversionAtLeast(7,0,0))
|
||||
|
||||
// governor constants
|
||||
#define POLL_NS 5'000'000 // 5 ms – governor poll rate
|
||||
#define DOWN_HOLD_TICKS 10 // 50 ms – how long to in POLL_NS to hold while ramping down
|
||||
#define STEP_UTIL 900 // multiplier for step calculations
|
||||
|
||||
bool isGpuGovernorEnabled = false;
|
||||
bool isCpuGovernorEnabled = false;
|
||||
bool lastGpuGovernorState = false;
|
||||
bool lastCpuGovernorState = false;
|
||||
bool lastVrrGovernorState = false;
|
||||
bool hasChanged = true;
|
||||
ClockManager *ClockManager::instance = NULL;
|
||||
Thread cpuGovernorTHREAD;
|
||||
Thread gpuGovernorTHREAD;
|
||||
Thread vrrTHREAD;
|
||||
u32 initialConfigValues[SysClkConfigValue_EnumMax]; // initial config. used for safety checks
|
||||
bool kipAvailable = false;
|
||||
bool isCpuGovernorInBoostMode = false;
|
||||
|
||||
bool isVRREnabled = false;
|
||||
ClockManager *ClockManager::GetInstance()
|
||||
{
|
||||
return instance;
|
||||
@@ -94,6 +101,8 @@ ClockManager::ClockManager()
|
||||
this->lastCsvWriteNs = 0;
|
||||
|
||||
this->sysDockIntegration = new SysDockIntegration;
|
||||
this->saltyNXIntegration = new SaltyNXIntegration;
|
||||
|
||||
memset(&initialConfigValues, 0, sizeof(initialConfigValues));
|
||||
this->GetKipData();
|
||||
|
||||
@@ -117,8 +126,15 @@ ClockManager::ClockManager()
|
||||
-2
|
||||
);
|
||||
|
||||
threadStart(&cpuGovernorTHREAD);
|
||||
threadStart(&gpuGovernorTHREAD);
|
||||
threadCreate(
|
||||
&vrrTHREAD,
|
||||
ClockManager::VRRThread,
|
||||
this,
|
||||
NULL,
|
||||
0x2000,
|
||||
0x3F,
|
||||
-2
|
||||
);
|
||||
|
||||
for(int i = 0; i < HorizonOCSpeedo_EnumMax; i++) {
|
||||
this->context->speedos[i] = Board::getSpeedo((HorizonOCSpeedo)i);
|
||||
@@ -129,13 +145,27 @@ ClockManager::ClockManager()
|
||||
this->context->isDram8GB = Board::IsDram8GB();
|
||||
Board::SetGpuSchedulingMode((GpuSchedulingMode)this->config->GetConfigValue(HorizonOCConfigValue_GPUScheduling), (GpuSchedulingOverrideMethod)this->config->GetConfigValue(HorizonOCConfigValue_GPUSchedulingMethod));
|
||||
this->context->gpuSchedulingMode = (GpuSchedulingMode)this->config->GetConfigValue(HorizonOCConfigValue_GPUScheduling);
|
||||
|
||||
this->context->isSysDockInstalled = this->sysDockIntegration->getCurrentSysDockState();
|
||||
this->context->isSaltyNXInstalled = this->saltyNXIntegration->getCurrentSaltyNXState();
|
||||
if(this->context->isSaltyNXInstalled) {
|
||||
this->saltyNXIntegration->LoadSaltyNX();
|
||||
}
|
||||
|
||||
|
||||
threadStart(&cpuGovernorTHREAD);
|
||||
threadStart(&gpuGovernorTHREAD);
|
||||
threadStart(&vrrTHREAD);
|
||||
}
|
||||
|
||||
ClockManager::~ClockManager()
|
||||
{
|
||||
threadClose(&cpuGovernorTHREAD);
|
||||
threadClose(&gpuGovernorTHREAD);
|
||||
threadClose(&vrrTHREAD);
|
||||
|
||||
delete this->sysDockIntegration;
|
||||
delete this->saltyNXIntegration;
|
||||
delete this->config;
|
||||
delete this->context;
|
||||
}
|
||||
@@ -309,319 +339,233 @@ void ClockManager::RefreshFreqTableRow(SysClkModule module)
|
||||
FileUtils::LogLine("[mgr] count = %u", this->freqTable[module].count);
|
||||
}
|
||||
|
||||
u32 findIndex(u32 arr[], u32 size, u32 value) {
|
||||
for (u32 i = 0; i < size; i++) {
|
||||
if (arr[i] == value) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
u32 ClockManager::SchedutilTargetHz(u32 util, u32 tableMaxHz) {
|
||||
u64 hz = (u64)tableMaxHz * util / STEP_UTIL;
|
||||
return (u32)(std::min(hz, static_cast<u64>(tableMaxHz)));
|
||||
}
|
||||
|
||||
u32 findIndexMHz(u32 arr[], u32 size, u32 value) {
|
||||
for (u32 i = 0; i < size; i++) {
|
||||
if (arr[i] / 1000000 == value) {
|
||||
u32 ClockManager::TableIndexForHz(const FreqTable& table, u32 targetHz) { // must pass in a freqTable as tables are different for cpu/gpu
|
||||
for (u32 i = 0; i < table.count; i++)
|
||||
if (table.list[i] >= targetHz)
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return table.count - 1;
|
||||
}
|
||||
|
||||
void ClockManager::CpuGovernorThread(void* arg)
|
||||
{
|
||||
u32 ClockManager::ResolveTargetHz(ClockManager* mgr, SysClkModule module) {
|
||||
u32 hz = mgr->context->overrideFreqs[module];
|
||||
if (!hz)
|
||||
hz = mgr->config->GetAutoClockHz(
|
||||
mgr->context->applicationId, module,
|
||||
mgr->context->profile, false);
|
||||
if (!hz)
|
||||
hz = mgr->config->GetAutoClockHz(
|
||||
GLOBAL_PROFILE_ID, module,
|
||||
mgr->context->profile, false);
|
||||
return hz;
|
||||
}
|
||||
|
||||
void ClockManager::CpuGovernorThread(void* arg) {
|
||||
ClockManager* mgr = static_cast<ClockManager*>(arg);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (!mgr->running)
|
||||
{
|
||||
svcSleepThread(50'000'000);
|
||||
u32 downHoldRemaining = 0;
|
||||
u32 lastHz = 0;
|
||||
|
||||
for (;;) {
|
||||
if (!mgr->running || !isCpuGovernorEnabled) {
|
||||
downHoldRemaining = 0;
|
||||
lastHz = 0;
|
||||
svcSleepThread(POLL_NS);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isCpuGovernorEnabled)
|
||||
{
|
||||
svcSleepThread(50'000'000);
|
||||
continue;
|
||||
}
|
||||
u32 mode = 0;
|
||||
Result rc = apmExtGetCurrentPerformanceConfiguration(&mode);
|
||||
|
||||
std::uint32_t mode = 0;
|
||||
Result rc = apmExtGetCurrentPerformanceConfiguration(&mode);
|
||||
bool isInBoostMode = R_SUCCEEDED(rc) && apmExtIsBoostMode(mode);
|
||||
|
||||
if (isInBoostMode)
|
||||
{
|
||||
if (R_SUCCEEDED(rc) && apmExtIsBoostMode(mode)) {
|
||||
isCpuGovernorInBoostMode = true;
|
||||
svcSleepThread(50'000'000);
|
||||
continue;
|
||||
downHoldRemaining = 0;
|
||||
lastHz = 0;
|
||||
continue; // TODO: figure out a way to get boost clock easily and set it instead of just skipping the governor
|
||||
} else if(!apmExtIsBoostMode(mode)) {
|
||||
isCpuGovernorInBoostMode = false;
|
||||
}
|
||||
|
||||
isCpuGovernorInBoostMode = false;
|
||||
|
||||
auto& table = mgr->freqTable[SysClkModule_CPU];
|
||||
|
||||
if (table.count == 0)
|
||||
{
|
||||
svcSleepThread(50'000'000);
|
||||
continue;
|
||||
}
|
||||
|
||||
std::scoped_lock lock{mgr->contextMutex};
|
||||
|
||||
u32 currentHz = Board::GetHz(SysClkModule_CPU);
|
||||
|
||||
u32 index = table.count - 1;
|
||||
for (u32 i = 0; i < table.count; i++)
|
||||
{
|
||||
if (table.list[i] == currentHz)
|
||||
{
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (table.list[index] != currentHz)
|
||||
{
|
||||
for (u32 i = 0; i < table.count; i++)
|
||||
{
|
||||
if (table.list[i] >= currentHz)
|
||||
{
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u32 targetHz = mgr->context->overrideFreqs[SysClkModule_CPU];
|
||||
if (!targetHz)
|
||||
{
|
||||
targetHz = mgr->config->GetAutoClockHz(
|
||||
mgr->context->applicationId,
|
||||
SysClkModule_CPU,
|
||||
mgr->context->profile,
|
||||
false
|
||||
);
|
||||
|
||||
if (!targetHz)
|
||||
{
|
||||
targetHz = mgr->config->GetAutoClockHz(
|
||||
GLOBAL_PROFILE_ID,
|
||||
SysClkModule_CPU,
|
||||
mgr->context->profile,
|
||||
false
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
int gpuLoad = Board::GetPartLoad(HocClkPartLoad_GPU);
|
||||
int cpuLoad = Board::GetPartLoad(HocClkPartLoad_CPUMax);
|
||||
|
||||
if (isGpuGovernorEnabled && gpuLoad < 800)
|
||||
{
|
||||
if (cpuLoad < 600 && index > 0)
|
||||
{
|
||||
index--;
|
||||
}
|
||||
else if (cpuLoad > 800 && index + 1 < table.count)
|
||||
{
|
||||
index++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cpuLoad < 600 && index > 0)
|
||||
{
|
||||
index--;
|
||||
}
|
||||
else if (cpuLoad > 800 && index + 1 < table.count)
|
||||
{
|
||||
index++;
|
||||
}
|
||||
}
|
||||
u32 cpuLoad = Board::GetPartLoad(HocClkPartLoad_CPUMax);
|
||||
|
||||
u32 tableMaxHz = table.list[table.count - 1];
|
||||
u32 desiredHz = ClockManager::SchedutilTargetHz(cpuLoad, tableMaxHz);
|
||||
u32 targetHz = ClockManager::ResolveTargetHz(mgr, SysClkModule_CPU);
|
||||
u32 maxHz = mgr->GetMaxAllowedHz(SysClkModule_CPU, mgr->context->profile);
|
||||
|
||||
if (targetHz)
|
||||
{
|
||||
u32 targetIndex = table.count - 1;
|
||||
for (u32 i = 0; i < table.count; i++)
|
||||
{
|
||||
if (table.list[i] >= targetHz)
|
||||
{
|
||||
targetIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (targetHz && desiredHz > targetHz)
|
||||
desiredHz = targetHz;
|
||||
|
||||
if (index > targetIndex)
|
||||
{
|
||||
index = targetIndex;
|
||||
}
|
||||
}
|
||||
if (maxHz && desiredHz > maxHz)
|
||||
desiredHz = maxHz;
|
||||
|
||||
if (maxHz > 0 && table.list[index] > maxHz)
|
||||
{
|
||||
for (u32 i = table.count; i > 0; i--)
|
||||
{
|
||||
if (table.list[i - 1] <= maxHz)
|
||||
{
|
||||
index = i - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
u32 newHz = table.list[ClockManager::TableIndexForHz(table, desiredHz)];
|
||||
|
||||
u32 newHz = table.list[index];
|
||||
if (mgr->IsAssignableHz(SysClkModule_CPU, newHz))
|
||||
{
|
||||
// ramp up fast, go down slow
|
||||
bool goingDown = (lastHz != 0) && (newHz < lastHz);
|
||||
|
||||
if (!goingDown)
|
||||
downHoldRemaining = 0;
|
||||
else if (downHoldRemaining == 0)
|
||||
downHoldRemaining = DOWN_HOLD_TICKS;
|
||||
|
||||
if (downHoldRemaining > 0)
|
||||
downHoldRemaining--;
|
||||
|
||||
if ((!goingDown || (downHoldRemaining == 0)) && mgr->IsAssignableHz(SysClkModule_CPU, newHz)) {
|
||||
Board::SetHz(SysClkModule_CPU, newHz);
|
||||
mgr->context->freqs[SysClkModule_CPU] = newHz;
|
||||
lastHz = newHz;
|
||||
}
|
||||
|
||||
svcSleepThread(50'000'000);
|
||||
svcSleepThread(POLL_NS);
|
||||
}
|
||||
}
|
||||
|
||||
void ClockManager::GovernorThread(void* arg)
|
||||
{
|
||||
void ClockManager::GovernorThread(void* arg) {
|
||||
ClockManager* mgr = static_cast<ClockManager*>(arg);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (!mgr->running)
|
||||
{
|
||||
svcSleepThread(50'000'000);
|
||||
continue;
|
||||
}
|
||||
u32 downHoldRemaining = 0;
|
||||
u32 lastHz = 0;
|
||||
|
||||
if (!isGpuGovernorEnabled)
|
||||
{
|
||||
svcSleepThread(50'000'000);
|
||||
for (;;) {
|
||||
if (!mgr->running || !isGpuGovernorEnabled) {
|
||||
downHoldRemaining = 0;
|
||||
lastHz = 0;
|
||||
svcSleepThread(POLL_NS);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto& table = mgr->freqTable[SysClkModule_GPU];
|
||||
if (table.count == 0)
|
||||
{
|
||||
svcSleepThread(50'000'000);
|
||||
continue;
|
||||
|
||||
std::scoped_lock lock{mgr->contextMutex};
|
||||
|
||||
u32 gpuLoad = Board::GetPartLoad(HocClkPartLoad_GPU);
|
||||
u32 tableMaxHz = table.list[table.count - 1];
|
||||
u32 desiredHz = ClockManager::SchedutilTargetHz(gpuLoad, tableMaxHz);
|
||||
u32 targetHz = ClockManager::ResolveTargetHz(mgr, SysClkModule_GPU);
|
||||
u32 maxHz = mgr->GetMaxAllowedHz(SysClkModule_GPU, mgr->context->profile);
|
||||
|
||||
if (targetHz && desiredHz > targetHz)
|
||||
desiredHz = targetHz;
|
||||
|
||||
if (maxHz && desiredHz > maxHz)
|
||||
desiredHz = maxHz;
|
||||
|
||||
u32 newHz = table.list[ClockManager::TableIndexForHz(table, desiredHz)];
|
||||
bool goingDown = (lastHz != 0) && (newHz < lastHz);
|
||||
|
||||
if (!goingDown)
|
||||
downHoldRemaining = 0;
|
||||
else if (downHoldRemaining == 0)
|
||||
downHoldRemaining = DOWN_HOLD_TICKS;
|
||||
|
||||
if (downHoldRemaining > 0)
|
||||
downHoldRemaining--;
|
||||
|
||||
if ((!goingDown || (downHoldRemaining == 0)) && mgr->IsAssignableHz(SysClkModule_GPU, newHz)) {
|
||||
Board::SetHz(SysClkModule_GPU, newHz);
|
||||
mgr->context->freqs[SysClkModule_GPU] = newHz;
|
||||
lastHz = newHz;
|
||||
}
|
||||
|
||||
svcSleepThread(POLL_NS);
|
||||
}
|
||||
}
|
||||
|
||||
void ClockManager::VRRThread(void* arg) {
|
||||
ClockManager* mgr = static_cast<ClockManager*>(arg);
|
||||
u8 tick = 0;
|
||||
for (;;) {
|
||||
if (!mgr->running || mgr->context->profile == SysClkProfile_Docked || !isVRREnabled) {
|
||||
svcSleepThread(POLL_NS);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(Board::IsHoag()) { // don't do anything on lite
|
||||
svcSleepThread(~0ULL);
|
||||
continue;
|
||||
}
|
||||
|
||||
std::scoped_lock lock{mgr->contextMutex};
|
||||
|
||||
u32 currentHz = Board::GetHz(SysClkModule_GPU);
|
||||
u8 fps;
|
||||
|
||||
u32 index = table.count - 1;
|
||||
for (u32 i = 0; i < table.count; i++)
|
||||
{
|
||||
if (table.list[i] == currentHz)
|
||||
{
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
if(mgr->context->isSaltyNXInstalled) {
|
||||
fps = mgr->saltyNXIntegration->GetFPS();
|
||||
} else {
|
||||
svcSleepThread(~0ULL); // effectively disable the thread if SaltyNX isn't installed, as there's no point in it running
|
||||
continue;
|
||||
}
|
||||
|
||||
if (table.list[index] != currentHz)
|
||||
{
|
||||
for (u32 i = 0; i < table.count; i++)
|
||||
{
|
||||
if (table.list[i] >= currentHz)
|
||||
{
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u32 targetHz = mgr->context->overrideFreqs[SysClkModule_GPU];
|
||||
if(fps == 254) {
|
||||
svcSleepThread(POLL_NS);
|
||||
continue;
|
||||
}
|
||||
// if(appletGetFocusState() != AppletFocusState_InFocus) {
|
||||
// Board::ResetToStockDisplay();
|
||||
// continue;
|
||||
// }
|
||||
|
||||
u32 targetHz = mgr->context->overrideFreqs[HorizonOCModule_Display];
|
||||
if (!targetHz)
|
||||
{
|
||||
targetHz = mgr->config->GetAutoClockHz(
|
||||
mgr->context->applicationId,
|
||||
SysClkModule_GPU,
|
||||
mgr->context->profile,
|
||||
false
|
||||
);
|
||||
targetHz = mgr->config->GetAutoClockHz(mgr->context->applicationId, HorizonOCModule_Display, mgr->context->profile, false);
|
||||
if(!targetHz)
|
||||
targetHz = mgr->config->GetAutoClockHz(GLOBAL_PROFILE_ID, HorizonOCModule_Display, mgr->context->profile, false);
|
||||
}
|
||||
|
||||
if (!targetHz)
|
||||
{
|
||||
targetHz = mgr->config->GetAutoClockHz(
|
||||
GLOBAL_PROFILE_ID,
|
||||
SysClkModule_GPU,
|
||||
mgr->context->profile,
|
||||
false
|
||||
);
|
||||
u8 maxDisplay;
|
||||
if(targetHz) {
|
||||
maxDisplay = targetHz;
|
||||
} else {
|
||||
if(Board::GetConsoleType() == HorizonOCConsoleType_Aula) {
|
||||
maxDisplay = mgr->config->GetConfigValue(HorizonOCConfigValue_EnableUnsafeDisplayFreqs) ? 65 : 60;
|
||||
} else {
|
||||
maxDisplay = mgr->config->GetConfigValue(HorizonOCConfigValue_EnableUnsafeDisplayFreqs) ? 72 : 60;
|
||||
}
|
||||
}
|
||||
|
||||
int gpuLoad = Board::GetPartLoad(HocClkPartLoad_GPU);
|
||||
int cpuLoad = Board::GetPartLoad(HocClkPartLoad_CPUMax);
|
||||
u8 minDisplay = Board::GetConsoleType() == HorizonOCConsoleType_Aula ? 45 : 40;
|
||||
if(maxDisplay == minDisplay)
|
||||
continue;
|
||||
|
||||
if (isCpuGovernorEnabled && !isCpuGovernorInBoostMode && cpuLoad < 600)
|
||||
{
|
||||
if (gpuLoad < 600 && index > 0)
|
||||
{
|
||||
index--;
|
||||
}
|
||||
else if (gpuLoad > 750 && index + 1 < table.count)
|
||||
{
|
||||
index++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gpuLoad < 600 && index > 0)
|
||||
{
|
||||
index--;
|
||||
}
|
||||
else if (gpuLoad > 800 && index + 1 < table.count)
|
||||
{
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
u32 maxHz = mgr->GetMaxAllowedHz(SysClkModule_GPU, mgr->context->profile);
|
||||
|
||||
if (targetHz)
|
||||
{
|
||||
u32 targetIndex = table.count - 1;
|
||||
for (u32 i = 0; i < table.count; i++)
|
||||
{
|
||||
if (table.list[i] >= targetHz)
|
||||
{
|
||||
targetIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index > targetIndex)
|
||||
{
|
||||
index = targetIndex;
|
||||
}
|
||||
}
|
||||
|
||||
if (maxHz > 0 && table.list[index] > maxHz)
|
||||
{
|
||||
for (u32 i = table.count; i > 0; i--)
|
||||
{
|
||||
if (table.list[i - 1] <= maxHz)
|
||||
{
|
||||
index = i - 1;
|
||||
if(fps >= minDisplay && fps <= maxDisplay)
|
||||
Board::SetHz(HorizonOCModule_Display, fps);
|
||||
else {
|
||||
for(u32 i = 0; i < 10; i++) {
|
||||
u32 compareHz = fps * i;
|
||||
if(compareHz >= minDisplay && compareHz <= maxDisplay) {
|
||||
Board::SetHz(HorizonOCModule_Display, compareHz);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u32 newHz = table.list[index];
|
||||
if (mgr->IsAssignableHz(SysClkModule_GPU, newHz))
|
||||
{
|
||||
Board::SetHz(SysClkModule_GPU, newHz);
|
||||
mgr->context->freqs[SysClkModule_GPU] = newHz;
|
||||
if(++tick > 50) {
|
||||
Board::ResetToStockDisplay();
|
||||
tick = 0;
|
||||
svcSleepThread(25'000'000);
|
||||
}
|
||||
|
||||
svcSleepThread(50'000'000);
|
||||
svcSleepThread(POLL_NS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
GovernorState ClockManager::GetEffectiveGovernorState(GovernorState appState, GovernorState tempState)
|
||||
{
|
||||
if (tempState == GovernorState_Disabled)
|
||||
@@ -677,25 +621,41 @@ void ClockManager::HandleGovernor(uint32_t targetHz) {
|
||||
|
||||
GovernorState effectiveState = this->GetEffectiveGovernorState(appGovernorState, tempGovernorState);
|
||||
|
||||
bool newCpuGovernorState = (effectiveState == GovernorState_Enabled_CpuGpu || effectiveState == GovernorState_Enabled_Cpu);
|
||||
bool newGpuGovernorState = (effectiveState == GovernorState_Enabled_CpuGpu || effectiveState == GovernorState_Enabled_Gpu);
|
||||
bool newCpuGovernorState = (effectiveState == GovernorState_Enabled_CpuGpuVrr ||
|
||||
effectiveState == GovernorState_Enabled_CpuVrr ||
|
||||
effectiveState == GovernorState_Enabled_CpuGpu ||
|
||||
effectiveState == GovernorState_Enabled_Cpu);
|
||||
|
||||
bool newGpuGovernorState = (effectiveState == GovernorState_Enabled_CpuGpuVrr ||
|
||||
effectiveState == GovernorState_Enabled_GpuVrr ||
|
||||
effectiveState == GovernorState_Enabled_CpuGpu ||
|
||||
effectiveState == GovernorState_Enabled_Gpu);
|
||||
|
||||
bool newVrrGovernorState = (effectiveState == GovernorState_Enabled_CpuGpuVrr ||
|
||||
effectiveState == GovernorState_Enabled_CpuVrr ||
|
||||
effectiveState == GovernorState_Enabled_GpuVrr ||
|
||||
effectiveState == GovernorState_Enabled_Vrr);
|
||||
|
||||
isCpuGovernorEnabled = newCpuGovernorState;
|
||||
isGpuGovernorEnabled = newGpuGovernorState;
|
||||
|
||||
isVRREnabled = newVrrGovernorState;
|
||||
if(newCpuGovernorState == false && lastCpuGovernorState == true) {
|
||||
svcSleepThread(150'000'000); // thread syncing. probably a cleaner way to do this but hey, it works!
|
||||
svcSleepThread(50'000'000); // thread syncing. probably a cleaner way to do this but hey, it works!
|
||||
Board::ResetToStockCpu();
|
||||
}
|
||||
if(newGpuGovernorState == false && lastGpuGovernorState == true) {
|
||||
svcSleepThread(150'000'000);
|
||||
svcSleepThread(50'000'000);
|
||||
Board::ResetToStockGpu();
|
||||
}
|
||||
|
||||
if(newCpuGovernorState != lastCpuGovernorState || newGpuGovernorState != lastGpuGovernorState) {
|
||||
FileUtils::LogLine("[mgr] Governor state changed: CPU %s, GPU %s", newCpuGovernorState ? "enabled" : "disabled", newGpuGovernorState ? "enabled" : "disabled");
|
||||
if (newVrrGovernorState == false && lastVrrGovernorState == true) {
|
||||
svcSleepThread(50'000'000);
|
||||
Board::ResetToStockDisplay();
|
||||
}
|
||||
if(newCpuGovernorState != lastCpuGovernorState || newGpuGovernorState != lastGpuGovernorState || newVrrGovernorState != lastVrrGovernorState) {
|
||||
FileUtils::LogLine("[mgr] Governor state changed: CPU %s, GPU %s, VRR %s", newCpuGovernorState ? "enabled" : "disabled", newGpuGovernorState ? "enabled" : "disabled", newVrrGovernorState ? "enabled" : "disabled");
|
||||
lastCpuGovernorState = newCpuGovernorState;
|
||||
lastGpuGovernorState = newGpuGovernorState;
|
||||
lastVrrGovernorState = newVrrGovernorState;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -712,6 +672,7 @@ void ClockManager::DVFSBeforeSet(u32 targetHz) {
|
||||
|
||||
this->context->voltages[HocClkVoltage_GPU] = vmin * 1000;
|
||||
}
|
||||
|
||||
void ClockManager::DVFSAfterSet(u32 targetHz) {
|
||||
s32 dvfsOffset = this->config->GetConfigValue(HorizonOCConfigValue_DVFSOffset);
|
||||
dvfsOffset = std::max(dvfsOffset, -50);
|
||||
@@ -725,9 +686,16 @@ void ClockManager::DVFSAfterSet(u32 targetHz) {
|
||||
if(!targetHz)
|
||||
targetHz = this->config->GetAutoClockHz(GLOBAL_PROFILE_ID, SysClkModule_GPU, this->context->profile, false);
|
||||
}
|
||||
|
||||
u32 maxHz = this->GetMaxAllowedHz(SysClkModule_GPU, this->context->profile);
|
||||
u32 nearestHz = this->GetNearestHz(SysClkModule_GPU, targetHz, maxHz);
|
||||
|
||||
if(targetHz) {
|
||||
Board::SetHz(SysClkModule_GPU, ~0);
|
||||
Board::SetHz(SysClkModule_GPU, targetHz);
|
||||
Board::SetHz(SysClkModule_GPU, nearestHz);
|
||||
} else {
|
||||
Board::SetHz(SysClkModule_GPU, ~0);
|
||||
Board::ResetToStockGpu();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -781,6 +749,12 @@ void ClockManager::HandleFreqReset(SysClkModule module, bool isBoost) {
|
||||
case SysClkModule_MEM:
|
||||
Board::ResetToStockMem();
|
||||
DVFSReset();
|
||||
break;
|
||||
case HorizonOCModule_Display:
|
||||
if(this->config->GetConfigValue(HorizonOCConfigValue_OverwriteRefreshRate) && !Board::IsHoag()) {
|
||||
Board::ResetToStockDisplay();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -803,7 +777,7 @@ void ClockManager::SetClocks(bool isBoost) {
|
||||
bool returnRaw = false; // Return a value scaled to MHz instead of raw value
|
||||
for (unsigned int module = 0; module < SysClkModule_EnumMax; module++)
|
||||
{
|
||||
u32 oldHz = Board::GetHz((SysClkModule)module); // Get Old RAM hz (used primarily for DVFS Logic)
|
||||
u32 oldHz = Board::GetHz((SysClkModule)module); // Get Old hz (used primarily for DVFS Logic)
|
||||
|
||||
if(module > SysClkModule_MEM)
|
||||
returnRaw = true;
|
||||
@@ -821,11 +795,19 @@ void ClockManager::SetClocks(bool isBoost) {
|
||||
HandleGovernor(targetHz);
|
||||
}
|
||||
|
||||
if(module == HorizonOCModule_Display && this->config->GetConfigValue(HorizonOCConfigValue_OverwriteRefreshRate) && Board::GetConsoleType() != HorizonOCConsoleType_Hoag) {
|
||||
if(targetHz)
|
||||
Board::SetHz(HorizonOCModule_Display, targetHz);
|
||||
else
|
||||
Board::ResetToStockDisplay();
|
||||
bool noCPU = isCpuGovernorEnabled;
|
||||
bool noGPU = isGpuGovernorEnabled;
|
||||
if(!Board::IsHoag()) {
|
||||
bool noDisp = isVRREnabled;
|
||||
if(noDisp && module == HorizonOCModule_Display)
|
||||
continue;
|
||||
|
||||
if(module == HorizonOCModule_Display && this->config->GetConfigValue(HorizonOCConfigValue_OverwriteRefreshRate)) {
|
||||
if(targetHz)
|
||||
Board::SetHz(HorizonOCModule_Display, targetHz);
|
||||
else
|
||||
Board::ResetToStockDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
// Skip GPU and CPU if governors handle them
|
||||
@@ -833,8 +815,6 @@ void ClockManager::SetClocks(bool isBoost) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool noCPU = isCpuGovernorEnabled;
|
||||
bool noGPU = isGpuGovernorEnabled;
|
||||
|
||||
if(noCPU && module == SysClkModule_CPU)
|
||||
continue;
|
||||
@@ -861,8 +841,7 @@ void ClockManager::SetClocks(bool isBoost) {
|
||||
Board::SetHz((SysClkModule)module, nearestHz);
|
||||
this->context->freqs[module] = nearestHz;
|
||||
|
||||
if(module == SysClkModule_CPU && this->config->GetConfigValue(HorizonOCConfigValue_LiveCpuUv))
|
||||
{
|
||||
if(module == SysClkModule_CPU && (this->config->GetConfigValue(HorizonOCConfigValue_LiveCpuUv))) {
|
||||
HandleCpuUv();
|
||||
}
|
||||
|
||||
@@ -1033,21 +1012,25 @@ bool ClockManager::RefreshContext()
|
||||
}
|
||||
|
||||
// this->context->maxDisplayFreq = Board::GetHighestDockedDisplayRate();
|
||||
if(!Board::IsHoag()) {
|
||||
u32 targetHz = this->context->overrideFreqs[HorizonOCModule_Display];
|
||||
if (!targetHz)
|
||||
{
|
||||
targetHz = this->config->GetAutoClockHz(this->context->applicationId, HorizonOCModule_Display, this->context->profile, true);
|
||||
if(!targetHz)
|
||||
targetHz = this->config->GetAutoClockHz(GLOBAL_PROFILE_ID, HorizonOCModule_Display, this->context->profile, true);
|
||||
}
|
||||
|
||||
u32 targetHz = this->context->overrideFreqs[HorizonOCModule_Display];
|
||||
if (!targetHz)
|
||||
{
|
||||
targetHz = this->config->GetAutoClockHz(this->context->applicationId, HorizonOCModule_Display, this->context->profile, true);
|
||||
if(!targetHz)
|
||||
targetHz = this->config->GetAutoClockHz(GLOBAL_PROFILE_ID, HorizonOCModule_Display, this->context->profile, true);
|
||||
}
|
||||
if(targetHz && this->context->realFreqs[HorizonOCModule_Display] > targetHz && this->context->profile != SysClkProfile_Docked)
|
||||
this->context->realFreqs[HorizonOCModule_Display] = targetHz; // clean up display real freqs, should probably be moved to the real freqs loop?
|
||||
|
||||
if(targetHz && this->context->realFreqs[HorizonOCModule_Display] > targetHz && this->context->profile != SysClkProfile_Docked)
|
||||
this->context->realFreqs[HorizonOCModule_Display] = targetHz; // clean up display real freqs, should probably be moved to the real freqs loop?
|
||||
|
||||
if(Board::GetConsoleType() != HorizonOCConsoleType_Hoag)
|
||||
Board::SetDisplayRefreshDockedState(this->context->profile == SysClkProfile_Docked);
|
||||
|
||||
}
|
||||
if(this->context->isSaltyNXInstalled)
|
||||
this->context->fps = saltyNXIntegration->GetFPS();
|
||||
else
|
||||
this->context->fps = 254; // N/A
|
||||
|
||||
return hasChanged;
|
||||
}
|
||||
|
||||
@@ -1126,11 +1109,11 @@ void ClockManager::SetKipData() {
|
||||
CUST_WRITE_FIELD_BATCH(&table, commonGpuVoltOffset, this->config->GetConfigValue(KipConfigValue_commonGpuVoltOffset));
|
||||
CUST_WRITE_FIELD_BATCH(&table, gpuSpeedo, this->config->GetConfigValue(KipConfigValue_gpuSpeedo));
|
||||
|
||||
for (int i = 0; i < 31; i++) {
|
||||
for (int i = 0; i < 24; i++) {
|
||||
table.marikoGpuVoltArray[i] = this->config->GetConfigValue((SysClkConfigValue)(KipConfigValue_g_volt_76800 + i));
|
||||
}
|
||||
|
||||
for (int i = 0; i < 24; i++) {
|
||||
for (int i = 0; i < 27; i++) {
|
||||
table.eristaGpuVoltArray[i] = this->config->GetConfigValue((SysClkConfigValue)(KipConfigValue_g_volt_e_76800 + i));
|
||||
}
|
||||
|
||||
@@ -1298,12 +1281,12 @@ void ClockManager::GetKipData() {
|
||||
configValues.values[KipConfigValue_commonGpuVoltOffset] = cust_get_common_gpu_offset(&table);
|
||||
configValues.values[KipConfigValue_gpuSpeedo] = Board::getSpeedo(HorizonOCSpeedo_GPU); // cust_get_gpu_speedo(&table);
|
||||
|
||||
for (int i = 0; i < 31; i++) {
|
||||
for (int i = 0; i < 24; i++) {
|
||||
configValues.values[KipConfigValue_g_volt_76800 + i] = cust_get_mariko_gpu_volt(&table, i);
|
||||
initialConfigValues[KipConfigValue_g_volt_76800 + i] = cust_get_mariko_gpu_volt(&table, i);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 24; i++) {
|
||||
for (int i = 0; i < 27; i++) {
|
||||
configValues.values[KipConfigValue_g_volt_e_76800 + i] = cust_get_erista_gpu_volt(&table, i);
|
||||
initialConfigValues[KipConfigValue_g_volt_e_76800 + i] = cust_get_erista_gpu_volt(&table, i);
|
||||
}
|
||||
@@ -1329,4 +1312,4 @@ void ClockManager::GetKipData() {
|
||||
FileUtils::LogLine("[clock_manager] Config refresh error in GetKipData!");
|
||||
writeNotification("Horizon OC\nConfig refresh failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,18 +33,52 @@
|
||||
#include "integrations.h"
|
||||
|
||||
class SysDockIntegration;
|
||||
class SaltyNXIntegration;
|
||||
class ClockManager
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Get instance
|
||||
* @return Pointer to a ClockManager instance
|
||||
*/
|
||||
static ClockManager* GetInstance();
|
||||
static void Initialize();
|
||||
static void Exit();
|
||||
ClockManager();
|
||||
virtual ~ClockManager();
|
||||
|
||||
/**
|
||||
* Get context object
|
||||
* @return Context instance
|
||||
*/
|
||||
SysClkContext GetCurrentContext();
|
||||
|
||||
/**
|
||||
* Get config object
|
||||
* @return Pointer to a config instance
|
||||
*/
|
||||
Config* GetConfig();
|
||||
|
||||
/**
|
||||
* Set clock manager running
|
||||
* @param running Is running or not?
|
||||
*/
|
||||
void SetRunning(bool running);
|
||||
|
||||
/**
|
||||
* Is clock manager running
|
||||
* @return running or not?
|
||||
*/
|
||||
bool Running();
|
||||
|
||||
/**
|
||||
* Get frequency list from clkrst
|
||||
*
|
||||
* @param module Module to get frequency list for
|
||||
* @param list List of frequencies
|
||||
* @param maxCount How many entries to expect in list. Usually 32
|
||||
* @param outCount How many entries were retrived
|
||||
*/
|
||||
void GetFreqList(SysClkModule module, std::uint32_t* list, std::uint32_t maxCount, std::uint32_t* outCount);
|
||||
|
||||
/**
|
||||
@@ -151,6 +185,13 @@ class ClockManager
|
||||
*/
|
||||
static void GovernorThread(void* arg);
|
||||
|
||||
/**
|
||||
* Runs the VRR Algorithm
|
||||
*
|
||||
* @param arg Cast to ClockManager* for context
|
||||
*/
|
||||
static void VRRThread(void* arg);
|
||||
|
||||
/**
|
||||
* Gets the effective governor state from application/temporary override
|
||||
*
|
||||
@@ -160,10 +201,10 @@ class ClockManager
|
||||
GovernorState GetEffectiveGovernorState(GovernorState appState, GovernorState tempState);
|
||||
|
||||
/**
|
||||
* Frequency tables
|
||||
* Frequency table
|
||||
*
|
||||
*/
|
||||
struct {
|
||||
struct FreqTable {
|
||||
std::uint32_t count;
|
||||
std::uint32_t list[SYSCLK_FREQ_LIST_MAX];
|
||||
} freqTable[SysClkModule_EnumMax];
|
||||
@@ -183,6 +224,30 @@ class ClockManager
|
||||
*/
|
||||
unsigned int GetGpuVoltage (unsigned int freq, int speedo);
|
||||
|
||||
/**
|
||||
* Gets the required vMin for a ram frequency for a speedo
|
||||
*
|
||||
* @param util Utilization in percentile
|
||||
* @param tableMaxHz Table Max Hz
|
||||
*/
|
||||
static u32 SchedutilTargetHz(u32 util, u32 tableMaxHz);
|
||||
|
||||
/**
|
||||
* Gets the required vMin for a ram frequency for a speedo
|
||||
*
|
||||
* @param table FreqTable for module
|
||||
* @param targetHz Hz to search for
|
||||
*/
|
||||
static u32 TableIndexForHz(const FreqTable& table, u32 targetHz);
|
||||
|
||||
/**
|
||||
* Gets the required vMin for a ram frequency for a speedo
|
||||
*
|
||||
* @param mgr ClockManager instance (runs in a thread so must be passed)
|
||||
* @param module Module for which to resolve target Hz
|
||||
*/
|
||||
static u32 ResolveTargetHz(ClockManager* mgr, SysClkModule module);
|
||||
|
||||
protected:
|
||||
bool IsAssignableHz(SysClkModule module, std::uint32_t hz);
|
||||
inline std::uint32_t GetMaxAllowedHz(SysClkModule module, SysClkProfile profile);
|
||||
@@ -200,4 +265,5 @@ class ClockManager
|
||||
std::uint64_t lastPowerLogNs;
|
||||
std::uint64_t lastCsvWriteNs;
|
||||
SysDockIntegration *sysDockIntegration;
|
||||
SaltyNXIntegration *saltyNXIntegration;
|
||||
};
|
||||
@@ -18,15 +18,93 @@
|
||||
|
||||
#include "integrations.h"
|
||||
#include <sys/stat.h>
|
||||
#include <SaltyNX.h>
|
||||
#include "process_management.h"
|
||||
|
||||
SysDockIntegration::SysDockIntegration() {
|
||||
}
|
||||
|
||||
bool SysDockIntegration::getCurrentSysDockState() {
|
||||
struct stat st = {0};
|
||||
if (stat("sdmc:/atmosphere/contents/42000000000000A0", &st) == 0 && S_ISDIR(st.st_mode)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
return stat("sdmc:/atmosphere/contents/42000000000000A0/flags/boot2.flag", &st) == 0;
|
||||
}
|
||||
|
||||
SaltyNXIntegration::SaltyNXIntegration() {
|
||||
}
|
||||
|
||||
void SaltyNXIntegration::LoadSaltyNX() {
|
||||
if (!CheckPort())
|
||||
return;
|
||||
LoadSharedMemory();
|
||||
}
|
||||
|
||||
bool SaltyNXIntegration::getCurrentSaltyNXState() {
|
||||
struct stat st = {0};
|
||||
return stat("sdmc:/atmosphere/contents/0000000000534C56/flags/boot2.flag", &st) == 0;
|
||||
}
|
||||
|
||||
bool SaltyNXIntegration::CheckPort() {
|
||||
Handle saltysd;
|
||||
|
||||
for (int i = 0; i < 67; i++) {
|
||||
if (R_SUCCEEDED(svcConnectToNamedPort(&saltysd, "InjectServ"))) {
|
||||
svcCloseHandle(saltysd);
|
||||
break;
|
||||
}
|
||||
if (i == 66) return false;
|
||||
svcSleepThread(1'000'000);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 67; i++) {
|
||||
if (R_SUCCEEDED(svcConnectToNamedPort(&saltysd, "InjectServ"))) {
|
||||
svcCloseHandle(saltysd);
|
||||
return true;
|
||||
}
|
||||
svcSleepThread(1'000'000);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void SaltyNXIntegration::LoadSharedMemory() {
|
||||
if (SaltySD_Connect())
|
||||
return;
|
||||
SaltySD_GetSharedMemoryHandle(&remoteSharedMemory);
|
||||
SaltySD_Term();
|
||||
shmemLoadRemote(&_sharedmemory, remoteSharedMemory, 0x1000, Perm_Rw);
|
||||
if (!shmemMap(&_sharedmemory))
|
||||
SharedMemoryUsed = true;
|
||||
}
|
||||
|
||||
void SaltyNXIntegration::searchSharedMemoryBlock(uintptr_t base) {
|
||||
ptrdiff_t search_offset = 0;
|
||||
while (search_offset < 0x1000) {
|
||||
NxFps = (NxFpsSharedBlock*)(base + search_offset);
|
||||
if (NxFps->MAGIC == 0x465053)
|
||||
return;
|
||||
search_offset += 4;
|
||||
}
|
||||
NxFps = 0;
|
||||
}
|
||||
|
||||
u64 prevTid = 0;
|
||||
u8 SaltyNXIntegration::GetFPS() {
|
||||
if (!SharedMemoryUsed)
|
||||
return 254;
|
||||
|
||||
u64 tid = ProcessManagement::GetCurrentApplicationId();
|
||||
if (tid == 0)
|
||||
return 254;
|
||||
|
||||
if (prevTid != tid) {
|
||||
NxFps = 0;
|
||||
prevTid = tid;
|
||||
}
|
||||
|
||||
if (!NxFps) {
|
||||
uintptr_t base = (uintptr_t)shmemGetAddr(&_sharedmemory);
|
||||
searchSharedMemoryBlock(base);
|
||||
}
|
||||
|
||||
return NxFps ? NxFps->FPS : 254;
|
||||
}
|
||||
@@ -34,4 +34,60 @@ public:
|
||||
SysDockIntegration();
|
||||
|
||||
bool getCurrentSysDockState();
|
||||
};
|
||||
|
||||
class SaltyNXIntegration {
|
||||
public:
|
||||
struct resolutionCalls {
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
uint16_t calls;
|
||||
};
|
||||
|
||||
struct NxFpsSharedBlock {
|
||||
uint32_t MAGIC;
|
||||
uint8_t FPS;
|
||||
float FPSavg;
|
||||
bool pluginActive;
|
||||
uint8_t FPSlocked;
|
||||
uint8_t FPSmode;
|
||||
uint8_t ZeroSync;
|
||||
uint8_t patchApplied;
|
||||
uint8_t API;
|
||||
uint32_t FPSticks[10];
|
||||
uint8_t Buffers;
|
||||
uint8_t SetBuffers;
|
||||
uint8_t ActiveBuffers;
|
||||
uint8_t SetActiveBuffers;
|
||||
union {
|
||||
struct {
|
||||
bool handheld: 1;
|
||||
bool docked: 1;
|
||||
unsigned int reserved: 6;
|
||||
} NX_PACKED ds;
|
||||
uint8_t general;
|
||||
} displaySync;
|
||||
resolutionCalls renderCalls[8];
|
||||
resolutionCalls viewportCalls[8];
|
||||
bool forceOriginalRefreshRate;
|
||||
bool dontForce60InDocked;
|
||||
bool forceSuspend;
|
||||
uint8_t currentRefreshRate;
|
||||
float readSpeedPerSecond;
|
||||
uint8_t FPSlockedDocked;
|
||||
uint64_t frameNumber;
|
||||
} NX_PACKED;
|
||||
|
||||
NxFpsSharedBlock* NxFps = 0;
|
||||
SharedMemory _sharedmemory = {};
|
||||
bool SharedMemoryUsed = false;
|
||||
Handle remoteSharedMemory = 1;
|
||||
SaltyNXIntegration();
|
||||
void LoadSaltyNX();
|
||||
bool getCurrentSaltyNXState();
|
||||
|
||||
bool CheckPort();
|
||||
void LoadSharedMemory();
|
||||
void searchSharedMemoryBlock(uintptr_t base);
|
||||
u8 GetFPS();
|
||||
};
|
||||
@@ -77,8 +77,8 @@ typedef struct {
|
||||
|
||||
u32 gpuSpeedo;
|
||||
|
||||
u32 eristaGpuVoltArray[24];
|
||||
u32 marikoGpuVoltArray[31];
|
||||
u32 eristaGpuVoltArray[27];
|
||||
u32 marikoGpuVoltArray[24];
|
||||
|
||||
u32 t6_tRTW_fine_tune;
|
||||
u32 t7_tWTR_fine_tune;
|
||||
@@ -308,12 +308,12 @@ static inline u32 cust_get_gpu_speedo(const CustomizeTable* t) { return CUST_GET
|
||||
static inline u32 cust_get_marikoCpuMaxClock(const CustomizeTable* t) { return CUST_GET_FIELD(t, marikoCpuMaxClock); }
|
||||
|
||||
static inline u32 cust_get_erista_gpu_volt(const CustomizeTable* t, int idx) {
|
||||
if (!t || idx < 0 || idx > 24) return 0;
|
||||
if (!t || idx < 0 || idx >= 27) return 0;
|
||||
return t->eristaGpuVoltArray[idx];
|
||||
}
|
||||
|
||||
static inline u32 cust_get_mariko_gpu_volt(const CustomizeTable* t, int idx) {
|
||||
if (!t || idx < 0 || idx > 31) return 0;
|
||||
if (!t || idx < 0 || idx >= 24) return 0;
|
||||
return t->marikoGpuVoltArray[idx];
|
||||
}
|
||||
|
||||
@@ -330,30 +330,32 @@ static inline bool cust_set_mariko_gpu_volt_##freq( \
|
||||
}
|
||||
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(76800, 0)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(153600, 1)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(230400, 2)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(307200, 3)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(384000, 4)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(460800, 5)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(537600, 6)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(614400, 7)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(691200, 8)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(768000, 9)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(844800, 10)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(921600, 11)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(998400, 12)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(1075200, 13)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(1152000, 14)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(1228800, 15)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(1267200, 16)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(1305600, 17)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(1344000, 18)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(1382400, 19)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(1420800, 20)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(1459200, 21)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(1497600, 22)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(1536000, 23)
|
||||
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(115200, 1)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(153600, 2)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(192000, 3)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(230400, 4)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(268800, 5)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(307200, 6)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(345600, 7)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(384000, 8)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(422400, 9)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(460800, 10)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(499200, 11)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(537600, 12)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(576000, 13)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(614400, 14)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(652800, 15)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(691200, 16)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(729600, 17)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(768000, 18)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(806400, 19)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(844800, 20)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(883200, 21)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(921600, 22)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(960000, 23)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(998400, 24)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(1036800, 25)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(1075200, 26)
|
||||
|
||||
DECL_MARIKO_GPU_VOLT_HELPER(76800, 0)
|
||||
DECL_MARIKO_GPU_VOLT_HELPER(153600, 1)
|
||||
@@ -379,13 +381,6 @@ DECL_MARIKO_GPU_VOLT_HELPER(1420800, 20)
|
||||
DECL_MARIKO_GPU_VOLT_HELPER(1459200, 21)
|
||||
DECL_MARIKO_GPU_VOLT_HELPER(1497600, 22)
|
||||
DECL_MARIKO_GPU_VOLT_HELPER(1536000, 23)
|
||||
DECL_MARIKO_GPU_VOLT_HELPER(1574400, 24)
|
||||
DECL_MARIKO_GPU_VOLT_HELPER(1612800, 25)
|
||||
DECL_MARIKO_GPU_VOLT_HELPER(1651200, 26)
|
||||
DECL_MARIKO_GPU_VOLT_HELPER(1689600, 27)
|
||||
DECL_MARIKO_GPU_VOLT_HELPER(1728000, 28)
|
||||
DECL_MARIKO_GPU_VOLT_HELPER(1766400, 29)
|
||||
DECL_MARIKO_GPU_VOLT_HELPER(1804800, 30)
|
||||
|
||||
|
||||
#define DECL_ERISTA_GPU_VOLT_GET(freq, idx) \
|
||||
@@ -401,32 +396,33 @@ static inline u32 cust_get_mariko_gpu_volt_##freq##_val(const char* p) { \
|
||||
return cust_get_mariko_gpu_volt(&t, idx); \
|
||||
}
|
||||
|
||||
|
||||
DECL_ERISTA_GPU_VOLT_GET(76800, 0)
|
||||
DECL_ERISTA_GPU_VOLT_GET(153600, 1)
|
||||
DECL_ERISTA_GPU_VOLT_GET(230400, 2)
|
||||
DECL_ERISTA_GPU_VOLT_GET(307200, 3)
|
||||
DECL_ERISTA_GPU_VOLT_GET(384000, 4)
|
||||
DECL_ERISTA_GPU_VOLT_GET(460800, 5)
|
||||
DECL_ERISTA_GPU_VOLT_GET(537600, 6)
|
||||
DECL_ERISTA_GPU_VOLT_GET(614400, 7)
|
||||
DECL_ERISTA_GPU_VOLT_GET(691200, 8)
|
||||
DECL_ERISTA_GPU_VOLT_GET(768000, 9)
|
||||
DECL_ERISTA_GPU_VOLT_GET(844800, 10)
|
||||
DECL_ERISTA_GPU_VOLT_GET(921600, 11)
|
||||
DECL_ERISTA_GPU_VOLT_GET(998400, 12)
|
||||
DECL_ERISTA_GPU_VOLT_GET(1075200, 13)
|
||||
DECL_ERISTA_GPU_VOLT_GET(1152000, 14)
|
||||
DECL_ERISTA_GPU_VOLT_GET(1228800, 15)
|
||||
DECL_ERISTA_GPU_VOLT_GET(1267200, 16)
|
||||
DECL_ERISTA_GPU_VOLT_GET(1305600, 17)
|
||||
DECL_ERISTA_GPU_VOLT_GET(1344000, 18)
|
||||
DECL_ERISTA_GPU_VOLT_GET(1382400, 19)
|
||||
DECL_ERISTA_GPU_VOLT_GET(1420800, 20)
|
||||
DECL_ERISTA_GPU_VOLT_GET(1459200, 21)
|
||||
DECL_ERISTA_GPU_VOLT_GET(1497600, 22)
|
||||
DECL_ERISTA_GPU_VOLT_GET(1536000, 23)
|
||||
|
||||
DECL_ERISTA_GPU_VOLT_GET(115200, 1)
|
||||
DECL_ERISTA_GPU_VOLT_GET(153600, 2)
|
||||
DECL_ERISTA_GPU_VOLT_GET(192000, 3)
|
||||
DECL_ERISTA_GPU_VOLT_GET(230400, 4)
|
||||
DECL_ERISTA_GPU_VOLT_GET(268800, 5)
|
||||
DECL_ERISTA_GPU_VOLT_GET(307200, 6)
|
||||
DECL_ERISTA_GPU_VOLT_GET(345600, 7)
|
||||
DECL_ERISTA_GPU_VOLT_GET(384000, 8)
|
||||
DECL_ERISTA_GPU_VOLT_GET(422400, 9)
|
||||
DECL_ERISTA_GPU_VOLT_GET(460800, 10)
|
||||
DECL_ERISTA_GPU_VOLT_GET(499200, 11)
|
||||
DECL_ERISTA_GPU_VOLT_GET(537600, 12)
|
||||
DECL_ERISTA_GPU_VOLT_GET(576000, 13)
|
||||
DECL_ERISTA_GPU_VOLT_GET(614400, 14)
|
||||
DECL_ERISTA_GPU_VOLT_GET(652800, 15)
|
||||
DECL_ERISTA_GPU_VOLT_GET(691200, 16)
|
||||
DECL_ERISTA_GPU_VOLT_GET(729600, 17)
|
||||
DECL_ERISTA_GPU_VOLT_GET(768000, 18)
|
||||
DECL_ERISTA_GPU_VOLT_GET(806400, 19)
|
||||
DECL_ERISTA_GPU_VOLT_GET(844800, 20)
|
||||
DECL_ERISTA_GPU_VOLT_GET(883200, 21)
|
||||
DECL_ERISTA_GPU_VOLT_GET(921600, 22)
|
||||
DECL_ERISTA_GPU_VOLT_GET(960000, 23)
|
||||
DECL_ERISTA_GPU_VOLT_GET(998400, 24)
|
||||
DECL_ERISTA_GPU_VOLT_GET(1036800, 25)
|
||||
DECL_ERISTA_GPU_VOLT_GET(1075200, 26)
|
||||
|
||||
DECL_MARIKO_GPU_VOLT_GET(76800, 0)
|
||||
DECL_MARIKO_GPU_VOLT_GET(153600, 1)
|
||||
@@ -451,11 +447,4 @@ DECL_MARIKO_GPU_VOLT_GET(1382400, 19)
|
||||
DECL_MARIKO_GPU_VOLT_GET(1420800, 20)
|
||||
DECL_MARIKO_GPU_VOLT_GET(1459200, 21)
|
||||
DECL_MARIKO_GPU_VOLT_GET(1497600, 22)
|
||||
DECL_MARIKO_GPU_VOLT_GET(1536000, 23)
|
||||
DECL_MARIKO_GPU_VOLT_GET(1574400, 24)
|
||||
DECL_MARIKO_GPU_VOLT_GET(1612800, 25)
|
||||
DECL_MARIKO_GPU_VOLT_GET(1651200, 26)
|
||||
DECL_MARIKO_GPU_VOLT_GET(1689600, 27)
|
||||
DECL_MARIKO_GPU_VOLT_GET(1728000, 28)
|
||||
DECL_MARIKO_GPU_VOLT_GET(1766400, 29)
|
||||
DECL_MARIKO_GPU_VOLT_GET(1804800, 30)
|
||||
DECL_MARIKO_GPU_VOLT_GET(1536000, 23)
|
||||
@@ -38,8 +38,11 @@
|
||||
#include "ipc_service.h"
|
||||
#define INNER_HEAP_SIZE 0x40000
|
||||
|
||||
|
||||
extern "C"
|
||||
{
|
||||
void virtmemSetup(void);
|
||||
|
||||
extern std::uint32_t __start__;
|
||||
|
||||
std::uint32_t __nx_applet_type = AppletType_None;
|
||||
@@ -62,6 +65,8 @@ extern "C"
|
||||
|
||||
fake_heap_start = (char*)addr;
|
||||
fake_heap_end = (char*)addr + size;
|
||||
|
||||
virtmemSetup();
|
||||
}
|
||||
|
||||
void __appInit(void)
|
||||
@@ -88,6 +93,9 @@ extern "C"
|
||||
rc = i2cInitialize();
|
||||
if (R_FAILED(rc))
|
||||
diagAbortWithResult(MAKERESULT(Module_Libnx, LibnxError_ShouldNotHappen));
|
||||
rc = appletInitialize();
|
||||
if (R_FAILED(rc))
|
||||
diagAbortWithResult(MAKERESULT(Module_Libnx, LibnxError_ShouldNotHappen));
|
||||
}
|
||||
|
||||
void __appExit(void)
|
||||
@@ -97,6 +105,7 @@ extern "C"
|
||||
i2cExit();
|
||||
fsExit();
|
||||
fsdevUnmountAll();
|
||||
appletExit();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BIN
assets/logo.png
BIN
assets/logo.png
Binary file not shown.
|
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 233 KiB |
6
dist/README.md
vendored
6
dist/README.md
vendored
@@ -1,7 +1,7 @@
|
||||
|
||||
<div align="center">
|
||||
|
||||
<img src="assets/logo.png" alt="logo" width="350"/>
|
||||
<img src="assets/logo.png" alt="logo" width="768"/>
|
||||
|
||||
---
|
||||
|
||||
@@ -36,12 +36,12 @@ It enables advanced CPU, GPU, and RAM tuning with user-friendly configuration to
|
||||
|
||||
* **CPU:** Up to 1963MHz (Mariko) / 1785MHz (Erista)
|
||||
* **GPU:** Up to 1075MHz (Mariko) / 921MHz (Erista)
|
||||
* **RAM:** Up to 1866MHz (Mariko) / 1600MHz (Erista)
|
||||
* **RAM:** Up to 1866/2133MHz (Mariko) / 1600MHz (Erista)
|
||||
* Over/undervolting support
|
||||
* Built-in configurator
|
||||
* Compatible with most homebrew
|
||||
|
||||
> It is reccomended to read the [guide](https://rentry.co/howtoget60fps) before proceeding, as this can help you get a *significant* performance boost over the default settings, often times with less power draw and heat output
|
||||
> It is recommended to read the [guide](https://rentry.co/howtoget60fps) before proceeding, as this can help you get a *significant* performance boost over the default settings, often times with less power draw and heat output
|
||||
|
||||
---
|
||||
|
||||
|
||||
BIN
dist/atmosphere/contents/00FF0000636C6BFF/exefs.nsp
vendored
BIN
dist/atmosphere/contents/00FF0000636C6BFF/exefs.nsp
vendored
Binary file not shown.
BIN
dist/atmosphere/kips/hoc.kip
vendored
BIN
dist/atmosphere/kips/hoc.kip
vendored
Binary file not shown.
BIN
dist/switch/.overlays/Horizon-OC-Monitor.ovl
vendored
BIN
dist/switch/.overlays/Horizon-OC-Monitor.ovl
vendored
Binary file not shown.
BIN
dist/switch/.overlays/horizon-oc-overlay.ovl
vendored
BIN
dist/switch/.overlays/horizon-oc-overlay.ovl
vendored
Binary file not shown.
@@ -1,140 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Horizon OC Configurator</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link href="https://unpkg.com/aos@2.3.1/dist/aos.css" rel="stylesheet">
|
||||
|
||||
<style>
|
||||
body {
|
||||
background: linear-gradient(160deg, #1a1a1a 0%, #2a2a2a 50%, #3a3a3a 100%);
|
||||
color: white;
|
||||
font-family: 'Segoe UI', Roboto, system-ui, sans-serif;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.glass {
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
border: 1px solid rgba(255, 255, 255, 0.15);
|
||||
backdrop-filter: blur(20px);
|
||||
border-radius: 20px;
|
||||
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.3);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.glass:hover {
|
||||
background: rgba(255, 255, 255, 0.12);
|
||||
transform: translateY(-3px);
|
||||
}
|
||||
|
||||
.button-glass {
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
backdrop-filter: blur(20px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.25);
|
||||
color: white;
|
||||
padding: 0.8rem 1.6rem;
|
||||
border-radius: 9999px;
|
||||
font-weight: 600;
|
||||
transition: all 0.3s;
|
||||
display: inline-block;
|
||||
text-decoration: none;
|
||||
margin: 0.25rem 0;
|
||||
}
|
||||
|
||||
.button-glass:hover {
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
input[type="number"], input[type="file"] {
|
||||
padding: 0.5rem 0.8rem;
|
||||
border-radius: 12px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.25);
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
color: white;
|
||||
font-weight: 500;
|
||||
outline: none;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
input[type="number"]:focus, input[type="file"]:focus {
|
||||
border-color: #b8f3ff;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
label {
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
section {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
footer {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.15);
|
||||
padding: 1.5rem 0;
|
||||
text-align: center;
|
||||
color: #ccc;
|
||||
font-size: 0.9rem;
|
||||
margin-top: 4rem;
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!-- Navigation / Go Back -->
|
||||
<nav class="flex justify-start p-6">
|
||||
<a href="index.html" class="button-glass">← Go Back to Main Page</a>
|
||||
</nav>
|
||||
|
||||
<!-- Configurator -->
|
||||
<section id="config" class="max-w-4xl mx-auto px-6 py-16 glass mt-6" data-aos="fade-up">
|
||||
<h2 class="text-3xl font-bold mb-4 text-center">Configurator</h2>
|
||||
<p class="text-gray-400 text-center mb-8">Configure frequencies and voltages to suit your hardware and preferences.</p>
|
||||
|
||||
<form class="space-y-6 text-center">
|
||||
<!-- Unit selection buttons -->
|
||||
<div class="flex justify-center gap-2">
|
||||
<button type="button" class="button-glass">All</button>
|
||||
<button type="button" class="button-glass">Erista</button>
|
||||
<button type="button" class="button-glass">Mariko</button>
|
||||
</div>
|
||||
|
||||
<!-- File upload -->
|
||||
<div class="flex flex-col items-center">
|
||||
<input type="file" id="file">
|
||||
<p class="text-sm text-gray-400 mt-2">Upload loader.kip here</p>
|
||||
</div>
|
||||
|
||||
<!-- Example numeric inputs -->
|
||||
<div class="flex flex-wrap justify-center gap-4 mt-4">
|
||||
<div>
|
||||
<label for="commonEmcMemVolt">EMC Voltage:</label>
|
||||
<input type="number" id="commonEmcMemVolt" min="0" max="1250000" step="12500">
|
||||
</div>
|
||||
<div>
|
||||
<label for="commonCpuVolt">CPU Voltage:</label>
|
||||
<input type="number" id="commonCpuVolt" min="0" max="1250000" step="12500">
|
||||
</div>
|
||||
<div>
|
||||
<label for="commonGpuVolt">GPU Voltage:</label>
|
||||
<input type="number" id="commonGpuVolt" min="0" max="1250000" step="12500">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
<!-- Footer -->
|
||||
<footer>
|
||||
Built with ❤️. All trademarks and logos are the property of their respective owners.
|
||||
</footer>
|
||||
|
||||
<script src="https://unpkg.com/aos@2.3.1/dist/aos.js"></script>
|
||||
<script>AOS.init({ once: true, duration: 700 });</script>
|
||||
<script src="configurator.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,683 +0,0 @@
|
||||
/* configurator.js
|
||||
Clean, readable reconstruction of the original minified configurator
|
||||
- Keeps original behavior (tables, parsing, localStorage, GitHub release fetching)
|
||||
- Uses modern async/await and DOMContentLoaded guarding
|
||||
*/
|
||||
|
||||
const CUST_REV_ADV = 11;
|
||||
|
||||
const CustPlatform = Object.freeze({
|
||||
Undefined: 0,
|
||||
Erista: 1,
|
||||
Mariko: 2,
|
||||
All: 3
|
||||
});
|
||||
|
||||
class CustEntry {
|
||||
constructor(id, name, platform, size, desc = [], defval = 0, range = [0, 1e6], step = 1, zeroable = true) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.platform = platform;
|
||||
this.size = size;
|
||||
this.desc = desc;
|
||||
this.defval = defval;
|
||||
this.step = step;
|
||||
this.zeroable = zeroable;
|
||||
this.min = range[0];
|
||||
this.max = range[1];
|
||||
this.value = this.defval;
|
||||
}
|
||||
|
||||
validate() {
|
||||
const err = new ErrorToolTip(this.id).clear();
|
||||
if (Number.isNaN(this.value) || this.value === undefined) {
|
||||
err.setMsg("Invalid value: Not a number").show();
|
||||
return false;
|
||||
}
|
||||
if (!this.zeroable && this.value === 0) {
|
||||
err.setMsg("Zero is not allowed for this entry").show();
|
||||
return false;
|
||||
}
|
||||
if (this.value < this.min || this.value > this.max) {
|
||||
err.setMsg(`Expected range: [${this.min}, ${this.max}], got ${this.value}.`).show();
|
||||
return false;
|
||||
}
|
||||
if ((this.value % this.step) !== 0) {
|
||||
err.setMsg(`${this.value} % ${this.step} ≠ 0`).show();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
getInputElement() {
|
||||
return document.getElementById(this.id);
|
||||
}
|
||||
|
||||
updateValueFromElement() {
|
||||
const el = this.getInputElement();
|
||||
this.value = Number(el?.value);
|
||||
}
|
||||
|
||||
isAvailableFor(platform) {
|
||||
return platform === CustPlatform.Undefined || this.platform === platform || this.platform === CustPlatform.All;
|
||||
}
|
||||
|
||||
createElement(containerId = "config-list-basic") {
|
||||
let input = this.getInputElement();
|
||||
if (!input) {
|
||||
const wrapper = document.createElement("div");
|
||||
wrapper.classList.add("grid", "cust-element", "mb-3");
|
||||
|
||||
input = document.createElement("input");
|
||||
input.min = String(this.zeroable ? 0 : this.min);
|
||||
input.max = String(this.max);
|
||||
input.id = this.id;
|
||||
input.type = "number";
|
||||
input.step = String(this.step);
|
||||
input.classList.add("text-black", "w-36");
|
||||
|
||||
const label = document.createElement("label");
|
||||
label.setAttribute("for", this.id);
|
||||
label.innerHTML = `<strong>${this.name}</strong>`;
|
||||
label.classList.add("block", "mb-1");
|
||||
|
||||
const desc = document.createElement("blockquote");
|
||||
desc.innerHTML = "<ul>" + (this.desc || []).map(d => `<li>${d}</li>`).join("") + "</ul>";
|
||||
desc.setAttribute("for", this.id);
|
||||
desc.classList.add("text-sm", "text-gray-300");
|
||||
|
||||
wrapper.appendChild(label);
|
||||
wrapper.appendChild(input);
|
||||
wrapper.appendChild(desc);
|
||||
|
||||
const container = document.getElementById(containerId);
|
||||
if (container) container.appendChild(wrapper);
|
||||
new ErrorToolTip(this.id).addChangeListener();
|
||||
}
|
||||
input.value = String(this.value);
|
||||
}
|
||||
|
||||
setElementValue() {
|
||||
const el = this.getInputElement();
|
||||
if (el) el.value = String(this.value);
|
||||
}
|
||||
|
||||
setElementDefaultValue() {
|
||||
const el = this.getInputElement();
|
||||
if (el) el.value = String(this.defval);
|
||||
}
|
||||
|
||||
removeElement() {
|
||||
const el = this.getInputElement();
|
||||
if (el && el.parentElement && el.parentElement.parentElement) el.parentElement.parentElement.remove();
|
||||
}
|
||||
|
||||
showElement() {
|
||||
const el = this.getInputElement();
|
||||
if (el && el.parentElement && el.parentElement.parentElement) el.parentElement.parentElement.style.removeProperty("display");
|
||||
}
|
||||
|
||||
hideElement() {
|
||||
const el = this.getInputElement();
|
||||
if (el && el.parentElement && el.parentElement.parentElement) el.parentElement.parentElement.style.setProperty("display", "none");
|
||||
}
|
||||
}
|
||||
|
||||
class AdvEntry extends CustEntry {
|
||||
createElement() {
|
||||
super.createElement("config-list-advanced");
|
||||
}
|
||||
}
|
||||
|
||||
class GpuEntry extends CustEntry {
|
||||
constructor(id, name, platform = CustPlatform.Mariko, size = 4, desc = ["range: 610 ≤ x ≤ 1000"], defval = 610, range = [610, 1000], step = 5, zeroable = false) {
|
||||
super(id, name, platform, size, desc, defval, range, step, zeroable);
|
||||
}
|
||||
|
||||
createElement() {
|
||||
super.createElement("config-list-gpu");
|
||||
}
|
||||
}
|
||||
|
||||
/* === Tables (reconstructed from original) ===
|
||||
Note: Numeric defaults preserved where feasible.
|
||||
*/
|
||||
const CustTable = [
|
||||
new CustEntry("mtcConf", "DRAM Timing", CustPlatform.All, 4,
|
||||
[
|
||||
"<b>0</b>: AUTO_ADJ_ALL: Auto adjust mtc table with LPDDR4 3733 Mbps specs, 8Gb density. Change timing with Advanced Config (Default)",
|
||||
"<b>1</b>: CUSTOM_ADJ_ALL: Adjust only non-zero preset timings in Advanced Config",
|
||||
"<b>2</b>: NO_ADJ_ALL: Use 1600 mtc table without adjusting (Timing becomes tighter if you raise dram clock)."
|
||||
], 0, [0, 2], 1),
|
||||
new CustEntry("commonCpuBoostClock", "Boost Clock in kHz", CustPlatform.All, 4,
|
||||
["System default: 1785000", "Boost clock will be applied when applications request Boost Mode via performance configuration."],
|
||||
1785000, [1020000, 3000000], 1, false),
|
||||
new CustEntry("commonEmcMemVolt", "EMC Vdd2 Voltage in uV", CustPlatform.All, 4,
|
||||
["Acceptable range: 1100000 ≤ x ≤ 1250000, and it should be divided evenly by 12500.", "Erista Default: 1125000", "Mariko Default: 1100000", "Official lpddr4(x) range: 1060mV~1175mV (1100mV nominal)", "OCS need high voltage unlike l4t because of not scaling mtc table well. However it is recommended to stay within official limits", "Not enabled by default"],
|
||||
0, [1100000, 1250000], 12500),
|
||||
new CustEntry("eristaCpuMaxVolt", "Erista CPU Max Voltage in mV", CustPlatform.Erista, 4,
|
||||
["Acceptable range: 1120 ≤ x ≤ 1300", "L4T Default: 1235"], 1235, [1120, 1300], 1),
|
||||
new CustEntry("eristaEmcMaxClock", "Erista RAM Max Clock in kHz", CustPlatform.Erista, 4,
|
||||
["Values should be ≥ 1600000, and divided evenly by 3200.", "Recommended Clocks: 1862400, 2131200 (JEDEC)", "<b>WARNING:</b> RAM overclock could be UNSTABLE if timing parameters are not suitable for your DRAM"], 1862400, [1600000, 2131200], 3200),
|
||||
new CustEntry("marikoCpuMaxVolt", "Mariko CPU Max Voltage in mV", CustPlatform.Mariko, 4,
|
||||
["System default: 1120", "Acceptable range: 1120 ≤ x ≤ 1300", "Changing this value affects cpu voltage calculation"], 1235, [1120, 1300], 5),
|
||||
new CustEntry("marikoEmcMaxClock", "Mariko RAM Max Clock in kHz", CustPlatform.Mariko, 4,
|
||||
["Values should be ≥ 1600000, and divided evenly by 3200.", "Recommended Clocks: 1862400, 2131200, 2400000 (JEDEC)", "Some clocks above 2400Mhz might not boot, because OCS doesn't scale table very well", "<b>WARNING:</b> RAM overclock could be UNSTABLE if timing parameters are not suitable for your DRAM."],
|
||||
1996800, [1600000, 2502400], 3200),
|
||||
new CustEntry("marikoEmcVddqVolt", "EMC Vddq (Mariko Only) Voltage in uV", CustPlatform.Mariko, 4,
|
||||
["Acceptable range: 550000 ≤ x ≤ 650000", "Value should be divided evenly by 5000", "Default: 600000", "Official lpddr4(x) range: 570mV~650mV (600mV nominal)", "Not enabled by default."],
|
||||
0, [550000, 650000], 5000),
|
||||
new CustEntry("marikoCpuUV", "Enable Mariko CPU Undervolt", CustPlatform.Mariko, 4,
|
||||
["Reduce CPU power draw", "<b>0</b> : Default Table", "<b>1</b> : Undervolt Level 1 (SLT - CPU speedo < 1650)", "<b>2</b> : Undervolt Level 1 (SLT - CPU speedo >= 1650)"], 0, [0, 2], 1),
|
||||
new CustEntry("marikoGpuUV", "Enable Mariko GPU Undervolt", CustPlatform.Mariko, 4,
|
||||
["Reduce GPU power draw", "Your GPU might not withstand undervolt, and can hang your console, or crash games", "Undervolting too much will drop GPU performance even if it seems stable", "GPU voltages are dynamic and will change with temperature and gpu speedo", "<b>0</b> : Default Table", "<b>1</b> : Undervolt Level 1 (SLT: Aggressive)", "<b>2</b> : Undervolt Level 2 (HiOPT: Drastic)", "<b>3</b> : Custom static GPU Voltage Table (Use Gpu Configuration below)"],
|
||||
0, [0, 3], 1),
|
||||
new CustEntry("commonGpuVoltOffset", "GPU Volt Offset", CustPlatform.All, 4,
|
||||
["Negative Voltage offset value for gpu dynamic voltage calculation", "For example, value of 10 will decrease 10mV gpu volt from all frequencies", "Default gpu vmin: Erista - 812.5mV / Mariko - 610mV", "Acceptable range: 0 ~ 100"],
|
||||
0, [0, 100], 1)
|
||||
];
|
||||
|
||||
const AdvTable = [
|
||||
new AdvEntry("marikoEmcDvbShift", "Step up Mariko EMC DVB Table", CustPlatform.Mariko, 4,
|
||||
["Each number adds 25mV to SoC voltage", "Helps with stability at higher memory clock", "Acceptable range : 0~9"], 0, [0, 9], 1),
|
||||
new AdvEntry("ramTimingPresetOne", "Primary RAM Timing Preset", CustPlatform.Mariko, 4,
|
||||
["<b>WARNING</b>: Unstable timings can corrupt your nand", "Select Timing Preset for both AUTO_ADJ and CUSTOM_ADJ", "Values are : tRCD - tRP - tRAS (tRC = tRP + tRAS)", "<b>0</b> : Do Not Adjust (2400Mhz: 12 - 12 - 28) (CUST_ADJ only)", "<b>1</b> : 18 - 18 - 42 (Default timing)", "<b>2</b> : 17 - 17 - 39", "<b>3</b> : 16 - 16 - 36", "<b>4</b> : 15 - 15 - 34", "<b>5</b> : 14 - 14 - 32", "<b>6</b> : 13 - 13 - 30"],
|
||||
1, [0, 6], 1),
|
||||
new AdvEntry("ramTimingPresetTwo", "Secondary RAM Timing Preset", CustPlatform.Mariko, 4,
|
||||
["WARNING: Unstable timings can corrupt your nand", "Secondary Timing Preset for both AUTO_ADJ and CUSTOM_ADJ", "Values are : tRRD - tFAW", "<b>0</b> : Do Not Adjust (2400Mhz: 6.6 - 26.6) (CUST_ADJ only)", "<b>1</b> : 10 - 40 (Default timing) (3733 specs)", "<b>2</b> : 7.5 - 30 (4266 specs)", "<b>3</b> : 6 - 24", "<b>4</b> : 4 - 16", "<b>5</b> : 3 - 12"],
|
||||
1, [0, 5], 1),
|
||||
new AdvEntry("ramTimingPresetThree", "Secondary RAM Timing Preset", CustPlatform.Mariko, 4,
|
||||
["WARNING: Unstable timings can corrupt your nand", "Secondary Timing Preset for both AUTO_ADJ and CUSTOM_ADJ", "Values are : tWR - tRTP", "<b>0</b> : Do Not Adjust (2400Mhz: ?? - 5) (CUST_ADJ only)", "<b>1</b> : 18 - 7.5 (Default timing)", "<b>2</b> : 15 - 7.5", "<b>3</b> : 15 - 6", "<b>4</b> : 12 - 6", "<b>5</b> : 12 - 4", "<b>6</b> : 8 - 4"],
|
||||
1, [0, 6], 1),
|
||||
new AdvEntry("ramTimingPresetFour", "Secondary RAM Timing Preset", CustPlatform.Mariko, 4,
|
||||
["WARNING: Unstable timings can corrupt your nand", "Secondary Timing Preset for both AUTO_ADJ and CUSTOM_ADJ", "Values are : tRFC", "<b>0</b> : Do Not Adjust (2400Mhz: 93.3) (CUST_ADJ only)", "<b>1</b> : 140 (Default timing)", "<b>2</b> : 120", "<b>3</b> : 100", "<b>4</b> : 80", "<b>5</b> : 70", "<b>6</b> : 60"],
|
||||
1, [0, 6], 1),
|
||||
new AdvEntry("ramTimingPresetFive", "Secondary RAM Timing Preset", CustPlatform.Mariko, 4,
|
||||
["WARNING: Unstable timings can corrupt your nand", "Secondary Timing Preset for both AUTO_ADJ and CUSTOM_ADJ", "Values are : tWTR", "<b>0</b> : Do Not Adjust (2400Mhz: ??) (CUST_ADJ only)", "<b>1</b> : 10 (Default timing)", "<b>2</b> : 8", "<b>3</b> : 6", "<b>4</b> : 4", "<b>5</b> : 2", "<b>6</b> : 1"],
|
||||
1, [0, 6], 1),
|
||||
new AdvEntry("ramTimingPresetSix", "Tertiary RAM Timing Preset", CustPlatform.Mariko, 4,
|
||||
["WARNING: Unstable timings can corrupt your nand", "Tertiary Timing Preset for both AUTO_ADJ and CUSTOM_ADJ", "Values are : tREFpb", "<b>0</b> : Do Not Adjust (2400Mhz: 325) (CUST_ADJ only)", "<b>1</b> : 488 (Default timing)", "<b>2</b> : 976", "<b>3</b> : 1952", "<b>4</b> : 3256", "<b>5</b> : MAX"],
|
||||
1, [0, 5], 1),
|
||||
new AdvEntry("ramTimingPresetSeven", "Latency Decrement", CustPlatform.Mariko, 4,
|
||||
["WARNING: Unstable timings can corrupt your nand", "Latency decrement for both AUTO_ADJ and CUSTOM_ADJ", "This preset decreases Write/Read related delays. Values are Write - Read", "<b>0</b> : 0 - 0, Do Not Adjust for CUST_ADJ", "<b>1</b> : '-2' - '-4'", "<b>2</b> : '-4' - '-8'", "<b>3</b> : '-6' - '-12'", "<b>4</b> : '-8' - '-16'", "<b>5</b> : '-10' - '-20'", "<b>6</b> : '-12' - '-24'"],
|
||||
0, [0, 6], 1)
|
||||
];
|
||||
|
||||
const GpuTable = [
|
||||
new GpuEntry("0", "76.8"),
|
||||
new GpuEntry("1", "153.6"),
|
||||
new GpuEntry("2", "230.4"),
|
||||
new GpuEntry("3", "307.2"),
|
||||
new GpuEntry("4", "384.0"),
|
||||
new GpuEntry("5", "460.8"),
|
||||
new GpuEntry("6", "537.6"),
|
||||
new GpuEntry("7", "614.4"),
|
||||
new GpuEntry("8", "691.2"),
|
||||
new GpuEntry("9", "768.0"),
|
||||
new GpuEntry("10", "844.8"),
|
||||
new GpuEntry("11", "921.6"),
|
||||
new GpuEntry("12", "998.4"),
|
||||
new GpuEntry("13", "1075.2"),
|
||||
new GpuEntry("14", "1152.0"),
|
||||
new GpuEntry("15", "1228.8"),
|
||||
new GpuEntry("16", "1267.2")
|
||||
];
|
||||
|
||||
/* ===== ErrorToolTip ===== */
|
||||
class ErrorToolTip {
|
||||
constructor(id, msg) {
|
||||
this.id = id;
|
||||
this.msg = msg;
|
||||
this.element = document.getElementById(id);
|
||||
if (msg) this.setMsg(msg);
|
||||
}
|
||||
|
||||
setMsg(msg) {
|
||||
this.msg = String(msg);
|
||||
return this;
|
||||
}
|
||||
|
||||
show() {
|
||||
if (this.element) this.element.setAttribute("aria-invalid", "true");
|
||||
if (this.msg && this.element) {
|
||||
this.element.setAttribute("title", this.msg);
|
||||
if (this.element.parentElement) {
|
||||
this.element.parentElement.setAttribute("data-tooltip", this.msg);
|
||||
this.element.parentElement.setAttribute("data-placement", "top");
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
clear() {
|
||||
if (this.element) this.element.removeAttribute("aria-invalid");
|
||||
if (this.element) this.element.removeAttribute("title");
|
||||
if (this.element && this.element.parentElement) {
|
||||
this.element.parentElement.removeAttribute("data-tooltip");
|
||||
this.element.parentElement.removeAttribute("data-placement");
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
addChangeListener() {
|
||||
if (!this.element) return;
|
||||
this.element.addEventListener("change", () => {
|
||||
const tableEntry = CustTable.find(e => e.id === this.id);
|
||||
if (tableEntry) {
|
||||
tableEntry.value = Number(this.element.value);
|
||||
tableEntry.validate();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== CustStorage ===== */
|
||||
class CustStorage {
|
||||
constructor() {
|
||||
this.storage = {};
|
||||
this.key = "last_saved";
|
||||
}
|
||||
|
||||
updateFromTable() {
|
||||
// helper to update and validate each entry
|
||||
const updateOne = (entry) => {
|
||||
entry.updateValueFromElement();
|
||||
if (!entry.validate()) {
|
||||
const el = entry.getInputElement();
|
||||
if (el) el.focus();
|
||||
throw new Error(`Invalid ${entry.name}`);
|
||||
}
|
||||
};
|
||||
|
||||
CustTable.forEach(updateOne);
|
||||
AdvTable.forEach(updateOne);
|
||||
GpuTable.forEach(updateOne);
|
||||
|
||||
this.storage = {};
|
||||
let t = Object.fromEntries(CustTable.map(e => [e.id, e.value]));
|
||||
Object.keys(t).forEach(k => (this.storage[k] = t[k]));
|
||||
t = Object.fromEntries(AdvTable.map(e => [e.id, e.value]));
|
||||
Object.keys(t).forEach(k => (this.storage[k] = t[k]));
|
||||
// GPU table could be included too if desired
|
||||
}
|
||||
|
||||
setTable() {
|
||||
const keys = Object.keys(this.storage);
|
||||
keys.forEach(k => {
|
||||
const c = CustTable.find(e => e.id === k);
|
||||
if (c) c.value = this.storage[k];
|
||||
});
|
||||
keys.forEach(k => {
|
||||
const a = AdvTable.find(e => e.id === k);
|
||||
if (a) a.value = this.storage[k];
|
||||
});
|
||||
|
||||
// Set defaults for entries not found
|
||||
CustTable.filter(e => !keys.includes(e.id)).forEach(e => e.value = e.defval);
|
||||
AdvTable.filter(e => !keys.includes(e.id)).forEach(e => e.value = e.defval);
|
||||
|
||||
// Validate and set element values
|
||||
CustTable.forEach(e => {
|
||||
if (!e.validate()) {
|
||||
const el = e.getInputElement();
|
||||
if (el) el.focus();
|
||||
throw new Error(`Invalid ${e.name}`);
|
||||
}
|
||||
e.setElementValue();
|
||||
});
|
||||
AdvTable.forEach(e => {
|
||||
if (!e.validate()) {
|
||||
const el = e.getInputElement();
|
||||
if (el) el.focus();
|
||||
throw new Error(`Invalid ${e.name}`);
|
||||
}
|
||||
e.setElementValue();
|
||||
});
|
||||
GpuTable.forEach(e => {
|
||||
if (!e.validate()) {
|
||||
const el = e.getInputElement();
|
||||
if (el) el.focus();
|
||||
throw new Error(`Invalid ${e.name}`);
|
||||
}
|
||||
e.setElementValue();
|
||||
});
|
||||
}
|
||||
|
||||
save() {
|
||||
localStorage.setItem(this.key, JSON.stringify(this.storage));
|
||||
}
|
||||
|
||||
load() {
|
||||
const raw = localStorage.getItem(this.key);
|
||||
if (!raw) return null;
|
||||
const parsed = JSON.parse(raw);
|
||||
|
||||
// Filter unknown keys and warn
|
||||
const custIds = CustTable.map(e => e.id);
|
||||
const ignoredCust = Object.keys(parsed).filter(k => !custIds.includes(k));
|
||||
if (ignoredCust.length) console.log("Ignored (cust):", ignoredCust);
|
||||
Object.keys(parsed).filter(k => custIds.includes(k)).forEach(k => (this.storage[k] = parsed[k]));
|
||||
|
||||
const advIds = AdvTable.map(e => e.id);
|
||||
const ignoredAdv = Object.keys(parsed).filter(k => !advIds.includes(k));
|
||||
if (ignoredAdv.length) console.log("Ignored (adv):", ignoredAdv);
|
||||
Object.keys(parsed).filter(k => advIds.includes(k)).forEach(k => (this.storage[k] = parsed[k]));
|
||||
|
||||
return this.storage;
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== Cust (binary parser/patcher) =====
|
||||
This class follows the original structure:
|
||||
- find magic in buffer using magicLen, mapper sizes
|
||||
- parse data using size-mapped getters/setters
|
||||
- produce Blob for download (patched buffer)
|
||||
*/
|
||||
class Cust {
|
||||
constructor() {
|
||||
this.storage = new CustStorage();
|
||||
this.magic = 1414747459; // original magic
|
||||
this.magicLen = 4;
|
||||
this.mapper = {
|
||||
2: { get: (offset) => this.view.getUint16(offset, true), set: (offset, v) => this.view.setUint16(offset, v, true) },
|
||||
4: { get: (offset) => this.view.getUint32(offset, true), set: (offset, v) => this.view.setUint32(offset, v, true) }
|
||||
};
|
||||
}
|
||||
|
||||
findMagicOffset() {
|
||||
this.view = new DataView(this.buffer);
|
||||
for (let offset = 0; offset < this.view.byteLength; offset += this.magicLen) {
|
||||
if (this.mapper[this.magicLen].get(offset) === this.magic) {
|
||||
this.beginOffset = offset;
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new Error("Invalid loader.kip file (magic not found)");
|
||||
}
|
||||
|
||||
save() {
|
||||
// update from table (validate & populate storage)
|
||||
this.storage.updateFromTable();
|
||||
|
||||
const writeOne = (entry) => {
|
||||
if (!entry.offset && entry.offset !== 0) {
|
||||
// If offset is missing in the UI, it's an error in mapping
|
||||
const el = entry.getInputElement();
|
||||
if (el) el.focus();
|
||||
throw new Error(`Failed to get offset for ${entry.name}`);
|
||||
}
|
||||
const mapper = this.mapper[entry.size];
|
||||
if (!mapper) {
|
||||
const el = entry.getInputElement();
|
||||
if (el) el.focus();
|
||||
throw new Error(`Unknown size at ${entry.name}`);
|
||||
}
|
||||
mapper.set(entry.offset, entry.value);
|
||||
};
|
||||
|
||||
// The original iterated over tables and used .offset values stored in entries
|
||||
CustTable.forEach(writeOne);
|
||||
AdvTable.forEach(writeOne);
|
||||
GpuTable.forEach(writeOne);
|
||||
|
||||
// persist storage to localStorage
|
||||
this.storage.save();
|
||||
|
||||
// create download link for patched buffer
|
||||
const blob = new Blob([this.buffer], { type: "application/octet-stream" });
|
||||
const url = URL.createObjectURL(blob);
|
||||
|
||||
const a = document.createElement("a");
|
||||
a.href = url;
|
||||
a.download = "loader.kip";
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
a.remove();
|
||||
URL.revokeObjectURL(url);
|
||||
|
||||
// UI: enable load last saved if needed
|
||||
this.toggleLoadLastSavedBtn(true);
|
||||
}
|
||||
|
||||
removeHTMLForm() {
|
||||
CustTable.forEach(e => e.removeElement());
|
||||
}
|
||||
|
||||
toggleLoadLastSavedBtn(visible) {
|
||||
const btn = document.getElementById("load_saved");
|
||||
if (!btn) return;
|
||||
if (visible) {
|
||||
btn.addEventListener("click", () => {
|
||||
if (this.storage.load()) this.storage.setTable();
|
||||
});
|
||||
btn.style.removeProperty("display");
|
||||
btn.removeAttribute("disabled");
|
||||
} else {
|
||||
btn.style.setProperty("display", "none");
|
||||
}
|
||||
}
|
||||
|
||||
createHTMLForm() {
|
||||
// create elements for each table entry
|
||||
CustTable.forEach(e => e.createElement("config-list-basic"));
|
||||
|
||||
// Add separators/titles for advanced and gpu lists
|
||||
const advContainer = document.getElementById("config-list-advanced");
|
||||
if (advContainer) {
|
||||
const p = document.createElement("p");
|
||||
p.innerHTML = "Advanced configuration";
|
||||
advContainer.appendChild(p);
|
||||
}
|
||||
const gpuContainer = document.getElementById("config-list-gpu");
|
||||
if (gpuContainer) {
|
||||
const p = document.createElement("p");
|
||||
p.innerHTML = "Gpu Volt configuration";
|
||||
gpuContainer.appendChild(p);
|
||||
}
|
||||
|
||||
AdvTable.forEach(e => e.createElement("config-list-advanced"));
|
||||
GpuTable.forEach(e => e.createElement("config-list-gpu"));
|
||||
|
||||
// Buttons: load default, load saved, save
|
||||
const loadDefaultBtn = document.getElementById("load_default");
|
||||
if (loadDefaultBtn) {
|
||||
loadDefaultBtn.removeAttribute("disabled");
|
||||
loadDefaultBtn.addEventListener("click", () => {
|
||||
CustTable.forEach(e => e.setElementDefaultValue());
|
||||
});
|
||||
}
|
||||
|
||||
// show load saved if we have saved storage
|
||||
this.toggleLoadLastSavedBtn(this.storage.load() !== null);
|
||||
|
||||
const saveBtn = document.getElementById("save");
|
||||
if (saveBtn) {
|
||||
saveBtn.removeAttribute("disabled");
|
||||
saveBtn.addEventListener("click", () => {
|
||||
try {
|
||||
this.save();
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
alert(String(err));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
initCustTabs() {
|
||||
// map nav buttons (role="tablist") to platform toggles
|
||||
const tabButtons = Array.from(document.querySelectorAll('nav[role="tablist"] > button, .cust-platform-tabs > button'));
|
||||
if (!tabButtons.length) return;
|
||||
tabButtons.forEach(btn => {
|
||||
btn.removeAttribute("disabled");
|
||||
const plat = Number(btn.getAttribute("data-platform"));
|
||||
btn.addEventListener("click", (ev) => {
|
||||
// style toggling
|
||||
const outlineClass = ["outline"];
|
||||
btn.classList.remove(...outlineClass);
|
||||
tabButtons.filter(x => x !== btn).forEach(x => x.classList.add(...outlineClass));
|
||||
// show/hide entries
|
||||
CustTable.forEach(e => {
|
||||
if (e.isAvailableFor(plat)) e.showElement(); else e.hideElement();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
parse() {
|
||||
// beginOffset should already exist
|
||||
let offset = this.beginOffset + this.magicLen;
|
||||
// read revision (4-byte)
|
||||
this.rev = this.mapper[4].get(offset);
|
||||
if (this.rev !== CUST_REV_ADV) throw new Error(`Unsupported custRev, expected: ${CUST_REV_ADV}, got ${this.rev}`);
|
||||
offset += 4;
|
||||
const revEl = document.getElementById("cust_rev");
|
||||
if (revEl) revEl.innerHTML = `Cust v${this.rev} is loaded.`;
|
||||
|
||||
const readOne = (entry) => {
|
||||
entry.offset = offset;
|
||||
const mapper = this.mapper[entry.size];
|
||||
if (!mapper) {
|
||||
const el = entry.getInputElement();
|
||||
if (el) el.focus();
|
||||
throw new Error(`Unknown size at ${entry.name}`);
|
||||
}
|
||||
entry.value = mapper.get(offset);
|
||||
offset += entry.size;
|
||||
entry.validate();
|
||||
};
|
||||
|
||||
CustTable.forEach(readOne);
|
||||
AdvTable.forEach(readOne);
|
||||
GpuTable.forEach(readOne);
|
||||
}
|
||||
|
||||
load(buffer) {
|
||||
try {
|
||||
this.buffer = buffer;
|
||||
this.findMagicOffset();
|
||||
this.removeHTMLForm();
|
||||
this.parse();
|
||||
this.initCustTabs();
|
||||
this.createHTMLForm();
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
alert(String(err));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== Release fetching classes ===== */
|
||||
class ReleaseAsset {
|
||||
constructor(obj) {
|
||||
this.downloadUrl = obj?.browser_download_url;
|
||||
this.updatedAt = obj?.updated_at;
|
||||
}
|
||||
}
|
||||
|
||||
class ReleaseInfo {
|
||||
constructor() {
|
||||
this.ocLatestApi = "https://api.github.com/repos/Horizon-OC/Horizon-OC/releases/latest";
|
||||
}
|
||||
|
||||
async load() {
|
||||
try {
|
||||
const json = await this.responseFromApi(this.ocLatestApi);
|
||||
this.parseOcResponse(json);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
alert(String(err));
|
||||
}
|
||||
}
|
||||
|
||||
async responseFromApi(url) {
|
||||
const res = await fetch(url, { method: "GET", headers: { Accept: "application/json" } });
|
||||
if (!res.ok) throw new Error(`Failed to connect to "${url}": ${res.status}`);
|
||||
return await res.json();
|
||||
}
|
||||
|
||||
parseOcResponse(json) {
|
||||
this.ocVer = json.tag_name;
|
||||
const assets = json.assets || [];
|
||||
this.loaderKipAsset = new ReleaseAsset(assets.find(a => a.name.endsWith("hoc.kip")) || {});
|
||||
this.sdOutZipAsset = new ReleaseAsset(assets.find(a => a.name.endsWith("dist.zip")) || {});
|
||||
}
|
||||
}
|
||||
|
||||
class DownloadSection {
|
||||
constructor() {
|
||||
this.element = document.getElementById("download_btn_grid") || document.getElementById("download");
|
||||
}
|
||||
|
||||
async load() {
|
||||
// Wait until the element is visible in the viewport
|
||||
for (; !this.isVisible();) {
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
}
|
||||
const release = new ReleaseInfo();
|
||||
await release.load();
|
||||
this.update("loader_kip_btn", `hoc.kip <b>${release.ocVer}</b><br>${release.loaderKipAsset.updatedAt}`, release.loaderKipAsset.downloadUrl);
|
||||
this.update("sdout_zip_btn", `dist.zip <b>${release.ocVer}</b><br>${release.sdOutZipAsset.updatedAt}`, release.sdOutZipAsset.downloadUrl);
|
||||
}
|
||||
|
||||
isVisible() {
|
||||
if (!this.element) return true;
|
||||
const r = this.element.getBoundingClientRect();
|
||||
return r.top > 0 && r.left > 0 && r.bottom - r.height < (window.innerHeight || document.documentElement.clientHeight) && r.right - r.width < (window.innerWidth || document.documentElement.clientWidth);
|
||||
}
|
||||
|
||||
update(id, html, href) {
|
||||
const el = document.getElementById(id);
|
||||
if (!el) return;
|
||||
el.innerHTML = html;
|
||||
el.removeAttribute("aria-busy");
|
||||
if (href) el.setAttribute("href", href);
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== Initialization wiring ===== */
|
||||
document.addEventListener("DOMContentLoaded", async () => {
|
||||
// Ensure containers exist (fail gracefully if not)
|
||||
const ensureEl = (id, createTag = "div") => {
|
||||
if (!document.getElementById(id)) {
|
||||
const container = document.createElement(createTag);
|
||||
container.id = id;
|
||||
container.classList.add("mt-4");
|
||||
// append to config section or body as fallback
|
||||
const config = document.getElementById("config") || document.body;
|
||||
config.appendChild(container);
|
||||
}
|
||||
};
|
||||
|
||||
["config-list-basic", "config-list-advanced", "config-list-gpu"].forEach(id => ensureEl(id));
|
||||
|
||||
// Wire file input
|
||||
const fileInput = document.getElementById("file");
|
||||
if (fileInput) {
|
||||
fileInput.addEventListener("change", (ev) => {
|
||||
const cust = new Cust();
|
||||
const target = ev.target;
|
||||
if (!target || !target.files) return;
|
||||
const fr = new FileReader();
|
||||
fr.readAsArrayBuffer(target.files[0]);
|
||||
fr.onloadend = (e) => {
|
||||
if (e.target && e.target.readyState === FileReader.DONE) {
|
||||
cust.load(e.target.result);
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
// Wire DownloadSection (non-blocking)
|
||||
(async () => {
|
||||
try {
|
||||
const ds = new DownloadSection();
|
||||
await ds.load();
|
||||
} catch (err) {
|
||||
console.warn("DownloadSection failed:", err);
|
||||
}
|
||||
})();
|
||||
|
||||
// If HTML had DOMContentLoaded wiring in original minified code, emulate it:
|
||||
// some initialization that original file did on DOMContentLoaded -> start the DownloadSection (done above)
|
||||
});
|
||||
153
docs/index.html
153
docs/index.html
@@ -1,153 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Horizon OC</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link href="https://unpkg.com/aos@2.3.1/dist/aos.css" rel="stylesheet">
|
||||
<style>
|
||||
/* Background gradient */
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: 'Segoe UI', Roboto, system-ui, sans-serif;
|
||||
color: white;
|
||||
background: linear-gradient(160deg, #1a1a1a 0%, #2a2a2a 50%, #3a3a3a 100%);
|
||||
min-height: 100vh;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
/* Liquid glass panels */
|
||||
.glass {
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
border: 1px solid rgba(255, 255, 255, 0.15);
|
||||
backdrop-filter: blur(20px);
|
||||
border-radius: 20px;
|
||||
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.3);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.glass:hover {
|
||||
background: rgba(255, 255, 255, 0.12);
|
||||
transform: translateY(-4px);
|
||||
}
|
||||
|
||||
/* Hero gradient text */
|
||||
.gradient-text {
|
||||
background: linear-gradient(to right, #a3baff, #b8f3ff);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
|
||||
/* Buttons: Liquid glass style */
|
||||
.button-glass {
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
backdrop-filter: blur(20px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.25);
|
||||
color: #fff;
|
||||
padding: 0.8rem 2rem;
|
||||
border-radius: 9999px;
|
||||
font-weight: 600;
|
||||
transition: all 0.25s ease;
|
||||
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.6rem;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.button-glass:hover {
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
footer {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.15);
|
||||
padding: 1.5rem 0;
|
||||
text-align: center;
|
||||
color: #ccc;
|
||||
font-size: 0.9rem;
|
||||
margin-top: 4rem;
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
/* GitHub Icon */
|
||||
.github-icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
fill: white;
|
||||
transition: fill 0.3s;
|
||||
}
|
||||
.button-glass:hover .github-icon {
|
||||
fill: #b8f3ff;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- Header -->
|
||||
<header class="text-center py-20">
|
||||
<h1 class="text-6xl font-extrabold mb-4 gradient-text">Horizon OC</h1>
|
||||
<p class="text-gray-300 text-lg">Upgrade the performance of your Nintendo Switch Console</p>
|
||||
|
||||
<div class="mt-6 flex justify-center gap-4">
|
||||
<a href="#download" class="button-glass">Download Now</a>
|
||||
<a href="configurator.html" class="button-glass">Open Configurator</a>
|
||||
<a href="https://github.com/Horizon-OC/Horizon-OC" target="_blank" class="button-glass">
|
||||
<!-- GitHub SVG Icon -->
|
||||
<svg class="github-icon" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8a8 8 0 005.47 7.59c.4.07.55-.17.55-.38v-1.32C3.73 14.9 3.27 13.4 3.27 13.4c-.36-.9-.88-1.14-.88-1.14-.72-.49.05-.48.05-.48.8.06 1.22.83 1.22.83.71 1.21 1.87.86 2.33.66.07-.52.28-.86.5-1.06-2.22-.25-4.55-1.11-4.55-4.95 0-1.09.39-1.98 1.03-2.68-.1-.25-.45-1.27.1-2.65 0 0 .84-.27 2.75 1.02A9.56 9.56 0 018 3.43a9.6 9.6 0 012.5.34c1.9-1.29 2.74-1.02 2.74-1.02.55 1.38.2 2.4.1 2.65.64.7 1.03 1.59 1.03 2.68 0 3.85-2.34 4.7-4.57 4.95.29.25.54.73.54 1.48v2.2c0 .21.15.45.55.38A8 8 0 0016 8c0-4.42-3.58-8-8-8z"/>
|
||||
</svg>
|
||||
GitHub
|
||||
</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- About Section -->
|
||||
<section class="max-w-3xl mx-auto text-center py-16 px-6 glass" data-aos="fade-up">
|
||||
<h2 class="text-3xl font-bold mb-4">What is Horizon OC?</h2>
|
||||
<p class="text-gray-300">
|
||||
Horizon OC is a tool to overclock your modded Nintendo Switch console.
|
||||
This can help improve frame rates, load times, and latency in games.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<!-- Features -->
|
||||
<section class="py-20">
|
||||
<div class="max-w-6xl mx-auto grid md:grid-cols-3 gap-8 px-6">
|
||||
<div class="glass p-6 text-center" data-aos="zoom-in" data-aos-delay="100">
|
||||
<h3 class="text-xl font-semibold mb-2">⚡ Performance</h3>
|
||||
<p class="text-gray-300">Overclocking your console can lead to significantly better performance in demanding titles.</p>
|
||||
</div>
|
||||
<div class="glass p-6 text-center" data-aos="zoom-in" data-aos-delay="200">
|
||||
<h3 class="text-xl font-semibold mb-2">☣ Safety</h3>
|
||||
<p class="text-gray-300">Horizon OC aims to be as safe as possible, while allowing advanced users to customize it further.</p>
|
||||
</div>
|
||||
<div class="glass p-6 text-center" data-aos="zoom-in" data-aos-delay="300">
|
||||
<h3 class="text-xl font-semibold mb-2">🔧 Customizable</h3>
|
||||
<p class="text-gray-300">Horizon OC comes with an advanced configurator allowing you to tune it for your own needs.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Download Section -->
|
||||
<section id="download" class="text-center py-20 glass max-w-3xl mx-auto px-6" data-aos="fade-up">
|
||||
<h2 class="text-3xl font-bold mb-6">Get Horizon OC</h2>
|
||||
<a href="#" class="button-glass">Download Latest Release</a>
|
||||
<p class="text-gray-400 mt-4">Ensure you are using the latest version of Atmosphere.</p>
|
||||
</section>
|
||||
|
||||
<!-- Footer -->
|
||||
<footer>
|
||||
This website is open source and licensed under the GPLv2.
|
||||
</footer>
|
||||
|
||||
<script src="https://unpkg.com/aos@2.3.1/dist/aos.js"></script>
|
||||
<script>AOS.init({ once: true, duration: 800 });</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user