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:
@@ -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,
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
@@ -16,6 +16,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "oc_suite_common.hpp"
|
||||
#include "oc_common.hpp"
|
||||
#include "pcv/pcv.hpp"
|
||||
#include "ptm/ptm.hpp"
|
||||
@@ -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");
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../oc_suite_common.hpp"
|
||||
#include "../oc_common.hpp"
|
||||
|
||||
namespace ams::ldr::oc::ptm {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user