- Fixed gpu_hz_list typo in governor (#46)
- Parse loader.kip config from { "/", "/atmosphere/", "/atmosphere/kips/", "/bootloader/" } (#44)
This commit is contained in:
@@ -31,7 +31,7 @@ Result sysclkIpcSetProfiles(u64 tid, SysClkTitleProfileList* profiles);
|
||||
Result sysclkIpcGetConfigValues(SysClkConfigValueList* out_configValues);
|
||||
Result sysclkIpcSetConfigValues(SysClkConfigValueList* configValues);
|
||||
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);
|
||||
|
||||
static inline Result sysclkIpcRemoveOverride(SysClkModule module)
|
||||
|
||||
@@ -65,10 +65,13 @@ typedef struct
|
||||
bool allowUnsafeFreq;
|
||||
bool governor;
|
||||
SysClkProfile realProfile;
|
||||
uint32_t maxMEMFreq;
|
||||
uint32_t boostCPUFreq;
|
||||
} SysClkOcExtra;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t values[20];
|
||||
} SysClkFrequencyTable;
|
||||
|
||||
uint32_t* GetTable(SysClkModule module);
|
||||
|
||||
typedef struct
|
||||
|
||||
@@ -50,5 +50,4 @@ typedef struct
|
||||
{
|
||||
SysClkModule module;
|
||||
SysClkProfile profile;
|
||||
size_t max_entry_num;
|
||||
} SysClkIpc_GetFrequencyTable_Args;
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#include <switch.h>
|
||||
#include <string.h>
|
||||
#include <stdatomic.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static Service g_sysclkSrv;
|
||||
static atomic_size_t g_refCnt;
|
||||
@@ -121,30 +120,13 @@ Result sysclkIpcSetReverseNXRTMode(ReverseNXMode 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 = {
|
||||
.module = module,
|
||||
.profile = profile,
|
||||
.max_entry_num = max_entry_num
|
||||
};
|
||||
size_t table_size = sizeof(uint32_t) * max_entry_num;
|
||||
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;
|
||||
return serviceDispatchInOut(&g_sysclkSrv, SysClkIpcCmd_GetFrequencyTable, args, *out_table);
|
||||
}
|
||||
|
||||
Result sysclkIpcGetIsMariko(bool* out_is_mariko)
|
||||
|
||||
@@ -13,13 +13,13 @@
|
||||
#include "../elements/base_frame.h"
|
||||
// #include "logo_rgba_bin.h"
|
||||
|
||||
#define LOGO_LABEL_X 20
|
||||
#define LOGO_LABEL_X 40
|
||||
#define LOGO_LABEL_Y 35
|
||||
#define LOGO_LABEL_FONT_SIZE 20
|
||||
|
||||
#define VERSION_X 246
|
||||
#define VERSION_X 266
|
||||
#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)
|
||||
{
|
||||
|
||||
@@ -34,46 +34,46 @@ void BaseMenuGui::preDraw(tsl::gfx::Renderer* renderer)
|
||||
{
|
||||
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);
|
||||
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(sysclkFormatProfile(context->profile, true), false, 302, 60, SMALL_TEXT_SIZE, VALUE_COLOR);
|
||||
renderer->drawString("Profile: ", false, 266, 60, SMALL_TEXT_SIZE, DESC_COLOR);
|
||||
renderer->drawString(sysclkFormatProfile(context->profile, true), false, 322, 60, SMALL_TEXT_SIZE, VALUE_COLOR);
|
||||
|
||||
static struct
|
||||
{
|
||||
SysClkModule m;
|
||||
std::uint32_t x;
|
||||
} freqOffsets[SysClkModule_EnumMax] = {
|
||||
{ SysClkModule_CPU, 61 },
|
||||
{ SysClkModule_GPU, 204 },
|
||||
{ SysClkModule_MEM, 342 },
|
||||
{ SysClkModule_CPU, 80 },
|
||||
{ SysClkModule_GPU, 200 },
|
||||
{ SysClkModule_MEM, 320 },
|
||||
};
|
||||
|
||||
for(unsigned int i = 0; i < SysClkModule_EnumMax; i++)
|
||||
{
|
||||
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("CPU:", false, 20, 85, SMALL_TEXT_SIZE, DESC_COLOR);
|
||||
renderer->drawString("GPU:", false, 162, 85, SMALL_TEXT_SIZE, DESC_COLOR);
|
||||
renderer->drawString("MEM:", false, 295, 85, SMALL_TEXT_SIZE, DESC_COLOR);
|
||||
renderer->drawString("CPU:", false, 40, 85, SMALL_TEXT_SIZE, DESC_COLOR);
|
||||
renderer->drawString("GPU:", false, 160, 85, SMALL_TEXT_SIZE, DESC_COLOR);
|
||||
renderer->drawString("MEM:", false, 270, 85, SMALL_TEXT_SIZE, DESC_COLOR);
|
||||
|
||||
static struct
|
||||
{
|
||||
SysClkThermalSensor s;
|
||||
std::uint32_t x;
|
||||
} tempOffsets[SysClkModule_EnumMax] = {
|
||||
{ SysClkThermalSensor_SOC, 60 },
|
||||
{ SysClkThermalSensor_PCB, 165 },
|
||||
{ SysClkThermalSensor_Skin, 268 },
|
||||
{ SysClkThermalSensor_SOC, 80 },
|
||||
{ SysClkThermalSensor_PCB, 200 },
|
||||
{ SysClkThermalSensor_Skin, 320 },
|
||||
};
|
||||
|
||||
renderer->drawString("SOC:", false, 20, 110, SMALL_TEXT_SIZE, DESC_COLOR);
|
||||
renderer->drawString("PCB:", false, 125, 110, SMALL_TEXT_SIZE, DESC_COLOR);
|
||||
renderer->drawString("Skin:", false, 230, 110, SMALL_TEXT_SIZE, DESC_COLOR);
|
||||
renderer->drawString("SOC:", false, 40, 110, SMALL_TEXT_SIZE, DESC_COLOR);
|
||||
renderer->drawString("PCB:", false, 160, 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++)
|
||||
{
|
||||
std::uint32_t millis = this->context->temps[tempOffsets[i].s];
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
|
||||
FreqChoiceGui::FreqChoiceGui(std::uint32_t selectedMHz, SysClkModule module, SysClkProfile profile, FreqChoiceListener listener)
|
||||
{
|
||||
this->hzTable = new uint32_t[MAX_ENTRIES];
|
||||
Result rc = sysclkIpcGetFrequencyTable(module, profile, MAX_ENTRIES, hzTable);
|
||||
this->hzTable = new SysClkFrequencyTable;
|
||||
Result rc = sysclkIpcGetFrequencyTable(module, profile, hzTable);
|
||||
if (R_FAILED(rc)) {
|
||||
FatalGui::openWithResultCode("sysclkIpcGetFrequencyTable", rc);
|
||||
}
|
||||
@@ -26,7 +26,7 @@ FreqChoiceGui::FreqChoiceGui(std::uint32_t selectedMHz, SysClkModule module, Sys
|
||||
}
|
||||
|
||||
FreqChoiceGui::~FreqChoiceGui() {
|
||||
delete[] this->hzTable;
|
||||
delete this->hzTable;
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
uint32_t* p = this->hzTable;
|
||||
while(*p)
|
||||
size_t idx = 0;
|
||||
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));
|
||||
p++;
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ class FreqChoiceGui : public BaseMenuGui
|
||||
protected:
|
||||
std::uint32_t selectedMHz;
|
||||
static constexpr size_t MAX_ENTRIES = 20;
|
||||
std::uint32_t* hzTable;
|
||||
SysClkFrequencyTable* hzTable;
|
||||
FreqChoiceListener listener;
|
||||
tsl::elm::ListItem* createFreqListItem(std::uint32_t mhz, bool selected);
|
||||
|
||||
|
||||
@@ -20,8 +20,11 @@ extern "C"
|
||||
Result apmExtInitialize(void);
|
||||
void apmExtExit(void);
|
||||
|
||||
Result apmExtGetPerformanceMode(u32 *out_mode);
|
||||
// Silently fail
|
||||
Result apmExtSysRequestPerformanceMode(u32 mode);
|
||||
Result apmExtSysSetCpuBoostMode(u32 mode);
|
||||
|
||||
Result apmExtGetPerformanceMode(u32 *out_mode);
|
||||
Result apmExtGetCurrentPerformanceConfiguration(u32 *out_conf);
|
||||
|
||||
inline bool apmExtIsCPUBoosted(u32 conf_id) { // CPU boosted to 1785 MHz
|
||||
|
||||
@@ -21,22 +21,15 @@ Result apmExtInitialize(void)
|
||||
g_refCnt++;
|
||||
|
||||
if (serviceIsActive(&g_apmSrv))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
Result rc = 0;
|
||||
Result rc = smGetService(&g_apmSrv, "apm");
|
||||
|
||||
rc = smGetService(&g_apmSrv, "apm");
|
||||
if(R_SUCCEEDED(rc))
|
||||
{
|
||||
rc = smGetService(&g_apmSysSrv, "apm:sys");
|
||||
}
|
||||
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
apmExtExit();
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -50,6 +43,11 @@ void apmExtExit(void)
|
||||
}
|
||||
}
|
||||
|
||||
Result apmExtSysSetCpuBoostMode(u32 mode)
|
||||
{
|
||||
return serviceDispatchIn(&g_apmSysSrv, 6, mode);
|
||||
}
|
||||
|
||||
Result apmExtGetPerformanceMode(u32 *out_mode)
|
||||
{
|
||||
return serviceDispatchOut(&g_apmSrv, 1, *out_mode);
|
||||
|
||||
@@ -60,8 +60,6 @@ ClockManager::ClockManager()
|
||||
this->oc->systemCoreBoostCPU = false;
|
||||
this->oc->governor = false;
|
||||
this->oc->realProfile = SysClkProfile_Handheld;
|
||||
this->oc->maxMEMFreq = 0;
|
||||
this->oc->boostCPUFreq = 0;
|
||||
|
||||
this->rnxSync = new ReverseNXSync;
|
||||
this->governor = new Governor;
|
||||
@@ -76,17 +74,6 @@ ClockManager::~ClockManager()
|
||||
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)
|
||||
{
|
||||
this->running = running;
|
||||
@@ -127,7 +114,7 @@ uint32_t ClockManager::GetHz(SysClkModule module)
|
||||
case SysClkModule_MEM:
|
||||
hz = (mode == ReverseNX_Docked ||
|
||||
this->oc->realProfile == SysClkProfile_Docked) ?
|
||||
MAX_MEM_CLOCK : 1600'000'000;
|
||||
Clocks::maxMemFreq : 1600'000'000;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -138,27 +125,13 @@ uint32_t ClockManager::GetHz(SysClkModule module)
|
||||
{
|
||||
/* Considering realProfile frequency limit */
|
||||
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 */
|
||||
if (module == SysClkModule_CPU)
|
||||
{
|
||||
if (this->oc->systemCoreBoostCPU && hz < this->oc->boostCPUFreq)
|
||||
return this->oc->boostCPUFreq;
|
||||
if (this->oc->systemCoreBoostCPU && hz < Clocks::boostCpuFreq)
|
||||
return Clocks::boostCpuFreq;
|
||||
if (!hz)
|
||||
/* Trigger RefreshContext() and Tick(), resetting default CPU frequency */
|
||||
return 1020'000'000;
|
||||
@@ -182,7 +155,8 @@ void ClockManager::Tick()
|
||||
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
|
||||
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) {
|
||||
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);
|
||||
@@ -210,7 +184,7 @@ void ClockManager::WaitForNextTick()
|
||||
this->GetConfig()->GetConfigValue(SysClkConfigValue_AutoCPUBoost) &&
|
||||
this->context->enabled &&
|
||||
this->oc->realProfile != SysClkProfile_Handheld &&
|
||||
this->context->freqs[SysClkModule_CPU] <= this->oc->boostCPUFreq;
|
||||
this->context->freqs[SysClkModule_CPU] <= Clocks::boostCpuFreq;
|
||||
|
||||
if (boostOK) {
|
||||
uint32_t core3Util = CpuCoreUtil(3, tickWaitTimeMs * 1000'000ULL).Get();
|
||||
@@ -222,7 +196,7 @@ void ClockManager::WaitForNextTick()
|
||||
Clocks::SetHz(SysClkModule_CPU, GetHz(SysClkModule_CPU));
|
||||
|
||||
if (!lastBoost && this->oc->systemCoreBoostCPU)
|
||||
Clocks::SetHz(SysClkModule_CPU, this->oc->boostCPUFreq);
|
||||
Clocks::SetHz(SysClkModule_CPU, Clocks::boostCpuFreq);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -313,7 +287,7 @@ bool ClockManager::RefreshContext()
|
||||
}
|
||||
|
||||
// let ptm module handle boost clocks rather than resetting
|
||||
if (hasChanged && !IsBoostMode()) {
|
||||
if (hasChanged && !apmExtIsBoostMode(this->context->perfConfId)) {
|
||||
Clocks::ResetToStock();
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,5 @@ class ClockManager
|
||||
ReverseNXSync *rnxSync;
|
||||
Governor *governor;
|
||||
|
||||
bool IsBoostMode();
|
||||
|
||||
uint32_t GetHz(SysClkModule);
|
||||
};
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <nxExt.h>
|
||||
#include "clocks.h"
|
||||
#include "errors.h"
|
||||
#include "file_utils.h"
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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* max = NULL;
|
||||
memset(out_table, 0, max_entry_num * sizeof(uint32_t));
|
||||
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;
|
||||
|
||||
memset(out_table, 0, sizeof(SysClkFrequencyTable));
|
||||
uint32_t* p = min;
|
||||
size_t idx = 0;
|
||||
while(p <= max)
|
||||
out_table[idx++] = *p++;
|
||||
out_table->values[idx++] = *p++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -78,7 +79,6 @@ void Clocks::Initialize()
|
||||
{
|
||||
Result rc = 0;
|
||||
|
||||
// Check if it's Mariko
|
||||
u64 hardware_type = 0;
|
||||
rc = splInitialize();
|
||||
ASSERT_RESULT_OK(rc, "splInitialize");
|
||||
@@ -89,11 +89,11 @@ void Clocks::Initialize()
|
||||
switch (hardware_type) {
|
||||
case 0: // Icosa
|
||||
case 1: // Copper
|
||||
case 4: // Calcio
|
||||
isMariko = false;
|
||||
break;
|
||||
case 2: // Hoag
|
||||
case 3: // Iowa
|
||||
case 4: // Calcio
|
||||
case 5: // Aula
|
||||
isMariko = true;
|
||||
break;
|
||||
@@ -127,6 +127,19 @@ void Clocks::Initialize()
|
||||
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()
|
||||
@@ -359,6 +372,9 @@ std::uint32_t Clocks::GetCurrentHz(SysClkModule module)
|
||||
|
||||
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* max = NULL;
|
||||
GetRange(module, profile, &min, &max);
|
||||
|
||||
@@ -18,8 +18,11 @@
|
||||
class Clocks
|
||||
{
|
||||
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 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 bool GetIsMariko() { return isMariko; };
|
||||
static void Exit();
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#include "file_utils.h"
|
||||
#include "clocks.h"
|
||||
#include <dirent.h>
|
||||
#include <filesystem>
|
||||
#include <nxExt.h>
|
||||
|
||||
static LockableMutex g_log_mutex;
|
||||
@@ -182,3 +181,126 @@ void FileUtils::Exit()
|
||||
fsdevUnmountAll();
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <time.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <atomic>
|
||||
#include <cstdarg>
|
||||
#include <sysclk.h>
|
||||
@@ -34,6 +35,23 @@ class FileUtils
|
||||
static void InitializeAsync();
|
||||
static void LogLine(const char *format, ...);
|
||||
static void WriteContextToCsv(const SysClkContext* context);
|
||||
static void ParseLoaderKip();
|
||||
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 Result CustParser(const char* path, size_t filesize);
|
||||
};
|
||||
|
||||
@@ -164,8 +164,8 @@ Result IpcService::ServiceHandlerFunc(void* arg, const IpcServerRequest* r, u8*
|
||||
if(r->data.size >= sizeof(SysClkIpc_GetFrequencyTable_Args))
|
||||
{
|
||||
SysClkIpc_GetFrequencyTable_Args* in_args = (SysClkIpc_GetFrequencyTable_Args*)r->data.ptr;
|
||||
*out_dataSize = sizeof(uint32_t) * in_args->max_entry_num;
|
||||
return ipcSrv->GetFrequencyTable(in_args, (uint32_t*)out_data);
|
||||
*out_dataSize = sizeof(SysClkFrequencyTable);
|
||||
return ipcSrv->GetFrequencyTable(in_args, (SysClkFrequencyTable*)out_data);
|
||||
}
|
||||
break;
|
||||
case SysClkIpcCmd_GetIsMariko:
|
||||
@@ -313,8 +313,8 @@ Result IpcService::SetReverseNXRTMode(ReverseNXMode mode) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Result IpcService::GetFrequencyTable(SysClkIpc_GetFrequencyTable_Args* args, uint32_t* out_table) {
|
||||
return Clocks::GetTable(args->module, args->profile, args->max_entry_num, out_table);
|
||||
Result IpcService::GetFrequencyTable(SysClkIpc_GetFrequencyTable_Args* args, SysClkFrequencyTable* out_table) {
|
||||
return Clocks::GetTable(args->module, args->profile, out_table);
|
||||
}
|
||||
|
||||
Result IpcService::GetIsMariko(bool* out_is_mariko) {
|
||||
|
||||
@@ -37,7 +37,7 @@ class IpcService
|
||||
Result GetConfigValues(SysClkConfigValueList* out_configValues);
|
||||
Result SetConfigValues(SysClkConfigValueList* configValues);
|
||||
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);
|
||||
|
||||
bool running;
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include "ipc_service.h"
|
||||
#include "oc_extra.h"
|
||||
|
||||
#define INNER_HEAP_SIZE 0x38000
|
||||
#define INNER_HEAP_SIZE 0x40000
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
@@ -135,10 +135,10 @@ Governor::Governor() {
|
||||
m_cpu_freq.module = SysClkModule_CPU;
|
||||
m_gpu_freq.module = SysClkModule_GPU;
|
||||
|
||||
m_cpu_freq.hz_list = &g_freq_table_cpu_hz[0];
|
||||
m_gpu_freq.hz_list = &g_freq_table_cpu_hz[0];
|
||||
m_cpu_freq.hz_list = GetTable(SysClkModule_CPU);
|
||||
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_gpu_freq.boost_hz = 76'800'000;
|
||||
@@ -244,7 +244,7 @@ void Governor::s_FreqContext::SetNextFreq(uint32_t norm_util) {
|
||||
} else {
|
||||
uint32_t* p = hz_list;
|
||||
do {
|
||||
if (*p > next_freq) {
|
||||
if (*p >= next_freq) {
|
||||
adj_next_freq = *p;
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user