diff --git a/Source/sys-clk/common/include/registers.h b/Source/sys-clk/common/include/registers.h index e782f1c6..d645e331 100644 --- a/Source/sys-clk/common/include/registers.h +++ b/Source/sys-clk/common/include/registers.h @@ -12,9 +12,8 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . - * + * */ - #pragma once @@ -310,6 +309,9 @@ #define EMC_PMACRO_CMD_CTRL_1_0 0x784 #define EMC_PMACRO_CMD_CTRL_2_0 0x788 +#define MC_REGISTER_BASE 0x70019000 +#define MC_REGISTER_REGION_SIZE 0x1000 + #define MC_INTSTATUS_0 0x000 #define MC_INTMASK_0 0x004 #define MC_ERR_STATUS_0 0x008 @@ -489,4 +491,40 @@ #define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_7 0xBEC #define MC_ERR_GENERALIZED_CARVEOUT_STATUS_0 0xC00 #define MC_SECURITY_CARVEOUT2_BOM_0 0xC5C -#define MC_SECURITY_CARVEOUT3_BOM_0 0xCAC \ No newline at end of file +#define MC_SECURITY_CARVEOUT3_BOM_0 0xCAC + +#define CLDVFS_REGION_BASE 0x70110000 +#define CLDVFS_REGION_SIZE 0x1000 +#define CL_DVFS_CTRL_0 0x0 +#define CL_DVFS_CONFIG_0 0x4 +#define CL_DVFS_PARAMS_0 0x8 +#define CL_DVFS_TUNE0_0 0xC +#define CL_DVFS_TUNE1_0 0x10 +#define CL_DVFS_FREQ_REQ_0 0x14 +#define CL_DVFS_SCALE_RAMP_0 0x18 +#define CL_DVFS_DROOP_CTRL_0 0x1C +#define CL_DVFS_OUTPUT_CFG_0 0x20 +#define CL_DVFS_OUTPUT_FORCE_0 0x24 +#define CL_DVFS_MONITOR_CTRL_0 0x28 +#define CL_DVFS_MONITOR_DATA_0 0x2C +#define CL_DVFS_I2C_CFG_0 0x40 +#define CL_DVFS_I2C_VDD_REG_ADDR_0 0x44 +#define CL_DVFS_I2C_STS_0 0x48 +#define CL_DVFS_INTR_STS_0 0x5C +#define CL_DVFS_INTR_EN_0 0x60 +#define DVFS_DFLL_THROTTLE_CTRL_0 0x64 +#define DVFS_DFLL_THROTTLE_LIGHT_0 0x68 +#define DVFS_DFLL_THROTTLE_MEDIUM_0 0x6C +#define DVFS_DFLL_THROTTLE_HEAVY_0 0x70 +#define DVFS_CC4_HVC_0 0x74 +#define CL_DVFS_MONITOR_DATA_0 0x2C +#define CL_DVFS_I2C_CFG_0 0x40 +#define CL_DVFS_I2C_VDD_REG_ADDR_0 0x44 +#define CL_DVFS_I2C_STS_0 0x48 +#define CL_DVFS_INTR_STS_0 0x5C +#define CL_DVFS_INTR_EN_0 0x60 +#define DVFS_DFLL_THROTTLE_CTRL_0 0x64 +#define DVFS_DFLL_THROTTLE_LIGHT_0 0x68 +#define DVFS_DFLL_THROTTLE_MEDIUM_0 0x6C +#define DVFS_DFLL_THROTTLE_HEAVY_0 0x70 +#define CL_DVFS_I2C_CLK_DIVISOR_REGISTER_0 0x16C diff --git a/Source/sys-clk/common/include/sysclk/config.h b/Source/sys-clk/common/include/sysclk/config.h index d9db7297..c0aba13e 100644 --- a/Source/sys-clk/common/include/sysclk/config.h +++ b/Source/sys-clk/common/include/sysclk/config.h @@ -58,7 +58,7 @@ typedef enum { HorizonOCConfigValue_DVFSMode, HorizonOCConfigValue_DVFSOffset, - + HorizonOCConfigValue_LiveCpuUv, HorizonOCConfigValue_EnableExperimentalSettings, HorizonOCConfigValue_GPUScheduling, @@ -235,6 +235,9 @@ static inline const char* sysclkFormatConfigValue(SysClkConfigValue val, bool pr case HorizonOCConfigValue_GPUScheduling: return pretty ? "GPU Scheduling" : "gpu_scheduling"; + case HorizonOCConfigValue_LiveCpuUv: + return pretty ? "Live CPU Undervolt" : "live_cpu_uv"; + case HorizonOCConfigValue_EnableExperimentalSettings: return pretty ? "Enable Experimental Settings" : "enable_experimental_settings"; @@ -416,6 +419,7 @@ static inline uint64_t sysclkDefaultConfigValue(SysClkConfigValue val) case HorizonOCConfigValue_OverwriteRefreshRate: case HorizonOCConfigValue_EnableUnsafeDisplayFreqs: case HorizonOCConfigValue_GPUScheduling: + case HorizonOCConfigValue_LiveCpuUv: return 0ULL; case HocClkConfigValue_EristaMaxCpuClock: return 1785ULL; @@ -463,6 +467,7 @@ static inline uint64_t sysclkValidConfigValue(SysClkConfigValue val, uint64_t in case HorizonOCConfigValue_EnableUnsafeDisplayFreqs: case HocClkConfigValue_IsFirstLoad: case HorizonOCConfigValue_EnableExperimentalSettings: + case HorizonOCConfigValue_LiveCpuUv: return (input & 0x1) == input; case KipConfigValue_custRev: diff --git a/Source/sys-clk/overlay/src/ui/gui/misc_gui.cpp b/Source/sys-clk/overlay/src/ui/gui/misc_gui.cpp index 7148ef84..67466b82 100644 --- a/Source/sys-clk/overlay/src/ui/gui/misc_gui.cpp +++ b/Source/sys-clk/overlay/src/ui/gui/misc_gui.cpp @@ -409,7 +409,8 @@ void MiscGui::listUI() // }; if(this->configList->values[HorizonOCConfigValue_EnableExperimentalSettings]) { this->listElement->addItem(new tsl::elm::CategoryHeader("Experimental")); - + + addConfigToggle(HorizonOCConfigValue_LiveCpuUv, nullptr); std::vector gpuSchedValues = { NamedValue("Do not override", GpuSchedulingMode_DoNotOverride), NamedValue("Enabled", GpuSchedulingMode_Enabled, "96.5% limit"), diff --git a/Source/sys-clk/sysmodule/perms.json b/Source/sys-clk/sysmodule/perms.json index c4eb76b9..5b705463 100644 --- a/Source/sys-clk/sysmodule/perms.json +++ b/Source/sys-clk/sysmodule/perms.json @@ -57,6 +57,15 @@ "is_io": true } }, + { + "type": "map", + "value": { + "address": "0x70110000", + "size": "0x1000", + "is_ro": false, + "is_io": true + } + }, { "type": "syscalls", "value": { diff --git a/Source/sys-clk/sysmodule/src/board.cpp b/Source/sys-clk/sysmodule/src/board.cpp index 57e7a1cc..4cc7fe45 100644 --- a/Source/sys-clk/sysmodule/src/board.cpp +++ b/Source/sys-clk/sysmodule/src/board.cpp @@ -105,6 +105,8 @@ u16 cpuSpeedo0, cpuSpeedo2, socSpeedo0; // CPU, GPU, SOC u32 speedoBracket; u16 cpuIDDQ, gpuIDDQ, socIDDQ; u8 g_dramID = 0; +u64 cldvfs, cldvfs_temp; +u32 cachedEristaUvLowTune0 = 0, cachedEristaUvLowTune1 = 0, cachedMarikoUvHighTune0 = 0; static const u32 ramBrackets[][22] = { { 2133, 2200, 2266, 2300, 2366, 2400, 2433, 2466, 2533, 2566, 2600, 2633, 2700, 2733, 2766, 2833, 2866, 2900, 2933, 3033, 3066, 3100, }, @@ -290,6 +292,16 @@ void Board::Initialize() } FetchHardwareInfos(); + rc = svcQueryMemoryMapping(&cldvfs, &cldvfs_temp, CLDVFS_REGION_BASE, CLDVFS_REGION_SIZE); + ASSERT_RESULT_OK(rc, "svcQueryMemoryMapping (cldvfs)"); + if(Board::GetSocType() == SysClkSocType_Erista) { + cachedEristaUvLowTune0 = *(u32*)(cldvfs + CL_DVFS_TUNE0_0); + cachedEristaUvLowTune1 = *(u32*)(cldvfs + CL_DVFS_TUNE1_0); + } else { + Board::SetHz(SysClkModule_CPU, 1785000000); + cachedMarikoUvHighTune0 = *(u32*)(cldvfs + CL_DVFS_TUNE0_0); + Board::ResetToStockCpu(); + } } void Board::fuseReadSpeedos() { @@ -1134,9 +1146,6 @@ void Board::PcvHijackDvfs(u32 vmin) { FileUtils::LogLine("[dvfs] voltage set to %u mV", vmin); } -#define MC_REGISTER_BASE 0x70019000 -#define MC_REGISTER_REGION_SIZE 0x1000 - bool Board::IsDram8GB() { SecmonArgs args = {}; args.X[0] = 0xF0000002; @@ -1173,4 +1182,125 @@ void Board::SetDisplayRefreshDockedState(bool docked) { if(Board::GetConsoleType() != HorizonOCConsoleType_Hoag) { DisplayRefresh_SetDockedState(docked); } +} + + +typedef struct EristaCpuUvEntry { + u32 tune0; + u32 tune1; +} EristaCpuUvEntry; +typedef struct MarikoCpuUvEntry { + u32 tune0_low; + u32 tune0_high; + u32 tune1_low; + u32 tune1_high; +} MarikoCpuUvEntry; + +EristaCpuUvEntry eristaCpuUvTable[5] = { + {0xffff, 0x27007ff}, + {0xefff, 0x27407ff}, + {0xdfff, 0x27807ff}, + {0xdfdf, 0x27a07ff}, + {0xcfdf, 0x37007ff}, +}; + +MarikoCpuUvEntry marikoCpuUvLow[12] = { + {0xffa0, 0xffff, 0x21107ff, 0}, + {0x0, 0xffdf, 0x21107ff, 0x27207ff}, + {0xffdf, 0xffdf, 0x21107ff, 0x27307ff}, + {0xffff, 0xffdf, 0x21107ff, 0x27407ff}, + {0x0, 0xffdf, 0x21607ff, 0x27707ff}, + {0x0, 0xffdf, 0x21607ff, 0x27807ff}, + {0x0, 0xdfff, 0x21607ff, 0x27b07ff}, + {0xdfff, 0xdfff, 0x21707ff, 0x27b07ff}, + {0xdfff, 0xdfff, 0x21707ff, 0x27c07ff}, + {0xdfff, 0xdfff, 0x21707ff, 0x27d07ff}, + {0xdfff, 0xdfff, 0x21707ff, 0x27e07ff}, + {0xdfff, 0xdfff, 0x21707ff, 0x27f07ff}, +}; + +MarikoCpuUvEntry marikoCpuUvHigh[12] = { + {0x0, 0xffff, 0, 0}, + {0x0, 0xffdf, 0, 0x27207ff}, + {0x0, 0xffdf, 0, 0x27307ff}, + {0x0, 0xffdf, 0, 0x27407ff}, + {0x0, 0xffdf, 0, 0x27707ff}, + {0x0, 0xffdf, 0, 0x27807ff}, + {0x0, 0xdfff, 0, 0x27b07ff}, + {0x0, 0xdfff, 0, 0x27c07ff}, + {0x0, 0xdfff, 0, 0x27d07ff}, + {0x0, 0xdfff, 0, 0x27e07ff}, + {0x0, 0xdfff, 0, 0x27f07ff}, + {0x0, 0xdfff, 0, 0x27f07ff}, +}; +void Board::SetCpuUvLevel(u32 levelLow, u32 levelHigh, u32 tbreakPoint) { + + u32* tune0_ptr = (u32*)(cldvfs + CL_DVFS_TUNE0_0); + u32* tune1_ptr = (u32*)(cldvfs + CL_DVFS_TUNE1_0); + if(Board::GetSocType() == SysClkSocType_Mariko) { + if(Board::GetHz(SysClkModule_CPU) < tbreakPoint && (levelLow || levelHigh)) { + if(levelLow) { + *tune0_ptr = marikoCpuUvLow[levelLow-1].tune0_low; + *tune1_ptr = marikoCpuUvLow[levelLow-1].tune1_low; + } + return; + } else { + if(levelLow) { + *tune0_ptr = marikoCpuUvLow[levelLow-1].tune0_low; + *tune1_ptr = marikoCpuUvLow[levelLow-1].tune1_low; + } + if(levelHigh) { + *tune0_ptr = marikoCpuUvHigh[levelHigh-1].tune0_high; + *tune1_ptr = marikoCpuUvHigh[levelHigh-1].tune1_high; + } + return; + } + if(Board::GetHz(SysClkModule_CPU) < tbreakPoint || (!levelLow)) { // account for tbreak + *tune0_ptr = 0xCFFF; + *tune1_ptr = 0xFF072201; + return; + } else if (Board::GetHz(SysClkModule_CPU) >= tbreakPoint || (!levelHigh)) { + *tune0_ptr = cachedMarikoUvHighTune0; // per console? + *tune1_ptr = 0xFFF7FF3F; + return; + } + } else { + if(Board::GetHz(SysClkModule_CPU) < tbreakPoint || (!levelLow)) { // account for tbreak + *tune0_ptr = cachedEristaUvLowTune0; // I think each erista has a different tune0/tune1? + *tune1_ptr = cachedEristaUvLowTune1; + return; + } else { + if(levelLow) { + *tune0_ptr = eristaCpuUvTable[levelLow-1].tune0; + *tune1_ptr = eristaCpuUvTable[levelLow-1].tune1; + } else { + *tune0_ptr = 0x0; + *tune1_ptr = 0x0; + } + } + } +} +/* +enum TableConfig: u32 { + DEFAULT_TABLE = 1, + TBREAK_1581 = 2, + TBREAK_1683 = 3, + EXTREME_TABLE = 4, +}; +*/ +u32 Board::CalculateTbreak(u32 table) { + if(Board::GetSocType() == SysClkSocType_Erista) + return 1581000000; + else { + switch(table) { + case 1 ... 2: + case 4: + return 1581000000; + case 3: + return 1683000000; + default: + return 1581000000; + } + } + } \ No newline at end of file diff --git a/Source/sys-clk/sysmodule/src/board.h b/Source/sys-clk/sysmodule/src/board.h index f8c040a3..4b7a28c3 100644 --- a/Source/sys-clk/sysmodule/src/board.h +++ b/Source/sys-clk/sysmodule/src/board.h @@ -66,6 +66,8 @@ class Board static bool IsDram8GB(); static void SetGpuSchedulingMode(GpuSchedulingMode mode); static void SetDisplayRefreshDockedState(bool docked); + static void SetCpuUvLevel(u32 levelLow, u32 levelHigh, u32 tbreakPoint); + static u32 CalculateTbreak(u32 table); protected: static void FetchHardwareInfos(); static PcvModule GetPcvModule(SysClkModule sysclkModule); diff --git a/Source/sys-clk/sysmodule/src/clock_manager.cpp b/Source/sys-clk/sysmodule/src/clock_manager.cpp index cf5e4c89..d9be4b5a 100644 --- a/Source/sys-clk/sysmodule/src/clock_manager.cpp +++ b/Source/sys-clk/sysmodule/src/clock_manager.cpp @@ -550,9 +550,15 @@ void ClockManager::Tick() this->context->voltages[HocClkVoltage_GPU] = vmin * 1000; } - Board::SetHz((SysClkModule)module, nearestHz); this->context->freqs[module] = nearestHz; + if(module == SysClkModule_CPU && this->config->GetConfigValue(HorizonOCConfigValue_LiveCpuUv)) + { + if(Board::GetSocType() == SysClkSocType_Erista) + Board::SetCpuUvLevel(this->config->GetConfigValue(KipConfigValue_eristaCpuUV), 0, 1581000000); + else + Board::SetCpuUvLevel(this->config->GetConfigValue(KipConfigValue_marikoCpuUVLow), this->config->GetConfigValue(KipConfigValue_marikoCpuUVHigh), Board::CalculateTbreak(this->config->GetConfigValue(KipConfigValue_tableConf))); + } } if(module == SysClkModule_MEM && Board::GetSocType() == SysClkSocType_Mariko && targetHz < oldHz && this->config->GetConfigValue(HorizonOCConfigValue_DVFSMode) == DVFSMode_Hijack) { @@ -583,6 +589,14 @@ void ClockManager::Tick() void ClockManager::ResetToStockClocks() { Board::ResetToStockCpu(); + if(this->config->GetConfigValue(HorizonOCConfigValue_LiveCpuUv)) + { + if(Board::GetSocType() == SysClkSocType_Erista) + Board::SetCpuUvLevel(this->config->GetConfigValue(KipConfigValue_eristaCpuUV), 0, 1581000000); + else + Board::SetCpuUvLevel(this->config->GetConfigValue(KipConfigValue_marikoCpuUVLow), this->config->GetConfigValue(KipConfigValue_marikoCpuUVHigh), Board::CalculateTbreak(this->config->GetConfigValue(KipConfigValue_tableConf))); + } + Board::ResetToStockGpu(); } @@ -656,6 +670,13 @@ bool ClockManager::RefreshContext() case SysClkModule_CPU: if(!(apmExtIsBoostMode(mode) || (this->config->GetConfigValue(HocClkConfigValue_OverwriteBoostMode) && apmExtIsBoostMode(mode)))) Board::ResetToStockCpu(); + if(this->config->GetConfigValue(HorizonOCConfigValue_LiveCpuUv)) { + if(Board::GetSocType() == SysClkSocType_Erista) + Board::SetCpuUvLevel(this->config->GetConfigValue(KipConfigValue_eristaCpuUV), 0, 1581000000); + else + Board::SetCpuUvLevel(this->config->GetConfigValue(KipConfigValue_marikoCpuUVLow), this->config->GetConfigValue(KipConfigValue_marikoCpuUVHigh), Board::CalculateTbreak(this->config->GetConfigValue(KipConfigValue_tableConf))); + } + break; case SysClkModule_GPU: Board::ResetToStockGpu(); diff --git a/dist/atmosphere/contents/00FF0000636C6BFF/exefs.nsp b/dist/atmosphere/contents/00FF0000636C6BFF/exefs.nsp index 95f7a010..cd3813f3 100644 Binary files a/dist/atmosphere/contents/00FF0000636C6BFF/exefs.nsp and b/dist/atmosphere/contents/00FF0000636C6BFF/exefs.nsp differ diff --git a/dist/atmosphere/kips/hoc.kip b/dist/atmosphere/kips/hoc.kip index 08205552..9a9745e8 100644 Binary files a/dist/atmosphere/kips/hoc.kip and b/dist/atmosphere/kips/hoc.kip differ diff --git a/dist/switch/.overlays/Horizon-OC-Monitor.ovl b/dist/switch/.overlays/Horizon-OC-Monitor.ovl index d48cb866..fb0767fb 100644 Binary files a/dist/switch/.overlays/Horizon-OC-Monitor.ovl and b/dist/switch/.overlays/Horizon-OC-Monitor.ovl differ diff --git a/dist/switch/.overlays/horizon-oc-overlay.ovl b/dist/switch/.overlays/horizon-oc-overlay.ovl index cda28f06..ffd93bbf 100644 Binary files a/dist/switch/.overlays/horizon-oc-overlay.ovl and b/dist/switch/.overlays/horizon-oc-overlay.ovl differ