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

@@ -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;