74 Commits
0.34 ... 0.39

Author SHA1 Message Date
Lightos1
3f9a5f61fb Add mrf for erista 2026-02-15 15:41:52 +01:00
souldbminersmwc
b9156d6861 sysclk: add sys-dock intergration 2026-02-14 21:16:14 -05:00
souldbminersmwc
5d59be7b77 sysclk: add experemental gpu sched override option 2026-02-14 20:55:44 -05:00
souldbminersmwc
dd4c5a8732 sysclk: make memmem proper 2026-02-14 20:27:43 -05:00
souldbminersmwc
837543fb0f Merge branch 'main' of https://github.com/Horizon-OC/Horizon-OC 2026-02-14 20:23:25 -05:00
souldbminersmwc
03ede8f171 sysclk: fix crashing on boot and raise minimum refresh rate on aula 2026-02-14 20:23:22 -05:00
Lightos1
078d8164fc Remove include 2026-02-15 01:29:11 +01:00
Lightos1
ceff8a083e Remove function in header 2026-02-15 01:28:49 +01:00
Lightos1
b32efcc177 Erista: dvb + more precise timings/timings from eos & formating 2026-02-15 01:27:50 +01:00
Lightos1
d57fccc463 Add cpu load, thanks masa for the help! 2026-02-14 21:47:25 +01:00
Souldbminer
26cf028f2d Update contact information for reporting vulnerabilities 2026-02-13 19:59:36 -05:00
souldbminersmwc
6e80c9a75f chore: depricate exosphere patch 2026-02-13 19:53:13 -05:00
souldbminersmwc
42bdfb55f2 remove charge current from overlay 2026-02-13 19:35:40 -05:00
souldbminersmwc
e0967a9fd6 sysclk: fix ui issues 2026-02-13 19:33:42 -05:00
souldbminersmwc
2406ce4f86 sysclk: fix real freq bug 2026-02-13 19:12:01 -05:00
souldbminersmwc
3b40a4a3e5 sysclk: turn on size compiler optimization 2026-02-13 16:36:04 -05:00
souldbminersmwc
38c408dde6 Merge branch 'main' of https://github.com/Horizon-OC/Horizon-OC 2026-02-13 16:33:31 -05:00
souldbminersmwc
5e62eb3f5d sysclk: fix compile issue and remove 1152 no uv gpu 2026-02-13 16:33:29 -05:00
Lightos1
b4b5599ed2 sleep of 300'000 is enough 2026-02-13 12:15:46 +01:00
souldbminersmwc
b4917f3e1a sysclk: remove enforce board limit
this setting is bugged, so remove it
2026-02-12 19:55:15 -05:00
souldbminersmwc
e6b4cb6612 sysclk: add lineon's cpu volt bugfix
thanks, lineon!
2026-02-12 19:49:52 -05:00
souldbminersmwc
b1ca62ce61 sysclk: fix voltage display issue 2026-02-12 19:19:53 -05:00
souldbminersmwc
243f614887 Update clock_manager.cpp 2026-02-12 18:22:43 -05:00
souldbminersmwc
a8577378f6 Update misc_gui.cpp 2026-02-12 17:01:33 -05:00
souldbminersmwc
564703b7c5 sysclk: improve cpu volt bugfix 2026-02-12 17:00:31 -05:00
souldbminersmwc
5ef56bed25 sysclk: remove live timing update and fix profile change dvfs bug 2026-02-12 16:15:25 -05:00
Lightos1
afddb963a9 Remove dvfsOffset capping 2026-02-12 21:22:53 +01:00
Lightos1
aa72176196 Remove budget dvfs 2026-02-12 17:15:26 +01:00
Lightos1
7af0721847 DVFS: Safety check fix 2026-02-12 17:02:52 +01:00
Lightos1
2a6320e646 Bracket fix 2026-02-12 16:49:12 +01:00
Lightos1
fc212bb419 Bump version 2026-02-12 16:46:49 +01:00
Lightos1
14e0053335 DVFS: Add offset 2026-02-12 16:44:04 +01:00
Lightos1
8f28daceef DVFS: Add safety check 2026-02-12 16:12:36 +01:00
souldbminersmwc
f1044673d0 sysclk: modify dvfs logic 2026-02-11 19:28:43 -05:00
souldbminersmwc
61a0ebffee sysclk: fully fix dvfs 2026-02-11 19:22:25 -05:00
souldbminersmwc
8de8f4013e sysclk: fix dvfs config option 2026-02-11 19:11:02 -05:00
souldbminersmwc
dd447553d4 sysclk: make dvfs work 2026-02-11 19:09:55 -05:00
Lightos1
11c456e00c Fix random } 2026-02-11 17:42:10 +01:00
Lightos1
5efb4bdd6b Add hijack dvfs from sys-clk-eos 2026-02-11 16:57:26 +01:00
Lightos1
e331f1249b Why did this not commit? 2026-02-11 11:08:29 +01:00
Lightos1
786467d7ea add r2w fine tuning 2026-02-11 11:05:45 +01:00
Lightos1
496e77301b bump version 2026-02-11 01:06:52 +01:00
Lightos1
d657f1d156 Fix typo 2 2026-02-10 15:33:47 +01:00
Lightos1
7ab5c2f540 Fix typo 2026-02-10 15:33:03 +01:00
Lightos1
71900721cf Make AUTO_RAM default (for now) 2026-02-10 15:26:12 +01:00
Lightos1
0bc9547701 Add advanced header 2026-02-10 15:12:17 +01:00
Lightos1
96ac254022 Add w2r fine tune 2026-02-10 15:04:28 +01:00
Souldbminer
92f378a80f fix svfs again 2026-02-09 18:59:09 -05:00
Lightos1
589af01ad8 Budget dvfs fix 2026-02-10 00:39:22 +01:00
Lightos1
e7f14b88e5 Replace floor with ceil 2026-02-09 16:29:05 +01:00
souldbminersmwc
35a269e4a7 Update README.md 2026-02-08 15:51:46 -05:00
souldbminersmwc
ff95ca527f Merge branch 'develop' of https://github.com/Horizon-OC/Horizon-OC into develop 2026-02-08 15:33:53 -05:00
souldbminersmwc
550e4e5204 Delete HOC_AUTO_RAM_TEST.zip 2026-02-08 15:33:39 -05:00
Lightos1
a088c4795a Update readme 2026-02-08 18:52:23 +01:00
Lightos1
e8a264fa11 New timings, fix budget gpu dvfs 2026-02-08 18:46:10 +01:00
souldbminersmwc
de681c20a0 ldr: code cleanup 2026-02-08 12:00:27 -05:00
souldbminersmwc
22aef264ab Update pcv_mariko.cpp 2026-02-08 11:57:54 -05:00
souldbminersmwc
309717c468 ldr: fix auto_ram vmin 2026-02-08 11:57:43 -05:00
souldbminersmwc
9b91d7487c ldr: rename namespace 2026-02-08 11:56:04 -05:00
souldbminersmwc
c0b458243c ldr: add auto ram vmin 2026-02-08 11:54:21 -05:00
souldbminersmwc
7d9c60cdfe Merge branch 'develop' of https://github.com/Horizon-OC/Horizon-OC into develop 2026-02-07 19:20:33 -05:00
souldbminersmwc
12c9effec2 Update README.md 2026-02-07 19:20:31 -05:00
Souldbminer
6eeab63075 Rearrange CPU clock entries in README
Reordered CPU clock entries for clarity.
2026-02-07 18:53:41 -05:00
Souldbminer
2d81c5e127 Merge pull request #34 from OEMunlag/develop
Remove dist.zip hash on actions
2026-02-07 18:51:12 -05:00
souldbminersmwc
b1739cea74 sysclk: rework clock capping 2026-02-07 18:38:37 -05:00
souldbminersmwc
aa607ab1a7 sysclk: safety display changes 2026-02-07 18:28:49 -05:00
souldbminersmwc
d1242a17d4 sysclk: 2133MHz is a JEDEC clock 2026-02-07 18:23:49 -05:00
2fort sink
80701c2891 Merge branch 'Horizon-OC:develop' into develop 2026-02-07 20:18:15 -03:00
souldbminersmwc
cfd0d84ac8 update dist 2026-02-07 18:10:21 -05:00
souldbminersmwc
c33aabdc84 chore: code cleanup 2026-02-07 18:10:12 -05:00
2fort sink
c70fd82e60 Modify build.yml to set commit SHA and dist
Updated the GitHub Actions workflow to include a distribution file with the commit SHA.
2026-02-07 20:07:56 -03:00
2fort sink
574c248d68 Merge branch 'Horizon-OC:develop' into develop 2026-02-07 19:55:21 -03:00
2fort sink
0ae65c8740 Merge branch 'Horizon-OC:develop' into develop 2026-02-04 18:07:27 -03:00
2fort sink
39fbe25afc Update build.yml 2026-02-04 18:07:16 -03:00
60 changed files with 1298 additions and 1317 deletions

View File

@@ -10,7 +10,7 @@ jobs:
build:
runs-on: ubuntu-latest
# Minimal devkitA64 container, apparently dkp-toolchain isn't needed?
# Minimal devkitA64 container
container:
image: devkitpro/devkita64:20251231
@@ -47,9 +47,12 @@ jobs:
# -------------------------------------------------
# Get short commit SHA
# -------------------------------------------------
- name: Set commit SHA
- name: Set commit SHA & dist
id: vars
run: echo "SHORT_SHA=$(echo $GITHUB_SHA | cut -c1-7)" >> $GITHUB_ENV
run: |
echo "SHORT_SHA=$(echo $GITHUB_SHA | cut -c1-7)" >> $GITHUB_ENV
echo $SHORT_SHA > dist/.commit
echo $GITHUB_SHA >> dist/.commit
- name: Clone Atmosphere
run: git clone --depth=1 --single-branch https://github.com/Atmosphere-NX/Atmosphere.git atmosphere -b $(cat ams_ver.txt)
@@ -149,23 +152,12 @@ jobs:
- name: ccache stats
run: ccache --show-stats
# -------------------------------------------------
# Package dist folder as ZIP with commit SHA
# -------------------------------------------------
- name: Package dist
# working-directory: horizon-oc
run: |
ZIP_NAME="horizon-oc-zeus-dist-${SHORT_SHA}.zip"
zip -r "$ZIP_NAME" dist
echo "ZIP_NAME=$ZIP_NAME" >> $GITHUB_ENV
# -------------------------------------------------
# Upload ZIP artifact
# -------------------------------------------------
- name: Upload build artifact
uses: actions/upload-artifact@v6
with:
name: horizon-oc-zeus-dist-${{ env.SHORT_SHA }}
name: horizon-oc-zeus-dist
path: dist/
compression-level: 3

View File

@@ -41,10 +41,8 @@ It enables advanced CPU, GPU, and RAM tuning with user-friendly configuration to
* Built-in configurator
* Compatible with most homebrew
> *Higher (potentially dangerous) frequencies are unlockable via configuration.*
> *Erista and Mariko units can usually push a bit further fully safely with a bit of undervolting, however this may not work on all units.*
> *The exact maximum overclock possible varies per console, although most consoles should be able to do this safely.*
> *You may refer to the Clock Table to see clocks in more detail*
> It is reccomended to read the [guide](https://rentry.co/howtoget60fps) before proceeding, as this can help you get a *significant* performance boost over the default settings, often times with less power draw and heat output
---
## Installation
@@ -91,15 +89,15 @@ Refer to COMPILATION.md
* 1866 → mariko safe max (3733 Modules), JEDEC.
* 1600 → official docked, boost mode, erista safe max, JEDEC.
* 1331 → official handheld, JEDEC.
* 1065
* 1065
* 800
* 665
### CPU clocks
* 2601 → mariko absolute max, very dangerous
* 2499
* 2397
* 2295 → mariko safe max with UV (low speedo)
* 2397 → mariko safe max with UV (low speedo)
* 2295
* 2193
* 2091
* 1963 → mariko no UV max clock
@@ -153,6 +151,7 @@ Refer to COMPILATION.md
* **Souldbminer** hoc-clk and loader development
* **Lightos** loader patches development
* **SciresM** - Atmosphere CFW
* **CTCaer** - L4T, Hekate, perfect ram timings
* **KazushiMe** Switch OC Suite
* **hanai3bi (meha)** Switch OC Suite, EOS, sys-clk-eos
* **NaGaa95** L4T-OC-kernel

View File

@@ -8,4 +8,4 @@
## Reporting a Vulnerability
Contact me on discord (soul_9017) or email me (souldbminer@gmail.com)
Contact Souldbminer or Lightos_ on discord (souldbminer, lightos_)

View File

@@ -694,11 +694,11 @@ namespace ams::ldr {
/* Apply PCV and PTM patches */
if (g_is_pcv) {
oc::pcv::Patch(map_address, nso_size);
hoc::pcv::Patch(map_address, nso_size);
}
if (g_is_ptm) {
oc::ptm::Patch(map_address, nso_size);
hoc::ptm::Patch(map_address, nso_size);
}
}

View File

@@ -28,17 +28,19 @@
#define GPU_MIN_MIN_VOLT 480000
#define CPU_MAX_MAX_VOLT 1235000
namespace ams::ldr::oc {
namespace ams::ldr::hoc {
volatile CustomizeTable C = {
/* Disables RAM powerdown */
.hpMode = DISABLED,
.commonEmcMemVolt = 1175000, // LPDDR4X JEDEC Specification
.eristaEmcMaxClock = 1600000, // Maximum HB-MGCH ram rating
.commonEmcMemVolt = 1175000, /* LPDDR4X JEDEC Specification */
.eristaEmcMaxClock = 1600000, /* Maximum HB-MGCH ram rating */
.eristaEmcMaxClock1 = 1600000,
.eristaEmcMaxClock2 = 1600000,
.marikoEmcMaxClock = 1866000, // 1866MHz @ 1866tWRL is guaranteed to work on all Mariko units
.marikoEmcVddqVolt = 600000,
.marikoEmcMaxClock = 1866000, /* 1866MHz @ 1866tWRL is guaranteed to work on all Mariko units */
.marikoEmcVddqVolt = 600000, /* Micron: 600mV, other manafacturers: 640mV */
.emcDvbShift = 0,
// Primary
@@ -52,9 +54,7 @@ volatile CustomizeTable C = {
.t7_tWTR = 0,
.t8_tREFI = 0,
/* Set to 4 read and 2 write for 1866b tWRL. */
/* For 2133 tWRL: 8 read and 4 write. */
/* You can mix and match different latencies if needed */
/*
* Read:
* 2133RL = 40
@@ -67,8 +67,9 @@ volatile CustomizeTable C = {
* 1600WL = 14
* 1331WL = 12
*/
.mem_burst_read_latency = 36,
.mem_burst_write_latency = 16,
.mem_burst_read_latency = RL_1866,
.mem_burst_write_latency = WL_1866,
.eristaCpuUV = 0,
.eristaCpuVmin = 800,
@@ -78,9 +79,11 @@ volatile CustomizeTable C = {
.marikoCpuUVLow = 0, // No undervolt
.marikoCpuUVHigh = 0, // No undervolt
.tableConf = DEFAULT_TABLE,
.marikoCpuLowVmin = 620,
.marikoCpuHighVmin = 750,
/* 1120mV is NVIDIA rating */
.marikoCpuMaxVolt = 1120,
/* Supported values: 1963000, 2091000, 2193000, 2295000, 2397000, 2499000, 2601000, 2703000. */
@@ -99,19 +102,22 @@ volatile CustomizeTable C = {
.eristaGpuVmin = 810,
.marikoGpuUV = 0,
/* For automatic vmin detection, set this to AUTO. */
/* vmin past 795mV won't work due to HOS limitation */
/* Vmin is automatically set to 800mV when SoC temperature is below 20C */
.marikoGpuVmin = AUTO,
.marikoGpuVmax = 800,
.commonGpuVoltOffset = 0,
/* Speedo is automatically set by hoc-clk on first boot */
.gpuSpeedo = 1450,
/* This table is used with a gpu uv mode of 2. */
/* Setting DEACTIVATED_GPU_FREQ on any freq will disable it and all freqs greater than it. (the latter is a bug :/) */
/* AUTO: Voltage is optimally chosen; with commonGpuVoltOffset applied. */
/* AUTO only works up to 1305 GPU on Mariko and 921 GPU on Erista */
/* AUTO only works up to 1305 GPU on Mariko and 998 GPU on Erista (it is reccomended to manually set your 998MHz voltage though) */
/* You can overwrite auto with any voltage (in mv) of your choice - offset will not be applied. */
.eristaGpuVoltArray = {
@@ -159,8 +165,8 @@ volatile CustomizeTable C = {
AUTO /* 921 */,
AUTO /* 998 */,
AUTO /* 1075 */,
DEACTIVATED_GPU_FREQ /* 1152 */,
DEACTIVATED_GPU_FREQ /* 1228 */,
AUTO /* 1152 (SLT / HiOPT Only!) */,
AUTO /* 1228 (HiOPT Only!) */,
DEACTIVATED_GPU_FREQ /* 1267 (Disabled by default) */,
DEACTIVATED_GPU_FREQ /* 1305 (Disabled by default) */,
DEACTIVATED_GPU_FREQ /* 1344 (Disabled by default) */,
@@ -171,6 +177,10 @@ volatile CustomizeTable C = {
DEACTIVATED_GPU_FREQ /* 1536 (Disabled by default) */,
},
/* Advanced. */
.fineTune_t6_tRTW = 0,
.fineTune_t7_tWTR = 0,
/* You shouldn't have to anything past here. */
.eristaCpuDvfsTable = {
{ 204000, { 721094, }, { } },
@@ -455,7 +465,7 @@ volatile CustomizeTable C = {
{ 921600, { }, { 970060,-10108, -614,-179, 1508, -13 } },
{ 998400, { }, { 1065665,-16075, -497,-179, 3213, 9 } },
{ 1075200, { }, { 1132576,-16093, -648, 0, 1077, 40 } },
{ 1152000, { }, { 1180029,-14534, -830, 0, 1469, 110 } },
// { 1152000, { }, { 1180029,-14534, -830, 0, 1469, 110 } },
// { 1228800, { }, { 1248293,-16383, -859, 0, 3722, 313 } },
// { 1267200, { }, { 1286399,-17475, -867, 0, 3681, 559 } },
},

View File

@@ -20,20 +20,15 @@
#pragma once
#define CUST_REV 11
#define CUST_REV 1
#include "oc_common.hpp"
#include "pcv/pcv_common.hpp"
namespace ams::ldr::oc {
namespace ams::ldr::hoc {
#include "mtc_timing_table.hpp"
enum MtcConfig: u32 {
AUTO_ADJ = 0,
AUTO_ADJ_BL = 1,
};
enum TableConfig: u32 {
DEFAULT_TABLE = 1,
TBREAK_1581 = 2,
@@ -41,6 +36,33 @@ enum TableConfig: u32 {
EXTREME_TABLE = 4,
};
/*
* Read:
* 2133RL = 40
* 1866RL = 36
* 1600RL = 32
* 1331RL = 28
* Write:
* 2133WL = 18
* 1866WL = 16
* 1600WL = 14
* 1331WL = 12
*/
enum ReadLatency: u32 {
RL_2133 = 40,
RL_1866 = 36,
RL_1600 = 32,
RL_1331 = 28,
};
enum WriteLatency: u32 {
WL_2133 = 18,
WL_1866 = 16,
WL_1600 = 14,
WL_1331 = 12,
};
using CustomizeCpuDvfsTable = pcv::cvb_entry_t[pcv::DvfsTableEntryLimit];
using CustomizeGpuDvfsTable = pcv::cvb_entry_t[pcv::DvfsTableEntryLimit];
static_assert(sizeof(CustomizeCpuDvfsTable) == sizeof(CustomizeGpuDvfsTable));
@@ -53,11 +75,13 @@ typedef struct CustomizeTable {
u8 cust[4] = {'C', 'U', 'S', 'T'};
u32 custRev = CUST_REV;
u32 mtcConf;
u32 placeholder;
u32 hpMode;
u32 commonEmcMemVolt;
u32 eristaEmcMaxClock;
u32 eristaEmcMaxClock1;
u32 eristaEmcMaxClock2;
u32 marikoEmcMaxClock;
u32 marikoEmcVddqVolt;
u32 emcDvbShift;
@@ -99,12 +123,16 @@ typedef struct CustomizeTable {
u32 commonGpuVoltOffset;
/* TODO: Automatically detect speedo. */
u32 gpuSpeedo;
u32 eristaGpuVoltArray[27];
u32 marikoGpuVoltArray[24];
u32 reserved[64];
u32 fineTune_t6_tRTW;
u32 fineTune_t7_tWTR;
u32 reserved[60];
CustomizeCpuDvfsTable eristaCpuDvfsTable;
CustomizeCpuDvfsTable eristaCpuDvfsTableSLT;

View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) Lightos_
*
* 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/>.
*/
#include "../oc_common.hpp"
#include "../mtc_timing_value.hpp"
namespace ams::ldr::hoc::pcv::erista {
void CalculateTimings(double tCK_avg) {
tR2W = FLOOR(FLOOR((5.0 / tCK_avg) + ((FLOOR(48.0 / WL) - 0.478) * 3.0)) / 1.501) + RL_DBI - (C.t6_tRTW * 3) + finetRTW;
tWTPDEN = CEIL(((1.803 / tCK_avg) + MAX(RL_DBI + (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_DBI)), 1.964)) * 1.964) + WL - CEIL(tWTR / tCK_avg) + finetWTR;
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;
const double tMMRI = tRCD + (tCK_avg * 3);
pdex2mrr = tMMRI + 10;
}
}

View File

@@ -0,0 +1,23 @@
/*
* Copyright (c) Lightos_
*
* 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/>.
*/
#pragma once
namespace ams::ldr::hoc::pcv::erista {
void CalculateTimings(double tCK_avg);
}

View File

@@ -18,49 +18,16 @@
#include "../mtc_timing_value.hpp"
#include "timing_tables.hpp"
namespace ams::ldr::oc::pcv::mariko {
namespace ams::ldr::hoc::pcv::mariko {
u32 GetRext() {
void GetRext() {
if (auto r = FindRext()) {
return r->correct;
rext = r->rext;
return;
}
return 0x1A;
}
void CalculateTWTPDEN() {
tWTPDEN = tW2P + 1 + CEIL(tDQSS_max / tCK_avg) + CEIL(tDQS2DQ_max / tCK_avg) + 6;
if (C.marikoEmcMaxClock >= 2'233'000 && C.marikoEmcMaxClock < 2'533'000) tWTPDEN++;
if (C.marikoEmcMaxClock >= 2'433'000 && C.marikoEmcMaxClock < 2'800'000) tWTPDEN--;
}
void CalculateTR2W() {
tR2W = CEIL(RL_DBI + (tDQSCK_max / tCK_avg) + (BL / 2) - WL + tWPRE + FLOOR(tRPST) + 9.0) - (C.t6_tRTW * 3);
if (auto patch = FindTR2WPatch()) {
tR2W += patch->adjust;
}
}
void CalculatePdex2rw() {
double freq_mhz = C.marikoEmcMaxClock / 1000.0;
double pdex_local = (0.011 * freq_mhz) - 1.443;
pdex2rw = static_cast<u32>(ROUND(pdex_local));
if (pdex2rw < 22) pdex2rw = 22;
if (pdex2rw > 33) pdex2rw = 33;
if (auto patch = FindPdex2rwPatch()) {
pdex2rw += patch->adjust;
}
}
void CalculateCke2pden() {
cke2pden = (static_cast<double>((C.marikoEmcMaxClock / 1000.0) * 0.00875) - 0.65);
if (auto patch = FindCke2pdenPatch()) {
cke2pden += patch->adjust;
}
/* Fallback. */
rext = 0x1A;
}
void CalculateMrw2() {
@@ -93,11 +60,7 @@ namespace ams::ldr::oc::pcv::mariko {
}
void CalculateTimings() {
rext = GetRext();
CalculateTWTPDEN();
CalculateTR2W();
CalculatePdex2rw();
CalculateCke2pden();
GetRext();
CalculateMrw2();
}

View File

@@ -16,8 +16,9 @@
#pragma once
namespace ams::ldr::oc::pcv::mariko {
namespace ams::ldr::hoc::pcv::mariko {
void CalculateTimings();
}

View File

@@ -17,7 +17,7 @@
#include "../mtc_timing_value.hpp"
#include "timing_tables.hpp"
namespace ams::ldr::oc::pcv::mariko {
namespace ams::ldr::hoc::pcv::mariko {
const ReplacePatch g_rext_table[] = {
{2'133'000, 0x1A}, {2'166'000, 0x19}, {2'200'000, 0x19},
@@ -36,78 +36,11 @@ namespace ams::ldr::oc::pcv::mariko {
const u32 g_rext_table_size = sizeof(g_rext_table) / sizeof(g_rext_table[0]);
const ReplacePatch *FindRext() {
for (u32 i = 0; i < g_rext_table_size; i++)
if (g_rext_table[i].freq == C.marikoEmcMaxClock)
for (u32 i = 0; i < g_rext_table_size; i++) {
if (g_rext_table[i].freq >= C.marikoEmcMaxClock) {
return &g_rext_table[i];
return nullptr;
}
const AdjustPatch g_tr2w_patches[] = {
{2'500'000, 1},
{2'533'000, 1},
{2'566'000, 1},
{2'866'000, -1},
{3'100'000, 1},
{3'133'000, 1},
};
const u32 g_tr2w_table_size = sizeof(g_tr2w_patches) / sizeof(g_tr2w_patches[0]);
const AdjustPatch *FindTR2WPatch() {
for (u32 i = 0; i < g_tr2w_table_size; i++)
if (g_tr2w_patches[i].freq == C.marikoEmcMaxClock)
return &g_tr2w_patches[i];
return nullptr;
}
const AdjustPatch g_pdex2rw_patches[] = {
{2'166'000, 1},
{2'300'000, 1},
{2'333'000, 1},
{2'433'000, 1},
{2'533'000, 0},
{2'633'000, -1},
{2'666'000, -1},
{2'733'000, -1},
{2'766'000, -1},
{2'800'000, -1},
{2'833'000, -1},
{2'933'000, -1},
{3'066'000, 1},
};
const u32 g_pdex2rw_table_size = sizeof(g_pdex2rw_patches) / sizeof(g_pdex2rw_patches[0]);
const AdjustPatch *FindPdex2rwPatch() {
for (u32 i = 0; i < g_pdex2rw_table_size; i++)
if (g_pdex2rw_patches[i].freq == C.marikoEmcMaxClock)
return &g_pdex2rw_patches[i];
return nullptr;
}
const AdjustPatch g_cke2pden_patches[] = {
{2'133'000, 1},
{2'166'000, 1},
{2'266'000, 1},
{2'300'000, 1},
{2'366'000, 1},
{2'400'000, 1},
{2'500'000, 1},
{2'633'000, 1},
{2'733'000, 1},
{2'833'000, 1},
{2'866'000, 1},
{2'966'000, 1},
{3'066'000, 1},
{3'100'000, 1},
};
const u32 g_cke2pden_table_size = sizeof(g_cke2pden_patches) / sizeof(g_cke2pden_patches[0]);
const AdjustPatch *FindCke2pdenPatch() {
for (u32 i = 0; i < g_cke2pden_table_size; i++)
if (g_cke2pden_patches[i].freq == C.marikoEmcMaxClock)
return &g_cke2pden_patches[i];
}
}
return nullptr;
}

View File

@@ -17,32 +17,15 @@
#pragma once
#include "../mtc_timing_value.hpp"
namespace ams::ldr::oc::pcv::mariko {
namespace ams::ldr::hoc::pcv::mariko {
struct ReplacePatch {
u32 freq;
u32 correct;
u32 rext;
};
extern const ReplacePatch g_rext_table[];
extern const u32 g_rext_table_size;
const ReplacePatch *FindRext();
struct AdjustPatch {
u32 freq;
s32 adjust;
};
extern const AdjustPatch g_tr2w_patches[];
extern const u32 g_tr2w_table_size;
const AdjustPatch *FindTR2WPatch();
extern const AdjustPatch g_pdex2rw_patches[];
extern const u32 g_pdex2rw_table_size;
const AdjustPatch *FindPdex2rwPatch();
extern const AdjustPatch g_cke2pden_patches[];
extern const u32 g_cke2pden_table_size;
const AdjustPatch *FindCke2pdenPatch();
}

View File

@@ -20,24 +20,17 @@
#include "oc_common.hpp"
namespace ams::ldr::oc {
#define MAX(A, B) std::max(A, B)
#define MIN(A, B) std::min(A, B)
#define CEIL(A) std::ceil(A)
#define FLOOR(A) std::floor(A)
#define ROUND(A) std::lround(A)
namespace ams::ldr::hoc {
#define MAX(A, B) std::max(A, B)
#define MIN(A, B) std::min(A, B)
#define CEIL(A) std::ceil(A)
#define FLOOR(A) std::floor(A)
#define ROUND(A) std::lround(A)
#define PACK_U32(high, low) ((static_cast<u32>(high) << 16) | (static_cast<u32>(low) & 0xFFFF))
#define PACK_U32_NIBBLE_HIGH_BYTE_LOW(high, low) ((static_cast<u32>(high & 0xF) << 28) | (static_cast<u32>(low) & 0xFF))
/* Primary timings. */
const std::array<u32, 8> tRCD_values = { 18, 17, 16, 15, 14, 13, 12, 11 };
const std::array<u32, 8> tRP_values = { 18, 17, 16, 15, 14, 13, 12, 11 };
const std::array<u32, 10> tRAS_values = { 42, 36, 34, 32, 30, 28, 26, 24, 22, 20 };
const std::array<double, 7> tRRD_values = { /*10.0,*/ 7.5, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0 }; /* 10.0 is used for <2133mhz; do we care? 8gb uses 7.5 tRRD on >=1331. */
const std::array<u32, 11> tRFC_values = { 140, 130, 120, 110, 100, 90, 80, 70, 60, 50, 40 };
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 };
/* Burst latency, not to be confused with base latency (tWRL). */
const u32 BL = 16;
@@ -75,56 +68,14 @@ namespace ams::ldr::oc {
/* Write recovery time. */
const u32 tWR = 18;
/* TOOD: Fix erista */
namespace pcv::erista {
const double tCK_avg = 1000'000.0 / C.eristaEmcMaxClock;
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 u32 tRC = tRAS + tRPpb;
const u32 tRFCab = tRFCpb * 2;
const double tXSR = (double) (tRFCab + 7.5);
const u32 tFAW = static_cast<u32>(tRRD * 4.0);
const double tRPab = tRPpb + 3;
const u32 tR2P = 12;
const u32 tW2P = (CEIL(WL * 1.7303) * 2) - 5;
const u32 tW2R = CEIL(MAX(WL + (0.010322547033278747 * (C.eristaEmcMaxClock / 1000.0)), (WL * -0.2067922202979121) + FLOOR(((RL_DBI * -0.1331159971685554) + WL) * 3.654131957826108)) - (tWTR / tCK_avg));
const u32 wdv = WL;
const u32 wsv = WL - 2;
const u32 wev = 0xA + (WL - 14);
const double freq_mhz = C.eristaEmcMaxClock / 1000.0;
const u32 quse_width = CEIL(((3.7165006256863955 - freq_mhz) + (-0.002446584377651142 * freq_mhz)) - FLOOR(freq_mhz / -0.9952024303111688));
const u32 quse = CEIL(MIN(RL_DBI + (2.991255208275918 - (quse_width + (-0.00511180626826906 * freq_mhz))), freq_mhz * 0.021333773138874437));
const u32 ibdly = 0x10000000 + FLOOR(MAX(RL_DBI - 1.9999956603408224, quse - 5.9999987787411175) + (-0.0011929079761504341 * freq_mhz));
const u32 obdlyHigh = 3 / FLOOR(MIN(static_cast<double>(2), tCK_avg * (WL - 7)));
const u32 obdlyLow = WL - MIN(static_cast<double>(WL), 12 - (CEIL(-0.0003991 * freq_mhz) * 2));
const u32 obdly = PACK_U32_NIBBLE_HIGH_BYTE_LOW(obdlyHigh, obdlyLow);
const u32 tCKE = CEIL(1.0795 * CEIL(0.0074472 * (C.eristaEmcMaxClock / 1000.0)));
const double tMMRI = tRCD + (tCK_avg * 3);
const double pdex2mrr = tMMRI + 10;
const u32 tWTPDEN = tW2P + 1 + CEIL(tDQSS_max / tCK_avg) + CEIL(tDQS2DQ_max / tCK_avg) + 6;
const u32 tR2W = CEIL(RL_DBI + (tDQSCK_max / tCK_avg) + (BL / 2) - WL + tWPRE + FLOOR(tRPST) + 9.0) - (C.t6_tRTW * 3);
const double pdex_local = (0.011 * freq_mhz) - 1.443;
const u32 pdex2rw = static_cast<u32>(ROUND(pdex_local)) < 22 ? 22 : (static_cast<u32>(ROUND(pdex_local)) > 33 ? 33 : static_cast<u32>(ROUND(pdex_local)));
const double cke2pden = (static_cast<double>((C.eristaEmcMaxClock / 1000.0) * 0.00875) - 0.65);
}
namespace pcv::mariko {
const double tCK_avg = 1000'000.0 / C.marikoEmcMaxClock;
const double ramFreqMhz = C.marikoEmcMaxClock / 1000.0;
const std::array<u32, 8> tRCD_values = { 18, 17, 16, 15, 14, 13, 12, 11 };
const std::array<u32, 8> tRP_values = { 18, 17, 16, 15, 14, 13, 12, 11 };
const std::array<u32, 10> tRAS_values = { 42, 36, 34, 32, 30, 28, 26, 24, 22, 20 };
const std::array<double, 8> tRRD_values = { 10.0, 7.5, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0 };
const std::array<u32, 11> tRFC_values = { 140, 130, 120, 110, 100, 90, 80, 70, 60, 50, 40 };
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 u32 tRCD = tRCD_values[C.t1_tRCD];
const u32 tRPpb = tRP_values[C.t2_tRP];
@@ -132,6 +83,8 @@ namespace ams::ldr::oc {
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;
const u32 tRC = tRAS + tRPpb;
const u32 tRFCab = tRFCpb * 2;
@@ -139,43 +92,81 @@ namespace ams::ldr::oc {
const u32 tFAW = static_cast<u32>(tRRD * 4.0);
const double tRPab = tRPpb + 3;
const u32 tR2P = 12 + ((RL_DBI - 32) / 2);
const u32 tR2P = CEIL((RL_DBI * 0.426) - 2.0);
inline u32 tR2W;
const u32 tRTM = RL + 9 + (tDQSCK_max / tCK_avg) + FLOOR(tRPST) + CEIL(10 / tCK_avg); // Fix?
const u32 tRATM = tRTM + CEIL(10 / tCK_avg) - 12; // Fix?
inline u32 rext;
const u32 rdv = FLOOR(17.02046755653219 + (RL_DBI + (ramFreqMhz * 0.00510056573299173)));
const u32 qpop = rdv - 14;
const u32 quse_width = CEIL(((3.7165006256863955 - ramFreqMhz) + (-0.002446584377651142 * ramFreqMhz)) - FLOOR(ramFreqMhz / -0.9952024303111688));
const u32 quse = CEIL(MIN(RL_DBI + (2.991255208275918 - (quse_width + (-0.00511180626826906 * ramFreqMhz))), ramFreqMhz * 0.021333773138874437));
const u32 einput_duration = CEIL(quse_width + (ramFreqMhz * 0.01) + 4);
const u32 einput = 5 + qpop - einput_duration;
const u32 ibdly = 0x10000000 + FLOOR(MAX(RL_DBI - 1.9999956603408224, quse - 5.9999987787411175) + (-0.0011929079761504341 * ramFreqMhz));
const u32 qrst_duration = FLOOR((ramFreqMhz * 0.001477125119082522) + 4.272302254983803);
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 qsafe = (einput_duration + 3) + MAX(MIN(qrstLow * rdv, qrst_duration + qrst_duration), einput);
const u32 tW2P = (CEIL(WL * 1.7303) * 2) - 5;
const u32 tW2P = (CEIL(WL * 1.7303) * 2) - 5;
inline u32 tWTPDEN;
const u32 tW2R = CEIL(MAX(WL + (0.010322547033278747 * ramFreqMhz), (WL * -0.2067922202979121) + FLOOR(((RL_DBI * -0.1331159971685554) + WL) * 3.654131957826108)) - (tWTR / tCK_avg));
const u32 tWTM = WL + (BL / 2) + 1 + CEIL(7.5 / tCK_avg);
const u32 tWATM = tWTM + CEIL(tWR / tCK_avg);
inline u32 tW2R;
inline u32 pdex2rw;
inline u32 tCLKSTOP;
inline double pdex2mrr;
}
namespace pcv::mariko {
const std::array<u32, 8> tRCD_values = { 18, 17, 16, 15, 14, 13, 12, 11 };
const std::array<u32, 8> tRP_values = { 18, 17, 16, 15, 14, 13, 12, 11 };
const std::array<u32, 10> tRAS_values = { 42, 36, 34, 32, 30, 28, 26, 24, 22, 20 };
const std::array<double, 7> tRRD_values = { /*10.0,*/ 7.5, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0 }; /* 10.0 is used for <2133mhz; do we care? 8gb uses 7.5 tRRD on >=1331. */
const std::array<u32, 11> tRFC_values = { 140, 130, 120, 110, 100, 90, 80, 70, 60, 50, 40 };
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;
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;
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;
const u32 tR2P = CEIL((RL_DBI * 0.426) - 2.0);
const u32 tR2W = FLOOR(FLOOR((5.0 / tCK_avg) + ((FLOOR(48.0 / WL) - 0.478) * 3.0)) / 1.501) + RL_DBI - (C.t6_tRTW * 3) + finetRTW;
const u32 tRTM = FLOOR((10.0 + RL_DBI) + (3.502 / tCK_avg)) + FLOOR(7.489 / tCK_avg);
const u32 tRATM = CEIL((tRTM - 10.0) + (RL_DBI * 0.426));
inline u32 rext;
const u32 rdv = RL_DBI + 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_DBI + ((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_DBI + (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_DBI)), 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;
const u32 wdv = WL;
const u32 wsv = WL - 2;
const u32 wev = 0xA + (WL - 14);
const u32 obdlyHigh = 3 / FLOOR(MIN(static_cast<double>(2), tCK_avg * (WL - 7)));
const u32 obdlyLow = WL - MIN(static_cast<double>(WL), 12 - (CEIL(-0.0003991 * ramFreqMhz) * 2));
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 pdex2rw;
inline u32 cke2pden;
const u32 pdex2rw = CEIL((CEIL(12.335 - tCK_avg) + (7.430 / tCK_avg) - CEIL(tCK_avg * 11.361)));
const u32 tCKE = CEIL(1.0795 * CEIL(0.0074472 * ramFreqMhz));
const u32 tCLKSTOP = FLOOR(MIN(8.488 / tCK_avg, 23.0)) + 8.0;
const double tMMRI = tRCD + (tCK_avg * 3);
const double pdex2mrr = tMMRI + 10; /* Do this properly? */

View File

@@ -52,7 +52,7 @@ namespace ams::ldr {
R_DEFINE_ERROR_RESULT(SafetyCheckFailure, 1015);
}
namespace ams::ldr::oc {
namespace ams::ldr::hoc {
template<typename Pointer>
struct PatcherEntry {
using patternFn = bool(*)(Pointer* ptr);

View File

@@ -65,7 +65,7 @@ void saveExec(const char* file_loc, const void* buf, size_t size) {
}
Result Test_PcvDvfsTable() {
using namespace ams::ldr::oc::pcv;
using namespace ams::ldr::hoc::pcv;
assert(GetDvfsTableEntryCount((cvb_entry_t *)(&mariko::CpuCvbTableDefault)) == 18);
assert(GetDvfsTableEntryCount((cvb_entry_t *)(&erista::CpuCvbTableDefault)) == 16);
@@ -76,19 +76,19 @@ Result Test_PcvDvfsTable() {
cvb_entry_t last_mariko_cpu_cvb_entry_default = { 1963500, { 1675751, -38635, 27 }, { 1120000 } };
assert(memcmp(GetDvfsTableLastEntry((cvb_entry_t *)(&mariko::CpuCvbTableDefault)), (void *)&last_mariko_cpu_cvb_entry_default, sizeof(last_mariko_cpu_cvb_entry_default)) == 0);
assert(GetDvfsTableLastEntry((cvb_entry_t *)(&erista::GpuCvbTableDefault))->freq == 921600);
assert(GetDvfsTableEntryCount((cvb_entry_t *)(&ams::ldr::oc::C.marikoCpuDvfsTableSLT)) == 25);
assert(GetDvfsTableEntryCount((cvb_entry_t *)(&ams::ldr::hoc::C.marikoCpuDvfsTableSLT)) == 25);
// Customized table default
assert(GetDvfsTableEntryCount((cvb_entry_t *)(&ams::ldr::oc::C.eristaCpuDvfsTable)) == 19);
assert(GetDvfsTableEntryCount((cvb_entry_t *)(&ams::ldr::oc::C.marikoCpuDvfsTable)) == 21);
assert(GetDvfsTableEntryCount((cvb_entry_t *)(&ams::ldr::oc::C.marikoCpuDvfsTableSLT)) == 22);
assert(GetDvfsTableEntryCount((cvb_entry_t *)(&ams::ldr::hoc::C.eristaCpuDvfsTable)) == 19);
assert(GetDvfsTableEntryCount((cvb_entry_t *)(&ams::ldr::hoc::C.marikoCpuDvfsTable)) == 21);
assert(GetDvfsTableEntryCount((cvb_entry_t *)(&ams::ldr::hoc::C.marikoCpuDvfsTableSLT)) == 22);
assert(GetDvfsTableEntryCount((cvb_entry_t *)(&ams::ldr::oc::C.eristaGpuDvfsTable)) == 12);
assert(GetDvfsTableEntryCount((cvb_entry_t *)(&ams::ldr::oc::C.marikoGpuDvfsTable)) == 17);
assert(GetDvfsTableEntryCount((cvb_entry_t *)(&ams::ldr::oc::C.marikoGpuDvfsTableSLT)) == 17);
assert(GetDvfsTableEntryCount((cvb_entry_t *)(&ams::ldr::oc::C.marikoGpuDvfsTableHiOPT)) == 17);
assert(GetDvfsTableEntryCount((cvb_entry_t *)(&ams::ldr::hoc::C.eristaGpuDvfsTable)) == 12);
assert(GetDvfsTableEntryCount((cvb_entry_t *)(&ams::ldr::hoc::C.marikoGpuDvfsTable)) == 17);
assert(GetDvfsTableEntryCount((cvb_entry_t *)(&ams::ldr::hoc::C.marikoGpuDvfsTableSLT)) == 17);
assert(GetDvfsTableEntryCount((cvb_entry_t *)(&ams::ldr::hoc::C.marikoGpuDvfsTableHiOPT)) == 17);
constexpr size_t limit = ams::ldr::oc::pcv::DvfsTableEntryLimit;
constexpr size_t limit = ams::ldr::hoc::pcv::DvfsTableEntryLimit;
cvb_entry_t customized_table[limit] = {};
for (size_t i = 0; i < limit; i++) {
assert(GetDvfsTableEntryCount(customized_table) == i);
@@ -156,14 +156,14 @@ int main(int argc, char** argv) {
size_t exec_path_patched_len = exec_path_len + std::max(strlen(mariko_ext), strlen(erista_ext)) + 1;
if (exe_opt == EXE_PCV) {
ams::ldr::oc::pcv::SafetyCheck();
ams::ldr::hoc::pcv::SafetyCheck();
{
void* erista_buf = malloc(file_size);
std::memcpy(erista_buf, file_buffer, file_size);
printf("Patching %s for Erista...\n", pcv_opt);
ams::ldr::oc::pcv::erista::Patch(reinterpret_cast<uintptr_t>(erista_buf), file_size);
ams::ldr::hoc::pcv::erista::Patch(reinterpret_cast<uintptr_t>(erista_buf), file_size);
if (save_patched) {
char* exec_path_erista = reinterpret_cast<char *>(malloc(exec_path_patched_len));
strncpy(exec_path_erista, exec_path, exec_path_patched_len);
@@ -179,7 +179,7 @@ int main(int argc, char** argv) {
std::memcpy(mariko_buf, file_buffer, file_size);
printf("Patching %s for Mariko...\n", pcv_opt);
ams::ldr::oc::pcv::mariko::Patch(reinterpret_cast<uintptr_t>(mariko_buf), file_size);
ams::ldr::hoc::pcv::mariko::Patch(reinterpret_cast<uintptr_t>(mariko_buf), file_size);
if (save_patched) {
char* exec_path_mariko = reinterpret_cast<char *>(malloc(exec_path_patched_len));
strncpy(exec_path_mariko, exec_path, exec_path_patched_len);
@@ -196,7 +196,7 @@ int main(int argc, char** argv) {
std::memcpy(mariko_buf, file_buffer, file_size);
printf("Patching %s (Mariko Only)...\n", ptm_opt);
ams::ldr::oc::ptm::Patch(reinterpret_cast<uintptr_t>(mariko_buf), file_size);
ams::ldr::hoc::ptm::Patch(reinterpret_cast<uintptr_t>(mariko_buf), file_size);
if (save_patched) {
char* exec_path_mariko = reinterpret_cast<char *>(malloc(exec_path_patched_len));
strncpy(exec_path_mariko, exec_path, exec_path_patched_len);

View File

@@ -20,7 +20,7 @@
#include "pcv.hpp"
namespace ams::ldr::oc::pcv {
namespace ams::ldr::hoc::pcv {
Result MemFreqPllmLimit(u32* ptr) {
clk_pll_param* entry = reinterpret_cast<clk_pll_param *>(ptr);
@@ -138,19 +138,20 @@ void SafetyCheck() {
break;
}
using namespace ams::ldr::hoc::pcv;
sValidator validators[] = {
{ C.eristaCpuBoostClock, 1020'000, 2295'000, true },
{ C.marikoCpuBoostClock, 1020'000, 2703'000, true },
{ C.commonEmcMemVolt, 912'500, 1350'000 }, // Official burst vmax for the RAMs is 1500mV
{ C.eristaCpuMaxVolt, 1000, 1257 },
{ C.eristaEmcMaxClock, 1600'000, 2600'000 },
{ C.marikoCpuMaxVolt, 1000, 1235 },
{ C.marikoEmcMaxClock, 1600'000, 3500'000 },
{ C.marikoEmcVddqVolt, 250'000, 700'000 },
{ eristaCpuDvfsMaxFreq, 1785'000, 2295'000 },
{ marikoCpuDvfsMaxFreq, 1785'000, 2703'000 },
{ eristaGpuDvfsMaxFreq, 768'000, 1152'000 },
{ marikoGpuDvfsMaxFreq, 768'000, 1536'000 },
{ C.commonEmcMemVolt, 912'500, 1350'000 }, // Official burst vmax for the RAMs is 1500mV
{ C.eristaCpuMaxVolt, 1000, 1257 },
{ GET_MAX_OF_ARR(erista::maxClocks), 1600'000, 2600'000 },
{ C.marikoCpuMaxVolt, 1000, 1235 },
{ C.marikoEmcMaxClock, 1600'000, 3500'000 },
{ C.marikoEmcVddqVolt, 250'000, 700'000 },
{ eristaCpuDvfsMaxFreq, 1785'000, 2295'000 },
{ marikoCpuDvfsMaxFreq, 1785'000, 2703'000 },
{ eristaGpuDvfsMaxFreq, 768'000, 1152'000 },
{ marikoGpuDvfsMaxFreq, 768'000, 1536'000 },
};
for (auto& i : validators) {

View File

@@ -23,7 +23,7 @@
#include "../oc_common.hpp"
#include "pcv_common.hpp"
namespace ams::ldr::oc::pcv {
namespace ams::ldr::hoc::pcv {
namespace mariko {
constexpr cvb_entry_t CpuCvbTableDefault[] = {
@@ -178,6 +178,9 @@ namespace ams::ldr::oc::pcv {
}
namespace erista {
const u32 maxClocks[] = { C.eristaEmcMaxClock2, C.eristaEmcMaxClock1, C.eristaEmcMaxClock, };
#define GET_MAX_OF_ARR(ARR) (*std::max_element(ARR, ARR + std::size(ARR)))
constexpr cvb_entry_t CpuCvbTableDefault[] = {
// CPU_PLL_CVB_TABLE_ODN
{ 204000, {721094}, { } },

View File

@@ -18,7 +18,7 @@
#pragma once
namespace ams::ldr::oc::pcv {
namespace ams::ldr::hoc::pcv {
typedef struct cvb_coefficients {
s32 c0 = 0;

View File

@@ -20,8 +20,9 @@
#include "pcv.hpp"
#include "../mtc_timing_value.hpp"
#include "../erista/calculate_timings_erista.hpp"
namespace ams::ldr::oc::pcv::erista {
namespace ams::ldr::hoc::pcv::erista {
Result CpuVoltDvfs(u32 *ptr) {
if (MatchesPattern(ptr, cpuVoltDvfsPattern, cpuVoltDvfsOffsets)) {
@@ -180,325 +181,19 @@ namespace ams::ldr::oc::pcv::erista {
R_SUCCEED();
}
// void MemMtcTableAutoAdjustBaseLatency(EristaMtcTable *table) {
// using namespace pcv::erista;
/* #define WRITE_PARAM_ALL_REG(TABLE, PARAM, VALUE) \
TABLE->burst_regs.PARAM = VALUE; \
TABLE->shadow_regs_ca_train.PARAM = VALUE; \
TABLE->shadow_regs_quse_train.PARAM = VALUE; \
TABLE->shadow_regs_rdwr_train.PARAM = VALUE;
*/
// #define GET_CYCLE(PARAM) ((u32)((double)(PARAM) / tCK_avg))
/* This condition is insane but it's done in eos. */
/* Need to clean up at some point. */
// u32 rext;
// u32 wext;
// if (C.eristaEmcMaxClock < 3200001) {
// if (C.eristaEmcMaxClock < 2133001) {
// rext = 26;
// wext = 22;
// } else {
// rext = 28;
// wext = 22;
//
// if (2400000 < C.eristaEmcMaxClock) {
// wext = 25;
// }
// }
// } else {
// rext = 30;
// wext = 25;
// }
// u32 refresh_raw = 0xFFFF;
// u32 trefbw = 0;
//
// if (C.t8_tREFI != 6) {
// refresh_raw = static_cast<u32>(std::floor(static_cast<double>(tREFpb_values[C.t8_tREFI]) / tCK_avg)) - 0x40;
// refresh_raw = MIN(refresh_raw, static_cast<u32>(0xFFFF));
// }
//
// trefbw = refresh_raw + 0x40;
// trefbw = MIN(trefbw, static_cast<u32>(0x3FFF));
//
// if (C.hpMode) {
// WRITE_PARAM_ALL_REG(table, emc_cfg, 0x13200000);
// } else {
// WRITE_PARAM_ALL_REG(table, emc_cfg, 0xF3200000);
// }
// WRITE_PARAM_ALL_REG(table, emc_rc, /*0x00000060*/ GET_CYCLE(tRC));
// WRITE_PARAM_ALL_REG(table, emc_rfc, /*0x00000120*/ GET_CYCLE(tRFCab));
// WRITE_PARAM_ALL_REG(table, emc_ras, /*0x00000044*/ GET_CYCLE(tRAS));
// WRITE_PARAM_ALL_REG(table, emc_rp, /*0x0000001D*/ GET_CYCLE(tRPpb));
// WRITE_PARAM_ALL_REG(table, emc_r2w, /*0x0000002A*/ tR2W);
// WRITE_PARAM_ALL_REG(table, emc_w2r, /*0x00000021*/ tW2R);
// WRITE_PARAM_ALL_REG(table, emc_r2p, 0x0000000C);
// WRITE_PARAM_ALL_REG(table, emc_w2p, 0x0000002D);
// WRITE_PARAM_ALL_REG(table, emc_rd_rcd, /*0x0000001D*/ GET_CYCLE(tRCD));
// WRITE_PARAM_ALL_REG(table, emc_wr_rcd, /*0x0000001D*/ GET_CYCLE(tRCD));
// WRITE_PARAM_ALL_REG(table, emc_rrd, /*0x00000010*/ GET_CYCLE(tRRD));
// WRITE_PARAM_ALL_REG(table, emc_rext, 0x00000017);
// WRITE_PARAM_ALL_REG(table, emc_wdv, 0x0000000E);
// WRITE_PARAM_ALL_REG(table, emc_quse, 0x00000024);
// WRITE_PARAM_ALL_REG(table, emc_qrst, 0x0006000C);
// WRITE_PARAM_ALL_REG(table, emc_qsafe, 0x00000034);
// WRITE_PARAM_ALL_REG(table, emc_rdv, 0x0000003C);
// WRITE_PARAM_ALL_REG(table, emc_refresh, /*0x00001820*/ refresh_raw);
// WRITE_PARAM_ALL_REG(table, emc_burst_refresh_num, 0x00000000);
// WRITE_PARAM_ALL_REG(table, emc_pdex2wr, 0x00000010);
// WRITE_PARAM_ALL_REG(table, emc_pdex2rd, 0x00000010);
// WRITE_PARAM_ALL_REG(table, emc_pchg2pden, 0x00000003);
// WRITE_PARAM_ALL_REG(table, emc_act2pden, 0x00000003);
// WRITE_PARAM_ALL_REG(table, emc_ar2pden, 0x00000003);
// WRITE_PARAM_ALL_REG(table, emc_rw2pden, /*0x00000038*/ GET_CYCLE(tRW2PDEN));
// WRITE_PARAM_ALL_REG(table, emc_txsr, /*0x0000012C*/ MIN(GET_CYCLE(tXSR), (u32) 1022));
// WRITE_PARAM_ALL_REG(table, emc_tcke, 0x0000000D);
// WRITE_PARAM_ALL_REG(table, emc_tfaw, /*0x00000040*/ GET_CYCLE(tFAW));
// WRITE_PARAM_ALL_REG(table, emc_trpab, /*0x00000022*/ GET_CYCLE(tRPab));
// WRITE_PARAM_ALL_REG(table, emc_tclkstable, 0x00000004);
// WRITE_PARAM_ALL_REG(table, emc_tclkstop, 0x00000014);
// WRITE_PARAM_ALL_REG(table, emc_trefbw, /* 0x00001860*/ trefbw);
// WRITE_PARAM_ALL_REG(table, emc_tppd, 0x00000004);
// WRITE_PARAM_ALL_REG(table, emc_odt_write, 0x00000000);
// WRITE_PARAM_ALL_REG(table, emc_pdex2mrr, /*0x0000002E*/ GET_CYCLE(pdex2mrr));
// WRITE_PARAM_ALL_REG(table, emc_wext, 0x00000016);
// WRITE_PARAM_ALL_REG(table, emc_rfc_slr, 0x00000000);
// WRITE_PARAM_ALL_REG(table, emc_mrs_wait_cnt2, 0x01900017);
// WRITE_PARAM_ALL_REG(table, emc_mrs_wait_cnt, 0x0640002F);
// // table->emc_mrs = 0x00000000;
// // table->emc_emrs = 0x00000000;
// // table->emc_mrw = 0x00170040;
// WRITE_PARAM_ALL_REG(table, emc_fbio_spare, 0x00000012);
// WRITE_PARAM_ALL_REG(table, emc_fbio_cfg5, 0x9960A00D);
// WRITE_PARAM_ALL_REG(table, emc_pdex2cke, 0x00000002);
// WRITE_PARAM_ALL_REG(table, emc_cke2pden, 0x0000000E);
// // table->emc_emrs2 = 0x00000000;
// // table->emc_mrw2 = 0x0802002D;
// // table->emc_mrw3 = 0x0C0D00C0;
// // table->emc_mrw4 = 0xC0000000;
// WRITE_PARAM_ALL_REG(table, emc_r2r, 0x00000000);
// WRITE_PARAM_ALL_REG(table, emc_einput, 0x00000014);
// WRITE_PARAM_ALL_REG(table, emc_einput_duration, 0x0000001D);
// WRITE_PARAM_ALL_REG(table, emc_puterm_extra, 0x0000001F);
// WRITE_PARAM_ALL_REG(table, emc_tckesr, 0x00000018);
// WRITE_PARAM_ALL_REG(table, emc_tpd, 0x0000000C);
// table->emc_auto_cal_config = 0x201A51D8;
// table->emc_cfg_2 = 0x00110835;
// WRITE_PARAM_ALL_REG(table, emc_cfg_dig_dll, 0x002C03A9);
// WRITE_PARAM_ALL_REG(table, emc_cfg_dig_dll_period, 0x00008000);
// WRITE_PARAM_ALL_REG(table, emc_rdv_mask, 0x0000003E);
// WRITE_PARAM_ALL_REG(table, emc_wdv_mask, 0x0000000E);
// WRITE_PARAM_ALL_REG(table, emc_rdv_early_mask, 0x0000003C);
// WRITE_PARAM_ALL_REG(table, emc_rdv_early, 0x0000003A);
// table->emc_auto_cal_config8 = 0x00770000;
// WRITE_PARAM_ALL_REG(table, emc_zcal_interval, 0x00064000);
// WRITE_PARAM_ALL_REG(table, emc_zcal_wait_cnt, 0x00310640);
// WRITE_PARAM_ALL_REG(table, emc_fdpd_ctrl_dq, 0x8020221F);
// WRITE_PARAM_ALL_REG(table, emc_fdpd_ctrl_cmd, 0x0220F40F);
// // WRITE_PARAM_ALL_REG(table, emc_pmacro_cmd_brick_ctrl_fdpd, 0x00000000);
// // WRITE_PARAM_ALL_REG(table, emc_pmacro_data_brick_ctrl_fdpd, 0x00000000);
// // WRITE_PARAM_ALL_REG(table, emc_pmacro_brick_ctrl_rfu1, 0x1FFF1FFF);
// // WRITE_PARAM_ALL_REG(table, emc_pmacro_brick_ctrl_rfu2, 0x00000000);
// WRITE_PARAM_ALL_REG(table, emc_tr_timing_0, 0x01186190);
// // WRITE_PARAM_ALL_REG(table, emc_tr_ctrl_1, 0x00000000);
// WRITE_PARAM_ALL_REG(table, emc_tr_rdv, 0x0000003C);
// table->emc_sel_dpd_ctrl = 0x00040000;
// WRITE_PARAM_ALL_REG(table, emc_pre_refresh_req_cnt, /*0x00000608*/ (u32) (refresh_raw / 4));
// WRITE_PARAM_ALL_REG(table, emc_dyn_self_ref_control, 0x8000308C);
// WRITE_PARAM_ALL_REG(table, emc_txsrdll, /*0x0000012C*/ MIN(GET_CYCLE(tXSR), (u32) 1022));
// WRITE_PARAM_ALL_REG(table, emc_tr_qpop, 0x0000002C);
// WRITE_PARAM_ALL_REG(table, emc_tr_rdv_mask, 0x0000003E);
// WRITE_PARAM_ALL_REG(table, emc_tr_qsafe, 0x00000034);
// WRITE_PARAM_ALL_REG(table, emc_tr_qrst, 0x0006000C);
// table->emc_auto_cal_config2 = 0x05500000;
// table->emc_auto_cal_config3 = 0x00770000;
// // WRITE_PARAM_ALL_REG(table, emc_tr_dvfs, 0x00000000);
// WRITE_PARAM_ALL_REG(table, emc_auto_cal_channel, 0xC1E0030A);
// WRITE_PARAM_ALL_REG(table, emc_ibdly, 0x1000001C);
// WRITE_PARAM_ALL_REG(table, emc_obdly, 0x10000002);
// WRITE_PARAM_ALL_REG(table, emc_txdsrvttgen, 0x00000000);
// WRITE_PARAM_ALL_REG(table, emc_we_duration, 0x0000000D);
// WRITE_PARAM_ALL_REG(table, emc_ws_duration, 0x00000008);
// WRITE_PARAM_ALL_REG(table, emc_wev, 0x0000000A);
// WRITE_PARAM_ALL_REG(table, emc_wsv, 0x0000000C);
// WRITE_PARAM_ALL_REG(table, emc_cfg_3, 0x00000040);
// // WRITE_PARAM_ALL_REG(table, emc_mrw6, 0x08037171);
// // WRITE_PARAM_ALL_REG(table, emc_mrw7, 0x48037171);
// // WRITE_PARAM_ALL_REG(table, emc_mrw8, 0x080B6666);
// // table->emc_mrw9 = 0x0C0E7272;
// // table->emc_mrw10 = 0x880C4848;
// // table->emc_mrw11 = 0x480C4848; /* Check them maybe */
// // table->emc_mrw12 = 0x880E1718;
// // table->emc_mrw13 = 0x480E1814;
// // WRITE_PARAM_ALL_REG(table, emc_mrw14, 0x08161414);
// // WRITE_PARAM_ALL_REG(table, emc_mrw15, 0x48161414);
// // table->emc_fdpd_ctrl_cmd_no_ramp = 0x00000001;
// WRITE_PARAM_ALL_REG(table, emc_wdv_chk, 0x00000006);
// // WRITE_PARAM_ALL_REG(table, emc_cfg_pipe_2, 0x00000000);
// // WRITE_PARAM_ALL_REG(table, emc_cfg_pipe_1, 0x00000000);
// // WRITE_PARAM_ALL_REG(table, emc_cfg_pipe, 0x00000000);
// WRITE_PARAM_ALL_REG(table, emc_qpop, 0x0000002C);
// WRITE_PARAM_ALL_REG(table, emc_quse_width, 0x00000009);
// WRITE_PARAM_ALL_REG(table, emc_puterm_width, 0x0000000E);
// table->emc_auto_cal_config7 = 0x00770000;
// // WRITE_PARAM_ALL_REG(table, emc_refctrl2, 0x00000000);
// WRITE_PARAM_ALL_REG(table, emc_fbio_cfg7, 0x00003BFF);
// WRITE_PARAM_ALL_REG(table, emc_rfcpb, /*0x00000090*/ GET_CYCLE(tRFCpb));
// // WRITE_PARAM_ALL_REG(table, emc_dqs_brlshft_0, 0x00000000); /* brlshft may or may not be important, I don't think it matters but who knows. */
// // WRITE_PARAM_ALL_REG(table, emc_dqs_brlshft_1, 0x00000000);
// table->emc_auto_cal_config4 = 0x00770000;
// table->emc_auto_cal_config5 = 0x00770000;
// WRITE_PARAM_ALL_REG(table, emc_ccdmw, 0x00000020);
// table->emc_auto_cal_config6 = 0x00770000;
// WRITE_PARAM_ALL_REG(table, emc_dll_cfg_0, 0x1F13612F);
// WRITE_PARAM_ALL_REG(table, emc_dll_cfg_1, 0x00000014);
// WRITE_PARAM_ALL_REG(table, emc_config_sample_delay, 0x00000020);
// // WRITE_PARAM_ALL_REG(table, emc_pmacro_tx_pwrd_0, 0x10000000);
// // WRITE_PARAM_ALL_REG(table, emc_pmacro_tx_pwrd_1, 0x08000000);
// // WRITE_PARAM_ALL_REG(table, emc_pmacro_tx_pwrd_2, 0x08000000);
// // WRITE_PARAM_ALL_REG(table, emc_pmacro_tx_pwrd_3, 0x00000000);
// // WRITE_PARAM_ALL_REG(table, emc_pmacro_tx_pwrd_4, 0x00000000);
// // WRITE_PARAM_ALL_REG(table, emc_pmacro_tx_pwrd_5, 0x00001000);
// // WRITE_PARAM_ALL_REG(table, emc_pmacro_ddll_bypass, 0xEFFF2210);
// // WRITE_PARAM_ALL_REG(table, emc_pmacro_ddll_pwrd_0, 0x00000000);
// // WRITE_PARAM_ALL_REG(table, emc_pmacro_ddll_pwrd_1, 0x00000000);
// // WRITE_PARAM_ALL_REG(table, emc_pmacro_ddll_pwrd_2, 0xDCDCDCDC);
// // WRITE_PARAM_ALL_REG(table, emc_pmacro_cmd_ctrl_0, 0x0A0A0A0A);
// // WRITE_PARAM_ALL_REG(table, emc_pmacro_cmd_ctrl_1, 0x0A0A0A0A);
// // WRITE_PARAM_ALL_REG(table, emc_pmacro_cmd_ctrl_2, 0x000A0A0A);
// // table->trim_regs.emc_pmacro_ib_vref_dq_0 = 0x15171414;
// // table->trim_regs.emc_pmacro_ib_vref_dq_1 = 0x15131513;
// // table->trim_regs.emc_pmacro_ib_vref_dqs_0 = 0x11111111;
// // table->trim_regs.emc_pmacro_ib_vref_dqs_1 = 0x11111111;
// // WRITE_PARAM_ALL_REG(table, emc_pmacro_ddll_long_cmd_0, 0x000C000C);
// // WRITE_PARAM_ALL_REG(table, emc_pmacro_ddll_long_cmd_1, 0x000B000B);
// // WRITE_PARAM_ALL_REG(table, emc_pmacro_ddll_long_cmd_2, 0x000A000A);
// // WRITE_PARAM_ALL_REG(table, emc_pmacro_ddll_long_cmd_3, 0x000C000C);
// // WRITE_PARAM_ALL_REG(table, emc_pmacro_ddll_long_cmd_4, 0x0000000C);
// // WRITE_PARAM_ALL_REG(table, emc_pmacro_ddll_short_cmd_0, 0x00000000);
// // WRITE_PARAM_ALL_REG(table, emc_pmacro_ddll_short_cmd_1, 0x00000000);
// // WRITE_PARAM_ALL_REG(table, emc_pmacro_ddll_short_cmd_2, 0x00000000);
// // WRITE_PARAM_ALL_REG(table, emc_pmacro_vttgen_ctrl_0, 0x00030808);
// // WRITE_PARAM_ALL_REG(table, emc_pmacro_vttgen_ctrl_1, 0x00015C00);
// // WRITE_PARAM_ALL_REG(table, emc_pmacro_bg_bias_ctrl_0, 0x00000034);
// // WRITE_PARAM_ALL_REG(table, emc_pmacro_pad_cfg_ctrl, 0x00020000);
// // WRITE_PARAM_ALL_REG(table, emc_pmacro_zctrl, 0x00000550);
// // WRITE_PARAM_ALL_REG(table, emc_pmacro_cmd_pad_rx_ctrl, 0x00000000);
// // WRITE_PARAM_ALL_REG(table, emc_pmacro_data_pad_rx_ctrl, 0x00000033);
// // WRITE_PARAM_ALL_REG(table, emc_pmacro_cmd_rx_term_mode, 0x00003000);
// // WRITE_PARAM_ALL_REG(table, emc_pmacro_data_rx_term_mode, 0x00000011);
// // WRITE_PARAM_ALL_REG(table, emc_pmacro_cmd_pad_tx_ctrl, 0x02000000);
// // WRITE_PARAM_ALL_REG(table, emc_pmacro_data_pad_tx_ctrl, 0x02000101);
// // WRITE_PARAM_ALL_REG(table, emc_pmacro_common_pad_tx_ctrl, 0x00000007);
// // WRITE_PARAM_ALL_REG(table, emc_pmacro_autocal_cfg_common, 0x0000080D);
// // WRITE_PARAM_ALL_REG(table, emc_pmacro_vttgen_ctrl_2, 0x00102020);
// // WRITE_PARAM_ALL_REG(table, emc_pmacro_ib_rxrt, 0x00000055);
// WRITE_PARAM_ALL_REG(table, emc_training_ctrl, 0x00009080);
// WRITE_PARAM_ALL_REG(table, emc_training_quse_cors_ctrl, 0x01124000);
// WRITE_PARAM_ALL_REG(table, emc_training_quse_fine_ctrl, 0x01125B6A);
// WRITE_PARAM_ALL_REG(table, emc_training_quse_ctrl_misc, 0x0F081000);
// WRITE_PARAM_ALL_REG(table, emc_training_write_fine_ctrl, 0x1114FC00);
// WRITE_PARAM_ALL_REG(table, emc_training_write_ctrl_misc, 0x07004300);
// WRITE_PARAM_ALL_REG(table, emc_training_write_vref_ctrl, 0x00103200);
// WRITE_PARAM_ALL_REG(table, emc_training_read_fine_ctrl, 0x1110FC00);
// WRITE_PARAM_ALL_REG(table, emc_training_read_ctrl_misc, 0x0F085300);
// WRITE_PARAM_ALL_REG(table, emc_training_read_vref_ctrl, 0x00105800);
// WRITE_PARAM_ALL_REG(table, emc_training_ca_fine_ctrl, 0x0513801F);
// WRITE_PARAM_ALL_REG(table, emc_training_ca_ctrl_misc, 0x1F101100);
// WRITE_PARAM_ALL_REG(table, emc_training_ca_ctrl_misc1, 0x00000014);
// WRITE_PARAM_ALL_REG(table, emc_training_ca_vref_ctrl, 0x00103200);
// WRITE_PARAM_ALL_REG(table, emc_training_settle, 0x07070404);
// // WRITE_PARAM_ALL_REG(table, emc_training_mpc, 0x00000000);
//
// const u32 mc_tRCD = (int) ((double) (GET_CYCLE(tRCD) >> 2) - 2.0);
// const u32 mc_tRPpb = (int) (((double) (GET_CYCLE(tRPpb) >> 2) - 1.0) + 2.0);
// const u32 mc_tRC = (uint) ((double) (GET_CYCLE(tRC) >> 2) - 1.0);
// const u32 mc_tR2W = (uint) (((double) ((uint)tR2W >> 2) - 1.0) + 2.0);
// const u32 mc_tW2R = (uint) (((double) (tW2R >> 2) - 1.0) + 2.0);
// const u32 mc_tRAS = MIN(GET_CYCLE(tRAS), (u32) 0x7F);
// const u32 mc_tRRD = MIN(GET_CYCLE(tRRD), (u32) 31);
//
// table->burst_mc_regs.mc_emem_arb_timing_ras = (int) ((double) (mc_tRAS >> 2) - 2.0);
// table->burst_mc_regs.mc_emem_arb_timing_rcd = (int) ((double) (GET_CYCLE(tRCD) >> 2) - 2.0);
// table->burst_mc_regs.mc_emem_arb_timing_rp = (int) (((double) (GET_CYCLE(tRPpb) >> 2) - 1.0) + 2.0);
// table->burst_mc_regs.mc_emem_arb_timing_rc = (int) ((double) (GET_CYCLE(tRC) >> 2) - 1.0);
// table->burst_mc_regs.mc_emem_arb_timing_faw = (int) ((double) (GET_CYCLE(tFAW) >> 2) - 1.0);
// table->burst_mc_regs.mc_emem_arb_timing_rrd = (int) ((double) (mc_tRRD >> 2) - 1.0);
// table->burst_mc_regs.mc_emem_arb_timing_r2w = (uint) (((double) ((uint) tR2W >> 2) - 1.0) + 2.0);
// table->burst_mc_regs.mc_emem_arb_timing_w2r = (uint) (((double) (tW2R >> 2) - 1.0) + 2.0);
//
// table->burst_mc_regs.mc_emem_arb_da_turns = (table->burst_mc_regs.mc_emem_arb_da_turns & 0x0000FFFF) | (mc_tW2R << 24) | (mc_tR2W << 16);
// table->burst_mc_regs.mc_emem_arb_da_covers = (((uint) (mc_tRCD + 3 + mc_tRPpb) >> 1 & 0xff) << 8) | (((uint) (mc_tRCD + 11 + mc_tRPpb) >> 1 & 0xff) << 0x10) | ((mc_tRC >> 1) & 0xff);
// table->burst_mc_regs.mc_emem_arb_misc0 = (table->burst_mc_regs.mc_emem_arb_misc0 & 0xffe08000U) | ((mc_tRC + 1) & 0xff); /* Missing in l4t dump? TODO */
// table->burst_mc_regs.mc_emem_arb_timing_rfcpb = GET_CYCLE(tRFCpb) >> 2;
//
// table->burst_mc_regs.mc_emem_arb_cfg = 0x0000000c;
// // table->burst_mc_regs.mc_emem_arb_timing_rcd = 0x00000006;
// // table->burst_mc_regs.mc_emem_arb_timing_rp = 0x00000007;
// // table->burst_mc_regs.mc_emem_arb_timing_rc = 0x00000018;
// // table->burst_mc_regs.mc_emem_arb_timing_ras = 0x0000000f;
// // table->burst_mc_regs.mc_emem_arb_timing_faw = 0x0000000f;
// // table->burst_mc_regs.mc_emem_arb_timing_rrd = 0x00000003;
// table->burst_mc_regs.mc_emem_arb_timing_rap2pre = 0x00000003;
// table->burst_mc_regs.mc_emem_arb_timing_wap2pre = 0x0000000d;
// table->burst_mc_regs.mc_emem_arb_timing_r2r = 0x00000007;
// table->burst_mc_regs.mc_emem_arb_timing_w2w = 0x00000007;
// // table->burst_mc_regs.mc_emem_arb_timing_r2w = 0x0000000c;
// // table->burst_mc_regs.mc_emem_arb_timing_w2r = 0x0000000a;
// // table->burst_mc_regs.mc_emem_arb_da_turns = 0x05060303;
// // table->burst_mc_regs.mc_emem_arb_da_covers = 0x000d080c;
// table->burst_mc_regs.mc_emem_arb_ring1_throttle = 0x001f0000;
// // table->burst_mc_regs.mc_emem_arb_timing_rfcpb = 0x00000023;
// table->burst_mc_regs.mc_emem_arb_timing_ccdmw = 0x00000008;
// table->burst_mc_regs.mc_emem_arb_refpb_hp_ctrl = 0x000a1020;
// table->burst_mc_regs.mc_emem_arb_refpb_bank_ctrl = 0x80001028;
// // table->burst_mc_regs.mc_emem_arb_dhyst_ctrl = 0x00000002;
// table->burst_mc_regs.mc_emem_arb_dhyst_timeout_util_0 = 0x0000001a;
// table->burst_mc_regs.mc_emem_arb_dhyst_timeout_util_1 = 0x0000001a;
// table->burst_mc_regs.mc_emem_arb_dhyst_timeout_util_2 = 0x0000001a;
// table->burst_mc_regs.mc_emem_arb_dhyst_timeout_util_3 = 0x0000001a;
// table->burst_mc_regs.mc_emem_arb_dhyst_timeout_util_4 = 0x0000001a;
// table->burst_mc_regs.mc_emem_arb_dhyst_timeout_util_5 = 0x0000001a;
// table->burst_mc_regs.mc_emem_arb_dhyst_timeout_util_6 = 0x0000001a;
// table->burst_mc_regs.mc_emem_arb_dhyst_timeout_util_7 = 0x0000001a;
// table->la_scale_regs.mc_mll_mpcorer_ptsa_rate = 0x000000d0;
// table->la_scale_regs.mc_ftop_ptsa_rate = 0x00000018;
// table->la_scale_regs.mc_ptsa_grant_decrement = 0x00001203;
// table->la_scale_regs.mc_latency_allowance_avpc_0 = 0x00800004;
// table->la_scale_regs.mc_latency_allowance_xusb_1 = 0x00800038;
// table->la_scale_regs.mc_latency_allowance_sdmmcaa_0 = 0x00800005;
// table->la_scale_regs.mc_latency_allowance_sdmmca_0 = 0x00800014;
// table->la_scale_regs.mc_latency_allowance_isp2_0 = 0x0000002c;
// table->la_scale_regs.mc_latency_allowance_isp2_1 = 0x00800080;
// table->la_scale_regs.mc_latency_allowance_vic_0 = 0x0080001d;
// table->la_scale_regs.mc_latency_allowance_nvdec_0 = 0x00800095;
// table->la_scale_regs.mc_latency_allowance_tsec_0 = 0x00800041;
// table->la_scale_regs.mc_latency_allowance_ppcs_1 = 0x00800080;
// table->la_scale_regs.mc_latency_allowance_xusb_0 = 0x0080003d;
// table->la_scale_regs.mc_latency_allowance_ppcs_0 = 0x00340049;
// table->la_scale_regs.mc_latency_allowance_gpu2_0 = 0x00800019;
// table->la_scale_regs.mc_latency_allowance_hc_1 = 0x00000080;
// table->la_scale_regs.mc_latency_allowance_sdmmc_0 = 0x00800090;
// table->la_scale_regs.mc_latency_allowance_mpcore_0 = 0x00800004;
// table->la_scale_regs.mc_latency_allowance_vi2_0 = 0x00000080;
// table->la_scale_regs.mc_latency_allowance_hc_0 = 0x00080016;
// table->la_scale_regs.mc_latency_allowance_gpu_0 = 0x00800019;
// table->la_scale_regs.mc_latency_allowance_sdmmcab_0 = 0x00800005;
// table->la_scale_regs.mc_latency_allowance_nvenc_0 = 0x00800018;
// table->dram_timings.t_rp = tRFCpb;
// table->dram_timings.t_rfc = tRFCab;
// }
/* These timings are slightly off from eos, I am not sure why but I am going to figure it out at some point. */
/* Note: This does not have proper timings, so base latency adjustment will not work. */
/* However, it may still achieve a slightly higher frequency, but not as much as it could be. */
/* I'm certainly not insane enough to attempt this pain again, so this will have to do *for now*. */
void MemMtcTableAutoAdjust(EristaMtcTable *table) {
const double tCK_avg = 1000'000.0 / table->rate_khz;
#define WRITE_PARAM_ALL_REG(TABLE, PARAM, VALUE) \
TABLE->burst_regs.PARAM = VALUE; \
TABLE->shadow_regs_ca_train.PARAM = VALUE; \
TABLE->shadow_regs_rdwr_train.PARAM = VALUE;
#define GET_CYCLE_CEIL(PARAM) u32(CEIL(double(PARAM) / tCK_avg))
/* Ram power down */
/* B31: DRAM_CLKSTOP_PD */
/* B30: DRAM_CLKSTOP_SR */
@@ -515,9 +210,19 @@ namespace ams::ldr::oc::pcv::erista {
refresh_raw = MIN(refresh_raw, static_cast<u32>(0xFFFF));
}
if (table->rate_khz > 3200000) {
rext = 30;
} else if (table->rate_khz >= 2133001) {
rext = 28;
} else {
rext = 26;
}
u32 trefbw = refresh_raw + 0x40;
trefbw = MIN(trefbw, static_cast<u32>(0x3FFF));
CalculateTimings(tCK_avg);
WRITE_PARAM_ALL_REG(table, emc_rd_rcd, GET_CYCLE_CEIL(tRCD));
WRITE_PARAM_ALL_REG(table, emc_wr_rcd, GET_CYCLE_CEIL(tRCD));
WRITE_PARAM_ALL_REG(table, emc_rc, MIN(GET_CYCLE_CEIL(tRC), static_cast<u32>(0xB8)));
@@ -531,15 +236,15 @@ namespace ams::ldr::oc::pcv::erista {
WRITE_PARAM_ALL_REG(table, emc_tfaw, GET_CYCLE_CEIL(tFAW));
WRITE_PARAM_ALL_REG(table, emc_trpab, MIN(GET_CYCLE_CEIL(tRPab), static_cast<u32>(0x3F)));
WRITE_PARAM_ALL_REG(table, emc_tckesr, GET_CYCLE_CEIL(tSR));
WRITE_PARAM_ALL_REG(table, emc_tcke, tCKE);
WRITE_PARAM_ALL_REG(table, emc_tcke, GET_CYCLE_CEIL(7.425) + 2);
WRITE_PARAM_ALL_REG(table, emc_tpd, GET_CYCLE_CEIL(tXP));
WRITE_PARAM_ALL_REG(table, emc_tclkstop, GET_CYCLE_CEIL(tXP) + 8);
WRITE_PARAM_ALL_REG(table, emc_tclkstop, tCLKSTOP);
WRITE_PARAM_ALL_REG(table, emc_r2p, tR2P);
WRITE_PARAM_ALL_REG(table, emc_r2w, tR2W);
WRITE_PARAM_ALL_REG(table, emc_w2p, tW2P);
WRITE_PARAM_ALL_REG(table, emc_w2r, tW2R);
WRITE_PARAM_ALL_REG(table, emc_rext, C.eristaEmcMaxClock < 2133001 ? 26 : 28); // rext shouldn't be causing issues?
WRITE_PARAM_ALL_REG(table, emc_wext, (C.eristaEmcMaxClock >= 2533000) ? 0x19 : 0x16);
WRITE_PARAM_ALL_REG(table, emc_rext, rext);
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);
@@ -547,20 +252,46 @@ namespace ams::ldr::oc::pcv::erista {
WRITE_PARAM_ALL_REG(table, emc_dyn_self_ref_control, dyn_self_ref_control);
WRITE_PARAM_ALL_REG(table, emc_pdex2wr, pdex2rw);
WRITE_PARAM_ALL_REG(table, emc_pdex2rd, pdex2rw);
WRITE_PARAM_ALL_REG(table, emc_pchg2pden, GET_CYCLE_CEIL(1.75));
WRITE_PARAM_ALL_REG(table, emc_pchg2pden, GET_CYCLE_CEIL(1.763));
WRITE_PARAM_ALL_REG(table, emc_ar2pden, GET_CYCLE_CEIL(1.75));
WRITE_PARAM_ALL_REG(table, emc_pdex2cke, GET_CYCLE_CEIL(1.05));
WRITE_PARAM_ALL_REG(table, emc_act2pden, GET_CYCLE_CEIL(14.0));
WRITE_PARAM_ALL_REG(table, emc_cke2pden, /* cke2pden */ GET_CYCLE_CEIL(8.5));
(void) cke2pden;
WRITE_PARAM_ALL_REG(table, emc_cke2pden, GET_CYCLE_CEIL(8.499));
WRITE_PARAM_ALL_REG(table, emc_pdex2mrr, GET_CYCLE_CEIL(pdex2mrr));
WRITE_PARAM_ALL_REG(table, emc_rw2pden, tWTPDEN);
/* Accept imperfection or prepare for suffering. */
// WRITE_PARAM_ALL_REG(table, emc_einput, einput);
// WRITE_PARAM_ALL_REG(table, emc_einput_duration, einput_duration);
// WRITE_PARAM_ALL_REG(table, emc_obdly, obdly);
// WRITE_PARAM_ALL_REG(table, emc_ibdly, ibdly);
// WRITE_PARAM_ALL_REG(table, emc_wdv_mask, wdv);
// WRITE_PARAM_ALL_REG(table, emc_quse_width, quse_width);
// WRITE_PARAM_ALL_REG(table, emc_quse, quse);
// WRITE_PARAM_ALL_REG(table, emc_wdv, wdv);
// WRITE_PARAM_ALL_REG(table, emc_wsv, wsv);
// WRITE_PARAM_ALL_REG(table, emc_wev, wev);
// WRITE_PARAM_ALL_REG(table, emc_qrst, qrst);
// WRITE_PARAM_ALL_REG(table, emc_tr_qrst, qrst);
// WRITE_PARAM_ALL_REG(table, emc_qsafe, qsafe);
// WRITE_PARAM_ALL_REG(table, emc_tr_qsafe, qsafe);
// WRITE_PARAM_ALL_REG(table, emc_tr_qpop, qpop);
// WRITE_PARAM_ALL_REG(table, emc_qpop, qpop);
// WRITE_PARAM_ALL_REG(table, emc_rdv, rdv);
// WRITE_PARAM_ALL_REG(table, emc_tr_rdv_mask, rdv + 2);
// WRITE_PARAM_ALL_REG(table, emc_rdv_early, rdv - 2);
// WRITE_PARAM_ALL_REG(table, emc_rdv_early_mask, rdv);
// WRITE_PARAM_ALL_REG(table, emc_rdv_mask, rdv + 2);
// WRITE_PARAM_ALL_REG(table, emc_tr_rdv, rdv);
// ams::ldr::hoc::pcv::mariko::CalculateMrw2();
// table->emc_mrw2 = (table->emc_mrw2 & ~0xFFu) | static_cast<u32>(mrw2);
// table->dram_timings.rl = RL_DBI;
/* This needs some clean up. */
constexpr double MC_ARB_DIV = 4.0;
constexpr u32 MC_ARB_SFA = 2;
table->burst_mc_regs.mc_emem_arb_cfg = C.eristaEmcMaxClock / (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;
@@ -593,54 +324,50 @@ namespace ams::ldr::oc::pcv::erista {
table->burst_mc_regs.mc_emem_arb_misc0 = (table->burst_mc_regs.mc_emem_arb_misc0 & 0xFFE08000) | (table->burst_mc_regs.mc_emem_arb_timing_rc + 1);
table->la_scale_regs.mc_mll_mpcorer_ptsa_rate = 0x115;
u32 mpcorer_ptsa_rate = MAX(static_cast<u32>(227), (table->rate_khz / 1600000) * 208);
table->la_scale_regs.mc_mll_mpcorer_ptsa_rate = mpcorer_ptsa_rate;
if (C.eristaEmcMaxClock >= 2133000) {
table->la_scale_regs.mc_ftop_ptsa_rate = 0x1F;
} else {
table->la_scale_regs.mc_ftop_ptsa_rate = 0x1B;
}
u32 ftop_ptsa_rate = MAX(static_cast<u32>(31), (table->rate_khz / 1600000) * 24);
table->la_scale_regs.mc_ftop_ptsa_rate = ftop_ptsa_rate;
table->la_scale_regs.mc_ptsa_grant_decrement = 0x17ff;
u32 grant_decrement = MAX(static_cast<u32>(6143), (table->rate_khz / 1600000) * 4611);
table->la_scale_regs.mc_ptsa_grant_decrement = grant_decrement;
constexpr u32 MaskHigh = 0xFF00FFFF;
constexpr u32 Mask2 = 0xFFFFFF00;
constexpr u32 Mask3 = 0xFF00FF00;
const u32 allowance1 = static_cast<u32>(0x32000 / (C.eristaEmcMaxClock / 0x3E8)) & 0xFF;
const u32 allowance2 = static_cast<u32>(0x9C40 / (C.eristaEmcMaxClock / 0x3E8)) & 0xFF;
const u32 allowance3 = static_cast<u32>(0xB540 / (C.eristaEmcMaxClock / 0x3E8)) & 0xFF;
const u32 allowance4 = static_cast<u32>(0x9600 / (C.eristaEmcMaxClock / 0x3E8)) & 0xFF;
const u32 allowance5 = static_cast<u32>(0x8980 / (C.eristaEmcMaxClock / 0x3E8)) & 0xFF;
const u32 allowance1 = static_cast<u32>(0x32000 / (table->rate_khz / 0x3E8)) & 0xFF;
const u32 allowance2 = static_cast<u32>(0x9C40 / (table->rate_khz / 0x3E8)) & 0xFF;
const u32 allowance3 = static_cast<u32>(0xB540 / (table->rate_khz / 0x3E8)) & 0xFF;
const u32 allowance4 = static_cast<u32>(0x9600 / (table->rate_khz / 0x3E8)) & 0xFF;
const u32 allowance5 = static_cast<u32>(0x8980 / (table->rate_khz / 0x3E8)) & 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);
table->la_scale_regs.mc_latency_allowance_tsec_0 = (table->la_scale_regs.mc_latency_allowance_tsec_0 & MaskHigh) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_sdmmcaa_0 = (table->la_scale_regs.mc_latency_allowance_sdmmcaa_0 & MaskHigh) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_sdmmcab_0 = (table->la_scale_regs.mc_latency_allowance_sdmmcab_0 & MaskHigh) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_sdmmc_0 = (table->la_scale_regs.mc_latency_allowance_sdmmc_0 & MaskHigh) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_sdmmca_0 = (table->la_scale_regs.mc_latency_allowance_sdmmca_0 & MaskHigh) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_ppcs_1 = (table->la_scale_regs.mc_latency_allowance_ppcs_1 & MaskHigh) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_nvdec_0 = (table->la_scale_regs.mc_latency_allowance_nvdec_0 & MaskHigh) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_mpcore_0 = (table->la_scale_regs.mc_latency_allowance_mpcore_0 & MaskHigh) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_avpc_0 = (table->la_scale_regs.mc_latency_allowance_avpc_0 & MaskHigh) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_vic_0 = allowance3 | (table->la_scale_regs.mc_latency_allowance_vic_0 & Mask3) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_isp2_1 = (table->la_scale_regs.mc_latency_allowance_isp2_1 & Mask3) | (allowance1 << 16) | allowance1;
table->la_scale_regs.mc_latency_allowance_nvenc_0 = allowance4 | (table->la_scale_regs.mc_latency_allowance_nvenc_0 & Mask3) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_hc_0 = (table->la_scale_regs.mc_latency_allowance_hc_0 & Mask2) | allowance5;
table->la_scale_regs.mc_latency_allowance_gpu_0 = allowance2 | (table->la_scale_regs.mc_latency_allowance_gpu_0 & Mask3) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_gpu2_0 = allowance2 | (table->la_scale_regs.mc_latency_allowance_gpu2_0 & Mask3) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_hc_1 = (table->la_scale_regs.mc_latency_allowance_hc_1 & Mask2) | allowance1;
table->la_scale_regs.mc_latency_allowance_vi2_0 = (table->la_scale_regs.mc_latency_allowance_vi2_0 & Mask2) | allowance1;
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);
table->la_scale_regs.mc_latency_allowance_tsec_0 = (table->la_scale_regs.mc_latency_allowance_tsec_0 & MaskHigh) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_sdmmcaa_0 = (table->la_scale_regs.mc_latency_allowance_sdmmcaa_0 & MaskHigh) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_sdmmcab_0 = (table->la_scale_regs.mc_latency_allowance_sdmmcab_0 & MaskHigh) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_sdmmc_0 = (table->la_scale_regs.mc_latency_allowance_sdmmc_0 & MaskHigh) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_sdmmca_0 = (table->la_scale_regs.mc_latency_allowance_sdmmca_0 & MaskHigh) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_ppcs_1 = (table->la_scale_regs.mc_latency_allowance_ppcs_1 & MaskHigh) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_nvdec_0 = (table->la_scale_regs.mc_latency_allowance_nvdec_0 & MaskHigh) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_mpcore_0 = (table->la_scale_regs.mc_latency_allowance_mpcore_0 & MaskHigh) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_avpc_0 = (table->la_scale_regs.mc_latency_allowance_avpc_0 & MaskHigh) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_isp2_1 = allowance1 | (table->la_scale_regs.mc_latency_allowance_isp2_1 & Mask3) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_gpu_0 = allowance2 | (table->la_scale_regs.mc_latency_allowance_gpu_0 & Mask3) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_gpu2_0 = allowance2 | (table->la_scale_regs.mc_latency_allowance_gpu2_0 & Mask3) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_vic_0 = allowance3 | (table->la_scale_regs.mc_latency_allowance_vic_0 & Mask3) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_nvenc_0 = allowance4 | (table->la_scale_regs.mc_latency_allowance_nvenc_0 & Mask3) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_hc_0 = (table->la_scale_regs.mc_latency_allowance_hc_0 & Mask2) | allowance5;
table->la_scale_regs.mc_latency_allowance_hc_1 = (table->la_scale_regs.mc_latency_allowance_hc_1 & Mask2) | allowance1;
table->la_scale_regs.mc_latency_allowance_vi2_0 = (table->la_scale_regs.mc_latency_allowance_vi2_0 & Mask2) | allowance1;
table->dram_timings.t_rp = tRFCpb;
table->dram_timings.t_rfc = tRFCab;
table->dram_timings.rl = RL_DBI;
// WRITE_PARAM_ALL_REG(table, emc_obdly, obdly);
// WRITE_PARAM_ALL_REG(table, emc_ibdly, ibdly);
table->emc_cfg_2 = 0x11083D;
}
table->min_volt = std::min(static_cast<u32>(1050), 900 + C.emcDvbShift * 25);
}
Result MemFreqMtcTable(u32 *ptr) {
u32 khz_list[] = {1600000, 1331200, 1065600, 800000, 665600, 408000, 204000, 102000, 68000, 40800};
@@ -655,25 +382,32 @@ namespace ams::ldr::oc::pcv::erista {
R_UNLESS(table_list[i]->rev == MTC_TABLE_REV, ldr::ResultInvalidMtcTable());
}
if (C.eristaEmcMaxClock <= EmcClkOSLimit)
if (GET_MAX_OF_ARR(maxClocks) <= EmcClkOSLimit) {
R_SKIP();
}
// Make room for new mtc table, discarding useless 40.8 MHz table
// 40800 overwritten by 68000, ..., 1331200 overwritten by 1600000, leaving table_list[0] not overwritten
for (u32 i = khz_list_size - 1; i > 0; i--)
std::memcpy(static_cast<void *>(table_list[i]), static_cast<void *>(table_list[i - 1]), sizeof(EristaMtcTable));
// Make room for new mtc table, discarding useless 40.8, 68000 and 102000 MHz table
// 40800 overwritten by 68000, ..., 1331200 overwritten by 1600000, leaving table_list[0], table_list[1] and table_list[2] not overwritten
for (u32 i = khz_list_size - 1; i > 2; --i) {
std::memcpy(static_cast<void *>(table_list[i]), static_cast<void *>(table_list[i - 3]), sizeof(EristaMtcTable));
}
MemMtcTableAutoAdjust(table_list[0]);
for (u32 i = 0; i < std::size(maxClocks); ++i) {
if (maxClocks[i] > EmcClkOSLimit) {
table_list[i]->rate_khz = maxClocks[i];
MemMtcTableAutoAdjust(table_list[i]);
}
}
PATCH_OFFSET(ptr, C.eristaEmcMaxClock);
R_SUCCEED();
}
Result MemFreqMax(u32 *ptr) {
if (C.eristaEmcMaxClock <= EmcClkOSLimit)
if (GET_MAX_OF_ARR(maxClocks) <= EmcClkOSLimit) {
R_SKIP();
}
PATCH_OFFSET(ptr, C.eristaEmcMaxClock);
PATCH_OFFSET(ptr, GET_MAX_OF_ARR(maxClocks));
R_SUCCEED();
}

View File

@@ -22,7 +22,7 @@
#include "../mtc_timing_value.hpp"
#include "../mariko/calculate_timings.hpp"
namespace ams::ldr::oc::pcv::mariko {
namespace ams::ldr::hoc::pcv::mariko {
u32 GetGpuVminVoltage() {
for (auto e : vminTable) {
@@ -84,18 +84,18 @@ namespace ams::ldr::oc::pcv::mariko {
}
/* C.marikoGpuVmin is zero, auto voltage is applied. */
/* Get vmin depending on speedo and ram clock. */
u32 autoVmin = GetAutoVoltage();
PATCH_OFFSET(ptr, autoVmin);
R_SUCCEED();
}
Result GpuVoltThermals(u32 *ptr) {
u32 vmin = std::memcmp(ptr - 3, gpuVoltThermalPattern, sizeof(gpuVoltThermalPattern));
if (vmin) {
if (std::memcmp(ptr - 3, gpuVoltThermalPattern, sizeof(gpuVoltThermalPattern))) {
R_THROW(ldr::ResultInvalidGpuDvfs());
}
u32 vmin = C.marikoGpuVmin;
/* Automatic voltage. */
if (!C.marikoGpuVmin) {
vmin = GetAutoVoltage();
@@ -105,11 +105,10 @@ namespace ams::ldr::oc::pcv::mariko {
PATCH_OFFSET(ptr + 9, vmin);
} else {
/* Manual voltage. */
PATCH_OFFSET(ptr, C.marikoGpuVmin);
PATCH_OFFSET(ptr + 3, C.marikoGpuVmin);
PATCH_OFFSET(ptr + 6, C.marikoGpuVmin);
PATCH_OFFSET(ptr + 9, C.marikoGpuVmin);
vmin = C.marikoGpuVmin;
PATCH_OFFSET(ptr, vmin);
PATCH_OFFSET(ptr + 3, vmin);
PATCH_OFFSET(ptr + 6, vmin);
PATCH_OFFSET(ptr + 9, vmin);
}
PATCH_OFFSET(ptr + 12, vmin);
@@ -432,9 +431,9 @@ namespace ams::ldr::oc::pcv::mariko {
WRITE_PARAM_ALL_REG(table, emc_tfaw, GET_CYCLE_CEIL(tFAW));
WRITE_PARAM_ALL_REG(table, emc_trpab, MIN(GET_CYCLE_CEIL(tRPab), static_cast<u32>(0x3F)));
WRITE_PARAM_ALL_REG(table, emc_tckesr, GET_CYCLE_CEIL(tSR));
WRITE_PARAM_ALL_REG(table, emc_tcke, tCKE);
WRITE_PARAM_ALL_REG(table, emc_tcke, GET_CYCLE_CEIL(7.425) + 2);
WRITE_PARAM_ALL_REG(table, emc_tpd, GET_CYCLE_CEIL(tXP));
WRITE_PARAM_ALL_REG(table, emc_tclkstop, GET_CYCLE_CEIL(tXP) + 8); // TODO analyse
WRITE_PARAM_ALL_REG(table, emc_tclkstop, tCLKSTOP);
WRITE_PARAM_ALL_REG(table, emc_r2p, tR2P);
WRITE_PARAM_ALL_REG(table, emc_r2w, tR2W);
WRITE_PARAM_ALL_REG(table, emc_trtm, tRTM);
@@ -452,12 +451,11 @@ namespace ams::ldr::oc::pcv::mariko {
WRITE_PARAM_ALL_REG(table, emc_dyn_self_ref_control, dyn_self_ref_control);
WRITE_PARAM_ALL_REG(table, emc_pdex2wr, pdex2rw);
WRITE_PARAM_ALL_REG(table, emc_pdex2rd, pdex2rw);
WRITE_PARAM_ALL_REG(table, emc_pchg2pden, GET_CYCLE_CEIL(1.75));
WRITE_PARAM_ALL_REG(table, emc_pchg2pden, GET_CYCLE_CEIL(1.763));
WRITE_PARAM_ALL_REG(table, emc_ar2pden, GET_CYCLE_CEIL(1.75));
WRITE_PARAM_ALL_REG(table, emc_pdex2cke, GET_CYCLE_CEIL(1.05));
WRITE_PARAM_ALL_REG(table, emc_act2pden, GET_CYCLE_CEIL(14.0));
WRITE_PARAM_ALL_REG(table, emc_cke2pden, /* cke2pden */ GET_CYCLE_CEIL(8.5));
(void) cke2pden;
WRITE_PARAM_ALL_REG(table, emc_cke2pden, GET_CYCLE_CEIL(8.499));
WRITE_PARAM_ALL_REG(table, emc_pdex2mrr, GET_CYCLE_CEIL(pdex2mrr));
WRITE_PARAM_ALL_REG(table, emc_rw2pden, tWTPDEN);
WRITE_PARAM_ALL_REG(table, emc_einput, einput);
@@ -549,25 +547,25 @@ namespace ams::ldr::oc::pcv::mariko {
const u32 allowance4 = static_cast<u32>(0x9600 / (C.marikoEmcMaxClock / 0x3E8)) & 0xFF;
const u32 allowance5 = static_cast<u32>(0x8980 / (C.marikoEmcMaxClock / 0x3E8)) & 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);
table->la_scale_regs.mc_latency_allowance_tsec_0 = (table->la_scale_regs.mc_latency_allowance_tsec_0 & MaskHigh) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_sdmmcaa_0 = (table->la_scale_regs.mc_latency_allowance_sdmmcaa_0 & MaskHigh) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_sdmmcab_0 = (table->la_scale_regs.mc_latency_allowance_sdmmcab_0 & MaskHigh) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_sdmmc_0 = (table->la_scale_regs.mc_latency_allowance_sdmmc_0 & MaskHigh) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_sdmmca_0 = (table->la_scale_regs.mc_latency_allowance_sdmmca_0 & MaskHigh) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_ppcs_1 = (table->la_scale_regs.mc_latency_allowance_ppcs_1 & MaskHigh) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_nvdec_0 = (table->la_scale_regs.mc_latency_allowance_nvdec_0 & MaskHigh) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_mpcore_0 = (table->la_scale_regs.mc_latency_allowance_mpcore_0 & MaskHigh) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_avpc_0 = (table->la_scale_regs.mc_latency_allowance_avpc_0 & MaskHigh) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_vic_0 = allowance3 | (table->la_scale_regs.mc_latency_allowance_vic_0 & Mask3) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_isp2_1 = (table->la_scale_regs.mc_latency_allowance_isp2_1 & Mask3) | (allowance1 << 16) | allowance1;
table->la_scale_regs.mc_latency_allowance_nvenc_0 = allowance4 | (table->la_scale_regs.mc_latency_allowance_nvenc_0 & Mask3) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_hc_0 = (table->la_scale_regs.mc_latency_allowance_hc_0 & Mask2) | allowance5;
table->la_scale_regs.mc_latency_allowance_gpu_0 = allowance2 | (table->la_scale_regs.mc_latency_allowance_gpu_0 & Mask3) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_gpu2_0 = allowance2 | (table->la_scale_regs.mc_latency_allowance_gpu2_0 & Mask3) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_hc_1 = (table->la_scale_regs.mc_latency_allowance_hc_1 & Mask2) | allowance1;
table->la_scale_regs.mc_latency_allowance_vi2_0 = (table->la_scale_regs.mc_latency_allowance_vi2_0 & Mask2) | allowance1;
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);
table->la_scale_regs.mc_latency_allowance_tsec_0 = (table->la_scale_regs.mc_latency_allowance_tsec_0 & MaskHigh) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_sdmmcaa_0 = (table->la_scale_regs.mc_latency_allowance_sdmmcaa_0 & MaskHigh) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_sdmmcab_0 = (table->la_scale_regs.mc_latency_allowance_sdmmcab_0 & MaskHigh) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_sdmmc_0 = (table->la_scale_regs.mc_latency_allowance_sdmmc_0 & MaskHigh) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_sdmmca_0 = (table->la_scale_regs.mc_latency_allowance_sdmmca_0 & MaskHigh) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_ppcs_1 = (table->la_scale_regs.mc_latency_allowance_ppcs_1 & MaskHigh) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_nvdec_0 = (table->la_scale_regs.mc_latency_allowance_nvdec_0 & MaskHigh) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_mpcore_0 = (table->la_scale_regs.mc_latency_allowance_mpcore_0 & MaskHigh) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_avpc_0 = (table->la_scale_regs.mc_latency_allowance_avpc_0 & MaskHigh) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_isp2_1 = allowance1 | (table->la_scale_regs.mc_latency_allowance_isp2_1 & Mask3) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_gpu_0 = allowance2 | (table->la_scale_regs.mc_latency_allowance_gpu_0 & Mask3) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_gpu2_0 = allowance2 | (table->la_scale_regs.mc_latency_allowance_gpu2_0 & Mask3) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_vic_0 = allowance3 | (table->la_scale_regs.mc_latency_allowance_vic_0 & Mask3) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_nvenc_0 = allowance4 | (table->la_scale_regs.mc_latency_allowance_nvenc_0 & Mask3) | (allowance1 << 16);
table->la_scale_regs.mc_latency_allowance_hc_0 = (table->la_scale_regs.mc_latency_allowance_hc_0 & Mask2) | allowance5;
table->la_scale_regs.mc_latency_allowance_hc_1 = (table->la_scale_regs.mc_latency_allowance_hc_1 & Mask2) | allowance1;
table->la_scale_regs.mc_latency_allowance_vi2_0 = (table->la_scale_regs.mc_latency_allowance_vi2_0 & Mask2) | allowance1;
table->dram_timings.t_rp = tRFCpb;
table->dram_timings.t_rfc = tRFCab;

View File

@@ -18,7 +18,7 @@
#include "ptm.hpp"
namespace ams::ldr::oc::ptm {
namespace ams::ldr::hoc::ptm {
Result CpuPtmBoost(perf_conf_entry* entry) {

View File

@@ -20,7 +20,7 @@
#include "../oc_common.hpp"
namespace ams::ldr::oc::ptm {
namespace ams::ldr::hoc::ptm {
typedef struct {
u32 conf_id;

View File

@@ -169,15 +169,4 @@ Result hocClkIpcGetKipData()
{
u32 temp = 0;
return serviceDispatchIn(&g_sysclkSrv, HocClkIpcCmd_GetKipData, temp);
}
Result hocClkIpcUpdateEmcRegs()
{
u32 temp = 0;
return serviceDispatchIn(&g_sysclkSrv, HocClkIpcCmd_UpdateEmcRegs, temp);
}
Result hocClkIpcCalculateGpuVmin()
{
u32 temp = 0;
return serviceDispatchIn(&g_sysclkSrv, HocClkIpcCmd_CalculateGpuVmin, temp);
}

View File

@@ -12,7 +12,7 @@ def image_to_rgba8888_array(image_path, output_path):
# Write as C header file
with open(output_path, 'w') as f:
f.write('// This is a generated automatically generated file, do not edit manually.\n')
f.write('// This is a automatically generated file, do not edit manually.\n')
f.write(f'// {os.path.basename(image_path)} - {width}x{height}\n')
f.write(f'const unsigned int IMG_WIDTH = {width};\n')
f.write(f'const unsigned int IMG_HEIGHT = {height};\n')
@@ -32,7 +32,7 @@ def image_to_rgba8888_array(image_path, output_path):
def main():
parser = argparse.ArgumentParser(
description='PNG -> RGB8888 script'
description='PNG to RGB8888 script'
)
parser.add_argument('input', help='Input image file (e.g. cat.png)')
parser.add_argument(

View File

@@ -0,0 +1,41 @@
/*
MIT License
Copyright (c) 2024 Roy Merkel
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef MEMMEM_IMPL_H
#define MEMMEM_IMPL_H
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
void *memmem_impl(const void *haystack, size_t haystacklen,
const void *needle, size_t needlelen);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -12,9 +12,9 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
/* --------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
@@ -102,7 +102,7 @@ typedef enum
SysClkPartLoad_EMC = 0,
SysClkPartLoad_EMCCpu,
HocClkPartLoad_GPU,
HocClkPartLoad_CPUAvg,
HocClkPartLoad_CPUMax,
HocClkPartLoad_BAT,
HocClkPartLoad_FAN,
SysClkPartLoad_EnumMax
@@ -132,6 +132,21 @@ typedef enum {
GPUUVLevel_EnumMax,
} GPUUndervoltLevel;
enum {
DVFSMode_Disabled,
DVFSMode_Hijack,
// DVFSMode_OfficialService,
// DVFSMode_Hack,
DVFSMode_EnumMax,
};
typedef enum {
GpuSchedulingMode_DoNotOverride = 0,
GpuSchedulingMode_Enabled,
GpuSchedulingMode_Disabled,
GpuSchedulingMode_EnumMax,
} GpuSchedulingMode;
#define SYSCLK_ENUM_VALID(n, v) ((v) < n##_EnumMax)
static inline const char* sysclkFormatModule(SysClkModule module, bool pretty)

View File

@@ -43,10 +43,12 @@ typedef struct
uint32_t voltages[HocClkVoltage_EnumMax];
u16 speedos[HorizonOCSpeedo_EnumMax];
u16 iddq[HorizonOCSpeedo_EnumMax];
GpuSchedulingMode gpuSchedulingMode;
bool isSysDockInstalled;
u8 maxDisplayFreq;
u8 fps;
u8 dramID;
bool isDram8GB;
u8 fps;
} SysClkContext;
typedef struct

View File

@@ -12,9 +12,9 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
/* --------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
@@ -51,20 +51,24 @@ typedef enum {
HocClkConfigValue_LiteTDPLimit,
HocClkConfigValue_EnforceBoardLimit,
HorizonOCConfigValue_BatteryChargeCurrent,
HorizonOCConfigValue_OverwriteRefreshRate,
HorizonOCConfigValue_EnableUnsafeDisplayFreqs,
HocClkConfigValue_FixCpuVoltBug,
HorizonOCConfigValue_DVFSMode,
HorizonOCConfigValue_DVFSOffset,
HorizonOCConfigValue_GPUScheduling,
KipConfigValue_custRev,
KipConfigValue_mtcConf,
// KipConfigValue_mtcConf,
KipConfigValue_hpMode,
KipConfigValue_commonEmcMemVolt,
KipConfigValue_eristaEmcMaxClock,
KipConfigValue_eristaEmcMaxClock1,
KipConfigValue_eristaEmcMaxClock2,
KipConfigValue_marikoEmcMaxClock,
KipConfigValue_marikoEmcVddqVolt,
KipConfigValue_emcDvbShift,
@@ -158,6 +162,9 @@ typedef enum {
KipConfigValue_g_volt_e_1036800,
KipConfigValue_g_volt_e_1075200,
KipConfigValue_t6_tRTW_fine_tune,
KipConfigValue_t7_tWTR_fine_tune,
KipCrc32,
HocClkConfigValue_IsFirstLoad,
SysClkConfigValue_EnumMax,
@@ -208,26 +215,28 @@ static inline const char* sysclkFormatConfigValue(SysClkConfigValue val, bool pr
case HocClkConfigValue_LiteTDPLimit:
return pretty ? "Handheld TDP Limit" : "tdp_limit_l";
case HocClkConfigValue_EnforceBoardLimit:
return pretty ? "Enforce Board Limit" : "enforce_board_limit";
case HorizonOCConfigValue_BatteryChargeCurrent:
return pretty ? "Battery Charge Current" : "bat_charge_current";
case HorizonOCConfigValue_OverwriteRefreshRate:
return pretty ? "Display Refresh Rate Changing" : "drr_changing";
case HocClkConfigValue_FixCpuVoltBug:
return pretty ? "Fix CPU Volt Bug" : "cpu_volt_bugfix";
case HorizonOCConfigValue_EnableUnsafeDisplayFreqs:
return pretty ? "Enable Unsafe Display Frequencies" : "drr_unsafe";
case HorizonOCConfigValue_DVFSMode:
return pretty ? "DVFS Mode" : "dvfs_mode";
case HorizonOCConfigValue_DVFSOffset:
return pretty ? "DVFS Offset" : "dvfs_offset";
case HorizonOCConfigValue_GPUScheduling:
return pretty ? "GPU Scheduling" : "gpu_scheduling";
// KIP config values
case KipConfigValue_custRev:
return pretty ? "Custom Revision" : "kip_cust_rev";
case KipConfigValue_mtcConf:
return pretty ? "MTC Config" : "kip_mtc_conf";
// case KipConfigValue_mtcConf:
// return pretty ? "MTC Config" : "kip_mtc_conf";
case KipConfigValue_hpMode:
return pretty ? "HP Mode" : "kip_hp_mode";
@@ -235,7 +244,11 @@ static inline const char* sysclkFormatConfigValue(SysClkConfigValue val, bool pr
case KipConfigValue_commonEmcMemVolt:
return pretty ? "Common EMC/MEM Voltage" : "common_emc_mem_volt";
case KipConfigValue_eristaEmcMaxClock:
return pretty ? "Erista EMC Max Clock" : "erista_emc_max_clock";
return pretty ? "Erista EMC Max Clock 1" : "erista_emc_max_clock";
case KipConfigValue_eristaEmcMaxClock1:
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_marikoEmcMaxClock:
return pretty ? "Mariko EMC Max Clock" : "mariko_emc_max_clock";
case KipConfigValue_marikoEmcVddqVolt:
@@ -370,6 +383,8 @@ static inline const char* sysclkFormatConfigValue(SysClkConfigValue val, bool pr
case KipConfigValue_g_volt_e_998400: return pretty ? "Erista GPU Volt 998 MHz" : "g_volt_e_998400";
case KipConfigValue_g_volt_e_1036800: return pretty ? "Erista GPU Volt 1036 MHz" : "g_volt_e_1036800";
case KipConfigValue_g_volt_e_1075200: return pretty ? "Erista GPU Volt 1075 MHz" : "g_volt_e_1075200";
case KipConfigValue_t6_tRTW_fine_tune: return pretty ? "t6 - tRTW Fine Tune" : "t6_tRTW_fine_fune";
case KipConfigValue_t7_tWTR_fine_tune: return pretty ? "t7 - tWTR Fine Tune" : "t7_tWTR_fine_tune";
case KipCrc32:
return pretty ? "CRC32" : "crc32";
case HocClkConfigValue_IsFirstLoad:
@@ -394,6 +409,7 @@ static inline uint64_t sysclkDefaultConfigValue(SysClkConfigValue val)
case HorizonOCConfigValue_BatteryChargeCurrent:
case HorizonOCConfigValue_OverwriteRefreshRate:
case HorizonOCConfigValue_EnableUnsafeDisplayFreqs:
case HorizonOCConfigValue_GPUScheduling:
return 0ULL;
case HocClkConfigValue_EristaMaxCpuClock:
return 1785ULL;
@@ -403,9 +419,8 @@ static inline uint64_t sysclkDefaultConfigValue(SysClkConfigValue val)
case HocClkConfigValue_ThermalThrottle:
case HocClkConfigValue_HandheldTDP:
case HocClkConfigValue_EnforceBoardLimit:
case HocClkConfigValue_FixCpuVoltBug:
case HocClkConfigValue_IsFirstLoad:
case HorizonOCConfigValue_DVFSMode:
return 1ULL;
case HocClkConfigValue_ThermalThrottleThreshold:
return 70ULL;
@@ -429,7 +444,7 @@ static inline uint64_t sysclkValidConfigValue(SysClkConfigValue val, uint64_t in
case HocClkConfigValue_LiteTDPLimit:
case SysClkConfigValue_PollingIntervalMs:
return input > 0;
case SysClkConfigValue_TempLogIntervalMs:
case SysClkConfigValue_FreqLogIntervalMs:
case SysClkConfigValue_PowerLogIntervalMs:
@@ -438,18 +453,18 @@ static inline uint64_t sysclkValidConfigValue(SysClkConfigValue val, uint64_t in
case HocClkConfigValue_OverwriteBoostMode:
case HocClkConfigValue_ThermalThrottle:
case HocClkConfigValue_HandheldTDP:
case HocClkConfigValue_EnforceBoardLimit:
case HorizonOCConfigValue_OverwriteRefreshRate:
case HocClkConfigValue_FixCpuVoltBug:
case HorizonOCConfigValue_EnableUnsafeDisplayFreqs:
case HocClkConfigValue_IsFirstLoad:
return (input & 0x1) == input;
case KipConfigValue_custRev:
case KipConfigValue_mtcConf:
// case KipConfigValue_mtcConf:
case KipConfigValue_hpMode:
case KipConfigValue_commonEmcMemVolt:
case KipConfigValue_eristaEmcMaxClock:
case KipConfigValue_eristaEmcMaxClock1:
case KipConfigValue_eristaEmcMaxClock2:
case KipConfigValue_marikoEmcMaxClock:
case KipConfigValue_marikoEmcVddqVolt:
case KipConfigValue_emcDvbShift:
@@ -534,7 +549,12 @@ static inline uint64_t sysclkValidConfigValue(SysClkConfigValue val, uint64_t in
case KipConfigValue_g_volt_e_1075200:
case KipConfigValue_eristaCpuVmin:
case KipConfigValue_eristaCpuUnlock:
case KipConfigValue_t6_tRTW_fine_tune:
case KipConfigValue_t7_tWTR_fine_tune:
case KipCrc32:
case HorizonOCConfigValue_DVFSMode:
case HorizonOCConfigValue_DVFSOffset:
case HorizonOCConfigValue_GPUScheduling:
return true;
case HorizonOCConfigValue_BatteryChargeCurrent:
return ((input >= 1024) && (input <= 3072)) || !input;

View File

@@ -51,8 +51,6 @@ enum SysClkIpcCmd
SysClkIpcCmd_SetReverseNXRTMode = 12,
HocClkIpcCmd_SetKipData = 13,
HocClkIpcCmd_GetKipData = 14,
HocClkIpcCmd_UpdateEmcRegs = 15,
HocClkIpcCmd_CalculateGpuVmin = 16,
};

View File

@@ -169,15 +169,4 @@ Result hocClkIpcGetKipData()
{
u32 temp = 0;
return serviceDispatchIn(&g_sysclkSrv, HocClkIpcCmd_GetKipData, temp);
}
Result hocClkIpcUpdateEmcRegs()
{
u32 temp = 0;
return serviceDispatchIn(&g_sysclkSrv, HocClkIpcCmd_UpdateEmcRegs, temp);
}
Result hocClkIpcCalculateGpuVmin()
{
u32 temp = 0;
return serviceDispatchIn(&g_sysclkSrv, HocClkIpcCmd_CalculateGpuVmin, temp);
}

View File

@@ -42,9 +42,9 @@ static bool g_canChangeRefreshRateDocked = false;
static uint8_t g_lastVActiveSet = 0;
// Refresh rate tables
static const uint8_t g_dockedRefreshRates[] = {40, 45, 50, 55, 60, 70, 72, 75, 80, 90, 95, 100, 110, 120};
static bool g_dockedAllowed[14] = {0};
static bool g_dockedAllowed720p[14] = {0};
static const uint8_t g_dockedRefreshRates[] = {40, 45, 50, 55, 60, 70, 72, 75, 80, 90, 95, 100, 110, 120, 130, 144, 150, 160, 165, 170, 180, 190, 200, 210, 220, 230, 240};
static bool g_dockedAllowed[sizeof(g_dockedRefreshRates) / sizeof(g_dockedRefreshRates[0])] = {0};
static bool g_dockedAllowed720p[sizeof(g_dockedRefreshRates) / sizeof(g_dockedRefreshRates[0])] = {0};
static const DockedTimings g_dockedTimings1080p[] = {
{8, 32, 40, 7, 8, 6, 0, 88080}, // 40Hz

View File

@@ -0,0 +1,83 @@
/*
MIT License
Copyright (c) 2024 Roy Merkel
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "memmem.h"
void *memmem_impl(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen)
{
const unsigned char *cmpp;
const unsigned char *p;
const unsigned char *endp;
const unsigned char *q;
const unsigned char *endq;
unsigned char found;
if(haystack == NULL)
{
return NULL;
}
if(needle == NULL)
{
return (void*)haystack;
}
if(haystacklen == 0)
{
return NULL;
}
if(needlelen == 0)
{
return (void*)haystack;
}
if(needlelen > haystacklen)
{
return NULL;
}
endp = haystack + haystacklen - needlelen;
endq = needle + needlelen;
for(p = haystack; p <= endp; p++)
{
found = 1;
cmpp = p;
for(q = needle; q < endq; q++)
{
if(*cmpp != *q)
{
found = 0;
break;
}
else
{
cmpp++;
}
}
if(found)
{
return (void*)p;
}
}
return NULL;
}

View File

@@ -39,7 +39,7 @@ include ${TOPDIR}/lib/libultrahand/ultrahand.mk
# version control constants
#---------------------------------------------------------------------------------
#TARGET_VERSION := $(shell git describe --dirty --always --tags)
APP_VERSION := 0.34
APP_VERSION := 0.39
TARGET_VERSION := $(APP_VERSION)
#---------------------------------------------------------------------------------

View File

@@ -24,6 +24,7 @@
tsl::elm::ListItem* SpeedoItem = NULL;
tsl::elm::ListItem* IddqItem = NULL;
tsl::elm::ListItem* sysdockStatusItem = NULL;
ImageElement* CatImage = NULL;
HideableCategoryHeader* CatHeader = NULL;
HideableCustomDrawer* CatSpacer = NULL;
@@ -41,17 +42,21 @@ AboutGui::~AboutGui()
void AboutGui::listUI()
{
this->listElement->addItem(
new tsl::elm::CategoryHeader("Speedo/IDDQ")
new tsl::elm::CategoryHeader("Information")
);
SpeedoItem =
new tsl::elm::ListItem("Speedos:");
new tsl::elm::ListItem("Speedo:");
this->listElement->addItem(SpeedoItem);
IddqItem =
new tsl::elm::ListItem("IDDQ:");
this->listElement->addItem(IddqItem);
sysdockStatusItem =
new tsl::elm::ListItem("sys-dock status:");
this->listElement->addItem(sysdockStatusItem);
this->listElement->addItem(
new tsl::elm::CategoryHeader("Credits")
);
@@ -221,4 +226,5 @@ void AboutGui::refresh()
sprintf(strings[1], "%u/%u/%u", this->context->iddq[HorizonOCSpeedo_CPU], this->context->iddq[HorizonOCSpeedo_GPU], this->context->iddq[HorizonOCSpeedo_SOC]);
SpeedoItem->setValue(strings[0]);
IddqItem->setValue(strings[1]);
sysdockStatusItem->setValue(this->context->isSysDockInstalled ? "Installed" : "Not Installed");
}

View File

@@ -275,13 +275,16 @@ void AppProfileGui::addModuleListItemValue(
}
void AppProfileGui::addProfileUI(SysClkProfile profile)
{
{
BaseMenuGui::refresh();
if(!this->context)
return;
Result rc = sysclkIpcGetConfigValues(&configList); // idk why this is needed, probably some refreshing issue
if (R_FAILED(rc)) [[unlikely]] {
FatalGui::openWithResultCode("sysclkIpcGetConfigValues", rc);
return;
}
this->listElement->addItem(new tsl::elm::CategoryHeader(sysclkFormatProfile(profile, true) + std::string(" ") + ult::DIVIDER_SYMBOL + " Reset"));
this->listElement->addItem(new tsl::elm::CategoryHeader(sysclkFormatProfile(profile, true) + std::string(" ") + ult::DIVIDER_SYMBOL + " \ue0e3 Reset"));
this->addModuleListItem(profile, SysClkModule_CPU);
this->addModuleListItem(profile, SysClkModule_GPU);
this->addModuleListItem(profile, SysClkModule_MEM);
@@ -289,9 +292,9 @@ void AppProfileGui::addProfileUI(SysClkProfile profile)
ValueThresholds lcdThresholds(60, 65);
if(!IsHoag() && configList.values[HorizonOCConfigValue_OverwriteRefreshRate]) {
if(profile != SysClkProfile_Docked)
this->addModuleListItemValue(profile, HorizonOCModule_Display, "Display", 40, configList.values[HorizonOCConfigValue_EnableUnsafeDisplayFreqs] ? IsAula() ? 65 : 72 : 60, 1, " Hz", 1, 0, lcdThresholds);
this->addModuleListItemValue(profile, HorizonOCModule_Display, "Display", IsAula() ? 45 : 40, configList.values[HorizonOCConfigValue_EnableUnsafeDisplayFreqs] ? IsAula() ? 65 : 72 : 60, 1, " Hz", 1, 0, lcdThresholds);
else
this->addModuleListItemValue(profile, HorizonOCModule_Display, "Display", 50, 120, 5, " Hz", 1, 0);
this->addModuleListItemValue(profile, HorizonOCModule_Display, "Display", 50, IsAula() ? this->context->isSysDockInstalled ? 120 : 75 : 120, 5, " Hz", 1, 0);
}
#endif
this->addModuleListItemToggle(profile, HorizonOCModule_Governor);

View File

@@ -12,9 +12,9 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
/* --------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
@@ -36,13 +36,13 @@ BaseMenuGui::BaseMenuGui() : tempColors{ tsl::Color(0), tsl::Color(0), tsl::Colo
this->context = nullptr;
this->lastContextUpdate = 0;
this->listElement = nullptr;
// Pre-cache hardware model during initialization
IsAula();
IsMariko();
IsHoag();
// Initialize display strings
memset(displayStrings, 0, sizeof(displayStrings));
}
@@ -55,14 +55,14 @@ BaseMenuGui::~BaseMenuGui() {
void BaseMenuGui::preDraw(tsl::gfx::Renderer* renderer) {
BaseGui::preDraw(renderer);
if(!this->context) [[unlikely]] return;
// All constants pre-calculated and cached
static constexpr const char* const labels[] = {
"App ID", "Profile", "CPU", "GPU", "MEM", "SoC", "Board", "Skin", "Now", "Avg", "BAT", "PMIC", "FAN", "DISP"
};
static constexpr u32 dataPositions[6] = {63-3+3, 200-1, 344-1-3, 200-1, 342-1, 321-1};
static u32 labelWidths[10];
static bool positionsInitialized = false;
@@ -77,29 +77,29 @@ void BaseMenuGui::preDraw(tsl::gfx::Renderer* renderer) {
static u32 maxProfileValueWidth = renderer->getTextDimensions("PD Charger", false, SMALL_TEXT_SIZE).first; // longest word
u32 y = 91;
// === TOP SECTION ===
renderer->drawRoundedRect(14, 70-1, 420, 30+2, 15.0f, renderer->aWithOpacity(tsl::tableBGColor));
// App ID - use pre-formatted string
renderer->drawString(labels[0], false, positions[0], y, SMALL_TEXT_SIZE, tsl::sectionTextColor);
renderer->drawString(displayStrings[0], false, positions[0] + labelWidths[0] + 9, y, SMALL_TEXT_SIZE, tsl::infoTextColor);
// Profile - use pre-formatted string
renderer->drawString(labels[1], false, 423 - maxProfileValueWidth - labelWidths[1] - 9, y, SMALL_TEXT_SIZE, tsl::sectionTextColor);
renderer->drawString(displayStrings[1], false, 423 - maxProfileValueWidth, y, SMALL_TEXT_SIZE, tsl::infoTextColor);
y = 129; // Direct assignment instead of += 38
// === MAIN DATA SECTION ===
renderer->drawRoundedRect(14, 106, 420, 156, 10.0f, renderer->aWithOpacity(tsl::tableBGColor));
// === FREQUENCY SECTION ===
// Labels first (better cache locality)
renderer->drawString(labels[2], false, positions[2], y, SMALL_TEXT_SIZE, tsl::sectionTextColor);
renderer->drawString(labels[3], false, positions[3], y, SMALL_TEXT_SIZE, tsl::sectionTextColor);
renderer->drawString(labels[4], false, positions[4], y, SMALL_TEXT_SIZE, tsl::sectionTextColor);
// Current frequencies - use pre-formatted strings
renderer->drawString(displayStrings[2], false, dataPositions[0], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // CPU
renderer->drawString(displayStrings[3], false, dataPositions[1], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // GPU
@@ -107,7 +107,7 @@ void BaseMenuGui::preDraw(tsl::gfx::Renderer* renderer) {
y = 149; // Direct assignment (129 + 20)
// renderer->drawString(displayStrings[19], false, positions[2], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // CPU Usage
renderer->drawString(displayStrings[19], false, positions[2], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // CPU Usage
renderer->drawString(displayStrings[17], false, positions[3], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // GPU Usage
renderer->drawString(displayStrings[18], false, positions[4], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // RAM Usage
@@ -115,39 +115,39 @@ void BaseMenuGui::preDraw(tsl::gfx::Renderer* renderer) {
renderer->drawString(displayStrings[5], false, dataPositions[0], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // CPU real
renderer->drawString(displayStrings[6], false, dataPositions[1], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // GPU real
renderer->drawString(displayStrings[7], false, dataPositions[2], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // MEM real
y = 169; // Direct assignment (149 + 20)
// === VOLTAGES ===
renderer->drawString(displayStrings[8], false, dataPositions[0], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // CPU voltage
renderer->drawString(displayStrings[9], false, dataPositions[1], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // GPU voltage
renderer->drawStringWithColoredSections(displayStrings[10], false, {""}, dataPositions[5]-16, y, SMALL_TEXT_SIZE, tsl::infoTextColor, tsl::separatorColor);
y = 191; // Direct assignment (169 + 22)
// === TEMPERATURE SECTION ===
// Labels
renderer->drawString(labels[5], false, positions[5], y, SMALL_TEXT_SIZE, tsl::sectionTextColor);
renderer->drawString(labels[6], false, positions[6]-1, y, SMALL_TEXT_SIZE, tsl::sectionTextColor);
renderer->drawString(labels[7], false, positions[7], y, SMALL_TEXT_SIZE, tsl::sectionTextColor);
// Temperatures with color - use pre-computed colors
renderer->drawString(displayStrings[11], false, dataPositions[0], y, SMALL_TEXT_SIZE, tempColors[SysClkThermalSensor_SOC]); // SOC
renderer->drawString(displayStrings[12], false, dataPositions[1], y, SMALL_TEXT_SIZE, tempColors[SysClkThermalSensor_PCB]); // PCB
renderer->drawString(displayStrings[13], false, dataPositions[2], y, SMALL_TEXT_SIZE, tempColors[SysClkThermalSensor_Skin]); // Skin
y = 211; // Direct assignment (191 + 20)
renderer->drawString(displayStrings[14], false, dataPositions[0], y, SMALL_TEXT_SIZE, tsl::infoTextColor);
// Power labels and values
renderer->drawString(labels[8], false, positions[8]-1, y, SMALL_TEXT_SIZE, tsl::sectionTextColor);
renderer->drawString(labels[9], false, positions[9], y, SMALL_TEXT_SIZE, tsl::sectionTextColor);
renderer->drawString(displayStrings[15], false, dataPositions[3], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // Power now
renderer->drawString(displayStrings[16], false, dataPositions[4], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // Power avg
y+=20;
renderer->drawString(labels[10], false, positions[2], y, SMALL_TEXT_SIZE, tsl::sectionTextColor);
@@ -181,9 +181,9 @@ void BaseMenuGui::refresh()
if (armTicksToNs(ticks - this->lastContextUpdate) <= 1000000000UL) [[likely]] {
return; // Early exit for most calls
}
this->lastContextUpdate = ticks;
// Lazy context allocation
if (!this->context) [[unlikely]] {
this->context = new SysClkContext;
@@ -206,30 +206,30 @@ void BaseMenuGui::refresh()
// === FORMAT ALL DISPLAY STRINGS (once per second) ===
// App ID (hex conversion)
sprintf(displayStrings[0], "%016lX", context->applicationId);
// Profile
strcpy(displayStrings[1], sysclkFormatProfile(context->profile, true));
// Current frequencies
u32 hz = context->freqs[SysClkModule_CPU]; // CPU
sprintf(displayStrings[2], "%u.%u MHz", hz / 1000000U, (hz / 100000U) % 10U);
hz = context->freqs[SysClkModule_GPU]; // GPU
sprintf(displayStrings[3], "%u.%u MHz", hz / 1000000U, (hz / 100000U) % 10U);
hz = context->freqs[SysClkModule_MEM]; // MEM
sprintf(displayStrings[4], "%u.%u MHz", hz / 1000000U, (hz / 100000U) % 10U);
// Real frequencies
hz = context->realFreqs[SysClkModule_CPU]; // CPU
sprintf(displayStrings[5], "%u.%u MHz", hz / 1000000U, (hz / 100000U) % 10U);
hz = context->realFreqs[SysClkModule_GPU]; // GPU
sprintf(displayStrings[6], "%u.%u MHz", hz / 1000000U, (hz / 100000U) % 10U);
hz = context->realFreqs[SysClkModule_MEM]; // MEM
sprintf(displayStrings[7], "%u.%u MHz", hz / 1000000U, (hz / 100000U) % 10U);
// Voltages
sprintf(displayStrings[8], "%.1f mV", context->voltages[HocClkVoltage_CPU] / 1000.0);
sprintf(displayStrings[9], "%.1f mV", context->voltages[HocClkVoltage_GPU] / 1000.0);
@@ -243,31 +243,30 @@ void BaseMenuGui::refresh()
//sprintf(displayStrings[10], "%u mV", vddVoltageUv / 1000U);
sprintf(displayStrings[10], "%u.%u%u mV", context->voltages[HocClkVoltage_EMCVDD2] / 1000U, (context->voltages[HocClkVoltage_EMCVDD2] % 1000U) / 100U, context->voltages[HocClkVoltage_EMCVDD2] / 1000U);
}
// Temperatures and pre-compute colors
u32 millis = context->temps[SysClkThermalSensor_SOC]; // SOC
sprintf(displayStrings[11], "%u.%u °C", millis / 1000U, (millis % 1000U) / 100U);
tempColors[SysClkThermalSensor_SOC] = tsl::GradientColor(millis * 0.001f);
millis = context->temps[SysClkThermalSensor_PCB]; // PCB
sprintf(displayStrings[12], "%u.%u °C", millis / 1000U, (millis % 1000U) / 100U);
tempColors[SysClkThermalSensor_PCB] = tsl::GradientColor(millis * 0.001f);
millis = context->temps[SysClkThermalSensor_Skin]; // Skin
sprintf(displayStrings[13], "%u.%u °C", millis / 1000U, (millis % 1000U) / 100U);
tempColors[SysClkThermalSensor_Skin] = tsl::GradientColor(millis * 0.001f);
// SOC voltage (if available)
sprintf(displayStrings[14], "%u mV", context->voltages[HocClkVoltage_SOC] / 1000U);
// Power
sprintf(displayStrings[15], "%d mW", context->power[0]); // Now
sprintf(displayStrings[16], "%d mW", context->power[1]); // Avg
sprintf(displayStrings[17], "%u%%", context->partLoad[HocClkPartLoad_GPU] / 10);
sprintf(displayStrings[18], "%u%%", context->partLoad[SysClkPartLoad_EMC] / 10);
// sprintf(displayStrings[19], "%u", context->partLoad[HocClkPartLoad_CPUAvg]);
sprintf(displayStrings[19], "%u%%", context->partLoad[HocClkPartLoad_CPUMax] / 10);
millis = context->temps[HorizonOCThermalSensor_Battery]; // Battery
sprintf(displayStrings[20], "%u.%u °C", millis / 1000U, (millis % 1000U) / 100U);

View File

@@ -59,7 +59,6 @@ tsl::elm::ListItem* FreqChoiceGui::createFreqListItem(std::uint32_t hz, bool sel
if (selected)
text += " \uE14B";
// NEW: Right-side label
std::string rightText = "";
auto it = labels.find(hz);
if (it != labels.end())
@@ -156,16 +155,26 @@ void FreqChoiceGui::listUI()
if (IsMariko())
{
unsafe_cpu = 1964;
unsafe_gpu = 1076;
danger_cpu = 2398;
unsafe_cpu = this->configList->values[KipConfigValue_marikoCpuUVHigh] ? 2296 : 1964;
if(this->configList->values[KipConfigValue_marikoGpuUV] == 0) {
unsafe_gpu = 1076;
} else if (this->configList->values[KipConfigValue_marikoGpuUV] == 1) {
unsafe_gpu = 1153;
} else {
unsafe_gpu = 1229;
}
danger_cpu = this->configList->values[KipConfigValue_marikoCpuUVHigh] ? 2500 : 2398;
danger_gpu = 1306;
}
else
{
unsafe_cpu = 1786;
unsafe_gpu = 922;
danger_cpu = 2092;
unsafe_cpu = this->configList->values[KipConfigValue_eristaCpuUV] ? 1964 : 1786;
if(this->configList->values[KipConfigValue_eristaGpuUV] == 0) {
unsafe_gpu = 922;
} else {
unsafe_gpu = 961;
}
danger_cpu = this->configList->values[KipConfigValue_eristaCpuUV] ? 2194 : 1964;
danger_gpu = 999;
}

View File

@@ -285,14 +285,14 @@ void GlobalOverrideGui::listUI()
}
this->listElement->addItem(new tsl::elm::CategoryHeader(
"Temporary Overrides " + ult::DIVIDER_SYMBOL + " Reset"));
"Temporary Overrides " + ult::DIVIDER_SYMBOL + " \ue0e3 Reset"));
this->addModuleListItem(SysClkModule_CPU);
this->addModuleListItem(SysClkModule_GPU);
this->addModuleListItem(SysClkModule_MEM);
#if IS_MINIMAL == 0
ValueThresholds lcdThresholds(60, 65);
if(!IsHoag() && configList.values[HorizonOCConfigValue_OverwriteRefreshRate])
this->addModuleListItemValue(HorizonOCModule_Display, "Display", 40, configList.values[HorizonOCConfigValue_EnableUnsafeDisplayFreqs] ? IsAula() ? 65 : 72 : 60, 1, " Hz", 1, 0, lcdThresholds);
this->addModuleListItemValue(HorizonOCModule_Display, "Display", IsAula() ? 45 : 40, configList.values[HorizonOCConfigValue_EnableUnsafeDisplayFreqs] ? IsAula() ? 65 : 72 : 60, 1, " Hz", 1, 0, lcdThresholds);
#endif
this->addModuleToggleItem(HorizonOCModule_Governor);
}

View File

@@ -1,3 +1,20 @@
/*
* Copyright (c) Souldbminer, Lightos_ and Horizon OC Contributors
*
* 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/>.
*
*/
#include <map>
#include <cstdint>
#include <string>
@@ -30,7 +47,7 @@ std::map<uint32_t, std::string> gpu_freq_label_e = {
{768000000, "Docked"},
{921600000, "Safe Max"},
{960000000, "Unsafe Max"},
{1075200000, "Aboslute Max"},
{1075200000, "Absolute Max"},
};
std::map<uint32_t, std::string> gpu_freq_label_m = {
@@ -42,5 +59,6 @@ std::map<uint32_t, std::string> gpu_freq_label_m = {
{768000000, "Docked"},
{1075200000, "Safe Max"},
{1305600000, "Unsafe Max"},
{1536000000, "Aboslute Max"},
};
{1536000000, "Absolute Max"},
};

View File

@@ -1,3 +1,20 @@
/*
* Copyright (c) Souldbminer, Lightos_ and Horizon OC Contributors
*
* 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/>.
*
*/
#pragma once
#include <map>
#include <cstdint>

View File

@@ -27,6 +27,7 @@
#if IS_MINIMAL == 1
#pragma message("Compiling with minimal features")
#endif
class RamSubmenuGui;
class RamTimingsSubmenuGui;
class RamLatenciesSubmenuGui;
@@ -241,23 +242,15 @@ void MiscGui::listUI()
ValueThresholds thresholdsDisabled(0, 0);
std::vector<NamedValue> noNamedValues = {};
this->listElement->addItem(new tsl::elm::CategoryHeader("Settings"));
addConfigToggle(HocClkConfigValue_UncappedClocks, nullptr);
addConfigToggle(HocClkConfigValue_OverwriteBoostMode, nullptr);
#if IS_MINIMAL == 0
addConfigToggle(HocClkConfigValue_FixCpuVoltBug, nullptr);
#endif
addConfigToggle(HocClkConfigValue_ThermalThrottle, nullptr);
addConfigToggle(HocClkConfigValue_HandheldTDP, nullptr);
addConfigToggle(HocClkConfigValue_EnforceBoardLimit, nullptr);
// addConfigToggle(HocClkConfigValue_EnforceBoardLimit, nullptr);
#if IS_MINIMAL == 0
std::map<uint32_t, std::string> labels_pwr_r = {
{8600, "Official Rating"}
};
std::map<uint32_t, std::string> labels_pwr_l = {
{6400, "Official Rating"}
};
@@ -273,18 +266,16 @@ void MiscGui::listUI()
labels_pwr_l
);
} else {
ValueThresholds tdpThresholds(8600, 9500);
ValueThresholds tdpThresholds(9600, 11000);
addConfigButton(
HocClkConfigValue_HandheldTDPLimit,
"TDP Threshold",
ValueRange(5000, 10000, 100, "mW", 1),
ValueRange(8000, 12000, 100, "mW", 1),
"Power",
&tdpThresholds,
labels_pwr_r
&tdpThresholds
);
}
ValueThresholds throttleThresholds(70, 80);
addConfigButton(
HocClkConfigValue_ThermalThrottleThreshold,
@@ -301,6 +292,45 @@ void MiscGui::listUI()
addFreqButton(HocClkConfigValue_EristaMaxCpuClock, nullptr, SysClkModule_CPU, cpu_freq_label_e);
}
if (IsMariko()) {
std::vector<NamedValue> dvfsValues = {
NamedValue("Disabled", DVFSMode_Disabled),
NamedValue("PCV Hijack", DVFSMode_Hijack),
// NamedValue("Official Service", DVFSMode_OfficialService),
// NamedValue("Hack", DVFSMode_Hack),
};
addConfigButton(
HorizonOCConfigValue_DVFSMode,
"GPU DVFS Mode",
ValueRange(0, 0, 1, "", 0),
"GPU DVFS Mode",
&thresholdsDisabled,
{},
dvfsValues,
false
);
std::vector<NamedValue> dvfsOffset = {
NamedValue("-50 mV", 0xFFFFFFCE),
NamedValue("-45 mV", 0xFFFFFFD3),
NamedValue("-40 mV", 0xFFFFFFD8),
NamedValue("-30 mV", 0xFFFFFFE2),
NamedValue("-25 mV", 0xFFFFFFE7),
NamedValue("-20 mV", 0xFFFFFFEC),
NamedValue("-10 mV", 0xFFFFFFF6),
NamedValue(" -5 mV", 0xFFFFFFFB),
NamedValue("Disabled", 0),
NamedValue(" +5 mV", 5),
NamedValue("+10 mV", 10),
NamedValue("+15 mV", 15),
NamedValue("+20 mV", 20),
};
addConfigButton(HorizonOCConfigValue_DVFSOffset, "GPU DVFS Offset", ValueRange(0, 12, 1, "", 0), "GPU DVFS Offset", &thresholdsDisabled, {}, dvfsOffset, false);
}
this->listElement->addItem(new tsl::elm::CategoryHeader("KIP"));
tsl::elm::ListItem* saveBtn = new tsl::elm::ListItem("Save KIP Settings");
@@ -347,46 +377,69 @@ void MiscGui::listUI()
});
this->listElement->addItem(gpuSubmenu);
#if IS_MINIMAL == 0
// std::vector<NamedValue> chargerCurrents = {
// NamedValue("Disabled", 0),
// NamedValue("1024mA", 1024),
// NamedValue("1280mA", 1280),
// NamedValue("1536mA", 1536),
// NamedValue("1792mA", 1792),
// NamedValue("2048mA", 2048),
// NamedValue("2304mA", 2304),
// NamedValue("2560mA", 2560),
// NamedValue("2816mA", 2816),
// NamedValue("3072mA", 3072),
// };
this->listElement->addItem(new tsl::elm::CategoryHeader("Experimental"));
std::vector<NamedValue> chargerCurrents = {
NamedValue("Disabled", 0),
NamedValue("1024mA", 1024),
NamedValue("1280mA", 1280),
NamedValue("1536mA", 1536),
NamedValue("1792mA", 1792),
NamedValue("2048mA", 2048),
NamedValue("2304mA", 2304),
NamedValue("2560mA", 2560),
NamedValue("2816mA", 2816),
NamedValue("3072mA", 3072),
std::vector<NamedValue> gpuSchedValues = {
NamedValue("Do not override", GpuSchedulingMode_DoNotOverride),
NamedValue("Enabled", GpuSchedulingMode_Enabled, "96.5% limit"),
NamedValue("Disabled", GpuSchedulingMode_Disabled, "99.7% limit"),
};
tsl::elm::CustomDrawer* gpuSchedInfoText = new tsl::elm::CustomDrawer([](tsl::gfx::Renderer *renderer, s32 x, s32 y, s32 w, s32 h) {
renderer->drawString("\uE150 This option requires a reboot", false, x + 20, y + 30, 18, tsl::style::color::ColorText);
renderer->drawString("to take effect", false, x + 20, y + 50, 18, tsl::style::color::ColorText);
});
gpuSchedInfoText->setBoundaries(0, 0, tsl::cfg::FramebufferWidth, 70);
this->listElement->addItem(gpuSchedInfoText);
addConfigButton(
HorizonOCConfigValue_GPUScheduling,
"GPU Scheduling Override",
ValueRange(0, 0, 1, "", 0),
"GPU Scheduling Override",
&thresholdsDisabled,
{},
gpuSchedValues,
false
);
if(!IsHoag()) {
std::vector<NamedValue> chargerCurrents = {
NamedValue("Disabled", 0),
NamedValue("1024mA", 1024),
NamedValue("1280mA", 1280),
NamedValue("1536mA", 1536),
NamedValue("1792mA", 1792),
NamedValue("2048mA", 2048),
NamedValue("2304mA", 2304),
NamedValue("2560mA", 2560),
NamedValue("2816mA", 2816),
NamedValue("3072mA", 3072),
};
// std::vector<NamedValue> chargerCurrents = {
// NamedValue("Disabled", 0),
// NamedValue("1024mA", 1024),
// NamedValue("1280mA", 1280),
// NamedValue("1536mA", 1536),
// NamedValue("1792mA", 1792),
// NamedValue("2048mA", 2048),
// NamedValue("2304mA", 2304),
// NamedValue("2560mA", 2560),
// NamedValue("2816mA", 2816),
// NamedValue("3072mA", 3072),
// };
ValueThresholds chargerThresholds(2048, 2560);
// ValueThresholds chargerThresholds(2048, 2560);
addConfigButton(
HorizonOCConfigValue_BatteryChargeCurrent,
"Charge Current Override",
ValueRange(0, 0, 1, "", 0),
"Charge Current Override",
&chargerThresholds,
{},
chargerCurrents,
false
);
// addConfigButton(
// HorizonOCConfigValue_BatteryChargeCurrent,
// "Charge Current Override",
// ValueRange(0, 0, 1, "", 0),
// "Charge Current Override",
// &chargerThresholds,
// {},
// chargerCurrents,
// false
// );
addConfigToggle(HorizonOCConfigValue_OverwriteRefreshRate, nullptr);
tsl::elm::CustomDrawer* warningText = new tsl::elm::CustomDrawer([](tsl::gfx::Renderer *renderer, s32 x, s32 y, s32 w, s32 h) {
renderer->drawString("\uE150 Enabling unsafe display", false, x + 20, y + 30, 18, tsl::style::color::ColorText);
@@ -397,32 +450,33 @@ void MiscGui::listUI()
warningText->setBoundaries(0, 0, tsl::cfg::FramebufferWidth, 110);
this->listElement->addItem(warningText);
addConfigToggle(HorizonOCConfigValue_EnableUnsafeDisplayFreqs, nullptr);
} else {
std::vector<NamedValue> chargerCurrents = {
NamedValue("Disabled", 0),
NamedValue("1024mA", 1024),
NamedValue("1280mA", 1280),
NamedValue("1536mA", 1536),
NamedValue("1792mA", 1792),
NamedValue("2048mA", 2048),
NamedValue("2304mA", 2304),
NamedValue("2560mA", 2560),
};
ValueThresholds chargerThresholds(1792, 2048);
addConfigButton(
HorizonOCConfigValue_BatteryChargeCurrent,
"Charge Current Override",
ValueRange(0, 0, 1, "", 0),
"Charge Current Override",
&chargerThresholds,
{},
chargerCurrents,
false
);
}
// else {
// std::vector<NamedValue> chargerCurrents = {
// NamedValue("Disabled", 0),
// NamedValue("1024mA", 1024),
// NamedValue("1280mA", 1280),
// NamedValue("1536mA", 1536),
// NamedValue("1792mA", 1792),
// NamedValue("2048mA", 2048),
// NamedValue("2304mA", 2304),
// NamedValue("2560mA", 2560),
// };
// ValueThresholds chargerThresholds(1792, 2048);
// addConfigButton(
// HorizonOCConfigValue_BatteryChargeCurrent,
// "Charge Current Override",
// ValueRange(0, 0, 1, "", 0),
// "Charge Current Override",
// &chargerThresholds,
// {},
// chargerCurrents,
// false
// );
// }
#endif
}
@@ -461,7 +515,7 @@ protected:
NamedValue("2033MHz", 2033000),
NamedValue("2066MHz", 2066000),
NamedValue("2100MHz", 2100000),
NamedValue("2133MHz", 2133000),
NamedValue("2133MHz", 2133000, "JEDEC."),
NamedValue("2166MHz", 2166000),
NamedValue("2200MHz", 2200000),
NamedValue("2233MHz", 2233000),
@@ -546,16 +600,9 @@ protected:
};
if(IsErista()) {
addConfigButton(
KipConfigValue_eristaEmcMaxClock,
"RAM Max Clock",
ValueRange(0, 1, 1, "", 1),
"RAM Max Clock",
&eristaRamThresholds,
{},
eristaMaxEmcClock,
false
);
addConfigButton(KipConfigValue_eristaEmcMaxClock, "RAM Max Clock", ValueRange(0, 1, 1, "", 1), "RAM Max Clock", &eristaRamThresholds, {}, eristaMaxEmcClock, false);
addConfigButton(KipConfigValue_eristaEmcMaxClock1, "RAM Max Clock", ValueRange(0, 1, 1, "", 1), "RAM Max Clock", &eristaRamThresholds, {}, eristaMaxEmcClock, false);
addConfigButton(KipConfigValue_eristaEmcMaxClock2, "RAM Max Clock", ValueRange(0, 1, 1, "", 1), "RAM Max Clock", &eristaRamThresholds, {}, eristaMaxEmcClock, false);
} else {
addConfigButton(
KipConfigValue_marikoEmcMaxClock,
@@ -594,7 +641,7 @@ protected:
addConfigButton(
KipConfigValue_marikoEmcVddqVolt,
"RAM VDDQ Voltage",
ValueRange(550000, 700000, 5000, "mV", 1000),
ValueRange(400000, 700000, 5000, "mV", 1000),
"RAM VDDQ Voltage",
&thresholdsDisabled,
{},
@@ -654,36 +701,28 @@ protected:
addConfigButton(KipConfigValue_t6_tRTW, "t6 tRTW", ValueRange(0, 10, 1, "", 1), "tRTW", &thresholdsDisabled, {}, {}, false);
addConfigButton(KipConfigValue_t7_tWTR, "t7 tWTR", ValueRange(0, 10, 1, "", 1), "tWTR", &thresholdsDisabled, {}, {}, false);
addConfigButton(KipConfigValue_t8_tREFI, "t8 tREFI", ValueRange(0, 6, 1, "", 1), "tREFI", &thresholdsDisabled, {}, {}, false);
#if IS_MINIMAL == 0
if(IsMariko()) {
this->listElement->addItem(new tsl::elm::CategoryHeader("Experimental"));
tsl::elm::ListItem* emcUpdBtn = new tsl::elm::ListItem("Update RAM Timings");
emcUpdBtn->setClickListener([this](u64 keys) {
if (keys & HidNpadButton_A) {
if(this->context->freqs[SysClkModule_MEM] > 1600000000) {
Result rc = hocClkIpcUpdateEmcRegs();
if (R_FAILED(rc)) {
FatalGui::openWithResultCode("hocClkIpcUpdateEmcRegs", rc);
return false;
}
return true;
} else {
writeNotification("Horizon OC\nSet your ram frequency to max\nbefore applying timings!");
}
}
return false;
});
this->listElement->addItem(emcUpdBtn);
tsl::elm::CustomDrawer* warningText = new tsl::elm::CustomDrawer([](tsl::gfx::Renderer *renderer, s32 x, s32 y, s32 w, s32 h) {
renderer->drawString("\uE150 This feature is EXPERIMENTAL", false, x + 20, y + 30, 18, tsl::style::color::ColorText);
renderer->drawString("and should only be used for testing!", false, x + 20, y + 50, 18, tsl::style::color::ColorText);
});
warningText->setBoundaries(0, 0, tsl::cfg::FramebufferWidth, 70);
this->listElement->addItem(warningText);
}
#endif
std::vector<NamedValue> t6_tRTW_fine_tune = {
NamedValue("-2", 0xFFFFFFFE),
NamedValue("-1", 0xFFFFFFFF),
NamedValue(" 0", 0),
NamedValue("+1", 1),
NamedValue("+2", 2),
};
std::vector<NamedValue> t7_tWTR_fine_tune = {
NamedValue("-3", 0xFFFFFFFD),
NamedValue("-2", 0xFFFFFFFE),
NamedValue("-1", 0xFFFFFFFF),
NamedValue(" 0", 0),
NamedValue("+1", 1),
NamedValue("+2", 2),
NamedValue("+3", 3),
};
this->listElement->addItem(new tsl::elm::CategoryHeader("Advanced"));
addConfigButton(KipConfigValue_t6_tRTW_fine_tune, "t6 tRTW Fine Tune", ValueRange(0, 4, 1, "", 0), "tRTW Fine Tune", &thresholdsDisabled, {}, t6_tRTW_fine_tune, false);
addConfigButton(KipConfigValue_t7_tWTR_fine_tune, "t7 tWTR Fine Tune", ValueRange(0, 6, 1, "", 0), "tWTR Fine Tune", &thresholdsDisabled, {}, t7_tWTR_fine_tune, false);
}
};
@@ -1192,7 +1231,7 @@ protected:
};
if (IsMariko()) {
tsl::elm::CustomDrawer* warningText = new tsl::elm::CustomDrawer([](tsl::gfx::Renderer *renderer, s32 x, s32 y, s32 w, s32 h) {
renderer->drawString("\uE150 Setting GPU Clocks past", false, x + 20, y + 30, 18, tsl::style::color::ColorText);
renderer->drawString("1075MHz without UV, 1152MHz on SLT", false, x + 20, y + 50, 18, tsl::style::color::ColorText);

View File

@@ -39,7 +39,7 @@ DEFINES := -DDISABLE_IPC -DTARGET="\"$(TARGET)\"" -DTARGET_VERSION="\"$(TARGET_V
ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE
CFLAGS := -g -Wall -O2 -ffunction-sections \
CFLAGS := -g -Wall -Os -ffunction-sections \
$(ARCH) $(DEFINES)
CFLAGS += $(INCLUDE) -D__SWITCH__

View File

@@ -1,6 +1,7 @@
/*
* Copyright (c) 2020-2023 CTCaer
* Copyright (c) 2023 p-sam
* Copyright (c) 2026 Souldbminer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -47,7 +48,7 @@
#define PTO_CLK_CNT_BUSY BIT(31)
#define PTO_CLK_CNT 0xFFFFFF
#define CLK_PTO_CCLK_G 0x12
#define CLK_PTO_CCLK_G_DIV2 0x13
#define CLK_PTO_EMC 0x24
#define CLOCK(x) (*(volatile u32 *)(g_clk_base + (x)))
@@ -117,7 +118,7 @@ static u32 g_mem_freq = 0;
static u32 g_emc_lall = 0;
static u32 g_emc_lcpu = 0;
static u32 _clock_get_dev_freq(u32 id)
static u32 _clock_get_dev_freq(u32 id, u32 multiplier)
{
const u32 pto_win = 16;
const u32 pto_osc = 32768;
@@ -148,7 +149,7 @@ static u32 _clock_get_dev_freq(u32 id)
(void)CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL);
usleep(2);
u32 freq_khz = (u64)cnt * pto_osc / pto_win / 1000;
u32 freq_khz = (u64)cnt * multiplier * pto_osc / pto_win;
return freq_khz;
}
@@ -203,8 +204,8 @@ static void _clock_update_freqs(void)
return;
}
g_mem_freq = _clock_get_dev_freq(CLK_PTO_EMC) * 1000;
g_cpu_freq = _clock_get_dev_freq(CLK_PTO_CCLK_G) * 1000;
g_mem_freq = _clock_get_dev_freq(CLK_PTO_EMC, 1);
g_cpu_freq = _clock_get_dev_freq(CLK_PTO_CCLK_G_DIV2, 2);
if (!g_gpu_base)
{

View File

@@ -3,8 +3,8 @@
"title_id": "0x00FF0000636C6BFF",
"title_id_range_min": "0x00FF0000636C6BFF",
"title_id_range_max": "0x00FF0000636C6BFF",
"main_thread_stack_size": "0x00008000",
"main_thread_priority": 63,
"main_thread_stack_size": "0x0000C000",
"main_thread_priority": 16,
"default_cpu_id": 3,
"process_category": 0,
"is_retail": true,
@@ -25,7 +25,7 @@
"type": "kernel_flags",
"value": {
"highest_thread_priority": 63,
"lowest_thread_priority": 41,
"lowest_thread_priority": 16,
"lowest_cpu_id": 0,
"highest_cpu_id": 3
}

View File

@@ -12,9 +12,9 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
/* --------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
@@ -41,6 +41,7 @@
#include <cstring>
#include <registers.h>
#include <notification.h>
#include <memmem.h>
#define MAX(A, B) std::max(A, B)
#define MIN(A, B) std::min(A, B)
@@ -64,12 +65,16 @@
#define HOSSVC_HAS_CLKRST (hosversionAtLeast(8,0,0))
#define HOSSVC_HAS_TC (hosversionAtLeast(5,0,0))
#define NVGPU_GPU_IOCTL_PMU_GET_GPU_LOAD 0x80044715
#define NVSCHED_CTRL_ENABLE 0x00000601
#define NVSCHED_CTRL_DISABLE 0x00000602
#define systemtickfrequency 19200000
#define systemtickfrequencyF 19200000.0f
#define CPU_TICK_WAIT (1'000'000'000 / 60)
constexpr u64 CpuTimeOutNs = 500'000'000;
constexpr double Systemtickfrequency = 19200000.0 * (static_cast<double>(CpuTimeOutNs) / 1'000'000'000.0);
Result nvInitialize_rc;
Result nvCheck = 1;
Result nvCheck_sched = 1;
LEvent threadexit;
Thread gpuLThread;
Thread cpuCore0Thread;
Thread cpuCore1Thread;
@@ -84,21 +89,36 @@ Result pwmDutyCycleCheck = 1;
double Rotation_Duty = 0;
u8 fanLevel;
uint32_t GPU_Load_u = 0, fd = 0;
uint32_t GPU_Load_u = 0, fd = 0, fd2 = 0;
BatteryChargeInfo info;
static SysClkSocType g_socType = SysClkSocType_Erista;
static HorizonOCConsoleType g_consoleType = HorizonOCConsoleType_Iowa;
std::atomic<uint64_t> idletick0{systemtickfrequency};
std::atomic<uint64_t> idletick1{systemtickfrequency};
std::atomic<uint64_t> idletick2{systemtickfrequency};
std::atomic<uint64_t> idletick3{systemtickfrequency};
u64 idletick0 = 0;
u64 idletick1 = 0;
u64 idletick2 = 0;
// u64 idletick3 = 0;
u32 cpu0, cpu1, cpu2, cpu3, cpuAvg;
u16 cpuSpeedo0, cpuSpeedo2, socSpeedo0; // CPU, GPU, SOC
u32 speedoBracket;
u16 cpuIDDQ, gpuIDDQ, socIDDQ;
u8 g_dramID = 0;
static const u32 ramBrackets[][22] = {
{ 2133, 2200, 2266, 2300, 2366, 2400, 2433, 2466, 2533, 2566, 2600, 2633, 2700, 2733, 2766, 2833, 2866, 2900, 2933, 3033, 3066, 3100, },
{ 2300, 2366, 2433, 2466, 2533, 2566, 2633, 2700, 2733, 2800, 2833, 2900, 2933, 2966, 3033, 3066, 3100, 3133, 3166, 3200, 3233, 3266, },
{ 2433, 2466, 2533, 2600, 2666, 2733, 2766, 2800, 2833, 2866, 2933, 2966, 3033, 3066, 3100, 3133, 3166, 3200, 3233, 3300, 3333, 3366, },
{ 2500, 2533, 2600, 2633, 2666, 2733, 2800, 2866, 2900, 2966, 3033, 3100, 3166, 3200, 3233, 3266, 3300, 3333, 3366, 3400, 3400, 3400, },
};
static const u32 gpuDvfsArray[] = { 590, 600, 610, 620, 630, 640, 650, 660, 670, 680, 690, 700, 710, 720, 730, 740, 750, 760, 770, 780, 790, 800};
u32 dvfsTable[6][32] = {};
u64 dvfsAddress;
u32 ramVmin;
const char* Board::GetModuleName(SysClkModule module, bool pretty)
{
ASSERT_ENUM_VALID(SysClkModule, module);
@@ -149,16 +169,16 @@ PcvModuleId Board::GetPcvModuleId(SysClkModule sysclkModule)
return pcvModuleId;
}
void CheckCore(void* idletick_ptr) {
std::atomic<uint64_t>* idletick = (std::atomic<uint64_t>*)idletick_ptr;
while (true) {
uint64_t idletick_a;
uint64_t idletick_b;
svcGetInfo(&idletick_b, InfoType_IdleTickCount, INVALID_HANDLE, -1);
svcSleepThread(CPU_TICK_WAIT);
svcGetInfo(&idletick_a, InfoType_IdleTickCount, INVALID_HANDLE, -1);
idletick->store(idletick_a - idletick_b, std::memory_order_release);
}
void CheckCore(void *idletickPtr) {
u64* idletick = static_cast<u64 *>(idletickPtr);
while(true) {
u64 idletickA;
u64 idletickB;
svcGetInfo(&idletickB, InfoType_IdleTickCount, INVALID_HANDLE, -1);
svcWaitForAddress(&threadexit, ArbitrationType_WaitIfEqual, 0, CpuTimeOutNs);
svcGetInfo(&idletickA, InfoType_IdleTickCount, INVALID_HANDLE, -1);
*idletick = idletickA - idletickB;
}
}
void gpuLoadThread(void*) {
@@ -190,7 +210,6 @@ void miscThreadFunc(void*) {
}
}
void Board::Initialize()
{
Result rc = 0;
@@ -222,8 +241,11 @@ void Board::Initialize()
rc = tmp451Initialize();
ASSERT_RESULT_OK(rc, "tmp451Initialize");
if (R_SUCCEEDED(nvInitialize())) nvCheck = nvOpen(&fd, "/dev/nvhost-ctrl-gpu");
nvInitialize_rc = nvInitialize();
if (R_SUCCEEDED(nvInitialize_rc)) {
nvCheck = nvOpen(&fd, "/dev/nvhost-ctrl-gpu");
nvCheck_sched = nvOpen(&fd2, "/dev/nvsched-ctrl");
}
rc = rgltrInitialize();
ASSERT_RESULT_OK(rc, "rgltrInitialize");
@@ -238,17 +260,17 @@ void Board::Initialize()
threadCreate(&gpuLThread, gpuLoadThread, NULL, NULL, 0x1000, 0x3F, -2);
threadStart(&gpuLThread);
threadCreate(&cpuCore0Thread, CheckCore, &idletick0, NULL, 0x500, 0x10, 0);
threadCreate(&cpuCore1Thread, CheckCore, &idletick1, NULL, 0x500, 0x10, 1);
threadCreate(&cpuCore2Thread, CheckCore, &idletick2, NULL, 0x500, 0x10, 2);
threadCreate(&cpuCore3Thread, CheckCore, &idletick3, NULL, 0x500, 0x10, 3);
threadCreate(&miscThread, miscThreadFunc, NULL, NULL, 0x1000, 0x3F, 3);
leventClear(&threadexit);
threadCreate(&cpuCore0Thread, CheckCore, &idletick0, NULL, 0x1000, 0x10, 0);
threadCreate(&cpuCore1Thread, CheckCore, &idletick1, NULL, 0x1000, 0x10, 1);
threadCreate(&cpuCore2Thread, CheckCore, &idletick2, NULL, 0x1000, 0x10, 2);
// threadCreate(&cpuCore3Thread, CheckCore, &idletick3, NULL, 0x1000, 0x10, 3);
threadCreate(&miscThread, miscThreadFunc, NULL, NULL, 0x1000, 0x10, 3);
threadStart(&cpuCore0Thread);
threadStart(&cpuCore1Thread);
threadStart(&cpuCore2Thread);
threadStart(&cpuCore3Thread);
// threadStart(&cpuCore3Thread);
threadStart(&miscThread);
batteryInfoInitialize();
@@ -311,7 +333,7 @@ void Board::fuseReadSpeedos() {
cpuIDDQ = *reinterpret_cast<const u16*>(dump + FUSE_CPU_IDDQ_CALIB);
gpuIDDQ = *reinterpret_cast<const u16*>(dump + FUSE_SOC_IDDQ_CALIB);
socIDDQ = *reinterpret_cast<const u16*>(dump + FUSE_GPU_IDDQ_CALIB);
svcCloseHandle(debug);
return;
}
@@ -378,7 +400,7 @@ void Board::Exit()
threadClose(&cpuCore0Thread);
threadClose(&cpuCore1Thread);
threadClose(&cpuCore2Thread);
threadClose(&cpuCore3Thread);
// threadClose(&cpuCore3Thread);
threadClose(&miscThread);
pwmChannelSessionClose(&g_ICon);
@@ -386,6 +408,7 @@ void Board::Exit()
rgltrExit();
batteryInfoExit();
pmdmntExit();
nvExit();
if(Board::GetConsoleType() != HorizonOCConsoleType_Hoag)
DisplayRefresh_Shutdown();
}
@@ -436,13 +459,22 @@ void Board::SetHz(SysClkModule module, std::uint32_t hz)
ASSERT_RESULT_OK(rc, "clkrstOpenSession");
rc = clkrstSetClockRate(&session, hz);
ASSERT_RESULT_OK(rc, "clkrstSetClockRate");
if (module == SysClkModule_CPU) {
svcSleepThread(300'000);
rc = clkrstSetClockRate(&session, hz);
ASSERT_RESULT_OK(rc, "clkrstSetClockRate");
}
clkrstCloseSession(&session);
}
else
{
rc = pcvSetClockRate(Board::GetPcvModule(module), hz);
ASSERT_RESULT_OK(rc, "pcvSetClockRate");
if (module == SysClkModule_CPU) {
svcSleepThread(300'000);
rc = pcvSetClockRate(Board::GetPcvModule(module), hz);
ASSERT_RESULT_OK(rc, "pcvSetClockRate");
}
}
}
@@ -458,7 +490,7 @@ std::uint32_t Board::GetHz(SysClkModule module)
hz = 60;
return hz;
}
if(HOSSVC_HAS_CLKRST)
{
ClkrstSession session = {0};
@@ -752,8 +784,17 @@ std::int32_t Board::GetPowerMw(SysClkPowerSensor sensor)
return 0;
}
u32 GetMaxCpuLoad() {
float cpuUsage0 = std::clamp(((Systemtickfrequency - idletick0) / static_cast<double>(Systemtickfrequency)) * 1000.0, 0.0, 1000.0);
float cpuUsage1 = std::clamp(((Systemtickfrequency - idletick1) / static_cast<double>(Systemtickfrequency)) * 1000.0, 0.0, 1000.0);
float cpuUsage2 = std::clamp(((Systemtickfrequency - idletick2) / static_cast<double>(Systemtickfrequency)) * 1000.0, 0.0, 1000.0);
// float cpuUsage3 = std::clamp(((Systemtickfrequency - idletick3) / static_cast<double>(Systemtickfrequency)) * 1000.0, 0.0, 1000.0);
return std::round(std::max({cpuUsage0, cpuUsage1, cpuUsage2}));
}
std::uint32_t Board::GetPartLoad(SysClkPartLoad loadSource)
{
{
switch(loadSource)
{
case SysClkPartLoad_EMC:
@@ -762,8 +803,8 @@ std::uint32_t Board::GetPartLoad(SysClkPartLoad loadSource)
return t210EmcLoadCpu();
case HocClkPartLoad_GPU:
return GPU_Load_u;
case HocClkPartLoad_CPUAvg:
return idletick0;
case HocClkPartLoad_CPUMax:
return GetMaxCpuLoad();
case HocClkPartLoad_BAT:
batteryInfoGetChargeInfo(&info);
return info.RawBatteryCharge;
@@ -792,6 +833,7 @@ u8 Board::GetDramID() {
void Board::FetchHardwareInfos()
{
fuseReadSpeedos();
SetSpeedoBracket();
u64 sku = 0, dramID = 0;
Result rc = splInitialize();
ASSERT_RESULT_OK(rc, "splInitialize");
@@ -801,7 +843,7 @@ void Board::FetchHardwareInfos()
rc = splGetConfig(SplConfigItem_DramId, &dramID);
ASSERT_RESULT_OK(rc, "splGetConfig");
splExit();
switch(sku)
@@ -816,9 +858,12 @@ void Board::FetchHardwareInfos()
g_socType = SysClkSocType_Erista;
}
if (g_socType == SysClkSocType_Mariko) {
CacheDvfsTable();
}
g_consoleType = (HorizonOCConsoleType)sku;
g_dramID = (u8)dramID;
}
/*
@@ -926,174 +971,200 @@ std::uint32_t Board::GetVoltage(HocClkVoltage voltage)
return out > 0 ? out : 0;
}
#define MC_REGISTER_BASE 0x70019000
#define MC_REGISTER_REGION_SIZE 0x1000
void Board::SetSpeedoBracket() {
if (cpuSpeedo2 >= 1754) {
speedoBracket = 3;
} else if (cpuSpeedo2 >= 1690) {
speedoBracket = 2;
} else if (cpuSpeedo2 > 1625) {
speedoBracket = 1;
} else {
speedoBracket = 0;
}
}
#define EMC_REGISTER_BASE 0x7001b000
#define EMC_REGISTER_REGION_SIZE 0x1000
u32 Board::GetMinimumGpuVoltage(u32 freqMhz) {
if (freqMhz <= 1600)
return 0;
#define GET_CYCLE_CEIL(PARAM) u32(CEIL(double(PARAM) / tCK_avg))
#define WRITE_REGISTER_EMC(TIMING_OFFSET, VALUE) \
do { \
args = {}; \
args.X[0] = 0xF0000002; \
args.X[1] = EMC_REGISTER_BASE + (TIMING_OFFSET); \
args.X[2] = 0xFFFFFFFF; \
args.X[3] = (VALUE); \
svcCallSecureMonitor(&args); \
} while (false)
#define WRITE_REGISTER_MC(TIMING_OFFSET, VALUE) \
do { \
args = {}; \
args.X[0] = 0xF0000002; \
args.X[1] = MC_REGISTER_BASE + (TIMING_OFFSET); \
args.X[2] = 0xFFFFFFFF; \
args.X[3] = (VALUE); \
svcCallSecureMonitor(&args); \
} while (false)
// NOTE: needs patch to exosphere to expose emc region to secmon. MC does NOT need this patch
u32 tRCD_values[] = { 18, 17, 16, 15, 14, 13, 12, 11 };
u32 tRP_values[] = { 18, 17, 16, 15, 14, 13, 12, 11 };
u32 tRAS_values[] = { 42, 36, 34, 32, 30, 28, 26, 24, 22, 20 };
double tRRD_values[] = { /*10.0,*/ 7.5, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0 }; /* 10.0 is used for <2133mhz; do we care? */
u32 tRFC_values[] = { 140, 130, 120, 110, 100, 90, 80, 70, 60, 50, 40 };
u32 tWTR_values[] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
u32 tREFpb_values[] = { 3900, 5850, 7800, 11700, 15600, 99999 };
// Credit to Lightos for these timings!
void Board::UpdateShadowRegs(u32 tRCD_i, u32 tRP_i, u32 tRAS_i, u32 tRRD_i, u32 tRFC_i, u32 tRTW_i, u32 tWTR_i, u32 tREFpb_i, u32 ramFreq, u32 rlAdd, u32 wlAdd, bool hpMode) {
// timing stuff
SecmonArgs args = {};
constexpr double MC_ARB_DIV = 4.0;
constexpr u32 MC_ARB_SFA = 2;
double tCK_avg = 1000'000.0 / ramFreq;
u32 BL = 16;
u32 RL = 28 + rlAdd;
u32 WL = 14 + wlAdd;
u32 RL_DBI = RL + 4;
u32 tRCD = tRCD_values[tRCD_i];
u32 tRPpb = tRP_values[tRP_i];
u32 tRAS = tRAS_values[tRAS_i];
double tRRD = tRRD_values[tRRD_i];
u32 tRFCpb = tRFC_values[tRFC_i];
u32 tWTR = 10 - tWTR_values[tWTR_i];
u32 tFAW = static_cast<u32>(tRRD * 4.0);
double tDQSCK_max = 3.5;
u32 tWPRE = 2;
double tRPST = 0.5;
u32 tR2W = CEIL(RL_DBI + (tDQSCK_max / tCK_avg) + (BL / 2) - WL + tWPRE + FLOOR(tRPST) + 9.0) - (tRTW_i * 3);
u32 tRC = tRAS + tRPpb;
u32 tRFCab = tRFCpb * 2;
u32 tRPab = tRPpb + 3;
u32 tW2R = CEIL(MAX(WL + (0.010322547033278747 * (ramFreq / 1000.0)), (WL * -0.2067922202979121) + FLOOR(((RL_DBI * -0.1331159971685554) + WL) * 3.654131957826108)) - (tWTR / tCK_avg));
double tMMRI = tRCD + (tCK_avg * 3);
double pdex2mrr = tMMRI + 10;
u32 emc_cfg = hpMode ? 0x13200000 : 0xF3200000;
u32 refresh_raw = 0xFFFF;
if (tREFpb_i != 6) {
refresh_raw = CEIL(tREFpb_values[tREFpb_i] / tCK_avg) - 0x40;
refresh_raw = MIN(refresh_raw, static_cast<u32>(0xFFFF));
for (u32 voltageIndex = 0; voltageIndex < 22; ++voltageIndex) {
if (freqMhz <= ramBrackets[speedoBracket][voltageIndex]) {
return gpuDvfsArray[voltageIndex];
}
}
u32 trefbw = refresh_raw + 0x40;
trefbw = MIN(trefbw, static_cast<u32>(0x3FFF));
return 800;
}
u32 tR2P = 12 + (rlAdd / 2);
u32 tW2P = (CEIL(WL * 1.7303) * 2) - 5;
Handle Board::GetPcvHandle() {
constexpr u64 PcvID = 0x10000000000001a;
u64 processIDList[80]{};
s32 processCount = 0;
Handle handle = INVALID_HANDLE;
double tXSR = (double) (tRFCab + 7.5);
DebugEventInfo debugEvent{};
args = {};
args.X[0] = 0xF0000002;
args.X[1] = EMC_REGISTER_BASE + EMC_INTSTATUS_0;
svcCallSecureMonitor(&args);
/* Get all running processes. */
Result resultGetProcessList = svcGetProcessList(&processCount, processIDList, std::size(processIDList));
if (R_FAILED(resultGetProcessList)) {
return INVALID_HANDLE;
}
if(args.X[1] == (EMC_REGISTER_BASE + EMC_INTSTATUS_0)) { // if param 1 is identical read failed, exosphere needs patch!
writeNotification("Horizon OC\nExosphere not patched\nfor EMC r/w");
/* Try to find pcv. */
for (int i = 0; i < processCount; ++i) {
if (handle != INVALID_HANDLE) {
svcCloseHandle(handle);
handle = INVALID_HANDLE;
}
/* Try to debug process, if it fails, try next process. */
Result resultSvcDebugProcess = svcDebugActiveProcess(&handle, processIDList[i]);
if (R_FAILED(resultSvcDebugProcess)) {
continue;
}
/* Try to get a debug event. */
Result resultDebugEvent = svcGetDebugEvent(&debugEvent, handle);
if (R_SUCCEEDED(resultDebugEvent)) {
if (debugEvent.info.create_process.program_id == PcvID) {
return handle;
}
}
}
/* Failed to get handle. */
return INVALID_HANDLE;
}
void Board::CacheDvfsTable() {
const u32 voltagePattern[] = { 600000, 12500, 1400000, };
Handle handle = GetPcvHandle();
if (handle == INVALID_HANDLE) {
FileUtils::LogLine("[Board] Invalid handle!");
return;
}
// actually write the timings
WRITE_REGISTER_EMC(EMC_CFG_0, emc_cfg);
WRITE_REGISTER_EMC(EMC_RD_RCD_0, GET_CYCLE_CEIL(tRCD));
WRITE_REGISTER_EMC(EMC_WR_RCD_0, GET_CYCLE_CEIL(tRCD));
WRITE_REGISTER_EMC(EMC_RC_0, MIN(GET_CYCLE_CEIL(tRC), static_cast<u32>(0xB8)));
WRITE_REGISTER_EMC(EMC_RAS_0, MIN(GET_CYCLE_CEIL(tRAS), static_cast<u32>(0x7F)));
WRITE_REGISTER_EMC(EMC_RRD_0, GET_CYCLE_CEIL(tRRD));
WRITE_REGISTER_EMC(EMC_RFCPB_0, GET_CYCLE_CEIL(tRFCpb));
WRITE_REGISTER_EMC(EMC_RFC_0, GET_CYCLE_CEIL(tRFCab));
WRITE_REGISTER_EMC(EMC_RP_0, GET_CYCLE_CEIL(tRPpb));
WRITE_REGISTER_EMC(EMC_TRPAB_0, MIN(GET_CYCLE_CEIL(tRPab), static_cast<u32>(0x3F)));
WRITE_REGISTER_EMC(EMC_R2W_0, tR2W);
WRITE_REGISTER_EMC(EMC_W2R_0, tW2R);
WRITE_REGISTER_EMC(EMC_REFRESH_0, refresh_raw);
WRITE_REGISTER_EMC(EMC_PRE_REFRESH_REQ_CNT_0, refresh_raw / 4);
WRITE_REGISTER_EMC(EMC_TREFBW_0, trefbw);
WRITE_REGISTER_EMC(EMC_PDEX2MRR_0, GET_CYCLE_CEIL(pdex2mrr));
WRITE_REGISTER_EMC(EMC_TXSR_0, MIN(GET_CYCLE_CEIL(tXSR), static_cast<u32>(0x3fe)));
WRITE_REGISTER_EMC(EMC_TXSRDLL_0, MIN(GET_CYCLE_CEIL(tXSR), static_cast<u32>(0x3fe)));
MemoryInfo memoryInfo = {};
u64 address = 0;
u32 pageInfo = 0;
constexpr u32 PageSize = 0x1000;
u8 buffer[PageSize];
WRITE_REGISTER_MC(MC_EMEM_ARB_TIMING_RCD_0, CEIL(GET_CYCLE_CEIL(tRCD) / MC_ARB_DIV) - 2);
WRITE_REGISTER_MC(MC_EMEM_ARB_TIMING_RP_0, CEIL(GET_CYCLE_CEIL(tRPpb) / MC_ARB_DIV) - 1);
WRITE_REGISTER_MC(MC_EMEM_ARB_TIMING_RC_0, CEIL(GET_CYCLE_CEIL(tRC) / MC_ARB_DIV) - 1);
WRITE_REGISTER_MC(MC_EMEM_ARB_TIMING_RAS_0, CEIL(GET_CYCLE_CEIL(tRAS) / MC_ARB_DIV) - 2);
WRITE_REGISTER_MC(MC_EMEM_ARB_TIMING_FAW_0, CEIL(GET_CYCLE_CEIL(tFAW) / MC_ARB_DIV) - 1);
WRITE_REGISTER_MC(MC_EMEM_ARB_TIMING_RRD_0, CEIL(GET_CYCLE_CEIL(tRRD) / MC_ARB_DIV) - 1);
WRITE_REGISTER_MC(MC_EMEM_ARB_TIMING_RFCPB_0, CEIL(GET_CYCLE_CEIL(tRFCpb) / MC_ARB_DIV) - 1);
/* Loop until failure. */
while (true) {
/* Find pcv heap. */
while (true) {
Result resultProcessMemory = svcQueryDebugProcessMemory(&memoryInfo, &pageInfo, handle, address);
address = memoryInfo.addr + memoryInfo.size;
WRITE_REGISTER_MC(MC_EMEM_ARB_TIMING_R2W_0, CEIL(tR2W / MC_ARB_DIV) - 1 + MC_ARB_SFA);
WRITE_REGISTER_MC(MC_EMEM_ARB_TIMING_W2R_0, CEIL(tW2R / MC_ARB_DIV) - 1 + MC_ARB_SFA);
if (R_FAILED(resultProcessMemory) || !address) {
svcCloseHandle(handle);
FileUtils::LogLine("[Board] Failed to get process data. %u", R_DESCRIPTION(resultProcessMemory));
handle = INVALID_HANDLE;
return;
}
WRITE_REGISTER_MC(MC_EMEM_ARB_TIMING_RAP2PRE_0, CEIL(tR2P / MC_ARB_DIV));
WRITE_REGISTER_MC(MC_EMEM_ARB_TIMING_WAP2PRE_0, CEIL(tW2P / MC_ARB_DIV) + MC_ARB_SFA);
if (memoryInfo.size && (memoryInfo.perm & 3) == 3 && static_cast<char>(memoryInfo.type) == 0x04) {
/* Found valid memory. */
break;
}
}
u32 da_turns = 0;
da_turns |= u8((CEIL(tR2W / MC_ARB_DIV) - 1 + MC_ARB_SFA) / 2) << 16;
da_turns |= u8((CEIL(tW2R / MC_ARB_DIV) - 1 + MC_ARB_SFA) / 2) << 24;
WRITE_REGISTER_MC(MC_EMEM_ARB_DA_TURNS_0, da_turns);
for (u64 base = 0; base < memoryInfo.size; base += PageSize) {
u32 memorySize = std::min(memoryInfo.size, static_cast<u64>(PageSize));
if (R_FAILED(svcReadDebugProcessMemory(buffer, handle, base + memoryInfo.addr, memorySize))) {
break;
}
u32 da_covers = 0;
u8 r_cover = ((CEIL(tR2P / MC_ARB_DIV)) + (CEIL(GET_CYCLE_CEIL(tRPpb) / MC_ARB_DIV) - 1) + (CEIL(GET_CYCLE_CEIL(tRCD) / MC_ARB_DIV) - 2)) / 2;
u8 w_cover = ((CEIL(tW2P / MC_ARB_DIV) + MC_ARB_SFA) + (CEIL(GET_CYCLE_CEIL(tRPpb) / MC_ARB_DIV) - 1) + (CEIL(GET_CYCLE_CEIL(tRCD) / MC_ARB_DIV) - 2)) / 2;
da_covers |= ((u32)(CEIL(GET_CYCLE_CEIL(tRC) / (u32)MC_ARB_DIV) - 1) / 2);
da_covers |= (r_cover << 8);
da_covers |= (w_cover << 16);
u8 *resultPattern = static_cast<u8 *>(memmem_impl(buffer, sizeof(buffer), voltagePattern, sizeof(voltagePattern)));
u32 index = resultPattern - buffer;
WRITE_REGISTER_MC(MC_EMEM_ARB_DA_COVERS_0, da_covers);
// TODO: modify mc_emem_arb_misc0
WRITE_REGISTER_MC(MC_TIMING_CONTROL_0, 0x1); // update timing regs as they are shadowed
WRITE_REGISTER_EMC(EMC_TIMING_CONTROL_0, 0x1);
if (!resultPattern) {
continue;
}
/* Assuming mariko. */
const u32 vmax = 800;
constexpr u32 DvfsTableOffset = 312;
if (!std::memcmp(&buffer[index + DvfsTableOffset], &vmax, sizeof(vmax))) {
std::memcpy(dvfsTable, &buffer[index + DvfsTableOffset], sizeof(dvfsTable));
dvfsAddress = base + memoryInfo.addr + DvfsTableOffset + index;
}
svcCloseHandle(handle);
handle = INVALID_HANDLE;
return;
}
}
svcCloseHandle(handle);
handle = INVALID_HANDLE;
return;
}
void Board::PcvHijackDvfs(u32 vmin) {
u32 table[192];
static_assert(sizeof(table) == sizeof(dvfsTable));
std::memcpy(table, dvfsTable, sizeof(dvfsTable));
if (ramVmin == vmin) {
return;
}
for (u32 i = 0; i < std::size(table); ++i) {
if (table[i] && table[i] <= vmin) {
table[i] = vmin;
}
}
Handle handle = GetPcvHandle();
if (handle == INVALID_HANDLE) {
FileUtils::LogLine("Invalid handle!");
return;
}
Result rc = svcWriteDebugProcessMemory(handle, table, dvfsAddress, sizeof(table));
if (R_SUCCEEDED(rc)) {
ramVmin = vmin;
}
svcCloseHandle(handle);
FileUtils::LogLine("[dvfs] voltage set to %u mV", vmin);
}
#define MC_REGISTER_BASE 0x70019000
#define MC_REGISTER_REGION_SIZE 0x1000
bool Board::IsDram8GB() {
SecmonArgs args = {};
args.X[0] = 0xF0000002;
args.X[1] = MC_REGISTER_BASE + MC_EMEM_CFG_0;
svcCallSecureMonitor(&args);
SecmonArgs args = {};
args.X[0] = 0xF0000002;
args.X[1] = MC_REGISTER_BASE + MC_EMEM_CFG_0;
svcCallSecureMonitor(&args);
if(args.X[1] == (MC_REGISTER_BASE + MC_EMEM_CFG_0)) { // if param 1 is identical read failed
writeNotification("Horizon OC\nSecmon read failed!\n This may be a hardware issue!");
writeNotification("Horizon OC\nSecmon read failed!\n This may be a hardware issue!");
return false;
} else
return args.X[1] == 0x00002000 ? true : false;
}
void Board::SetGpuSchedulingMode(GpuSchedulingMode mode) {
if (nvCheck_sched == 1) {
return;
}
u32 temp;
switch(mode) {
case GpuSchedulingMode_DoNotOverride:
return;
case GpuSchedulingMode_Disabled:
nvIoctl(fd2, NVSCHED_CTRL_DISABLE, &temp);
break;
case GpuSchedulingMode_Enabled:
nvIoctl(fd2, NVSCHED_CTRL_ENABLE, &temp);
break;
default:
ASSERT_ENUM_VALID(GpuSchedulingMode, mode);
}
}

View File

@@ -12,9 +12,9 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
/* --------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
@@ -33,6 +33,8 @@
class Board
{
public:
static void PcvHijackDvfs(u32 vmin);
static u32 GetMinimumGpuVoltage(u32 freqMhz);
static void fuseReadSpeedos();
static u16 getSpeedo(HorizonOCSpeedo speedoType);
static u16 getIDDQ(HorizonOCSpeedo speedoType);
@@ -61,10 +63,14 @@ class Board
static std::uint32_t GetVoltage(HocClkVoltage voltage);
static u8 GetFanRotationLevel();
static u8 GetDramID();
static void UpdateShadowRegs(u32 tRCD_i, u32 tRP_i, u32 tRAS_i, u32 tRRD_i, u32 tRFC_i, u32 tRTW_i, u32 tWTR_i, u32 tREFpb_i, u32 ramFreq, u32 rlAdd, u32 wlAdd, bool hpMode);
static bool IsDram8GB();
static void SetGpuSchedulingMode(GpuSchedulingMode mode);
protected:
static void FetchHardwareInfos();
static PcvModule GetPcvModule(SysClkModule sysclkModule);
static PcvModuleId GetPcvModuleId(SysClkModule sysclkModule);
private:
static void SetSpeedoBracket();
static void CacheDvfsTable();
static Handle GetPcvHandle();
};

View File

@@ -39,6 +39,7 @@
#include <cstring>
#include <cstdio>
#include <crc32.h>
#include <sys/stat.h>
#define HOSPPC_HAS_BOOST (hosversionAtLeast(7,0,0))
bool isGovernorEnabled = false; // to avoid thread messes
@@ -47,8 +48,9 @@ bool hasChanged = true;
ClockManager *ClockManager::instance = NULL;
Thread governorTHREAD;
u32 initialConfigValues[SysClkConfigValue_EnumMax]; // initial config. used for safety checks
u64 previousRamHz;
bool kipAvailable = false;
ClockManager *ClockManager::GetInstance()
{
return instance;
@@ -110,36 +112,15 @@ ClockManager::ClockManager()
this->context->dramID = Board::GetDramID();
this->context->isDram8GB = Board::IsDram8GB();
}
previousRamHz = Board::GetHz(SysClkModule_MEM);
Board::SetGpuSchedulingMode((GpuSchedulingMode)this->config->GetConfigValue(HorizonOCConfigValue_GPUScheduling));
this->context->gpuSchedulingMode = (GpuSchedulingMode)this->config->GetConfigValue(HorizonOCConfigValue_GPUScheduling);
void ClockManager::FixCpuBug() {
if(this->config->Refresh() && this->RefreshContext()) {
u32 targetHz = 0;
u32 maxHz = 0;
u32 nearestHz = 0;
// ResetToStockClocks();
targetHz = this->context->overrideFreqs[SysClkModule_CPU];
if (!targetHz) {
targetHz = this->config->GetAutoClockHz(this->context->applicationId, SysClkModule_CPU, this->context->profile, false);
if(!targetHz)
targetHz = this->config->GetAutoClockHz(GLOBAL_PROFILE_ID, SysClkModule_CPU, this->context->profile, false);
}
if (targetHz) {
maxHz = this->GetMaxAllowedHz(SysClkModule_CPU, this->context->profile);
nearestHz = this->GetNearestHz(SysClkModule_CPU, targetHz, maxHz);
while ((nearestHz = this->GetNearestHz(SysClkModule_CPU, targetHz, maxHz)) != targetHz) {
Board::SetHz(SysClkModule_CPU, 1020000000);
svcSleepThread(1'000'000);
Board::SetHz(SysClkModule_CPU, maxHz);
this->context->freqs[SysClkModule_CPU] = maxHz;
}
Board::SetHz(SysClkModule_CPU, targetHz);
}
struct stat st = {0};
if (stat("sdmc:/atmosphere/contents/42000000000000A0", &st) == 0 && S_ISDIR(st.st_mode)) {
this->context->isSysDockInstalled = true;
} else {
this->context->isSysDockInstalled = false;
}
}
@@ -196,7 +177,7 @@ std::uint32_t ClockManager::GetMaxAllowedHz(SysClkModule module, SysClkProfile p
{
if (this->config->GetConfigValue(HocClkConfigValue_UncappedClocks))
{
return 4294967294; // Integer limit, uncapped clocks ON
return ~0; // Integer limit, uncapped clocks ON
}
else
{
@@ -208,9 +189,18 @@ std::uint32_t ClockManager::GetMaxAllowedHz(SysClkModule module, SysClkProfile p
case SysClkSocType_Erista:
return 460800000;
case SysClkSocType_Mariko:
return 614400000;
switch(this->config->GetConfigValue(KipConfigValue_marikoGpuUV)) {
case 0:
return 614400000;
case 1:
return 691200000;
case 2:
return 768000000;
default:
return 614400000;
}
default:
return 4294967294;
return 460800000;
}
}
else if (profile <= SysClkProfile_HandheldChargingUSB)
@@ -219,11 +209,26 @@ std::uint32_t ClockManager::GetMaxAllowedHz(SysClkModule module, SysClkProfile p
case SysClkSocType_Erista:
return 768000000;
case SysClkSocType_Mariko:
return 921600000;
switch(this->config->GetConfigValue(KipConfigValue_marikoGpuUV)) {
case 0:
return 844800000;
case 1:
return 921600000;
case 2:
return 998400000;
default:
return 844800000;
}
default:
return 4294967294;
return 768000000;
}
}
} else if(module == SysClkModule_CPU) {
if(profile < SysClkProfile_HandheldCharging && Board::GetSocType() == SysClkSocType_Erista) {
return 1581000000;
} else {
return ~0;
}
}
}
return 0;
@@ -338,7 +343,7 @@ void ClockManager::GovernorThread(void* arg)
svcSleepThread(50'000'000);
continue;
}
std::scoped_lock lock{mgr->contextMutex};
u32 currentHz = Board::GetHz(SysClkModule_GPU);
@@ -439,12 +444,12 @@ void ClockManager::Tick()
}
}
if(this->config->GetConfigValue(HocClkConfigValue_EnforceBoardLimit) && opMode == AppletOperationMode_Console ) {
if(Board::GetPowerMw(SysClkPowerSensor_Now) < 0) {
ResetToStockClocks();
return;
}
}
// if(this->config->GetConfigValue(HocClkConfigValue_EnforceBoardLimit) && opMode == AppletOperationMode_Console ) {
// if(Board::GetPowerMw(SysClkPowerSensor_Now) < 0) {
// ResetToStockClocks();
// return;
// }
// }
if(((tmp451TempSoc() / 1000) > (int)this->config->GetConfigValue(HocClkConfigValue_ThermalThrottleThreshold)) && this->config->GetConfigValue(HocClkConfigValue_ThermalThrottle)) {
ResetToStockClocks();
@@ -460,6 +465,7 @@ void ClockManager::Tick()
if (this->RefreshContext() || this->config->Refresh())
{
if(this->config->GetConfigValue(HorizonOCConfigValue_BatteryChargeCurrent)) {
I2c_Bq24193_SetFastChargeCurrentLimit(this->config->GetConfigValue(HorizonOCConfigValue_BatteryChargeCurrent));
}
@@ -471,10 +477,13 @@ void ClockManager::Tick()
// ResetToStockClocks();
return;
}
previousRamHz = Board::GetHz(SysClkModule_MEM);
bool returnRaw = false;
for (unsigned int module = 0; module < SysClkModule_EnumMax; module++)
{
u32 oldHz = Board::GetHz((SysClkModule)module);
if(module > SysClkModule_MEM)
returnRaw = true;
else
@@ -535,11 +544,44 @@ void ClockManager::Tick()
targetHz / 1000000, targetHz / 100000 - targetHz / 1000000 * 10
);
if(module == SysClkModule_MEM && Board::GetSocType() == SysClkSocType_Mariko && targetHz > oldHz && this->config->GetConfigValue(HorizonOCConfigValue_DVFSMode) == DVFSMode_Hijack) {
s32 dvfsOffset = this->config->GetConfigValue(HorizonOCConfigValue_DVFSOffset);
u32 vmin = Board::GetMinimumGpuVoltage(targetHz / 1000000) + dvfsOffset;
Board::PcvHijackDvfs(vmin);
/* Update the voltage. */
if (I2c_BuckConverter_GetMvOut(&I2c_Mariko_GPU) < vmin) {
I2c_BuckConverter_SetMvOut(&I2c_Mariko_GPU, vmin);
}
this->context->voltages[HocClkVoltage_GPU] = vmin * 1000;
}
Board::SetHz((SysClkModule)module, nearestHz);
this->context->freqs[module] = nearestHz;
}
if(module == SysClkModule_CPU && this->config->GetConfigValue(HocClkConfigValue_FixCpuVoltBug)) {
FixCpuBug();
if(module == SysClkModule_MEM && Board::GetSocType() == SysClkSocType_Mariko && targetHz < oldHz && this->config->GetConfigValue(HorizonOCConfigValue_DVFSMode) == DVFSMode_Hijack) {
s32 dvfsOffset = this->config->GetConfigValue(HorizonOCConfigValue_DVFSOffset);
dvfsOffset = std::max(dvfsOffset, -50);
u32 vmin = Board::GetMinimumGpuVoltage(targetHz / 1000000) + dvfsOffset;
Board::PcvHijackDvfs(vmin);
targetHz = this->context->overrideFreqs[SysClkModule_GPU];
if (!targetHz)
{
targetHz = this->config->GetAutoClockHz(this->context->applicationId, SysClkModule_GPU, this->context->profile, false);
if(!targetHz)
targetHz = this->config->GetAutoClockHz(GLOBAL_PROFILE_ID, SysClkModule_GPU, this->context->profile, false);
}
if(targetHz) {
Board::SetHz(SysClkModule_GPU, ~0);
Board::SetHz(SysClkModule_GPU, targetHz);
} else {
Board::SetHz(SysClkModule_GPU, ~0);
Board::ResetToStockGpu();
}
}
}
}
@@ -562,7 +604,7 @@ void ClockManager::WaitForNextTick()
bool ClockManager::RefreshContext()
{
bool hasChanged = false;
std::uint32_t mode = 0;
Result rc = apmExtGetCurrentPerformanceConfiguration(&mode);
ASSERT_RESULT_OK(rc, "apmExtGetCurrentPerformanceConfiguration");
@@ -589,6 +631,11 @@ bool ClockManager::RefreshContext()
{
// this->rnxSync->ToggleSync(this->GetConfig()->GetConfigValue(HocClkConfigValue_SyncReverseNXMode));
Board::ResetToStock();
if (Board::GetSocType() == SysClkSocType_Mariko && this->config->GetConfigValue(HorizonOCConfigValue_DVFSMode) == DVFSMode_Hijack) {
Board::PcvHijackDvfs(0);
Board::SetHz(SysClkModule_GPU, ~0);
Board::ResetToStockGpu();
}
this->WaitForNextTick();
}
@@ -624,6 +671,26 @@ bool ClockManager::RefreshContext()
break;
case SysClkModule_MEM:
Board::ResetToStockMem();
if (Board::GetSocType() == SysClkSocType_Mariko && this->config->GetConfigValue(HorizonOCConfigValue_DVFSMode) == DVFSMode_Hijack) {
Board::PcvHijackDvfs(0);
u32 targetHz = this->context->overrideFreqs[SysClkModule_GPU];
if (!targetHz)
{
targetHz = this->config->GetAutoClockHz(this->context->applicationId, SysClkModule_GPU, this->context->profile, false);
if(!targetHz)
targetHz = this->config->GetAutoClockHz(GLOBAL_PROFILE_ID, SysClkModule_GPU, this->context->profile, false);
}
if(targetHz) {
Board::SetHz(SysClkModule_GPU, ~0);
Board::SetHz(SysClkModule_GPU, targetHz);
} else {
Board::SetHz(SysClkModule_GPU, ~0);
Board::ResetToStockGpu();
}
}
break;
}
}
@@ -739,11 +806,13 @@ void ClockManager::SetKipData() {
}
CUST_WRITE_FIELD_BATCH(&table, custRev, this->config->GetConfigValue(KipConfigValue_custRev));
CUST_WRITE_FIELD_BATCH(&table, mtcConf, this->config->GetConfigValue(KipConfigValue_mtcConf));
// CUST_WRITE_FIELD_BATCH(&table, mtcConf, this->config->GetConfigValue(KipConfigValue_mtcConf));
CUST_WRITE_FIELD_BATCH(&table, hpMode, this->config->GetConfigValue(KipConfigValue_hpMode));
CUST_WRITE_FIELD_BATCH(&table, commonEmcMemVolt, this->config->GetConfigValue(KipConfigValue_commonEmcMemVolt));
CUST_WRITE_FIELD_BATCH(&table, eristaEmcMaxClock, this->config->GetConfigValue(KipConfigValue_eristaEmcMaxClock));
CUST_WRITE_FIELD_BATCH(&table, eristaEmcMaxClock1, this->config->GetConfigValue(KipConfigValue_eristaEmcMaxClock1));
CUST_WRITE_FIELD_BATCH(&table, eristaEmcMaxClock2, this->config->GetConfigValue(KipConfigValue_eristaEmcMaxClock2));
CUST_WRITE_FIELD_BATCH(&table, marikoEmcMaxClock, this->config->GetConfigValue(KipConfigValue_marikoEmcMaxClock));
CUST_WRITE_FIELD_BATCH(&table, marikoEmcVddqVolt, this->config->GetConfigValue(KipConfigValue_marikoEmcVddqVolt));
CUST_WRITE_FIELD_BATCH(&table, emcDvbShift, this->config->GetConfigValue(KipConfigValue_emcDvbShift));
@@ -792,6 +861,9 @@ void ClockManager::SetKipData() {
table.eristaGpuVoltArray[i] = this->config->GetConfigValue((SysClkConfigValue)(KipConfigValue_g_volt_e_76800 + i));
}
CUST_WRITE_FIELD_BATCH(&table, t6_tRTW_fine_tune, this->config->GetConfigValue(KipConfigValue_t6_tRTW_fine_tune));
CUST_WRITE_FIELD_BATCH(&table, t7_tWTR_fine_tune, this->config->GetConfigValue(KipConfigValue_t7_tWTR_fine_tune));
if (!cust_write_table("sdmc:/atmosphere/kips/hoc.kip", &table)) {
FileUtils::LogLine("[clock_manager] Failed to write KIP file");
writeNotification("Horizon OC\nKip write failed");
@@ -859,11 +931,13 @@ void ClockManager::GetKipData() {
if(writeBootConfigValues) {
writeBootConfigValues = false;
initialConfigValues[KipConfigValue_mtcConf] = cust_get_mtc_conf(&table);
// initialConfigValues[KipConfigValue_mtcConf] = cust_get_mtc_conf(&table);
initialConfigValues[KipConfigValue_hpMode] = cust_get_hp_mode(&table);
initialConfigValues[KipConfigValue_commonEmcMemVolt] = cust_get_common_emc_volt(&table);
initialConfigValues[KipConfigValue_eristaEmcMaxClock] = cust_get_erista_emc_max(&table);
initialConfigValues[KipConfigValue_eristaEmcMaxClock1] = cust_get_erista_emc_max1(&table);
initialConfigValues[KipConfigValue_eristaEmcMaxClock2] = cust_get_erista_emc_max2(&table);
initialConfigValues[KipConfigValue_marikoEmcMaxClock] = cust_get_mariko_emc_max(&table);
initialConfigValues[KipConfigValue_marikoEmcVddqVolt] = cust_get_mariko_emc_vddq(&table);
initialConfigValues[KipConfigValue_emcDvbShift] = cust_get_emc_dvb_shift(&table);
@@ -884,7 +958,6 @@ void ClockManager::GetKipData() {
initialConfigValues[KipConfigValue_eristaCpuMaxVolt] = cust_get_erista_cpu_max_volt(&table);
initialConfigValues[KipConfigValue_eristaCpuUnlock] = cust_get_eristaCpuUnlock(&table);
initialConfigValues[KipConfigValue_marikoCpuUVLow] = cust_get_mariko_cpu_uv_low(&table);
initialConfigValues[KipConfigValue_marikoCpuUVHigh] = cust_get_mariko_cpu_uv_high(&table);
initialConfigValues[KipConfigValue_tableConf] = cust_get_table_conf(&table);
@@ -902,13 +975,17 @@ void ClockManager::GetKipData() {
initialConfigValues[KipConfigValue_marikoGpuVmax] = cust_get_mariko_gpu_vmax(&table);
initialConfigValues[KipConfigValue_commonGpuVoltOffset] = cust_get_common_gpu_offset(&table);
initialConfigValues[KipConfigValue_gpuSpeedo] = cust_get_gpu_speedo(&table);
initialConfigValues[KipConfigValue_t6_tRTW_fine_tune] = cust_get_tRTW_fine_tune(&table);
initialConfigValues[KipConfigValue_t7_tWTR_fine_tune] = cust_get_tWTR_fine_tune(&table);
}
configValues.values[KipConfigValue_mtcConf] = cust_get_mtc_conf(&table);
// configValues.values[KipConfigValue_mtcConf] = cust_get_mtc_conf(&table);
configValues.values[KipConfigValue_hpMode] = cust_get_hp_mode(&table);
configValues.values[KipConfigValue_commonEmcMemVolt] = cust_get_common_emc_volt(&table);
configValues.values[KipConfigValue_eristaEmcMaxClock] = cust_get_erista_emc_max(&table);
configValues.values[KipConfigValue_eristaEmcMaxClock1] = cust_get_erista_emc_max1(&table);
configValues.values[KipConfigValue_eristaEmcMaxClock2] = cust_get_erista_emc_max2(&table);
configValues.values[KipConfigValue_marikoEmcMaxClock] = cust_get_mariko_emc_max(&table);
configValues.values[KipConfigValue_marikoEmcVddqVolt] = cust_get_mariko_emc_vddq(&table);
configValues.values[KipConfigValue_emcDvbShift] = cust_get_emc_dvb_shift(&table);
@@ -958,6 +1035,9 @@ void ClockManager::GetKipData() {
initialConfigValues[KipConfigValue_g_volt_e_76800 + i] = cust_get_erista_gpu_volt(&table, i);
}
configValues.values[KipConfigValue_t7_tWTR_fine_tune] = cust_get_tWTR_fine_tune(&table);
configValues.values[KipConfigValue_t6_tRTW_fine_tune] = cust_get_tRTW_fine_tune(&table);
// if(cust_get_cust_rev(&table) == KIP_CUST_REV)
// return;
@@ -977,74 +1057,3 @@ void ClockManager::GetKipData() {
writeNotification("Horizon OC\nConfig refresh failed");
}
}
void ClockManager::UpdateRamTimings() {
u32 t1_tRCD = this->config->GetConfigValue(KipConfigValue_t1_tRCD);
u32 t2_tRP = this->config->GetConfigValue(KipConfigValue_t2_tRP);
u32 t3_tRAS = this->config->GetConfigValue(KipConfigValue_t3_tRAS);
u32 t4_tRRD = this->config->GetConfigValue(KipConfigValue_t4_tRRD);
u32 t5_tRFC = this->config->GetConfigValue(KipConfigValue_t5_tRFC);
u32 t6_tRTW = this->config->GetConfigValue(KipConfigValue_t6_tRTW);
u32 t7_tWTR = this->config->GetConfigValue(KipConfigValue_t7_tWTR);
u32 t8_tREFI = this->config->GetConfigValue(KipConfigValue_t8_tREFI);
bool hpMode = (bool)this->config->GetConfigValue(KipConfigValue_hpMode);
u64 ramFreq = initialConfigValues[KipConfigValue_marikoEmcMaxClock];
u32 rlAdd = initialConfigValues[KipConfigValue_mem_burst_read_latency];
u32 wlAdd = initialConfigValues[KipConfigValue_mem_burst_write_latency];
Board::UpdateShadowRegs(t1_tRCD, t2_tRP, t3_tRAS, t4_tRRD, t5_tRFC, t6_tRTW, t7_tWTR, t8_tREFI, ramFreq, rlAdd, wlAdd, hpMode);
}
unsigned int ramBrackets[][22] =
{
{ 2133, 2200, 2266, 2300, 2366, 2400, 2433, 2466, 2533, 2566, 2600, 2633, 2700, 2733, 2766, 2833, 2866, 2900, 2933, 3033, 3066, 3100, },
{ 2300, 2366, 2433, 2466, 2533, 2566, 2633, 2700, 2733, 2800, 2833, 2900, 2933, 2966, 3033, 3066, 3100, 3133, 3166, 3200, 3233, 3266, },
{ 2433, 2466, 2533, 2600, 2666, 2733, 2766, 2800, 2833, 2866, 2933, 2966, 3033, 3066, 3100, 3133, 3166, 3200, 3233, 3300, 3333, 3366, },
{ 2500, 2533, 2600, 2633, 2666, 2733, 2800, 2866, 2900, 2966, 3033, 3100, 3166, 3200, 3233, 3266, 3300, 3333, 3366, 3400, 3400, 3400, }
};
unsigned int gpuDvfsArray[] = { 590, 600, 610, 620, 630, 640, 650, 660, 670, 680, 690, 700, 710, 720, 730, 740, 750, 760, 770, 780, 790, 800};
int ClockManager::GetSpeedoBracket (int speedo)
{
int speedoBracket = 3;
if ((speedo < 1754) && (speedoBracket = 2, speedo < 1690)) {
speedoBracket = !!(1625 < speedo);
}
return speedoBracket;
}
unsigned int ClockManager::GetGpuVoltage (unsigned int freq, int speedo)
{
long int loop;
int bracket = GetSpeedoBracket(speedo);
if (freq < 1601)
return 610;
loop = 0;
do
{
if (freq <= ramBrackets[bracket][loop])
return gpuDvfsArray[loop];
loop++;
} while (loop != 22);
return 800;
}
void ClockManager::calculateGpuVmin (void)
{
if(this->config->Refresh()) {
SysClkConfigValueList configValues;
this->config->GetConfigValues(&configValues);
int speedo = Board::getSpeedo(HorizonOCSpeedo_CPU), freq = this->config->GetConfigValue(KipConfigValue_marikoEmcMaxClock);
configValues.values[KipConfigValue_marikoGpuVmin] = GetGpuVoltage(freq, speedo);
this->config->SetConfigValues(&configValues, true);
}
}

View File

@@ -49,7 +49,6 @@ class ClockManager
ClockManager();
virtual ~ClockManager();
void FixCpuBug();
SysClkContext GetCurrentContext();
Config* GetConfig();
@@ -63,7 +62,6 @@ class ClockManager
void SetKipData();
void GetKipData();
static void GovernorThread(void* arg);
void UpdateRamTimings();
struct {
std::uint32_t count;
std::uint32_t list[SYSCLK_FREQ_LIST_MAX];

View File

@@ -12,9 +12,9 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
/* --------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
@@ -43,7 +43,7 @@ IpcService::IpcService(ClockManager* clockMgr)
this->running = false;
this->clockMgr = clockMgr;
}
void IpcService::SetRunning(bool running)
@@ -209,16 +209,6 @@ Result IpcService::ServiceHandlerFunc(void* arg, const IpcServerRequest* r, u8*
return ipcSrv->SetKipData();
}
break;
case HocClkIpcCmd_UpdateEmcRegs:
if (r->data.size >= 0) {
return ipcSrv->UpdateEmcRegs();
}
break;
case HocClkIpcCmd_CalculateGpuVmin:
if (r->data.size >= 0) {
return ipcSrv->CalculateGPUVmin();
}
break;
}
return SYSCLK_ERROR(Generic);
@@ -377,23 +367,12 @@ Result IpcService::SetReverseNXRTMode(ReverseNXMode mode) {
Result IpcService::SetKipData() {
this->clockMgr->SetKipData();
return 0;
}
Result IpcService::GetKipData() {
this->clockMgr->GetKipData();
return 0;
}
Result IpcService::UpdateEmcRegs() {
this->clockMgr->UpdateRamTimings();
return 0;
}
Result IpcService::CalculateGPUVmin() {
this->clockMgr->calculateGpuVmin();
return 0;
}

View File

@@ -57,8 +57,6 @@ class IpcService
Result SetReverseNXRTMode(ReverseNXMode mode);
Result SetKipData();
Result GetKipData();
Result UpdateEmcRegs();
Result CalculateGPUVmin();
bool running;
Thread thread;
LockableMutex threadMutex;

View File

@@ -12,9 +12,9 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
#pragma once
#include <switch.h>
@@ -28,10 +28,12 @@
typedef struct {
u8 cust[4];
u32 custRev;
u32 mtcConf;
u32 placeholder;
u32 hpMode;
u32 commonEmcMemVolt;
u32 eristaEmcMaxClock;
u32 eristaEmcMaxClock1;
u32 eristaEmcMaxClock2;
u32 marikoEmcMaxClock;
u32 marikoEmcVddqVolt;
u32 emcDvbShift;
@@ -77,7 +79,11 @@ typedef struct {
u32 eristaGpuVoltArray[27];
u32 marikoGpuVoltArray[24];
u32 reserved[64];
u32 t6_tRTW_fine_tune;
u32 t7_tWTR_fine_tune;
u32 reserved[60];
} CustomizeTable;
#pragma pack(pop)
@@ -183,11 +189,13 @@ static inline bool cust_read_and_cache(const char* path, CustomizeTable* out) {
} while (0)
static inline bool cust_set_cust_rev(const char* p, u32 v) { CUST_WRITE_FIELD(p, custRev, v); }
static inline bool cust_set_mtc_conf(const char* p, u32 v) { CUST_WRITE_FIELD(p, mtcConf, v); }
// static inline bool cust_set_mtc_conf(const char* p, u32 v) { CUST_WRITE_FIELD(p, mtcConf, v); }
static inline bool cust_set_hp_mode(const char* p, u32 v) { CUST_WRITE_FIELD(p, hpMode, v); }
static inline bool cust_set_common_emc_volt(const char* p, u32 v) { CUST_WRITE_FIELD(p, commonEmcMemVolt, v); }
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_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); }
@@ -200,6 +208,8 @@ static inline bool cust_set_tRFC(const char* p, u32 v) { CUST_WRITE_FIELD(p, t5_
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_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_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); }
@@ -250,11 +260,13 @@ static inline u32 cust_get_field(const CustomizeTable* t, u32 offset) {
#define CUST_GET_FIELD(table, field) ((table) ? (table)->field : 0)
static inline u32 cust_get_cust_rev(const CustomizeTable* t) { return CUST_GET_FIELD(t, custRev); }
static inline u32 cust_get_mtc_conf(const CustomizeTable* t) { return CUST_GET_FIELD(t, mtcConf); }
// static inline u32 cust_get_mtc_conf(const CustomizeTable* t) { return CUST_GET_FIELD(t, mtcConf); }
static inline u32 cust_get_hp_mode(const CustomizeTable* t) { return CUST_GET_FIELD(t, hpMode); }
static inline u32 cust_get_common_emc_volt(const CustomizeTable* t) { return CUST_GET_FIELD(t, commonEmcMemVolt); }
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_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); }
@@ -267,6 +279,8 @@ static inline u32 cust_get_tRFC(const CustomizeTable* t) { return CUST_GET_FIELD
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_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_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); }

View File

@@ -12,9 +12,9 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
/* --------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
@@ -36,7 +36,7 @@
#include "process_management.h"
#include "clock_manager.h"
#include "ipc_service.h"
#define INNER_HEAP_SIZE 0x30000
#define INNER_HEAP_SIZE 0x40000
extern "C"
{
@@ -80,11 +80,11 @@ extern "C"
hosversionSet(MAKEHOSVERSION(fw.major, fw.minor, fw.micro));
setsysExit();
}
// rc = fanInitialize();
// if (R_FAILED(rc))
// diagAbortWithResult(MAKERESULT(Module_Libnx, LibnxError_ShouldNotHappen));
rc = i2cInitialize();
if (R_FAILED(rc))
diagAbortWithResult(MAKERESULT(Module_Libnx, LibnxError_ShouldNotHappen));
@@ -96,7 +96,7 @@ extern "C"
// fanExit();
i2cExit();
fsExit();
fsdevUnmountAll();
fsdevUnmountAll();
}
}
@@ -154,6 +154,6 @@ int main(int argc, char** argv)
FileUtils::LogLine("Exit");
svcSleepThread(1000000ULL);
FileUtils::Exit();
return 0;
}

View File

@@ -28,6 +28,7 @@
#include "process_management.h"
#include "file_utils.h"
#include "errors.h"
#define IS_QLAUNCH 0x20f
void ProcessManagement::Initialize()
{
@@ -47,7 +48,7 @@ void ProcessManagement::WaitForQLaunch()
do
{
rc = pmdmntGetProcessId(&pid, PROCESS_MANAGEMENT_QLAUNCH_TID);
svcSleepThread(500000000ULL);
svcSleepThread(50 * 1000000ULL); // 50ms
} while (R_FAILED(rc));
}
@@ -58,7 +59,7 @@ std::uint64_t ProcessManagement::GetCurrentApplicationId()
std::uint64_t tid = 0;
rc = pmdmntGetApplicationProcessId(&pid);
if (rc == 0x20f)
if (rc == IS_QLAUNCH)
{
return PROCESS_MANAGEMENT_QLAUNCH_TID;
}
@@ -67,7 +68,7 @@ std::uint64_t ProcessManagement::GetCurrentApplicationId()
rc = pminfoGetProgramId(&tid, pid);
if (rc == 0x20f)
if (rc == IS_QLAUNCH)
{
return PROCESS_MANAGEMENT_QLAUNCH_TID;
}

View File

@@ -21,20 +21,4 @@ cd ../../
cd Source/Horizon-OC-Monitor/
make -j"$(nproc)"
cp Horizon-OC-Monitor.ovl ../../dist/switch/.overlays/Horizon-OC-Monitor.ovl
cd ../../
ROOT="build"
PATCHES="Source/Atmosphere-Patches"
cp "$PATCHES/secmon_memory_layout.hpp" "$ROOT/libraries/libexosphere/include/exosphere/secmon/"
cp "$PATCHES/secmon_emc_access_table_data.inc" "$ROOT/exosphere/program/source/smc/"
cp "$PATCHES/secmon_define_emc_access_table.inc" "$ROOT/exosphere/program/source/smc/"
cp "$PATCHES/secmon_smc_register_access.cpp" "$ROOT/exosphere/program/source/smc/"
cd build/exosphere
make -j"$(nproc)"
cd out/nintendo_nx_arm64_armv8a/release
cp "exosphere.bin" "../../../../../dist/"
cp Horizon-OC-Monitor.ovl ../../dist/switch/.overlays/Horizon-OC-Monitor.ovl

13
dist/README.md vendored
View File

@@ -41,10 +41,8 @@ It enables advanced CPU, GPU, and RAM tuning with user-friendly configuration to
* Built-in configurator
* Compatible with most homebrew
> *Higher (potentially dangerous) frequencies are unlockable via configuration.*
> *Erista and Mariko units can usually push a bit further fully safely with a bit of undervolting, however this may not work on all units.*
> *The exact maximum overclock possible varies per console, although most consoles should be able to do this safely.*
> *You may refer to the Clock Table to see clocks in more detail*
> It is reccomended to read the [guide](https://rentry.co/howtoget60fps) before proceeding, as this can help you get a *significant* performance boost over the default settings, often times with less power draw and heat output
---
## Installation
@@ -91,15 +89,15 @@ Refer to COMPILATION.md
* 1866 → mariko safe max (3733 Modules), JEDEC.
* 1600 → official docked, boost mode, erista safe max, JEDEC.
* 1331 → official handheld, JEDEC.
* 1065
* 1065
* 800
* 665
### CPU clocks
* 2601 → mariko absolute max, very dangerous
* 2499
* 2397
* 2295 → mariko safe max with UV (low speedo)
* 2397 → mariko safe max with UV (low speedo)
* 2295
* 2193
* 2091
* 1963 → mariko no UV max clock
@@ -153,6 +151,7 @@ Refer to COMPILATION.md
* **Souldbminer** hoc-clk and loader development
* **Lightos** loader patches development
* **SciresM** - Atmosphere CFW
* **CTCaer** - L4T, Hekate, perfect ram timings
* **KazushiMe** Switch OC Suite
* **hanai3bi (meha)** Switch OC Suite, EOS, sys-clk-eos
* **NaGaa95** L4T-OC-kernel

Binary file not shown.

BIN
dist/exosphere.bin vendored

Binary file not shown.

Binary file not shown.

Binary file not shown.