Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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
|
||||
|
||||
|
||||
11
README.md
11
README.md
@@ -114,6 +114,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 +143,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 +165,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
|
||||
|
||||
@@ -30,8 +30,6 @@ 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;
|
||||
|
||||
@@ -73,7 +71,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 };
|
||||
|
||||
@@ -176,3 +174,4 @@ namespace ams::ldr::hoc {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -144,7 +144,7 @@ void SafetyCheck() {
|
||||
{ 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 },
|
||||
{ GET_MAX_OF_ARR(erista::maxEmcClocks), 1600'000, 2600'000 },
|
||||
{ C.marikoCpuMaxVolt, 1000, 1235 },
|
||||
{ C.marikoEmcMaxClock, 1600'000, 3500'000 },
|
||||
{ C.marikoEmcVddqVolt, 250'000, 700'000 },
|
||||
|
||||
@@ -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[] = {
|
||||
|
||||
@@ -324,13 +324,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 +370,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,32 +387,37 @@ 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();
|
||||
}
|
||||
@@ -445,4 +455,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);
|
||||
@@ -575,14 +574,6 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -12,9 +12,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 +309,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 +491,40 @@
|
||||
#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_INTR_EN_0 0x60
|
||||
#define DVFS_DFLL_THROTTLE_CTRL_0 0x64
|
||||
#define DVFS_DFLL_THROTTLE_LIGHT_0 0x68
|
||||
#define DVFS_DFLL_THROTTLE_MEDIUM_0 0x6C
|
||||
#define DVFS_DFLL_THROTTLE_HEAVY_0 0x70
|
||||
#define CL_DVFS_I2C_CLK_DIVISOR_REGISTER_0 0x16C
|
||||
|
||||
@@ -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,21 @@ 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;
|
||||
|
||||
#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,9 +58,11 @@ typedef enum {
|
||||
|
||||
HorizonOCConfigValue_DVFSMode,
|
||||
HorizonOCConfigValue_DVFSOffset,
|
||||
HorizonOCConfigValue_LiveCpuUv,
|
||||
HorizonOCConfigValue_EnableExperimentalSettings,
|
||||
|
||||
HorizonOCConfigValue_GPUScheduling,
|
||||
|
||||
HorizonOCConfigValue_GPUSchedulingMethod,
|
||||
KipConfigValue_custRev,
|
||||
// KipConfigValue_mtcConf,
|
||||
KipConfigValue_hpMode,
|
||||
@@ -232,6 +234,16 @@ 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";
|
||||
|
||||
// KIP config values
|
||||
case KipConfigValue_custRev:
|
||||
return pretty ? "Custom Revision" : "kip_cust_rev";
|
||||
@@ -410,6 +422,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 +470,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:
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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.41
|
||||
TARGET_VERSION := $(APP_VERSION)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
@@ -55,7 +55,7 @@ CFLAGS := -Os -Wall -flto -fdata-sections -ffunction-sections -fno-rtti -fno-com
|
||||
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,88 @@ 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> 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),
|
||||
};
|
||||
|
||||
this->addModuleListItemValue(profile, HorizonOCModule_Governor, "Governor", 0, 0, 1, "", 1, 0, ValueThresholds(), governorSettings, false);
|
||||
}
|
||||
|
||||
void AppProfileGui::listUI()
|
||||
@@ -337,4 +414,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;
|
||||
};
|
||||
};
|
||||
@@ -118,32 +118,32 @@ 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)
|
||||
continue;
|
||||
// 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 == "gpu" &&
|
||||
// // this->configList->values[HocClkConfigValue_MarikoMaxGpuClock] < mhz)
|
||||
// // continue;
|
||||
|
||||
// if (moduleName == "mem" &&
|
||||
// this->configList->values[HocClkConfigValue_MarikoMaxMemClock] < 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;
|
||||
// } 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 == "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,16 @@ 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> 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),
|
||||
};
|
||||
|
||||
this->addModuleListItemValue(HorizonOCModule_Governor, "Governor", 0, 0, 1, "", 1, 0, ValueThresholds(), governorSettings, false);
|
||||
}
|
||||
|
||||
void GlobalOverrideGui::refresh()
|
||||
@@ -306,17 +330,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);
|
||||
};
|
||||
};
|
||||
@@ -239,13 +239,14 @@ void MiscGui::addFreqButton(SysClkConfigValue configVal,
|
||||
|
||||
void MiscGui::listUI()
|
||||
{
|
||||
ValueThresholds thresholdsDisabled(0, 0);
|
||||
std::vector<NamedValue> noNamedValues = {};
|
||||
|
||||
this->listElement->addItem(new tsl::elm::CategoryHeader("Settings"));
|
||||
Result rc = sysclkIpcGetConfigValues(configList);
|
||||
if (R_FAILED(rc)) [[unlikely]] {
|
||||
FatalGui::openWithResultCode("sysclkIpcGetConfigValues", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
this->listElement->addItem(new tsl::elm::CategoryHeader("Safety Settings"));
|
||||
addConfigToggle(HocClkConfigValue_UncappedClocks, nullptr);
|
||||
addConfigToggle(HocClkConfigValue_OverwriteBoostMode, nullptr);
|
||||
addConfigToggle(HocClkConfigValue_ThermalThrottle, nullptr);
|
||||
addConfigToggle(HocClkConfigValue_HandheldTDP, nullptr);
|
||||
// addConfigToggle(HocClkConfigValue_EnforceBoardLimit, nullptr);
|
||||
@@ -286,11 +287,28 @@ void MiscGui::listUI()
|
||||
);
|
||||
#endif
|
||||
|
||||
if(IsMariko()) {
|
||||
addFreqButton(HocClkConfigValue_MarikoMaxCpuClock, nullptr, SysClkModule_CPU, cpu_freq_label_m);
|
||||
} else {
|
||||
addFreqButton(HocClkConfigValue_EristaMaxCpuClock, nullptr, SysClkModule_CPU, cpu_freq_label_e);
|
||||
}
|
||||
ValueThresholds thresholdsDisabled(0, 0);
|
||||
std::vector<NamedValue> noNamedValues = {};
|
||||
|
||||
this->listElement->addItem(new tsl::elm::CategoryHeader("CPU Settings"));
|
||||
addConfigToggle(HocClkConfigValue_OverwriteBoostMode, nullptr);
|
||||
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"),
|
||||
};
|
||||
|
||||
this->listElement->addItem(new tsl::elm::CategoryHeader("GPU Settings"));
|
||||
addConfigButton(
|
||||
HorizonOCConfigValue_GPUScheduling,
|
||||
"GPU Scheduling Override",
|
||||
ValueRange(0, 0, 1, "", 0),
|
||||
"GPU Scheduling Override",
|
||||
&thresholdsDisabled,
|
||||
{},
|
||||
gpuSchedValues,
|
||||
false
|
||||
);
|
||||
|
||||
if (IsMariko()) {
|
||||
std::vector<NamedValue> dvfsValues = {
|
||||
@@ -328,7 +346,6 @@ void MiscGui::listUI()
|
||||
};
|
||||
|
||||
addConfigButton(HorizonOCConfigValue_DVFSOffset, "GPU DVFS Offset", ValueRange(0, 12, 1, "", 0), "GPU DVFS Offset", &thresholdsDisabled, {}, dvfsOffset, false);
|
||||
|
||||
}
|
||||
|
||||
this->listElement->addItem(new tsl::elm::CategoryHeader("KIP"));
|
||||
@@ -377,6 +394,17 @@ void MiscGui::listUI()
|
||||
});
|
||||
this->listElement->addItem(gpuSubmenu);
|
||||
|
||||
this->listElement->addItem(new tsl::elm::CategoryHeader("Display"));
|
||||
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);
|
||||
renderer->drawString("refresh rates may cause stress", false, x + 20, y + 50, 18, tsl::style::color::ColorText);
|
||||
renderer->drawString("or damage to your display! ", false, x + 20, y + 70, 18, tsl::style::color::ColorText);
|
||||
renderer->drawString("Proceed at your own risk!", false, x + 20, y + 90, 18, tsl::style::color::ColorText);
|
||||
});
|
||||
warningText->setBoundaries(0, 0, tsl::cfg::FramebufferWidth, 110);
|
||||
this->listElement->addItem(warningText);
|
||||
addConfigToggle(HorizonOCConfigValue_EnableUnsafeDisplayFreqs, nullptr);
|
||||
|
||||
#if IS_MINIMAL == 0
|
||||
// std::vector<NamedValue> chargerCurrents = {
|
||||
@@ -391,92 +419,86 @@ 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
|
||||
);
|
||||
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);
|
||||
renderer->drawString("refresh rates may cause stress", false, x + 20, y + 50, 18, tsl::style::color::ColorText);
|
||||
renderer->drawString("or damage to your display! ", false, x + 20, y + 70, 18, tsl::style::color::ColorText);
|
||||
renderer->drawString("Proceed at your own risk!", false, x + 20, y + 90, 18, tsl::style::color::ColorText);
|
||||
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);
|
||||
});
|
||||
warningText->setBoundaries(0, 0, tsl::cfg::FramebufferWidth, 110);
|
||||
this->listElement->addItem(warningText);
|
||||
addConfigToggle(HorizonOCConfigValue_EnableUnsafeDisplayFreqs, nullptr);
|
||||
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
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
// 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);
|
||||
|
||||
// addConfigButton(
|
||||
// HorizonOCConfigValue_BatteryChargeCurrent,
|
||||
// "Charge Current Override",
|
||||
// ValueRange(0, 0, 1, "", 0),
|
||||
// "Charge Current Override",
|
||||
// &chargerThresholds,
|
||||
// {},
|
||||
// chargerCurrents,
|
||||
// false
|
||||
// );
|
||||
|
||||
// }
|
||||
#endif
|
||||
|
||||
}
|
||||
@@ -785,8 +807,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),
|
||||
|
||||
@@ -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,162 @@ 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,258 @@ 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);
|
||||
}
|
||||
if(targetHz) {
|
||||
Board::SetHz(SysClkModule_GPU, ~0);
|
||||
Board::SetHz(SysClkModule_GPU, targetHz);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if(apmExtIsBoostMode(mode) && !this->config->GetConfigValue(HocClkConfigValue_OverwriteBoostMode)) {
|
||||
// ResetToStockClocks();
|
||||
return;
|
||||
Board::SetHz(SysClkModule_GPU, ~0);
|
||||
if(targetHz) {
|
||||
Board::SetHz(SysClkModule_GPU, targetHz);
|
||||
} 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)) {
|
||||
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))
|
||||
{
|
||||
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))
|
||||
{
|
||||
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 +927,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 +940,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 +967,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 +1029,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 +1039,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 +1326,4 @@ void ClockManager::GetKipData() {
|
||||
FileUtils::LogLine("[clock_manager] Config refresh error in GetKipData!");
|
||||
writeNotification("Horizon OC\nConfig refresh failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,52 +23,166 @@
|
||||
* 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:
|
||||
static ClockManager* GetInstance();
|
||||
static void Initialize();
|
||||
static void Exit();
|
||||
|
||||
|
||||
ClockManager();
|
||||
virtual ~ClockManager();
|
||||
|
||||
SysClkContext GetCurrentContext();
|
||||
Config* GetConfig();
|
||||
void SetRunning(bool running);
|
||||
bool Running();
|
||||
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 +190,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 +199,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;
|
||||
|
||||
BIN
dist/atmosphere/contents/00FF0000636C6BFF/exefs.nsp
vendored
BIN
dist/atmosphere/contents/00FF0000636C6BFF/exefs.nsp
vendored
Binary file not shown.
BIN
dist/atmosphere/kips/hoc.kip
vendored
BIN
dist/atmosphere/kips/hoc.kip
vendored
Binary file not shown.
BIN
dist/switch/.overlays/Horizon-OC-Monitor.ovl
vendored
BIN
dist/switch/.overlays/Horizon-OC-Monitor.ovl
vendored
Binary file not shown.
BIN
dist/switch/.overlays/horizon-oc-overlay.ovl
vendored
BIN
dist/switch/.overlays/horizon-oc-overlay.ovl
vendored
Binary file not shown.
Reference in New Issue
Block a user