add gpu voltage request
This commit is contained in:
@@ -12,9 +12,9 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "THE BEER-WARE LICENSE" (Revision 42):
|
||||
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
|
||||
@@ -50,6 +50,7 @@ Result hocclkIpcSetConfigValues(HocClkConfigValueList* configValues);
|
||||
Result hocclkIpcGetFreqList(HocClkModule module, u32* list, u32 maxCount, u32* outCount);
|
||||
Result hocClkIpcSetKipData();
|
||||
Result hocClkIpcGetKipData();
|
||||
Result hocClkIpcRequestGpuVoltage(u32 voltage);
|
||||
|
||||
static inline Result hocclkIpcRemoveOverride(HocClkModule module)
|
||||
{
|
||||
|
||||
@@ -70,6 +70,7 @@ typedef enum {
|
||||
|
||||
HocClkConfigValue_AulaDisplayColorPreset,
|
||||
HocClkConfigValue_MarikoMiddleFreqs,
|
||||
HocClkConfigValue_LiveGpuVoltage,
|
||||
|
||||
HocClkConfigValue_AutoRAMCPUOverclock,
|
||||
HocClkConfigValue_AutoRamCpuCpuOCFreq,
|
||||
@@ -315,6 +316,9 @@ static inline const char* hocclkFormatConfigValue(HocClkConfigValue val, bool pr
|
||||
case HocClkConfigValue_MarikoMiddleFreqs:
|
||||
return pretty ? "Mariko Middle Clocks" : "mariko_middle_freqs";
|
||||
|
||||
case HocClkConfigValue_LiveGpuVoltage:
|
||||
return pretty ? "GPU Voltage Request" : "gpu_voltage_request";
|
||||
|
||||
case HocClkConfigValue_AutoRAMCPUOverclock:
|
||||
return pretty ? "Auto High RAM CPU OC" : "auto_high_ram_cpu_oc";
|
||||
case HocClkConfigValue_AutoRamCpuCpuOCFreq:
|
||||
@@ -568,6 +572,7 @@ static inline uint64_t hocclkDefaultConfigValue(HocClkConfigValue val)
|
||||
case HocClkConfigValue_GPUSchedulingMethod:
|
||||
case HocClkConfigValue_MemoryFrequencyMeasurementMode:
|
||||
case HocClkConfigValue_MarikoMiddleFreqs:
|
||||
case HocClkConfigValue_LiveGpuVoltage:
|
||||
return 0ULL;
|
||||
case HocClkConfigValue_RamDisplayUnit:
|
||||
return (uint64_t)RamDisplayUnit_MHz;
|
||||
@@ -625,6 +630,7 @@ static inline uint64_t hocclkValidConfigValue(HocClkConfigValue val, uint64_t in
|
||||
case HocClkConfigValue_LiveCpuUv:
|
||||
case HocClkConfigValue_GPUSchedulingMethod:
|
||||
case HocClkConfigValue_MarikoMiddleFreqs:
|
||||
case HocClkConfigValue_LiveGpuVoltage:
|
||||
case HocClkConfigValue_AutoRAMCPUOverclock:
|
||||
return (input & 0x1) == input;
|
||||
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "THE BEER-WARE LICENSE" (Revision 42):
|
||||
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
|
||||
@@ -50,9 +50,9 @@ enum HocClkIpcCmd
|
||||
HocClkIpcCmd_GetFreqList = 11,
|
||||
HocClkIpcCmd_SetKipData = 12,
|
||||
HocClkIpcCmd_GetKipData = 13,
|
||||
HocClkIpcCmd_RequestGpuVoltage = 14,
|
||||
};
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint64_t tid;
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "THE BEER-WARE LICENSE" (Revision 42):
|
||||
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
|
||||
@@ -166,4 +166,8 @@ Result hocClkIpcGetKipData()
|
||||
{
|
||||
u32 temp = 0;
|
||||
return serviceDispatchIn(&g_hocclkSrv, HocClkIpcCmd_GetKipData, temp);
|
||||
}
|
||||
}
|
||||
|
||||
Result hocClkIpcRequestGpuVoltage(u32 voltage) {
|
||||
return serviceDispatchIn(&g_hocclkSrv, HocClkIpcCmd_RequestGpuVoltage, voltage);
|
||||
}
|
||||
|
||||
@@ -542,6 +542,15 @@ std::vector<std::string> ConfigInfoStrings(HocClkConfigValue val, bool isMariko,
|
||||
"- Enabled: Enables GPU scheduling, 96.5% GPU max load",
|
||||
"Default: Do not override"
|
||||
};
|
||||
case HocClkConfigValue_LiveGpuVoltage:
|
||||
return {
|
||||
"Adjust GPU voltage on the fly.",
|
||||
"Warning: unstable settings allowed.",
|
||||
"Exception: while RAM OC is active, voltage cannot drop below stability minimum.",
|
||||
"RAM frequency changes overwrite requested voltage.",
|
||||
"Voltage applies globally across all frequencies.",
|
||||
"\"Reset\" restores default or RAM-stable minimum."
|
||||
};
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -662,6 +662,9 @@ class ExperimentalSettingsSubMenuGui : public MiscGui {
|
||||
addConfigToggle(HocClkConfigValue_MarikoMiddleFreqs, nullptr, true);
|
||||
addConfigToggle(HocClkConfigValue_LiveCpuUv, nullptr);
|
||||
}
|
||||
|
||||
addConfigToggle(HocClkConfigValue_LiveGpuVoltage, "Live GPU Volt Request", false);
|
||||
|
||||
std::vector<NamedValue> gpuSchedMethodValues = {
|
||||
NamedValue("INI", GpuSchedulingOverrideMethod_Ini),
|
||||
NamedValue("NV Service", GpuSchedulingOverrideMethod_NvService),
|
||||
@@ -2126,6 +2129,41 @@ class GpuSubmenuGui : public MiscGui {
|
||||
addConfigButton(HocClkConfigValue_DVFSOffset, "GPU DVFS Offset", ValueRange(0, 12, 1, "", 0), "GPU DVFS Offset", &thresholdsDisabled, {},
|
||||
dvfsOffset, false);
|
||||
|
||||
if (this->configList->values[HocClkConfigValue_LiveGpuVoltage]) {
|
||||
std::vector<NamedValue> gpuVoltRequestValues = {
|
||||
NamedValue("Reset", 0),
|
||||
};
|
||||
|
||||
for (u32 mv = IsMariko() ? 420 : 700; mv <= 1050; mv += 5) {
|
||||
gpuVoltRequestValues.push_back(NamedValue(std::to_string(mv) + "mV", mv));
|
||||
}
|
||||
|
||||
tsl::elm::ListItem *gpuVoltRequestBtn = new tsl::elm::ListItem("GPU Volt Request");
|
||||
gpuVoltRequestBtn->setTextColor(tsl::Color(120, 235, 255, 255));
|
||||
gpuVoltRequestBtn->setValue("Request");
|
||||
|
||||
gpuVoltRequestBtn->setClickListener([gpuVoltRequestValues](u64 keys) {
|
||||
if ((keys & HidNpadButton_A) == 0)
|
||||
return false;
|
||||
|
||||
tsl::changeTo<ValueChoiceGui>(
|
||||
0, ValueRange(0, 0, 1, "", 1), "GPU Volt Request",
|
||||
[](u32 value) {
|
||||
Result rc = hocClkIpcRequestGpuVoltage(value);
|
||||
if (R_FAILED(rc)) {
|
||||
FatalGui::openWithResultCode("hocClkIpcRequestGpuVoltage", rc);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
ValueThresholds(), false, std::map<u32, std::string>{}, gpuVoltRequestValues, false, false);
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
this->listElement->addItem(gpuVoltRequestBtn);
|
||||
}
|
||||
|
||||
tsl::elm::ListItem *customTableSubmenu = new tsl::elm::ListItem("GPU Voltage Table");
|
||||
customTableSubmenu->setClickListener([](u64 keys) {
|
||||
if (keys & HidNpadButton_A) {
|
||||
|
||||
@@ -335,9 +335,9 @@ namespace board {
|
||||
}
|
||||
|
||||
/* 800mV on Mariko, 950mV on Erista. */
|
||||
u32 vmax = GetSocType() == HocClkSocType_Mariko ? 800 : 950;
|
||||
u32 bootVoltage = GetSocType() == HocClkSocType_Mariko ? 800 : 950;
|
||||
constexpr u32 GpuVoltageTableOffset = 312;
|
||||
if (!std::memcmp(&buffer[index + GpuVoltageTableOffset], &vmax, sizeof(vmax))) {
|
||||
if (!std::memcmp(&buffer[index + GpuVoltageTableOffset], &bootVoltage, sizeof(bootVoltage))) {
|
||||
std::memcpy(voltData.voltTable, &buffer[index + GpuVoltageTableOffset], sizeof(voltData.voltTable));
|
||||
voltData.voltTableAddress = base + memoryInfo.addr + GpuVoltageTableOffset + index;
|
||||
}
|
||||
@@ -365,18 +365,34 @@ namespace board {
|
||||
return;
|
||||
}
|
||||
|
||||
void PcvHijackGpuVolts(u32 vmin) {
|
||||
void PcvHijackGpuVolts(u32 vmin, bool forceOverwrite) {
|
||||
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) {
|
||||
/* forceOverwrite needs to be handled regardless. */
|
||||
if (voltData.ramVmin == vmin && !forceOverwrite) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < std::size(table); ++i) {
|
||||
if (table[i] && table[i] <= vmin) {
|
||||
table[i] = vmin;
|
||||
/* Skip adjusting table if vmin is zero (voltage reset), unless forced. */
|
||||
if (vmin != 0 || forceOverwrite) {
|
||||
/* Only apply forced voltage override if it's safe to do so. */
|
||||
if (forceOverwrite && vmin < voltData.ramVmin) {
|
||||
vmin = voltData.ramVmin;
|
||||
}
|
||||
|
||||
if (vmin != 0) {
|
||||
for (u32 i = 0; i < std::size(table); ++i) {
|
||||
if (!table[i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const bool raiseVoltageRamOc = table[i] <= vmin && !forceOverwrite;
|
||||
if (raiseVoltageRamOc || forceOverwrite) {
|
||||
table[i] = vmin;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -388,7 +404,7 @@ namespace board {
|
||||
|
||||
Result rc = svcWriteDebugProcessMemory(handle, table, voltData.voltTableAddress, sizeof(table));
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
if (R_SUCCEEDED(rc) && !forceOverwrite) {
|
||||
voltData.ramVmin = vmin;
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace board {
|
||||
u32 CalculateTbreak(u32 table);
|
||||
u32 GetVoltage(HocClkVoltage voltage);
|
||||
void CacheGpuVoltTable();
|
||||
void PcvHijackGpuVolts(u32 vmin);
|
||||
void PcvHijackGpuVolts(u32 vmin, bool forceOverwrite);
|
||||
u32 GetMinimumGpuVmin(u32 freqMhz, u32 bracket);
|
||||
|
||||
} // namespace board
|
||||
|
||||
@@ -235,6 +235,15 @@ namespace ipcService {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case HocClkIpcCmd_RequestGpuVoltage:
|
||||
if (r->data.size >= sizeof(u32)) {
|
||||
u32 voltage;
|
||||
memcpy(&voltage, r->data.ptr, sizeof(u32));
|
||||
clockManager::ApplyGpuVoltageRequest(voltage);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return HOCCLK_ERROR(Generic);
|
||||
|
||||
@@ -332,6 +332,28 @@ namespace clockManager {
|
||||
}
|
||||
}
|
||||
|
||||
u32 ClampGpuVoltage(u32 voltage) {
|
||||
constexpr u32 MaxGpuVoltage = 960;
|
||||
return std::min(voltage, MaxGpuVoltage);
|
||||
}
|
||||
|
||||
u32 GetCurrentNearestGpuFrequency() {
|
||||
u32 gpuHz = board::GetHz(HocClkModule_GPU);
|
||||
u32 maxHz = GetMaxAllowedHz(HocClkModule_GPU, gContext.profile);
|
||||
return GetNearestHz(HocClkModule_GPU, gpuHz, maxHz);
|
||||
}
|
||||
|
||||
void ApplyGpuVoltageRequest(u32 voltage) {
|
||||
fileUtils::LogLine("Unclamped voltage request: %u", voltage);
|
||||
voltage = ClampGpuVoltage(voltage);
|
||||
fileUtils::LogLine("Actual voltage: %u", voltage);
|
||||
|
||||
board::PcvHijackGpuVolts(voltage, true);
|
||||
|
||||
/* Update the voltage using the currently nearest valid gpu frequency. */
|
||||
board::SetHz(HocClkModule_GPU, GetCurrentNearestGpuFrequency());
|
||||
}
|
||||
|
||||
void ApplyGpuDvfs(u32 targetHz) {
|
||||
s32 dvfsOffset = config::GetConfigValue(HocClkConfigValue_DVFSOffset);
|
||||
dvfsOffset = std::max(dvfsOffset, -80);
|
||||
@@ -342,19 +364,14 @@ namespace clockManager {
|
||||
}
|
||||
|
||||
/* Prevent console from combusting if for some reason bad shit happens :P */
|
||||
vmin = std::min(vmin, 1000u);
|
||||
|
||||
/* Get nearest gpu clock; we need this in a second to update the voltage. */
|
||||
u32 gpuHz = board::GetHz(HocClkModule_GPU);
|
||||
u32 maxHz = GetMaxAllowedHz(HocClkModule_GPU, gContext.profile);
|
||||
u32 nearestGpuHz = GetNearestHz(HocClkModule_GPU, gpuHz, maxHz);
|
||||
vmin = ClampGpuVoltage(vmin);
|
||||
|
||||
/* Hijack gpu volt table. */
|
||||
board::PcvHijackGpuVolts(vmin);
|
||||
board::PcvHijackGpuVolts(vmin, false);
|
||||
|
||||
/* Update gpu frequency to actually use the voltage. */
|
||||
if (targetHz) {
|
||||
board::SetHz(HocClkModule_GPU, nearestGpuHz);
|
||||
board::SetHz(HocClkModule_GPU, GetCurrentNearestGpuFrequency());
|
||||
} else {
|
||||
/* If the target frequency is zero, we reset the frequency to ensure it gets updated even without any frequency override. */
|
||||
board::ResetToStockGpu();
|
||||
@@ -363,7 +380,7 @@ namespace clockManager {
|
||||
|
||||
void DVFSReset() {
|
||||
if (config::GetConfigValue(HocClkConfigValue_DVFSMode) == DVFSMode_Hijack) {
|
||||
board::PcvHijackGpuVolts(0); // Reset to vMin
|
||||
board::PcvHijackGpuVolts(0, false); // Reset to vMin
|
||||
|
||||
u32 targetHz = gContext.overrideFreqs[HocClkModule_GPU];
|
||||
if (!targetHz) {
|
||||
@@ -515,6 +532,7 @@ namespace clockManager {
|
||||
if (module == HocClkModule_MEM && targetHz > oldHz && config::GetConfigValue(HocClkConfigValue_DVFSMode) == DVFSMode_Hijack) {
|
||||
ApplyGpuDvfs(targetHz);
|
||||
}
|
||||
|
||||
board::SetHz((HocClkModule)module, nearestHz);
|
||||
gContext.freqs[module] = nearestHz;
|
||||
|
||||
@@ -560,7 +578,7 @@ namespace clockManager {
|
||||
if (hasChanged) {
|
||||
board::ResetToStock();
|
||||
if (config::GetConfigValue(HocClkConfigValue_DVFSMode) == DVFSMode_Hijack) {
|
||||
board::PcvHijackGpuVolts(0);
|
||||
board::PcvHijackGpuVolts(0, false);
|
||||
board::ResetToStockGpu();
|
||||
}
|
||||
WaitForNextTick();
|
||||
|
||||
@@ -63,6 +63,8 @@ namespace clockManager {
|
||||
|
||||
void GetFreqList(HocClkModule module, std::uint32_t *list, std::uint32_t maxCount, std::uint32_t *outCount);
|
||||
|
||||
void ApplyGpuVoltageRequest(u32 voltage);
|
||||
|
||||
void Tick();
|
||||
void WaitForNextTick();
|
||||
} // namespace clockManager
|
||||
|
||||
Reference in New Issue
Block a user