Compare commits
65 Commits
0.39
...
hocclk-on-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e1c66815f9 | ||
|
|
bde65f094d | ||
|
|
3fa2cfabd3 | ||
|
|
b8f4d02e4f | ||
|
|
436b7feb8e | ||
|
|
8bab4dd6ee | ||
|
|
99dfea631b | ||
|
|
16501bd6a8 | ||
|
|
88201b7308 | ||
|
|
2fb680b06a | ||
|
|
fb8116107b | ||
|
|
e6b83a1db5 | ||
|
|
607a19048b | ||
|
|
0db831e0c3 | ||
|
|
863cca507d | ||
|
|
3916a252d4 | ||
|
|
1594b76851 | ||
|
|
9e14fc5241 | ||
|
|
54fd3e2fd1 | ||
|
|
2348f8dba2 | ||
|
|
f0a3dc48f9 | ||
|
|
58ad43213b | ||
|
|
4a505b7238 | ||
|
|
7c6c0e68d2 | ||
|
|
1c5b22710d | ||
|
|
75755528b1 | ||
|
|
4dadcaf574 | ||
|
|
5a88d53443 | ||
|
|
2bd5faa7d9 | ||
|
|
29cb868f50 | ||
|
|
4eb222f5aa | ||
|
|
eca6ab2297 | ||
|
|
749e5147df | ||
|
|
55e84d0051 | ||
|
|
8cd9727429 | ||
|
|
660e839bed | ||
|
|
afb16d2045 | ||
|
|
f4b025f33c | ||
|
|
e03c3b7be0 | ||
|
|
5a2ba5f785 | ||
|
|
e1463dca05 | ||
|
|
82972127a1 | ||
|
|
272eaed351 | ||
|
|
989e67daac | ||
|
|
dcec618ae9 | ||
|
|
bc12388b6d | ||
|
|
6625488180 | ||
|
|
1209337af6 | ||
|
|
0f608b1702 | ||
|
|
cf547d517b | ||
|
|
8c75c68dca | ||
|
|
ab020c0a90 | ||
|
|
44dc402b54 | ||
|
|
a1d047f48d | ||
|
|
cbed5e11ab | ||
|
|
1ad3f6c441 | ||
|
|
820a26ba2a | ||
|
|
f0952119b6 | ||
|
|
ca5ddbd779 | ||
|
|
be49a27118 | ||
|
|
190353dc11 | ||
|
|
4a1772df77 | ||
|
|
460d1b8471 | ||
|
|
2493c798bc | ||
|
|
7525baf567 |
2
.gitmodules
vendored
2
.gitmodules
vendored
@@ -6,4 +6,4 @@
|
||||
url = https://github.com/ppkantorski/libultrahand
|
||||
[submodule "Source/sys-clk/overlay/lib/libultrahand"]
|
||||
path = Source/sys-clk/overlay/lib/libultrahand
|
||||
url = https://github.com/ppkantorski/libultrahand
|
||||
url = https://github.com/ppkantorski/libultrahand
|
||||
2
LICENSE
2
LICENSE
@@ -6,6 +6,8 @@
|
||||
|
||||
- Although "sys-clk" uses permissive license, all modifications towards it in this repo ("hoc-clk") are licensed under GPL v2.
|
||||
|
||||
- Status-Monitor is licensed under the GPLv2
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
|
||||
14
README.md
14
README.md
@@ -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
|
||||
@@ -56,7 +56,6 @@ It enables advanced CPU, GPU, and RAM tuning with user-friendly configuration to
|
||||
|
||||
```
|
||||
kip1=atmosphere/kips/hoc.kip
|
||||
secmon=exosphere.bin
|
||||
```
|
||||
|
||||
*(No changes needed if using fusee.)*
|
||||
@@ -114,6 +113,9 @@ Refer to COMPILATION.md
|
||||
* 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
|
||||
@@ -140,8 +142,10 @@ Refer to COMPILATION.md
|
||||
* 76 → boost mode
|
||||
|
||||
**Notes:**
|
||||
1. GPU overclock is capped at 460MHz in handheld and capped at 768MHz if charging, unless you're using the official charger.
|
||||
2. Clocks higher than 768MHz need the official charger is plugged in.
|
||||
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
|
||||
|
||||
---
|
||||
|
||||
@@ -160,5 +164,5 @@ Refer to COMPILATION.md
|
||||
* **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 and Xenshen** - Testing
|
||||
* **Dom, Samybigio, Arcdelta, Miki, Happy, Flopsider, Winnerboi77, Blaise, Alvise, TDRR, agjeococh, frost, letum00 and Xenshen** - Testing
|
||||
* **Samybigio2011** - Italian translations
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| 0.x | :white_check_mark: |
|
||||
| 1.x | :white_check_mark: |
|
||||
| 0.x | Not supported |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#define __ACCESS_TABLE_NAME__ EmcAccessTable1
|
||||
#define __ACCESS_TABLE_ADDRESS__ MemoryRegionPhysicalDeviceExternalMemoryController1.GetAddress()
|
||||
#define __ACCESS_TABLE_INC__ "secmon_emc_access_table_data.inc"
|
||||
|
||||
#include "secmon_define_access_table.inc"
|
||||
|
||||
#undef __ACCESS_TABLE_INC__
|
||||
#undef __ACCESS_TABLE_ADDRESS__
|
||||
#undef __ACCESS_TABLE_NAME__
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#define __ACCESS_TABLE_NAME__ EmcAccessTable2
|
||||
#define __ACCESS_TABLE_ADDRESS__ MemoryRegionPhysicalDeviceExternalMemoryController2.GetAddress()
|
||||
#define __ACCESS_TABLE_INC__ "secmon_emc_access_table_data.inc"
|
||||
|
||||
#include "secmon_define_access_table.inc"
|
||||
|
||||
#undef __ACCESS_TABLE_INC__
|
||||
#undef __ACCESS_TABLE_ADDRESS__
|
||||
#undef __ACCESS_TABLE_NAME__
|
||||
@@ -965,3 +965,76 @@ SetRegisterAllowed(0xECC);
|
||||
SetRegisterAllowed(0xED0);
|
||||
SetRegisterAllowed(0xED4);
|
||||
SetRegisterAllowed(0xED8);
|
||||
SetRegisterAllowed(0xEDC);
|
||||
SetRegisterAllowed(0xEE0);
|
||||
SetRegisterAllowed(0xEE4);
|
||||
SetRegisterAllowed(0xEE8);
|
||||
SetRegisterAllowed(0xEEC);
|
||||
SetRegisterAllowed(0xEF0);
|
||||
SetRegisterAllowed(0xEF4);
|
||||
SetRegisterAllowed(0xEF8);
|
||||
SetRegisterAllowed(0xEFC);
|
||||
SetRegisterAllowed(0xF00);
|
||||
SetRegisterAllowed(0xF04);
|
||||
SetRegisterAllowed(0xF08);
|
||||
SetRegisterAllowed(0xF0C);
|
||||
SetRegisterAllowed(0xF10);
|
||||
SetRegisterAllowed(0xF14);
|
||||
SetRegisterAllowed(0xF18);
|
||||
SetRegisterAllowed(0xF1C);
|
||||
SetRegisterAllowed(0xF20);
|
||||
SetRegisterAllowed(0xF24);
|
||||
SetRegisterAllowed(0xF28);
|
||||
SetRegisterAllowed(0xF2C);
|
||||
SetRegisterAllowed(0xF30);
|
||||
SetRegisterAllowed(0xF34);
|
||||
SetRegisterAllowed(0xF38);
|
||||
SetRegisterAllowed(0xF3C);
|
||||
SetRegisterAllowed(0xF40);
|
||||
SetRegisterAllowed(0xF44);
|
||||
SetRegisterAllowed(0xF48);
|
||||
SetRegisterAllowed(0xF4C);
|
||||
SetRegisterAllowed(0xF50);
|
||||
SetRegisterAllowed(0xF54);
|
||||
SetRegisterAllowed(0xF58);
|
||||
SetRegisterAllowed(0xF5C);
|
||||
SetRegisterAllowed(0xF60);
|
||||
SetRegisterAllowed(0xF64);
|
||||
SetRegisterAllowed(0xF68);
|
||||
SetRegisterAllowed(0xF6C);
|
||||
SetRegisterAllowed(0xF70);
|
||||
SetRegisterAllowed(0xF74);
|
||||
SetRegisterAllowed(0xF78);
|
||||
SetRegisterAllowed(0xF7C);
|
||||
SetRegisterAllowed(0xF80);
|
||||
SetRegisterAllowed(0xF84);
|
||||
SetRegisterAllowed(0xF88);
|
||||
SetRegisterAllowed(0xF8C);
|
||||
SetRegisterAllowed(0xF90);
|
||||
SetRegisterAllowed(0xF94);
|
||||
SetRegisterAllowed(0xF98);
|
||||
SetRegisterAllowed(0xF9C);
|
||||
SetRegisterAllowed(0xFA0);
|
||||
SetRegisterAllowed(0xFA4);
|
||||
SetRegisterAllowed(0xFA8);
|
||||
SetRegisterAllowed(0xFAC);
|
||||
SetRegisterAllowed(0xFB0);
|
||||
SetRegisterAllowed(0xFB4);
|
||||
SetRegisterAllowed(0xFB8);
|
||||
SetRegisterAllowed(0xFBC);
|
||||
SetRegisterAllowed(0xFC0);
|
||||
SetRegisterAllowed(0xFC4);
|
||||
SetRegisterAllowed(0xFC8);
|
||||
SetRegisterAllowed(0xFCC);
|
||||
SetRegisterAllowed(0xFD0);
|
||||
SetRegisterAllowed(0xFD4);
|
||||
SetRegisterAllowed(0xFD8);
|
||||
SetRegisterAllowed(0xFDC);
|
||||
SetRegisterAllowed(0xFE0);
|
||||
SetRegisterAllowed(0xFE4);
|
||||
SetRegisterAllowed(0xFE8);
|
||||
SetRegisterAllowed(0xFEC);
|
||||
SetRegisterAllowed(0xFF0);
|
||||
SetRegisterAllowed(0xFF4);
|
||||
SetRegisterAllowed(0xFF8);
|
||||
SetRegisterAllowed(0xFFC);
|
||||
|
||||
@@ -123,39 +123,41 @@ namespace ams::secmon {
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalIramBootCode = MemoryRegion(UINT64_C(0x40020000), 0x20000);
|
||||
static_assert(MemoryRegionPhysicalIram.Contains(MemoryRegionPhysicalIramBootCode));
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionVirtualDevice = MemoryRegion(UINT64_C(0x1F0040000), UINT64_C(0x40000));
|
||||
constexpr inline const MemoryRegion MemoryRegionVirtualDevice = MemoryRegion(UINT64_C(0x1F0040000), UINT64_C(0x40000 + 0x2000));
|
||||
static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualDevice));
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionVirtualDeviceEmpty = MemoryRegion(MemoryRegionVirtualDevice.GetStartAddress(), 0);
|
||||
|
||||
#define AMS_SECMON_FOREACH_DEVICE_REGION(HANDLER, ...) \
|
||||
HANDLER(GicDistributor, Empty, UINT64_C(0x50041000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(GicCpuInterface, GicDistributor, UINT64_C(0x50042000), UINT64_C(0x2000), true, ## __VA_ARGS__) \
|
||||
HANDLER(Uart, GicCpuInterface, UINT64_C(0x70006000), UINT64_C(0x1000), false, ## __VA_ARGS__) \
|
||||
HANDLER(ClkRst, Uart, UINT64_C(0x60006000), UINT64_C(0x1000), false, ## __VA_ARGS__) \
|
||||
HANDLER(RtcPmc, ClkRst, UINT64_C(0x7000E000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(Timer, RtcPmc, UINT64_C(0x60005000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(System, Timer, UINT64_C(0x6000C000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(SecurityEngine, System, UINT64_C(0x70012000), UINT64_C(0x2000), true, ## __VA_ARGS__) \
|
||||
HANDLER(SecurityEngine2, SecurityEngine, UINT64_C(0x70412000), UINT64_C(0x2000), true, ## __VA_ARGS__) \
|
||||
HANDLER(SysCtr0, SecurityEngine2, UINT64_C(0x700F0000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(MemoryController, SysCtr0, UINT64_C(0x70019000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(ExternalMemoryController, MemoryController, UINT64_C(0x7001b000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(FuseKFuse, ExternalMemoryController, UINT64_C(0x7000F000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(ApbMisc, FuseKFuse, UINT64_C(0x70000000), UINT64_C(0x4000), true, ## __VA_ARGS__) \
|
||||
HANDLER(FlowController, ApbMisc, UINT64_C(0x60007000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(BootloaderParams, FlowController, UINT64_C(0x40000000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(I2c5, BootloaderParams, UINT64_C(0x7000D000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(Gpio, I2c5, UINT64_C(0x6000D000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(I2c1, Gpio, UINT64_C(0x7000C000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(ExceptionVectors, I2c1, UINT64_C(0x6000F000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(MemoryController0, ExceptionVectors, UINT64_C(0x7001C000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(MemoryController1, MemoryController0, UINT64_C(0x7001D000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(Sdmmc, MemoryController1, UINT64_C(0x700B0000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(Disp1, Sdmmc, UINT64_C(0x54200000), UINT64_C(0x3000), true, ## __VA_ARGS__) \
|
||||
HANDLER(Dsi, Disp1, UINT64_C(0x54300000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(MipiCal, Dsi, UINT64_C(0x700E3000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(Soctherm, MipiCal, UINT64_C(0x700E2000), UINT64_C(0x1000), true, ## __VA_ARGS__)
|
||||
HANDLER(GicDistributor, Empty, UINT64_C(0x50041000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(GicCpuInterface, GicDistributor, UINT64_C(0x50042000), UINT64_C(0x2000), true, ## __VA_ARGS__) \
|
||||
HANDLER(Uart, GicCpuInterface, UINT64_C(0x70006000), UINT64_C(0x1000), false, ## __VA_ARGS__) \
|
||||
HANDLER(ClkRst, Uart, UINT64_C(0x60006000), UINT64_C(0x1000), false, ## __VA_ARGS__) \
|
||||
HANDLER(RtcPmc, ClkRst, UINT64_C(0x7000E000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(Timer, RtcPmc, UINT64_C(0x60005000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(System, Timer, UINT64_C(0x6000C000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(SecurityEngine, System, UINT64_C(0x70012000), UINT64_C(0x2000), true, ## __VA_ARGS__) \
|
||||
HANDLER(SecurityEngine2, SecurityEngine, UINT64_C(0x70412000), UINT64_C(0x2000), true, ## __VA_ARGS__) \
|
||||
HANDLER(SysCtr0, SecurityEngine2, UINT64_C(0x700F0000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(MemoryController, SysCtr0, UINT64_C(0x70019000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(ExternalMemoryController, MemoryController, UINT64_C(0x7001b000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(FuseKFuse, ExternalMemoryController, UINT64_C(0x7000F000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(ApbMisc, FuseKFuse, UINT64_C(0x70000000), UINT64_C(0x4000), true, ## __VA_ARGS__) \
|
||||
HANDLER(FlowController, ApbMisc, UINT64_C(0x60007000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(BootloaderParams, FlowController, UINT64_C(0x40000000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(I2c5, BootloaderParams, UINT64_C(0x7000D000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(Gpio, I2c5, UINT64_C(0x6000D000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(I2c1, Gpio, UINT64_C(0x7000C000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(ExceptionVectors, I2c1, UINT64_C(0x6000F000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(MemoryController0, ExceptionVectors, UINT64_C(0x7001C000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(MemoryController1, MemoryController0, UINT64_C(0x7001D000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(Sdmmc, MemoryController1, UINT64_C(0x700B0000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(Disp1, Sdmmc, UINT64_C(0x54200000), UINT64_C(0x3000), true, ## __VA_ARGS__) \
|
||||
HANDLER(Dsi, Disp1, UINT64_C(0x54300000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(MipiCal, Dsi, UINT64_C(0x700E3000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(Soctherm, MipiCal, UINT64_C(0x700E2000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(ExternalMemoryController1, Soctherm, UINT64_C(0x7001e000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(ExternalMemoryController2, ExternalMemoryController1, UINT64_C(0x7001f000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
|
||||
#define DEFINE_DEVICE_REGION(_NAME_, _PREV_, _ADDRESS_, _SIZE_, _SECURE_) \
|
||||
constexpr inline const MemoryRegion MemoryRegionVirtualDevice##_NAME_ = MemoryRegion(MemoryRegionVirtualDevice##_PREV_.GetEndAddress() + 0x1000, _SIZE_); \
|
||||
|
||||
@@ -99,6 +99,8 @@ namespace ams::secmon::smc {
|
||||
#include "secmon_define_pmc_access_table.inc"
|
||||
#include "secmon_define_mc_access_table.inc"
|
||||
#include "secmon_define_emc_access_table.inc"
|
||||
#include "secmon_define_emc1_access_table.inc"
|
||||
#include "secmon_define_emc2_access_table.inc"
|
||||
#include "secmon_define_soctherm_access_table.inc"
|
||||
#include "secmon_define_mc01_access_table.inc"
|
||||
|
||||
@@ -106,6 +108,8 @@ namespace ams::secmon::smc {
|
||||
{ PmcAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDevicePmc.GetAddress(), PmcAccessTable::Address, PmcAccessTable::Size, },
|
||||
{ McAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceMemoryController.GetAddress(), McAccessTable::Address, McAccessTable::Size, },
|
||||
{ EmcAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceExternalMemoryController.GetAddress(), EmcAccessTable::Address, EmcAccessTable::Size, },
|
||||
{ EmcAccessTable1::ReducedAccessTable.data(), MemoryRegionVirtualDeviceExternalMemoryController1.GetAddress(), EmcAccessTable1::Address, EmcAccessTable1::Size, },
|
||||
{ EmcAccessTable2::ReducedAccessTable.data(), MemoryRegionVirtualDeviceExternalMemoryController2.GetAddress(), EmcAccessTable2::Address, EmcAccessTable2::Size, },
|
||||
{ SocthermAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceSoctherm.GetAddress(), SocthermAccessTable::Address, SocthermAccessTable::Size, },
|
||||
{ Mc01AccessTable::ReducedAccessTable.data(), Mc01AccessTable::Address + MemoryRegionVirtualDeviceMemoryController0.GetAddress(), Mc01AccessTable::Address + MemoryRegionPhysicalDeviceMemoryController0.GetAddress(), Mc01AccessTable::Size, },
|
||||
{ Mc01AccessTable::ReducedAccessTable.data(), Mc01AccessTable::Address + MemoryRegionVirtualDeviceMemoryController1.GetAddress(), Mc01AccessTable::Address + MemoryRegionPhysicalDeviceMemoryController1.GetAddress(), Mc01AccessTable::Size, },
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#define DISABLED 0
|
||||
#define DEACTIVATED_GPU_FREQ 2000
|
||||
#define GPU_MIN_MIN_VOLT 480000
|
||||
#define CPU_MAX_MAX_VOLT 1235000
|
||||
#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,
|
||||
@@ -222,10 +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, } },
|
||||
{ 2091000, { 1256250, }, { 5100873, -279186, 4747, } },
|
||||
{ 2193000, { 1256250, }, { 5100873, -279186, 4747, } },
|
||||
{ 1963500, { 1227500, }, { 5100873, -279186, 4747, } },
|
||||
{ 2091000, { 1227500, }, { 5100873, -279186, 4747, } },
|
||||
{ 2193000, { 1227500, }, { 5100873, -279186, 4747, } },
|
||||
{ 2295000, { 1256250, }, { 5100873, -279186, 4747, } },
|
||||
{ 2397000, { 1256250, }, { 5100873, -279186, 4747, } }, // Only for god speedo!
|
||||
},
|
||||
|
||||
.marikoCpuDvfsTable = {
|
||||
|
||||
@@ -20,9 +20,9 @@
|
||||
namespace ams::ldr::hoc::pcv::erista {
|
||||
|
||||
void CalculateTimings(double tCK_avg) {
|
||||
tR2W = FLOOR(FLOOR((5.0 / tCK_avg) + ((FLOOR(48.0 / WL) - 0.478) * 3.0)) / 1.501) + RL_DBI - (C.t6_tRTW * 3) + finetRTW;
|
||||
tWTPDEN = CEIL(((1.803 / tCK_avg) + MAX(RL_DBI + (2.694 / tCK_avg), static_cast<double>(tW2P))) + (BL / 2));
|
||||
tW2R = FLOOR(MAX((5.020 / tCK_avg) + 1.130, WL - MAX(-CEIL(0.258 * (WL - RL_DBI)), 1.964)) * 1.964) + WL - CEIL(tWTR / tCK_avg) + finetWTR;
|
||||
tR2W = FLOOR(FLOOR((5.0 / tCK_avg) + ((FLOOR(48.0 / WL) - 0.478) * 3.0)) / 1.501) + RL - (C.t6_tRTW * 3) + finetRTW;
|
||||
tWTPDEN = CEIL(((1.803 / tCK_avg) + MAX(RL + (2.694 / tCK_avg), static_cast<double>(tW2P))) + (BL / 2));
|
||||
tW2R = FLOOR(MAX((5.020 / tCK_avg) + 1.130, WL - MAX(-CEIL(0.258 * (WL - RL)), 1.964)) * 1.964) + WL - CEIL(tWTR / tCK_avg) + finetWTR;
|
||||
|
||||
pdex2rw = CEIL((CEIL(12.335 - tCK_avg) + (7.430 / tCK_avg) - CEIL(tCK_avg * 11.361)));
|
||||
tCLKSTOP = FLOOR(MIN(8.488 / tCK_avg, 23.0)) + 8.0;
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
u32 wlIndex = 0;
|
||||
|
||||
for (u32 i = 0; i < std::size(rlMapDBI); ++i) {
|
||||
if (rlMapDBI[i] == RL_DBI) {
|
||||
if (rlMapDBI[i] == RL) {
|
||||
rlIndex = i;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -30,18 +30,13 @@ namespace ams::ldr::hoc {
|
||||
#define PACK_U32(high, low) ((static_cast<u32>(high) << 16) | (static_cast<u32>(low) & 0xFFFF))
|
||||
#define PACK_U32_NIBBLE_HIGH_BYTE_LOW(high, low) ((static_cast<u32>(high & 0xF) << 28) | (static_cast<u32>(low) & 0xFF))
|
||||
|
||||
|
||||
|
||||
/* Burst latency, not to be confused with base latency (tWRL). */
|
||||
const u32 BL = 16;
|
||||
|
||||
/* Base latency for read and write (tWRL). */
|
||||
const u32 RL = C.mem_burst_read_latency - 4; /* (This is a lazy fix for now) */
|
||||
const u32 RL = C.mem_burst_read_latency;
|
||||
const u32 WL = C.mem_burst_write_latency;
|
||||
|
||||
/* Switch uses RL_DBI, todo: get rid of non DBI_RL. */
|
||||
const u32 RL_DBI = RL + 4;
|
||||
|
||||
/* Precharge to Precharge Delay. (tCK) */
|
||||
const u32 tPPD = 4;
|
||||
|
||||
@@ -73,7 +68,7 @@ namespace ams::ldr::hoc {
|
||||
const std::array<u32, 8> tRP_values = { 18, 17, 16, 15, 14, 13, 12, 11 };
|
||||
const std::array<u32, 10> tRAS_values = { 42, 36, 34, 32, 30, 28, 26, 24, 22, 20 };
|
||||
const std::array<double, 8> tRRD_values = { 10.0, 7.5, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0 };
|
||||
const std::array<u32, 11> tRFC_values = { 140, 130, 120, 110, 100, 90, 80, 70, 60, 50, 40 };
|
||||
const std::array<u32, 6> tRFC_values = { 90, 80, 70, 60, 50, 40 };
|
||||
const std::array<u32, 10> tWTR_values = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
|
||||
const std::array<u32, 6> tREFpb_values = { 3900, 5850, 7800, 11700, 15600, 99999 };
|
||||
|
||||
@@ -92,7 +87,7 @@ namespace ams::ldr::hoc {
|
||||
const u32 tFAW = static_cast<u32>(tRRD * 4.0);
|
||||
const double tRPab = tRPpb + 3;
|
||||
|
||||
const u32 tR2P = CEIL((RL_DBI * 0.426) - 2.0);
|
||||
const u32 tR2P = CEIL((RL * 0.426) - 2.0);
|
||||
inline u32 tR2W;
|
||||
inline u32 rext;
|
||||
|
||||
@@ -133,16 +128,16 @@ namespace ams::ldr::hoc {
|
||||
const u32 tFAW = static_cast<u32>(tRRD * 4.0);
|
||||
const double tRPab = tRPpb + 3;
|
||||
|
||||
const u32 tR2P = CEIL((RL_DBI * 0.426) - 2.0);
|
||||
const u32 tR2W = FLOOR(FLOOR((5.0 / tCK_avg) + ((FLOOR(48.0 / WL) - 0.478) * 3.0)) / 1.501) + RL_DBI - (C.t6_tRTW * 3) + finetRTW;
|
||||
const u32 tRTM = FLOOR((10.0 + RL_DBI) + (3.502 / tCK_avg)) + FLOOR(7.489 / tCK_avg);
|
||||
const u32 tRATM = CEIL((tRTM - 10.0) + (RL_DBI * 0.426));
|
||||
const u32 tR2P = CEIL((RL * 0.426) - 2.0);
|
||||
const u32 tR2W = FLOOR(FLOOR((5.0 / tCK_avg) + ((FLOOR(48.0 / WL) - 0.478) * 3.0)) / 1.501) + RL - (C.t6_tRTW * 3) + finetRTW;
|
||||
const u32 tRTM = FLOOR((10.0 + RL) + (3.502 / tCK_avg)) + FLOOR(7.489 / tCK_avg);
|
||||
const u32 tRATM = CEIL((tRTM - 10.0) + (RL * 0.426));
|
||||
inline u32 rext;
|
||||
|
||||
const u32 rdv = RL_DBI + FLOOR((5.105 / tCK_avg) + 17.017);
|
||||
const u32 rdv = RL + FLOOR((5.105 / tCK_avg) + 17.017);
|
||||
const u32 qpop = rdv - 14;
|
||||
const u32 quse_width = CEIL(((4.897 / tCK_avg) - FLOOR(2.538 / tCK_avg)) + 3.782);
|
||||
const u32 quse = FLOOR(RL_DBI + ((5.082 / tCK_avg) + FLOOR(2.560 / tCK_avg))) - CEIL(4.820 / tCK_avg);
|
||||
const u32 quse = FLOOR(RL + ((5.082 / tCK_avg) + FLOOR(2.560 / tCK_avg))) - CEIL(4.820 / tCK_avg);
|
||||
const u32 einput_duration = FLOOR(9.936 / tCK_avg) + 5.0 + quse_width;
|
||||
const u32 einput = quse - CEIL(9.928 / tCK_avg);
|
||||
const u32 qrst_duration = FLOOR(8.399 - tCK_avg);
|
||||
@@ -151,8 +146,8 @@ namespace ams::ldr::hoc {
|
||||
const u32 ibdly = PACK_U32_NIBBLE_HIGH_BYTE_LOW(1, quse - qrst_duration - 2.0);
|
||||
const u32 qsafe = (einput_duration + 3) + MAX(MIN(qrstLow * rdv, qrst_duration + qrst_duration), einput);
|
||||
const u32 tW2P = (CEIL(WL * 1.7303) * 2) - 5;
|
||||
const u32 tWTPDEN = CEIL(((1.803 / tCK_avg) + MAX(RL_DBI + (2.694 / tCK_avg), static_cast<double>(tW2P))) + (BL / 2));
|
||||
const u32 tW2R = FLOOR(MAX((5.020 / tCK_avg) + 1.130, WL - MAX(-CEIL(0.258 * (WL - RL_DBI)), 1.964)) * 1.964) + WL - CEIL(tWTR / tCK_avg) + finetWTR;
|
||||
const u32 tWTPDEN = CEIL(((1.803 / tCK_avg) + MAX(RL + (2.694 / tCK_avg), static_cast<double>(tW2P))) + (BL / 2));
|
||||
const u32 tW2R = FLOOR(MAX((5.020 / tCK_avg) + 1.130, WL - MAX(-CEIL(0.258 * (WL - RL)), 1.964)) * 1.964) + WL - CEIL(tWTR / tCK_avg) + finetWTR;
|
||||
const u32 tWTM = CEIL(WL + ((7.570 / tCK_avg) + 8.753));
|
||||
const u32 tWATM = (tWTM + (FLOOR(WL / 0.816) * 2.0)) - 4.0;
|
||||
|
||||
@@ -176,3 +171,4 @@ namespace ams::ldr::hoc {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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, 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, 1257 },
|
||||
{ GET_MAX_OF_ARR(erista::maxClocks), 1600'000, 2600'000 },
|
||||
{ C.marikoCpuMaxVolt, 1000, 1235 },
|
||||
{ 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");
|
||||
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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -178,7 +178,7 @@ namespace ams::ldr::hoc::pcv {
|
||||
}
|
||||
|
||||
namespace erista {
|
||||
const u32 maxClocks[] = { C.eristaEmcMaxClock2, C.eristaEmcMaxClock1, C.eristaEmcMaxClock, };
|
||||
static u32 maxEmcClocks[] = { C.eristaEmcMaxClock2, C.eristaEmcMaxClock1, C.eristaEmcMaxClock, };
|
||||
#define GET_MAX_OF_ARR(ARR) (*std::max_element(ARR, ARR + std::size(ARR)))
|
||||
|
||||
constexpr cvb_entry_t CpuCvbTableDefault[] = {
|
||||
@@ -202,12 +202,11 @@ namespace ams::ldr::hoc::pcv {
|
||||
{ },
|
||||
};
|
||||
|
||||
|
||||
constexpr u32 CpuVoltOfficial = 1235;
|
||||
constexpr u32 CpuVoltOfficial = 1227;
|
||||
|
||||
constexpr u32 CpuVminOfficial = 825;
|
||||
|
||||
constexpr u32 CpuVoltL4T = 1235'000;
|
||||
constexpr u32 CpuVoltL4T = 1257'000;
|
||||
|
||||
static const u32 cpuVoltDvfsPattern[] = { 1227, 1000, 100, 1000, 0 };
|
||||
static const u32 cpuVoltDvfsOffsets[] = { 5, 6, 7, 8, 9 };
|
||||
@@ -215,17 +214,23 @@ namespace ams::ldr::hoc::pcv {
|
||||
|
||||
static const u32 cpuVoltageThermalPattern[] = { 950, 1132, 0, 950, 1227, 0, 825, 1227, 15000, 825, 1170, 60000, 825, 1132, 80000 };
|
||||
static_assert(sizeof(cpuVoltageThermalPattern) == 0x3c, "invalid cpuVoltageThermalPattern size");
|
||||
|
||||
constexpr u32 GpuClkPllLimit = 921'600'000;
|
||||
constexpr u32 GpuClkPllLimit = 2'600'000;
|
||||
constexpr u32 GpuClkPllMax = 921'600'000;
|
||||
constexpr u32 GpuVminOfficial = 810;
|
||||
|
||||
constexpr u16 CpuMinVolts[] = { 950, 850, 825, 810 };
|
||||
|
||||
inline bool CpuMaxVoltPatternFn(u32* ptr32) {
|
||||
u32 val = *ptr32;
|
||||
return (val == 1132 || val == 1170 || val == 1227);
|
||||
}
|
||||
|
||||
static const u32 gpuVoltDvfsPattern[] = { 810, 1150, 1000, 100, 1000, 10, };
|
||||
static_assert(sizeof(gpuVoltDvfsPattern) == (sizeof(u32) * 6), "Invalid gpuVoltDvfsPattern");
|
||||
|
||||
static const u32 gpuVoltThermalPattern[] = { 950, 1132, 0, 810, 1132, 15000, 810, 1132, 30000, 810, 1132, 50000, 810, 1132, 70000, 810, 1132, 105000 };
|
||||
static_assert(sizeof(gpuVoltThermalPattern) == 0x48, "invalid gpuVoltageThermalPattern size");
|
||||
|
||||
|
||||
/* GPU Max Clock asm Pattern:
|
||||
*
|
||||
* MOV W11, #0x1000 MOV (wide immediate) 0x1000 0xB (11)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
@@ -167,20 +183,6 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result GpuFreqPllLimit(u32 *ptr) {
|
||||
clk_pll_param *entry = reinterpret_cast<clk_pll_param *>(ptr);
|
||||
|
||||
// All zero except for freq
|
||||
for (size_t i = 1; i < sizeof(clk_pll_param) / sizeof(u32); i++) {
|
||||
R_UNLESS(*(ptr + i) == 0, ldr::ResultInvalidGpuPllEntry());
|
||||
}
|
||||
|
||||
// Double the max clk simply
|
||||
u32 max_clk = entry->freq * 2;
|
||||
entry->freq = max_clk;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
/* Note: This does not have proper timings, so base latency adjustment will not work. */
|
||||
/* However, it may still achieve a slightly higher frequency, but not as much as it could be. */
|
||||
/* I'm certainly not insane enough to attempt this pain again, so this will have to do *for now*. */
|
||||
@@ -285,7 +287,7 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
// WRITE_PARAM_ALL_REG(table, emc_tr_rdv, rdv);
|
||||
// ams::ldr::hoc::pcv::mariko::CalculateMrw2();
|
||||
// table->emc_mrw2 = (table->emc_mrw2 & ~0xFFu) | static_cast<u32>(mrw2);
|
||||
// table->dram_timings.rl = RL_DBI;
|
||||
// table->dram_timings.rl = RL;
|
||||
|
||||
/* This needs some clean up. */
|
||||
constexpr double MC_ARB_DIV = 4.0;
|
||||
@@ -324,13 +326,13 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
|
||||
table->burst_mc_regs.mc_emem_arb_misc0 = (table->burst_mc_regs.mc_emem_arb_misc0 & 0xFFE08000) | (table->burst_mc_regs.mc_emem_arb_timing_rc + 1);
|
||||
|
||||
u32 mpcorer_ptsa_rate = MAX(static_cast<u32>(227), (table->rate_khz / 1600000) * 208);
|
||||
u32 mpcorer_ptsa_rate = MIN(static_cast<u32>(227), (table->rate_khz / 1600000) * 208);
|
||||
table->la_scale_regs.mc_mll_mpcorer_ptsa_rate = mpcorer_ptsa_rate;
|
||||
|
||||
u32 ftop_ptsa_rate = MAX(static_cast<u32>(31), (table->rate_khz / 1600000) * 24);
|
||||
u32 ftop_ptsa_rate = MIN(static_cast<u32>(31), (table->rate_khz / 1600000) * 24);
|
||||
table->la_scale_regs.mc_ftop_ptsa_rate = ftop_ptsa_rate;
|
||||
|
||||
u32 grant_decrement = MAX(static_cast<u32>(6143), (table->rate_khz / 1600000) * 4611);
|
||||
u32 grant_decrement = MIN(static_cast<u32>(6143), (table->rate_khz / 1600000) * 4611);
|
||||
table->la_scale_regs.mc_ptsa_grant_decrement = grant_decrement;
|
||||
|
||||
constexpr u32 MaskHigh = 0xFF00FFFF;
|
||||
@@ -370,7 +372,12 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
}
|
||||
|
||||
Result MemFreqMtcTable(u32 *ptr) {
|
||||
if (GET_MAX_OF_ARR(maxEmcClocks) <= EmcClkOSLimit) {
|
||||
R_SKIP();
|
||||
}
|
||||
|
||||
u32 khz_list[] = {1600000, 1331200, 1065600, 800000, 665600, 408000, 204000, 102000, 68000, 40800};
|
||||
std::sort(maxEmcClocks, maxEmcClocks + std::size(maxEmcClocks), std::greater<>());
|
||||
u32 khz_list_size = sizeof(khz_list) / sizeof(u32);
|
||||
|
||||
// Generate list for mtc table pointers
|
||||
@@ -382,47 +389,80 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
R_UNLESS(table_list[i]->rev == MTC_TABLE_REV, ldr::ResultInvalidMtcTable());
|
||||
}
|
||||
|
||||
if (GET_MAX_OF_ARR(maxClocks) <= EmcClkOSLimit) {
|
||||
R_SKIP();
|
||||
u32 additionalFreqs = 0;
|
||||
for (u32 i = 0; i < std::size(maxEmcClocks); ++i) {
|
||||
if (maxEmcClocks[i] > EmcClkOSLimit) {
|
||||
++additionalFreqs;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Make room for new mtc table, discarding useless 40.8, 68000 and 102000 MHz table
|
||||
// 40800 overwritten by 68000, ..., 1331200 overwritten by 1600000, leaving table_list[0], table_list[1] and table_list[2] not overwritten
|
||||
for (u32 i = khz_list_size - 1; i > 2; --i) {
|
||||
std::memcpy(static_cast<void *>(table_list[i]), static_cast<void *>(table_list[i - 3]), sizeof(EristaMtcTable));
|
||||
// 40800 overwritten by 204000, ..., 1331200 overwritten by 1600000, leaving table_list[0], table_list[1] and table_list[2] not overwritten
|
||||
for (u32 i = khz_list_size - 1; i > additionalFreqs - 1; --i) {
|
||||
std::memcpy(static_cast<void *>(table_list[i]), static_cast<void *>(table_list[i - additionalFreqs]), sizeof(EristaMtcTable));
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < std::size(maxClocks); ++i) {
|
||||
if (maxClocks[i] > EmcClkOSLimit) {
|
||||
table_list[i]->rate_khz = maxClocks[i];
|
||||
MemMtcTableAutoAdjust(table_list[i]);
|
||||
}
|
||||
for (u32 i = 0; i < additionalFreqs; ++i) {
|
||||
/* Since we're not scaling latency timings properly, copy over the 1600Mhz table to get the closest timings. */
|
||||
std::memcpy(table_list[i], table_list[additionalFreqs], sizeof(EristaMtcTable));
|
||||
table_list[i]->rate_khz = maxEmcClocks[i];
|
||||
MemMtcTableAutoAdjust(table_list[i]);
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result MemFreqMax(u32 *ptr) {
|
||||
if (GET_MAX_OF_ARR(maxClocks) <= EmcClkOSLimit) {
|
||||
if (GET_MAX_OF_ARR(maxEmcClocks) <= EmcClkOSLimit) {
|
||||
R_SKIP();
|
||||
}
|
||||
|
||||
PATCH_OFFSET(ptr, GET_MAX_OF_ARR(maxClocks));
|
||||
PATCH_OFFSET(ptr, GET_MAX_OF_ARR(maxEmcClocks));
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result GpuFreqPllMax(u32 *ptr) {
|
||||
clk_pll_param *entry = reinterpret_cast<clk_pll_param *>(ptr);
|
||||
|
||||
// All zero except for freq
|
||||
for (size_t i = 1; i < sizeof(clk_pll_param) / sizeof(u32); i++) {
|
||||
R_UNLESS(*(ptr + i) == 0, ldr::ResultInvalidGpuPllEntry());
|
||||
}
|
||||
|
||||
// Double the max clk simply
|
||||
u32 max_clk = entry->freq * 2;
|
||||
entry->freq = max_clk;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
// 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());
|
||||
// }
|
||||
|
||||
// PATCH_OFFSET(ptr, 3600000);
|
||||
|
||||
// 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 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 Freq PLL", &GpuFreqPllLimit, 1, nullptr, GpuClkPllLimit},
|
||||
{"GPU PLL Max", &GpuFreqPllMax, 1, nullptr, GpuClkPllMax},
|
||||
// {"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},
|
||||
@@ -445,4 +485,5 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -266,7 +266,6 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
switch (C.marikoCpuUVHigh) {
|
||||
case 1:
|
||||
PATCH_OFFSET(&(entry->tune1_high), 0);
|
||||
@@ -569,20 +568,12 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
|
||||
table->dram_timings.t_rp = tRFCpb;
|
||||
table->dram_timings.t_rfc = tRFCab;
|
||||
table->dram_timings.rl = RL_DBI;
|
||||
table->dram_timings.rl = RL;
|
||||
|
||||
table->emc_mrw2 = (table->emc_mrw2 & ~0xFFu) | static_cast<u32>(mrw2);
|
||||
table->emc_cfg_2 = 0x11083D;
|
||||
}
|
||||
|
||||
// WRITE_PARAM_ALL_REG(table, emc_pdex2wr, GET_CYCLE(10.0));
|
||||
// WRITE_PARAM_ALL_REG(table, emc_pdex2rd, GET_CYCLE(10.0));
|
||||
// WRITE_PARAM_ALL_REG(table, emc_pchg2pden, GET_CYCLE(1.75));
|
||||
// WRITE_PARAM_ALL_REG(table, emc_ar2pden, GET_CYCLE(1.75));
|
||||
// WRITE_PARAM_ALL_REG(table, emc_pdex2cke, GET_CYCLE(1.75));
|
||||
// WRITE_PARAM_ALL_REG(table, emc_act2pden, GET_CYCLE(14.0));
|
||||
// WRITE_PARAM_ALL_REG(table, emc_cke2pden, GET_CYCLE(5.0));
|
||||
|
||||
void MemMtcPllmbDivisor(MarikoMtcTable *table) {
|
||||
constexpr u32 PllOscInKHz = 38400;
|
||||
constexpr u32 PllOscHalfKHz = 19200;
|
||||
@@ -661,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);
|
||||
@@ -692,6 +682,7 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
|
||||
#define DVB_VOLT(zero, one, two) std::min(zero + voltAdd, 1050), std::min(one + voltAdd, 1025), std::min(two + voltAdd, 1000),
|
||||
|
||||
/* TODO: More fine tuned values? */
|
||||
if (C.marikoEmcMaxClock < 1862400) {
|
||||
std::memcpy(new_start, default_end, sizeof(emc_dvb_dvfs_table_t));
|
||||
} else if (C.marikoEmcMaxClock < 2131200) {
|
||||
|
||||
@@ -20,116 +20,111 @@
|
||||
|
||||
namespace ams::ldr::hoc::ptm {
|
||||
|
||||
Result CpuPtmBoost(perf_conf_entry* entry) {
|
||||
Result CpuPtmBoost(perf_conf_entry* entry) {
|
||||
#ifdef ATMOSPHERE_IS_STRATOSPHERE
|
||||
bool isMariko = (spl::GetSocType() == spl::SocType_Mariko);
|
||||
#else
|
||||
bool isMariko = true;
|
||||
#endif
|
||||
|
||||
#ifdef ATMOSPHERE_IS_STRATOSPHERE
|
||||
bool isMariko = (spl::GetSocType() == spl::SocType_Mariko);
|
||||
#else
|
||||
bool isMariko = true;
|
||||
#endif
|
||||
if (!C.eristaCpuBoostClock || !C.marikoCpuBoostClock) {
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
u32 cpuPtmBoostNew = isMariko ? C.marikoCpuBoostClock * 1000 : C.eristaCpuBoostClock * 1000;
|
||||
|
||||
PATCH_OFFSET(&(entry->cpu_freq_1), cpuPtmBoostNew);
|
||||
PATCH_OFFSET(&(entry->cpu_freq_2), cpuPtmBoostNew);
|
||||
|
||||
if (!C.eristaCpuBoostClock || !C.marikoCpuBoostClock)
|
||||
R_SUCCEED();
|
||||
|
||||
u32 cpuPtmBoostNew = isMariko ? C.marikoCpuBoostClock * 1000 : C.eristaCpuBoostClock * 1000;
|
||||
|
||||
PATCH_OFFSET(&(entry->cpu_freq_1), cpuPtmBoostNew);
|
||||
PATCH_OFFSET(&(entry->cpu_freq_2), cpuPtmBoostNew);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result MemPtm(perf_conf_entry* entry) {
|
||||
PATCH_OFFSET(&(entry->emc_freq_1), memPtmLimit);
|
||||
PATCH_OFFSET(&(entry->emc_freq_2), memPtmLimit);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
bool PtmEntryIsValid(perf_conf_entry* entry) {
|
||||
return (entry->cpu_freq_1 == entry->cpu_freq_2 &&
|
||||
entry->gpu_freq_1 == entry->gpu_freq_2 &&
|
||||
entry->emc_freq_1 == entry->emc_freq_2);
|
||||
}
|
||||
|
||||
bool PtmTablePatternFn(u32* ptr) {
|
||||
perf_conf_entry* entry = reinterpret_cast<perf_conf_entry *>(ptr);
|
||||
if (!PtmEntryIsValid(entry))
|
||||
return false;
|
||||
|
||||
return entry->cpu_freq_1 == cpuPtmDefault;
|
||||
}
|
||||
|
||||
void Patch(uintptr_t mapped_nso, size_t nso_size) {
|
||||
perf_conf_entry* confTable = nullptr;
|
||||
for (uintptr_t ptr = mapped_nso;
|
||||
ptr <= mapped_nso + nso_size - sizeof(perf_conf_entry) * entryCnt;
|
||||
ptr += sizeof(u32))
|
||||
{
|
||||
u32* ptr32 = reinterpret_cast<u32 *>(ptr);
|
||||
if (PtmTablePatternFn(ptr32)) {
|
||||
confTable = reinterpret_cast<perf_conf_entry *>(ptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!confTable) {
|
||||
CRASH("confTable not found!");
|
||||
Result MemPtm(perf_conf_entry* entry) {
|
||||
PATCH_OFFSET(&(entry->emc_freq_1), memPtmLimit);
|
||||
PATCH_OFFSET(&(entry->emc_freq_2), memPtmLimit);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
PatcherEntry<perf_conf_entry> cpuPtmBoostPatch = { "CPU Ptm Boost", &CpuPtmBoost, 2, };
|
||||
PatcherEntry<perf_conf_entry> memPtmPatch = { "MEM Ptm", &MemPtm, 16, };
|
||||
|
||||
#ifdef ATMOSPHERE_IS_STRATOSPHERE
|
||||
bool isMariko = (spl::GetSocType() == spl::SocType_Mariko);
|
||||
#else
|
||||
bool isMariko = true;
|
||||
#endif
|
||||
|
||||
|
||||
for (u32 i = 0; i < entryCnt; i++) {
|
||||
perf_conf_entry* entry = confTable + i;
|
||||
bool PtmEntryIsValid(perf_conf_entry* entry) {
|
||||
return (entry->cpu_freq_1 == entry->cpu_freq_2 && entry->gpu_freq_1 == entry->gpu_freq_2 && entry->emc_freq_1 == entry->emc_freq_2);
|
||||
}
|
||||
|
||||
bool PtmTablePatternFn(u32* ptr) {
|
||||
perf_conf_entry* entry = reinterpret_cast<perf_conf_entry *>(ptr);
|
||||
if (!PtmEntryIsValid(entry)) {
|
||||
LOGGING("@%p", &entry);
|
||||
CRASH("Invalid ptm confTable entry");
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (entry->cpu_freq_1) {
|
||||
case cpuPtmBoost:
|
||||
cpuPtmBoostPatch.Apply(entry);
|
||||
return entry->cpu_freq_1 == cpuPtmDefault;
|
||||
}
|
||||
|
||||
void Patch(uintptr_t mapped_nso, size_t nso_size) {
|
||||
perf_conf_entry* confTable = nullptr;
|
||||
for (uintptr_t ptr = mapped_nso; ptr <= mapped_nso + nso_size - sizeof(perf_conf_entry) * entryCnt; ptr += sizeof(u32)) {
|
||||
u32* ptr32 = reinterpret_cast<u32 *>(ptr);
|
||||
if (PtmTablePatternFn(ptr32)) {
|
||||
confTable = reinterpret_cast<perf_conf_entry *>(ptr);
|
||||
break;
|
||||
case cpuPtmDefault:
|
||||
case cpuPtmDevOC:
|
||||
break;
|
||||
default:
|
||||
LOGGING("%u (0x%08x) @%p", entry->cpu_freq_1, entry->conf_id, &(entry->cpu_freq_1));
|
||||
CRASH("Unknown CPU Freq");
|
||||
}
|
||||
}
|
||||
|
||||
switch (entry->emc_freq_1) {
|
||||
case memPtmLimit:
|
||||
case memPtmAlt:
|
||||
case memPtmClamp:
|
||||
if (isMariko) {
|
||||
memPtmPatch.Apply(entry);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOGGING("%u (0x%08x) @%p", entry->emc_freq_1, entry->conf_id, &(entry->emc_freq_2));
|
||||
CRASH("Unknown MEM Freq");
|
||||
if (!confTable) {
|
||||
CRASH("confTable not found!");
|
||||
}
|
||||
|
||||
PatcherEntry<perf_conf_entry> cpuPtmBoostPatch = { "CPU Ptm Boost", &CpuPtmBoost, 2, };
|
||||
PatcherEntry<perf_conf_entry> memPtmPatch = { "MEM Ptm", &MemPtm, 16, };
|
||||
|
||||
#ifdef ATMOSPHERE_IS_STRATOSPHERE
|
||||
bool isMariko = (spl::GetSocType() == spl::SocType_Mariko);
|
||||
#else
|
||||
bool isMariko = true;
|
||||
#endif
|
||||
|
||||
for (u32 i = 0; i < entryCnt; i++) {
|
||||
perf_conf_entry *entry = confTable + i;
|
||||
|
||||
if (!PtmEntryIsValid(entry)) {
|
||||
LOGGING("@%p", &entry);
|
||||
CRASH("Invalid ptm confTable entry");
|
||||
}
|
||||
|
||||
switch (entry->cpu_freq_1) {
|
||||
case cpuPtmBoost:
|
||||
cpuPtmBoostPatch.Apply(entry);
|
||||
break;
|
||||
case cpuPtmDefault:
|
||||
case cpuPtmDevOC:
|
||||
break;
|
||||
default:
|
||||
LOGGING("%u (0x%08x) @%p", entry->cpu_freq_1, entry->conf_id, &(entry->cpu_freq_1));
|
||||
CRASH("Unknown CPU Freq");
|
||||
}
|
||||
|
||||
switch (entry->emc_freq_1) {
|
||||
case memPtmLimit:
|
||||
case memPtmAlt:
|
||||
case memPtmClamp:
|
||||
if (isMariko) {
|
||||
memPtmPatch.Apply(entry);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOGGING("%u (0x%08x) @%p", entry->emc_freq_1, entry->conf_id, &(entry->emc_freq_2));
|
||||
CRASH("Unknown MEM Freq");
|
||||
}
|
||||
}
|
||||
|
||||
LOGGING("%s Count: %zu", cpuPtmBoostPatch.description, cpuPtmBoostPatch.patched_count);
|
||||
if (R_FAILED(cpuPtmBoostPatch.CheckResult()))
|
||||
CRASH(cpuPtmBoostPatch.description);
|
||||
|
||||
if (isMariko) {
|
||||
LOGGING("%s Count: %zu", memPtmPatch.description, memPtmPatch.patched_count);
|
||||
if (R_FAILED(memPtmPatch.CheckResult()))
|
||||
CRASH(memPtmPatch.description);
|
||||
}
|
||||
}
|
||||
|
||||
LOGGING("%s Count: %zu", cpuPtmBoostPatch.description, cpuPtmBoostPatch.patched_count);
|
||||
if (R_FAILED(cpuPtmBoostPatch.CheckResult()))
|
||||
CRASH(cpuPtmBoostPatch.description);
|
||||
|
||||
if (isMariko) {
|
||||
LOGGING("%s Count: %zu", memPtmPatch.description, memPtmPatch.patched_count);
|
||||
if (R_FAILED(memPtmPatch.CheckResult()))
|
||||
CRASH(memPtmPatch.description);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -22,26 +22,26 @@
|
||||
|
||||
namespace ams::ldr::hoc::ptm {
|
||||
|
||||
typedef struct {
|
||||
u32 conf_id;
|
||||
u32 cpu_freq_1; // min-max pair?
|
||||
u32 cpu_freq_2;
|
||||
u32 gpu_freq_1;
|
||||
u32 gpu_freq_2;
|
||||
u32 emc_freq_1;
|
||||
u32 emc_freq_2;
|
||||
u32 padding;
|
||||
} perf_conf_entry;
|
||||
typedef struct {
|
||||
u32 conf_id;
|
||||
u32 cpu_freq_1; // min-max pair?
|
||||
u32 cpu_freq_2;
|
||||
u32 gpu_freq_1;
|
||||
u32 gpu_freq_2;
|
||||
u32 emc_freq_1;
|
||||
u32 emc_freq_2;
|
||||
u32 padding;
|
||||
} perf_conf_entry;
|
||||
|
||||
constexpr u32 entryCnt = 16;
|
||||
constexpr u32 cpuPtmDefault = 1020'000'000;
|
||||
constexpr u32 cpuPtmDevOC = 1224'000'000;
|
||||
constexpr u32 cpuPtmBoost = 1785'000'000;
|
||||
constexpr u32 entryCnt = 16;
|
||||
constexpr u32 cpuPtmDefault = 1020'000'000;
|
||||
constexpr u32 cpuPtmDevOC = 1224'000'000;
|
||||
constexpr u32 cpuPtmBoost = 1785'000'000;
|
||||
|
||||
constexpr u32 memPtmLimit = 1600'000'000;
|
||||
constexpr u32 memPtmAlt = 1331'200'000;
|
||||
constexpr u32 memPtmClamp = 1065'600'000;
|
||||
constexpr u32 memPtmLimit = 1600'000'000;
|
||||
constexpr u32 memPtmAlt = 1331'200'000;
|
||||
constexpr u32 memPtmClamp = 1065'600'000;
|
||||
|
||||
void Patch(uintptr_t mapped_nso, size_t nso_size);
|
||||
void Patch(uintptr_t mapped_nso, size_t nso_size);
|
||||
|
||||
}
|
||||
|
||||
@@ -685,7 +685,7 @@ void Misc2(void*) {
|
||||
|
||||
void Misc3(void*) {
|
||||
const bool isUsingEOS = usingEOS();
|
||||
|
||||
|
||||
// Initialize voltage reading if needed
|
||||
bool canReadVoltages = false;
|
||||
if (!isUsingEOS && realVoltsPolling) {
|
||||
@@ -694,7 +694,7 @@ void Misc3(void*) {
|
||||
realVoltsPolling = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
do {
|
||||
mutexLock(&mutex_Misc);
|
||||
|
||||
@@ -706,7 +706,7 @@ void Misc3(void*) {
|
||||
if (R_SUCCEEDED(tcCheck)) {
|
||||
tcGetSkinTemperatureMilliC(&skin_temperaturemiliC);
|
||||
}
|
||||
|
||||
|
||||
// Fan
|
||||
if (R_SUCCEEDED(pwmCheck)) {
|
||||
double temp = 0;
|
||||
@@ -720,16 +720,21 @@ void Misc3(void*) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// GPU Load
|
||||
if (R_SUCCEEDED(nvCheck)) {
|
||||
nvIoctl(fd, NVGPU_GPU_IOCTL_PMU_GET_GPU_LOAD, &GPU_Load_u);
|
||||
}
|
||||
|
||||
|
||||
SysClkContext sysclkCTX;
|
||||
if (R_SUCCEEDED(sysclkIpcGetCurrentContext(&sysclkCTX))) {
|
||||
partLoad[SysClkPartLoad_EMC] = sysclkCTX.partLoad[SysClkPartLoad_EMC];
|
||||
}
|
||||
|
||||
mutexUnlock(&mutex_Misc);
|
||||
|
||||
|
||||
} while (!leventWait(&threadexit, 1'000'000'000)); // 1 second timeout
|
||||
|
||||
|
||||
// Cleanup voltage reading if initialized
|
||||
if (canReadVoltages) {
|
||||
rgltrExit();
|
||||
@@ -2453,4 +2458,4 @@ ALWAYS_INLINE void GetConfigSettings(ResolutionSettings* settings) {
|
||||
convertToUpper(key);
|
||||
settings->disableScreenshots = (key != "FALSE");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,12 +153,6 @@ Result sysclkIpcGetFreqList(SysClkModule module, u32* list, u32 maxCount, u32* o
|
||||
);
|
||||
}
|
||||
|
||||
Result sysclkIpcSetReverseNXRTMode(ReverseNXMode mode)
|
||||
{
|
||||
return serviceDispatchIn(&g_sysclkSrv, SysClkIpcCmd_SetReverseNXRTMode, mode);
|
||||
}
|
||||
|
||||
|
||||
Result hocClkIpcSetKipData()
|
||||
{
|
||||
u32 temp = 0;
|
||||
|
||||
54
Source/sys-clk/bpmp/Makefile
Normal file
54
Source/sys-clk/bpmp/Makefile
Normal 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"
|
||||
BIN
Source/sys-clk/bpmp/firmware.bin
Normal file
BIN
Source/sys-clk/bpmp/firmware.bin
Normal file
Binary file not shown.
BIN
Source/sys-clk/bpmp/firmware.elf
Normal file
BIN
Source/sys-clk/bpmp/firmware.elf
Normal file
Binary file not shown.
69
Source/sys-clk/bpmp/linker.ld
Normal file
69
Source/sys-clk/bpmp/linker.ld
Normal 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)
|
||||
}
|
||||
}
|
||||
184
Source/sys-clk/bpmp/src/main.c
Normal file
184
Source/sys-clk/bpmp/src/main.c
Normal 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;
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
@echo off
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
REM --- Root directory ---
|
||||
set ROOT_DIR=%~dp0
|
||||
set DIST_DIR=%ROOT_DIR%dist
|
||||
|
||||
REM --- Number of CPU cores ---
|
||||
set CORES=%NUMBER_OF_PROCESSORS%
|
||||
|
||||
REM --- Optional first argument as DIST_DIR ---
|
||||
if not "%~1"=="" set DIST_DIR=%~1
|
||||
|
||||
echo DIST_DIR: %DIST_DIR%
|
||||
echo CORES: %CORES%
|
||||
|
||||
REM ========================
|
||||
REM sysmodule
|
||||
REM ========================
|
||||
echo *** sysmodule ***
|
||||
|
||||
REM Extract TITLE_ID from perms.json using findstr (rough approximation)
|
||||
for /f "tokens=2 delims=: " %%A in ('findstr /i "title_id" "%ROOT_DIR%sysmodule\perms.json"') do (
|
||||
set TITLE_ID=%%A
|
||||
)
|
||||
|
||||
REM Remove quotes and 0x prefix
|
||||
set TITLE_ID=!TITLE_ID:"=!
|
||||
set TITLE_ID=!TITLE_ID:0x=!
|
||||
|
||||
REM Build sysmodule
|
||||
pushd "%ROOT_DIR%sysmodule"
|
||||
make -j %CORES%
|
||||
popd
|
||||
|
||||
REM Copy sysmodule files to dist
|
||||
if not exist "%DIST_DIR%\atmosphere\contents\%TITLE_ID%\flags" mkdir "%DIST_DIR%\atmosphere\contents\%TITLE_ID%\flags"
|
||||
copy /Y "%ROOT_DIR%sysmodule\out\horizon-oc.nsp" "%DIST_DIR%\atmosphere\contents\%TITLE_ID%\exefs.nsp"
|
||||
type nul > "%DIST_DIR%\atmosphere\contents\%TITLE_ID%\flags\boot2.flag"
|
||||
copy /Y "%ROOT_DIR%sysmodule\toolbox.json" "%DIST_DIR%\atmosphere\contents\%TITLE_ID%\toolbox.json"
|
||||
|
||||
REM ========================
|
||||
REM overlay
|
||||
REM ========================
|
||||
echo *** overlay ***
|
||||
pushd "%ROOT_DIR%overlay"
|
||||
make -j %CORES%
|
||||
popd
|
||||
|
||||
if not exist "%DIST_DIR%\switch\.overlays" mkdir "%DIST_DIR%\switch\.overlays"
|
||||
copy /Y "%ROOT_DIR%overlay\out\horizon-oc-overlay.ovl" "%DIST_DIR%\switch\.overlays\horizon-oc-overlay.ovl"
|
||||
|
||||
REM ========================
|
||||
REM assets
|
||||
REM ========================
|
||||
echo *** assets ***
|
||||
if not exist "%DIST_DIR%\config\horizon-oc" mkdir "%DIST_DIR%\config\horizon-oc"
|
||||
copy /Y "%ROOT_DIR%config.ini.template" "%DIST_DIR%\config\horizon-oc\config.ini.template"
|
||||
copy /Y "%ROOT_DIR%..\..\README.md" "%DIST_DIR%\README.md"
|
||||
|
||||
endlocal
|
||||
@@ -36,3 +36,7 @@ echo "*** assets ***"
|
||||
mkdir -p "$DIST_DIR/config/horizon-oc"
|
||||
cp -vf "$ROOT_DIR/config.ini.template" "$DIST_DIR/config/horizon-oc/config.ini.template"
|
||||
cp -vf "$ROOT_DIR/../../README.md" "$DIST_DIR/README.md"
|
||||
|
||||
echo "*** lang ***"
|
||||
|
||||
cp -r "$ROOT_DIR/overlay/lang/" "$DIST_DIR/config/horizon-oc/lang/"
|
||||
|
||||
@@ -124,8 +124,8 @@ typedef struct {
|
||||
bool displaySyncDocked;
|
||||
bool displaySyncDockedOutOfFocus60;
|
||||
} DisplayRefreshConfig;
|
||||
|
||||
bool DisplayRefresh_Initialize(const DisplayRefreshConfig* config);
|
||||
void DisplayRefresh_SetDockedState(bool isDocked);
|
||||
bool DisplayRefresh_SetRate(uint32_t new_refreshRate);
|
||||
bool DisplayRefresh_GetRate(uint32_t* out_refreshRate, bool internal);
|
||||
uint8_t DisplayRefresh_GetDockedHighestAllowed(void);
|
||||
|
||||
@@ -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.
|
||||
@@ -12,9 +14,8 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -310,6 +311,9 @@
|
||||
#define EMC_PMACRO_CMD_CTRL_1_0 0x784
|
||||
#define EMC_PMACRO_CMD_CTRL_2_0 0x788
|
||||
|
||||
#define MC_REGISTER_BASE 0x70019000
|
||||
#define MC_REGISTER_REGION_SIZE 0x1000
|
||||
|
||||
#define MC_INTSTATUS_0 0x000
|
||||
#define MC_INTMASK_0 0x004
|
||||
#define MC_ERR_STATUS_0 0x008
|
||||
@@ -489,4 +493,35 @@
|
||||
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_7 0xBEC
|
||||
#define MC_ERR_GENERALIZED_CARVEOUT_STATUS_0 0xC00
|
||||
#define MC_SECURITY_CARVEOUT2_BOM_0 0xC5C
|
||||
#define MC_SECURITY_CARVEOUT3_BOM_0 0xCAC
|
||||
#define MC_SECURITY_CARVEOUT3_BOM_0 0xCAC
|
||||
|
||||
#define CLDVFS_REGION_BASE 0x70110000
|
||||
#define CLDVFS_REGION_SIZE 0x1000
|
||||
#define CL_DVFS_CTRL_0 0x0
|
||||
#define CL_DVFS_CONFIG_0 0x4
|
||||
#define CL_DVFS_PARAMS_0 0x8
|
||||
#define CL_DVFS_TUNE0_0 0xC
|
||||
#define CL_DVFS_TUNE1_0 0x10
|
||||
#define CL_DVFS_FREQ_REQ_0 0x14
|
||||
#define CL_DVFS_SCALE_RAMP_0 0x18
|
||||
#define CL_DVFS_DROOP_CTRL_0 0x1C
|
||||
#define CL_DVFS_OUTPUT_CFG_0 0x20
|
||||
#define CL_DVFS_OUTPUT_FORCE_0 0x24
|
||||
#define CL_DVFS_MONITOR_CTRL_0 0x28
|
||||
#define CL_DVFS_MONITOR_DATA_0 0x2C
|
||||
#define CL_DVFS_I2C_CFG_0 0x40
|
||||
#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 DVFS_CC4_HVC_0 0x74
|
||||
#define CL_DVFS_MONITOR_DATA_0 0x2C
|
||||
#define CL_DVFS_I2C_CFG_0 0x40
|
||||
#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_I2C_CLK_DIVISOR_REGISTER_0 0x16C
|
||||
|
||||
@@ -34,3 +34,5 @@ void rgltrCloseSession(RgltrSession* session);
|
||||
Result rgltrGetVoltage(RgltrSession* session, u32 *out_volt);
|
||||
Result rgltrGetPowerModuleNumLimit(u32 *out);
|
||||
Result rgltrGetVoltageEnabled(RgltrSession* session, u32 *out);
|
||||
Result rgltrRequestVoltage(RgltrSession* session, u32 microvolt);
|
||||
Result rgltrCancelVoltageRequest(RgltrSession* session);
|
||||
@@ -108,16 +108,6 @@ typedef enum
|
||||
SysClkPartLoad_EnumMax
|
||||
} SysClkPartLoad;
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ReverseNX_NotFound = 0,
|
||||
ReverseNX_SystemDefault = 0,
|
||||
ReverseNX_Handheld,
|
||||
ReverseNX_Docked,
|
||||
} ReverseNXMode;
|
||||
|
||||
|
||||
typedef enum {
|
||||
HorizonOCSpeedo_CPU = 0,
|
||||
HorizonOCSpeedo_GPU,
|
||||
@@ -133,7 +123,7 @@ typedef enum {
|
||||
} GPUUndervoltLevel;
|
||||
|
||||
enum {
|
||||
DVFSMode_Disabled,
|
||||
DVFSMode_Disabled = 0,
|
||||
DVFSMode_Hijack,
|
||||
// DVFSMode_OfficialService,
|
||||
// DVFSMode_Hack,
|
||||
@@ -147,6 +137,27 @@ typedef enum {
|
||||
GpuSchedulingMode_EnumMax,
|
||||
} GpuSchedulingMode;
|
||||
|
||||
typedef enum {
|
||||
GpuSchedulingOverrideMethod_Ini = 0,
|
||||
GpuSchedulingOverrideMethod_NvService,
|
||||
GpuSchedulingOverrideMethod_EnumMax,
|
||||
} GpuSchedulingOverrideMethod;
|
||||
|
||||
typedef enum {
|
||||
GovernorState_DoNotOverride = 0,
|
||||
GovernorState_Disabled,
|
||||
GovernorState_Enabled_CpuGpu,
|
||||
GovernorState_Enabled_Cpu,
|
||||
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)
|
||||
|
||||
static inline const char* sysclkFormatModule(SysClkModule module, bool pretty)
|
||||
|
||||
@@ -48,11 +48,8 @@ Result sysclkIpcSetProfiles(u64 tid, SysClkTitleProfileList* profiles);
|
||||
Result sysclkIpcGetConfigValues(SysClkConfigValueList* out_configValues);
|
||||
Result sysclkIpcSetConfigValues(SysClkConfigValueList* configValues);
|
||||
Result sysclkIpcGetFreqList(SysClkModule module, u32* list, u32 maxCount, u32* outCount);
|
||||
Result sysclkIpcSetReverseNXRTMode(ReverseNXMode mode);
|
||||
Result hocClkIpcSetKipData();
|
||||
Result hocClkIpcGetKipData();
|
||||
Result hocClkIpcUpdateEmcRegs();
|
||||
Result hocClkIpcCalculateGpuVmin();
|
||||
|
||||
static inline Result sysclkIpcRemoveOverride(SysClkModule module)
|
||||
{
|
||||
|
||||
@@ -58,8 +58,13 @@ typedef enum {
|
||||
|
||||
HorizonOCConfigValue_DVFSMode,
|
||||
HorizonOCConfigValue_DVFSOffset,
|
||||
HorizonOCConfigValue_LiveCpuUv,
|
||||
HorizonOCConfigValue_EnableExperimentalSettings,
|
||||
|
||||
HorizonOCConfigValue_GPUScheduling,
|
||||
HorizonOCConfigValue_GPUSchedulingMethod,
|
||||
|
||||
HorizonOCConfigValue_RAMVoltUsageDisplayMode,
|
||||
|
||||
KipConfigValue_custRev,
|
||||
// KipConfigValue_mtcConf,
|
||||
@@ -195,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";
|
||||
@@ -232,6 +237,19 @@ static inline const char* sysclkFormatConfigValue(SysClkConfigValue val, bool pr
|
||||
|
||||
case HorizonOCConfigValue_GPUScheduling:
|
||||
return pretty ? "GPU Scheduling" : "gpu_scheduling";
|
||||
|
||||
case HorizonOCConfigValue_GPUSchedulingMethod:
|
||||
return pretty ? "GPU Scheduling Method" : "gpu_sched_method";
|
||||
|
||||
case HorizonOCConfigValue_LiveCpuUv:
|
||||
return pretty ? "Live CPU Undervolt" : "live_cpu_uv";
|
||||
|
||||
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";
|
||||
@@ -410,6 +428,8 @@ static inline uint64_t sysclkDefaultConfigValue(SysClkConfigValue val)
|
||||
case HorizonOCConfigValue_OverwriteRefreshRate:
|
||||
case HorizonOCConfigValue_EnableUnsafeDisplayFreqs:
|
||||
case HorizonOCConfigValue_GPUScheduling:
|
||||
case HorizonOCConfigValue_LiveCpuUv:
|
||||
case HorizonOCConfigValue_GPUSchedulingMethod:
|
||||
return 0ULL;
|
||||
case HocClkConfigValue_EristaMaxCpuClock:
|
||||
return 1785ULL;
|
||||
@@ -456,6 +476,9 @@ static inline uint64_t sysclkValidConfigValue(SysClkConfigValue val, uint64_t in
|
||||
case HorizonOCConfigValue_OverwriteRefreshRate:
|
||||
case HorizonOCConfigValue_EnableUnsafeDisplayFreqs:
|
||||
case HocClkConfigValue_IsFirstLoad:
|
||||
case HorizonOCConfigValue_EnableExperimentalSettings:
|
||||
case HorizonOCConfigValue_LiveCpuUv:
|
||||
case HorizonOCConfigValue_GPUSchedulingMethod:
|
||||
return (input & 0x1) == input;
|
||||
|
||||
case KipConfigValue_custRev:
|
||||
@@ -555,6 +578,7 @@ 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;
|
||||
|
||||
@@ -48,9 +48,8 @@ enum SysClkIpcCmd
|
||||
SysClkIpcCmd_GetConfigValues = 9,
|
||||
SysClkIpcCmd_SetConfigValues = 10,
|
||||
SysClkIpcCmd_GetFreqList = 11,
|
||||
SysClkIpcCmd_SetReverseNXRTMode = 12,
|
||||
HocClkIpcCmd_SetKipData = 13,
|
||||
HocClkIpcCmd_GetKipData = 14,
|
||||
HocClkIpcCmd_SetKipData = 12,
|
||||
HocClkIpcCmd_GetKipData = 13,
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -153,12 +153,6 @@ Result sysclkIpcGetFreqList(SysClkModule module, u32* list, u32 maxCount, u32* o
|
||||
);
|
||||
}
|
||||
|
||||
Result sysclkIpcSetReverseNXRTMode(ReverseNXMode mode)
|
||||
{
|
||||
return serviceDispatchIn(&g_sysclkSrv, SysClkIpcCmd_SetReverseNXRTMode, mode);
|
||||
}
|
||||
|
||||
|
||||
Result hocClkIpcSetKipData()
|
||||
{
|
||||
u32 temp = 0;
|
||||
|
||||
@@ -42,10 +42,23 @@ static bool g_canChangeRefreshRateDocked = false;
|
||||
static uint8_t g_lastVActiveSet = 0;
|
||||
|
||||
// Refresh rate tables
|
||||
static const uint8_t g_dockedRefreshRates[] = {40, 45, 50, 55, 60, 70, 72, 75, 80, 90, 95, 100, 110, 120, 130, 144, 150, 160, 165, 170, 180, 190, 200, 210, 220, 230, 240};
|
||||
static bool g_dockedAllowed[sizeof(g_dockedRefreshRates) / sizeof(g_dockedRefreshRates[0])] = {0};
|
||||
static bool g_dockedAllowed720p[sizeof(g_dockedRefreshRates) / sizeof(g_dockedRefreshRates[0])] = {0};
|
||||
static const uint8_t g_dockedRefreshRates[] = {40, 45, 50, 55, 60, 70, 72, 75, 80, 90, 95, 100, 110, 120, 130, 140, 144, 150, 160, 165, 170, 180, 190, 200, 210, 220, 230, 240};
|
||||
// Calculate with this tool:
|
||||
|
||||
// https://tomverbeure.github.io/video_timings_calculator?horiz_pixels=1920&vert_pixels=1080&refresh_rate=240&margins=false&interlaced=false&bpc=8&color_fmt=rgb444&video_opt=false&custom_hblank=80&custom_vblank=6
|
||||
|
||||
/*
|
||||
typedef struct {
|
||||
uint16_t hFrontPorch;
|
||||
uint8_t hSyncWidth;
|
||||
uint8_t hBackPorch;
|
||||
uint8_t vFrontPorch;
|
||||
uint8_t vSyncWidth;
|
||||
uint8_t vBackPorch;
|
||||
uint8_t VIC;
|
||||
uint32_t pixelClock_kHz;
|
||||
} DockedTimings;
|
||||
*/
|
||||
static const DockedTimings g_dockedTimings1080p[] = {
|
||||
{8, 32, 40, 7, 8, 6, 0, 88080}, // 40Hz
|
||||
{8, 32, 40, 9, 8, 6, 0, 99270}, // 45Hz
|
||||
@@ -60,7 +73,21 @@ static const DockedTimings g_dockedTimings1080p[] = {
|
||||
{8, 32, 40, 36, 8, 6, 0, 214700}, // 95Hz
|
||||
{528, 44, 148, 4, 5, 36, 64, 297000}, // 100Hz
|
||||
{8, 32, 40, 44, 8, 6, 0, 250360}, // 110Hz
|
||||
{88, 44, 148, 4, 5, 36, 63, 297000} // 120Hz
|
||||
{88, 44, 148, 4, 5, 36, 63, 297000}, // 120Hz
|
||||
{8, 32, 40, 55, 8, 6, 0, 298750}, //130Hz CVT-RBv2
|
||||
{8, 32, 40, 61, 8, 6, 0, 323400}, //140Hz CVT-RBv2
|
||||
{8, 32, 40, 63, 8, 6, 0, 333216}, //144Hz CVT-RBv2
|
||||
{8, 32, 40, 67, 8, 6, 0, 348300}, //150Hz CVT-RBv2
|
||||
{8, 32, 40, 72, 8, 6, 0, 373120}, //160Hz CVT-RBv2
|
||||
{8, 32, 40, 75, 8, 6, 0, 385770}, //165Hz CVT-RBv2
|
||||
{8, 32, 40, 78, 8, 6, 0, 398480}, //170Hz CVT-RBv2
|
||||
{8, 32, 40, 84, 8, 6, 0, 424080}, //180Hz CVT-RBv2
|
||||
{8, 32, 40, 90, 8, 6, 0, 449920}, //190Hz CVT-RBv2
|
||||
{8, 32, 40, 96, 8, 6, 0, 476000}, //200Hz CVT-RBv2
|
||||
{8, 32, 40, 102, 8, 6, 0, 502320}, //210Hz CVT-RBv2
|
||||
{8, 32, 40, 108, 8, 6, 0, 528880}, //220Hz CVT-RBv2
|
||||
{8, 32, 40, 114, 8, 6, 0, 555680}, //230Hz CVT-RBv2
|
||||
{8, 32, 40, 121, 8, 6, 0, 583200}, //240Hz CVT-RBv2
|
||||
};
|
||||
|
||||
static const HandheldTimings g_handheldTimingsRETRO[] = {
|
||||
@@ -81,15 +108,6 @@ static uint8_t _getDockedRefreshRateIterator(uint32_t refreshRate) {
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
static void _setDefaultDockedSettings(void) {
|
||||
memset(g_dockedAllowed, 0, sizeof(g_dockedAllowed));
|
||||
g_dockedAllowed[_getDockedRefreshRateIterator(50)] = true;
|
||||
g_dockedAllowed[_getDockedRefreshRateIterator(60)] = true;
|
||||
memset(g_dockedAllowed720p, 0, sizeof(g_dockedAllowed720p));
|
||||
g_dockedAllowed720p[_getDockedRefreshRateIterator(50)] = true;
|
||||
g_dockedAllowed720p[_getDockedRefreshRateIterator(60)] = true;
|
||||
}
|
||||
|
||||
static void _changeOledElvssSettings(const uint32_t* offsets, const uint32_t* value, uint32_t size, uint32_t start) {
|
||||
if (!g_config.dsiVirtAddr || !value || !size) return;
|
||||
|
||||
@@ -126,13 +144,14 @@ static void _changeOledElvssSettings(const uint32_t* offsets, const uint32_t* va
|
||||
dsi[DSI_VIDEO_MODE_CONTROL] = false;
|
||||
svcSleepThread(20000000);
|
||||
}
|
||||
|
||||
void DisplayRefresh_SetDockedState(bool isDocked) {
|
||||
g_config.isDocked = isDocked;
|
||||
}
|
||||
|
||||
bool DisplayRefresh_Initialize(const DisplayRefreshConfig* config) {
|
||||
if (!config) return false;
|
||||
|
||||
g_config = *config;
|
||||
_setDefaultDockedSettings();
|
||||
g_initialized = true;
|
||||
return true;
|
||||
}
|
||||
@@ -180,69 +199,20 @@ void DisplayRefresh_CorrectOledGamma(uint32_t refresh_rate) {
|
||||
}
|
||||
|
||||
void DisplayRefresh_SetAllowedDockedRatesIPC(uint32_t refreshRates, bool is720p) {
|
||||
struct {
|
||||
unsigned int Hz_40: 1;
|
||||
unsigned int Hz_45: 1;
|
||||
unsigned int Hz_50: 1;
|
||||
unsigned int Hz_55: 1;
|
||||
unsigned int Hz_60: 1;
|
||||
unsigned int Hz_70: 1;
|
||||
unsigned int Hz_72: 1;
|
||||
unsigned int Hz_75: 1;
|
||||
unsigned int Hz_80: 1;
|
||||
unsigned int Hz_90: 1;
|
||||
unsigned int Hz_95: 1;
|
||||
unsigned int Hz_100: 1;
|
||||
unsigned int Hz_110: 1;
|
||||
unsigned int Hz_120: 1;
|
||||
unsigned int reserved: 18;
|
||||
} rates;
|
||||
|
||||
memcpy(&rates, &refreshRates, 4);
|
||||
|
||||
bool* target = is720p ? g_dockedAllowed720p : g_dockedAllowed;
|
||||
target[_getDockedRefreshRateIterator(40)] = rates.Hz_40;
|
||||
target[_getDockedRefreshRateIterator(45)] = rates.Hz_45;
|
||||
target[_getDockedRefreshRateIterator(50)] = rates.Hz_50;
|
||||
target[_getDockedRefreshRateIterator(55)] = rates.Hz_55;
|
||||
target[_getDockedRefreshRateIterator(60)] = true;
|
||||
target[_getDockedRefreshRateIterator(70)] = rates.Hz_70;
|
||||
target[_getDockedRefreshRateIterator(72)] = rates.Hz_72;
|
||||
target[_getDockedRefreshRateIterator(75)] = rates.Hz_75;
|
||||
target[_getDockedRefreshRateIterator(80)] = rates.Hz_80;
|
||||
target[_getDockedRefreshRateIterator(90)] = rates.Hz_90;
|
||||
target[_getDockedRefreshRateIterator(95)] = rates.Hz_95;
|
||||
target[_getDockedRefreshRateIterator(100)] = rates.Hz_100;
|
||||
target[_getDockedRefreshRateIterator(110)] = rates.Hz_110;
|
||||
target[_getDockedRefreshRateIterator(120)] = rates.Hz_120;
|
||||
// Function kept for API compatibility but does nothing
|
||||
(void)refreshRates;
|
||||
(void)is720p;
|
||||
}
|
||||
|
||||
uint8_t DisplayRefresh_GetDockedHighestAllowed(void) {
|
||||
const size_t numRates = sizeof(g_dockedRefreshRates) / sizeof(g_dockedRefreshRates[0]);
|
||||
|
||||
if (g_lastVActive == 1080) {
|
||||
for (int i = numRates - 1; g_dockedRefreshRates[i] > 60; i--) {
|
||||
if (g_dockedAllowed[i])
|
||||
return (g_dockedRefreshRates[i] > g_dockedHighestRefreshRate) ? g_dockedHighestRefreshRate : g_dockedRefreshRates[i];
|
||||
}
|
||||
} else if (g_lastVActive == 720) {
|
||||
for (int i = numRates - 1; g_dockedRefreshRates[i] > 60; i--) {
|
||||
if (g_dockedAllowed720p[i])
|
||||
return (g_dockedRefreshRates[i] > g_dockedHighestRefreshRate) ? g_dockedHighestRefreshRate : g_dockedRefreshRates[i];
|
||||
}
|
||||
}
|
||||
return 60;
|
||||
return (g_dockedHighestRefreshRate > 60) ? g_dockedHighestRefreshRate : 60;
|
||||
}
|
||||
|
||||
static void _getDockedHighestRefreshRate(uint32_t fd_in) {
|
||||
uint8_t highestRefreshRate = 60;
|
||||
uint32_t fd = fd_in;
|
||||
|
||||
if (!fd && nvOpen(&fd, "/dev/nvdisp-disp1")) {
|
||||
g_dockedHighestRefreshRate = 60;
|
||||
return;
|
||||
}
|
||||
|
||||
if(!fd) nvOpen(&fd, "/dev/nvdisp-disp1");
|
||||
NvdcModeDB2 db2 = {0};
|
||||
int rc = nvIoctl(fd, NVDISP_GET_MODE_DB2, &db2);
|
||||
|
||||
@@ -288,8 +258,8 @@ static void _getDockedHighestRefreshRate(uint32_t fd_in) {
|
||||
rc = nvIoctl(fd, NVDISP_GET_PANEL_DATA, &dpaux);
|
||||
if (rc == 0) {
|
||||
g_dockedLinkRate = dpaux.set.link_rate;
|
||||
if (display_b.hActive == 1920 && display_b.vActive == 1080 && highestRefreshRate > 75 && dpaux.set.link_rate < 20)
|
||||
highestRefreshRate = 75;
|
||||
// if (display_b.hActive == 1920 && display_b.vActive == 1080 && highestRefreshRate > 75 && dpaux.set.link_rate < 20 && )
|
||||
// highestRefreshRate = 75;
|
||||
}
|
||||
|
||||
if (!fd_in) nvClose(fd);
|
||||
@@ -403,10 +373,6 @@ static bool _setNvDispDockedRefreshRate(uint32_t new_refreshRate) {
|
||||
|
||||
if (display_b.vActive != g_lastVActiveSet) {
|
||||
g_lastVActiveSet = display_b.vActive;
|
||||
if (display_b.vActive != 720 && display_b.vActive != 1080) {
|
||||
memset(g_dockedAllowed, 0, sizeof(g_dockedAllowed));
|
||||
g_dockedAllowed[_getDockedRefreshRateIterator(60)] = true;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t h_total = display_b.hActive + display_b.hFrontPorch + display_b.hSyncWidth + display_b.hBackPorch;
|
||||
@@ -416,15 +382,13 @@ static bool _setNvDispDockedRefreshRate(uint32_t new_refreshRate) {
|
||||
int8_t itr = -1;
|
||||
const size_t numRates = sizeof(g_dockedRefreshRates) / sizeof(g_dockedRefreshRates[0]);
|
||||
|
||||
// Find closest matching refresh rate
|
||||
if ((new_refreshRate <= 60) && ((60 % new_refreshRate) == 0)) {
|
||||
itr = _getDockedRefreshRateIterator(60);
|
||||
}
|
||||
|
||||
if (itr == -1) {
|
||||
for (size_t i = 0; i < numRates; i++) {
|
||||
bool* allowed = (display_b.vActive == 720) ? g_dockedAllowed720p : g_dockedAllowed;
|
||||
if (allowed[i] != true) continue;
|
||||
|
||||
uint8_t val = g_dockedRefreshRates[i];
|
||||
if ((val % new_refreshRate) == 0) {
|
||||
itr = i;
|
||||
@@ -437,9 +401,8 @@ static bool _setNvDispDockedRefreshRate(uint32_t new_refreshRate) {
|
||||
if (!g_config.matchLowestDocked) {
|
||||
itr = _getDockedRefreshRateIterator(60);
|
||||
} else {
|
||||
bool* allowed = (display_b.vActive == 1080) ? g_dockedAllowed : g_dockedAllowed720p;
|
||||
for (size_t i = 0; i < numRates; i++) {
|
||||
if ((allowed[i] == true) && (new_refreshRate < g_dockedRefreshRates[i])) {
|
||||
if (new_refreshRate < g_dockedRefreshRates[i]) {
|
||||
itr = i;
|
||||
break;
|
||||
}
|
||||
@@ -449,15 +412,13 @@ static bool _setNvDispDockedRefreshRate(uint32_t new_refreshRate) {
|
||||
|
||||
if (itr == -1) itr = _getDockedRefreshRateIterator(60);
|
||||
|
||||
bool increase = refreshRateNow < g_dockedRefreshRates[itr];
|
||||
bool* allowed = (display_b.vActive == 720) ? g_dockedAllowed720p : g_dockedAllowed;
|
||||
|
||||
while(itr >= 0 && itr < (int8_t)numRates && allowed[itr] != true) {
|
||||
if (!g_config.displaySyncDocked) {
|
||||
if (increase) itr++;
|
||||
else itr--;
|
||||
} else {
|
||||
itr++;
|
||||
// Clamp to highest allowed refresh rate
|
||||
if (g_dockedRefreshRates[itr] > g_dockedHighestRefreshRate) {
|
||||
for (int8_t i = itr; i >= 0; i--) {
|
||||
if (g_dockedRefreshRates[i] <= g_dockedHighestRefreshRate) {
|
||||
itr = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -629,8 +590,7 @@ bool DisplayRefresh_SetRate(uint32_t new_refreshRate) {
|
||||
|
||||
bool DisplayRefresh_GetRate(uint32_t* out_refreshRate, bool internal) {
|
||||
if (!out_refreshRate || !g_initialized || !g_config.clkVirtAddr) return false;
|
||||
|
||||
uint32_t value = 60;
|
||||
static uint32_t value = 60;
|
||||
|
||||
if (g_config.isRetroSUPER && !g_config.isDocked) {
|
||||
uint32_t fd = 0;
|
||||
@@ -705,7 +665,10 @@ bool DisplayRefresh_GetRate(uint32_t* out_refreshRate, bool internal) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(internal) {
|
||||
*out_refreshRate = value;
|
||||
return true;
|
||||
}
|
||||
uint32_t fd = 0;
|
||||
if (!nvOpen(&fd, "/dev/nvdisp-disp1")) {
|
||||
NvdcMode2 display_b = {0};
|
||||
|
||||
@@ -53,6 +53,14 @@ Result rgltrGetVoltage(RgltrSession* session, u32* out_volt) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result rgltrRequestVoltage(RgltrSession* session, u32 microvolt) {
|
||||
return serviceDispatchIn(&session->s, 5, microvolt);
|
||||
}
|
||||
|
||||
Result rgltrCancelVoltageRequest(RgltrSession* session) {
|
||||
return serviceDispatch(&session->s, 6);
|
||||
}
|
||||
|
||||
void rgltrCloseSession(RgltrSession* session) {
|
||||
serviceClose(&session->s);
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ include ${TOPDIR}/lib/libultrahand/ultrahand.mk
|
||||
# version control constants
|
||||
#---------------------------------------------------------------------------------
|
||||
#TARGET_VERSION := $(shell git describe --dirty --always --tags)
|
||||
APP_VERSION := 0.39
|
||||
APP_VERSION := 0.42
|
||||
TARGET_VERSION := $(APP_VERSION)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
@@ -49,13 +49,13 @@ 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__
|
||||
|
||||
# Enable appearance overriding
|
||||
UI_OVERRIDE_PATH := /config/sys-clk/
|
||||
UI_OVERRIDE_PATH := /config/horizon-oc/
|
||||
CFLAGS += -DUI_OVERRIDE_PATH="\"$(UI_OVERRIDE_PATH)\""
|
||||
|
||||
# Disable fstream
|
||||
|
||||
@@ -95,7 +95,8 @@ void AppProfileGui::openValueChoiceGui(
|
||||
enableThresholds,
|
||||
labels,
|
||||
namedValues,
|
||||
showDefaultValue
|
||||
showDefaultValue,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
@@ -148,6 +149,36 @@ void AppProfileGui::addModuleListItemToggle(SysClkProfile profile, SysClkModule
|
||||
this->listElement->addItem(toggle);
|
||||
}
|
||||
|
||||
std::string AppProfileGui::formatValueDisplay(
|
||||
std::uint32_t value,
|
||||
const std::vector<NamedValue>& namedValues,
|
||||
const std::string& suffix,
|
||||
std::uint32_t divisor,
|
||||
int decimalPlaces
|
||||
)
|
||||
{
|
||||
if (value == 0) {
|
||||
return FREQ_DEFAULT_TEXT;
|
||||
}
|
||||
|
||||
if (!namedValues.empty()) {
|
||||
for (const auto& namedValue : namedValues) {
|
||||
if (namedValue.value == value) {
|
||||
return namedValue.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char buf[32];
|
||||
if (decimalPlaces > 0) {
|
||||
double displayValue = (double)value / divisor;
|
||||
snprintf(buf, sizeof(buf), "%.*f%s", decimalPlaces, displayValue, suffix.c_str());
|
||||
} else {
|
||||
snprintf(buf, sizeof(buf), "%u%s", value / divisor, suffix.c_str());
|
||||
}
|
||||
return std::string(buf);
|
||||
}
|
||||
|
||||
void AppProfileGui::addModuleListItemValue(
|
||||
SysClkProfile profile,
|
||||
SysClkModule module,
|
||||
@@ -158,26 +189,17 @@ void AppProfileGui::addModuleListItemValue(
|
||||
const std::string& suffix,
|
||||
std::uint32_t divisor,
|
||||
int decimalPlaces,
|
||||
ValueThresholds thresholds
|
||||
ValueThresholds thresholds,
|
||||
std::vector<NamedValue> namedValues,
|
||||
bool showDefaultValue
|
||||
)
|
||||
{
|
||||
tsl::elm::ListItem* listItem =
|
||||
new tsl::elm::ListItem(sysclkFormatModule(module, true));
|
||||
|
||||
std::uint32_t storedValue = this->profileList->mhzMap[profile][module];
|
||||
if (storedValue == 0) {
|
||||
listItem->setValue(FREQ_DEFAULT_TEXT);
|
||||
} else {
|
||||
char buf[32];
|
||||
if (decimalPlaces > 0) {
|
||||
double displayValue = (double)storedValue / divisor;
|
||||
snprintf(buf, sizeof(buf), "%.*f%s", decimalPlaces, displayValue, suffix.c_str());
|
||||
} else {
|
||||
snprintf(buf, sizeof(buf), "%u%s", storedValue / divisor, suffix.c_str());
|
||||
}
|
||||
listItem->setValue(buf);
|
||||
}
|
||||
|
||||
|
||||
listItem->setValue(this->formatValueDisplay(storedValue, namedValues, suffix, divisor, decimalPlaces));
|
||||
|
||||
listItem->setClickListener(
|
||||
[this,
|
||||
listItem,
|
||||
@@ -190,13 +212,14 @@ void AppProfileGui::addModuleListItemValue(
|
||||
suffix,
|
||||
divisor,
|
||||
decimalPlaces,
|
||||
thresholds](u64 keys)
|
||||
thresholds,
|
||||
namedValues,
|
||||
showDefaultValue](u64 keys)
|
||||
{
|
||||
if ((keys & HidNpadButton_A) == HidNpadButton_A)
|
||||
{
|
||||
std::uint32_t currentValue =
|
||||
this->profileList->mhzMap[profile][module] * divisor;
|
||||
|
||||
ValueRange range(
|
||||
min,
|
||||
max,
|
||||
@@ -205,36 +228,19 @@ void AppProfileGui::addModuleListItemValue(
|
||||
divisor,
|
||||
decimalPlaces
|
||||
);
|
||||
|
||||
this->openValueChoiceGui(
|
||||
listItem,
|
||||
currentValue,
|
||||
range,
|
||||
categoryName,
|
||||
|
||||
[this, listItem, profile, module, divisor, suffix, decimalPlaces, thresholds](std::uint32_t value) -> bool
|
||||
[this, listItem, profile, module, divisor, suffix, decimalPlaces, thresholds, namedValues](std::uint32_t value) -> bool
|
||||
{
|
||||
this->profileList->mhzMap[profile][module] = value / divisor;
|
||||
|
||||
if (value == 0) {
|
||||
listItem->setValue(FREQ_DEFAULT_TEXT);
|
||||
} else {
|
||||
char buf[32];
|
||||
if (decimalPlaces > 0) {
|
||||
double displayValue = (double)value / divisor;
|
||||
snprintf(buf, sizeof(buf), "%.*f%s",
|
||||
decimalPlaces, displayValue, suffix.c_str());
|
||||
} else {
|
||||
snprintf(buf, sizeof(buf), "%u%s",
|
||||
value / divisor, suffix.c_str());
|
||||
}
|
||||
listItem->setValue(buf);
|
||||
}
|
||||
|
||||
listItem->setValue(this->formatValueDisplay(value / divisor, namedValues, suffix, divisor, decimalPlaces));
|
||||
|
||||
Result rc =
|
||||
sysclkIpcSetProfiles(this->applicationId,
|
||||
this->profileList);
|
||||
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
FatalGui::openWithResultCode(
|
||||
@@ -243,34 +249,30 @@ void AppProfileGui::addModuleListItemValue(
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
thresholds,
|
||||
false
|
||||
false,
|
||||
{},
|
||||
namedValues,
|
||||
showDefaultValue
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
else if ((keys & HidNpadButton_Y) == HidNpadButton_Y)
|
||||
{
|
||||
this->profileList->mhzMap[profile][module] = 0;
|
||||
listItem->setValue(FREQ_DEFAULT_TEXT);
|
||||
|
||||
Result rc =
|
||||
sysclkIpcSetProfiles(this->applicationId,
|
||||
this->profileList);
|
||||
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
FatalGui::openWithResultCode("sysclkIpcSetProfiles", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
this->listElement->addItem(listItem);
|
||||
}
|
||||
|
||||
@@ -279,7 +281,7 @@ void AppProfileGui::addProfileUI(SysClkProfile profile)
|
||||
BaseMenuGui::refresh();
|
||||
if(!this->context)
|
||||
return;
|
||||
Result rc = sysclkIpcGetConfigValues(&configList); // idk why this is needed, probably some refreshing issue
|
||||
Result rc = sysclkIpcGetConfigValues(&configList);
|
||||
if (R_FAILED(rc)) [[unlikely]] {
|
||||
FatalGui::openWithResultCode("sysclkIpcGetConfigValues", rc);
|
||||
return;
|
||||
@@ -291,13 +293,93 @@ void AppProfileGui::addProfileUI(SysClkProfile profile)
|
||||
#if IS_MINIMAL == 0
|
||||
ValueThresholds lcdThresholds(60, 65);
|
||||
if(!IsHoag() && configList.values[HorizonOCConfigValue_OverwriteRefreshRate]) {
|
||||
if(profile != SysClkProfile_Docked)
|
||||
if(profile != SysClkProfile_Docked) {
|
||||
this->addModuleListItemValue(profile, HorizonOCModule_Display, "Display", IsAula() ? 45 : 40, configList.values[HorizonOCConfigValue_EnableUnsafeDisplayFreqs] ? IsAula() ? 65 : 72 : 60, 1, " Hz", 1, 0, lcdThresholds);
|
||||
else
|
||||
this->addModuleListItemValue(profile, HorizonOCModule_Display, "Display", 50, IsAula() ? this->context->isSysDockInstalled ? 120 : 75 : 120, 5, " Hz", 1, 0);
|
||||
} else {
|
||||
if(IsAula() && this->context->isSysDockInstalled) {
|
||||
std::vector<NamedValue> dockedFreqs = {
|
||||
NamedValue("40 Hz", 40),
|
||||
NamedValue("45 Hz", 45),
|
||||
NamedValue("50 Hz", 50),
|
||||
NamedValue("55 Hz", 55),
|
||||
NamedValue("60 Hz", 60),
|
||||
NamedValue("70 Hz", 70),
|
||||
NamedValue("72 Hz", 72),
|
||||
NamedValue("75 Hz", 75),
|
||||
NamedValue("80 Hz", 80),
|
||||
NamedValue("90 Hz", 90),
|
||||
NamedValue("95 Hz", 95),
|
||||
NamedValue("100 Hz", 100),
|
||||
NamedValue("110 Hz", 110),
|
||||
NamedValue("120 Hz", 120),
|
||||
NamedValue("130 Hz", 130),
|
||||
NamedValue("140 Hz", 140),
|
||||
NamedValue("144 Hz", 144),
|
||||
NamedValue("150 Hz", 150),
|
||||
NamedValue("160 Hz", 160),
|
||||
NamedValue("165 Hz", 165),
|
||||
NamedValue("170 Hz", 170),
|
||||
NamedValue("180 Hz", 180),
|
||||
NamedValue("190 Hz", 190),
|
||||
NamedValue("200 Hz", 200),
|
||||
NamedValue("210 Hz", 210),
|
||||
NamedValue("220 Hz", 220),
|
||||
NamedValue("230 Hz", 230),
|
||||
NamedValue("240 Hz", 240)
|
||||
};
|
||||
|
||||
this->addModuleListItemValue(profile, HorizonOCModule_Display, "Display", 40, 240, 1, " Hz", 1, 0, ValueThresholds(), dockedFreqs);
|
||||
} else if (IsAula() && !this->context->isSysDockInstalled) {
|
||||
std::vector<NamedValue> dockedFreqsLimited = {
|
||||
NamedValue("50 Hz", 50),
|
||||
NamedValue("55 Hz", 55),
|
||||
NamedValue("60 Hz", 60),
|
||||
NamedValue("65 Hz", 65),
|
||||
NamedValue("70 Hz", 70),
|
||||
NamedValue("72 Hz", 72),
|
||||
NamedValue("75 Hz", 75)
|
||||
};
|
||||
|
||||
this->addModuleListItemValue(profile, HorizonOCModule_Display, "Display", 50, 75, 1, " Hz", 1, 0, ValueThresholds(), dockedFreqsLimited);
|
||||
} else {
|
||||
std::vector<NamedValue> dockedFreqsStandard = {
|
||||
NamedValue("50 Hz", 50),
|
||||
NamedValue("55 Hz", 55),
|
||||
NamedValue("60 Hz", 60),
|
||||
NamedValue("65 Hz", 65),
|
||||
NamedValue("70 Hz", 70),
|
||||
NamedValue("72 Hz", 72),
|
||||
NamedValue("75 Hz", 75),
|
||||
NamedValue("80 Hz", 80),
|
||||
NamedValue("85 Hz", 85),
|
||||
NamedValue("90 Hz", 90),
|
||||
NamedValue("95 Hz", 95),
|
||||
NamedValue("100 Hz", 100),
|
||||
NamedValue("105 Hz", 105),
|
||||
NamedValue("110 Hz", 110),
|
||||
NamedValue("115 Hz", 115),
|
||||
NamedValue("120 Hz", 120)
|
||||
};
|
||||
|
||||
this->addModuleListItemValue(profile, HorizonOCModule_Display, "Display", 50, 120, 1, " Hz", 1, 0, ValueThresholds(), dockedFreqsStandard);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
this->addModuleListItemToggle(profile, HorizonOCModule_Governor);
|
||||
std::vector<NamedValue> governorSettingsE = {
|
||||
NamedValue("Do Not Override", GovernorState_DoNotOverride),
|
||||
NamedValue("Disabled", GovernorState_Disabled),
|
||||
NamedValue("CPU + GPU", GovernorState_Enabled_CpuGpu),
|
||||
NamedValue("CPU", GovernorState_Enabled_Cpu),
|
||||
NamedValue("GPU", GovernorState_Enabled_Gpu),
|
||||
};
|
||||
|
||||
std::vector<NamedValue> governorSettings = {
|
||||
NamedValue("Do Not Override", GovernorState_DoNotOverride),
|
||||
NamedValue("Disabled", GovernorState_Disabled),
|
||||
NamedValue("GPU", GovernorState_Enabled_Gpu),
|
||||
};
|
||||
this->addModuleListItemValue(profile, HorizonOCModule_Governor, "Governor", 0, 0, 1, "", 1, 0, ValueThresholds(), configList.values[HorizonOCConfigValue_EnableExperimentalSettings] ?governorSettingsE : governorSettings, false);
|
||||
}
|
||||
|
||||
void AppProfileGui::listUI()
|
||||
@@ -337,4 +419,4 @@ void AppProfileGui::update()
|
||||
""
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,22 +23,17 @@
|
||||
* stuff is worth it, you can buy us a beer in return. - The sys-clk authors
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../ipc.h"
|
||||
#include "base_menu_gui.h"
|
||||
#include "freq_choice_gui.h"
|
||||
#include "value_choice_gui.h"
|
||||
#define SYSCLK_GLOBAL_PROFILE_TID 0xA111111111111111
|
||||
|
||||
class AppProfileGui : public BaseMenuGui
|
||||
{
|
||||
protected:
|
||||
std::uint64_t applicationId;
|
||||
SysClkTitleProfileList* profileList;
|
||||
|
||||
void openFreqChoiceGui(tsl::elm::ListItem* listItem, SysClkProfile profile, SysClkModule module);
|
||||
void addModuleListItem(SysClkProfile profile, SysClkModule module);
|
||||
void addModuleListItemToggle(SysClkProfile profile, SysClkModule module);
|
||||
@@ -54,6 +49,13 @@ class AppProfileGui : public BaseMenuGui
|
||||
const std::vector<NamedValue>& namedValues = {},
|
||||
bool showDefaultValue = true
|
||||
);
|
||||
std::string formatValueDisplay(
|
||||
std::uint32_t value,
|
||||
const std::vector<NamedValue>& namedValues,
|
||||
const std::string& suffix,
|
||||
std::uint32_t divisor,
|
||||
int decimalPlaces
|
||||
);
|
||||
void addModuleListItemValue(
|
||||
SysClkProfile profile,
|
||||
SysClkModule module,
|
||||
@@ -64,14 +66,15 @@ class AppProfileGui : public BaseMenuGui
|
||||
const std::string& suffix,
|
||||
std::uint32_t divisor,
|
||||
int decimalPlaces,
|
||||
ValueThresholds thresholds = {}
|
||||
ValueThresholds thresholds,
|
||||
std::vector<NamedValue> namedValues = {},
|
||||
bool showDefaultValue = true
|
||||
);
|
||||
void addProfileUI(SysClkProfile profile);
|
||||
|
||||
public:
|
||||
AppProfileGui(std::uint64_t applicationId, SysClkTitleProfileList* profileList);
|
||||
~AppProfileGui();
|
||||
void listUI() override;
|
||||
static void changeTo(std::uint64_t applicationId);
|
||||
void update() override;
|
||||
};
|
||||
};
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -118,32 +118,31 @@ void FreqChoiceGui::listUI()
|
||||
std::uint32_t hz = this->hzList[i];
|
||||
uint32_t mhz = hz / 1000000;
|
||||
|
||||
if (checkMax && IsMariko()) {
|
||||
if (moduleName == "cpu" &&
|
||||
this->configList->values[HocClkConfigValue_MarikoMaxCpuClock] < mhz)
|
||||
// if (checkMax && IsMariko()) {
|
||||
// if (moduleName == "cpu" &&
|
||||
// this->configList->values[HocClkConfigValue_MarikoMaxCpuClock] < mhz)
|
||||
// continue;
|
||||
|
||||
// // if (moduleName == "gpu" &&
|
||||
// // this->configList->values[HocClkConfigValue_MarikoMaxGpuClock] < mhz)
|
||||
// // continue;
|
||||
|
||||
// // if (moduleName == "mem" &&
|
||||
// // this->configList->values[HocClkConfigValue_MarikoMaxMemClock] < mhz)
|
||||
// // continue;
|
||||
|
||||
if (checkMax && IsErista())
|
||||
if (moduleName == "cpu" && this->configList->values[HocClkConfigValue_EristaMaxCpuClock] < mhz)
|
||||
continue;
|
||||
|
||||
// if (moduleName == "gpu" &&
|
||||
// this->configList->values[HocClkConfigValue_MarikoMaxGpuClock] < mhz)
|
||||
// continue;
|
||||
// // if (moduleName == "gpu" &&
|
||||
// // this->configList->values[HocClkConfigValue_EristaMaxGpuClock] < mhz)
|
||||
// // continue;
|
||||
|
||||
// if (moduleName == "mem" &&
|
||||
// this->configList->values[HocClkConfigValue_MarikoMaxMemClock] < mhz)
|
||||
// continue;
|
||||
|
||||
} else if (checkMax && IsErista()) {
|
||||
if (moduleName == "cpu" &&
|
||||
this->configList->values[HocClkConfigValue_EristaMaxCpuClock] < mhz)
|
||||
continue;
|
||||
|
||||
// if (moduleName == "gpu" &&
|
||||
// this->configList->values[HocClkConfigValue_EristaMaxGpuClock] < mhz)
|
||||
// continue;
|
||||
|
||||
// if (moduleName == "mem" &&
|
||||
// this->configList->values[HocClkConfigValue_EristaMaxMemClock] < mhz)
|
||||
// continue;
|
||||
}
|
||||
// // if (moduleName == "mem" &&
|
||||
// // this->configList->values[HocClkConfigValue_EristaMaxMemClock] < mhz)
|
||||
// // continue;
|
||||
// }
|
||||
|
||||
if (moduleName == "mem" && mhz <= 600)
|
||||
continue;
|
||||
|
||||
@@ -99,11 +99,16 @@ void GlobalOverrideGui::addModuleListItemValue(
|
||||
const std::string& suffix,
|
||||
std::uint32_t divisor,
|
||||
int decimalPlaces,
|
||||
ValueThresholds thresholds
|
||||
ValueThresholds thresholds,
|
||||
const std::vector<NamedValue>& namedValues,
|
||||
bool showDefaultValue
|
||||
)
|
||||
{
|
||||
bool hasNamedValues = !namedValues.empty();
|
||||
|
||||
this->customFormatModules[module] = std::make_tuple(suffix, divisor, decimalPlaces);
|
||||
if (!hasNamedValues) {
|
||||
this->customFormatModules[module] = std::make_tuple(suffix, divisor, decimalPlaces);
|
||||
}
|
||||
|
||||
tsl::elm::ListItem* listItem =
|
||||
new tsl::elm::ListItem(sysclkFormatModule(module, true));
|
||||
@@ -121,7 +126,10 @@ void GlobalOverrideGui::addModuleListItemValue(
|
||||
suffix,
|
||||
divisor,
|
||||
decimalPlaces,
|
||||
thresholds](u64 keys)
|
||||
thresholds,
|
||||
namedValues,
|
||||
hasNamedValues,
|
||||
showDefaultValue](u64 keys)
|
||||
{
|
||||
if ((keys & HidNpadButton_A) == HidNpadButton_A)
|
||||
{
|
||||
@@ -147,7 +155,7 @@ void GlobalOverrideGui::addModuleListItemValue(
|
||||
range,
|
||||
categoryName,
|
||||
|
||||
[this, listItem, module, divisor, suffix, decimalPlaces, thresholds](std::uint32_t value) -> bool
|
||||
[this, listItem, module, divisor, suffix, decimalPlaces, thresholds, namedValues, hasNamedValues, showDefaultValue](std::uint32_t value) -> bool
|
||||
{
|
||||
if (!this->context) {
|
||||
return false;
|
||||
@@ -158,6 +166,13 @@ void GlobalOverrideGui::addModuleListItemValue(
|
||||
|
||||
if (value == 0) {
|
||||
listItem->setValue(FREQ_DEFAULT_TEXT);
|
||||
} else if (hasNamedValues) {
|
||||
for (const auto& namedValue : namedValues) {
|
||||
if (namedValue.value == value / divisor) {
|
||||
listItem->setValue(namedValue.name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
char buf[32];
|
||||
if (decimalPlaces > 0) {
|
||||
@@ -188,8 +203,8 @@ void GlobalOverrideGui::addModuleListItemValue(
|
||||
thresholds,
|
||||
false,
|
||||
std::map<std::uint32_t, std::string>(),
|
||||
std::vector<NamedValue>(),
|
||||
true
|
||||
namedValues,
|
||||
showDefaultValue
|
||||
);
|
||||
|
||||
return true;
|
||||
@@ -294,7 +309,21 @@ void GlobalOverrideGui::listUI()
|
||||
if(!IsHoag() && configList.values[HorizonOCConfigValue_OverwriteRefreshRate])
|
||||
this->addModuleListItemValue(HorizonOCModule_Display, "Display", IsAula() ? 45 : 40, configList.values[HorizonOCConfigValue_EnableUnsafeDisplayFreqs] ? IsAula() ? 65 : 72 : 60, 1, " Hz", 1, 0, lcdThresholds);
|
||||
#endif
|
||||
this->addModuleToggleItem(HorizonOCModule_Governor);
|
||||
|
||||
std::vector<NamedValue> governorSettingsE = {
|
||||
NamedValue("Do Not Override", GovernorState_DoNotOverride),
|
||||
NamedValue("Disabled", GovernorState_Disabled),
|
||||
NamedValue("CPU + GPU", GovernorState_Enabled_CpuGpu),
|
||||
NamedValue("CPU", GovernorState_Enabled_Cpu),
|
||||
NamedValue("GPU", GovernorState_Enabled_Gpu),
|
||||
};
|
||||
|
||||
std::vector<NamedValue> governorSettings = {
|
||||
NamedValue("Do Not Override", GovernorState_DoNotOverride),
|
||||
NamedValue("Disabled", GovernorState_Disabled),
|
||||
NamedValue("GPU", GovernorState_Enabled_Gpu),
|
||||
};
|
||||
this->addModuleListItemValue(HorizonOCModule_Governor, "Governor", 0, 0, 1, "", 1, 0, ValueThresholds(), configList.values[HorizonOCConfigValue_EnableExperimentalSettings] ?governorSettingsE : governorSettings, false);
|
||||
}
|
||||
|
||||
void GlobalOverrideGui::refresh()
|
||||
@@ -306,17 +335,30 @@ void GlobalOverrideGui::refresh()
|
||||
|
||||
for (std::uint16_t m = 0; m < SysClkModule_EnumMax; m++) {
|
||||
if (m == HorizonOCModule_Governor) {
|
||||
auto *toggle =
|
||||
static_cast<tsl::elm::ToggleListItem *>(this->listItems[m]);
|
||||
if (!toggle)
|
||||
continue;
|
||||
|
||||
bool newState = this->context->overrideFreqs[m] != 0;
|
||||
|
||||
if (toggle->getState() != newState) {
|
||||
toggle->setState(newState);
|
||||
if (this->listItems[m] != nullptr &&
|
||||
this->listHz[m] != this->context->overrideFreqs[m]) {
|
||||
|
||||
std::string displayText = FREQ_DEFAULT_TEXT;
|
||||
std::uint32_t currentValue = this->context->overrideFreqs[m];
|
||||
|
||||
std::vector<NamedValue> governorSettings = {
|
||||
NamedValue("Do Not Override", GovernorState_DoNotOverride),
|
||||
NamedValue("Disabled", GovernorState_Disabled),
|
||||
NamedValue("CPU + GPU", GovernorState_Enabled_CpuGpu),
|
||||
NamedValue("CPU", GovernorState_Enabled_Cpu),
|
||||
NamedValue("GPU", GovernorState_Enabled_Gpu),
|
||||
};
|
||||
|
||||
for (const auto& setting : governorSettings) {
|
||||
if (setting.value == currentValue) {
|
||||
displayText = setting.name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this->listItems[m]->setValue(displayText);
|
||||
this->listHz[m] = currentValue;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) Souldbminer, Lightos_ and Horizon OC Contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -23,10 +24,7 @@
|
||||
* stuff is worth it, you can buy us a beer in return. - The sys-clk authors
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../ipc.h"
|
||||
#include "base_menu_gui.h"
|
||||
#include "freq_choice_gui.h"
|
||||
@@ -63,7 +61,9 @@ class GlobalOverrideGui : public BaseMenuGui
|
||||
const std::string& suffix,
|
||||
std::uint32_t divisor,
|
||||
int decimalPlaces,
|
||||
ValueThresholds thresholds = {}
|
||||
ValueThresholds thresholds = {},
|
||||
const std::vector<NamedValue>& namedValues = {},
|
||||
bool showDefaultValue = true
|
||||
);
|
||||
public:
|
||||
GlobalOverrideGui();
|
||||
@@ -71,4 +71,4 @@ class GlobalOverrideGui : public BaseMenuGui
|
||||
void listUI() override;
|
||||
void refresh() override;
|
||||
void setModuleCustomFormat(SysClkModule module, const std::string& suffix, std::uint32_t divisor, int decimalPlaces);
|
||||
};
|
||||
};
|
||||
@@ -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"},
|
||||
|
||||
@@ -28,13 +28,15 @@
|
||||
#pragma message("Compiling with minimal features")
|
||||
#endif
|
||||
|
||||
class DisplaySubMenuGui;
|
||||
class SafetySubMenuGui;
|
||||
class RamSubmenuGui;
|
||||
class RamTimingsSubmenuGui;
|
||||
class RamLatenciesSubmenuGui;
|
||||
class CpuSubmenuGui;
|
||||
class GpuSubmenuGui;
|
||||
class GpuCustomTableSubmenuGui;
|
||||
|
||||
class RamTableEditor;
|
||||
MiscGui::MiscGui()
|
||||
{
|
||||
this->configList = new SysClkConfigValueList {};
|
||||
@@ -167,6 +169,113 @@ void MiscGui::addConfigButton(SysClkConfigValue configVal,
|
||||
this->configNamedValues[configVal] = namedValues;
|
||||
}
|
||||
|
||||
void MiscGui::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,
|
||||
const char* subText)
|
||||
{
|
||||
tsl::elm::ListItem* listItem = new tsl::elm::ListItem("");
|
||||
|
||||
uint64_t currentValue = this->configList->values[configVal];
|
||||
char valueText[32];
|
||||
if (currentValue == 0 && showDefaultValue) {
|
||||
snprintf(valueText, sizeof(valueText), "%s", VALUE_DEFAULT_TEXT);
|
||||
} else {
|
||||
bool foundNamedValue = false;
|
||||
for (const auto& namedValue : namedValues) {
|
||||
if (currentValue == namedValue.value) {
|
||||
snprintf(valueText, sizeof(valueText), "%s", namedValue.name.c_str());
|
||||
foundNamedValue = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundNamedValue) {
|
||||
uint64_t displayValue = currentValue / range.divisor;
|
||||
if (!range.suffix.empty()) {
|
||||
snprintf(valueText, sizeof(valueText), "%lu %s", displayValue, range.suffix.c_str());
|
||||
} else {
|
||||
snprintf(valueText, sizeof(valueText), "%lu", displayValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
listItem->setText(valueText);
|
||||
listItem->setValue(subText ? subText : "");
|
||||
|
||||
ValueThresholds thresholdsCopy = (thresholds ? *thresholds : ValueThresholds{});
|
||||
|
||||
listItem->setClickListener(
|
||||
[this, configVal, range, categoryName, thresholdsCopy, labels, namedValues, showDefaultValue](u64 keys)
|
||||
{
|
||||
if ((keys & HidNpadButton_A) == 0)
|
||||
return false;
|
||||
|
||||
std::uint32_t currentValue = this->configList->values[configVal];
|
||||
|
||||
if (thresholdsCopy.warning != 0 || thresholdsCopy.danger != 0) {
|
||||
|
||||
tsl::changeTo<ValueChoiceGui>(
|
||||
currentValue,
|
||||
range,
|
||||
categoryName,
|
||||
[this, configVal](std::uint32_t value) {
|
||||
this->configList->values[configVal] = value;
|
||||
Result rc = sysclkIpcSetConfigValues(this->configList);
|
||||
if (R_FAILED(rc)) {
|
||||
FatalGui::openWithResultCode("sysclkIpcSetConfigValues", rc);
|
||||
return false;
|
||||
}
|
||||
this->lastContextUpdate = armGetSystemTick();
|
||||
return true;
|
||||
},
|
||||
thresholdsCopy,
|
||||
true,
|
||||
labels,
|
||||
namedValues,
|
||||
showDefaultValue
|
||||
);
|
||||
} else {
|
||||
|
||||
tsl::changeTo<ValueChoiceGui>(
|
||||
currentValue,
|
||||
range,
|
||||
categoryName,
|
||||
[this, configVal](std::uint32_t value) {
|
||||
this->configList->values[configVal] = value;
|
||||
Result rc = sysclkIpcSetConfigValues(this->configList);
|
||||
if (R_FAILED(rc)) {
|
||||
FatalGui::openWithResultCode("sysclkIpcSetConfigValues", rc);
|
||||
return false;
|
||||
}
|
||||
this->lastContextUpdate = armGetSystemTick();
|
||||
return true;
|
||||
},
|
||||
ValueThresholds(),
|
||||
false,
|
||||
labels,
|
||||
namedValues,
|
||||
showDefaultValue
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
this->listElement->addItem(listItem);
|
||||
this->configButtons[configVal] = listItem;
|
||||
this->configRanges[configVal] = range;
|
||||
this->configNamedValues[configVal] = namedValues;
|
||||
this->configButtonSKeys.insert(configVal);
|
||||
if (subText)
|
||||
this->configButtonSSubtext[configVal] = std::string(subText);
|
||||
}
|
||||
|
||||
void MiscGui::updateConfigToggles() {
|
||||
for (const auto& [value, toggle] : this->configToggles) {
|
||||
if (toggle != nullptr)
|
||||
@@ -239,97 +348,33 @@ void MiscGui::addFreqButton(SysClkConfigValue configVal,
|
||||
|
||||
void MiscGui::listUI()
|
||||
{
|
||||
Result rc = sysclkIpcGetConfigValues(configList);
|
||||
if (R_FAILED(rc)) [[unlikely]] {
|
||||
FatalGui::openWithResultCode("sysclkIpcGetConfigValues", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
ValueThresholds thresholdsDisabled(0, 0);
|
||||
std::vector<NamedValue> noNamedValues = {};
|
||||
|
||||
this->listElement->addItem(new tsl::elm::CategoryHeader("Settings"));
|
||||
this->listElement->addItem(new tsl::elm::CategoryHeader("Hoc-clk Settings"));
|
||||
std::vector<NamedValue> ramVoltDispModes = {
|
||||
NamedValue("VDD2 + VDDQ", RamDisplayMode_VDD2VDDQ),
|
||||
NamedValue("VDD2 + Usage", RamDisplayMode_VDD2Usage),
|
||||
NamedValue("VDDQ + Usage", RamDisplayMode_VDDQUsage),
|
||||
};
|
||||
|
||||
addConfigToggle(HocClkConfigValue_UncappedClocks, nullptr);
|
||||
addConfigToggle(HocClkConfigValue_OverwriteBoostMode, nullptr);
|
||||
addConfigToggle(HocClkConfigValue_ThermalThrottle, nullptr);
|
||||
addConfigToggle(HocClkConfigValue_HandheldTDP, nullptr);
|
||||
// addConfigToggle(HocClkConfigValue_EnforceBoardLimit, nullptr);
|
||||
addConfigButton(HorizonOCConfigValue_RAMVoltUsageDisplayMode, "RAM Voltage Display Mode", ValueRange(0, 12, 1, "", 0), "RAM Voltage Display Mode", &thresholdsDisabled, {}, ramVoltDispModes, false);
|
||||
|
||||
#if IS_MINIMAL == 0
|
||||
std::map<uint32_t, std::string> labels_pwr_l = {
|
||||
{6400, "Official Rating"}
|
||||
};
|
||||
|
||||
if(IsHoag()) {
|
||||
ValueThresholds tdpThresholdsLite(6400, 7500);
|
||||
addConfigButton(
|
||||
HocClkConfigValue_LiteTDPLimit,
|
||||
"Lite TDP Threshold",
|
||||
ValueRange(4000, 8000, 100, "mW", 1),
|
||||
"Power",
|
||||
&tdpThresholdsLite,
|
||||
labels_pwr_l
|
||||
);
|
||||
} else {
|
||||
ValueThresholds tdpThresholds(9600, 11000);
|
||||
addConfigButton(
|
||||
HocClkConfigValue_HandheldTDPLimit,
|
||||
"TDP Threshold",
|
||||
ValueRange(8000, 12000, 100, "mW", 1),
|
||||
"Power",
|
||||
&tdpThresholds
|
||||
);
|
||||
tsl::elm::ListItem* safetySubmenu = new tsl::elm::ListItem("Safety Settings");
|
||||
safetySubmenu->setClickListener([](u64 keys) {
|
||||
if (keys & HidNpadButton_A) {
|
||||
tsl::changeTo<SafetySubMenuGui>();
|
||||
return true;
|
||||
}
|
||||
|
||||
ValueThresholds throttleThresholds(70, 80);
|
||||
addConfigButton(
|
||||
HocClkConfigValue_ThermalThrottleThreshold,
|
||||
"Thermal Throttle Limit",
|
||||
ValueRange(50, 85, 1, "°C", 1),
|
||||
"Temp",
|
||||
&throttleThresholds
|
||||
);
|
||||
#endif
|
||||
|
||||
if(IsMariko()) {
|
||||
addFreqButton(HocClkConfigValue_MarikoMaxCpuClock, nullptr, SysClkModule_CPU, cpu_freq_label_m);
|
||||
} else {
|
||||
addFreqButton(HocClkConfigValue_EristaMaxCpuClock, nullptr, SysClkModule_CPU, cpu_freq_label_e);
|
||||
}
|
||||
|
||||
if (IsMariko()) {
|
||||
std::vector<NamedValue> dvfsValues = {
|
||||
NamedValue("Disabled", DVFSMode_Disabled),
|
||||
NamedValue("PCV Hijack", DVFSMode_Hijack),
|
||||
// NamedValue("Official Service", DVFSMode_OfficialService),
|
||||
// NamedValue("Hack", DVFSMode_Hack),
|
||||
};
|
||||
|
||||
addConfigButton(
|
||||
HorizonOCConfigValue_DVFSMode,
|
||||
"GPU DVFS Mode",
|
||||
ValueRange(0, 0, 1, "", 0),
|
||||
"GPU DVFS Mode",
|
||||
&thresholdsDisabled,
|
||||
{},
|
||||
dvfsValues,
|
||||
false
|
||||
);
|
||||
|
||||
std::vector<NamedValue> dvfsOffset = {
|
||||
NamedValue("-50 mV", 0xFFFFFFCE),
|
||||
NamedValue("-45 mV", 0xFFFFFFD3),
|
||||
NamedValue("-40 mV", 0xFFFFFFD8),
|
||||
NamedValue("-30 mV", 0xFFFFFFE2),
|
||||
NamedValue("-25 mV", 0xFFFFFFE7),
|
||||
NamedValue("-20 mV", 0xFFFFFFEC),
|
||||
NamedValue("-10 mV", 0xFFFFFFF6),
|
||||
NamedValue(" -5 mV", 0xFFFFFFFB),
|
||||
NamedValue("Disabled", 0),
|
||||
NamedValue(" +5 mV", 5),
|
||||
NamedValue("+10 mV", 10),
|
||||
NamedValue("+15 mV", 15),
|
||||
NamedValue("+20 mV", 20),
|
||||
};
|
||||
|
||||
addConfigButton(HorizonOCConfigValue_DVFSOffset, "GPU DVFS Offset", ValueRange(0, 12, 1, "", 0), "GPU DVFS Offset", &thresholdsDisabled, {}, dvfsOffset, false);
|
||||
|
||||
}
|
||||
return false;
|
||||
});
|
||||
this->listElement->addItem(safetySubmenu);
|
||||
|
||||
this->listElement->addItem(new tsl::elm::CategoryHeader("KIP"));
|
||||
|
||||
@@ -377,6 +422,16 @@ void MiscGui::listUI()
|
||||
});
|
||||
this->listElement->addItem(gpuSubmenu);
|
||||
|
||||
this->listElement->addItem(new tsl::elm::CategoryHeader("Display"));
|
||||
tsl::elm::ListItem* displaySubMenu = new tsl::elm::ListItem("Display Settings");
|
||||
displaySubMenu->setClickListener([](u64 keys) {
|
||||
if (keys & HidNpadButton_A) {
|
||||
tsl::changeTo<DisplaySubMenuGui>();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
this->listElement->addItem(displaySubMenu);
|
||||
|
||||
#if IS_MINIMAL == 0
|
||||
// std::vector<NamedValue> chargerCurrents = {
|
||||
@@ -391,55 +446,96 @@ void MiscGui::listUI()
|
||||
// NamedValue("2816mA", 2816),
|
||||
// NamedValue("3072mA", 3072),
|
||||
// };
|
||||
this->listElement->addItem(new tsl::elm::CategoryHeader("Experimental"));
|
||||
if(this->configList->values[HorizonOCConfigValue_EnableExperimentalSettings]) {
|
||||
this->listElement->addItem(new tsl::elm::CategoryHeader("Experimental"));
|
||||
|
||||
std::vector<NamedValue> gpuSchedValues = {
|
||||
NamedValue("Do not override", GpuSchedulingMode_DoNotOverride),
|
||||
NamedValue("Enabled", GpuSchedulingMode_Enabled, "96.5% limit"),
|
||||
NamedValue("Disabled", GpuSchedulingMode_Disabled, "99.7% limit"),
|
||||
};
|
||||
tsl::elm::CustomDrawer* gpuSchedInfoText = new tsl::elm::CustomDrawer([](tsl::gfx::Renderer *renderer, s32 x, s32 y, s32 w, s32 h) {
|
||||
renderer->drawString("\uE150 This option requires a reboot", false, x + 20, y + 30, 18, tsl::style::color::ColorText);
|
||||
renderer->drawString("to take effect", false, x + 20, y + 50, 18, tsl::style::color::ColorText);
|
||||
});
|
||||
gpuSchedInfoText->setBoundaries(0, 0, tsl::cfg::FramebufferWidth, 70);
|
||||
this->listElement->addItem(gpuSchedInfoText);
|
||||
addConfigButton(
|
||||
HorizonOCConfigValue_GPUScheduling,
|
||||
"GPU Scheduling Override",
|
||||
ValueRange(0, 0, 1, "", 0),
|
||||
"GPU Scheduling Override",
|
||||
&thresholdsDisabled,
|
||||
{},
|
||||
gpuSchedValues,
|
||||
false
|
||||
);
|
||||
addConfigToggle(HorizonOCConfigValue_LiveCpuUv, nullptr);
|
||||
std::vector<NamedValue> gpuSchedMethodValues = {
|
||||
NamedValue("INI", GpuSchedulingOverrideMethod_Ini),
|
||||
NamedValue("NV Service", GpuSchedulingOverrideMethod_NvService),
|
||||
};
|
||||
addConfigButton(
|
||||
HorizonOCConfigValue_GPUSchedulingMethod,
|
||||
"GPU Scheduling Override Method",
|
||||
ValueRange(0, 0, 1, "", 0),
|
||||
"GPU Scheduling Override Method",
|
||||
&thresholdsDisabled,
|
||||
{},
|
||||
gpuSchedMethodValues,
|
||||
false
|
||||
);
|
||||
tsl::elm::CustomDrawer* chargeWarningText = new tsl::elm::CustomDrawer([](tsl::gfx::Renderer *renderer, s32 x, s32 y, s32 w, s32 h) {
|
||||
renderer->drawString("\uE150 Overriding the charge current", false, x + 20, y + 30, 18, tsl::style::color::ColorText);
|
||||
renderer->drawString("can be dangerous and may cause", false, x + 20, y + 50, 18, tsl::style::color::ColorText);
|
||||
renderer->drawString("damage to your battery or charger!", false, x + 20, y + 70, 18, tsl::style::color::ColorText);
|
||||
});
|
||||
chargeWarningText->setBoundaries(0, 0, tsl::cfg::FramebufferWidth, 90);
|
||||
this->listElement->addItem(chargeWarningText);
|
||||
|
||||
if(!IsHoag()) {
|
||||
std::vector<NamedValue> chargerCurrents = {
|
||||
NamedValue("Disabled", 0),
|
||||
NamedValue("1024mA", 1024),
|
||||
NamedValue("1280mA", 1280),
|
||||
NamedValue("1536mA", 1536),
|
||||
NamedValue("1792mA", 1792),
|
||||
NamedValue("2048mA", 2048),
|
||||
NamedValue("2304mA", 2304),
|
||||
NamedValue("2560mA", 2560),
|
||||
NamedValue("2816mA", 2816),
|
||||
NamedValue("3072mA", 3072),
|
||||
};
|
||||
|
||||
ValueThresholds chargerThresholds(2048, 2049);
|
||||
|
||||
addConfigButton(
|
||||
HorizonOCConfigValue_BatteryChargeCurrent,
|
||||
"Charge Current Override",
|
||||
ValueRange(0, 0, 1, "", 0),
|
||||
"Charge Current Override",
|
||||
&chargerThresholds,
|
||||
{},
|
||||
chargerCurrents,
|
||||
false
|
||||
);
|
||||
}
|
||||
else {
|
||||
std::vector<NamedValue> chargerCurrents = {
|
||||
NamedValue("Disabled", 0),
|
||||
NamedValue("1024mA", 1024),
|
||||
NamedValue("1280mA", 1280),
|
||||
NamedValue("1536mA", 1536),
|
||||
NamedValue("1792mA", 1792),
|
||||
NamedValue("2048mA", 2048),
|
||||
NamedValue("2304mA", 2304),
|
||||
NamedValue("2560mA", 2560),
|
||||
};
|
||||
|
||||
ValueThresholds chargerThresholds(1792, 1793);
|
||||
|
||||
addConfigButton(
|
||||
HorizonOCConfigValue_BatteryChargeCurrent,
|
||||
"Charge Current Override",
|
||||
ValueRange(0, 0, 1, "", 0),
|
||||
"Charge Current Override",
|
||||
&chargerThresholds,
|
||||
{},
|
||||
chargerCurrents,
|
||||
false
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
class DisplaySubMenuGui : public MiscGui {
|
||||
public:
|
||||
DisplaySubMenuGui() { }
|
||||
|
||||
protected:
|
||||
void listUI() override {
|
||||
if(!IsHoag()) {
|
||||
// std::vector<NamedValue> chargerCurrents = {
|
||||
// NamedValue("Disabled", 0),
|
||||
// NamedValue("1024mA", 1024),
|
||||
// NamedValue("1280mA", 1280),
|
||||
// NamedValue("1536mA", 1536),
|
||||
// NamedValue("1792mA", 1792),
|
||||
// NamedValue("2048mA", 2048),
|
||||
// NamedValue("2304mA", 2304),
|
||||
// NamedValue("2560mA", 2560),
|
||||
// NamedValue("2816mA", 2816),
|
||||
// NamedValue("3072mA", 3072),
|
||||
// };
|
||||
|
||||
// ValueThresholds chargerThresholds(2048, 2560);
|
||||
|
||||
// addConfigButton(
|
||||
// HorizonOCConfigValue_BatteryChargeCurrent,
|
||||
// "Charge Current Override",
|
||||
// ValueRange(0, 0, 1, "", 0),
|
||||
// "Charge Current Override",
|
||||
// &chargerThresholds,
|
||||
// {},
|
||||
// chargerCurrents,
|
||||
// false
|
||||
// );
|
||||
addConfigToggle(HorizonOCConfigValue_OverwriteRefreshRate, nullptr);
|
||||
tsl::elm::CustomDrawer* warningText = new tsl::elm::CustomDrawer([](tsl::gfx::Renderer *renderer, s32 x, s32 y, s32 w, s32 h) {
|
||||
renderer->drawString("\uE150 Enabling unsafe display", false, x + 20, y + 30, 18, tsl::style::color::ColorText);
|
||||
@@ -451,36 +547,57 @@ void MiscGui::listUI()
|
||||
this->listElement->addItem(warningText);
|
||||
addConfigToggle(HorizonOCConfigValue_EnableUnsafeDisplayFreqs, nullptr);
|
||||
}
|
||||
// else {
|
||||
// std::vector<NamedValue> chargerCurrents = {
|
||||
// NamedValue("Disabled", 0),
|
||||
// NamedValue("1024mA", 1024),
|
||||
// NamedValue("1280mA", 1280),
|
||||
// NamedValue("1536mA", 1536),
|
||||
// NamedValue("1792mA", 1792),
|
||||
// NamedValue("2048mA", 2048),
|
||||
// NamedValue("2304mA", 2304),
|
||||
// NamedValue("2560mA", 2560),
|
||||
// };
|
||||
}
|
||||
};
|
||||
|
||||
// ValueThresholds chargerThresholds(1792, 2048);
|
||||
class SafetySubMenuGui : public MiscGui {
|
||||
public:
|
||||
SafetySubMenuGui() { }
|
||||
|
||||
// addConfigButton(
|
||||
// HorizonOCConfigValue_BatteryChargeCurrent,
|
||||
// "Charge Current Override",
|
||||
// ValueRange(0, 0, 1, "", 0),
|
||||
// "Charge Current Override",
|
||||
// &chargerThresholds,
|
||||
// {},
|
||||
// chargerCurrents,
|
||||
// false
|
||||
// );
|
||||
protected:
|
||||
void listUI() override {
|
||||
this->listElement->addItem(new tsl::elm::CategoryHeader("Safety Settings"));
|
||||
addConfigToggle(HocClkConfigValue_UncappedClocks, nullptr);
|
||||
addConfigToggle(HocClkConfigValue_ThermalThrottle, nullptr);
|
||||
addConfigToggle(HocClkConfigValue_HandheldTDP, nullptr);
|
||||
|
||||
// }
|
||||
#endif
|
||||
#if IS_MINIMAL == 0
|
||||
std::map<uint32_t, std::string> labels_pwr_l = {
|
||||
{6400, "Official Rating"}
|
||||
};
|
||||
|
||||
}
|
||||
if(IsHoag()) {
|
||||
ValueThresholds tdpThresholdsLite(6400, 7500);
|
||||
addConfigButton(
|
||||
HocClkConfigValue_LiteTDPLimit,
|
||||
"Lite TDP Threshold",
|
||||
ValueRange(4000, 8000, 100, "mW", 1),
|
||||
"Power",
|
||||
&tdpThresholdsLite,
|
||||
labels_pwr_l
|
||||
);
|
||||
} else {
|
||||
ValueThresholds tdpThresholds(9600, 11000);
|
||||
addConfigButton(
|
||||
HocClkConfigValue_HandheldTDPLimit,
|
||||
"TDP Threshold",
|
||||
ValueRange(8000, 12000, 100, "mW", 1),
|
||||
"Power",
|
||||
&tdpThresholds
|
||||
);
|
||||
}
|
||||
|
||||
ValueThresholds throttleThresholds(70, 80);
|
||||
addConfigButton(
|
||||
HocClkConfigValue_ThermalThrottleThreshold,
|
||||
"Thermal Throttle Limit",
|
||||
ValueRange(50, 85, 1, "°C", 1),
|
||||
"Temp",
|
||||
&throttleThresholds
|
||||
);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
class RamSubmenuGui : public MiscGui {
|
||||
public:
|
||||
@@ -495,127 +612,6 @@ protected:
|
||||
|
||||
addConfigToggle(KipConfigValue_hpMode, "HP Mode");
|
||||
|
||||
ValueThresholds eristaRamThresholds(2208000, 2304000);
|
||||
|
||||
std::vector<NamedValue> marikoMaxEmcClock = {
|
||||
NamedValue("1600MHz", 1600000, "JEDEC."),
|
||||
NamedValue("1633MHz", 1633000),
|
||||
NamedValue("1666MHz", 1666000),
|
||||
NamedValue("1700MHz", 1700000),
|
||||
NamedValue("1733MHz", 1733000),
|
||||
NamedValue("1766MHz", 1766000),
|
||||
NamedValue("1800MHz", 1800000),
|
||||
NamedValue("1833MHz", 1833000),
|
||||
NamedValue("1866MHz", 1866000, "JEDEC."),
|
||||
NamedValue("1900MHz", 1900000),
|
||||
NamedValue("1933MHz", 1933000),
|
||||
NamedValue("1966MHz", 1966000),
|
||||
NamedValue("1996MHz", 1996800, "JEDEC."),
|
||||
NamedValue("2000MHz", 2000000),
|
||||
NamedValue("2033MHz", 2033000),
|
||||
NamedValue("2066MHz", 2066000),
|
||||
NamedValue("2100MHz", 2100000),
|
||||
NamedValue("2133MHz", 2133000, "JEDEC."),
|
||||
NamedValue("2166MHz", 2166000),
|
||||
NamedValue("2200MHz", 2200000),
|
||||
NamedValue("2233MHz", 2233000),
|
||||
NamedValue("2266MHz", 2266000),
|
||||
NamedValue("2300MHz", 2300000),
|
||||
NamedValue("2333MHz", 2333000),
|
||||
NamedValue("2366MHz", 2366000),
|
||||
NamedValue("2400MHz", 2400000, "JEDEC."),
|
||||
NamedValue("2433MHz", 2433000),
|
||||
NamedValue("2466MHz", 2466000),
|
||||
NamedValue("2500MHz", 2500000),
|
||||
NamedValue("2533MHz", 2533000),
|
||||
NamedValue("2566MHz", 2566000),
|
||||
NamedValue("2600MHz", 2600000),
|
||||
NamedValue("2633MHz", 2633000),
|
||||
NamedValue("2666MHz", 2666000, "JEDEC."),
|
||||
NamedValue("2700MHz", 2700000),
|
||||
NamedValue("2733MHz", 2733000),
|
||||
NamedValue("2766MHz", 2766000),
|
||||
NamedValue("2800MHz", 2800000),
|
||||
NamedValue("2833MHz", 2833000),
|
||||
NamedValue("2866MHz", 2866000),
|
||||
NamedValue("2900MHz", 2900000),
|
||||
NamedValue("2933MHz", 2933000, "JEDEC."),
|
||||
NamedValue("2966MHz", 2966000),
|
||||
NamedValue("3000MHz", 3000000),
|
||||
NamedValue("3033MHz", 3033000),
|
||||
NamedValue("3066MHz", 3066000),
|
||||
NamedValue("3100MHz", 3100000),
|
||||
NamedValue("3133MHz", 3133000),
|
||||
NamedValue("3166MHz", 3166000),
|
||||
NamedValue("3200MHz", 3200000, "JEDEC."),
|
||||
NamedValue("3233MHz", 3233000, "High speedo needed!"),
|
||||
NamedValue("3266MHz", 3266000, "High speedo needed!"),
|
||||
NamedValue("3300MHz", 3300000, "High speedo needed!"),
|
||||
// NamedValue("3333MHz (Needs extreme Speedo/PLL)", 3333000),
|
||||
// NamedValue("3366MHz (Needs extreme Speedo/PLL)", 3366000),
|
||||
// NamedValue("3400MHz (Needs extreme Speedo/PLL)", 3400000),
|
||||
// NamedValue("3433MHz (Needs ridiculous Speedo/PLL)", 3433000),
|
||||
// NamedValue("3466MHz (Needs ridiculous Speedo/PLL)", 3466000),
|
||||
// NamedValue("3500MHz (Needs ridiculous Speedo/PLL)", 3500000),
|
||||
};
|
||||
|
||||
std::vector<NamedValue> eristaMaxEmcClock = {
|
||||
NamedValue("1600MHz", 1600000, "JEDEC."),
|
||||
NamedValue("1633MHz", 1633000),
|
||||
NamedValue("1666MHz", 1666000),
|
||||
NamedValue("1700MHz", 1700000),
|
||||
NamedValue("1733MHz", 1733000),
|
||||
NamedValue("1766MHz", 1766000),
|
||||
NamedValue("1800MHz", 1800000),
|
||||
NamedValue("1833MHz", 1833000),
|
||||
NamedValue("1862MHz", 1862400, "JEDEC."),
|
||||
NamedValue("1881MHz", 1881600),
|
||||
NamedValue("1900MHz", 1900800),
|
||||
NamedValue("1920MHz", 1920000),
|
||||
NamedValue("1939MHz", 1939200),
|
||||
NamedValue("1958MHz", 1958400),
|
||||
NamedValue("1977MHz", 1977600),
|
||||
NamedValue("1996MHz", 1996800, "JEDEC."),
|
||||
NamedValue("2016MHz", 2016000),
|
||||
NamedValue("2035MHz", 2035200),
|
||||
NamedValue("2054MHz", 2054400),
|
||||
NamedValue("2073MHz", 2073600),
|
||||
NamedValue("2092MHz", 2092800),
|
||||
NamedValue("2112MHz", 2112000),
|
||||
NamedValue("2131MHz", 2131200, "JEDEC."),
|
||||
NamedValue("2150MHz", 2150400),
|
||||
NamedValue("2169MHz", 2169600),
|
||||
NamedValue("2188MHz", 2188800),
|
||||
NamedValue("2208MHz", 2208000),
|
||||
NamedValue("2227MHz", 2227200),
|
||||
NamedValue("2246MHz", 2246400),
|
||||
NamedValue("2265MHz", 2265600),
|
||||
NamedValue("2284MHz", 2284800),
|
||||
NamedValue("2304MHz", 2304000),
|
||||
NamedValue("2323MHz", 2323200),
|
||||
NamedValue("2342MHz", 2342400),
|
||||
NamedValue("2361MHz", 2361600),
|
||||
NamedValue("2380MHz", 2380800),
|
||||
NamedValue("2400MHz", 2400000, "JEDEC."),
|
||||
};
|
||||
|
||||
if(IsErista()) {
|
||||
addConfigButton(KipConfigValue_eristaEmcMaxClock, "RAM Max Clock", ValueRange(0, 1, 1, "", 1), "RAM Max Clock", &eristaRamThresholds, {}, eristaMaxEmcClock, false);
|
||||
addConfigButton(KipConfigValue_eristaEmcMaxClock1, "RAM Max Clock", ValueRange(0, 1, 1, "", 1), "RAM Max Clock", &eristaRamThresholds, {}, eristaMaxEmcClock, false);
|
||||
addConfigButton(KipConfigValue_eristaEmcMaxClock2, "RAM Max Clock", ValueRange(0, 1, 1, "", 1), "RAM Max Clock", &eristaRamThresholds, {}, eristaMaxEmcClock, false);
|
||||
} else {
|
||||
addConfigButton(
|
||||
KipConfigValue_marikoEmcMaxClock,
|
||||
"RAM Max Clock",
|
||||
ValueRange(0, 1, 1, "", 1),
|
||||
"RAM Max Clock",
|
||||
&thresholdsDisabled,
|
||||
{},
|
||||
marikoMaxEmcClock,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
std::map<uint32_t, std::string> emc_voltage_label = {
|
||||
{1100000, "Default (Mariko)"},
|
||||
{1125000, "Default (Erista)"},
|
||||
@@ -661,6 +657,26 @@ protected:
|
||||
false
|
||||
);
|
||||
|
||||
tsl::elm::ListItem* freqSubmenu = new tsl::elm::ListItem("RAM Frequency Editor");
|
||||
freqSubmenu->setClickListener([](u64 keys) {
|
||||
if (keys & HidNpadButton_A) {
|
||||
tsl::changeTo<RamTableEditor>();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
this->listElement->addItem(freqSubmenu);
|
||||
|
||||
tsl::elm::ListItem* latenciesSubmenu = new tsl::elm::ListItem("RAM Latency Editor");
|
||||
latenciesSubmenu->setClickListener([](u64 keys) {
|
||||
if (keys & HidNpadButton_A) {
|
||||
tsl::changeTo<RamLatenciesSubmenuGui>();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
this->listElement->addItem(latenciesSubmenu);
|
||||
|
||||
tsl::elm::ListItem* timingsSubmenu = new tsl::elm::ListItem("RAM Timing Reductions");
|
||||
timingsSubmenu->setClickListener([](u64 keys) {
|
||||
if (keys & HidNpadButton_A) {
|
||||
@@ -671,15 +687,6 @@ protected:
|
||||
});
|
||||
this->listElement->addItem(timingsSubmenu);
|
||||
|
||||
tsl::elm::ListItem* latenciesSubmenu = new tsl::elm::ListItem("RAM Latencies");
|
||||
latenciesSubmenu->setClickListener([](u64 keys) {
|
||||
if (keys & HidNpadButton_A) {
|
||||
tsl::changeTo<RamLatenciesSubmenuGui>();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
this->listElement->addItem(latenciesSubmenu);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -785,8 +792,6 @@ protected:
|
||||
this->listElement->addItem(new tsl::elm::CategoryHeader("CPU Settings"));
|
||||
if(IsMariko()) {
|
||||
std::vector<NamedValue> ClkOptions = {
|
||||
NamedValue("1785 MHz", 1785000),
|
||||
NamedValue("1887 MHz", 1887000),
|
||||
NamedValue("1963 MHz", 1963000),
|
||||
NamedValue("2091 MHz", 2091000),
|
||||
NamedValue("2193 MHz", 2193000),
|
||||
@@ -815,6 +820,7 @@ protected:
|
||||
NamedValue("2091 MHz", 2091000),
|
||||
NamedValue("2193 MHz", 2193000),
|
||||
NamedValue("2295 MHz", 2295000),
|
||||
NamedValue("2397 MHz", 2295000),
|
||||
};
|
||||
ValueThresholds eCpuClockThresholds(1785000, 2091000);
|
||||
addConfigButton(
|
||||
@@ -851,16 +857,39 @@ protected:
|
||||
{},
|
||||
false
|
||||
);
|
||||
|
||||
ValueThresholds eCpuVoltThresholds(1235, 1260);
|
||||
addConfigButton(
|
||||
KipConfigValue_eristaCpuMaxVolt,
|
||||
"CPU Max Voltage",
|
||||
ValueRange(1120, 1235, 5, "mV", 1),
|
||||
ValueRange(1120, 1260, 5, "mV", 1),
|
||||
"CPU Max Voltage",
|
||||
&thresholdsDisabled,
|
||||
&eCpuVoltThresholds,
|
||||
{},
|
||||
{},
|
||||
false
|
||||
);
|
||||
|
||||
std::vector<NamedValue> maxClkOptions = {
|
||||
NamedValue("1785 MHz", 1785),
|
||||
NamedValue("1887 MHz", 1887),
|
||||
NamedValue("1963 MHz", 1963),
|
||||
NamedValue("2091 MHz", 2091),
|
||||
NamedValue("2193 MHz", 2193),
|
||||
NamedValue("2295 MHz", 2295),
|
||||
NamedValue("2397 MHz", 2397),
|
||||
};
|
||||
ValueThresholds eCpuMaxClockThresholds(1785, 2091);
|
||||
addConfigButton(
|
||||
HocClkConfigValue_EristaMaxCpuClock,
|
||||
"CPU Max Clock",
|
||||
ValueRange(0, 0, 1, "", 1),
|
||||
"CPU Max Clock",
|
||||
&eCpuMaxClockThresholds,
|
||||
{},
|
||||
maxClkOptions,
|
||||
false
|
||||
);
|
||||
} else {
|
||||
std::vector<NamedValue> marikoTableConf = {
|
||||
// NamedValue("Auto", 0),
|
||||
@@ -951,17 +980,172 @@ protected:
|
||||
addConfigButton(
|
||||
KipConfigValue_marikoCpuMaxVolt,
|
||||
"CPU Max Voltage",
|
||||
ValueRange(1000, 1235, 5, "mV", 1),
|
||||
ValueRange(1000, 1200, 5, "mV", 1),
|
||||
"CPU Max Voltage",
|
||||
&mCpuVoltThresholds,
|
||||
{},
|
||||
{},
|
||||
false
|
||||
);
|
||||
|
||||
addConfigToggle(HocClkConfigValue_OverwriteBoostMode, nullptr);
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class RamTableEditor : public MiscGui {
|
||||
public:
|
||||
RamTableEditor() { }
|
||||
|
||||
protected:
|
||||
void listUI() override {
|
||||
this->listElement->addItem(new tsl::elm::CategoryHeader("RAM Frequency Editor"));
|
||||
|
||||
ValueThresholds thresholdsDisabled(0, 0);
|
||||
if(IsMariko()) {
|
||||
tsl::elm::ListItem* ramItem1600 = new tsl::elm::ListItem("1600 MHz");
|
||||
this->listElement->addItem(ramItem1600);
|
||||
|
||||
std::vector<NamedValue> marikoMaxEmcClock = {
|
||||
NamedValue("Disabled", 1600000),
|
||||
NamedValue("1633 MHz", 1633000),
|
||||
NamedValue("1666 MHz", 1666000),
|
||||
NamedValue("1700 MHz", 1700000),
|
||||
NamedValue("1733 MHz", 1733000),
|
||||
NamedValue("1766 MHz", 1766000),
|
||||
NamedValue("1800 MHz", 1800000),
|
||||
NamedValue("1833 MHz", 1833000),
|
||||
NamedValue("1866 MHz", 1866000, "JEDEC."),
|
||||
NamedValue("1900 MHz", 1900000),
|
||||
NamedValue("1933 MHz", 1933000),
|
||||
NamedValue("1966 MHz", 1966000),
|
||||
NamedValue("1996 MHz", 1996800, "JEDEC."),
|
||||
NamedValue("2000 MHz", 2000000),
|
||||
NamedValue("2033 MHz", 2033000),
|
||||
NamedValue("2066 MHz", 2066000),
|
||||
NamedValue("2100 MHz", 2100000),
|
||||
NamedValue("2133 MHz", 2133000, "JEDEC."),
|
||||
NamedValue("2166 MHz", 2166000),
|
||||
NamedValue("2200 MHz", 2200000),
|
||||
NamedValue("2233 MHz", 2233000),
|
||||
NamedValue("2266 MHz", 2266000),
|
||||
NamedValue("2300 MHz", 2300000),
|
||||
NamedValue("2333 MHz", 2333000),
|
||||
NamedValue("2366 MHz", 2366000),
|
||||
NamedValue("2400 MHz", 2400000, "JEDEC."),
|
||||
NamedValue("2433 MHz", 2433000),
|
||||
NamedValue("2466 MHz", 2466000),
|
||||
NamedValue("2500 MHz", 2500000),
|
||||
NamedValue("2533 MHz", 2533000),
|
||||
NamedValue("2566 MHz", 2566000),
|
||||
NamedValue("2600 MHz", 2600000),
|
||||
NamedValue("2633 MHz", 2633000),
|
||||
NamedValue("2666 MHz", 2666000, "JEDEC."),
|
||||
NamedValue("2700 MHz", 2700000),
|
||||
NamedValue("2733 MHz", 2733000),
|
||||
NamedValue("2766 MHz", 2766000),
|
||||
NamedValue("2800 MHz", 2800000),
|
||||
NamedValue("2833 MHz", 2833000),
|
||||
NamedValue("2866 MHz", 2866000),
|
||||
NamedValue("2900 MHz", 2900000),
|
||||
NamedValue("2933 MHz", 2933000, "JEDEC."),
|
||||
NamedValue("2966 MHz", 2966000),
|
||||
NamedValue("3000 MHz", 3000000),
|
||||
NamedValue("3033 MHz", 3033000),
|
||||
NamedValue("3066 MHz", 3066000),
|
||||
NamedValue("3100 MHz", 3100000),
|
||||
NamedValue("3133 MHz", 3133000),
|
||||
NamedValue("3166 MHz", 3166000),
|
||||
NamedValue("3200 MHz", 3200000, "JEDEC."),
|
||||
NamedValue("3233 MHz", 3233000, "High speedo needed!"),
|
||||
NamedValue("3266 MHz", 3266000, "High speedo needed!"),
|
||||
NamedValue("3300 MHz", 3300000, "High speedo needed!"),
|
||||
// NamedValue("3333MHz (Needs extreme Speedo/PLL)", 3333000),
|
||||
// NamedValue("3366MHz (Needs extreme Speedo/PLL)", 3366000),
|
||||
// NamedValue("3400MHz (Needs extreme Speedo/PLL)", 3400000),
|
||||
// NamedValue("3433MHz (Needs ridiculous Speedo/PLL)", 3433000),
|
||||
// NamedValue("3466MHz (Needs ridiculous Speedo/PLL)", 3466000),
|
||||
// NamedValue("3500MHz (Needs ridiculous Speedo/PLL)", 3500000),
|
||||
};
|
||||
addConfigButtonS(
|
||||
KipConfigValue_marikoEmcMaxClock,
|
||||
"",
|
||||
ValueRange(0, 1, 1, "", 1),
|
||||
"",
|
||||
&thresholdsDisabled,
|
||||
{},
|
||||
marikoMaxEmcClock,
|
||||
false,
|
||||
"\ue0e0"
|
||||
);
|
||||
} else {
|
||||
// 1600000, 1331200, 1065600, 800000, 665600, 408000, 204000
|
||||
|
||||
tsl::elm::ListItem* ramItem665 = new tsl::elm::ListItem("665 MHz");
|
||||
this->listElement->addItem(ramItem665);
|
||||
|
||||
tsl::elm::ListItem* ramItem800 = new tsl::elm::ListItem("800 MHz");
|
||||
this->listElement->addItem(ramItem800);
|
||||
|
||||
tsl::elm::ListItem* ramItem1065 = new tsl::elm::ListItem("1065 MHz");
|
||||
this->listElement->addItem(ramItem1065);
|
||||
|
||||
tsl::elm::ListItem* ramItem1331 = new tsl::elm::ListItem("1331 MHz");
|
||||
this->listElement->addItem(ramItem1331);
|
||||
|
||||
tsl::elm::ListItem* ramItem1600 = new tsl::elm::ListItem("1600 MHz");
|
||||
this->listElement->addItem(ramItem1600);
|
||||
|
||||
ValueThresholds eristaRamThresholds(2208000, 2304000);
|
||||
|
||||
std::vector<NamedValue> eristaMaxEmcClock = {
|
||||
NamedValue("Disabled", 1600000),
|
||||
NamedValue("1633 MHz", 1633000),
|
||||
NamedValue("1666 MHz", 1666000),
|
||||
NamedValue("1700 MHz", 1700000),
|
||||
NamedValue("1733 MHz", 1733000),
|
||||
NamedValue("1766 MHz", 1766000),
|
||||
NamedValue("1800 MHz", 1800000),
|
||||
NamedValue("1833 MHz", 1833000),
|
||||
NamedValue("1862 MHz", 1862400, "JEDEC."),
|
||||
NamedValue("1881 MHz", 1881600),
|
||||
NamedValue("1900 MHz", 1900800),
|
||||
NamedValue("1920 MHz", 1920000),
|
||||
NamedValue("1939 MHz", 1939200),
|
||||
NamedValue("1958 MHz", 1958400),
|
||||
NamedValue("1977 MHz", 1977600),
|
||||
NamedValue("1996 MHz", 1996800, "JEDEC."),
|
||||
NamedValue("2016 MHz", 2016000),
|
||||
NamedValue("2035 MHz", 2035200),
|
||||
NamedValue("2054 MHz", 2054400),
|
||||
NamedValue("2073 MHz", 2073600),
|
||||
NamedValue("2092 MHz", 2092800),
|
||||
NamedValue("2112 MHz", 2112000),
|
||||
NamedValue("2131 MHz", 2131200, "JEDEC."),
|
||||
NamedValue("2150 MHz", 2150400),
|
||||
NamedValue("2169 MHz", 2169600),
|
||||
NamedValue("2188 MHz", 2188800),
|
||||
NamedValue("2208 MHz", 2208000),
|
||||
NamedValue("2227 MHz", 2227200),
|
||||
NamedValue("2246 MHz", 2246400),
|
||||
NamedValue("2265 MHz", 2265600),
|
||||
NamedValue("2284 MHz", 2284800),
|
||||
NamedValue("2304 MHz", 2304000),
|
||||
NamedValue("2323 MHz", 2323200),
|
||||
NamedValue("2342 MHz", 2342400),
|
||||
NamedValue("2361 MHz", 2361600),
|
||||
NamedValue("2380 MHz", 2380800),
|
||||
NamedValue("2400 MHz", 2400000, "JEDEC."),
|
||||
};
|
||||
|
||||
addConfigButtonS(KipConfigValue_eristaEmcMaxClock, "", ValueRange(0, 1, 1, "", 1), "", &eristaRamThresholds, {}, eristaMaxEmcClock, false, "\ue0e0");
|
||||
addConfigButtonS(KipConfigValue_eristaEmcMaxClock1, "", ValueRange(0, 1, 1, "", 1), "", &eristaRamThresholds, {}, eristaMaxEmcClock, false, "\ue0e0");
|
||||
addConfigButtonS(KipConfigValue_eristaEmcMaxClock2, "", ValueRange(0, 1, 1, "", 1), "", &eristaRamThresholds, {}, eristaMaxEmcClock, false, "\ue0e0");
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
class GpuSubmenuGui : public MiscGui {
|
||||
public:
|
||||
GpuSubmenuGui() { }
|
||||
@@ -1076,6 +1260,66 @@ protected:
|
||||
false
|
||||
);
|
||||
|
||||
std::vector<NamedValue> gpuSchedValues = {
|
||||
NamedValue("Do not override", GpuSchedulingMode_DoNotOverride),
|
||||
NamedValue("Enabled (Default)", GpuSchedulingMode_Enabled, "96.6% limit"),
|
||||
NamedValue("Disabled", GpuSchedulingMode_Disabled, "99.7% limit"),
|
||||
};
|
||||
|
||||
addConfigButton(
|
||||
HorizonOCConfigValue_GPUScheduling,
|
||||
"GPU Scheduling Override",
|
||||
ValueRange(0, 0, 1, "", 0),
|
||||
"GPU Scheduling Override",
|
||||
&thresholdsDisabled,
|
||||
{},
|
||||
gpuSchedValues,
|
||||
false
|
||||
);
|
||||
|
||||
if (IsMariko()) {
|
||||
std::vector<NamedValue> dvfsOffset = {
|
||||
NamedValue("-80 mV", 0xFFFFFFB0),
|
||||
NamedValue("-75 mV", 0xFFFFFFB5),
|
||||
NamedValue("-70 mV", 0xFFFFFFBA),
|
||||
NamedValue("-65 mV", 0xFFFFFFBF),
|
||||
NamedValue("-60 mV", 0xFFFFFFC4),
|
||||
NamedValue("-55 mV", 0xFFFFFFC9),
|
||||
NamedValue("-50 mV", 0xFFFFFFCE),
|
||||
NamedValue("-45 mV", 0xFFFFFFD3),
|
||||
NamedValue("-40 mV", 0xFFFFFFD8),
|
||||
NamedValue("-30 mV", 0xFFFFFFE2),
|
||||
NamedValue("-25 mV", 0xFFFFFFE7),
|
||||
NamedValue("-20 mV", 0xFFFFFFEC),
|
||||
NamedValue("-10 mV", 0xFFFFFFF6),
|
||||
NamedValue(" -5 mV", 0xFFFFFFFB),
|
||||
NamedValue("Disabled", 0),
|
||||
NamedValue(" +5 mV", 5),
|
||||
NamedValue("+10 mV", 10),
|
||||
NamedValue("+15 mV", 15),
|
||||
NamedValue("+20 mV", 20),
|
||||
};
|
||||
|
||||
std::vector<NamedValue> dvfsValues = {
|
||||
NamedValue("Disabled", DVFSMode_Disabled),
|
||||
NamedValue("PCV Hijack", DVFSMode_Hijack),
|
||||
// NamedValue("Official Service", DVFSMode_OfficialService),
|
||||
};
|
||||
|
||||
addConfigButton(
|
||||
HorizonOCConfigValue_DVFSMode,
|
||||
"GPU DVFS Mode",
|
||||
ValueRange(0, 0, 1, "", 0),
|
||||
"GPU DVFS Mode",
|
||||
&thresholdsDisabled,
|
||||
{},
|
||||
dvfsValues,
|
||||
false
|
||||
);
|
||||
|
||||
addConfigButton(HorizonOCConfigValue_DVFSOffset, "GPU DVFS Offset", ValueRange(0, 12, 1, "", 0), "GPU DVFS Offset", &thresholdsDisabled, {}, dvfsOffset, false);
|
||||
}
|
||||
|
||||
tsl::elm::ListItem* customTableSubmenu = new tsl::elm::ListItem("GPU Voltage Table");
|
||||
customTableSubmenu->setClickListener([](u64 keys) {
|
||||
if (keys & HidNpadButton_A) {
|
||||
@@ -1384,7 +1628,16 @@ void MiscGui::refresh() {
|
||||
}
|
||||
}
|
||||
|
||||
button->setValue(valueText);
|
||||
if (this->configButtonSKeys.count(configVal)) {
|
||||
button->setText(valueText);
|
||||
auto subtextIt = this->configButtonSSubtext.find(configVal);
|
||||
if (subtextIt != this->configButtonSSubtext.end())
|
||||
button->setValue(subtextIt->second);
|
||||
else
|
||||
button->setValue("");
|
||||
} else {
|
||||
button->setValue(valueText);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -30,7 +30,8 @@ ValueChoiceGui::ValueChoiceGui(std::uint32_t selectedValue,
|
||||
bool enableThresholds,
|
||||
std::map<std::uint32_t, std::string> labels,
|
||||
std::vector<NamedValue> namedValues,
|
||||
bool showDefaultValue)
|
||||
bool showDefaultValue,
|
||||
bool showDNO)
|
||||
: selectedValue(selectedValue),
|
||||
range(range),
|
||||
categoryName(categoryName),
|
||||
@@ -39,7 +40,8 @@ ValueChoiceGui::ValueChoiceGui(std::uint32_t selectedValue,
|
||||
enableThresholds(enableThresholds),
|
||||
labels(labels),
|
||||
namedValues(namedValues),
|
||||
showDefaultValue(showDefaultValue)
|
||||
showDefaultValue(showDefaultValue),
|
||||
showDNO(showDNO)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -52,7 +54,7 @@ std::string ValueChoiceGui::formatValue(std::uint32_t value)
|
||||
std::ostringstream oss;
|
||||
if(showDefaultValue) {
|
||||
if (value == 0) {
|
||||
return VALUE_DEFAULT_TEXT;
|
||||
return this->showDNO ? FREQ_DEFAULT_TEXT : VALUE_DEFAULT_TEXT;
|
||||
}
|
||||
}
|
||||
double displayValue = static_cast<double>(value) / static_cast<double>(range.divisor);
|
||||
@@ -164,17 +166,16 @@ void ValueChoiceGui::listUI()
|
||||
if (!categoryName.empty()) {
|
||||
this->listElement->addItem(new tsl::elm::CategoryHeader(categoryName));
|
||||
}
|
||||
|
||||
|
||||
if (showDefaultValue) {
|
||||
this->listElement->addItem(this->createValueListItem(0, this->selectedValue == 0, 0));
|
||||
}
|
||||
for (const auto& namedValue : namedValues) {
|
||||
int safety = enableThresholds ? getSafetyLevel(namedValue.value) : 0;
|
||||
bool selected = (namedValue.value == this->selectedValue);
|
||||
this->listElement->addItem(this->createNamedValueListItem(namedValue, selected, safety));
|
||||
}
|
||||
|
||||
if (showDefaultValue) {
|
||||
this->listElement->addItem(this->createValueListItem(0, this->selectedValue == 0, 0));
|
||||
}
|
||||
|
||||
if (namedValues.empty()) {
|
||||
for (std::uint32_t value = range.min; value <= range.max; value += range.step)
|
||||
{
|
||||
|
||||
@@ -71,7 +71,7 @@ protected:
|
||||
|
||||
std::vector<NamedValue> namedValues;
|
||||
bool showDefaultValue = true;
|
||||
|
||||
bool showDNO = false;
|
||||
tsl::elm::ListItem* createValueListItem(std::uint32_t value, bool selected, int safety);
|
||||
tsl::elm::ListItem* createNamedValueListItem(const NamedValue& namedValue, bool selected, int safety);
|
||||
std::string formatValue(std::uint32_t value);
|
||||
@@ -86,7 +86,8 @@ public:
|
||||
bool enableThresholds = false,
|
||||
std::map<std::uint32_t, std::string> labels = {},
|
||||
std::vector<NamedValue> namedValues = {},
|
||||
bool showDefaultValue = true);
|
||||
bool showDefaultValue = true,
|
||||
bool showDNO = false);
|
||||
~ValueChoiceGui();
|
||||
|
||||
void addNamedValue(const std::string& name, std::uint32_t value, const std::string& rightText = "")
|
||||
|
||||
@@ -57,6 +57,15 @@
|
||||
"is_io": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "map",
|
||||
"value": {
|
||||
"address": "0x70110000",
|
||||
"size": "0x1000",
|
||||
"is_ro": false,
|
||||
"is_io": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "syscalls",
|
||||
"value": {
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include <registers.h>
|
||||
#include <notification.h>
|
||||
#include <memmem.h>
|
||||
#include <minIni.h>
|
||||
|
||||
#define MAX(A, B) std::max(A, B)
|
||||
#define MIN(A, B) std::min(A, B)
|
||||
@@ -105,6 +106,8 @@ u16 cpuSpeedo0, cpuSpeedo2, socSpeedo0; // CPU, GPU, SOC
|
||||
u32 speedoBracket;
|
||||
u16 cpuIDDQ, gpuIDDQ, socIDDQ;
|
||||
u8 g_dramID = 0;
|
||||
u64 cldvfs, cldvfs_temp;
|
||||
u32 cachedEristaUvLowTune0 = 0, cachedEristaUvLowTune1 = 0, cachedMarikoUvHighTune0 = 0;
|
||||
|
||||
static const u32 ramBrackets[][22] = {
|
||||
{ 2133, 2200, 2266, 2300, 2366, 2400, 2433, 2466, 2533, 2566, 2600, 2633, 2700, 2733, 2766, 2833, 2866, 2900, 2933, 3033, 3066, 3100, },
|
||||
@@ -290,6 +293,16 @@ void Board::Initialize()
|
||||
}
|
||||
|
||||
FetchHardwareInfos();
|
||||
rc = svcQueryMemoryMapping(&cldvfs, &cldvfs_temp, CLDVFS_REGION_BASE, CLDVFS_REGION_SIZE);
|
||||
ASSERT_RESULT_OK(rc, "svcQueryMemoryMapping (cldvfs)");
|
||||
if(Board::GetSocType() == SysClkSocType_Erista) {
|
||||
cachedEristaUvLowTune0 = *(u32*)(cldvfs + CL_DVFS_TUNE0_0);
|
||||
cachedEristaUvLowTune1 = *(u32*)(cldvfs + CL_DVFS_TUNE1_0);
|
||||
} else {
|
||||
Board::SetHz(SysClkModule_CPU, 1785000000);
|
||||
cachedMarikoUvHighTune0 = *(u32*)(cldvfs + CL_DVFS_TUNE0_0);
|
||||
Board::ResetToStockCpu();
|
||||
}
|
||||
}
|
||||
|
||||
void Board::fuseReadSpeedos() {
|
||||
@@ -444,7 +457,6 @@ SysClkProfile Board::GetProfile()
|
||||
void Board::SetHz(SysClkModule module, std::uint32_t hz)
|
||||
{
|
||||
Result rc = 0;
|
||||
|
||||
if(module == HorizonOCModule_Display && Board::GetConsoleType() != HorizonOCConsoleType_Hoag) {
|
||||
DisplayRefresh_SetRate(hz);
|
||||
return;
|
||||
@@ -460,7 +472,7 @@ void Board::SetHz(SysClkModule module, std::uint32_t hz)
|
||||
rc = clkrstSetClockRate(&session, hz);
|
||||
ASSERT_RESULT_OK(rc, "clkrstSetClockRate");
|
||||
if (module == SysClkModule_CPU) {
|
||||
svcSleepThread(300'000);
|
||||
svcSleepThread(200'000);
|
||||
rc = clkrstSetClockRate(&session, hz);
|
||||
ASSERT_RESULT_OK(rc, "clkrstSetClockRate");
|
||||
}
|
||||
@@ -471,7 +483,7 @@ void Board::SetHz(SysClkModule module, std::uint32_t hz)
|
||||
rc = pcvSetClockRate(Board::GetPcvModule(module), hz);
|
||||
ASSERT_RESULT_OK(rc, "pcvSetClockRate");
|
||||
if (module == SysClkModule_CPU) {
|
||||
svcSleepThread(300'000);
|
||||
svcSleepThread(200'000);
|
||||
rc = pcvSetClockRate(Board::GetPcvModule(module), hz);
|
||||
ASSERT_RESULT_OK(rc, "pcvSetClockRate");
|
||||
}
|
||||
@@ -722,14 +734,15 @@ void Board::ResetToStockGpu()
|
||||
}
|
||||
|
||||
void Board::ResetToStockDisplay() {
|
||||
if(Board::GetConsoleType() != HorizonOCConsoleType_Hoag)
|
||||
if(Board::GetConsoleType() != HorizonOCConsoleType_Hoag) {
|
||||
DisplayRefresh_SetRate(60);
|
||||
}
|
||||
}
|
||||
|
||||
u8 Board::GetHighestDockedDisplayRate() {
|
||||
if(Board::GetConsoleType() != HorizonOCConsoleType_Hoag)
|
||||
if(Board::GetConsoleType() != HorizonOCConsoleType_Hoag) {
|
||||
return DisplayRefresh_GetDockedHighestAllowed();
|
||||
else
|
||||
} else
|
||||
return 60;
|
||||
}
|
||||
|
||||
@@ -1134,9 +1147,6 @@ void Board::PcvHijackDvfs(u32 vmin) {
|
||||
FileUtils::LogLine("[dvfs] voltage set to %u mV", vmin);
|
||||
}
|
||||
|
||||
#define MC_REGISTER_BASE 0x70019000
|
||||
#define MC_REGISTER_REGION_SIZE 0x1000
|
||||
|
||||
bool Board::IsDram8GB() {
|
||||
SecmonArgs args = {};
|
||||
args.X[0] = 0xF0000002;
|
||||
@@ -1150,21 +1160,161 @@ bool Board::IsDram8GB() {
|
||||
return args.X[1] == 0x00002000 ? true : false;
|
||||
}
|
||||
|
||||
void Board::SetGpuSchedulingMode(GpuSchedulingMode mode) {
|
||||
if (nvCheck_sched == 1) {
|
||||
void Board::SetGpuSchedulingMode(GpuSchedulingMode mode, GpuSchedulingOverrideMethod method) {
|
||||
if (nvCheck_sched == 1 && method == GpuSchedulingOverrideMethod_NvService) {
|
||||
return;
|
||||
}
|
||||
u32 temp;
|
||||
bool enabled = false;
|
||||
switch(mode) {
|
||||
case GpuSchedulingMode_DoNotOverride:
|
||||
return;
|
||||
case GpuSchedulingMode_DoNotOverride: break;
|
||||
case GpuSchedulingMode_Disabled:
|
||||
nvIoctl(fd2, NVSCHED_CTRL_DISABLE, &temp);
|
||||
if(method == GpuSchedulingOverrideMethod_NvService)
|
||||
nvIoctl(fd2, NVSCHED_CTRL_DISABLE, &temp);
|
||||
else
|
||||
enabled = false;
|
||||
break;
|
||||
case GpuSchedulingMode_Enabled:
|
||||
nvIoctl(fd2, NVSCHED_CTRL_ENABLE, &temp);
|
||||
if(method == GpuSchedulingOverrideMethod_NvService)
|
||||
nvIoctl(fd2, NVSCHED_CTRL_ENABLE, &temp);
|
||||
else
|
||||
enabled = true;
|
||||
break;
|
||||
default:
|
||||
ASSERT_ENUM_VALID(GpuSchedulingMode, mode);
|
||||
}
|
||||
if(method == GpuSchedulingOverrideMethod_Ini) {
|
||||
const char* ini_path = "sdmc:/atmosphere/config/system_settings.ini";
|
||||
const char* section = "am.gpu";
|
||||
const char* key = "gpu_scheduling_enabled";
|
||||
|
||||
const char* value = enabled ? "u8!0x1" : "u8!0x0";
|
||||
|
||||
ini_puts(section, key, value, ini_path);
|
||||
}
|
||||
}
|
||||
void Board::SetDisplayRefreshDockedState(bool docked) {
|
||||
if(Board::GetConsoleType() != HorizonOCConsoleType_Hoag) {
|
||||
DisplayRefresh_SetDockedState(docked);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
typedef struct EristaCpuUvEntry {
|
||||
u32 tune0;
|
||||
u32 tune1;
|
||||
} EristaCpuUvEntry;
|
||||
typedef struct MarikoCpuUvEntry {
|
||||
u32 tune0_low;
|
||||
u32 tune0_high;
|
||||
u32 tune1_low;
|
||||
u32 tune1_high;
|
||||
} MarikoCpuUvEntry;
|
||||
|
||||
EristaCpuUvEntry eristaCpuUvTable[5] = {
|
||||
{0xffff, 0x27007ff},
|
||||
{0xefff, 0x27407ff},
|
||||
{0xdfff, 0x27807ff},
|
||||
{0xdfdf, 0x27a07ff},
|
||||
{0xcfdf, 0x37007ff},
|
||||
};
|
||||
|
||||
MarikoCpuUvEntry marikoCpuUvLow[12] = {
|
||||
{0xffa0, 0xffff, 0x21107ff, 0},
|
||||
{0x0, 0xffdf, 0x21107ff, 0x27207ff},
|
||||
{0xffdf, 0xffdf, 0x21107ff, 0x27307ff},
|
||||
{0xffff, 0xffdf, 0x21107ff, 0x27407ff},
|
||||
{0x0, 0xffdf, 0x21607ff, 0x27707ff},
|
||||
{0x0, 0xffdf, 0x21607ff, 0x27807ff},
|
||||
{0x0, 0xdfff, 0x21607ff, 0x27b07ff},
|
||||
{0xdfff, 0xdfff, 0x21707ff, 0x27b07ff},
|
||||
{0xdfff, 0xdfff, 0x21707ff, 0x27c07ff},
|
||||
{0xdfff, 0xdfff, 0x21707ff, 0x27d07ff},
|
||||
{0xdfff, 0xdfff, 0x21707ff, 0x27e07ff},
|
||||
{0xdfff, 0xdfff, 0x21707ff, 0x27f07ff},
|
||||
};
|
||||
|
||||
MarikoCpuUvEntry marikoCpuUvHigh[12] = {
|
||||
{0x0, 0xffff, 0, 0},
|
||||
{0x0, 0xffdf, 0, 0x27207ff},
|
||||
{0x0, 0xffdf, 0, 0x27307ff},
|
||||
{0x0, 0xffdf, 0, 0x27407ff},
|
||||
{0x0, 0xffdf, 0, 0x27707ff},
|
||||
{0x0, 0xffdf, 0, 0x27807ff},
|
||||
{0x0, 0xdfff, 0, 0x27b07ff},
|
||||
{0x0, 0xdfff, 0, 0x27c07ff},
|
||||
{0x0, 0xdfff, 0, 0x27d07ff},
|
||||
{0x0, 0xdfff, 0, 0x27e07ff},
|
||||
{0x0, 0xdfff, 0, 0x27f07ff},
|
||||
{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) {
|
||||
if(Board::GetHz(SysClkModule_CPU) < tbreakPoint && (levelLow || levelHigh)) {
|
||||
if(levelLow) {
|
||||
*tune0_ptr = marikoCpuUvLow[levelLow-1].tune0_low;
|
||||
*tune1_ptr = marikoCpuUvLow[levelLow-1].tune1_low;
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
if(levelLow) {
|
||||
*tune0_ptr = marikoCpuUvLow[levelLow-1].tune0_low;
|
||||
*tune1_ptr = marikoCpuUvLow[levelLow-1].tune1_low;
|
||||
}
|
||||
if(levelHigh) {
|
||||
*tune0_ptr = marikoCpuUvHigh[levelHigh-1].tune0_high;
|
||||
*tune1_ptr = marikoCpuUvHigh[levelHigh-1].tune1_high;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(Board::GetHz(SysClkModule_CPU) < tbreakPoint || (!levelLow)) { // account for tbreak
|
||||
*tune0_ptr = 0xCFFF;
|
||||
*tune1_ptr = 0xFF072201;
|
||||
return;
|
||||
} else if (Board::GetHz(SysClkModule_CPU) >= tbreakPoint || (!levelHigh)) {
|
||||
*tune0_ptr = cachedMarikoUvHighTune0; // per console?
|
||||
*tune1_ptr = 0xFFF7FF3F;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if(Board::GetHz(SysClkModule_CPU) < tbreakPoint || (!levelLow)) { // account for tbreak
|
||||
*tune0_ptr = cachedEristaUvLowTune0; // I think each erista has a different tune0/tune1?
|
||||
*tune1_ptr = cachedEristaUvLowTune1;
|
||||
return;
|
||||
} else {
|
||||
if(levelLow) {
|
||||
*tune0_ptr = eristaCpuUvTable[levelLow-1].tune0;
|
||||
*tune1_ptr = eristaCpuUvTable[levelLow-1].tune1;
|
||||
} else {
|
||||
*tune0_ptr = 0x0;
|
||||
*tune1_ptr = 0x0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
enum TableConfig: u32 {
|
||||
DEFAULT_TABLE = 1,
|
||||
TBREAK_1581 = 2,
|
||||
TBREAK_1683 = 3,
|
||||
EXTREME_TABLE = 4,
|
||||
};
|
||||
*/
|
||||
u32 Board::CalculateTbreak(u32 table) {
|
||||
if(Board::GetSocType() == SysClkSocType_Erista)
|
||||
return 1581000000;
|
||||
else {
|
||||
switch(table) {
|
||||
case 1 ... 2:
|
||||
case 4:
|
||||
return 1581000000;
|
||||
case 3:
|
||||
return 1683000000;
|
||||
default:
|
||||
return 1581000000;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -64,7 +64,10 @@ class Board
|
||||
static u8 GetFanRotationLevel();
|
||||
static u8 GetDramID();
|
||||
static bool IsDram8GB();
|
||||
static void SetGpuSchedulingMode(GpuSchedulingMode mode);
|
||||
static void SetGpuSchedulingMode(GpuSchedulingMode mode, GpuSchedulingOverrideMethod method);
|
||||
static void SetDisplayRefreshDockedState(bool docked);
|
||||
static void SetCpuUvLevel(u32 levelLow, u32 levelHigh, u32 tbreakPoint);
|
||||
static u32 CalculateTbreak(u32 table);
|
||||
protected:
|
||||
static void FetchHardwareInfos();
|
||||
static PcvModule GetPcvModule(SysClkModule sysclkModule);
|
||||
|
||||
@@ -39,17 +39,19 @@
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <crc32.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#define HOSPPC_HAS_BOOST (hosversionAtLeast(7,0,0))
|
||||
bool isGovernorEnabled = false; // to avoid thread messes
|
||||
bool lastGovernorState = false;
|
||||
bool isGpuGovernorEnabled = false;
|
||||
bool isCpuGovernorEnabled = false;
|
||||
bool lastGpuGovernorState = false;
|
||||
bool lastCpuGovernorState = false;
|
||||
bool hasChanged = true;
|
||||
ClockManager *ClockManager::instance = NULL;
|
||||
Thread governorTHREAD;
|
||||
Thread cpuGovernorTHREAD;
|
||||
Thread gpuGovernorTHREAD;
|
||||
u32 initialConfigValues[SysClkConfigValue_EnumMax]; // initial config. used for safety checks
|
||||
u64 previousRamHz;
|
||||
bool kipAvailable = false;
|
||||
bool isCpuGovernorInBoostMode = false;
|
||||
|
||||
ClockManager *ClockManager::GetInstance()
|
||||
{
|
||||
@@ -90,11 +92,22 @@ ClockManager::ClockManager()
|
||||
this->lastTempLogNs = 0;
|
||||
this->lastCsvWriteNs = 0;
|
||||
|
||||
this->rnxSync = new ReverseNXSync;
|
||||
this->sysDockIntegration = new SysDockIntegration;
|
||||
memset(&initialConfigValues, 0, sizeof(initialConfigValues));
|
||||
this->GetKipData();
|
||||
|
||||
threadCreate(
|
||||
&governorTHREAD,
|
||||
&cpuGovernorTHREAD,
|
||||
ClockManager::CpuGovernorThread,
|
||||
this,
|
||||
NULL,
|
||||
0x2000,
|
||||
0x3F,
|
||||
-2
|
||||
);
|
||||
|
||||
threadCreate(
|
||||
&gpuGovernorTHREAD,
|
||||
ClockManager::GovernorThread,
|
||||
this,
|
||||
NULL,
|
||||
@@ -103,7 +116,8 @@ ClockManager::ClockManager()
|
||||
-2
|
||||
);
|
||||
|
||||
threadStart(&governorTHREAD);
|
||||
threadStart(&cpuGovernorTHREAD);
|
||||
threadStart(&gpuGovernorTHREAD);
|
||||
|
||||
for(int i = 0; i < HorizonOCSpeedo_EnumMax; i++) {
|
||||
this->context->speedos[i] = Board::getSpeedo((HorizonOCSpeedo)i);
|
||||
@@ -112,21 +126,15 @@ ClockManager::ClockManager()
|
||||
|
||||
this->context->dramID = Board::GetDramID();
|
||||
this->context->isDram8GB = Board::IsDram8GB();
|
||||
previousRamHz = Board::GetHz(SysClkModule_MEM);
|
||||
Board::SetGpuSchedulingMode((GpuSchedulingMode)this->config->GetConfigValue(HorizonOCConfigValue_GPUScheduling));
|
||||
Board::SetGpuSchedulingMode((GpuSchedulingMode)this->config->GetConfigValue(HorizonOCConfigValue_GPUScheduling), (GpuSchedulingOverrideMethod)this->config->GetConfigValue(HorizonOCConfigValue_GPUSchedulingMethod));
|
||||
this->context->gpuSchedulingMode = (GpuSchedulingMode)this->config->GetConfigValue(HorizonOCConfigValue_GPUScheduling);
|
||||
|
||||
struct stat st = {0};
|
||||
if (stat("sdmc:/atmosphere/contents/42000000000000A0", &st) == 0 && S_ISDIR(st.st_mode)) {
|
||||
this->context->isSysDockInstalled = true;
|
||||
} else {
|
||||
this->context->isSysDockInstalled = false;
|
||||
}
|
||||
this->context->isSysDockInstalled = this->sysDockIntegration->getCurrentSysDockState();
|
||||
}
|
||||
|
||||
ClockManager::~ClockManager()
|
||||
{
|
||||
threadClose(&governorTHREAD);
|
||||
threadClose(&cpuGovernorTHREAD);
|
||||
threadClose(&gpuGovernorTHREAD);
|
||||
delete this->config;
|
||||
delete this->context;
|
||||
}
|
||||
@@ -318,6 +326,160 @@ u32 findIndexMHz(u32 arr[], u32 size, u32 value) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ClockManager::CpuGovernorThread(void* arg)
|
||||
{
|
||||
ClockManager* mgr = static_cast<ClockManager*>(arg);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (!mgr->running)
|
||||
{
|
||||
svcSleepThread(50'000'000);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isCpuGovernorEnabled)
|
||||
{
|
||||
svcSleepThread(50'000'000);
|
||||
continue;
|
||||
}
|
||||
|
||||
std::uint32_t mode = 0;
|
||||
Result rc = apmExtGetCurrentPerformanceConfiguration(&mode);
|
||||
bool isInBoostMode = R_SUCCEEDED(rc) && apmExtIsBoostMode(mode);
|
||||
|
||||
if (isInBoostMode)
|
||||
{
|
||||
isCpuGovernorInBoostMode = true;
|
||||
svcSleepThread(50'000'000);
|
||||
continue;
|
||||
}
|
||||
|
||||
isCpuGovernorInBoostMode = false;
|
||||
|
||||
auto& table = mgr->freqTable[SysClkModule_CPU];
|
||||
if (table.count == 0)
|
||||
{
|
||||
svcSleepThread(50'000'000);
|
||||
continue;
|
||||
}
|
||||
|
||||
std::scoped_lock lock{mgr->contextMutex};
|
||||
|
||||
u32 currentHz = Board::GetHz(SysClkModule_CPU);
|
||||
|
||||
u32 index = table.count - 1;
|
||||
for (u32 i = 0; i < table.count; i++)
|
||||
{
|
||||
if (table.list[i] == currentHz)
|
||||
{
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (table.list[index] != currentHz)
|
||||
{
|
||||
for (u32 i = 0; i < table.count; i++)
|
||||
{
|
||||
if (table.list[i] >= currentHz)
|
||||
{
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u32 targetHz = mgr->context->overrideFreqs[SysClkModule_CPU];
|
||||
if (!targetHz)
|
||||
{
|
||||
targetHz = mgr->config->GetAutoClockHz(
|
||||
mgr->context->applicationId,
|
||||
SysClkModule_CPU,
|
||||
mgr->context->profile,
|
||||
false
|
||||
);
|
||||
|
||||
if (!targetHz)
|
||||
{
|
||||
targetHz = mgr->config->GetAutoClockHz(
|
||||
GLOBAL_PROFILE_ID,
|
||||
SysClkModule_CPU,
|
||||
mgr->context->profile,
|
||||
false
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
int gpuLoad = Board::GetPartLoad(HocClkPartLoad_GPU);
|
||||
int cpuLoad = Board::GetPartLoad(HocClkPartLoad_CPUMax);
|
||||
|
||||
if (isGpuGovernorEnabled && gpuLoad < 800)
|
||||
{
|
||||
if (cpuLoad < 600 && index > 0)
|
||||
{
|
||||
index--;
|
||||
}
|
||||
else if (cpuLoad > 800 && index + 1 < table.count)
|
||||
{
|
||||
index++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cpuLoad < 600 && index > 0)
|
||||
{
|
||||
index--;
|
||||
}
|
||||
else if (cpuLoad > 800 && index + 1 < table.count)
|
||||
{
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
u32 maxHz = mgr->GetMaxAllowedHz(SysClkModule_CPU, mgr->context->profile);
|
||||
|
||||
if (targetHz)
|
||||
{
|
||||
u32 targetIndex = table.count - 1;
|
||||
for (u32 i = 0; i < table.count; i++)
|
||||
{
|
||||
if (table.list[i] >= targetHz)
|
||||
{
|
||||
targetIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index > targetIndex)
|
||||
{
|
||||
index = targetIndex;
|
||||
}
|
||||
}
|
||||
|
||||
if (maxHz > 0 && table.list[index] > maxHz)
|
||||
{
|
||||
for (u32 i = table.count; i > 0; i--)
|
||||
{
|
||||
if (table.list[i - 1] <= maxHz)
|
||||
{
|
||||
index = i - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u32 newHz = table.list[index];
|
||||
if (mgr->IsAssignableHz(SysClkModule_CPU, newHz))
|
||||
{
|
||||
Board::SetHz(SysClkModule_CPU, newHz);
|
||||
mgr->context->freqs[SysClkModule_CPU] = newHz;
|
||||
}
|
||||
|
||||
svcSleepThread(50'000'000);
|
||||
}
|
||||
}
|
||||
|
||||
void ClockManager::GovernorThread(void* arg)
|
||||
{
|
||||
ClockManager* mgr = static_cast<ClockManager*>(arg);
|
||||
@@ -330,8 +492,7 @@ void ClockManager::GovernorThread(void* arg)
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (!isGovernorEnabled)
|
||||
if (!isGpuGovernorEnabled)
|
||||
{
|
||||
svcSleepThread(50'000'000);
|
||||
continue;
|
||||
@@ -348,7 +509,7 @@ void ClockManager::GovernorThread(void* arg)
|
||||
|
||||
u32 currentHz = Board::GetHz(SysClkModule_GPU);
|
||||
|
||||
u32 index = 0;
|
||||
u32 index = table.count - 1;
|
||||
for (u32 i = 0; i < table.count; i++)
|
||||
{
|
||||
if (table.list[i] == currentHz)
|
||||
@@ -358,6 +519,18 @@ void ClockManager::GovernorThread(void* arg)
|
||||
}
|
||||
}
|
||||
|
||||
if (table.list[index] != currentHz)
|
||||
{
|
||||
for (u32 i = 0; i < table.count; i++)
|
||||
{
|
||||
if (table.list[i] >= currentHz)
|
||||
{
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u32 targetHz = mgr->context->overrideFreqs[SysClkModule_GPU];
|
||||
if (!targetHz)
|
||||
{
|
||||
@@ -379,17 +552,34 @@ void ClockManager::GovernorThread(void* arg)
|
||||
}
|
||||
}
|
||||
|
||||
int load = Board::GetPartLoad(HocClkPartLoad_GPU);
|
||||
int gpuLoad = Board::GetPartLoad(HocClkPartLoad_GPU);
|
||||
int cpuLoad = Board::GetPartLoad(HocClkPartLoad_CPUMax);
|
||||
|
||||
if (load < 600 && index > 0)
|
||||
if (isCpuGovernorEnabled && !isCpuGovernorInBoostMode && cpuLoad < 600)
|
||||
{
|
||||
index--;
|
||||
if (gpuLoad < 600 && index > 0)
|
||||
{
|
||||
index--;
|
||||
}
|
||||
else if (gpuLoad > 750 && index + 1 < table.count)
|
||||
{
|
||||
index++;
|
||||
}
|
||||
}
|
||||
else if (load > 800 && index + 1 < table.count)
|
||||
else
|
||||
{
|
||||
index++;
|
||||
if (gpuLoad < 600 && index > 0)
|
||||
{
|
||||
index--;
|
||||
}
|
||||
else if (gpuLoad > 800 && index + 1 < table.count)
|
||||
{
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
u32 maxHz = mgr->GetMaxAllowedHz(SysClkModule_GPU, mgr->context->profile);
|
||||
|
||||
if (targetHz)
|
||||
{
|
||||
u32 targetIndex = table.count - 1;
|
||||
@@ -408,6 +598,17 @@ void ClockManager::GovernorThread(void* arg)
|
||||
}
|
||||
}
|
||||
|
||||
if (maxHz > 0 && table.list[index] > maxHz)
|
||||
{
|
||||
for (u32 i = table.count; i > 0; i--)
|
||||
{
|
||||
if (table.list[i - 1] <= maxHz)
|
||||
{
|
||||
index = i - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u32 newHz = table.list[index];
|
||||
if (mgr->IsAssignableHz(SysClkModule_GPU, newHz))
|
||||
@@ -420,16 +621,21 @@ void ClockManager::GovernorThread(void* arg)
|
||||
}
|
||||
}
|
||||
|
||||
bool prevBoostMode = true;
|
||||
|
||||
void ClockManager::Tick()
|
||||
GovernorState ClockManager::GetEffectiveGovernorState(GovernorState appState, GovernorState tempState)
|
||||
{
|
||||
std::scoped_lock lock{this->contextMutex};
|
||||
std::uint32_t mode = 0;
|
||||
AppletOperationMode opMode = appletGetOperationMode();
|
||||
Result rc = apmExtGetCurrentPerformanceConfiguration(&mode);
|
||||
ASSERT_RESULT_OK(rc, "apmExtGetCurrentPerformanceConfiguration");
|
||||
if (tempState == GovernorState_Disabled)
|
||||
{
|
||||
return GovernorState_Disabled;
|
||||
}
|
||||
if (tempState != GovernorState_DoNotOverride)
|
||||
{
|
||||
return tempState;
|
||||
}
|
||||
return appState;
|
||||
}
|
||||
|
||||
void ClockManager::HandleSafetyFeatures() {
|
||||
AppletOperationMode opMode = appletGetOperationMode();
|
||||
if(this->config->GetConfigValue(HocClkConfigValue_HandheldTDP) && opMode == AppletOperationMode_Handheld) {
|
||||
if(Board::GetConsoleType() == HorizonOCConsoleType_Hoag) {
|
||||
if(Board::GetPowerMw(SysClkPowerSensor_Avg) < -(int)this->config->GetConfigValue(HocClkConfigValue_LiteTDPLimit)) {
|
||||
@@ -444,152 +650,265 @@ void ClockManager::Tick()
|
||||
}
|
||||
}
|
||||
|
||||
// if(this->config->GetConfigValue(HocClkConfigValue_EnforceBoardLimit) && opMode == AppletOperationMode_Console ) {
|
||||
// if(Board::GetPowerMw(SysClkPowerSensor_Now) < 0) {
|
||||
// ResetToStockClocks();
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
|
||||
if(((tmp451TempSoc() / 1000) > (int)this->config->GetConfigValue(HocClkConfigValue_ThermalThrottleThreshold)) && this->config->GetConfigValue(HocClkConfigValue_ThermalThrottle)) {
|
||||
ResetToStockClocks();
|
||||
return;
|
||||
}
|
||||
bool isBoost = apmExtIsBoostMode(mode);
|
||||
// if(isBoost) {
|
||||
// Board::SetHz(SysClkModule_CPU, Board::GetSocType() == SysClkSocType_Mariko ? this->config->GetConfigValue(HocClkConfigValue_MarikoBoostCpuClock) * 1000'000 : this->config->GetConfigValue(HocClkConfigValue_EristaBoostCpuClock) * 1000'000);
|
||||
// }
|
||||
prevBoostMode = isBoost;
|
||||
}
|
||||
|
||||
bool noGPU = false;
|
||||
void ClockManager::HandleMiscFeatures() {
|
||||
if(this->config->GetConfigValue(HorizonOCConfigValue_BatteryChargeCurrent)) {
|
||||
I2c_Bq24193_SetFastChargeCurrentLimit(this->config->GetConfigValue(HorizonOCConfigValue_BatteryChargeCurrent));
|
||||
}
|
||||
}
|
||||
|
||||
if (this->RefreshContext() || this->config->Refresh())
|
||||
void ClockManager::HandleGovernor(uint32_t targetHz) {
|
||||
GovernorState appGovernorState = (GovernorState)targetHz;
|
||||
|
||||
u32 tempTargetHz = this->context->overrideFreqs[HorizonOCModule_Governor];
|
||||
if (!tempTargetHz)
|
||||
{
|
||||
tempTargetHz = this->config->GetAutoClockHz(this->context->applicationId, HorizonOCModule_Governor, this->context->profile, true);
|
||||
if(!tempTargetHz)
|
||||
tempTargetHz = this->config->GetAutoClockHz(GLOBAL_PROFILE_ID, HorizonOCModule_Governor, this->context->profile, true);
|
||||
}
|
||||
GovernorState tempGovernorState = (GovernorState)tempTargetHz;
|
||||
|
||||
if(this->config->GetConfigValue(HorizonOCConfigValue_BatteryChargeCurrent)) {
|
||||
I2c_Bq24193_SetFastChargeCurrentLimit(this->config->GetConfigValue(HorizonOCConfigValue_BatteryChargeCurrent));
|
||||
GovernorState effectiveState = this->GetEffectiveGovernorState(appGovernorState, tempGovernorState);
|
||||
|
||||
bool newCpuGovernorState = (effectiveState == GovernorState_Enabled_CpuGpu || effectiveState == GovernorState_Enabled_Cpu);
|
||||
bool newGpuGovernorState = (effectiveState == GovernorState_Enabled_CpuGpu || effectiveState == GovernorState_Enabled_Gpu);
|
||||
|
||||
isCpuGovernorEnabled = newCpuGovernorState;
|
||||
isGpuGovernorEnabled = newGpuGovernorState;
|
||||
|
||||
if(newCpuGovernorState == false && lastCpuGovernorState == true) {
|
||||
svcSleepThread(150'000'000); // thread syncing. probably a cleaner way to do this but hey, it works!
|
||||
Board::ResetToStockCpu();
|
||||
}
|
||||
if(newGpuGovernorState == false && lastGpuGovernorState == true) {
|
||||
svcSleepThread(150'000'000);
|
||||
Board::ResetToStockGpu();
|
||||
}
|
||||
|
||||
if(newCpuGovernorState != lastCpuGovernorState || newGpuGovernorState != lastGpuGovernorState) {
|
||||
FileUtils::LogLine("[mgr] Governor state changed: CPU %s, GPU %s", newCpuGovernorState ? "enabled" : "disabled", newGpuGovernorState ? "enabled" : "disabled");
|
||||
lastCpuGovernorState = newCpuGovernorState;
|
||||
lastGpuGovernorState = newGpuGovernorState;
|
||||
}
|
||||
}
|
||||
|
||||
void ClockManager::DVFSBeforeSet(u32 targetHz) {
|
||||
s32 dvfsOffset = this->config->GetConfigValue(HorizonOCConfigValue_DVFSOffset);
|
||||
u32 vmin = Board::GetMinimumGpuVoltage(targetHz / 1000000) + dvfsOffset;
|
||||
|
||||
Board::PcvHijackDvfs(vmin);
|
||||
|
||||
/* Update the voltage. */
|
||||
if (I2c_BuckConverter_GetMvOut(&I2c_Mariko_GPU) < vmin) {
|
||||
I2c_BuckConverter_SetMvOut(&I2c_Mariko_GPU, vmin);
|
||||
}
|
||||
|
||||
this->context->voltages[HocClkVoltage_GPU] = vmin * 1000;
|
||||
}
|
||||
|
||||
void ClockManager::DVFSAfterSet(u32 targetHz) {
|
||||
s32 dvfsOffset = this->config->GetConfigValue(HorizonOCConfigValue_DVFSOffset);
|
||||
dvfsOffset = std::max(dvfsOffset, -50);
|
||||
u32 vmin = Board::GetMinimumGpuVoltage(targetHz / 1000000) + dvfsOffset;
|
||||
Board::PcvHijackDvfs(vmin);
|
||||
|
||||
targetHz = this->context->overrideFreqs[SysClkModule_GPU];
|
||||
if (!targetHz)
|
||||
{
|
||||
targetHz = this->config->GetAutoClockHz(this->context->applicationId, SysClkModule_GPU, this->context->profile, false);
|
||||
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, nearestHz);
|
||||
}
|
||||
}
|
||||
|
||||
void ClockManager::HandleCpuUv() {
|
||||
if(Board::GetSocType() == SysClkSocType_Erista)
|
||||
Board::SetCpuUvLevel(this->config->GetConfigValue(KipConfigValue_eristaCpuUV), 0, 1581000000);
|
||||
else
|
||||
Board::SetCpuUvLevel(this->config->GetConfigValue(KipConfigValue_marikoCpuUVLow), this->config->GetConfigValue(KipConfigValue_marikoCpuUVHigh), Board::CalculateTbreak(this->config->GetConfigValue(KipConfigValue_tableConf)));
|
||||
}
|
||||
|
||||
void ClockManager::DVFSReset() {
|
||||
if (Board::GetSocType() == SysClkSocType_Mariko && this->config->GetConfigValue(HorizonOCConfigValue_DVFSMode) == DVFSMode_Hijack) {
|
||||
Board::PcvHijackDvfs(0);
|
||||
|
||||
u32 targetHz = this->context->overrideFreqs[SysClkModule_GPU];
|
||||
if (!targetHz) {
|
||||
targetHz = this->config->GetAutoClockHz(this->context->applicationId, SysClkModule_GPU, this->context->profile, false);
|
||||
if(!targetHz) {
|
||||
targetHz = this->config->GetAutoClockHz(GLOBAL_PROFILE_ID, SysClkModule_GPU, this->context->profile, false);
|
||||
}
|
||||
}
|
||||
std::uint32_t targetHz = 0;
|
||||
std::uint32_t maxHz = 0;
|
||||
std::uint32_t nearestHz = 0;
|
||||
u32 maxHz = this->GetMaxAllowedHz(SysClkModule_GPU, this->context->profile);
|
||||
u32 nearestHz = this->GetNearestHz(SysClkModule_GPU, targetHz, maxHz);
|
||||
|
||||
if(apmExtIsBoostMode(mode) && !this->config->GetConfigValue(HocClkConfigValue_OverwriteBoostMode)) {
|
||||
// ResetToStockClocks();
|
||||
return;
|
||||
Board::SetHz(SysClkModule_GPU, ~0);
|
||||
if(targetHz) {
|
||||
Board::SetHz(SysClkModule_GPU, nearestHz);
|
||||
} else {
|
||||
Board::ResetToStockGpu();
|
||||
}
|
||||
previousRamHz = Board::GetHz(SysClkModule_MEM);
|
||||
}
|
||||
}
|
||||
|
||||
bool returnRaw = false;
|
||||
for (unsigned int module = 0; module < SysClkModule_EnumMax; module++)
|
||||
{
|
||||
u32 oldHz = Board::GetHz((SysClkModule)module);
|
||||
|
||||
if(module > SysClkModule_MEM)
|
||||
returnRaw = true;
|
||||
void ClockManager::HandleFreqReset(SysClkModule module, bool isBoost) {
|
||||
switch (module)
|
||||
{
|
||||
case SysClkModule_CPU:
|
||||
if(!(isBoost || (this->config->GetConfigValue(HocClkConfigValue_OverwriteBoostMode) && isBoost)))
|
||||
Board::ResetToStockCpu();
|
||||
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
|
||||
returnRaw = false;
|
||||
targetHz = this->context->overrideFreqs[module];
|
||||
if (!targetHz)
|
||||
{
|
||||
targetHz = this->config->GetAutoClockHz(this->context->applicationId, (SysClkModule)module, this->context->profile, returnRaw);
|
||||
if(!targetHz)
|
||||
targetHz = this->config->GetAutoClockHz(GLOBAL_PROFILE_ID, (SysClkModule)module, this->context->profile, returnRaw);
|
||||
}
|
||||
Board::SetCpuUvLevel(this->config->GetConfigValue(KipConfigValue_marikoCpuUVLow), this->config->GetConfigValue(KipConfigValue_marikoCpuUVHigh), Board::CalculateTbreak(this->config->GetConfigValue(KipConfigValue_tableConf)));
|
||||
}
|
||||
|
||||
if(module == HorizonOCModule_Governor) {
|
||||
bool newGovernorState = targetHz;
|
||||
if(newGovernorState != lastGovernorState) {
|
||||
FileUtils::LogLine("[mgr] Governor state changed: %s", newGovernorState ? "enabled" : "disabled");
|
||||
lastGovernorState = newGovernorState;
|
||||
break;
|
||||
case SysClkModule_GPU:
|
||||
Board::ResetToStockGpu();
|
||||
break;
|
||||
case SysClkModule_MEM:
|
||||
Board::ResetToStockMem();
|
||||
DVFSReset();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
hasChanged = true;
|
||||
Board::ResetToStock();
|
||||
}
|
||||
|
||||
void ClockManager::SetClocks(bool isBoost) {
|
||||
std::uint32_t targetHz = 0;
|
||||
std::uint32_t maxHz = 0;
|
||||
std::uint32_t nearestHz = 0;
|
||||
|
||||
if(isBoost && !this->config->GetConfigValue(HocClkConfigValue_OverwriteBoostMode)) {
|
||||
u32 boostFreq = Board::GetHz(SysClkModule_CPU);
|
||||
if (boostFreq / 1000000 > 1785) {
|
||||
Board::SetHz(SysClkModule_CPU, boostFreq);
|
||||
}
|
||||
return; // Return if we are't overwriting boost mode
|
||||
}
|
||||
|
||||
bool returnRaw = false; // Return a value scaled to MHz instead of raw value
|
||||
for (unsigned int module = 0; module < SysClkModule_EnumMax; module++)
|
||||
{
|
||||
u32 oldHz = Board::GetHz((SysClkModule)module); // Get Old RAM hz (used primarily for DVFS Logic)
|
||||
|
||||
if(module > SysClkModule_MEM)
|
||||
returnRaw = true;
|
||||
else
|
||||
returnRaw = false;
|
||||
targetHz = this->context->overrideFreqs[module];
|
||||
if (!targetHz)
|
||||
{
|
||||
targetHz = this->config->GetAutoClockHz(this->context->applicationId, (SysClkModule)module, this->context->profile, returnRaw);
|
||||
if(!targetHz)
|
||||
targetHz = this->config->GetAutoClockHz(GLOBAL_PROFILE_ID, (SysClkModule)module, this->context->profile, returnRaw);
|
||||
}
|
||||
|
||||
if(module == HorizonOCModule_Governor) {
|
||||
HandleGovernor(targetHz);
|
||||
}
|
||||
|
||||
if(module == HorizonOCModule_Display && this->config->GetConfigValue(HorizonOCConfigValue_OverwriteRefreshRate) && Board::GetConsoleType() != HorizonOCConsoleType_Hoag) {
|
||||
if(targetHz)
|
||||
Board::SetHz(HorizonOCModule_Display, targetHz);
|
||||
else
|
||||
Board::ResetToStockDisplay();
|
||||
}
|
||||
|
||||
// Skip GPU and CPU if governors handle them
|
||||
if(module > SysClkModule_MEM) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool noCPU = isCpuGovernorEnabled;
|
||||
bool noGPU = isGpuGovernorEnabled;
|
||||
|
||||
if(noCPU && module == SysClkModule_CPU)
|
||||
continue;
|
||||
if(noGPU && module == SysClkModule_GPU)
|
||||
continue;
|
||||
|
||||
if (targetHz)
|
||||
{
|
||||
maxHz = this->GetMaxAllowedHz((SysClkModule)module, this->context->profile);
|
||||
nearestHz = this->GetNearestHz((SysClkModule)module, targetHz, maxHz);
|
||||
|
||||
if (nearestHz != this->context->freqs[module]) {
|
||||
FileUtils::LogLine(
|
||||
"[mgr] %s clock set : %u.%u MHz (target = %u.%u MHz)",
|
||||
Board::GetModuleName((SysClkModule)module, true),
|
||||
nearestHz / 1000000, nearestHz / 100000 - nearestHz / 1000000 * 10,
|
||||
targetHz / 1000000, targetHz / 100000 - targetHz / 1000000 * 10
|
||||
);
|
||||
|
||||
if(module == SysClkModule_MEM && Board::GetSocType() == SysClkSocType_Mariko && targetHz > oldHz && this->config->GetConfigValue(HorizonOCConfigValue_DVFSMode) == DVFSMode_Hijack) {
|
||||
DVFSBeforeSet(targetHz);
|
||||
}
|
||||
isGovernorEnabled = newGovernorState;
|
||||
}
|
||||
|
||||
if(module == HorizonOCModule_Display && this->config->GetConfigValue(HorizonOCConfigValue_OverwriteRefreshRate) && Board::GetConsoleType() != HorizonOCConsoleType_Hoag) {
|
||||
if(targetHz)
|
||||
Board::SetHz(HorizonOCModule_Display, targetHz);
|
||||
else
|
||||
Board::ResetToStockDisplay();
|
||||
Board::SetHz((SysClkModule)module, nearestHz);
|
||||
this->context->freqs[module] = nearestHz;
|
||||
|
||||
}
|
||||
|
||||
if(targetHz && this->context->realFreqs[HorizonOCModule_Display] != targetHz && module == HorizonOCModule_Display)
|
||||
this->context->realFreqs[HorizonOCModule_Display] = targetHz;
|
||||
|
||||
// Skip GPU if governor handles it
|
||||
if(module > SysClkModule_MEM) {
|
||||
continue;
|
||||
}
|
||||
if(isGovernorEnabled) {
|
||||
noGPU = true;
|
||||
} else {
|
||||
noGPU = false;
|
||||
}
|
||||
if(noGPU && module == SysClkModule_GPU)
|
||||
continue;
|
||||
|
||||
if (targetHz)
|
||||
{
|
||||
maxHz = this->GetMaxAllowedHz((SysClkModule)module, this->context->profile);
|
||||
nearestHz = this->GetNearestHz((SysClkModule)module, targetHz, maxHz);
|
||||
|
||||
if (nearestHz != this->context->freqs[module]) {
|
||||
FileUtils::LogLine(
|
||||
"[mgr] %s clock set : %u.%u MHz (target = %u.%u MHz)",
|
||||
Board::GetModuleName((SysClkModule)module, true),
|
||||
nearestHz / 1000000, nearestHz / 100000 - nearestHz / 1000000 * 10,
|
||||
targetHz / 1000000, targetHz / 100000 - targetHz / 1000000 * 10
|
||||
);
|
||||
|
||||
if(module == SysClkModule_MEM && Board::GetSocType() == SysClkSocType_Mariko && targetHz > oldHz && this->config->GetConfigValue(HorizonOCConfigValue_DVFSMode) == DVFSMode_Hijack) {
|
||||
s32 dvfsOffset = this->config->GetConfigValue(HorizonOCConfigValue_DVFSOffset);
|
||||
u32 vmin = Board::GetMinimumGpuVoltage(targetHz / 1000000) + dvfsOffset;
|
||||
|
||||
Board::PcvHijackDvfs(vmin);
|
||||
|
||||
/* Update the voltage. */
|
||||
if (I2c_BuckConverter_GetMvOut(&I2c_Mariko_GPU) < vmin) {
|
||||
I2c_BuckConverter_SetMvOut(&I2c_Mariko_GPU, vmin);
|
||||
}
|
||||
|
||||
this->context->voltages[HocClkVoltage_GPU] = vmin * 1000;
|
||||
}
|
||||
|
||||
Board::SetHz((SysClkModule)module, nearestHz);
|
||||
this->context->freqs[module] = nearestHz;
|
||||
if(module == SysClkModule_CPU && (this->config->GetConfigValue(HorizonOCConfigValue_LiveCpuUv) || (kipAvailable && Board::GetSocType() == SysClkSocType_Erista)))
|
||||
{
|
||||
HandleCpuUv();
|
||||
}
|
||||
|
||||
if(module == SysClkModule_MEM && Board::GetSocType() == SysClkSocType_Mariko && targetHz < oldHz && this->config->GetConfigValue(HorizonOCConfigValue_DVFSMode) == DVFSMode_Hijack) {
|
||||
s32 dvfsOffset = this->config->GetConfigValue(HorizonOCConfigValue_DVFSOffset);
|
||||
dvfsOffset = std::max(dvfsOffset, -50);
|
||||
u32 vmin = Board::GetMinimumGpuVoltage(targetHz / 1000000) + dvfsOffset;
|
||||
Board::PcvHijackDvfs(vmin);
|
||||
|
||||
targetHz = this->context->overrideFreqs[SysClkModule_GPU];
|
||||
if (!targetHz)
|
||||
{
|
||||
targetHz = this->config->GetAutoClockHz(this->context->applicationId, SysClkModule_GPU, this->context->profile, false);
|
||||
if(!targetHz)
|
||||
targetHz = this->config->GetAutoClockHz(GLOBAL_PROFILE_ID, SysClkModule_GPU, this->context->profile, false);
|
||||
}
|
||||
if(targetHz) {
|
||||
Board::SetHz(SysClkModule_GPU, ~0);
|
||||
Board::SetHz(SysClkModule_GPU, targetHz);
|
||||
} else {
|
||||
Board::SetHz(SysClkModule_GPU, ~0);
|
||||
Board::ResetToStockGpu();
|
||||
}
|
||||
DVFSAfterSet(targetHz);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
HandleFreqReset((SysClkModule)module, isBoost);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ClockManager::Tick()
|
||||
{
|
||||
std::scoped_lock lock{this->contextMutex};
|
||||
std::uint32_t mode = 0;
|
||||
Result rc = apmExtGetCurrentPerformanceConfiguration(&mode);
|
||||
ASSERT_RESULT_OK(rc, "apmExtGetCurrentPerformanceConfiguration");
|
||||
|
||||
bool isBoost = apmExtIsBoostMode(mode);
|
||||
|
||||
HandleSafetyFeatures();
|
||||
|
||||
if (this->RefreshContext() || this->config->Refresh())
|
||||
{
|
||||
HandleMiscFeatures();
|
||||
SetClocks(isBoost);
|
||||
}
|
||||
}
|
||||
|
||||
void ClockManager::ResetToStockClocks() {
|
||||
Board::ResetToStockCpu();
|
||||
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
|
||||
Board::SetCpuUvLevel(this->config->GetConfigValue(KipConfigValue_marikoCpuUVLow), this->config->GetConfigValue(KipConfigValue_marikoCpuUVHigh), Board::CalculateTbreak(this->config->GetConfigValue(KipConfigValue_tableConf)));
|
||||
}
|
||||
|
||||
Board::ResetToStockGpu();
|
||||
}
|
||||
|
||||
@@ -615,7 +934,6 @@ bool ClockManager::RefreshContext()
|
||||
FileUtils::LogLine("[mgr] TitleID change: %016lX", applicationId);
|
||||
this->context->applicationId = applicationId;
|
||||
hasChanged = true;
|
||||
this->rnxSync->Reset(applicationId);
|
||||
}
|
||||
|
||||
SysClkProfile profile = Board::GetProfile();
|
||||
@@ -629,7 +947,6 @@ bool ClockManager::RefreshContext()
|
||||
// restore clocks to stock values on app or profile change
|
||||
if (hasChanged)
|
||||
{
|
||||
// this->rnxSync->ToggleSync(this->GetConfig()->GetConfigValue(HocClkConfigValue_SyncReverseNXMode));
|
||||
Board::ResetToStock();
|
||||
if (Board::GetSocType() == SysClkSocType_Mariko && this->config->GetConfigValue(HorizonOCConfigValue_DVFSMode) == DVFSMode_Hijack) {
|
||||
Board::PcvHijackDvfs(0);
|
||||
@@ -657,43 +974,6 @@ bool ClockManager::RefreshContext()
|
||||
{
|
||||
FileUtils::LogLine("[mgr] %s override change: %u.%u MHz", Board::GetModuleName((SysClkModule)module, true), hz / 1000000, hz / 100000 - hz / 1000000 * 10);
|
||||
}
|
||||
else
|
||||
{
|
||||
FileUtils::LogLine("[mgr] %s override disabled", Board::GetModuleName((SysClkModule)module, true));
|
||||
switch (module)
|
||||
{
|
||||
case SysClkModule_CPU:
|
||||
if(!(apmExtIsBoostMode(mode) || (this->config->GetConfigValue(HocClkConfigValue_OverwriteBoostMode) && apmExtIsBoostMode(mode))))
|
||||
Board::ResetToStockCpu();
|
||||
break;
|
||||
case SysClkModule_GPU:
|
||||
Board::ResetToStockGpu();
|
||||
break;
|
||||
case SysClkModule_MEM:
|
||||
Board::ResetToStockMem();
|
||||
|
||||
if (Board::GetSocType() == SysClkSocType_Mariko && this->config->GetConfigValue(HorizonOCConfigValue_DVFSMode) == DVFSMode_Hijack) {
|
||||
Board::PcvHijackDvfs(0);
|
||||
|
||||
u32 targetHz = this->context->overrideFreqs[SysClkModule_GPU];
|
||||
if (!targetHz)
|
||||
{
|
||||
targetHz = this->config->GetAutoClockHz(this->context->applicationId, SysClkModule_GPU, this->context->profile, false);
|
||||
if(!targetHz)
|
||||
targetHz = this->config->GetAutoClockHz(GLOBAL_PROFILE_ID, SysClkModule_GPU, this->context->profile, false);
|
||||
}
|
||||
if(targetHz) {
|
||||
Board::SetHz(SysClkModule_GPU, ~0);
|
||||
Board::SetHz(SysClkModule_GPU, targetHz);
|
||||
} else {
|
||||
Board::SetHz(SysClkModule_GPU, ~0);
|
||||
Board::ResetToStockGpu();
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
this->context->overrideFreqs[module] = hz;
|
||||
hasChanged = true;
|
||||
}
|
||||
@@ -756,7 +1036,7 @@ bool ClockManager::RefreshContext()
|
||||
FileUtils::WriteContextToCsv(this->context);
|
||||
}
|
||||
|
||||
this->context->maxDisplayFreq = Board::GetHighestDockedDisplayRate();
|
||||
// this->context->maxDisplayFreq = Board::GetHighestDockedDisplayRate();
|
||||
|
||||
u32 targetHz = this->context->overrideFreqs[HorizonOCModule_Display];
|
||||
if (!targetHz)
|
||||
@@ -766,18 +1046,15 @@ bool ClockManager::RefreshContext()
|
||||
targetHz = this->config->GetAutoClockHz(GLOBAL_PROFILE_ID, HorizonOCModule_Display, this->context->profile, true);
|
||||
}
|
||||
|
||||
if(targetHz && this->context->realFreqs[HorizonOCModule_Display] > targetHz)
|
||||
if(targetHz && this->context->realFreqs[HorizonOCModule_Display] > targetHz && this->context->profile != SysClkProfile_Docked)
|
||||
this->context->realFreqs[HorizonOCModule_Display] = targetHz; // clean up display real freqs, should probably be moved to the real freqs loop?
|
||||
|
||||
if(Board::GetConsoleType() != HorizonOCConsoleType_Hoag)
|
||||
Board::SetDisplayRefreshDockedState(this->context->profile == SysClkProfile_Docked);
|
||||
|
||||
return hasChanged;
|
||||
}
|
||||
|
||||
void ClockManager::SetRNXRTMode(ReverseNXMode mode)
|
||||
{
|
||||
this->rnxSync->SetRTMode(mode);
|
||||
}
|
||||
|
||||
void ClockManager::SetKipData() {
|
||||
// TODO: figure out if this REALLY causes issues (i doubt it)
|
||||
// if(Board::GetSocType() == SysClkSocType_Mariko) {
|
||||
@@ -1056,4 +1333,4 @@ void ClockManager::GetKipData() {
|
||||
FileUtils::LogLine("[clock_manager] Config refresh error in GetKipData!");
|
||||
writeNotification("Horizon OC\nConfig refresh failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,52 +23,199 @@
|
||||
* stuff is worth it, you can buy us a beer in return. - The sys-clk authors
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <sysclk.h>
|
||||
#include <switch.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "board.h"
|
||||
#include <nxExt/cpp/lockable_mutex.h>
|
||||
#include "integrations.h"
|
||||
void governorThread(void*);
|
||||
|
||||
class ReverseNXSync;
|
||||
|
||||
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);
|
||||
|
||||
/**
|
||||
* Handles safety features
|
||||
*
|
||||
*/
|
||||
void HandleSafetyFeatures();
|
||||
|
||||
/**
|
||||
* Handles misc features (currently only battery charge current).
|
||||
*
|
||||
*/
|
||||
void HandleMiscFeatures();
|
||||
|
||||
/**
|
||||
* Handles governor state resolution and applies CPU/GPU governor transitions.
|
||||
*
|
||||
* @param targetHz Governor override value for the current profile.
|
||||
*/
|
||||
void HandleGovernor(uint32_t targetHz);
|
||||
|
||||
/**
|
||||
* Handles DVFS logic before the frequency set
|
||||
*
|
||||
* @param targetHz Governor override value for the current profile.
|
||||
*/
|
||||
void DVFSBeforeSet(u32 targetHz);
|
||||
|
||||
/**
|
||||
* Handles DVFS logic after the frequency set
|
||||
*
|
||||
* @param targetHz Governor override value for the current profile.
|
||||
*/
|
||||
void DVFSAfterSet(u32 targetHz);
|
||||
|
||||
/**
|
||||
* Reset the GPU vMin
|
||||
*
|
||||
*/
|
||||
void DVFSReset();
|
||||
|
||||
/**
|
||||
* Handles the Live CPU UV Feature
|
||||
*
|
||||
*/
|
||||
void HandleCpuUv();
|
||||
|
||||
/**
|
||||
* Handles frequency resets
|
||||
*
|
||||
* @param module The module to reset frequency for
|
||||
* @param isBoost Is in boost mode
|
||||
*/
|
||||
void HandleFreqReset(SysClkModule module, bool isBoost);
|
||||
|
||||
/**
|
||||
* Sets clocks
|
||||
*
|
||||
* @param isBoost Is in boost mode
|
||||
*/
|
||||
void SetClocks(bool isBoost);
|
||||
|
||||
/**
|
||||
* Main function, runs every 5s in sleep mode, and a user specified amount when awake
|
||||
*
|
||||
*/
|
||||
void Tick();
|
||||
|
||||
/**
|
||||
* Reset CPU/GPU to stock values
|
||||
*
|
||||
*/
|
||||
void ResetToStockClocks();
|
||||
|
||||
/**
|
||||
* Wait for the next tick event
|
||||
*
|
||||
*/
|
||||
void WaitForNextTick();
|
||||
void SetRNXRTMode(ReverseNXMode mode);
|
||||
|
||||
/**
|
||||
* Set the data in the KIP
|
||||
*
|
||||
*/
|
||||
void SetKipData();
|
||||
|
||||
/**
|
||||
* Get the data from the KIP
|
||||
*
|
||||
*/
|
||||
void GetKipData();
|
||||
|
||||
/**
|
||||
* Runs the CPU Governor
|
||||
*
|
||||
* @param arg Cast to ClockManager* for context
|
||||
*/
|
||||
static void CpuGovernorThread(void* arg);
|
||||
|
||||
/**
|
||||
* Runs the GPU Governor
|
||||
*
|
||||
* @param arg Cast to ClockManager* for context
|
||||
*/
|
||||
static void GovernorThread(void* arg);
|
||||
|
||||
/**
|
||||
* Gets the effective governor state from application/temporary override
|
||||
*
|
||||
* @param appState Governor state from app
|
||||
* @param tempState Governor state from temporary override
|
||||
*/
|
||||
GovernorState GetEffectiveGovernorState(GovernorState appState, GovernorState tempState);
|
||||
|
||||
/**
|
||||
* Frequency tables
|
||||
*
|
||||
*/
|
||||
struct {
|
||||
std::uint32_t count;
|
||||
std::uint32_t list[SYSCLK_FREQ_LIST_MAX];
|
||||
} freqTable[SysClkModule_EnumMax];
|
||||
|
||||
/**
|
||||
* Gets the current GPU speedo bracket
|
||||
*
|
||||
* @param speedo GPU Speedo
|
||||
*/
|
||||
int GetSpeedoBracket (int speedo);
|
||||
|
||||
/**
|
||||
* Gets the required vMin for a ram frequency for a speedo
|
||||
*
|
||||
* @param freq RAM Freq in MHz
|
||||
* @param speedo GPU Speedo
|
||||
*/
|
||||
unsigned int GetGpuVoltage (unsigned int freq, int speedo);
|
||||
void calculateGpuVmin(void);
|
||||
|
||||
protected:
|
||||
bool IsAssignableHz(SysClkModule module, std::uint32_t hz);
|
||||
inline std::uint32_t GetMaxAllowedHz(SysClkModule module, SysClkProfile profile);
|
||||
@@ -76,9 +223,7 @@ class ClockManager
|
||||
bool ConfigIntervalTimeout(SysClkConfigValue intervalMsConfigValue, std::uint64_t ns, std::uint64_t* lastLogNs);
|
||||
void RefreshFreqTableRow(SysClkModule module);
|
||||
bool RefreshContext();
|
||||
|
||||
static ClockManager *instance;
|
||||
|
||||
std::atomic_bool running;
|
||||
LockableMutex contextMutex;
|
||||
Config* config;
|
||||
@@ -87,5 +232,5 @@ class ClockManager
|
||||
std::uint64_t lastFreqLogNs;
|
||||
std::uint64_t lastPowerLogNs;
|
||||
std::uint64_t lastCsvWriteNs;
|
||||
ReverseNXSync *rnxSync;
|
||||
};
|
||||
SysDockIntegration *sysDockIntegration;
|
||||
};
|
||||
@@ -17,68 +17,16 @@
|
||||
|
||||
|
||||
#include "integrations.h"
|
||||
#include <sys/stat.h>
|
||||
|
||||
ReverseNXSync::ReverseNXSync()
|
||||
: m_rt_mode(ReverseNX_NotFound), m_tool_mode(ReverseNX_NotFound) {
|
||||
FILE *fp = fopen("/atmosphere/contents/0000000000534C56/flags/boot2.flag", "r");
|
||||
m_tool_enabled = fp ? true : false;
|
||||
if (fp)
|
||||
fclose(fp);
|
||||
SysDockIntegration::SysDockIntegration() {
|
||||
}
|
||||
|
||||
SysClkProfile ReverseNXSync::GetProfile(SysClkProfile real) {
|
||||
switch (this->GetMode()) {
|
||||
case ReverseNX_Docked:
|
||||
return SysClkProfile_Docked;
|
||||
case ReverseNX_Handheld:
|
||||
if (real == SysClkProfile_Docked)
|
||||
return SysClkProfile_HandheldChargingOfficial;
|
||||
default:
|
||||
return real;
|
||||
bool SysDockIntegration::getCurrentSysDockState() {
|
||||
struct stat st = {0};
|
||||
if (stat("sdmc:/atmosphere/contents/42000000000000A0", &st) == 0 && S_ISDIR(st.st_mode)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ReverseNXMode ReverseNXSync::GetMode() {
|
||||
if (!this->m_sync_enabled)
|
||||
return ReverseNX_NotFound;
|
||||
if (this->m_rt_mode)
|
||||
return this->m_rt_mode;
|
||||
return this->m_tool_mode;
|
||||
}
|
||||
|
||||
ReverseNXMode ReverseNXSync::GetToolModeFromPatch(const char* patch_path) {
|
||||
constexpr uint32_t DOCKED_MAGIC = 0x320003E0;
|
||||
constexpr uint32_t HANDHELD_MAGIC = 0x52A00000;
|
||||
FILE *fp = fopen(patch_path, "rb");
|
||||
if (fp) {
|
||||
uint32_t buf = 0;
|
||||
fread(&buf, sizeof(buf), 1, fp);
|
||||
fclose(fp);
|
||||
|
||||
if (buf == DOCKED_MAGIC)
|
||||
return ReverseNX_Docked;
|
||||
if (buf == HANDHELD_MAGIC)
|
||||
return ReverseNX_Handheld;
|
||||
}
|
||||
|
||||
return ReverseNX_NotFound;
|
||||
}
|
||||
|
||||
ReverseNXMode ReverseNXSync::RecheckToolMode() {
|
||||
ReverseNXMode mode = ReverseNX_NotFound;
|
||||
if (this->m_tool_enabled) {
|
||||
const char* fileName = "_ZN2nn2oe18GetPerformanceModeEv.asm64"; // or _ZN2nn2oe18GetPerformanceModeEv.asm64
|
||||
const char* filePath = new char[72];
|
||||
SCOPE_EXIT { delete[] filePath; };
|
||||
/* Check per-game patch */
|
||||
snprintf((char*)filePath, 72, "/SaltySD/patches/%016lX/%s", this->m_app_id, fileName);
|
||||
mode = this->GetToolModeFromPatch(filePath);
|
||||
if (!mode) {
|
||||
/* Check global patch */
|
||||
snprintf((char*)filePath, 72, "/SaltySD/patches/%s", fileName);
|
||||
mode = this->GetToolModeFromPatch(filePath);
|
||||
}
|
||||
}
|
||||
|
||||
return mode;
|
||||
}
|
||||
@@ -29,25 +29,9 @@
|
||||
|
||||
#include "clock_manager.h"
|
||||
|
||||
class ReverseNXSync {
|
||||
class SysDockIntegration {
|
||||
public:
|
||||
ReverseNXSync ();
|
||||
SysDockIntegration();
|
||||
|
||||
void ToggleSync(bool enable) { m_sync_enabled = enable; };
|
||||
void Reset(uint64_t app_id) { m_app_id = app_id; SetRTMode(ReverseNX_NotFound); GetToolMode(); }
|
||||
ReverseNXMode GetRTMode() { return m_rt_mode; };
|
||||
void SetRTMode(ReverseNXMode mode) { m_rt_mode = mode; };
|
||||
ReverseNXMode GetToolMode() { return m_tool_mode = RecheckToolMode(); };
|
||||
SysClkProfile GetProfile(SysClkProfile real);
|
||||
ReverseNXMode GetMode();
|
||||
|
||||
protected:
|
||||
std::atomic<ReverseNXMode> m_rt_mode;
|
||||
ReverseNXMode m_tool_mode;
|
||||
uint64_t m_app_id = 0;
|
||||
bool m_tool_enabled;
|
||||
bool m_sync_enabled;
|
||||
|
||||
ReverseNXMode GetToolModeFromPatch(const char* patch_path);
|
||||
ReverseNXMode RecheckToolMode();
|
||||
bool getCurrentSysDockState();
|
||||
};
|
||||
@@ -198,12 +198,6 @@ Result IpcService::ServiceHandlerFunc(void* arg, const IpcServerRequest* r, u8*
|
||||
);
|
||||
}
|
||||
break;
|
||||
case SysClkIpcCmd_SetReverseNXRTMode:
|
||||
if (r->data.size >= sizeof(ReverseNXMode)) {
|
||||
ReverseNXMode mode = *((ReverseNXMode*)r->data.ptr);
|
||||
return ipcSrv->SetReverseNXRTMode(mode);
|
||||
}
|
||||
break;
|
||||
case HocClkIpcCmd_SetKipData:
|
||||
if (r->data.size >= 0) {
|
||||
return ipcSrv->SetKipData();
|
||||
@@ -361,10 +355,6 @@ Result IpcService::GetFreqList(SysClkIpc_GetFreqList_Args* args, std::uint32_t*
|
||||
return 0;
|
||||
}
|
||||
|
||||
Result IpcService::SetReverseNXRTMode(ReverseNXMode mode) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Result IpcService::SetKipData() {
|
||||
this->clockMgr->SetKipData();
|
||||
|
||||
|
||||
@@ -54,7 +54,6 @@ class IpcService
|
||||
Result GetConfigValues(SysClkConfigValueList* out_configValues);
|
||||
Result SetConfigValues(SysClkConfigValueList* configValues);
|
||||
Result GetFreqList(SysClkIpc_GetFreqList_Args* args, std::uint32_t* out_list, std::size_t size, std::uint32_t* out_count);
|
||||
Result SetReverseNXRTMode(ReverseNXMode mode);
|
||||
Result SetKipData();
|
||||
Result GetKipData();
|
||||
bool running;
|
||||
|
||||
164
dist/README.md
vendored
164
dist/README.md
vendored
@@ -1,164 +0,0 @@
|
||||
|
||||
<div align="center">
|
||||
|
||||
<img src="assets/logo.png" alt="logo" width="350"/>
|
||||
|
||||
---
|
||||
|
||||

|
||||

|
||||
[](https://dsc.gg/horizonoc)
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
---
|
||||
|
||||
</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
|
||||
secmon=exosphere.bin
|
||||
```
|
||||
|
||||
*(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
|
||||
|
||||
### 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 in handheld and capped at 768MHz if charging, unless you're using the official charger.
|
||||
2. Clocks higher than 768MHz need the official charger is plugged in.
|
||||
|
||||
---
|
||||
|
||||
## 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 and Xenshen** - Testing
|
||||
* **Samybigio2011** - Italian translations
|
||||
BIN
dist/atmosphere/contents/00FF0000636C6BFF/exefs.nsp
vendored
BIN
dist/atmosphere/contents/00FF0000636C6BFF/exefs.nsp
vendored
Binary file not shown.
BIN
dist/atmosphere/kips/hoc.kip
vendored
BIN
dist/atmosphere/kips/hoc.kip
vendored
Binary file not shown.
132
dist/config/horizon-oc/lang/en.json
vendored
Normal file
132
dist/config/horizon-oc/lang/en.json
vendored
Normal file
@@ -0,0 +1,132 @@
|
||||
{
|
||||
"Horizon OC Zeus": "Horizon OC Zeus",
|
||||
"Edit App Profile": "Edit App Profile",
|
||||
"Advanced": "Advanced",
|
||||
"Edit Global Profile": "Edit Global Profile",
|
||||
"Temporary Overrides": "Temporary Overrides",
|
||||
"Temporary Overrides Reset": "Temporary Overrides Reset",
|
||||
"Settings": "Settings",
|
||||
"Information": "Information",
|
||||
"Enable": "Enable",
|
||||
"Uncapped Clocks": "Uncapped Clocks",
|
||||
"Override Boost Mode": "Override Boost Mode",
|
||||
"CPU Max Display Clock": "CPU Max Display Clock",
|
||||
"Thermal Throttle": "Thermal Throttle",
|
||||
"Thermal Throttle Threshold": "Thermal Throttle Threshold",
|
||||
"Handheld TDP": "Handheld TDP",
|
||||
"Handheld TDP Limit": "Handheld TDP Limit",
|
||||
"Lite TDP Limit": "Lite TDP Limit",
|
||||
"Enforce Board Limit": "Enforce Board Limit",
|
||||
"Battery Charge Current": "Battery Charge Current",
|
||||
"Display Refresh Rate Changing": "Display Refresh Rate Changing",
|
||||
"Fix CPU Volt Bug": "Fix CPU Volt Bug",
|
||||
"[cfg] no enum format string": "[cfg] no enum format string",
|
||||
"KIP": "KIP",
|
||||
"Save KIP Settings": "Save KIP Settings",
|
||||
"RAM Settings": "RAM Settings",
|
||||
"CPU Settings": "CPU Settings",
|
||||
"GPU Settings": "GPU Settings",
|
||||
"Experimental": "Experimental",
|
||||
"Charge Current Override": "Charge Current Override",
|
||||
"Disabled": "Disabled",
|
||||
"HP Mode": "HP Mode",
|
||||
"EMC Max Clock": "EMC Max Clock",
|
||||
"EMC VDD2 Voltage": "EMC VDD2 Voltage",
|
||||
"EMC VDDQ Voltage": "EMC VDDQ Voltage",
|
||||
"DVB Shift": "DVB Shift",
|
||||
"Memory Timings": "Memory Timings",
|
||||
"Memory Latencies": "Memory Latencies",
|
||||
"t1 tRCD": "t1 tRCD",
|
||||
"t2 tRP": "t2 tRP",
|
||||
"t3 tRAS": "t3 tRAS",
|
||||
"t4 tRRD": "t4 tRRD",
|
||||
"t5 tRFC": "t5 tRFC",
|
||||
"t6 tRTW": "t6 tRTW",
|
||||
"t7 tWTR": "t7 tWTR",
|
||||
"t8 tREFI": "t8 tREFI",
|
||||
"Update RAM Timings": "Update RAM Timings",
|
||||
"\uE150 This feature is EXPERIMENTAL": "\uE150 This feature is EXPERIMENTAL",
|
||||
"and should only be used for testing!": "and should only be used for testing!",
|
||||
"Read Latency": "Read Latency",
|
||||
"Write Latency": "Write Latency",
|
||||
"CPU UV": "CPU UV",
|
||||
"CPU Unlock": "CPU Unlock",
|
||||
"CPU VMIN": "CPU VMIN",
|
||||
"CPU Max Voltage": "CPU Max Voltage",
|
||||
"CPU UV Table": "CPU UV Table",
|
||||
"CPU Low UV": "CPU Low UV",
|
||||
"CPU High UV": "CPU High UV",
|
||||
"CPU Max Clock": "CPU Max Clock",
|
||||
"CPU Low VMIN": "CPU Low VMIN",
|
||||
"CPU High VMIN": "CPU High VMIN",
|
||||
"GPU Undervolt Table": "GPU Undervolt Table",
|
||||
"Calculate GPU Vmin": "Calculate GPU Vmin",
|
||||
"GPU VMIN": "GPU VMIN",
|
||||
"GPU VMAX": "GPU VMAX",
|
||||
"GPU Volt Offset": "GPU Volt Offset",
|
||||
"GPU Custom Table": "GPU Custom Table",
|
||||
"GPU Custom Table (mV)": "GPU Custom Table (mV)",
|
||||
"\uE150 Setting GPU Clocks past": "\uE150 Setting GPU Clocks past",
|
||||
"1075MHz without UV, 1152MHz on SLT or ": "1075MHz without UV, 1152MHz on SLT or ",
|
||||
"1228MHz on HiOPT can cause ": "1228MHz on HiOPT can cause ",
|
||||
"permanent damage to your Switch!": "permanent damage to your Switch!",
|
||||
"Proceed at your own risk!": "Proceed at your own risk!",
|
||||
"921MHz without UV and 960MHz on": "921MHz without UV and 960MHz on",
|
||||
"SLT or HiOPT can cause ": "SLT or HiOPT can cause ",
|
||||
"Auto": "Auto",
|
||||
"Sleep Mode": "Sleep Mode",
|
||||
"Stock": "Stock",
|
||||
"Dev OC": "Dev OC",
|
||||
"Boost Mode": "Boost Mode",
|
||||
"Safe Max": "Safe Max",
|
||||
"Unsafe Max": "Unsafe Max",
|
||||
"Absolute Max": "Absolute Max",
|
||||
"Boost Mode & Safe Max": "Boost Mode & Safe Max",
|
||||
"Official Rating": "Official Rating",
|
||||
"Default (Mariko)": "Default (Mariko)",
|
||||
"Default (Erista)": "Default (Erista)",
|
||||
"Rating": "Rating",
|
||||
"Safe Max (Mariko)": "Safe Max (Mariko)",
|
||||
"Safe Max (Erista)": "Safe Max (Erista)",
|
||||
"Default": "Default",
|
||||
"1581MHz Tbreak": "1581MHz Tbreak",
|
||||
"1683MHz Tbreak": "1683MHz Tbreak",
|
||||
"Extreme UV Table": "Extreme UV Table",
|
||||
"No UV": "No UV",
|
||||
"SLT Table": "SLT Table",
|
||||
"HiOPT Table": "HiOPT Table",
|
||||
"Power": "Power",
|
||||
"Temp": "Temp",
|
||||
"Voltage": "Voltage",
|
||||
"TDP Threshold": "TDP Threshold",
|
||||
"Lite TDP Threshold": "Lite TDP Threshold",
|
||||
"Thermal Throttle Limit": "Thermal Throttle Limit",
|
||||
"1600BL": "1600BL",
|
||||
"1866BL": "1866BL",
|
||||
"2133BL": "2133BL",
|
||||
"BAT": "BAT",
|
||||
"FAN": "FAN",
|
||||
"DISP": "DISP",
|
||||
"Board": "Board",
|
||||
"Skin": "Skin",
|
||||
"Now": "Now",
|
||||
"Avg": "Avg",
|
||||
"App ID": "App ID",
|
||||
"Profile": "Profile",
|
||||
"CPU": "CPU",
|
||||
"GPU": "GPU",
|
||||
"Memory": "Memory",
|
||||
"Display": "Display",
|
||||
"Governor": "Governor",
|
||||
"SOC": "SOC",
|
||||
"PCB": "PCB",
|
||||
"PMIC": "PMIC",
|
||||
"Docked": "Docked",
|
||||
"Handheld": "Handheld",
|
||||
"Charging": "Charging",
|
||||
"USB Charger": "USB Charger",
|
||||
"PD Charger": "PD Charger",
|
||||
"VDD2": "VDD2",
|
||||
"VDDQ": "VDDQ",
|
||||
"GPU DVFS": "GPU DVFS"
|
||||
}
|
||||
35
dist/config/horizon-oc/lang/es.json
vendored
Normal file
35
dist/config/horizon-oc/lang/es.json
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"Edit App Profile": "Editar perfil de la app",
|
||||
"Advanced": "Avanzado",
|
||||
"Edit Global Profile": "Editar perfil global",
|
||||
"Temporary Overrides": "Anulaciones temporales",
|
||||
"Temporary Overrides Reset": "Anulaciones temporales Reiniciar",
|
||||
"Settings": "Configuración",
|
||||
"Enable": "Habilitar",
|
||||
"Uncapped Clocks": "Relojes sin límite",
|
||||
"Override Boost Mode": "Sobrescribir modo Boost",
|
||||
"Auto CPU Boost": "Impulso automático de CPU",
|
||||
"Sync ReverseNX": "Sincronizar con ReverseNX",
|
||||
"GPU DVFS": "GPU DVFS",
|
||||
"Off": "Apagado",
|
||||
"Official Service Method": "Método de servicio oficial",
|
||||
"Hijack Method": "Método de secuestro",
|
||||
"App ID": "ID App",
|
||||
"EOS mode": "Modo EOS",
|
||||
"Skin": "Tema",
|
||||
"Now": "Ahora",
|
||||
"Avg": "Med",
|
||||
"Docked": "Conectado al dock",
|
||||
"Handheld": "Portátil",
|
||||
"Charging": "Cargando",
|
||||
"PD Charger": "Cargador oficial",
|
||||
"USB Charger": "Cargador USB",
|
||||
"Docked Reset": "Conectado al dock Reiniciar",
|
||||
"Handheld Reset": "Portátil Reiniciar",
|
||||
"Charging Reset": "Cargando Reiniciar",
|
||||
"PD Charger Reset": "Cargador oficial Reiniciar",
|
||||
"USB Charger Reset": "Cargador USB Reiniciar",
|
||||
"Memory": "Memoria",
|
||||
"Default": "No sobrescribir",
|
||||
"Profile": "Perfil"
|
||||
}
|
||||
132
dist/config/horizon-oc/lang/it.json
vendored
Normal file
132
dist/config/horizon-oc/lang/it.json
vendored
Normal file
@@ -0,0 +1,132 @@
|
||||
{
|
||||
"Information about Translation": "This is a translation made by Samybigio2011. If you find any errors, please report them on GitHub, or feel free to contribute!",
|
||||
"Horizon OC Zeus": "Horizon OC Zeus",
|
||||
"Edit App Profile": "Profilo App",
|
||||
"Advanced": "Avanzate",
|
||||
"Edit Global Profile": "Profilo Globale",
|
||||
"Temporary Overrides": "Override Temporaneo",
|
||||
"Temporary Overrides Reset": "Temporary Overrides Reset",
|
||||
"Settings": "Impostazioni",
|
||||
"Information": "Informazioni",
|
||||
"Enable": "Abilita",
|
||||
"Uncapped Clocks": "Sblocca Clock",
|
||||
"Override Boost Mode": "Sovrascrivi Boost Mode",
|
||||
"CPU Max Display Clock": "Massimo Clock CPU mostrato",
|
||||
"Thermal Throttle": "Rallentamento Termico",
|
||||
"Thermal Throttle Threshold": "Soglia Rallentamento Termico",
|
||||
"Handheld TDP": "TPD Handheld",
|
||||
"Handheld TDP Limit": "Limite TDP Handheld",
|
||||
"Lite TDP Limit": "Limite TDP Lite",
|
||||
"Enforce Board Limit": "Forza Limite di Potenza",
|
||||
"Battery Charge Current": "Corrente di Ricarica",
|
||||
"Display Refresh Rate Changing": "Cambio di Frequenza Display",
|
||||
"Fix CPU Volt Bug": "Risolvi Bug CPU",
|
||||
"[cfg] no enum format string": "[cfg] no enum format string",
|
||||
"KIP": "KIP",
|
||||
"Save KIP Settings": "Salva Impotazioni KIP",
|
||||
"RAM Settings": "Impostazioni RAM",
|
||||
"CPU Settings": "Impostazioni CPU",
|
||||
"GPU Settings": "Impostazioni GPU",
|
||||
"Experimental": "Esperimentale",
|
||||
"Charge Current Override": "Sovrascrivi Corrente di Ricarica",
|
||||
"Disabled": "Disabilitato",
|
||||
"HP Mode": "Modalità HP",
|
||||
"EMC Max Clock": "Clock EMC Massimo",
|
||||
"EMC VDD2 Voltage": "Voltaggio VDD2 EMC",
|
||||
"EMC VDDQ Voltage": "Voltaggio VDDQ EMC",
|
||||
"DVB Shift": "Shift DVB",
|
||||
"Memory Timings": "Timing Memoria",
|
||||
"Memory Latencies": "Latency Memoria",
|
||||
"t1 tRCD": "t1 tRCD",
|
||||
"t2 tRP": "t2 tRP",
|
||||
"t3 tRAS": "t3 tRAS",
|
||||
"t4 tRRD": "t4 tRRD",
|
||||
"t5 tRFC": "t5 tRFC",
|
||||
"t6 tRTW": "t6 tRTW",
|
||||
"t7 tWTR": "t7 tWTR",
|
||||
"t8 tREFI": "t8 tREFI",
|
||||
"Update RAM Timings": "Aggiorna Timing RAM",
|
||||
"\uE150 This feature is EXPERIMENTAL": "\uE150 Questa funzione è ESPERIMENRALE!",
|
||||
"and should only be used for testing!": "e dovrebbe essere usata solo per testare!",
|
||||
"Read Latency": "Latency Lettura",
|
||||
"Write Latency": "Latency Scrittura",
|
||||
"CPU UV": "UV CPU",
|
||||
"CPU Unlock": "Sblocco CPU",
|
||||
"CPU VMIN": "VMIN CPU",
|
||||
"CPU Max Voltage": "Voltaggio Massimo CPU",
|
||||
"CPU UV Table": "Tavola UV CPU",
|
||||
"CPU Low UV": "UV Basso CPU",
|
||||
"CPU High UV": "UV Alto CPU",
|
||||
"CPU Max Clock": "Clock Massimo CPU",
|
||||
"CPU Low VMIN": "VMIN Basso CPU",
|
||||
"CPU High VMIN": "VMIN Alto CPU",
|
||||
"GPU Undervolt Table": "Tavola Undervolt GPU",
|
||||
"Calculate GPU Vmin": "Calcola VMIN GPU",
|
||||
"GPU VMIN": "VMIN GPU",
|
||||
"GPU VMAX": "VMAX GPU",
|
||||
"GPU Volt Offset": "Offset Voltaggio GPU",
|
||||
"GPU Custom Table": "Tavola GPU Custom",
|
||||
"GPU Custom Table (mV)": "Tavola GPU Custom (mV)",
|
||||
"\uE150 Setting GPU Clocks past": "\uE150 Impostare Clock GPU oltre",
|
||||
"1075MHz without UV, 1152MHz on SLT or ": "1075MHz senza UV, 1152MHz su SLT o ",
|
||||
"1228MHz on HiOPT can cause ": "1228MHz su HiOPT può causare ",
|
||||
"permanent damage to your Switch!": "danni permanenti alla tua console!",
|
||||
"Proceed at your own risk!": "Procedi al tuo rischio!",
|
||||
"921MHz without UV and 960MHz on": "921MHz senza UV e 960MHz su",
|
||||
"SLT or HiOPT can cause ": "SLT o HiOPT può causare ",
|
||||
"Auto": "Auto",
|
||||
"Sleep Mode": "Modalità Sleep",
|
||||
"Stock": "Stock",
|
||||
"Dev OC": "OC Sviluppo",
|
||||
"Boost Mode": "Modalità Boost",
|
||||
"Safe Max": "Massimo Sicuro",
|
||||
"Unsafe Max": "Massimo Insicuro",
|
||||
"Absolute Max": "Massimo Assoluto",
|
||||
"Boost Mode & Safe Max": "Modalità Boost e Massimo Sicuro",
|
||||
"Official Rating": "Rating Ufficiale",
|
||||
"Default (Mariko)": "Default (Mariko)",
|
||||
"Default (Erista)": "Default (Erista)",
|
||||
"Rating": "Rating",
|
||||
"Safe Max (Mariko)": "Max Sicuro (Mariko)",
|
||||
"Safe Max (Erista)": "Max Sicuro (Erista)",
|
||||
"Default": "Default",
|
||||
"1581MHz Tbreak": "Tbreak 1581MHz",
|
||||
"1683MHz Tbreak": "Tbreak 1683MHz",
|
||||
"Extreme UV Table": "Tavola UV Estremo",
|
||||
"No UV": "No UV",
|
||||
"SLT Table": "Tavola SLT",
|
||||
"HiOPT Table": "Tavola HiOPT",
|
||||
"Power": "Potenza",
|
||||
"Temp": "Temperatura",
|
||||
"Voltage": "Voltaggio",
|
||||
"TDP Threshold": "Soglia TDP",
|
||||
"Lite TDP Threshold": "Soglia TDP Lite",
|
||||
"Thermal Throttle Limit": "Limite Rallentamento Termico",
|
||||
"1600BL": "BL1600",
|
||||
"1866BL": "BL1866",
|
||||
"2133BL": "BL2133",
|
||||
"BAT": "BAT",
|
||||
"FAN": "FAN",
|
||||
"DISP": "DISP",
|
||||
"Board": "Scheda",
|
||||
"Skin": "Skin",
|
||||
"Now": "Ora",
|
||||
"Avg": "Med",
|
||||
"App ID": "ID App",
|
||||
"Profile": "Profilo",
|
||||
"CPU": "CPU",
|
||||
"GPU": "GPU",
|
||||
"Memory": "Memoria",
|
||||
"Display": "Display",
|
||||
"Governor": "Governor",
|
||||
"SOC": "SOC",
|
||||
"PCB": "PCB",
|
||||
"PMIC": "PMIC",
|
||||
"Docked": "Dock",
|
||||
"Handheld": "Handheld",
|
||||
"Charging": "In Carica",
|
||||
"USB Charger": "Caricatore USB",
|
||||
"PD Charger": "Caricatore PD",
|
||||
"VDD2": "VDD2",
|
||||
"VDDQ": "VDDQ"
|
||||
}
|
||||
132
dist/config/horizon-oc/lang/lang/en.json
vendored
Normal file
132
dist/config/horizon-oc/lang/lang/en.json
vendored
Normal file
@@ -0,0 +1,132 @@
|
||||
{
|
||||
"Horizon OC Zeus": "Horizon OC Zeus",
|
||||
"Edit App Profile": "Edit App Profile",
|
||||
"Advanced": "Advanced",
|
||||
"Edit Global Profile": "Edit Global Profile",
|
||||
"Temporary Overrides": "Temporary Overrides",
|
||||
"Temporary Overrides Reset": "Temporary Overrides Reset",
|
||||
"Settings": "Settings",
|
||||
"Information": "Information",
|
||||
"Enable": "Enable",
|
||||
"Uncapped Clocks": "Uncapped Clocks",
|
||||
"Override Boost Mode": "Override Boost Mode",
|
||||
"CPU Max Display Clock": "CPU Max Display Clock",
|
||||
"Thermal Throttle": "Thermal Throttle",
|
||||
"Thermal Throttle Threshold": "Thermal Throttle Threshold",
|
||||
"Handheld TDP": "Handheld TDP",
|
||||
"Handheld TDP Limit": "Handheld TDP Limit",
|
||||
"Lite TDP Limit": "Lite TDP Limit",
|
||||
"Enforce Board Limit": "Enforce Board Limit",
|
||||
"Battery Charge Current": "Battery Charge Current",
|
||||
"Display Refresh Rate Changing": "Display Refresh Rate Changing",
|
||||
"Fix CPU Volt Bug": "Fix CPU Volt Bug",
|
||||
"[cfg] no enum format string": "[cfg] no enum format string",
|
||||
"KIP": "KIP",
|
||||
"Save KIP Settings": "Save KIP Settings",
|
||||
"RAM Settings": "RAM Settings",
|
||||
"CPU Settings": "CPU Settings",
|
||||
"GPU Settings": "GPU Settings",
|
||||
"Experimental": "Experimental",
|
||||
"Charge Current Override": "Charge Current Override",
|
||||
"Disabled": "Disabled",
|
||||
"HP Mode": "HP Mode",
|
||||
"EMC Max Clock": "EMC Max Clock",
|
||||
"EMC VDD2 Voltage": "EMC VDD2 Voltage",
|
||||
"EMC VDDQ Voltage": "EMC VDDQ Voltage",
|
||||
"DVB Shift": "DVB Shift",
|
||||
"Memory Timings": "Memory Timings",
|
||||
"Memory Latencies": "Memory Latencies",
|
||||
"t1 tRCD": "t1 tRCD",
|
||||
"t2 tRP": "t2 tRP",
|
||||
"t3 tRAS": "t3 tRAS",
|
||||
"t4 tRRD": "t4 tRRD",
|
||||
"t5 tRFC": "t5 tRFC",
|
||||
"t6 tRTW": "t6 tRTW",
|
||||
"t7 tWTR": "t7 tWTR",
|
||||
"t8 tREFI": "t8 tREFI",
|
||||
"Update RAM Timings": "Update RAM Timings",
|
||||
"\uE150 This feature is EXPERIMENTAL": "\uE150 This feature is EXPERIMENTAL",
|
||||
"and should only be used for testing!": "and should only be used for testing!",
|
||||
"Read Latency": "Read Latency",
|
||||
"Write Latency": "Write Latency",
|
||||
"CPU UV": "CPU UV",
|
||||
"CPU Unlock": "CPU Unlock",
|
||||
"CPU VMIN": "CPU VMIN",
|
||||
"CPU Max Voltage": "CPU Max Voltage",
|
||||
"CPU UV Table": "CPU UV Table",
|
||||
"CPU Low UV": "CPU Low UV",
|
||||
"CPU High UV": "CPU High UV",
|
||||
"CPU Max Clock": "CPU Max Clock",
|
||||
"CPU Low VMIN": "CPU Low VMIN",
|
||||
"CPU High VMIN": "CPU High VMIN",
|
||||
"GPU Undervolt Table": "GPU Undervolt Table",
|
||||
"Calculate GPU Vmin": "Calculate GPU Vmin",
|
||||
"GPU VMIN": "GPU VMIN",
|
||||
"GPU VMAX": "GPU VMAX",
|
||||
"GPU Volt Offset": "GPU Volt Offset",
|
||||
"GPU Custom Table": "GPU Custom Table",
|
||||
"GPU Custom Table (mV)": "GPU Custom Table (mV)",
|
||||
"\uE150 Setting GPU Clocks past": "\uE150 Setting GPU Clocks past",
|
||||
"1075MHz without UV, 1152MHz on SLT or ": "1075MHz without UV, 1152MHz on SLT or ",
|
||||
"1228MHz on HiOPT can cause ": "1228MHz on HiOPT can cause ",
|
||||
"permanent damage to your Switch!": "permanent damage to your Switch!",
|
||||
"Proceed at your own risk!": "Proceed at your own risk!",
|
||||
"921MHz without UV and 960MHz on": "921MHz without UV and 960MHz on",
|
||||
"SLT or HiOPT can cause ": "SLT or HiOPT can cause ",
|
||||
"Auto": "Auto",
|
||||
"Sleep Mode": "Sleep Mode",
|
||||
"Stock": "Stock",
|
||||
"Dev OC": "Dev OC",
|
||||
"Boost Mode": "Boost Mode",
|
||||
"Safe Max": "Safe Max",
|
||||
"Unsafe Max": "Unsafe Max",
|
||||
"Absolute Max": "Absolute Max",
|
||||
"Boost Mode & Safe Max": "Boost Mode & Safe Max",
|
||||
"Official Rating": "Official Rating",
|
||||
"Default (Mariko)": "Default (Mariko)",
|
||||
"Default (Erista)": "Default (Erista)",
|
||||
"Rating": "Rating",
|
||||
"Safe Max (Mariko)": "Safe Max (Mariko)",
|
||||
"Safe Max (Erista)": "Safe Max (Erista)",
|
||||
"Default": "Default",
|
||||
"1581MHz Tbreak": "1581MHz Tbreak",
|
||||
"1683MHz Tbreak": "1683MHz Tbreak",
|
||||
"Extreme UV Table": "Extreme UV Table",
|
||||
"No UV": "No UV",
|
||||
"SLT Table": "SLT Table",
|
||||
"HiOPT Table": "HiOPT Table",
|
||||
"Power": "Power",
|
||||
"Temp": "Temp",
|
||||
"Voltage": "Voltage",
|
||||
"TDP Threshold": "TDP Threshold",
|
||||
"Lite TDP Threshold": "Lite TDP Threshold",
|
||||
"Thermal Throttle Limit": "Thermal Throttle Limit",
|
||||
"1600BL": "1600BL",
|
||||
"1866BL": "1866BL",
|
||||
"2133BL": "2133BL",
|
||||
"BAT": "BAT",
|
||||
"FAN": "FAN",
|
||||
"DISP": "DISP",
|
||||
"Board": "Board",
|
||||
"Skin": "Skin",
|
||||
"Now": "Now",
|
||||
"Avg": "Avg",
|
||||
"App ID": "App ID",
|
||||
"Profile": "Profile",
|
||||
"CPU": "CPU",
|
||||
"GPU": "GPU",
|
||||
"Memory": "Memory",
|
||||
"Display": "Display",
|
||||
"Governor": "Governor",
|
||||
"SOC": "SOC",
|
||||
"PCB": "PCB",
|
||||
"PMIC": "PMIC",
|
||||
"Docked": "Docked",
|
||||
"Handheld": "Handheld",
|
||||
"Charging": "Charging",
|
||||
"USB Charger": "USB Charger",
|
||||
"PD Charger": "PD Charger",
|
||||
"VDD2": "VDD2",
|
||||
"VDDQ": "VDDQ",
|
||||
"GPU DVFS": "GPU DVFS"
|
||||
}
|
||||
35
dist/config/horizon-oc/lang/lang/es.json
vendored
Normal file
35
dist/config/horizon-oc/lang/lang/es.json
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"Edit App Profile": "Editar perfil de la app",
|
||||
"Advanced": "Avanzado",
|
||||
"Edit Global Profile": "Editar perfil global",
|
||||
"Temporary Overrides": "Anulaciones temporales",
|
||||
"Temporary Overrides Reset": "Anulaciones temporales Reiniciar",
|
||||
"Settings": "Configuración",
|
||||
"Enable": "Habilitar",
|
||||
"Uncapped Clocks": "Relojes sin límite",
|
||||
"Override Boost Mode": "Sobrescribir modo Boost",
|
||||
"Auto CPU Boost": "Impulso automático de CPU",
|
||||
"Sync ReverseNX": "Sincronizar con ReverseNX",
|
||||
"GPU DVFS": "GPU DVFS",
|
||||
"Off": "Apagado",
|
||||
"Official Service Method": "Método de servicio oficial",
|
||||
"Hijack Method": "Método de secuestro",
|
||||
"App ID": "ID App",
|
||||
"EOS mode": "Modo EOS",
|
||||
"Skin": "Tema",
|
||||
"Now": "Ahora",
|
||||
"Avg": "Med",
|
||||
"Docked": "Conectado al dock",
|
||||
"Handheld": "Portátil",
|
||||
"Charging": "Cargando",
|
||||
"PD Charger": "Cargador oficial",
|
||||
"USB Charger": "Cargador USB",
|
||||
"Docked Reset": "Conectado al dock Reiniciar",
|
||||
"Handheld Reset": "Portátil Reiniciar",
|
||||
"Charging Reset": "Cargando Reiniciar",
|
||||
"PD Charger Reset": "Cargador oficial Reiniciar",
|
||||
"USB Charger Reset": "Cargador USB Reiniciar",
|
||||
"Memory": "Memoria",
|
||||
"Default": "No sobrescribir",
|
||||
"Profile": "Perfil"
|
||||
}
|
||||
132
dist/config/horizon-oc/lang/lang/it.json
vendored
Normal file
132
dist/config/horizon-oc/lang/lang/it.json
vendored
Normal file
@@ -0,0 +1,132 @@
|
||||
{
|
||||
"Information about Translation": "This is a translation made by Samybigio2011. If you find any errors, please report them on GitHub, or feel free to contribute!",
|
||||
"Horizon OC Zeus": "Horizon OC Zeus",
|
||||
"Edit App Profile": "Profilo App",
|
||||
"Advanced": "Avanzate",
|
||||
"Edit Global Profile": "Profilo Globale",
|
||||
"Temporary Overrides": "Override Temporaneo",
|
||||
"Temporary Overrides Reset": "Temporary Overrides Reset",
|
||||
"Settings": "Impostazioni",
|
||||
"Information": "Informazioni",
|
||||
"Enable": "Abilita",
|
||||
"Uncapped Clocks": "Sblocca Clock",
|
||||
"Override Boost Mode": "Sovrascrivi Boost Mode",
|
||||
"CPU Max Display Clock": "Massimo Clock CPU mostrato",
|
||||
"Thermal Throttle": "Rallentamento Termico",
|
||||
"Thermal Throttle Threshold": "Soglia Rallentamento Termico",
|
||||
"Handheld TDP": "TPD Handheld",
|
||||
"Handheld TDP Limit": "Limite TDP Handheld",
|
||||
"Lite TDP Limit": "Limite TDP Lite",
|
||||
"Enforce Board Limit": "Forza Limite di Potenza",
|
||||
"Battery Charge Current": "Corrente di Ricarica",
|
||||
"Display Refresh Rate Changing": "Cambio di Frequenza Display",
|
||||
"Fix CPU Volt Bug": "Risolvi Bug CPU",
|
||||
"[cfg] no enum format string": "[cfg] no enum format string",
|
||||
"KIP": "KIP",
|
||||
"Save KIP Settings": "Salva Impotazioni KIP",
|
||||
"RAM Settings": "Impostazioni RAM",
|
||||
"CPU Settings": "Impostazioni CPU",
|
||||
"GPU Settings": "Impostazioni GPU",
|
||||
"Experimental": "Esperimentale",
|
||||
"Charge Current Override": "Sovrascrivi Corrente di Ricarica",
|
||||
"Disabled": "Disabilitato",
|
||||
"HP Mode": "Modalità HP",
|
||||
"EMC Max Clock": "Clock EMC Massimo",
|
||||
"EMC VDD2 Voltage": "Voltaggio VDD2 EMC",
|
||||
"EMC VDDQ Voltage": "Voltaggio VDDQ EMC",
|
||||
"DVB Shift": "Shift DVB",
|
||||
"Memory Timings": "Timing Memoria",
|
||||
"Memory Latencies": "Latency Memoria",
|
||||
"t1 tRCD": "t1 tRCD",
|
||||
"t2 tRP": "t2 tRP",
|
||||
"t3 tRAS": "t3 tRAS",
|
||||
"t4 tRRD": "t4 tRRD",
|
||||
"t5 tRFC": "t5 tRFC",
|
||||
"t6 tRTW": "t6 tRTW",
|
||||
"t7 tWTR": "t7 tWTR",
|
||||
"t8 tREFI": "t8 tREFI",
|
||||
"Update RAM Timings": "Aggiorna Timing RAM",
|
||||
"\uE150 This feature is EXPERIMENTAL": "\uE150 Questa funzione è ESPERIMENRALE!",
|
||||
"and should only be used for testing!": "e dovrebbe essere usata solo per testare!",
|
||||
"Read Latency": "Latency Lettura",
|
||||
"Write Latency": "Latency Scrittura",
|
||||
"CPU UV": "UV CPU",
|
||||
"CPU Unlock": "Sblocco CPU",
|
||||
"CPU VMIN": "VMIN CPU",
|
||||
"CPU Max Voltage": "Voltaggio Massimo CPU",
|
||||
"CPU UV Table": "Tavola UV CPU",
|
||||
"CPU Low UV": "UV Basso CPU",
|
||||
"CPU High UV": "UV Alto CPU",
|
||||
"CPU Max Clock": "Clock Massimo CPU",
|
||||
"CPU Low VMIN": "VMIN Basso CPU",
|
||||
"CPU High VMIN": "VMIN Alto CPU",
|
||||
"GPU Undervolt Table": "Tavola Undervolt GPU",
|
||||
"Calculate GPU Vmin": "Calcola VMIN GPU",
|
||||
"GPU VMIN": "VMIN GPU",
|
||||
"GPU VMAX": "VMAX GPU",
|
||||
"GPU Volt Offset": "Offset Voltaggio GPU",
|
||||
"GPU Custom Table": "Tavola GPU Custom",
|
||||
"GPU Custom Table (mV)": "Tavola GPU Custom (mV)",
|
||||
"\uE150 Setting GPU Clocks past": "\uE150 Impostare Clock GPU oltre",
|
||||
"1075MHz without UV, 1152MHz on SLT or ": "1075MHz senza UV, 1152MHz su SLT o ",
|
||||
"1228MHz on HiOPT can cause ": "1228MHz su HiOPT può causare ",
|
||||
"permanent damage to your Switch!": "danni permanenti alla tua console!",
|
||||
"Proceed at your own risk!": "Procedi al tuo rischio!",
|
||||
"921MHz without UV and 960MHz on": "921MHz senza UV e 960MHz su",
|
||||
"SLT or HiOPT can cause ": "SLT o HiOPT può causare ",
|
||||
"Auto": "Auto",
|
||||
"Sleep Mode": "Modalità Sleep",
|
||||
"Stock": "Stock",
|
||||
"Dev OC": "OC Sviluppo",
|
||||
"Boost Mode": "Modalità Boost",
|
||||
"Safe Max": "Massimo Sicuro",
|
||||
"Unsafe Max": "Massimo Insicuro",
|
||||
"Absolute Max": "Massimo Assoluto",
|
||||
"Boost Mode & Safe Max": "Modalità Boost e Massimo Sicuro",
|
||||
"Official Rating": "Rating Ufficiale",
|
||||
"Default (Mariko)": "Default (Mariko)",
|
||||
"Default (Erista)": "Default (Erista)",
|
||||
"Rating": "Rating",
|
||||
"Safe Max (Mariko)": "Max Sicuro (Mariko)",
|
||||
"Safe Max (Erista)": "Max Sicuro (Erista)",
|
||||
"Default": "Default",
|
||||
"1581MHz Tbreak": "Tbreak 1581MHz",
|
||||
"1683MHz Tbreak": "Tbreak 1683MHz",
|
||||
"Extreme UV Table": "Tavola UV Estremo",
|
||||
"No UV": "No UV",
|
||||
"SLT Table": "Tavola SLT",
|
||||
"HiOPT Table": "Tavola HiOPT",
|
||||
"Power": "Potenza",
|
||||
"Temp": "Temperatura",
|
||||
"Voltage": "Voltaggio",
|
||||
"TDP Threshold": "Soglia TDP",
|
||||
"Lite TDP Threshold": "Soglia TDP Lite",
|
||||
"Thermal Throttle Limit": "Limite Rallentamento Termico",
|
||||
"1600BL": "BL1600",
|
||||
"1866BL": "BL1866",
|
||||
"2133BL": "BL2133",
|
||||
"BAT": "BAT",
|
||||
"FAN": "FAN",
|
||||
"DISP": "DISP",
|
||||
"Board": "Scheda",
|
||||
"Skin": "Skin",
|
||||
"Now": "Ora",
|
||||
"Avg": "Med",
|
||||
"App ID": "ID App",
|
||||
"Profile": "Profilo",
|
||||
"CPU": "CPU",
|
||||
"GPU": "GPU",
|
||||
"Memory": "Memoria",
|
||||
"Display": "Display",
|
||||
"Governor": "Governor",
|
||||
"SOC": "SOC",
|
||||
"PCB": "PCB",
|
||||
"PMIC": "PMIC",
|
||||
"Docked": "Dock",
|
||||
"Handheld": "Handheld",
|
||||
"Charging": "In Carica",
|
||||
"USB Charger": "Caricatore USB",
|
||||
"PD Charger": "Caricatore PD",
|
||||
"VDD2": "VDD2",
|
||||
"VDDQ": "VDDQ"
|
||||
}
|
||||
133
dist/config/horizon-oc/lang/lang/zh-cn.json
vendored
Normal file
133
dist/config/horizon-oc/lang/lang/zh-cn.json
vendored
Normal file
@@ -0,0 +1,133 @@
|
||||
{
|
||||
"Information about Translation": "This is a machine translation. If you find any errors, please report them on GitHub, or feel free to contribute!",
|
||||
"Horizon OC Zeus": "Horizon OC Zeus",
|
||||
"Edit App Profile": "编辑应用配置",
|
||||
"Advanced": "高级",
|
||||
"Edit Global Profile": "编辑全局配置",
|
||||
"Temporary Overrides": "临时覆盖",
|
||||
"Temporary Overrides Reset": "临时覆盖 重置",
|
||||
"Settings": "设置",
|
||||
"Information": "信息",
|
||||
"Enable": "启用",
|
||||
"Uncapped Clocks": "解除频率上限",
|
||||
"Override Boost Mode": "覆盖加速模式",
|
||||
"CPU Max Display Clock": "CPU 最大显示频率",
|
||||
"Thermal Throttle": "温度节流",
|
||||
"Thermal Throttle Threshold": "温度节流阈值",
|
||||
"Handheld TDP": "掌机模式 TDP",
|
||||
"Handheld TDP Limit": "掌机模式 TDP 限制",
|
||||
"Lite TDP Limit": "Lite TDP 限制",
|
||||
"Enforce Board Limit": "强制主板限制",
|
||||
"Battery Charge Current": "电池充电电流",
|
||||
"Display Refresh Rate Changing": "显示刷新率变更",
|
||||
"Fix CPU Volt Bug": "修复 CPU 电压错误",
|
||||
"[cfg] no enum format string": "[cfg] 无枚举格式字符串",
|
||||
"KIP": "KIP",
|
||||
"Save KIP Settings": "保存 KIP 设置",
|
||||
"RAM Settings": "内存设置",
|
||||
"CPU Settings": "CPU 设置",
|
||||
"GPU Settings": "GPU 设置",
|
||||
"Experimental": "实验性功能",
|
||||
"Charge Current Override": "充电电流覆盖",
|
||||
"Disabled": "禁用",
|
||||
"HP Mode": "高性能模式",
|
||||
"EMC Max Clock": "EMC 最大频率",
|
||||
"EMC VDD2 Voltage": "EMC VDD2 电压",
|
||||
"EMC VDDQ Voltage": "EMC VDDQ 电压",
|
||||
"DVB Shift": "DVB 偏移",
|
||||
"Memory Timings": "内存时序",
|
||||
"Memory Latencies": "内存延迟",
|
||||
"t1 tRCD": "t1 tRCD",
|
||||
"t2 tRP": "t2 tRP",
|
||||
"t3 tRAS": "t3 tRAS",
|
||||
"t4 tRRD": "t4 tRRD",
|
||||
"t5 tRFC": "t5 tRFC",
|
||||
"t6 tRTW": "t6 tRTW",
|
||||
"t7 tWTR": "t7 tWTR",
|
||||
"t8 tREFI": "t8 tREFI",
|
||||
"Update RAM Timings": "更新内存时序",
|
||||
"\uE150 This feature is EXPERIMENTAL": "\uE150 此功能为实验性功能",
|
||||
"and should only be used for testing!": "仅应用于测试!",
|
||||
"Read Latency": "读取延迟",
|
||||
"Write Latency": "写入延迟",
|
||||
"CPU UV": "CPU 降压",
|
||||
"CPU Unlock": "CPU 解锁",
|
||||
"CPU VMIN": "CPU 最低电压",
|
||||
"CPU Max Voltage": "CPU 最大电压",
|
||||
"CPU UV Table": "CPU 降压表",
|
||||
"CPU Low UV": "CPU 低频降压",
|
||||
"CPU High UV": "CPU 高频降压",
|
||||
"CPU Max Clock": "CPU 最大频率",
|
||||
"CPU Low VMIN": "CPU 低频最低电压",
|
||||
"CPU High VMIN": "CPU 高频最低电压",
|
||||
"GPU Undervolt Table": "GPU 降压表",
|
||||
"Calculate GPU Vmin": "计算 GPU 最低电压",
|
||||
"GPU VMIN": "GPU 最低电压",
|
||||
"GPU VMAX": "GPU 最大电压",
|
||||
"GPU Volt Offset": "GPU 电压偏移",
|
||||
"GPU Custom Table": "GPU 自定义表",
|
||||
"GPU Custom Table (mV)": "GPU 自定义表 (mV)",
|
||||
"\uE150 Setting GPU Clocks past": "\uE150 将 GPU 频率设置超过",
|
||||
"1075MHz without UV, 1152MHz on SLT or ": "无降压时的 1075MHz、SLT 时的 1152MHz 或",
|
||||
"1228MHz on HiOPT can cause ": "HiOPT 时的 1228MHz 可能会造成",
|
||||
"permanent damage to your Switch!": "对您的 Switch 造成永久性损坏!",
|
||||
"Proceed at your own risk!": "风险自负!",
|
||||
"921MHz without UV and 960MHz on": "无降压时的 921MHz 和",
|
||||
"SLT or HiOPT can cause ": "SLT 或 HiOPT 时的 960MHz 可能会造成",
|
||||
"Auto": "自动",
|
||||
"Sleep Mode": "休眠模式",
|
||||
"Stock": "默认",
|
||||
"Dev OC": "开发超频",
|
||||
"Boost Mode": "加速模式",
|
||||
"Safe Max": "安全最大值",
|
||||
"Unsafe Max": "不安全最大值",
|
||||
"Absolute Max": "绝对最大值",
|
||||
"Boost Mode & Safe Max": "加速模式 & 安全最大值",
|
||||
"Official Rating": "官方额定值",
|
||||
"Default (Mariko)": "默认 (Mariko)",
|
||||
"Default (Erista)": "默认 (Erista)",
|
||||
"Rating": "额定值",
|
||||
"Safe Max (Mariko)": "安全最大值 (Mariko)",
|
||||
"Safe Max (Erista)": "安全最大值 (Erista)",
|
||||
"Default": "默认",
|
||||
"1581MHz Tbreak": "1581MHz Tbreak",
|
||||
"1683MHz Tbreak": "1683MHz Tbreak",
|
||||
"Extreme UV Table": "极限降压表",
|
||||
"No UV": "不降压",
|
||||
"SLT Table": "SLT 表",
|
||||
"HiOPT Table": "HiOPT 表",
|
||||
"Power": "功耗",
|
||||
"Temp": "温度",
|
||||
"Voltage": "电压",
|
||||
"TDP Threshold": "TDP 阈值",
|
||||
"Lite TDP Threshold": "Lite TDP 阈值",
|
||||
"Thermal Throttle Limit": "温度节流限制",
|
||||
"1600BL": "1600BL",
|
||||
"1866BL": "1866BL",
|
||||
"2133BL": "2133BL",
|
||||
"BAT": "电池",
|
||||
"FAN": "风扇",
|
||||
"DISP": "显示",
|
||||
"Board": "主板",
|
||||
"Skin": "外壳",
|
||||
"Now": "当前",
|
||||
"Avg": "平均",
|
||||
"App ID": "应用 ID",
|
||||
"Profile": "配置",
|
||||
"CPU": "CPU",
|
||||
"GPU": "GPU",
|
||||
"Memory": "内存",
|
||||
"Display": "显示",
|
||||
"Governor": "调速器",
|
||||
"SOC": "SOC",
|
||||
"PCB": "PCB",
|
||||
"PMIC": "PMIC",
|
||||
"Docked": "底座模式",
|
||||
"Handheld": "掌机模式",
|
||||
"Charging": "充电中",
|
||||
"USB Charger": "USB 充电器",
|
||||
"PD Charger": "PD 充电器",
|
||||
"VDD2": "VDD2",
|
||||
"VDDQ": "VDDQ",
|
||||
"GPU DVFS": "GPU DVFS"
|
||||
}
|
||||
133
dist/config/horizon-oc/lang/zh-cn.json
vendored
Normal file
133
dist/config/horizon-oc/lang/zh-cn.json
vendored
Normal file
@@ -0,0 +1,133 @@
|
||||
{
|
||||
"Information about Translation": "This is a machine translation. If you find any errors, please report them on GitHub, or feel free to contribute!",
|
||||
"Horizon OC Zeus": "Horizon OC Zeus",
|
||||
"Edit App Profile": "编辑应用配置",
|
||||
"Advanced": "高级",
|
||||
"Edit Global Profile": "编辑全局配置",
|
||||
"Temporary Overrides": "临时覆盖",
|
||||
"Temporary Overrides Reset": "临时覆盖 重置",
|
||||
"Settings": "设置",
|
||||
"Information": "信息",
|
||||
"Enable": "启用",
|
||||
"Uncapped Clocks": "解除频率上限",
|
||||
"Override Boost Mode": "覆盖加速模式",
|
||||
"CPU Max Display Clock": "CPU 最大显示频率",
|
||||
"Thermal Throttle": "温度节流",
|
||||
"Thermal Throttle Threshold": "温度节流阈值",
|
||||
"Handheld TDP": "掌机模式 TDP",
|
||||
"Handheld TDP Limit": "掌机模式 TDP 限制",
|
||||
"Lite TDP Limit": "Lite TDP 限制",
|
||||
"Enforce Board Limit": "强制主板限制",
|
||||
"Battery Charge Current": "电池充电电流",
|
||||
"Display Refresh Rate Changing": "显示刷新率变更",
|
||||
"Fix CPU Volt Bug": "修复 CPU 电压错误",
|
||||
"[cfg] no enum format string": "[cfg] 无枚举格式字符串",
|
||||
"KIP": "KIP",
|
||||
"Save KIP Settings": "保存 KIP 设置",
|
||||
"RAM Settings": "内存设置",
|
||||
"CPU Settings": "CPU 设置",
|
||||
"GPU Settings": "GPU 设置",
|
||||
"Experimental": "实验性功能",
|
||||
"Charge Current Override": "充电电流覆盖",
|
||||
"Disabled": "禁用",
|
||||
"HP Mode": "高性能模式",
|
||||
"EMC Max Clock": "EMC 最大频率",
|
||||
"EMC VDD2 Voltage": "EMC VDD2 电压",
|
||||
"EMC VDDQ Voltage": "EMC VDDQ 电压",
|
||||
"DVB Shift": "DVB 偏移",
|
||||
"Memory Timings": "内存时序",
|
||||
"Memory Latencies": "内存延迟",
|
||||
"t1 tRCD": "t1 tRCD",
|
||||
"t2 tRP": "t2 tRP",
|
||||
"t3 tRAS": "t3 tRAS",
|
||||
"t4 tRRD": "t4 tRRD",
|
||||
"t5 tRFC": "t5 tRFC",
|
||||
"t6 tRTW": "t6 tRTW",
|
||||
"t7 tWTR": "t7 tWTR",
|
||||
"t8 tREFI": "t8 tREFI",
|
||||
"Update RAM Timings": "更新内存时序",
|
||||
"\uE150 This feature is EXPERIMENTAL": "\uE150 此功能为实验性功能",
|
||||
"and should only be used for testing!": "仅应用于测试!",
|
||||
"Read Latency": "读取延迟",
|
||||
"Write Latency": "写入延迟",
|
||||
"CPU UV": "CPU 降压",
|
||||
"CPU Unlock": "CPU 解锁",
|
||||
"CPU VMIN": "CPU 最低电压",
|
||||
"CPU Max Voltage": "CPU 最大电压",
|
||||
"CPU UV Table": "CPU 降压表",
|
||||
"CPU Low UV": "CPU 低频降压",
|
||||
"CPU High UV": "CPU 高频降压",
|
||||
"CPU Max Clock": "CPU 最大频率",
|
||||
"CPU Low VMIN": "CPU 低频最低电压",
|
||||
"CPU High VMIN": "CPU 高频最低电压",
|
||||
"GPU Undervolt Table": "GPU 降压表",
|
||||
"Calculate GPU Vmin": "计算 GPU 最低电压",
|
||||
"GPU VMIN": "GPU 最低电压",
|
||||
"GPU VMAX": "GPU 最大电压",
|
||||
"GPU Volt Offset": "GPU 电压偏移",
|
||||
"GPU Custom Table": "GPU 自定义表",
|
||||
"GPU Custom Table (mV)": "GPU 自定义表 (mV)",
|
||||
"\uE150 Setting GPU Clocks past": "\uE150 将 GPU 频率设置超过",
|
||||
"1075MHz without UV, 1152MHz on SLT or ": "无降压时的 1075MHz、SLT 时的 1152MHz 或",
|
||||
"1228MHz on HiOPT can cause ": "HiOPT 时的 1228MHz 可能会造成",
|
||||
"permanent damage to your Switch!": "对您的 Switch 造成永久性损坏!",
|
||||
"Proceed at your own risk!": "风险自负!",
|
||||
"921MHz without UV and 960MHz on": "无降压时的 921MHz 和",
|
||||
"SLT or HiOPT can cause ": "SLT 或 HiOPT 时的 960MHz 可能会造成",
|
||||
"Auto": "自动",
|
||||
"Sleep Mode": "休眠模式",
|
||||
"Stock": "默认",
|
||||
"Dev OC": "开发超频",
|
||||
"Boost Mode": "加速模式",
|
||||
"Safe Max": "安全最大值",
|
||||
"Unsafe Max": "不安全最大值",
|
||||
"Absolute Max": "绝对最大值",
|
||||
"Boost Mode & Safe Max": "加速模式 & 安全最大值",
|
||||
"Official Rating": "官方额定值",
|
||||
"Default (Mariko)": "默认 (Mariko)",
|
||||
"Default (Erista)": "默认 (Erista)",
|
||||
"Rating": "额定值",
|
||||
"Safe Max (Mariko)": "安全最大值 (Mariko)",
|
||||
"Safe Max (Erista)": "安全最大值 (Erista)",
|
||||
"Default": "默认",
|
||||
"1581MHz Tbreak": "1581MHz Tbreak",
|
||||
"1683MHz Tbreak": "1683MHz Tbreak",
|
||||
"Extreme UV Table": "极限降压表",
|
||||
"No UV": "不降压",
|
||||
"SLT Table": "SLT 表",
|
||||
"HiOPT Table": "HiOPT 表",
|
||||
"Power": "功耗",
|
||||
"Temp": "温度",
|
||||
"Voltage": "电压",
|
||||
"TDP Threshold": "TDP 阈值",
|
||||
"Lite TDP Threshold": "Lite TDP 阈值",
|
||||
"Thermal Throttle Limit": "温度节流限制",
|
||||
"1600BL": "1600BL",
|
||||
"1866BL": "1866BL",
|
||||
"2133BL": "2133BL",
|
||||
"BAT": "电池",
|
||||
"FAN": "风扇",
|
||||
"DISP": "显示",
|
||||
"Board": "主板",
|
||||
"Skin": "外壳",
|
||||
"Now": "当前",
|
||||
"Avg": "平均",
|
||||
"App ID": "应用 ID",
|
||||
"Profile": "配置",
|
||||
"CPU": "CPU",
|
||||
"GPU": "GPU",
|
||||
"Memory": "内存",
|
||||
"Display": "显示",
|
||||
"Governor": "调速器",
|
||||
"SOC": "SOC",
|
||||
"PCB": "PCB",
|
||||
"PMIC": "PMIC",
|
||||
"Docked": "底座模式",
|
||||
"Handheld": "掌机模式",
|
||||
"Charging": "充电中",
|
||||
"USB Charger": "USB 充电器",
|
||||
"PD Charger": "PD 充电器",
|
||||
"VDD2": "VDD2",
|
||||
"VDDQ": "VDDQ",
|
||||
"GPU DVFS": "GPU DVFS"
|
||||
}
|
||||
BIN
dist/switch/.overlays/Horizon-OC-Monitor.ovl
vendored
BIN
dist/switch/.overlays/Horizon-OC-Monitor.ovl
vendored
Binary file not shown.
BIN
dist/switch/.overlays/horizon-oc-overlay.ovl
vendored
BIN
dist/switch/.overlays/horizon-oc-overlay.ovl
vendored
Binary file not shown.
@@ -1,140 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Horizon OC Configurator</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link href="https://unpkg.com/aos@2.3.1/dist/aos.css" rel="stylesheet">
|
||||
|
||||
<style>
|
||||
body {
|
||||
background: linear-gradient(160deg, #1a1a1a 0%, #2a2a2a 50%, #3a3a3a 100%);
|
||||
color: white;
|
||||
font-family: 'Segoe UI', Roboto, system-ui, sans-serif;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.glass {
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
border: 1px solid rgba(255, 255, 255, 0.15);
|
||||
backdrop-filter: blur(20px);
|
||||
border-radius: 20px;
|
||||
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.3);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.glass:hover {
|
||||
background: rgba(255, 255, 255, 0.12);
|
||||
transform: translateY(-3px);
|
||||
}
|
||||
|
||||
.button-glass {
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
backdrop-filter: blur(20px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.25);
|
||||
color: white;
|
||||
padding: 0.8rem 1.6rem;
|
||||
border-radius: 9999px;
|
||||
font-weight: 600;
|
||||
transition: all 0.3s;
|
||||
display: inline-block;
|
||||
text-decoration: none;
|
||||
margin: 0.25rem 0;
|
||||
}
|
||||
|
||||
.button-glass:hover {
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
input[type="number"], input[type="file"] {
|
||||
padding: 0.5rem 0.8rem;
|
||||
border-radius: 12px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.25);
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
color: white;
|
||||
font-weight: 500;
|
||||
outline: none;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
input[type="number"]:focus, input[type="file"]:focus {
|
||||
border-color: #b8f3ff;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
label {
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
section {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
footer {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.15);
|
||||
padding: 1.5rem 0;
|
||||
text-align: center;
|
||||
color: #ccc;
|
||||
font-size: 0.9rem;
|
||||
margin-top: 4rem;
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!-- Navigation / Go Back -->
|
||||
<nav class="flex justify-start p-6">
|
||||
<a href="index.html" class="button-glass">← Go Back to Main Page</a>
|
||||
</nav>
|
||||
|
||||
<!-- Configurator -->
|
||||
<section id="config" class="max-w-4xl mx-auto px-6 py-16 glass mt-6" data-aos="fade-up">
|
||||
<h2 class="text-3xl font-bold mb-4 text-center">Configurator</h2>
|
||||
<p class="text-gray-400 text-center mb-8">Configure frequencies and voltages to suit your hardware and preferences.</p>
|
||||
|
||||
<form class="space-y-6 text-center">
|
||||
<!-- Unit selection buttons -->
|
||||
<div class="flex justify-center gap-2">
|
||||
<button type="button" class="button-glass">All</button>
|
||||
<button type="button" class="button-glass">Erista</button>
|
||||
<button type="button" class="button-glass">Mariko</button>
|
||||
</div>
|
||||
|
||||
<!-- File upload -->
|
||||
<div class="flex flex-col items-center">
|
||||
<input type="file" id="file">
|
||||
<p class="text-sm text-gray-400 mt-2">Upload loader.kip here</p>
|
||||
</div>
|
||||
|
||||
<!-- Example numeric inputs -->
|
||||
<div class="flex flex-wrap justify-center gap-4 mt-4">
|
||||
<div>
|
||||
<label for="commonEmcMemVolt">EMC Voltage:</label>
|
||||
<input type="number" id="commonEmcMemVolt" min="0" max="1250000" step="12500">
|
||||
</div>
|
||||
<div>
|
||||
<label for="commonCpuVolt">CPU Voltage:</label>
|
||||
<input type="number" id="commonCpuVolt" min="0" max="1250000" step="12500">
|
||||
</div>
|
||||
<div>
|
||||
<label for="commonGpuVolt">GPU Voltage:</label>
|
||||
<input type="number" id="commonGpuVolt" min="0" max="1250000" step="12500">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
<!-- Footer -->
|
||||
<footer>
|
||||
Built with ❤️. All trademarks and logos are the property of their respective owners.
|
||||
</footer>
|
||||
|
||||
<script src="https://unpkg.com/aos@2.3.1/dist/aos.js"></script>
|
||||
<script>AOS.init({ once: true, duration: 700 });</script>
|
||||
<script src="configurator.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,683 +0,0 @@
|
||||
/* configurator.js
|
||||
Clean, readable reconstruction of the original minified configurator
|
||||
- Keeps original behavior (tables, parsing, localStorage, GitHub release fetching)
|
||||
- Uses modern async/await and DOMContentLoaded guarding
|
||||
*/
|
||||
|
||||
const CUST_REV_ADV = 11;
|
||||
|
||||
const CustPlatform = Object.freeze({
|
||||
Undefined: 0,
|
||||
Erista: 1,
|
||||
Mariko: 2,
|
||||
All: 3
|
||||
});
|
||||
|
||||
class CustEntry {
|
||||
constructor(id, name, platform, size, desc = [], defval = 0, range = [0, 1e6], step = 1, zeroable = true) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.platform = platform;
|
||||
this.size = size;
|
||||
this.desc = desc;
|
||||
this.defval = defval;
|
||||
this.step = step;
|
||||
this.zeroable = zeroable;
|
||||
this.min = range[0];
|
||||
this.max = range[1];
|
||||
this.value = this.defval;
|
||||
}
|
||||
|
||||
validate() {
|
||||
const err = new ErrorToolTip(this.id).clear();
|
||||
if (Number.isNaN(this.value) || this.value === undefined) {
|
||||
err.setMsg("Invalid value: Not a number").show();
|
||||
return false;
|
||||
}
|
||||
if (!this.zeroable && this.value === 0) {
|
||||
err.setMsg("Zero is not allowed for this entry").show();
|
||||
return false;
|
||||
}
|
||||
if (this.value < this.min || this.value > this.max) {
|
||||
err.setMsg(`Expected range: [${this.min}, ${this.max}], got ${this.value}.`).show();
|
||||
return false;
|
||||
}
|
||||
if ((this.value % this.step) !== 0) {
|
||||
err.setMsg(`${this.value} % ${this.step} ≠ 0`).show();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
getInputElement() {
|
||||
return document.getElementById(this.id);
|
||||
}
|
||||
|
||||
updateValueFromElement() {
|
||||
const el = this.getInputElement();
|
||||
this.value = Number(el?.value);
|
||||
}
|
||||
|
||||
isAvailableFor(platform) {
|
||||
return platform === CustPlatform.Undefined || this.platform === platform || this.platform === CustPlatform.All;
|
||||
}
|
||||
|
||||
createElement(containerId = "config-list-basic") {
|
||||
let input = this.getInputElement();
|
||||
if (!input) {
|
||||
const wrapper = document.createElement("div");
|
||||
wrapper.classList.add("grid", "cust-element", "mb-3");
|
||||
|
||||
input = document.createElement("input");
|
||||
input.min = String(this.zeroable ? 0 : this.min);
|
||||
input.max = String(this.max);
|
||||
input.id = this.id;
|
||||
input.type = "number";
|
||||
input.step = String(this.step);
|
||||
input.classList.add("text-black", "w-36");
|
||||
|
||||
const label = document.createElement("label");
|
||||
label.setAttribute("for", this.id);
|
||||
label.innerHTML = `<strong>${this.name}</strong>`;
|
||||
label.classList.add("block", "mb-1");
|
||||
|
||||
const desc = document.createElement("blockquote");
|
||||
desc.innerHTML = "<ul>" + (this.desc || []).map(d => `<li>${d}</li>`).join("") + "</ul>";
|
||||
desc.setAttribute("for", this.id);
|
||||
desc.classList.add("text-sm", "text-gray-300");
|
||||
|
||||
wrapper.appendChild(label);
|
||||
wrapper.appendChild(input);
|
||||
wrapper.appendChild(desc);
|
||||
|
||||
const container = document.getElementById(containerId);
|
||||
if (container) container.appendChild(wrapper);
|
||||
new ErrorToolTip(this.id).addChangeListener();
|
||||
}
|
||||
input.value = String(this.value);
|
||||
}
|
||||
|
||||
setElementValue() {
|
||||
const el = this.getInputElement();
|
||||
if (el) el.value = String(this.value);
|
||||
}
|
||||
|
||||
setElementDefaultValue() {
|
||||
const el = this.getInputElement();
|
||||
if (el) el.value = String(this.defval);
|
||||
}
|
||||
|
||||
removeElement() {
|
||||
const el = this.getInputElement();
|
||||
if (el && el.parentElement && el.parentElement.parentElement) el.parentElement.parentElement.remove();
|
||||
}
|
||||
|
||||
showElement() {
|
||||
const el = this.getInputElement();
|
||||
if (el && el.parentElement && el.parentElement.parentElement) el.parentElement.parentElement.style.removeProperty("display");
|
||||
}
|
||||
|
||||
hideElement() {
|
||||
const el = this.getInputElement();
|
||||
if (el && el.parentElement && el.parentElement.parentElement) el.parentElement.parentElement.style.setProperty("display", "none");
|
||||
}
|
||||
}
|
||||
|
||||
class AdvEntry extends CustEntry {
|
||||
createElement() {
|
||||
super.createElement("config-list-advanced");
|
||||
}
|
||||
}
|
||||
|
||||
class GpuEntry extends CustEntry {
|
||||
constructor(id, name, platform = CustPlatform.Mariko, size = 4, desc = ["range: 610 ≤ x ≤ 1000"], defval = 610, range = [610, 1000], step = 5, zeroable = false) {
|
||||
super(id, name, platform, size, desc, defval, range, step, zeroable);
|
||||
}
|
||||
|
||||
createElement() {
|
||||
super.createElement("config-list-gpu");
|
||||
}
|
||||
}
|
||||
|
||||
/* === Tables (reconstructed from original) ===
|
||||
Note: Numeric defaults preserved where feasible.
|
||||
*/
|
||||
const CustTable = [
|
||||
new CustEntry("mtcConf", "DRAM Timing", CustPlatform.All, 4,
|
||||
[
|
||||
"<b>0</b>: AUTO_ADJ_ALL: Auto adjust mtc table with LPDDR4 3733 Mbps specs, 8Gb density. Change timing with Advanced Config (Default)",
|
||||
"<b>1</b>: CUSTOM_ADJ_ALL: Adjust only non-zero preset timings in Advanced Config",
|
||||
"<b>2</b>: NO_ADJ_ALL: Use 1600 mtc table without adjusting (Timing becomes tighter if you raise dram clock)."
|
||||
], 0, [0, 2], 1),
|
||||
new CustEntry("commonCpuBoostClock", "Boost Clock in kHz", CustPlatform.All, 4,
|
||||
["System default: 1785000", "Boost clock will be applied when applications request Boost Mode via performance configuration."],
|
||||
1785000, [1020000, 3000000], 1, false),
|
||||
new CustEntry("commonEmcMemVolt", "EMC Vdd2 Voltage in uV", CustPlatform.All, 4,
|
||||
["Acceptable range: 1100000 ≤ x ≤ 1250000, and it should be divided evenly by 12500.", "Erista Default: 1125000", "Mariko Default: 1100000", "Official lpddr4(x) range: 1060mV~1175mV (1100mV nominal)", "OCS need high voltage unlike l4t because of not scaling mtc table well. However it is recommended to stay within official limits", "Not enabled by default"],
|
||||
0, [1100000, 1250000], 12500),
|
||||
new CustEntry("eristaCpuMaxVolt", "Erista CPU Max Voltage in mV", CustPlatform.Erista, 4,
|
||||
["Acceptable range: 1120 ≤ x ≤ 1300", "L4T Default: 1235"], 1235, [1120, 1300], 1),
|
||||
new CustEntry("eristaEmcMaxClock", "Erista RAM Max Clock in kHz", CustPlatform.Erista, 4,
|
||||
["Values should be ≥ 1600000, and divided evenly by 3200.", "Recommended Clocks: 1862400, 2131200 (JEDEC)", "<b>WARNING:</b> RAM overclock could be UNSTABLE if timing parameters are not suitable for your DRAM"], 1862400, [1600000, 2131200], 3200),
|
||||
new CustEntry("marikoCpuMaxVolt", "Mariko CPU Max Voltage in mV", CustPlatform.Mariko, 4,
|
||||
["System default: 1120", "Acceptable range: 1120 ≤ x ≤ 1300", "Changing this value affects cpu voltage calculation"], 1235, [1120, 1300], 5),
|
||||
new CustEntry("marikoEmcMaxClock", "Mariko RAM Max Clock in kHz", CustPlatform.Mariko, 4,
|
||||
["Values should be ≥ 1600000, and divided evenly by 3200.", "Recommended Clocks: 1862400, 2131200, 2400000 (JEDEC)", "Some clocks above 2400Mhz might not boot, because OCS doesn't scale table very well", "<b>WARNING:</b> RAM overclock could be UNSTABLE if timing parameters are not suitable for your DRAM."],
|
||||
1996800, [1600000, 2502400], 3200),
|
||||
new CustEntry("marikoEmcVddqVolt", "EMC Vddq (Mariko Only) Voltage in uV", CustPlatform.Mariko, 4,
|
||||
["Acceptable range: 550000 ≤ x ≤ 650000", "Value should be divided evenly by 5000", "Default: 600000", "Official lpddr4(x) range: 570mV~650mV (600mV nominal)", "Not enabled by default."],
|
||||
0, [550000, 650000], 5000),
|
||||
new CustEntry("marikoCpuUV", "Enable Mariko CPU Undervolt", CustPlatform.Mariko, 4,
|
||||
["Reduce CPU power draw", "<b>0</b> : Default Table", "<b>1</b> : Undervolt Level 1 (SLT - CPU speedo < 1650)", "<b>2</b> : Undervolt Level 1 (SLT - CPU speedo >= 1650)"], 0, [0, 2], 1),
|
||||
new CustEntry("marikoGpuUV", "Enable Mariko GPU Undervolt", CustPlatform.Mariko, 4,
|
||||
["Reduce GPU power draw", "Your GPU might not withstand undervolt, and can hang your console, or crash games", "Undervolting too much will drop GPU performance even if it seems stable", "GPU voltages are dynamic and will change with temperature and gpu speedo", "<b>0</b> : Default Table", "<b>1</b> : Undervolt Level 1 (SLT: Aggressive)", "<b>2</b> : Undervolt Level 2 (HiOPT: Drastic)", "<b>3</b> : Custom static GPU Voltage Table (Use Gpu Configuration below)"],
|
||||
0, [0, 3], 1),
|
||||
new CustEntry("commonGpuVoltOffset", "GPU Volt Offset", CustPlatform.All, 4,
|
||||
["Negative Voltage offset value for gpu dynamic voltage calculation", "For example, value of 10 will decrease 10mV gpu volt from all frequencies", "Default gpu vmin: Erista - 812.5mV / Mariko - 610mV", "Acceptable range: 0 ~ 100"],
|
||||
0, [0, 100], 1)
|
||||
];
|
||||
|
||||
const AdvTable = [
|
||||
new AdvEntry("marikoEmcDvbShift", "Step up Mariko EMC DVB Table", CustPlatform.Mariko, 4,
|
||||
["Each number adds 25mV to SoC voltage", "Helps with stability at higher memory clock", "Acceptable range : 0~9"], 0, [0, 9], 1),
|
||||
new AdvEntry("ramTimingPresetOne", "Primary RAM Timing Preset", CustPlatform.Mariko, 4,
|
||||
["<b>WARNING</b>: Unstable timings can corrupt your nand", "Select Timing Preset for both AUTO_ADJ and CUSTOM_ADJ", "Values are : tRCD - tRP - tRAS (tRC = tRP + tRAS)", "<b>0</b> : Do Not Adjust (2400Mhz: 12 - 12 - 28) (CUST_ADJ only)", "<b>1</b> : 18 - 18 - 42 (Default timing)", "<b>2</b> : 17 - 17 - 39", "<b>3</b> : 16 - 16 - 36", "<b>4</b> : 15 - 15 - 34", "<b>5</b> : 14 - 14 - 32", "<b>6</b> : 13 - 13 - 30"],
|
||||
1, [0, 6], 1),
|
||||
new AdvEntry("ramTimingPresetTwo", "Secondary RAM Timing Preset", CustPlatform.Mariko, 4,
|
||||
["WARNING: Unstable timings can corrupt your nand", "Secondary Timing Preset for both AUTO_ADJ and CUSTOM_ADJ", "Values are : tRRD - tFAW", "<b>0</b> : Do Not Adjust (2400Mhz: 6.6 - 26.6) (CUST_ADJ only)", "<b>1</b> : 10 - 40 (Default timing) (3733 specs)", "<b>2</b> : 7.5 - 30 (4266 specs)", "<b>3</b> : 6 - 24", "<b>4</b> : 4 - 16", "<b>5</b> : 3 - 12"],
|
||||
1, [0, 5], 1),
|
||||
new AdvEntry("ramTimingPresetThree", "Secondary RAM Timing Preset", CustPlatform.Mariko, 4,
|
||||
["WARNING: Unstable timings can corrupt your nand", "Secondary Timing Preset for both AUTO_ADJ and CUSTOM_ADJ", "Values are : tWR - tRTP", "<b>0</b> : Do Not Adjust (2400Mhz: ?? - 5) (CUST_ADJ only)", "<b>1</b> : 18 - 7.5 (Default timing)", "<b>2</b> : 15 - 7.5", "<b>3</b> : 15 - 6", "<b>4</b> : 12 - 6", "<b>5</b> : 12 - 4", "<b>6</b> : 8 - 4"],
|
||||
1, [0, 6], 1),
|
||||
new AdvEntry("ramTimingPresetFour", "Secondary RAM Timing Preset", CustPlatform.Mariko, 4,
|
||||
["WARNING: Unstable timings can corrupt your nand", "Secondary Timing Preset for both AUTO_ADJ and CUSTOM_ADJ", "Values are : tRFC", "<b>0</b> : Do Not Adjust (2400Mhz: 93.3) (CUST_ADJ only)", "<b>1</b> : 140 (Default timing)", "<b>2</b> : 120", "<b>3</b> : 100", "<b>4</b> : 80", "<b>5</b> : 70", "<b>6</b> : 60"],
|
||||
1, [0, 6], 1),
|
||||
new AdvEntry("ramTimingPresetFive", "Secondary RAM Timing Preset", CustPlatform.Mariko, 4,
|
||||
["WARNING: Unstable timings can corrupt your nand", "Secondary Timing Preset for both AUTO_ADJ and CUSTOM_ADJ", "Values are : tWTR", "<b>0</b> : Do Not Adjust (2400Mhz: ??) (CUST_ADJ only)", "<b>1</b> : 10 (Default timing)", "<b>2</b> : 8", "<b>3</b> : 6", "<b>4</b> : 4", "<b>5</b> : 2", "<b>6</b> : 1"],
|
||||
1, [0, 6], 1),
|
||||
new AdvEntry("ramTimingPresetSix", "Tertiary RAM Timing Preset", CustPlatform.Mariko, 4,
|
||||
["WARNING: Unstable timings can corrupt your nand", "Tertiary Timing Preset for both AUTO_ADJ and CUSTOM_ADJ", "Values are : tREFpb", "<b>0</b> : Do Not Adjust (2400Mhz: 325) (CUST_ADJ only)", "<b>1</b> : 488 (Default timing)", "<b>2</b> : 976", "<b>3</b> : 1952", "<b>4</b> : 3256", "<b>5</b> : MAX"],
|
||||
1, [0, 5], 1),
|
||||
new AdvEntry("ramTimingPresetSeven", "Latency Decrement", CustPlatform.Mariko, 4,
|
||||
["WARNING: Unstable timings can corrupt your nand", "Latency decrement for both AUTO_ADJ and CUSTOM_ADJ", "This preset decreases Write/Read related delays. Values are Write - Read", "<b>0</b> : 0 - 0, Do Not Adjust for CUST_ADJ", "<b>1</b> : '-2' - '-4'", "<b>2</b> : '-4' - '-8'", "<b>3</b> : '-6' - '-12'", "<b>4</b> : '-8' - '-16'", "<b>5</b> : '-10' - '-20'", "<b>6</b> : '-12' - '-24'"],
|
||||
0, [0, 6], 1)
|
||||
];
|
||||
|
||||
const GpuTable = [
|
||||
new GpuEntry("0", "76.8"),
|
||||
new GpuEntry("1", "153.6"),
|
||||
new GpuEntry("2", "230.4"),
|
||||
new GpuEntry("3", "307.2"),
|
||||
new GpuEntry("4", "384.0"),
|
||||
new GpuEntry("5", "460.8"),
|
||||
new GpuEntry("6", "537.6"),
|
||||
new GpuEntry("7", "614.4"),
|
||||
new GpuEntry("8", "691.2"),
|
||||
new GpuEntry("9", "768.0"),
|
||||
new GpuEntry("10", "844.8"),
|
||||
new GpuEntry("11", "921.6"),
|
||||
new GpuEntry("12", "998.4"),
|
||||
new GpuEntry("13", "1075.2"),
|
||||
new GpuEntry("14", "1152.0"),
|
||||
new GpuEntry("15", "1228.8"),
|
||||
new GpuEntry("16", "1267.2")
|
||||
];
|
||||
|
||||
/* ===== ErrorToolTip ===== */
|
||||
class ErrorToolTip {
|
||||
constructor(id, msg) {
|
||||
this.id = id;
|
||||
this.msg = msg;
|
||||
this.element = document.getElementById(id);
|
||||
if (msg) this.setMsg(msg);
|
||||
}
|
||||
|
||||
setMsg(msg) {
|
||||
this.msg = String(msg);
|
||||
return this;
|
||||
}
|
||||
|
||||
show() {
|
||||
if (this.element) this.element.setAttribute("aria-invalid", "true");
|
||||
if (this.msg && this.element) {
|
||||
this.element.setAttribute("title", this.msg);
|
||||
if (this.element.parentElement) {
|
||||
this.element.parentElement.setAttribute("data-tooltip", this.msg);
|
||||
this.element.parentElement.setAttribute("data-placement", "top");
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
clear() {
|
||||
if (this.element) this.element.removeAttribute("aria-invalid");
|
||||
if (this.element) this.element.removeAttribute("title");
|
||||
if (this.element && this.element.parentElement) {
|
||||
this.element.parentElement.removeAttribute("data-tooltip");
|
||||
this.element.parentElement.removeAttribute("data-placement");
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
addChangeListener() {
|
||||
if (!this.element) return;
|
||||
this.element.addEventListener("change", () => {
|
||||
const tableEntry = CustTable.find(e => e.id === this.id);
|
||||
if (tableEntry) {
|
||||
tableEntry.value = Number(this.element.value);
|
||||
tableEntry.validate();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== CustStorage ===== */
|
||||
class CustStorage {
|
||||
constructor() {
|
||||
this.storage = {};
|
||||
this.key = "last_saved";
|
||||
}
|
||||
|
||||
updateFromTable() {
|
||||
// helper to update and validate each entry
|
||||
const updateOne = (entry) => {
|
||||
entry.updateValueFromElement();
|
||||
if (!entry.validate()) {
|
||||
const el = entry.getInputElement();
|
||||
if (el) el.focus();
|
||||
throw new Error(`Invalid ${entry.name}`);
|
||||
}
|
||||
};
|
||||
|
||||
CustTable.forEach(updateOne);
|
||||
AdvTable.forEach(updateOne);
|
||||
GpuTable.forEach(updateOne);
|
||||
|
||||
this.storage = {};
|
||||
let t = Object.fromEntries(CustTable.map(e => [e.id, e.value]));
|
||||
Object.keys(t).forEach(k => (this.storage[k] = t[k]));
|
||||
t = Object.fromEntries(AdvTable.map(e => [e.id, e.value]));
|
||||
Object.keys(t).forEach(k => (this.storage[k] = t[k]));
|
||||
// GPU table could be included too if desired
|
||||
}
|
||||
|
||||
setTable() {
|
||||
const keys = Object.keys(this.storage);
|
||||
keys.forEach(k => {
|
||||
const c = CustTable.find(e => e.id === k);
|
||||
if (c) c.value = this.storage[k];
|
||||
});
|
||||
keys.forEach(k => {
|
||||
const a = AdvTable.find(e => e.id === k);
|
||||
if (a) a.value = this.storage[k];
|
||||
});
|
||||
|
||||
// Set defaults for entries not found
|
||||
CustTable.filter(e => !keys.includes(e.id)).forEach(e => e.value = e.defval);
|
||||
AdvTable.filter(e => !keys.includes(e.id)).forEach(e => e.value = e.defval);
|
||||
|
||||
// Validate and set element values
|
||||
CustTable.forEach(e => {
|
||||
if (!e.validate()) {
|
||||
const el = e.getInputElement();
|
||||
if (el) el.focus();
|
||||
throw new Error(`Invalid ${e.name}`);
|
||||
}
|
||||
e.setElementValue();
|
||||
});
|
||||
AdvTable.forEach(e => {
|
||||
if (!e.validate()) {
|
||||
const el = e.getInputElement();
|
||||
if (el) el.focus();
|
||||
throw new Error(`Invalid ${e.name}`);
|
||||
}
|
||||
e.setElementValue();
|
||||
});
|
||||
GpuTable.forEach(e => {
|
||||
if (!e.validate()) {
|
||||
const el = e.getInputElement();
|
||||
if (el) el.focus();
|
||||
throw new Error(`Invalid ${e.name}`);
|
||||
}
|
||||
e.setElementValue();
|
||||
});
|
||||
}
|
||||
|
||||
save() {
|
||||
localStorage.setItem(this.key, JSON.stringify(this.storage));
|
||||
}
|
||||
|
||||
load() {
|
||||
const raw = localStorage.getItem(this.key);
|
||||
if (!raw) return null;
|
||||
const parsed = JSON.parse(raw);
|
||||
|
||||
// Filter unknown keys and warn
|
||||
const custIds = CustTable.map(e => e.id);
|
||||
const ignoredCust = Object.keys(parsed).filter(k => !custIds.includes(k));
|
||||
if (ignoredCust.length) console.log("Ignored (cust):", ignoredCust);
|
||||
Object.keys(parsed).filter(k => custIds.includes(k)).forEach(k => (this.storage[k] = parsed[k]));
|
||||
|
||||
const advIds = AdvTable.map(e => e.id);
|
||||
const ignoredAdv = Object.keys(parsed).filter(k => !advIds.includes(k));
|
||||
if (ignoredAdv.length) console.log("Ignored (adv):", ignoredAdv);
|
||||
Object.keys(parsed).filter(k => advIds.includes(k)).forEach(k => (this.storage[k] = parsed[k]));
|
||||
|
||||
return this.storage;
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== Cust (binary parser/patcher) =====
|
||||
This class follows the original structure:
|
||||
- find magic in buffer using magicLen, mapper sizes
|
||||
- parse data using size-mapped getters/setters
|
||||
- produce Blob for download (patched buffer)
|
||||
*/
|
||||
class Cust {
|
||||
constructor() {
|
||||
this.storage = new CustStorage();
|
||||
this.magic = 1414747459; // original magic
|
||||
this.magicLen = 4;
|
||||
this.mapper = {
|
||||
2: { get: (offset) => this.view.getUint16(offset, true), set: (offset, v) => this.view.setUint16(offset, v, true) },
|
||||
4: { get: (offset) => this.view.getUint32(offset, true), set: (offset, v) => this.view.setUint32(offset, v, true) }
|
||||
};
|
||||
}
|
||||
|
||||
findMagicOffset() {
|
||||
this.view = new DataView(this.buffer);
|
||||
for (let offset = 0; offset < this.view.byteLength; offset += this.magicLen) {
|
||||
if (this.mapper[this.magicLen].get(offset) === this.magic) {
|
||||
this.beginOffset = offset;
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new Error("Invalid loader.kip file (magic not found)");
|
||||
}
|
||||
|
||||
save() {
|
||||
// update from table (validate & populate storage)
|
||||
this.storage.updateFromTable();
|
||||
|
||||
const writeOne = (entry) => {
|
||||
if (!entry.offset && entry.offset !== 0) {
|
||||
// If offset is missing in the UI, it's an error in mapping
|
||||
const el = entry.getInputElement();
|
||||
if (el) el.focus();
|
||||
throw new Error(`Failed to get offset for ${entry.name}`);
|
||||
}
|
||||
const mapper = this.mapper[entry.size];
|
||||
if (!mapper) {
|
||||
const el = entry.getInputElement();
|
||||
if (el) el.focus();
|
||||
throw new Error(`Unknown size at ${entry.name}`);
|
||||
}
|
||||
mapper.set(entry.offset, entry.value);
|
||||
};
|
||||
|
||||
// The original iterated over tables and used .offset values stored in entries
|
||||
CustTable.forEach(writeOne);
|
||||
AdvTable.forEach(writeOne);
|
||||
GpuTable.forEach(writeOne);
|
||||
|
||||
// persist storage to localStorage
|
||||
this.storage.save();
|
||||
|
||||
// create download link for patched buffer
|
||||
const blob = new Blob([this.buffer], { type: "application/octet-stream" });
|
||||
const url = URL.createObjectURL(blob);
|
||||
|
||||
const a = document.createElement("a");
|
||||
a.href = url;
|
||||
a.download = "loader.kip";
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
a.remove();
|
||||
URL.revokeObjectURL(url);
|
||||
|
||||
// UI: enable load last saved if needed
|
||||
this.toggleLoadLastSavedBtn(true);
|
||||
}
|
||||
|
||||
removeHTMLForm() {
|
||||
CustTable.forEach(e => e.removeElement());
|
||||
}
|
||||
|
||||
toggleLoadLastSavedBtn(visible) {
|
||||
const btn = document.getElementById("load_saved");
|
||||
if (!btn) return;
|
||||
if (visible) {
|
||||
btn.addEventListener("click", () => {
|
||||
if (this.storage.load()) this.storage.setTable();
|
||||
});
|
||||
btn.style.removeProperty("display");
|
||||
btn.removeAttribute("disabled");
|
||||
} else {
|
||||
btn.style.setProperty("display", "none");
|
||||
}
|
||||
}
|
||||
|
||||
createHTMLForm() {
|
||||
// create elements for each table entry
|
||||
CustTable.forEach(e => e.createElement("config-list-basic"));
|
||||
|
||||
// Add separators/titles for advanced and gpu lists
|
||||
const advContainer = document.getElementById("config-list-advanced");
|
||||
if (advContainer) {
|
||||
const p = document.createElement("p");
|
||||
p.innerHTML = "Advanced configuration";
|
||||
advContainer.appendChild(p);
|
||||
}
|
||||
const gpuContainer = document.getElementById("config-list-gpu");
|
||||
if (gpuContainer) {
|
||||
const p = document.createElement("p");
|
||||
p.innerHTML = "Gpu Volt configuration";
|
||||
gpuContainer.appendChild(p);
|
||||
}
|
||||
|
||||
AdvTable.forEach(e => e.createElement("config-list-advanced"));
|
||||
GpuTable.forEach(e => e.createElement("config-list-gpu"));
|
||||
|
||||
// Buttons: load default, load saved, save
|
||||
const loadDefaultBtn = document.getElementById("load_default");
|
||||
if (loadDefaultBtn) {
|
||||
loadDefaultBtn.removeAttribute("disabled");
|
||||
loadDefaultBtn.addEventListener("click", () => {
|
||||
CustTable.forEach(e => e.setElementDefaultValue());
|
||||
});
|
||||
}
|
||||
|
||||
// show load saved if we have saved storage
|
||||
this.toggleLoadLastSavedBtn(this.storage.load() !== null);
|
||||
|
||||
const saveBtn = document.getElementById("save");
|
||||
if (saveBtn) {
|
||||
saveBtn.removeAttribute("disabled");
|
||||
saveBtn.addEventListener("click", () => {
|
||||
try {
|
||||
this.save();
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
alert(String(err));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
initCustTabs() {
|
||||
// map nav buttons (role="tablist") to platform toggles
|
||||
const tabButtons = Array.from(document.querySelectorAll('nav[role="tablist"] > button, .cust-platform-tabs > button'));
|
||||
if (!tabButtons.length) return;
|
||||
tabButtons.forEach(btn => {
|
||||
btn.removeAttribute("disabled");
|
||||
const plat = Number(btn.getAttribute("data-platform"));
|
||||
btn.addEventListener("click", (ev) => {
|
||||
// style toggling
|
||||
const outlineClass = ["outline"];
|
||||
btn.classList.remove(...outlineClass);
|
||||
tabButtons.filter(x => x !== btn).forEach(x => x.classList.add(...outlineClass));
|
||||
// show/hide entries
|
||||
CustTable.forEach(e => {
|
||||
if (e.isAvailableFor(plat)) e.showElement(); else e.hideElement();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
parse() {
|
||||
// beginOffset should already exist
|
||||
let offset = this.beginOffset + this.magicLen;
|
||||
// read revision (4-byte)
|
||||
this.rev = this.mapper[4].get(offset);
|
||||
if (this.rev !== CUST_REV_ADV) throw new Error(`Unsupported custRev, expected: ${CUST_REV_ADV}, got ${this.rev}`);
|
||||
offset += 4;
|
||||
const revEl = document.getElementById("cust_rev");
|
||||
if (revEl) revEl.innerHTML = `Cust v${this.rev} is loaded.`;
|
||||
|
||||
const readOne = (entry) => {
|
||||
entry.offset = offset;
|
||||
const mapper = this.mapper[entry.size];
|
||||
if (!mapper) {
|
||||
const el = entry.getInputElement();
|
||||
if (el) el.focus();
|
||||
throw new Error(`Unknown size at ${entry.name}`);
|
||||
}
|
||||
entry.value = mapper.get(offset);
|
||||
offset += entry.size;
|
||||
entry.validate();
|
||||
};
|
||||
|
||||
CustTable.forEach(readOne);
|
||||
AdvTable.forEach(readOne);
|
||||
GpuTable.forEach(readOne);
|
||||
}
|
||||
|
||||
load(buffer) {
|
||||
try {
|
||||
this.buffer = buffer;
|
||||
this.findMagicOffset();
|
||||
this.removeHTMLForm();
|
||||
this.parse();
|
||||
this.initCustTabs();
|
||||
this.createHTMLForm();
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
alert(String(err));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== Release fetching classes ===== */
|
||||
class ReleaseAsset {
|
||||
constructor(obj) {
|
||||
this.downloadUrl = obj?.browser_download_url;
|
||||
this.updatedAt = obj?.updated_at;
|
||||
}
|
||||
}
|
||||
|
||||
class ReleaseInfo {
|
||||
constructor() {
|
||||
this.ocLatestApi = "https://api.github.com/repos/Horizon-OC/Horizon-OC/releases/latest";
|
||||
}
|
||||
|
||||
async load() {
|
||||
try {
|
||||
const json = await this.responseFromApi(this.ocLatestApi);
|
||||
this.parseOcResponse(json);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
alert(String(err));
|
||||
}
|
||||
}
|
||||
|
||||
async responseFromApi(url) {
|
||||
const res = await fetch(url, { method: "GET", headers: { Accept: "application/json" } });
|
||||
if (!res.ok) throw new Error(`Failed to connect to "${url}": ${res.status}`);
|
||||
return await res.json();
|
||||
}
|
||||
|
||||
parseOcResponse(json) {
|
||||
this.ocVer = json.tag_name;
|
||||
const assets = json.assets || [];
|
||||
this.loaderKipAsset = new ReleaseAsset(assets.find(a => a.name.endsWith("hoc.kip")) || {});
|
||||
this.sdOutZipAsset = new ReleaseAsset(assets.find(a => a.name.endsWith("dist.zip")) || {});
|
||||
}
|
||||
}
|
||||
|
||||
class DownloadSection {
|
||||
constructor() {
|
||||
this.element = document.getElementById("download_btn_grid") || document.getElementById("download");
|
||||
}
|
||||
|
||||
async load() {
|
||||
// Wait until the element is visible in the viewport
|
||||
for (; !this.isVisible();) {
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
}
|
||||
const release = new ReleaseInfo();
|
||||
await release.load();
|
||||
this.update("loader_kip_btn", `hoc.kip <b>${release.ocVer}</b><br>${release.loaderKipAsset.updatedAt}`, release.loaderKipAsset.downloadUrl);
|
||||
this.update("sdout_zip_btn", `dist.zip <b>${release.ocVer}</b><br>${release.sdOutZipAsset.updatedAt}`, release.sdOutZipAsset.downloadUrl);
|
||||
}
|
||||
|
||||
isVisible() {
|
||||
if (!this.element) return true;
|
||||
const r = this.element.getBoundingClientRect();
|
||||
return r.top > 0 && r.left > 0 && r.bottom - r.height < (window.innerHeight || document.documentElement.clientHeight) && r.right - r.width < (window.innerWidth || document.documentElement.clientWidth);
|
||||
}
|
||||
|
||||
update(id, html, href) {
|
||||
const el = document.getElementById(id);
|
||||
if (!el) return;
|
||||
el.innerHTML = html;
|
||||
el.removeAttribute("aria-busy");
|
||||
if (href) el.setAttribute("href", href);
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== Initialization wiring ===== */
|
||||
document.addEventListener("DOMContentLoaded", async () => {
|
||||
// Ensure containers exist (fail gracefully if not)
|
||||
const ensureEl = (id, createTag = "div") => {
|
||||
if (!document.getElementById(id)) {
|
||||
const container = document.createElement(createTag);
|
||||
container.id = id;
|
||||
container.classList.add("mt-4");
|
||||
// append to config section or body as fallback
|
||||
const config = document.getElementById("config") || document.body;
|
||||
config.appendChild(container);
|
||||
}
|
||||
};
|
||||
|
||||
["config-list-basic", "config-list-advanced", "config-list-gpu"].forEach(id => ensureEl(id));
|
||||
|
||||
// Wire file input
|
||||
const fileInput = document.getElementById("file");
|
||||
if (fileInput) {
|
||||
fileInput.addEventListener("change", (ev) => {
|
||||
const cust = new Cust();
|
||||
const target = ev.target;
|
||||
if (!target || !target.files) return;
|
||||
const fr = new FileReader();
|
||||
fr.readAsArrayBuffer(target.files[0]);
|
||||
fr.onloadend = (e) => {
|
||||
if (e.target && e.target.readyState === FileReader.DONE) {
|
||||
cust.load(e.target.result);
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
// Wire DownloadSection (non-blocking)
|
||||
(async () => {
|
||||
try {
|
||||
const ds = new DownloadSection();
|
||||
await ds.load();
|
||||
} catch (err) {
|
||||
console.warn("DownloadSection failed:", err);
|
||||
}
|
||||
})();
|
||||
|
||||
// If HTML had DOMContentLoaded wiring in original minified code, emulate it:
|
||||
// some initialization that original file did on DOMContentLoaded -> start the DownloadSection (done above)
|
||||
});
|
||||
153
docs/index.html
153
docs/index.html
@@ -1,153 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Horizon OC</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link href="https://unpkg.com/aos@2.3.1/dist/aos.css" rel="stylesheet">
|
||||
<style>
|
||||
/* Background gradient */
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: 'Segoe UI', Roboto, system-ui, sans-serif;
|
||||
color: white;
|
||||
background: linear-gradient(160deg, #1a1a1a 0%, #2a2a2a 50%, #3a3a3a 100%);
|
||||
min-height: 100vh;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
/* Liquid glass panels */
|
||||
.glass {
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
border: 1px solid rgba(255, 255, 255, 0.15);
|
||||
backdrop-filter: blur(20px);
|
||||
border-radius: 20px;
|
||||
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.3);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.glass:hover {
|
||||
background: rgba(255, 255, 255, 0.12);
|
||||
transform: translateY(-4px);
|
||||
}
|
||||
|
||||
/* Hero gradient text */
|
||||
.gradient-text {
|
||||
background: linear-gradient(to right, #a3baff, #b8f3ff);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
|
||||
/* Buttons: Liquid glass style */
|
||||
.button-glass {
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
backdrop-filter: blur(20px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.25);
|
||||
color: #fff;
|
||||
padding: 0.8rem 2rem;
|
||||
border-radius: 9999px;
|
||||
font-weight: 600;
|
||||
transition: all 0.25s ease;
|
||||
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.6rem;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.button-glass:hover {
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
footer {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.15);
|
||||
padding: 1.5rem 0;
|
||||
text-align: center;
|
||||
color: #ccc;
|
||||
font-size: 0.9rem;
|
||||
margin-top: 4rem;
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
/* GitHub Icon */
|
||||
.github-icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
fill: white;
|
||||
transition: fill 0.3s;
|
||||
}
|
||||
.button-glass:hover .github-icon {
|
||||
fill: #b8f3ff;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- Header -->
|
||||
<header class="text-center py-20">
|
||||
<h1 class="text-6xl font-extrabold mb-4 gradient-text">Horizon OC</h1>
|
||||
<p class="text-gray-300 text-lg">Upgrade the performance of your Nintendo Switch Console</p>
|
||||
|
||||
<div class="mt-6 flex justify-center gap-4">
|
||||
<a href="#download" class="button-glass">Download Now</a>
|
||||
<a href="configurator.html" class="button-glass">Open Configurator</a>
|
||||
<a href="https://github.com/Horizon-OC/Horizon-OC" target="_blank" class="button-glass">
|
||||
<!-- GitHub SVG Icon -->
|
||||
<svg class="github-icon" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8a8 8 0 005.47 7.59c.4.07.55-.17.55-.38v-1.32C3.73 14.9 3.27 13.4 3.27 13.4c-.36-.9-.88-1.14-.88-1.14-.72-.49.05-.48.05-.48.8.06 1.22.83 1.22.83.71 1.21 1.87.86 2.33.66.07-.52.28-.86.5-1.06-2.22-.25-4.55-1.11-4.55-4.95 0-1.09.39-1.98 1.03-2.68-.1-.25-.45-1.27.1-2.65 0 0 .84-.27 2.75 1.02A9.56 9.56 0 018 3.43a9.6 9.6 0 012.5.34c1.9-1.29 2.74-1.02 2.74-1.02.55 1.38.2 2.4.1 2.65.64.7 1.03 1.59 1.03 2.68 0 3.85-2.34 4.7-4.57 4.95.29.25.54.73.54 1.48v2.2c0 .21.15.45.55.38A8 8 0 0016 8c0-4.42-3.58-8-8-8z"/>
|
||||
</svg>
|
||||
GitHub
|
||||
</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- About Section -->
|
||||
<section class="max-w-3xl mx-auto text-center py-16 px-6 glass" data-aos="fade-up">
|
||||
<h2 class="text-3xl font-bold mb-4">What is Horizon OC?</h2>
|
||||
<p class="text-gray-300">
|
||||
Horizon OC is a tool to overclock your modded Nintendo Switch console.
|
||||
This can help improve frame rates, load times, and latency in games.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<!-- Features -->
|
||||
<section class="py-20">
|
||||
<div class="max-w-6xl mx-auto grid md:grid-cols-3 gap-8 px-6">
|
||||
<div class="glass p-6 text-center" data-aos="zoom-in" data-aos-delay="100">
|
||||
<h3 class="text-xl font-semibold mb-2">⚡ Performance</h3>
|
||||
<p class="text-gray-300">Overclocking your console can lead to significantly better performance in demanding titles.</p>
|
||||
</div>
|
||||
<div class="glass p-6 text-center" data-aos="zoom-in" data-aos-delay="200">
|
||||
<h3 class="text-xl font-semibold mb-2">☣ Safety</h3>
|
||||
<p class="text-gray-300">Horizon OC aims to be as safe as possible, while allowing advanced users to customize it further.</p>
|
||||
</div>
|
||||
<div class="glass p-6 text-center" data-aos="zoom-in" data-aos-delay="300">
|
||||
<h3 class="text-xl font-semibold mb-2">🔧 Customizable</h3>
|
||||
<p class="text-gray-300">Horizon OC comes with an advanced configurator allowing you to tune it for your own needs.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Download Section -->
|
||||
<section id="download" class="text-center py-20 glass max-w-3xl mx-auto px-6" data-aos="fade-up">
|
||||
<h2 class="text-3xl font-bold mb-6">Get Horizon OC</h2>
|
||||
<a href="#" class="button-glass">Download Latest Release</a>
|
||||
<p class="text-gray-400 mt-4">Ensure you are using the latest version of Atmosphere.</p>
|
||||
</section>
|
||||
|
||||
<!-- Footer -->
|
||||
<footer>
|
||||
This website is open source and licensed under the GPLv2.
|
||||
</footer>
|
||||
|
||||
<script src="https://unpkg.com/aos@2.3.1/dist/aos.js"></script>
|
||||
<script>AOS.init({ once: true, duration: 800 });</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user