14 Commits

Author SHA1 Message Date
e962de8373 hocclk: translate user notifications to German
Some checks failed
Build Horizon OC Zeus / build (push) Failing after 1m16s
2026-05-16 11:52:08 +02:00
souldbminersmwc
0d227cfb82 hocclk: add info about new feature 2026-05-13 19:52:11 -04:00
souldbminersmwc
3010c915a7 hocclk: add info to hocclk 2026-05-13 19:49:48 -04:00
souldbminersmwc
196933a6b3 hocclk: read voltage from i2c instead of rgltr 2026-05-12 17:00:46 -04:00
Lightos1
bfc93c6238 ldr: don't be an idiot, remove debug code 2026-05-12 21:29:27 +02:00
Lightos1
6d284d9c2b ldr: fix dvb brackets 2026-05-12 21:26:42 +02:00
Lightos1
7384404ac1 ldr: use DvbMeta struct 2026-05-12 20:05:02 +02:00
Lightos1
1b07df5f08 Revert "change cust rev back to 2, it shouldn't have been changed in the first place"
This reverts commit d6c2ddf2ea.
2026-05-12 13:40:35 +02:00
Lightos1
34e1f39510 ldr: even more (partially guessed) labeling of CvbMeta 2026-05-12 13:07:46 +02:00
Lightos1
ef830ce3f6 ldr: label more of CvbMeta 2026-05-12 13:03:51 +02:00
Lightos1
d7e22b3ccc ldr: add partially labeled CvbMeta struct 2026-05-12 12:44:52 +02:00
Lightos1
d6c2ddf2ea change cust rev back to 2, it shouldn't have been changed in the first place 2026-05-12 11:22:51 +02:00
Lightos1
b4627ad171 ldr: minVolt -> MinVolt 2026-05-12 10:34:05 +02:00
Lightos1
381a1eafc4 ldr: properly clamp soc voltage 2026-05-12 10:32:14 +02:00
25 changed files with 988 additions and 501 deletions

View File

@@ -21,7 +21,7 @@
#pragma once #pragma once
#define CUST_REV 3 #define CUST_REV 3
#define KIP_VERSION 230 #define KIP_VERSION 231
#include "oc_common.hpp" #include "oc_common.hpp"
#include "pcv/pcv_common.hpp" #include "pcv/pcv_common.hpp"

View File

@@ -38,14 +38,14 @@ namespace ams::ldr::hoc::pcv {
}; };
static_assert(sizeof(cvb_entry_t) == 0x38); static_assert(sizeof(cvb_entry_t) == 0x38);
struct cvb_cpu_dfll_data { struct CvbCpuDfllData {
u32 tune0_low; u32 tune0_low;
u32 tune0_high; u32 tune0_high;
u32 tune1_low; u32 tune1_low;
u32 tune1_high; u32 tune1_high;
unsigned int tune_high_min_millivolts; u32 tune_high_min_millivolts;
unsigned int tune_high_margin_millivolts; u32 tune_high_margin_millivolts;
unsigned long dvco_calibration_max; u64 dvco_calibration_max;
}; };
struct __attribute__((packed)) div_nmp { struct __attribute__((packed)) div_nmp {
@@ -115,6 +115,25 @@ namespace ams::ldr::hoc::pcv {
}; };
static_assert(sizeof(regulator) == 0x120); static_assert(sizeof(regulator) == 0x120);
struct __attribute__((packed)) CvbMeta {
u64 socType;
CvbCpuDfllData dfllData; /* Maybe? */
u32 unkZero2[6];
u32 unkMagic;
u32 unkZero3;
u32 highVmin;
u32 unkStepMaybe;
u32 vmin;
u32 unkZero4[3];
u32 pllMinMilliVolts;
u32 vmax;
u32 unkScale2;
u32 speedoScale;
u32 voltageScale;
u32 unkZero5;
};
static_assert(sizeof(CvbMeta) == 0x78);
constexpr u32 CpuClkOSLimit = 1785'000; constexpr u32 CpuClkOSLimit = 1785'000;
constexpr u32 GpuClkOsLimit = 921'600; constexpr u32 GpuClkOsLimit = 921'600;
constexpr u32 EmcClkOSLimit = 1600'000; constexpr u32 EmcClkOSLimit = 1600'000;

View File

@@ -66,11 +66,12 @@ namespace ams::ldr::hoc::pcv::erista {
} }
Result CpuVoltDfll(u32* ptr) { Result CpuVoltDfll(u32* ptr) {
cvb_cpu_dfll_data *entry = reinterpret_cast<cvb_cpu_dfll_data *>(ptr); CvbCpuDfllData *entry = reinterpret_cast<CvbCpuDfllData *>(ptr);
R_UNLESS(entry->tune0_low == 0xFFEAD0FF, ldr::ResultInvalidCpuVoltDfllEntry());
R_UNLESS(entry->tune0_high == 0x0, ldr::ResultInvalidCpuVoltDfllEntry()); R_UNLESS(entry->tune0_low == 0xFFEAD0FF, ldr::ResultInvalidCpuVoltDfllEntry());
R_UNLESS(entry->tune1_low == 0x0, ldr::ResultInvalidCpuVoltDfllEntry()); R_UNLESS(entry->tune0_high == 0x0, ldr::ResultInvalidCpuVoltDfllEntry());
R_UNLESS(entry->tune1_high == 0x0, ldr::ResultInvalidCpuVoltDfllEntry()); R_UNLESS(entry->tune1_low == 0x0, ldr::ResultInvalidCpuVoltDfllEntry());
R_UNLESS(entry->tune1_high == 0x0, ldr::ResultInvalidCpuVoltDfllEntry());
if (!C.eristaCpuUV) { if (!C.eristaCpuUV) {
R_SKIP(); R_SKIP();
@@ -100,6 +101,7 @@ namespace ams::ldr::hoc::pcv::erista {
default: default:
break; break;
} }
R_SUCCEED(); R_SUCCEED();
} }
@@ -121,10 +123,10 @@ namespace ams::ldr::hoc::pcv::erista {
} }
if (C.eristaGpuVmin) { if (C.eristaGpuVmin) {
PATCH_OFFSET(ptr , C.eristaGpuVmin); PATCH_OFFSET(ptr, C.eristaGpuVmin);
PATCH_OFFSET(ptr + 3, C.eristaGpuVmin); PATCH_OFFSET(ptr + 3, C.eristaGpuVmin);
PATCH_OFFSET(ptr + 6, C.eristaGpuVmin); PATCH_OFFSET(ptr + 6, C.eristaGpuVmin);
PATCH_OFFSET(ptr + 9, C.eristaGpuVmin); PATCH_OFFSET(ptr + 9, C.eristaGpuVmin);
PATCH_OFFSET(ptr + 12, C.eristaGpuVmin); PATCH_OFFSET(ptr + 12, C.eristaGpuVmin);
} }
@@ -165,8 +167,10 @@ namespace ams::ldr::hoc::pcv::erista {
} }
u32 asm_patch[2] = { u32 asm_patch[2] = {
asm_set_rd(asm_set_imm16(GpuAsmPattern[0], max_clock), rd), asm_set_rd(asm_set_imm16(GpuAsmPattern[0], max_clock), rd),
asm_set_rd(asm_set_imm16(GpuAsmPattern[1], max_clock >> 16), rd)}; asm_set_rd(asm_set_imm16(GpuAsmPattern[1], max_clock >> 16), rd)
PATCH_OFFSET(ptr32, asm_patch[0]); };
PATCH_OFFSET(ptr32, asm_patch[0]);
PATCH_OFFSET(ptr32 + 1, asm_patch[1]); PATCH_OFFSET(ptr32 + 1, asm_patch[1]);
R_SUCCEED(); R_SUCCEED();
@@ -210,7 +214,9 @@ namespace ams::ldr::hoc::pcv::erista {
} }
u32 trefbw = refresh_raw + 0x40; u32 trefbw = refresh_raw + 0x40;
trefbw = MIN(trefbw, static_cast<u32>(0x3FFF)); trefbw = MIN(trefbw, static_cast<u32>(0x3FFF));
const u32 dyn_self_ref_control = (static_cast<u32>(7605.0 / tCK_avg) + 260) | (table->burst_regs.emc_dyn_self_ref_control & 0xffff0000);
CalculateTimings(tCK_avg); CalculateTimings(tCK_avg);
@@ -239,7 +245,6 @@ namespace ams::ldr::hoc::pcv::erista {
WRITE_PARAM_ALL_REG(table, emc_refresh, refresh_raw); WRITE_PARAM_ALL_REG(table, emc_refresh, refresh_raw);
WRITE_PARAM_ALL_REG(table, emc_pre_refresh_req_cnt, refresh_raw / 4); WRITE_PARAM_ALL_REG(table, emc_pre_refresh_req_cnt, refresh_raw / 4);
WRITE_PARAM_ALL_REG(table, emc_trefbw, trefbw); WRITE_PARAM_ALL_REG(table, emc_trefbw, trefbw);
const u32 dyn_self_ref_control = (static_cast<u32>(7605.0 / tCK_avg) + 260) | (table->burst_regs.emc_dyn_self_ref_control & 0xffff0000);
WRITE_PARAM_ALL_REG(table, emc_dyn_self_ref_control, dyn_self_ref_control); WRITE_PARAM_ALL_REG(table, emc_dyn_self_ref_control, dyn_self_ref_control);
WRITE_PARAM_ALL_REG(table, emc_pdex2wr, pdex2rw); WRITE_PARAM_ALL_REG(table, emc_pdex2wr, pdex2rw);
WRITE_PARAM_ALL_REG(table, emc_pdex2rd, pdex2rw); WRITE_PARAM_ALL_REG(table, emc_pdex2rd, pdex2rw);
@@ -280,7 +285,7 @@ namespace ams::ldr::hoc::pcv::erista {
/* This needs some clean up. */ /* This needs some clean up. */
constexpr double MC_ARB_DIV = 4.0; constexpr double MC_ARB_DIV = 4.0;
constexpr u32 MC_ARB_SFA = 2; constexpr u32 MC_ARB_SFA = 2;
table->burst_mc_regs.mc_emem_arb_cfg = table->rate_khz / (33.3 * 1000) / MC_ARB_DIV; table->burst_mc_regs.mc_emem_arb_cfg = table->rate_khz / (33.3 * 1000) / MC_ARB_DIV;
table->burst_mc_regs.mc_emem_arb_timing_rcd = CEIL(GET_CYCLE_CEIL(tRCD) / MC_ARB_DIV) - 2; table->burst_mc_regs.mc_emem_arb_timing_rcd = CEIL(GET_CYCLE_CEIL(tRCD) / MC_ARB_DIV) - 2;
@@ -325,8 +330,8 @@ namespace ams::ldr::hoc::pcv::erista {
table->la_scale_regs.mc_ptsa_grant_decrement = grant_decrement; table->la_scale_regs.mc_ptsa_grant_decrement = grant_decrement;
constexpr u32 MaskHigh = 0xFF00FFFF; constexpr u32 MaskHigh = 0xFF00FFFF;
constexpr u32 Mask2 = 0xFFFFFF00; constexpr u32 Mask2 = 0xFFFFFF00;
constexpr u32 Mask3 = 0xFF00FF00; constexpr u32 Mask3 = 0xFF00FF00;
const u32 allowance1 = static_cast<u32>(0x32000 / (table->rate_khz / 0x3E8)) & 0xFF; const u32 allowance1 = static_cast<u32>(0x32000 / (table->rate_khz / 0x3E8)) & 0xFF;
const u32 allowance2 = static_cast<u32>(0x9C40 / (table->rate_khz / 0x3E8)) & 0xFF; const u32 allowance2 = static_cast<u32>(0x9C40 / (table->rate_khz / 0x3E8)) & 0xFF;
@@ -354,10 +359,10 @@ namespace ams::ldr::hoc::pcv::erista {
table->la_scale_regs.mc_latency_allowance_hc_1 = (table->la_scale_regs.mc_latency_allowance_hc_1 & Mask2) | allowance1; table->la_scale_regs.mc_latency_allowance_hc_1 = (table->la_scale_regs.mc_latency_allowance_hc_1 & Mask2) | allowance1;
table->la_scale_regs.mc_latency_allowance_vi2_0 = (table->la_scale_regs.mc_latency_allowance_vi2_0 & Mask2) | allowance1; table->la_scale_regs.mc_latency_allowance_vi2_0 = (table->la_scale_regs.mc_latency_allowance_vi2_0 & Mask2) | allowance1;
table->dram_timings.t_rp = tRFCpb; table->dram_timings.t_rp = tRFCpb;
table->dram_timings.t_rfc = tRFCab; table->dram_timings.t_rfc = tRFCab;
table->emc_cfg_2 = 0x11083D; table->emc_cfg_2 = 0x11083D;
table->min_volt = (u32)std::min(static_cast<s32>(1050), 900 + C.emcDvbShift * 25); table->min_volt = std::clamp(900 + (C.emcDvbShift * 25), 900, 1050);
} }
/* Probably more intuitive to point to 40800 rather than 1600000, but oh well. */ /* Probably more intuitive to point to 40800 rather than 1600000, but oh well. */

View File

@@ -140,7 +140,7 @@ namespace ams::ldr::hoc::pcv::erista {
MtcTableIndex index; MtcTableIndex index;
}; };
constexpr MtcDramIndex mtcIndexTable[] = { const inline MtcDramIndex mtcIndexTable[] = {
{ ICOSA_4GB_SAMSUNG_K4F6E304HB_MGCH, T210SdevEmcDvfsTableS4gb01, }, { ICOSA_4GB_SAMSUNG_K4F6E304HB_MGCH, T210SdevEmcDvfsTableS4gb01, },
{ ICOSA_4GB_MICRON_MT53B512M32D2NP_062_WTC, T210SdevEmcDvfsTableS4gb01, }, { ICOSA_4GB_MICRON_MT53B512M32D2NP_062_WTC, T210SdevEmcDvfsTableS4gb01, },
{ ICOSA_6GB_SAMSUNG_K4FHE3D4HM_MGCH, T210SdevEmcDvfsTableS6gb01, }, { ICOSA_6GB_SAMSUNG_K4FHE3D4HM_MGCH, T210SdevEmcDvfsTableS6gb01, },

View File

@@ -94,23 +94,29 @@ namespace ams::ldr::hoc::pcv::mariko {
} }
Result CpuVoltDVFS(u32 *ptr) { Result CpuVoltDVFS(u32 *ptr) {
if (MatchesPattern(ptr, cpuVoltagePatchOffsets, cpuVoltagePatchValues)) { CvbMeta *cpuCvbMeta = reinterpret_cast<CvbMeta *>(reinterpret_cast<u8 *>(ptr) - offsetof(CvbMeta, vmin));
if (C.marikoCpuLowVmin) {
PATCH_OFFSET(ptr, C.marikoCpuLowVmin);
}
if (C.marikoCpuHighVmin) { R_UNLESS(cpuCvbMeta->highVmin == CpuHighVminOfficial, ldr::ResultInvalidCpuMinVolt());
PATCH_OFFSET(ptr - 2, C.marikoCpuHighVmin); R_UNLESS(cpuCvbMeta->unkStepMaybe == 38, ldr::ResultInvalidCpuMinVolt());
} R_UNLESS(cpuCvbMeta->vmax == CpuVoltOfficial, ldr::ResultInvalidCpuMinVolt());
R_UNLESS(cpuCvbMeta->unkScale2 == 1000, ldr::ResultInvalidCpuMinVolt());
R_UNLESS(cpuCvbMeta->speedoScale == 100, ldr::ResultInvalidCpuMinVolt());
R_UNLESS(cpuCvbMeta->voltageScale == 1000, ldr::ResultInvalidCpuMinVolt());
R_UNLESS(cpuCvbMeta->unkZero5 == 0, ldr::ResultInvalidCpuMinVolt());
if (C.marikoCpuMaxVolt) { if (C.marikoCpuLowVmin) {
PATCH_OFFSET(ptr + 5, C.marikoCpuMaxVolt); PATCH_OFFSET(&(cpuCvbMeta->vmin), C.marikoCpuLowVmin);
}
R_SUCCEED();
} }
R_THROW(ldr::ResultInvalidCpuMinVolt()); if (C.marikoCpuHighVmin) {
PATCH_OFFSET(&(cpuCvbMeta->highVmin), C.marikoCpuHighVmin);
}
if (C.marikoCpuMaxVolt) {
PATCH_OFFSET(&(cpuCvbMeta->vmax), C.marikoCpuMaxVolt);
}
R_SUCCEED();
} }
Result CpuVoltThermals(u32 *ptr) { Result CpuVoltThermals(u32 *ptr) {
@@ -134,80 +140,80 @@ namespace ams::ldr::hoc::pcv::mariko {
} }
Result CpuVoltDfll(u32 *ptr) { Result CpuVoltDfll(u32 *ptr) {
cvb_cpu_dfll_data *entry = reinterpret_cast<cvb_cpu_dfll_data *>(ptr); CvbCpuDfllData *entry = reinterpret_cast<CvbCpuDfllData *>(ptr);
R_UNLESS(entry->tune0_low == 0xFFCF, ldr::ResultInvalidCpuVoltDfllEntry()); R_UNLESS(entry->tune0_low == 0xFFCF, ldr::ResultInvalidCpuVoltDfllEntry());
R_UNLESS(entry->tune0_high == 0x0, ldr::ResultInvalidCpuVoltDfllEntry()); R_UNLESS(entry->tune0_high == 0x0, ldr::ResultInvalidCpuVoltDfllEntry());
R_UNLESS(entry->tune1_low == 0x12207FF, ldr::ResultInvalidCpuVoltDfllEntry()); R_UNLESS(entry->tune1_low == 0x12207FF, ldr::ResultInvalidCpuVoltDfllEntry());
R_UNLESS(entry->tune1_high == 0x3FFF7FF, ldr::ResultInvalidCpuVoltDfllEntry()); R_UNLESS(entry->tune1_high == 0x3FFF7FF, ldr::ResultInvalidCpuVoltDfllEntry());
switch (C.marikoCpuUVLow) { switch (C.marikoCpuUVLow) {
case 1: case 1:
PATCH_OFFSET(&(entry->tune0_low), 0xffa0); PATCH_OFFSET(&(entry->tune0_low), 0xffa0);
PATCH_OFFSET(&(entry->tune0_high), 0xffff); PATCH_OFFSET(&(entry->tune0_high), 0xffff);
PATCH_OFFSET(&(entry->tune1_low), 0x21107ff); PATCH_OFFSET(&(entry->tune1_low), 0x21107ff);
PATCH_OFFSET(&(entry->tune1_high), 0); PATCH_OFFSET(&(entry->tune1_high), 0x0);
break; break;
case 2: case 2:
PATCH_OFFSET(&(entry->tune0_high), 0xffdf); PATCH_OFFSET(&(entry->tune0_high), 0xffdf);
PATCH_OFFSET(&(entry->tune1_low), 0x21107ff); PATCH_OFFSET(&(entry->tune1_low), 0x21107ff);
PATCH_OFFSET(&(entry->tune1_high), 0x27207ff); PATCH_OFFSET(&(entry->tune1_high), 0x27207ff);
break; break;
case 3: case 3:
PATCH_OFFSET(&(entry->tune0_low), 0xffdf); PATCH_OFFSET(&(entry->tune0_low), 0xffdf);
PATCH_OFFSET(&(entry->tune0_high), 0xffdf); PATCH_OFFSET(&(entry->tune0_high), 0xffdf);
PATCH_OFFSET(&(entry->tune1_low), 0x21107ff); PATCH_OFFSET(&(entry->tune1_low), 0x21107ff);
PATCH_OFFSET(&(entry->tune1_high), 0x27307ff); PATCH_OFFSET(&(entry->tune1_high), 0x27307ff);
break; break;
case 4: case 4:
PATCH_OFFSET(&(entry->tune0_low), 0xffff); PATCH_OFFSET(&(entry->tune0_low), 0xffff);
PATCH_OFFSET(&(entry->tune0_high), 0xffdf); PATCH_OFFSET(&(entry->tune0_high), 0xffdf);
PATCH_OFFSET(&(entry->tune1_low), 0x21107ff); PATCH_OFFSET(&(entry->tune1_low), 0x21107ff);
PATCH_OFFSET(&(entry->tune1_high), 0x27407ff); PATCH_OFFSET(&(entry->tune1_high), 0x27407ff);
break; break;
case 5: case 5:
PATCH_OFFSET(&(entry->tune0_high), 0xffdf); PATCH_OFFSET(&(entry->tune0_high), 0xffdf);
PATCH_OFFSET(&(entry->tune1_low), 0x21607ff); PATCH_OFFSET(&(entry->tune1_low), 0x21607ff);
PATCH_OFFSET(&(entry->tune1_high), 0x27707ff); PATCH_OFFSET(&(entry->tune1_high), 0x27707ff);
break; break;
case 6: case 6:
PATCH_OFFSET(&(entry->tune0_high), 0xffdf); PATCH_OFFSET(&(entry->tune0_high), 0xffdf);
PATCH_OFFSET(&(entry->tune1_low), 0x21607ff); PATCH_OFFSET(&(entry->tune1_low), 0x21607ff);
PATCH_OFFSET(&(entry->tune1_high), 0x27807ff); PATCH_OFFSET(&(entry->tune1_high), 0x27807ff);
break; break;
case 7: case 7:
PATCH_OFFSET(&(entry->tune0_high), 0xdfff); PATCH_OFFSET(&(entry->tune0_high), 0xdfff);
PATCH_OFFSET(&(entry->tune1_low), 0x21607ff); PATCH_OFFSET(&(entry->tune1_low), 0x21607ff);
PATCH_OFFSET(&(entry->tune1_high), 0x27b07ff); PATCH_OFFSET(&(entry->tune1_high), 0x27b07ff);
break; break;
case 8: case 8:
PATCH_OFFSET(&(entry->tune0_low), 0xdfff); PATCH_OFFSET(&(entry->tune0_low), 0xdfff);
PATCH_OFFSET(&(entry->tune0_high), 0xdfff); PATCH_OFFSET(&(entry->tune0_high), 0xdfff);
PATCH_OFFSET(&(entry->tune1_low), 0x21707ff); PATCH_OFFSET(&(entry->tune1_low), 0x21707ff);
PATCH_OFFSET(&(entry->tune1_high), 0x27b07ff); PATCH_OFFSET(&(entry->tune1_high), 0x27b07ff);
break; break;
case 9: case 9:
PATCH_OFFSET(&(entry->tune0_low), 0xdfff); PATCH_OFFSET(&(entry->tune0_low), 0xdfff);
PATCH_OFFSET(&(entry->tune0_high), 0xdfff); PATCH_OFFSET(&(entry->tune0_high), 0xdfff);
PATCH_OFFSET(&(entry->tune1_low), 0x21707ff); PATCH_OFFSET(&(entry->tune1_low), 0x21707ff);
PATCH_OFFSET(&(entry->tune1_high), 0x27c07ff); PATCH_OFFSET(&(entry->tune1_high), 0x27c07ff);
break; break;
case 10: case 10:
PATCH_OFFSET(&(entry->tune0_low), 0xdfff); PATCH_OFFSET(&(entry->tune0_low), 0xdfff);
PATCH_OFFSET(&(entry->tune0_high), 0xdfff); PATCH_OFFSET(&(entry->tune0_high), 0xdfff);
PATCH_OFFSET(&(entry->tune1_low), 0x21707ff); PATCH_OFFSET(&(entry->tune1_low), 0x21707ff);
PATCH_OFFSET(&(entry->tune1_high), 0x27d07ff); PATCH_OFFSET(&(entry->tune1_high), 0x27d07ff);
break; break;
case 11: case 11:
PATCH_OFFSET(&(entry->tune0_low), 0xdfff); PATCH_OFFSET(&(entry->tune0_low), 0xdfff);
PATCH_OFFSET(&(entry->tune0_high), 0xdfff); PATCH_OFFSET(&(entry->tune0_high), 0xdfff);
PATCH_OFFSET(&(entry->tune1_low), 0x21707ff); PATCH_OFFSET(&(entry->tune1_low), 0x21707ff);
PATCH_OFFSET(&(entry->tune1_high), 0x27e07ff); PATCH_OFFSET(&(entry->tune1_high), 0x27e07ff);
break; break;
case 12: case 12:
PATCH_OFFSET(&(entry->tune0_low), 0xdfff); PATCH_OFFSET(&(entry->tune0_low), 0xdfff);
PATCH_OFFSET(&(entry->tune0_high), 0xdfff); PATCH_OFFSET(&(entry->tune0_high), 0xdfff);
PATCH_OFFSET(&(entry->tune1_low), 0x21707ff); PATCH_OFFSET(&(entry->tune1_low), 0x21707ff);
PATCH_OFFSET(&(entry->tune1_high), 0x27f07ff); PATCH_OFFSET(&(entry->tune1_high), 0x27f07ff);
break; break;
default: default:
@@ -216,7 +222,7 @@ namespace ams::ldr::hoc::pcv::mariko {
switch (C.marikoCpuUVHigh) { switch (C.marikoCpuUVHigh) {
case 1: case 1:
PATCH_OFFSET(&(entry->tune1_high), 0); PATCH_OFFSET(&(entry->tune1_high), 0x0);
PATCH_OFFSET(&(entry->tune0_high), 0xffff); PATCH_OFFSET(&(entry->tune0_high), 0xffff);
break; break;
case 2: case 2:
@@ -301,7 +307,7 @@ namespace ams::ldr::hoc::pcv::mariko {
asm_set_rd(asm_set_imm16(GpuAsmPattern[1], max_clock >> 16), rd) asm_set_rd(asm_set_imm16(GpuAsmPattern[1], max_clock >> 16), rd)
}; };
PATCH_OFFSET(ptr32, asm_patch[0]); PATCH_OFFSET(ptr32, asm_patch[0]);
PATCH_OFFSET(ptr32 + 1, asm_patch[1]); PATCH_OFFSET(ptr32 + 1, asm_patch[1]);
R_SUCCEED(); R_SUCCEED();
@@ -366,7 +372,7 @@ namespace ams::ldr::hoc::pcv::mariko {
} }
u32 trefbw = refresh_raw + 0x40; u32 trefbw = refresh_raw + 0x40;
trefbw = MIN(trefbw, static_cast<u32>(0x3FFF)); trefbw = MIN(trefbw, static_cast<u32>(0x3FFF));
const u32 dyn_self_ref_control = (static_cast<u32>(7605.0 / tCK_avg) + 260) | (table->burst_regs.emc_dyn_self_ref_control & 0xffff0000); const u32 dyn_self_ref_control = (static_cast<u32>(7605.0 / tCK_avg) + 260) | (table->burst_regs.emc_dyn_self_ref_control & 0xffff0000);
@@ -796,9 +802,9 @@ namespace ams::ldr::hoc::pcv::mariko {
R_SKIP(); R_SKIP();
} }
u32 max0 = 1050; s32 max0 = 1050;
u32 max1 = 1025; s32 max1 = 1025;
u32 max2 = 1000; s32 max2 = 1000;
s32 voltAdd = 25 * C.emcDvbShift; s32 voltAdd = 25 * C.emcDvbShift;
if (C.marikoSocVmax && C.marikoSocVmax > 1000) { if (C.marikoSocVmax && C.marikoSocVmax > 1000) {
@@ -807,11 +813,17 @@ namespace ams::ldr::hoc::pcv::mariko {
max2 = C.marikoSocVmax; max2 = C.marikoSocVmax;
} }
auto DvbVolt = [&](u32 zero, u32 one, u32 two) { constexpr s32 MinVolt = 637;
return std::array<u32, 3>{
std::min((u32)((s32)zero + voltAdd), max0), auto ClampVolt = [&](s32 value, s32 max) {
std::min((u32)((s32)one + voltAdd), max1), return std::clamp(value + voltAdd, MinVolt, max);
std::min((u32)((s32)two + voltAdd), max2) };
auto DvbVolt = [&](s32 zero, s32 one, s32 two) {
return std::array<s32, 3>{
ClampVolt(zero, max0),
ClampVolt(one, max1),
ClampVolt(two, max2)
}; };
}; };
@@ -819,7 +831,7 @@ namespace ams::ldr::hoc::pcv::mariko {
static_cast<u32>((v)[0]), \ static_cast<u32>((v)[0]), \
static_cast<u32>((v)[1]), \ static_cast<u32>((v)[1]), \
static_cast<u32>((v)[2]) static_cast<u32>((v)[2])
DvbEntry emcDvbTableNew[] = { DvbEntry emcDvbOcTableBrackets[] = {
{ 204000, { 637, 637, 637, }, }, { 204000, { 637, 637, 637, }, },
{ 1331200, { 650, 637, 637, }, }, { 1331200, { 650, 637, 637, }, },
{ 1600000, { 675, 650, 637, }, }, { 1600000, { 675, 650, 637, }, },
@@ -829,22 +841,23 @@ namespace ams::ldr::hoc::pcv::mariko {
{ 2666000, { DVB(DvbVolt( 850, 825, 800)) }, }, { 2666000, { DVB(DvbVolt( 850, 825, 800)) }, },
{ 2933000, { DVB(DvbVolt( 950, 925, 900)) }, }, { 2933000, { DVB(DvbVolt( 950, 925, 900)) }, },
{ 3200000, { DVB(DvbVolt(1050, 1025, 1000)) }, }, { 3200000, { DVB(DvbVolt(1050, 1025, 1000)) }, },
{ 0xFFFFFFFF, { }, }, { ~0u, { }, },
}; };
#undef DVB #undef DVB
DvbEntry emcDvbTableOc[newEmcList.size()];
u32 j = MtcTableCountDefault; u32 bracketIndex = 0;
for (u32 i = MtcTableCountDefault; i < newEmcList.size(); ++i) { for (u32 i = 0; i < newEmcList.size(); ++i) {
if (newEmcList[i] >= emcDvbTableNew[j].freq && newEmcList[i] < emcDvbTableNew[j + 1].freq) { while (newEmcList[i] >= emcDvbOcTableBrackets[bracketIndex + 1].freq) {
emcDvbTableNew[j].freq = newEmcList[i]; ++bracketIndex;
++j;
} else {
break;
} }
emcDvbTableOc[i].freq = newEmcList[i];
std::memcpy(emcDvbTableOc[i].volt, emcDvbOcTableBrackets[bracketIndex].volt, sizeof(emcDvbTableOc[i].volt));
} }
std::memset(mem_dvb_table_head, 0, sizeof(EmcDvbTableDefault)); std::memset(mem_dvb_table_head, 0, sizeof(EmcDvbTableDefault));
std::memcpy(mem_dvb_table_head, &emcDvbTableNew, sizeof(emcDvbTableNew)); std::memcpy(mem_dvb_table_head, &emcDvbTableOc, sizeof(emcDvbTableOc));
/* Max dvfs entry is 32, but HOS doesn't seem to boot if exact freq doesn't exist in dvb table, /* Max dvfs entry is 32, but HOS doesn't seem to boot if exact freq doesn't exist in dvb table,
reason why it's like this reason why it's like this

View File

@@ -48,11 +48,11 @@ namespace ams::ldr::hoc::pcv::mariko {
{ }, { },
}; };
constexpr u32 CpuClkOfficial = 1963'500; constexpr u32 CpuClkOfficial = 1963'500;
constexpr u32 CpuVoltOfficial = 1120; constexpr u32 CpuVoltOfficial = 1120;
constexpr u32 CpuVminOfficial = 620; constexpr u32 CpuHighVminOfficial = 850;
constexpr u32 CpuVminOfficial = 620;
constexpr u32 CpuTune0Low = 0xFFCF; constexpr u32 CpuTune0Low = 0xFFCF;
static const u32 cpuVoltagePatchValues[] = { 850, 38, 1120, 1000, 100, 1000, 0 }; static const u32 cpuVoltagePatchValues[] = { 850, 38, 1120, 1000, 100, 1000, 0 };
static const s32 cpuVoltagePatchOffsets[] = { -2, -1, 5, 6, 7, 8, 9 }; static const s32 cpuVoltagePatchOffsets[] = { -2, -1, 5, 6, 7, 8, 9 };
@@ -230,7 +230,7 @@ namespace ams::ldr::hoc::pcv::mariko {
MtcTableIndex index; MtcTableIndex index;
}; };
constexpr MtcDramIndex mtcIndexTable[] = { const inline MtcDramIndex mtcIndexTable[] = {
{ HOAG_4GB_HYNIX_H9HCNNNBKMMLXR_NEE, T210b0SdevEmcDvfsTableH1y4gb01, }, { HOAG_4GB_HYNIX_H9HCNNNBKMMLXR_NEE, T210b0SdevEmcDvfsTableH1y4gb01, },
{ AULA_4GB_HYNIX_H9HCNNNBKMMLXR_NEE, T210b0SdevEmcDvfsTableH1y4gb01, }, { AULA_4GB_HYNIX_H9HCNNNBKMMLXR_NEE, T210b0SdevEmcDvfsTableH1y4gb01, },
{ IOWA_4GB_HYNIX_H9HCNNNBKMMLXR_NEE, T210b0SdevEmcDvfsTableH1y4gb01, }, { IOWA_4GB_HYNIX_H9HCNNNBKMMLXR_NEE, T210b0SdevEmcDvfsTableH1y4gb01, },

View File

@@ -39,7 +39,7 @@ include ${TOPDIR}/lib/libultrahand/ultrahand.mk
# version control constants # version control constants
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
#TARGET_VERSION := $(shell git describe --dirty --always --tags) #TARGET_VERSION := $(shell git describe --dirty --always --tags)
APP_VERSION := 2.3.0 # ensure to set KIP_VERSION and CUST_REV in sysmodule Makefile when updating this APP_VERSION := 2.3.1 # ensure to set KIP_VERSION and CUST_REV in sysmodule Makefile when updating this
TARGET_VERSION := $(APP_VERSION) TARGET_VERSION := $(APP_VERSION)
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------

View File

@@ -0,0 +1,570 @@
/*
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#include "config_info_strings.h"
std::vector<std::string> ConfigInfoStrings(HocClkConfigValue val, bool isMariko, bool isHoag)
{
switch (val)
{
case HocClkConfigValue_PollingIntervalMs:
return {
"The interval (in miliseconds) where clocks are applied, tempratures and voltages are polled and logs are written (if enabled).",
"Higher values may cause more delay between changing a setting and it taking effect, and lower values may increase sysmodule memory usage",
"Default: 300ms"
};
case HocClkConfigValue_RamDisplayUnit:
return {
"The unit used when displaying RAM frequency values.",
"Options:",
"- MHz: Megahertz (e.g. 1600 MHz)",
"- MT/s: MegaTransfers per second (e.g. 3200 MT/s)",
"Default: MHz"
};
case HocClkConfigValue_RAMVoltDisplayMode:
return {
"The method used to display RAM voltage values.",
"Options:",
"- VDD2 - Display VDD2 voltage",
"- VDDQ - Display VDDQ voltage",
"Default: VDD2"
};
case HocClkConfigValue_EnableExperimentalSettings:
return {
"When enabled, shows settings that are still being tested and may be unstable or not work at all.",
"Use with caution and report any issues to the developers."
};
case HocClkConfigValue_MarikoMiddleFreqs:
return {
"Allows usage of frequencies stepped by 38.4MHz instead of 76.8MHz below 1228MHz GPU clock",
"Default: OFF"
};
case HocClkConfigValue_LiveCpuUv:
return {
"Allows changing CPU undervolt settings without a reboot",
"Default: OFF"
};
case HocClkConfigValue_GPUSchedulingMethod:
return {
"Method used for GPU scheduling override",
"Options:",
"- INI: override via system_settings.ini",
"- NV Service: override via nvservices sysmodule (experimental)",
"Default: INI"
};
case HocClkConfigValue_MemoryFrequencyMeasurementMode:
return {
"How the RAM real frequency is measured",
"Options:",
"- PLL: Measure from PLLMB and PLLM (more accurate)",
"- Actmon: Measure from Actmon (less accurate)",
"Default: PLL"
};
case HocClkConfigValue_BatteryChargeCurrent:
return {
"Overrides the charge current to the battery. Use with caution!",
isHoag ? "Default: 1664 mA" : "2048 mA"
};
case HocClkConfigValue_AulaDisplayColorPreset:
return {
"Current display color preset. Default is Basic",
"Options:",
"- Saturated: Based on Vivid but over-saturated.",
"- Washed: Washed out colors.",
"- Basic: Real natural profile.",
"- Natural: Not actually natural.. Extra saturation.",
"- Vivid: Saturated.",
"Default: Do not override"
};
case HocClkConfigValue_CpuGovernorMinimumFreq:
return {
"The minimum frequency that the CPU governor will allow.",
"Default: 612MHz"
};
case HocClkConfigValue_OverwriteRefreshRate:
return {
"Conrols the avaiability of display refresh rate features.",
"When enabled, allows changing the display refresh rate and using display refresh rate related features."
};
case HocClkConfigValue_MaxDisplayClockH:
return {
"The maximum display clock frequency in handheld mode (in Hz).",
"Warning: Changing this value may cause instability or display damage.",
"Default: 60 Hz"
};
case HocClkConfigValue_DisplayVoltage:
return {
"The voltage supplied to the display panel (in mV).",
"Warning: Changing this value may cause instability.",
"Default: 1200mV"
};
case HocClkConfigValue_UncappedClocks:
if(isMariko) {
return {
"When enabled, disables clock cappings",
"Warning: Enabling this may cause damage to your device without a proper undervolt. Use with caution!",
"Clock cappings:",
"- Handheld:",
" - GPU (HiOPT): 614 MHz",
" - GPU (HiOPT - 15mV): 691 MHz",
" - GPU (High UV): 768 MHz",
"- USB Charger",
" - GPU (HiOPT): 844 MHz",
" - GPU (HiOPT - 15mV): 921 MHz",
" - GPU (High UV): 998 MHz",
"- PD Charger / Docked:",
" - No capping applied",
"Default: OFF"
};
} else {
return {
"When enabled, disables clock cappings",
"Warning: Enabling this may cause damage to your device without a proper undervolt. Use with caution!",
"Clock cappings:",
"- Handheld:",
" - GPU: 460 MHz",
" - CPU: 1581 MHz",
"- USB Charger",
" - GPU: 768 MHz",
"- PD Charger / Docked:",
" - No capping applied",
"Default: OFF"
};
}
case HocClkConfigValue_ThermalThrottle:
return {
"If enabled, Resets to stock clocks after the threshold is applied",
"Default: ON",
};
case HocClkConfigValue_HandheldTDP:
return {
"If enabled, Resets to stock clocks when power consumption is above the threshold in handheld mode",
"Default: ON",
};
case HocClkConfigValue_HandheldTDPLimit:
case HocClkConfigValue_LiteTDPLimit:
return {
"The power consumption threshold (in mW) for resetting to stock clocks in handheld mode when Handheld TDP is enabled.",
isHoag ? "Default: 6400mW" : "Default: 9600mW"
};
case HocClkConfigValue_ThermalThrottleThreshold:
return {
"The temperature threshold (in °C) for resetting to stock clocks when Thermal Throttle is enabled.",
"Default: 70°C"
};
case KipConfigValue_emcDvbShift:
return {
"Each level adds/removes 25mV from the SOC Voltage table",
"Consoles are bracketed by SoC Speedo. The brackets are as follows:",
" - Speedo 1487-1598: Bracket 0",
" - Speedo 1598-1709: Bracket 1",
" - Speedo 1709-1820: Bracket 2",
"SOC Volt Table:",
" - 1331/1600MHz tables are not modified",
" - 1633-1866MHz:",
" - Bracket 0: 700mV",
" - Bracket 1: 675mV",
" - Bracket 2: 650mV",
" - 1900-2133MHz:",
" - Bracket 0: 725mV",
" - Bracket 1: 700mV",
" - Bracket 2: 675mV",
" - 2166-2400MHz:",
" - Bracket 0: 750mV",
" - Bracket 1: 725mV",
" - Bracket 2: 700mV",
" - 2433-2666MHz:",
" - Bracket 0: 850mV",
" - Bracket 1: 825mV",
" - Bracket 2: 800mV",
" - 2700-2933MHz:",
" - Bracket 0: 950mV",
" - Bracket 1: 925mV",
" - Bracket 2: 900mV",
" - 2966-3200MHz:",
" - Bracket 0: 1050mV",
" - Bracket 1: 1025mV",
" - Bracket 2: 1000mV",
"Default: 0"
};
case KipConfigValue_marikoSocVmax:
return {
"The maximum available SOC Voltage that the DVB-adjusted table can use",
"Default: Do not override"
};
case KipConfigValue_hpMode:
return {
"When enabled, disables RAM powerdown. Helps with latency significantly",
"Default: OFF"
};
case KipConfigValue_commonEmcMemVolt:
return {
"RAM VDD2 voltage",
"Increasing this WILL NOT increase your maximum frequency, but may help with timing reduction.",
"Undervolting RAM is pointless and may hurt performance and stability",
"Default: 1175 mV"
};
case KipConfigValue_marikoEmcVddqVolt:
return {
"RAM VDDQ voltage",
"Increasing this may help, but the default value is usually good enough.",
"Undervolting RAM is pointless and may hurt performance and stability",
"Default: 600 mV"
};
case KipConfigValue_stepMode:
return {
"The step that RAM clocks take.",
"Options (with examples):",
" - 66MHz - 66 MHz step (ex. 1600, 1666, 1733, etc.)",
" - 100MHz - 100 MHz step (ex. 1600, 1700, 1800, etc.)",
" - 133MHz - 66 MHz step (ex. 1600, 1733, 1866, etc.)",
" - JEDEC:",
" - 1600, 1866, 1996, 2133, 2400, 2666, 2933 and 3200 MHz are used",
"The RAM max clock will always be available regardless of the step mode, but the intermediate frequencies will be limited by the selected step mode.",
"This setting does not affect performance and the option you choose mostly is based on your personal taste",
"33 MHz step mode is not possible due to certian limitations of Horizon OS",
"Default: 66 MHz",
};
case KipConfigValue_marikoEmcMaxClock:
return {
"The maximum RAM frequency available.",
"Higher frequencies may cause instability, so increase this gradually and test for stability.",
"Default: 2133 MHz"
};
case KipConfigValue_eristaEmcMaxClock:
case KipConfigValue_eristaEmcMaxClock1:
case KipConfigValue_eristaEmcMaxClock2:
return {
"The RAM frequency used in the particular slot. Higher frequencies may cause instability, so increase this gradually and test for stability.",
"Default: Disabled (1600 MHz)"
};
case KipConfigValue_t1_tRCD:
return {
"RAS-to-CAS delay",
"Default: 0"
};
case KipConfigValue_t2_tRP:
return {
"Row precharge time",
"Default: 0"
};
case KipConfigValue_t3_tRAS:
return {
"Row active time",
"Default: 0"
};
case KipConfigValue_t4_tRRD:
return {
"Row refresh time",
"Default: 0"
};
case KipConfigValue_t5_tRFC:
return {
"Refresh Cycle Time",
"Default: 0"
};
case KipConfigValue_t6_tRTW:
return {
"Read To Write (High bracket)",
"Default: 0"
};
case KipConfigValue_t7_tWTR:
return {
"Write To Read (High bracket)",
"Default: 0"
};
case KipConfigValue_t8_tREFI:
return {
"Refresh command interval",
"Default: 0"
};
case KipConfigValue_timingEmcTbreak:
return {
"Frequency where t6 and t7 break between the low and high brackets",
"Example:",
"Tbreak is set to 1866 MHz, and t6Low is set to 4 and t6High is set to 2. At frequencies below 1866 MHz, t6 will be 4, and at frequencies above 1866 MHz, t6 will be 2.",
"Default: Disabled"
};
case KipConfigValue_low_t6_tRTW:
return {
"Read To Write (Low bracket)",
"Default: 0"
};
case KipConfigValue_low_t7_tWTR:
return {
"Write To Read (Low bracket)",
"Default: 0"
};
case KipConfigValue_t2_tRP_cap:
return {
"Cap for t2 when 1333WL is used.",
"The default value is sufficient for most RAMs but some may need a lower value",
"Default: 2"
};
case KipConfigValue_t6_tRTW_fine_tune:
return {
"Finetunes the raw calculation of t6",
"Default: 0"
};
case KipConfigValue_t7_tWTR_fine_tune:
return {
"Finetunes the raw calculation of t6",
"Default: 0"
};
case KipConfigValue_write_latency_1333:
case KipConfigValue_write_latency_1600:
case KipConfigValue_write_latency_1866:
case KipConfigValue_write_latency_2133:
case KipConfigValue_read_latency_1333:
case KipConfigValue_read_latency_1600:
case KipConfigValue_read_latency_1866:
case KipConfigValue_read_latency_2133:
return {
"Latency bracket settings",
"Example:",
"If 1333 is set to 2000 MHz, 1600 set to 2500 MHz, 1866 set to 2766 MHz and 2133 set to 2933 MHz:",
"Frequencies below 2000 MHz use 1333, 2033-2500 MHz use 1600, 2533-2766 MHz use 1866 and 2800-2933 MHz use 2133. ",
"Either of these can be ommited and it will work (say you set 1333 to -, then <2000 MHz will use 1600 latency)",
"If all of these parameters are ommited the latency will automatically be calculated as follows:",
"1633-1866 MHz - 1866 WRL",
"1900+ MHz - 2133 WRL",
"These properties apply for both write and read latencies, and you can mix-and-match the brackets if nessesary",
"Default: -"
};
case KipConfigValue_mem_burst_read_latency:
return {
"The read latency for the ram",
"Default: 1600 RL"
};
case KipConfigValue_mem_burst_write_latency:
return {
"The write latency for the ram",
"Default: 1600 WL"
};
case KipConfigValue_marikoCpuUVLow:
return {
"The CPU UV level used before tBreak",
"Default: 0"
};
case KipConfigValue_marikoCpuUVHigh:
return {
"The CPU UV level used after tBreak",
"Default: 0"
};
case KipConfigValue_tableConf:
return {
"The current UV table used. The tbreaks are as follows:",
"1581 MHz tBreak and 1683 MHz tBreak use their respective tBreaks",
"The other tables use 1581 MHz as tBreak",
"The \"Default\" table does not contain frequencies past 1963 MHz and may not undervolt correctly"
};
case KipConfigValue_marikoCpuLowVmin:
return {
"The CPU vmin used before tBreak",
"Default: 620 mV"
};
case KipConfigValue_marikoCpuHighVmin:
return {
"The CPU vmin used after tBreak",
"Default: 750 mV"
};
case KipConfigValue_marikoCpuMaxVolt:
return {
"The maximum voltage that the CPU can use",
"Change this setting with caution!",
"Default: 1120 mV"
};
case KipConfigValue_marikoCpuMaxClock:
return {
"The maximum available CPU clock",
"Default: 1963 MHz"
};
case KipConfigValue_marikoCpuBoostClock:
return {
"The clock used for the CPU in \"boost mode\"",
"Default: 1963 MHz"
};
case KipConfigValue_eristaCpuUV:
return {
"CPU undervolt level",
"Default: 0"
};
case KipConfigValue_eristaCpuUnlock:
return {
"Unlock unsafe CPU clocks",
"Default: OFF"
};
case KipConfigValue_eristaCpuVmin:
return {
"Minimum CPU voltage",
"Default: 825 mV"
};
case KipConfigValue_eristaCpuMaxVolt:
return {
"Maximum CPU voltage",
"Default: 1235 mV"
};
case HocClkConfigValue_EristaMaxCpuClock:
return {
"The maximum available CPU clock",
"Default: 1785 MHz"
};
case KipConfigValue_eristaCpuBoostClock:
return {
"The clock used for the CPU in \"boost mode\"",
"Default: 1785 MHz"
};
case HocClkConfigValue_OverwriteBoostMode:
return {
"If enabled, profiles can override the boost mode setting",
"Default: OFF"
};
case KipConfigValue_marikoGpuUV:
return {
"GPU undervolt level",
"Options:",
" - HiOPT: L4T Custom HiOPT table",
" - HiOPT - 15mV: L4T Custom HiOPT table with a 15mV offset",
" - High UV: The highest undervolt table, reccomended",
"Default: HiOPT"
};
case KipConfigValue_marikoGpuVmin:
return {
"Minimum GPU voltage",
"Note: DVFS may change this value when the RAM clock is changed if the DVFS mode is set to PCV Hijack",
"Default: 610 mV"
};
case KipConfigValue_marikoGpuVmax:
return {
"Maximum GPU voltage",
"Default: 800 mV"
};
case HocClkConfigValue_DVFSMode:
return {
"The mode used for GPU DVFS",
"Adjusts GPU vmin when RAM clock is changed due to a higher requirement",
"Options:",
"- Disabled: disabled...",
"- PCV Hijack: hijack PCV for override",
"Default: PCV Hijack"
};
case HocClkConfigValue_DVFSOffset:
return {
"The offset added/subtracted to the GPU vmin when the RAM clock is changed due to a higher requirement in PCV Hijack mode",
"Default: 0 mV (Disabled)"
};
case KipConfigValue_eristaGpuUV:
return {
"GPU undervolt level",
"Options:",
" - HiOPT: L4T Custom HiOPT table",
" - HiOPT - 15mV: L4T Custom HiOPT table with a 15mV offset",
" - High UV: The highest undervolt table, reccomended",
"Default: HiOPT"
};
case KipConfigValue_eristaGpuVmin:
return {
"Minimum GPU voltage",
"Default: 810 mV (812mV as erista is stepped my 6.5mV instead of 5mV)"
};
case KipConfigValue_commonGpuVoltOffset:
return {
"The offset added/subtracted to all AUTO GPU voltages",
"Default: 0 mV (Disabled)"
};
case HocClkConfigValue_GPUScheduling:
return {
"The scheduling method used for GPU clocks",
"Options:",
"- Do Not Override: Do not override existing scheduling mode",
"- Disabled: Disables GPU scheduling, 99.7% GPU max load",
"- Enabled: Enables GPU scheduling, 96.5% GPU max load",
"Default: Do not override"
};
default:
return {};
}
}

View File

@@ -0,0 +1,23 @@
/*
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#pragma once
#include "misc_gui.h"
#include <vector>
#include <string>
std::vector<std::string> ConfigInfoStrings(HocClkConfigValue val, bool isMariko, bool isHoag);

View File

@@ -0,0 +1,88 @@
/*
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#include "info_gui.h"
#include "ult_ext.h"
#include <sstream>
InfoGui::InfoGui(std::string title, std::vector<std::string> strings)
: m_title(std::move(title)), m_strings(std::move(strings)) {}
static constexpr s32 TEXT_SIZE = 16;
static constexpr s32 LINE_H = 22;
static constexpr s32 PARA_GAP = 10;
static constexpr s32 MARGIN_L = 20;
static constexpr s32 MARGIN_R = 35;
static std::vector<std::string> wrapText(const std::string& text, s32 maxWidth)
{
constexpr float CHAR_W = 10.0f;
// Preserve leading whitespace as an indent prefix for wrapped continuation lines.
std::string indent;
for (char c : text) {
if (c == ' ') indent += ' ';
else break;
}
std::vector<std::string> lines;
std::istringstream ss(text);
std::string word, line = indent; // seed with indent so first word inherits it
bool first = true;
while (ss >> word) {
std::string candidate = (first && !indent.empty()) ? indent + word
: line.empty() ? word
: line + " " + word;
first = false;
if (static_cast<s32>(candidate.size() * CHAR_W) <= maxWidth)
line = std::move(candidate);
else {
if (!line.empty() && line != indent) lines.push_back(line);
line = indent + word;
}
}
if (!line.empty() && line != indent) lines.push_back(line);
if (lines.empty()) lines.emplace_back("");
return lines;
}
void InfoGui::listUI()
{
this->listElement->addItem(new tsl::elm::CategoryHeader(m_title));
const s32 maxWidth = tsl::cfg::FramebufferWidth - MARGIN_L - MARGIN_R;
for (const auto& para : m_strings) {
for (const auto& lineText : wrapText(para, maxWidth)) {
auto* d = new FocusableDrawer(
[lineText](tsl::gfx::Renderer* r, s32 x, s32 y, s32 w, s32 h) {
r->drawString((lineText + "\n").c_str(), false,
x + MARGIN_L, y + LINE_H - 5,
TEXT_SIZE, tsl::style::color::ColorText);
});
d->setBoundaries(0, 0, tsl::cfg::FramebufferWidth, LINE_H);
this->listElement->addItem(d, LINE_H);
}
// paragraph gap
auto* gap = new tsl::elm::CustomDrawer(
[](tsl::gfx::Renderer*, s32, s32, s32, s32) {});
gap->setBoundaries(0, 0, tsl::cfg::FramebufferWidth, PARA_GAP);
this->listElement->addItem(gap, PARA_GAP);
}
}

View File

@@ -1,5 +1,6 @@
/* /*
* Copyright (c) ppkantorski (bord2death) *
* Copyright (c) Souldbminer, Lightos_ and Horizon OC Contributors
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -14,19 +15,19 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
#pragma once #pragma once
#include "base_menu_gui.h"
#include <string>
#include <vector>
#include <switch.h> // for Service, Result, hosversionBefore(), smGetService(), serviceClose(), etc. class InfoGui : public BaseMenuGui
#include "rgltr.h" // for RgltrSession, PowerDomainId, etc. {
public:
InfoGui(std::string title, std::vector<std::string> strings);
~InfoGui() = default;
void listUI() override;
extern Service g_rgltrSrv; private:
std::string m_title;
Result rgltrInitialize(void); std::vector<std::string> m_strings;
void rgltrExit(void); };
Result rgltrOpenSession(RgltrSession* session_out, PowerDomainId module_id);
Result rgltrGetVoltage(RgltrSession* session, u32* out_volt);
void rgltrCloseSession(RgltrSession* session);

View File

@@ -18,6 +18,7 @@
#include "misc_gui.h" #include "misc_gui.h"
#include "fatal_gui.h" #include "fatal_gui.h"
#include "config_info_strings.h"
#include "../format.h" #include "../format.h"
#include <cstdio> #include <cstdio>
#include <cstring> #include <cstring>
@@ -88,7 +89,24 @@ MiscGui::~MiscGui()
void MiscGui::addConfigToggle(HocClkConfigValue configVal, const char* altName, bool kip) { void MiscGui::addConfigToggle(HocClkConfigValue configVal, const char* altName, bool kip) {
const char* configName = altName ? altName : hocclkFormatConfigValue(configVal, true); const char* configName = altName ? altName : hocclkFormatConfigValue(configVal, true);
tsl::elm::ToggleListItem* toggle = new tsl::elm::ToggleListItem(configName, this->configList->values[configVal]); auto infoStrings = ConfigInfoStrings(configVal, IsMariko(), IsHoag());
struct YAwareToggle : tsl::elm::ToggleListItem {
std::vector<std::string> m_info;
std::string m_title;
YAwareToggle(const char* text, bool state, std::string title, std::vector<std::string> info)
: tsl::elm::ToggleListItem(text, state), m_info(std::move(info)), m_title(std::move(title)) {}
bool onClick(u64 keys) override {
if (!m_info.empty() && (keys & HidNpadButton_Y) && !(keys & ~HidNpadButton_Y)) {
tsl::changeTo<InfoGui>(m_title, m_info);
return true;
}
return tsl::elm::ToggleListItem::onClick(keys);
}
};
auto* toggle = new YAwareToggle(configName, this->configList->values[configVal],
configName, std::move(infoStrings));
if (!kip) if (!kip)
toggle->setTextColor(tsl::Color(120, 235, 255, 255)); toggle->setTextColor(tsl::Color(120, 235, 255, 255));
toggle->setStateChangedListener([this, configVal, kip](bool state) { toggle->setStateChangedListener([this, configVal, kip](bool state) {
@@ -106,9 +124,13 @@ void MiscGui::addConfigToggle(HocClkConfigValue configVal, const char* altName,
} }
void MiscGui::addConfigTrackbar(HocClkConfigValue configVal, const char* altName, const ValueRange& range, bool kip) { void MiscGui::addConfigTrackbar(HocClkConfigValue configVal, const char* altName, const ValueRange& range, bool kip) {
auto infoStrings = ConfigInfoStrings(configVal, IsMariko(), IsHoag());
struct IndexedBar : tsl::elm::NamedStepTrackBar { struct IndexedBar : tsl::elm::NamedStepTrackBar {
IndexedBar(const char* label, const ValueRange& r) std::vector<std::string> m_info;
: tsl::elm::NamedStepTrackBar("", {""}, true, label) { std::string m_title;
IndexedBar(const char* label, const ValueRange& r, std::string title, std::vector<std::string> info)
: tsl::elm::NamedStepTrackBar("", {""}, true, label),
m_info(std::move(info)), m_title(std::move(title)) {
m_stepDescriptions.clear(); m_stepDescriptions.clear();
u32 numSteps = (r.max - r.min) / r.step + 1; u32 numSteps = (r.max - r.min) / r.step + 1;
for (u32 i = 0; i < numSteps; i++) { for (u32 i = 0; i < numSteps; i++) {
@@ -120,9 +142,17 @@ void MiscGui::addConfigTrackbar(HocClkConfigValue configVal, const char* altName
m_numSteps = (u8)m_stepDescriptions.size(); m_numSteps = (u8)m_stepDescriptions.size();
m_selection = m_stepDescriptions[0]; m_selection = m_stepDescriptions[0];
} }
bool handleInput(u64 keysDown, u64 keysHeld, const HidTouchState& touchPos,
HidAnalogStickState leftJoyStick, HidAnalogStickState rightJoyStick) override {
if (!m_info.empty() && (keysDown & HidNpadButton_Y) && !(keysDown & ~HidNpadButton_Y)) {
tsl::changeTo<InfoGui>(m_title, m_info);
return true;
}
return tsl::elm::NamedStepTrackBar::handleInput(keysDown, keysHeld, touchPos, leftJoyStick, rightJoyStick);
}
}; };
const char* name = altName ? altName : hocclkFormatConfigValue(configVal, true); const char* name = altName ? altName : hocclkFormatConfigValue(configVal, true);
auto* bar = new IndexedBar(name, range); auto* bar = new IndexedBar(name, range, name, std::move(infoStrings));
u32 cur = (u32)this->configList->values[configVal]; u32 cur = (u32)this->configList->values[configVal];
u16 curStep = 0; u16 curStep = 0;
if (cur >= range.min && cur <= range.max && range.step > 0 && (cur - range.min) % range.step == 0) if (cur >= range.min && cur <= range.max && range.step > 0 && (cur - range.min) % range.step == 0)
@@ -141,7 +171,25 @@ void MiscGui::addMappedConfigTrackbar(HocClkConfigValue configVal, const char* a
std::vector<u32> vals, std::vector<u32> vals,
std::initializer_list<std::string> names, bool kip) { std::initializer_list<std::string> names, bool kip) {
const char* name = altName ? altName : hocclkFormatConfigValue(configVal, true); const char* name = altName ? altName : hocclkFormatConfigValue(configVal, true);
auto* bar = new tsl::elm::NamedStepTrackBar("", names, true, name); auto infoStrings = ConfigInfoStrings(configVal, IsMariko(), IsHoag());
struct YAwareTrackBar : tsl::elm::NamedStepTrackBar {
std::vector<std::string> m_info;
std::string m_title;
YAwareTrackBar(const char* label, std::initializer_list<std::string> steps, std::string title, std::vector<std::string> info)
: tsl::elm::NamedStepTrackBar("", steps, true, label),
m_info(std::move(info)), m_title(std::move(title)) {}
bool handleInput(u64 keysDown, u64 keysHeld, const HidTouchState& touchPos,
HidAnalogStickState leftJoyStick, HidAnalogStickState rightJoyStick) override {
if (!m_info.empty() && (keysDown & HidNpadButton_Y) && !(keysDown & ~HidNpadButton_Y)) {
tsl::changeTo<InfoGui>(m_title, m_info);
return true;
}
return tsl::elm::NamedStepTrackBar::handleInput(keysDown, keysHeld, touchPos, leftJoyStick, rightJoyStick);
}
};
auto* bar = new YAwareTrackBar(name, names, name, std::move(infoStrings));
u32 cur = (u32)this->configList->values[configVal]; u32 cur = (u32)this->configList->values[configVal];
u16 curIdx = 0; u16 curIdx = 0;
for (u16 i = 0; i < (u16)vals.size(); i++) { for (u16 i = 0; i < (u16)vals.size(); i++) {
@@ -170,6 +218,7 @@ void MiscGui::addConfigButton(HocClkConfigValue configVal,
bool kip) bool kip)
{ {
const char* configName = altName ? altName : hocclkFormatConfigValue(configVal, true); const char* configName = altName ? altName : hocclkFormatConfigValue(configVal, true);
auto infoStrings = ConfigInfoStrings(configVal, IsMariko(), IsHoag());
tsl::elm::ListItem* listItem = new tsl::elm::ListItem(configName); tsl::elm::ListItem* listItem = new tsl::elm::ListItem(configName);
if (!kip) if (!kip)
@@ -203,8 +252,14 @@ void MiscGui::addConfigButton(HocClkConfigValue configVal,
ValueThresholds thresholdsCopy = (thresholds ? *thresholds : ValueThresholds{}); ValueThresholds thresholdsCopy = (thresholds ? *thresholds : ValueThresholds{});
listItem->setClickListener( listItem->setClickListener(
[this, configVal, range, categoryName, thresholdsCopy, labels, showDefaultValue, kip](u64 keys) [this, configVal, range, categoryName, thresholdsCopy, labels, showDefaultValue, kip,
infoStrings = std::move(infoStrings), configName = std::string(configName)](u64 keys)
{ {
if (!infoStrings.empty() && (keys & HidNpadButton_Y) && !(keys & ~HidNpadButton_Y)) {
tsl::changeTo<InfoGui>(configName, infoStrings);
return true;
}
if ((keys & HidNpadButton_A) == 0) if ((keys & HidNpadButton_A) == 0)
return false; return false;
@@ -287,6 +342,8 @@ void MiscGui::addConfigButtonS(HocClkConfigValue configVal,
const char* subText, const char* subText,
bool kip) bool kip)
{ {
const char* configName = altName ? altName : hocclkFormatConfigValue(configVal, true);
auto infoStrings = ConfigInfoStrings(configVal, IsMariko(), IsHoag());
tsl::elm::ListItem* listItem = new tsl::elm::ListItem(""); tsl::elm::ListItem* listItem = new tsl::elm::ListItem("");
if (!kip) if (!kip)
listItem->setTextColor(tsl::Color(120, 235, 255, 255)); listItem->setTextColor(tsl::Color(120, 235, 255, 255));
@@ -321,8 +378,14 @@ void MiscGui::addConfigButtonS(HocClkConfigValue configVal,
ValueThresholds thresholdsCopy = (thresholds ? *thresholds : ValueThresholds{}); ValueThresholds thresholdsCopy = (thresholds ? *thresholds : ValueThresholds{});
listItem->setClickListener( listItem->setClickListener(
[this, configVal, range, categoryName, thresholdsCopy, labels, showDefaultValue, kip](u64 keys) [this, configVal, range, categoryName, thresholdsCopy, labels, showDefaultValue, kip,
infoStrings = std::move(infoStrings), configName = std::string(configName)](u64 keys)
{ {
if (!infoStrings.empty() && (keys & HidNpadButton_Y) && !(keys & ~HidNpadButton_Y)) {
tsl::changeTo<InfoGui>(configName, infoStrings);
return true;
}
if ((keys & HidNpadButton_A) == 0) if ((keys & HidNpadButton_A) == 0)
return false; return false;
@@ -410,6 +473,7 @@ void MiscGui::addFreqButton(HocClkConfigValue configVal,
const std::map<uint32_t, std::string>& labels) const std::map<uint32_t, std::string>& labels)
{ {
const char* configName = altName ? altName : hocclkFormatConfigValue(configVal, true); const char* configName = altName ? altName : hocclkFormatConfigValue(configVal, true);
auto infoStrings = ConfigInfoStrings(configVal, IsMariko(), IsHoag());
tsl::elm::ListItem* listItem = new tsl::elm::ListItem(configName); tsl::elm::ListItem* listItem = new tsl::elm::ListItem(configName);
@@ -419,8 +483,14 @@ void MiscGui::addFreqButton(HocClkConfigValue configVal,
listItem->setValue(valueText); listItem->setValue(valueText);
listItem->setClickListener( listItem->setClickListener(
[this, configVal, module, labels](u64 keys) [this, configVal, module, labels,
infoStrings = std::move(infoStrings), configName = std::string(configName)](u64 keys)
{ {
if (!infoStrings.empty() && (keys & HidNpadButton_Y) && !(keys & ~HidNpadButton_Y)) {
tsl::changeTo<InfoGui>(configName, infoStrings);
return true;
}
if ((keys & HidNpadButton_A) == 0) if ((keys & HidNpadButton_A) == 0)
return false; return false;
@@ -483,8 +553,11 @@ void MiscGui::listUI()
tsl::elm::CustomDrawer* rebootSetWarning = new tsl::elm::CustomDrawer([](tsl::gfx::Renderer *renderer, s32 x, s32 y, s32 w, s32 h) { tsl::elm::CustomDrawer* rebootSetWarning = new tsl::elm::CustomDrawer([](tsl::gfx::Renderer *renderer, s32 x, s32 y, s32 w, s32 h) {
renderer->drawString("\uE150 Settings marked in blue", false, x + 20, y + 30, 18, tsl::style::color::ColorText); renderer->drawString("\uE150 Settings marked in blue", false, x + 20, y + 30, 18, tsl::style::color::ColorText);
renderer->drawString("don't require a reboot to apply!", false, x + 20, y + 50, 18, tsl::style::color::ColorText); renderer->drawString("don't require a reboot to apply!", false, x + 20, y + 50, 18, tsl::style::color::ColorText);
renderer->drawString("You can also press \ue0e3 to show", false, x + 20, y + 70, 18, tsl::style::color::ColorText);
renderer->drawString("information about each setting.", false, x + 20, y + 90, 18, tsl::style::color::ColorText);
}); });
rebootSetWarning->setBoundaries(0, 0, tsl::cfg::FramebufferWidth, 70); rebootSetWarning->setBoundaries(0, 0, tsl::cfg::FramebufferWidth, 110);
this->listElement->addItem(rebootSetWarning); this->listElement->addItem(rebootSetWarning);
tsl::elm::ListItem* sysmoduleSettingsSubMenu = new tsl::elm::ListItem("General Settings"); tsl::elm::ListItem* sysmoduleSettingsSubMenu = new tsl::elm::ListItem("General Settings");
@@ -1350,7 +1423,12 @@ protected:
tsl::elm::ListItem* item = new tsl::elm::ListItem(label); tsl::elm::ListItem* item = new tsl::elm::ListItem(label);
item->setValue(makeValueText(currentVal)); item->setValue(makeValueText(currentVal));
item->setClickListener([this, tierIdx, thisKey, keysArr](u64 keys) -> bool { item->setClickListener([this, tierIdx, thisKey, keysArr, label](u64 keys) -> bool {
auto infoStrings = ConfigInfoStrings(thisKey, IsMariko(), IsHoag());
if (!infoStrings.empty() && (keys & HidNpadButton_Y) && !(keys & ~HidNpadButton_Y)) {
tsl::changeTo<InfoGui>(std::string(label), infoStrings);
return true;
}
if ((keys & HidNpadButton_A) == 0) if ((keys & HidNpadButton_A) == 0)
return false; return false;

View File

@@ -25,6 +25,7 @@
#include <vector> #include <vector>
#include "freq_choice_gui.h" #include "freq_choice_gui.h"
#include "value_choice_gui.h" #include "value_choice_gui.h"
#include "info_gui.h"
class MiscGui : public BaseMenuGui class MiscGui : public BaseMenuGui
{ {
public: public:

View File

@@ -95,6 +95,18 @@ public:
} }
}; };
class FocusableDrawer : public tsl::elm::CustomDrawer {
public:
template<typename... Args>
FocusableDrawer(Args&&... args) : tsl::elm::CustomDrawer(std::forward<Args>(args)...) {
m_isItem = true;
}
Element* requestFocus(Element*, tsl::FocusDirection) override {
return this;
}
void drawHighlight(tsl::gfx::Renderer*) override {}
};
class HideableCustomDrawer : public tsl::elm::Element { class HideableCustomDrawer : public tsl::elm::Element {
private: private:
bool visible; bool visible;

View File

@@ -28,8 +28,8 @@ INCLUDES := ../common/include src/hos src/soc src/i2c src/util src/pwr src/ipc
EXEFS_SRC := exefs_src EXEFS_SRC := exefs_src
LIBNAMES := minIni LIBNAMES := minIni
# major minor patch # major minor patch
TARGET_VERSION := 2.3.0 TARGET_VERSION := 2.3.1
KIP_VERSION := 230 KIP_VERSION := 231
CUST_REV := 3 CUST_REV := 3
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------

View File

@@ -37,7 +37,6 @@
#include <registers.h> #include <registers.h>
#include <battery.h> #include <battery.h>
#include "../display/display_refresh_rate.hpp" #include "../display/display_refresh_rate.hpp"
#include <rgltr.h>
#include <notification.h> #include <notification.h>
#include "board.hpp" #include "board.hpp"
@@ -135,9 +134,6 @@ namespace board {
rc = tmp451Initialize(); rc = tmp451Initialize();
ASSERT_RESULT_OK(rc, "tmp451Initialize"); ASSERT_RESULT_OK(rc, "tmp451Initialize");
rc = rgltrInitialize();
ASSERT_RESULT_OK(rc, "rgltrInitialize");
rc = pmdmntInitialize(); rc = pmdmntInitialize();
ASSERT_RESULT_OK(rc, "pmdmntInitialize"); ASSERT_RESULT_OK(rc, "pmdmntInitialize");
@@ -220,7 +216,6 @@ namespace board {
pwmChannelSessionClose(&iCon); pwmChannelSessionClose(&iCon);
pwmExit(); pwmExit();
rgltrExit();
batteryInfoExit(); batteryInfoExit();
pmdmntExit(); pmdmntExit();
nvExit(); nvExit();
@@ -245,7 +240,7 @@ namespace board {
svcCallSecureMonitor(&args); svcCallSecureMonitor(&args);
if (args.X[1] == (MC_REGISTER_BASE + MC_EMEM_CFG_0)) { // if param 1 is identical read failed if (args.X[1] == (MC_REGISTER_BASE + MC_EMEM_CFG_0)) { // if param 1 is identical read failed
notification::writeNotification("Horizon OC\nSecmon read failed!\n This may be a hardware issue!"); notification::writeNotification("Horizon OC\nSecmon-Lesen fehlgeschlagen!\nDies könnte ein Hardwareproblem sein!");
return false; return false;
} }

View File

@@ -27,7 +27,6 @@
#include <switch.h> #include <switch.h>
#include <pwm.h> #include <pwm.h>
#include <cmath> #include <cmath>
#include <rgltr.h>
namespace board { namespace board {

View File

@@ -22,13 +22,12 @@
#include <memmem.h> #include <memmem.h>
#include <registers.h> #include <registers.h>
#include <cstring> #include <cstring>
#include <rgltr.h>
#include <battery.h> #include <battery.h>
#include "board.hpp" #include "board.hpp"
#include "board_freq.hpp" #include "board_freq.hpp"
#include "board_volt.hpp" #include "board_volt.hpp"
#include "../file/file_utils.hpp" #include "../file/file_utils.hpp"
#include "../i2c/i2cDrv.h"
namespace board { namespace board {
GpuVoltData voltData = {}; GpuVoltData voltData = {};
@@ -215,59 +214,39 @@ namespace board {
} PowerDomainId; } PowerDomainId;
*/ */
u32 GetVoltage(HocClkVoltage voltage) { u32 GetVoltage(HocClkVoltage voltage) {
RgltrSession session;
Result rc = 0;
u32 out = 0; u32 out = 0;
BatteryChargeInfo info; BatteryChargeInfo info;
switch (voltage) { switch (voltage) {
case HocClkVoltage_SOC: case HocClkVoltage_SOC:
rc = rgltrOpenSession(&session, PcvPowerDomainId_Max77620_Sd0); out = I2c_BuckConverter_GetUvOut(&I2c_SOC);
ASSERT_RESULT_OK(rc, "rgltrOpenSession")
rgltrGetVoltage(&session, &out);
rgltrCloseSession(&session);
break; break;
case HocClkVoltage_EMCVDD2: case HocClkVoltage_EMCVDD2:
rc = rgltrOpenSession(&session, PcvPowerDomainId_Max77620_Sd1); out = I2c_BuckConverter_GetUvOut(&I2c_VDD2);
ASSERT_RESULT_OK(rc, "rgltrOpenSession")
rgltrGetVoltage(&session, &out);
rgltrCloseSession(&session);
break; break;
case HocClkVoltage_CPU: case HocClkVoltage_CPU:
if (GetSocType() == HocClkSocType_Mariko) { if(GetSocType() == HocClkSocType_Mariko) {
rc = rgltrOpenSession(&session, PcvPowerDomainId_Max77621_Cpu); out = I2c_BuckConverter_GetUvOut(&I2c_Mariko_CPU);
} else { } else {
rc = rgltrOpenSession(&session, PcvPowerDomainId_Max77812_Cpu); out = I2c_BuckConverter_GetUvOut(&I2c_Erista_CPU);
} }
ASSERT_RESULT_OK(rc, "rgltrOpenSession")
rgltrGetVoltage(&session, &out);
rgltrCloseSession(&session);
break; break;
case HocClkVoltage_GPU: case HocClkVoltage_GPU:
if (GetSocType() == HocClkSocType_Mariko) { if(GetSocType() == HocClkSocType_Mariko) {
rc = rgltrOpenSession(&session, PcvPowerDomainId_Max77621_Gpu); out = I2c_BuckConverter_GetUvOut(&I2c_Mariko_GPU);
} else { } else {
rc = rgltrOpenSession(&session, PcvPowerDomainId_Max77812_Gpu); out = I2c_BuckConverter_GetUvOut(&I2c_Erista_GPU);
} }
ASSERT_RESULT_OK(rc, "rgltrOpenSession")
rgltrGetVoltage(&session, &out);
rgltrCloseSession(&session);
break; break;
case HocClkVoltage_EMCVDDQ: case HocClkVoltage_EMCVDDQ:
if (GetSocType() == HocClkSocType_Mariko) { if(GetSocType() == HocClkSocType_Mariko) {
rc = rgltrOpenSession(&session, PcvPowerDomainId_Max77812_Dram); out = I2c_BuckConverter_GetUvOut(&I2c_Mariko_DRAM_VDDQ);
ASSERT_RESULT_OK(rc, "rgltrOpenSession")
rgltrGetVoltage(&session, &out);
rgltrCloseSession(&session);
} else { } else {
out = GetVoltage(HocClkVoltage_EMCVDD2); // VDD2 and VDDQ are always connected to the same rail on Erista out = I2c_BuckConverter_GetUvOut(&I2c_VDD2);
} }
break; break;
case HocClkVoltage_Display: case HocClkVoltage_Display:
rc = rgltrOpenSession(&session, PcvPowerDomainId_Max77620_Ldo0); out = I2c_BuckConverter_GetUvOut(&I2c_Display);
ASSERT_RESULT_OK(rc, "rgltrOpenSession")
rgltrGetVoltage(&session, &out);
rgltrCloseSession(&session);
break; break;
case HocClkVoltage_Battery: case HocClkVoltage_Battery:
batteryInfoGetChargeInfo(&info); batteryInfoGetChargeInfo(&info);

View File

@@ -31,7 +31,7 @@ namespace kip {
// if(board::GetSocType() == HocClkSocType_Mariko) { // if(board::GetSocType() == HocClkSocType_Mariko) {
// if(R_FAILED(I2c_BuckConverter_SetMvOut(&I2c_Mariko_DRAM_VDDQ, config::GetConfigValue(KipConfigValue_marikoEmcVddqVolt) / 1000))) { // if(R_FAILED(I2c_BuckConverter_SetMvOut(&I2c_Mariko_DRAM_VDDQ, config::GetConfigValue(KipConfigValue_marikoEmcVddqVolt) / 1000))) {
// fileUtils::LogLine("[clock_manager] Failed set i2c vddq"); // fileUtils::LogLine("[clock_manager] Failed set i2c vddq");
// notification::writeNotification("Horizon OC\nFailed to write I2C\nwhile setting vddq"); // notification::writeNotification("Horizon OC\nI2C-Schreiben fehlgeschlagen!\nbeim Setzen von vddq");
// } // }
// } // }
CustomizeTable table; CustomizeTable table;
@@ -39,7 +39,7 @@ namespace kip {
fp = fopen("sdmc:/atmosphere/kips/hoc.kip", "r"); fp = fopen("sdmc:/atmosphere/kips/hoc.kip", "r");
if (fp == NULL) { if (fp == NULL) {
notification::writeNotification("Horizon OC\nKip opening failed"); notification::writeNotification("Horizon OC\nKIP konnte nicht geöffnet werden!");
kipAvailable = false; kipAvailable = false;
return; return;
} else { } else {
@@ -49,19 +49,19 @@ namespace kip {
if (!cust_read_and_cache("sdmc:/atmosphere/kips/hoc.kip", &table)) { if (!cust_read_and_cache("sdmc:/atmosphere/kips/hoc.kip", &table)) {
fileUtils::LogLine("[kip] Failed to read KIP file"); fileUtils::LogLine("[kip] Failed to read KIP file");
notification::writeNotification("Horizon OC\nKip read failed"); notification::writeNotification("Horizon OC\nKIP konnte nicht gelesen werden!");
return; return;
} }
u32 custRev = cust_get_cust_rev(&table); u32 custRev = cust_get_cust_rev(&table);
u32 kipVersion = cust_get_kip_version(&table); u32 kipVersion = cust_get_kip_version(&table);
if (custRev < CUST_REV || kipVersion < KIP_VERSION) { if (custRev < CUST_REV || kipVersion < KIP_VERSION) {
notification::writeNotification("Horizon OC\nOutdated kip detected!\nPlease update Horizon OC"); notification::writeNotification("Horizon OC\nVeraltetes KIP erkannt!\nBitte Horizon OC aktualisieren");
fileUtils::LogLine("Cust revision: %u", custRev); fileUtils::LogLine("Cust revision: %u", custRev);
fileUtils::LogLine("Kip version: %u", kipVersion); fileUtils::LogLine("Kip version: %u", kipVersion);
return; return;
} else if (custRev > CUST_REV || kipVersion > KIP_VERSION) { } else if (custRev > CUST_REV || kipVersion > KIP_VERSION) {
notification::writeNotification("Horizon OC\nOutdated sysmodule detected!\nPlease update Horizon OC"); notification::writeNotification("Horizon OC\nVeraltetes Sysmodule erkannt!\nBitte Horizon OC aktualisieren");
fileUtils::LogLine("Cust revision: %u", custRev); fileUtils::LogLine("Cust revision: %u", custRev);
fileUtils::LogLine("Kip version: %u", kipVersion); fileUtils::LogLine("Kip version: %u", kipVersion);
return; return;
@@ -145,7 +145,7 @@ namespace kip {
if (!cust_write_table("sdmc:/atmosphere/kips/hoc.kip", &table)) { if (!cust_write_table("sdmc:/atmosphere/kips/hoc.kip", &table)) {
fileUtils::LogLine("[kip] Failed to write KIP file"); fileUtils::LogLine("[kip] Failed to write KIP file");
notification::writeNotification("Horizon OC\nKip write failed"); notification::writeNotification("Horizon OC\nKIP konnte nicht geschrieben werden!");
} }
HocClkConfigValueList configValues; HocClkConfigValueList configValues;
@@ -160,7 +160,7 @@ namespace kip {
} }
} else { } else {
fileUtils::LogLine("[kip] Warning: Failed to set config values from KIP"); fileUtils::LogLine("[kip] Warning: Failed to set config values from KIP");
notification::writeNotification("Horizon OC\nKip config set failed"); notification::writeNotification("Horizon OC\nKIP-Konfiguration konnte nicht gesetzt werden!");
} }
} }
@@ -172,7 +172,7 @@ namespace kip {
fp = fopen("sdmc:/atmosphere/kips/hoc.kip", "r"); fp = fopen("sdmc:/atmosphere/kips/hoc.kip", "r");
if (fp == NULL) { if (fp == NULL) {
notification::writeNotification("Horizon OC\nKip opening failed"); notification::writeNotification("Horizon OC\nKIP konnte nicht geöffnet werden!");
kipAvailable = false; kipAvailable = false;
return; return;
} else { } else {
@@ -186,23 +186,23 @@ namespace kip {
CustomizeTable table; CustomizeTable table;
if (!cust_read_and_cache("sdmc:/atmosphere/kips/hoc.kip", &table)) { if (!cust_read_and_cache("sdmc:/atmosphere/kips/hoc.kip", &table)) {
fileUtils::LogLine("[kip] Failed to read KIP file for GetKipData"); fileUtils::LogLine("[kip] Failed to read KIP file for GetKipData");
notification::writeNotification("Horizon OC\nKip read failed"); notification::writeNotification("Horizon OC\nKIP konnte nicht gelesen werden!");
return; return;
} }
// if(cust_get_cust_rev(&table) != CUST_REV) { // if(cust_get_cust_rev(&table) != CUST_REV) {
// notification::writeNotification("Horizon OC\nKip version mismatch\nPlease reinstall Horizon OC"); // notification::writeNotification("Horizon OC\nKIP-Versionskonflikt!\nBitte Horizon OC neu installieren");
// return; // return;
// } // }
if ((u64)crc32::checksum_file("sdmc:/atmosphere/kips/hoc.kip") != config::GetConfigValue(KipCrc32) && !config::GetConfigValue(HocClkConfigValue_IsFirstLoad)) { if ((u64)crc32::checksum_file("sdmc:/atmosphere/kips/hoc.kip") != config::GetConfigValue(KipCrc32) && !config::GetConfigValue(HocClkConfigValue_IsFirstLoad)) {
SetKipData(); SetKipData();
notification::writeNotification("Horizon OC\nKIP has been updated\nPlease reboot your console"); notification::writeNotification("Horizon OC\nKIP wurde aktualisiert\nBitte Konsole neu starten");
return; return;
} }
if (config::GetConfigValue(HocClkConfigValue_IsFirstLoad) == true) { if (config::GetConfigValue(HocClkConfigValue_IsFirstLoad) == true) {
configValues.values[HocClkConfigValue_IsFirstLoad] = (u64)false; configValues.values[HocClkConfigValue_IsFirstLoad] = (u64)false;
notification::writeNotification("Horizon OC has been installed"); notification::writeNotification("Horizon OC wurde installiert");
} }
configValues.values[KipCrc32] = (u64)crc32::checksum_file("sdmc:/atmosphere/kips/hoc.kip"); // write checksum configValues.values[KipCrc32] = (u64)crc32::checksum_file("sdmc:/atmosphere/kips/hoc.kip"); // write checksum
@@ -212,12 +212,12 @@ namespace kip {
u32 custRev = cust_get_cust_rev(&table); u32 custRev = cust_get_cust_rev(&table);
u32 kipVersion = cust_get_kip_version(&table); u32 kipVersion = cust_get_kip_version(&table);
if (custRev < CUST_REV || kipVersion < KIP_VERSION) { if (custRev < CUST_REV || kipVersion < KIP_VERSION) {
notification::writeNotification("Horizon OC\nOutdated kip detected!\nPlease update Horizon OC"); notification::writeNotification("Horizon OC\nVeraltetes KIP erkannt!\nBitte Horizon OC aktualisieren");
fileUtils::LogLine("Cust revision: %u", custRev); fileUtils::LogLine("Cust revision: %u", custRev);
fileUtils::LogLine("Kip version: %u", kipVersion); fileUtils::LogLine("Kip version: %u", kipVersion);
return; return;
} else if (custRev > CUST_REV || kipVersion > KIP_VERSION) { } else if (custRev > CUST_REV || kipVersion > KIP_VERSION) {
notification::writeNotification("Horizon OC\nOutdated sysmodule detected!\nPlease update Horizon OC"); notification::writeNotification("Horizon OC\nVeraltetes Sysmodule erkannt!\nBitte Horizon OC aktualisieren");
fileUtils::LogLine("Cust revision: %u", custRev); fileUtils::LogLine("Cust revision: %u", custRev);
fileUtils::LogLine("Kip version: %u", kipVersion); fileUtils::LogLine("Kip version: %u", kipVersion);
return; return;
@@ -306,11 +306,11 @@ namespace kip {
} }
} else { } else {
fileUtils::LogLine("[kip] Warning: Failed to set config values from KIP"); fileUtils::LogLine("[kip] Warning: Failed to set config values from KIP");
notification::writeNotification("Horizon OC\nKip config set failed"); notification::writeNotification("Horizon OC\nKIP-Konfiguration konnte nicht gesetzt werden!");
} }
} else { } else {
fileUtils::LogLine("[kip] Error: Config value list buffer size mismatch"); fileUtils::LogLine("[kip] Error: Config value list buffer size mismatch");
notification::writeNotification("Horizon OC\nConfig Buffer Mismatch"); notification::writeNotification("Horizon OC\nKonfigurationspuffer stimmt nicht überein");
} }
} }
} }

View File

@@ -1,38 +0,0 @@
/*
* Copyright (c) ppkantorski (bord2death)
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#pragma once
#include <switch.h>
#include "pcv_types.h"
typedef struct {
Service s;
} RgltrSession;
Result rgltrInitialize(void);
void rgltrExit(void);
Service* rgltrGetServiceSession(void);
Result rgltrOpenSession(RgltrSession* session_out, PowerDomainId module_id);
void rgltrCloseSession(RgltrSession* session);
Result rgltrGetVoltage(RgltrSession* session, u32 *out_volt);
Result rgltrGetPowerModuleNumLimit(u32 *out);
Result rgltrGetVoltageEnabled(RgltrSession* session, u32 *out);
Result rgltrRequestVoltage(RgltrSession* session, u32 microvolt);
Result rgltrCancelVoltageRequest(RgltrSession* session);

View File

@@ -1,66 +0,0 @@
/*
* Copyright (c) ppkantorski (bord2death)
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#include <switch.h>
#include "rgltr.h"
#include "rgltr_services.h" // for extern Service g_rgltrSrv, etc.
// Global service handle
Service g_rgltrSrv;
Result rgltrInitialize(void) {
if (hosversionBefore(8, 0, 0)) {
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
}
return smGetService(&g_rgltrSrv, "rgltr");
}
void rgltrExit(void) {
serviceClose(&g_rgltrSrv);
}
Result rgltrOpenSession(RgltrSession* session_out, PowerDomainId module_id) {
const u32 in = (u32)module_id;
return serviceDispatchIn(
&g_rgltrSrv,
0,
in,
.out_num_objects = 1,
.out_objects = &session_out->s
);
}
Result rgltrGetVoltage(RgltrSession* session, u32* out_volt) {
u32 temp = 0;
Result rc = serviceDispatchOut(&session->s, 4, temp);
if (R_SUCCEEDED(rc)) {
*out_volt = temp;
}
return rc;
}
Result rgltrRequestVoltage(RgltrSession* session, u32 microvolt) {
return serviceDispatchIn(&session->s, 5, microvolt);
}
Result rgltrCancelVoltageRequest(RgltrSession* session) {
return serviceDispatch(&session->s, 6);
}
void rgltrCloseSession(RgltrSession* session) {
serviceClose(&session->s);
}

View File

@@ -103,6 +103,10 @@ u32 I2c_BuckConverter_MultiplierToMvOut(const I2c_BuckConverter_Domain* domain,
return (domain->uv_min + domain->uv_step * multiplier) / 1000; return (domain->uv_min + domain->uv_step * multiplier) / 1000;
} }
u32 I2c_BuckConverter_MultiplierToUvOut(const I2c_BuckConverter_Domain* domain, u8 multiplier) {
return domain->uv_min + domain->uv_step * multiplier;
}
u8 I2c_BuckConverter_MvOutToMultiplier(const I2c_BuckConverter_Domain* domain, u32 mvolt) { u8 I2c_BuckConverter_MvOutToMultiplier(const I2c_BuckConverter_Domain* domain, u32 mvolt) {
u32 uvolt = mvolt * 1000; u32 uvolt = mvolt * 1000;
if (uvolt < domain->uv_min) if (uvolt < domain->uv_min)
@@ -129,6 +133,22 @@ u32 I2c_BuckConverter_GetMvOut(const I2c_BuckConverter_Domain* domain) {
return I2c_BuckConverter_MultiplierToMvOut(domain, val & domain->volt_mask); return I2c_BuckConverter_MultiplierToMvOut(domain, val & domain->volt_mask);
} }
u32 I2c_BuckConverter_GetUvOut(const I2c_BuckConverter_Domain* domain) {
u8 val;
// Retry 5 times if received POR value
for (int i = 0; i < 5; i++) {
if (R_FAILED(I2cRead_OutU8(domain->device, domain->reg, &val)))
return 0u;
// Wait 1us
svcSleepThread(1E3);
if (!domain->por_val || val != domain->por_val)
break;
}
return I2c_BuckConverter_MultiplierToUvOut(domain, val & domain->volt_mask);
}
Result I2c_BuckConverter_SetMvOut(const I2c_BuckConverter_Domain* domain, u32 mvolt) { Result I2c_BuckConverter_SetMvOut(const I2c_BuckConverter_Domain* domain, u32 mvolt) {
u8 val; u8 val;
Result res = I2cRead_OutU8(domain->device, domain->reg, &val); Result res = I2cRead_OutU8(domain->device, domain->reg, &val);

View File

@@ -21,6 +21,7 @@ const u8 MAX17050_CURRENT_REG = 0x0A;
// Buck Converter // Buck Converter
typedef enum I2c_BuckConverter_Reg { typedef enum I2c_BuckConverter_Reg {
I2c_Max77620_SD0VOLT_REG = 0x16,
I2c_Max77620_SD1VOLT_REG = 0x17, // Used for Erista DDR VDDQ+VDD2 / Mariko VDD2 I2c_Max77620_SD1VOLT_REG = 0x17, // Used for Erista DDR VDDQ+VDD2 / Mariko VDD2
I2c_Max77620_LDO0VOLT_REG = 0x23, // Used for Erista DDR VDDQ+VDD2 / Mariko VDD2 I2c_Max77620_LDO0VOLT_REG = 0x23, // Used for Erista DDR VDDQ+VDD2 / Mariko VDD2
I2c_Max77621_VOLT_REG = 0x00, I2c_Max77621_VOLT_REG = 0x00,
@@ -39,16 +40,17 @@ typedef struct I2c_BuckConverter_Domain {
u8 por_val; u8 por_val;
} I2c_BuckConverter_Domain; } I2c_BuckConverter_Domain;
const I2c_BuckConverter_Domain I2c_SOC = { I2cDevice_Max77620Pmic, I2c_Max77620_SD0VOLT_REG, 0x7F, 12500, 600000, 1400000, };
const I2c_BuckConverter_Domain I2c_VDD2 = { I2cDevice_Max77620Pmic, I2c_Max77620_SD1VOLT_REG, 0x7F, 12500, 600000, 1350000, };
const I2c_BuckConverter_Domain I2c_Display = { I2cDevice_Max77620Pmic, I2c_Max77620_LDO0VOLT_REG, 0x3F, 25000, 800000, 1325000, };
const I2c_BuckConverter_Domain I2c_Erista_CPU = { I2cDevice_Max77621Cpu, I2c_Max77621_VOLT_REG, 0x7F, 6250, 606250, 1400000, }; const I2c_BuckConverter_Domain I2c_Erista_CPU = { I2cDevice_Max77621Cpu, I2c_Max77621_VOLT_REG, 0x7F, 6250, 606250, 1400000, };
const I2c_BuckConverter_Domain I2c_Erista_GPU = { I2cDevice_Max77621Gpu, I2c_Max77621_VOLT_REG, 0x7F, 6250, 606250, 1400000, }; const I2c_BuckConverter_Domain I2c_Erista_GPU = { I2cDevice_Max77621Gpu, I2c_Max77621_VOLT_REG, 0x7F, 6250, 606250, 1400000, };
const I2c_BuckConverter_Domain I2c_Erista_DRAM = { I2cDevice_Max77620Pmic, I2c_Max77620_SD1VOLT_REG, 0x3F, 12500, 600000, 1250000, };
const I2c_BuckConverter_Domain I2c_Display = { I2cDevice_Max77620Pmic, I2c_Max77620_LDO0VOLT_REG, 0x7F, 25000, 800000, 1325000, };
const I2c_BuckConverter_Domain I2c_Mariko_CPU = { I2cDevice_Max77812_2, I2c_Max77812_CPUVOLT_REG, 0xFF, 5000, 250000, 1525000, 0x78 }; const I2c_BuckConverter_Domain I2c_Mariko_CPU = { I2cDevice_Max77812_2, I2c_Max77812_CPUVOLT_REG, 0xFF, 5000, 250000, 1525000, 0x78 };
const I2c_BuckConverter_Domain I2c_Mariko_GPU = { I2cDevice_Max77812_2, I2c_Max77812_GPUVOLT_REG, 0xFF, 5000, 250000, 1525000, 0x78 }; const I2c_BuckConverter_Domain I2c_Mariko_GPU = { I2cDevice_Max77812_2, I2c_Max77812_GPUVOLT_REG, 0xFF, 5000, 250000, 1525000, 0x78 };
const I2c_BuckConverter_Domain I2c_Mariko_DRAM_VDDQ = { I2cDevice_Max77812_2, I2c_Max77812_MEMVOLT_REG, 0xFF, 5000, 250000, 700000, 0x78 }; const I2c_BuckConverter_Domain I2c_Mariko_DRAM_VDDQ = { I2cDevice_Max77812_2, I2c_Max77812_MEMVOLT_REG, 0xFF, 5000, 250000, 700000, 0x78 };
const I2c_BuckConverter_Domain I2c_Mariko_DRAM_VDD2 = { I2cDevice_Max77620Pmic, I2c_Max77620_SD1VOLT_REG, 0x7F, 12500, 600000, 1250000, };
u32 I2c_BuckConverter_GetMvOut(const I2c_BuckConverter_Domain* domain); u32 I2c_BuckConverter_GetMvOut(const I2c_BuckConverter_Domain* domain);
u32 I2c_BuckConverter_GetUvOut(const I2c_BuckConverter_Domain* domain);
Result I2c_BuckConverter_SetMvOut(const I2c_BuckConverter_Domain* domain, u32 mvolt); Result I2c_BuckConverter_SetMvOut(const I2c_BuckConverter_Domain* domain, u32 mvolt);
// Bq24193 Battery management // Bq24193 Battery management

214
dist/README.md vendored
View File

@@ -1,214 +0,0 @@
<div align="center">
<img src="assets/logo.png" alt="logo" width="768"/>
---
![License: GPL-2.0](https://img.shields.io/badge/GPL--2.0-red?style=for-the-badge)
![Nintendo Switch](https://img.shields.io/badge/Nintendo_Switch-E60012?style=for-the-badge\&logo=nintendo-switch\&logoColor=white)
[![Discord](https://img.shields.io/badge/Discord-5865F2?style=for-the-badge\&logo=discord\&logoColor=white)](https://dsc.gg/horizonoc)
![VSCode](https://img.shields.io/badge/VSCode-0078D4?style=for-the-badge\&logo=visual%20studio%20code\&logoColor=white)
![Made with Notepad++](assets/np++.png?raw=true)
![C++](https://img.shields.io/badge/C%2B%2B-00599C?style=for-the-badge\&logo=c%2B%2B\&logoColor=white)
![Downloads](https://img.shields.io/github/downloads/Horizon-OC/Horizon-OC/total.svg?style=for-the-badge)
---
</div>
## ⚠️ Disclaimer
> **THIS TOOL CAN BE DANGEROUS IF MISUSED. PROCEED WITH CAUTION.**
> Due to the design of Horizon OS, **overclocking RAM can cause NAND OR SD CORRUPTION.**
> Ensure you have a **full NAND, PROINFO, EMUMMC and SD backup** before proceeding.
---
## About
**Horizon OC** is an open-source overclocking tool for Nintendo Switch consoles running **Atmosphere custom firmware**.
It enables advanced CPU, GPU, and RAM tuning with user-friendly configuration tools.
---
## Default clocks
* **CPU:** Up to 1963MHz (Mariko) / 1785MHz (Erista)
* **GPU:** Up to 1075MHz (Mariko) / 921MHz (Erista)
* **RAM:** Up to 1866/2133MHz (Mariko) / 1600MHz (Erista)
* Over/undervolting support
* Built-in configurator
* Compatible with most homebrew
> It is recommended to read the [guide](https://rentry.co/howtoget60fps) before proceeding, as this can help you get a *significant* performance boost over the default settings, often times with less power draw and heat output
---
## Installation
1. Ensure you have the latest versions of
* [Atmosphere](https://github.com/Atmosphere-NX/Atmosphere)
* [Ultrahand Overlay](https://github.com/ppkantorski/Ultrahand-Overlay)
2. Download and extract the **Horizon OC Package** to the root of your SD card.
3. If using **Hekate**, edit `hekate_ipl.ini` to include:
```
kip1=atmosphere/kips/hoc.kip
```
*(No changes needed if using fusee.)*
---
## Configuration
1. Open the Horizon OC Overlay
2. Open the settings menu
3. Adjust your overclocking settings as desired. A helpful guide can be found [here.](https://rentry.co/mariko#oc-settings-for-horizon-oc)
4. Click **Save KIP Settings** to apply your configuration.
---
## Building from Source
Refer to COMPILATION.md
---
## Clock table
### MEM clocks (mhz)
* 3200 → max on mariko, JEDEC.
* 3166
* 3133
* 3100
* 3066
* 3033
* 3000
* 2966
* 2933 → JEDEC.
* 2900
* 2866
* 2833
* 2800
* 2766
* 2733
* 2700
* 2666 → JEDEC.
* 2633
* 2600
* 2566
* 2533
* 2500
* 2466
* 2433
* 2400 → max on erista, JEDEC.
* 2366
* 2333
* 2300
* 2266
* 2233
* 2200
* 2166
* 2133 → Mariko JEDEC standard max (4266 Modules)
* 2100
* 2066
* 2033
* 2000
* 1996 → JEDEC standard
* 1966
* 1933
* 1900
* 1866 → Mariko JEDEC standard max (3733 Modules)
* 1833
* 1800
* 1766
* 1733
* 1700
* 1666
* 1633
* 1600 → official docked, boost mode, Erista JEDEC standard max (3200 Modules), JEDEC.
* 1331 → official handheld, JEDEC.
* 1065
* 800
* 665
### CPU clocks (mhz)
* 2703 → mariko absolute max, dangerous
* 2601 → unsafe
* 2499
* 2397 → mariko safe max with UV (low speedo)
* 2295
* 2193
* 2091
* 1963 → mariko no UV max clock
* 1887
* 1785 → erista no UV max clock, boost mode
* 1683
* 1581
* 1428
* 1326
* 1224 → sdev oc
* 1122
* 1020 → official docked & handheld
* 918
* 816
* 714
* 612 → sleep mode
### GPU clocks (mhz)
* 1536 → absolute max clock on mariko. very dangerous
* 1459
* 1382
* 1305
* 1267 → NVIDIA T214(mariko) rating
* 1228 → mariko High UV safe clock
* 1152 → mariko hiOpt-15mV max clock
* 1075 → mariko hiOpt max clock. absolute max clock on erista. very dangerous
* 998 → NVIDIA T210 (erista) rating
* 960 (erista only) → erista high uv/hiOpt-15mV safe max clock
* 921 → erista no UV max clock
* 844
* 768 → official docked
* 691
* 614
* 537
* 460 → max handheld
* 384 → official handheld
* 307 → official handheld
* 230
* 153
* 76 → boost mode
**Notes:**
1. On Erista, CPU in handheld is capped to 1581MHz
2. GPU overclock is capped at 460MHz on erista in handheld
3. On Mariko, cap with hiOpt is 614MHz, with hiOpt-15mV it is 691MHz and with High UV it's 768MHz
4. Clocks higher than 768MHz on erista need the official charger is plugged in.
---
## Credits
* **Lightos's Cat** - Cat
* **Souldbminer** - hoc-clk and loader development
* **Lightos** - Loader patches development, hoc-clk development, guides
* **TDRR** - HOC Logo Design
* **tetetete-ctrl** - Website design
* **SciresM** - Atmosphere CFW
* **CTCaer** - L4T, Hekate, proper RAM timings
* **KazushiMe** - Switch OC Suite
* **Hanai3bi (Meha)** - Switch OC Suite, EOS, sys-clk-eos
* **NaGaa95** - L4T-OC kernel, Status Monitor fork
* **B3711 (halop)** - EOS, contributions
* **sys-clk team (m4xw, p-sam, natinusala)** - sys-clk
* **Dominatorul** - Soctherm driver, guides, general help
* **ppkantorski** - Ultrahand sys-clk & Status Monitor fork
* **MasaGratoR and ZachyCatGames** - General help
* **MasaGratoR** - Status Monitor & Display Refresh Rate driver
* **Dominatorul, Samybigio, Arcdelta, Miki, Happy, Winnerboi77, Blaise, Alvise, agjeococh, frost, letum00, and Xenshen** - Testing
* **Samybigio2011, Miki** - Italian translations
* **angelblaster** - Korean translations
* **q1332348216-glitch** - Chinese translations
* **Nvidia** - [Tegra X1 Technical Reference Manual](https://developer.nvidia.com/embedded/dlc/tegra-x1-technical-reference-manual), soctherm driver, L4T

Binary file not shown.