Read PTO (PLL test output) regs; Prevent CPU clock from being stuck at boost freq when "Auto CPU Boost" is toggled off

This commit is contained in:
KazushiM
2022-02-12 19:56:24 +08:00
parent 4ff20f15f1
commit eaed085697
3 changed files with 151 additions and 27 deletions

View File

@@ -4,6 +4,7 @@
#include <string.h> #include <string.h>
#include <stdbool.h> #include <stdbool.h>
#include <inttypes.h> #include <inttypes.h>
#include <unistd.h>
#include <switch.h> #include <switch.h>
/* Recompile nx-hbloader with following added in config.json "kernel_capabilities" /* Recompile nx-hbloader with following added in config.json "kernel_capabilities"
@@ -18,16 +19,103 @@
} }
*/ */
void waitForKeyA(PadState pad) { void waitForKey(PadState pad) {
while (appletMainLoop()) { while (appletMainLoop())
{
padUpdate(&pad); padUpdate(&pad);
u64 kDown = padGetButtonsDown(&pad); u64 kDown = padGetButtonsDown(&pad);
if (kDown & HidNpadButton_A) if (kDown & HidNpadButton_A)
break; break;
if (kDown & HidNpadButton_Plus || kDown & HidNpadButton_B) {
consoleExit(NULL);
exit(0);
}
consoleUpdate(NULL); consoleUpdate(NULL);
} }
} }
#define CLK_RST_IO_BASE 0x60006000
#define CLK_RST_IO_SIZE 0x1000
#define REG(OFFSET) (*reinterpret_cast<volatile u32 *>(OFFSET))
#define GET_BITS(VAL, HIGH, LOW) ((VAL & ((1UL << (HIGH + 1UL)) - 1UL)) >> LOW)
#define GET_BIT(VAL, BIT) GET_BITS(VAL, BIT, BIT)
static u64 clkrst_base = 0;
static u64 clkrst_size = 0;
// From jetson nano kernel
typedef enum {
/* divider = 2 */
CLK_PLLX = 5,
CLK_PLLM = 2,
CLK_PLLMB = 37,
/* PLLX & PLLG are backup PLLs for CPU & GPU */
/* divider = 1 */
CLK_CCLK_G = 18, // A57 CPU cluster
CLK_EMC = 36,
} PTO_ID; // PLL Test Output Register ID
/* See if GM20B clock GPC PLL regs are accessible. */
#define PLLX_MISC0 0xE4
#define PLLM_MISC2 0x9C
double ptoGetMHz(PTO_ID pto_id, u32 divider = 1, u32 presel_reg = 0, u32 presel_mask = 0) {
u32 pre_val, val, presel_val;
if (presel_reg) {
val = REG(clkrst_base + presel_reg);
usleep(10);
presel_val = val & presel_mask;
val &= ~presel_mask;
val |= presel_mask;
REG(clkrst_base + presel_reg) = val;
usleep(10);
}
constexpr u32 cycle_count = 16;
pre_val = REG(clkrst_base + 0x60);
val = BIT(23) | BIT(13) | (cycle_count - 1);
val |= pto_id << 14;
REG(clkrst_base + 0x60) = val;
usleep(10);
REG(clkrst_base + 0x60) = val | BIT(10);
usleep(10);
REG(clkrst_base + 0x60) = val;
usleep(10);
REG(clkrst_base + 0x60) = val | BIT(9);
usleep(500);
while(REG(clkrst_base + 0x64) & BIT(31))
;
val = REG(clkrst_base + 0x64);
val &= 0xFFFFFF;
val *= divider;
double rate_mhz = (u64)val * 32768. / cycle_count / 1000. / 1000.;
usleep(10);
REG(clkrst_base + 0x60) = pre_val;
usleep(10);
if (presel_reg) {
val = REG(clkrst_base + presel_reg);
usleep(10);
val &= ~presel_mask;
val |= presel_val;
REG(clkrst_base + presel_reg) = val;
usleep(10);
}
return rate_mhz;
}
int main() { int main() {
consoleInit(NULL); consoleInit(NULL);
PadState pad; PadState pad;
@@ -35,28 +123,19 @@ int main() {
padInitializeDefault(&pad); padInitializeDefault(&pad);
// Get clkrst MMIO virtual address // Get clkrst MMIO virtual address
#define CLK_RST_IO_BASE 0x60006000 Result rc = svcQueryIoMapping(&clkrst_base, &clkrst_size, CLK_RST_IO_BASE, CLK_RST_IO_SIZE);
#define CLK_RST_IO_SIZE 0x1000
u64 virtaddr_base = 0;
u64 virtaddr_size = 0;
Result rc = svcQueryIoMapping(&virtaddr_base, &virtaddr_size, CLK_RST_IO_BASE, CLK_RST_IO_SIZE);
if (R_FAILED(rc)) { if (R_FAILED(rc)) {
printf("[ERROR] svcQueryIoMapping: 0x%X\n", rc); printf("[ERROR] svcQueryIoMapping: 0x%X\n", rc);
consoleUpdate(NULL); consoleUpdate(NULL);
waitForKeyA(pad); waitForKey(pad);
consoleExit(NULL); consoleExit(NULL);
return -1;
} }
printf("virtaddr_base: 0x%lX\nvirtaddr_size: 0x%lX\n", virtaddr_base, virtaddr_size); printf("clkrst_base: 0x%lX\nclkrst_size: 0x%lX\n", clkrst_base, clkrst_size);
#define READ_REG(OFFSET) (*reinterpret_cast<volatile u32 *>(OFFSET))
#define GET_BITS(VAL, HIGH, LOW) ((VAL & ((1UL << (HIGH + 1UL)) - 1UL)) >> LOW)
#define GET_BIT(VAL, BIT) GET_BITS(VAL, BIT, BIT)
{ {
#define CLKRST_PLLX_BASE 0xE0 #define CLKRST_PLLX_BASE 0xE0
u32 pllx_base = READ_REG(virtaddr_base + CLKRST_PLLX_BASE); u32 pllx_base = REG(clkrst_base + CLKRST_PLLX_BASE);
printf("\n"\ printf("\n"\
"PLLX_BASE: 0x%X\n"\ "PLLX_BASE: 0x%X\n"\
"PLLX_ENABLE: %lu\n"\ "PLLX_ENABLE: %lu\n"\
@@ -64,7 +143,7 @@ int main() {
"PLLX_LOCK: %lu\n"\ "PLLX_LOCK: %lu\n"\
"PLLX_DIVP: %lu\n"\ "PLLX_DIVP: %lu\n"\
"PLLX_DIVN: %lu\n"\ "PLLX_DIVN: %lu\n"\
"PLLX_DIVM: %lu", "PLLX_DIVM: %lu\n",
pllx_base, pllx_base,
GET_BIT(pllx_base, 30), GET_BIT(pllx_base, 30),
GET_BIT(pllx_base, 29), GET_BIT(pllx_base, 29),
@@ -76,12 +155,12 @@ int main() {
{ {
#define CLKRST_PLLX_MISC 0xE4 #define CLKRST_PLLX_MISC 0xE4
u32 pllx_misc = READ_REG(virtaddr_base + CLKRST_PLLX_MISC); u32 pllx_misc = REG(clkrst_base + CLKRST_PLLX_MISC);
printf("\n"\ printf("\n"\
"PLLX_MISC: 0x%X\n"\ "PLLX_MISC: 0x%X\n"\
"PLLX_FO_G_DISABLE: %lu\n"\ "PLLX_FO_G_DISABLE: %lu\n"\
"PLLX_PTS: %lu\n"\ "PLLX_PTS: %lu\n"\
"PLLX_LOCK_ENABLE: %lu", "PLLX_LOCK_ENABLE: %lu\n",
pllx_misc, pllx_misc,
GET_BIT(pllx_misc, 28), GET_BIT(pllx_misc, 28),
GET_BITS(pllx_misc, 23, 22), GET_BITS(pllx_misc, 23, 22),
@@ -90,11 +169,11 @@ int main() {
{ {
#define CLKRST_PLLMB_SS_CFG 0x780 #define CLKRST_PLLMB_SS_CFG 0x780
u32 pllmb_ss_cfg = READ_REG(virtaddr_base + CLKRST_PLLMB_SS_CFG); u32 pllmb_ss_cfg = REG(clkrst_base + CLKRST_PLLMB_SS_CFG);
printf("\n"\ printf("\n"\
"PLLMB_SS_CFG: 0x%X\n"\ "PLLMB_SS_CFG: 0x%X\n"\
"PLLMB_EN_SDM: %lu\n"\ "PLLMB_EN_SDM: %lu\n"\
"PLLMB_EN_SSC: %lu", "PLLMB_EN_SSC: %lu\n",
pllmb_ss_cfg, pllmb_ss_cfg,
GET_BIT(pllmb_ss_cfg, 31), GET_BIT(pllmb_ss_cfg, 31),
GET_BIT(pllmb_ss_cfg, 30)); GET_BIT(pllmb_ss_cfg, 30));
@@ -102,18 +181,60 @@ int main() {
{ {
#define CLKRST_PLLMB_SS_CTRL1 0x784 #define CLKRST_PLLMB_SS_CTRL1 0x784
u32 pllmb_ss_ctrl1 = READ_REG(virtaddr_base + CLKRST_PLLMB_SS_CTRL1); u32 pllmb_ss_ctrl1 = REG(clkrst_base + CLKRST_PLLMB_SS_CTRL1);
printf("\n"\ printf("\n"\
"PLLMB_SS_CTRL1: 0x%X\n"\ "PLLMB_SS_CTRL1: 0x%X\n"\
"PLLMB_SDM_SSC_MAX: %lu\n"\ "PLLMB_SDM_SSC_MAX: %lu\n"\
"PLLMB_SDM_SSC_MIN: %lu", "PLLMB_SDM_SSC_MIN: %lu\n",
pllmb_ss_ctrl1, pllmb_ss_ctrl1,
GET_BITS(pllmb_ss_ctrl1, 31, 16), GET_BITS(pllmb_ss_ctrl1, 31, 16),
GET_BITS(pllmb_ss_ctrl1, 15, 0)); GET_BITS(pllmb_ss_ctrl1, 15, 0));
} }
consoleUpdate(NULL);
waitForKeyA(pad); {
#define CLKRST_PLLM_BASE 0x90
u32 pllm_base = REG(clkrst_base + CLKRST_PLLM_BASE);
printf("\n"\
"PLLM_BASE: 0x%X\n"\
"PLLM_DIVP: %lu\n"\
"PLLM_DIVN: %lu\n"\
"PLLM_DIVM: %lu\n",
pllm_base,
GET_BITS(pllm_base, 24, 20),
GET_BITS(pllm_base, 15, 8),
GET_BITS(pllm_base, 7, 0));
}
{
#define CLKRST_PLLMB_BASE 0x5e8
u32 pllmb_base = REG(clkrst_base + CLKRST_PLLMB_BASE);
printf("\n"\
"PLLMB_BASE: 0x%X\n"\
"PLLMB_DIVP: %lu\n"\
"PLLMB_DIVN: %lu\n"\
"PLLMB_DIVM: %lu\n",
pllmb_base,
GET_BITS(pllmb_base, 24, 20),
GET_BITS(pllmb_base, 15, 8),
GET_BITS(pllmb_base, 7, 0));
}
printf("\n"\
"EMC: %6.1f MHz\n"\
"CCLK_G: %6.1f MHz\n"\
"PLLX: %6.1f MHz\n"\
"PLLM: %6.1f MHz\n"\
"PLLMB: %6.1f MHz\n",
ptoGetMHz(CLK_EMC),
ptoGetMHz(CLK_CCLK_G),
ptoGetMHz(CLK_PLLX, 2, PLLX_MISC0, BIT(22)),
ptoGetMHz(CLK_PLLM, 2, PLLM_MISC2, BIT(8)),
ptoGetMHz(CLK_PLLMB, 2, PLLM_MISC2, BIT(9))
);
waitForKey(pad);
consoleExit(NULL); consoleExit(NULL);
return 0; return 0;

View File

@@ -200,7 +200,7 @@ void ClockManager::WaitForNextTick()
uint64_t tickWaitTimeMs = this->GetConfig()->GetConfigValue(SysClkConfigValue_PollingIntervalMs); uint64_t tickWaitTimeMs = this->GetConfig()->GetConfigValue(SysClkConfigValue_PollingIntervalMs);
uint64_t tickWaitTimeNs = tickWaitTimeMs * 1000000ULL; uint64_t tickWaitTimeNs = tickWaitTimeMs * 1000000ULL;
uint64_t isAutoBoostEnabled = this->GetConfig()->GetConfigValue(SysClkConfigValue_AutoCPUBoost); bool isAutoBoostEnabled = this->GetConfig()->GetConfigValue(SysClkConfigValue_AutoCPUBoost);
if ( isAutoBoostEnabled if ( isAutoBoostEnabled
&& this->context->realProfile != SysClkProfile_Handheld && this->context->realProfile != SysClkProfile_Handheld
&& this->context->enabled && this->context->enabled
@@ -242,6 +242,10 @@ void ClockManager::WaitForNextTick()
} }
else else
{ {
if (this->oc->systemCoreBoostCPU) {
this->oc->systemCoreBoostCPU = false;
Clocks::SetHz(SysClkModule_CPU, GetHz(SysClkModule_CPU));
}
svcSleepThread(tickWaitTimeNs); svcSleepThread(tickWaitTimeNs);
} }
} }
@@ -341,7 +345,7 @@ bool ClockManager::RefreshContext()
{ {
bool hasChanged = false; bool hasChanged = false;
bool enabled = this->GetConfig()->Enabled(); bool enabled = this->GetConfig()->Enabled();
uint64_t isReverseNXSyncEnabled = this->GetConfig()->GetConfigValue(SysClkConfigValue_SyncReverseNXMode); bool isReverseNXSyncEnabled = this->GetConfig()->GetConfigValue(SysClkConfigValue_SyncReverseNXMode);
if(enabled != this->context->enabled) if(enabled != this->context->enabled)
{ {
this->context->enabled = enabled; this->context->enabled = enabled;

View File

@@ -23,7 +23,6 @@
#define FILE_LOG_FLAG_PATH FILE_CONFIG_DIR "/log.flag" #define FILE_LOG_FLAG_PATH FILE_CONFIG_DIR "/log.flag"
#define FILE_LOG_FILE_PATH FILE_CONFIG_DIR "/log.txt" #define FILE_LOG_FILE_PATH FILE_CONFIG_DIR "/log.txt"
#define FILE_SALTYNX_PATH "/atmosphere/contents/0000000000534C56/flags/boot2.flag" // Just check for SaltyNX boot flag #define FILE_SALTYNX_PATH "/atmosphere/contents/0000000000534C56/flags/boot2.flag" // Just check for SaltyNX boot flag
#define FILE_REVERSENX_RT_CONF_PATH FILE_CONFIG_DIR "/ReverseNX-RT.conf"
class FileUtils class FileUtils
{ {