UV2 with dynamic voltages

This commit is contained in:
Lightos1
2025-12-12 18:16:15 +01:00
parent 5ed2c33e50
commit a637c0460a
5 changed files with 202 additions and 86 deletions

View File

@@ -48,8 +48,9 @@ namespace ams::ldr::oc::pcv {
{ },
};
constexpr int gpuVmax = 750;
constexpr int gpuVmin = 610;
constexpr u32 CpuClkOfficial = 1963'500;
constexpr u32 CpuVoltOfficial = 1120;
constexpr u32 CpuVminOfficial = 620;
constexpr u32 CpuVoltagePatchValues[] = { 850, 38, 1120, 1000, 100, 1000, 0 };
constexpr s32 CpuVoltagePatchOffsets[] = { -2, -1, 5, 6, 7, 8, 9 };
@@ -59,9 +60,6 @@ namespace ams::ldr::oc::pcv {
constexpr s32 CpuVoltageSecondaryPatchOffsets[] = { -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
static_assert(sizeof(CpuVoltageSecondaryPatchValues) == sizeof(CpuVoltageSecondaryPatchOffsets), "Invalid secondary CpuVoltagePatch size");
constexpr u32 CpuClkOfficial = 1963'500;
constexpr u32 CpuVoltOfficial = 1120;
constexpr cvb_entry_t GpuCvbTableDefault[] = {
// GPUB01_NA_CVB_TABLE
{ 76800, {}, { 610000, } },
@@ -86,8 +84,68 @@ namespace ams::ldr::oc::pcv {
constexpr u32 GpuClkPllMax = 1300'000'000;
constexpr u32 GpuClkPllLimit = 2'600'000;
constexpr int GpuVminOfficial = 610;
constexpr u32 CpuVminOfficial = 620;
constexpr u32 GpuDVFSPattern[] = { 1050, 1000, 100, 1000, 10, };
constexpr 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");
struct SpeedoVminTable {
u32 speedo;
u32 voltage;
};
struct RamVminOffsetTable {
u32 maxClock;
u32 offset;
};
constexpr u32 GetGpuVminVoltage() {
constexpr SpeedoVminTable Table[] {
{1560, 590},
{1583, 570},
{1620, 565},
{1670, 560},
{1694, 555},
{1731, 550},
{1750, 540},
{0xFFFFFFFF, 530},
};
for (auto e : Table) {
if (C.gpuSpeedo <= e.speedo) {
return e.voltage;
}
}
return 530;
}
constexpr u32 GetRamVminAdjustment(u32 vmin) {
if (C.marikoEmcMaxClock < 2133000) {
return vmin;
}
const u32 ramScale = (((C.marikoEmcMaxClock / 1000) - 2133) / 33) * 5 + vmin;
constexpr RamVminOffsetTable RamOffset[] {
{2400000, 5},
{2533000, 10},
{2666000, 15},
{2800000, 20},
{2933000, 25},
{3200000, 30},
{0xFFFFFFFF, 35},
};
for (auto r : RamOffset) {
if (C.marikoEmcMaxClock < r.maxClock) {
return ramScale + r.offset;
}
}
return ramScale;
}
/* GPU Max Clock asm Pattern:
*
@@ -157,7 +215,7 @@ namespace ams::ldr::oc::pcv {
{ },
};
constexpr int gpuVmin = 810;
constexpr int GpuVminOfficial = 810;
constexpr u32 CpuVoltOfficial = 1235;

View File

@@ -473,9 +473,9 @@ namespace ams::ldr::oc::pcv::erista {
// using namespace pcv::erista;
//
// #define WRITE_PARAM_ALL_REG(TABLE, PARAM, VALUE) // note: add backslashes to make the macro definition work
// TABLE->burst_regs.PARAM = VALUE;
// TABLE->shadow_regs_ca_train.PARAM = VALUE;
// TABLE->shadow_regs_quse_train.PARAM = VALUE;
// TABLE->burst_regs.PARAM = VALUE;
// TABLE->shadow_regs_ca_train.PARAM = VALUE;
// TABLE->shadow_regs_quse_train.PARAM = VALUE;
// TABLE->shadow_regs_rdwr_train.PARAM = VALUE;
//
#define GET_CYCLE(PARAM) ((u32)((double)(PARAM) / (1000000.0 / 1600000.0)))
@@ -726,7 +726,7 @@ namespace ams::ldr::oc::pcv::erista {
{"MEM Freq Max", &MemFreqMax, 0, nullptr, EmcClkOSLimit},
{"MEM Freq PLLM", &MemFreqPllmLimit, 2, nullptr, EmcClkPllmLimit},
{"MEM Volt", &MemVoltHandler, 2, nullptr, MemVoltHOS},
{"GPU Vmin", &GpuVmin, 0, nullptr, gpuVmin},
{"GPU Vmin", &GpuVmin, 0, nullptr, GpuVminOfficial},
};
for (uintptr_t ptr = mapped_nso;

View File

@@ -24,17 +24,70 @@
namespace ams::ldr::oc::pcv::mariko {
Result GpuVmin(u32 *ptr) {
if (!C.marikoGpuVmin)
R_SKIP();
PATCH_OFFSET(ptr, (int)C.marikoGpuVmin);
/* 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) {
/* Check for valid pattern. */
for (size_t i = 0; i < std::size(GpuDVFSPattern); ++i) {
if (*(ptr + i + 1) != GpuDVFSPattern[i]) {
R_THROW(ldr::ResultInvalidGpuDvfs());
}
}
/* Default value is 800mV. */
if (C.marikoGpuVmax) {
PATCH_OFFSET(ptr + 1, C.marikoGpuVmax);
}
/* C.marikoGpuVmin is non zero, user sets manual voltage. */
if (C.marikoGpuVmin) {
PATCH_OFFSET(ptr, C.marikoGpuVmin);
R_SUCCEED();
}
/* C.marikoGpuVmin is zero, auto voltage is applied. */
/* Get vmin depending on speedo and ram clock. */
u32 autoVmin = GetAutoVoltage();
PATCH_OFFSET(ptr, autoVmin);
R_SUCCEED();
}
Result GpuVmax(u32 *ptr) {
if (!C.marikoGpuVmax)
R_SKIP();
PATCH_OFFSET(ptr, (int)C.marikoGpuVmax);
Result GpuVoltThermals(u32 *ptr) {
u32 vmin = std::memcmp(ptr - 3, GpuVoltThermalPattern, sizeof(GpuVoltThermalPattern));
if (vmin) {
R_THROW(ldr::ResultInvalidGpuDvfs());
}
/* Automatic voltage. */
if (!C.marikoGpuVmin) {
vmin = GetAutoVoltage();
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, C.marikoGpuVmin);
PATCH_OFFSET(ptr + 3, C.marikoGpuVmin);
PATCH_OFFSET(ptr + 6, C.marikoGpuVmin);
PATCH_OFFSET(ptr + 9, C.marikoGpuVmin);
vmin = C.marikoGpuVmin;
}
PATCH_OFFSET(ptr + 12, vmin);
R_SUCCEED();
}
@@ -944,9 +997,10 @@ namespace ams::ldr::oc::pcv::mariko {
PatcherEntry<u32> patches[] = {
{"CPU Freq Vdd", &CpuFreqVdd, 1, nullptr, CpuClkOSLimit},
{"CPU Freq Table", CpuFreqCvbTable<true>, 1, nullptr, CpuCvbDefaultMaxFreq},
{"CPU Volt DVFS", &CpuVoltDVFS, 2, nullptr, /*CpuVminOfficial*/ 620},
// {"CPU Volt Thermals", &CpuVoltThermals, 1, nullptr, /*CpuVminOfficial*/ 620},
{"CPU Volt DVFS", &CpuVoltDVFS, 2, nullptr, CpuVminOfficial},
{"CPU Volt Dfll", &CpuVoltDfll, 1, nullptr, 0x0000FFCF},
{"GPU Volt DVFS", &GpuVoltDVFS, 1, nullptr, GpuVminOfficial},
{"Gpu Volt Thermals", &GpuVoltThermals, 1, nullptr, GpuVminOfficial},
{"GPU Freq Table", GpuFreqCvbTable<true>, 1, nullptr, GpuCvbDefaultMaxFreq},
{"GPU Freq Asm", &GpuFreqMaxAsm, 2, &GpuMaxClockPatternFn},
{"GPU PLL Max", &GpuFreqPllMax, 1, nullptr, GpuClkPllMax},
@@ -957,8 +1011,6 @@ namespace ams::ldr::oc::pcv::mariko {
{"MEM Freq PLLM", &MemFreqPllmLimit, 2, nullptr, EmcClkPllmLimit},
{"MEM Vddq", &EmcVddqVolt, 2, nullptr, EmcVddqDefault},
{"MEM Vdd2", &MemVoltHandler, 2, nullptr, MemVdd2Default},
{"GPU Vmin", &GpuVmin, 0, nullptr, gpuVmin},
{"GPU Vmax", &GpuVmax, 0, nullptr, gpuVmax},
};
for (uintptr_t ptr = mapped_nso; ptr <= mapped_nso + nso_size - sizeof(MarikoMtcTable); ptr += sizeof(u32)) {