diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/customize.cpp b/Source/Atmosphere/stratosphere/loader/source/oc/customize.cpp
index 8781b4f6..9a570f5a 100644
--- a/Source/Atmosphere/stratosphere/loader/source/oc/customize.cpp
+++ b/Source/Atmosphere/stratosphere/loader/source/oc/customize.cpp
@@ -76,7 +76,9 @@ volatile CustomizeTable C = {
// .mem_burst_latency = 0, // 0 - 1600l, 1 = 1866bl, 2 = 2133bl /* TODO: Remove/fix. */
-.marikoCpuVmin = 600,
+.marikoCpuHighVmin = 750,
+
+.marikoCpuLowVmin = 600,
.eristaGpuVmin = 810,
@@ -318,8 +320,8 @@ volatile CustomizeTable C = {
{ 921600, { }, { 1191317, 8144, -940, 808, -21583, 226 } },
{ 960000, { }, { 1233208, 8144, -940, 808, -21583, 226 } },
{ 998400, { }, { 1233208, 8144, -940, 808, -21583, 226 } },
- { 1036800, { }, { 1275100, 8144, -940, 808, -21583, 226 } },
- { 1075200, { }, { 1275100, 8144, -940, 808, -21583, 226 } },
+ { 1036800, { }, { 1275100, 8144, -940, 808, -21583, 226 } },
+ { 1075200, { }, { 1275100, 8144, -940, 808, -21583, 226 } },
},
/* - Mariko GPU DVFS Table:
@@ -348,7 +350,7 @@ volatile CustomizeTable C = {
},
.marikoGpuDvfsTableSLT = {
- { 76800, {}, { 600000, } },
+ { 76800, {}, { 600000, } },
{ 153600, {}, { 600000, } },
{ 230400, {}, { 600000, } },
{ 307200, {}, { 600000, } },
diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/customize.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/customize.hpp
index 2dcdaff4..a0018d30 100644
--- a/Source/Atmosphere/stratosphere/loader/source/oc/customize.hpp
+++ b/Source/Atmosphere/stratosphere/loader/source/oc/customize.hpp
@@ -16,96 +16,90 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
- */
+*/
- #pragma once
+#pragma once
- #define CUST_REV 11
+#define CUST_REV 11
- #include "oc_common.hpp"
- #include "pcv/pcv_common.hpp"
+#include "oc_common.hpp"
+#include "pcv/pcv_common.hpp"
- namespace ams::ldr::oc {
+namespace ams::ldr::oc {
- #include "mtc_timing_table.hpp"
+#include "mtc_timing_table.hpp"
- enum MtcConfig: u32 {
- AUTO_ADJ = 0,
- AUTO_ADJ_BL = 1,
- };
+enum MtcConfig: u32 {
+ AUTO_ADJ = 0,
+ AUTO_ADJ_BL = 1,
+};
- using CustomizeCpuDvfsTable = pcv::cvb_entry_t[pcv::DvfsTableEntryLimit];
- using CustomizeGpuDvfsTable = pcv::cvb_entry_t[pcv::DvfsTableEntryLimit];
- static_assert(sizeof(CustomizeCpuDvfsTable) == sizeof(CustomizeGpuDvfsTable));
- static_assert(sizeof(CustomizeCpuDvfsTable) == sizeof(pcv::cvb_entry_t) * pcv::DvfsTableEntryLimit);
+using CustomizeCpuDvfsTable = pcv::cvb_entry_t[pcv::DvfsTableEntryLimit];
+using CustomizeGpuDvfsTable = pcv::cvb_entry_t[pcv::DvfsTableEntryLimit];
+static_assert(sizeof(CustomizeCpuDvfsTable) == sizeof(CustomizeGpuDvfsTable));
+static_assert(sizeof(CustomizeCpuDvfsTable) == sizeof(pcv::cvb_entry_t) * pcv::DvfsTableEntryLimit);
- constexpr uint32_t ERISTA_MTC_MAGIC = 0x43544D45; // EMTC
- constexpr uint32_t MARIKO_MTC_MAGIC = 0x43544D4D; // MMTC
+constexpr uint32_t ERISTA_MTC_MAGIC = 0x43544D45; // EMTC
+constexpr uint32_t MARIKO_MTC_MAGIC = 0x43544D4D; // MMTC
- typedef struct CustomizeTable {
- u8 cust[4] = {'C', 'U', 'S', 'T'};
- u32 custRev = CUST_REV;
- u32 mtcConf = AUTO_ADJ;
- u32 hpMode;
- u32 commonCpuBoostClock;
- u32 commonEmcMemVolt;
- u32 eristaCpuMaxVolt;
- u32 eristaEmcMaxClock;
- u32 marikoCpuMaxVolt;
- u32 marikoEmcMaxClock;
- u32 marikoEmcVddqVolt;
- u32 marikoCpuUV;
- u32 marikoGpuUV;
+typedef struct CustomizeTable {
+ u8 cust[4] = {'C', 'U', 'S', 'T'};
+ u32 custRev = CUST_REV;
+ u32 mtcConf = AUTO_ADJ;
+ u32 hpMode;
+ u32 commonCpuBoostClock;
+ u32 commonEmcMemVolt;
+ u32 eristaCpuMaxVolt;
+ u32 eristaEmcMaxClock;
+ u32 marikoCpuMaxVolt;
+ u32 marikoEmcMaxClock;
+ u32 marikoEmcVddqVolt;
+ u32 marikoCpuUV;
+ u32 marikoGpuUV;
- u32 eristaCpuUV;
- u32 eristaGpuUV;
+ u32 eristaCpuUV;
+ u32 eristaGpuUV;
- u32 commonGpuVoltOffset;
+ u32 commonGpuVoltOffset;
- u32 EmcDvbShift;
+ u32 EmcDvbShift;
- // advanced config
- u32 t1_tRCD;
- u32 t2_tRP;
- u32 t3_tRAS;
- u32 t4_tRRD;
- u32 t5_tRFC;
- u32 t6_tRTW;
- u32 t7_tWTR;
- u32 t8_tREFI;
- u32 mem_burst_latency;
+ // advanced config
+ u32 t1_tRCD;
+ u32 t2_tRP;
+ u32 t3_tRAS;
+ u32 t4_tRRD;
+ u32 t5_tRFC;
+ u32 t6_tRTW;
+ u32 t7_tWTR;
+ u32 t8_tREFI;
+ u32 mem_burst_latency;
- u32 marikoCpuVmin;
+ u32 marikoCpuHighVmin;
+ u32 marikoCpuLowVmin;
- u32 eristaGpuVmin;
- u32 marikoGpuVmin;
- u32 marikoGpuVmax;
+ u32 eristaGpuVmin;
+ u32 marikoGpuVmin;
+ u32 marikoGpuVmax;
- u32 marikoGpuVoltArray[24];
- u32 eristaGpuVoltArray[27];
+ u32 marikoGpuVoltArray[24];
+ u32 eristaGpuVoltArray[27];
- CustomizeCpuDvfsTable eristaCpuDvfsTable;
- CustomizeCpuDvfsTable marikoCpuDvfsTable;
- CustomizeCpuDvfsTable marikoCpuDvfsTableSLT;
+ CustomizeCpuDvfsTable eristaCpuDvfsTable;
+ CustomizeCpuDvfsTable marikoCpuDvfsTable;
+ CustomizeCpuDvfsTable marikoCpuDvfsTableSLT;
- CustomizeGpuDvfsTable eristaGpuDvfsTable;
- CustomizeGpuDvfsTable eristaGpuDvfsTableSLT;
- CustomizeGpuDvfsTable eristaGpuDvfsTableHigh;
+ CustomizeGpuDvfsTable eristaGpuDvfsTable;
+ CustomizeGpuDvfsTable eristaGpuDvfsTableSLT;
+ CustomizeGpuDvfsTable eristaGpuDvfsTableHigh;
- CustomizeGpuDvfsTable marikoGpuDvfsTable;
- CustomizeGpuDvfsTable marikoGpuDvfsTableSLT;
- CustomizeGpuDvfsTable marikoGpuDvfsTableHiOPT;
- //EristaMtcTable* eristaMtcTable;
- //MarikoMtcTable* marikoMtcTable;
- } CustomizeTable;
- //static_assert(sizeof(CustomizeTable) == sizeof(u8) * 4 + sizeof(u32) * 10 + sizeof(CustomizeCpuDvfsTable) * 5 + sizeof(void*) * 2);
- //static_assert(sizeof(CustomizeTable) == 7000);
+ CustomizeGpuDvfsTable marikoGpuDvfsTable;
+ CustomizeGpuDvfsTable marikoGpuDvfsTableSLT;
+ CustomizeGpuDvfsTable marikoGpuDvfsTableHiOPT;
+} CustomizeTable;
- extern volatile CustomizeTable C;
+extern volatile CustomizeTable C;
- //extern volatile EristaMtcTable EristaMtcTablePlaceholder;
- //extern volatile MarikoMtcTable MarikoMtcTablePlaceholder;
-
- }
+}
diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/mtc_timing_value.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/mtc_timing_value.hpp
index 08c987b7..c99a3277 100644
--- a/Source/Atmosphere/stratosphere/loader/source/oc/mtc_timing_value.hpp
+++ b/Source/Atmosphere/stratosphere/loader/source/oc/mtc_timing_value.hpp
@@ -1,6 +1,8 @@
/*
* Copyright (c) 2023 hanai3Bi
*
+ * Copyright (c) 2025 Lightos_
+ *
* 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.
@@ -37,15 +39,18 @@ namespace ams::ldr::oc {
/* Set to 4 read and 2 write for 1866bl. */
/* For 2131bl: 8 read and 4 write. */
- const u32 latency_offset_read = 0;
- const u32 latency_offset_write = 0;
+ const u32 rl_offset = 8;
+ const u32 wl_offset = 4;
+
+ const u32 RL = 28 + rl_offset;
+ const u32 WL = 14 + wl_offset;
/* Precharge to Precharge Delay. (Cycles) */
const u32 tPPD = 4;
/* DQS output access time from CK_t/CK_c. */
const double tDQSCK_max = 3.5;
- const double tWPRE = 1.8;
+ const u32 tWPRE = 2;
/* tCK Read postamble. */
const double tRPST = 0.5;
@@ -63,9 +68,6 @@ namespace ams::ldr::oc {
namespace pcv::erista {
const double tCK_avg = 1000'000.0 / C.eristaEmcMaxClock;
- const u32 RL = 28 + latency_offset_read;
- const u32 WL = 14 + latency_offset_write;
-
/* Primary timings. */
const u32 tRCD = tRCD_values[C.t1_tRCD];
const u32 tRPpb = tRP_values[C.t2_tRP];
@@ -111,9 +113,6 @@ namespace ams::ldr::oc {
const u32 tRFCpb = tRFC_values[C.t5_tRFC];
const u32 tWTR = tWTR_values[C.t7_tWTR];
- const u32 RL = 36;
- const u32 WL = 18;
-
const u32 tRC = tRAS + tRPpb;
const u32 tRFCab = tRFCpb * 2;
const double tXSR = (double) (tRFCab + 7.5);
@@ -134,6 +133,11 @@ namespace ams::ldr::oc {
const double tMMRI = tRCD + (tCK_avg * 3);
const double tPDEX2MRR = tMMRI + 10;
const u32 tWTPDEN = tW2P + 1 + CEIL(tDQSS_max / tCK_avg) + CEIL(tDQS2DQ_max / tCK_avg) + 6.0;
+
+ inline u32 obdly = 0x10000002 + wl_offset;
+ const u32 wdv = 0xE + wl_offset;
+ const u32 wsv = 0xC + wl_offset;
+ const u32 wev = 0xA + wl_offset;
}
}
diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.hpp
index 525dcbe7..33f8d72d 100644
--- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.hpp
+++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.hpp
@@ -94,9 +94,7 @@ namespace ams::ldr::oc::pcv
{},
};
- constexpr u32 GpuClkPllLimit = 2600'000;
-
- constexpr u32 GpuClkMax = 1300'000'000;
+ constexpr u32 GpuClkPllLimit = 1300'000'000;
/* GPU Max Clock asm Pattern:
*
diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_erista.cpp b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_erista.cpp
index 15f3db19..3b1aca4a 100644
--- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_erista.cpp
+++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_erista.cpp
@@ -23,24 +23,25 @@
namespace ams::ldr::oc::pcv::erista {
+ /* Remove? */
Result CpuFreqVdd(u32* ptr) {
dvfs_rail* entry = reinterpret_cast(reinterpret_cast(ptr) - offsetof(dvfs_rail, freq));
- PATCH_OFFSET(ptr, GetDvfsTableLastEntry(C.eristaCpuDvfsTable)->freq);
- R_SUCCEED();
-}
-Result GpuVmin(u32 *ptr) {
- if (!C.eristaGpuVmin)
- R_SKIP();
- PATCH_OFFSET(ptr, (int)C.eristaGpuVmin);
+ R_UNLESS(entry->id == 1, ldr::ResultInvalidCpuFreqVddEntry());
+ R_UNLESS(entry->min_mv == 250'000, ldr::ResultInvalidCpuFreqVddEntry());
+ R_UNLESS(entry->step_mv == 5000, ldr::ResultInvalidCpuFreqVddEntry());
+ R_UNLESS(entry->max_mv == 1525'000, ldr::ResultInvalidCpuFreqVddEntry());
+
R_SUCCEED();
}
Result GpuVmin(u32 *ptr) {
- if (!C.eristaGpuVmin)
+ if (!C.eristaGpuVmin) {
R_SKIP();
- PATCH_OFFSET(ptr, (int)C.eristaGpuVmin);
- R_SUCCEED();
+ }
+
+ PATCH_OFFSET(ptr, (int)C.eristaGpuVmin);
+ R_SUCCEED();
}
Result CpuVoltRange(u32 *ptr) {
@@ -68,6 +69,7 @@ Result GpuVmin(u32 *ptr) {
if(!C.eristaCpuUV) {
R_SKIP();
}
+
PATCH_OFFSET(&(entry->dvco_calibration_max), 0x1C);
PATCH_OFFSET(&(entry->tune1_high), 0x10);
PATCH_OFFSET(&(entry->tune_high_margin_millivolts), 0xc);
diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.cpp b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.cpp
index beec6db3..1acee14c 100644
--- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.cpp
+++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.cpp
@@ -66,10 +66,10 @@ namespace ams::ldr::oc::pcv::mariko {
// Patch vmin for slt
if (C.marikoCpuUV) {
if (*(ptr - 5) == 620) {
- PATCH_OFFSET((ptr - 5), C.marikoCpuVmin);
+ PATCH_OFFSET((ptr - 5), C.marikoCpuHighVmin); // hf vmin
}
if (*(ptr - 1) == 620) {
- PATCH_OFFSET((ptr - 1), 600);
+ PATCH_OFFSET((ptr - 1), C.marikoCpuLowVmin); // lf vmin
}
}
R_SUCCEED();
@@ -180,8 +180,16 @@ namespace ams::ldr::oc::pcv::mariko {
}
Result GpuFreqPllLimit(u32 *ptr) {
- int UPPER_GPU_FREQ = -1; // uncap the gpu frequency
- PATCH_OFFSET(ptr, UPPER_GPU_FREQ);
+ clk_pll_param *entry = reinterpret_cast(ptr);
+
+ // All zero except for freq
+ for (size_t i = 1; i < sizeof(clk_pll_param) / sizeof(u32); i++) {
+ R_UNLESS(*(ptr + i) == 0, ldr::ResultInvalidGpuPllEntry());
+ }
+
+ // Double the max clk simply
+ u32 max_clk = entry->freq * 2;
+ entry->freq = max_clk;
R_SUCCEED();
}
@@ -190,7 +198,7 @@ namespace ams::ldr::oc::pcv::mariko {
R_SUCCEED();
}
- void MemMtcTableAutoAdjustBaseLatency(MarikoMtcTable *table) {
+void MemMtcTableAutoAdjustBaseLatency(MarikoMtcTable *table) {
#define WRITE_PARAM_ALL_REG(TABLE, PARAM, VALUE) \
TABLE->burst_regs.PARAM = VALUE; \
TABLE->shadow_regs_ca_train.PARAM = VALUE; \
@@ -213,6 +221,15 @@ namespace ams::ldr::oc::pcv::mariko {
u32 trefbw = refresh_raw + 0x40;
trefbw = MIN(trefbw, static_cast(0x3FFF));
+ /* TODO: Make this less uggly and actually work by finding real clocks */
+ if (C.marikoEmcMaxClock > 3'100'000) {
+ obdly -= 2;
+ }
+
+ if (C.marikoEmcMaxClock > 2'500'000) {
+ obdly -= 2;
+ }
+
WRITE_PARAM_ALL_REG(table, emc_rd_rcd, GET_CYCLE_CEIL(tRCD));
WRITE_PARAM_ALL_REG(table, emc_wr_rcd, GET_CYCLE_CEIL(tRCD));
WRITE_PARAM_ALL_REG(table, emc_rc, GET_CYCLE_CEIL(tRC));
@@ -253,14 +270,14 @@ namespace ams::ldr::oc::pcv::mariko {
WRITE_PARAM_ALL_REG(table, emc_rw2pden, tWTPDEN);
WRITE_PARAM_ALL_REG(table, emc_einput, 0xF);
WRITE_PARAM_ALL_REG(table, emc_einput_duration, 0x31);
- WRITE_PARAM_ALL_REG(table, emc_obdly, 0x10000002);
+ WRITE_PARAM_ALL_REG(table, emc_obdly, obdly);
WRITE_PARAM_ALL_REG(table, emc_ibdly, 0x1000001C);
- WRITE_PARAM_ALL_REG(table, emc_wdv_mask, 0x12);
+ WRITE_PARAM_ALL_REG(table, emc_wdv_mask, wdv);
WRITE_PARAM_ALL_REG(table, emc_quse_width, 0xD);
WRITE_PARAM_ALL_REG(table, emc_quse, 0x2F);
- WRITE_PARAM_ALL_REG(table, emc_wdv, 0x12);
- WRITE_PARAM_ALL_REG(table, emc_wsv, 0x10);
- WRITE_PARAM_ALL_REG(table, emc_wev, 0xE);
+ WRITE_PARAM_ALL_REG(table, emc_wdv, wdv);
+ WRITE_PARAM_ALL_REG(table, emc_wsv, wsv);
+ WRITE_PARAM_ALL_REG(table, emc_wev, wev);
WRITE_PARAM_ALL_REG(table, emc_qrst, 0x00080005);
WRITE_PARAM_ALL_REG(table, emc_qsafe, 0x44);
WRITE_PARAM_ALL_REG(table, emc_tr_qpop, 0x3B);
@@ -640,8 +657,7 @@ namespace ams::ldr::oc::pcv::mariko {
{"CPU Volt Dfll", &CpuVoltDfll, 1, nullptr, 0x0000FFCF},
{"GPU Freq Table", GpuFreqCvbTable, 1, nullptr, GpuCvbDefaultMaxFreq},
{"GPU Freq Asm", &GpuFreqMaxAsm, 2, &GpuMaxClockPatternFn},
- {"GPU Freq Max (Patch 1)", &GpuFreqMax, 1, nullptr, GpuClkMax},
- {"GPU Freq PLL (Patch 2)", &GpuFreqPllLimit, 0, nullptr, GpuClkPllLimit},
+ {"GPU Freq PLL", &GpuFreqPllLimit, 1, nullptr, GpuClkPllLimit},
{"MEM Freq Mtc", &MemFreqMtcTable, 0, nullptr, EmcClkOSLimit},
{"MEM Freq Dvb", &MemFreqDvbTable, 1, nullptr, EmcClkOSLimit},
{"MEM Freq Max", &MemFreqMax, 0, nullptr, EmcClkOSLimit},