diff --git a/Source/rewrite-hoc-clk/sysmodule/src/board/board.cpp b/Source/rewrite-hoc-clk/sysmodule/src/board/board.cpp index 4cafe2d3..906a6bb8 100644 --- a/Source/rewrite-hoc-clk/sysmodule/src/board/board.cpp +++ b/Source/rewrite-hoc-clk/sysmodule/src/board/board.cpp @@ -33,7 +33,7 @@ #include "board.hpp" #include "board_fuse.hpp" #include "board_load.hpp" -#include "board_ram_oc_dvfs.hpp" +#include "board_volt.hpp" #include "board_misc.hpp" namespace board { @@ -114,7 +114,7 @@ namespace board { ASSERT_RESULT_OK(rc, "pmdmntInitialize"); StartGpuLoad(nvCheck, fd); - /* TODO: Add back fan. */ + StartMiscThread(pwmCheck) batteryInfoInitialize(); @@ -140,17 +140,7 @@ namespace board { DisplayRefresh_Initialize(&cfg); } - // rc = svcQueryMemoryMapping(&cldvfs, &cldvfs_temp, CLDVFS_REGION_BASE, CLDVFS_REGION_SIZE); - // ASSERT_RESULT_OK(rc, "svcQueryMemoryMapping (cldvfs)"); - - // if (socType == SysClkSocType_Erista) { - // cachedEristaUvLowTune0 = *(u32*) (cldvfs + CL_DVFS_TUNE0_0); - // cachedEristaUvLowTune1 = *(u32*) (cldvfs + CL_DVFS_TUNE1_0); - // } else { - // SetHz(SysClkModule_CPU, 1785000000); - // cachedMarikoUvHighTune0 = *(u32*) (cldvfs + CL_DVFS_TUNE0_0); - // ResetToStockCpu(); - // } + CacheDfllData(); } void Exit() { diff --git a/Source/rewrite-hoc-clk/sysmodule/src/board/board_load.cpp b/Source/rewrite-hoc-clk/sysmodule/src/board/board_load.cpp index 73e7cc5f..1c495c04 100644 --- a/Source/rewrite-hoc-clk/sysmodule/src/board/board_load.cpp +++ b/Source/rewrite-hoc-clk/sysmodule/src/board/board_load.cpp @@ -31,6 +31,7 @@ #include #include #include "board_misc.hpp" +#include namespace board { @@ -130,4 +131,47 @@ namespace board { threadClose(&cpuCore2Thread); } + namespace { + constexpr u32 NVschedCtrlEnable = 0x00000601; + constexpr u32 NVschedCtrlDisable = 0x00000602; + } + + void SetGpuSchedulingMode(GpuSchedulingMode mode, GpuSchedulingOverrideMethod method, Result nvCheckSched, u32 fd2) { + if (R_FAILED(nvCheckSched) && method == GpuSchedulingOverrideMethod_NvService) { + return; + } + + u32 temp; + bool enabled = false; + switch (mode) { + case GpuSchedulingMode_DoNotOverride: break; + case GpuSchedulingMode_Disabled: + if (method == GpuSchedulingOverrideMethod_NvService) { + nvIoctl(fd2, NVschedCtrlDisable, &temp); + } else { + enabled = false; + } + break; + case GpuSchedulingMode_Enabled: + if (method == GpuSchedulingOverrideMethod_NvService) { + nvIoctl(fd2, NVschedCtrlEnable, &temp); + } else { + enabled = true; + } + break; + default: + ASSERT_ENUM_VALID(GpuSchedulingMode, mode); + } + + if (method == GpuSchedulingOverrideMethod_Ini) { + constexpr const char *IniPath = "sdmc:/atmosphere/config/system_settings.ini"; + constexpr const char *Section = "am.gpu"; + constexpr const char *Key = "gpu_scheduling_enabled"; + + const char *value = enabled ? "u8!0x1" : "u8!0x0"; + + ini_puts(Section, Key, value, IniPath); + } + } + } diff --git a/Source/rewrite-hoc-clk/sysmodule/src/board/board_load.hpp b/Source/rewrite-hoc-clk/sysmodule/src/board/board_load.hpp index a46fa7b7..6f830738 100644 --- a/Source/rewrite-hoc-clk/sysmodule/src/board/board_load.hpp +++ b/Source/rewrite-hoc-clk/sysmodule/src/board/board_load.hpp @@ -32,5 +32,6 @@ namespace board { void StartLoad(Result nvCheck, u32 fd); void ExitLoad(); u32 GetPartLoad(); + void SetGpuSchedulingMode(GpuSchedulingMode mode, GpuSchedulingOverrideMethod method, Result nvCheckSched, u32 fd2); } diff --git a/Source/rewrite-hoc-clk/sysmodule/src/board/board_power.cpp b/Source/rewrite-hoc-clk/sysmodule/src/board/board_power.cpp deleted file mode 100644 index a0701043..00000000 --- a/Source/rewrite-hoc-clk/sysmodule/src/board/board_power.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) Souldbminer, Lightos_ and Horizon OC Contributors - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -/* -------------------------------------------------------------------------- - * "THE BEER-WARE LICENSE" (Revision 42): - * , , - * wrote this file. As long as you retain this notice you can do whatever you - * want with this stuff. If you meet any of us some day, and you think this - * stuff is worth it, you can buy us a beer in return. - The sys-clk authors - * -------------------------------------------------------------------------- - */ - -#include -#include -#include - -namespace board { - - u32 GetPowerMw(SysClkPowerSensor sensor) { - switch (sensor) { - case SysClkPowerSensor_Now: - return max17050PowerNow(); - case SysClkPowerSensor_Avg: - return max17050PowerAvg(); - default: - ASSERT_ENUM_VALID(SysClkPowerSensor, sensor); - } - - return 0; - } - -} diff --git a/Source/rewrite-hoc-clk/sysmodule/src/board/board_power.hpp b/Source/rewrite-hoc-clk/sysmodule/src/board/board_power.hpp deleted file mode 100644 index 2d0f2616..00000000 --- a/Source/rewrite-hoc-clk/sysmodule/src/board/board_power.hpp +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) Souldbminer, Lightos_ and Horizon OC Contributors - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -/* -------------------------------------------------------------------------- - * "THE BEER-WARE LICENSE" (Revision 42): - * , , - * wrote this file. As long as you retain this notice you can do whatever you - * want with this stuff. If you meet any of us some day, and you think this - * stuff is worth it, you can buy us a beer in return. - The sys-clk authors - * -------------------------------------------------------------------------- - */ - -#pragma once -#include -#include - -namespace board { - - u32 GetPowerMw(SysClkPowerSensor sensor) - -} diff --git a/Source/rewrite-hoc-clk/sysmodule/src/board/board_ram_oc_dvfs.cpp b/Source/rewrite-hoc-clk/sysmodule/src/board/board_ram_oc_dvfs.cpp deleted file mode 100644 index cda16f4b..00000000 --- a/Source/rewrite-hoc-clk/sysmodule/src/board/board_ram_oc_dvfs.cpp +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright (c) Souldbminer, Lightos_ and Horizon OC Contributors - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -/* -------------------------------------------------------------------------- - * "THE BEER-WARE LICENSE" (Revision 42): - * , , - * wrote this file. As long as you retain this notice you can do whatever you - * want with this stuff. If you meet any of us some day, and you think this - * stuff is worth it, you can buy us a beer in return. - The sys-clk authors - * -------------------------------------------------------------------------- - */ - -#include -#include -#include "../file_utils.h" -#include -#include "board_ram_oc_dvfs.hpp" - -namespace board { - - GpuVoltData voltData = {}; - - Handle GetPcvHandle() { - constexpr u64 PcvID = 0x10000000000001a; - u64 processIDList[80]{}; - s32 processCount = 0; - Handle handle = INVALID_HANDLE; - - DebugEventInfo debugEvent{}; - - /* Get all running processes. */ - Result resultGetProcessList = svcGetProcessList(&processCount, processIDList, std::size(processIDList)); - if (R_FAILED(resultGetProcessList)) { - return INVALID_HANDLE; - } - - /* Try to find pcv. */ - for (int i = 0; i < processCount; ++i) { - if (handle != INVALID_HANDLE) { - svcCloseHandle(handle); - handle = INVALID_HANDLE; - } - - /* Try to debug process, if it fails, try next process. */ - Result resultSvcDebugProcess = svcDebugActiveProcess(&handle, processIDList[i]); - if (R_FAILED(resultSvcDebugProcess)) { - continue; - } - - /* Try to get a debug event. */ - Result resultDebugEvent = svcGetDebugEvent(&debugEvent, handle); - if (R_SUCCEEDED(resultDebugEvent)) { - if (debugEvent.info.create_process.program_id == PcvID) { - return handle; - } - } - } - - /* Failed to get handle. */ - return INVALID_HANDLE; - } - - void CacheGpuVoltTable() { - UnkRegulator reg = { - .voltageMinUV = 600000, - .voltageStep = 12500, - .voltageMax = 1400000, - }; - - Handle handle = GetPcvHandle(); - if (handle == INVALID_HANDLE) { - FileUtils::LogLine("[dvfs] Invalid handle!"); - return; - } - - MemoryInfo memoryInfo = {}; - u64 address = 0; - u32 pageInfo = 0; - constexpr u32 PageSize = 0x1000; - u8 buffer[PageSize]; - - /* Loop until failure. */ - while (true) { - /* Find pcv heap. */ - while (true) { - Result resultProcessMemory = svcQueryDebugProcessMemory(&memoryInfo, &pageInfo, handle, address); - address = memoryInfo.addr + memoryInfo.size; - - if (R_FAILED(resultProcessMemory) || !address) { - svcCloseHandle(handle); - FileUtils::LogLine("[dvfs] Failed to get process data. %u", R_DESCRIPTION(resultProcessMemory)); - handle = INVALID_HANDLE; - return; - } - - if (memoryInfo.size && (memoryInfo.perm & 3) == 3 && static_cast(memoryInfo.type) == 0x4) { - /* Found valid memory. */ - break; - } - } - - for (u64 base = 0; base < memoryInfo.size; base += PageSize) { - u32 memorySize = std::min(memoryInfo.size, static_cast(PageSize)); - if (R_FAILED(svcReadDebugProcessMemory(buffer, handle, base + memoryInfo.addr, memorySize))) { - break; - } - - u8 *resultFindReg = static_cast(memmem_impl(buffer, sizeof(buffer), ®, sizeof(reg))); - u32 index = resultFindReg - buffer; - - if (!resultFindReg) { - continue; - } - - /* Assuming mariko. */ - const u32 vmax = 800; - constexpr u32 VoltageTableOffset = 312; - if (!std::memcmp(&buffer[index + VoltageTableOffset], &vmax, sizeof(vmax))) { - std::memcpy(voltData.voltTable, &buffer[index + VoltageTableOffset], sizeof(voltData.voltTable)); - voltData.voltTableAddress = base + memoryInfo.addr + VoltageTableOffset + index; - } - - svcCloseHandle(handle); - handle = INVALID_HANDLE; - return; - } - } - - svcCloseHandle(handle); - handle = INVALID_HANDLE; - return; - } - - void PcvHijackGpuVolts(u32 vmin) { - u32 table[192]; - static_assert(sizeof(table) == sizeof(voltData.voltTable)); - std::memcpy(table, voltData.voltTable, sizeof(voltData.voltTable)); - - if (voltData.ramVmin == vmin) { - return; - } - - for (u32 i = 0; i < std::size(table); ++i) { - if (table[i] && table[i] <= vmin) { - table[i] = vmin; - } - } - - Handle handle = GetPcvHandle(); - if (handle == INVALID_HANDLE) { - FileUtils::LogLine("Invalid handle!"); - return; - } - - Result rc = svcWriteDebugProcessMemory(handle, table, voltData.dvfsAddress, sizeof(table)); - - if (R_SUCCEEDED(rc)) { - voltData.ramVmin = vmin; - } - - svcCloseHandle(handle); - FileUtils::LogLine("[dvfs] voltage set to %u mV", vmin); - } - - u32 GetMinimumVmin(u32 freqMhz, u32 bracket) { - static const u32 ramTable[][22] = { - { 2133, 2200, 2266, 2300, 2366, 2400, 2433, 2466, 2533, 2566, 2600, 2633, 2700, 2733, 2766, 2833, 2866, 2900, 2933, 3033, 3066, 3100, }, - { 2300, 2366, 2433, 2466, 2533, 2566, 2633, 2700, 2733, 2800, 2833, 2900, 2933, 2966, 3033, 3066, 3100, 3133, 3166, 3200, 3233, 3266, }, - { 2433, 2466, 2533, 2600, 2666, 2733, 2766, 2800, 2833, 2866, 2933, 2966, 3033, 3066, 3100, 3133, 3166, 3200, 3233, 3300, 3333, 3366, }, - { 2500, 2533, 2600, 2633, 2666, 2733, 2800, 2866, 2900, 2966, 3033, 3100, 3166, 3200, 3233, 3266, 3300, 3333, 3366, 3400, 3400, 3400, }, - }; - - static const u32 gpuVoltArray[] = { 590, 600, 610, 620, 630, 640, 650, 660, 670, 680, 690, 700, 710, 720, 730, 740, 750, 760, 770, 780, 790, 800, }; - - if (freqMhz <= 1600) { - return 0; - } - - for (u32 i = 0; std::size(gpuDvfsArray) < 22; ++i) { - if (freqMhz <= ramTable[bracket][i]) { - return gpuVoltArray[i]; - } - } - - return gpuVoltArray[std::size(gpuVoltArray) - 1]; - } - -} diff --git a/Source/rewrite-hoc-clk/sysmodule/src/board/board_ram_oc_dvfs.hpp b/Source/rewrite-hoc-clk/sysmodule/src/board/board_ram_oc_dvfs.hpp deleted file mode 100644 index d61a4b5b..00000000 --- a/Source/rewrite-hoc-clk/sysmodule/src/board/board_ram_oc_dvfs.hpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) Souldbminer, Lightos_ and Horizon OC Contributors - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -/* -------------------------------------------------------------------------- - * "THE BEER-WARE LICENSE" (Revision 42): - * , , - * wrote this file. As long as you retain this notice you can do whatever you - * want with this stuff. If you meet any of us some day, and you think this - * stuff is worth it, you can buy us a beer in return. - The sys-clk authors - * -------------------------------------------------------------------------- - */ - -#pragma once -#include - -namespace board { - - struct GpuVoltData { - u32 voltTable[6][32] = {}; - u64 voltTableAddress; - u32 ramVmin; - }; - - /* TODO: Find out what component this actually targets. */ - struct UnkRegulator { - u32 voltageMinUV; - u32 voltageStep; - u32 voltageMax; - } - - void CacheGpuVoltTable(); - void PcvHijackGpuVolts(u32 vmin); - u32 GetMinimumVmin(u32 freqMhz, u32 bracket); - -} diff --git a/Source/rewrite-hoc-clk/sysmodule/src/board/board_temp.cpp b/Source/rewrite-hoc-clk/sysmodule/src/board/board_sensor.cpp similarity index 86% rename from Source/rewrite-hoc-clk/sysmodule/src/board/board_temp.cpp rename to Source/rewrite-hoc-clk/sysmodule/src/board/board_sensor.cpp index d102241a..955a1b38 100644 --- a/Source/rewrite-hoc-clk/sysmodule/src/board/board_temp.cpp +++ b/Source/rewrite-hoc-clk/sysmodule/src/board/board_sensor.cpp @@ -58,4 +58,17 @@ namespace board { return std::max(0, millis); } + u32 GetPowerMw(SysClkPowerSensor sensor) { + switch (sensor) { + case SysClkPowerSensor_Now: + return max17050PowerNow(); + case SysClkPowerSensor_Avg: + return max17050PowerAvg(); + default: + ASSERT_ENUM_VALID(SysClkPowerSensor, sensor); + } + + return 0; + } + } diff --git a/Source/rewrite-hoc-clk/sysmodule/src/board/board_temp.hpp b/Source/rewrite-hoc-clk/sysmodule/src/board/board_sensor.hpp similarity index 96% rename from Source/rewrite-hoc-clk/sysmodule/src/board/board_temp.hpp rename to Source/rewrite-hoc-clk/sysmodule/src/board/board_sensor.hpp index 71b02d3d..ec95e1ac 100644 --- a/Source/rewrite-hoc-clk/sysmodule/src/board/board_temp.hpp +++ b/Source/rewrite-hoc-clk/sysmodule/src/board/board_sensor.hpp @@ -31,5 +31,6 @@ namespace board { u32 GetTemperatureMilli(SysClkThermalSensor sensor); + u32 GetPowerMw(SysClkPowerSensor sensor); } diff --git a/Source/rewrite-hoc-clk/sysmodule/src/board/board_volt.cpp b/Source/rewrite-hoc-clk/sysmodule/src/board/board_volt.cpp index 8be8b891..d1c8b886 100644 --- a/Source/rewrite-hoc-clk/sysmodule/src/board/board_volt.cpp +++ b/Source/rewrite-hoc-clk/sysmodule/src/board/board_volt.cpp @@ -26,10 +26,160 @@ #include #include +#include +#include +#include #include "board.hpp" +#include "board_freq.hpp" +#include "board_volt.hpp" +#include "../file_utils.h" namespace board { + GpuVoltData voltData = {}; + u64 cldvfs; + CpuDfllData cachedTune; + + /* ... This really needs some cleanup... */ + namespace { + struct EristaCpuUvEntry { + u32 tune0; + u32 tune1; + } EristaCpuUvEntry; + + 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 CacheDfllData() { + u64 temp; + rc = svcQueryMemoryMapping(&cldvfs, &temp, CLDVFS_REGION_BASE, CLDVFS_REGION_SIZE); + ASSERT_RESULT_OK(rc, "svcQueryMemoryMapping (cldvfs)"); + + if (GetSocType() == SysClkSocType_Erista) { + cachedTune.tune0Low = *static_cast(cldvfs + CL_DVFS_TUNE0_0); + cachedTune.tune1Low = *static_cast(cldvfs + CL_DVFS_TUNE1_0); + } else { + SetHz(SysClkModule_CPU, 1785000000); + cachedTune.tune0High = *static_cast(cldvfs + CL_DVFS_TUNE0_0); + ResetToStockCpu(); + } + } + + /* TODO: clean up this code. */ + void SetDfllTunings(u32 levelLow, u32 levelHigh, u32 tbreakPoint) { + u32* tune0_ptr = static_cast(cldvfs + CL_DVFS_TUNE0_0); + u32* tune1_ptr = static_cast(cldvfs + CL_DVFS_TUNE1_0); + if (GetSocType() == SysClkSocType_Mariko) { + if (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 (GetHz(SysClkModule_CPU) < tbreakPoint || (!levelLow)) { // account for tbreak + *tune0_ptr = 0xCFFF; + *tune1_ptr = 0xFF072201; + return; + } else if (GetHz(SysClkModule_CPU) >= tbreakPoint || (!levelHigh)) { + *tune0_ptr = cachedTune.tune0High; // per console? + *tune1_ptr = 0xFFF7FF3F; + return; + } + } else { + if (GetHz(SysClkModule_CPU) < tbreakPoint || (!levelLow)) { // account for tbreak + *tune0_ptr = cachedTune.tune0Low; // I think each erista has a different tune0/tune1? + *tune1_ptr = cachedTune.tune1Low; + 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 CalculateTbreak(u32 table) { + if (GetSocType() == SysClkSocType_Erista) { + return 1581000000; + } else { + switch (table) { + case 1 ... 2: + case 4: + return 1581000000; + case 3: + return 1683000000; + default: + return 1581000000; + } + } + } + /* * Switch Power domains (max77620): * Name | Usage | uV step | uV min | uV default | uV max | Init @@ -135,4 +285,169 @@ namespace board { return out > 0 ? out : 0; } + Handle GetPcvHandle() { + constexpr u64 PcvID = 0x10000000000001a; + u64 processIDList[80]{}; + s32 processCount = 0; + Handle handle = INVALID_HANDLE; + + DebugEventInfo debugEvent{}; + + /* Get all running processes. */ + Result resultGetProcessList = svcGetProcessList(&processCount, processIDList, std::size(processIDList)); + if (R_FAILED(resultGetProcessList)) { + return INVALID_HANDLE; + } + + /* Try to find pcv. */ + for (int i = 0; i < processCount; ++i) { + if (handle != INVALID_HANDLE) { + svcCloseHandle(handle); + handle = INVALID_HANDLE; + } + + /* Try to debug process, if it fails, try next process. */ + Result resultSvcDebugProcess = svcDebugActiveProcess(&handle, processIDList[i]); + if (R_FAILED(resultSvcDebugProcess)) { + continue; + } + + /* Try to get a debug event. */ + Result resultDebugEvent = svcGetDebugEvent(&debugEvent, handle); + if (R_SUCCEEDED(resultDebugEvent)) { + if (debugEvent.info.create_process.program_id == PcvID) { + return handle; + } + } + } + + /* Failed to get handle. */ + return INVALID_HANDLE; + } + + void CacheGpuVoltTable() { + UnkRegulator reg = { + .voltageMinUV = 600000, + .voltageStep = 12500, + .voltageMax = 1400000, + }; + + Handle handle = GetPcvHandle(); + if (handle == INVALID_HANDLE) { + FileUtils::LogLine("[dvfs] Invalid handle!"); + return; + } + + MemoryInfo memoryInfo = {}; + u64 address = 0; + u32 pageInfo = 0; + constexpr u32 PageSize = 0x1000; + u8 buffer[PageSize]; + + /* Loop until failure. */ + while (true) { + /* Find pcv heap. */ + while (true) { + Result resultProcessMemory = svcQueryDebugProcessMemory(&memoryInfo, &pageInfo, handle, address); + address = memoryInfo.addr + memoryInfo.size; + + if (R_FAILED(resultProcessMemory) || !address) { + svcCloseHandle(handle); + FileUtils::LogLine("[dvfs] Failed to get process data. %u", R_DESCRIPTION(resultProcessMemory)); + handle = INVALID_HANDLE; + return; + } + + if (memoryInfo.size && (memoryInfo.perm & 3) == 3 && static_cast(memoryInfo.type) == 0x4) { + /* Found valid memory. */ + break; + } + } + + for (u64 base = 0; base < memoryInfo.size; base += PageSize) { + u32 memorySize = std::min(memoryInfo.size, static_cast(PageSize)); + if (R_FAILED(svcReadDebugProcessMemory(buffer, handle, base + memoryInfo.addr, memorySize))) { + break; + } + + u8 *resultFindReg = static_cast(memmem_impl(buffer, sizeof(buffer), ®, sizeof(reg))); + u32 index = resultFindReg - buffer; + + if (!resultFindReg) { + continue; + } + + /* Assuming mariko. */ + const u32 vmax = 800; + constexpr u32 VoltageTableOffset = 312; + if (!std::memcmp(&buffer[index + VoltageTableOffset], &vmax, sizeof(vmax))) { + std::memcpy(voltData.voltTable, &buffer[index + VoltageTableOffset], sizeof(voltData.voltTable)); + voltData.voltTableAddress = base + memoryInfo.addr + VoltageTableOffset + index; + } + + svcCloseHandle(handle); + handle = INVALID_HANDLE; + return; + } + } + + svcCloseHandle(handle); + handle = INVALID_HANDLE; + return; + } + + void PcvHijackGpuVolts(u32 vmin) { + u32 table[192]; + static_assert(sizeof(table) == sizeof(voltData.voltTable), "Invalid gpu voltage table size!"); + std::memcpy(table, voltData.voltTable, sizeof(voltData.voltTable)); + + if (voltData.ramVmin == vmin) { + return; + } + + for (u32 i = 0; i < std::size(table); ++i) { + if (table[i] && table[i] <= vmin) { + table[i] = vmin; + } + } + + Handle handle = GetPcvHandle(); + if (handle == INVALID_HANDLE) { + FileUtils::LogLine("Invalid handle!"); + return; + } + + Result rc = svcWriteDebugProcessMemory(handle, table, voltData.dvfsAddress, sizeof(table)); + + if (R_SUCCEEDED(rc)) { + voltData.ramVmin = vmin; + } + + svcCloseHandle(handle); + FileUtils::LogLine("[dvfs] voltage set to %u mV", vmin); + } + + u32 GetMinimumGpuVmin(u32 freqMhz, u32 bracket) { + static const u32 ramTable[][22] = { + { 2133, 2200, 2266, 2300, 2366, 2400, 2433, 2466, 2533, 2566, 2600, 2633, 2700, 2733, 2766, 2833, 2866, 2900, 2933, 3033, 3066, 3100, }, + { 2300, 2366, 2433, 2466, 2533, 2566, 2633, 2700, 2733, 2800, 2833, 2900, 2933, 2966, 3033, 3066, 3100, 3133, 3166, 3200, 3233, 3266, }, + { 2433, 2466, 2533, 2600, 2666, 2733, 2766, 2800, 2833, 2866, 2933, 2966, 3033, 3066, 3100, 3133, 3166, 3200, 3233, 3300, 3333, 3366, }, + { 2500, 2533, 2600, 2633, 2666, 2733, 2800, 2866, 2900, 2966, 3033, 3100, 3166, 3200, 3233, 3266, 3300, 3333, 3366, 3400, 3400, 3400, }, + }; + + static const u32 gpuVoltArray[] = { 590, 600, 610, 620, 630, 640, 650, 660, 670, 680, 690, 700, 710, 720, 730, 740, 750, 760, 770, 780, 790, 800, }; + + if (freqMhz <= 1600) { + return 0; + } + + for (u32 i = 0; i < std::size(gpuDvfsArray); ++i) { + if (freqMhz <= ramTable[bracket][i]) { + return gpuVoltArray[i]; + } + } + + return gpuVoltArray[std::size(gpuVoltArray) - 1]; + } + } diff --git a/Source/rewrite-hoc-clk/sysmodule/src/board/board_volt.hpp b/Source/rewrite-hoc-clk/sysmodule/src/board/board_volt.hpp index 64e9872b..9bed0117 100644 --- a/Source/rewrite-hoc-clk/sysmodule/src/board/board_volt.hpp +++ b/Source/rewrite-hoc-clk/sysmodule/src/board/board_volt.hpp @@ -30,6 +30,34 @@ namespace board { + struct GpuVoltData { + u32 voltTable[6][32] = {}; + u64 voltTableAddress; + u32 ramVmin; + }; + + /* TODO: Find out what component this actually targets. */ + struct UnkRegulator { + u32 voltageMinUV; + u32 voltageStep; + u32 voltageMax; + }; + + struct CpuDfllData { + u32 tune0Low; + u32 tune0High; + u32 tune1Low; + u32 tune1High; + // u32 tune_high_min_millivolts; + // u32 tune_high_margin_millivolts; + // u64 dvco_calibration_max; + }; + + void CacheDfllData(); + u32 CalculateTbreak(); u32 GetVoltage(HocClkVoltage voltage); + void CacheGpuVoltTable(); + void PcvHijackGpuVolts(u32 vmin); + u32 GetMinimumGpuVmin(u32 freqMhz, u32 bracket); } diff --git a/Source/sys-clk/sysmodule/src/clock_manager.cpp b/Source/sys-clk/sysmodule/src/clock_manager.cpp index dd87e036..9386ba51 100644 --- a/Source/sys-clk/sysmodule/src/clock_manager.cpp +++ b/Source/sys-clk/sysmodule/src/clock_manager.cpp @@ -566,7 +566,7 @@ void ClockManager::VRRThread(void* arg) { if(++tick > 50) { Board::SetHz(HorizonOCModule_Display, maxDisplay); tick = 0; - svcSleepThread(25'000'000); + svcSleepThread(50'000'000); } svcSleepThread(POLL_NS);