- Fixed gpu_hz_list typo in governor (#46)

- Parse loader.kip config from { "/", "/atmosphere/", "/atmosphere/kips/", "/bootloader/" } (#44)
This commit is contained in:
KazushiM
2022-10-31 00:43:40 +08:00
parent 524247955f
commit 859841ab8e
20 changed files with 232 additions and 115 deletions

View File

@@ -31,7 +31,7 @@ Result sysclkIpcSetProfiles(u64 tid, SysClkTitleProfileList* profiles);
Result sysclkIpcGetConfigValues(SysClkConfigValueList* out_configValues); Result sysclkIpcGetConfigValues(SysClkConfigValueList* out_configValues);
Result sysclkIpcSetConfigValues(SysClkConfigValueList* configValues); Result sysclkIpcSetConfigValues(SysClkConfigValueList* configValues);
Result sysclkIpcSetReverseNXRTMode(ReverseNXMode mode); Result sysclkIpcSetReverseNXRTMode(ReverseNXMode mode);
Result sysclkIpcGetFrequencyTable(SysClkModule module, SysClkProfile profile, size_t max_entry_num, uint32_t* out_table); Result sysclkIpcGetFrequencyTable(SysClkModule module, SysClkProfile profile, SysClkFrequencyTable* out_table);
Result sysclkIpcGetIsMariko(bool* out_is_mariko); Result sysclkIpcGetIsMariko(bool* out_is_mariko);
static inline Result sysclkIpcRemoveOverride(SysClkModule module) static inline Result sysclkIpcRemoveOverride(SysClkModule module)

View File

@@ -65,10 +65,13 @@ typedef struct
bool allowUnsafeFreq; bool allowUnsafeFreq;
bool governor; bool governor;
SysClkProfile realProfile; SysClkProfile realProfile;
uint32_t maxMEMFreq;
uint32_t boostCPUFreq;
} SysClkOcExtra; } SysClkOcExtra;
typedef struct
{
uint32_t values[20];
} SysClkFrequencyTable;
uint32_t* GetTable(SysClkModule module); uint32_t* GetTable(SysClkModule module);
typedef struct typedef struct

View File

@@ -50,5 +50,4 @@ typedef struct
{ {
SysClkModule module; SysClkModule module;
SysClkProfile profile; SysClkProfile profile;
size_t max_entry_num;
} SysClkIpc_GetFrequencyTable_Args; } SysClkIpc_GetFrequencyTable_Args;

View File

@@ -13,7 +13,6 @@
#include <switch.h> #include <switch.h>
#include <string.h> #include <string.h>
#include <stdatomic.h> #include <stdatomic.h>
#include <stdlib.h>
static Service g_sysclkSrv; static Service g_sysclkSrv;
static atomic_size_t g_refCnt; static atomic_size_t g_refCnt;
@@ -121,30 +120,13 @@ Result sysclkIpcSetReverseNXRTMode(ReverseNXMode mode)
return serviceDispatchIn(&g_sysclkSrv, SysClkIpcCmd_SetReverseNXRTMode, mode); return serviceDispatchIn(&g_sysclkSrv, SysClkIpcCmd_SetReverseNXRTMode, mode);
} }
Result sysclkIpcGetFrequencyTable(SysClkModule module, SysClkProfile profile, size_t max_entry_num, uint32_t* out_table) Result sysclkIpcGetFrequencyTable(SysClkModule module, SysClkProfile profile, SysClkFrequencyTable* out_table)
{ {
SysClkIpc_GetFrequencyTable_Args args = { SysClkIpc_GetFrequencyTable_Args args = {
.module = module, .module = module,
.profile = profile, .profile = profile,
.max_entry_num = max_entry_num
}; };
size_t table_size = sizeof(uint32_t) * max_entry_num; return serviceDispatchInOut(&g_sysclkSrv, SysClkIpcCmd_GetFrequencyTable, args, *out_table);
uint32_t* table = malloc(table_size);
memset(table, 0, table_size);
SfDispatchParams disp;
Result rc = serviceDispatchImpl(
&g_sysclkSrv, SysClkIpcCmd_GetFrequencyTable,
&args, sizeof(args),
table, table_size, disp);
if (R_FAILED(rc))
return rc;
memcpy(out_table, table, table_size);
free(table);
return 0;
} }
Result sysclkIpcGetIsMariko(bool* out_is_mariko) Result sysclkIpcGetIsMariko(bool* out_is_mariko)

View File

@@ -13,13 +13,13 @@
#include "../elements/base_frame.h" #include "../elements/base_frame.h"
// #include "logo_rgba_bin.h" // #include "logo_rgba_bin.h"
#define LOGO_LABEL_X 20 #define LOGO_LABEL_X 40
#define LOGO_LABEL_Y 35 #define LOGO_LABEL_Y 35
#define LOGO_LABEL_FONT_SIZE 20 #define LOGO_LABEL_FONT_SIZE 20
#define VERSION_X 246 #define VERSION_X 266
#define VERSION_Y LOGO_LABEL_Y #define VERSION_Y LOGO_LABEL_Y
#define VERSION_FONT_SIZE 15 #define VERSION_FONT_SIZE SMALL_TEXT_SIZE
void BaseGui::preDraw(tsl::gfx::Renderer* renderer) void BaseGui::preDraw(tsl::gfx::Renderer* renderer)
{ {

View File

@@ -34,46 +34,46 @@ void BaseMenuGui::preDraw(tsl::gfx::Renderer* renderer)
{ {
char buf[32]; char buf[32];
renderer->drawString("App ID: ", false, 20, 60, SMALL_TEXT_SIZE, DESC_COLOR); renderer->drawString("App ID: ", false, 40, 60, SMALL_TEXT_SIZE, DESC_COLOR);
snprintf(buf, sizeof(buf), "%016lX", context->applicationId); snprintf(buf, sizeof(buf), "%016lX", context->applicationId);
renderer->drawString(buf, false, 81, 60, SMALL_TEXT_SIZE, VALUE_COLOR); renderer->drawString(buf, false, 100, 60, SMALL_TEXT_SIZE, VALUE_COLOR);
renderer->drawString("Profile: ", false, 246, 60, SMALL_TEXT_SIZE, DESC_COLOR); renderer->drawString("Profile: ", false, 266, 60, SMALL_TEXT_SIZE, DESC_COLOR);
renderer->drawString(sysclkFormatProfile(context->profile, true), false, 302, 60, SMALL_TEXT_SIZE, VALUE_COLOR); renderer->drawString(sysclkFormatProfile(context->profile, true), false, 322, 60, SMALL_TEXT_SIZE, VALUE_COLOR);
static struct static struct
{ {
SysClkModule m; SysClkModule m;
std::uint32_t x; std::uint32_t x;
} freqOffsets[SysClkModule_EnumMax] = { } freqOffsets[SysClkModule_EnumMax] = {
{ SysClkModule_CPU, 61 }, { SysClkModule_CPU, 80 },
{ SysClkModule_GPU, 204 }, { SysClkModule_GPU, 200 },
{ SysClkModule_MEM, 342 }, { SysClkModule_MEM, 320 },
}; };
for(unsigned int i = 0; i < SysClkModule_EnumMax; i++) for(unsigned int i = 0; i < SysClkModule_EnumMax; i++)
{ {
std::uint32_t hz = this->context->freqs[freqOffsets[i].m]; std::uint32_t hz = this->context->freqs[freqOffsets[i].m];
snprintf(buf, sizeof(buf), "%u.%u MHz", hz / 1000000, hz / 100000 - hz / 1000000 * 10); snprintf(buf, sizeof(buf), "%u MHz", hz / 1000000);
renderer->drawString(buf, false, freqOffsets[i].x, 85, SMALL_TEXT_SIZE, VALUE_COLOR); renderer->drawString(buf, false, freqOffsets[i].x, 85, SMALL_TEXT_SIZE, VALUE_COLOR);
} }
renderer->drawString("CPU:", false, 20, 85, SMALL_TEXT_SIZE, DESC_COLOR); renderer->drawString("CPU:", false, 40, 85, SMALL_TEXT_SIZE, DESC_COLOR);
renderer->drawString("GPU:", false, 162, 85, SMALL_TEXT_SIZE, DESC_COLOR); renderer->drawString("GPU:", false, 160, 85, SMALL_TEXT_SIZE, DESC_COLOR);
renderer->drawString("MEM:", false, 295, 85, SMALL_TEXT_SIZE, DESC_COLOR); renderer->drawString("MEM:", false, 270, 85, SMALL_TEXT_SIZE, DESC_COLOR);
static struct static struct
{ {
SysClkThermalSensor s; SysClkThermalSensor s;
std::uint32_t x; std::uint32_t x;
} tempOffsets[SysClkModule_EnumMax] = { } tempOffsets[SysClkModule_EnumMax] = {
{ SysClkThermalSensor_SOC, 60 }, { SysClkThermalSensor_SOC, 80 },
{ SysClkThermalSensor_PCB, 165 }, { SysClkThermalSensor_PCB, 200 },
{ SysClkThermalSensor_Skin, 268 }, { SysClkThermalSensor_Skin, 320 },
}; };
renderer->drawString("SOC:", false, 20, 110, SMALL_TEXT_SIZE, DESC_COLOR); renderer->drawString("SOC:", false, 40, 110, SMALL_TEXT_SIZE, DESC_COLOR);
renderer->drawString("PCB:", false, 125, 110, SMALL_TEXT_SIZE, DESC_COLOR); renderer->drawString("PCB:", false, 160, 110, SMALL_TEXT_SIZE, DESC_COLOR);
renderer->drawString("Skin:", false, 230, 110, SMALL_TEXT_SIZE, DESC_COLOR); renderer->drawString("Skin:", false, 270, 110, SMALL_TEXT_SIZE, DESC_COLOR);
for(unsigned int i = 0; i < SysClkModule_EnumMax; i++) for(unsigned int i = 0; i < SysClkModule_EnumMax; i++)
{ {
std::uint32_t millis = this->context->temps[tempOffsets[i].s]; std::uint32_t millis = this->context->temps[tempOffsets[i].s];

View File

@@ -15,8 +15,8 @@
FreqChoiceGui::FreqChoiceGui(std::uint32_t selectedMHz, SysClkModule module, SysClkProfile profile, FreqChoiceListener listener) FreqChoiceGui::FreqChoiceGui(std::uint32_t selectedMHz, SysClkModule module, SysClkProfile profile, FreqChoiceListener listener)
{ {
this->hzTable = new uint32_t[MAX_ENTRIES]; this->hzTable = new SysClkFrequencyTable;
Result rc = sysclkIpcGetFrequencyTable(module, profile, MAX_ENTRIES, hzTable); Result rc = sysclkIpcGetFrequencyTable(module, profile, hzTable);
if (R_FAILED(rc)) { if (R_FAILED(rc)) {
FatalGui::openWithResultCode("sysclkIpcGetFrequencyTable", rc); FatalGui::openWithResultCode("sysclkIpcGetFrequencyTable", rc);
} }
@@ -26,7 +26,7 @@ FreqChoiceGui::FreqChoiceGui(std::uint32_t selectedMHz, SysClkModule module, Sys
} }
FreqChoiceGui::~FreqChoiceGui() { FreqChoiceGui::~FreqChoiceGui() {
delete[] this->hzTable; delete this->hzTable;
} }
tsl::elm::ListItem* FreqChoiceGui::createFreqListItem(std::uint32_t mhz, bool selected) tsl::elm::ListItem* FreqChoiceGui::createFreqListItem(std::uint32_t mhz, bool selected)
@@ -54,11 +54,12 @@ void FreqChoiceGui::listUI()
{ {
this->listElement->addItem(this->createFreqListItem(0, this->selectedMHz == 0)); this->listElement->addItem(this->createFreqListItem(0, this->selectedMHz == 0));
uint32_t* p = this->hzTable; size_t idx = 0;
while(*p) uint32_t freq;
while(idx < 20 && (freq = this->hzTable->values[idx]))
{ {
uint32_t mhz = *p / 1000'000; uint32_t mhz = freq / 1000'000;
this->listElement->addItem(this->createFreqListItem(mhz, mhz == this->selectedMHz)); this->listElement->addItem(this->createFreqListItem(mhz, mhz == this->selectedMHz));
p++; idx++;
} }
} }

View File

@@ -23,7 +23,7 @@ class FreqChoiceGui : public BaseMenuGui
protected: protected:
std::uint32_t selectedMHz; std::uint32_t selectedMHz;
static constexpr size_t MAX_ENTRIES = 20; static constexpr size_t MAX_ENTRIES = 20;
std::uint32_t* hzTable; SysClkFrequencyTable* hzTable;
FreqChoiceListener listener; FreqChoiceListener listener;
tsl::elm::ListItem* createFreqListItem(std::uint32_t mhz, bool selected); tsl::elm::ListItem* createFreqListItem(std::uint32_t mhz, bool selected);

View File

@@ -20,8 +20,11 @@ extern "C"
Result apmExtInitialize(void); Result apmExtInitialize(void);
void apmExtExit(void); void apmExtExit(void);
Result apmExtGetPerformanceMode(u32 *out_mode); // Silently fail
Result apmExtSysRequestPerformanceMode(u32 mode); Result apmExtSysRequestPerformanceMode(u32 mode);
Result apmExtSysSetCpuBoostMode(u32 mode);
Result apmExtGetPerformanceMode(u32 *out_mode);
Result apmExtGetCurrentPerformanceConfiguration(u32 *out_conf); Result apmExtGetCurrentPerformanceConfiguration(u32 *out_conf);
inline bool apmExtIsCPUBoosted(u32 conf_id) { // CPU boosted to 1785 MHz inline bool apmExtIsCPUBoosted(u32 conf_id) { // CPU boosted to 1785 MHz

View File

@@ -21,22 +21,15 @@ Result apmExtInitialize(void)
g_refCnt++; g_refCnt++;
if (serviceIsActive(&g_apmSrv)) if (serviceIsActive(&g_apmSrv))
{
return 0; return 0;
}
Result rc = 0; Result rc = smGetService(&g_apmSrv, "apm");
rc = smGetService(&g_apmSrv, "apm");
if(R_SUCCEEDED(rc)) if(R_SUCCEEDED(rc))
{
rc = smGetService(&g_apmSysSrv, "apm:sys"); rc = smGetService(&g_apmSysSrv, "apm:sys");
}
if (R_FAILED(rc)) if (R_FAILED(rc))
{
apmExtExit(); apmExtExit();
}
return rc; return rc;
} }
@@ -50,6 +43,11 @@ void apmExtExit(void)
} }
} }
Result apmExtSysSetCpuBoostMode(u32 mode)
{
return serviceDispatchIn(&g_apmSysSrv, 6, mode);
}
Result apmExtGetPerformanceMode(u32 *out_mode) Result apmExtGetPerformanceMode(u32 *out_mode)
{ {
return serviceDispatchOut(&g_apmSrv, 1, *out_mode); return serviceDispatchOut(&g_apmSrv, 1, *out_mode);

View File

@@ -60,8 +60,6 @@ ClockManager::ClockManager()
this->oc->systemCoreBoostCPU = false; this->oc->systemCoreBoostCPU = false;
this->oc->governor = false; this->oc->governor = false;
this->oc->realProfile = SysClkProfile_Handheld; this->oc->realProfile = SysClkProfile_Handheld;
this->oc->maxMEMFreq = 0;
this->oc->boostCPUFreq = 0;
this->rnxSync = new ReverseNXSync; this->rnxSync = new ReverseNXSync;
this->governor = new Governor; this->governor = new Governor;
@@ -76,17 +74,6 @@ ClockManager::~ClockManager()
delete this->config; delete this->config;
} }
bool ClockManager::IsBoostMode()
{
std::uint32_t confId = this->context->perfConfId;
bool isBoostMode = apmExtIsBoostMode(confId);
if (apmExtIsCPUBoosted(confId) && !this->oc->boostCPUFreq) {
this->oc->boostCPUFreq = std::max(this->context->freqs[SysClkModule_CPU], 1785'000'000U);
this->governor->SetCPUBoostHz(this->oc->boostCPUFreq);
}
return isBoostMode;
}
void ClockManager::SetRunning(bool running) void ClockManager::SetRunning(bool running)
{ {
this->running = running; this->running = running;
@@ -127,7 +114,7 @@ uint32_t ClockManager::GetHz(SysClkModule module)
case SysClkModule_MEM: case SysClkModule_MEM:
hz = (mode == ReverseNX_Docked || hz = (mode == ReverseNX_Docked ||
this->oc->realProfile == SysClkProfile_Docked) ? this->oc->realProfile == SysClkProfile_Docked) ?
MAX_MEM_CLOCK : 1600'000'000; Clocks::maxMemFreq : 1600'000'000;
break; break;
default: default:
break; break;
@@ -138,27 +125,13 @@ uint32_t ClockManager::GetHz(SysClkModule module)
{ {
/* Considering realProfile frequency limit */ /* Considering realProfile frequency limit */
hz = Clocks::GetNearestHz(module, this->oc->realProfile, hz); hz = Clocks::GetNearestHz(module, this->oc->realProfile, hz);
if (module == SysClkModule_MEM && hz == MAX_MEM_CLOCK)
{
/* Trigger Max Mem Clock and record it */
if (!this->oc->maxMEMFreq)
{
uint32_t currentHz = Clocks::GetCurrentHz(SysClkModule_MEM);
Clocks::SetHz(SysClkModule_MEM, MAX_MEM_CLOCK);
this->oc->maxMEMFreq = Clocks::GetCurrentHz(SysClkModule_MEM);
Clocks::SetHz(SysClkModule_MEM, currentHz);
}
return this->oc->maxMEMFreq;
}
} }
/* Handle CPU Auto Boost, no user-defined hz required */ /* Handle CPU Auto Boost, no user-defined hz required */
if (module == SysClkModule_CPU) if (module == SysClkModule_CPU)
{ {
if (this->oc->systemCoreBoostCPU && hz < this->oc->boostCPUFreq) if (this->oc->systemCoreBoostCPU && hz < Clocks::boostCpuFreq)
return this->oc->boostCPUFreq; return Clocks::boostCpuFreq;
if (!hz) if (!hz)
/* Trigger RefreshContext() and Tick(), resetting default CPU frequency */ /* Trigger RefreshContext() and Tick(), resetting default CPU frequency */
return 1020'000'000; return 1020'000'000;
@@ -182,7 +155,8 @@ void ClockManager::Tick()
if (hz && hz != this->context->freqs[module] && !this->oc->governor) if (hz && hz != this->context->freqs[module] && !this->oc->governor)
{ {
// Skip setting CPU or GPU clocks in CpuBoostMode if CPU <= boostCPUFreq or GPU >= 76.8MHz // Skip setting CPU or GPU clocks in CpuBoostMode if CPU <= boostCPUFreq or GPU >= 76.8MHz
bool skipBoost = IsBoostMode() && ((module == SysClkModule_CPU && hz <= this->oc->boostCPUFreq) || module == SysClkModule_GPU); bool skipBoost = apmExtIsBoostMode(this->context->perfConfId);
skipBoost &= (module == SysClkModule_CPU && hz <= Clocks::boostCpuFreq) || module == SysClkModule_GPU;
if (!skipBoost) { if (!skipBoost) {
FileUtils::LogLine("[mgr] %s clock set : %u.%u MHz", Clocks::GetModuleName((SysClkModule)module, true), hz/1000000, hz/100000 - hz/1000000*10); FileUtils::LogLine("[mgr] %s clock set : %u.%u MHz", Clocks::GetModuleName((SysClkModule)module, true), hz/1000000, hz/100000 - hz/1000000*10);
Clocks::SetHz((SysClkModule)module, hz); Clocks::SetHz((SysClkModule)module, hz);
@@ -210,7 +184,7 @@ void ClockManager::WaitForNextTick()
this->GetConfig()->GetConfigValue(SysClkConfigValue_AutoCPUBoost) && this->GetConfig()->GetConfigValue(SysClkConfigValue_AutoCPUBoost) &&
this->context->enabled && this->context->enabled &&
this->oc->realProfile != SysClkProfile_Handheld && this->oc->realProfile != SysClkProfile_Handheld &&
this->context->freqs[SysClkModule_CPU] <= this->oc->boostCPUFreq; this->context->freqs[SysClkModule_CPU] <= Clocks::boostCpuFreq;
if (boostOK) { if (boostOK) {
uint32_t core3Util = CpuCoreUtil(3, tickWaitTimeMs * 1000'000ULL).Get(); uint32_t core3Util = CpuCoreUtil(3, tickWaitTimeMs * 1000'000ULL).Get();
@@ -222,7 +196,7 @@ void ClockManager::WaitForNextTick()
Clocks::SetHz(SysClkModule_CPU, GetHz(SysClkModule_CPU)); Clocks::SetHz(SysClkModule_CPU, GetHz(SysClkModule_CPU));
if (!lastBoost && this->oc->systemCoreBoostCPU) if (!lastBoost && this->oc->systemCoreBoostCPU)
Clocks::SetHz(SysClkModule_CPU, this->oc->boostCPUFreq); Clocks::SetHz(SysClkModule_CPU, Clocks::boostCpuFreq);
return; return;
} }
@@ -313,7 +287,7 @@ bool ClockManager::RefreshContext()
} }
// let ptm module handle boost clocks rather than resetting // let ptm module handle boost clocks rather than resetting
if (hasChanged && !IsBoostMode()) { if (hasChanged && !apmExtIsBoostMode(this->context->perfConfId)) {
Clocks::ResetToStock(); Clocks::ResetToStock();
} }

View File

@@ -52,7 +52,5 @@ class ClockManager
ReverseNXSync *rnxSync; ReverseNXSync *rnxSync;
Governor *governor; Governor *governor;
bool IsBoostMode();
uint32_t GetHz(SysClkModule); uint32_t GetHz(SysClkModule);
}; };

View File

@@ -12,6 +12,7 @@
#include <nxExt.h> #include <nxExt.h>
#include "clocks.h" #include "clocks.h"
#include "errors.h" #include "errors.h"
#include "file_utils.h"
void Clocks::GetRange(SysClkModule module, SysClkProfile profile, uint32_t** min, uint32_t** max) void Clocks::GetRange(SysClkModule module, SysClkProfile profile, uint32_t** min, uint32_t** max)
{ {
@@ -58,18 +59,18 @@ void Clocks::GetRange(SysClkModule module, SysClkProfile profile, uint32_t** min
ERROR_THROW("No such PcvModule: %u", module); ERROR_THROW("No such PcvModule: %u", module);
} }
Result Clocks::GetTable(SysClkModule module, SysClkProfile profile, size_t max_entry_num, uint32_t* out_table) { Result Clocks::GetTable(SysClkModule module, SysClkProfile profile, SysClkFrequencyTable* out_table) {
uint32_t* min = NULL; uint32_t* min = NULL;
uint32_t* max = NULL; uint32_t* max = NULL;
memset(out_table, 0, max_entry_num * sizeof(uint32_t));
GetRange(module, profile, &min, &max); GetRange(module, profile, &min, &max);
if (!min || !max || (max - min) / sizeof(uint32_t) >= max_entry_num) if (!min || !max || (max - min) / sizeof(uint32_t) >= sizeof(SysClkFrequencyTable) / sizeof(uint32_t))
return 1; return 1;
memset(out_table, 0, sizeof(SysClkFrequencyTable));
uint32_t* p = min; uint32_t* p = min;
size_t idx = 0; size_t idx = 0;
while(p <= max) while(p <= max)
out_table[idx++] = *p++; out_table->values[idx++] = *p++;
return 0; return 0;
} }
@@ -78,7 +79,6 @@ void Clocks::Initialize()
{ {
Result rc = 0; Result rc = 0;
// Check if it's Mariko
u64 hardware_type = 0; u64 hardware_type = 0;
rc = splInitialize(); rc = splInitialize();
ASSERT_RESULT_OK(rc, "splInitialize"); ASSERT_RESULT_OK(rc, "splInitialize");
@@ -89,11 +89,11 @@ void Clocks::Initialize()
switch (hardware_type) { switch (hardware_type) {
case 0: // Icosa case 0: // Icosa
case 1: // Copper case 1: // Copper
case 4: // Calcio
isMariko = false; isMariko = false;
break; break;
case 2: // Hoag case 2: // Hoag
case 3: // Iowa case 3: // Iowa
case 4: // Calcio
case 5: // Aula case 5: // Aula
isMariko = true; isMariko = true;
break; break;
@@ -127,6 +127,19 @@ void Clocks::Initialize()
rc = tcInitialize(); rc = tcInitialize();
ASSERT_RESULT_OK(rc, "tcInitialize"); ASSERT_RESULT_OK(rc, "tcInitialize");
} }
FileUtils::ParseLoaderKip();
if (!maxMemFreq) {
uint32_t curr_mem_hz = GetCurrentHz(SysClkModule_MEM);
SetHz(SysClkModule_MEM, MAX_MEM_CLOCK);
svcSleepThread(1'000'000);
if (uint32_t hz = GetCurrentHz(SysClkModule_MEM))
maxMemFreq = hz;
else
maxMemFreq = MAX_MEM_CLOCK;
SetHz(SysClkModule_MEM, curr_mem_hz);
}
} }
void Clocks::Exit() void Clocks::Exit()
@@ -359,6 +372,9 @@ std::uint32_t Clocks::GetCurrentHz(SysClkModule module)
std::uint32_t Clocks::GetNearestHz(SysClkModule module, SysClkProfile profile, std::uint32_t inHz) std::uint32_t Clocks::GetNearestHz(SysClkModule module, SysClkProfile profile, std::uint32_t inHz)
{ {
if (module == SysClkModule_MEM && inHz == MAX_MEM_CLOCK)
return Clocks::maxMemFreq;
uint32_t* min = NULL; uint32_t* min = NULL;
uint32_t* max = NULL; uint32_t* max = NULL;
GetRange(module, profile, &min, &max); GetRange(module, profile, &min, &max);

View File

@@ -18,8 +18,11 @@
class Clocks class Clocks
{ {
public: public:
static inline uint32_t boostCpuFreq = 1785000000;
static inline uint32_t maxMemFreq = MAX_MEM_CLOCK;
static void GetRange(SysClkModule module, SysClkProfile profile, uint32_t** min, uint32_t** max); static void GetRange(SysClkModule module, SysClkProfile profile, uint32_t** min, uint32_t** max);
static Result GetTable(SysClkModule module, SysClkProfile profile, size_t max_entry_num, uint32_t* out_table); static Result GetTable(SysClkModule module, SysClkProfile profile, SysClkFrequencyTable* out_table);
static void SetAllowUnsafe(bool allow) { allowUnsafe = allow; }; static void SetAllowUnsafe(bool allow) { allowUnsafe = allow; };
static bool GetIsMariko() { return isMariko; }; static bool GetIsMariko() { return isMariko; };
static void Exit(); static void Exit();

View File

@@ -11,7 +11,6 @@
#include "file_utils.h" #include "file_utils.h"
#include "clocks.h" #include "clocks.h"
#include <dirent.h> #include <dirent.h>
#include <filesystem>
#include <nxExt.h> #include <nxExt.h>
static LockableMutex g_log_mutex; static LockableMutex g_log_mutex;
@@ -182,3 +181,126 @@ void FileUtils::Exit()
fsdevUnmountAll(); fsdevUnmountAll();
fsExit(); fsExit();
} }
void FileUtils::ParseLoaderKip() {
const char* dirs[] = { "/", "/atmosphere/", "/atmosphere/kips/", "/bootloader/" };
char* full_path = new char[0x200];
for (auto const& dir : dirs) {
struct dirent *entry = NULL;
DIR *dp = opendir(dir);
if (!dp)
continue;
while ((entry = readdir(dp))) {
if (entry->d_type != DT_REG)
continue;
snprintf(full_path, 0x200, "%s%s", dir, entry->d_name);
FILE* fp = fopen(full_path, "r");
if (!fp)
continue;
fseek(fp, 0, SEEK_END);
long res = ftell(fp);
fclose(fp);
if (res == -1)
continue;
size_t filesize = (size_t)res;
if (filesize < 0x1000 || filesize > 512 * 1024)
continue;
const char kip_ext[] = {'.', 'k', 'i', 'p'};
size_t file_name_len = strnlen(reinterpret_cast<const char*>(&entry->d_name), 256);
const char* file_ext = &entry->d_name[file_name_len - sizeof(kip_ext)];
if (strncasecmp((const char*)kip_ext, file_ext, sizeof(kip_ext)))
continue;
if (R_SUCCEEDED(CustParser(full_path, filesize))) {
LogLine("Parsed cust config from %s, maxMemFreq: %u MHz, boostCpuFreq: %u MHz",
full_path,
Clocks::maxMemFreq / 1'000'000,
Clocks::boostCpuFreq / 1'000'000
);
delete[] full_path;
return;
}
}
}
delete[] full_path;
}
Result FileUtils::CustParser(const char* filepath, size_t filesize) {
enum ParseError {
ParseError_Success = 0,
ParseError_OpenReadFailed,
ParseError_WrongKipMagic,
ParseError_CustNotFound,
ParseError_WrongCustRev,
};
FILE* fp = fopen(filepath, "r");
if (!fp)
return ParseError_OpenReadFailed;
constexpr uint8_t KIP_MAGIC[] = {'K', 'I', 'P', '1', 'L', 'o', 'a', 'd', 'e', 'r'};
constexpr size_t BLOCK_SIZE = 0x1000;
char* tmp_block = new char[BLOCK_SIZE];
fread(tmp_block, sizeof(char), BLOCK_SIZE, fp);
if (memcmp(KIP_MAGIC, tmp_block, sizeof(KIP_MAGIC))) {
delete[] tmp_block;
return ParseError_WrongKipMagic;
}
CustTable table {};
fpos_t cust_pos = 0;
long block_pos = 0;
while ((block_pos = ftell(fp)) >= 0 && (size_t)block_pos < filesize) {
for (size_t i = 0; i < BLOCK_SIZE; i += sizeof(table.cust)) {
if (memcmp(table.cust, &tmp_block[i], sizeof(table.cust)))
continue;
fgetpos(fp, &cust_pos);
cust_pos = cust_pos + i - BLOCK_SIZE;
goto found;
}
fread(tmp_block, sizeof(char), BLOCK_SIZE, fp);
}
found:
delete[] tmp_block;
if (!cust_pos) {
fclose(fp);
return ParseError_CustNotFound;
}
memset(reinterpret_cast<void*>(&table), 0, sizeof(CustTable));
fsetpos(fp, &cust_pos);
if (!fread(reinterpret_cast<char*>(&table), 1, sizeof(CustTable), fp)) {
fclose(fp);
return ParseError_OpenReadFailed;
}
fclose(fp);
if (table.custRev != 2)
return ParseError_WrongCustRev;
if (Clocks::GetIsMariko()) {
if (table.marikoCpuBoostClock)
Clocks::boostCpuFreq = table.marikoCpuBoostClock * 1000;
if (table.marikoEmcMaxClock)
Clocks::maxMemFreq = table.marikoEmcMaxClock * 1000;
} else {
if (table.eristaEmcMaxClock)
Clocks::maxMemFreq = table.eristaEmcMaxClock * 1000;
}
return ParseError_Success;
}

View File

@@ -13,6 +13,7 @@
#include <time.h> #include <time.h>
#include <vector> #include <vector>
#include <string> #include <string>
#include <cstring>
#include <atomic> #include <atomic>
#include <cstdarg> #include <cstdarg>
#include <sysclk.h> #include <sysclk.h>
@@ -34,6 +35,23 @@ class FileUtils
static void InitializeAsync(); static void InitializeAsync();
static void LogLine(const char *format, ...); static void LogLine(const char *format, ...);
static void WriteContextToCsv(const SysClkContext* context); static void WriteContextToCsv(const SysClkContext* context);
static void ParseLoaderKip();
protected: protected:
typedef struct CustTable {
uint8_t cust[4] = {'C', 'U', 'S', 'T'};
uint16_t custRev;
uint16_t mtcConf;
uint32_t marikoCpuMaxClock;
uint32_t marikoCpuBoostClock;
uint32_t marikoCpuMaxVolt;
uint32_t marikoGpuMaxClock;
uint32_t marikoEmcMaxClock;
uint32_t eristaCpuOCEnable;
uint32_t eristaCpuMaxVolt;
uint32_t eristaEmcMaxClock;
uint32_t eristaEmcVolt;
} CustTable;
static void RefreshFlags(bool force); static void RefreshFlags(bool force);
static Result CustParser(const char* path, size_t filesize);
}; };

View File

@@ -164,8 +164,8 @@ Result IpcService::ServiceHandlerFunc(void* arg, const IpcServerRequest* r, u8*
if(r->data.size >= sizeof(SysClkIpc_GetFrequencyTable_Args)) if(r->data.size >= sizeof(SysClkIpc_GetFrequencyTable_Args))
{ {
SysClkIpc_GetFrequencyTable_Args* in_args = (SysClkIpc_GetFrequencyTable_Args*)r->data.ptr; SysClkIpc_GetFrequencyTable_Args* in_args = (SysClkIpc_GetFrequencyTable_Args*)r->data.ptr;
*out_dataSize = sizeof(uint32_t) * in_args->max_entry_num; *out_dataSize = sizeof(SysClkFrequencyTable);
return ipcSrv->GetFrequencyTable(in_args, (uint32_t*)out_data); return ipcSrv->GetFrequencyTable(in_args, (SysClkFrequencyTable*)out_data);
} }
break; break;
case SysClkIpcCmd_GetIsMariko: case SysClkIpcCmd_GetIsMariko:
@@ -313,8 +313,8 @@ Result IpcService::SetReverseNXRTMode(ReverseNXMode mode) {
return 0; return 0;
} }
Result IpcService::GetFrequencyTable(SysClkIpc_GetFrequencyTable_Args* args, uint32_t* out_table) { Result IpcService::GetFrequencyTable(SysClkIpc_GetFrequencyTable_Args* args, SysClkFrequencyTable* out_table) {
return Clocks::GetTable(args->module, args->profile, args->max_entry_num, out_table); return Clocks::GetTable(args->module, args->profile, out_table);
} }
Result IpcService::GetIsMariko(bool* out_is_mariko) { Result IpcService::GetIsMariko(bool* out_is_mariko) {

View File

@@ -37,7 +37,7 @@ class IpcService
Result GetConfigValues(SysClkConfigValueList* out_configValues); Result GetConfigValues(SysClkConfigValueList* out_configValues);
Result SetConfigValues(SysClkConfigValueList* configValues); Result SetConfigValues(SysClkConfigValueList* configValues);
Result SetReverseNXRTMode(ReverseNXMode mode); Result SetReverseNXRTMode(ReverseNXMode mode);
Result GetFrequencyTable(SysClkIpc_GetFrequencyTable_Args* args, uint32_t* out_table); Result GetFrequencyTable(SysClkIpc_GetFrequencyTable_Args* args, SysClkFrequencyTable* out_table);
Result GetIsMariko(bool* out_is_mariko); Result GetIsMariko(bool* out_is_mariko);
bool running; bool running;

View File

@@ -22,7 +22,7 @@
#include "ipc_service.h" #include "ipc_service.h"
#include "oc_extra.h" #include "oc_extra.h"
#define INNER_HEAP_SIZE 0x38000 #define INNER_HEAP_SIZE 0x40000
extern "C" extern "C"
{ {

View File

@@ -135,10 +135,10 @@ Governor::Governor() {
m_cpu_freq.module = SysClkModule_CPU; m_cpu_freq.module = SysClkModule_CPU;
m_gpu_freq.module = SysClkModule_GPU; m_gpu_freq.module = SysClkModule_GPU;
m_cpu_freq.hz_list = &g_freq_table_cpu_hz[0]; m_cpu_freq.hz_list = GetTable(SysClkModule_CPU);
m_gpu_freq.hz_list = &g_freq_table_cpu_hz[0]; m_gpu_freq.hz_list = GetTable(SysClkModule_GPU);
m_cpu_freq.boost_hz = 1785'000'000; m_cpu_freq.boost_hz = Clocks::boostCpuFreq;
m_cpu_freq.utilref_hz = 2397'000'000; m_cpu_freq.utilref_hz = 2397'000'000;
m_gpu_freq.boost_hz = 76'800'000; m_gpu_freq.boost_hz = 76'800'000;
@@ -244,7 +244,7 @@ void Governor::s_FreqContext::SetNextFreq(uint32_t norm_util) {
} else { } else {
uint32_t* p = hz_list; uint32_t* p = hz_list;
do { do {
if (*p > next_freq) { if (*p >= next_freq) {
adj_next_freq = *p; adj_next_freq = *p;
break; break;
} }