sysclk: add on-the-fly CPU undervolt
This commit is contained in:
@@ -12,9 +12,8 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#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
|
||||
#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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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<NamedValue> gpuSchedValues = {
|
||||
NamedValue("Do not override", GpuSchedulingMode_DoNotOverride),
|
||||
NamedValue("Enabled", GpuSchedulingMode_Enabled, "96.5% limit"),
|
||||
|
||||
@@ -57,6 +57,15 @@
|
||||
"is_io": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "map",
|
||||
"value": {
|
||||
"address": "0x70110000",
|
||||
"size": "0x1000",
|
||||
"is_ro": false,
|
||||
"is_io": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "syscalls",
|
||||
"value": {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
BIN
dist/atmosphere/contents/00FF0000636C6BFF/exefs.nsp
vendored
BIN
dist/atmosphere/contents/00FF0000636C6BFF/exefs.nsp
vendored
Binary file not shown.
BIN
dist/atmosphere/kips/hoc.kip
vendored
BIN
dist/atmosphere/kips/hoc.kip
vendored
Binary file not shown.
BIN
dist/switch/.overlays/Horizon-OC-Monitor.ovl
vendored
BIN
dist/switch/.overlays/Horizon-OC-Monitor.ovl
vendored
Binary file not shown.
BIN
dist/switch/.overlays/horizon-oc-overlay.ovl
vendored
BIN
dist/switch/.overlays/horizon-oc-overlay.ovl
vendored
Binary file not shown.
Reference in New Issue
Block a user