- CPU OC for Erista (does NOT work out of the box)
- DRAM Bus voltage for Erista - Mariko DRAM timing customization
This commit is contained in:
40
README.md
40
README.md
@@ -16,9 +16,7 @@ I'd appreciate if someone is willing to contribute or upload latest binaries. Bu
|
|||||||
|
|
||||||
- There is **no dynamic frequency scaling** in HOS, which makes _overclocking acts differently than PC_ or other mobile devices. The console will be _sticking to what frequency you've set in the long term_, until you close the game or put it into sleep.
|
- There is **no dynamic frequency scaling** in HOS, which makes _overclocking acts differently than PC_ or other mobile devices. The console will be _sticking to what frequency you've set in the long term_, until you close the game or put it into sleep.
|
||||||
|
|
||||||
- **ONLY ramp up RAM clock** beyond HOS maximum to 1862 / 1996 MHz if you want to _stay safe_.
|
- Higher RAM clocks (> 1996.8 MHz) without proper timings could be UNSTABLE and cause graphical glitches / instabilities / filesystem corruption. **Always make backup before usage.**
|
||||||
|
|
||||||
- Higher RAM clocks (> 1996.8 MHz) could be UNSTABLE and cause graphical glitches / instabilities / filesystem corruption. **Always make backup before usage.**
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -28,14 +26,15 @@ I'd appreciate if someone is willing to contribute or upload latest binaries. Bu
|
|||||||
|
|
||||||
- Most games are **bottlenecked by RAM bandwidth**
|
- Most games are **bottlenecked by RAM bandwidth**
|
||||||
|
|
||||||
- Safe: 1862.4 / 1996.8 MHz
|
- Timings could be auto-adjusted (default), partially customized, or overwritten with entire mtc table.
|
||||||
- 1862.4 / 1996.8 MHz is stable for all (Samsung / Micron / Hynix).
|
|
||||||
- Adjusted memory parameters (Mariko only). [Discussion](https://github.com/KazushiMe/Switch-OC-Suite/issues/5).
|
- Safe: ≤1996.8 MHz
|
||||||
|
- 1996.8 MHz has been tested stable for all (Samsung / Micron / Hynix), with built-in timing auto-adjustment.
|
||||||
|
|
||||||
- Unsafe: > 1996.8 MHz or overvolting
|
- Unsafe: > 1996.8 MHz or overvolting
|
||||||
- Higher RAM clocks might be stable for some chips without overvolting. [Not publicly available.](#Build)
|
- Timing customization: No GUI tool, requires [rebuilding](#Build).
|
||||||
- No evidence suggests that DRAM bus overvolting is useful.
|
- DRAM bus overvolting (Erista Only).
|
||||||
- [Use this to set DRAM bus voltage](https://gist.github.com/KazushiMe/6bb0fcbefe0e03b1274079522516d56d).
|
- Mariko: [use this to set DRAM bus voltage](https://gist.github.com/KazushiMe/6bb0fcbefe0e03b1274079522516d56d).
|
||||||
|
|
||||||
- **[System Settings (Optional)](https://github.com/KazushiMe/Switch-OC-Suite/blob/master/system_settings.md)**
|
- **[System Settings (Optional)](https://github.com/KazushiMe/Switch-OC-Suite/blob/master/system_settings.md)**
|
||||||
|
|
||||||
@@ -96,9 +95,25 @@ I'd appreciate if someone is willing to contribute or upload latest binaries. Bu
|
|||||||
2. Mariko Only: Copy all files in `SdOut` to the root of SD card.
|
2. Mariko Only: Copy all files in `SdOut` to the root of SD card.
|
||||||
- Erista: Use official sys-clk instead. Only `loader.kip` and some benchmark homebrew are available.
|
- Erista: Use official sys-clk instead. Only `loader.kip` and some benchmark homebrew are available.
|
||||||
|
|
||||||
3. Grab `x.x.x_loader_xxxx.x.kip` for your Atmosphere version and desired RAM frequency, rename it to `loader.kip` and place it in `/atmosphere/kips/`.
|
3. Grab `x.x.x_loader.kip` for your Atmosphere version, rename it to `loader.kip` and place it in `/atmosphere/kips/`.
|
||||||
|
|
||||||
4. **Hekate-ipl bootloader**
|
4. Customization
|
||||||
|
| Defaults | Mariko | Erista |
|
||||||
|
| ---------- | ------------- | ------------ |
|
||||||
|
| CPU OC | 2397 MHz Max | Disabled |
|
||||||
|
| CPU Volt | 1220 mV Max | Disabled |
|
||||||
|
| GPU OC | 1305 MHz Max | N/A |
|
||||||
|
| RAM OC | 1996 MHz Max | 1996 MHz Max |
|
||||||
|
| RAM Volt | N/A | Disabled |
|
||||||
|
| RAM Timing | Auto-Adjusted | Disabled |
|
||||||
|
|
||||||
|
- No parser/editor currently, although you could easily customize those with a hex editor:
|
||||||
|
- Search for ASCII string `CUST`
|
||||||
|
- All values are little-endian
|
||||||
|
- Switch to override or replace mode, NOT insert mode
|
||||||
|
- See `ldr_oc_suite.hpp` for config struct
|
||||||
|
|
||||||
|
5. **Hekate-ipl bootloader**
|
||||||
- Rename the kip to `loader.kip` and add `kip1=atmosphere/kips/loader.kip` in `bootloader/hekate_ipl.ini`
|
- Rename the kip to `loader.kip` and add `kip1=atmosphere/kips/loader.kip` in `bootloader/hekate_ipl.ini`
|
||||||
- Erista: Minerva module conflicts with HOS DRAM training. Recompile with frequency changed is recommeded, although you could simply remove `bootloader/sys/libsys_minerva.bso`.
|
- Erista: Minerva module conflicts with HOS DRAM training. Recompile with frequency changed is recommeded, although you could simply remove `bootloader/sys/libsys_minerva.bso`.
|
||||||
|
|
||||||
@@ -113,6 +128,8 @@ Grab necessary patches from the repo, then compile sys-clk, ReverseNX-RT and Atm
|
|||||||
|
|
||||||
If you are to install nro forwarders, remove `R_TRY(ValidateAcidSignature(std::addressof(g_original_meta_cache.meta)));` in `Atmosphere/stratosphere/loader/source/ldr_meta.cpp` to make them work again.
|
If you are to install nro forwarders, remove `R_TRY(ValidateAcidSignature(std::addressof(g_original_meta_cache.meta)));` in `Atmosphere/stratosphere/loader/source/ldr_meta.cpp` to make them work again.
|
||||||
|
|
||||||
|
Uncompress the kip to make it work with config editor: `hactool -t kip1 Atmosphere/stratosphere/loader/loader.kip --uncompress=Atmosphere/stratosphere/loader/loader.kip`
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Why no CPU/GPU OC for Erista?
|
## Why no CPU/GPU OC for Erista?
|
||||||
@@ -125,6 +142,7 @@ If you are to install nro forwarders, remove `R_TRY(ValidateAcidSignature(std::a
|
|||||||
- You could spot battery draining at higher clocks under stress test, even with official 39W PD charger.
|
- You could spot battery draining at higher clocks under stress test, even with official 39W PD charger.
|
||||||
- CPU / GPU performance at max clocks will be worse if power supply is not enough.
|
- CPU / GPU performance at max clocks will be worse if power supply is not enough.
|
||||||
|
|
||||||
|
- CPU OC (up to ~ 2.1 GHz, depending on your CPU bin) is available mainly for emulation, but it does NOT work out of the box.
|
||||||
|
|
||||||
|
|
||||||
## Acknowledgement
|
## Acknowledgement
|
||||||
|
|||||||
@@ -15,47 +15,79 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
//#define EXPERIMENTAL
|
//#define EXPERIMENTAL
|
||||||
#pragma once
|
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
|
#include "ldr_oc_suite.hpp"
|
||||||
|
|
||||||
namespace ams::ldr {
|
namespace ams::ldr::oc {
|
||||||
#include "ldr_oc_type.hpp"
|
|
||||||
/* Allocate CustomizeTable in loader.kip (could be customized by user without recompiling) */
|
/* Allocate CustomizeTable in loader.kip (could be customized by user without recompiling) */
|
||||||
static volatile CustomizeTable Customized = {
|
static const volatile CustomizeTable C = {
|
||||||
/******************** C P U ********************/
|
/* DRAM Timing:
|
||||||
// Max Clock in kHz:
|
* AUTO_ADJ_MARIKO_SAFE: Auto adjust timings for LPDDR4 ≤3733 Mbps specs, 8Gb density (Default).
|
||||||
// >= 2193000 will enable overvolting (> 1120 mV)
|
* AUTO_ADJ_MARIKO_4266: Auto adjust timings for LPDDR4X 4266 Mbps specs, 8Gb density.
|
||||||
.cpuMaxClock = 2397000,
|
* ENTIRE_TABLE_ERISTA/ENTIRE_TABLE_MARIKO:
|
||||||
|
* Replace the entire max mtc table with customized one.
|
||||||
|
* CUSTOMIZED_MARIKO: Override timings (partially).
|
||||||
|
*/
|
||||||
|
.mtcConf = AUTO_ADJ_MARIKO_SAFE;
|
||||||
|
|
||||||
// Max Voltage in mV:
|
/* Mariko CPU:
|
||||||
// Default voltage: 1120
|
* - Max Clock in kHz:
|
||||||
// Haven't tested anything higher than 1220.
|
* Default: 1785000
|
||||||
.cpuMaxVolt = 1220,
|
* >= 2193000 will enable overvolting (> 1120 mV)
|
||||||
|
* - Max Voltage in mV:
|
||||||
|
* Default voltage: 1120
|
||||||
|
* Haven't tested anything higher than 1220.
|
||||||
|
*/
|
||||||
|
.marikoCpuMaxClock = 2397000,
|
||||||
|
.marikoCpuMaxVolt = 1220,
|
||||||
|
|
||||||
/******************** G P U ********************/
|
/* Mariko GPU:
|
||||||
// Max Clock in kHz:
|
* - Max Clock in kHz:
|
||||||
.gpuMaxClock = 1305600,
|
* Default: 921600
|
||||||
|
* NVIDIA Maximum: 1267200
|
||||||
|
*/
|
||||||
|
.marikoGpuMaxClock = 1305600,
|
||||||
|
|
||||||
/****************** RAM / EMC ******************/
|
/* Erista CPU:
|
||||||
// RAM(EMC) Clock in kHz:
|
* Untested and not enabled by default.
|
||||||
// 1862400, 1894400, 1932800, 1996800, 2064000, 2099200, 2131200
|
* - Enable Overclock
|
||||||
// (Other values might work as well)
|
* Require modificaitions towards NewCpuTables!
|
||||||
// [Warning] RAM overclock could be UNSTABLE and cause severe problems:
|
* - Max Voltage in mV
|
||||||
// - Graphical glitches
|
*/
|
||||||
// - System instabilities
|
.eristaCpuOCEnable = 0,
|
||||||
// - NAND corruption
|
.eristaCpuMaxVolt = 0,
|
||||||
// 1862400/1996800 has been tested stable for all DRAM chips
|
|
||||||
.emcMaxClock = 1996800,
|
/* Erista EMC:
|
||||||
|
* - RAM Voltage in mV
|
||||||
|
* Default(HOS): 1125
|
||||||
|
* Not enabled by default.
|
||||||
|
*/
|
||||||
|
.eristaEmcVolt = 0,
|
||||||
|
|
||||||
|
/* Common EMC:
|
||||||
|
* - RAM Clock in kHz:
|
||||||
|
* Values should be > 1600000, and divided evenly by 9600 or 12800.
|
||||||
|
* [WARNING]
|
||||||
|
* RAM overclock could be UNSTABLE if timing parameters are not suitable for your DRAM:
|
||||||
|
* - Graphical glitches
|
||||||
|
* - System instabilities
|
||||||
|
* - NAND corruption
|
||||||
|
* Timings from auto-adjustment have been tested safe for up to 1996.8 MHz for all DRAM chips.
|
||||||
|
*/
|
||||||
|
.commonEmcMaxClock = 1996800,
|
||||||
};
|
};
|
||||||
|
|
||||||
const u32 EmcClock = Customized.emcMaxClock;
|
namespace pcv::Mariko {
|
||||||
const u32 CpuMaxClock = Customized.cpuMaxClock;
|
constexpr u32 CpuClkOSLimit = 1785'000;
|
||||||
const u32 CpuMaxVolt = Customized.cpuMaxVolt;
|
constexpr u32 CpuClkOfficial = 1963'500;
|
||||||
const u32 GpuMaxClock = Customized.gpuMaxClock;
|
constexpr u32 CpuVoltOfficial = 1120;
|
||||||
MarikoMtcTable* const MtcCustomized = const_cast<MarikoMtcTable *>(std::addressof(Customized.mtcTable));
|
constexpr u32 GpuClkOfficial = 1267'200;
|
||||||
|
constexpr u32 MemClkOSLimit = 1600'000;
|
||||||
|
constexpr u32 MemClkOSAlt = 1331'200;
|
||||||
|
|
||||||
namespace pcv {
|
constexpr u32 CommonDvfsEntryCnt = 32;
|
||||||
/* CPU */
|
/* CPU */
|
||||||
|
constexpr u32 OldCpuDvfsEntryCnt = 18;
|
||||||
constexpr cpu_freq_cvb_table_t NewCpuTables[] = {
|
constexpr cpu_freq_cvb_table_t NewCpuTables[] = {
|
||||||
// OldCpuTables
|
// OldCpuTables
|
||||||
// { 204000, { 721589, -12695, 27 }, {} },
|
// { 204000, { 721589, -12695, 27 }, {} },
|
||||||
@@ -81,9 +113,10 @@ namespace ams::ldr {
|
|||||||
{ 2295000, { 1975655, -43531, 27 }, { 1120000 } },
|
{ 2295000, { 1975655, -43531, 27 }, { 1120000 } },
|
||||||
{ 2397000, { 2076220, -45036, 27 }, { 1120000 } },
|
{ 2397000, { 2076220, -45036, 27 }, { 1120000 } },
|
||||||
};
|
};
|
||||||
static_assert(sizeof(NewCpuTables) <= sizeof(cpu_freq_cvb_table_t)*14);
|
static_assert(sizeof(NewCpuTables) <= sizeof(cpu_freq_cvb_table_t) * (CommonDvfsEntryCnt - OldCpuDvfsEntryCnt));
|
||||||
|
|
||||||
/* GPU */
|
/* GPU */
|
||||||
|
constexpr u32 OldGpuDvfsEntryCnt = 17;
|
||||||
constexpr gpu_cvb_pll_table_t NewGpuTables[] = {
|
constexpr gpu_cvb_pll_table_t NewGpuTables[] = {
|
||||||
// OldGpuTables
|
// OldGpuTables
|
||||||
// { 76800, {}, { 610000, } },
|
// { 76800, {}, { 610000, } },
|
||||||
@@ -105,7 +138,7 @@ namespace ams::ldr {
|
|||||||
// { 1267200, {}, { 1335531, -12567, -867, 0, 3681, 559 } },
|
// { 1267200, {}, { 1335531, -12567, -867, 0, 3681, 559 } },
|
||||||
{ 1305600, {}, { 1374130, -13725, -859, 0, 4442, 576 } },
|
{ 1305600, {}, { 1374130, -13725, -859, 0, 4442, 576 } },
|
||||||
};
|
};
|
||||||
static_assert(sizeof(NewGpuTables) <= sizeof(gpu_cvb_pll_table_t)*15);
|
static_assert(sizeof(NewGpuTables) <= sizeof(gpu_cvb_pll_table_t) * (CommonDvfsEntryCnt - OldGpuDvfsEntryCnt));
|
||||||
|
|
||||||
/* GPU Max Clock asm Pattern:
|
/* GPU Max Clock asm Pattern:
|
||||||
*
|
*
|
||||||
@@ -123,9 +156,9 @@ namespace ams::ldr {
|
|||||||
0x52820000,
|
0x52820000,
|
||||||
0x72A001C0
|
0x72A001C0
|
||||||
};
|
};
|
||||||
volatile u32 gpuMaxClockMarikoPattern[2] = {
|
const u32 gpuMaxClockMarikoPattern[2] = {
|
||||||
0x52800000 | ((GpuMaxClock & 0xFFFF) << 5),
|
(gpuOfficialMarikoPattern[0] & 0xFFE00000) | ((C.marikoGpuMaxClock & 0xFFFF) << 5),
|
||||||
0x72A00000 | (((GpuMaxClock >> 16) & 0xFFFF) << 5)
|
(gpuOfficialMarikoPattern[1] & 0xFFE00000) | (((C.marikoGpuMaxClock >> 16) & 0xFFFF) << 5)
|
||||||
};
|
};
|
||||||
#define COMPARE_HIGH(val1, val2, bit_div) (((val1 ^ val2) >> bit_div) == 0)
|
#define COMPARE_HIGH(val1, val2, bit_div) (((val1 ^ val2) >> bit_div) == 0)
|
||||||
|
|
||||||
@@ -142,7 +175,36 @@ namespace ams::ldr {
|
|||||||
// { 1600000, { 675, 650, 637, } },
|
// { 1600000, { 675, 650, 637, } },
|
||||||
// };
|
// };
|
||||||
|
|
||||||
void AdjustMtcTable(MarikoMtcTable* table, MarikoMtcTable* ref)
|
static void MtcPllmbDivHandler(MarikoMtcTable* table) {
|
||||||
|
// Calculate DIVM and DIVN (clock divisors)
|
||||||
|
// Common PLL oscillator is 38.4 MHz
|
||||||
|
// PLLMB_OUT = 38.4 MHz / PLLLMB_DIVM * PLLMB_DIVN
|
||||||
|
typedef struct {
|
||||||
|
u8 numerator : 4;
|
||||||
|
u8 denominator : 4;
|
||||||
|
} pllmb_div;
|
||||||
|
|
||||||
|
constexpr pllmb_div div[] = {
|
||||||
|
{3, 4}, {2, 3}, {1, 2}, {1, 3}, {1, 4}, {0, 1}
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr u32 pll_osc_in = 38400;
|
||||||
|
|
||||||
|
u32 divm {}, divn {};
|
||||||
|
const u32 remainder = C.commonEmcMaxClock % pll_osc_in;
|
||||||
|
for (const auto &index : div) {
|
||||||
|
if (remainder >= pll_osc_in * index.numerator / index.denominator) {
|
||||||
|
divm = index.denominator;
|
||||||
|
divn = C.commonEmcMaxClock / pll_osc_in * divm + index.numerator;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
table->pllmb_divm = divm;
|
||||||
|
table->pllmb_divn = divn;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void MtcTableAutoAdjust(MarikoMtcTable* table, const MarikoMtcTable* ref)
|
||||||
{
|
{
|
||||||
/* Official Tegra X1 TRM, sign up for nvidia developer program (free) to download:
|
/* Official Tegra X1 TRM, sign up for nvidia developer program (free) to download:
|
||||||
* https://developer.nvidia.com/embedded/dlc/tegra-x1-technical-reference-manual
|
* https://developer.nvidia.com/embedded/dlc/tegra-x1-technical-reference-manual
|
||||||
@@ -161,8 +223,8 @@ namespace ams::ldr {
|
|||||||
* you'd better calculate timings yourself rather than relying on following algorithm.
|
* you'd better calculate timings yourself rather than relying on following algorithm.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define ADJUST_PROP(TARGET, REF) \
|
#define ADJUST_PROP(TARGET, REF) \
|
||||||
(u32)(std::ceil(REF + ((EmcClock-MemClkOSAlt)*(TARGET-REF))/(MemClkOSLimit-MemClkOSAlt)))
|
(u32)(std::ceil(REF + ((C.commonEmcMaxClock-MemClkOSAlt)*(TARGET-REF))/(MemClkOSLimit-MemClkOSAlt)))
|
||||||
|
|
||||||
#define ADJUST_PARAM(TARGET, REF) \
|
#define ADJUST_PARAM(TARGET, REF) \
|
||||||
TARGET = ADJUST_PROP(TARGET, REF);
|
TARGET = ADJUST_PROP(TARGET, REF);
|
||||||
@@ -202,43 +264,11 @@ namespace ams::ldr {
|
|||||||
// ADJUST_PARAM_TABLE(table, min_mrs_wait); // not used on LPDDR4X
|
// ADJUST_PARAM_TABLE(table, min_mrs_wait); // not used on LPDDR4X
|
||||||
// ADJUST_PARAM_TABLE(table, latency); // not used
|
// ADJUST_PARAM_TABLE(table, latency); // not used
|
||||||
|
|
||||||
/* Patch PLLMB divisors */
|
|
||||||
{
|
|
||||||
// Calculate DIVM and DIVN (clock divisors)
|
|
||||||
// Common PLL oscillator is 38.4 MHz
|
|
||||||
// PLLMB_OUT = 38.4 MHz / PLLLMB_DIVM * PLLMB_DIVN
|
|
||||||
u32 divm = 1;
|
|
||||||
u32 divn = EmcClock / 38400;
|
|
||||||
u32 remainder = EmcClock % 38400;
|
|
||||||
if (remainder >= 38400 * (3/4)) {
|
|
||||||
divm = 4;
|
|
||||||
divn = divn * divm + 3;
|
|
||||||
} else
|
|
||||||
if (remainder >= 38400 * (2/3)) {
|
|
||||||
divm = 3;
|
|
||||||
divn = divn * divm + 2;
|
|
||||||
} else
|
|
||||||
if (remainder >= 38400 * (1/2)) {
|
|
||||||
divm = 2;
|
|
||||||
divn = divn * divm + 1;
|
|
||||||
} else
|
|
||||||
if (remainder >= 38400 * (1/3)) {
|
|
||||||
divm = 3;
|
|
||||||
divn = divn * divm + 1;
|
|
||||||
} else
|
|
||||||
if (remainder >= 38400 * (1/4)) {
|
|
||||||
divm = 4;
|
|
||||||
divn = divn * divm + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
table->pllmb_divm = divm;
|
|
||||||
table->pllmb_divn = divn;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Timings that are available in or can be derived from LPDDR4X datasheet or TRM */
|
/* 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;
|
||||||
// tCK_avg (average clock period) in ns
|
// tCK_avg (average clock period) in ns
|
||||||
const double tCK_avg = (EmcClock == 2131200) ? 0.468 : 1000'000. / EmcClock;
|
const double tCK_avg = 1000'000. / C.commonEmcMaxClock;
|
||||||
// tRPpb (row precharge time per bank) in ns
|
// tRPpb (row precharge time per bank) in ns
|
||||||
const u32 tRPpb = 18;
|
const u32 tRPpb = 18;
|
||||||
// tRPab (row precharge time all banks) in ns
|
// tRPab (row precharge time all banks) in ns
|
||||||
@@ -254,7 +284,7 @@ namespace ams::ldr {
|
|||||||
// tRCD (RAS-CAS delay) in ns
|
// tRCD (RAS-CAS delay) in ns
|
||||||
const u32 tRCD = 18;
|
const u32 tRCD = 18;
|
||||||
// tRRD (Active bank-A to Active bank-B) in ns
|
// tRRD (Active bank-A to Active bank-B) in ns
|
||||||
const double tRRD = (EmcClock == 2131200) ? 7.5 : 10.;
|
const double tRRD = use_4266_spec ? 7.5 : 10.;
|
||||||
// tREFpb (average refresh interval per bank) in ns for 8Gb density
|
// tREFpb (average refresh interval per bank) in ns for 8Gb density
|
||||||
const u32 tREFpb = 488;
|
const u32 tREFpb = 488;
|
||||||
// tREFab (average refresh interval all 8 banks) in ns for 8Gb density
|
// tREFab (average refresh interval all 8 banks) in ns for 8Gb density
|
||||||
@@ -264,7 +294,7 @@ namespace ams::ldr {
|
|||||||
// {REFRESH, REFRESH_LO} = max[(tREF/#_of_rows) / (emc_clk_period) - 64, (tREF/#_of_rows) / (emc_clk_period) * 97%]
|
// {REFRESH, REFRESH_LO} = max[(tREF/#_of_rows) / (emc_clk_period) - 64, (tREF/#_of_rows) / (emc_clk_period) * 97%]
|
||||||
// emc_clk_period = dram_clk / 2;
|
// emc_clk_period = dram_clk / 2;
|
||||||
// 1600 MHz: 5894, but N' set to 6176 (~4.8% margin)
|
// 1600 MHz: 5894, but N' set to 6176 (~4.8% margin)
|
||||||
const u32 REFRESH = std::ceil((double(tREFpb) * EmcClock / numOfRows * (1.048) / 2 - 64)) / 4 * 4;
|
const u32 REFRESH = u32(std::ceil((double(tREFpb) * C.commonEmcMaxClock / numOfRows * 1.048 / 2 - 64))) / 4 * 4;
|
||||||
// tPDEX2WR, tPDEX2RD (timing delay from exiting powerdown mode to a write/read command) in ns
|
// tPDEX2WR, tPDEX2RD (timing delay from exiting powerdown mode to a write/read command) in ns
|
||||||
const u32 tPDEX2 = 10;
|
const u32 tPDEX2 = 10;
|
||||||
// [Guessed] tACT2PDEN (timing delay from an activate, MRS or EMRS command to power-down entry) in ns
|
// [Guessed] tACT2PDEN (timing delay from an activate, MRS or EMRS command to power-down entry) in ns
|
||||||
@@ -282,9 +312,9 @@ namespace ams::ldr {
|
|||||||
// [Guessed] tPD (minimum CKE low pulse width in power-down mode) in ns
|
// [Guessed] tPD (minimum CKE low pulse width in power-down mode) in ns
|
||||||
const double tPD = 7.5;
|
const double tPD = 7.5;
|
||||||
// tFAW (Four-bank Activate Window) in ns
|
// tFAW (Four-bank Activate Window) in ns
|
||||||
const u32 tFAW = (EmcClock == 2131200) ? 30 : 40;
|
const u32 tFAW = use_4266_spec ? 30 : 40;
|
||||||
|
|
||||||
#define GET_CYCLE_CEIL(PARAM) std::ceil(double(PARAM) / tCK_avg)
|
#define GET_CYCLE_CEIL(PARAM) u32(std::ceil(double(PARAM) / tCK_avg))
|
||||||
|
|
||||||
WRITE_PARAM_ALL_REG(table, emc_rc, GET_CYCLE_CEIL(tRC));
|
WRITE_PARAM_ALL_REG(table, emc_rc, GET_CYCLE_CEIL(tRC));
|
||||||
WRITE_PARAM_ALL_REG(table, emc_rfc, GET_CYCLE_CEIL(tRFCab));
|
WRITE_PARAM_ALL_REG(table, emc_rfc, GET_CYCLE_CEIL(tRFCab));
|
||||||
@@ -324,6 +354,8 @@ namespace ams::ldr {
|
|||||||
table->burst_mc_regs.mc_emem_arb_timing_rfcpb = std::ceil(GET_CYCLE_CEIL(tRFCpb) / MC_ARB_DIV + 1); // ?
|
table->burst_mc_regs.mc_emem_arb_timing_rfcpb = std::ceil(GET_CYCLE_CEIL(tRFCpb) / MC_ARB_DIV + 1); // ?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MtcPllmbDivHandler(table);
|
||||||
|
|
||||||
#ifdef EXPERIMENTAL
|
#ifdef EXPERIMENTAL
|
||||||
{
|
{
|
||||||
#define ADJUST_PARAM_ROUND2_ALL_REG(TARGET_TABLE, REF_TABLE, PARAM) \
|
#define ADJUST_PARAM_ROUND2_ALL_REG(TARGET_TABLE, REF_TABLE, PARAM) \
|
||||||
@@ -363,7 +395,7 @@ namespace ams::ldr {
|
|||||||
| ADJUST_BIT(TARGET_TABLE->shadow_regs_rdwr_train.PARAM, REF_TABLE->shadow_regs_rdwr_train.PARAM, HIGH2, LOW2) << LOW2;
|
| ADJUST_BIT(TARGET_TABLE->shadow_regs_rdwr_train.PARAM, REF_TABLE->shadow_regs_rdwr_train.PARAM, HIGH2, LOW2) << LOW2;
|
||||||
|
|
||||||
/* For latency allowance */
|
/* For latency allowance */
|
||||||
#define ADJUST_INVERSE(TARGET) (TARGET * (MemClkOSLimit / 1000) / (EmcClock / 1000))
|
#define ADJUST_INVERSE(TARGET) (TARGET * (MemClkOSLimit / 1000) / (C.commonEmcMaxClock / 1000))
|
||||||
|
|
||||||
/* emc_wdv, emc_wsv, emc_wev, emc_wdv_mask,
|
/* emc_wdv, emc_wsv, emc_wev, emc_wdv_mask,
|
||||||
emc_quse, emc_quse_width, emc_ibdly, emc_obdly,
|
emc_quse, emc_quse_width, emc_ibdly, emc_obdly,
|
||||||
@@ -661,19 +693,187 @@ namespace ams::ldr {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
Result PcvCpuClockVddHandler(u32* ptr) {
|
static void MtcTableCustomize(MarikoMtcTable* table) {
|
||||||
u32 value_next2 = *(ptr + 2);
|
#define HANDLER_COMMON(PARAM) \
|
||||||
constexpr u32 cpuClockVddCpuPatternNext = 0;
|
if (C.marikoTiming.common.PARAM != DO_NOT_OVERRIDE) {\
|
||||||
if (value_next2 != cpuClockVddCpuPatternNext)
|
u32 cache = C.marikoTiming.common.PARAM; \
|
||||||
{
|
if (cache == OVERRIDE_WITH_ZERO) \
|
||||||
return ResultFailure();
|
cache = 0; \
|
||||||
}
|
table->burst_regs.PARAM = cache; \
|
||||||
|
table->shadow_regs_ca_train.PARAM = cache; \
|
||||||
|
table->shadow_regs_rdwr_train.PARAM = cache; \
|
||||||
|
}
|
||||||
|
|
||||||
PatchOffset(ptr, CpuMaxClock);
|
#define HANDLER(PARAM) \
|
||||||
|
if (C.marikoTiming.PARAM) { \
|
||||||
|
u32 cache = C.marikoTiming.PARAM;\
|
||||||
|
if (cache == OVERRIDE_WITH_ZERO) \
|
||||||
|
cache = 0; \
|
||||||
|
table->PARAM = cache; \
|
||||||
|
}
|
||||||
|
|
||||||
|
HANDLER_COMMON(emc_rc);
|
||||||
|
HANDLER_COMMON(emc_rfc);
|
||||||
|
HANDLER_COMMON(emc_rfcpb);
|
||||||
|
HANDLER_COMMON(emc_ras);
|
||||||
|
HANDLER_COMMON(emc_rp);
|
||||||
|
HANDLER_COMMON(emc_r2w);
|
||||||
|
HANDLER_COMMON(emc_w2r);
|
||||||
|
HANDLER_COMMON(emc_r2p);
|
||||||
|
HANDLER_COMMON(emc_w2p);
|
||||||
|
HANDLER_COMMON(emc_trtm);
|
||||||
|
HANDLER_COMMON(emc_twtm);
|
||||||
|
HANDLER_COMMON(emc_tratm);
|
||||||
|
HANDLER_COMMON(emc_twatm);
|
||||||
|
HANDLER_COMMON(emc_rd_rcd);
|
||||||
|
HANDLER_COMMON(emc_wr_rcd);
|
||||||
|
HANDLER_COMMON(emc_rrd);
|
||||||
|
HANDLER_COMMON(emc_wdv);
|
||||||
|
HANDLER_COMMON(emc_wsv);
|
||||||
|
HANDLER_COMMON(emc_wev);
|
||||||
|
HANDLER_COMMON(emc_wdv_mask);
|
||||||
|
HANDLER_COMMON(emc_quse);
|
||||||
|
HANDLER_COMMON(emc_quse_width);
|
||||||
|
HANDLER_COMMON(emc_ibdly);
|
||||||
|
HANDLER_COMMON(emc_obdly);
|
||||||
|
HANDLER_COMMON(emc_einput);
|
||||||
|
HANDLER_COMMON(emc_einput_duration);
|
||||||
|
HANDLER_COMMON(emc_qrst);
|
||||||
|
HANDLER_COMMON(emc_qsafe);
|
||||||
|
HANDLER_COMMON(emc_rdv);
|
||||||
|
HANDLER_COMMON(emc_rdv_mask);
|
||||||
|
HANDLER_COMMON(emc_rdv_early);
|
||||||
|
HANDLER_COMMON(emc_rdv_early_mask);
|
||||||
|
HANDLER_COMMON(emc_refresh);
|
||||||
|
HANDLER_COMMON(emc_pre_refresh_req_cnt);
|
||||||
|
HANDLER_COMMON(emc_pdex2wr);
|
||||||
|
HANDLER_COMMON(emc_pdex2rd);
|
||||||
|
HANDLER_COMMON(emc_act2pden);
|
||||||
|
HANDLER_COMMON(emc_rw2pden);
|
||||||
|
HANDLER_COMMON(emc_cke2pden);
|
||||||
|
HANDLER_COMMON(emc_pdex2mrr);
|
||||||
|
HANDLER_COMMON(emc_txsr);
|
||||||
|
HANDLER_COMMON(emc_txsrdll);
|
||||||
|
HANDLER_COMMON(emc_tcke);
|
||||||
|
HANDLER_COMMON(emc_tckesr);
|
||||||
|
HANDLER_COMMON(emc_tpd);
|
||||||
|
HANDLER_COMMON(emc_tfaw);
|
||||||
|
HANDLER_COMMON(emc_trpab);
|
||||||
|
HANDLER_COMMON(emc_tclkstop);
|
||||||
|
HANDLER_COMMON(emc_trefbw);
|
||||||
|
HANDLER_COMMON(emc_pmacro_ob_ddll_long_dq_rank1_4);
|
||||||
|
HANDLER_COMMON(emc_pmacro_ob_ddll_long_dq_rank1_5);
|
||||||
|
HANDLER_COMMON(emc_pmacro_ob_ddll_long_dqs_rank0_0);
|
||||||
|
HANDLER_COMMON(emc_pmacro_ob_ddll_long_dqs_rank0_1);
|
||||||
|
HANDLER_COMMON(emc_pmacro_ob_ddll_long_dqs_rank0_3);
|
||||||
|
HANDLER_COMMON(emc_pmacro_ob_ddll_long_dqs_rank0_4);
|
||||||
|
HANDLER_COMMON(emc_pmacro_ob_ddll_long_dqs_rank0_5);
|
||||||
|
HANDLER_COMMON(emc_pmacro_ob_ddll_long_dqs_rank1_0);
|
||||||
|
HANDLER_COMMON(emc_pmacro_ob_ddll_long_dqs_rank1_1);
|
||||||
|
HANDLER_COMMON(emc_pmacro_ob_ddll_long_dqs_rank1_3);
|
||||||
|
HANDLER_COMMON(emc_pmacro_ob_ddll_long_dqs_rank1_4);
|
||||||
|
HANDLER_COMMON(emc_pmacro_ob_ddll_long_dqs_rank1_5);
|
||||||
|
HANDLER_COMMON(emc_pmacro_ddll_long_cmd_0);
|
||||||
|
HANDLER_COMMON(emc_pmacro_ddll_long_cmd_1);
|
||||||
|
HANDLER_COMMON(emc_pmacro_ddll_long_cmd_2);
|
||||||
|
HANDLER_COMMON(emc_pmacro_ddll_long_cmd_3);
|
||||||
|
HANDLER_COMMON(emc_pmacro_ddll_long_cmd_4);
|
||||||
|
HANDLER_COMMON(emc_zcal_wait_cnt);
|
||||||
|
HANDLER_COMMON(emc_mrs_wait_cnt);
|
||||||
|
HANDLER_COMMON(emc_mrs_wait_cnt2);
|
||||||
|
HANDLER_COMMON(emc_auto_cal_channel);
|
||||||
|
HANDLER_COMMON(emc_pmacro_dll_cfg_2);
|
||||||
|
HANDLER_COMMON(emc_pmacro_autocal_cfg_common);
|
||||||
|
HANDLER_COMMON(emc_dyn_self_ref_control);
|
||||||
|
HANDLER_COMMON(emc_qpop);
|
||||||
|
HANDLER_COMMON(emc_pmacro_cmd_pad_tx_ctrl);
|
||||||
|
HANDLER_COMMON(emc_tr_timing_0);
|
||||||
|
HANDLER_COMMON(emc_tr_rdv);
|
||||||
|
HANDLER_COMMON(emc_tr_qpop);
|
||||||
|
HANDLER_COMMON(emc_tr_rdv_mask);
|
||||||
|
HANDLER_COMMON(emc_tr_qsafe);
|
||||||
|
HANDLER_COMMON(emc_tr_qrst);
|
||||||
|
HANDLER_COMMON(emc_training_vref_settle);
|
||||||
|
|
||||||
|
HANDLER(trim_regs.emc_pmacro_ob_ddll_long_dq_rank0_0);
|
||||||
|
HANDLER(trim_regs.emc_pmacro_ob_ddll_long_dq_rank0_1);
|
||||||
|
HANDLER(trim_regs.emc_pmacro_ob_ddll_long_dq_rank0_2);
|
||||||
|
HANDLER(trim_regs.emc_pmacro_ob_ddll_long_dq_rank0_3);
|
||||||
|
HANDLER(trim_regs.emc_pmacro_ob_ddll_long_dq_rank0_4);
|
||||||
|
HANDLER(trim_regs.emc_pmacro_ob_ddll_long_dq_rank0_5);
|
||||||
|
HANDLER(trim_regs.emc_pmacro_ob_ddll_long_dq_rank1_0);
|
||||||
|
HANDLER(trim_regs.emc_pmacro_ob_ddll_long_dq_rank1_1);
|
||||||
|
HANDLER(trim_regs.emc_pmacro_ob_ddll_long_dq_rank1_2);
|
||||||
|
HANDLER(trim_regs.emc_pmacro_ob_ddll_long_dq_rank1_3);
|
||||||
|
|
||||||
|
HANDLER(dram_timings.rl);
|
||||||
|
|
||||||
|
HANDLER(burst_mc_regs.mc_emem_arb_cfg);
|
||||||
|
HANDLER(burst_mc_regs.mc_emem_arb_timing_rcd);
|
||||||
|
HANDLER(burst_mc_regs.mc_emem_arb_timing_rp);
|
||||||
|
HANDLER(burst_mc_regs.mc_emem_arb_timing_rc);
|
||||||
|
HANDLER(burst_mc_regs.mc_emem_arb_timing_ras);
|
||||||
|
HANDLER(burst_mc_regs.mc_emem_arb_timing_faw);
|
||||||
|
HANDLER(burst_mc_regs.mc_emem_arb_timing_wap2pre);
|
||||||
|
HANDLER(burst_mc_regs.mc_emem_arb_timing_r2w);
|
||||||
|
HANDLER(burst_mc_regs.mc_emem_arb_timing_w2r);
|
||||||
|
HANDLER(burst_mc_regs.mc_emem_arb_timing_rfcpb);
|
||||||
|
HANDLER(burst_mc_regs.mc_emem_arb_da_turns);
|
||||||
|
HANDLER(burst_mc_regs.mc_emem_arb_da_covers);
|
||||||
|
HANDLER(burst_mc_regs.mc_emem_arb_misc0);
|
||||||
|
|
||||||
|
HANDLER(la_scale_regs.mc_mll_mpcorer_ptsa_rate);
|
||||||
|
HANDLER(la_scale_regs.mc_ptsa_grant_decrement);
|
||||||
|
HANDLER(la_scale_regs.mc_latency_allowance_xusb_0);
|
||||||
|
HANDLER(la_scale_regs.mc_latency_allowance_xusb_1);
|
||||||
|
HANDLER(la_scale_regs.mc_latency_allowance_tsec_0);
|
||||||
|
HANDLER(la_scale_regs.mc_latency_allowance_sdmmca_0);
|
||||||
|
HANDLER(la_scale_regs.mc_latency_allowance_sdmmcaa_0);
|
||||||
|
HANDLER(la_scale_regs.mc_latency_allowance_sdmmc_0);
|
||||||
|
HANDLER(la_scale_regs.mc_latency_allowance_sdmmcab_0);
|
||||||
|
HANDLER(la_scale_regs.mc_latency_allowance_ppcs_1);
|
||||||
|
HANDLER(la_scale_regs.mc_latency_allowance_mpcore_0);
|
||||||
|
HANDLER(la_scale_regs.mc_latency_allowance_hc_0);
|
||||||
|
HANDLER(la_scale_regs.mc_latency_allowance_hc_1);
|
||||||
|
HANDLER(la_scale_regs.mc_latency_allowance_avpc_0);
|
||||||
|
HANDLER(la_scale_regs.mc_latency_allowance_gpu_0);
|
||||||
|
HANDLER(la_scale_regs.mc_latency_allowance_gpu2_0);
|
||||||
|
HANDLER(la_scale_regs.mc_latency_allowance_nvenc_0);
|
||||||
|
HANDLER(la_scale_regs.mc_latency_allowance_nvdec_0);
|
||||||
|
HANDLER(la_scale_regs.mc_latency_allowance_vic_0);
|
||||||
|
HANDLER(la_scale_regs.mc_latency_allowance_vi2_0);
|
||||||
|
HANDLER(la_scale_regs.mc_latency_allowance_isp2_1);
|
||||||
|
|
||||||
|
HANDLER(pllm_ss_ctrl1);
|
||||||
|
HANDLER(pllm_ss_ctrl2);
|
||||||
|
HANDLER(pllmb_ss_ctrl1);
|
||||||
|
HANDLER(pllmb_ss_ctrl2);
|
||||||
|
HANDLER(pllmb_divm);
|
||||||
|
HANDLER(pllmb_divn);
|
||||||
|
HANDLER(min_mrs_wait);
|
||||||
|
HANDLER(emc_mrw);
|
||||||
|
HANDLER(emc_mrw2);
|
||||||
|
HANDLER(emc_cfg_2);
|
||||||
|
HANDLER(latency);
|
||||||
|
|
||||||
|
if (C.marikoTiming.pllmb_divm == DO_NOT_OVERRIDE || C.marikoTiming.pllmb_divn == DO_NOT_OVERRIDE)
|
||||||
|
MtcPllmbDivHandler(table);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result CpuClockVddHandler(u32* ptr) {
|
||||||
|
if (C.marikoCpuMaxClock) {
|
||||||
|
u32 value_next2 = *(ptr + 2);
|
||||||
|
constexpr u32 cpuClockVddCpuPatternNext = 0;
|
||||||
|
if (value_next2 != cpuClockVddCpuPatternNext)
|
||||||
|
return ResultFailure();
|
||||||
|
|
||||||
|
PatchOffset(ptr, C.marikoCpuMaxClock);
|
||||||
|
}
|
||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result PcvCpuDvfsHandler(cpu_freq_cvb_table_t* entry_1963, uintptr_t nso_end_offset) {
|
static Result CpuDvfsHandler(u32* ptr, uintptr_t nso_end_offset) {
|
||||||
|
cpu_freq_cvb_table_t* entry_1963 = reinterpret_cast<cpu_freq_cvb_table_t *>(ptr);
|
||||||
cpu_freq_cvb_table_t* entry_free = entry_1963 + 1;
|
cpu_freq_cvb_table_t* entry_free = entry_1963 + 1;
|
||||||
cpu_freq_cvb_table_t* entry_204 = entry_free - 18;
|
cpu_freq_cvb_table_t* entry_204 = entry_free - 18;
|
||||||
uintptr_t entry_end_offset = reinterpret_cast<uintptr_t>(entry_free) + sizeof(NewCpuTables) - sizeof(u32);
|
uintptr_t entry_end_offset = reinterpret_cast<uintptr_t>(entry_free) + sizeof(NewCpuTables) - sizeof(u32);
|
||||||
@@ -693,16 +893,18 @@ namespace ams::ldr {
|
|||||||
if (entry_current->cvb_pll_param.c0 != CpuVoltOfficial * 1000)
|
if (entry_current->cvb_pll_param.c0 != CpuVoltOfficial * 1000)
|
||||||
return ResultFailure();
|
return ResultFailure();
|
||||||
|
|
||||||
while (entry_current->cvb_pll_param.c0 == CpuVoltOfficial * 1000)
|
if (C.marikoCpuMaxVolt) {
|
||||||
{
|
while (entry_current->cvb_pll_param.c0 == CpuVoltOfficial * 1000) {
|
||||||
PatchOffset(reinterpret_cast<u32 *>(std::addressof(entry_current->cvb_pll_param)), CpuMaxVolt * 1000);
|
PatchOffset(reinterpret_cast<u32 *>(std::addressof(entry_current->cvb_pll_param)), C.marikoCpuMaxVolt * 1000);
|
||||||
entry_current--;
|
entry_current--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result PcvGpuDvfsHandler(gpu_cvb_pll_table_t* entry_1267, uintptr_t nso_end_offset) {
|
static Result GpuDvfsHandler(u32* ptr, uintptr_t nso_end_offset) {
|
||||||
|
gpu_cvb_pll_table_t* entry_1267 = reinterpret_cast<gpu_cvb_pll_table_t *>(ptr);
|
||||||
gpu_cvb_pll_table_t* entry_free = entry_1267 + 1;
|
gpu_cvb_pll_table_t* entry_free = entry_1267 + 1;
|
||||||
gpu_cvb_pll_table_t* entry_76_8 = entry_free - 17;
|
gpu_cvb_pll_table_t* entry_76_8 = entry_free - 17;
|
||||||
uintptr_t entry_end_offset = reinterpret_cast<uintptr_t>(entry_free) + sizeof(NewGpuTables) - sizeof(u32);
|
uintptr_t entry_end_offset = reinterpret_cast<uintptr_t>(entry_free) + sizeof(NewGpuTables) - sizeof(u32);
|
||||||
@@ -719,23 +921,24 @@ namespace ams::ldr {
|
|||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result PcvCpuVoltRangeHandler(u32* ptr) {
|
static Result CpuVoltRangeHandler(u32* ptr) {
|
||||||
const std::vector<u32> acceptableCpuMinVolt = { 800, 637, 620, 610 };
|
if (!C.marikoCpuMaxVolt)
|
||||||
|
return ResultSuccess();
|
||||||
|
|
||||||
u32 value_cpu_min_volt = *(ptr - 1);
|
u32 value_cpu_min_volt = *(ptr - 1);
|
||||||
|
switch (value_cpu_min_volt) {
|
||||||
for (const auto &min_volt : acceptableCpuMinVolt)
|
case 800:
|
||||||
{
|
case 637:
|
||||||
if (min_volt == value_cpu_min_volt)
|
case 620:
|
||||||
{
|
case 610:
|
||||||
PatchOffset(ptr, CpuMaxVolt);
|
PatchOffset(ptr, C.marikoCpuMaxVolt);
|
||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
default:
|
||||||
|
return ResultFailure();
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResultFailure();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result PcvGpuMaxClockMarikoAsmHandler(u32* ptr) {
|
static Result GpuMaxClockHandler(u32* ptr) {
|
||||||
u32 value = *(ptr);
|
u32 value = *(ptr);
|
||||||
u32* ptr_next = ptr + 1;
|
u32* ptr_next = ptr + 1;
|
||||||
u32 value_next = *(ptr_next);
|
u32 value_next = *(ptr_next);
|
||||||
@@ -754,149 +957,314 @@ namespace ams::ldr {
|
|||||||
return ResultFailure();
|
return ResultFailure();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result PcvMemMaxClockHandler(uintptr_t ptr, bool isMariko) {
|
static Result MtcTableHandler(u32* ptr) {
|
||||||
if (isMariko)
|
MarikoMtcTable* const mtc_table_max = reinterpret_cast<MarikoMtcTable *>(ptr - offsetof(MarikoMtcTable, rate_khz) / sizeof(u32));
|
||||||
{
|
MarikoMtcTable* const mtc_table_alt = mtc_table_max - 1;
|
||||||
// Mariko have 3 mtc tables (204/1331/1600 MHz), only these 3 frequencies could be set.
|
constexpr u32 mtc_mariko_rev = 3;
|
||||||
// Replace 1331 MHz with 1600 MHz as perf @ 1331 MHz is crap.
|
if ( mtc_table_max->rev != mtc_mariko_rev
|
||||||
u32 value_next = *(reinterpret_cast<u32 *>(ptr) + 1);
|
|| mtc_table_alt->rev != mtc_mariko_rev
|
||||||
u32 value_next2 = *(reinterpret_cast<u32 *>(ptr) + 2);
|
|| mtc_table_alt->rate_khz != MemClkOSAlt )
|
||||||
|
return ResultFailure();
|
||||||
|
|
||||||
constexpr u32 mtc_mariko_min_volt = 1100;
|
MarikoMtcTable* const table = const_cast<MarikoMtcTable *>(std::addressof(C.marikoMtc));
|
||||||
// constexpr u32 mtc_erista_min_volt = 887;
|
bool replace_entire_table = (C.mtcConf == ENTIRE_TABLE_MARIKO);
|
||||||
constexpr u32 dvb_entry_volt = 675;
|
if (replace_entire_table) {
|
||||||
constexpr u32 mtc_mariko_rev = 3;
|
std::memcpy(reinterpret_cast<void *>(mtc_table_alt), reinterpret_cast<void *>(mtc_table_max), sizeof(MarikoMtcTable));
|
||||||
|
std::memcpy(reinterpret_cast<void *>(mtc_table_max), reinterpret_cast<void *>(table), sizeof(MarikoMtcTable));
|
||||||
if (value_next == mtc_mariko_min_volt)
|
return ResultSuccess();
|
||||||
{
|
|
||||||
MarikoMtcTable* const mtc_table_max = reinterpret_cast<MarikoMtcTable *>(ptr - offsetof(MarikoMtcTable, rate_khz));
|
|
||||||
MarikoMtcTable* const mtc_table_alt = mtc_table_max - 1;
|
|
||||||
if ( mtc_table_max->rev != mtc_mariko_rev
|
|
||||||
|| mtc_table_alt->rev != mtc_mariko_rev
|
|
||||||
|| mtc_table_alt->rate_khz != MemClkOSAlt )
|
|
||||||
return ResultFailure();
|
|
||||||
|
|
||||||
bool useCustomizedTable = MtcCustomized->rev != INVALID_MTC_TABLE;
|
|
||||||
if (useCustomizedTable)
|
|
||||||
{
|
|
||||||
std::memcpy(reinterpret_cast<void *>(mtc_table_alt), reinterpret_cast<void *>(mtc_table_max), sizeof(MarikoMtcTable));
|
|
||||||
std::memcpy(reinterpret_cast<void *>(mtc_table_max), reinterpret_cast<void *>(MtcCustomized), sizeof(MarikoMtcTable));
|
|
||||||
return ResultSuccess();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::memcpy(reinterpret_cast<void *>(MtcCustomized), reinterpret_cast<void *>(mtc_table_max), sizeof(MarikoMtcTable));
|
|
||||||
AdjustMtcTable(mtc_table_max, mtc_table_alt);
|
|
||||||
std::memcpy(reinterpret_cast<void *>(mtc_table_alt), reinterpret_cast<void *>(MtcCustomized), sizeof(MarikoMtcTable));
|
|
||||||
MtcCustomized->rev = INVALID_MTC_TABLE;
|
|
||||||
}
|
|
||||||
else if (value_next2 == dvb_entry_volt)
|
|
||||||
{
|
|
||||||
emc_dvb_dvfs_table_t* dvb_max_entry = reinterpret_cast<emc_dvb_dvfs_table_t *>(ptr);
|
|
||||||
emc_dvb_dvfs_table_t* dvb_1331_entry = dvb_max_entry - 1;
|
|
||||||
|
|
||||||
u32* dvb_1331_offset = reinterpret_cast<u32 *>(dvb_1331_entry);
|
|
||||||
if (*(dvb_1331_offset) != MemClkOSAlt)
|
|
||||||
return ResultFailure();
|
|
||||||
|
|
||||||
PatchOffset(dvb_1331_offset, MemClkOSLimit);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PatchOffset(ptr, EmcClock);
|
bool customized_timing = (C.mtcConf == CUSTOMIZED_MARIKO);
|
||||||
|
if (customized_timing) {
|
||||||
|
std::memcpy(reinterpret_cast<void *>(mtc_table_alt), reinterpret_cast<void *>(mtc_table_max), sizeof(MarikoMtcTable));
|
||||||
|
MtcTableCustomize(mtc_table_max);
|
||||||
|
} else {
|
||||||
|
std::memcpy(reinterpret_cast<void *>(table), reinterpret_cast<void *>(mtc_table_max), sizeof(MarikoMtcTable));
|
||||||
|
MtcTableAutoAdjust(mtc_table_max, mtc_table_alt);
|
||||||
|
std::memcpy(reinterpret_cast<void *>(mtc_table_alt), reinterpret_cast<void *>(table), sizeof(MarikoMtcTable));
|
||||||
|
}
|
||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApplyAutoPcvPatch(uintptr_t mapped_nso, size_t nso_size) {
|
static Result DvbTableHandler(u32* ptr) {
|
||||||
/* Abort immediately once something goes wrong */
|
emc_dvb_dvfs_table_t* dvb_max_entry = reinterpret_cast<emc_dvb_dvfs_table_t *>(ptr);
|
||||||
bool isMariko = (spl::GetSocType() == spl::SocType_Mariko);
|
emc_dvb_dvfs_table_t* dvb_1331_entry = dvb_max_entry - 1;
|
||||||
|
|
||||||
u8 cpuClockVddMariko {};
|
u32* dvb_1331_offset = reinterpret_cast<u32 *>(dvb_1331_entry);
|
||||||
u8 cpuTableMariko {};
|
if (*(dvb_1331_offset) != MemClkOSAlt)
|
||||||
u8 gpuTableMariko {};
|
return ResultFailure();
|
||||||
u8 cpuMaxVoltMariko {};
|
|
||||||
u8 gpuMaxClockMariko {};
|
|
||||||
|
|
||||||
uintptr_t ptr = mapped_nso;
|
PatchOffset(dvb_1331_offset, MemClkOSLimit);
|
||||||
while (ptr <= mapped_nso + nso_size - std::max(sizeof(MarikoMtcTable), sizeof(EristaMtcTable)))
|
return ResultSuccess();
|
||||||
{
|
}
|
||||||
u32 value = *(reinterpret_cast<u32 *>(ptr));
|
|
||||||
|
|
||||||
if (isMariko)
|
static Result MemMaxClockHandler(u32* ptr) {
|
||||||
{
|
u32 value_next = *(ptr + 1);
|
||||||
if (value == CpuClkOSLimit)
|
u32 value_next2 = *(ptr + 2);
|
||||||
{
|
|
||||||
if (R_SUCCEEDED(PcvCpuClockVddHandler(reinterpret_cast<u32 *>(ptr))))
|
|
||||||
cpuClockVddMariko++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value == CpuClkOfficial)
|
// Mariko have 3 mtc tables (204/1331/1600 MHz), only these 3 frequencies could be set.
|
||||||
{
|
// Replace 1331 MHz with 1600 MHz as perf @ 1331 MHz is crap.
|
||||||
if (R_SUCCEEDED(PcvCpuDvfsHandler(reinterpret_cast<cpu_freq_cvb_table_t *>(ptr), mapped_nso + nso_size)))
|
constexpr u32 mtc_min_volt = 1100;
|
||||||
cpuTableMariko++;
|
constexpr u32 dvb_entry_volt = 675;
|
||||||
}
|
|
||||||
|
|
||||||
if (value == GpuClkOfficial)
|
Result rc = ResultSuccess();
|
||||||
{
|
|
||||||
if (R_SUCCEEDED(PcvGpuDvfsHandler(reinterpret_cast<gpu_cvb_pll_table_t *>(ptr), mapped_nso + nso_size)))
|
|
||||||
gpuTableMariko++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value == CpuVoltOfficial)
|
if (value_next == mtc_min_volt) {
|
||||||
{
|
rc = MtcTableHandler(ptr);
|
||||||
if (R_SUCCEEDED(PcvCpuVoltRangeHandler(reinterpret_cast<u32 *>(ptr))))
|
} else if (value_next2 == dvb_entry_volt) {
|
||||||
cpuMaxVoltMariko++;
|
rc = DvbTableHandler(ptr);
|
||||||
}
|
|
||||||
|
|
||||||
if (COMPARE_HIGH(value, gpuOfficialMarikoPattern[0], 5))
|
|
||||||
{
|
|
||||||
if (R_SUCCEEDED(PcvGpuMaxClockMarikoAsmHandler(reinterpret_cast<u32 *>(ptr))))
|
|
||||||
gpuMaxClockMariko++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value == MemClkOSLimit)
|
|
||||||
{
|
|
||||||
if (R_FAILED(PcvMemMaxClockHandler(ptr, isMariko)))
|
|
||||||
AMS_ABORT();
|
|
||||||
}
|
|
||||||
|
|
||||||
ptr += sizeof(u32);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isMariko)
|
PatchOffset(ptr, C.commonEmcMaxClock);
|
||||||
{
|
return rc;
|
||||||
constexpr u8 cpuMaxVoltMarikoMaxCnt = 13;
|
}
|
||||||
constexpr u8 gpuMaxClockMarikoReqCnt = 2;
|
|
||||||
|
|
||||||
if (cpuClockVddMariko != 1)
|
static void Patch(uintptr_t mapped_nso, size_t nso_size) {
|
||||||
AMS_ABORT();
|
if (C.custRev != CUST_REV) {
|
||||||
if (cpuTableMariko != 1)
|
AMS_ABORT();
|
||||||
AMS_ABORT();
|
__builtin_unreachable();
|
||||||
if (gpuTableMariko != 1)
|
}
|
||||||
AMS_ABORT();
|
|
||||||
if (cpuMaxVoltMariko > cpuMaxVoltMarikoMaxCnt || !cpuMaxVoltMariko)
|
enum PatchSuccessCnt {
|
||||||
AMS_ABORT();
|
MEM_CLOCK,
|
||||||
if (gpuMaxClockMariko != gpuMaxClockMarikoReqCnt)
|
CPU_CLOCK_VDD,
|
||||||
AMS_ABORT();
|
CPU_TABLE,
|
||||||
|
GPU_TABLE,
|
||||||
|
CPU_MAX_VOLT,
|
||||||
|
GPU_MAX_CLOCK,
|
||||||
|
CNT_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
|
u8 cnt[CNT_MAX] = {};
|
||||||
|
|
||||||
|
for (uintptr_t ptr = mapped_nso;
|
||||||
|
ptr <= mapped_nso + nso_size - sizeof(MarikoMtcTable);
|
||||||
|
ptr += sizeof(u32))
|
||||||
|
{
|
||||||
|
u32* ptr32 = reinterpret_cast<u32 *>(ptr);
|
||||||
|
u32 value = *(ptr32);
|
||||||
|
|
||||||
|
switch (value) {
|
||||||
|
case CpuClkOSLimit: [[unlikely]]
|
||||||
|
if (R_SUCCEEDED(CpuClockVddHandler(ptr32)))
|
||||||
|
cnt[CPU_CLOCK_VDD]++;
|
||||||
|
continue;
|
||||||
|
case CpuClkOfficial: [[unlikely]]
|
||||||
|
if (R_SUCCEEDED(CpuDvfsHandler(ptr32, mapped_nso + nso_size)))
|
||||||
|
cnt[CPU_TABLE]++;
|
||||||
|
continue;
|
||||||
|
case GpuClkOfficial: [[unlikely]]
|
||||||
|
if (R_SUCCEEDED(GpuDvfsHandler(ptr32, mapped_nso + nso_size)))
|
||||||
|
cnt[GPU_TABLE]++;
|
||||||
|
continue;
|
||||||
|
case CpuVoltOfficial:[[unlikely]]
|
||||||
|
if (R_SUCCEEDED(CpuVoltRangeHandler(ptr32)))
|
||||||
|
cnt[CPU_MAX_VOLT]++;
|
||||||
|
continue;
|
||||||
|
case MemClkOSLimit: [[unlikely]]
|
||||||
|
if (R_SUCCEEDED(MemMaxClockHandler(ptr32)))
|
||||||
|
cnt[MEM_CLOCK]++;
|
||||||
|
continue;
|
||||||
|
default: [[likely]]
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (COMPARE_HIGH(value, gpuOfficialMarikoPattern[0], 5)) {
|
||||||
|
if (R_SUCCEEDED(GpuMaxClockHandler(ptr32)))
|
||||||
|
cnt[GPU_MAX_CLOCK]++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !cnt[MEM_CLOCK]
|
||||||
|
|| cnt[CPU_CLOCK_VDD] != 1
|
||||||
|
|| cnt[CPU_TABLE] != 1
|
||||||
|
|| cnt[GPU_TABLE] != 1
|
||||||
|
|| cnt[CPU_MAX_VOLT] > 13 || !cnt[CPU_MAX_VOLT]
|
||||||
|
|| cnt[GPU_MAX_CLOCK] != 2)
|
||||||
|
{
|
||||||
|
AMS_ABORT();
|
||||||
|
__builtin_unreachable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace pcv::Erista {
|
||||||
|
constexpr u32 CpuClkOSLimit = 1785'000;
|
||||||
|
constexpr u32 CpuVoltLimit1 = 1132;
|
||||||
|
constexpr u32 CpuVoltLimit2 = 1170;
|
||||||
|
constexpr u32 CpuVoltLimit3 = 1227;
|
||||||
|
constexpr u32 MemVoltHOS = 1125'000;
|
||||||
|
constexpr u32 MemClkOSLimit = 1600'000;
|
||||||
|
|
||||||
|
constexpr cpu_freq_cvb_table_t NewCpuTables[] = {
|
||||||
|
// OldCpuTables
|
||||||
|
// { 204000, { 721094 }, {} },
|
||||||
|
// { 306000, { 754040 }, {} },
|
||||||
|
// { 408000, { 786986 }, {} },
|
||||||
|
// { 510000, { 819932 }, {} },
|
||||||
|
// { 612000, { 852878 }, {} },
|
||||||
|
// { 714000, { 885824 }, {} },
|
||||||
|
// { 816000, { 918770 }, {} },
|
||||||
|
// { 918000, { 951716 }, {} },
|
||||||
|
// { 1020000, { 984662 }, { -2875621, 358099, -8585 } },
|
||||||
|
// { 1122000, { 1017608 }, { -52225, 104159, -2816 } },
|
||||||
|
// { 1224000, { 1050554 }, { 1076868, 8356, -727 } },
|
||||||
|
// { 1326000, { 1083500 }, { 2208191, -84659, 1240 } },
|
||||||
|
// { 1428000, { 1116446 }, { 2519460, -105063, 1611 } },
|
||||||
|
// { 1581000, { 1130000 }, { 2889664, -122173, 1834 } },
|
||||||
|
// { 1683000, { 1168000 }, { 5100873, -279186, 4747 } },
|
||||||
|
// { 1785000, { 1227500 }, { 5100873, -279186, 4747 } },
|
||||||
|
{ 1887000, {}, {} },
|
||||||
|
{ 1989000, {}, {} },
|
||||||
|
{ 2091000, {}, {} },
|
||||||
|
};
|
||||||
|
|
||||||
|
static Result CpuDvfsHandler(u32* ptr, uintptr_t nso_end_offset) {
|
||||||
|
if (!C.eristaCpuOCEnable)
|
||||||
|
return ResultSuccess();
|
||||||
|
|
||||||
|
cpu_freq_cvb_table_t* entry_1785 = reinterpret_cast<cpu_freq_cvb_table_t *>(ptr);
|
||||||
|
cpu_freq_cvb_table_t* entry_free = entry_1785 + 1;
|
||||||
|
cpu_freq_cvb_table_t* entry_204 = entry_free - 16;
|
||||||
|
uintptr_t entry_end_offset = reinterpret_cast<uintptr_t>(entry_free) + sizeof(NewCpuTables) - sizeof(u32);
|
||||||
|
|
||||||
|
if ( entry_end_offset >= nso_end_offset
|
||||||
|
|| *(reinterpret_cast<u32 *>(entry_free)) != 0
|
||||||
|
|| *(reinterpret_cast<u32 *>(entry_204)) != 204'000
|
||||||
|
|| *(reinterpret_cast<u32 *>(entry_end_offset)) != 0 )
|
||||||
|
{
|
||||||
|
return ResultFailure();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::memcpy(reinterpret_cast<void *>(entry_free), NewCpuTables, sizeof(NewCpuTables));
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result CpuVoltRangeHandler(u32* ptr) {
|
||||||
|
if (!C.eristaCpuMaxVolt)
|
||||||
|
return ResultSuccess();
|
||||||
|
|
||||||
|
u32 value_cpu_min_volt = *(ptr - 1);
|
||||||
|
switch (value_cpu_min_volt) {
|
||||||
|
case 950:
|
||||||
|
case 850:
|
||||||
|
case 825:
|
||||||
|
case 810:
|
||||||
|
PatchOffset(ptr, C.eristaCpuMaxVolt);
|
||||||
|
return ResultSuccess();
|
||||||
|
default:
|
||||||
|
return ResultFailure();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result MtcTableHandler(u32* ptr) {
|
||||||
|
bool replace_entire_table = (C.mtcConf == ENTIRE_TABLE_ERISTA);
|
||||||
|
if (replace_entire_table) {
|
||||||
|
EristaMtcTable* const mtc_table_max = reinterpret_cast<EristaMtcTable *>(ptr - offsetof(EristaMtcTable, rate_khz) / sizeof(u32));
|
||||||
|
EristaMtcTable* const table = const_cast<EristaMtcTable *>(std::addressof(C.eristaMtc));
|
||||||
|
std::memcpy(reinterpret_cast<void *>(mtc_table_max), reinterpret_cast<void *>(table), sizeof(EristaMtcTable));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result MemMaxClockHandler(u32* ptr) {
|
||||||
|
u32 value_next = *(ptr + 1);
|
||||||
|
constexpr u32 mtc_min_volt = 887;
|
||||||
|
|
||||||
|
Result rc = ResultSuccess();
|
||||||
|
if (value_next == mtc_min_volt) {
|
||||||
|
rc = MtcTableHandler(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
PatchOffset(ptr, C.commonEmcMaxClock);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result MemVoltHandler(u32* ptr) {
|
||||||
|
if (C.eristaEmcVolt)
|
||||||
|
PatchOffset(ptr, C.eristaEmcVolt);
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Patch(uintptr_t mapped_nso, size_t nso_size) {
|
||||||
|
enum PatchSuccessCnt {
|
||||||
|
CPU_CLOCK,
|
||||||
|
CPU_MAX_VOLT,
|
||||||
|
MEM_CLOCK,
|
||||||
|
MEM_VOLT,
|
||||||
|
CNT_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
|
u8 cnt[CNT_MAX] = {};
|
||||||
|
|
||||||
|
for (uintptr_t ptr = mapped_nso;
|
||||||
|
ptr <= mapped_nso + nso_size - sizeof(EristaMtcTable);
|
||||||
|
ptr += sizeof(u32))
|
||||||
|
{
|
||||||
|
u32* ptr32 = reinterpret_cast<u32 *>(ptr);
|
||||||
|
u32 value = *(ptr32);
|
||||||
|
|
||||||
|
switch (value) {
|
||||||
|
case CpuClkOSLimit: [[unlikely]]
|
||||||
|
if (R_SUCCEEDED(CpuDvfsHandler(ptr32, mapped_nso + nso_size)))
|
||||||
|
cnt[CPU_CLOCK]++;
|
||||||
|
continue;
|
||||||
|
case CpuVoltLimit1: [[unlikely]]
|
||||||
|
case CpuVoltLimit2: [[unlikely]]
|
||||||
|
case CpuVoltLimit3: [[unlikely]]
|
||||||
|
if (R_SUCCEEDED(CpuVoltRangeHandler(ptr32)))
|
||||||
|
cnt[CPU_MAX_VOLT]++;
|
||||||
|
continue;
|
||||||
|
case MemClkOSLimit: [[unlikely]]
|
||||||
|
if (R_SUCCEEDED(MemMaxClockHandler(ptr32)))
|
||||||
|
cnt[MEM_CLOCK]++;
|
||||||
|
continue;
|
||||||
|
case MemVoltHOS: [[unlikely]]
|
||||||
|
if (R_SUCCEEDED(MemVoltHandler(ptr32)))
|
||||||
|
cnt[MEM_VOLT]++;
|
||||||
|
continue;
|
||||||
|
default: [[likely]]
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cnt[MEM_CLOCK] || cnt[MEM_VOLT] != 2) {
|
||||||
|
AMS_ABORT();
|
||||||
|
__builtin_unreachable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace pcv {
|
||||||
|
void Patch(uintptr_t mapped_nso, size_t nso_size) {
|
||||||
|
bool isMariko = (spl::GetSocType() == spl::SocType_Mariko);
|
||||||
|
if (isMariko)
|
||||||
|
Mariko::Patch(mapped_nso, nso_size);
|
||||||
|
else
|
||||||
|
Erista::Patch(mapped_nso, nso_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace ptm {
|
namespace ptm {
|
||||||
void ApplyAutoPtmPatch(uintptr_t mapped_nso, size_t nso_size) {
|
void Patch(uintptr_t mapped_nso, size_t nso_size) {
|
||||||
/* No abort here as ptm is not that critical */
|
/* No abort here as ptm is not that critical */
|
||||||
if (spl::GetSocType() == spl::SocType_Erista)
|
bool isMariko = (spl::GetSocType() == spl::SocType_Mariko);
|
||||||
|
if (!isMariko)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
perf_conf_entry* confTable = 0;
|
perf_conf_entry* confTable = 0;
|
||||||
constexpr u32 entryCnt = 16;
|
constexpr u32 entryCnt = 16;
|
||||||
constexpr u32 memPtmLimit = MemClkOSLimit * 1000;
|
constexpr u32 memPtmLimit = 1600'000'000;
|
||||||
constexpr u32 memPtmAlt = MemClkOSAlt * 1000;
|
constexpr u32 memPtmAlt = 1331'200'000;
|
||||||
constexpr u32 memPtmClamp = MemClkOSClampDn * 1000;
|
constexpr u32 memPtmClamp = 1065'600'000;
|
||||||
const u32 memPtmMax = EmcClock * 1000;
|
const u32 memPtmMax = C.commonEmcMaxClock * 1000;
|
||||||
|
|
||||||
uintptr_t ptr = mapped_nso;
|
for (uintptr_t ptr = mapped_nso;
|
||||||
while (ptr <= mapped_nso + nso_size - sizeof(perf_conf_entry) * entryCnt)
|
ptr <= mapped_nso + nso_size - sizeof(perf_conf_entry) * entryCnt;
|
||||||
|
ptr += sizeof(u32))
|
||||||
{
|
{
|
||||||
u32 value = *(reinterpret_cast<u32 *>(ptr));
|
u32 value = *(reinterpret_cast<u32 *>(ptr));
|
||||||
|
|
||||||
@@ -905,8 +1273,6 @@ namespace ams::ldr {
|
|||||||
confTable = reinterpret_cast<perf_conf_entry *>(ptr - offsetof(perf_conf_entry, emc_freq_1));
|
confTable = reinterpret_cast<perf_conf_entry *>(ptr - offsetof(perf_conf_entry, emc_freq_1));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ptr += sizeof(u32);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!confTable)
|
if (!confTable)
|
||||||
101
Source/Atmosphere/stratosphere/loader/source/ldr_oc_suite.hpp
Normal file
101
Source/Atmosphere/stratosphere/loader/source/ldr_oc_suite.hpp
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) Switch-OC-Suite
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CUST_REV 1
|
||||||
|
|
||||||
|
namespace ams::ldr::oc {
|
||||||
|
#include "mtc_timing_table.hpp"
|
||||||
|
|
||||||
|
enum MtcConfig {
|
||||||
|
AUTO_ADJ_MARIKO_SAFE = 0,
|
||||||
|
AUTO_ADJ_MARIKO_4266 = 1,
|
||||||
|
ENTIRE_TABLE_ERISTA = 2,
|
||||||
|
ENTIRE_TABLE_MARIKO = 3,
|
||||||
|
CUSTOMIZED_MARIKO = 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
u8 cust[4] = {'C', 'U', 'S', 'T'};
|
||||||
|
u16 custRev = CUST_REV;
|
||||||
|
u16 mtcConf = AUTO_ADJ_MARIKO_SAFE;
|
||||||
|
u32 marikoCpuMaxClock;
|
||||||
|
u32 marikoCpuMaxVolt;
|
||||||
|
u32 marikoGpuMaxClock;
|
||||||
|
u32 eristaCpuOCEnable;
|
||||||
|
u32 eristaCpuMaxVolt;
|
||||||
|
u32 eristaEmcVolt;
|
||||||
|
u32 commonEmcMaxClock;
|
||||||
|
union {
|
||||||
|
EristaMtcTable eristaMtc;
|
||||||
|
MarikoMtcTable marikoMtc;
|
||||||
|
MarikoCustomizedTable marikoTiming;
|
||||||
|
};
|
||||||
|
} CustomizeTable;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
DO_NOT_OVERRIDE = 0,
|
||||||
|
OVERRIDE_WITH_ZERO = UINT32_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
|
inline void PatchOffset(u32* offset, u32 value) { *(offset) = value; }
|
||||||
|
|
||||||
|
inline Result ResultFailure() { return -1; }
|
||||||
|
|
||||||
|
namespace pcv {
|
||||||
|
typedef struct {
|
||||||
|
s32 c0 = 0;
|
||||||
|
s32 c1 = 0;
|
||||||
|
s32 c2 = 0;
|
||||||
|
s32 c3 = 0;
|
||||||
|
s32 c4 = 0;
|
||||||
|
s32 c5 = 0;
|
||||||
|
} cvb_coefficients;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
u64 freq;
|
||||||
|
cvb_coefficients cvb_dfll_param;
|
||||||
|
cvb_coefficients cvb_pll_param; // only c0 is reserved
|
||||||
|
} cpu_freq_cvb_table_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
u64 freq;
|
||||||
|
cvb_coefficients cvb_dfll_param; // empty, dfll clock source not selected
|
||||||
|
cvb_coefficients cvb_pll_param;
|
||||||
|
} gpu_cvb_pll_table_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
u64 freq;
|
||||||
|
s32 volt[4] = {0};
|
||||||
|
} emc_dvb_dvfs_table_t;
|
||||||
|
|
||||||
|
void Patch(uintptr_t mapped_nso, size_t nso_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ptm {
|
||||||
|
typedef struct {
|
||||||
|
u32 conf_id;
|
||||||
|
u32 cpu_freq_1;
|
||||||
|
u32 cpu_freq_2;
|
||||||
|
u32 gpu_freq_1;
|
||||||
|
u32 gpu_freq_2;
|
||||||
|
u32 emc_freq_1;
|
||||||
|
u32 emc_freq_2;
|
||||||
|
u32 padding;
|
||||||
|
} perf_conf_entry;
|
||||||
|
|
||||||
|
void Patch(uintptr_t mapped_nso, size_t nso_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
#include "mtc_timing_table.hpp"
|
|
||||||
|
|
||||||
constexpr u32 CpuClkOSLimit = 1785'000;
|
|
||||||
constexpr u32 CpuClkOfficial = 1963'500;
|
|
||||||
constexpr u32 CpuVoltOfficial = 1120;
|
|
||||||
constexpr u32 GpuClkOfficial = 1267'200;
|
|
||||||
constexpr u32 MemClkOSLimit = 1600'000;
|
|
||||||
constexpr u32 MemClkOSAlt = 1331'200;
|
|
||||||
constexpr u32 MemClkOSClampDn = 1065'600;
|
|
||||||
|
|
||||||
#define INVALID_MTC_TABLE UINT32_MAX
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
u8 magic[4] = {'C', 'U', 'S', 'T'};
|
|
||||||
u32 cpuMaxClock = CpuClkOfficial;
|
|
||||||
u32 cpuMaxVolt = CpuVoltOfficial;
|
|
||||||
u32 gpuMaxClock = GpuClkOfficial;
|
|
||||||
u32 emcMaxClock = 1862'400;
|
|
||||||
MarikoMtcTable mtcTable = { INVALID_MTC_TABLE };
|
|
||||||
} CustomizeTable;
|
|
||||||
|
|
||||||
inline void PatchOffset(uintptr_t offset, u32 value) {
|
|
||||||
*(reinterpret_cast<u32 *>(offset)) = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void PatchOffset(u32* offset, u32 value) {
|
|
||||||
*(offset) = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define ResultFailure() -1
|
|
||||||
|
|
||||||
namespace pcv {
|
|
||||||
typedef struct {
|
|
||||||
s32 c0 = 0;
|
|
||||||
s32 c1 = 0;
|
|
||||||
s32 c2 = 0;
|
|
||||||
s32 c3 = 0;
|
|
||||||
s32 c4 = 0;
|
|
||||||
s32 c5 = 0;
|
|
||||||
} cvb_coefficients;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
u64 freq;
|
|
||||||
cvb_coefficients cvb_dfll_param;
|
|
||||||
cvb_coefficients cvb_pll_param; // only c0 is reserved
|
|
||||||
} cpu_freq_cvb_table_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
u64 freq;
|
|
||||||
cvb_coefficients cvb_dfll_param; // empty, dfll clock source not selected
|
|
||||||
cvb_coefficients cvb_pll_param;
|
|
||||||
} gpu_cvb_pll_table_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
u64 freq;
|
|
||||||
s32 volt[4] = {0};
|
|
||||||
} emc_dvb_dvfs_table_t;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace ptm {
|
|
||||||
typedef struct {
|
|
||||||
u32 conf_id;
|
|
||||||
u32 cpu_freq_1;
|
|
||||||
u32 cpu_freq_2;
|
|
||||||
u32 gpu_freq_1;
|
|
||||||
u32 gpu_freq_2;
|
|
||||||
u32 emc_freq_1;
|
|
||||||
u32 emc_freq_2;
|
|
||||||
u32 padding;
|
|
||||||
} perf_conf_entry;
|
|
||||||
}
|
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
#include "ldr_patcher.hpp"
|
#include "ldr_patcher.hpp"
|
||||||
#include "ldr_process_creation.hpp"
|
#include "ldr_process_creation.hpp"
|
||||||
#include "ldr_ro_manager.hpp"
|
#include "ldr_ro_manager.hpp"
|
||||||
#include "ldr_oc_patch.hpp"
|
#include "ldr_oc_suite.hpp"
|
||||||
|
|
||||||
namespace ams::ldr {
|
namespace ams::ldr {
|
||||||
|
|
||||||
@@ -608,10 +608,10 @@ namespace ams::ldr {
|
|||||||
|
|
||||||
/* Apply pcv and ptm patches. */
|
/* Apply pcv and ptm patches. */
|
||||||
if (g_is_pcv) {
|
if (g_is_pcv) {
|
||||||
pcv::ApplyAutoPcvPatch(map_address, nso_size);
|
oc::pcv::Patch(map_address, nso_size);
|
||||||
}
|
}
|
||||||
if (g_is_ptm) {
|
if (g_is_ptm) {
|
||||||
ptm::ApplyAutoPtmPatch(map_address, nso_size);
|
oc::ptm::Patch(map_address, nso_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,162 @@
|
|||||||
* from GCC preprocessor output
|
* from GCC preprocessor output
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
struct MarikoCustomizedTable {
|
||||||
|
struct {
|
||||||
|
uint32_t emc_rc;
|
||||||
|
uint32_t emc_rfc;
|
||||||
|
uint32_t emc_rfcpb;
|
||||||
|
uint32_t emc_ras;
|
||||||
|
uint32_t emc_rp;
|
||||||
|
uint32_t emc_r2w;
|
||||||
|
uint32_t emc_w2r;
|
||||||
|
uint32_t emc_r2p;
|
||||||
|
uint32_t emc_w2p;
|
||||||
|
uint32_t emc_trtm;
|
||||||
|
uint32_t emc_twtm;
|
||||||
|
uint32_t emc_tratm;
|
||||||
|
uint32_t emc_twatm;
|
||||||
|
uint32_t emc_rd_rcd;
|
||||||
|
uint32_t emc_wr_rcd;
|
||||||
|
uint32_t emc_rrd;
|
||||||
|
uint32_t emc_wdv;
|
||||||
|
uint32_t emc_wsv;
|
||||||
|
uint32_t emc_wev;
|
||||||
|
uint32_t emc_wdv_mask;
|
||||||
|
uint32_t emc_quse;
|
||||||
|
uint32_t emc_quse_width;
|
||||||
|
uint32_t emc_ibdly;
|
||||||
|
uint32_t emc_obdly;
|
||||||
|
uint32_t emc_einput;
|
||||||
|
uint32_t emc_einput_duration;
|
||||||
|
uint32_t emc_qrst;
|
||||||
|
uint32_t emc_qsafe;
|
||||||
|
uint32_t emc_rdv;
|
||||||
|
uint32_t emc_rdv_mask;
|
||||||
|
uint32_t emc_rdv_early;
|
||||||
|
uint32_t emc_rdv_early_mask;
|
||||||
|
uint32_t emc_refresh;
|
||||||
|
uint32_t emc_pre_refresh_req_cnt;
|
||||||
|
uint32_t emc_pdex2wr;
|
||||||
|
uint32_t emc_pdex2rd;
|
||||||
|
uint32_t emc_act2pden;
|
||||||
|
uint32_t emc_rw2pden;
|
||||||
|
uint32_t emc_cke2pden;
|
||||||
|
uint32_t emc_pdex2mrr;
|
||||||
|
uint32_t emc_txsr;
|
||||||
|
uint32_t emc_txsrdll;
|
||||||
|
uint32_t emc_tcke;
|
||||||
|
uint32_t emc_tckesr;
|
||||||
|
uint32_t emc_tpd;
|
||||||
|
uint32_t emc_tfaw;
|
||||||
|
uint32_t emc_trpab;
|
||||||
|
uint32_t emc_tclkstop;
|
||||||
|
uint32_t emc_trefbw;
|
||||||
|
uint32_t emc_pmacro_ob_ddll_long_dq_rank1_4;
|
||||||
|
uint32_t emc_pmacro_ob_ddll_long_dq_rank1_5;
|
||||||
|
uint32_t emc_pmacro_ob_ddll_long_dqs_rank0_0;
|
||||||
|
uint32_t emc_pmacro_ob_ddll_long_dqs_rank0_1;
|
||||||
|
uint32_t emc_pmacro_ob_ddll_long_dqs_rank0_3;
|
||||||
|
uint32_t emc_pmacro_ob_ddll_long_dqs_rank0_4;
|
||||||
|
uint32_t emc_pmacro_ob_ddll_long_dqs_rank0_5;
|
||||||
|
uint32_t emc_pmacro_ob_ddll_long_dqs_rank1_0;
|
||||||
|
uint32_t emc_pmacro_ob_ddll_long_dqs_rank1_1;
|
||||||
|
uint32_t emc_pmacro_ob_ddll_long_dqs_rank1_3;
|
||||||
|
uint32_t emc_pmacro_ob_ddll_long_dqs_rank1_4;
|
||||||
|
uint32_t emc_pmacro_ob_ddll_long_dqs_rank1_5;
|
||||||
|
uint32_t emc_pmacro_ddll_long_cmd_0;
|
||||||
|
uint32_t emc_pmacro_ddll_long_cmd_1;
|
||||||
|
uint32_t emc_pmacro_ddll_long_cmd_2;
|
||||||
|
uint32_t emc_pmacro_ddll_long_cmd_3;
|
||||||
|
uint32_t emc_pmacro_ddll_long_cmd_4;
|
||||||
|
uint32_t emc_zcal_wait_cnt;
|
||||||
|
uint32_t emc_mrs_wait_cnt;
|
||||||
|
uint32_t emc_mrs_wait_cnt2;
|
||||||
|
uint32_t emc_auto_cal_channel;
|
||||||
|
uint32_t emc_pmacro_dll_cfg_2;
|
||||||
|
uint32_t emc_pmacro_autocal_cfg_common;
|
||||||
|
uint32_t emc_dyn_self_ref_control;
|
||||||
|
uint32_t emc_qpop;
|
||||||
|
uint32_t emc_pmacro_cmd_pad_tx_ctrl;
|
||||||
|
uint32_t emc_tr_timing_0;
|
||||||
|
uint32_t emc_tr_rdv;
|
||||||
|
uint32_t emc_tr_qpop;
|
||||||
|
uint32_t emc_tr_rdv_mask;
|
||||||
|
uint32_t emc_tr_qsafe;
|
||||||
|
uint32_t emc_tr_qrst;
|
||||||
|
uint32_t emc_training_vref_settle;
|
||||||
|
} common;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
uint32_t emc_pmacro_ob_ddll_long_dq_rank0_0;
|
||||||
|
uint32_t emc_pmacro_ob_ddll_long_dq_rank0_1;
|
||||||
|
uint32_t emc_pmacro_ob_ddll_long_dq_rank0_2;
|
||||||
|
uint32_t emc_pmacro_ob_ddll_long_dq_rank0_3;
|
||||||
|
uint32_t emc_pmacro_ob_ddll_long_dq_rank0_4;
|
||||||
|
uint32_t emc_pmacro_ob_ddll_long_dq_rank0_5;
|
||||||
|
uint32_t emc_pmacro_ob_ddll_long_dq_rank1_0;
|
||||||
|
uint32_t emc_pmacro_ob_ddll_long_dq_rank1_1;
|
||||||
|
uint32_t emc_pmacro_ob_ddll_long_dq_rank1_2;
|
||||||
|
uint32_t emc_pmacro_ob_ddll_long_dq_rank1_3;
|
||||||
|
} trim_regs;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
uint32_t rl;
|
||||||
|
} dram_timings;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
uint32_t mc_emem_arb_cfg;
|
||||||
|
uint32_t mc_emem_arb_timing_rcd;
|
||||||
|
uint32_t mc_emem_arb_timing_rp;
|
||||||
|
uint32_t mc_emem_arb_timing_rc;
|
||||||
|
uint32_t mc_emem_arb_timing_ras;
|
||||||
|
uint32_t mc_emem_arb_timing_faw;
|
||||||
|
uint32_t mc_emem_arb_timing_wap2pre;
|
||||||
|
uint32_t mc_emem_arb_timing_r2w;
|
||||||
|
uint32_t mc_emem_arb_timing_w2r;
|
||||||
|
uint32_t mc_emem_arb_timing_rfcpb;
|
||||||
|
uint32_t mc_emem_arb_da_turns;
|
||||||
|
uint32_t mc_emem_arb_da_covers;
|
||||||
|
uint32_t mc_emem_arb_misc0;
|
||||||
|
} burst_mc_regs;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
uint32_t mc_mll_mpcorer_ptsa_rate;
|
||||||
|
uint32_t mc_ptsa_grant_decrement;
|
||||||
|
uint32_t mc_latency_allowance_xusb_0;
|
||||||
|
uint32_t mc_latency_allowance_xusb_1;
|
||||||
|
uint32_t mc_latency_allowance_tsec_0;
|
||||||
|
uint32_t mc_latency_allowance_sdmmca_0;
|
||||||
|
uint32_t mc_latency_allowance_sdmmcaa_0;
|
||||||
|
uint32_t mc_latency_allowance_sdmmc_0;
|
||||||
|
uint32_t mc_latency_allowance_sdmmcab_0;
|
||||||
|
uint32_t mc_latency_allowance_ppcs_1;
|
||||||
|
uint32_t mc_latency_allowance_mpcore_0;
|
||||||
|
uint32_t mc_latency_allowance_hc_0;
|
||||||
|
uint32_t mc_latency_allowance_hc_1;
|
||||||
|
uint32_t mc_latency_allowance_avpc_0;
|
||||||
|
uint32_t mc_latency_allowance_gpu_0;
|
||||||
|
uint32_t mc_latency_allowance_gpu2_0;
|
||||||
|
uint32_t mc_latency_allowance_nvenc_0;
|
||||||
|
uint32_t mc_latency_allowance_nvdec_0;
|
||||||
|
uint32_t mc_latency_allowance_vic_0;
|
||||||
|
uint32_t mc_latency_allowance_vi2_0;
|
||||||
|
uint32_t mc_latency_allowance_isp2_1;
|
||||||
|
} la_scale_regs;
|
||||||
|
|
||||||
|
uint32_t pllm_ss_ctrl1;
|
||||||
|
uint32_t pllm_ss_ctrl2;
|
||||||
|
uint32_t pllmb_ss_ctrl1;
|
||||||
|
uint32_t pllmb_ss_ctrl2;
|
||||||
|
uint32_t pllmb_divm;
|
||||||
|
uint32_t pllmb_divn;
|
||||||
|
uint32_t min_mrs_wait;
|
||||||
|
uint32_t emc_mrw;
|
||||||
|
uint32_t emc_mrw2;
|
||||||
|
uint32_t emc_cfg_2;
|
||||||
|
uint32_t latency;
|
||||||
|
};
|
||||||
|
|
||||||
struct MarikoMtcTable {
|
struct MarikoMtcTable {
|
||||||
uint32_t rev;
|
uint32_t rev;
|
||||||
char dvfs_ver[60];
|
char dvfs_ver[60];
|
||||||
@@ -2370,4 +2526,4 @@ struct EristaMtcTable {
|
|||||||
uint32_t latency;
|
uint32_t latency;
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(sizeof(EristaMtcTable) == 0x1340);
|
static_assert(sizeof(EristaMtcTable) == 0x1340);
|
||||||
|
|||||||
Reference in New Issue
Block a user