diff --git a/Source/sys-clk/sysmodule/src/clock_manager.cpp b/Source/sys-clk/sysmodule/src/clock_manager.cpp index da9c97cb..dad62042 100644 --- a/Source/sys-clk/sysmodule/src/clock_manager.cpp +++ b/Source/sys-clk/sysmodule/src/clock_manager.cpp @@ -39,7 +39,7 @@ #define HOSPPC_HAS_BOOST (hosversionAtLeast(7,0,0)) ClockManager *ClockManager::instance = NULL; - +Thread governorTHREAD; ClockManager *ClockManager::GetInstance() { @@ -84,13 +84,26 @@ ClockManager::ClockManager() this->rnxSync = new ReverseNXSync; if(this->config->GetConfigValue(HocClkConfigValue_KipEditing)) - this->GetKipData(); + this->GetKipData(); + threadCreate( + &governorTHREAD, + ClockManager::GovernorThread, + this, + NULL, + 0x2000, + 0x3F, + -2 + ); + + threadStart(&governorTHREAD); + } ClockManager::~ClockManager() { delete this->config; delete this->context; + threadClose(&governorTHREAD); } SysClkContext ClockManager::GetCurrentContext() @@ -249,6 +262,105 @@ u32 findIndexMHz(u32 arr[], u32 size, u32 value) { return 0; } +void ClockManager::GovernorThread(void* arg) +{ + ClockManager* mgr = static_cast(arg); + + for (;;) + { + if (!mgr->running) + { + svcSleepThread(50'000'000); + continue; + } + + std::scoped_lock lock{mgr->contextMutex}; + + if (!mgr->config->GetConfigValue(HocClkConfigValue_HandheldGovernor)) + { + svcSleepThread(50'000'000); + continue; + } + + auto& table = mgr->freqTable[SysClkModule_GPU]; + if (table.count == 0) + { + svcSleepThread(50'000'000); + continue; + } + + u32 currentHz = Board::GetHz(SysClkModule_GPU); + + u32 index = 0; + 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) + { + targetHz = mgr->config->GetAutoClockHz( + mgr->context->applicationId, + SysClkModule_GPU, + mgr->context->profile + ); + + if (!targetHz) + { + targetHz = mgr->config->GetAutoClockHz( + GLOBAL_PROFILE_ID, + SysClkModule_GPU, + mgr->context->profile + ); + } + } + + int load = Board::GetPartLoad(HocClkPartLoad_GPU); + + if (load < 600 && index > 0) + { + index--; + } + else if (load > 800 && index + 1 < table.count) + { + index++; + } + + if (targetHz) + { + u32 targetIndex = index; + for (u32 i = 0; i < table.count; i++) + { + if (table.list[i] >= targetHz) + { + targetIndex = i; + break; + } + } + + if (index > targetIndex && index > 0) + index--; + else if (index < targetIndex && index + 1 < table.count) + index++; + } + + u32 newHz = table.list[index]; + if (mgr->IsAssignableHz(SysClkModule_GPU, newHz)) + { + Board::SetHz(SysClkModule_GPU, newHz); + mgr->context->freqs[SysClkModule_GPU] = newHz; + } + + svcSleepThread(50'000'000); + } +} + + void ClockManager::Tick() { std::scoped_lock lock{this->contextMutex}; @@ -281,50 +393,6 @@ void ClockManager::Tick() return; } - u64 currentFreqIndex = findIndex(freqTable[SysClkModule_GPU].list, SYSCLK_FREQ_LIST_MAX, Board::GetHz(SysClkModule_GPU)); - if(this->config->GetConfigValue(HocClkConfigValue_HandheldGovernor)) { - u64 targetHz = this->context->overrideFreqs[SysClkModule_GPU]; - if (!targetHz) - { - targetHz = this->config->GetAutoClockHz(this->context->applicationId, SysClkModule_GPU, this->context->profile); - if(!targetHz) - targetHz = this->config->GetAutoClockHz(GLOBAL_PROFILE_ID, SysClkModule_GPU, this->context->profile); - } - if(Board::GetPartLoad(HocClkPartLoad_GPU) < 600) { - currentFreqIndex--; - if(currentFreqIndex < 0) { - currentFreqIndex = 0; - } - Board::SetHz(SysClkModule_GPU, freqTable[SysClkModule_GPU].list[currentFreqIndex]); - } - if(Board::GetPartLoad(HocClkPartLoad_GPU) > 800) { - currentFreqIndex++; - - if(!targetHz) { - if(IsAssignableHz(SysClkModule_GPU, freqTable[SysClkModule_GPU].list[currentFreqIndex])) { - if(Board::GetSocType() == SysClkSocType_Mariko) { - if(freqTable[SysClkModule_GPU].list[currentFreqIndex] / 1000000 < this->config->GetConfigValue(HocClkConfigValue_MarikoMaxGpuClock)) - currentFreqIndex++; // TODO: make this properly go back to target freq if the old target freq is more than one index away - else // probably needs the max clocks to be stored in hz instead of mhz to compare easily - currentFreqIndex--; - } else { - if(freqTable[SysClkModule_GPU].list[currentFreqIndex] / 1000000 < this->config->GetConfigValue(HocClkConfigValue_EristaMaxGpuClock)) - currentFreqIndex++; - else - currentFreqIndex--; - } - } else { - currentFreqIndex--; - } - } else { - if(currentFreqIndex > findIndex(freqTable[SysClkModule_GPU].list, SYSCLK_FREQ_LIST_MAX, targetHz)) - currentFreqIndex--; - } - Board::SetHz(SysClkModule_GPU, freqTable[SysClkModule_GPU].list[currentFreqIndex]); - - } - } - bool noGPU = false; if (this->RefreshContext() || this->config->Refresh()) diff --git a/Source/sys-clk/sysmodule/src/clock_manager.h b/Source/sys-clk/sysmodule/src/clock_manager.h index c9fab4e9..2f94c905 100644 --- a/Source/sys-clk/sysmodule/src/clock_manager.h +++ b/Source/sys-clk/sysmodule/src/clock_manager.h @@ -35,6 +35,7 @@ #include "board.h" #include #include "integrations.h" +void governorThread(void*); class ReverseNXSync; @@ -60,6 +61,7 @@ class ClockManager void SetRNXRTMode(ReverseNXMode mode); void SetKipData(); void GetKipData(); + static void GovernorThread(void* arg); struct { std::uint32_t count; std::uint32_t list[SYSCLK_FREQ_LIST_MAX]; diff --git a/Source/sys-clk/sysmodule/src/fancontrol.c b/Source/sys-clk/sysmodule/src/fancontrol.c deleted file mode 100644 index 11e1be1d..00000000 --- a/Source/sys-clk/sysmodule/src/fancontrol.c +++ /dev/null @@ -1,250 +0,0 @@ -#include "fancontrol.h" -#include "tmp451.h" - -//Fan curve table -TemperaturePoint defaultTable[] = -{ - { .temperature_c = 25.0, .fanLevel_f = 0.00 }, - { .temperature_c = 30.0, .fanLevel_f = 0.00 }, - { .temperature_c = 35.0, .fanLevel_f = 0.00 }, - { .temperature_c = 40.0, .fanLevel_f = 0.00 }, - { .temperature_c = 45.0, .fanLevel_f = 0.30 }, - { .temperature_c = 50.0, .fanLevel_f = 0.50 }, - { .temperature_c = 55.0, .fanLevel_f = 0.60 }, - { .temperature_c = 60.0, .fanLevel_f = 0.85 }, - { .temperature_c = 65.0, .fanLevel_f = 0.95 }, - { .temperature_c = 70.0, .fanLevel_f = 1.00 } -}; - - -TemperaturePoint *fanControllerTable; - -//Fan -Thread FanControllerThread; -bool fanControllerThreadExit = false; - -//Log -char logPath[PATH_MAX]; - -//Power management -Event powerStateChangeEvent; -bool isPowerStateInitialized = false; - -void CreateDir(char *dir) -{ - char dirPath[PATH_MAX]; - - for(int i = 0; i < PATH_MAX; i++) - { - if(*(dir + i) == '/' && access(dirPath, F_OK) == -1) - { - mkdir(dirPath, 0777); - } - dirPath[i] = *(dir + i); - } -} - -void InitLog() -{ - if(access(LOG_DIR, F_OK) == -1) - CreateDir(LOG_DIR); - - if(access(LOG_FILE, F_OK) != -1) - remove(LOG_FILE); -} - -void WriteLog(char *buffer) -{ - FILE *log = fopen(LOG_FILE, "a"); - if(log != NULL) - { - fprintf(log, "%s\n", buffer); - } - fclose(log); -} - -void WriteConfigFile(TemperaturePoint *table) -{ - if(table == NULL) - { - table = malloc(sizeof(defaultTable)); - memcpy(table, defaultTable, sizeof(defaultTable)); - } - - if(access(CONFIG_DIR, F_OK) == -1) - CreateDir(CONFIG_DIR); - - FILE *config = fopen(CONFIG_FILE, "w"); - fwrite(table, TABLE_SIZE, 1, config); - fclose(config); -} - - - -void ReadConfigFile(TemperaturePoint **table_out) -{ - InitLog(); - - *table_out = malloc(sizeof(defaultTable)); - memcpy(*table_out, defaultTable, sizeof(defaultTable)); - - if(access(CONFIG_DIR, F_OK) == -1) - { - CreateDir(CONFIG_DIR); - WriteConfigFile(NULL); - } - else - { - if(access(CONFIG_FILE, F_OK) == -1) - { - WriteConfigFile(NULL); - } - else - { - FILE *config = fopen(CONFIG_FILE, "r"); - fread(*table_out, TABLE_SIZE, 1, config); - fclose(config); - } - } -} - -bool IsSystemAwake() -{ - // Check if system is in sleep mode by checking applet state - // appletGetOperationMode returns the current operation mode - AppletOperationMode opMode = appletGetOperationMode(); - - // If in handheld or console mode, system is awake - // If in any other mode (like sleep), we consider it asleep - return (opMode == AppletOperationMode_Handheld || opMode == AppletOperationMode_Console); -} - -void InitFanController(TemperaturePoint *table) -{ - fanControllerTable = table; - - if(R_FAILED(threadCreate(&FanControllerThread, FanControllerThreadFunction, NULL, NULL, 0x4000, 0x3F, -2))) - { - WriteLog("Error creating FanControllerThread"); - diagAbortWithResult(MAKERESULT(Module_Libnx, LibnxError_ShouldNotHappen)); - } -} - -void FanControllerThreadFunction(void*) -{ - FanController fc; - float fanLevelSet_f = 0; - float temperatureC_f = 0; - u64 awakeSleepTime = 1000000000ULL; // 1 second when awake - u64 sleepSleepTime = 10000000000ULL; // 10 seconds when in sleep - int sleepCheckCounter = 0; - - Result rs = fanOpenController(&fc, 0x3D000001); - if(R_FAILED(rs)) - { - WriteLog("Error opening fanController"); - diagAbortWithResult(MAKERESULT(Module_Libnx, LibnxError_ShouldNotHappen)); - } - - while(!fanControllerThreadExit) - { - // Check if system is awake every 40 iterations (~10 seconds) to reduce overhead - sleepCheckCounter++; - if(sleepCheckCounter >= 40) - { - bool isAwake = IsSystemAwake(); - sleepCheckCounter = 0; - - // If system is asleep, use longer sleep interval - if(!isAwake) - { - svcSleepThread(sleepSleepTime); - continue; - } - } - - rs = Tmp451GetSocTemp(&temperatureC_f); - if(R_FAILED(rs)) - { - WriteLog("tsSessionGetTemperature error"); - diagAbortWithResult(MAKERESULT(Module_Libnx, LibnxError_ShouldNotHappen)); - } - - if(temperatureC_f >= 0 && temperatureC_f <= fanControllerTable->temperature_c) - { - float m = 0; - float q = 0; - - m = fanControllerTable->fanLevel_f / fanControllerTable->temperature_c; - q = 0 - m; - - fanLevelSet_f = (m * temperatureC_f) + q; - - }else if(temperatureC_f >= (fanControllerTable + 9)->temperature_c) - { - fanLevelSet_f = (fanControllerTable + 9)->fanLevel_f; - }else - { - for(int i = 0; i < (TABLE_SIZE/sizeof(TemperaturePoint)) - 1; i++) - { - if(temperatureC_f >= (fanControllerTable + i)->temperature_c && temperatureC_f <= (fanControllerTable + i + 1)->temperature_c) - { - float m = 0; - float q = 0; - - m = ((fanControllerTable + i + 1)->fanLevel_f - (fanControllerTable + i)->fanLevel_f ) / ((fanControllerTable + i + 1)->temperature_c - (fanControllerTable + i)->temperature_c); - q = (fanControllerTable + i)->fanLevel_f - (m * (fanControllerTable + i)->temperature_c); - - fanLevelSet_f = (m * temperatureC_f) + q; - break; - } - } - } - - // Always update fan speed for immediate response - rs = fanControllerSetRotationSpeedLevel(&fc, fanLevelSet_f); - if(R_FAILED(rs)) - { - WriteLog("fanControllerSetRotationSpeedLevel error"); - diagAbortWithResult(MAKERESULT(Module_Libnx, LibnxError_ShouldNotHappen)); - } - - // Use responsive sleep time when awake (250ms) - svcSleepThread(awakeSleepTime); - } - - fanControllerClose(&fc); -} - -void StartFanControllerThread() -{ - if(R_FAILED(threadStart(&FanControllerThread))) - { - WriteLog("Error starting FanControllerThread"); - diagAbortWithResult(MAKERESULT(Module_Libnx, LibnxError_ShouldNotHappen)); - } -} - -void CloseFanControllerThread() -{ - Result rs; - fanControllerThreadExit = true; - rs = threadWaitForExit(&FanControllerThread); - if(R_FAILED(rs)) - { - WriteLog("Error waiting fanControllerThread"); - diagAbortWithResult(MAKERESULT(Module_Libnx, LibnxError_ShouldNotHappen)); - } - threadClose(&FanControllerThread); - fanControllerThreadExit = false; - free(fanControllerTable); -} - -void WaitFanController() -{ - if(R_FAILED(threadWaitForExit(&FanControllerThread))) - { - WriteLog("Error waiting fanControllerThread"); - diagAbortWithResult(MAKERESULT(Module_Libnx, LibnxError_ShouldNotHappen)); - } -} \ No newline at end of file diff --git a/Source/sys-clk/sysmodule/src/fancontrol.h b/Source/sys-clk/sysmodule/src/fancontrol.h deleted file mode 100644 index d7d16030..00000000 --- a/Source/sys-clk/sysmodule/src/fancontrol.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#define LOG_DIR "./config/horizon-oc/" -#define LOG_FILE "./config/horizon-oc/fan_log.txt" -#define CONFIG_DIR "./config/horizon-oc/" -#define CONFIG_FILE "./config/horizon-oc/config.dat" -#define TABLE_SIZE sizeof(TemperaturePoint) * 10 - - -typedef struct -{ - int temperature_c; - float fanLevel_f; -} TemperaturePoint; - -void WriteConfigFile(TemperaturePoint *table); -void ReadConfigFile(TemperaturePoint **table_out); - -void InitFanController(TemperaturePoint *table); -void FanControllerThreadFunction(void*); -void StartFanControllerThread(); -void CloseFanControllerThread(); -void WaitFanController(); -void WriteLog(char *buffer); - -#ifdef __cplusplus -} -#endif diff --git a/Source/sys-clk/sysmodule/src/i2c.h b/Source/sys-clk/sysmodule/src/i2c.h deleted file mode 100644 index 653e7e1e..00000000 --- a/Source/sys-clk/sysmodule/src/i2c.h +++ /dev/null @@ -1,82 +0,0 @@ -#ifndef I2C_H -#define I2C_H - -#include - -Result I2cReadRegHandler16(u8 reg, I2cDevice dev, u16 *out) -{ - struct readReg { - u8 send; - u8 sendLength; - u8 sendData; - u8 receive; - u8 receiveLength; - }; - - I2cSession _session; - - Result res = i2cOpenSession(&_session, dev); - if (res) - return res; - - u16 val; - - struct readReg readRegister = { - .send = 0 | (I2cTransactionOption_Start << 6), - .sendLength = sizeof(reg), - .sendData = reg, - .receive = 1 | (I2cTransactionOption_All << 6), - .receiveLength = sizeof(val), - }; - - res = i2csessionExecuteCommandList(&_session, &val, sizeof(val), &readRegister, sizeof(readRegister)); - if (res) - { - i2csessionClose(&_session); - return res; - } - - *out = val; - i2csessionClose(&_session); - return 0; -} - -Result I2cReadRegHandler8(u8 reg, I2cDevice dev, u8 *out) -{ - struct readReg { - u8 send; - u8 sendLength; - u8 sendData; - u8 receive; - u8 receiveLength; - }; - - I2cSession _session; - - Result res = i2cOpenSession(&_session, dev); - if (res) - return res; - - u8 val; - - struct readReg readRegister = { - .send = 0 | (I2cTransactionOption_Start << 6), - .sendLength = sizeof(reg), - .sendData = reg, - .receive = 1 | (I2cTransactionOption_All << 6), - .receiveLength = sizeof(val), - }; - - res = i2csessionExecuteCommandList(&_session, &val, sizeof(val), &readRegister, sizeof(readRegister)); - if (res) - { - i2csessionClose(&_session); - return res; - } - - *out = val; - i2csessionClose(&_session); - return 0; -} - -#endif \ No newline at end of file diff --git a/Source/sys-clk/sysmodule/src/main.cpp b/Source/sys-clk/sysmodule/src/main.cpp index dd659b24..d092e48d 100644 --- a/Source/sys-clk/sysmodule/src/main.cpp +++ b/Source/sys-clk/sysmodule/src/main.cpp @@ -37,7 +37,6 @@ #include "process_management.h" #include "clock_manager.h" #include "ipc_service.h" -#include "fancontrol.h" #define INNER_HEAP_SIZE 0x30000 extern "C" diff --git a/Source/sys-clk/sysmodule/src/tmp451.h b/Source/sys-clk/sysmodule/src/tmp451.h deleted file mode 100644 index 3d71aaee..00000000 --- a/Source/sys-clk/sysmodule/src/tmp451.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * SOC/PCB Temperature driver for Nintendo Switch's TI TMP451 - * - * Copyright (c) 2018 CTCaer - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/* - * Modified by: MasaGratoR - */ - -//#include -#include "i2c.h" - -//#define TMP451_I2C_ADDR 0x4C - -#define TMP451_PCB_TEMP_REG 0x00 -#define TMP451_SOC_TEMP_REG 0x01 - -/* -#define TMP451_CONFIG_REG 0x09 -#define TMP451_CNV_RATE_REG 0x0A -*/ - -#define TMP451_SOC_TEMP_DEC_REG 0x10 -#define TMP451_PCB_TEMP_DEC_REG 0x15 - -/* -#define TMP451_SOC_TMP_OFH_REG 0x11 -#define TMP451_SOC_TMP_OFL_REG 0x12 -*/ - -// If input is false, the return value is packed. MSByte is the integer in oC -// and the LSByte is the decimal point truncated to 2 decimal places. -// Otherwise it's an integer oC. -/* -u16 tmp451_get_soc_temp(bool integer); -u16 tmp451_get_pcb_temp(bool integer); -void tmp451_init(); -void tmp451_end(); -*/ - -Result Tmp451ReadReg(u8 reg, u8 *out) -{ - u8 data = 0; - Result res = I2cReadRegHandler8(reg, I2cDevice_Tmp451, &data); - - if (R_FAILED(res)) - { - return res; - } - - *out = data; - return res; -} - -Result Tmp451GetSocTemp(float* temperature) { - u8 integer = 0; - u8 decimals = 0; - - Result rc = Tmp451ReadReg(TMP451_SOC_TEMP_REG, &integer); - if (R_FAILED(rc)) - return rc; - rc = Tmp451ReadReg(TMP451_SOC_TEMP_DEC_REG, &decimals); - if (R_FAILED(rc)) - return rc; - - decimals = ((u16)(decimals >> 4) * 625) / 100; - *temperature = (float)(integer) + ((float)(decimals) / 100); - return rc; -} - -Result Tmp451GetPcbTemp(float* temperature) { - u8 integer = 0; - u8 decimals = 0; - - Result rc = Tmp451ReadReg(TMP451_PCB_TEMP_REG, &integer); - if (R_FAILED(rc)) - return rc; - rc = Tmp451ReadReg(TMP451_PCB_TEMP_DEC_REG, &decimals); - if (R_FAILED(rc)) - return rc; - - decimals = ((u16)(decimals >> 4) * 625) / 100; - *temperature = (float)(integer) + ((float)(decimals) / 100); - return rc; -}