sysclk: finish display refresh rate change support

This commit is contained in:
souldbminersmwc
2025-12-24 17:27:41 -05:00
parent 15fc7bc8f2
commit b335412bc4
12 changed files with 490 additions and 101 deletions

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;

View File

@@ -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<SysClkProfile> profiles)
std::uint32_t Config::FindClockHzFromProfiles(std::uint64_t tid, SysClkModule module, std::initializer_list<SysClkProfile> 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);
}

View File

@@ -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<SysClkProfile> profiles);
std::uint32_t FindClockHzFromProfiles(std::uint64_t tid, SysClkModule module, std::initializer_list<SysClkProfile> profiles, u32 mhzMultiplier = 1000000);
static int BrowseIniFunc(const char* section, const char* key, const char* value, void* userdata);
std::map<std::tuple<std::uint64_t, SysClkProfile, SysClkModule>, std::uint32_t> profileMHzMap;