From b335412bc443d637bba771e88d52a51999fb7176 Mon Sep 17 00:00:00 2001 From: souldbminersmwc Date: Wed, 24 Dec 2025 17:27:41 -0500 Subject: [PATCH] sysclk: finish display refresh rate change support --- Source/sys-clk/common/include/sysclk/board.h | 9 +- Source/sys-clk/overlay/src/ui/format.h | 3 +- .../overlay/src/ui/gui/app_profile_gui.cpp | 152 ++++++++- .../overlay/src/ui/gui/app_profile_gui.h | 24 ++ .../overlay/src/ui/gui/base_menu_gui.cpp | 8 +- .../src/ui/gui/global_override_gui.cpp | 297 +++++++++++++----- .../overlay/src/ui/gui/global_override_gui.h | 27 +- Source/sys-clk/sysmodule/src/board.cpp | 26 +- Source/sys-clk/sysmodule/src/board.h | 1 + .../sys-clk/sysmodule/src/clock_manager.cpp | 26 +- Source/sys-clk/sysmodule/src/config.cpp | 14 +- Source/sys-clk/sysmodule/src/config.h | 4 +- 12 files changed, 490 insertions(+), 101 deletions(-) diff --git a/Source/sys-clk/common/include/sysclk/board.h b/Source/sys-clk/common/include/sysclk/board.h index 93813928..02503c1f 100644 --- a/Source/sys-clk/common/include/sysclk/board.h +++ b/Source/sys-clk/common/include/sysclk/board.h @@ -77,7 +77,7 @@ typedef enum SysClkModule_GPU, SysClkModule_MEM, HorizonOCModule_Governor, - HorizonOCModule_LCD, + HorizonOCModule_Display, SysClkModule_EnumMax, } SysClkModule; @@ -131,6 +131,8 @@ static inline const char* sysclkFormatModule(SysClkModule module, bool pretty) return pretty ? "GPU" : "gpu"; case SysClkModule_MEM: return pretty ? "Memory" : "mem"; + case HorizonOCModule_Display: + return pretty ? "Display" : "display"; case HorizonOCModule_Governor: return pretty ? "Governor" : "gov"; default: @@ -148,6 +150,11 @@ static inline const char* sysclkFormatThermalSensor(SysClkThermalSensor thermSen return pretty ? "PCB" : "pcb"; case SysClkThermalSensor_Skin: return pretty ? "Skin" : "skin"; + case HorizonOCThermalSensor_Battery: + return pretty ? "BAT" : "battery"; + case HorizonOCThermalSensor_PMIC: + return pretty ? "PMIC" : "pmic"; + default: return NULL; } diff --git a/Source/sys-clk/overlay/src/ui/format.h b/Source/sys-clk/overlay/src/ui/format.h index e09cd431..880a3dfb 100644 --- a/Source/sys-clk/overlay/src/ui/format.h +++ b/Source/sys-clk/overlay/src/ui/format.h @@ -28,7 +28,8 @@ #pragma once #include - +#include +#include #define FREQ_DEFAULT_TEXT "Default" static inline std::string formatListFreqMHz(std::uint32_t mhz) diff --git a/Source/sys-clk/overlay/src/ui/gui/app_profile_gui.cpp b/Source/sys-clk/overlay/src/ui/gui/app_profile_gui.cpp index 834a8659..7cab72bf 100644 --- a/Source/sys-clk/overlay/src/ui/gui/app_profile_gui.cpp +++ b/Source/sys-clk/overlay/src/ui/gui/app_profile_gui.cpp @@ -67,6 +67,32 @@ void AppProfileGui::openFreqChoiceGui(tsl::elm::ListItem* listItem, SysClkProfil ); } +void AppProfileGui::openValueChoiceGui( + tsl::elm::ListItem* listItem, + std::uint32_t currentValue, + const ValueRange& range, + const std::string& categoryName, + ValueChoiceListener listener, + const ValueThresholds& thresholds, + bool enableThresholds, + const std::map& labels, + const std::vector& namedValues, + bool showDefaultValue +) +{ + tsl::changeTo( + currentValue, + range, + categoryName, + listener, + thresholds, + enableThresholds, + labels, + namedValues, + showDefaultValue + ); +} + void AppProfileGui::addModuleListItem(SysClkProfile profile, SysClkModule module) { tsl::elm::ListItem* listItem = new tsl::elm::ListItem(sysclkFormatModule(module, true)); @@ -83,7 +109,6 @@ void AppProfileGui::addModuleListItem(SysClkProfile profile, SysClkModule module this->profileList->mhzMap[profile][module] = 0; listItem->setValue(formatListFreqMHz(0)); - // Save the updated profile Result rc = sysclkIpcSetProfiles(this->applicationId, this->profileList); if(R_FAILED(rc)) { @@ -117,12 +142,137 @@ void AppProfileGui::addModuleListItemToggle(SysClkProfile profile, SysClkModule this->listElement->addItem(toggle); } +void AppProfileGui::addModuleListItemValue( + SysClkProfile profile, + SysClkModule module, + const std::string& categoryName, + std::uint32_t min, + std::uint32_t max, + std::uint32_t step, + const std::string& suffix, + std::uint32_t divisor, + int decimalPlaces +) +{ + 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->setClickListener( + [this, + listItem, + profile, + module, + categoryName, + min, + max, + step, + suffix, + divisor, + decimalPlaces](u64 keys) + { + if ((keys & HidNpadButton_A) == HidNpadButton_A) + { + std::uint32_t currentValue = + this->profileList->mhzMap[profile][module] * divisor; + + ValueRange range( + min, + max, + step, + suffix, + divisor, + decimalPlaces + ); + + this->openValueChoiceGui( + listItem, + currentValue, + range, + categoryName, + + [this, listItem, profile, module, divisor, suffix, decimalPlaces](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); + } + + Result rc = + sysclkIpcSetProfiles(this->applicationId, + this->profileList); + + if (R_FAILED(rc)) + { + FatalGui::openWithResultCode( + "sysclkIpcSetProfiles", rc); + return false; + } + return true; + }, + + ValueThresholds(), + false + ); + + 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); +} + void AppProfileGui::addProfileUI(SysClkProfile profile) { this->listElement->addItem(new tsl::elm::CategoryHeader(sysclkFormatProfile(profile, true) + std::string(" ") + ult::DIVIDER_SYMBOL + "  Reset")); this->addModuleListItem(profile, SysClkModule_CPU); this->addModuleListItem(profile, SysClkModule_GPU); this->addModuleListItem(profile, SysClkModule_MEM); + this->addModuleListItemValue(profile, HorizonOCModule_Display, "Display", 40, 60, 5, " Hz", 1, 0); this->addModuleListItemToggle(profile, HorizonOCModule_Governor); } diff --git a/Source/sys-clk/overlay/src/ui/gui/app_profile_gui.h b/Source/sys-clk/overlay/src/ui/gui/app_profile_gui.h index 4ed0e94d..51fb8ddc 100644 --- a/Source/sys-clk/overlay/src/ui/gui/app_profile_gui.h +++ b/Source/sys-clk/overlay/src/ui/gui/app_profile_gui.h @@ -30,6 +30,7 @@ #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 @@ -41,6 +42,29 @@ class AppProfileGui : public BaseMenuGui void openFreqChoiceGui(tsl::elm::ListItem* listItem, SysClkProfile profile, SysClkModule module); void addModuleListItem(SysClkProfile profile, SysClkModule module); void addModuleListItemToggle(SysClkProfile profile, SysClkModule module); + void openValueChoiceGui( + tsl::elm::ListItem* listItem, + std::uint32_t currentValue, + const ValueRange& range, + const std::string& categoryName, + ValueChoiceListener listener, + const ValueThresholds& thresholds = ValueThresholds(), + bool enableThresholds = false, + const std::map& labels = {}, + const std::vector& namedValues = {}, + bool showDefaultValue = true + ); + void addModuleListItemValue( + SysClkProfile profile, + SysClkModule module, + const std::string& categoryName, + std::uint32_t min, + std::uint32_t max, + std::uint32_t step, + const std::string& suffix, + std::uint32_t divisor, + int decimalPlaces + ); void addProfileUI(SysClkProfile profile); public: diff --git a/Source/sys-clk/overlay/src/ui/gui/base_menu_gui.cpp b/Source/sys-clk/overlay/src/ui/gui/base_menu_gui.cpp index 7255af7d..8a84f742 100644 --- a/Source/sys-clk/overlay/src/ui/gui/base_menu_gui.cpp +++ b/Source/sys-clk/overlay/src/ui/gui/base_menu_gui.cpp @@ -56,7 +56,7 @@ void BaseMenuGui::preDraw(tsl::gfx::Renderer* renderer) { // All constants pre-calculated and cached static constexpr const char* const labels[] = { - "App ID", "Profile", "CPU", "GPU", "MEM", "SoC", "Board", "Skin", "Now", "Avg", "BAT", "PMIC", "FAN" + "App ID", "Profile", "CPU", "GPU", "MEM", "SoC", "Board", "Skin", "Now", "Avg", "BAT", "PMIC", "FAN", "DISP" }; static constexpr u32 dataPositions[6] = {63-3+3, 200-1, 344-1-3, 200-1, 342-1, 321-1}; @@ -163,6 +163,10 @@ void BaseMenuGui::preDraw(tsl::gfx::Renderer* renderer) { renderer->drawString(displayStrings[24], false, dataPositions[1], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // fan speed + renderer->drawString(labels[13], false, positions[7], y, SMALL_TEXT_SIZE, tsl::sectionTextColor); // fan label + + renderer->drawString(displayStrings[25], false, dataPositions[2], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // fan speed + } // Optimized refresh - now does all the string formatting once per second @@ -268,6 +272,8 @@ void BaseMenuGui::refresh() sprintf(displayStrings[24], "%u%%", context->PartLoad[HocClkPartLoad_FAN]); + sprintf(displayStrings[25], "%u Hz", context->realFreqs[HorizonOCModule_Display]); + } tsl::elm::Element* BaseMenuGui::baseUI() diff --git a/Source/sys-clk/overlay/src/ui/gui/global_override_gui.cpp b/Source/sys-clk/overlay/src/ui/gui/global_override_gui.cpp index 82cd93ea..5f06e357 100644 --- a/Source/sys-clk/overlay/src/ui/gui/global_override_gui.cpp +++ b/Source/sys-clk/overlay/src/ui/gui/global_override_gui.cpp @@ -1,39 +1,11 @@ -/* - * Copyright (c) Souldbminer and Horizon OC Contributors - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * 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 . - * - */ - -/* -------------------------------------------------------------------------- - * "THE BEER-WARE LICENSE" (Revision 42): - * , , - * wrote this file. As long as you retain this notice you can do whatever you - * want with this stuff. If you meet any of us some day, and you think this - * stuff is worth it, you can buy us a beer in return. - The sys-clk authors - * -------------------------------------------------------------------------- - */ - - -#include "global_override_gui.h" - -#include "fatal_gui.h" #include "../format.h" +#include "fatal_gui.h" +#include "global_override_gui.h" +#include "value_choice_gui.h" GlobalOverrideGui::GlobalOverrideGui() { - for(std::uint16_t m = 0; m < SysClkModule_EnumMax; m++) - { + for (std::uint16_t m = 0; m < SysClkModule_EnumMax; m++) { this->listItems[m] = nullptr; this->listHz[m] = 0; } @@ -43,16 +15,17 @@ void GlobalOverrideGui::openFreqChoiceGui(SysClkModule module) { std::uint32_t hzList[SYSCLK_FREQ_LIST_MAX]; std::uint32_t hzCount; - Result rc = sysclkIpcGetFreqList(module, &hzList[0], SYSCLK_FREQ_LIST_MAX, &hzCount); - if(R_FAILED(rc)) - { + Result rc = + sysclkIpcGetFreqList(module, &hzList[0], SYSCLK_FREQ_LIST_MAX, &hzCount); + if (R_FAILED(rc)) { FatalGui::openWithResultCode("sysclkIpcGetFreqList", rc); return; } - tsl::changeTo(this->context->overrideFreqs[module], hzList, hzCount, module, [this, module](std::uint32_t hz) { + tsl::changeTo( + this->context->overrideFreqs[module], hzList, hzCount, module, + [this, module](std::uint32_t hz) { Result rc = sysclkIpcSetOverride(module, hz); - if(R_FAILED(rc)) - { + if (R_FAILED(rc)) { FatalGui::openWithResultCode("sysclkIpcSetOverride", rc); return false; } @@ -61,78 +34,228 @@ void GlobalOverrideGui::openFreqChoiceGui(SysClkModule module) this->context->overrideFreqs[module] = hz; return true; - }, true); + }, + true); +} + +void GlobalOverrideGui::openValueChoiceGui( + tsl::elm::ListItem* listItem, + std::uint32_t currentValue, + const ValueRange& range, + const std::string& categoryName, + ValueChoiceListener listener, + const ValueThresholds& thresholds, + bool enableThresholds, + const std::map& labels, + const std::vector& namedValues, + bool showDefaultValue +) +{ + tsl::changeTo( + currentValue, + range, + categoryName, + listener, + thresholds, + enableThresholds, + labels, + namedValues, + showDefaultValue + ); +} + +void GlobalOverrideGui::addModuleListItemValue( + SysClkModule module, + const std::string& categoryName, + std::uint32_t min, + std::uint32_t max, + std::uint32_t step, + const std::string& suffix, + std::uint32_t divisor, + int decimalPlaces +) +{ + + this->customFormatModules[module] = std::make_tuple(suffix, divisor, decimalPlaces); + + tsl::elm::ListItem* listItem = + new tsl::elm::ListItem(sysclkFormatModule(module, true)); + + listItem->setValue(FREQ_DEFAULT_TEXT); + + listItem->setClickListener( + [this, + listItem, + module, + categoryName, + min, + max, + step, + suffix, + divisor, + decimalPlaces](u64 keys) + { + if ((keys & HidNpadButton_A) == HidNpadButton_A) + { + if (!this->context) { + return false; + } + + std::uint32_t currentValue = + this->context->overrideFreqs[module] * divisor; + + ValueRange range( + min, + max, + step, + suffix, + divisor, + decimalPlaces + ); + + this->openValueChoiceGui( + listItem, + currentValue, + range, + categoryName, + + [this, listItem, module, divisor, suffix, decimalPlaces](std::uint32_t value) -> bool + { + if (!this->context) { + return false; + } + + this->context->overrideFreqs[module] = value / divisor; + this->listHz[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); + } + + Result rc = + sysclkIpcSetOverride(module, this->context->overrideFreqs[module]); + + if (R_FAILED(rc)) + { + FatalGui::openWithResultCode( + "sysclkIpcSetOverride", rc); + return false; + } + + this->lastContextUpdate = armGetSystemTick(); + return true; + }, + + ValueThresholds(), + false, + std::map(), + std::vector(), + true + ); + + return true; + } + else if ((keys & HidNpadButton_Y) == HidNpadButton_Y) + { + if (!this->context) { + return false; + } + + this->context->overrideFreqs[module] = 0; + this->listHz[module] = 0; + listItem->setValue(FREQ_DEFAULT_TEXT); + + Result rc = sysclkIpcSetOverride(module, 0); + + if (R_FAILED(rc)) + { + FatalGui::openWithResultCode("sysclkIpcSetOverride", rc); + return false; + } + + this->lastContextUpdate = armGetSystemTick(); + return true; + } + + return false; + }); + + this->listElement->addItem(listItem); + this->listItems[module] = listItem; } void GlobalOverrideGui::addModuleListItem(SysClkModule module) { - tsl::elm::ListItem* listItem = new tsl::elm::ListItem(sysclkFormatModule(module, true)); + tsl::elm::ListItem *listItem = + new tsl::elm::ListItem(sysclkFormatModule(module, true)); listItem->setValue(formatListFreqMHz(0)); listItem->setClickListener([this, module](u64 keys) { - if((keys & HidNpadButton_A) == HidNpadButton_A) - { + if ((keys & HidNpadButton_A) == HidNpadButton_A) { this->openFreqChoiceGui(module); return true; - } - else if((keys & HidNpadButton_Y) == HidNpadButton_Y) - { - // Reset override to "Default" (0 Hz) + } else if ((keys & HidNpadButton_Y) == HidNpadButton_Y) { Result rc = sysclkIpcSetOverride(module, 0); - if(R_FAILED(rc)) - { + if (R_FAILED(rc)) { FatalGui::openWithResultCode("sysclkIpcSetOverride", rc); return false; } - - // Update context and tracking variables + this->lastContextUpdate = armGetSystemTick(); this->context->overrideFreqs[module] = 0; this->listHz[module] = 0; - - // Update display + this->listItems[module]->setValue(formatListFreqHz(0)); - + return true; } return false; }); - this->listElement->addItem(listItem); this->listItems[module] = listItem; } void GlobalOverrideGui::addModuleToggleItem(SysClkModule module) { - const char* moduleName = sysclkFormatModule(module, true); + const char *moduleName = sysclkFormatModule(module, true); bool isOn = this->listHz[module]; - - // Create a ToggleListItem - tsl::elm::ToggleListItem* toggle = new tsl::elm::ToggleListItem(moduleName, isOn); - - toggle->setStateChangedListener([this, module, toggle](bool state) { + tsl::elm::ToggleListItem *toggle = + new tsl::elm::ToggleListItem(moduleName, isOn); + + toggle->setStateChangedListener([this, module, toggle](bool state) { Result rc = sysclkIpcSetOverride(module, state ? 1 : 0); - if(R_FAILED(rc)) - { + if (R_FAILED(rc)) { FatalGui::openWithResultCode("sysclkIpcSetProfiles", rc); } this->lastContextUpdate = armGetSystemTick(); this->context->overrideFreqs[module] = 0; this->listHz[module] = 0; - }); - // Add to list and track this->listElement->addItem(toggle); this->listItems[module] = toggle; } + void GlobalOverrideGui::listUI() { - this->listElement->addItem(new tsl::elm::CategoryHeader("Temporary Overrides " + ult::DIVIDER_SYMBOL + "  Reset")); + this->listElement->addItem(new tsl::elm::CategoryHeader( + "Temporary Overrides " + ult::DIVIDER_SYMBOL + " Reset")); this->addModuleListItem(SysClkModule_CPU); this->addModuleListItem(SysClkModule_GPU); this->addModuleListItem(SysClkModule_MEM); + this->addModuleListItemValue(HorizonOCModule_Display, "Display", 40, 60, 5, " Hz", 1, 0); this->addModuleToggleItem(HorizonOCModule_Governor); } @@ -143,18 +266,16 @@ void GlobalOverrideGui::refresh() if (!this->context) return; - for (std::uint16_t m = 0; m < SysClkModule_EnumMax; m++) - { - if (m == HorizonOCModule_Governor) - { - auto* toggle = static_cast(this->listItems[m]); + for (std::uint16_t m = 0; m < SysClkModule_EnumMax; m++) { + if (m == HorizonOCModule_Governor) { + auto *toggle = + static_cast(this->listItems[m]); if (!toggle) continue; bool newState = this->context->overrideFreqs[m] != 0; - if (toggle->getState() != newState) - { + if (toggle->getState() != newState) { toggle->setState(newState); } @@ -162,11 +283,33 @@ void GlobalOverrideGui::refresh() } if (this->listItems[m] != nullptr && - this->listHz[m] != this->context->overrideFreqs[m]) - { - this->listItems[m]->setValue( - formatListFreqHz(this->context->overrideFreqs[m]) - ); + this->listHz[m] != this->context->overrideFreqs[m]) { + + auto it = this->customFormatModules.find((SysClkModule)m); + if (it != this->customFormatModules.end()) { + std::string suffix = std::get<0>(it->second); + std::uint32_t divisor = std::get<1>(it->second); + int decimalPlaces = std::get<2>(it->second); + + if (this->context->overrideFreqs[m] == 0) { + this->listItems[m]->setValue(FREQ_DEFAULT_TEXT); + } else { + char buf[32]; + if (decimalPlaces > 0) { + double displayValue = (double)this->context->overrideFreqs[m] / divisor; + snprintf(buf, sizeof(buf), "%.*f%s", + decimalPlaces, displayValue, suffix.c_str()); + } else { + snprintf(buf, sizeof(buf), "%u%s", + this->context->overrideFreqs[m] / divisor, suffix.c_str()); + } + this->listItems[m]->setValue(buf); + } + } else { + this->listItems[m]->setValue( + formatListFreqHz(this->context->overrideFreqs[m])); + } + this->listHz[m] = this->context->overrideFreqs[m]; } } diff --git a/Source/sys-clk/overlay/src/ui/gui/global_override_gui.h b/Source/sys-clk/overlay/src/ui/gui/global_override_gui.h index bcfa3dfe..c0cc9395 100644 --- a/Source/sys-clk/overlay/src/ui/gui/global_override_gui.h +++ b/Source/sys-clk/overlay/src/ui/gui/global_override_gui.h @@ -30,19 +30,44 @@ #include "../../ipc.h" #include "base_menu_gui.h" #include "freq_choice_gui.h" - +#include +#include "value_choice_gui.h" class GlobalOverrideGui : public BaseMenuGui { protected: + std::map> customFormatModules; tsl::elm::ListItem* listItems[SysClkModule_EnumMax]; std::uint32_t listHz[SysClkModule_EnumMax]; bool isGovernorEnabled; void openFreqChoiceGui(SysClkModule module); void addModuleListItem(SysClkModule module); void addModuleToggleItem(SysClkModule module); + void openValueChoiceGui( + tsl::elm::ListItem* listItem, + std::uint32_t currentValue, + const ValueRange& range, + const std::string& categoryName, + ValueChoiceListener listener, + const ValueThresholds& thresholds, + bool enableThresholds, + const std::map& labels, + const std::vector& namedValues, + bool showDefaultValue + ); + void addModuleListItemValue( + SysClkModule module, + const std::string& categoryName, + std::uint32_t min, + std::uint32_t max, + std::uint32_t step, + const std::string& suffix, + std::uint32_t divisor, + int decimalPlaces + ); public: GlobalOverrideGui(); ~GlobalOverrideGui() {} void listUI() override; void refresh() override; + void setModuleCustomFormat(SysClkModule module, const std::string& suffix, std::uint32_t divisor, int decimalPlaces); }; diff --git a/Source/sys-clk/sysmodule/src/board.cpp b/Source/sys-clk/sysmodule/src/board.cpp index 72bb6b6a..aac038cc 100644 --- a/Source/sys-clk/sysmodule/src/board.cpp +++ b/Source/sys-clk/sysmodule/src/board.cpp @@ -229,15 +229,14 @@ void Board::Initialize() } u64 clkVirtAddr, dsiVirtAddr, outsize; - Result rc = svcQueryMemoryMapping(&clkVirtAddr, &outsize, 0x60006000, 0x1000); + rc = svcQueryMemoryMapping(&clkVirtAddr, &outsize, 0x60006000, 0x1000); ASSERT_RESULT_OK(rc, "svcQueryMemoryMapping (clk)"); - Result rc = svcQueryMemoryMapping(&dsiVirtAddr, &outsize, 0x54300000, 0x40000); + rc = svcQueryMemoryMapping(&dsiVirtAddr, &outsize, 0x54300000, 0x40000); ASSERT_RESULT_OK(rc, "svcQueryMemoryMapping (dsi)"); DisplayRefreshConfig cfg = {.clkVirtAddr = clkVirtAddr, .dsiVirtAddr = dsiVirtAddr}; DisplayRefresh_Initialize(&cfg); - FetchHardwareInfos(); } @@ -308,6 +307,11 @@ void Board::SetHz(SysClkModule module, std::uint32_t hz) { Result rc = 0; + if(module == HorizonOCModule_Display) { + DisplayRefresh_SetRate(hz); + return; + } + if(HOSSVC_HAS_CLKRST) { ClkrstSession session = {0}; @@ -332,6 +336,11 @@ std::uint32_t Board::GetHz(SysClkModule module) Result rc = 0; std::uint32_t hz = 0; + if(module == HorizonOCModule_Display) { + DisplayRefresh_GetRate(&hz, false); + return hz; + } + if(HOSSVC_HAS_CLKRST) { ClkrstSession session = {0}; @@ -355,6 +364,7 @@ std::uint32_t Board::GetHz(SysClkModule module) std::uint32_t Board::GetRealHz(SysClkModule module) { + u32 hz = 0; switch(module) { case SysClkModule_CPU: @@ -363,6 +373,9 @@ std::uint32_t Board::GetRealHz(SysClkModule module) return t210ClkGpuFreq(); case SysClkModule_MEM: return t210ClkMemFreq(); + case HorizonOCModule_Display: + DisplayRefresh_GetRate(&hz, false); + return hz; default: ASSERT_ENUM_VALID(SysClkModule, module); } @@ -377,6 +390,8 @@ void Board::GetFreqList(SysClkModule module, std::uint32_t* outList, std::uint32 s32 tmpInMaxCount = maxCount; s32 tmpOutCount = 0; + + if(HOSSVC_HAS_CLKRST) { ClkrstSession session = {0}; @@ -552,6 +567,11 @@ void Board::ResetToStockGpu() ASSERT_RESULT_OK(rc, "apmExtSysRequestPerformanceMode"); } } + +void Board::ResetToStockDisplay() { + DisplayRefresh_SetRate(60); +} + std::uint32_t Board::GetTemperatureMilli(SysClkThermalSensor sensor) { std::int32_t millis = 0; diff --git a/Source/sys-clk/sysmodule/src/board.h b/Source/sys-clk/sysmodule/src/board.h index f12c59a1..d2b0d460 100644 --- a/Source/sys-clk/sysmodule/src/board.h +++ b/Source/sys-clk/sysmodule/src/board.h @@ -43,6 +43,7 @@ class Board static void ResetToStockCpu(); static void ResetToStockMem(); static void ResetToStockGpu(); + static void ResetToStockDisplay(); static SysClkProfile GetProfile(); static void SetHz(SysClkModule module, std::uint32_t hz); diff --git a/Source/sys-clk/sysmodule/src/clock_manager.cpp b/Source/sys-clk/sysmodule/src/clock_manager.cpp index c9a03934..f18f7610 100644 --- a/Source/sys-clk/sysmodule/src/clock_manager.cpp +++ b/Source/sys-clk/sysmodule/src/clock_manager.cpp @@ -312,7 +312,8 @@ void ClockManager::GovernorThread(void* arg) targetHz = mgr->config->GetAutoClockHz( mgr->context->applicationId, SysClkModule_GPU, - mgr->context->profile + mgr->context->profile, + false ); if (!targetHz) @@ -320,7 +321,8 @@ void ClockManager::GovernorThread(void* arg) targetHz = mgr->config->GetAutoClockHz( GLOBAL_PROFILE_ID, SysClkModule_GPU, - mgr->context->profile + mgr->context->profile, + false ); } } @@ -410,15 +412,19 @@ void ClockManager::Tick() ResetToStockClocks(); return; } - + bool returnRaw = false; for (unsigned int module = 0; module < SysClkModule_EnumMax; module++) { + 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); + 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); + targetHz = this->config->GetAutoClockHz(GLOBAL_PROFILE_ID, (SysClkModule)module, this->context->profile, returnRaw); } if(module == HorizonOCModule_Governor) { @@ -427,14 +433,20 @@ void ClockManager::Tick() FileUtils::LogLine("[mgr] Governor state changed: %s", newGovernorState ? "enabled" : "disabled"); lastGovernorState = newGovernorState; - // Force a "context refresh" like on app/profile change hasChanged = true; this->context->enabled = this->GetConfig()->Enabled(); - Board::ResetToStock(); // optional: reset clocks before re-applying + Board::ResetToStock(); } isGovernorEnabled = newGovernorState; } + if(module == HorizonOCModule_Display) { + if(targetHz) + Board::SetHz(HorizonOCModule_Display, targetHz); + else + Board::ResetToStockDisplay(); + } + // Skip GPU if governor handles it if(module > SysClkModule_MEM) { continue; diff --git a/Source/sys-clk/sysmodule/src/config.cpp b/Source/sys-clk/sysmodule/src/config.cpp index 8b5b5e64..6422dec3 100644 --- a/Source/sys-clk/sysmodule/src/config.cpp +++ b/Source/sys-clk/sysmodule/src/config.cpp @@ -138,7 +138,7 @@ std::uint32_t Config::FindClockMHz(std::uint64_t tid, SysClkModule module, SysCl return 0; } -std::uint32_t Config::FindClockHzFromProfiles(std::uint64_t tid, SysClkModule module, std::initializer_list profiles) +std::uint32_t Config::FindClockHzFromProfiles(std::uint64_t tid, SysClkModule module, std::initializer_list profiles, u32 mhzMultiplier) { std::uint32_t mhz = 0; @@ -155,23 +155,23 @@ std::uint32_t Config::FindClockHzFromProfiles(std::uint64_t tid, SysClkModule mo } } - return std::max((std::uint32_t)0, mhz * 1000000); + return std::max((std::uint32_t)0, mhz * mhzMultiplier); } -std::uint32_t Config::GetAutoClockHz(std::uint64_t tid, SysClkModule module, SysClkProfile profile) +std::uint32_t Config::GetAutoClockHz(std::uint64_t tid, SysClkModule module, SysClkProfile profile, bool returnRaw) { std::scoped_lock lock{this->configMutex}; switch(profile) { case SysClkProfile_Handheld: - return FindClockHzFromProfiles(tid, module, {SysClkProfile_Handheld}); + return FindClockHzFromProfiles(tid, module, {SysClkProfile_Handheld}, returnRaw ? 1 : 1000000); case SysClkProfile_HandheldCharging: case SysClkProfile_HandheldChargingUSB: - return FindClockHzFromProfiles(tid, module, {SysClkProfile_HandheldChargingUSB, SysClkProfile_HandheldCharging, SysClkProfile_Handheld}); + return FindClockHzFromProfiles(tid, module, {SysClkProfile_HandheldChargingUSB, SysClkProfile_HandheldCharging, SysClkProfile_Handheld}, returnRaw ? 1 : 1000000); case SysClkProfile_HandheldChargingOfficial: - return FindClockHzFromProfiles(tid, module, {SysClkProfile_HandheldChargingOfficial, SysClkProfile_HandheldCharging, SysClkProfile_Handheld}); + return FindClockHzFromProfiles(tid, module, {SysClkProfile_HandheldChargingOfficial, SysClkProfile_HandheldCharging, SysClkProfile_Handheld}, returnRaw ? 1 : 1000000); case SysClkProfile_Docked: - return FindClockHzFromProfiles(tid, module, {SysClkProfile_Docked}); + return FindClockHzFromProfiles(tid, module, {SysClkProfile_Docked}, returnRaw ? 1 : 1000000); default: ERROR_THROW("Unhandled SysClkProfile: %u", profile); } diff --git a/Source/sys-clk/sysmodule/src/config.h b/Source/sys-clk/sysmodule/src/config.h index b1dc4746..49dfa0b8 100644 --- a/Source/sys-clk/sysmodule/src/config.h +++ b/Source/sys-clk/sysmodule/src/config.h @@ -54,7 +54,7 @@ class Config std::uint8_t GetProfileCount(std::uint64_t tid); void GetProfiles(std::uint64_t tid, SysClkTitleProfileList* out_profiles); bool SetProfiles(std::uint64_t tid, SysClkTitleProfileList* profiles, bool immediate); - std::uint32_t GetAutoClockHz(std::uint64_t tid, SysClkModule module, SysClkProfile profile); + std::uint32_t GetAutoClockHz(std::uint64_t tid, SysClkModule module, SysClkProfile profile, bool returnRaw); void SetEnabled(bool enabled); bool Enabled(); @@ -76,7 +76,7 @@ class Config bool kipOverride[SysClkConfigValue_EnumMax]; time_t CheckModificationTime(); std::uint32_t FindClockMHz(std::uint64_t tid, SysClkModule module, SysClkProfile profile); - std::uint32_t FindClockHzFromProfiles(std::uint64_t tid, SysClkModule module, std::initializer_list profiles); + std::uint32_t FindClockHzFromProfiles(std::uint64_t tid, SysClkModule module, std::initializer_list profiles, u32 mhzMultiplier = 1000000); static int BrowseIniFunc(const char* section, const char* key, const char* value, void* userdata); std::map, std::uint32_t> profileMHzMap;