This commit is contained in:
souldbminersmwc
2026-04-03 12:34:17 -04:00
8 changed files with 852 additions and 877 deletions

View File

@@ -34,7 +34,7 @@ volatile CustomizeTable C = {
/* Disables RAM powerdown */ /* Disables RAM powerdown */
.hpMode = DISABLED, .hpMode = DISABLED,
.commonEmcMemVolt = 1175000, /* LPDDR4X JEDEC Specification */ .commonEmcMemVolt = 1175000, /* LPDDR4(X) JEDEC Specification */
.eristaEmcMaxClock = 1600000, /* Maximum HB-MGCH ram rating */ .eristaEmcMaxClock = 1600000, /* Maximum HB-MGCH ram rating */
.eristaEmcMaxClock1 = 1600000, .eristaEmcMaxClock1 = 1600000,
.eristaEmcMaxClock2 = 1600000, .eristaEmcMaxClock2 = 1600000,
@@ -103,10 +103,8 @@ volatile CustomizeTable C = {
.marikoGpuUV = 0, .marikoGpuUV = 0,
/* For automatic vmin detection, set this to AUTO. */ /* Vmin past 795mV won't work due boot voltage being 800mV. */
/* vmin past 795mV won't work due to HOS limitation */ .marikoGpuVmin = 610,
/* Vmin is automatically set to 800mV when SoC temperature is below 20C */
.marikoGpuVmin = AUTO,
.marikoGpuVmax = 800, .marikoGpuVmax = 800,

View File

@@ -90,38 +90,6 @@ namespace ams::ldr::hoc::pcv {
static const u32 gpuVoltThermalPattern[] = { 800, 1120, 0, 610, 1120, 20000, 610, 1120, 30000, 610, 1120, 50000, 610, 1120, 70000, 610, 1120, 90000, }; static const u32 gpuVoltThermalPattern[] = { 800, 1120, 0, 610, 1120, 20000, 610, 1120, 30000, 610, 1120, 50000, 610, 1120, 70000, 610, 1120, 90000, };
static_assert(sizeof(gpuVoltThermalPattern) == 72, "Invalid gpuVoltThermalPattern"); static_assert(sizeof(gpuVoltThermalPattern) == 72, "Invalid gpuVoltThermalPattern");
struct SpeedoVminTable {
u32 speedo;
u32 voltage;
};
struct RamVminOffsetTable {
u32 maxClock;
u32 offset;
};
static const SpeedoVminTable vminTable[] {
{1400, 610}, // LOW SPEEDO -> use stock vmin
{1560, 590},
{1583, 570},
{1620, 565},
{1670, 560},
{1694, 555},
{1731, 550},
{1750, 540},
{0xFFFFFFFF, 530},
};
static const RamVminOffsetTable ramOffset[] {
{2400000, 5},
{2533000, 10},
{2666000, 15},
{2800000, 20},
{2933000, 25},
{3200000, 30},
{0xFFFFFFFF, 35},
};
/* GPU Max Clock asm Pattern: /* GPU Max Clock asm Pattern:
* *
* MOV W11, #0x1000 MOV (wide immediate) 0x1000 0xB (11) * MOV W11, #0x1000 MOV (wide immediate) 0x1000 0xB (11)

View File

@@ -24,46 +24,6 @@
namespace ams::ldr::hoc::pcv::mariko { namespace ams::ldr::hoc::pcv::mariko {
u32 GetGpuVminVoltage() {
for (auto e : vminTable) {
if (C.gpuSpeedo <= e.speedo) {
return e.voltage;
}
}
return 530;
}
u32 GetRamVminAdjustment(u32 vmin) {
if (C.marikoEmcMaxClock < 2133000) {
return vmin;
}
const u32 ramScale = (((C.marikoEmcMaxClock / 1000) - 2133) / 33) * 5 + vmin;
for (auto r : ramOffset) {
if (C.marikoEmcMaxClock < r.maxClock) {
return ramScale + r.offset;
}
}
return ramScale;
}
/* Note: EOS (probably?) has a bug in this function that always results in high vmin, this is fixed here. */
u32 GetAutoVoltage() {
u32 voltage = GetGpuVminVoltage();
voltage = GetRamVminAdjustment(voltage);
u32 voltageOffset = 590 - C.commonGpuVoltOffset;
if (voltageOffset < voltage) {
voltage = voltageOffset;
}
return voltage;
}
Result GpuVoltDVFS(u32 *ptr) { Result GpuVoltDVFS(u32 *ptr) {
/* Check for valid pattern. */ /* Check for valid pattern. */
for (size_t i = 0; i < std::size(gpuDVFSPattern); ++i) { for (size_t i = 0; i < std::size(gpuDVFSPattern); ++i) {
@@ -77,15 +37,10 @@ namespace ams::ldr::hoc::pcv::mariko {
PATCH_OFFSET(ptr + 1, C.marikoGpuVmax); PATCH_OFFSET(ptr + 1, C.marikoGpuVmax);
} }
/* C.marikoGpuVmin is non zero, user sets manual voltage. */
if (C.marikoGpuVmin) { if (C.marikoGpuVmin) {
PATCH_OFFSET(ptr, C.marikoGpuVmin); PATCH_OFFSET(ptr, C.marikoGpuVmin);
R_SUCCEED();
} }
/* C.marikoGpuVmin is zero, auto voltage is applied. */
u32 autoVmin = GetAutoVoltage();
PATCH_OFFSET(ptr, autoVmin);
R_SUCCEED(); R_SUCCEED();
} }
@@ -94,24 +49,15 @@ namespace ams::ldr::hoc::pcv::mariko {
R_THROW(ldr::ResultInvalidGpuDvfs()); R_THROW(ldr::ResultInvalidGpuDvfs());
} }
u32 vmin = C.marikoGpuVmin;
/* Automatic voltage. */
if (!C.marikoGpuVmin) { if (!C.marikoGpuVmin) {
vmin = GetAutoVoltage(); R_SKIP();
PATCH_OFFSET(ptr, vmin);
PATCH_OFFSET(ptr + 3, vmin);
PATCH_OFFSET(ptr + 6, vmin);
PATCH_OFFSET(ptr + 9, vmin);
} else {
/* Manual voltage. */
PATCH_OFFSET(ptr, vmin);
PATCH_OFFSET(ptr + 3, vmin);
PATCH_OFFSET(ptr + 6, vmin);
PATCH_OFFSET(ptr + 9, vmin);
} }
PATCH_OFFSET(ptr + 12, vmin); PATCH_OFFSET(ptr + 0, C.marikoGpuVmin);
PATCH_OFFSET(ptr + 3, C.marikoGpuVmin);
PATCH_OFFSET(ptr + 6, C.marikoGpuVmin);
PATCH_OFFSET(ptr + 9, C.marikoGpuVmin);
PATCH_OFFSET(ptr + 12, C.marikoGpuVmin);
R_SUCCEED(); R_SUCCEED();
} }

View File

@@ -232,6 +232,7 @@ uint8_t refreshRate = 0;
//Read real temps from sys-clk sysmodule //Read real temps from sys-clk sysmodule
int32_t realCPU_Temp = 0; int32_t realCPU_Temp = 0;
int32_t realGPU_Temp = 0; int32_t realGPU_Temp = 0;
u32 realPLLX_Temp = 0;
int32_t realRAM_Temp = 0; int32_t realRAM_Temp = 0;
int compare (const void* elem1, const void* elem2) { int compare (const void* elem1, const void* elem2) {
@@ -585,6 +586,7 @@ void Misc(void*) {
partLoad[HocClkPartLoad_EMCCpu] = hocclkCTX.partLoad[HocClkPartLoad_EMCCpu]; partLoad[HocClkPartLoad_EMCCpu] = hocclkCTX.partLoad[HocClkPartLoad_EMCCpu];
realCPU_Temp = hocclkCTX.temps[HocClkThermalSensor_CPU]; realCPU_Temp = hocclkCTX.temps[HocClkThermalSensor_CPU];
realGPU_Temp = hocclkCTX.temps[HocClkThermalSensor_GPU]; realGPU_Temp = hocclkCTX.temps[HocClkThermalSensor_GPU];
realPLLX_Temp = hocclkCTX.temps[HocClkThermalSensor_PLLX];
realRAM_Temp = hocclkCTX.temps[HocClkThermalSensor_MEM]; realRAM_Temp = hocclkCTX.temps[HocClkThermalSensor_MEM];
realCPU_mV = hocclkCTX.voltages[HocClkVoltage_CPU]; realCPU_mV = hocclkCTX.voltages[HocClkVoltage_CPU];
@@ -719,6 +721,7 @@ void Misc3(void*) {
realCPU_Temp = hocclkCTX.temps[HocClkThermalSensor_CPU]; realCPU_Temp = hocclkCTX.temps[HocClkThermalSensor_CPU];
realGPU_Temp = hocclkCTX.temps[HocClkThermalSensor_GPU]; realGPU_Temp = hocclkCTX.temps[HocClkThermalSensor_GPU];
realPLLX_Temp = hocclkCTX.temps[HocClkThermalSensor_PLLX];
realRAM_Temp = hocclkCTX.temps[HocClkThermalSensor_MEM]; realRAM_Temp = hocclkCTX.temps[HocClkThermalSensor_MEM];
realCPU_mV = hocclkCTX.voltages[HocClkVoltage_CPU]; realCPU_mV = hocclkCTX.voltages[HocClkVoltage_CPU];
@@ -1288,6 +1291,7 @@ struct MiniSettings {
bool realFrequencies; bool realFrequencies;
bool realVolts; bool realVolts;
bool realTemps; bool realTemps;
bool realTempsDec;
bool showFullCPU; bool showFullCPU;
bool showFullResolution; bool showFullResolution;
bool showFanPercentage; bool showFanPercentage;
@@ -1324,6 +1328,7 @@ struct MicroSettings {
bool realFrequencies; bool realFrequencies;
bool realVolts; bool realVolts;
bool realTemps; bool realTemps;
bool realTempsDec;
bool showFullCPU; bool showFullCPU;
bool showFullResolution; bool showFullResolution;
bool showSOCVoltage; bool showSOCVoltage;
@@ -1408,6 +1413,7 @@ ALWAYS_INLINE void GetConfigSettings(MiniSettings* settings) {
settings->realFrequencies = true; settings->realFrequencies = true;
settings->realVolts = true; settings->realVolts = true;
settings->realTemps = true; settings->realTemps = true;
settings->realTempsDec = false;
settings->showFullCPU = false; settings->showFullCPU = false;
settings->showFullResolution = true; settings->showFullResolution = true;
settings->showFanPercentage = true; settings->showFanPercentage = true;
@@ -1491,6 +1497,14 @@ ALWAYS_INLINE void GetConfigSettings(MiniSettings* settings) {
convertToUpper(key); convertToUpper(key);
settings->realTemps = (key == "TRUE"); settings->realTemps = (key == "TRUE");
} }
it = section.find("real_temps_dec");
if (it != section.end()) {
key = it->second;
convertToUpper(key);
settings->realTempsDec = !(key == "FALSE");
}
// Process font sizes with shared bounds // Process font sizes with shared bounds
static constexpr long minFontSize = 8; static constexpr long minFontSize = 8;
static constexpr long maxFontSize = 22; static constexpr long maxFontSize = 22;
@@ -1707,6 +1721,7 @@ ALWAYS_INLINE void GetConfigSettings(MicroSettings* settings) {
settings->realFrequencies = true; settings->realFrequencies = true;
settings->realVolts = true; settings->realVolts = true;
settings->realTemps = true; settings->realTemps = true;
settings->realTempsDec = false;
settings->showFullCPU = false; settings->showFullCPU = false;
settings->showFullResolution = false; settings->showFullResolution = false;
settings->showSOCVoltage = true; settings->showSOCVoltage = true;
@@ -1782,7 +1797,14 @@ ALWAYS_INLINE void GetConfigSettings(MicroSettings* settings) {
key = it->second; key = it->second;
convertToUpper(key); convertToUpper(key);
settings->realTemps = (key == "TRUE"); settings->realTemps = (key == "TRUE");
} }
it = section.find("real_temps_dec");
if (it != section.end()) {
key = it->second;
convertToUpper(key);
settings->realTempsDec = !(key == "FALSE");
}
it = section.find("show_full_cpu"); it = section.find("show_full_cpu");
if (it != section.end()) { if (it != section.end()) {

View File

@@ -411,6 +411,12 @@ public:
}); });
list->addItem(realTemps); list->addItem(realTemps);
auto *realTempsDec = new tsl::elm::ToggleListItem("Real Temp Decimals", getCurrentRealTempsDec());
realTempsDec->setStateChangedListener([this, section](bool state) {
ult::setIniFileValue(configIniPath, section, "real_temps_dec", state ? "true" : "false");
});
list->addItem(realTempsDec);
auto* showFullCPU = new tsl::elm::ToggleListItem("Full CPU", getCurrentShowFullCPU()); auto* showFullCPU = new tsl::elm::ToggleListItem("Full CPU", getCurrentShowFullCPU());
showFullCPU->setStateChangedListener([this, section](bool state) { showFullCPU->setStateChangedListener([this, section](bool state) {
ult::setIniFileValue(configIniPath, section, "show_full_cpu", state ? "true" : "false"); ult::setIniFileValue(configIniPath, section, "show_full_cpu", state ? "true" : "false");
@@ -567,6 +573,14 @@ private:
return value == "TRUE"; return value == "TRUE";
} }
bool getCurrentRealTempsDec() {
const std::string section = isMiniMode ? "mini" : "micro";
std::string value = ult::parseValueFromIniSection(configIniPath, section, "real_temps_dec");
if (value.empty()) return true;
convertToUpper(value);
return value == "TRUE";
}
bool getCurrentShowFullCPU() { bool getCurrentShowFullCPU() {
const std::string section = isMiniMode ? "mini" : "micro"; const std::string section = isMiniMode ? "mini" : "micro";
std::string value = ult::parseValueFromIniSection(configIniPath, section, "show_full_cpu"); std::string value = ult::parseValueFromIniSection(configIniPath, section, "show_full_cpu");

View File

@@ -109,6 +109,10 @@ private:
public: public:
MicroOverlay() { MicroOverlay() {
CPU_temp_c[0] = '\0';
GPU_temp_c[0] = '\0';
RAM_temp_c[0] = '\0';
tsl::hlp::requestForeground(false); tsl::hlp::requestForeground(false);
disableJumpTo = true; disableJumpTo = true;
//tsl::initializeUltrahandSettings(); //tsl::initializeUltrahandSettings();
@@ -882,7 +886,7 @@ public:
maxUsage, cpuDiff, cpuFreq / 1000000, (cpuFreq / 100000) % 10); maxUsage, cpuDiff, cpuFreq / 1000000, (cpuFreq / 100000) % 10);
} }
if (settings.realTemps && realCPU_Temp != 0) { if (settings.realTemps && realCPU_Temp != 0 && CPU_temp_c[0] != '\0') {
char temp_buffer[48]; char temp_buffer[48];
snprintf(temp_buffer, sizeof(temp_buffer), " %s", CPU_temp_c); snprintf(temp_buffer, sizeof(temp_buffer), " %s", CPU_temp_c);
strncat(CPU_compressed_c, temp_buffer, sizeof(CPU_compressed_c) - strlen(CPU_compressed_c) - 1); strncat(CPU_compressed_c, temp_buffer, sizeof(CPU_compressed_c) - strlen(CPU_compressed_c) - 1);
@@ -912,7 +916,7 @@ public:
GPU_Load_u / 10, GPU_Load_u / 10,
gpuDiff, gpuFreq / 1000000, (gpuFreq / 100000) % 10); gpuDiff, gpuFreq / 1000000, (gpuFreq / 100000) % 10);
if (settings.realTemps && realGPU_Temp != 0) { if (settings.realTemps && realGPU_Temp != 0 && GPU_temp_c[0] != '\0') {
char temp_buffer[48]; char temp_buffer[48];
snprintf(temp_buffer, sizeof(temp_buffer), " %s", GPU_temp_c); snprintf(temp_buffer, sizeof(temp_buffer), " %s", GPU_temp_c);
strncat(GPU_Load_c, temp_buffer, sizeof(GPU_Load_c) - strlen(GPU_Load_c) - 1); strncat(GPU_Load_c, temp_buffer, sizeof(GPU_Load_c) - strlen(GPU_Load_c) - 1);
@@ -977,7 +981,7 @@ public:
"%s%s%u.%u", MICRO_RAM_all_c, ramDiff, "%s%s%u.%u", MICRO_RAM_all_c, ramDiff,
ramFreq / 1000000, (ramFreq / 100000) % 10); ramFreq / 1000000, (ramFreq / 100000) % 10);
if (settings.realTemps && realRAM_Temp != 0) { if (settings.realTemps && realRAM_Temp != 0 && RAM_temp_c[0] != '\0') {
char temp_buffer[48]; char temp_buffer[48];
snprintf(temp_buffer, sizeof(temp_buffer), " %s", RAM_temp_c); snprintf(temp_buffer, sizeof(temp_buffer), " %s", RAM_temp_c);
strncat(RAM_var_compressed_c, temp_buffer, sizeof(RAM_var_compressed_c) - strlen(RAM_var_compressed_c) - 1); strncat(RAM_var_compressed_c, temp_buffer, sizeof(RAM_var_compressed_c) - strlen(RAM_var_compressed_c) - 1);
@@ -1099,16 +1103,28 @@ public:
} }
if (settings.realTemps) { if (settings.realTemps) {
if (realCPU_Temp != 0) { if (realCPU_Temp != 0) {
snprintf(CPU_temp_c, sizeof(CPU_temp_c), " %.1f°C", realCPU_Temp / 1000.0f); if (settings.realTempsDec) {
} snprintf(CPU_temp_c, sizeof(CPU_temp_c), "%.1f°C", realCPU_Temp / 1000.0f);
if (realGPU_Temp != 0) { } else {
snprintf(GPU_temp_c, sizeof(GPU_temp_c), " %.1f°C", realGPU_Temp / 1000.0f); snprintf(CPU_temp_c, sizeof(CPU_temp_c), "%u°C", static_cast<u32>(realCPU_Temp / 1000.0));
} }
if (realRAM_Temp != 0) { }
snprintf(RAM_temp_c, sizeof(RAM_temp_c), " %.1f°C", realRAM_Temp / 1000.0f); if (realGPU_Temp != 0) {
} if (settings.realTempsDec) {
} snprintf(GPU_temp_c, sizeof(GPU_temp_c), "%.1f°C", realGPU_Temp / 1000.0f);
} else {
snprintf(GPU_temp_c, sizeof(GPU_temp_c), "%u°C", static_cast<u32>(realGPU_Temp / 1000.0));
}
}
if (realRAM_Temp != 0) {
if (settings.realTempsDec) {
snprintf(RAM_temp_c, sizeof(RAM_temp_c), "%.1f°C", realRAM_Temp / 1000.0f);
} else {
snprintf(RAM_temp_c, sizeof(RAM_temp_c), "%u°C", static_cast<u32>(realRAM_Temp / 1000.0));
}
}
}
// Resolution processing // Resolution processing
//char RES_var_compressed_c[32] = ""; //char RES_var_compressed_c[32] = "";

View File

@@ -1290,15 +1290,27 @@ public:
if (settings.realTemps) { if (settings.realTemps) {
if (realCPU_Temp != 0) { if (realCPU_Temp != 0) {
snprintf(CPU_temp_c, sizeof(CPU_temp_c), "%.1f°C", realCPU_Temp / 1000.0f); if (settings.realTempsDec) {
snprintf(CPU_temp_c, sizeof(CPU_temp_c), "%.1f°C", realCPU_Temp / 1000.0f);
} else {
snprintf(CPU_temp_c, sizeof(CPU_temp_c), "%u°C", static_cast<u32>(realCPU_Temp / 1000.0));
}
} }
if (realGPU_Temp != 0) { if (realGPU_Temp != 0) {
snprintf(GPU_temp_c, sizeof(GPU_temp_c), "%.1f°C", realGPU_Temp / 1000.0f); if (settings.realTempsDec) {
snprintf(GPU_temp_c, sizeof(GPU_temp_c), "%.1f°C", realGPU_Temp / 1000.0f);
} else {
snprintf(GPU_temp_c, sizeof(GPU_temp_c), "%u°C", static_cast<u32>(realGPU_Temp / 1000.0));
}
} }
if (realRAM_Temp != 0) { if (realRAM_Temp != 0) {
snprintf(RAM_temp_c, sizeof(RAM_temp_c), "%.1f°C", realRAM_Temp / 1000.0f); if (settings.realTempsDec) {
snprintf(RAM_temp_c, sizeof(RAM_temp_c), "%.1f°C", realRAM_Temp / 1000.0f);
} else {
snprintf(RAM_temp_c, sizeof(RAM_temp_c), "%u°C", static_cast<u32>(realRAM_Temp / 1000.0));
}
} }
} }
// Only process resolution if RES is active and game is running // Only process resolution if RES is active and game is running
if (isActive("RES") && GameRunning && NxFps) { if (isActive("RES") && GameRunning && NxFps) {

View File

@@ -1266,7 +1266,6 @@ protected:
}; };
std::vector<NamedValue> mGpuVoltsVmin = { std::vector<NamedValue> mGpuVoltsVmin = {
NamedValue("Auto", 0),
NamedValue("480mV", 480), NamedValue("485mV", 485), NamedValue("490mV", 490), NamedValue("480mV", 480), NamedValue("485mV", 485), NamedValue("490mV", 490),
NamedValue("495mV", 495), NamedValue("500mV", 500), NamedValue("505mV", 505), NamedValue("495mV", 495), NamedValue("500mV", 500), NamedValue("505mV", 505),
NamedValue("510mV", 510), NamedValue("515mV", 515), NamedValue("520mV", 520), NamedValue("510mV", 510), NamedValue("515mV", 515), NamedValue("520mV", 520),