@@ -31,6 +31,7 @@
|
||||
namespace ams::ldr::hoc {
|
||||
|
||||
volatile CustomizeTable C = {
|
||||
|
||||
/* Disables RAM powerdown */
|
||||
.hpMode = DISABLED,
|
||||
|
||||
@@ -39,8 +40,12 @@ volatile CustomizeTable C = {
|
||||
.eristaEmcMaxClock1 = 1600000,
|
||||
.eristaEmcMaxClock2 = 1600000,
|
||||
|
||||
/* Available: 66MHz step rate, 100MHz step rate and jedec. */
|
||||
/* Jedec freqs are 1333MHz, 1600MHz, 1866MHz, 2133MHz, 2400MHz, 2666MHz, 2933MHz, 3200MHz. */
|
||||
.stepMode = StepMode_66MHz,
|
||||
|
||||
.marikoEmcMaxClock = 1866000, /* 1866MHz @ 1866tWRL is guaranteed to work on all Mariko units */
|
||||
.marikoEmcVddqVolt = 600000, /* Micron: 600mV, other manafacturers: 640mV */
|
||||
.marikoEmcVddqVolt = 600000,
|
||||
.emcDvbShift = 0,
|
||||
|
||||
// Primary
|
||||
@@ -54,6 +59,29 @@ volatile CustomizeTable C = {
|
||||
.t7_tWTR = 0,
|
||||
.t8_tREFI = 0,
|
||||
|
||||
/* At 1333WL, for some reason (incorrect ram timing config in mtc table?), tRP causes crashes at high reductions - 2 seems to be the most common limit. */
|
||||
/* This is a lazy workaround until I find the issue... */
|
||||
.t2_tRP_cap = 2,
|
||||
|
||||
/* Frequency where non low timings gets used. */
|
||||
.timingEmcTbreak = DISABLED,
|
||||
.low_t6_tRTW = DISABLED,
|
||||
.low_t7_tWTR = DISABLED,
|
||||
|
||||
.readLatency = {
|
||||
DISABLED,
|
||||
DISABLED,
|
||||
DISABLED,
|
||||
DISABLED,
|
||||
},
|
||||
|
||||
.writeLatency = {
|
||||
DISABLED,
|
||||
DISABLED,
|
||||
DISABLED,
|
||||
DISABLED,
|
||||
},
|
||||
|
||||
/* You can mix and match different latencies if needed */
|
||||
/*
|
||||
* Read:
|
||||
@@ -74,7 +102,7 @@ volatile CustomizeTable C = {
|
||||
.eristaCpuUV = 0,
|
||||
.eristaCpuVmin = 800,
|
||||
.eristaCpuMaxVolt = 1200,
|
||||
/* Unlocks up to 2295 Mhz CPU, usage is not recommended. */
|
||||
/* Unlocks up to 2397 Mhz CPU, usage is not recommended. */
|
||||
.eristaCpuUnlock = DISABLED,
|
||||
|
||||
.marikoCpuUVLow = 0, // No undervolt
|
||||
|
||||
@@ -36,6 +36,12 @@ enum TableConfig: u32 {
|
||||
EXTREME_TABLE = 4,
|
||||
};
|
||||
|
||||
enum StepMode:u32 {
|
||||
StepMode_66MHz = 0,
|
||||
StepMode_100MHz = 1,
|
||||
StepMode_Jedec = 2,
|
||||
};
|
||||
|
||||
/*
|
||||
* Read:
|
||||
* 2133RL = 40
|
||||
@@ -82,6 +88,8 @@ typedef struct CustomizeTable {
|
||||
u32 eristaEmcMaxClock;
|
||||
u32 eristaEmcMaxClock1;
|
||||
u32 eristaEmcMaxClock2;
|
||||
|
||||
StepMode stepMode;
|
||||
u32 marikoEmcMaxClock;
|
||||
u32 marikoEmcVddqVolt;
|
||||
u32 emcDvbShift;
|
||||
@@ -95,6 +103,15 @@ typedef struct CustomizeTable {
|
||||
u32 t7_tWTR;
|
||||
u32 t8_tREFI;
|
||||
|
||||
u32 t2_tRP_cap;
|
||||
|
||||
u32 timingEmcTbreak;
|
||||
u32 low_t6_tRTW;
|
||||
u32 low_t7_tWTR;
|
||||
|
||||
u32 readLatency[4];
|
||||
u32 writeLatency[4];
|
||||
|
||||
u32 mem_burst_read_latency;
|
||||
u32 mem_burst_write_latency;
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "../oc_common.hpp"
|
||||
#include <stratosphere.hpp>
|
||||
#include "../mtc_timing_value.hpp"
|
||||
|
||||
namespace ams::ldr::hoc::pcv::erista {
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "../oc_common.hpp"
|
||||
#include <stratosphere.hpp>
|
||||
#include "../mtc_timing_value.hpp"
|
||||
#include "timing_tables.hpp"
|
||||
|
||||
@@ -30,6 +30,73 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
rext = 0x1A;
|
||||
}
|
||||
|
||||
void SwitchLatency(volatile u32 &latency, u32 index, u32 latencyStep) {
|
||||
latency += index * latencyStep;
|
||||
}
|
||||
|
||||
static u32 GetMaxLatencyIndex(volatile u32 *latencyArray, u32 latencySize) {
|
||||
u32 maxIndex = 0;
|
||||
for (u32 i = 0; i < latencySize; ++i) {
|
||||
if (latencyArray[i]) {
|
||||
maxIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
return maxIndex;
|
||||
}
|
||||
|
||||
void AutoLatency(volatile u32 &latency, u32 freq, u32 latencyStep) {
|
||||
if (freq >= 1866'000 && freq < 2133000) {
|
||||
latency += latencyStep * 2;
|
||||
} else if (freq >= 2133'000) {
|
||||
latency += latencyStep * 3;
|
||||
} else {
|
||||
latency += latencyStep;
|
||||
}
|
||||
/* 1333 latency is not possible with this config. */
|
||||
}
|
||||
|
||||
void HandleLatency(u32 freq, volatile u32 &latency, volatile u32 *latencyArray, u32 indexMax, u32 latencyStep) {
|
||||
for (u32 i = 0; i <= indexMax; ++i) {
|
||||
if (latencyArray[i] != 0 && freq <= latencyArray[i]) {
|
||||
SwitchLatency(latency, i, latencyStep);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SwitchLatency(latency, indexMax, latencyStep);
|
||||
}
|
||||
|
||||
void HandleLatency(u32 freq) {
|
||||
static u32 rlIndexMax = GetMaxLatencyIndex(C.readLatency, std::size(C.readLatency));
|
||||
static u32 wlIndexMax = GetMaxLatencyIndex(C.writeLatency, std::size(C.writeLatency));
|
||||
constexpr u32 ReadLatencyStep = 4;
|
||||
constexpr u32 WriteLatencyStep = 2;
|
||||
bool autoLatencyRead = false, autoLatencyWrite = false;
|
||||
|
||||
if (rlIndexMax == 0) {
|
||||
AutoLatency(RL, freq, ReadLatencyStep);
|
||||
autoLatencyRead = true;
|
||||
}
|
||||
|
||||
if (wlIndexMax == 0) {
|
||||
AutoLatency(WL, freq, WriteLatencyStep);
|
||||
autoLatencyWrite = true;
|
||||
}
|
||||
|
||||
if (autoLatencyRead && autoLatencyWrite) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!autoLatencyRead) {
|
||||
HandleLatency(freq, RL, C.readLatency, rlIndexMax, ReadLatencyStep);
|
||||
}
|
||||
|
||||
if (!autoLatencyWrite) {
|
||||
HandleLatency(freq, WL, C.writeLatency, wlIndexMax, WriteLatencyStep);
|
||||
}
|
||||
}
|
||||
|
||||
void CalculateMrw2() {
|
||||
static const u8 rlMapDBI[8] = {
|
||||
6, 12, 16, 22, 28, 32, 36, 40
|
||||
@@ -59,8 +126,80 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
mrw2 = static_cast<u8>(((rlIndex & 0x7) | ((wlIndex & 0x7) << 3) | ((0 & 0x1) << 6)));
|
||||
}
|
||||
|
||||
void CalculateTimings() {
|
||||
void CalculateTimings(double tCK_avg, u32 freq) {
|
||||
RL = RL_1331;
|
||||
WL = WL_1331;
|
||||
|
||||
HandleLatency(freq);
|
||||
|
||||
GetRext();
|
||||
|
||||
/* At 1333WL, for some reason (incorrect ram timing config in mtc table?), tRP causes crashes at high reductions - 2 seems to be the most common limit. */
|
||||
/* This is a lazy workaround until I find the issue... */
|
||||
u32 tRPpbIndex = C.t2_tRP;
|
||||
if (WL == WL_1331) {
|
||||
tRPpbIndex = MIN(C.t2_tRP_cap, C.t2_tRP);
|
||||
}
|
||||
|
||||
tRCD = tRCD_values[C.t1_tRCD];
|
||||
tRPpb = tRP_values[tRPpbIndex];
|
||||
tRAS = tRAS_values[C.t3_tRAS];
|
||||
tRRD = tRRD_values[C.t4_tRRD];
|
||||
tRFCpb = tRFC_values[C.t5_tRFC];
|
||||
u32 tRTW = C.t6_tRTW;
|
||||
u32 tWTR = 10 - tWTR_values[C.t7_tWTR];
|
||||
|
||||
if (freq < C.timingEmcTbreak) {
|
||||
tRTW = C.low_t6_tRTW;
|
||||
tWTR = 10 - tWTR_values[C.low_t7_tWTR];
|
||||
}
|
||||
|
||||
s32 finetRTW = C.fineTune_t6_tRTW;
|
||||
s32 finetWTR = C.fineTune_t7_tWTR;
|
||||
|
||||
tRC = tRAS + tRPpb;
|
||||
tRFCab = tRFCpb * 2;
|
||||
tXSR = static_cast<double>(tRFCab + 7.5);
|
||||
tFAW = static_cast<u32>(tRRD * 4.0);
|
||||
tRPab = tRPpb + 3;
|
||||
|
||||
tR2P = CEIL((RL * 0.426) - 2.0);
|
||||
tR2W = FLOOR(FLOOR((5.0 / tCK_avg) + ((FLOOR(48.0 / WL) - 0.478) * 3.0)) / 1.501) + RL - (tRTW * 3) + finetRTW;
|
||||
tRTM = FLOOR((10.0 + RL) + (3.502 / tCK_avg)) + FLOOR(7.489 / tCK_avg);
|
||||
tRATM = CEIL((tRTM - 10.0) + (RL * 0.426));
|
||||
|
||||
rdv = RL + FLOOR((5.105 / tCK_avg) + 17.017);
|
||||
qpop = rdv - 14;
|
||||
quse_width = CEIL(((4.897 / tCK_avg) - FLOOR(2.538 / tCK_avg)) + 3.782);
|
||||
quse = FLOOR(RL + ((5.082 / tCK_avg) + FLOOR(2.560 / tCK_avg))) - CEIL(4.820 / tCK_avg);
|
||||
einput_duration = FLOOR(9.936 / tCK_avg) + 5.0 + quse_width;
|
||||
einput = quse - CEIL(9.928 / tCK_avg);
|
||||
u32 qrst_duration = FLOOR(8.399 - tCK_avg);
|
||||
u32 qrstLow = MAX(static_cast<s32>(einput - qrst_duration - 2), static_cast<s32>(0));
|
||||
qrst = PACK_U32(qrst_duration, qrstLow);
|
||||
ibdly = PACK_U32_NIBBLE_HIGH_BYTE_LOW(1, quse - qrst_duration - 2.0);
|
||||
qsafe = (einput_duration + 3) + MAX(MIN(qrstLow * rdv, qrst_duration + qrst_duration), einput);
|
||||
tW2P = (CEIL(WL * 1.7303) * 2) - 5;
|
||||
tWTPDEN = CEIL(((1.803 / tCK_avg) + MAX(RL + (2.694 / tCK_avg), static_cast<double>(tW2P))) + (BL / 2));
|
||||
tW2R = FLOOR(MAX((5.020 / tCK_avg) + 1.130, WL - MAX(-CEIL(0.258 * (WL - RL)), 1.964)) * 1.964) + WL - CEIL(tWTR / tCK_avg) + finetWTR;
|
||||
tWTM = CEIL(WL + ((7.570 / tCK_avg) + 8.753));
|
||||
tWATM = (tWTM + (FLOOR(WL / 0.816) * 2.0)) - 4.0;
|
||||
|
||||
wdv = WL;
|
||||
wsv = WL - 2;
|
||||
wev = 0xA + (WL - 14);
|
||||
|
||||
u32 obdlyHigh = 3 / FLOOR(MIN(static_cast<double>(2), tCK_avg * (WL - 7)));
|
||||
u32 obdlyLow = MAX(WL - FLOOR((126.0 / CEIL(tCK_avg + 8.601))), 0.0);
|
||||
obdly = PACK_U32_NIBBLE_HIGH_BYTE_LOW(obdlyHigh, obdlyLow);
|
||||
|
||||
pdex2rw = CEIL((CEIL(12.335 - tCK_avg) + (7.430 / tCK_avg) - CEIL(tCK_avg * 11.361)));
|
||||
|
||||
tCLKSTOP = FLOOR(MIN(8.488 / tCK_avg, 23.0)) + 8.0;
|
||||
|
||||
u32 tMMRI = tRCD + (tCK_avg * 3);
|
||||
pdex2mrr = tMMRI + 10;
|
||||
|
||||
CalculateMrw2();
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
namespace ams::ldr::hoc::pcv::mariko {
|
||||
|
||||
void CalculateTimings();
|
||||
void CalculateTimings(double tCK_avg, u32 freq);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -111,60 +111,54 @@ namespace ams::ldr::hoc {
|
||||
const std::array<u32, 10> tWTR_values = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
|
||||
const std::array<u32, 6> tREFpb_values = { 3900, 5850, 7800, 11700, 15600, 99999 };
|
||||
|
||||
const double tCK_avg = 1000'000.0 / C.marikoEmcMaxClock;
|
||||
inline u32 tRCD;
|
||||
inline u32 tRPpb;
|
||||
inline u32 tRAS;
|
||||
inline double tRRD;
|
||||
inline u32 tRFCpb;
|
||||
|
||||
const u32 tRCD = tRCD_values[C.t1_tRCD];
|
||||
const u32 tRPpb = tRP_values[C.t2_tRP];
|
||||
const u32 tRAS = tRAS_values[C.t3_tRAS];
|
||||
const double tRRD = tRRD_values[C.t4_tRRD];
|
||||
const u32 tRFCpb = tRFC_values[C.t5_tRFC];
|
||||
const u32 tWTR = 10 - tWTR_values[C.t7_tWTR];
|
||||
const s32 finetRTW = C.fineTune_t6_tRTW;
|
||||
const s32 finetWTR = C.fineTune_t7_tWTR;
|
||||
inline u32 tRC;
|
||||
inline u32 tRFCab;
|
||||
inline double tXSR;
|
||||
inline u32 tFAW;
|
||||
inline double tRPab;
|
||||
|
||||
const u32 tRC = tRAS + tRPpb;
|
||||
const u32 tRFCab = tRFCpb * 2;
|
||||
const double tXSR = static_cast<double>(tRFCab + 7.5);
|
||||
const u32 tFAW = static_cast<u32>(tRRD * 4.0);
|
||||
const double tRPab = tRPpb + 3;
|
||||
inline u32 RL;
|
||||
inline u32 WL;
|
||||
|
||||
const u32 tR2P = CEIL((RL * 0.426) - 2.0);
|
||||
const u32 tR2W = FLOOR(FLOOR((5.0 / tCK_avg) + ((FLOOR(48.0 / WL) - 0.478) * 3.0)) / 1.501) + RL - (C.t6_tRTW * 3) + finetRTW;
|
||||
const u32 tRTM = FLOOR((10.0 + RL) + (3.502 / tCK_avg)) + FLOOR(7.489 / tCK_avg);
|
||||
const u32 tRATM = CEIL((tRTM - 10.0) + (RL * 0.426));
|
||||
inline u32 tR2P;
|
||||
inline u32 tR2W;
|
||||
inline u32 tRTM;
|
||||
inline u32 tRATM;
|
||||
inline u32 rext;
|
||||
|
||||
const u32 rdv = RL + FLOOR((5.105 / tCK_avg) + 17.017);
|
||||
const u32 qpop = rdv - 14;
|
||||
const u32 quse_width = CEIL(((4.897 / tCK_avg) - FLOOR(2.538 / tCK_avg)) + 3.782);
|
||||
const u32 quse = FLOOR(RL + ((5.082 / tCK_avg) + FLOOR(2.560 / tCK_avg))) - CEIL(4.820 / tCK_avg);
|
||||
const u32 einput_duration = FLOOR(9.936 / tCK_avg) + 5.0 + quse_width;
|
||||
const u32 einput = quse - CEIL(9.928 / tCK_avg);
|
||||
const u32 qrst_duration = FLOOR(8.399 - tCK_avg);
|
||||
const u32 qrstLow = MAX(static_cast<s32>(einput - qrst_duration - 2), static_cast<s32>(0));
|
||||
const u32 qrst = PACK_U32(qrst_duration, qrstLow);
|
||||
const u32 ibdly = PACK_U32_NIBBLE_HIGH_BYTE_LOW(1, quse - qrst_duration - 2.0);
|
||||
const u32 qsafe = (einput_duration + 3) + MAX(MIN(qrstLow * rdv, qrst_duration + qrst_duration), einput);
|
||||
const u32 tW2P = (CEIL(WL * 1.7303) * 2) - 5;
|
||||
const u32 tWTPDEN = CEIL(((1.803 / tCK_avg) + MAX(RL + (2.694 / tCK_avg), static_cast<double>(tW2P))) + (BL / 2));
|
||||
const u32 tW2R = FLOOR(MAX((5.020 / tCK_avg) + 1.130, WL - MAX(-CEIL(0.258 * (WL - RL)), 1.964)) * 1.964) + WL - CEIL(tWTR / tCK_avg) + finetWTR;
|
||||
const u32 tWTM = CEIL(WL + ((7.570 / tCK_avg) + 8.753));
|
||||
const u32 tWATM = (tWTM + (FLOOR(WL / 0.816) * 2.0)) - 4.0;
|
||||
inline u32 rdv;
|
||||
inline u32 qpop;
|
||||
inline u32 quse_width;
|
||||
inline u32 quse;
|
||||
inline u32 einput_duration;
|
||||
inline u32 einput;
|
||||
inline u32 qrst;
|
||||
inline u32 ibdly;
|
||||
inline u32 qsafe;
|
||||
|
||||
const u32 wdv = WL;
|
||||
const u32 wsv = WL - 2;
|
||||
const u32 wev = 0xA + (WL - 14);
|
||||
inline u32 tW2P;
|
||||
inline u32 tWTPDEN;
|
||||
inline u32 tW2R;
|
||||
inline u32 tWTM;
|
||||
inline u32 tWATM;
|
||||
|
||||
const u32 obdlyHigh = 3 / FLOOR(MIN(static_cast<double>(2), tCK_avg * (WL - 7)));
|
||||
const u32 obdlyLow = MAX(WL - FLOOR((126.0 / CEIL(tCK_avg + 8.601))), 0.0);
|
||||
const u32 obdly = PACK_U32_NIBBLE_HIGH_BYTE_LOW(obdlyHigh, obdlyLow);
|
||||
inline u32 wdv;
|
||||
inline u32 wsv;
|
||||
inline u32 wev;
|
||||
|
||||
const u32 pdex2rw = CEIL((CEIL(12.335 - tCK_avg) + (7.430 / tCK_avg) - CEIL(tCK_avg * 11.361)));
|
||||
inline u32 obdly;
|
||||
|
||||
const u32 tCLKSTOP = FLOOR(MIN(8.488 / tCK_avg, 23.0)) + 8.0;
|
||||
inline u32 pdex2rw;
|
||||
|
||||
const double tMMRI = tRCD + (tCK_avg * 3);
|
||||
const double pdex2mrr = tMMRI + 10; /* Do this properly? */
|
||||
inline u32 tCLKSTOP;
|
||||
|
||||
inline u32 pdex2mrr;
|
||||
|
||||
inline u8 mrw2;
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@ namespace ams::ldr {
|
||||
R_DEFINE_ERROR_RESULT(UninitializedPatcher, 1013);
|
||||
R_DEFINE_ERROR_RESULT(UnsuccessfulPatcher, 1014);
|
||||
R_DEFINE_ERROR_RESULT(SafetyCheckFailure, 1015);
|
||||
R_DEFINE_ERROR_RESULT(InvalidMtcTablePattern, 1016);
|
||||
}
|
||||
|
||||
namespace ams::ldr::hoc {
|
||||
|
||||
@@ -20,10 +20,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../oc_common.hpp"
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::ldr::hoc::pcv {
|
||||
|
||||
constexpr u32 NopIns = 0x1f2003d5;
|
||||
|
||||
inline auto asm_compare_no_rd = [](u32 ins1, u32 ins2) {
|
||||
return ((ins1 ^ ins2) >> 5) == 0;
|
||||
};
|
||||
@@ -44,4 +46,19 @@ namespace ams::ldr::hoc::pcv {
|
||||
return static_cast<u16>((ins >> 5) & 0xFFFF);
|
||||
};
|
||||
|
||||
inline auto AsmCompareBrNoRd = [](u32 ins1, u32 ins2) {
|
||||
constexpr u32 RegMask = ~(((1 << 5) - 1) << 5);
|
||||
return ((ins1 & RegMask) ^ (ins2 & RegMask)) == 0;
|
||||
};
|
||||
|
||||
inline auto AsmCompareAddNoImm12 = [](u32 ins1, u32 ins2) {
|
||||
constexpr u32 Imm12Mask = ~(((1 << 12) - 1) << 10);
|
||||
return ((ins1 & Imm12Mask) ^ (ins2 & Imm12Mask)) == 0;
|
||||
};
|
||||
|
||||
inline auto AsmCompareAdrpNoImm = [](u32 ins1, u32 ins2) {
|
||||
constexpr u32 ImmMask = ~((((1 << 2) - 1) << 29) | (((1 << 19) - 1) << 5));
|
||||
return ((ins1 & ImmMask) ^ (ins2 & ImmMask)) == 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -46,11 +46,6 @@ namespace ams::ldr::hoc::pcv {
|
||||
unsigned long dvco_calibration_max;
|
||||
} cvb_cpu_dfll_data;
|
||||
|
||||
typedef struct emc_dvb_dvfs_table_t {
|
||||
u64 freq;
|
||||
s32 volt[4] = {0};
|
||||
} emc_dvb_dvfs_table_t;
|
||||
|
||||
typedef struct __attribute__((packed)) div_nmp {
|
||||
u8 divn_shift;
|
||||
u8 divn_width;
|
||||
|
||||
@@ -113,7 +113,38 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
constexpr u32 EmcClkMinFreq = 40800; /* 40.8 MHz table only exists on erista. */
|
||||
constexpr u32 EmcClkPllmLimit = 1866'000'000;
|
||||
|
||||
constexpr u32 MTC_TABLE_REV = 7;
|
||||
constexpr u32 MTC_TABLE_REV = 7;
|
||||
constexpr u32 MtcTableCountDefault = 10;
|
||||
|
||||
constexpr size_t MtcFullTableSize = sizeof(EristaMtcTable) * MtcTableCountDefault;
|
||||
constexpr u32 MtcFullTableCount = 3;
|
||||
|
||||
/* These dramids were copied from Hekate -- see /bdk/mem/sdram.h */
|
||||
enum DramId {
|
||||
ICOSA_4GB_SAMSUNG_K4F6E304HB_MGCH = 0,
|
||||
ICOSA_4GB_HYNIX_H9HCNNNBPUMLHR_NLE = 1,
|
||||
ICOSA_4GB_MICRON_MT53B512M32D2NP_062_WTC = 2, /* This doesn't have a table in pcv? Wtf? */
|
||||
ICOSA_6GB_SAMSUNG_K4FHE3D4HM_MGCH = 4,
|
||||
ICOSA_8GB_SAMSUNG_K4FBE3D4HM_MGXX = 7, /* No table, but expected */
|
||||
};
|
||||
|
||||
enum MtcTableIndex {
|
||||
T210SdevEmcDvfsTableS4gb01 = 0, /* HB-MGCH */
|
||||
T210SdevEmcDvfsTableS6gb01 = 1, /* HM-MGCH */
|
||||
T210SdevEmcDvfsTableH4gb01 = 2, /* HR-NLE */
|
||||
MtcTableIndex_Invalid = 3,
|
||||
};
|
||||
|
||||
struct MtcDramIndex {
|
||||
DramId dramId;
|
||||
MtcTableIndex index;
|
||||
};
|
||||
|
||||
constexpr MtcDramIndex mtcIndexTable[] = {
|
||||
{ ICOSA_4GB_SAMSUNG_K4F6E304HB_MGCH, T210SdevEmcDvfsTableS4gb01, },
|
||||
{ ICOSA_6GB_SAMSUNG_K4FHE3D4HM_MGCH, T210SdevEmcDvfsTableS6gb01, },
|
||||
{ ICOSA_4GB_HYNIX_H9HCNNNBPUMLHR_NLE, T210SdevEmcDvfsTableH4gb01, },
|
||||
};
|
||||
|
||||
void Patch(uintptr_t mapped_nso, size_t nso_size);
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <vector>
|
||||
#include "pcv.hpp"
|
||||
#include "../mtc_timing_value.hpp"
|
||||
#include "../mariko/calculate_timings.hpp"
|
||||
@@ -53,7 +54,7 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
R_SKIP();
|
||||
}
|
||||
|
||||
PATCH_OFFSET(ptr + 0, C.marikoGpuVmin);
|
||||
PATCH_OFFSET(ptr, C.marikoGpuVmin);
|
||||
PATCH_OFFSET(ptr + 3, C.marikoGpuVmin);
|
||||
PATCH_OFFSET(ptr + 6, C.marikoGpuVmin);
|
||||
PATCH_OFFSET(ptr + 9, C.marikoGpuVmin);
|
||||
@@ -349,6 +350,8 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
TABLE->shadow_regs_ca_train.PARAM = VALUE; \
|
||||
TABLE->shadow_regs_rdwr_train.PARAM = VALUE;
|
||||
|
||||
const double tCK_avg = 1000'000.0 / table->rate_khz;
|
||||
|
||||
#define GET_CYCLE_CEIL(PARAM) u32(CEIL(double(PARAM) / tCK_avg))
|
||||
|
||||
/* Ram power down */
|
||||
@@ -372,7 +375,7 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
|
||||
const u32 dyn_self_ref_control = (static_cast<u32>(7605.0 / tCK_avg) + 260) | (table->burst_regs.emc_dyn_self_ref_control & 0xffff0000);
|
||||
|
||||
CalculateTimings();
|
||||
CalculateTimings(tCK_avg, table->rate_khz);
|
||||
|
||||
WRITE_PARAM_ALL_REG(table, emc_rd_rcd, GET_CYCLE_CEIL(tRCD));
|
||||
WRITE_PARAM_ALL_REG(table, emc_wr_rcd, GET_CYCLE_CEIL(tRCD));
|
||||
@@ -399,7 +402,7 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
WRITE_PARAM_ALL_REG(table, emc_twtm, tWTM);
|
||||
WRITE_PARAM_ALL_REG(table, emc_twatm, tWATM);
|
||||
WRITE_PARAM_ALL_REG(table, emc_rext, rext);
|
||||
WRITE_PARAM_ALL_REG(table, emc_wext, (C.marikoEmcMaxClock >= 2533000) ? 0x19 : 0x16);
|
||||
WRITE_PARAM_ALL_REG(table, emc_wext, (table->rate_khz >= 2533000) ? 0x19 : 0x16);
|
||||
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_trefbw, trefbw);
|
||||
@@ -443,7 +446,7 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
constexpr double MC_ARB_DIV = 4.0;
|
||||
constexpr u32 MC_ARB_SFA = 2;
|
||||
|
||||
table->burst_mc_regs.mc_emem_arb_cfg = C.marikoEmcMaxClock / (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_rp = CEIL(GET_CYCLE_CEIL(tRPpb) / MC_ARB_DIV) - 1;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_rc = CEIL(GET_CYCLE_CEIL(tRC) / MC_ARB_DIV) - 1;
|
||||
@@ -485,7 +488,7 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
|
||||
table->la_scale_regs.mc_mll_mpcorer_ptsa_rate = 0x115;
|
||||
|
||||
if (C.marikoEmcMaxClock >= 2133000) {
|
||||
if (table->rate_khz >= 2133000) {
|
||||
table->la_scale_regs.mc_ftop_ptsa_rate = 0x1F;
|
||||
} else {
|
||||
table->la_scale_regs.mc_ftop_ptsa_rate = 0x1B;
|
||||
@@ -494,14 +497,14 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
table->la_scale_regs.mc_ptsa_grant_decrement = 0x17ff;
|
||||
|
||||
constexpr u32 MaskHigh = 0xFF00FFFF;
|
||||
constexpr u32 Mask2 = 0xFFFFFF00;
|
||||
constexpr u32 Mask3 = 0xFF00FF00;
|
||||
constexpr u32 Mask2 = 0xFFFFFF00;
|
||||
constexpr u32 Mask3 = 0xFF00FF00;
|
||||
|
||||
const u32 allowance1 = static_cast<u32>(0x32000 / (C.marikoEmcMaxClock / 0x3E8)) & 0xFF;
|
||||
const u32 allowance2 = static_cast<u32>(0x9C40 / (C.marikoEmcMaxClock / 0x3E8)) & 0xFF;
|
||||
const u32 allowance3 = static_cast<u32>(0xB540 / (C.marikoEmcMaxClock / 0x3E8)) & 0xFF;
|
||||
const u32 allowance4 = static_cast<u32>(0x9600 / (C.marikoEmcMaxClock / 0x3E8)) & 0xFF;
|
||||
const u32 allowance5 = static_cast<u32>(0x8980 / (C.marikoEmcMaxClock / 0x3E8)) & 0xFF;
|
||||
const u32 allowance1 = static_cast<u32>(0x32000 / (table->rate_khz / 1000)) & 0xFF;
|
||||
const u32 allowance2 = static_cast<u32>(0x9C40 / (table->rate_khz / 1000)) & 0xFF;
|
||||
const u32 allowance3 = static_cast<u32>(0xB540 / (table->rate_khz / 1000)) & 0xFF;
|
||||
const u32 allowance4 = static_cast<u32>(0x9600 / (table->rate_khz / 1000)) & 0xFF;
|
||||
const u32 allowance5 = static_cast<u32>(0x8980 / (table->rate_khz / 1000)) & 0xFF;
|
||||
|
||||
table->la_scale_regs.mc_latency_allowance_xusb_0 = (table->la_scale_regs.mc_latency_allowance_xusb_0 & MaskHigh) | (allowance1 << 16);
|
||||
table->la_scale_regs.mc_latency_allowance_xusb_1 = (table->la_scale_regs.mc_latency_allowance_xusb_1 & MaskHigh) | (allowance1 << 16);
|
||||
@@ -525,8 +528,8 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
|
||||
table->dram_timings.t_rp = tRFCpb;
|
||||
table->dram_timings.t_rfc = tRFCab;
|
||||
table->dram_timings.rl = RL;
|
||||
|
||||
table->dram_timings.rl = RL;
|
||||
table->emc_mrw2 = (table->emc_mrw2 & ~0xFFu) | static_cast<u32>(mrw2);
|
||||
table->emc_cfg_2 = 0x11083D;
|
||||
}
|
||||
@@ -535,24 +538,24 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
constexpr u32 PllOscInKHz = 38400;
|
||||
constexpr u32 PllOscHalfKHz = 19200;
|
||||
|
||||
double target_freq_d = static_cast<double>(C.marikoEmcMaxClock);
|
||||
double target_freq_d = static_cast<double>(table->rate_khz);
|
||||
|
||||
s32 divm_candidate_half = static_cast<u8>(C.marikoEmcMaxClock / PllOscHalfKHz);
|
||||
s32 divm_candidate_half = static_cast<u8>(table->rate_khz / PllOscHalfKHz);
|
||||
|
||||
bool remainder_check = (C.marikoEmcMaxClock - PllOscInKHz * (C.marikoEmcMaxClock / PllOscInKHz)) > (C.marikoEmcMaxClock - PllOscHalfKHz * divm_candidate_half) && static_cast<int>(((target_freq_d / PllOscHalfKHz - divm_candidate_half - 0.5) * 8192.0)) != 0;
|
||||
bool remainder_check = (table->rate_khz - PllOscInKHz * (table->rate_khz / PllOscInKHz)) > (table->rate_khz - PllOscHalfKHz * divm_candidate_half) && static_cast<int>(((target_freq_d / PllOscHalfKHz - divm_candidate_half - 0.5) * 8192.0)) != 0;
|
||||
|
||||
u32 divm_final = remainder_check + 1;
|
||||
table->pllmb_divm = divm_final;
|
||||
|
||||
double div_step_d = static_cast<double>(PllOscInKHz) / divm_final;
|
||||
s32 divn_integer = static_cast<u8>(C.marikoEmcMaxClock / div_step_d);
|
||||
s32 divn_integer = static_cast<u8>(table->rate_khz / div_step_d);
|
||||
table->pllmb_divn = divn_integer;
|
||||
|
||||
u32 divn_fraction = static_cast<s32>((target_freq_d / div_step_d - divn_integer - 0.5) * 8192.0);
|
||||
|
||||
u32 actual_freq_khz = static_cast<u32>((divn_integer + 0.5 + divn_fraction * 0.000122070312) * div_step_d);
|
||||
|
||||
if (C.marikoEmcMaxClock - 2366001 < 133999) {
|
||||
if (table->rate_khz - 2366001 < 133999) {
|
||||
s32 divn_fraction_ssc = static_cast<s32>((actual_freq_khz * 0.997 / div_step_d - divn_integer - 0.5) * 8192.0);
|
||||
|
||||
double delta_scaled = (0.3 / div_step_d + 0.3 / div_step_d) * (divn_fraction - divn_fraction_ssc);
|
||||
@@ -580,7 +583,7 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
table->pllm_ss_cfg &= 0xBFFFFFFF;
|
||||
table->pllmb_ss_cfg &= 0xBFFFFFFF;
|
||||
|
||||
u64 pair = (static_cast<u64>(divn_fraction) << 32) | static_cast<u64>(C.marikoEmcMaxClock);
|
||||
u64 pair = (static_cast<u64>(divn_fraction) << 32) | static_cast<u64>(table->rate_khz);
|
||||
u32 pll_misc = (table->pllm_ss_ctrl2 & 0xFFFF0000) | static_cast<u32>((pair - actual_freq_khz) >> 32);
|
||||
|
||||
table->pllm_ss_ctrl2 = pll_misc;
|
||||
@@ -588,80 +591,222 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
}
|
||||
}
|
||||
|
||||
Result MemFreqMtcTable(u32 *ptr) {
|
||||
u32 khz_list[] = {1600000, 1331200, 204000};
|
||||
u32 khz_list_size = sizeof(khz_list) / sizeof(u32);
|
||||
namespace {
|
||||
std::vector<u32> newEmcList;
|
||||
u32 *nsoStart;
|
||||
}
|
||||
|
||||
// Generate list for mtc table pointers
|
||||
MarikoMtcTable *table_list[khz_list_size];
|
||||
for (u32 i = 0; i < khz_list_size; i++) {
|
||||
u8 *table = reinterpret_cast<u8 *>(ptr) - offsetof(MarikoMtcTable, rate_khz) - i * sizeof(MarikoMtcTable);
|
||||
table_list[i] = reinterpret_cast<MarikoMtcTable *>(table);
|
||||
R_UNLESS(table_list[i]->rate_khz == khz_list[i], ldr::ResultInvalidMtcTable());
|
||||
R_UNLESS(table_list[i]->rev == MTC_TABLE_REV, ldr::ResultInvalidMtcTable());
|
||||
void MtcGenerateJedecTable() {
|
||||
const u32 jedecFreqs[] = { 1866000, 1996000, 2133000, 2400000, 2666000, 2933000, 3200000 };
|
||||
constexpr u32 JedecFreqCount = std::size(jedecFreqs);
|
||||
|
||||
for (u32 i = 0; i < JedecFreqCount; ++i) {
|
||||
if (jedecFreqs[i] <= C.marikoEmcMaxClock) {
|
||||
newEmcList.push_back(jedecFreqs[i]);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (C.marikoEmcMaxClock <= EmcClkOSLimit)
|
||||
newEmcList.resize(std::min(newEmcList.size(), DvfsTableEntryLimit));
|
||||
}
|
||||
|
||||
void MtcGenerateFreqTables() {
|
||||
if (C.marikoEmcMaxClock <= EmcClkOSLimit) {
|
||||
return;
|
||||
}
|
||||
|
||||
newEmcList.clear();
|
||||
newEmcList.reserve(DvfsTableEntryCount);
|
||||
newEmcList.insert(newEmcList.end(), std::begin(EmcListDefault), std::end(EmcListDefault));
|
||||
|
||||
u32 stepRate = 0;
|
||||
switch (C.stepMode) {
|
||||
case StepMode_66MHz:
|
||||
stepRate = 66667;
|
||||
break;
|
||||
case StepMode_100MHz:
|
||||
stepRate = 100000;
|
||||
break;
|
||||
case StepMode_Jedec:
|
||||
MtcGenerateJedecTable();
|
||||
return;
|
||||
default:
|
||||
stepRate = 66667;
|
||||
break;
|
||||
}
|
||||
|
||||
constexpr u32 RoundHz = 1000;
|
||||
for (u32 stepIndex = 1;; ++stepIndex) {
|
||||
u32 newFreq = EmcClkOSLimit + stepIndex * stepRate;
|
||||
newFreq = (newFreq / RoundHz) * RoundHz;
|
||||
if (newFreq > C.marikoEmcMaxClock) {
|
||||
if (newEmcList.back() != C.marikoEmcMaxClock) {
|
||||
newEmcList.push_back(static_cast<u32>(C.marikoEmcMaxClock));
|
||||
}
|
||||
break;
|
||||
}
|
||||
newEmcList.push_back(newFreq);
|
||||
}
|
||||
|
||||
newEmcList.resize(std::min(newEmcList.size(), DvfsTableEntryLimit));
|
||||
}
|
||||
|
||||
Result VerifyMtcTable(MarikoMtcTable *tableStart, u32 expectedFreq) {
|
||||
R_UNLESS(tableStart->rate_khz == expectedFreq, ldr::ResultInvalidMtcTable());
|
||||
R_UNLESS(tableStart->rev == MTC_TABLE_REV, ldr::ResultInvalidMtcTable());
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result MtcValidateAllTables(MarikoMtcTable *tableStart, const u32 *validationList, u32 tableCount) {
|
||||
for (u32 i = 0; i < tableCount; ++i) {
|
||||
R_UNLESS(R_SUCCEEDED(VerifyMtcTable(&tableStart[i], validationList[i])), ldr::ResultInvalidMtcTable());
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
DramId GetDramId() {
|
||||
u64 id64;
|
||||
splGetConfig(SplConfigItem_DramId, &id64);
|
||||
return static_cast<DramId>(id64);
|
||||
}
|
||||
|
||||
MtcTableIndex GetMtcDramIndex(DramId dramId) {
|
||||
for (u32 i = 0; i < std::size(mtcIndexTable); ++i) {
|
||||
if (mtcIndexTable[i].dramId == dramId) {
|
||||
return mtcIndexTable[i].index;
|
||||
}
|
||||
}
|
||||
|
||||
return MtcTableIndex_Invalid;
|
||||
}
|
||||
|
||||
NORETURN void AbortInvalidDramId() {
|
||||
panic::SmcError(panic::Emc);
|
||||
CRASH("Invalid dram id\n");
|
||||
}
|
||||
|
||||
u32 GetMtcOffset(MtcTableIndex index) {
|
||||
if (index < T210b0SdevEmcDvfsTableS4gb03) {
|
||||
return index * mariko::MtcFullTableSize;
|
||||
}
|
||||
|
||||
/* There are 2 erista mtc tables between T210b0SdevEmcDvfsTableS4gb01 and T210b0SdevEmcDvfsTableS4gb03, so we have to do this adjustment. */
|
||||
return mariko::MtcFullTableSize * index + (2 * erista::MtcFullTableSize);
|
||||
}
|
||||
|
||||
void PrepareMtcMemoryRegion(u8 *firstTable, MarikoMtcTable *usedTable) {
|
||||
memmove(firstTable, usedTable, mariko::MtcFullTableSize);
|
||||
|
||||
/* Clear all other tables. */
|
||||
/* 1 erista table is excluded because it's always before firstTable. */
|
||||
/* We also exclude the used table obviously. */
|
||||
constexpr size_t RemainingRegionSize = (mariko::MtcFullTableSize) * (mariko::MtcFullTableCount - 1) + (erista::MtcFullTableSize * (erista::MtcFullTableCount - 1));
|
||||
memset(firstTable + mariko::MtcFullTableSize, 0, RemainingRegionSize);
|
||||
}
|
||||
|
||||
void MtcExtendTables(MarikoMtcTable *table) {
|
||||
for (u32 i = mariko::MtcTableCountDefault; i < newEmcList.size(); ++i) {
|
||||
std::memcpy(&table[i], &table[i - 1], sizeof(MarikoMtcTable));
|
||||
table[i].rate_khz = newEmcList[i];
|
||||
}
|
||||
}
|
||||
|
||||
bool patchedMtc = false;
|
||||
Result MemFreqMtcTable(u32 *ptr) {
|
||||
if (C.marikoEmcMaxClock <= EmcClkOSLimit || patchedMtc) {
|
||||
R_SKIP();
|
||||
}
|
||||
|
||||
MarikoMtcTable *table_alt = table_list[1], *table_max = table_list[0];
|
||||
MarikoMtcTable *tmp = new MarikoMtcTable;
|
||||
static const DramId dramId = [] {
|
||||
DramId id = GetDramId();
|
||||
id = IOWA_4GB_SAMSUNG_K4U6E3S4AA_MGCL;
|
||||
return id;
|
||||
}();
|
||||
|
||||
// Copy unmodified 1600000 table to tmp
|
||||
std::memcpy(reinterpret_cast<void *>(tmp), reinterpret_cast<void *>(table_max), sizeof(MarikoMtcTable));
|
||||
static const MtcTableIndex mtcIndex = [] {
|
||||
MtcTableIndex idx = GetMtcDramIndex(dramId);
|
||||
/* If for some reason this happens, there is no chance of recovering this. */
|
||||
if (idx == MtcTableIndex_Invalid) {
|
||||
AbortInvalidDramId();
|
||||
}
|
||||
return idx;
|
||||
}();
|
||||
|
||||
/* Adjust timings properly according to the new frequency. */
|
||||
MemMtcTableAutoAdjust(table_max);
|
||||
/* Offset to dram id specific mtc table. */
|
||||
static const u32 mtcOffset = GetMtcOffset(mtcIndex);
|
||||
|
||||
MemMtcPllmbDivisor(table_max);
|
||||
// Overwrite 13312000 table with unmodified 1600000 table copied back
|
||||
std::memcpy(reinterpret_cast<void *>(table_alt), reinterpret_cast<void *>(tmp), sizeof(MarikoMtcTable));
|
||||
/* Offset from 1600MHz pointer to 204Mhz table start. */
|
||||
constexpr u32 StartAdjustment = offsetof(MarikoMtcTable, rate_khz) + sizeof(MarikoMtcTable) * 2;
|
||||
u8 *startPtr = reinterpret_cast<u8 *>(ptr) - StartAdjustment;
|
||||
MarikoMtcTable *table = reinterpret_cast<MarikoMtcTable *>(startPtr + mtcOffset);
|
||||
R_UNLESS(R_SUCCEEDED(MtcValidateAllTables(table, EmcListDefault, EmcListSizeDefault)), ldr::ResultInvalidMtcTable());
|
||||
|
||||
delete tmp;
|
||||
table = reinterpret_cast<MarikoMtcTable *>(startPtr);
|
||||
|
||||
PATCH_OFFSET(ptr, C.marikoEmcMaxClock);
|
||||
PrepareMtcMemoryRegion(startPtr, table);
|
||||
if (R_FAILED(MtcValidateAllTables(table, EmcListDefault, EmcListSizeDefault))) {
|
||||
panic::SmcError(panic::Emc);
|
||||
}
|
||||
|
||||
MtcExtendTables(table);
|
||||
|
||||
if (R_FAILED(MtcValidateAllTables(table, newEmcList.data(), newEmcList.size()))) {
|
||||
panic::SmcError(panic::Emc);
|
||||
}
|
||||
|
||||
for (u32 i = mariko::MtcTableCountDefault; i < newEmcList.size(); ++i) {
|
||||
MemMtcTableAutoAdjust(&table[i]);
|
||||
MemMtcPllmbDivisor(&table[i]);
|
||||
}
|
||||
|
||||
patchedMtc = true;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result MemFreqDvbTable(u32 *ptr) {
|
||||
emc_dvb_dvfs_table_t *default_end = reinterpret_cast<emc_dvb_dvfs_table_t *>(ptr);
|
||||
emc_dvb_dvfs_table_t *new_start = default_end + 1;
|
||||
DvbEntry *default_end = reinterpret_cast<DvbEntry *>(ptr);
|
||||
DvbEntry *new_start = default_end + 1;
|
||||
|
||||
// Validate existing table
|
||||
void *mem_dvb_table_head = reinterpret_cast<u8 *>(new_start) - sizeof(EmcDvbTableDefault);
|
||||
bool validated = std::memcmp(mem_dvb_table_head, EmcDvbTableDefault, sizeof(EmcDvbTableDefault)) == 0;
|
||||
bool validated = std::memcmp(mem_dvb_table_head, EmcDvbTableDefault, sizeof(EmcDvbTableDefault)) == 0;
|
||||
R_UNLESS(validated, ldr::ResultInvalidDvbTable());
|
||||
|
||||
if (C.marikoEmcMaxClock <= EmcClkOSLimit)
|
||||
if (C.marikoEmcMaxClock <= EmcClkOSLimit) {
|
||||
R_SKIP();
|
||||
|
||||
int32_t voltAdd = 25 * C.emcDvbShift;
|
||||
|
||||
#define DVB_VOLT(zero, one, two) std::min(zero + voltAdd, 1050), std::min(one + voltAdd, 1025), std::min(two + voltAdd, 1000),
|
||||
|
||||
/* TODO: More fine tuned values? */
|
||||
if (C.marikoEmcMaxClock < 1862400) {
|
||||
std::memcpy(new_start, default_end, sizeof(emc_dvb_dvfs_table_t));
|
||||
} else if (C.marikoEmcMaxClock < 2131200) {
|
||||
emc_dvb_dvfs_table_t oc_table = {1862400, {700, 675, 650, }};
|
||||
std::memcpy(new_start, &oc_table, sizeof(emc_dvb_dvfs_table_t));
|
||||
} else if (C.marikoEmcMaxClock < 2400000) {
|
||||
emc_dvb_dvfs_table_t oc_table = {2131200, { 725, 700, 675} };
|
||||
std::memcpy(new_start, &oc_table, sizeof(emc_dvb_dvfs_table_t));
|
||||
} else if (C.marikoEmcMaxClock < 2665600) {
|
||||
emc_dvb_dvfs_table_t oc_table = {2400000, {DVB_VOLT(750, 725, 700)}};
|
||||
std::memcpy(new_start, &oc_table, sizeof(emc_dvb_dvfs_table_t));
|
||||
} else if (C.marikoEmcMaxClock < 2931200) {
|
||||
emc_dvb_dvfs_table_t oc_table = {2665600, {DVB_VOLT(775, 750, 725)}};
|
||||
std::memcpy(new_start, &oc_table, sizeof(emc_dvb_dvfs_table_t));
|
||||
} else if (C.marikoEmcMaxClock < 3200000) {
|
||||
emc_dvb_dvfs_table_t oc_table = {2931200, {DVB_VOLT(800, 775, 750)}};
|
||||
std::memcpy(new_start, &oc_table, sizeof(emc_dvb_dvfs_table_t));
|
||||
} else {
|
||||
emc_dvb_dvfs_table_t oc_table = {3200000, {DVB_VOLT(800, 800, 775)}};
|
||||
std::memcpy(new_start, &oc_table, sizeof(emc_dvb_dvfs_table_t));
|
||||
}
|
||||
new_start->freq = C.marikoEmcMaxClock;
|
||||
|
||||
s32 voltAdd = 25 * C.emcDvbShift;
|
||||
#define DVB_VOLT(zero, one, two) std::min(zero + voltAdd, 1050), std::min(one + voltAdd, 1025), std::min(two + voltAdd, 1000),
|
||||
DvbEntry emcDvbTableNew[] = {
|
||||
{ 204000, { 637, 637, 637, } },
|
||||
{ 1331200, { 650, 637, 637, } },
|
||||
{ 1600000, { 675, 650, 637, } },
|
||||
{ 1866000, { DVB_VOLT(700, 675, 650) } },
|
||||
{ 2133000, { DVB_VOLT(725, 700, 675) } },
|
||||
{ 2400000, { DVB_VOLT(750, 725, 700) } },
|
||||
{ 2666000, { DVB_VOLT(775, 750, 725) } },
|
||||
{ 2933000, { DVB_VOLT(800, 775, 750) } },
|
||||
{ 3200000, { DVB_VOLT(800, 800, 775) } },
|
||||
{ 0xFFFFFFFF, { } },
|
||||
};
|
||||
|
||||
u32 j = MtcTableCountDefault;
|
||||
for (u32 i = MtcTableCountDefault; i < newEmcList.size(); ++i) {
|
||||
if (newEmcList[i] >= emcDvbTableNew[j].freq && newEmcList[i] < emcDvbTableNew[j + 1].freq) {
|
||||
emcDvbTableNew[j].freq = newEmcList[i];
|
||||
++j;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::memset(mem_dvb_table_head, 0, sizeof(EmcDvbTableDefault));
|
||||
std::memcpy(mem_dvb_table_head, &emcDvbTableNew, sizeof(emcDvbTableNew));
|
||||
|
||||
/* 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
|
||||
*/
|
||||
@@ -670,8 +815,9 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
}
|
||||
|
||||
Result MemFreqMax(u32 *ptr) {
|
||||
if (C.marikoEmcMaxClock <= EmcClkOSLimit)
|
||||
if (C.marikoEmcMaxClock <= EmcClkOSLimit) {
|
||||
R_SKIP();
|
||||
}
|
||||
|
||||
PATCH_OFFSET(ptr, C.marikoEmcMaxClock);
|
||||
R_SUCCEED();
|
||||
@@ -685,12 +831,13 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
|
||||
I2cSession _session;
|
||||
Result res = i2cOpenSession(&_session, dev);
|
||||
if (R_FAILED(res))
|
||||
if (R_FAILED(res)) {
|
||||
return res;
|
||||
}
|
||||
|
||||
cmd.reg = reg;
|
||||
cmd.val = val;
|
||||
res = i2csessionSendAuto(&_session, &cmd, sizeof(cmd), I2cTransactionOption_All);
|
||||
res = i2csessionSendAuto(&_session, &cmd, sizeof(cmd), I2cTransactionOption_All);
|
||||
i2csessionClose(&_session);
|
||||
return res;
|
||||
}
|
||||
@@ -702,21 +849,24 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
constexpr u32 uv_min = 250'000;
|
||||
|
||||
auto validator = [entry]() {
|
||||
R_UNLESS(entry->id == 2, ldr::ResultInvalidRegulatorEntry());
|
||||
R_UNLESS(entry->type == 3, ldr::ResultInvalidRegulatorEntry());
|
||||
R_UNLESS(entry->id == 2, ldr::ResultInvalidRegulatorEntry());
|
||||
R_UNLESS(entry->type == 3, ldr::ResultInvalidRegulatorEntry());
|
||||
R_UNLESS(entry->type_2_3.step_uv == uv_step, ldr::ResultInvalidRegulatorEntry());
|
||||
R_UNLESS(entry->type_2_3.min_uv == uv_min, ldr::ResultInvalidRegulatorEntry());
|
||||
R_UNLESS(entry->type_2_3.min_uv == uv_min, ldr::ResultInvalidRegulatorEntry());
|
||||
R_SUCCEED();
|
||||
};
|
||||
|
||||
R_TRY(validator());
|
||||
|
||||
u32 emc_uv = C.marikoEmcVddqVolt;
|
||||
if (!emc_uv)
|
||||
R_SKIP();
|
||||
|
||||
if (emc_uv % uv_step)
|
||||
if (!emc_uv) {
|
||||
R_SKIP();
|
||||
}
|
||||
|
||||
if (emc_uv % uv_step) {
|
||||
emc_uv = (emc_uv + uv_step - 1) / uv_step * uv_step; // rounding
|
||||
}
|
||||
|
||||
PATCH_OFFSET(ptr, emc_uv);
|
||||
|
||||
@@ -731,28 +881,61 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
return resultI2C;
|
||||
}
|
||||
|
||||
Result MemMtcTableAsm(u32 *ptr) {
|
||||
constexpr u32 AddpOffset = 1;
|
||||
constexpr u32 BrOffset = 12;
|
||||
constexpr u32 MovOffset = 10;
|
||||
|
||||
/* Ensure we don't dereference memory before nso start. */
|
||||
R_UNLESS(ptr - BrOffset >= nsoStart, ldr::ResultInvalidMtcTable());
|
||||
|
||||
u32 adrp = *(ptr - AddpOffset);
|
||||
R_UNLESS(AsmCompareAdrpNoImm(adrp, MtcAdrpAsm), ldr::ResultInvalidMtcTable());
|
||||
|
||||
/* We don't check for matching register because both registers must be x0 in order to pass the previous checks. */
|
||||
/* The correct instructions will always be x0 since the mtcTable pointer is returned. */
|
||||
|
||||
/* Pray this does not break. */
|
||||
u32 br = *(ptr - BrOffset);
|
||||
R_UNLESS(AsmCompareBrNoRd(br, MtcBrAsm), ldr::ResultInvalidMtcTable());
|
||||
|
||||
/* Pray this does not break either. */
|
||||
u32 mov = *(ptr - MovOffset);
|
||||
R_UNLESS(asm_compare_no_rd(mov, MtcMovAsm), ldr::ResultInvalidMtcTable());
|
||||
|
||||
u8 movRd = asm_get_rd(mov);
|
||||
u32 movCountPatch = asm_set_rd(asm_set_imm16(MtcMovAsm, newEmcList.size()), movRd);
|
||||
|
||||
PATCH_OFFSET(ptr - BrOffset, NopIns);
|
||||
PATCH_OFFSET(ptr - MovOffset, movCountPatch);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void Patch(uintptr_t mapped_nso, size_t nso_size) {
|
||||
nsoStart = reinterpret_cast<u32 *>(mapped_nso);
|
||||
MtcGenerateFreqTables();
|
||||
u32 CpuCvbDefaultMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(CpuCvbTableDefault)->freq);
|
||||
u32 GpuCvbDefaultMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(GpuCvbTableDefault)->freq);
|
||||
|
||||
PatcherEntry<u32> patches[] = {
|
||||
{"CPU Freq Vdd", &CpuFreqVdd, 1, nullptr, CpuClkOSLimit},
|
||||
{"CPU Freq Table", CpuFreqCvbTable<true>, 1, nullptr, CpuCvbDefaultMaxFreq},
|
||||
{"CPU Volt DVFS", &CpuVoltDVFS, 1, nullptr, CpuVminOfficial},
|
||||
{"CPU Volt Thermals", &CpuVoltThermals, 1, nullptr, CpuVminOfficial},
|
||||
{"CPU Volt Dfll", &CpuVoltDfll, 1, nullptr, 0x0000FFCF},
|
||||
{"GPU Volt DVFS", &GpuVoltDVFS, 1, nullptr, GpuVminOfficial},
|
||||
{"GPU Volt Thermals", &GpuVoltThermals, 1, nullptr, GpuVminOfficial},
|
||||
{"GPU Freq Table", GpuFreqCvbTable<true>, 1, nullptr, GpuCvbDefaultMaxFreq},
|
||||
{"GPU Freq Asm", &GpuFreqMaxAsm, 2, &GpuMaxClockPatternFn},
|
||||
{"GPU PLL Max", &GpuFreqPllMax, 1, nullptr, GpuClkPllMax},
|
||||
{"GPU PLL Limit", &GpuFreqPllLimit, 4, nullptr, GpuClkPllLimit},
|
||||
{"MEM Freq Mtc", &MemFreqMtcTable, 0, nullptr, EmcClkOSLimit},
|
||||
{"MEM Freq Dvb", &MemFreqDvbTable, 1, nullptr, EmcClkOSLimit},
|
||||
{"MEM Freq Max", &MemFreqMax, 0, nullptr, EmcClkOSLimit},
|
||||
{"MEM Freq PLLM", &MemFreqPllmLimit, 2, nullptr, EmcClkPllmLimit},
|
||||
{"MEM Vddq", &EmcVddqVolt, 2, nullptr, EmcVddqDefault},
|
||||
{"MEM Vdd2", &MemVoltHandler, 2, nullptr, MemVdd2Default},
|
||||
{ "CPU Freq Vdd", &CpuFreqVdd, 1, nullptr, CpuClkOSLimit },
|
||||
{ "CPU Freq Table", CpuFreqCvbTable<true>, 1, nullptr, CpuCvbDefaultMaxFreq },
|
||||
{ "CPU Volt DVFS", &CpuVoltDVFS, 1, nullptr, CpuVminOfficial },
|
||||
{ "CPU Volt Thermals", &CpuVoltThermals, 1, nullptr, CpuVminOfficial },
|
||||
{ "CPU Volt Dfll", &CpuVoltDfll, 1, nullptr, CpuTune0Low },
|
||||
{ "GPU Volt DVFS", &GpuVoltDVFS, 1, nullptr, GpuVminOfficial },
|
||||
{ "GPU Volt Thermals", &GpuVoltThermals, 1, nullptr, GpuVminOfficial },
|
||||
{ "GPU Freq Table", GpuFreqCvbTable<true>, 1, nullptr, GpuCvbDefaultMaxFreq },
|
||||
{ "GPU Freq Asm", &GpuFreqMaxAsm, 2, &GpuMaxClockPatternFn },
|
||||
{ "GPU PLL Max", &GpuFreqPllMax, 1, nullptr, GpuClkPllMax },
|
||||
{ "GPU PLL Limit", &GpuFreqPllLimit, 4, nullptr, GpuClkPllLimit },
|
||||
{ "MEM Freq Mtc", &MemFreqMtcTable, 0, nullptr, EmcClkOSLimit },
|
||||
{ "MEM Freq Dvb", &MemFreqDvbTable, 1, nullptr, EmcClkOSLimit },
|
||||
{ "MEM Freq Max", &MemFreqMax, 0, nullptr, EmcClkOSLimit },
|
||||
{ "MEM Freq PLLM", &MemFreqPllmLimit, 2, nullptr, EmcClkPllmLimit },
|
||||
{ "MEM Vddq", &EmcVddqVolt, 2, nullptr, EmcVddqDefault },
|
||||
{ "MEM Vdd2", &MemVoltHandler, 2, nullptr, MemVdd2Default },
|
||||
{ "Mem Table Asm", &MemMtcTableAsm, 0, &MemMtcGetGetTablePatternFn },
|
||||
};
|
||||
|
||||
for (uintptr_t ptr = mapped_nso; ptr <= mapped_nso + nso_size - sizeof(MarikoMtcTable); ptr += sizeof(u32)) {
|
||||
|
||||
@@ -52,6 +52,8 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
constexpr u32 CpuVoltOfficial = 1120;
|
||||
constexpr u32 CpuVminOfficial = 620;
|
||||
|
||||
constexpr u32 CpuTune0Low = 0xFFCF;
|
||||
|
||||
static const u32 cpuVoltagePatchValues[] = { 850, 38, 1120, 1000, 100, 1000, 0 };
|
||||
static const s32 cpuVoltagePatchOffsets[] = { -2, -1, 5, 6, 7, 8, 9 };
|
||||
static_assert(sizeof(cpuVoltagePatchValues) == sizeof(cpuVoltagePatchOffsets), "Invalid cpuVoltagePatch size");
|
||||
@@ -108,7 +110,12 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
return asm_compare_no_rd(*ptr32, GpuAsmPattern[0]);
|
||||
}
|
||||
|
||||
constexpr emc_dvb_dvfs_table_t EmcDvbTableDefault[] = {
|
||||
struct DvbEntry {
|
||||
u64 freq;
|
||||
s32 volt[4] = {};
|
||||
};
|
||||
|
||||
constexpr DvbEntry EmcDvbTableDefault[] = {
|
||||
{ 204000, { 637, 637, 637, } },
|
||||
{ 408000, { 637, 637, 637, } },
|
||||
{ 800000, { 637, 637, 637, } },
|
||||
@@ -117,12 +124,161 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
{ 1600000, { 675, 650, 637, } },
|
||||
};
|
||||
|
||||
constexpr u32 EmcListDefault[] = { 204000, 1331200, 1600000, };
|
||||
constexpr u32 EmcListSizeDefault = std::size(EmcListDefault);
|
||||
constexpr u32 EmcListEndDefault = EmcListSizeDefault - 1;
|
||||
constexpr u32 EmcRateStep = 33'000;
|
||||
constexpr u32 EmcRateStepScale = 33'200;
|
||||
|
||||
constexpr u32 EmcClkOSAlt = 1331'200;
|
||||
constexpr u32 EmcClkPllmLimit = 2133'000'000;
|
||||
constexpr u32 EmcVddqDefault = 600'000;
|
||||
constexpr u32 MemVdd2Default = 1100'000;
|
||||
|
||||
constexpr u32 MTC_TABLE_REV = 3;
|
||||
constexpr u32 MTC_TABLE_REV = 3;
|
||||
constexpr u32 MtcTableCountDefault = 3;
|
||||
|
||||
constexpr size_t MtcFullTableSize = sizeof(MarikoMtcTable) * MtcTableCountDefault;
|
||||
constexpr u32 MtcFullTableCount = 17;
|
||||
|
||||
/* These dramids were copied from Hekate -- see /bdk/mem/sdram.h */
|
||||
enum DramId : u64 {
|
||||
HOAG_4GB_HYNIX_H9HCNNNBKMMLXR_NEE = 3,
|
||||
AULA_4GB_HYNIX_H9HCNNNBKMMLXR_NEE = 5,
|
||||
IOWA_4GB_HYNIX_H9HCNNNBKMMLXR_NEE = 6,
|
||||
|
||||
IOWA_4GB_SAMSUNG_K4U6E3S4AM_MGCJ = 8,
|
||||
IOWA_8GB_SAMSUNG_K4UBE3D4AM_MGCJ = 9,
|
||||
IOWA_4GB_HYNIX_H9HCNNNBKMMLHR_NME = 10,
|
||||
IOWA_4GB_MICRON_MT53E512M32D2NP_046_WTE = 11,
|
||||
|
||||
HOAG_4GB_SAMSUNG_K4U6E3S4AM_MGCJ = 12,
|
||||
HOAG_8GB_SAMSUNG_K4UBE3D4AM_MGCJ = 13,
|
||||
HOAG_4GB_HYNIX_H9HCNNNBKMMLHR_NME = 14,
|
||||
HOAG_4GB_MICRON_MT53E512M32D2NP_046_WTE = 15,
|
||||
|
||||
IOWA_4GB_SAMSUNG_K4U6E3S4AA_MGCL = 17,
|
||||
IOWA_8GB_SAMSUNG_K4UBE3D4AA_MGCL = 18,
|
||||
HOAG_4GB_SAMSUNG_K4U6E3S4AA_MGCL = 19,
|
||||
|
||||
IOWA_4GB_SAMSUNG_K4U6E3S4AB_MGCL = 20,
|
||||
HOAG_4GB_SAMSUNG_K4U6E3S4AB_MGCL = 21,
|
||||
AULA_4GB_SAMSUNG_K4U6E3S4AB_MGCL = 22,
|
||||
|
||||
HOAG_8GB_SAMSUNG_K4UBE3D4AA_MGCL = 23,
|
||||
AULA_4GB_SAMSUNG_K4U6E3S4AA_MGCL = 24,
|
||||
|
||||
IOWA_4GB_MICRON_MT53E512M32D2NP_046_WTF = 25,
|
||||
HOAG_4GB_MICRON_MT53E512M32D2NP_046_WTF = 26,
|
||||
AULA_4GB_MICRON_MT53E512M32D2NP_046_WTF = 27,
|
||||
|
||||
AULA_8GB_SAMSUNG_K4UBE3D4AA_MGCL = 28,
|
||||
|
||||
IOWA_4GB_HYNIX_H54G46CYRBX267 = 29,
|
||||
HOAG_4GB_HYNIX_H54G46CYRBX267 = 30,
|
||||
AULA_4GB_HYNIX_H54G46CYRBX267 = 31,
|
||||
|
||||
IOWA_4GB_MICRON_MT53E512M32D1NP_046_WTB = 32,
|
||||
HOAG_4GB_MICRON_MT53E512M32D1NP_046_WTB = 33,
|
||||
AULA_4GB_MICRON_MT53E512M32D1NP_046_WTB = 34,
|
||||
};
|
||||
|
||||
enum MtcTableIndex {
|
||||
T210b0SdevEmcDvfsTableS4gb01 = 0, /* (Unused) Samsung 4Gb */
|
||||
T210b0SdevEmcDvfsTableS4gb03 = 1, /* Samsung AM-MGCJ 4Gb */
|
||||
T210b0SdevEmcDvfsTableS8gb03 = 2, /* (Unused) Samsung 4Gb */
|
||||
T210b0SdevEmcDvfsTableH4gb03 = 3, /* Hynix NME 4Gb */
|
||||
T210b0SdevEmcDvfsTableM4gb03 = 4, /* Micron WT:F 4Gb */
|
||||
T210b0SdevEmcDvfsTableS4gbY01 = 5, /* (Unused) Samsung 4Gb */
|
||||
T210b0SdevEmcDvfsTableS1y4gbY01 = 6, /* (Unused) Samsung 4Gb */
|
||||
T210b0SdevEmcDvfsTableS1y8gbY01 = 7, /* (Unused) Samsung 4Gb */
|
||||
T210b0SdevEmcDvfsTableS1y4gbX03 = 8, /* Samsung AA-MGCL 4Gb */
|
||||
T210b0SdevEmcDvfsTableS1y8gbX03 = 9, /* Samsung AA-MGCL 8Gb */
|
||||
T210b0SdevEmcDvfsTableS1y4gb01 = 10, /* (Unused) Samsung 4Gb */
|
||||
T210b0SdevEmcDvfsTableM1y4gb01 = 11, /* Micron WT:E 4Gb */
|
||||
T210b0SdevEmcDvfsTableH1y4gb01 = 12, /* Hynix NEE 4Gb */
|
||||
T210b0SdevEmcDvfsTableS1y8gb04 = 13, /* Samsung AM-MGCJ 8Gb */
|
||||
T210b0SdevEmcDvfsTableS1z4gb01 = 14, /* Samsung AB-MGCL 4Gb */
|
||||
T210b0SdevEmcDvfsTableH1a4gb01 = 15, /* Hynix x267 4Gb */
|
||||
T210b0SdevEmcDvfsTableM1a4gb01 = 16, /* Micron WT:B 8Gb */
|
||||
MtcTableIndex_Invalid = 17,
|
||||
};
|
||||
|
||||
struct MtcDramIndex {
|
||||
DramId dramId;
|
||||
MtcTableIndex index;
|
||||
};
|
||||
|
||||
constexpr MtcDramIndex mtcIndexTable[] = {
|
||||
{ HOAG_4GB_HYNIX_H9HCNNNBKMMLXR_NEE, T210b0SdevEmcDvfsTableH1y4gb01, },
|
||||
{ AULA_4GB_HYNIX_H9HCNNNBKMMLXR_NEE, T210b0SdevEmcDvfsTableH1y4gb01, },
|
||||
{ IOWA_4GB_HYNIX_H9HCNNNBKMMLXR_NEE, T210b0SdevEmcDvfsTableH1y4gb01, },
|
||||
{ IOWA_4GB_SAMSUNG_K4U6E3S4AM_MGCJ, T210b0SdevEmcDvfsTableS4gb03, },
|
||||
{ IOWA_8GB_SAMSUNG_K4UBE3D4AM_MGCJ, T210b0SdevEmcDvfsTableS1y8gb04, },
|
||||
{ IOWA_4GB_HYNIX_H9HCNNNBKMMLHR_NME, T210b0SdevEmcDvfsTableH4gb03, },
|
||||
{ IOWA_4GB_MICRON_MT53E512M32D2NP_046_WTE, T210b0SdevEmcDvfsTableM1y4gb01, },
|
||||
{ HOAG_4GB_SAMSUNG_K4U6E3S4AM_MGCJ, T210b0SdevEmcDvfsTableS4gb03, },
|
||||
{ HOAG_8GB_SAMSUNG_K4UBE3D4AM_MGCJ, T210b0SdevEmcDvfsTableS1y8gb04, },
|
||||
{ HOAG_4GB_HYNIX_H9HCNNNBKMMLHR_NME, T210b0SdevEmcDvfsTableH4gb03, },
|
||||
{ HOAG_4GB_MICRON_MT53E512M32D2NP_046_WTE, T210b0SdevEmcDvfsTableM1y4gb01, },
|
||||
{ IOWA_4GB_SAMSUNG_K4U6E3S4AA_MGCL, T210b0SdevEmcDvfsTableS1y4gbX03, },
|
||||
{ IOWA_8GB_SAMSUNG_K4UBE3D4AA_MGCL, T210b0SdevEmcDvfsTableS1y8gbX03, },
|
||||
{ HOAG_4GB_SAMSUNG_K4U6E3S4AA_MGCL, T210b0SdevEmcDvfsTableS1y4gbX03, },
|
||||
{ IOWA_4GB_SAMSUNG_K4U6E3S4AB_MGCL, T210b0SdevEmcDvfsTableS1z4gb01, },
|
||||
{ HOAG_4GB_SAMSUNG_K4U6E3S4AB_MGCL, T210b0SdevEmcDvfsTableS1y8gb04, },
|
||||
{ AULA_4GB_SAMSUNG_K4U6E3S4AB_MGCL, T210b0SdevEmcDvfsTableS1y8gb04, },
|
||||
{ HOAG_8GB_SAMSUNG_K4UBE3D4AA_MGCL, T210b0SdevEmcDvfsTableS1y8gbX03, },
|
||||
{ AULA_4GB_SAMSUNG_K4U6E3S4AA_MGCL, T210b0SdevEmcDvfsTableS1y4gbX03, },
|
||||
{ IOWA_4GB_MICRON_MT53E512M32D2NP_046_WTF, T210b0SdevEmcDvfsTableM4gb03, },
|
||||
{ HOAG_4GB_MICRON_MT53E512M32D2NP_046_WTF, T210b0SdevEmcDvfsTableM4gb03, },
|
||||
{ AULA_4GB_MICRON_MT53E512M32D2NP_046_WTF, T210b0SdevEmcDvfsTableM4gb03, },
|
||||
{ AULA_8GB_SAMSUNG_K4UBE3D4AA_MGCL, T210b0SdevEmcDvfsTableS1y8gbX03, },
|
||||
{ IOWA_4GB_HYNIX_H54G46CYRBX267, T210b0SdevEmcDvfsTableH1a4gb01, },
|
||||
{ HOAG_4GB_HYNIX_H54G46CYRBX267, T210b0SdevEmcDvfsTableH1a4gb01, },
|
||||
{ AULA_4GB_HYNIX_H54G46CYRBX267, T210b0SdevEmcDvfsTableH1a4gb01, },
|
||||
{ IOWA_4GB_MICRON_MT53E512M32D1NP_046_WTB, T210b0SdevEmcDvfsTableM1a4gb01, },
|
||||
{ HOAG_4GB_MICRON_MT53E512M32D1NP_046_WTB, T210b0SdevEmcDvfsTableM1a4gb01, },
|
||||
{ AULA_4GB_MICRON_MT53E512M32D1NP_046_WTB, T210b0SdevEmcDvfsTableM1a4gb01, },
|
||||
};
|
||||
|
||||
/*
|
||||
710006abfc 40 01 1f d6 br x10
|
||||
*/
|
||||
|
||||
/*
|
||||
710006ac28 a0 03 00 90 adrp x0,0x71000de000
|
||||
710006ac2c 00 80 16 91 add x0=>SdevEmcDvfsTableS4gb01,x0,#0x5a0
|
||||
*/
|
||||
|
||||
/* Br */
|
||||
/*
|
||||
| Z | OP | Fixed | A | M | RN | RM
|
||||
31 30 29 28 27 26 25 | 24 23 | 22 | 21 20 19 18 17 16 15 14 13 12 |11 | 10 | 9 8 7 6 5 | 4 3 2 1 0
|
||||
1 1 0 1 0 1 1 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 Rn 0 0 0 0 0
|
||||
Z op A M Rm
|
||||
*/
|
||||
|
||||
/* Adrp */
|
||||
/*
|
||||
OP | ImmLow | ImmHigh | RD
|
||||
31 | 30 29 28 27 26 25 24 | 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 | 4 3 2 1 0
|
||||
*/
|
||||
|
||||
/* ADD (immediate) */
|
||||
/*
|
||||
SF | OP | S | Fixed value | Sh | Imm12 | RN | RD
|
||||
31 | 30 | 29 | 28 27 26 25 24 23 | 22 | 21 20 19 18 17 16 15 14 13 12 11 10 | 9 8 7 6 5 | 4 3 2 1 0
|
||||
*/
|
||||
|
||||
constexpr u32 MtcBrAsm = 0xD61F0140;
|
||||
constexpr u32 MtcMovAsm = 0x52800068;
|
||||
constexpr u32 MtcAdrpAsm = 0x900003A0;
|
||||
constexpr u32 MtcAddAsm = 0x91168000;
|
||||
|
||||
ALWAYS_INLINE bool MemMtcGetGetTablePatternFn(u32 *ptr) {
|
||||
/* This builds an address that gets returned, so the register must be x0 by convention. */
|
||||
return AsmCompareAddNoImm12(*ptr, MtcAddAsm);
|
||||
}
|
||||
|
||||
void Patch(uintptr_t mapped_nso, size_t nso_size);
|
||||
|
||||
|
||||
@@ -79,6 +79,8 @@ typedef enum {
|
||||
KipConfigValue_eristaEmcMaxClock,
|
||||
KipConfigValue_eristaEmcMaxClock1,
|
||||
KipConfigValue_eristaEmcMaxClock2,
|
||||
|
||||
KipConfigValue_stepMode,
|
||||
KipConfigValue_marikoEmcMaxClock,
|
||||
KipConfigValue_marikoEmcVddqVolt,
|
||||
KipConfigValue_emcDvbShift,
|
||||
@@ -91,6 +93,23 @@ typedef enum {
|
||||
KipConfigValue_t6_tRTW,
|
||||
KipConfigValue_t7_tWTR,
|
||||
KipConfigValue_t8_tREFI,
|
||||
|
||||
KipConfigValue_timingEmcTbreak,
|
||||
KipConfigValue_low_t6_tRTW,
|
||||
KipConfigValue_low_t7_tWTR,
|
||||
|
||||
KipConfigValue_t2_tRP_cap,
|
||||
|
||||
KipConfigValue_read_latency_1333,
|
||||
KipConfigValue_read_latency_1600,
|
||||
KipConfigValue_read_latency_1866,
|
||||
KipConfigValue_read_latency_2133,
|
||||
|
||||
KipConfigValue_write_latency_1333,
|
||||
KipConfigValue_write_latency_1600,
|
||||
KipConfigValue_write_latency_1866,
|
||||
KipConfigValue_write_latency_2133,
|
||||
|
||||
KipConfigValue_mem_burst_read_latency,
|
||||
KipConfigValue_mem_burst_write_latency,
|
||||
|
||||
@@ -283,6 +302,8 @@ static inline const char* hocclkFormatConfigValue(HocClkConfigValue val, bool pr
|
||||
return pretty ? "Erista EMC Max Clock 2" : "erista_emc_max_clock1";
|
||||
case KipConfigValue_eristaEmcMaxClock2:
|
||||
return pretty ? "Erista EMC Max Clock 3" : "erista_emc_max_clock2";
|
||||
case KipConfigValue_stepMode:
|
||||
return pretty ? "Step Mode:" : "step_mode";
|
||||
case KipConfigValue_marikoEmcMaxClock:
|
||||
return pretty ? "Mariko EMC Max Clock" : "mariko_emc_max_clock";
|
||||
case KipConfigValue_marikoEmcVddqVolt:
|
||||
@@ -307,6 +328,35 @@ static inline const char* hocclkFormatConfigValue(HocClkConfigValue val, bool pr
|
||||
return pretty ? "t7 - tWTR" : "t7_twtr";
|
||||
case KipConfigValue_t8_tREFI:
|
||||
return pretty ? "t8 - tREFI" : "t8_trefi";
|
||||
|
||||
case KipConfigValue_timingEmcTbreak:
|
||||
return pretty ? "Timing Emc Tbreak" : "timingEmcTbreak";
|
||||
case KipConfigValue_low_t6_tRTW:
|
||||
return pretty ? "Low T6 - tRTW" : "low_t6_tRTW";
|
||||
case KipConfigValue_low_t7_tWTR:
|
||||
return pretty ? "Low T7 - tWTR" : "low_t7_tWTR";
|
||||
|
||||
case KipConfigValue_t2_tRP_cap:
|
||||
return pretty ? "t2 - trp 1333WL Cap" : "t2_tRP_cap";
|
||||
|
||||
case KipConfigValue_read_latency_1333:
|
||||
return pretty ? "1333 Read Latency" : "read_latency_1333";
|
||||
case KipConfigValue_read_latency_1600:
|
||||
return pretty ? "1600 Read Latency" : "read_latency_1600";
|
||||
case KipConfigValue_read_latency_1866:
|
||||
return pretty ? "1866 Read Latency" : "read_latency_1866";
|
||||
case KipConfigValue_read_latency_2133:
|
||||
return pretty ? "2133 Read Latency" : "read_latency_2133";
|
||||
|
||||
case KipConfigValue_write_latency_1333:
|
||||
return pretty ? "1333 Write Latency" : "write_latency_1333";
|
||||
case KipConfigValue_write_latency_1600:
|
||||
return pretty ? "1600 Write Latency" : "write_latency_1600";
|
||||
case KipConfigValue_write_latency_1866:
|
||||
return pretty ? "1866 Write Latency" : "write_latency_1866";
|
||||
case KipConfigValue_write_latency_2133:
|
||||
return pretty ? "2133 Write Latency" : "write_latency_2133";
|
||||
|
||||
case KipConfigValue_mem_burst_read_latency:
|
||||
return pretty ? "Memory Burst Read Latency" : "mem_burst_read_latency";
|
||||
case KipConfigValue_mem_burst_write_latency:
|
||||
@@ -512,6 +562,7 @@ static inline uint64_t hocclkValidConfigValue(HocClkConfigValue val, uint64_t in
|
||||
case KipConfigValue_eristaEmcMaxClock:
|
||||
case KipConfigValue_eristaEmcMaxClock1:
|
||||
case KipConfigValue_eristaEmcMaxClock2:
|
||||
case KipConfigValue_stepMode:
|
||||
case KipConfigValue_marikoEmcMaxClock:
|
||||
case KipConfigValue_marikoEmcVddqVolt:
|
||||
case KipConfigValue_emcDvbShift:
|
||||
@@ -523,6 +574,18 @@ static inline uint64_t hocclkValidConfigValue(HocClkConfigValue val, uint64_t in
|
||||
case KipConfigValue_t6_tRTW:
|
||||
case KipConfigValue_t7_tWTR:
|
||||
case KipConfigValue_t8_tREFI:
|
||||
case KipConfigValue_timingEmcTbreak:
|
||||
case KipConfigValue_low_t6_tRTW:
|
||||
case KipConfigValue_low_t7_tWTR:
|
||||
case KipConfigValue_t2_tRP_cap:
|
||||
case KipConfigValue_read_latency_1333:
|
||||
case KipConfigValue_read_latency_1600:
|
||||
case KipConfigValue_read_latency_1866:
|
||||
case KipConfigValue_read_latency_2133:
|
||||
case KipConfigValue_write_latency_1333:
|
||||
case KipConfigValue_write_latency_1600:
|
||||
case KipConfigValue_write_latency_1866:
|
||||
case KipConfigValue_write_latency_2133:
|
||||
case KipConfigValue_mem_burst_read_latency:
|
||||
case KipConfigValue_mem_burst_write_latency:
|
||||
case KipConfigValue_eristaCpuUV:
|
||||
|
||||
@@ -39,7 +39,7 @@ include ${TOPDIR}/lib/libultrahand/ultrahand.mk
|
||||
# version control constants
|
||||
#---------------------------------------------------------------------------------
|
||||
#TARGET_VERSION := $(shell git describe --dirty --always --tags)
|
||||
APP_VERSION := 1.3.0
|
||||
APP_VERSION := 2.0.0
|
||||
TARGET_VERSION := $(APP_VERSION)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
@@ -423,7 +423,7 @@ void MiscGui::listUI()
|
||||
std::vector<NamedValue> noNamedValues = {};
|
||||
|
||||
this->listElement->addItem(new tsl::elm::CategoryHeader("Settings"));
|
||||
|
||||
|
||||
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 orange", false, x + 20, y + 30, 18, tsl::style::color::ColorText);
|
||||
renderer->drawString("require a reboot to apply!", false, x + 20, y + 50, 18, tsl::style::color::ColorText);
|
||||
@@ -554,7 +554,7 @@ protected:
|
||||
{},
|
||||
RamDisplayUnitValues,
|
||||
false
|
||||
|
||||
|
||||
);
|
||||
addConfigButton(
|
||||
HocClkConfigValue_PollingIntervalMs,
|
||||
@@ -604,7 +604,7 @@ protected:
|
||||
false
|
||||
);
|
||||
|
||||
|
||||
|
||||
std::vector<NamedValue> ramRFMeasurementMethods = {
|
||||
NamedValue("Actmon", MemoryFrequencyMeasurementMode_Actmon),
|
||||
NamedValue("PLL", MemoryFrequencyMeasurementMode_PLL),
|
||||
@@ -724,7 +724,7 @@ public:
|
||||
protected:
|
||||
void listUI() override {
|
||||
ValueThresholds thresholdsDisabled(0, 0);
|
||||
|
||||
|
||||
BaseMenuGui::refresh(); // get latest context
|
||||
if(!this->context)
|
||||
return;
|
||||
@@ -876,6 +876,14 @@ protected:
|
||||
true
|
||||
);
|
||||
|
||||
std::vector<NamedValue> stepMode = {
|
||||
NamedValue("66MHz", 0),
|
||||
NamedValue("100MHz", 1),
|
||||
NamedValue("Jedec", 2),
|
||||
};
|
||||
|
||||
addConfigButton(KipConfigValue_stepMode, "Step Mode", ValueRange(0, 0, 2, "", 0), "Step Mode", &thresholdsDisabled, {}, stepMode, false, true);
|
||||
|
||||
if (IsErista()) {
|
||||
tsl::elm::ListItem* freqSubmenu = new tsl::elm::ListItem("RAM Frequency Editor");
|
||||
freqSubmenu->setTextColor(tsl::Color(255, 165, 0, 255));
|
||||
@@ -889,6 +897,7 @@ protected:
|
||||
freqSubmenu->setValue(R_ARROW);
|
||||
this->listElement->addItem(freqSubmenu);
|
||||
} else {
|
||||
RamDisplayUnit unit = (RamDisplayUnit)this->configList->values[HocClkConfigValue_RamDisplayUnit];
|
||||
std::vector<NamedValue> marikoMaxEmcClock = {
|
||||
NamedValue("1600 MHz", 1600000),
|
||||
NamedValue("1633 MHz", 1633000),
|
||||
@@ -950,14 +959,13 @@ protected:
|
||||
// NamedValue("3466MHz (Needs ridiculous Speedo/PLL)", 3466000),
|
||||
// NamedValue("3500MHz (Needs ridiculous Speedo/PLL)", 3500000),
|
||||
};
|
||||
|
||||
RamDisplayUnit unit = (RamDisplayUnit)this->configList->values[HocClkConfigValue_RamDisplayUnit];
|
||||
for (auto& nv : marikoMaxEmcClock)
|
||||
nv.name = formatMemClockKhzLabel(nv.value, unit);
|
||||
|
||||
addConfigButton(KipConfigValue_marikoEmcMaxClock, "Ram Max Clock", ValueRange(0, 1, 1, "", 1), "Ram Max Clock", &thresholdsDisabled, {}, marikoMaxEmcClock, false, true);
|
||||
}
|
||||
|
||||
|
||||
tsl::elm::ListItem* latenciesSubmenu = new tsl::elm::ListItem("RAM Latency Editor");
|
||||
latenciesSubmenu->setTextColor(tsl::Color(255, 165, 0, 255));
|
||||
latenciesSubmenu->setClickListener([](u64 keys) {
|
||||
@@ -1022,7 +1030,80 @@ protected:
|
||||
NamedValue("+3", 3),
|
||||
};
|
||||
|
||||
/* Yes this is duplicated code, yes I don't care. */
|
||||
std::vector<NamedValue> timingTbreakFreqs = {
|
||||
NamedValue("Disabled", 0),
|
||||
NamedValue("1633 MHz", 1633000),
|
||||
NamedValue("1666 MHz", 1666000),
|
||||
NamedValue("1700 MHz", 1700000),
|
||||
NamedValue("1733 MHz", 1733000),
|
||||
NamedValue("1766 MHz", 1766000),
|
||||
NamedValue("1800 MHz", 1800000),
|
||||
NamedValue("1833 MHz", 1833000),
|
||||
NamedValue("1866 MHz", 1866000, "JEDEC."),
|
||||
NamedValue("1900 MHz", 1900000),
|
||||
NamedValue("1933 MHz", 1933000),
|
||||
NamedValue("1966 MHz", 1966000),
|
||||
NamedValue("1996 MHz", 1996800, "JEDEC."),
|
||||
NamedValue("2000 MHz", 2000000),
|
||||
NamedValue("2033 MHz", 2033000),
|
||||
NamedValue("2066 MHz", 2066000),
|
||||
NamedValue("2100 MHz", 2100000),
|
||||
NamedValue("2133 MHz", 2133000, "JEDEC."),
|
||||
NamedValue("2166 MHz", 2166000),
|
||||
NamedValue("2200 MHz", 2200000),
|
||||
NamedValue("2233 MHz", 2233000),
|
||||
NamedValue("2266 MHz", 2266000),
|
||||
NamedValue("2300 MHz", 2300000),
|
||||
NamedValue("2333 MHz", 2333000),
|
||||
NamedValue("2366 MHz", 2366000),
|
||||
NamedValue("2400 MHz", 2400000, "JEDEC."),
|
||||
NamedValue("2433 MHz", 2433000),
|
||||
NamedValue("2466 MHz", 2466000),
|
||||
NamedValue("2500 MHz", 2500000),
|
||||
NamedValue("2533 MHz", 2533000),
|
||||
NamedValue("2566 MHz", 2566000),
|
||||
NamedValue("2600 MHz", 2600000),
|
||||
NamedValue("2633 MHz", 2633000),
|
||||
NamedValue("2666 MHz", 2666000, "JEDEC."),
|
||||
NamedValue("2700 MHz", 2700000),
|
||||
NamedValue("2733 MHz", 2733000),
|
||||
NamedValue("2766 MHz", 2766000),
|
||||
NamedValue("2800 MHz", 2800000),
|
||||
NamedValue("2833 MHz", 2833000),
|
||||
NamedValue("2866 MHz", 2866000),
|
||||
NamedValue("2900 MHz", 2900000),
|
||||
NamedValue("2933 MHz", 2933000, "JEDEC."),
|
||||
NamedValue("2966 MHz", 2966000),
|
||||
NamedValue("3000 MHz", 3000000),
|
||||
NamedValue("3033 MHz", 3033000),
|
||||
NamedValue("3066 MHz", 3066000),
|
||||
NamedValue("3100 MHz", 3100000),
|
||||
NamedValue("3133 MHz", 3133000),
|
||||
NamedValue("3166 MHz", 3166000),
|
||||
NamedValue("3200 MHz", 3200000, "JEDEC."),
|
||||
NamedValue("3233 MHz", 3233000, "High speedo needed"),
|
||||
NamedValue("3266 MHz", 3266000, "High speedo needed!"),
|
||||
NamedValue("3300 MHz", 3300000, "High speedo needed!"),
|
||||
// NamedValue("3333MHz (Needs extreme Speedo/PLL)", 3333000),
|
||||
// NamedValue("3366MHz (Needs extreme Speedo/PLL)", 3366000),
|
||||
// NamedValue("3400MHz (Needs extreme Speedo/PLL)", 3400000),
|
||||
// NamedValue("3433MHz (Needs ridiculous Speedo/PLL)", 3433000),
|
||||
// NamedValue("3466MHz (Needs ridiculous Speedo/PLL)", 3466000),
|
||||
// NamedValue("3500MHz (Needs ridiculous Speedo/PLL)", 3500000),
|
||||
};
|
||||
RamDisplayUnit unit = (RamDisplayUnit)this->configList->values[HocClkConfigValue_RamDisplayUnit];
|
||||
|
||||
for (size_t i = 1; i < timingTbreakFreqs.size(); ++i) {
|
||||
auto &nv = timingTbreakFreqs[i];
|
||||
nv.name = formatMemClockKhzLabel(nv.value, unit);
|
||||
}
|
||||
|
||||
this->listElement->addItem(new tsl::elm::CategoryHeader("Advanced"));
|
||||
addConfigButton(KipConfigValue_timingEmcTbreak, "RAM-Timing tBreak", ValueRange(0, 1, 1, "", 1), "tBreak", &thresholdsDisabled, {}, timingTbreakFreqs, false, true);
|
||||
addConfigButton(KipConfigValue_low_t6_tRTW, "Low t6 tRTW", ValueRange(0, 10, 1, "", 1), "low tRTW", &thresholdsDisabled, {}, {}, false, true );
|
||||
addConfigButton(KipConfigValue_low_t7_tWTR, "Low t7 tWTR", ValueRange(0, 10, 1, "", 1), "low tWTR", &thresholdsDisabled, {}, {}, false, true );
|
||||
addConfigButton(KipConfigValue_t2_tRP_cap, "1333WL t2 RP Cap", ValueRange(0, 8, 1, "", 1), "tRP Cap", &thresholdsDisabled, {}, {}, false, true );
|
||||
addConfigButton(KipConfigValue_t6_tRTW_fine_tune, "t6 tRTW Fine Tune", ValueRange(0, 4, 1, "", 0), "tRTW Fine Tune", &thresholdsDisabled, {}, t6_tRTW_fine_tune, false, true);
|
||||
addConfigButton(KipConfigValue_t7_tWTR_fine_tune, "t7 tWTR Fine Tune", ValueRange(0, 6, 1, "", 0), "tWTR Fine Tune", &thresholdsDisabled, {}, t7_tWTR_fine_tune, false, true);
|
||||
}
|
||||
@@ -1033,48 +1114,252 @@ public:
|
||||
RamLatenciesSubmenuGui() { }
|
||||
|
||||
protected:
|
||||
|
||||
void normalizeLatencies(const HocClkConfigValue keysArr[4]) {
|
||||
uint32_t maxClock = (uint32_t)this->configList->values[KipConfigValue_marikoEmcMaxClock];
|
||||
uint32_t vals[4];
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
vals[i] = (uint32_t)this->configList->values[keysArr[i]];
|
||||
if (vals[i] == 0xFFFFFFFFu) vals[i] = maxClock;
|
||||
}
|
||||
|
||||
uint32_t currentLimit = 0;
|
||||
for (int i = 3; i >= 0; i--) {
|
||||
if (vals[i] != 0) {
|
||||
if (currentLimit != 0 && vals[i] > currentLimit) {
|
||||
vals[i] = currentLimit;
|
||||
}
|
||||
currentLimit = vals[i];
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t last = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (vals[i] == 0) continue;
|
||||
|
||||
if (vals[i] < last) vals[i] = last;
|
||||
if (vals[i] > maxClock) vals[i] = maxClock;
|
||||
|
||||
last = vals[i];
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
this->configList->values[keysArr[i]] = vals[i];
|
||||
}
|
||||
}
|
||||
|
||||
void listUI() override {
|
||||
ValueThresholds thresholdsDisabled(0, 0);
|
||||
|
||||
this->listElement->addItem(new tsl::elm::CategoryHeader("Memory Latencies"));
|
||||
if (IsErista()) {
|
||||
std::vector<NamedValue> rlLabels = { NamedValue("1333 RL", 28), NamedValue("1600 RL", 32), NamedValue("1866 RL", 36), NamedValue("2133 RL", 40) };
|
||||
std::vector<NamedValue> wlLabels = { NamedValue("1333 WL", 12), NamedValue("1600 WL", 14), NamedValue("1866 WL", 16), NamedValue("2133 WL", 18) };
|
||||
|
||||
std::vector<NamedValue> rlLabels = {
|
||||
NamedValue("1333 RL", 28),
|
||||
NamedValue("1600 RL", 32),
|
||||
NamedValue("1866 RL", 36),
|
||||
NamedValue("2133 RL", 40)
|
||||
addConfigButton(KipConfigValue_mem_burst_read_latency, "Read Latency", ValueRange(0, 6, 1, "", 0), "Read Latency", &thresholdsDisabled, {}, rlLabels, false, true);
|
||||
addConfigButton(KipConfigValue_mem_burst_write_latency, "Write Latency", ValueRange(0, 6, 1, "", 0), "Write Latency", &thresholdsDisabled, {}, wlLabels, false, true);
|
||||
return;
|
||||
}
|
||||
|
||||
Result rc = hocclkIpcGetConfigValues(this->configList);
|
||||
if (R_FAILED(rc)) [[unlikely]] {
|
||||
FatalGui::openWithResultCode("hocclkIpcGetConfigValues", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t maxClock = (uint32_t)this->configList->values[KipConfigValue_marikoEmcMaxClock];
|
||||
RamDisplayUnit unit = (RamDisplayUnit)this->configList->values[HocClkConfigValue_RamDisplayUnit];
|
||||
|
||||
static const std::vector<uint32_t> kFreqOptions = {
|
||||
1633000, 1666000, 1700000, 1733000, 1766000, 1800000,
|
||||
1833000, 1866000, 1900000, 1933000, 1966000, 1996800, 2000000,
|
||||
2033000, 2066000, 2100000, 2133000, 2166000, 2200000, 2233000,
|
||||
2266000, 2300000, 2333000, 2366000, 2400000, 2433000, 2466000,
|
||||
2500000, 2533000, 2566000, 2600000, 2633000, 2666000, 2700000,
|
||||
2733000, 2766000, 2800000, 2833000, 2866000, 2900000, 2933000,
|
||||
2966000, 3000000, 3033000, 3066000, 3100000, 3133000, 3166000,
|
||||
3200000, 3233000, 3266000, 3300000,
|
||||
};
|
||||
|
||||
std::vector<NamedValue> wlLabels = {
|
||||
NamedValue("1333 WL", 12),
|
||||
NamedValue("1600 WL", 14),
|
||||
NamedValue("1866 WL", 16),
|
||||
NamedValue("2133 WL", 18)
|
||||
static const HocClkConfigValue kLatencyRKeys[4] = {
|
||||
KipConfigValue_read_latency_1333,
|
||||
KipConfigValue_read_latency_1600,
|
||||
KipConfigValue_read_latency_1866,
|
||||
KipConfigValue_read_latency_2133,
|
||||
};
|
||||
static const HocClkConfigValue kLatencyWKeys[4] = {
|
||||
KipConfigValue_write_latency_1333,
|
||||
KipConfigValue_write_latency_1600,
|
||||
KipConfigValue_write_latency_1866,
|
||||
KipConfigValue_write_latency_2133,
|
||||
};
|
||||
|
||||
addConfigButton(
|
||||
KipConfigValue_mem_burst_read_latency,
|
||||
"Read Latency",
|
||||
ValueRange(0, 6, 1, "", 0),
|
||||
"Read Latency",
|
||||
&thresholdsDisabled,
|
||||
{},
|
||||
rlLabels,
|
||||
false,
|
||||
true
|
||||
);
|
||||
static const char* kTierLabels[4] = { "1333 Latency Max", "1600 Latency Max", "1866 Latency Max", "2133 Latency Max" };
|
||||
|
||||
addConfigButton(
|
||||
KipConfigValue_mem_burst_write_latency,
|
||||
"Write Latency",
|
||||
ValueRange(0, 6, 1, "", 0),
|
||||
"Write Latency",
|
||||
&thresholdsDisabled,
|
||||
{},
|
||||
wlLabels,
|
||||
false,
|
||||
true
|
||||
);
|
||||
auto buildNamedValues = [&](int tierIdx) -> std::vector<NamedValue> {
|
||||
std::vector<NamedValue> nv;
|
||||
nv.push_back(NamedValue("-", 0u));
|
||||
if (tierIdx == 3) {
|
||||
nv.push_back(NamedValue(formatMemClockKhzLabel(maxClock, unit), maxClock));
|
||||
nv.push_back(NamedValue(formatMemClockKhzLabel(maxClock, unit), 0xFFFFFFFFu));
|
||||
} else {
|
||||
for (uint32_t freq : kFreqOptions) {
|
||||
if (freq > maxClock) continue;
|
||||
nv.push_back(NamedValue(formatMemClockKhzLabel(freq, unit), freq));
|
||||
}
|
||||
nv.push_back(NamedValue(formatMemClockKhzLabel(maxClock, unit), maxClock));
|
||||
nv.push_back(NamedValue(formatMemClockKhzLabel(maxClock, unit), 0xFFFFFFFFu));
|
||||
}
|
||||
return nv;
|
||||
};
|
||||
|
||||
auto makeValueText = [&](uint32_t rawVal) -> std::string {
|
||||
if (rawVal == 0) return "-";
|
||||
if (rawVal == 0xFFFFFFFFu) return formatMemClockKhzLabel(maxClock, unit);
|
||||
return formatMemClockKhzLabel(rawVal, unit);
|
||||
};
|
||||
|
||||
auto addLatencyRow = [&](const char* label, int tierIdx, const HocClkConfigValue keysArr[4]) {
|
||||
HocClkConfigValue thisKey = keysArr[tierIdx];
|
||||
uint32_t currentVal = (uint32_t)this->configList->values[thisKey];
|
||||
|
||||
tsl::elm::ListItem* item = new tsl::elm::ListItem(label);
|
||||
item->setTextColor(tsl::Color(255, 165, 0, 255));
|
||||
item->setValue(makeValueText(currentVal));
|
||||
|
||||
item->setClickListener([this, tierIdx, thisKey, keysArr](u64 keys) -> bool {
|
||||
if ((keys & HidNpadButton_A) == 0)
|
||||
return false;
|
||||
|
||||
uint32_t vals[4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
vals[i] = (uint32_t)this->configList->values[keysArr[i]];
|
||||
|
||||
uint32_t maxClock = (uint32_t)this->configList->values[KipConfigValue_marikoEmcMaxClock];
|
||||
RamDisplayUnit unit = (RamDisplayUnit)this->configList->values[HocClkConfigValue_RamDisplayUnit];
|
||||
|
||||
auto resolveVal = [maxClock](uint32_t v) -> uint32_t {
|
||||
return (v == 0xFFFFFFFFu) ? maxClock : v;
|
||||
};
|
||||
|
||||
if (tierIdx == 3) {
|
||||
bool maxOccupied = false;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (resolveVal(vals[i]) == maxClock) {
|
||||
maxOccupied = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<NamedValue> opts;
|
||||
opts.push_back(NamedValue("-", 0u));
|
||||
|
||||
if (!maxOccupied) {
|
||||
opts.push_back(NamedValue(formatMemClockKhzLabel(maxClock, unit), maxClock));
|
||||
}
|
||||
|
||||
uint32_t displayCurrent = resolveVal(vals[3]);
|
||||
if (maxOccupied && displayCurrent == maxClock) {
|
||||
displayCurrent = 0;
|
||||
}
|
||||
|
||||
tsl::changeTo<ValueChoiceGui>(
|
||||
displayCurrent,
|
||||
ValueRange(0, 0, 1, "", 1),
|
||||
std::string("2133 Latency Max"),
|
||||
[this, thisKey, keysArr](uint32_t chosen) -> bool {
|
||||
this->configList->values[thisKey] = chosen;
|
||||
Result rc = hocclkIpcSetConfigValues(this->configList);
|
||||
if (R_FAILED(rc)) {
|
||||
FatalGui::openWithResultCode("hocclkIpcSetConfigValues", rc);
|
||||
return false;
|
||||
}
|
||||
sendKipData();
|
||||
this->lastContextUpdate = armGetSystemTick();
|
||||
return true;
|
||||
},
|
||||
ValueThresholds(), false,
|
||||
std::map<uint32_t, std::string>{},
|
||||
opts,
|
||||
false,
|
||||
false
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t lowerBound = 0;
|
||||
for (int i = 0; i < tierIdx; i++) {
|
||||
uint32_t v = resolveVal(vals[i]);
|
||||
if (v != 0 && v > lowerBound)
|
||||
lowerBound = v;
|
||||
}
|
||||
|
||||
uint32_t upperBound = 0;
|
||||
for (int i = tierIdx + 1; i < 4; i++) {
|
||||
uint32_t v;
|
||||
if (i == 3) {
|
||||
uint32_t r = resolveVal(vals[i]);
|
||||
v = (r != 0) ? maxClock : 0;
|
||||
} else {
|
||||
v = resolveVal(vals[i]);
|
||||
}
|
||||
if (v != 0 && (upperBound == 0 || v < upperBound))
|
||||
upperBound = v;
|
||||
}
|
||||
|
||||
std::vector<NamedValue> opts;
|
||||
opts.push_back(NamedValue("-", 0u));
|
||||
for (uint32_t freq : kFreqOptions) {
|
||||
if (freq <= lowerBound) continue;
|
||||
if (freq > maxClock) continue;
|
||||
if (upperBound != 0 && freq >= upperBound) continue;
|
||||
opts.push_back(NamedValue(formatMemClockKhzLabel(freq, unit), freq));
|
||||
}
|
||||
|
||||
uint32_t displayCurrent = resolveVal(vals[tierIdx]);
|
||||
bool currentInList = false;
|
||||
for (auto& nv : opts)
|
||||
if (nv.value == displayCurrent) { currentInList = true; break; }
|
||||
if (!currentInList) displayCurrent = 0;
|
||||
|
||||
tsl::changeTo<ValueChoiceGui>(
|
||||
displayCurrent,
|
||||
ValueRange(0, 0, 1, "", 1),
|
||||
std::string("Latency Max"),
|
||||
[this, thisKey, keysArr](uint32_t chosen) -> bool {
|
||||
this->configList->values[thisKey] = chosen;
|
||||
normalizeLatencies(keysArr);
|
||||
Result rc = hocclkIpcSetConfigValues(this->configList);
|
||||
if (R_FAILED(rc)) {
|
||||
FatalGui::openWithResultCode("hocclkIpcSetConfigValues", rc);
|
||||
return false;
|
||||
}
|
||||
sendKipData();
|
||||
this->lastContextUpdate = armGetSystemTick();
|
||||
return true;
|
||||
},
|
||||
ValueThresholds(), false,
|
||||
std::map<uint32_t, std::string>{},
|
||||
opts,
|
||||
false,
|
||||
false
|
||||
);
|
||||
return true;
|
||||
});
|
||||
|
||||
this->listElement->addItem(item);
|
||||
this->configButtons[thisKey] = item;
|
||||
this->configRanges[thisKey] = ValueRange(0, 0, 1, "", 1);
|
||||
this->configNamedValues[thisKey] = buildNamedValues(tierIdx);
|
||||
};
|
||||
|
||||
this->listElement->addItem(new tsl::elm::CategoryHeader("Read Latency"));
|
||||
for (int i = 0; i < 4; i++)
|
||||
addLatencyRow(kTierLabels[i], i, kLatencyRKeys);
|
||||
|
||||
this->listElement->addItem(new tsl::elm::CategoryHeader("Write Latency"));
|
||||
for (int i = 0; i < 4; i++)
|
||||
addLatencyRow(kTierLabels[i], i, kLatencyWKeys);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1373,7 +1658,7 @@ protected:
|
||||
for (auto& nv : eristaMaxEmcClock)
|
||||
if (nv.name != "Disabled")
|
||||
nv.name = formatMemClockKhzLabel(nv.value, unit);
|
||||
|
||||
|
||||
addConfigButtonS(KipConfigValue_eristaEmcMaxClock, "", ValueRange(0, 1, 1, "", 1), "", &eristaRamThresholds, {}, eristaMaxEmcClock, false, A_BTN, true);
|
||||
addConfigButtonS(KipConfigValue_eristaEmcMaxClock1, "", ValueRange(0, 1, 1, "", 1), "", &eristaRamThresholds, {}, eristaMaxEmcClock, false, A_BTN, true);
|
||||
addConfigButtonS(KipConfigValue_eristaEmcMaxClock2, "", ValueRange(0, 1, 1, "", 1), "", &eristaRamThresholds, {}, eristaMaxEmcClock, false, A_BTN, true);
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
namespace kip {
|
||||
|
||||
bool kipAvailable = false;
|
||||
|
||||
|
||||
void SetKipData()
|
||||
{
|
||||
// TODO: figure out if this REALLY causes issues (i doubt it)
|
||||
@@ -70,6 +70,23 @@ namespace kip {
|
||||
CUST_WRITE_FIELD_BATCH(&table, t6_tRTW, config::GetConfigValue(KipConfigValue_t6_tRTW));
|
||||
CUST_WRITE_FIELD_BATCH(&table, t7_tWTR, config::GetConfigValue(KipConfigValue_t7_tWTR));
|
||||
CUST_WRITE_FIELD_BATCH(&table, t8_tREFI, config::GetConfigValue(KipConfigValue_t8_tREFI));
|
||||
CUST_WRITE_FIELD_BATCH(&table, stepMode, config::GetConfigValue(KipConfigValue_stepMode));
|
||||
|
||||
CUST_WRITE_FIELD_BATCH(&table, timingEmcTbreak, config::GetConfigValue(KipConfigValue_timingEmcTbreak));
|
||||
CUST_WRITE_FIELD_BATCH(&table, low_t6_tRTW, config::GetConfigValue(KipConfigValue_low_t6_tRTW));
|
||||
CUST_WRITE_FIELD_BATCH(&table, low_t7_tWTR, config::GetConfigValue(KipConfigValue_low_t7_tWTR));
|
||||
CUST_WRITE_FIELD_BATCH(&table, t2_tRP_cap, config::GetConfigValue(KipConfigValue_t2_tRP_cap));
|
||||
|
||||
CUST_WRITE_FIELD_BATCH(&table, readLatency1333, config::GetConfigValue(KipConfigValue_read_latency_1333));
|
||||
CUST_WRITE_FIELD_BATCH(&table, readLatency1600, config::GetConfigValue(KipConfigValue_read_latency_1600));
|
||||
CUST_WRITE_FIELD_BATCH(&table, readLatency1866, config::GetConfigValue(KipConfigValue_read_latency_1866));
|
||||
CUST_WRITE_FIELD_BATCH(&table, readLatency2133, config::GetConfigValue(KipConfigValue_read_latency_2133));
|
||||
|
||||
CUST_WRITE_FIELD_BATCH(&table, writeLatency1333, config::GetConfigValue(KipConfigValue_write_latency_1333));
|
||||
CUST_WRITE_FIELD_BATCH(&table, writeLatency1600, config::GetConfigValue(KipConfigValue_write_latency_1600));
|
||||
CUST_WRITE_FIELD_BATCH(&table, writeLatency1866, config::GetConfigValue(KipConfigValue_write_latency_1866));
|
||||
CUST_WRITE_FIELD_BATCH(&table, writeLatency2133, config::GetConfigValue(KipConfigValue_write_latency_2133));
|
||||
|
||||
CUST_WRITE_FIELD_BATCH(&table, mem_burst_read_latency, config::GetConfigValue(KipConfigValue_mem_burst_read_latency));
|
||||
CUST_WRITE_FIELD_BATCH(&table, mem_burst_write_latency, config::GetConfigValue(KipConfigValue_mem_burst_write_latency));
|
||||
CUST_WRITE_FIELD_BATCH(&table, eristaCpuUV, config::GetConfigValue(KipConfigValue_eristaCpuUV));
|
||||
@@ -166,7 +183,7 @@ namespace kip {
|
||||
configValues.values[HocClkConfigValue_IsFirstLoad] = (u64)false;
|
||||
notification::writeNotification("Horizon OC has been installed");
|
||||
}
|
||||
|
||||
|
||||
configValues.values[KipCrc32] = (u64)crc32::checksum_file("sdmc:/atmosphere/kips/hoc.kip"); // write checksum
|
||||
// configValues.values[KipConfigValue_mtcConf] = cust_get_mtc_conf(&table);
|
||||
configValues.values[KipConfigValue_hpMode] = cust_get_hp_mode(&table);
|
||||
@@ -187,6 +204,23 @@ namespace kip {
|
||||
configValues.values[KipConfigValue_t6_tRTW] = cust_get_tRTW(&table);
|
||||
configValues.values[KipConfigValue_t7_tWTR] = cust_get_tWTR(&table);
|
||||
configValues.values[KipConfigValue_t8_tREFI] = cust_get_tREFI(&table);
|
||||
configValues.values[KipConfigValue_stepMode] = cust_get_step_mode(&table);
|
||||
|
||||
configValues.values[KipConfigValue_timingEmcTbreak] = cust_get_timing_emc_tbreak(&table);
|
||||
configValues.values[KipConfigValue_low_t6_tRTW] = cust_get_low_t6_tRTW(&table);
|
||||
configValues.values[KipConfigValue_low_t7_tWTR] = cust_get_low_t7_tWTR(&table);
|
||||
configValues.values[KipConfigValue_t2_tRP_cap] = cust_get_tRP_cap(&table);
|
||||
|
||||
configValues.values[KipConfigValue_read_latency_1333] = cust_get_read_latency_1333(&table);
|
||||
configValues.values[KipConfigValue_read_latency_1600] = cust_get_read_latency_1600(&table);
|
||||
configValues.values[KipConfigValue_read_latency_1866] = cust_get_read_latency_1866(&table);
|
||||
configValues.values[KipConfigValue_read_latency_2133] = cust_get_read_latency_2133(&table);
|
||||
|
||||
configValues.values[KipConfigValue_write_latency_1333] = cust_get_write_latency_1333(&table);
|
||||
configValues.values[KipConfigValue_write_latency_1600] = cust_get_write_latency_1600(&table);
|
||||
configValues.values[KipConfigValue_write_latency_1866] = cust_get_write_latency_1866(&table);
|
||||
configValues.values[KipConfigValue_write_latency_2133] = cust_get_write_latency_2133(&table);
|
||||
|
||||
configValues.values[KipConfigValue_mem_burst_read_latency] = cust_get_burst_read_lat(&table);
|
||||
configValues.values[KipConfigValue_mem_burst_write_latency] = cust_get_burst_write_lat(&table);
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
namespace kip {
|
||||
extern bool kipAvailable;
|
||||
|
||||
|
||||
typedef struct {
|
||||
u8 cust[4];
|
||||
u32 custRev;
|
||||
@@ -40,6 +40,7 @@ namespace kip {
|
||||
u32 eristaEmcMaxClock;
|
||||
u32 eristaEmcMaxClock1;
|
||||
u32 eristaEmcMaxClock2;
|
||||
u32 stepMode;
|
||||
u32 marikoEmcMaxClock;
|
||||
u32 marikoEmcVddqVolt;
|
||||
u32 emcDvbShift;
|
||||
@@ -53,6 +54,16 @@ namespace kip {
|
||||
u32 t7_tWTR;
|
||||
u32 t8_tREFI;
|
||||
|
||||
u32 t2_tRP_cap;
|
||||
|
||||
u32 timingEmcTbreak;
|
||||
u32 low_t6_tRTW;
|
||||
u32 low_t7_tWTR;
|
||||
|
||||
/* These latencies are arrays in loader, but it's easier to handle it this way in the configurator. */
|
||||
u32 readLatency1333, readLatency1600, readLatency1866, readLatency2133;
|
||||
u32 writeLatency1333, writeLatency1600, writeLatency1866, writeLatency2133;
|
||||
|
||||
u32 mem_burst_read_latency;
|
||||
u32 mem_burst_write_latency;
|
||||
|
||||
@@ -201,6 +212,7 @@ namespace kip {
|
||||
static inline bool cust_set_erista_emc_max(const char* p, u32 v) { CUST_WRITE_FIELD(p, eristaEmcMaxClock, v); }
|
||||
static inline bool cust_set_erista_emc_max1(const char* p, u32 v) { CUST_WRITE_FIELD(p, eristaEmcMaxClock1, v); }
|
||||
static inline bool cust_set_erista_emc_max2(const char* p, u32 v) { CUST_WRITE_FIELD(p, eristaEmcMaxClock2, v); }
|
||||
static inline bool cust_set_step_mode(const char* p, u32 v) { CUST_WRITE_FIELD(p, stepMode, v); }
|
||||
static inline bool cust_set_mariko_emc_max(const char* p, u32 v) { CUST_WRITE_FIELD(p, marikoEmcMaxClock, v); }
|
||||
static inline bool cust_set_mariko_emc_vddq(const char* p, u32 v) { CUST_WRITE_FIELD(p, marikoEmcVddqVolt, v); }
|
||||
static inline bool cust_set_emc_dvb_shift(const char* p, u32 v) { CUST_WRITE_FIELD(p, emcDvbShift, v); }
|
||||
@@ -213,8 +225,23 @@ namespace kip {
|
||||
static inline bool cust_set_tRTW(const char* p, u32 v) { CUST_WRITE_FIELD(p, t6_tRTW, v); }
|
||||
static inline bool cust_set_tWTR(const char* p, u32 v) { CUST_WRITE_FIELD(p, t7_tWTR, v); }
|
||||
static inline bool cust_set_tREFI(const char* p, u32 v) { CUST_WRITE_FIELD(p, t8_tREFI, v); }
|
||||
static inline bool cust_set_tRP_cap(const char* p, u32 v) { CUST_WRITE_FIELD(p, t2_tRP_cap, v); }
|
||||
static inline bool cust_set_timing_emc_tbreak(const char* p, u32 v) { CUST_WRITE_FIELD(p, timingEmcTbreak, v); }
|
||||
static inline bool cust_set_low_tRTW(const char* p, u32 v) { CUST_WRITE_FIELD(p, low_t6_tRTW, v); }
|
||||
static inline bool cust_set_low_tWTR(const char* p, u32 v) { CUST_WRITE_FIELD(p, low_t7_tWTR, v); }
|
||||
static inline bool cust_set_tRTW_fine_tune(const char* p, u32 v) { CUST_WRITE_FIELD(p, t6_tRTW_fine_tune, v); }
|
||||
static inline bool cust_set_tWTR_fine_tune(const char* p, u32 v) { CUST_WRITE_FIELD(p, t7_tWTR_fine_tune, v); }
|
||||
|
||||
static inline bool cust_set_read_latency_1333(const char* p, u32 v) { CUST_WRITE_FIELD(p, readLatency1333, v); }
|
||||
static inline bool cust_set_read_latency_1600(const char* p, u32 v) { CUST_WRITE_FIELD(p, readLatency1600, v); }
|
||||
static inline bool cust_set_read_latency_1866(const char* p, u32 v) { CUST_WRITE_FIELD(p, readLatency1866, v); }
|
||||
static inline bool cust_set_read_latency_2133(const char* p, u32 v) { CUST_WRITE_FIELD(p, readLatency2133, v); }
|
||||
|
||||
static inline bool cust_set_write_latency_1333(const char* p, u32 v) { CUST_WRITE_FIELD(p, writeLatency1333, v); }
|
||||
static inline bool cust_set_write_latency_1600(const char* p, u32 v) { CUST_WRITE_FIELD(p, writeLatency1600, v); }
|
||||
static inline bool cust_set_write_latency_1866(const char* p, u32 v) { CUST_WRITE_FIELD(p, writeLatency1866, v); }
|
||||
static inline bool cust_set_write_latency_2133(const char* p, u32 v) { CUST_WRITE_FIELD(p, writeLatency2133, v); }
|
||||
|
||||
static inline bool cust_set_burst_read_lat(const char* p, u32 v) { CUST_WRITE_FIELD(p, mem_burst_read_latency, v); }
|
||||
static inline bool cust_set_burst_write_lat(const char* p, u32 v) { CUST_WRITE_FIELD(p, mem_burst_write_latency, v); }
|
||||
|
||||
@@ -272,6 +299,7 @@ namespace kip {
|
||||
static inline u32 cust_get_erista_emc_max(const CustomizeTable* t) { return CUST_GET_FIELD(t, eristaEmcMaxClock); }
|
||||
static inline u32 cust_get_erista_emc_max1(const CustomizeTable* t) { return CUST_GET_FIELD(t, eristaEmcMaxClock1); }
|
||||
static inline u32 cust_get_erista_emc_max2(const CustomizeTable* t) { return CUST_GET_FIELD(t, eristaEmcMaxClock2); }
|
||||
static inline u32 cust_get_step_mode(const CustomizeTable* t) { return CUST_GET_FIELD(t, stepMode); }
|
||||
static inline u32 cust_get_mariko_emc_max(const CustomizeTable* t) { return CUST_GET_FIELD(t, marikoEmcMaxClock); }
|
||||
static inline u32 cust_get_mariko_emc_vddq(const CustomizeTable* t) { return CUST_GET_FIELD(t, marikoEmcVddqVolt); }
|
||||
static inline u32 cust_get_emc_dvb_shift(const CustomizeTable* t) { return CUST_GET_FIELD(t, emcDvbShift); }
|
||||
@@ -284,8 +312,23 @@ namespace kip {
|
||||
static inline u32 cust_get_tRTW(const CustomizeTable* t) { return CUST_GET_FIELD(t, t6_tRTW); }
|
||||
static inline u32 cust_get_tWTR(const CustomizeTable* t) { return CUST_GET_FIELD(t, t7_tWTR); }
|
||||
static inline u32 cust_get_tREFI(const CustomizeTable* t) { return CUST_GET_FIELD(t, t8_tREFI); }
|
||||
static inline u32 cust_get_tRP_cap(const CustomizeTable* t) { return CUST_GET_FIELD(t, t2_tRP_cap); }
|
||||
static inline u32 cust_get_timing_emc_tbreak(const CustomizeTable* t) { return CUST_GET_FIELD(t, timingEmcTbreak); }
|
||||
static inline u32 cust_get_low_t6_tRTW(const CustomizeTable* t) { return CUST_GET_FIELD(t, low_t6_tRTW); }
|
||||
static inline u32 cust_get_low_t7_tWTR(const CustomizeTable* t) { return CUST_GET_FIELD(t, low_t7_tWTR); }
|
||||
static inline u32 cust_get_tRTW_fine_tune(const CustomizeTable* t) { return CUST_GET_FIELD(t, t6_tRTW_fine_tune); }
|
||||
static inline u32 cust_get_tWTR_fine_tune(const CustomizeTable* t) { return CUST_GET_FIELD(t, t7_tWTR_fine_tune); }
|
||||
|
||||
static inline u32 cust_get_read_latency_1333(const CustomizeTable* t) { return CUST_GET_FIELD(t, readLatency1333); }
|
||||
static inline u32 cust_get_read_latency_1600(const CustomizeTable* t) { return CUST_GET_FIELD(t, readLatency1600); }
|
||||
static inline u32 cust_get_read_latency_1866(const CustomizeTable* t) { return CUST_GET_FIELD(t, readLatency1866); }
|
||||
static inline u32 cust_get_read_latency_2133(const CustomizeTable* t) { return CUST_GET_FIELD(t, readLatency2133); }
|
||||
|
||||
static inline u32 cust_get_write_latency_1333(const CustomizeTable* t) { return CUST_GET_FIELD(t, writeLatency1333); }
|
||||
static inline u32 cust_get_write_latency_1600(const CustomizeTable* t) { return CUST_GET_FIELD(t, writeLatency1600); }
|
||||
static inline u32 cust_get_write_latency_1866(const CustomizeTable* t) { return CUST_GET_FIELD(t, writeLatency1866); }
|
||||
static inline u32 cust_get_write_latency_2133(const CustomizeTable* t) { return CUST_GET_FIELD(t, writeLatency2133); }
|
||||
|
||||
static inline u32 cust_get_burst_read_lat(const CustomizeTable* t) { return CUST_GET_FIELD(t, mem_burst_read_latency); }
|
||||
static inline u32 cust_get_burst_write_lat(const CustomizeTable* t) { return CUST_GET_FIELD(t, mem_burst_write_latency); }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user