33 Commits

Author SHA1 Message Date
souldbminersmwc
e1c66815f9 add bpmp basics 2026-03-08 18:13:15 -04:00
Lightos1
bde65f094d Misc3: Add missing ram load 2026-03-08 13:27:36 +01:00
Lightos1
3fa2cfabd3 Reorder menus/put settings into submenus to improve scrolling 2026-03-07 23:19:50 +01:00
souldbminersmwc
b8f4d02e4f sysclk: UI rework + bump version 2026-03-07 11:24:21 -05:00
souldbminersmwc
436b7feb8e sysclk: fix dvfs after set logic 2026-03-07 10:35:40 -05:00
souldbminersmwc
8bab4dd6ee Merge branch 'main' of https://github.com/Horizon-OC/Horizon-OC 2026-03-07 10:30:50 -05:00
souldbminersmwc
99dfea631b add rgltr services 2026-03-07 10:30:47 -05:00
Lightos1
16501bd6a8 Remove deprecated configurator 2026-03-01 21:37:31 +01:00
Lightos1
88201b7308 Add/update comments 2026-03-01 21:35:07 +01:00
Lightos1
2fb680b06a Remove ancient todo 2026-03-01 21:32:54 +01:00
Lightos1
fb8116107b correct CpuVoltOfficial for informational purposes 2026-03-01 21:30:54 +01:00
Lightos1
e6b83a1db5 Adjust l4t limit 2026-03-01 21:29:03 +01:00
Lightos1
607a19048b Extend dvfs offset to -80 2026-03-01 21:05:41 +01:00
Lightos1
0db831e0c3 lower cpu vmax 2026-03-01 16:57:38 +01:00
Lightos1
863cca507d lower cpu vmax validators 2026-03-01 16:54:19 +01:00
Lightos1
3916a252d4 Lower max max voltage 2026-03-01 16:53:46 +01:00
souldbminersmwc
1594b76851 100th commit 2026-02-26 15:34:45 -05:00
souldbminersmwc
9e14fc5241 add some more docs 2026-02-24 18:32:54 -05:00
souldbminersmwc
54fd3e2fd1 Update registers.h 2026-02-24 18:27:12 -05:00
souldbminersmwc
2348f8dba2 apparently, claude can't generate defines correctly 2026-02-24 18:24:05 -05:00
souldbminersmwc
f0a3dc48f9 fix live uv 2026-02-24 17:19:58 -05:00
souldbminersmwc
58ad43213b sysclk: add RAM table editor 2026-02-24 17:09:24 -05:00
souldbminersmwc
4a505b7238 update binaries 2026-02-24 16:25:28 -05:00
souldbminersmwc
7c6c0e68d2 Update pcv.cpp 2026-02-24 16:23:42 -05:00
souldbminersmwc
1c5b22710d Update pcv.cpp 2026-02-24 16:22:48 -05:00
souldbminersmwc
75755528b1 Merge branch 'main' of https://github.com/Horizon-OC/Horizon-OC 2026-02-24 16:22:03 -05:00
Lightos1
4dadcaf574 Revert to defaults 2026-02-24 20:17:53 +01:00
Lightos1
5a88d53443 Erista uv stuff: this makes no sense 2026-02-24 20:16:10 +01:00
Lightos1
2bd5faa7d9 Erista uv & vmin fixes 2026-02-24 19:20:41 +01:00
Lightos1
29cb868f50 Improve formating 2026-02-24 09:08:09 +01:00
souldbminersmwc
4eb222f5aa ldr/sysclk: add 2397 erista cpu, fix cpu uv, add erista cpu max clock 2026-02-23 19:09:59 -05:00
souldbminersmwc
eca6ab2297 sysclk: fix erista cpu uv 2026-02-23 18:45:39 -05:00
souldbminersmwc
749e5147df ldr: add commented pll limit patch 2026-02-23 18:44:10 -05:00
40 changed files with 1729 additions and 2228 deletions

View File

@@ -36,7 +36,7 @@ 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

View File

@@ -4,7 +4,8 @@
| Version | Supported |
| ------- | ------------------ |
| 0.x | :white_check_mark: |
| 1.x | :white_check_mark: |
| 0.x | Not supported |
## Reporting a Vulnerability

View File

@@ -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 */
@@ -98,7 +98,7 @@ volatile CustomizeTable C = {
.eristaCpuBoostClock = 1785000, // Default boost clock
.marikoCpuBoostClock = 1963000, // Default boost clock
.eristaGpuUV = 0,
.eristaGpuUV = 2,
.eristaGpuVmin = 810,
.marikoGpuUV = 0,
@@ -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 } },
},
};

View File

@@ -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;

View File

@@ -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
}
}

View File

@@ -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,17 +202,12 @@ 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");
@@ -223,13 +218,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)

View File

@@ -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;
}
}
}

View File

@@ -24,6 +24,21 @@
namespace ams::ldr::hoc::pcv::erista {
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 CpuVoltDvfs(u32 *ptr) {
if (MatchesPattern(ptr, cpuVoltDvfsPattern, cpuVoltDvfsOffsets)) {
if (C.eristaCpuVmin) {
@@ -65,12 +80,13 @@ namespace ams::ldr::hoc::pcv::erista {
R_SUCCEED();
}
/* In theory this should work, but it doesn't, I have no idea why ¯\_(ツ)_/¯ */
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) {
R_SKIP();
@@ -407,20 +423,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 +438,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},

View File

@@ -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) {

View File

@@ -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);
}
}
}

View File

@@ -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);
}

View File

@@ -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");
}
}
}

View File

@@ -0,0 +1,54 @@
# Configuration
PROJECT_NAME = firmware
CPU = arm7tdmi
ARCH = armv4t
OPTIMIZATION = -Ofast
# Toolchain
CC = arm-none-eabi-gcc
OBJCOPY = arm-none-eabi-objcopy
SIZE = arm-none-eabi-size
# Directories
SRC_DIR = src
BUILD_DIR = build
# Source files
SOURCES = $(wildcard $(SRC_DIR)/*.c)
OBJECTS = $(patsubst $(SRC_DIR)/%.c, $(BUILD_DIR)/%.o, $(SOURCES))
# Output files
ELF = $(PROJECT_NAME).elf
BIN = $(PROJECT_NAME).bin
# Compiler flags
CFLAGS = -mcpu=$(CPU) -march=$(ARCH) \
$(OPTIMIZATION) -Wall -ffunction-sections -fdata-sections \
-I$(SRC_DIR)
# Linker flags
LDFLAGS = -mcpu=$(CPU) -march=$(ARCH) \
-T linker.ld -Wl,--gc-sections
# Targets
.PHONY: all clean
all: $(BIN)
@echo "✓ Built: $(BIN)"
@$(SIZE) $(ELF)
$(BIN): $(ELF)
@$(OBJCOPY) -O binary $(ELF) $(BIN)
$(ELF): $(OBJECTS)
@echo "Linking..."
@$(CC) $(LDFLAGS) $(OBJECTS) -o $(ELF)
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c
@mkdir -p $(BUILD_DIR)
@echo "Compiling: $<"
@$(CC) $(CFLAGS) -c $< -o $@
clean:
@rm -rf $(BUILD_DIR) $(ELF) $(BIN)
@echo "✓ Cleaned"

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,69 @@
/*
* Copyright (c) Souldbminer
*
* 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/>.
*
*/
MEMORY
{
SRAM (rwx) : ORIGIN = 0x60000000, LENGTH = 32K
}
ENTRY(Reset_Handler)
SECTIONS
{
.vectors :
{
KEEP(*(.vectors))
. = ALIGN(4);
} > SRAM
.text :
{
*(.text*)
*(.rodata*)
. = ALIGN(4);
} > SRAM
.data :
{
_sdata = .;
*(.data*)
_edata = .;
. = ALIGN(4);
} > SRAM
_sidata = _edata;
.bss :
{
_sbss = .;
*(.bss*)
*(COMMON)
_ebss = .;
. = ALIGN(4);
} > SRAM
/* Stack at end of SRAM */
_estack = ORIGIN(SRAM) + LENGTH(SRAM);
/* Discard debug sections */
/DISCARD/ :
{
*(.debug_*)
*(.comment)
}
}

View File

@@ -0,0 +1,184 @@
/*
* Copyright (c) Souldbminer
*
* 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/>.
*
*/
/*
* Exception Vector Table (ARM7TDMI):
* 0x00: Reset
* 0x04: Undefined Instruction
* 0x08: Software Interrupt (SWI)
* 0x0C: Prefetch Abort
* 0x10: Data Abort
* 0x14: Reserved
* 0x18: IRQ
* 0x1C: FIQ
*/
#include <stdint.h>
#include <string.h>
extern uint32_t _sdata; /* Start of .data section */
extern uint32_t _edata; /* End of .data section */
extern uint32_t _sidata; /* Start of .data in SRAM */
extern uint32_t _sbss; /* Start of .bss section */
extern uint32_t _ebss; /* End of .bss section */
extern uint32_t _estack; /* End of stack */
extern int main(void);
/* Forward declarations */
void Reset_Handler(void);
void Undefined_Handler(void);
void SWI_Handler(void);
void PrefetchAbort_Handler(void);
void DataAbort_Handler(void);
void IRQ_Handler(void);
void FIQ_Handler(void);
void Reset_Handler(void) {
uint32_t data_size = (uint32_t)(&_edata) - (uint32_t)(&_sdata);
if (data_size > 0) {
memcpy(&_sdata, &_sidata, data_size);
}
uint32_t bss_size = (uint32_t)(&_ebss) - (uint32_t)(&_sbss);
if (bss_size > 0) {
memset(&_sbss, 0, bss_size);
}
main();
while (1) {
__asm__ volatile("wfi");
}
}
void DataAbort_Handler(void) {
uint32_t fault_addr;
uint32_t fault_status;
__asm__ volatile("mrc p15, 0, %0, c6, c0, 0" : "=r"(fault_addr)); /* DFAR */
__asm__ volatile("mrc p15, 0, %0, c5, c0, 0" : "=r"(fault_status)); /* DFSR */
(void)fault_addr;
(void)fault_status;
while (1) {
__asm__ volatile("nop");
}
}
void PrefetchAbort_Handler(void) {
uint32_t fault_addr;
uint32_t fault_status;
__asm__ volatile("mrc p15, 0, %0, c6, c0, 2" : "=r"(fault_addr)); /* IFAR */
__asm__ volatile("mrc p15, 0, %0, c5, c0, 1" : "=r"(fault_status)); /* IFSR */
(void)fault_addr;
(void)fault_status;
while (1) {
__asm__ volatile("nop");
}
}
void Undefined_Handler(void) {
while (1) {
__asm__ volatile("nop");
}
}
void SWI_Handler(void) {
uint32_t *lr;
uint32_t swi_instr;
uint32_t swi_number;
__asm__ volatile("mov %0, lr" : "=r"(lr));
swi_instr = *(lr - 1);
swi_number = swi_instr & 0xFFFFFF; /* Lower 24 bits = SWI number */
(void)swi_number; /* Use SWI number for dispatch */
}
void IRQ_Handler(void) {
while (1) {
__asm__ volatile("nop");
}
}
void FIQ_Handler(void) {
while (1) {
__asm__ volatile("nop");
}
}
void Default_Handler(void) {
while (1) {
__asm__ volatile("swi 0");
}
}
__attribute__((section(".vectors")))
void (*const exception_vectors[])(void) = {
Reset_Handler, /* 0x00 - Reset */
Undefined_Handler, /* 0x04 - Undefined Instruction */
SWI_Handler, /* 0x08 - Software Interrupt */
PrefetchAbort_Handler, /* 0x0C - Prefetch Abort */
DataAbort_Handler, /* 0x10 - Data Abort */
(void (*)(void))0, /* 0x14 - Reserved */
IRQ_Handler, /* 0x18 - IRQ */
FIQ_Handler /* 0x1C - FIQ */
};
static inline uint32_t get_cpsr(void) {
uint32_t cpsr;
__asm__ volatile("mrs %0, cpsr" : "=r"(cpsr));
return cpsr;
}
static inline void set_cpsr(uint32_t cpsr) {
__asm__ volatile("msr cpsr, %0" : : "r"(cpsr));
}
static inline void disable_irq(void) {
uint32_t cpsr = get_cpsr();
set_cpsr(cpsr | 0x80); /* Set I bit (disable IRQ) */
}
static inline void enable_irq(void) {
uint32_t cpsr = get_cpsr();
set_cpsr(cpsr & ~0x80); /* Clear I bit (enable IRQ) */
}
static inline void disable_fiq(void) {
uint32_t cpsr = get_cpsr();
set_cpsr(cpsr | 0x40); /* Set F bit (disable FIQ) */
}
static inline void enable_fiq(void) {
uint32_t cpsr = get_cpsr();
set_cpsr(cpsr & ~0x40); /* Clear F bit (enable FIQ) */
}
int main(void) {
while (1) {
__asm__("nop");
}
return 0;
}

View File

@@ -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

View File

@@ -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);

View File

@@ -151,6 +151,12 @@ typedef enum {
GovernorState_Enabled_Gpu,
GovernorState_EnumMax,
} GovernorState;
typedef enum {
RamDisplayMode_VDD2VDDQ = 0,
RamDisplayMode_VDD2Usage,
RamDisplayMode_VDDQUsage,
RamDisplayMode_EnumMax,
} RamDisplayMode;
#define SYSCLK_ENUM_VALID(n, v) ((v) < n##_EnumMax)

View File

@@ -63,6 +63,9 @@ typedef enum {
HorizonOCConfigValue_GPUScheduling,
HorizonOCConfigValue_GPUSchedulingMethod,
HorizonOCConfigValue_RAMVoltUsageDisplayMode,
KipConfigValue_custRev,
// KipConfigValue_mtcConf,
KipConfigValue_hpMode,
@@ -135,38 +138,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 +200,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 +247,9 @@ 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";
// KIP config values
case KipConfigValue_custRev:
return pretty ? "Custom Revision" : "kip_cust_rev";
@@ -370,41 +372,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 +422,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 +436,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;
@@ -521,6 +519,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 +578,11 @@ static inline uint64_t sysclkValidConfigValue(SysClkConfigValue val, uint64_t in
case HorizonOCConfigValue_DVFSMode:
case HorizonOCConfigValue_DVFSOffset:
case HorizonOCConfigValue_GPUScheduling:
case HorizonOCConfigValue_RAMVoltUsageDisplayMode:
return true;
case HorizonOCConfigValue_BatteryChargeCurrent:
return ((input >= 1024) && (input <= 3072)) || !input;
default:
return true;
return false;
}
}

View File

@@ -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);
}

View File

@@ -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 := 0.42
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__

View File

@@ -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);
@@ -234,14 +235,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
@@ -287,7 +293,7 @@ void BaseMenuGui::refresh()
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();

View File

@@ -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)

View File

@@ -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

View File

@@ -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,

View File

@@ -1249,7 +1249,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) {

View File

@@ -40,7 +40,6 @@
#include <cstdio>
#include <crc32.h>
#define HOSPPC_HAS_BOOST (hosversionAtLeast(7,0,0))
bool isGpuGovernorEnabled = false;
bool isCpuGovernorEnabled = false;
@@ -712,6 +711,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 +725,13 @@ 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);
}
}
@@ -767,7 +771,7 @@ void ClockManager::HandleFreqReset(SysClkModule module, bool isBoost) {
case SysClkModule_CPU:
if(!(isBoost || (this->config->GetConfigValue(HocClkConfigValue_OverwriteBoostMode) && isBoost)))
Board::ResetToStockCpu();
if(this->config->GetConfigValue(HorizonOCConfigValue_LiveCpuUv)) {
if(this->config->GetConfigValue(HorizonOCConfigValue_LiveCpuUv) || (kipAvailable && Board::GetSocType() == SysClkSocType_Erista)) {
if(Board::GetSocType() == SysClkSocType_Erista)
Board::SetCpuUvLevel(this->config->GetConfigValue(KipConfigValue_eristaCpuUV), 0, 1581000000);
else
@@ -861,7 +865,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) || (kipAvailable && Board::GetSocType() == SysClkSocType_Erista)))
{
HandleCpuUv();
}
@@ -897,7 +901,7 @@ void ClockManager::Tick()
void ClockManager::ResetToStockClocks() {
Board::ResetToStockCpu();
if(this->config->GetConfigValue(HorizonOCConfigValue_LiveCpuUv))
if(this->config->GetConfigValue(HorizonOCConfigValue_LiveCpuUv) || (kipAvailable && Board::GetSocType() == SysClkSocType_Erista))
{
if(Board::GetSocType() == SysClkSocType_Erista)
Board::SetCpuUvLevel(this->config->GetConfigValue(KipConfigValue_eristaCpuUV), 0, 1581000000);
@@ -1126,11 +1130,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 +1302,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);
}

View File

@@ -36,15 +36,48 @@ class SysDockIntegration;
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);
/**

View File

@@ -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)

168
dist/README.md vendored
View File

@@ -1,168 +0,0 @@
<div align="center">
<img src="assets/logo.png" alt="logo" width="350"/>
---
![License: GPL-2.0](https://img.shields.io/badge/GPL--2.0-red?style=for-the-badge)
![Nintendo Switch](https://img.shields.io/badge/Nintendo_Switch-E60012?style=for-the-badge\&logo=nintendo-switch\&logoColor=white)
[![Discord](https://img.shields.io/badge/Discord-5865F2?style=for-the-badge\&logo=discord\&logoColor=white)](https://dsc.gg/horizonoc)
![VSCode](https://img.shields.io/badge/VSCode-0078D4?style=for-the-badge\&logo=visual%20studio%20code\&logoColor=white)
![Made with Notepad++](assets/np++.png?raw=true)
![C++](https://img.shields.io/badge/C%2B%2B-00599C?style=for-the-badge\&logo=c%2B%2B\&logoColor=white)
![Downloads](https://img.shields.io/github/downloads/souldbminersmwc/Horizon-OC/total.svg?style=for-the-badge)
---
</div>
## ⚠️ Disclaimer
> **THIS TOOL CAN BE DANGEROUS IF MISUSED. PROCEED WITH CAUTION.**
> Due to the design of Horizon OS, **overclocking RAM can cause NAND OR SD CORRUPTION.**
> Ensure you have a **full NAND, PROINFO, EMUMMC and SD backup** before proceeding.
---
## About
**Horizon OC** is an open-source overclocking tool for Nintendo Switch consoles running **Atmosphere custom firmware**.
It enables advanced CPU, GPU, and RAM tuning with user-friendly configuration tools.
---
## Features
* **CPU:** Up to 1963MHz (Mariko) / 1785MHz (Erista)
* **GPU:** Up to 1075MHz (Mariko) / 921MHz (Erista)
* **RAM:** Up to 1866MHz (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
---
## Installation
1. Ensure you have the latest versions of
* [Atmosphere](https://github.com/Atmosphere-NX/Atmosphere)
* [Ultrahand Overlay](https://github.com/ppkantorski/Ultrahand-Overlay)
2. Download and extract the **Horizon OC Package** to the root of your SD card.
3. If using **Hekate**, edit `hekate_ipl.ini` to include:
```
kip1=atmosphere/kips/hoc.kip
```
*(No changes needed if using fusee.)*
---
## Configuration
1. Open the Horizon OC Overlay
2. Open the settings menu
3. Adjust your overclocking settings as desired. A helpful guide can be found [here.](https://rentry.co/mariko#oc-settings-for-horizon-oc)
4. Click **Save KIP Settings** to apply your configuration.
---
## Building from Source
Refer to COMPILATION.md
---
## Clock table
### MEM clocks
* 3200 → max on mariko, JEDEC.
* 2933 → JEDEC.
* 2666 → JEDEC.
* 2400 → max on erista, JEDEC.
* 2133 → mariko safe max (4266 Modules), JEDEC.
* 1996 → JEDEC.
* 1866 → mariko safe max (3733 Modules), JEDEC.
* 1600 → official docked, boost mode, erista safe max, JEDEC.
* 1331 → official handheld, JEDEC.
* 1065
* 800
* 665
### CPU clocks
* 2601 → mariko absolute max, very dangerous
* 2499
* 2397 → mariko safe max with UV (low speedo)
* 2295
* 2193
* 2091
* 1963 → mariko no UV max clock
* 1887
* 1785 → erista no UV max clock, boost mode
* 1683
* 1581
* 1428
* 1326
* 1224 → sdev oc
* 1122
* 1020 → official docked & handheld
* 918
* 816
* 714
* 612 → sleep mode
**Notes:**
1. On Erista, CPU in handheld is capped to 1581MHz
### GPU clocks
* 1536 → absolute max clock on mariko. very dangerous
* 1459
* 1382
* 1305
* 1267 → NVIDIA T214 rating
* 1228 → mariko HiOPT safe clock
* 1152 → mariko SLT max clock
* 1075 → mariko no UV max clock. absolute max clock on erista. very dangerous
* 998 → NVIDIA T210 rating
* 960 (erista only) → erista slt/hiopt safe max clock
* 921 → erista no UV max clock
* 844
* 768 → official docked
* 691
* 614
* 537
* 460 → max handheld
* 384 → official handheld
* 307 → official handheld
* 230
* 153
* 76 → boost mode
**Notes:**
1. GPU overclock is capped at 460MHz on erista in handheld
2. On Mariko, cap with No uv is 614MHz, with SLT it is 691MHz and with HiOPT it's 768MHz
3. Clocks higher than 768MHz on erista need the official charger is plugged in.
4. On Mariko, cap with No uv is 844MHz, with SLT it is 921MHz and with HiOPT it's 998MHz
---
## Credits
* **Lightos's Cat** - Cat
* **Souldbminer** hoc-clk and loader development
* **Lightos** loader patches development
* **SciresM** - Atmosphere CFW
* **CTCaer** - L4T, Hekate, perfect ram timings
* **KazushiMe** Switch OC Suite
* **hanai3bi (meha)** Switch OC Suite, EOS, sys-clk-eos
* **NaGaa95** L4T-OC-kernel
* **B3711 (halop)** EOS
* **sys-clk team (m4xw, p-sam, natinusala)** sys-clk
* **b0rd2death** Ultrahand sys-clk & Status Monitor fork
* **MasaGratoR and ZachyCatGames** - General help
* **MasaGratoR** - Status Monitor & Display Refresh Rate Driver
* **Dom, Samybigio, Arcdelta, Miki, Happy, Flopsider, Winnerboi77, Blaise, Alvise, TDRR, agjeococh, frost, letum00 and Xenshen** - Testing
* **Samybigio2011** - Italian translations

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -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>

View File

@@ -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)
});

View File

@@ -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>