EMC voltage for Mariko; Fix #60; Show battery & voltage info in overlay on Erista

- From previous analysis, EMC voltage is set before AMS loads on Mariko, and will not be set again or changed afterwards.

- sys-clk-OC will take care of setting emc voltage on Mariko once it loads.

- OS will not hang at boot as it always boots with EMC @ 1600 MHz.
This commit is contained in:
KazushiM
2023-01-24 23:24:58 +08:00
parent 012cd40a68
commit 120367cf7c
24 changed files with 324 additions and 146 deletions

View File

@@ -20,29 +20,34 @@ namespace ams::ldr::oc {
volatile CustomizeTable C = {
/* DRAM Timing:
* AUTO_ADJ_MARIKO_SAFE: Auto adjust timings for LPDDR4 ≤3733 Mbps specs, 8Gb density (Default).
* AUTO_ADJ_MARIKO_4266: Auto adjust timings for LPDDR4X 4266 Mbps specs, 8Gb density.
* AUTO_ADJ_MARIKO_SAFE_NO_ADJ_ERISTA: Auto adjust timings for Mariko LPDDR4X ≤3733 Mbps specs, 8Gb density; No timing adjustment for Erista. (Default)
* AUTO_ADJ_MARIKO_4266_NO_ADJ_ERISTA: Auto adjust timings for Mariko LPDDR4X 4266 Mbps specs, 8Gb density; No timing adjustments for Erista.
* NO_ADJ_ALL: No timing adjustment for both Erista and Mariko. Might achieve better performance on Mariko but lower maximum frequency is expected.
*/
.mtcConf = AUTO_ADJ_MARIKO_SAFE,
.mtcConf = AUTO_ADJ_MARIKO_SAFE_NO_ADJ_ERISTA,
/* Mariko CPU:
* - Max Clock in kHz:
* Default: 1785000
* >= 2397000 will enable overvolting (> 1120 mV)
* - Boost Clock in kHz:
* Default: 1785000
* Boost clock will be applied when applications request higher CPU frequency for quicker loading.
* - Max Voltage in mV:
* Default voltage: 1120
* 2397000 might be unreachable for some SoCs.
*/
.marikoCpuMaxClock = 2397000,
/* - Boost Clock in kHz:
* Default: 1785000
* Boost clock will be applied when applications request higher CPU frequency for quicker loading.
* This will be set regardless of whether sys-clk is enabled.
*/
.marikoCpuBoostClock = 1785000,
/* - Max Voltage in mV:
* Default voltage: 1120
*/
.marikoCpuMaxVolt = 1235,
/* Mariko GPU:
* - Max Clock in kHz:
* Default: 921600
* NVIDIA Maximum: 1267200
* 1305600 might be unreachable for some SoCs.
*/
.marikoGpuMaxClock = 1305600,
@@ -54,17 +59,22 @@ volatile CustomizeTable C = {
* - Graphical glitches
* - System instabilities
* - NAND corruption
* Timings from auto-adjustment have been tested safe for up to 1996.8 MHz for all DRAM chips.
*/
.marikoEmcMaxClock = 1996800,
/* - RAM Voltage in uV
* Range: 600'000 to 650'000 uV
* Value should be divided evenly by 5'000
* Default: 600'000
* Not enabled by default.
* This will not work without sys-clk-OC.
*/
.marikoEmcVolt = 0,
/* Erista CPU:
* Not tested but enabled by default.
* - Enable Overclock
* - Max Voltage in mV
*/
.eristaCpuOCEnabled= 1,
.eristaCpuMaxVolt = 1257,
.eristaCpuMaxVolt = 1235,
/* Erista EMC:
* - RAM Clock in kHz
@@ -73,13 +83,14 @@ volatile CustomizeTable C = {
* - Graphical glitches
* - System instabilities
* - NAND corruption
* - RAM Voltage in uV
*/
.eristaEmcMaxClock = 1862400,
/* - RAM Voltage in uV
* Range: 600'000 to 1250'000 uV
* Value should be divided evenly by 12'500
* Default(HOS): 1125'000
* Not enabled by default.
*/
.eristaEmcMaxClock = 1862400,
.eristaEmcVolt = 0,
};

View File

@@ -16,29 +16,30 @@
#pragma once
#define CUST_REV 2
#define CUST_REV 3
#include "oc_suite_common.hpp"
#include "oc_common.hpp"
namespace ams::ldr::oc {
#include "mtc_timing_table.hpp"
enum MtcConfig {
AUTO_ADJ_MARIKO_SAFE = 0,
AUTO_ADJ_MARIKO_4266 = 1,
AUTO_ADJ_MARIKO_SAFE_NO_ADJ_ERISTA = 0,
AUTO_ADJ_MARIKO_4266_NO_ADJ_ERISTA = 1,
NO_ADJ_ALL = 2,
};
typedef struct __attribute__((packed)) CustomizeTable {
u8 cust[4] = {'C', 'U', 'S', 'T'};
u16 custRev = CUST_REV;
u16 mtcConf = AUTO_ADJ_MARIKO_SAFE;
u16 mtcConf = AUTO_ADJ_MARIKO_SAFE_NO_ADJ_ERISTA;
u32 marikoCpuMaxClock;
u32 marikoCpuBoostClock;
u32 marikoCpuMaxVolt;
u32 marikoGpuMaxClock;
u32 marikoEmcMaxClock;
u32 eristaCpuOCEnabled;
u32 marikoEmcVolt;
u32 eristaCpuMaxVolt;
u32 eristaEmcMaxClock;
u32 eristaEmcVolt;

View File

@@ -22,7 +22,7 @@
#define LOGGING(fmt, ...) ((void)0)
#define CRASH(msg, ...) { ams::diag::AbortImpl(msg, __PRETTY_FUNCTION__, "", 0); __builtin_unreachable(); }
#else
#include "oc_suite_test.hpp"
#include "oc_test.hpp"
#endif
#include "customize.hpp"
@@ -39,8 +39,9 @@ namespace ams::ldr {
R_DEFINE_ERROR_RESULT(InvalidGpuDvfs, 1008);
R_DEFINE_ERROR_RESULT(InvalidGpuFreqMaxPattern, 1009);
R_DEFINE_ERROR_RESULT(InvalidGpuPllEntry, 1010);
R_DEFINE_ERROR_RESULT(UninitializedPatcher, 1011);
R_DEFINE_ERROR_RESULT(UnsuccessfulPatcher, 1012);
R_DEFINE_ERROR_RESULT(InvalidRegulatorEntry, 1011);
R_DEFINE_ERROR_RESULT(UninitializedPatcher, 1012);
R_DEFINE_ERROR_RESULT(UnsuccessfulPatcher, 1013);
}
namespace ams::ldr::oc {

View File

@@ -16,6 +16,6 @@
#pragma once
#include "oc_suite_common.hpp"
#include "oc_common.hpp"
#include "pcv/pcv.hpp"
#include "ptm/ptm.hpp"

View File

@@ -15,8 +15,8 @@
*/
#ifndef ATMOSPHERE_IS_STRATOSPHERE
#include "oc_suite_test.hpp"
#include "oc_suite.hpp"
#include "oc_test.hpp"
#include "oc_loader.hpp"
void* loadExec(const char* file_loc, size_t* out_size) {
FILE* fp = fopen(file_loc, "rb");

View File

@@ -33,7 +33,8 @@ void SafetyCheck() {
if (C.custRev != CUST_REV ||
C.marikoCpuMaxVolt >= 1300 ||
C.eristaCpuMaxVolt >= 1300 ||
(C.eristaEmcVolt && (C.eristaEmcVolt < 600'000 || C.eristaEmcVolt > 1250'000)))
(C.eristaEmcVolt && (C.eristaEmcVolt < 600'000 || C.eristaEmcVolt > 1250'000)) ||
(C.marikoEmcVolt && (C.marikoEmcVolt < 600'000 || C.marikoEmcVolt > 650'000)))
{
CRASH("Triggered");
}

View File

@@ -16,7 +16,7 @@
#pragma once
#include "../oc_suite_common.hpp"
#include "../oc_common.hpp"
namespace ams::ldr::oc::pcv {
@@ -88,6 +88,33 @@ typedef struct __attribute__((packed)) dvfs_rail {
u32 unk_2[11];
} dvfs_rail;
typedef struct __attribute__((packed)) regulator {
u64 id;
const char* name;
u32 type;
union {
struct {
u32 volt_reg;
u32 step_uv;
u32 min_uv;
u32 default_uv;
u32 max_uv;
u32 unk_0[2];
} type_1;
struct {
u32 unk_0;
u32 step_uv;
u32 unk_1;
u32 min_uv;
u32 max_uv;
u32 unk_2;
u32 default_uv;
} type_2_3;
};
u32 unk_x[60];
} regulator;
static_assert(sizeof(regulator) == 0x120);
constexpr u32 CpuClkOSLimit = 1785'000;
constexpr u32 MemClkOSLimit = 1600'000;

View File

@@ -27,11 +27,20 @@ Result CpuFreqCvbTable(u32* ptr) {
bool validated = std::memcmp(cpu_cvb_table_head, CpuCvbTableDefault, sizeof(CpuCvbTableDefault)) == 0;
R_UNLESS(validated, ldr::ResultInvalidCpuDvfs());
if (!C.eristaCpuOCEnabled)
R_SKIP();
std::memcpy(reinterpret_cast<void *>(new_start), CpuCvbTableAppend, sizeof(CpuCvbTableAppend));
// Patch CPU max volt in existing and appended CPU dvfs table
if (C.eristaCpuMaxVolt) {
size_t table_size = sizeof(CpuCvbTableAppend) / sizeof(cpu_freq_cvb_table_t);
cpu_freq_cvb_table_t* entry = new_start;
for (size_t i = 0; i < table_size; i++) {
if (entry->cvb_dfll_param.c0 == CpuVoltL4T) {
PatchOffset(reinterpret_cast<u32 *>(&(entry->cvb_dfll_param.c0)), C.eristaCpuMaxVolt * 1000);
}
entry++;
}
}
R_SUCCEED();
}

View File

@@ -40,10 +40,12 @@ constexpr cpu_freq_cvb_table_t CpuCvbTableDefault[] = {
{ 1785000, { 1227500 }, { 5100873, -279186, 4747 } },
};
constexpr u32 CpuVoltL4T = 1235'000;
constexpr cpu_freq_cvb_table_t CpuCvbTableAppend[] = {
{ 1887000, { 1235000 }, { 5100873, -279186, 4747 } },
{ 1963500, { 1235000 }, { 5100873, -279186, 4747 } },
{ 2091000, { 1235000 }, { 5100873, -279186, 4747 } },
{ 1887000, { CpuVoltL4T }, { 5100873, -279186, 4747 } },
{ 1963500, { CpuVoltL4T }, { 5100873, -279186, 4747 } },
{ 2091000, { CpuVoltL4T }, { 5100873, -279186, 4747 } },
};
constexpr u32 CpuMinVolts[] = { 950, 850, 825, 810 };

View File

@@ -149,6 +149,9 @@ void MemMtcTableAutoAdjust(MarikoMtcTable* table, const MarikoMtcTable* ref) {
* you'd better calculate timings yourself rather than relying on following algorithm.
*/
if (C.mtcConf == NO_ADJ_ALL)
return;
#define ADJUST_PROP(TARGET, REF) \
(u32)(std::ceil(REF + ((C.marikoEmcMaxClock-MemClkOSAlt)*(TARGET-REF))/(MemClkOSLimit-MemClkOSAlt)))
@@ -186,7 +189,7 @@ void MemMtcTableAutoAdjust(MarikoMtcTable* table, const MarikoMtcTable* ref) {
ADJUST_PARAM_TABLE(table, la_scale_regs.mc_ptsa_grant_decrement, ref);
/* Timings that are available in or can be derived from LPDDR4X datasheet or TRM */
const bool use_4266_spec = C.mtcConf == AUTO_ADJ_MARIKO_4266;
const bool use_4266_spec = C.mtcConf == AUTO_ADJ_MARIKO_4266_NO_ADJ_ERISTA;
// tCK_avg (average clock period) in ns
const double tCK_avg = 1000'000. / C.marikoEmcMaxClock;
// tRPpb (row precharge time per bank) in ns
@@ -368,6 +371,29 @@ Result MemFreqMax(u32* ptr) {
R_SUCCEED();
}
Result MemVoltHandler(u32* ptr) {
u32 emc_uv = C.marikoEmcVolt;
if (!emc_uv)
R_SKIP();
regulator* entry = reinterpret_cast<regulator *>(reinterpret_cast<u8 *>(ptr) - offsetof(regulator, type_2_3.default_uv));
constexpr u32 uv_step = 5'000;
constexpr u32 uv_min = 250'000;
if (entry->id != 2 || entry->type != 3 ||
entry->type_2_3.step_uv != uv_step ||
entry->type_2_3.min_uv != uv_min)
R_THROW(ldr::ResultInvalidRegulatorEntry());
if (emc_uv % uv_step)
emc_uv = emc_uv / uv_step * uv_step; // rounding
PatchOffset(ptr, emc_uv);
R_SUCCEED();
}
void Patch(uintptr_t mapped_nso, size_t nso_size) {
PatcherEntry<u32> patches[] = {
{ "CPU Freq Vdd", &CpuFreqVdd, 1, nullptr, CpuClkOSLimit },
@@ -380,6 +406,7 @@ void Patch(uintptr_t mapped_nso, size_t nso_size) {
{ "MEM Freq Dvb", &MemFreqDvbTable, 1, nullptr, MemClkOSLimit },
{ "MEM Freq Max", &MemFreqMax, 0, nullptr, MemClkOSLimit },
{ "MEM Freq PLLM", &MemFreqPllmLimit, 2, nullptr, MemClkPllmLimit },
{ "MEM Volt", &MemVoltHandler, 2, nullptr, MemVoltDefault }
};
for (uintptr_t ptr = mapped_nso;

View File

@@ -115,13 +115,9 @@ constexpr emc_dvb_dvfs_table_t EmcDvbTableDefault[] = {
{ 1600000, { 675, 650, 637, } },
};
constexpr emc_dvb_dvfs_table_t EmcDvbTableReplaced[] = {
{ 1862400, { 675, 650, 637, } },
{ 2133000, { 700, 675, 650, } },
};
constexpr u32 MemClkOSAlt = 1331'200;
constexpr u32 MemClkPllmLimit = 2133'000'000;
constexpr u32 MemVoltDefault = 600'000;
constexpr u32 MTC_TABLE_REV = 3;

View File

@@ -16,7 +16,7 @@
#pragma once
#include "../oc_suite_common.hpp"
#include "../oc_common.hpp"
namespace ams::ldr::oc::ptm {