diff --git a/Source/sys-clk/common/include/sysclk/clock_manager.h b/Source/sys-clk/common/include/sysclk/clock_manager.h index 98c1d335..d428b548 100644 --- a/Source/sys-clk/common/include/sysclk/clock_manager.h +++ b/Source/sys-clk/common/include/sysclk/clock_manager.h @@ -36,3 +36,5 @@ typedef struct } SysClkTitleProfileList; #define SYSCLK_FREQ_LIST_MAX 32 +#define SYSCLK_GPU_BOOST_HZ 76800000 +#define SYSCLK_CPU_BOOST_HZ 1785000000 \ No newline at end of file diff --git a/Source/sys-clk/common/include/sysclk/config.h b/Source/sys-clk/common/include/sysclk/config.h index 81938642..051b871f 100644 --- a/Source/sys-clk/common/include/sysclk/config.h +++ b/Source/sys-clk/common/include/sysclk/config.h @@ -15,15 +15,23 @@ typedef enum { SysClkConfigValue_PollingIntervalMs = 0, - SysClkConfigValue_TempLogIntervalMs = 1, - SysClkConfigValue_FreqLogIntervalMs = 2, - SysClkConfigValue_PowerLogIntervalMs = 3, - SysClkConfigValue_CsvWriteIntervalMs = 4, - HocClkConfigValue_UncappedClocks = 5, - HocClkConfigValue_OverwriteBoostMode = 6, - HocClkConfigValue_MaxCpuClock = 7, - HocClkConfigValue_MaxGpuClock = 8, - SysClkConfigValue_EnumMax = 9, + SysClkConfigValue_TempLogIntervalMs, + SysClkConfigValue_FreqLogIntervalMs, + SysClkConfigValue_PowerLogIntervalMs, + SysClkConfigValue_CsvWriteIntervalMs, + HocClkConfigValue_UncappedClocks, + HocClkConfigValue_OverwriteBoostMode, + HocClkConfigValue_EristaMaxCpuClock, + HocClkConfigValue_EristaMaxGpuClock, + HocClkConfigValue_EristaMaxMemClock, + HocClkConfigValue_MarikoMaxCpuClock, + HocClkConfigValue_MarikoMaxGpuClock, + HocClkConfigValue_MarikoMaxMemClock, + HocClkConfigValue_ThermalThrottle, + HocClkConfigValue_ThermalThrottleThreshold, + HocClkConfigValue_HandheldGovernor, + HocClkConfigValue_DockedGovernor, + SysClkConfigValue_EnumMax, } SysClkConfigValue; typedef struct { @@ -48,10 +56,32 @@ static inline const char* sysclkFormatConfigValue(SysClkConfigValue val, bool pr return pretty ? "Uncapped Clocks" : "uncapped_clocks"; case HocClkConfigValue_OverwriteBoostMode: return pretty ? "Overwrite Boost Mode" : "ow_boost"; - case HocClkConfigValue_MaxCpuClock: - return pretty ? "Max CPU Clock" : "cpu_max"; - case HocClkConfigValue_MaxGpuClock: - return pretty ? "Max GPU Clock" : "gpu_max"; + + case HocClkConfigValue_EristaMaxCpuClock: + return pretty ? "Max CPU Clock" : "cpu_max_e"; + case HocClkConfigValue_EristaMaxGpuClock: + return pretty ? "Max GPU Clock" : "gpu_max_e"; + case HocClkConfigValue_EristaMaxMemClock: + return pretty ? "Max MEM Clock" : "mem_max_e"; + + case HocClkConfigValue_MarikoMaxCpuClock: + return pretty ? "Max CPU Clock" : "cpu_max_m"; + case HocClkConfigValue_MarikoMaxGpuClock: + return pretty ? "Max GPU Clock" : "gpu_max_m"; + case HocClkConfigValue_MarikoMaxMemClock: + return pretty ? "Max MEM Clock" : "mem_max_m"; + + case HocClkConfigValue_ThermalThrottle: + return pretty ? "Thermal Throttle" : "thermal_throttle"; + + case HocClkConfigValue_ThermalThrottleThreshold: + return pretty ? "Thermal Throttle Threshold" : "thermal_throttle_threshold"; + + case HocClkConfigValue_DockedGovernor: + return pretty ? "Docked Governor" : "governor_docked"; + case HocClkConfigValue_HandheldGovernor: + return pretty ? "Handheld Governor" : "governor_handheld"; + default: return pretty ? "Null" : "null"; } @@ -70,10 +100,26 @@ static inline uint64_t sysclkDefaultConfigValue(SysClkConfigValue val) case HocClkConfigValue_UncappedClocks: case HocClkConfigValue_OverwriteBoostMode: return 0ULL; - case HocClkConfigValue_MaxCpuClock: + case HocClkConfigValue_EristaMaxCpuClock: return 1785ULL; - case HocClkConfigValue_MaxGpuClock: + case HocClkConfigValue_EristaMaxGpuClock: return 921ULL; + case HocClkConfigValue_EristaMaxMemClock: + return 1600ULL; + + case HocClkConfigValue_MarikoMaxCpuClock: + return 1963ULL; + case HocClkConfigValue_MarikoMaxGpuClock: + return 1075ULL; + case HocClkConfigValue_MarikoMaxMemClock: + return 1862ULL; + + case HocClkConfigValue_ThermalThrottle: + case HocClkConfigValue_ThermalThrottleThreshold: + case HocClkConfigValue_DockedGovernor: + case HocClkConfigValue_HandheldGovernor: + case HocClkConfigValue_ThermalThrottleThreshold: + return 1ULL; default: return 0ULL; } @@ -83,6 +129,13 @@ static inline uint64_t sysclkValidConfigValue(SysClkConfigValue val, uint64_t in { switch(val) { + case HocClkConfigValue_EristaMaxCpuClock: + case HocClkConfigValue_EristaMaxGpuClock: + case HocClkConfigValue_EristaMaxMemClock: + case HocClkConfigValue_MarikoMaxCpuClock: + case HocClkConfigValue_MarikoMaxGpuClock: + case HocClkConfigValue_MarikoMaxMemClock: + case HocClkConfigValue_ThermalThrottleThreshold: case SysClkConfigValue_PollingIntervalMs: return input > 0; case SysClkConfigValue_TempLogIntervalMs: @@ -92,10 +145,10 @@ static inline uint64_t sysclkValidConfigValue(SysClkConfigValue val, uint64_t in return input >= 0; case HocClkConfigValue_UncappedClocks: case HocClkConfigValue_OverwriteBoostMode: + case HocClkConfigValue_ThermalThrottle: + case HocClkConfigValue_DockedGovernor: + case HocClkConfigValue_HandheldGovernor: return (input & 0x1) == input; - case HocClkConfigValue_MaxCpuClock: - case HocClkConfigValue_MaxGpuClock: - return input > 0; default: return false; } diff --git a/Source/sys-clk/overlay/src/ui/gui/freq_choice_gui.cpp b/Source/sys-clk/overlay/src/ui/gui/freq_choice_gui.cpp index b7d0850a..68be07ab 100644 --- a/Source/sys-clk/overlay/src/ui/gui/freq_choice_gui.cpp +++ b/Source/sys-clk/overlay/src/ui/gui/freq_choice_gui.cpp @@ -79,15 +79,28 @@ FreqChoiceGui::~FreqChoiceGui() hz = this->hzList[i]; uint32_t mhz = hz / 1000000; // Skip 204 MHz exactly - if(checkMax) { - if (this->configList->values[HocClkConfigValue_MaxCpuClock] < mhz && moduleName == "cpu") { + if(checkMax && IsMariko()) { + if (this->configList->values[HocClkConfigValue_MarikoMaxCpuClock] < mhz && moduleName == "cpu") { continue; } - if (this->configList->values[HocClkConfigValue_MaxGpuClock] < mhz&& moduleName == "gpu") { + if (this->configList->values[HocClkConfigValue_MarikoMaxGpuClock] < mhz && moduleName == "gpu") { + continue; + } + if (this->configList->values[HocClkConfigValue_MarikoMaxMemClock] < mhz && moduleName == "mem") { + continue; + } + } else if (checkMax && IsErista()) { + if (this->configList->values[HocClkConfigValue_EristaMaxCpuClock] < mhz && moduleName == "cpu") { continue; } + if (this->configList->values[HocClkConfigValue_EristaMaxGpuClock] < mhz && moduleName == "gpu") { + continue; + } + if (this->configList->values[HocClkConfigValue_EristaMaxMemClock] < mhz && moduleName == "mem") { + continue; + } } if (moduleName == "mem" && mhz <= 600) { diff --git a/Source/sys-clk/overlay/src/ui/gui/misc_gui.cpp b/Source/sys-clk/overlay/src/ui/gui/misc_gui.cpp index e93f11aa..7142e756 100644 --- a/Source/sys-clk/overlay/src/ui/gui/misc_gui.cpp +++ b/Source/sys-clk/overlay/src/ui/gui/misc_gui.cpp @@ -102,12 +102,28 @@ void MiscGui::updateConfigToggles() { void MiscGui::listUI() { - this->listElement->addItem(new tsl::elm::CategoryHeader("Config")); + this->listElement->addItem(new tsl::elm::CategoryHeader("Settings")); addConfigToggle(HocClkConfigValue_UncappedClocks, nullptr); addConfigToggle(HocClkConfigValue_OverwriteBoostMode, nullptr); - addConfigButton(HocClkConfigValue_MaxCpuClock, nullptr, SysClkModule_CPU); - addConfigButton(HocClkConfigValue_MaxGpuClock, nullptr, SysClkModule_GPU); + this->listElement->addItem(new tsl::elm::CategoryHeader("Experimental")); + addConfigToggle(HocClkConfigValue_ThermalThrottle, nullptr); + addConfigToggle(HocClkConfigValue_DockedGovernor, nullptr); + addConfigToggle(HocClkConfigValue_HandheldGovernor, nullptr); + + + this->listElement->addItem(new tsl::elm::CategoryHeader("Max Clocks")); + if(IsMariko()) { + addConfigButton(HocClkConfigValue_MarikoMaxCpuClock, nullptr, SysClkModule_CPU); + addConfigButton(HocClkConfigValue_MarikoMaxGpuClock, nullptr, SysClkModule_GPU); + addConfigButton(HocClkConfigValue_MarikoMaxMemClock, nullptr, SysClkModule_MEM); + } else { + addConfigButton(HocClkConfigValue_EristaMaxCpuClock, nullptr, SysClkModule_CPU); + addConfigButton(HocClkConfigValue_EristaMaxGpuClock, nullptr, SysClkModule_GPU); + addConfigButton(HocClkConfigValue_EristaMaxMemClock, nullptr, SysClkModule_MEM); + } +// this->listElement->addItem(new tsl::elm::CategoryHeader("Voltages")); + } void MiscGui::refresh() { diff --git a/Source/sys-clk/sysmodule/perms.json b/Source/sys-clk/sysmodule/perms.json index e96d4005..a57e28e4 100644 --- a/Source/sys-clk/sysmodule/perms.json +++ b/Source/sys-clk/sysmodule/perms.json @@ -4,7 +4,7 @@ "title_id_range_min": "0x00FF0000636C6BFF", "title_id_range_max": "0x00FF0000636C6BFF", "main_thread_stack_size": "0x00008000", - "main_thread_priority": 49, + "main_thread_priority": 63, "default_cpu_id": 3, "process_category": 0, "is_retail": true, @@ -25,8 +25,8 @@ "type": "kernel_flags", "value": { "highest_thread_priority": 63, - "lowest_thread_priority": 24, - "lowest_cpu_id": 3, + "lowest_thread_priority": 63, + "lowest_cpu_id": 0, "highest_cpu_id": 3 } }, diff --git a/Source/sys-clk/sysmodule/src/clock_manager.cpp b/Source/sys-clk/sysmodule/src/clock_manager.cpp index df481cf2..97fc30df 100644 --- a/Source/sys-clk/sysmodule/src/clock_manager.cpp +++ b/Source/sys-clk/sysmodule/src/clock_manager.cpp @@ -16,6 +16,8 @@ #include "errors.h" #include "ipc_service.h" +#define HOSPPC_HAS_BOOST (hosversionAtLeast(7,0,0)) + ClockManager *ClockManager::instance = NULL; ClockManager *ClockManager::GetInstance() @@ -207,11 +209,20 @@ void ClockManager::Tick() std::uint32_t targetHz = 0; std::uint32_t maxHz = 0; std::uint32_t nearestHz = 0; + std::uint32_t mode = 0; + Result rc = apmExtGetCurrentPerformanceConfiguration(&mode); + ASSERT_RESULT_OK(rc, "apmExtGetCurrentPerformanceConfiguration"); + for (unsigned int module = 0; module < SysClkModule_EnumMax; module++) { targetHz = this->context->overrideFreqs[module]; // if (!this->config->GetConfigValue(HocClkConfigValue_DockedGovernor) || !this->config->GetConfigValue(HocClkConfigValue_HandheldGovernor)) // { + if((apmExtIsBoostMode(mode) && !this->config->GetConfigValue(HocClkConfigValue_OverwriteBoostMode)) || ((tmp451TempSoc() / 1000) > (int)this->config->GetConfigValue(HocClkConfigValue_ThermalThrottleThreshold) && this->config->GetConfigValue(HocClkConfigValue_ThermalThrottle)) ) { // WHY?!?!??!?!? + Board::ResetToStockCpu(); + Board::ResetToStockGpu(); + return; + } if (!targetHz) { targetHz = this->config->GetAutoClockHz(this->context->applicationId, (SysClkModule)module, this->context->profile); @@ -221,9 +232,7 @@ void ClockManager::Tick() { maxHz = this->GetMaxAllowedHz((SysClkModule)module, this->context->profile); nearestHz = this->GetNearestHz((SysClkModule)module, targetHz, maxHz); - - if (nearestHz != this->context->freqs[module] && this->context->enabled/* && !apmExtIsBoostMode(this->context->perfConfId) && !this->config->GetConfigValue(HocClkConfigValue_OverwriteBoostMode)*/) - { + if (nearestHz != this->context->freqs[module] && this->context->enabled) { FileUtils::LogLine( "[mgr] %s clock set : %u.%u MHz (target = %u.%u MHz)", Board::GetModuleName((SysClkModule)module, true), @@ -232,12 +241,10 @@ void ClockManager::Tick() Board::SetHz((SysClkModule)module, nearestHz); this->context->freqs[module] = nearestHz; - } - // else - // { - // Board::ResetToStockCpu(); - // Board::ResetToStockGpu(); - // } + } else { + Board::ResetToStockCpu(); + Board::ResetToStockGpu(); + } // } // } else { // #define GOVERNOR_LOAD_THRESHOLD 80 diff --git a/Source/sys-clk/sysmodule/src/config.cpp b/Source/sys-clk/sysmodule/src/config.cpp index 74b80d2f..52d656c0 100644 --- a/Source/sys-clk/sysmodule/src/config.cpp +++ b/Source/sys-clk/sysmodule/src/config.cpp @@ -180,24 +180,17 @@ bool Config::SetProfiles(std::uint64_t tid, SysClkTitleProfileList* profiles, bo std::scoped_lock lock{this->configMutex}; uint8_t numProfiles = 0; - // String pointer array passed to ini - char* iniKeys[SysClkProfile_EnumMax * SysClkModule_EnumMax + 1]; - char* iniValues[SysClkProfile_EnumMax * SysClkModule_EnumMax + 1]; - - // Char arrays to build strings - char keysStr[SysClkProfile_EnumMax * SysClkModule_EnumMax * 0x40]; - char valuesStr[SysClkProfile_EnumMax * SysClkModule_EnumMax * 0x10]; char section[17] = {0}; - - // Iteration pointers - char** ik = &iniKeys[0]; - char** iv = &iniValues[0]; - char* sk = &keysStr[0]; - char* sv = &valuesStr[0]; - std::uint32_t* mhz = &profiles->mhz[0]; - snprintf(section, sizeof(section), "%016lX", tid); + // Use dynamic allocation + std::vector keys; + std::vector values; + keys.reserve(SysClkProfile_EnumMax * SysClkModule_EnumMax); + values.reserve(SysClkProfile_EnumMax * SysClkModule_EnumMax); + + std::uint32_t* mhz = &profiles->mhz[0]; + for(unsigned int profile = 0; profile < SysClkProfile_EnumMax; profile++) { for(unsigned int module = 0; module < SysClkModule_EnumMax; module++) @@ -206,34 +199,38 @@ bool Config::SetProfiles(std::uint64_t tid, SysClkTitleProfileList* profiles, bo { numProfiles++; - // Put key and value as string - snprintf(sk, 0x40, "%s_%s", Board::GetProfileName((SysClkProfile)profile, false), Board::GetModuleName((SysClkModule)module, false)); - snprintf(sv, 0x10, "%d", *mhz); + // Build key and value strings + std::string key = std::string(Board::GetProfileName((SysClkProfile)profile, false)) + + "_" + + Board::GetModuleName((SysClkModule)module, false); + std::string value = std::to_string(*mhz); - // Add them to the ini key/value str arrays - *ik = sk; - *iv = sv; - ik++; - iv++; - - // We used those chars, get to the next ones - sk += 0x40; - sv += 0x10; + keys.push_back(key); + values.push_back(value); } - mhz++; } } - *ik = NULL; - *iv = NULL; + // Build pointer arrays + std::vector keyPointers; + std::vector valuePointers; + keyPointers.reserve(keys.size() + 1); + valuePointers.reserve(values.size() + 1); - if(!ini_putsection(section, (const char**)iniKeys, (const char**)iniValues, this->path.c_str())) + for(size_t i = 0; i < keys.size(); i++) { + keyPointers.push_back(keys[i].c_str()); + valuePointers.push_back(values[i].c_str()); + } + keyPointers.push_back(NULL); + valuePointers.push_back(NULL); + + if(!ini_putsection(section, keyPointers.data(), valuePointers.data(), this->path.c_str())) { return false; } - // Only actually apply changes in memory after a succesful save + // Only actually apply changes in memory after a successful save if(immediate) { mhz = &profiles->mhz[0]; @@ -414,46 +411,43 @@ bool Config::SetConfigValues(SysClkConfigValueList* configValues, bool immediate { std::scoped_lock lock{this->configMutex}; - // String pointer array passed to ini - const char* iniKeys[SysClkConfigValue_EnumMax + 1]; - char* iniValues[SysClkConfigValue_EnumMax + 1]; - - // char arrays to build strings - char valuesStr[SysClkConfigValue_EnumMax * 0x80]; - - // Iteration pointers - char* sv = &valuesStr[0]; - const char** ik = &iniKeys[0]; - char** iv = &iniValues[0]; + // Use dynamic allocation instead of fixed stack buffers + std::vector iniKeys; + std::vector iniValues; + + iniKeys.reserve(SysClkConfigValue_EnumMax + 1); + iniValues.reserve(SysClkConfigValue_EnumMax); for(unsigned int kval = 0; kval < SysClkConfigValue_EnumMax; kval++) { - if(!sysclkValidConfigValue((SysClkConfigValue)kval, configValues->values[kval]) || configValues->values[kval] == sysclkDefaultConfigValue((SysClkConfigValue)kval)) + if(!sysclkValidConfigValue((SysClkConfigValue)kval, configValues->values[kval]) || + configValues->values[kval] == sysclkDefaultConfigValue((SysClkConfigValue)kval)) { continue; } - // Put key and value as string - // And add them to the ini key/value str arrays - snprintf(sv, 0x20, "%ld", configValues->values[kval]); - *ik = sysclkFormatConfigValue((SysClkConfigValue)kval, false); - *iv = sv; - - // We used those chars, get to the next ones - sv += 0x20; - ik++; - iv++; + // Store as string in vector (automatically managed memory) + iniValues.push_back(std::to_string(configValues->values[kval])); + iniKeys.push_back(sysclkFormatConfigValue((SysClkConfigValue)kval, false)); } - *ik = NULL; - *iv = NULL; + // Null terminate + iniKeys.push_back(NULL); - if(!ini_putsection(CONFIG_VAL_SECTION, (const char**)iniKeys, (const char**)iniValues, this->path.c_str())) + // Build pointer array for ini function + std::vector valuePointers; + valuePointers.reserve(iniValues.size() + 1); + for(const auto& val : iniValues) { + valuePointers.push_back(val.c_str()); + } + valuePointers.push_back(NULL); + + if(!ini_putsection(CONFIG_VAL_SECTION, iniKeys.data(), valuePointers.data(), this->path.c_str())) { return false; } - // Only actually apply changes in memory after a succesful save + // Only actually apply changes in memory after a successful save if(immediate) { for(unsigned int kval = 0; kval < SysClkConfigValue_EnumMax; kval++) @@ -470,4 +464,4 @@ bool Config::SetConfigValues(SysClkConfigValueList* configValues, bool immediate } return true; -} +} \ No newline at end of file diff --git a/Source/sys-clk/sysmodule/src/fancontrol.c b/Source/sys-clk/sysmodule/src/fancontrol.c index 145a490e..ac253e90 100644 --- a/Source/sys-clk/sysmodule/src/fancontrol.c +++ b/Source/sys-clk/sysmodule/src/fancontrol.c @@ -4,15 +4,15 @@ //Fan curve table const TemperaturePoint defaultTable[] = { - { .temperature_c = 25.0, .fanLevel_f = 0.10 }, - { .temperature_c = 30.0, .fanLevel_f = 0.20 }, - { .temperature_c = 35.0, .fanLevel_f = 0.30 }, - { .temperature_c = 40.0, .fanLevel_f = 0.40 }, - { .temperature_c = 45.0, .fanLevel_f = 0.50 }, - { .temperature_c = 50.0, .fanLevel_f = 0.60 }, - { .temperature_c = 55.0, .fanLevel_f = 0.70 }, - { .temperature_c = 60.0, .fanLevel_f = 0.80 }, - { .temperature_c = 65.0, .fanLevel_f = 0.90 }, + { .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 } }; @@ -136,7 +136,7 @@ void FanControllerThreadFunction(void*) float fanLevelSet_f = 0; float temperatureC_f = 0; u64 awakeSleepTime = 250000000ULL; // 0.25 second when awake (250ms - responsive) - u64 sleepSleepTime = 5000000000ULL; // 5 seconds when in sleep + u64 sleepSleepTime = 10000000000ULL; // 10 seconds when in sleep int sleepCheckCounter = 0; Result rs = fanOpenController(&fc, 0x3D000001); @@ -148,9 +148,9 @@ void FanControllerThreadFunction(void*) while(!fanControllerThreadExit) { - // Check if system is awake every 20 iterations (~5 seconds) to reduce overhead + // Check if system is awake every 40 iterations (~10 seconds) to reduce overhead sleepCheckCounter++; - if(sleepCheckCounter >= 20) + if(sleepCheckCounter >= 40) { bool isAwake = IsSystemAwake(); sleepCheckCounter = 0; diff --git a/Source/sys-clk/sysmodule/src/ipc_service.cpp b/Source/sys-clk/sysmodule/src/ipc_service.cpp index 47bbdd8b..44d02b5a 100644 --- a/Source/sys-clk/sysmodule/src/ipc_service.cpp +++ b/Source/sys-clk/sysmodule/src/ipc_service.cpp @@ -145,7 +145,7 @@ Result IpcService::ServiceHandlerFunc(void* arg, const IpcServerRequest* r, u8* break; case SysClkIpcCmd_GetConfigValues: - *out_dataSize = sizeof(SysClkTitleProfileList); + *out_dataSize = sizeof(SysClkConfigValueList); // bug in stock sys-clk. really stupid bug :skull: return ipcSrv->GetConfigValues((SysClkConfigValueList*)out_data); case SysClkIpcCmd_SetConfigValues: