392 Commits
0.29 ... 1.1.0

Author SHA1 Message Date
souldbminersmwc
6bd3ba7b3d final changes 2026-03-22 19:25:47 -04:00
souldbminersmwc
bc06d65b72 sysclk: update translations 2026-03-22 19:14:52 -04:00
souldbminersmwc
7045332ef2 sysclk: fix build script 2026-03-22 19:07:30 -04:00
souldbminersmwc
35bc76074c sysclk: add merged manual translations 2026-03-22 19:03:38 -04:00
souldbminersmwc
cdb725dc86 sysclk: update translation 2026-03-22 18:57:17 -04:00
souldbminersmwc
215ccf9001 sysclk: add machine translations for all languages supported by ultrahand 2026-03-22 18:51:23 -04:00
souldbminersmwc
ec21e47b53 sysclk: rework selection method and fix translation bugs 2026-03-22 18:22:38 -04:00
souldbminersmwc
17e27ad6e9 sysclk: fix default text in temporary overrides for display 2026-03-22 16:55:36 -04:00
souldbminersmwc
7489a861f6 sysclk: fix translation bug 2026-03-22 16:52:22 -04:00
souldbminersmwc
ef65b4dea9 Update all submodules to latest upstream commits 2026-03-22 15:41:10 -04:00
souldbminersmwc
0829cc8545 fix commit stuff 2026-03-22 15:19:19 -04:00
souldbminersmwc
5fb0899bb8 sysclk: fix label 2026-03-21 18:18:21 -04:00
souldbminersmwc
c17d5a3999 sysclk: add missing line, new binaries 2026-03-21 18:15:52 -04:00
souldbminersmwc
42045c5c88 sysclk: more minor changes 2026-03-21 17:52:56 -04:00
souldbminersmwc
6e6f7b4f9f sysclk: display max clock rework 2026-03-21 17:51:01 -04:00
souldbminersmwc
0496839500 sysclk: remove redundant profile options 2026-03-21 17:42:57 -04:00
souldbminersmwc
87911b8b9e sysclk: small TDP rework 2026-03-21 17:38:52 -04:00
souldbminersmwc
d3c441f8ca sysclk: change cpu bugfix wait duration
should fix on 2703mhz
2026-03-21 17:33:02 -04:00
souldbminersmwc
af6b347762 sysclk: fix iddq multiplication 2026-03-21 17:11:26 -04:00
souldbminersmwc
96b6459282 sysclk: read wafer cord 2026-03-21 17:09:10 -04:00
souldbminersmwc
371577954b Merge branch 'main' of https://github.com/Horizon-OC/Horizon-OC 2026-03-21 16:04:19 -04:00
souldbminersmwc
6bdb79fc15 sysclk: remove unused value 2026-03-21 16:04:13 -04:00
Lightos1
e625e4251a add sched off code to rewrite 2026-03-21 18:02:05 +01:00
Lightos1
5d7a77074b actually add uv tuning values... clean this code up 2026-03-21 17:44:01 +01:00
Lightos1
3b907d3ca0 Add live tuning adjustment to rewrite 2026-03-21 17:37:52 +01:00
Lightos1
a697cac43c Add message to assertion 2026-03-21 17:03:46 +01:00
Lightos1
3d5147a6e2 merge pcv hijacking into voltage code 2026-03-21 17:01:50 +01:00
Lightos1
f46d0a714b actually fix the typo 2026-03-21 16:56:10 +01:00
Lightos1
3896c89a5c Revert "Fix typo"
This reverts commit 9afd3d44bd, reversing
changes made to 95930746d2.
2026-03-21 16:54:07 +01:00
Lightos1
dd645bb352 fix typo.
:Merge branch 'main' of https://github.com/horizon-oc/Horizon-OC
2026-03-21 16:48:20 +01:00
Lightos1
9afd3d44bd Fix typo 2026-03-21 16:48:13 +01:00
Lightos1
5db6ac9f25 Lol, we tried pushing code at the same time
Merge branch 'main' of https://github.com/horizon-oc/Horizon-OC
2026-03-21 16:45:00 +01:00
Lightos1
95930746d2 Merge temp and power into sensor 2026-03-21 16:44:32 +01:00
souldbminersmwc
81e6fb9699 sysclk: fix vrr delay
this is unfixable unfortunately due to quirks
2026-03-21 11:44:17 -04:00
souldbminersmwc
8b9fbdf13d sysclk: fix governor min hz 2026-03-21 11:39:50 -04:00
souldbminersmwc
901ab93e58 sysclk: reorder governor trackbars 2026-03-21 11:28:00 -04:00
souldbminersmwc
eb75fb2274 sysclk: fix haschanged logic 2026-03-21 11:02:05 -04:00
souldbminersmwc
dab17f527e sysclk: fix another logic error 2026-03-21 10:59:52 -04:00
souldbminersmwc
aabff0e948 sysclk: fix VRR issues 2026-03-21 10:58:35 -04:00
souldbminersmwc
610bf9ad82 sysclk: fix logic errors 2026-03-21 10:51:03 -04:00
souldbminersmwc
1a42ad1a67 sysclk: RETRO super timings till 60hz, improve support 2026-03-20 20:57:41 -04:00
souldbminersmwc
71f31e8f6a fix check in RETRO SUPER detection code 2026-03-20 20:45:06 -04:00
souldbminersmwc
d6bf10d113 sysclk: retro super support 2026-03-20 20:43:27 -04:00
souldbminersmwc
decd02b564 change display max to 75hz
some good displays can hit 75hz
2026-03-20 20:05:51 -04:00
souldbminersmwc
3b681f8c90 Merge branch 'main' of https://github.com/Horizon-OC/Horizon-OC 2026-03-20 20:03:38 -04:00
souldbminersmwc
95e68bd27e sysclk: fix refresh rate on lite
also increase heap size due to larger ipc packets
2026-03-20 20:03:36 -04:00
Lightos1
dfd5af7e80 add display func, todo: put into different file 2026-03-20 21:31:34 +01:00
Lightos1
0afef60198 add power 2026-03-20 21:24:55 +01:00
Lightos1
714eebb889 add temps 2026-03-20 21:22:02 +01:00
Lightos1
a5f58bfb3a add profile stuff 2026-03-20 21:16:49 +01:00
Lightos1
c29d6244a4 Fix typo 2026-03-20 21:09:43 +01:00
Lightos1
130f9101a2 Add dram id functions 2026-03-20 21:08:55 +01:00
Lightos1
308f39694c Add back misc thread 2026-03-20 21:02:24 +01:00
Lightos1
9e916b5d0f more formating 2026-03-20 20:47:35 +01:00
Lightos1
c2610472ce rewrite: formating 2026-03-20 20:45:59 +01:00
Lightos1
2dbd436307 rewrite: add freq functions 2026-03-20 20:43:08 +01:00
Lightos1
d525991beb Add info about power domains 2026-03-20 19:30:17 +01:00
Lightos1
b3ff426bfe GpuLoadThread: use proper types edition 2 2026-03-20 19:28:17 +01:00
Lightos1
958ca0530d GpuLoadThread: use proper types 2026-03-20 19:27:42 +01:00
Lightos1
981874a450 Change Result * to void * 2026-03-20 19:26:23 +01:00
Lightos1
4502dc6fdb Rewrite: full load 2026-03-20 19:24:45 +01:00
Lightos1
cc78b6193a Rename board_init.cpp -> board.cpp 2026-03-20 19:07:23 +01:00
Lightos1
327d64f22d Rewrite: Add real volts 2026-03-20 19:06:46 +01:00
Lightos1
c36052d477 remove new lines 2026-03-20 18:55:58 +01:00
Lightos1
bc9c30de56 rewrite: add Regulator type to ram oc dvfs 2026-03-20 18:54:48 +01:00
Lightos1
e1c3a7d018 Rewrite: add dvfs 2026-03-20 18:42:52 +01:00
Lightos1
179aee88af *actually* remove it for real 2026-03-20 18:09:42 +01:00
Lightos1
df4a59c269 fully uncomment miscThreadFunc 2026-03-20 18:05:56 +01:00
Lightos1
4d389cda63 what even is miscThreadFunc? 2026-03-20 18:05:00 +01:00
Lightos1
ae56a85811 Hoc-clk rewrite: More load implementation 2026-03-20 18:01:50 +01:00
Lightos1
3e75bd5b95 Start hoc-clk rewrite 2026-03-20 17:46:42 +01:00
souldbminersmwc
2454afd58f sysclk: fix resolution driver again 2026-03-19 19:57:03 -04:00
souldbminersmwc
7244093f21 sysclk: fix resolution 2026-03-19 19:50:20 -04:00
souldbminersmwc
52894e4c93 add resolution 2026-03-19 19:44:33 -04:00
souldbminersmwc
4e0b54c1a8 sysclk: refactor governor settings gui 2026-03-19 19:13:39 -04:00
souldbminersmwc
b5876ede0e sysclk: rework labels and warnings, bump version 2026-03-19 16:50:21 -04:00
souldbminersmwc
9558fd67bb update binaries 2026-03-17 20:33:19 -04:00
souldbminersmwc
59b62a835b misc: fix config bug 2026-03-17 20:30:33 -04:00
souldbminersmwc
ad6847ec59 Update zh-tw.json 2026-03-16 18:38:04 -04:00
Lightos1
061c255978 Change eristaCpuDvfsTable max to 2091, this is fine because vmax exists 2026-03-16 20:04:23 +01:00
Lightos1
bb44d0907d Fix dvfs yet again, todo make this not shit 2026-03-16 20:01:52 +01:00
Lightos1
2215b17a54 Merge pull request #45 from nangongjing1/main
Incorporate Traditional Chinese into Horizon-oc-overlay.
2026-03-16 16:18:46 +01:00
南宫镜
cc52eab3f6 Add files via upload 2026-03-16 23:13:15 +08:00
Lightos1
155a4ce50a Remove redundant else 2026-03-15 21:24:35 +01:00
Lightos1
17739377bd Fix Typo, add todo and ordering cleanup 2026-03-15 21:14:52 +01:00
Lightos1
782fae1624 minimum vmax = 800 2026-03-15 20:49:56 +01:00
Lightos1
59ca1f18d6 Add modified secmon_smc_handler.cpp for panic codes in loader 2026-03-15 20:44:25 +01:00
Lightos1
c6cda6eb30 Remove soctherm region unlock 2026-03-15 20:43:31 +01:00
Lightos1
9f3c5d8de6 Add debug panic codes 2026-03-15 20:35:45 +01:00
Souldbminer
e4c9ac6ee3 Update customize.cpp 2026-03-15 13:05:45 -04:00
souldbminersmwc
5d6500523b bump version 2026-03-15 12:36:32 -04:00
souldbminersmwc
b111ccabb5 sysclk: fix cpugovernorminimumfreq not setting correctly 2026-03-15 12:22:30 -04:00
souldbminersmwc
b90a67aa43 update binaries 2026-03-15 12:21:59 -04:00
souldbminersmwc
9ed72839f4 sysclk: the code should compile now 2026-03-15 10:29:49 -04:00
souldbminersmwc
b8f50da45f more lite changes 2026-03-15 10:27:30 -04:00
souldbminersmwc
1e4dada672 remove display refresh rate on hoag 2026-03-15 10:20:46 -04:00
souldbminersmwc
a943d14807 Revert "sysclk: attempt to fix lite issues"
This reverts commit 2b3889c897.
2026-03-15 10:13:24 -04:00
Lightos1
2cf437ff34 Fix typo 2026-03-15 14:57:09 +01:00
Lightos1
7cbccbbb5b Simplify dram module switch statement 2026-03-15 14:07:12 +01:00
Lightos1
f79af5b6f7 Show ram module in about 2026-03-15 13:59:55 +01:00
Lightos1
05af1d04ff Don't use ram frequency editor for mariko 2026-03-15 13:09:11 +01:00
Lightos1
2753646f06 Revert "Correct version"
This reverts commit 7ec9827db5.
2026-03-14 13:07:47 +01:00
souldbminersmwc
2b3889c897 sysclk: attempt to fix lite issues 2026-03-13 19:55:13 -04:00
souldbminersmwc
e01e346dea sysclk: refine menu 2026-03-13 19:18:26 -04:00
souldbminersmwc
7735037ad9 sysclk: cpu governor is no longer experimental 2026-03-13 18:49:03 -04:00
souldbminersmwc
b2bcd5fc3a sysclk: removed unused vrr config option 2026-03-13 18:40:42 -04:00
souldbminersmwc
a40ea357db sysclk: add per-game VRR setting 2026-03-13 18:35:38 -04:00
souldbminersmwc
7434c22772 sysclk: fix dvfs issue 2026-03-13 15:41:18 -04:00
Lightos1
f0eb25b88c Move sysmodule settings into its own submenu 2026-03-13 20:21:06 +01:00
Lightos1
7ec9827db5 Correct version 2026-03-13 19:48:02 +01:00
Lightos1
eeca31c92e 'merge' frame padding fix 2026-03-13 19:46:47 +01:00
Lightos1
2cd736035c configurator: when uv is active, cpu vmin can only be adjusted in 25mv steps 2026-03-13 17:19:27 +01:00
Lightos1
bc99616e43 erista uv: minor technicality fix 2026-03-13 16:44:11 +01:00
Lightos1
732f27fcf6 add back assertion 2026-03-13 16:25:59 +01:00
Lightos1
54e8465e47 Fix erista mrf 2026-03-13 16:22:47 +01:00
souldbminersmwc
7ceb02c001 bump version 2026-03-12 21:03:09 -04:00
souldbminersmwc
2450a348f1 sysclk: fix polling interval option 2026-03-12 20:57:58 -04:00
Souldbminer
7bd469939e Merge pull request #42 from Horizon-OC/saltynx
Saltynx integration + VRR
2026-03-12 20:53:00 -04:00
souldbminersmwc
89180359c0 todo: fix applet stuff 2026-03-12 20:52:38 -04:00
souldbminersmwc
4259ace5c4 sysclk: properly init applet service 2026-03-12 20:50:02 -04:00
souldbminersmwc
d7e5c38a62 sysclk: add VRR 2026-03-12 20:47:11 -04:00
souldbminersmwc
b601105998 sysclk: fix integration with saltynx 2026-03-12 18:39:57 -04:00
souldbminersmwc
ca07d0716f sysclk: fix up saltynx integration 2026-03-12 16:48:22 -04:00
souldbminersmwc
eb16df3450 fix pointers 2026-03-12 15:51:27 -04:00
souldbminersmwc
b44684760d fix defines 2026-03-12 15:51:06 -04:00
souldbminersmwc
be3fc1bb84 saltynx integration 2026-03-12 15:49:58 -04:00
souldbminersmwc
e781e67b43 sysclk: rework governor
now should work in more games and behave more like a schedutil (slow rampdown, fast rampup)

fixes issues in Kirby and the Forgotten Land
2026-03-11 19:03:46 -04:00
souldbminersmwc
40800ffe4b Revert "sysclk: add notification led driver"
This reverts commit 06e5d5e3d1.
2026-03-11 16:06:58 -04:00
souldbminersmwc
4e704e59e8 fix display oc 2026-03-11 16:06:55 -04:00
souldbminersmwc
06e5d5e3d1 sysclk: add notification led driver 2026-03-10 20:39:09 -04:00
souldbminersmwc
06010d7cd6 hocclk: fix 2397 boost clock 2026-03-10 18:12:28 -04:00
Souldbminer
2549cd9a71 Update README.md 2026-03-09 16:20:10 -04:00
souldbminersmwc
e89e35436e replace banner 2026-03-09 16:19:39 -04:00
Souldbminer
f5029ee3e9 actually remove live cpu uv enforced on erista 2026-03-09 15:44:39 -04:00
Lightos1
08a84e0a8b Clkmgr: remove forced live uv for erista 2026-03-09 20:39:20 +01:00
Lightos1
36c819de04 add cpuVoltDvfsPattern size assertion 2026-03-09 20:31:18 +01:00
Lightos1
f62987af4b remove cpuVoltDvfsOffsets 2026-03-09 20:28:59 +01:00
Lightos1
8d9b44d6ec Fix erista cpu uv, vmin, vmax 2026-03-09 20:26:23 +01:00
Lightos1
a5babb722d erista patches stuff 2026-03-09 20:25:40 +01:00
Lightos1
bde65f094d Misc3: Add missing ram load 2026-03-08 13:27:36 +01:00
Lightos1
3fa2cfabd3 Reorder menus/put settings into submenus to improve scrolling 2026-03-07 23:19:50 +01:00
souldbminersmwc
b8f4d02e4f sysclk: UI rework + bump version 2026-03-07 11:24:21 -05:00
souldbminersmwc
436b7feb8e sysclk: fix dvfs after set logic 2026-03-07 10:35:40 -05:00
souldbminersmwc
8bab4dd6ee Merge branch 'main' of https://github.com/Horizon-OC/Horizon-OC 2026-03-07 10:30:50 -05:00
souldbminersmwc
99dfea631b add rgltr services 2026-03-07 10:30:47 -05:00
Lightos1
16501bd6a8 Remove deprecated configurator 2026-03-01 21:37:31 +01:00
Lightos1
88201b7308 Add/update comments 2026-03-01 21:35:07 +01:00
Lightos1
2fb680b06a Remove ancient todo 2026-03-01 21:32:54 +01:00
Lightos1
fb8116107b correct CpuVoltOfficial for informational purposes 2026-03-01 21:30:54 +01:00
Lightos1
e6b83a1db5 Adjust l4t limit 2026-03-01 21:29:03 +01:00
Lightos1
607a19048b Extend dvfs offset to -80 2026-03-01 21:05:41 +01:00
Lightos1
0db831e0c3 lower cpu vmax 2026-03-01 16:57:38 +01:00
Lightos1
863cca507d lower cpu vmax validators 2026-03-01 16:54:19 +01:00
Lightos1
3916a252d4 Lower max max voltage 2026-03-01 16:53:46 +01:00
souldbminersmwc
1594b76851 100th commit 2026-02-26 15:34:45 -05:00
souldbminersmwc
9e14fc5241 add some more docs 2026-02-24 18:32:54 -05:00
souldbminersmwc
54fd3e2fd1 Update registers.h 2026-02-24 18:27:12 -05:00
souldbminersmwc
2348f8dba2 apparently, claude can't generate defines correctly 2026-02-24 18:24:05 -05:00
souldbminersmwc
f0a3dc48f9 fix live uv 2026-02-24 17:19:58 -05:00
souldbminersmwc
58ad43213b sysclk: add RAM table editor 2026-02-24 17:09:24 -05:00
souldbminersmwc
4a505b7238 update binaries 2026-02-24 16:25:28 -05:00
souldbminersmwc
7c6c0e68d2 Update pcv.cpp 2026-02-24 16:23:42 -05:00
souldbminersmwc
1c5b22710d Update pcv.cpp 2026-02-24 16:22:48 -05:00
souldbminersmwc
75755528b1 Merge branch 'main' of https://github.com/Horizon-OC/Horizon-OC 2026-02-24 16:22:03 -05:00
Lightos1
4dadcaf574 Revert to defaults 2026-02-24 20:17:53 +01:00
Lightos1
5a88d53443 Erista uv stuff: this makes no sense 2026-02-24 20:16:10 +01:00
Lightos1
2bd5faa7d9 Erista uv & vmin fixes 2026-02-24 19:20:41 +01:00
Lightos1
29cb868f50 Improve formating 2026-02-24 09:08:09 +01:00
souldbminersmwc
4eb222f5aa ldr/sysclk: add 2397 erista cpu, fix cpu uv, add erista cpu max clock 2026-02-23 19:09:59 -05:00
souldbminersmwc
eca6ab2297 sysclk: fix erista cpu uv 2026-02-23 18:45:39 -05:00
souldbminersmwc
749e5147df ldr: add commented pll limit patch 2026-02-23 18:44:10 -05:00
souldbminersmwc
55e84d0051 sysclk: fix compile error 2026-02-23 15:08:06 -05:00
souldbminersmwc
8cd9727429 sysclk: fix clock capping bypass bug 2026-02-23 10:39:29 -05:00
Lightos1
660e839bed Extend emc unlock 2026-02-21 19:36:52 +01:00
Lightos1
afb16d2045 Remove lazy rl_dbi stuff 2026-02-21 15:34:38 +01:00
souldbminersmwc
f4b025f33c sysclk: remove display option on hoag and mark cpu governor as experemental 2026-02-20 19:27:04 -05:00
Souldbminer
e03c3b7be0 Update README.md 2026-02-20 17:04:40 -05:00
Lightos1
5a2ba5f785 Board: Fix no sched override 2026-02-20 19:12:51 +01:00
Lightos1
e1463dca05 Bump version 2026-02-20 16:55:34 +01:00
Lightos1
82972127a1 Boost mode: Cpu voltage bug workaround 2026-02-20 16:53:30 +01:00
Lightos1
272eaed351 UI reordering and text removal for smoother scrolling 2026-02-20 16:30:55 +01:00
Lightos1
989e67daac Overlay: Remove unsupported cpu max freq 2026-02-20 15:40:30 +01:00
Lightos1
dcec618ae9 Fix freqs not being set 2026-02-20 15:15:21 +01:00
Lightos1
bc12388b6d formating 2026-02-20 07:34:17 +01:00
Lightos1
6625488180 Formating 2026-02-20 07:33:51 +01:00
Lightos1
1209337af6 Erista: MRf and timing fixes 2026-02-20 07:32:10 +01:00
Souldbminer
0f608b1702 Revise GPU overclocking notes in README
Updated GPU overclocking notes for Erista and Mariko.
2026-02-19 19:59:57 -05:00
Souldbminer
cf547d517b Update testing contributors in README.md 2026-02-19 19:57:54 -05:00
Souldbminer
8c75c68dca Update LICENSE 2026-02-19 19:56:22 -05:00
souldbminersmwc
ab020c0a90 sysclk: code cleanup 2026-02-19 19:41:17 -05:00
souldbminersmwc
44dc402b54 sysclk: revise governor and change override logic 2026-02-19 18:54:21 -05:00
souldbminersmwc
a1d047f48d sysclk: remove atmosphere-libs 2026-02-19 16:36:20 -05:00
souldbminersmwc
cbed5e11ab sysclk: remove unnessesary code 2026-02-19 16:35:12 -05:00
souldbminersmwc
1ad3f6c441 sysclk: add GPU sched ini method 2026-02-19 16:33:55 -05:00
souldbminersmwc
820a26ba2a sysclk: add atmosphere-libs as submodule 2026-02-19 16:11:21 -05:00
souldbminersmwc
f0952119b6 sysclk: add CPU governor and more governor settings 2026-02-18 19:32:33 -05:00
souldbminersmwc
ca5ddbd779 sysclk: fix translation 2026-02-17 10:59:49 -05:00
souldbminersmwc
be49a27118 Update clock_manager.cpp 2026-02-16 18:41:59 -05:00
souldbminersmwc
190353dc11 sysclk: add on-the-fly CPU undervolt 2026-02-16 18:27:26 -05:00
souldbminersmwc
4a1772df77 sysclk: remove unused variable 2026-02-16 14:06:54 -05:00
souldbminersmwc
460d1b8471 sysclk: fix up refresh rate driver 2026-02-16 14:06:35 -05:00
souldbminersmwc
2493c798bc Merge branch 'main' of https://github.com/Horizon-OC/Horizon-OC 2026-02-15 17:44:48 -05:00
souldbminersmwc
7525baf567 sysclk: remove reversenx mode, some code cleanup, display upto 240hz, experemental settings config option, remove max display clock , bump version 2026-02-15 17:43:41 -05:00
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
souldbminersmwc
ebcf07dab8 update files 2026-02-07 17:51:38 -05:00
souldbminersmwc
d170ca92ad ldr: rework reserved entries 2026-02-07 17:51:18 -05:00
souldbminersmwc
cab8a14b99 Merge branch 'develop' of https://github.com/Horizon-OC/Horizon-OC into develop 2026-02-06 19:43:48 -05:00
souldbminersmwc
b623dabce5 sysclk: fix 1963mhz bug 2026-02-06 19:42:58 -05:00
Dominator
e5eb49f2e5 Merge pull request #33 from Blaise-25/develop 2026-02-06 01:47:22 +02:00
Blaise-25
9f0a609735 Update README.md 2026-02-05 15:20:12 -08:00
Souldbminer
19a2e562bc Update README.md 2026-02-05 16:12:30 -05:00
souldbminersmwc
73c3311251 Merge branch 'develop' of https://github.com/Horizon-OC/Horizon-OC into develop 2026-02-04 19:33:30 -05:00
souldbminersmwc
eb7fca1c1a erista ram overclock support + reserved entried
if you use hoc-clk 0.33 and want to update follow these steps

go to config/horizon-oc/config.ini
remove these two entries:

crc32=xxxxxxxxxxx
is_first_load=0
2026-02-04 19:33:10 -05:00
Dominator
ad1f070a6b Update README.md 2026-02-05 01:17:10 +02: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
souldbminersmwc
3bad144280 sysclk: add cat script 2026-02-03 19:01:49 -05:00
souldbminersmwc
123d4b6080 Merge branch 'develop' of https://github.com/Horizon-OC/Horizon-OC into develop 2026-02-03 18:57:02 -05:00
souldbminersmwc
2f6ed69b92 sysclk: refine misc gui 2026-02-03 18:56:48 -05:00
Souldbminer
337f7e6ac0 Merge pull request #32 from OEMunlag/develop
proper github actions build
2026-02-03 15:57:29 -05:00
2fort sink
a5efa7ae72 Add files via upload 2026-02-03 16:55:48 -03:00
2fort sink
a8ee389681 Revert to last working
Updated the Docker image for the build container and removed unnecessary steps for creating compiler shims. Added packaging of the dist folder as a ZIP file with the commit SHA.
2026-02-03 16:40:38 -03:00
2fort sink
54554bacea Change Docker image and install switch-dev
Updated the Docker image for the build container and added a step to install switch-dev.
2026-02-03 16:28:09 -03:00
2fort sink
3da2fc4b6d Merge branch 'Horizon-OC:develop' into develop 2026-02-03 15:05:11 -03:00
2fort sink
83287b1f5c Update build.yml 2026-02-02 21:53:24 -03:00
2fort sink
4f6756c609 Update build.yml 2026-02-02 21:29:05 -03:00
souldbminersmwc
ef2434c457 try to fix status monitor issues 2026-02-02 19:13:08 -05:00
2fort sink
b0237a2042 Update build.yml 2026-02-02 21:07:54 -03:00
2fort sink
c6275eb977 Update build.yml 2026-02-02 20:51:49 -03:00
2fort sink
72961aa2f1 Update build.yml 2026-02-02 20:46:58 -03:00
2fort sink
9c60697344 Merge branch 'Horizon-OC:develop' into develop 2026-02-02 20:45:15 -03:00
2fort sink
f786d97de1 Update build.yml 2026-02-02 20:44:06 -03:00
2fort sink
20389043ac Enhance build.yml with ccache shims for compilers
very hacky I know but we also fix exosphere hopefully with this
2026-02-02 20:37:56 -03:00
souldbminersmwc
00b9d8550e ldr: fix erista cpu validator
this DOES NOT fix erista cpu uv, but is probably part of the issue
2026-02-02 18:18:22 -05:00
2fort sink
0c0a4b3d6b Merge branch 'Horizon-OC:develop' into develop 2026-02-01 19:14:07 -03:00
2fort sink
61fd9d74d3 Update build.yml 2026-02-01 19:14:00 -03:00
2fort sink
f36383d0e7 Update build.yml 2026-02-01 18:58:52 -03:00
souldbminersmwc
606cafbaad sysclk: rework TDP 2026-02-01 16:33:15 -05:00
2fort sink
cff4267a68 Fix ROOT variable assignment in build workflow 2026-02-01 18:32:01 -03:00
2fort sink
65e7d83972 Update build.yml 2026-02-01 18:26:30 -03:00
2fort sink
e2533e2bb0 Patch exosphere and build, fix comment and zip making redundancy 2026-02-01 18:19:23 -03:00
souldbminersmwc
0d4ca24538 sysclk: add kip auto update feature 2026-02-01 16:15:08 -05:00
2fort sink
6c94f5754c Update build.yml 2026-02-01 17:58:52 -03:00
2fort sink
aaf77997e1 Update build.yml 2026-02-01 17:52:44 -03:00
2fort sink
c933e02aed Merge branch 'Horizon-OC:develop' into develop 2026-02-01 17:46:47 -03:00
2fort sink
770c25dbcb build hoc-clk and shallow clone ams
Updated the build process to use shallow clones and added a new build step for the hoc-clk sysmodule and overlay.
2026-02-01 17:44:20 -03:00
souldbminersmwc
bf8a6c4785 sysclk: fix uv3 cappings 2026-02-01 15:27:17 -05:00
2fort sink
dbb4d698a0 Increase make parallel jobs and update file paths 2026-02-01 16:12:26 -03:00
2fort sink
6ae084433f Update build.yml 2026-02-01 15:58:29 -03:00
2fort sink
32f19c4f0e Update build.yml 2026-02-01 15:48:47 -03:00
2fort sink
05cf2ab4dd Clone Atmosphere with specific branch from file 2026-02-01 14:28:37 -03:00
2fort sink
13a4ea4ca0 create ams_ver.txt
Should be self-explanatory, we use this for the actions build system
2026-02-01 14:27:02 -03:00
2fort sink
e2ef52e095 Update build.yml 2026-02-01 14:25:15 -03:00
2fort sink
bbd3b1a0fc Refactor build.yml for environment setup and ccache
Updated the build workflow to set environment variables using GitHub Actions environment files and improved the ccache installation step.
2026-02-01 14:22:31 -03:00
2fort sink
8dcfb55646 retry
cache and actions cache
2026-02-01 14:15:59 -03:00
2fort sink
ae0f4c7963 Delete .github/workflows/build.yml 2026-02-01 13:54:21 -03:00
2fort sink
222db76200 refactor this test testing woo waa waewewe waowowoewewahaaswadisadasud
Updated comments and modified build steps in the GitHub Actions workflow.
2026-02-01 13:52:55 -03:00
souldbminersmwc
2376b85d3a remove build action
way too slow to be practical
2026-01-31 18:52:23 -05:00
souldbminersmwc
26fb76e448 Update build.yml 2026-01-31 18:42:54 -05:00
souldbminersmwc
159c7567c0 Update build.yml 2026-01-31 18:41:42 -05:00
souldbminersmwc
39366ce238 Update build.yml 2026-01-31 18:40:33 -05:00
souldbminersmwc
da631ad268 Create build.yml 2026-01-31 18:37:47 -05:00
souldbminersmwc
d508177d4b Delete build.yml 2026-01-31 17:31:47 -05:00
souldbminersmwc
d8527410de Update build.yml 2026-01-31 17:30:17 -05:00
souldbminersmwc
bae7216de0 Update build.yml 2026-01-31 17:29:34 -05:00
souldbminersmwc
b3ddf172e8 Update build.yml 2026-01-31 17:28:25 -05:00
souldbminersmwc
cdaea8f729 fix build script 2026-01-31 17:27:18 -05:00
souldbminersmwc
918ca5757c chore: add build script 2026-01-31 17:25:30 -05:00
souldbminersmwc
93cb0e99c4 build: remove broken build script 2026-01-31 17:20:06 -05:00
souldbminersmwc
4692529346 chore: clean up repo 2026-01-31 17:19:33 -05:00
souldbminersmwc
8de1191ed5 sysclk: rename ipc service 2026-01-31 17:15:06 -05:00
souldbminersmwc
1c21187f73 sysclk: remove unused stuff 2026-01-31 17:12:50 -05:00
souldbminersmwc
2646995b72 sysclk: rework clock capping 2026-01-30 19:44:12 -05:00
souldbminersmwc
cf21342b2e Update pcv_erista.cpp 2026-01-28 15:45:45 -05:00
souldbminersmwc
3709fb3fba ldr: fix default gpu vmin 2026-01-28 15:41:50 -05:00
souldbminersmwc
ea754707ee sysclk: fix erista gpu vmin 2026-01-28 15:39:56 -05:00
souldbminersmwc
bb96267d6c Adjust license 2026-01-26 19:30:18 -05:00
souldbminersmwc
a1fa16da3c misc changes 2026-01-26 19:29:45 -05:00
souldbminersmwc
aad126d611 rename uv table 2026-01-26 19:26:30 -05:00
souldbminersmwc
835189febc update 2026-01-26 19:23:28 -05:00
souldbminersmwc
a9cf59fe28 ldr: UV3 doesn't exist anymore 2026-01-26 19:08:27 -05:00
souldbminersmwc
7708e4bae6 Update pcv.cpp 2026-01-26 19:07:52 -05:00
souldbminersmwc
8c71227c63 sysclk: improve cpu fix 2026-01-26 16:41:35 -05:00
souldbminersmwc
627732326b Merge branch 'develop' of https://github.com/Horizon-OC/Horizon-OC into develop 2026-01-26 16:26:09 -05:00
souldbminersmwc
f5d9761853 fix cpu bug 2026-01-26 16:25:25 -05:00
Lightos1
1d219e9425 Extend vdd2 validators 2026-01-25 13:07:13 +01:00
Lightos1
2c14ddad5c Extend vddq validator 2026-01-25 11:41:05 +01:00
souldbminersmwc
fee7e7a4f4 Merge branch 'develop' of https://github.com/Horizon-OC/Horizon-OC into develop 2026-01-24 18:54:58 -05:00
souldbminersmwc
caeee5920b sysclk: fix cpu boost clock 2026-01-24 18:54:56 -05:00
Lightos1
71fbeef32a Revert "Update ptm.cpp", worked before
This reverts commit 86fce20b27.
2026-01-24 22:14:19 +01:00
souldbminersmwc
86fce20b27 Update ptm.cpp 2026-01-24 15:17:50 -05:00
Lightos1
5012836c7e finally fix voltage bug for real 2026-01-24 20:43:35 +01:00
Lightos1
af1c36d00a Fix 1333 base latency at >=2533Mhz 2026-01-24 20:13:48 +01:00
souldbminersmwc
5dca0a9d9b Update clock_manager.cpp 2026-01-23 19:49:43 -05:00
souldbminersmwc
d3b1e9d31d sysclk: revise cpu volt bugfix 2026-01-23 18:33:09 -05:00
souldbminersmwc
64301c6d33 sysclk: fix warnings 2026-01-21 19:55:25 -05:00
souldbminersmwc
9b4544856e Update format.h 2026-01-21 18:54:23 -05:00
souldbminersmwc
d8104bfc6f fix submodules yet again 2026-01-21 18:32:20 -05:00
souldbminersmwc
39e666599d finish submodule linking 2026-01-21 18:30:32 -05:00
souldbminersmwc
d3ff7857e7 sysclk: add licensed and link libultrahand as submodules 2026-01-21 18:29:59 -05:00
souldbminersmwc
662473b2c0 sysclk: include libnx globally 2026-01-21 18:23:30 -05:00
souldbminersmwc
051c637dd8 sysclk: add safety check to misc gui 2026-01-21 18:19:30 -05:00
souldbminersmwc
28a772c546 sysclk: add danger/warning colors to cpu max clock 2026-01-21 18:16:59 -05:00
souldbminersmwc
4a06176897 sysclk: add display unsafe freq option 2026-01-21 18:15:28 -05:00
souldbminersmwc
7325905476 Merge branch 'develop' of https://github.com/Horizon-OC/Horizon-OC into develop 2026-01-21 16:47:25 -05:00
souldbminersmwc
ed8eed2c57 bump version 2026-01-21 16:47:20 -05:00
Lightos1
9723fdc2e0 Lazy timing fix, clean up later 2026-01-21 22:45:47 +01:00
souldbminersmwc
2856f6f778 sysclk: add AUTO vmin to overlay and add warning/danger for LCD 2026-01-21 16:44:24 -05:00
Lightos1
4187daf029 Revert "pcv_mariko: unhardcode pllmb divisor"
This reverts commit 12e6f114a8.
2026-01-21 22:32:54 +01:00
souldbminersmwc
c479f9c53c ldr: allow 1963 cpu cap + revise gpu UV 2026-01-21 16:27:14 -05:00
souldbminersmwc
a5357e298a sysclk: fix typo 2026-01-21 15:53:33 -05:00
souldbminersmwc
045bd81887 pcv: fix auto vmin on low speedos 2026-01-21 15:52:54 -05:00
souldbminersmwc
ae22e70602 Merge branch 'develop' of https://github.com/Horizon-OC/Horizon-OC into develop 2026-01-21 15:49:50 -05:00
souldbminersmwc
12e6f114a8 pcv_mariko: unhardcode pllmb divisor 2026-01-21 15:49:43 -05:00
Lightos1
d6fec8bdaa Fix r2p 2026-01-21 21:49:07 +01:00
souldbminersmwc
5a8a9ae79d ldr: fix wev 2026-01-21 15:48:17 -05:00
souldbminersmwc
6d0399f352 ldr/sysclk: update tWRL setting method 2026-01-21 15:45:51 -05:00
Lightos1
382f6d5834 Bump version 2026-01-21 19:53:30 +01:00
Lightos1
679fd4fd79 1866/1600 support 2026-01-21 18:50:36 +01:00
souldbminersmwc
c4a59d72b7 Update horizon-oc-overlay.ovl 2026-01-18 19:39:20 -05:00
souldbminersmwc
cc2f58f1d7 fix settings button 2026-01-18 19:38:22 -05:00
367 changed files with 29355 additions and 47431 deletions

163
.github/workflows/build.yml vendored Normal file
View File

@@ -0,0 +1,163 @@
name: Build Horizon OC Zeus
on:
push:
branches: [ develop, main, master ]
pull_request:
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
# Minimal devkitA64 container
container:
image: devkitpro/devkita64:20251231
steps:
- name: Checkout repository and submodules # needed for hoc-clk
uses: actions/checkout@v6.0.2
with:
submodules: recursive
# -------------------------------------------------
# Fix PATH for devkitA64 and devkitARM
# -------------------------------------------------
- name: Set devkitPro PATH
run: |
echo "DEVKITPRO=/opt/devkitpro" >> $GITHUB_ENV
echo "DEVKITA64=/opt/devkitpro/devkitA64" >> $GITHUB_ENV
echo "DEVKITARM=/opt/devkitpro/devkitARM" >> $GITHUB_ENV
echo "PATH=/opt/devkitpro/devkitA64/bin:/opt/devkitpro/devkitARM/bin:$PATH" >> $GITHUB_ENV
shell: bash
- name: Check devkitPro gcc and g++ versions
run: |
aarch64-none-elf-gcc --version
aarch64-none-elf-g++ --version
shell: bash # is this even needed? but for consistency let's keep using it
- name: Install ccache
run: |
apt-get update
apt-get install -y ccache
shell: bash
# -------------------------------------------------
# Get short commit SHA
# -------------------------------------------------
- name: Set commit SHA & dist
id: vars
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)
- name: Prepare build folder
run: |
mkdir -p build
cp -r atmosphere/* build/
- name: Override ldr_process_creation.cpp
run: |
cp -rf Source/Atmosphere/stratosphere/loader/source/* build/stratosphere/loader/source/
- name: Cache ccache
uses: actions/cache@v5.0.3
with:
path: /root/.cache/ccache
key: ccache-${{ runner.os }}-devkitpro-ams-${{ hashFiles('ams_ver.txt') }} # last key was utter garbage, stick to ams versions,
restore-keys: |
ccache-${{ runner.os }}-devkitpro-
- name: Configure ccache
run: |
export CCACHE_DIR=/root/.cache/ccache
echo "CCACHE_DIR=/root/.cache/ccache" >> $GITHUB_ENV
ccache --set-config=max_size=10G
ccache --set-config=compiler_check=content
ccache --zero-stats
- name: Build hoc-clk sysmodule and overlay
shell: bash
run: |
export CC="ccache aarch64-none-elf-gcc"
export CXX="ccache aarch64-none-elf-g++"
ROOT_DIR="$GITHUB_WORKSPACE/Source/sys-clk"
DIST_DIR="$ROOT_DIR/dist"
mkdir -p "$DIST_DIR"
echo "*** sysmodule ***"
TITLE_ID="$(grep -oP '"title_id":\s*"0x\K(\w+)' \
"$ROOT_DIR/sysmodule/perms.json")"
echo "TITLE_ID: $TITLE_ID"
pushd "$ROOT_DIR/sysmodule"
make -j$(($(nproc) * 2)) CXX="ccache aarch64-none-elf-g++" CC="ccache aarch64-none-elf-gcc"
popd
mkdir -p "$DIST_DIR/atmosphere/contents/$TITLE_ID/flags"
cp -vf \
"$ROOT_DIR/sysmodule/out/horizon-oc.nsp" \
"$DIST_DIR/atmosphere/contents/$TITLE_ID/exefs.nsp"
: >"$DIST_DIR/atmosphere/contents/$TITLE_ID/flags/boot2.flag"
cp -vf \
"$ROOT_DIR/sysmodule/toolbox.json" \
"$DIST_DIR/atmosphere/contents/$TITLE_ID/toolbox.json"
echo "*** overlay ***"
pushd "$ROOT_DIR/overlay"
make -j$(($(nproc) * 2)) CXX="ccache aarch64-none-elf-g++" CC="ccache aarch64-none-elf-gcc"
popd
mkdir -p "$DIST_DIR/switch/.overlays"
cp -vf \
"$ROOT_DIR/overlay/out/horizon-oc-overlay.ovl" \
"$DIST_DIR/switch/.overlays/horizon-oc-overlay.ovl"
echo "*** assets ***"
mkdir -p "$DIST_DIR/config/horizon-oc"
cp -vf \
"$ROOT_DIR/config.ini.template" \
"$DIST_DIR/config/horizon-oc/config.ini.template"
cp -vf \
"$ROOT_DIR/README.md" \
"$DIST_DIR/README.md"
- name: Build kip
working-directory: build/stratosphere/loader
run: |
export CC="ccache aarch64-none-elf-gcc"
export CXX="ccache aarch64-none-elf-g++"
make -j$(($(nproc) * 4)) CXX="ccache aarch64-none-elf-g++" CC="ccache aarch64-none-elf-gcc"
hactool -t kip1 out/nintendo_nx_arm64_armv8a/release/loader.kip --uncompress=hoc.kip
cp hoc.kip ../../../dist/atmosphere/kips/hoc.kip
- name: ccache stats
run: ccache --show-stats
# -------------------------------------------------
# Upload ZIP artifact
# -------------------------------------------------
- name: Upload build artifact
uses: actions/upload-artifact@v6
with:
name: horizon-oc-zeus-dist
path: dist/
compression-level: 3

16
.gitmodules vendored
View File

@@ -1,6 +1,12 @@
[submodule "Source/Horizon-OC-Monitor/lib/Atmosphere-libs"]
path = Source/Horizon-OC-Monitor/lib/Atmosphere-libs
url = https://github.com/Atmosphere-NX/Atmosphere-libs
[submodule "Source/Horizon-OC-Monitor/lib/libultrahand"]
path = Source/Horizon-OC-Monitor/lib/libultrahand
[submodule "Source/Horizon-OC-Monitor/lib/Atmosphere-libs"]
path = Source/Horizon-OC-Monitor/lib/Atmosphere-libs
url = https://github.com/Atmosphere-NX/Atmosphere-libs
branch = master
[submodule "Source/Horizon-OC-Monitor/lib/libultrahand"]
path = Source/Horizon-OC-Monitor/lib/libultrahand
url = https://github.com/ppkantorski/libultrahand
branch = main
[submodule "Source/sys-clk/overlay/lib/libultrahand"]
path = Source/sys-clk/overlay/lib/libultrahand
url = https://github.com/ppkantorski/libultrahand
branch = main

View File

@@ -1,967 +0,0 @@
/*
* Copyright (c) Atmosphère-NX
*
* 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/>.
*/
SetRegisterAllowed(0x0);
SetRegisterAllowed(0x4);
SetRegisterAllowed(0x8);
SetRegisterAllowed(0xC);
SetRegisterAllowed(0x10);
SetRegisterAllowed(0x14);
SetRegisterAllowed(0x18);
SetRegisterAllowed(0x1C);
SetRegisterAllowed(0x20);
SetRegisterAllowed(0x24);
SetRegisterAllowed(0x28);
SetRegisterAllowed(0x2C);
SetRegisterAllowed(0x30);
SetRegisterAllowed(0x34);
SetRegisterAllowed(0x38);
SetRegisterAllowed(0x3C);
SetRegisterAllowed(0x40);
SetRegisterAllowed(0x44);
SetRegisterAllowed(0x48);
SetRegisterAllowed(0x4C);
SetRegisterAllowed(0x50);
SetRegisterAllowed(0x54);
SetRegisterAllowed(0x58);
SetRegisterAllowed(0x5C);
SetRegisterAllowed(0x60);
SetRegisterAllowed(0x64);
SetRegisterAllowed(0x68);
SetRegisterAllowed(0x6C);
SetRegisterAllowed(0x70);
SetRegisterAllowed(0x74);
SetRegisterAllowed(0x78);
SetRegisterAllowed(0x7C);
SetRegisterAllowed(0x80);
SetRegisterAllowed(0x84);
SetRegisterAllowed(0x88);
SetRegisterAllowed(0x8C);
SetRegisterAllowed(0x90);
SetRegisterAllowed(0x94);
SetRegisterAllowed(0x98);
SetRegisterAllowed(0x9C);
SetRegisterAllowed(0xA0);
SetRegisterAllowed(0xA4);
SetRegisterAllowed(0xA8);
SetRegisterAllowed(0xAC);
SetRegisterAllowed(0xB0);
SetRegisterAllowed(0xB4);
SetRegisterAllowed(0xB8);
SetRegisterAllowed(0xBC);
SetRegisterAllowed(0xC0);
SetRegisterAllowed(0xC4);
SetRegisterAllowed(0xC8);
SetRegisterAllowed(0xCC);
SetRegisterAllowed(0xD0);
SetRegisterAllowed(0xD4);
SetRegisterAllowed(0xD8);
SetRegisterAllowed(0xDC);
SetRegisterAllowed(0xE0);
SetRegisterAllowed(0xE4);
SetRegisterAllowed(0xE8);
SetRegisterAllowed(0xEC);
SetRegisterAllowed(0xF0);
SetRegisterAllowed(0xF4);
SetRegisterAllowed(0xF8);
SetRegisterAllowed(0xFC);
SetRegisterAllowed(0x100);
SetRegisterAllowed(0x104);
SetRegisterAllowed(0x108);
SetRegisterAllowed(0x10C);
SetRegisterAllowed(0x110);
SetRegisterAllowed(0x114);
SetRegisterAllowed(0x118);
SetRegisterAllowed(0x11C);
SetRegisterAllowed(0x120);
SetRegisterAllowed(0x124);
SetRegisterAllowed(0x128);
SetRegisterAllowed(0x12C);
SetRegisterAllowed(0x130);
SetRegisterAllowed(0x134);
SetRegisterAllowed(0x138);
SetRegisterAllowed(0x13C);
SetRegisterAllowed(0x140);
SetRegisterAllowed(0x144);
SetRegisterAllowed(0x148);
SetRegisterAllowed(0x14C);
SetRegisterAllowed(0x150);
SetRegisterAllowed(0x154);
SetRegisterAllowed(0x158);
SetRegisterAllowed(0x15C);
SetRegisterAllowed(0x160);
SetRegisterAllowed(0x164);
SetRegisterAllowed(0x168);
SetRegisterAllowed(0x16C);
SetRegisterAllowed(0x170);
SetRegisterAllowed(0x174);
SetRegisterAllowed(0x178);
SetRegisterAllowed(0x17C);
SetRegisterAllowed(0x180);
SetRegisterAllowed(0x184);
SetRegisterAllowed(0x188);
SetRegisterAllowed(0x18C);
SetRegisterAllowed(0x190);
SetRegisterAllowed(0x194);
SetRegisterAllowed(0x198);
SetRegisterAllowed(0x19C);
SetRegisterAllowed(0x1A0);
SetRegisterAllowed(0x1A4);
SetRegisterAllowed(0x1A8);
SetRegisterAllowed(0x1AC);
SetRegisterAllowed(0x1B0);
SetRegisterAllowed(0x1B4);
SetRegisterAllowed(0x1B8);
SetRegisterAllowed(0x1BC);
SetRegisterAllowed(0x1C0);
SetRegisterAllowed(0x1C4);
SetRegisterAllowed(0x1C8);
SetRegisterAllowed(0x1CC);
SetRegisterAllowed(0x1D0);
SetRegisterAllowed(0x1D4);
SetRegisterAllowed(0x1D8);
SetRegisterAllowed(0x1DC);
SetRegisterAllowed(0x1E0);
SetRegisterAllowed(0x1E4);
SetRegisterAllowed(0x1E8);
SetRegisterAllowed(0x1EC);
SetRegisterAllowed(0x1F0);
SetRegisterAllowed(0x1F4);
SetRegisterAllowed(0x1F8);
SetRegisterAllowed(0x1FC);
SetRegisterAllowed(0x200);
SetRegisterAllowed(0x204);
SetRegisterAllowed(0x208);
SetRegisterAllowed(0x20C);
SetRegisterAllowed(0x210);
SetRegisterAllowed(0x214);
SetRegisterAllowed(0x218);
SetRegisterAllowed(0x21C);
SetRegisterAllowed(0x220);
SetRegisterAllowed(0x224);
SetRegisterAllowed(0x228);
SetRegisterAllowed(0x22C);
SetRegisterAllowed(0x230);
SetRegisterAllowed(0x234);
SetRegisterAllowed(0x238);
SetRegisterAllowed(0x23C);
SetRegisterAllowed(0x240);
SetRegisterAllowed(0x244);
SetRegisterAllowed(0x248);
SetRegisterAllowed(0x24C);
SetRegisterAllowed(0x250);
SetRegisterAllowed(0x254);
SetRegisterAllowed(0x258);
SetRegisterAllowed(0x25C);
SetRegisterAllowed(0x260);
SetRegisterAllowed(0x264);
SetRegisterAllowed(0x268);
SetRegisterAllowed(0x26C);
SetRegisterAllowed(0x270);
SetRegisterAllowed(0x274);
SetRegisterAllowed(0x278);
SetRegisterAllowed(0x27C);
SetRegisterAllowed(0x280);
SetRegisterAllowed(0x284);
SetRegisterAllowed(0x288);
SetRegisterAllowed(0x28C);
SetRegisterAllowed(0x290);
SetRegisterAllowed(0x294);
SetRegisterAllowed(0x298);
SetRegisterAllowed(0x29C);
SetRegisterAllowed(0x2A0);
SetRegisterAllowed(0x2A4);
SetRegisterAllowed(0x2A8);
SetRegisterAllowed(0x2AC);
SetRegisterAllowed(0x2B0);
SetRegisterAllowed(0x2B4);
SetRegisterAllowed(0x2B8);
SetRegisterAllowed(0x2BC);
SetRegisterAllowed(0x2C0);
SetRegisterAllowed(0x2C4);
SetRegisterAllowed(0x2C8);
SetRegisterAllowed(0x2CC);
SetRegisterAllowed(0x2D0);
SetRegisterAllowed(0x2D4);
SetRegisterAllowed(0x2D8);
SetRegisterAllowed(0x2DC);
SetRegisterAllowed(0x2E0);
SetRegisterAllowed(0x2E4);
SetRegisterAllowed(0x2E8);
SetRegisterAllowed(0x2EC);
SetRegisterAllowed(0x2F0);
SetRegisterAllowed(0x2F4);
SetRegisterAllowed(0x2F8);
SetRegisterAllowed(0x2FC);
SetRegisterAllowed(0x300);
SetRegisterAllowed(0x304);
SetRegisterAllowed(0x308);
SetRegisterAllowed(0x30C);
SetRegisterAllowed(0x310);
SetRegisterAllowed(0x314);
SetRegisterAllowed(0x318);
SetRegisterAllowed(0x31C);
SetRegisterAllowed(0x320);
SetRegisterAllowed(0x324);
SetRegisterAllowed(0x328);
SetRegisterAllowed(0x32C);
SetRegisterAllowed(0x330);
SetRegisterAllowed(0x334);
SetRegisterAllowed(0x338);
SetRegisterAllowed(0x33C);
SetRegisterAllowed(0x340);
SetRegisterAllowed(0x344);
SetRegisterAllowed(0x348);
SetRegisterAllowed(0x34C);
SetRegisterAllowed(0x350);
SetRegisterAllowed(0x354);
SetRegisterAllowed(0x358);
SetRegisterAllowed(0x35C);
SetRegisterAllowed(0x360);
SetRegisterAllowed(0x364);
SetRegisterAllowed(0x368);
SetRegisterAllowed(0x36C);
SetRegisterAllowed(0x370);
SetRegisterAllowed(0x374);
SetRegisterAllowed(0x378);
SetRegisterAllowed(0x37C);
SetRegisterAllowed(0x380);
SetRegisterAllowed(0x384);
SetRegisterAllowed(0x388);
SetRegisterAllowed(0x38C);
SetRegisterAllowed(0x390);
SetRegisterAllowed(0x394);
SetRegisterAllowed(0x398);
SetRegisterAllowed(0x39C);
SetRegisterAllowed(0x3A0);
SetRegisterAllowed(0x3A4);
SetRegisterAllowed(0x3A8);
SetRegisterAllowed(0x3AC);
SetRegisterAllowed(0x3B0);
SetRegisterAllowed(0x3B4);
SetRegisterAllowed(0x3B8);
SetRegisterAllowed(0x3BC);
SetRegisterAllowed(0x3C0);
SetRegisterAllowed(0x3C4);
SetRegisterAllowed(0x3C8);
SetRegisterAllowed(0x3CC);
SetRegisterAllowed(0x3D0);
SetRegisterAllowed(0x3D4);
SetRegisterAllowed(0x3D8);
SetRegisterAllowed(0x3DC);
SetRegisterAllowed(0x3E0);
SetRegisterAllowed(0x3E4);
SetRegisterAllowed(0x3E8);
SetRegisterAllowed(0x3EC);
SetRegisterAllowed(0x3F0);
SetRegisterAllowed(0x3F4);
SetRegisterAllowed(0x3F8);
SetRegisterAllowed(0x3FC);
SetRegisterAllowed(0x400);
SetRegisterAllowed(0x404);
SetRegisterAllowed(0x408);
SetRegisterAllowed(0x40C);
SetRegisterAllowed(0x410);
SetRegisterAllowed(0x414);
SetRegisterAllowed(0x418);
SetRegisterAllowed(0x41C);
SetRegisterAllowed(0x420);
SetRegisterAllowed(0x424);
SetRegisterAllowed(0x428);
SetRegisterAllowed(0x42C);
SetRegisterAllowed(0x430);
SetRegisterAllowed(0x434);
SetRegisterAllowed(0x438);
SetRegisterAllowed(0x43C);
SetRegisterAllowed(0x440);
SetRegisterAllowed(0x444);
SetRegisterAllowed(0x448);
SetRegisterAllowed(0x44C);
SetRegisterAllowed(0x450);
SetRegisterAllowed(0x454);
SetRegisterAllowed(0x458);
SetRegisterAllowed(0x45C);
SetRegisterAllowed(0x460);
SetRegisterAllowed(0x464);
SetRegisterAllowed(0x468);
SetRegisterAllowed(0x46C);
SetRegisterAllowed(0x470);
SetRegisterAllowed(0x474);
SetRegisterAllowed(0x478);
SetRegisterAllowed(0x47C);
SetRegisterAllowed(0x480);
SetRegisterAllowed(0x484);
SetRegisterAllowed(0x488);
SetRegisterAllowed(0x48C);
SetRegisterAllowed(0x490);
SetRegisterAllowed(0x494);
SetRegisterAllowed(0x498);
SetRegisterAllowed(0x49C);
SetRegisterAllowed(0x4A0);
SetRegisterAllowed(0x4A4);
SetRegisterAllowed(0x4A8);
SetRegisterAllowed(0x4AC);
SetRegisterAllowed(0x4B0);
SetRegisterAllowed(0x4B4);
SetRegisterAllowed(0x4B8);
SetRegisterAllowed(0x4BC);
SetRegisterAllowed(0x4C0);
SetRegisterAllowed(0x4C4);
SetRegisterAllowed(0x4C8);
SetRegisterAllowed(0x4CC);
SetRegisterAllowed(0x4D0);
SetRegisterAllowed(0x4D4);
SetRegisterAllowed(0x4D8);
SetRegisterAllowed(0x4DC);
SetRegisterAllowed(0x4E0);
SetRegisterAllowed(0x4E4);
SetRegisterAllowed(0x4E8);
SetRegisterAllowed(0x4EC);
SetRegisterAllowed(0x4F0);
SetRegisterAllowed(0x4F4);
SetRegisterAllowed(0x4F8);
SetRegisterAllowed(0x4FC);
SetRegisterAllowed(0x500);
SetRegisterAllowed(0x504);
SetRegisterAllowed(0x508);
SetRegisterAllowed(0x50C);
SetRegisterAllowed(0x510);
SetRegisterAllowed(0x514);
SetRegisterAllowed(0x518);
SetRegisterAllowed(0x51C);
SetRegisterAllowed(0x520);
SetRegisterAllowed(0x524);
SetRegisterAllowed(0x528);
SetRegisterAllowed(0x52C);
SetRegisterAllowed(0x530);
SetRegisterAllowed(0x534);
SetRegisterAllowed(0x538);
SetRegisterAllowed(0x53C);
SetRegisterAllowed(0x540);
SetRegisterAllowed(0x544);
SetRegisterAllowed(0x548);
SetRegisterAllowed(0x54C);
SetRegisterAllowed(0x550);
SetRegisterAllowed(0x554);
SetRegisterAllowed(0x558);
SetRegisterAllowed(0x55C);
SetRegisterAllowed(0x560);
SetRegisterAllowed(0x564);
SetRegisterAllowed(0x568);
SetRegisterAllowed(0x56C);
SetRegisterAllowed(0x570);
SetRegisterAllowed(0x574);
SetRegisterAllowed(0x578);
SetRegisterAllowed(0x57C);
SetRegisterAllowed(0x580);
SetRegisterAllowed(0x584);
SetRegisterAllowed(0x588);
SetRegisterAllowed(0x58C);
SetRegisterAllowed(0x590);
SetRegisterAllowed(0x594);
SetRegisterAllowed(0x598);
SetRegisterAllowed(0x59C);
SetRegisterAllowed(0x5A0);
SetRegisterAllowed(0x5A4);
SetRegisterAllowed(0x5A8);
SetRegisterAllowed(0x5AC);
SetRegisterAllowed(0x5B0);
SetRegisterAllowed(0x5B4);
SetRegisterAllowed(0x5B8);
SetRegisterAllowed(0x5BC);
SetRegisterAllowed(0x5C0);
SetRegisterAllowed(0x5C4);
SetRegisterAllowed(0x5C8);
SetRegisterAllowed(0x5CC);
SetRegisterAllowed(0x5D0);
SetRegisterAllowed(0x5D4);
SetRegisterAllowed(0x5D8);
SetRegisterAllowed(0x5DC);
SetRegisterAllowed(0x5E0);
SetRegisterAllowed(0x5E4);
SetRegisterAllowed(0x5E8);
SetRegisterAllowed(0x5EC);
SetRegisterAllowed(0x5F0);
SetRegisterAllowed(0x5F4);
SetRegisterAllowed(0x5F8);
SetRegisterAllowed(0x5FC);
SetRegisterAllowed(0x600);
SetRegisterAllowed(0x604);
SetRegisterAllowed(0x608);
SetRegisterAllowed(0x60C);
SetRegisterAllowed(0x610);
SetRegisterAllowed(0x614);
SetRegisterAllowed(0x618);
SetRegisterAllowed(0x61C);
SetRegisterAllowed(0x620);
SetRegisterAllowed(0x624);
SetRegisterAllowed(0x628);
SetRegisterAllowed(0x62C);
SetRegisterAllowed(0x630);
SetRegisterAllowed(0x634);
SetRegisterAllowed(0x638);
SetRegisterAllowed(0x63C);
SetRegisterAllowed(0x640);
SetRegisterAllowed(0x644);
SetRegisterAllowed(0x648);
SetRegisterAllowed(0x64C);
SetRegisterAllowed(0x650);
SetRegisterAllowed(0x654);
SetRegisterAllowed(0x658);
SetRegisterAllowed(0x65C);
SetRegisterAllowed(0x660);
SetRegisterAllowed(0x664);
SetRegisterAllowed(0x668);
SetRegisterAllowed(0x66C);
SetRegisterAllowed(0x670);
SetRegisterAllowed(0x674);
SetRegisterAllowed(0x678);
SetRegisterAllowed(0x67C);
SetRegisterAllowed(0x680);
SetRegisterAllowed(0x684);
SetRegisterAllowed(0x688);
SetRegisterAllowed(0x68C);
SetRegisterAllowed(0x690);
SetRegisterAllowed(0x694);
SetRegisterAllowed(0x698);
SetRegisterAllowed(0x69C);
SetRegisterAllowed(0x6A0);
SetRegisterAllowed(0x6A4);
SetRegisterAllowed(0x6A8);
SetRegisterAllowed(0x6AC);
SetRegisterAllowed(0x6B0);
SetRegisterAllowed(0x6B4);
SetRegisterAllowed(0x6B8);
SetRegisterAllowed(0x6BC);
SetRegisterAllowed(0x6C0);
SetRegisterAllowed(0x6C4);
SetRegisterAllowed(0x6C8);
SetRegisterAllowed(0x6CC);
SetRegisterAllowed(0x6D0);
SetRegisterAllowed(0x6D4);
SetRegisterAllowed(0x6D8);
SetRegisterAllowed(0x6DC);
SetRegisterAllowed(0x6E0);
SetRegisterAllowed(0x6E4);
SetRegisterAllowed(0x6E8);
SetRegisterAllowed(0x6EC);
SetRegisterAllowed(0x6F0);
SetRegisterAllowed(0x6F4);
SetRegisterAllowed(0x6F8);
SetRegisterAllowed(0x6FC);
SetRegisterAllowed(0x700);
SetRegisterAllowed(0x704);
SetRegisterAllowed(0x708);
SetRegisterAllowed(0x70C);
SetRegisterAllowed(0x710);
SetRegisterAllowed(0x714);
SetRegisterAllowed(0x718);
SetRegisterAllowed(0x71C);
SetRegisterAllowed(0x720);
SetRegisterAllowed(0x724);
SetRegisterAllowed(0x728);
SetRegisterAllowed(0x72C);
SetRegisterAllowed(0x730);
SetRegisterAllowed(0x734);
SetRegisterAllowed(0x738);
SetRegisterAllowed(0x73C);
SetRegisterAllowed(0x740);
SetRegisterAllowed(0x744);
SetRegisterAllowed(0x748);
SetRegisterAllowed(0x74C);
SetRegisterAllowed(0x750);
SetRegisterAllowed(0x754);
SetRegisterAllowed(0x758);
SetRegisterAllowed(0x75C);
SetRegisterAllowed(0x760);
SetRegisterAllowed(0x764);
SetRegisterAllowed(0x768);
SetRegisterAllowed(0x76C);
SetRegisterAllowed(0x770);
SetRegisterAllowed(0x774);
SetRegisterAllowed(0x778);
SetRegisterAllowed(0x77C);
SetRegisterAllowed(0x780);
SetRegisterAllowed(0x784);
SetRegisterAllowed(0x788);
SetRegisterAllowed(0x78C);
SetRegisterAllowed(0x790);
SetRegisterAllowed(0x794);
SetRegisterAllowed(0x798);
SetRegisterAllowed(0x79C);
SetRegisterAllowed(0x7A0);
SetRegisterAllowed(0x7A4);
SetRegisterAllowed(0x7A8);
SetRegisterAllowed(0x7AC);
SetRegisterAllowed(0x7B0);
SetRegisterAllowed(0x7B4);
SetRegisterAllowed(0x7B8);
SetRegisterAllowed(0x7BC);
SetRegisterAllowed(0x7C0);
SetRegisterAllowed(0x7C4);
SetRegisterAllowed(0x7C8);
SetRegisterAllowed(0x7CC);
SetRegisterAllowed(0x7D0);
SetRegisterAllowed(0x7D4);
SetRegisterAllowed(0x7D8);
SetRegisterAllowed(0x7DC);
SetRegisterAllowed(0x7E0);
SetRegisterAllowed(0x7E4);
SetRegisterAllowed(0x7E8);
SetRegisterAllowed(0x7EC);
SetRegisterAllowed(0x7F0);
SetRegisterAllowed(0x7F4);
SetRegisterAllowed(0x7F8);
SetRegisterAllowed(0x7FC);
SetRegisterAllowed(0x800);
SetRegisterAllowed(0x804);
SetRegisterAllowed(0x808);
SetRegisterAllowed(0x80C);
SetRegisterAllowed(0x810);
SetRegisterAllowed(0x814);
SetRegisterAllowed(0x818);
SetRegisterAllowed(0x81C);
SetRegisterAllowed(0x820);
SetRegisterAllowed(0x824);
SetRegisterAllowed(0x828);
SetRegisterAllowed(0x82C);
SetRegisterAllowed(0x830);
SetRegisterAllowed(0x834);
SetRegisterAllowed(0x838);
SetRegisterAllowed(0x83C);
SetRegisterAllowed(0x840);
SetRegisterAllowed(0x844);
SetRegisterAllowed(0x848);
SetRegisterAllowed(0x84C);
SetRegisterAllowed(0x850);
SetRegisterAllowed(0x854);
SetRegisterAllowed(0x858);
SetRegisterAllowed(0x85C);
SetRegisterAllowed(0x860);
SetRegisterAllowed(0x864);
SetRegisterAllowed(0x868);
SetRegisterAllowed(0x86C);
SetRegisterAllowed(0x870);
SetRegisterAllowed(0x874);
SetRegisterAllowed(0x878);
SetRegisterAllowed(0x87C);
SetRegisterAllowed(0x880);
SetRegisterAllowed(0x884);
SetRegisterAllowed(0x888);
SetRegisterAllowed(0x88C);
SetRegisterAllowed(0x890);
SetRegisterAllowed(0x894);
SetRegisterAllowed(0x898);
SetRegisterAllowed(0x89C);
SetRegisterAllowed(0x8A0);
SetRegisterAllowed(0x8A4);
SetRegisterAllowed(0x8A8);
SetRegisterAllowed(0x8AC);
SetRegisterAllowed(0x8B0);
SetRegisterAllowed(0x8B4);
SetRegisterAllowed(0x8B8);
SetRegisterAllowed(0x8BC);
SetRegisterAllowed(0x8C0);
SetRegisterAllowed(0x8C4);
SetRegisterAllowed(0x8C8);
SetRegisterAllowed(0x8CC);
SetRegisterAllowed(0x8D0);
SetRegisterAllowed(0x8D4);
SetRegisterAllowed(0x8D8);
SetRegisterAllowed(0x8DC);
SetRegisterAllowed(0x8E0);
SetRegisterAllowed(0x8E4);
SetRegisterAllowed(0x8E8);
SetRegisterAllowed(0x8EC);
SetRegisterAllowed(0x8F0);
SetRegisterAllowed(0x8F4);
SetRegisterAllowed(0x8F8);
SetRegisterAllowed(0x8FC);
SetRegisterAllowed(0x900);
SetRegisterAllowed(0x904);
SetRegisterAllowed(0x908);
SetRegisterAllowed(0x90C);
SetRegisterAllowed(0x910);
SetRegisterAllowed(0x914);
SetRegisterAllowed(0x918);
SetRegisterAllowed(0x91C);
SetRegisterAllowed(0x920);
SetRegisterAllowed(0x924);
SetRegisterAllowed(0x928);
SetRegisterAllowed(0x92C);
SetRegisterAllowed(0x930);
SetRegisterAllowed(0x934);
SetRegisterAllowed(0x938);
SetRegisterAllowed(0x93C);
SetRegisterAllowed(0x940);
SetRegisterAllowed(0x944);
SetRegisterAllowed(0x948);
SetRegisterAllowed(0x94C);
SetRegisterAllowed(0x950);
SetRegisterAllowed(0x954);
SetRegisterAllowed(0x958);
SetRegisterAllowed(0x95C);
SetRegisterAllowed(0x960);
SetRegisterAllowed(0x964);
SetRegisterAllowed(0x968);
SetRegisterAllowed(0x96C);
SetRegisterAllowed(0x970);
SetRegisterAllowed(0x974);
SetRegisterAllowed(0x978);
SetRegisterAllowed(0x97C);
SetRegisterAllowed(0x980);
SetRegisterAllowed(0x984);
SetRegisterAllowed(0x988);
SetRegisterAllowed(0x98C);
SetRegisterAllowed(0x990);
SetRegisterAllowed(0x994);
SetRegisterAllowed(0x998);
SetRegisterAllowed(0x99C);
SetRegisterAllowed(0x9A0);
SetRegisterAllowed(0x9A4);
SetRegisterAllowed(0x9A8);
SetRegisterAllowed(0x9AC);
SetRegisterAllowed(0x9B0);
SetRegisterAllowed(0x9B4);
SetRegisterAllowed(0x9B8);
SetRegisterAllowed(0x9BC);
SetRegisterAllowed(0x9C0);
SetRegisterAllowed(0x9C4);
SetRegisterAllowed(0x9C8);
SetRegisterAllowed(0x9CC);
SetRegisterAllowed(0x9D0);
SetRegisterAllowed(0x9D4);
SetRegisterAllowed(0x9D8);
SetRegisterAllowed(0x9DC);
SetRegisterAllowed(0x9E0);
SetRegisterAllowed(0x9E4);
SetRegisterAllowed(0x9E8);
SetRegisterAllowed(0x9EC);
SetRegisterAllowed(0x9F0);
SetRegisterAllowed(0x9F4);
SetRegisterAllowed(0x9F8);
SetRegisterAllowed(0x9FC);
SetRegisterAllowed(0xA00);
SetRegisterAllowed(0xA04);
SetRegisterAllowed(0xA08);
SetRegisterAllowed(0xA0C);
SetRegisterAllowed(0xA10);
SetRegisterAllowed(0xA14);
SetRegisterAllowed(0xA18);
SetRegisterAllowed(0xA1C);
SetRegisterAllowed(0xA20);
SetRegisterAllowed(0xA24);
SetRegisterAllowed(0xA28);
SetRegisterAllowed(0xA2C);
SetRegisterAllowed(0xA30);
SetRegisterAllowed(0xA34);
SetRegisterAllowed(0xA38);
SetRegisterAllowed(0xA3C);
SetRegisterAllowed(0xA40);
SetRegisterAllowed(0xA44);
SetRegisterAllowed(0xA48);
SetRegisterAllowed(0xA4C);
SetRegisterAllowed(0xA50);
SetRegisterAllowed(0xA54);
SetRegisterAllowed(0xA58);
SetRegisterAllowed(0xA5C);
SetRegisterAllowed(0xA60);
SetRegisterAllowed(0xA64);
SetRegisterAllowed(0xA68);
SetRegisterAllowed(0xA6C);
SetRegisterAllowed(0xA70);
SetRegisterAllowed(0xA74);
SetRegisterAllowed(0xA78);
SetRegisterAllowed(0xA7C);
SetRegisterAllowed(0xA80);
SetRegisterAllowed(0xA84);
SetRegisterAllowed(0xA88);
SetRegisterAllowed(0xA8C);
SetRegisterAllowed(0xA90);
SetRegisterAllowed(0xA94);
SetRegisterAllowed(0xA98);
SetRegisterAllowed(0xA9C);
SetRegisterAllowed(0xAA0);
SetRegisterAllowed(0xAA4);
SetRegisterAllowed(0xAA8);
SetRegisterAllowed(0xAAC);
SetRegisterAllowed(0xAB0);
SetRegisterAllowed(0xAB4);
SetRegisterAllowed(0xAB8);
SetRegisterAllowed(0xABC);
SetRegisterAllowed(0xAC0);
SetRegisterAllowed(0xAC4);
SetRegisterAllowed(0xAC8);
SetRegisterAllowed(0xACC);
SetRegisterAllowed(0xAD0);
SetRegisterAllowed(0xAD4);
SetRegisterAllowed(0xAD8);
SetRegisterAllowed(0xADC);
SetRegisterAllowed(0xAE0);
SetRegisterAllowed(0xAE4);
SetRegisterAllowed(0xAE8);
SetRegisterAllowed(0xAEC);
SetRegisterAllowed(0xAF0);
SetRegisterAllowed(0xAF4);
SetRegisterAllowed(0xAF8);
SetRegisterAllowed(0xAFC);
SetRegisterAllowed(0xB00);
SetRegisterAllowed(0xB04);
SetRegisterAllowed(0xB08);
SetRegisterAllowed(0xB0C);
SetRegisterAllowed(0xB10);
SetRegisterAllowed(0xB14);
SetRegisterAllowed(0xB18);
SetRegisterAllowed(0xB1C);
SetRegisterAllowed(0xB20);
SetRegisterAllowed(0xB24);
SetRegisterAllowed(0xB28);
SetRegisterAllowed(0xB2C);
SetRegisterAllowed(0xB30);
SetRegisterAllowed(0xB34);
SetRegisterAllowed(0xB38);
SetRegisterAllowed(0xB3C);
SetRegisterAllowed(0xB40);
SetRegisterAllowed(0xB44);
SetRegisterAllowed(0xB48);
SetRegisterAllowed(0xB4C);
SetRegisterAllowed(0xB50);
SetRegisterAllowed(0xB54);
SetRegisterAllowed(0xB58);
SetRegisterAllowed(0xB5C);
SetRegisterAllowed(0xB60);
SetRegisterAllowed(0xB64);
SetRegisterAllowed(0xB68);
SetRegisterAllowed(0xB6C);
SetRegisterAllowed(0xB70);
SetRegisterAllowed(0xB74);
SetRegisterAllowed(0xB78);
SetRegisterAllowed(0xB7C);
SetRegisterAllowed(0xB80);
SetRegisterAllowed(0xB84);
SetRegisterAllowed(0xB88);
SetRegisterAllowed(0xB8C);
SetRegisterAllowed(0xB90);
SetRegisterAllowed(0xB94);
SetRegisterAllowed(0xB98);
SetRegisterAllowed(0xB9C);
SetRegisterAllowed(0xBA0);
SetRegisterAllowed(0xBA4);
SetRegisterAllowed(0xBA8);
SetRegisterAllowed(0xBAC);
SetRegisterAllowed(0xBB0);
SetRegisterAllowed(0xBB4);
SetRegisterAllowed(0xBB8);
SetRegisterAllowed(0xBBC);
SetRegisterAllowed(0xBC0);
SetRegisterAllowed(0xBC4);
SetRegisterAllowed(0xBC8);
SetRegisterAllowed(0xBCC);
SetRegisterAllowed(0xBD0);
SetRegisterAllowed(0xBD4);
SetRegisterAllowed(0xBD8);
SetRegisterAllowed(0xBDC);
SetRegisterAllowed(0xBE0);
SetRegisterAllowed(0xBE4);
SetRegisterAllowed(0xBE8);
SetRegisterAllowed(0xBEC);
SetRegisterAllowed(0xBF0);
SetRegisterAllowed(0xBF4);
SetRegisterAllowed(0xBF8);
SetRegisterAllowed(0xBFC);
SetRegisterAllowed(0xC00);
SetRegisterAllowed(0xC04);
SetRegisterAllowed(0xC08);
SetRegisterAllowed(0xC0C);
SetRegisterAllowed(0xC10);
SetRegisterAllowed(0xC14);
SetRegisterAllowed(0xC18);
SetRegisterAllowed(0xC1C);
SetRegisterAllowed(0xC20);
SetRegisterAllowed(0xC24);
SetRegisterAllowed(0xC28);
SetRegisterAllowed(0xC2C);
SetRegisterAllowed(0xC30);
SetRegisterAllowed(0xC34);
SetRegisterAllowed(0xC38);
SetRegisterAllowed(0xC3C);
SetRegisterAllowed(0xC40);
SetRegisterAllowed(0xC44);
SetRegisterAllowed(0xC48);
SetRegisterAllowed(0xC4C);
SetRegisterAllowed(0xC50);
SetRegisterAllowed(0xC54);
SetRegisterAllowed(0xC58);
SetRegisterAllowed(0xC5C);
SetRegisterAllowed(0xC60);
SetRegisterAllowed(0xC64);
SetRegisterAllowed(0xC68);
SetRegisterAllowed(0xC6C);
SetRegisterAllowed(0xC70);
SetRegisterAllowed(0xC74);
SetRegisterAllowed(0xC78);
SetRegisterAllowed(0xC7C);
SetRegisterAllowed(0xC80);
SetRegisterAllowed(0xC84);
SetRegisterAllowed(0xC88);
SetRegisterAllowed(0xC8C);
SetRegisterAllowed(0xC90);
SetRegisterAllowed(0xC94);
SetRegisterAllowed(0xC98);
SetRegisterAllowed(0xC9C);
SetRegisterAllowed(0xCA0);
SetRegisterAllowed(0xCA4);
SetRegisterAllowed(0xCA8);
SetRegisterAllowed(0xCAC);
SetRegisterAllowed(0xCB0);
SetRegisterAllowed(0xCB4);
SetRegisterAllowed(0xCB8);
SetRegisterAllowed(0xCBC);
SetRegisterAllowed(0xCC0);
SetRegisterAllowed(0xCC4);
SetRegisterAllowed(0xCC8);
SetRegisterAllowed(0xCCC);
SetRegisterAllowed(0xCD0);
SetRegisterAllowed(0xCD4);
SetRegisterAllowed(0xCD8);
SetRegisterAllowed(0xCDC);
SetRegisterAllowed(0xCE0);
SetRegisterAllowed(0xCE4);
SetRegisterAllowed(0xCE8);
SetRegisterAllowed(0xCEC);
SetRegisterAllowed(0xCF0);
SetRegisterAllowed(0xCF4);
SetRegisterAllowed(0xCF8);
SetRegisterAllowed(0xCFC);
SetRegisterAllowed(0xD00);
SetRegisterAllowed(0xD04);
SetRegisterAllowed(0xD08);
SetRegisterAllowed(0xD0C);
SetRegisterAllowed(0xD10);
SetRegisterAllowed(0xD14);
SetRegisterAllowed(0xD18);
SetRegisterAllowed(0xD1C);
SetRegisterAllowed(0xD20);
SetRegisterAllowed(0xD24);
SetRegisterAllowed(0xD28);
SetRegisterAllowed(0xD2C);
SetRegisterAllowed(0xD30);
SetRegisterAllowed(0xD34);
SetRegisterAllowed(0xD38);
SetRegisterAllowed(0xD3C);
SetRegisterAllowed(0xD40);
SetRegisterAllowed(0xD44);
SetRegisterAllowed(0xD48);
SetRegisterAllowed(0xD4C);
SetRegisterAllowed(0xD50);
SetRegisterAllowed(0xD54);
SetRegisterAllowed(0xD58);
SetRegisterAllowed(0xD5C);
SetRegisterAllowed(0xD60);
SetRegisterAllowed(0xD64);
SetRegisterAllowed(0xD68);
SetRegisterAllowed(0xD6C);
SetRegisterAllowed(0xD70);
SetRegisterAllowed(0xD74);
SetRegisterAllowed(0xD78);
SetRegisterAllowed(0xD7C);
SetRegisterAllowed(0xD80);
SetRegisterAllowed(0xD84);
SetRegisterAllowed(0xD88);
SetRegisterAllowed(0xD8C);
SetRegisterAllowed(0xD90);
SetRegisterAllowed(0xD94);
SetRegisterAllowed(0xD98);
SetRegisterAllowed(0xD9C);
SetRegisterAllowed(0xDA0);
SetRegisterAllowed(0xDA4);
SetRegisterAllowed(0xDA8);
SetRegisterAllowed(0xDAC);
SetRegisterAllowed(0xDB0);
SetRegisterAllowed(0xDB4);
SetRegisterAllowed(0xDB8);
SetRegisterAllowed(0xDBC);
SetRegisterAllowed(0xDC0);
SetRegisterAllowed(0xDC4);
SetRegisterAllowed(0xDC8);
SetRegisterAllowed(0xDCC);
SetRegisterAllowed(0xDD0);
SetRegisterAllowed(0xDD4);
SetRegisterAllowed(0xDD8);
SetRegisterAllowed(0xDDC);
SetRegisterAllowed(0xDE0);
SetRegisterAllowed(0xDE4);
SetRegisterAllowed(0xDE8);
SetRegisterAllowed(0xDEC);
SetRegisterAllowed(0xDF0);
SetRegisterAllowed(0xDF4);
SetRegisterAllowed(0xDF8);
SetRegisterAllowed(0xDFC);
SetRegisterAllowed(0xE00);
SetRegisterAllowed(0xE04);
SetRegisterAllowed(0xE08);
SetRegisterAllowed(0xE0C);
SetRegisterAllowed(0xE10);
SetRegisterAllowed(0xE14);
SetRegisterAllowed(0xE18);
SetRegisterAllowed(0xE1C);
SetRegisterAllowed(0xE20);
SetRegisterAllowed(0xE24);
SetRegisterAllowed(0xE28);
SetRegisterAllowed(0xE2C);
SetRegisterAllowed(0xE30);
SetRegisterAllowed(0xE34);
SetRegisterAllowed(0xE38);
SetRegisterAllowed(0xE3C);
SetRegisterAllowed(0xE40);
SetRegisterAllowed(0xE44);
SetRegisterAllowed(0xE48);
SetRegisterAllowed(0xE4C);
SetRegisterAllowed(0xE50);
SetRegisterAllowed(0xE54);
SetRegisterAllowed(0xE58);
SetRegisterAllowed(0xE5C);
SetRegisterAllowed(0xE60);
SetRegisterAllowed(0xE64);
SetRegisterAllowed(0xE68);
SetRegisterAllowed(0xE6C);
SetRegisterAllowed(0xE70);
SetRegisterAllowed(0xE74);
SetRegisterAllowed(0xE78);
SetRegisterAllowed(0xE7C);
SetRegisterAllowed(0xE80);
SetRegisterAllowed(0xE84);
SetRegisterAllowed(0xE88);
SetRegisterAllowed(0xE8C);
SetRegisterAllowed(0xE90);
SetRegisterAllowed(0xE94);
SetRegisterAllowed(0xE98);
SetRegisterAllowed(0xE9C);
SetRegisterAllowed(0xEA0);
SetRegisterAllowed(0xEA4);
SetRegisterAllowed(0xEA8);
SetRegisterAllowed(0xEAC);
SetRegisterAllowed(0xEB0);
SetRegisterAllowed(0xEB4);
SetRegisterAllowed(0xEB8);
SetRegisterAllowed(0xEBC);
SetRegisterAllowed(0xEC0);
SetRegisterAllowed(0xEC4);
SetRegisterAllowed(0xEC8);
SetRegisterAllowed(0xECC);
SetRegisterAllowed(0xED0);
SetRegisterAllowed(0xED4);
SetRegisterAllowed(0xED8);

View File

@@ -6,6 +6,8 @@
- Although "sys-clk" uses permissive license, all modifications towards it in this repo ("hoc-clk") are licensed under GPL v2.
- Status-Monitor is licensed under the GPLv2
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991

View File

@@ -1,13 +1,13 @@
<div align="center">
<img src="assets/logo.png" alt="logo" width="350"/>
<img src="assets/logo.png" alt="logo" width="768"/>
---
![License: GPL-2.0](https://img.shields.io/badge/GPL--2.0-red?style=for-the-badge)
![Nintendo Switch](https://img.shields.io/badge/Nintendo_Switch-E60012?style=for-the-badge\&logo=nintendo-switch\&logoColor=white)
[![Discord](https://img.shields.io/badge/Discord-5865F2?style=for-the-badge\&logo=discord\&logoColor=white)](https://discord.com/invite/S3eX47dHsB)
[![Discord](https://img.shields.io/badge/Discord-5865F2?style=for-the-badge\&logo=discord\&logoColor=white)](https://dsc.gg/horizonoc)
![VSCode](https://img.shields.io/badge/VSCode-0078D4?style=for-the-badge\&logo=visual%20studio%20code\&logoColor=white)
![Made with Notepad++](assets/np++.png?raw=true)
![C++](https://img.shields.io/badge/C%2B%2B-00599C?style=for-the-badge\&logo=c%2B%2B\&logoColor=white)
@@ -36,14 +36,12 @@ It enables advanced CPU, GPU, and RAM tuning with user-friendly configuration to
* **CPU:** Up to 1963MHz (Mariko) / 1785MHz (Erista)
* **GPU:** Up to 1075MHz (Mariko) / 921MHz (Erista)
* **RAM:** Up to 1866MHz (Mariko) / 1600MHz (Erista)
* **RAM:** Up to 1866/2133MHz (Mariko) / 1600MHz (Erista)
* Over/undervolting support
* 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.*
> It is recommended 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
---
@@ -58,7 +56,6 @@ It enables advanced CPU, GPU, and RAM tuning with user-friendly configuration to
```
kip1=atmosphere/kips/hoc.kip
secmon=exosphere.bin
```
*(No changes needed if using fusee.)*
@@ -69,7 +66,7 @@ It enables advanced CPU, GPU, and RAM tuning with user-friendly configuration to
1. Open the Horizon OC Overlay
2. Open the settings menu
3. Adjust your overclocking settings as desired.
3. Adjust your overclocking settings as desired. A helpful guide can be found [here.](https://rentry.co/mariko#oc-settings-for-horizon-oc)
4. Click **Save KIP Settings** to apply your configuration.
---
@@ -78,6 +75,78 @@ It enables advanced CPU, GPU, and RAM tuning with user-friendly configuration to
Refer to COMPILATION.md
---
## Clock table
### MEM clocks
* 3200 → max on mariko, JEDEC.
* 2933 → JEDEC.
* 2666 → JEDEC.
* 2400 → max on erista, JEDEC.
* 2133 → mariko safe max (4266 Modules), JEDEC.
* 1996 → JEDEC.
* 1866 → mariko safe max (3733 Modules), JEDEC.
* 1600 → official docked, boost mode, erista safe max, JEDEC.
* 1331 → official handheld, JEDEC.
* 1065
* 800
* 665
### CPU clocks
* 2601 → mariko absolute max, very dangerous
* 2499
* 2397 → mariko safe max with UV (low speedo)
* 2295
* 2193
* 2091
* 1963 → mariko no UV max clock
* 1887
* 1785 → erista no UV max clock, boost mode
* 1683
* 1581
* 1428
* 1326
* 1224 → sdev oc
* 1122
* 1020 → official docked & handheld
* 918
* 816
* 714
* 612 → sleep mode
**Notes:**
1. On Erista, CPU in handheld is capped to 1581MHz
### GPU clocks
* 1536 → absolute max clock on mariko. very dangerous
* 1459
* 1382
* 1305
* 1267 → NVIDIA T214 rating
* 1228 → mariko HiOPT safe clock
* 1152 → mariko SLT max clock
* 1075 → mariko no UV max clock. absolute max clock on erista. very dangerous
* 998 → NVIDIA T210 rating
* 960 (erista only) → erista slt/hiopt safe max clock
* 921 → erista no UV max clock
* 844
* 768 → official docked
* 691
* 614
* 537
* 460 → max handheld
* 384 → official handheld
* 307 → official handheld
* 230
* 153
* 76 → boost mode
**Notes:**
1. GPU overclock is capped at 460MHz on erista in handheld
2. On Mariko, cap with No uv is 614MHz, with SLT it is 691MHz and with HiOPT it's 768MHz
3. Clocks higher than 768MHz on erista need the official charger is plugged in.
4. On Mariko, cap with No uv is 844MHz, with SLT it is 921MHz and with HiOPT it's 998MHz
---
## Credits
@@ -86,13 +155,14 @@ 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
* **B3711 (halop)** EOS
* **sys-clk team (m4xw, p-sam, nautalis)** sys-clk
* **sys-clk team (m4xw, p-sam, natinusala)** sys-clk
* **b0rd2death** Ultrahand sys-clk & Status Monitor fork
* **MasaGratoR and ZachyCatGames** - General help
* **MasaGratoR** - Status Monitor & Display Refresh Rate Driver
* **Dom, Samybigio, Arcdelta, Miki, Happy, Flopsider, Winnerboi77, Blaise, Alvise, TDRR, agjeococh and Xenshen** - Testing
* **Samybigio2011** - Italian translations
* **Dom, Samybigio, Arcdelta, Miki, Happy, Flopsider, Winnerboi77, Blaise, Alvise, TDRR, agjeococh, frost, letum00 and Xenshen** - Testing
* **Samybigio2011** - Italian translations

View File

@@ -4,8 +4,9 @@
| Version | Supported |
| ------- | ------------------ |
| 0.x | :white_check_mark: |
| 1.x | :white_check_mark: |
| 0.x | Not supported |
## 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

@@ -14,9 +14,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define __ACCESS_TABLE_NAME__ SocthermAccessTable
#define __ACCESS_TABLE_ADDRESS__ MemoryRegionPhysicalDeviceSoctherm.GetAddress()
#define __ACCESS_TABLE_INC__ "secmon_soctherm_access_table_data.inc"
#define __ACCESS_TABLE_NAME__ EmcAccessTable1
#define __ACCESS_TABLE_ADDRESS__ MemoryRegionPhysicalDeviceExternalMemoryController1.GetAddress()
#define __ACCESS_TABLE_INC__ "secmon_emc_access_table_data.inc"
#include "secmon_define_access_table.inc"

View File

@@ -0,0 +1,25 @@
/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define __ACCESS_TABLE_NAME__ EmcAccessTable2
#define __ACCESS_TABLE_ADDRESS__ MemoryRegionPhysicalDeviceExternalMemoryController2.GetAddress()
#define __ACCESS_TABLE_INC__ "secmon_emc_access_table_data.inc"
#include "secmon_define_access_table.inc"
#undef __ACCESS_TABLE_INC__
#undef __ACCESS_TABLE_ADDRESS__
#undef __ACCESS_TABLE_NAME__

View File

@@ -129,33 +129,32 @@ namespace ams::secmon {
constexpr inline const MemoryRegion MemoryRegionVirtualDeviceEmpty = MemoryRegion(MemoryRegionVirtualDevice.GetStartAddress(), 0);
#define AMS_SECMON_FOREACH_DEVICE_REGION(HANDLER, ...) \
HANDLER(GicDistributor, Empty, UINT64_C(0x50041000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(GicCpuInterface, GicDistributor, UINT64_C(0x50042000), UINT64_C(0x2000), true, ## __VA_ARGS__) \
HANDLER(Uart, GicCpuInterface, UINT64_C(0x70006000), UINT64_C(0x1000), false, ## __VA_ARGS__) \
HANDLER(ClkRst, Uart, UINT64_C(0x60006000), UINT64_C(0x1000), false, ## __VA_ARGS__) \
HANDLER(RtcPmc, ClkRst, UINT64_C(0x7000E000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(Timer, RtcPmc, UINT64_C(0x60005000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(System, Timer, UINT64_C(0x6000C000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(SecurityEngine, System, UINT64_C(0x70012000), UINT64_C(0x2000), true, ## __VA_ARGS__) \
HANDLER(SecurityEngine2, SecurityEngine, UINT64_C(0x70412000), UINT64_C(0x2000), true, ## __VA_ARGS__) \
HANDLER(SysCtr0, SecurityEngine2, UINT64_C(0x700F0000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(MemoryController, SysCtr0, UINT64_C(0x70019000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(ExternalMemoryController, MemoryController, UINT64_C(0x7001b000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(FuseKFuse, ExternalMemoryController, UINT64_C(0x7000F000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(ApbMisc, FuseKFuse, UINT64_C(0x70000000), UINT64_C(0x4000), true, ## __VA_ARGS__) \
HANDLER(FlowController, ApbMisc, UINT64_C(0x60007000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(BootloaderParams, FlowController, UINT64_C(0x40000000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(I2c5, BootloaderParams, UINT64_C(0x7000D000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(Gpio, I2c5, UINT64_C(0x6000D000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(I2c1, Gpio, UINT64_C(0x7000C000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(ExceptionVectors, I2c1, UINT64_C(0x6000F000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(MemoryController0, ExceptionVectors, UINT64_C(0x7001C000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(MemoryController1, MemoryController0, UINT64_C(0x7001D000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(Sdmmc, MemoryController1, UINT64_C(0x700B0000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(Disp1, Sdmmc, UINT64_C(0x54200000), UINT64_C(0x3000), true, ## __VA_ARGS__) \
HANDLER(Dsi, Disp1, UINT64_C(0x54300000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(MipiCal, Dsi, UINT64_C(0x700E3000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(Soctherm, MipiCal, UINT64_C(0x700E2000), UINT64_C(0x1000), true, ## __VA_ARGS__)
HANDLER(GicDistributor, Empty, UINT64_C(0x50041000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(GicCpuInterface, GicDistributor, UINT64_C(0x50042000), UINT64_C(0x2000), true, ## __VA_ARGS__) \
HANDLER(Uart, GicCpuInterface, UINT64_C(0x70006000), UINT64_C(0x1000), false, ## __VA_ARGS__) \
HANDLER(ClkRst, Uart, UINT64_C(0x60006000), UINT64_C(0x1000), false, ## __VA_ARGS__) \
HANDLER(RtcPmc, ClkRst, UINT64_C(0x7000E000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(Timer, RtcPmc, UINT64_C(0x60005000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(System, Timer, UINT64_C(0x6000C000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(SecurityEngine, System, UINT64_C(0x70012000), UINT64_C(0x2000), true, ## __VA_ARGS__) \
HANDLER(SecurityEngine2, SecurityEngine, UINT64_C(0x70412000), UINT64_C(0x2000), true, ## __VA_ARGS__) \
HANDLER(SysCtr0, SecurityEngine2, UINT64_C(0x700F0000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(MemoryController, SysCtr0, UINT64_C(0x70019000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(ExternalMemoryController, MemoryController, UINT64_C(0x7001b000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(FuseKFuse, ExternalMemoryController, UINT64_C(0x7000F000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(ApbMisc, FuseKFuse, UINT64_C(0x70000000), UINT64_C(0x4000), true, ## __VA_ARGS__) \
HANDLER(FlowController, ApbMisc, UINT64_C(0x60007000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(BootloaderParams, FlowController, UINT64_C(0x40000000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(I2c5, BootloaderParams, UINT64_C(0x7000D000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(Gpio, I2c5, UINT64_C(0x6000D000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(I2c1, Gpio, UINT64_C(0x7000C000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(ExceptionVectors, I2c1, UINT64_C(0x6000F000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(MemoryController0, ExceptionVectors, UINT64_C(0x7001C000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(MemoryController1, MemoryController0, UINT64_C(0x7001D000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(Sdmmc, MemoryController1, UINT64_C(0x700B0000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(Disp1, Sdmmc, UINT64_C(0x54200000), UINT64_C(0x3000), true, ## __VA_ARGS__) \
HANDLER(Dsi, Disp1, UINT64_C(0x54300000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(MipiCal, Dsi, UINT64_C(0x700E3000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
#define DEFINE_DEVICE_REGION(_NAME_, _PREV_, _ADDRESS_, _SIZE_, _SECURE_) \
constexpr inline const MemoryRegion MemoryRegionVirtualDevice##_NAME_ = MemoryRegion(MemoryRegionVirtualDevice##_PREV_.GetEndAddress() + 0x1000, _SIZE_); \

View File

@@ -0,0 +1,268 @@
/*
* Copyright (c) Atmosphère-NX
*
* 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 <exosphere.hpp>
#include "../secmon_error.hpp"
#include "../secmon_misc.hpp"
#include "secmon_smc_common.hpp"
#include "secmon_smc_handler.hpp"
#include "secmon_smc_aes.hpp"
#include "secmon_smc_carveout.hpp"
#include "secmon_smc_device_unique_data.hpp"
#include "secmon_smc_error.hpp"
#include "secmon_smc_info.hpp"
#include "secmon_smc_memory_access.hpp"
#include "secmon_smc_power_management.hpp"
#include "secmon_smc_random.hpp"
#include "secmon_smc_register_access.hpp"
#include "secmon_smc_result.hpp"
#include "secmon_smc_rsa.hpp"
namespace ams::secmon::smc {
namespace {
struct HandlerInfo {
u32 function_id;
u32 restriction_mask;
SmcHandler handler;
};
struct HandlerTable {
const HandlerInfo *entries;
size_t count;
};
enum HandlerType : int {
HandlerType_User = 0,
HandlerType_Kern = 1,
HandlerType_Count = 2,
};
enum Restriction {
Restriction_None = (0 << 0),
Restriction_Normal = (1 << 0),
Restriction_DeviceUniqueDataNotAllowed = (1 << 1),
Restriction_SafeModeNotAllowed = (1 << 2),
};
enum SmcCallRange {
SmcCallRange_ArmArch = 0,
SmcCallRange_Cpu = 1,
SmcCallRange_Sip = 2,
SmcCallRange_Oem = 3,
SmcCallRange_Standard = 4,
SmcCallRange_TrustedApp = 0x30,
};
enum SmcArgumentType {
ArgumentType_Integer = 0,
ArgumentType_Pointer = 1,
};
enum SmcConvention {
Convention_Smc32 = 0,
Convention_Smc64 = 1,
};
enum SmcCallType {
SmcCallType_YieldingCall = 0,
SmcCallType_FastCall = 1,
};
struct SmcFunctionId {
using FunctionId = util::BitPack64::Field< 0, 8, u32>;
using ArgumentType0 = util::BitPack64::Field< 8, 1, SmcArgumentType>;
using ArgumentType1 = util::BitPack64::Field< 9, 1, SmcArgumentType>;
using ArgumentType2 = util::BitPack64::Field<10, 1, SmcArgumentType>;
using ArgumentType3 = util::BitPack64::Field<11, 1, SmcArgumentType>;
using ArgumentType4 = util::BitPack64::Field<12, 1, SmcArgumentType>;
using ArgumentType5 = util::BitPack64::Field<13, 1, SmcArgumentType>;
using ArgumentType6 = util::BitPack64::Field<14, 1, SmcArgumentType>;
using ArgumentType7 = util::BitPack64::Field<15, 1, SmcArgumentType>;
using Reserved = util::BitPack64::Field<16, 8, u32>;
using CallRange = util::BitPack64::Field<24, 6, SmcCallRange>;
using Convention = util::BitPack64::Field<30, 1, SmcConvention>;
using CallType = util::BitPack64::Field<31, 1, SmcCallType>;
using Reserved2 = util::BitPack64::Field<32, 32, u32>;
};
constinit HandlerInfo g_user_handlers[] = {
{ 0x00000000, Restriction_SafeModeNotAllowed, nullptr },
{ 0xC3000401, Restriction_SafeModeNotAllowed, SmcSetConfig },
{ 0xC3000002, Restriction_Normal, SmcGetConfigUser },
{ 0xC3000003, Restriction_Normal, SmcGetResult },
{ 0xC3000404, Restriction_Normal, SmcGetResultData },
{ 0xC3000E05, Restriction_SafeModeNotAllowed, SmcModularExponentiate },
{ 0xC3000006, Restriction_Normal, SmcGenerateRandomBytes },
{ 0xC3000007, Restriction_Normal, SmcGenerateAesKek },
{ 0xC3000008, Restriction_Normal, SmcLoadAesKey },
{ 0xC3000009, Restriction_Normal, SmcComputeAes },
{ 0xC300000A, Restriction_Normal, SmcGenerateSpecificAesKey },
{ 0xC300040B, Restriction_Normal, SmcComputeCmac },
{ 0xC300D60C, Restriction_Normal, SmcReencryptDeviceUniqueData },
{ 0xC300100D, Restriction_DeviceUniqueDataNotAllowed, SmcDecryptDeviceUniqueData },
{ 0xC300000E, Restriction_SafeModeNotAllowed, nullptr },
{ 0xC300060F, Restriction_DeviceUniqueDataNotAllowed, SmcModularExponentiateByStorageKey },
{ 0xC3000610, Restriction_SafeModeNotAllowed, SmcPrepareEsDeviceUniqueKey },
{ 0xC3000011, Restriction_SafeModeNotAllowed, SmcLoadPreparedAesKey },
{ 0xC3000012, Restriction_SafeModeNotAllowed, SmcPrepareEsCommonTitleKey }
};
/* Deprecated handlerss. */
constexpr inline const HandlerInfo DecryptAndImportEsDeviceKeyHandlerInfo = {
0xC300100C, Restriction_Normal, SmcDecryptAndImportEsDeviceKey
};
constexpr inline const HandlerInfo DecryptAndImportLotusKeyHandlerInfo = {
0xC300100E, Restriction_SafeModeNotAllowed, SmcDecryptAndImportLotusKey
};
constinit HandlerInfo g_kern_handlers[] = {
{ 0x00000000, Restriction_SafeModeNotAllowed, nullptr },
{ 0xC4000001, Restriction_SafeModeNotAllowed, SmcSuspendCpu },
{ 0x84000002, Restriction_SafeModeNotAllowed, SmcPowerOffCpu },
{ 0xC4000003, Restriction_SafeModeNotAllowed, SmcPowerOnCpu },
{ 0xC3000004, Restriction_Normal, SmcGetConfigKern },
{ 0xC3000005, Restriction_Normal, SmcGenerateRandomBytesNonBlocking },
{ 0xC3000006, Restriction_Normal, SmcShowError },
{ 0xC3000007, Restriction_Normal, SmcSetKernelCarveoutRegion },
{ 0xC3000008, Restriction_Normal, SmcReadWriteRegister },
/* NOTE: Atmosphere extension for mesosphere. This ID is subject to change at any time. */
{ 0xC3000409, Restriction_Normal, SmcSetConfig },
};
constinit HandlerInfo g_ams_handlers[] = {
{ 0x00000000, Restriction_SafeModeNotAllowed, nullptr },
{ 0xF0000201, Restriction_None, SmcIramCopy },
{ 0xF0000002, Restriction_None, SmcReadWriteRegister },
{ 0xF0000003, Restriction_None, SmcWriteAddress },
{ 0xF0000404, Restriction_None, SmcGetEmummcConfig },
{ 0xF0000005, Restriction_None, SmcShowError },
};
constexpr const HandlerInfo GetSecureDataHandlerInfo = {
0x67891234, Restriction_None, SmcGetSecureData
};
constinit HandlerTable g_handler_tables[] = {
{ g_user_handlers, util::size(g_user_handlers) },
{ g_kern_handlers, util::size(g_kern_handlers) },
};
constinit HandlerTable g_ams_handler_table = {
g_ams_handlers, util::size(g_ams_handlers)
};
NORETURN void InvalidSmcError(u64 id) {
SetError(pkg1::ErrorInfo_UnknownSmc);
AMS_ABORT("Invalid SMC: %lx", id);
}
const HandlerTable &GetHandlerTable(HandlerType type, u64 id) {
/* Ensure we have a valid handler type. */
if (AMS_UNLIKELY(!(0 <= type && type < HandlerType_Count))) {
InvalidSmcError(id);
}
/* Provide support for legacy SmcGetSecureData. */
if (id == GetSecureDataHandlerInfo.function_id) {
return g_handler_tables[HandlerType_User];
}
/* Check if we're a user SMC. */
if (type == HandlerType_User) {
/* Nintendo uses OEM SMCs. */
/* We will assign Atmosphere extension SMCs the TrustedApplication range. */
if (util::BitPack64{id}.Get<SmcFunctionId::CallRange>() == SmcCallRange_TrustedApp) {
return g_ams_handler_table;
}
/* If we're not performing an atmosphere extension smc, require that we're being invoked by spl on core 3. */
if (AMS_UNLIKELY(hw::GetCurrentCoreId() != 3)) {
InvalidSmcError(id);
}
}
return g_handler_tables[type];
}
const HandlerInfo &GetHandlerInfo(const HandlerTable &table, u64 id) {
/* Provide support for legacy SmcGetSecureData. */
if (id == GetSecureDataHandlerInfo.function_id) {
return GetSecureDataHandlerInfo;
}
/* Get and check the index. */
const auto index = util::BitPack64{id}.Get<SmcFunctionId::FunctionId>();
if (AMS_UNLIKELY(index >= table.count)) {
InvalidSmcError(id);
}
/* Get and check the handler info. */
const auto &handler_info = table.entries[index];
/* Check that the handler isn't null. */
if (AMS_UNLIKELY(handler_info.handler == nullptr)) {
InvalidSmcError(id);
}
/* Check that the handler's id matches. */
if (AMS_UNLIKELY(handler_info.function_id != id)) {
InvalidSmcError(id);
}
return handler_info;
}
bool IsHandlerRestricted(const HandlerInfo &info) {
return (info.restriction_mask & secmon::GetRestrictedSmcMask()) != 0;
}
SmcResult InvokeSmcHandler(const HandlerInfo &info, SmcArguments &args) {
/* Check if the smc is restricted. */
if (GetTargetFirmware() >= TargetFirmware_8_0_0 && AMS_UNLIKELY(IsHandlerRestricted(info))) {
return SmcResult::NotPermitted;
}
/* Invoke the smc. */
return info.handler(args);
}
}
void ConfigureSmcHandlersForTargetFirmware() {
const auto target_fw = GetTargetFirmware();
if (target_fw < TargetFirmware_5_0_0) {
g_user_handlers[DecryptAndImportEsDeviceKeyHandlerInfo.function_id & 0xFF] = DecryptAndImportEsDeviceKeyHandlerInfo;
g_user_handlers[DecryptAndImportLotusKeyHandlerInfo.function_id & 0xFF] = DecryptAndImportLotusKeyHandlerInfo;
}
}
void HandleSmc(int type, SmcArguments &args) {
/* Get the table. */
const auto &table = GetHandlerTable(static_cast<HandlerType>(type), args.r[0]);
/* Get the handler info. */
const auto &info = GetHandlerInfo(table, args.r[0]);
/* Set the invocation result. */
args.r[0] = static_cast<u64>(InvokeSmcHandler(info, args));
}
}

View File

@@ -99,14 +99,16 @@ namespace ams::secmon::smc {
#include "secmon_define_pmc_access_table.inc"
#include "secmon_define_mc_access_table.inc"
#include "secmon_define_emc_access_table.inc"
#include "secmon_define_soctherm_access_table.inc"
#include "secmon_define_emc1_access_table.inc"
#include "secmon_define_emc2_access_table.inc"
#include "secmon_define_mc01_access_table.inc"
constexpr const AccessTableEntry AccessTables[] = {
{ PmcAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDevicePmc.GetAddress(), PmcAccessTable::Address, PmcAccessTable::Size, },
{ McAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceMemoryController.GetAddress(), McAccessTable::Address, McAccessTable::Size, },
{ EmcAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceExternalMemoryController.GetAddress(), EmcAccessTable::Address, EmcAccessTable::Size, },
{ SocthermAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceSoctherm.GetAddress(), SocthermAccessTable::Address, SocthermAccessTable::Size, },
{ EmcAccessTable1::ReducedAccessTable.data(), MemoryRegionVirtualDeviceExternalMemoryController1.GetAddress(), EmcAccessTable1::Address, EmcAccessTable1::Size, },
{ EmcAccessTable2::ReducedAccessTable.data(), MemoryRegionVirtualDeviceExternalMemoryController2.GetAddress(), EmcAccessTable2::Address, EmcAccessTable2::Size, },
{ Mc01AccessTable::ReducedAccessTable.data(), Mc01AccessTable::Address + MemoryRegionVirtualDeviceMemoryController0.GetAddress(), Mc01AccessTable::Address + MemoryRegionPhysicalDeviceMemoryController0.GetAddress(), Mc01AccessTable::Size, },
{ Mc01AccessTable::ReducedAccessTable.data(), Mc01AccessTable::Address + MemoryRegionVirtualDeviceMemoryController1.GetAddress(), Mc01AccessTable::Address + MemoryRegionPhysicalDeviceMemoryController1.GetAddress(), Mc01AccessTable::Size, },
};

View File

@@ -1,6 +1,8 @@
/*
* Copyright (c) Atmosphère-NX
*
* 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.
@@ -692,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

@@ -3,7 +3,7 @@
*
* Copyright (c) 2023 hanai3Bi
*
* Copyright (c) Souldbminer and Horizon OC Contributors
* 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,
@@ -26,19 +26,21 @@
#define DISABLED 0
#define DEACTIVATED_GPU_FREQ 2000
#define GPU_MIN_MIN_VOLT 480000
#define CPU_MAX_MAX_VOLT 1235000
#define CPU_MAX_MAX_VOLT 1200000
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 = 2133000,
.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,10 +54,22 @@ 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. */
.mem_burst_read_latency = 8,
.mem_burst_write_latency = 4,
/* You can mix and match different latencies if needed */
/*
* Read:
* 2133RL = 40
* 1866RL = 36
* 1600RL = 32
* 1331RL = 28
* Write:
* 2133WL = 18
* 1866WL = 16
* 1600WL = 14
* 1331WL = 12
*/
.mem_burst_read_latency = RL_1866,
.mem_burst_write_latency = WL_1866,
.eristaCpuUV = 0,
.eristaCpuVmin = 800,
@@ -65,38 +79,47 @@ volatile CustomizeTable C = {
.marikoCpuUVLow = 0, // No undervolt
.marikoCpuUVHigh = 0, // No undervolt
.tableConf = DEFAULT_TABLE, /* TODO: Add AUTO */
.tableConf = TBREAK_1683,
.marikoCpuLowVmin = 620,
.marikoCpuHighVmin = 750,
/* 1120mV is NVIDIA rating */
.marikoCpuMaxVolt = 1120,
/* Supported values: 2397000, 2499000, 2601000, 2703000. */
/* Supported values: 1963000, 2091000, 2193000, 2295000, 2397000, 2499000, 2601000, 2703000. */
/* 1963000 is official rating of T214/Mariko, fully safe. */
/* 2091000-2295000 is a slight OC which should work on all units, but no guarantees. */
/* 2397000 is the max safe OC for most average units with tuned undervolt. */
/* 2499000 should be used with caution. */
/* 2601000 exceeds pmic limit on most consoles. */
/* 2703000 is potentially dangerous and not advised. */
.marikoCpuMaxClock = 2397000,
.marikoCpuMaxClock = 1963000,
.eristaCpuBoostClock = 1785000, // Default boost clock
.marikoCpuBoostClock = 1963000, // Default boost clock
.eristaGpuUV = 0,
.eristaGpuVmin = 800,
.eristaGpuVmin = 810,
.marikoGpuUV = 0,
/* For automatic vmin detection, set this to AUTO. */
.marikoGpuVmin = 610,
/* 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 */
/* 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 = {
AUTO /* 76 */,
AUTO /* 115 */,
@@ -142,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) */,
@@ -154,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, }, { } },
@@ -172,9 +199,9 @@ volatile CustomizeTable C = {
{ 1581000, { 1130000, }, { 2889664, -122173, 1834, } },
{ 1683000, { 1168000, }, { 5100873, -279186, 4747, } },
{ 1785000, { 1225000, }, { 5100873, -279186, 4747, } },
// { 1887000, { 1225000, }, { 5100873, -279186, 4747, } },
// { 1989000, { 1227500, }, { 5100873, -279186, 4747, } },
// { 2091000, { 1256250, }, { 5100873, -279186, 4747, } },
{ 1887000, { 1225000, }, { 5100873, -279186, 4747, } },
{ 1989000, { 1227500, }, { 5100873, -279186, 4747, } },
{ 2091000, { 1256250, }, { 5100873, -279186, 4747, } },
},
.eristaCpuDvfsTableSLT = {
@@ -195,10 +222,11 @@ volatile CustomizeTable C = {
{ 1683000, { 1168000, }, { 5100873, -279186, 4747, } },
{ 1785000, { 1225000, }, { 5100873, -279186, 4747, } },
{ 1887000, { 1225000, }, { 5100873, -279186, 4747, } },
{ 1989000, { 1227500, }, { 5100873, -279186, 4747, } },
{ 2091000, { 1256250, }, { 5100873, -279186, 4747, } },
{ 2193000, { 1256250, }, { 5100873, -279186, 4747, } },
{ 1963500, { 1227500, }, { 5100873, -279186, 4747, } },
{ 2091000, { 1227500, }, { 5100873, -279186, 4747, } },
{ 2193000, { 1227500, }, { 5100873, -279186, 4747, } },
{ 2295000, { 1256250, }, { 5100873, -279186, 4747, } },
{ 2397000, { 1256250, }, { 5100873, -279186, 4747, } }, // Only for god speedo!
},
.marikoCpuDvfsTable = {
@@ -310,7 +338,7 @@ volatile CustomizeTable C = {
{ 2703000, { 1838820, -36648, 113, }, { CPU_MAX_MAX_VOLT, } },
},
.marikoCpuDvfsTableHelios {
.marikoCpuDvfsTableExtreme {
{ 204000, { 732856, -17335, 113, }, { } },
{ 306000, { 760024, -18195, 113, }, { } },
{ 408000, { 789258, -19055, 113, }, { } },
@@ -438,7 +466,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

@@ -3,7 +3,7 @@
*
* Copyright (c) 2023 hanai3Bi
*
* Copyright (c) Souldbminer and Horizon OC Contributors
* 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,
@@ -20,25 +20,47 @@
#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,
TBREAK_1683 = 3,
HELIOS_TABLE = 4,
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];
@@ -53,16 +75,16 @@ 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;
// advanced config
u32 t1_tRCD;
u32 t2_tRP;
@@ -101,12 +123,16 @@ typedef struct CustomizeTable {
u32 commonGpuVoltOffset;
/* TODO: Automatically detect speedo. */
u32 gpuSpeedo;
u32 eristaGpuVoltArray[27];
u32 marikoGpuVoltArray[24];
u32 fineTune_t6_tRTW;
u32 fineTune_t7_tWTR;
u32 reserved[60];
CustomizeCpuDvfsTable eristaCpuDvfsTable;
CustomizeCpuDvfsTable eristaCpuDvfsTableSLT;
@@ -114,7 +140,7 @@ typedef struct CustomizeTable {
CustomizeCpuDvfsTable marikoCpuDvfsTableSLT;
CustomizeCpuDvfsTable marikoCpuDvfsTable1581Tbreak;
CustomizeCpuDvfsTable marikoCpuDvfsTable1683Tbreak;
CustomizeCpuDvfsTable marikoCpuDvfsTableHelios;
CustomizeCpuDvfsTable marikoCpuDvfsTableExtreme;
CustomizeGpuDvfsTable eristaGpuDvfsTable;
CustomizeGpuDvfsTable eristaGpuDvfsTableSLT;

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 - (C.t6_tRTW * 3) + finetRTW;
tWTPDEN = CEIL(((1.803 / tCK_avg) + MAX(RL + (2.694 / tCK_avg), static_cast<double>(tW2P))) + (BL / 2));
tW2R = FLOOR(MAX((5.020 / tCK_avg) + 1.130, WL - MAX(-CEIL(0.258 * (WL - RL)), 1.964)) * 1.964) + WL - CEIL(tWTR / tCK_avg) + finetWTR;
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,96 +18,50 @@
#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;
/* Fallback. */
rext = 0x1A;
}
/* TODO: This function is quite uggly, refactor! */
void CalculateMiscTimings() {
einput_duration = 0x1C;
void CalculateMrw2() {
static const u8 rlMapDBI[8] = {
6, 12, 16, 22, 28, 32, 36, 40
};
for (u32 i = 0; i < g_misc_table_size; i++) {
const auto& e = g_misc_table[i];
if (C.marikoEmcMaxClock >= e.min_freq) {
if (e.einput) einput_duration = e.einput;
static const u8 wlMapSetA[8] = {
4, 6, 8, 10, 12, 14, 16, 18
};
u32 rlIndex = 0;
u32 wlIndex = 0;
for (u32 i = 0; i < std::size(rlMapDBI); ++i) {
if (rlMapDBI[i] == RL) {
rlIndex = i;
break;
}
}
rext = GetRext();
}
void CalculateIbdly() {
/* Ibdly is so inconsistent, I am using the most common value and then checking with a lookup table. */
ibdly = 0x1000001D + C.mem_burst_read_latency;
if (auto patch = FindIbdlyPatch()) {
ibdly += patch->adjust;
for (u32 i = 0; i < std::size(wlMapSetA); ++i) {
if (wlMapSetA[i] == WL) {
wlIndex = i;
break;
}
}
}
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 CalculateQsafe() {
qsafe = ROUND((C.marikoEmcMaxClock / 1000.0) / 138.0 + 37.4) + C.mem_burst_read_latency;
if (auto patch = FindQsafePatch()) {
qsafe += patch->adjust;
}
}
void CalculateQpop() {
qpop = FLOOR(((C.marikoEmcMaxClock / 1000.0) - 2133 + 167) / 200.0) + 0x2D + C.mem_burst_read_latency;
if (C.marikoEmcMaxClock >= 3'133'000) qpop++;
}
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;
}
mrw2 = static_cast<u8>(((rlIndex & 0x7) | ((wlIndex & 0x7) << 3) | ((0 & 0x1) << 6)));
}
void CalculateTimings() {
CalculateMiscTimings();
CalculateIbdly();
CalculateTWTPDEN();
CalculateTR2W();
CalculateQsafe();
CalculateQpop();
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,35 +17,7 @@
#include "../mtc_timing_value.hpp"
#include "timing_tables.hpp"
namespace ams::ldr::oc::pcv::mariko {
const MiscTimings g_misc_table[] = {
{1'866'000, 0x20, },
{2'133'000, 0x24, },
{2'166'000, 0, },
{2'233'000, 0x25, },
{2'300'000, 0x26, },
{2'333'000, 0x27, },
{2'366'000, 0x26, },
{2'433'000, 0x27, },
{2'466'000, 0x2A, },
{2'500'000, 0x28, },
{2'533'000, 0x29, },
{2'566'000, 0, },
{2'633'000, 0x2A, },
{2'700'000, 0x2B, },
{2'733'000, 0x2C, },
{2'766'000, 0x2B, },
{2'833'000, 0x2C, },
{2'866'000, 0, },
{2'900'000, 0, },
{2'933'000, 0x2E, },
{2'966'000, 0, },
{3'033'000, 0x2F, },
{3'133'000, 0x31, },
};
const u32 g_misc_table_size = sizeof(g_misc_table) / sizeof(g_misc_table[0]);
namespace ams::ldr::hoc::pcv::mariko {
const ReplacePatch g_rext_table[] = {
{2'133'000, 0x1A}, {2'166'000, 0x19}, {2'200'000, 0x19},
@@ -64,137 +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_ibdly_patches[] = {
{2'133'000, -2},
{2'166'000, -1},
{2'200'000, -1},
{2'233'000, -1},
{2'266'000, -1},
{2'300'000, -2},
{2'333'000, -2},
{2'500'000, -1},
{2'533'000, -2},
{2'566'000, -1},
{2'600'000, -1},
{2'633'000, -1},
{2'666'000, -1},
{2'700'000, -2},
{2'733'000, -2},
{2'933'000, -1},
};
const u32 g_ibdly_table_size = sizeof(g_ibdly_patches) / sizeof(g_ibdly_patches[0]);
const AdjustPatch *FindIbdlyPatch() {
for (u32 i = 0; i < g_ibdly_table_size; i++)
if (g_ibdly_patches[i].freq == C.marikoEmcMaxClock)
return &g_ibdly_patches[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_qsafe_patches[] = {
{2'166'000, 1},
{2'200'000, 1},
{2'500'000, -1},
{2'533'000, -1},
{2'666'000, -1},
{2'700'000, -1},
{2'733'000, -1},
{2'800'000, -1},
{2'833'000, -1},
{2'866'000, -1},
{2'900'000, -1},
{2'933'000, -2},
{2'966'000, -1},
{3'000'000, -1},
{3'033'000, -1},
{3'066'000, -2},
{3'100'000, -2},
{3'166'000, -1},
{3'200'000, -1},
};
const u32 g_qsafe_table_size = sizeof(g_qsafe_patches) / sizeof(g_qsafe_patches[0]);
const AdjustPatch *FindQsafePatch() {
for (u32 i = 0; i < g_qsafe_table_size; i++)
if (g_qsafe_patches[i].freq == C.marikoEmcMaxClock)
return &g_qsafe_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,48 +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_ibdly_patches[];
extern const u32 g_ibdly_table_size;
const AdjustPatch *FindIbdlyPatch();
extern const AdjustPatch g_tr2w_patches[];
extern const u32 g_tr2w_table_size;
const AdjustPatch *FindTR2WPatch();
extern const AdjustPatch g_qsafe_patches[];
extern const u32 g_qsafe_table_size;
const AdjustPatch *FindQsafePatch();
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();
struct MiscTimings {
u32 min_freq;
u32 einput;
};
extern const MiscTimings g_misc_table[];
extern const u32 g_misc_table_size;
}

View File

@@ -20,33 +20,22 @@
#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<uint32_t>(high) << 16) | (static_cast<uint32_t>(low) & 0xFFFF))
/* 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 };
#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))
/* Burst latency, not to be confused with base latency (tWRL). */
const u32 BL = 16;
/* Base latency for read and write (tWRL). */
const u32 RL = 28 + C.mem_burst_read_latency;
const u32 WL = 14 + C.mem_burst_write_latency;
/* Switch uses RL_DBI, todo: get rid of non DBI_RL. */
const u32 RL_DBI = RL + 4;
const u32 RL = C.mem_burst_read_latency;
const u32 WL = C.mem_burst_write_latency;
/* Precharge to Precharge Delay. (tCK) */
const u32 tPPD = 4;
@@ -74,12 +63,54 @@ namespace ams::ldr::oc {
/* Write recovery time. */
const u32 tWR = 18;
/* TOOD: Fix erista */
namespace pcv::erista {
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, 6> tRFC_values = { 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];
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 * 0.426) - 2.0);
inline u32 tR2W;
inline u32 rext;
const u32 tW2P = (CEIL(WL * 1.7303) * 2) - 5;
inline u32 tWTPDEN;
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];
@@ -88,6 +119,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;
@@ -95,44 +128,47 @@ namespace ams::ldr::oc {
const u32 tFAW = static_cast<u32>(tRRD * 4.0);
const double tRPab = tRPpb + 3;
const u32 tR2P = 12 + (C.mem_burst_read_latency / 2);
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?
const u32 rdv = FLOOR(17.02046755653219 + (RL_DBI + ((C.marikoEmcMaxClock / 1000.0) * 0.00510056573299173)));
const u32 quse = FLOOR((-0.0048159 * (C.marikoEmcMaxClock / 1000.0)) + RL_DBI) + (FLOOR((C.marikoEmcMaxClock / 1000.0) * 0.0050997) * 1.5134);
const u32 einput = quse - ((C.marikoEmcMaxClock / 1000.0) * 0.01);
inline u32 einput_duration;
inline u32 ibdly;
const u32 obdly = 0x10000000 + CEIL(MAX((WL + (2.072347067198409 * CEIL(((C.marikoEmcMaxClock / 1000.0) * -0.0008701518090699537) + 1.1926184709583145))) - 12.368815500608948, -1.8792921762826563e-9));
const u32 quse_width = CEIL(((3.7165006256863955 - (C.marikoEmcMaxClock / 1000.0)) + (-0.002446584377651142 * (C.marikoEmcMaxClock / 1000.0))) - FLOOR((C.marikoEmcMaxClock / 1000.0) / -0.9952024303111688));
const u32 tR2P = CEIL((RL * 0.426) - 2.0);
const u32 tR2W = FLOOR(FLOOR((5.0 / tCK_avg) + ((FLOOR(48.0 / WL) - 0.478) * 3.0)) / 1.501) + RL - (C.t6_tRTW * 3) + finetRTW;
const u32 tRTM = FLOOR((10.0 + RL) + (3.502 / tCK_avg)) + FLOOR(7.489 / tCK_avg);
const u32 tRATM = CEIL((tRTM - 10.0) + (RL * 0.426));
inline u32 rext;
const u32 qrstHighDuration = FLOOR(((C.marikoEmcMaxClock / 1000.0) * 0.001477125119082522) + 4.272302254983803);
const u32 qrstLow = CEIL(MAX(((C.marikoEmcMaxClock / 1000.0) * -0.010085158701622026) + ((rdv + (-15.612107759528982 - quse_width)) - qrstHighDuration), -0.0004475366008085334));
const u32 qrst = PACK_U32(qrstHighDuration, qrstLow);
inline u32 qsafe;
inline u32 qpop;
const u32 tW2P = (CEIL(WL * 1.7303) * 2) - 5;
inline u32 tWTPDEN;
const u32 tW2R = CEIL(MAX(WL + (0.010322547033278747 * (C.marikoEmcMaxClock / 1000.0)), (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);
const u32 rdv = RL + FLOOR((5.105 / tCK_avg) + 17.017);
const u32 qpop = rdv - 14;
const u32 quse_width = CEIL(((4.897 / tCK_avg) - FLOOR(2.538 / tCK_avg)) + 3.782);
const u32 quse = FLOOR(RL + ((5.082 / tCK_avg) + FLOOR(2.560 / tCK_avg))) - CEIL(4.820 / tCK_avg);
const u32 einput_duration = FLOOR(9.936 / tCK_avg) + 5.0 + quse_width;
const u32 einput = quse - CEIL(9.928 / tCK_avg);
const u32 qrst_duration = FLOOR(8.399 - tCK_avg);
const u32 qrstLow = MAX(static_cast<s32>(einput - qrst_duration - 2), static_cast<s32>(0));
const u32 qrst = PACK_U32(qrst_duration, qrstLow);
const u32 ibdly = PACK_U32_NIBBLE_HIGH_BYTE_LOW(1, quse - qrst_duration - 2.0);
const u32 qsafe = (einput_duration + 3) + MAX(MIN(qrstLow * rdv, qrst_duration + qrst_duration), einput);
const u32 tW2P = (CEIL(WL * 1.7303) * 2) - 5;
const u32 tWTPDEN = CEIL(((1.803 / tCK_avg) + MAX(RL + (2.694 / tCK_avg), static_cast<double>(tW2P))) + (BL / 2));
const u32 tW2R = FLOOR(MAX((5.020 / tCK_avg) + 1.130, WL - MAX(-CEIL(0.258 * (WL - RL)), 1.964)) * 1.964) + WL - CEIL(tWTR / tCK_avg) + finetWTR;
const u32 tWTM = CEIL(WL + ((7.570 / tCK_avg) + 8.753));
const u32 tWATM = (tWTM + (FLOOR(WL / 0.816) * 2.0)) - 4.0;
const u32 wdv = WL;
const u32 wsv = WL - 2;
const u32 wev = 0xA + C.mem_burst_write_latency;
const u32 wev = 0xA + (WL - 14);
inline u32 pdex2rw;
inline u32 cke2pden;
const u32 obdlyHigh = 3 / FLOOR(MIN(static_cast<double>(2), tCK_avg * (WL - 7)));
const u32 obdlyLow = MAX(WL - FLOOR((126.0 / CEIL(tCK_avg + 8.601))), 0.0);
const u32 obdly = PACK_U32_NIBBLE_HIGH_BYTE_LOW(obdlyHigh, obdlyLow);
const u32 tCKE = CEIL(1.0795 * CEIL(0.0074472 * (C.marikoEmcMaxClock / 1000.0)));
const u32 pdex2rw = CEIL((CEIL(12.335 - tCK_avg) + (7.430 / tCK_avg) - CEIL(tCK_avg * 11.361)));
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? */
inline u8 mrw2;
}
}

View File

@@ -1,7 +1,7 @@
/*
* Copyright (C) Switch-OC-Suite
*
* Copyright (c) Souldbminer and Horizon OC Contributors
* 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,
@@ -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);
@@ -99,4 +99,25 @@ namespace ams::ldr::oc {
R_SUCCEED();
}
};
namespace panic {
/* Requires modifying g_ams_handlers in secmon_smc_handler.cpp */
constexpr inline void SmcError(u32 rgb) {
SecmonArgs args = {};
constexpr u32 SmcShowErrorID = 0xF0000005;
args.X[0] = SmcShowErrorID;
args.X[1] = rgb;
svcCallSecureMonitor(&args);
}
constexpr inline u32 PackCode(u32 r, u32 g, u32 b) {
return ((r & 0xF) << 8) | ((g & 0xF) << 4) | ((b & 0xF) << 0);
}
constexpr u32 Gpu = PackCode(0xF, 0x7, 0x0);
constexpr u32 Cpu = PackCode(0xF, 0x0, 0x0);
constexpr u32 Emc = PackCode(0x0, 0xF, 0xF);
constexpr u32 Patch = PackCode(0x8, 0x0, 0xF);
}
}

View File

@@ -1,7 +1,7 @@
/*
* Copyright (C) Switch-OC-Suite
*
* Copyright (c) Souldbminer and Horizon OC Contributors
* 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,

View File

@@ -1,7 +1,7 @@
/*
* Copyright (C) Switch-OC-Suite
*
* Copyright (c) Souldbminer and Horizon OC Contributors
* 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,
@@ -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

@@ -1,7 +1,7 @@
/*
* Copyright (C) Switch-OC-Suite
*
* Copyright (c) Souldbminer and Horizon OC Contributors
* 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,

View File

@@ -3,7 +3,7 @@
*
* Copyright (c) 2023 hanai3Bi
*
* Copyright (c) Souldbminer and Horizon OC Contributors
* 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,
@@ -20,156 +20,165 @@
#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);
R_UNLESS(entry->freq == entry->vco_max, ldr::ResultInvalidMemPllmEntry());
Result MemFreqPllmLimit(u32* ptr) {
clk_pll_param* entry = reinterpret_cast<clk_pll_param *>(ptr);
R_UNLESS(entry->freq == entry->vco_max, ldr::ResultInvalidMemPllmEntry());
// Double the max clk simply
u32 max_clk = entry->freq * 2;
entry->freq = max_clk;
entry->vco_max = max_clk;
R_SUCCEED();
}
Result MemVoltHandler(u32* ptr) {
// ptr value might be default_uv or max_uv
regulator* entries[2] = {
reinterpret_cast<regulator *>(reinterpret_cast<u8 *>(ptr) - offsetof(regulator, type_1.default_uv)),
reinterpret_cast<regulator *>(reinterpret_cast<u8 *>(ptr) - offsetof(regulator, type_1.max_uv)),
};
constexpr u32 uv_step = 12'500;
constexpr u32 uv_min = 600'000;
auto validator = [](regulator* entry) {
R_UNLESS(entry->id == 1, ldr::ResultInvalidRegulatorEntry());
R_UNLESS(entry->type == 1, ldr::ResultInvalidRegulatorEntry());
R_UNLESS(entry->type_1.volt_reg == 0x17, ldr::ResultInvalidRegulatorEntry());
R_UNLESS(entry->type_1.step_uv == uv_step, ldr::ResultInvalidRegulatorEntry());
R_UNLESS(entry->type_1.min_uv == uv_min, ldr::ResultInvalidRegulatorEntry());
// Double the max clk simply
u32 max_clk = entry->freq * 2;
entry->freq = max_clk;
entry->vco_max = max_clk;
R_SUCCEED();
};
regulator* entry = nullptr;
for (auto& i : entries) {
if (R_SUCCEEDED(validator(i)))
entry = i;
}
R_UNLESS(entry, ldr::ResultInvalidRegulatorEntry());
Result MemVoltHandler(u32* ptr) {
// ptr value might be default_uv or max_uv
regulator* entries[2] = {
reinterpret_cast<regulator *>(reinterpret_cast<u8 *>(ptr) - offsetof(regulator, type_1.default_uv)),
reinterpret_cast<regulator *>(reinterpret_cast<u8 *>(ptr) - offsetof(regulator, type_1.max_uv)),
};
u32 emc_uv = C.commonEmcMemVolt;
if (!emc_uv)
R_SKIP();
if (emc_uv % uv_step)
emc_uv = emc_uv / uv_step * uv_step; // rounding
PATCH_OFFSET(ptr, emc_uv);
R_SUCCEED();
}
void SafetyCheck() {
// if (C.custRev != CUST_REV)
// CRASH("Triggered");
struct sValidator {
volatile u32 value;
u32 min;
u32 max;
bool value_required = false;
Result check() {
if (!value_required && !value)
R_SUCCEED();
if (min && value < min)
R_THROW(ldr::ResultSafetyCheckFailure());
if (max && value > max)
R_THROW(ldr::ResultSafetyCheckFailure());
constexpr u32 uv_step = 12'500;
constexpr u32 uv_min = 600'000;
auto validator = [](regulator* entry) {
R_UNLESS(entry->id == 1, ldr::ResultInvalidRegulatorEntry());
R_UNLESS(entry->type == 1, ldr::ResultInvalidRegulatorEntry());
R_UNLESS(entry->type_1.volt_reg == 0x17, ldr::ResultInvalidRegulatorEntry());
R_UNLESS(entry->type_1.step_uv == uv_step, ldr::ResultInvalidRegulatorEntry());
R_UNLESS(entry->type_1.min_uv == uv_min, ldr::ResultInvalidRegulatorEntry());
R_SUCCEED();
};
regulator* entry = nullptr;
for (auto& i : entries) {
if (R_SUCCEEDED(validator(i))) {
entry = i;
}
}
};
u32 eristaCpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaCpuDvfsTable)->freq);
u32 marikoCpuDvfsMaxFreq;
if (C.marikoCpuUVHigh) {
marikoCpuDvfsMaxFreq = static_cast<u32>(
GetDvfsTableLastEntry(C.marikoCpuDvfsTableSLT)->freq
);
} else {
marikoCpuDvfsMaxFreq = static_cast<u32>(
GetDvfsTableLastEntry(C.marikoCpuDvfsTable)->freq
);
R_UNLESS(entry, ldr::ResultInvalidRegulatorEntry());
u32 emc_uv = C.commonEmcMemVolt;
if (!emc_uv) {
R_SKIP();
}
u32 eristaGpuDvfsMaxFreq;
switch (C.eristaGpuUV)
{
case 0:
eristaGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaGpuDvfsTable)->freq);
break;
case 1:
eristaGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaGpuDvfsTableSLT)->freq);
break;
case 2:
case 3:
eristaGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaGpuDvfsTableHiOPT)->freq);
break;
default:
eristaGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaGpuDvfsTable)->freq);
break;
if (emc_uv % uv_step) {
emc_uv = emc_uv / uv_step * uv_step; // rounding
}
PATCH_OFFSET(ptr, emc_uv);
R_SUCCEED();
}
u32 marikoGpuDvfsMaxFreq;
switch (C.marikoGpuUV) {
void SafetyCheck() {
// if (C.custRev != CUST_REV)
// CRASH("Triggered");
struct sValidator {
volatile u32 value;
u32 min;
u32 max;
bool value_required = false;
u32 panic;
Result check() {
if (!value_required && !value)
R_SUCCEED();
if (min && value < min)
R_THROW(ldr::ResultSafetyCheckFailure());
if (max && value > max)
R_THROW(ldr::ResultSafetyCheckFailure());
R_SUCCEED();
}
};
u32 eristaCpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaCpuDvfsTable)->freq);
u32 marikoCpuDvfsMaxFreq;
if (C.marikoCpuUVHigh) {
marikoCpuDvfsMaxFreq = static_cast<u32>(
GetDvfsTableLastEntry(C.marikoCpuDvfsTableSLT)->freq
);
} else {
marikoCpuDvfsMaxFreq = static_cast<u32>(
GetDvfsTableLastEntry(C.marikoCpuDvfsTable)->freq
);
}
u32 eristaGpuDvfsMaxFreq;
switch (C.eristaGpuUV) {
case 0:
marikoGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.marikoGpuDvfsTable)->freq);
eristaGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaGpuDvfsTable)->freq);
break;
case 1:
marikoGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.marikoGpuDvfsTableSLT)->freq);
eristaGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaGpuDvfsTableSLT)->freq);
break;
case 2:
case 3:
marikoGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.marikoGpuDvfsTableHiOPT)->freq);
eristaGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaGpuDvfsTableHiOPT)->freq);
break;
default:
marikoGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.marikoGpuDvfsTable)->freq);
eristaGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaGpuDvfsTable)->freq);
break;
}
u32 marikoGpuDvfsMaxFreq;
switch (C.marikoGpuUV) {
case 0:
marikoGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.marikoGpuDvfsTable)->freq);
break;
case 1:
marikoGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.marikoGpuDvfsTableSLT)->freq);
break;
case 2:
marikoGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.marikoGpuDvfsTableHiOPT)->freq);
break;
default:
marikoGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.marikoGpuDvfsTable)->freq);
break;
}
using namespace ams::ldr::hoc::pcv;
sValidator validators[] = {
{ C.eristaCpuBoostClock, 1020'000, 2295'000, true, panic::Cpu },
{ C.marikoCpuBoostClock, 1020'000, 2703'000, true, panic::Cpu },
{ C.eristaCpuMaxVolt, 1000, 1260, false, panic::Cpu },
{ C.marikoCpuMaxVolt, 1000, 1200, false, panic::Cpu },
{ eristaCpuDvfsMaxFreq, 1785'000, 2295'000, false, panic::Cpu },
{ marikoCpuDvfsMaxFreq, 1785'000, 2703'000, false, panic::Cpu },
{ C.commonEmcMemVolt, 912'500, 1350'000, false, panic::Emc }, // Official burst vmax for the RAMs is 1500mV
{ GET_MAX_OF_ARR(erista::maxEmcClocks), 1600'000, 2600'000, false, panic::Emc },
{ C.marikoEmcMaxClock, 1600'000, 3500'000, false, panic::Emc },
{ C.marikoEmcVddqVolt, 250'000, 700'000, false, panic::Emc },
{ eristaGpuDvfsMaxFreq, 768'000, 1152'000, false, panic::Gpu },
{ marikoGpuDvfsMaxFreq, 768'000, 1570'000, false, panic::Gpu },
{ C.marikoGpuVmax, 800, 960, false, panic::Gpu },
};
for (auto &v : validators) {
if (R_FAILED(v.check())) {
#if defined(AMS_BUILD_FOR_AUDITING) || defined(AMS_BUILD_FOR_DEBUGGING)
panic::SmcError(v.panic);
#endif
CRASH("Validation FAIL");
}
}
}
sValidator validators[] = {
{ C.eristaCpuBoostClock, 1020'000, 2295'000, true },
{ C.marikoCpuBoostClock, 1020'000, 2703'000, true },
{ C.commonEmcMemVolt, 1100'000, 1350'000 }, // Official burst vmax for the RAMs is 1500mV
{ C.eristaCpuMaxVolt, 1100, 1257 },
{ C.eristaEmcMaxClock, 1600'000, 2600'200 },
{ C.marikoCpuMaxVolt, 1100, 1235 },
{ C.marikoEmcMaxClock, 1600'000, 3500'000 },
{ C.marikoEmcVddqVolt, 550'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) {
if (R_FAILED(i.check()))
CRASH("Validation FAIL");
void Patch(uintptr_t mapped_nso, size_t nso_size) {
#ifdef ATMOSPHERE_IS_STRATOSPHERE
SafetyCheck();
bool isMariko = (spl::GetSocType() == spl::SocType_Mariko);
if (isMariko)
mariko::Patch(mapped_nso, nso_size);
else
erista::Patch(mapped_nso, nso_size);
#endif
}
}
void Patch(uintptr_t mapped_nso, size_t nso_size) {
#ifdef ATMOSPHERE_IS_STRATOSPHERE
SafetyCheck();
bool isMariko = (spl::GetSocType() == spl::SocType_Mariko);
if (isMariko)
mariko::Patch(mapped_nso, nso_size);
else
mariko::Patch(mapped_nso, nso_size);
#endif
}
}

View File

@@ -3,7 +3,7 @@
*
* Copyright (c) 2023 hanai3Bi
*
* Copyright (c) Souldbminer and Horizon OC Contributors
* 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,
@@ -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[] = {
@@ -58,7 +58,7 @@ namespace ams::ldr::oc::pcv {
static const u32 cpuVoltThermalData[] = { 620, 1120, 20000, 620, 1120, 70000, 950, 1132, 0, 950, 1227, 0 };
static const u32 allowedCpuMaxFrequencies[] = { 2'397'000, 2'499'000, 2'601'000, 2'703'000, };
static const u32 allowedCpuMaxFrequencies[] = { 1'963'000, 2'091'000, 2'193'000, 2'295'000, 2'397'000, 2'499'000, 2'601'000, 2'703'000, };
constexpr cvb_entry_t GpuCvbTableDefault[] = {
// GPUB01_NA_CVB_TABLE
@@ -101,6 +101,7 @@ namespace ams::ldr::oc::pcv {
};
static const SpeedoVminTable vminTable[] {
{1400, 610}, // LOW SPEEDO -> use stock vmin
{1560, 590},
{1583, 570},
{1620, 565},
@@ -177,6 +178,9 @@ namespace ams::ldr::oc::pcv {
}
namespace erista {
static u32 maxEmcClocks[] = { 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}, { } },
@@ -198,31 +202,34 @@ namespace ams::ldr::oc::pcv {
{ },
};
constexpr u32 CpuVoltOfficial = 1235;
constexpr u32 CpuVoltOfficial = 1227;
constexpr u32 CpuVminOfficial = 825;
constexpr u32 CpuVoltL4T = 1235'000;
constexpr u32 CpuVoltL4T = 1257'000;
static const u32 cpuVoltDvfsPattern[] = { 1227, 1000, 100, 1000, 0 };
static const u32 cpuVoltDvfsOffsets[] = { 5, 6, 7, 9, 8 };
static_assert(sizeof(cpuVoltDvfsPattern) == sizeof(cpuVoltDvfsOffsets), "Invalid cpuVoltDvfsPattern");
static_assert(sizeof(cpuVoltDvfsPattern) == 0x14, "invalid cpuVoltDvfsPattern size");
static const u32 cpuVoltageThermalPattern[] = { 950, 1132, 0, 950, 1227, 0, 825, 1227, 15000, 825, 1170, 60000, 825, 1132, 80000 };
static_assert(sizeof(cpuVoltageThermalPattern) == 0x3c, "invalid cpuVoltageThermalPattern size");
constexpr u32 GpuClkPllLimit = 921'600'000;
constexpr u32 GpuClkPllLimit = 2'600'000;
constexpr u32 GpuClkPllMax = 921'600'000;
constexpr u32 GpuVminOfficial = 810;
static const u32 gpuVoltDvfsPattern[] = { 1150, 1000, 100, 1000, 10, };
static const u32 gpuVoltDvfsOffsets[] = { 1, 2, 3, 4, 5, };
static_assert(sizeof(gpuVoltDvfsPattern) == sizeof(gpuVoltDvfsOffsets), "Invalid gpuVoltDvfsPattern");
constexpr u16 CpuMinVolts[] = { 950, 850, 825, 810 };
inline bool CpuMaxVoltPatternFn(u32* ptr32) {
u32 val = *ptr32;
return (val == 1132 || val == 1170 || val == 1227);
}
static const u32 gpuVoltDvfsPattern[] = { 810, 1150, 1000, 100, 1000, 10, };
static_assert(sizeof(gpuVoltDvfsPattern) == (sizeof(u32) * 6), "Invalid gpuVoltDvfsPattern");
static const u32 gpuVoltThermalPattern[] = { 950, 1132, 0, 810, 1132, 15000, 810, 1132, 30000, 810, 1132, 50000, 810, 1132, 70000, 810, 1132, 105000 };
static_assert(sizeof(gpuVoltThermalPattern) == 0x48, "invalid gpuVoltageThermalPattern size");
/* GPU Max Clock asm Pattern:
*
* MOV W11, #0x1000 MOV (wide immediate) 0x1000 0xB (11)
@@ -277,6 +284,7 @@ namespace ams::ldr::oc::pcv {
};
constexpr u32 MemVoltHOS = 1125'000;
constexpr u32 EmcClkMinFreq = 40800; /* 40.8 MHz table only exists on erista. */
constexpr u32 EmcClkPllmLimit = 1866'000'000;
constexpr u32 MTC_TABLE_REV = 7;
@@ -308,8 +316,8 @@ namespace ams::ldr::oc::pcv {
customize_table = const_cast<cvb_entry_t *>(C.marikoCpuDvfsTable1581Tbreak);
break;
}
case HELIOS_TABLE: {
customize_table = const_cast<cvb_entry_t *>(C.marikoCpuDvfsTableHelios);
case EXTREME_TABLE: {
customize_table = const_cast<cvb_entry_t *>(C.marikoCpuDvfsTableExtreme);
break;
}
case DEFAULT_TABLE:
@@ -419,27 +427,26 @@ namespace ams::ldr::oc::pcv {
std::memcpy(gpu_cvb_table_head, (void *)customize_table, customize_table_size);
// Patch GPU volt
if (C.marikoGpuUV == 2 || C.eristaGpuUV == 2) {
cvb_entry_t *entry = static_cast<cvb_entry_t *>(gpu_cvb_table_head);
for (size_t i = 0; i < customize_entry_count; ++i) {
if (isMariko) {
if (C.marikoGpuVoltArray[i] != 0) {
PATCH_OFFSET(&(entry->cvb_pll_param.c0), (C.marikoGpuVoltArray[i] * 1000));
ClearCvbPllEntry(entry);
} else {
PATCH_OFFSET(&(entry->cvb_pll_param.c0), (entry->cvb_pll_param.c0 - C.commonGpuVoltOffset * 1000));
}
cvb_entry_t *entry = static_cast<cvb_entry_t *>(gpu_cvb_table_head);
for (size_t i = 0; i < customize_entry_count; ++i) {
if (isMariko) {
if (C.marikoGpuVoltArray[i] != 0) {
PATCH_OFFSET(&(entry->cvb_pll_param.c0), (C.marikoGpuVoltArray[i] * 1000));
ClearCvbPllEntry(entry);
} else {
if (C.eristaGpuVoltArray[i] != 0) {
PATCH_OFFSET(&(entry->cvb_pll_param.c0), (C.eristaGpuVoltArray[i] * 1000));
ClearCvbPllEntry(entry);
} else {
PATCH_OFFSET(&(entry->cvb_pll_param.c0), (entry->cvb_pll_param.c0 - C.commonGpuVoltOffset * 1000));
}
PATCH_OFFSET(&(entry->cvb_pll_param.c0), (entry->cvb_pll_param.c0 - C.commonGpuVoltOffset * 1000));
}
} else {
if (C.eristaGpuVoltArray[i] != 0) {
PATCH_OFFSET(&(entry->cvb_pll_param.c0), (C.eristaGpuVoltArray[i] * 1000));
ClearCvbPllEntry(entry);
} else {
PATCH_OFFSET(&(entry->cvb_pll_param.c0), (entry->cvb_pll_param.c0 - C.commonGpuVoltOffset * 1000));
}
++entry;
}
} else if (C.commonGpuVoltOffset) {
++entry;
}
if (C.commonGpuVoltOffset && !(isMariko ? C.marikoGpuUV : C.eristaGpuUV)) {
cvb_entry_t *entry = static_cast<cvb_entry_t *>(gpu_cvb_table_head);
for (size_t i = 0; i < customize_entry_count; ++i) {
PATCH_OFFSET(&(entry->cvb_pll_param.c0), (entry->cvb_pll_param.c0 - C.commonGpuVoltOffset * 1000));

View File

@@ -1,7 +1,7 @@
/*
* Copyright (C) Switch-OC-Suite
*
* Copyright (c) Souldbminer and Horizon OC Contributors
* 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,
@@ -16,153 +16,154 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#pragma once
namespace ams::ldr::oc::pcv {
namespace ams::ldr::hoc::pcv {
typedef struct cvb_coefficients {
s32 c0 = 0;
s32 c1 = 0;
s32 c2 = 0;
s32 c3 = 0;
s32 c4 = 0;
s32 c5 = 0;
} cvb_coefficients;
typedef struct cvb_coefficients {
s32 c0 = 0;
s32 c1 = 0;
s32 c2 = 0;
s32 c3 = 0;
s32 c4 = 0;
s32 c5 = 0;
} cvb_coefficients;
typedef struct cvb_entry_t {
u64 freq;
cvb_coefficients cvb_dfll_param;
cvb_coefficients cvb_pll_param;
} cvb_entry_t;
static_assert(sizeof(cvb_entry_t) == 0x38);
typedef struct cvb_entry_t {
u64 freq;
cvb_coefficients cvb_dfll_param;
cvb_coefficients cvb_pll_param;
} cvb_entry_t;
static_assert(sizeof(cvb_entry_t) == 0x38);
typedef struct cvb_cpu_dfll_data {
u32 tune0_low;
u32 tune0_high;
u32 tune1_low;
u32 tune1_high;
unsigned int tune_high_min_millivolts;
unsigned int tune_high_margin_millivolts;
unsigned long dvco_calibration_max;
} cvb_cpu_dfll_data;
typedef struct cvb_cpu_dfll_data {
u32 tune0_low;
u32 tune0_high;
u32 tune1_low;
u32 tune1_high;
unsigned int tune_high_min_millivolts;
unsigned int tune_high_margin_millivolts;
unsigned long dvco_calibration_max;
} cvb_cpu_dfll_data;
typedef struct emc_dvb_dvfs_table_t {
u64 freq;
s32 volt[4] = {0};
} emc_dvb_dvfs_table_t;
typedef struct emc_dvb_dvfs_table_t {
u64 freq;
s32 volt[4] = {0};
} emc_dvb_dvfs_table_t;
typedef struct __attribute__((packed)) div_nmp {
u8 divn_shift;
u8 divn_width;
u8 divm_shift;
u8 divm_width;
u8 divp_shift;
u8 divp_width;
u8 override_divn_shift;
u8 override_divm_shift;
u8 override_divp_shift;
} div_nmp;
typedef struct __attribute__((packed)) div_nmp {
u8 divn_shift;
u8 divn_width;
u8 divm_shift;
u8 divm_width;
u8 divp_shift;
u8 divp_width;
u8 override_divn_shift;
u8 override_divm_shift;
u8 override_divp_shift;
} div_nmp;
typedef struct __attribute__((packed)) clk_pll_param {
u32 freq;
u32 input_min;
u32 input_max;
u32 cf_min;
u32 cf_max;
u32 vco_min;
u32 vco_max;
s32 lock_delay;
u32 fixed_rate;
u32 unk_0;
struct div_nmp *div_nmp;
u32 unk_1[4];
void (*unk_fn)(u64* unk_struct); // set_defaults?
} clk_pll_param;
typedef struct __attribute__((packed)) clk_pll_param {
u32 freq;
u32 input_min;
u32 input_max;
u32 cf_min;
u32 cf_max;
u32 vco_min;
u32 vco_max;
s32 lock_delay;
u32 fixed_rate;
u32 unk_0;
struct div_nmp *div_nmp;
u32 unk_1[4];
void (*unk_fn)(u64* unk_struct); // set_defaults?
} clk_pll_param;
typedef struct __attribute__((packed)) dvfs_rail {
u32 id;
u32 unk_0[5];
u32 freq;
u32 unk_1[8];
u32 unk_flag;
u32 min_mv;
u32 step_mv;
u32 max_mv;
u32 unk_2[11];
} dvfs_rail;
typedef struct __attribute__((packed)) dvfs_rail {
u32 id;
u32 unk_0[5];
u32 freq;
u32 unk_1[8];
u32 unk_flag;
u32 min_mv;
u32 step_mv;
u32 max_mv;
u32 unk_2[11];
} dvfs_rail;
typedef struct __attribute__((packed)) regulator {
u64 id;
const char* name;
u32 type;
union {
struct {
u32 volt_reg;
u32 step_uv;
u32 min_uv;
u32 default_uv;
u32 max_uv;
u32 unk_0[2];
} type_1;
struct {
u32 unk_0;
u32 step_uv;
u32 unk_1;
u32 min_uv;
u32 max_uv;
u32 unk_2;
u32 default_uv;
} type_2_3;
};
u32 unk_x[60];
} regulator;
static_assert(sizeof(regulator) == 0x120);
typedef struct __attribute__((packed)) regulator {
u64 id;
const char* name;
u32 type;
union {
struct {
u32 volt_reg;
u32 step_uv;
u32 min_uv;
u32 default_uv;
u32 max_uv;
u32 unk_0[2];
} type_1;
struct {
u32 unk_0;
u32 step_uv;
u32 unk_1;
u32 min_uv;
u32 max_uv;
u32 unk_2;
u32 default_uv;
} type_2_3;
};
u32 unk_x[60];
} regulator;
static_assert(sizeof(regulator) == 0x120);
constexpr u32 CpuClkOSLimit = 1785'000;
constexpr u32 CpuClkOSLimit = 1785'000;
constexpr u32 EmcClkOSLimit = 1600'000;
constexpr u32 EmcClkOSLimit = 1600'000;
#define R_SKIP() R_SUCCEED()
#define R_SKIP() R_SUCCEED()
// Count 32 / Index 31 is reserved to be empty
constexpr size_t DvfsTableEntryCount = 32;
constexpr size_t DvfsTableEntryLimit = DvfsTableEntryCount - 1;
// Count 32 / Index 31 is reserved to be empty
constexpr size_t DvfsTableEntryCount = 32;
constexpr size_t DvfsTableEntryLimit = DvfsTableEntryCount - 1;
template<typename T>
size_t GetDvfsTableEntryCount(T* table_head) {
using NT = std::remove_const_t<std::remove_volatile_t<T>>;
template<typename T>
size_t GetDvfsTableEntryCount(T* table_head) {
using NT = std::remove_const_t<std::remove_volatile_t<T>>;
auto is_empty = [](NT* entry) {
uint8_t* m = reinterpret_cast<uint8_t *>(entry);
for (size_t i = 0; i < sizeof(NT); i++) {
if (*(m + i))
return false;
}
return true;
};
auto is_empty = [](NT* entry) {
uint8_t* m = reinterpret_cast<uint8_t *>(entry);
for (size_t i = 0; i < sizeof(NT); i++) {
if (*(m + i)) {
return false;
}
}
return true;
};
NT* table = const_cast<NT *>(table_head);
size_t count = 0;
while (count < DvfsTableEntryLimit) {
if (is_empty(table++)) {
return count;
}
count++;
}
return DvfsTableEntryLimit;
}
NT* table = const_cast<NT *>(table_head);
size_t count = 0;
while (count < DvfsTableEntryLimit) {
if (is_empty(table++)) {
return count;
}
count++;
}
return DvfsTableEntryLimit;
}
template<typename T>
T* GetDvfsTableLastEntry(T* table_head) {
using NT = std::remove_const_t<std::remove_volatile_t<T>>;
template<typename T>
T* GetDvfsTableLastEntry(T* table_head) {
using NT = std::remove_const_t<std::remove_volatile_t<T>>;
NT* table = const_cast<NT *>(table_head);
size_t count = GetDvfsTableEntryCount(table_head);
if (!count) {
return nullptr;
}
size_t index = count - 1;
return table + index;
}
NT* table = const_cast<NT *>(table_head);
size_t count = GetDvfsTableEntryCount(table_head);
if (!count) {
return nullptr;
}
size_t index = count - 1;
return table + index;
}
}
}

View File

@@ -3,7 +3,7 @@
*
* Copyright (c) 2023 hanai3Bi
*
* Copyright (c) Souldbminer and Horizon OC Contributors
* 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,
@@ -20,39 +20,39 @@
#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)) {
if (C.eristaCpuVmin) {
PATCH_OFFSET(ptr, C.eristaCpuVmin);
}
if (C.eristaCpuUV) {
PATCH_OFFSET(ptr - 2, C.eristaCpuVmin);
}
if (C.eristaCpuMaxVolt) {
PATCH_OFFSET(ptr + 5, C.eristaCpuMaxVolt);
}
R_SUCCEED();
if (std::memcmp(ptr + 5, cpuVoltDvfsPattern, sizeof(cpuVoltDvfsPattern))) {
R_THROW(ldr::ResultInvalidCpuMinVolt());
}
R_THROW(ldr::ResultInvalidCpuMinVolt());
if (C.eristaCpuVmin) {
PATCH_OFFSET(ptr, C.eristaCpuVmin);
}
if (C.eristaCpuUV) {
PATCH_OFFSET(ptr - 2, C.eristaCpuVmin);
}
if (C.eristaCpuMaxVolt) {
PATCH_OFFSET(ptr + 5, C.eristaCpuMaxVolt);
}
R_SUCCEED();
}
Result CpuVoltThermals(u32 *ptr) {
if (std::memcmp(ptr - 6, cpuVoltageThermalPattern, sizeof(cpuVoltageThermalPattern))) {
// AMS_ABORT_UNLESS(0);
R_THROW(ldr::ResultInvalidCpuMinVolt());
}
if (C.eristaCpuVmin) {
PATCH_OFFSET( ptr, C.eristaCpuVmin);
PATCH_OFFSET(ptr + 3, C.eristaCpuVmin);
PATCH_OFFSET(ptr + 9, C.eristaCpuVmin);
PATCH_OFFSET(ptr + 6, C.eristaCpuVmin);
}
if (C.eristaCpuMaxVolt) {
@@ -67,13 +67,12 @@ namespace ams::ldr::oc::pcv::erista {
Result CpuVoltDfll(u32* ptr) {
cvb_cpu_dfll_data *entry = reinterpret_cast<cvb_cpu_dfll_data *>(ptr);
R_UNLESS(entry->tune0_low == 0xFFEAD0FF, ldr::ResultInvalidCpuVoltDfllEntry());
R_UNLESS(entry->tune0_high == 0x0, ldr::ResultInvalidCpuVoltDfllEntry());
R_UNLESS(entry->tune1_low == 0x0, ldr::ResultInvalidCpuVoltDfllEntry());
R_UNLESS(entry->tune1_high == 0x0, ldr::ResultInvalidCpuVoltDfllEntry());
R_UNLESS(entry->tune0_low == 0x0000FFCF, ldr::ResultInvalidCpuVoltDfllEntry());
R_UNLESS(entry->tune0_high == 0x00000000, ldr::ResultInvalidCpuVoltDfllEntry());
R_UNLESS(entry->tune1_low == 0x012207FF, ldr::ResultInvalidCpuVoltDfllEntry());
R_UNLESS(entry->tune1_high == 0x03FFF7FF, ldr::ResultInvalidCpuVoltDfllEntry());
if( !C.eristaCpuUV) {
if (!C.eristaCpuUV) {
R_SKIP();
}
@@ -105,19 +104,19 @@ namespace ams::ldr::oc::pcv::erista {
}
Result GpuVoltDVFS(u32 *ptr) {
if (MatchesPattern(ptr, gpuVoltDvfsPattern, gpuVoltDvfsOffsets)) {
if (C.eristaGpuVmin) {
PATCH_OFFSET(ptr, C.eristaGpuVmin);
}
R_SUCCEED();
if (std::memcmp(ptr, gpuVoltDvfsPattern, sizeof(gpuVoltDvfsPattern))) {
R_THROW(ldr::ResultInvalidGpuDvfs());
}
R_THROW(ldr::ResultInvalidGpuDvfs());
if (C.eristaGpuVmin) {
PATCH_OFFSET(ptr, C.eristaGpuVmin);
}
R_SUCCEED();
}
Result GpuVoltThermals(u32 *ptr) {
u32 result = std::memcmp(ptr - 3, gpuVoltThermalPattern, sizeof(gpuVoltThermalPattern));
if (result) {
if (std::memcmp(ptr - 3, gpuVoltThermalPattern, sizeof(gpuVoltThermalPattern))) {
R_THROW(ldr::ResultInvalidGpuDvfs());
}
@@ -167,7 +166,258 @@ namespace ams::ldr::oc::pcv::erista {
R_SUCCEED();
}
Result GpuFreqPllLimit(u32 *ptr) {
/* 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 */
/* B29: DRAM_ACPD */
if (C.hpMode) {
WRITE_PARAM_ALL_REG(table, emc_cfg, 0x13200000);
} else {
WRITE_PARAM_ALL_REG(table, emc_cfg, 0xF3200000);
}
u32 refresh_raw = 0xFFFF;
if (C.t8_tREFI != 6) {
refresh_raw = CEIL(tREFpb_values[C.t8_tREFI] / tCK_avg) - 0x40;
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)));
WRITE_PARAM_ALL_REG(table, emc_ras, MIN(GET_CYCLE_CEIL(tRAS), static_cast<u32>(0x7F)));
WRITE_PARAM_ALL_REG(table, emc_rrd, GET_CYCLE_CEIL(tRRD));
WRITE_PARAM_ALL_REG(table, emc_rfcpb, GET_CYCLE_CEIL(tRFCpb));
WRITE_PARAM_ALL_REG(table, emc_rfc, GET_CYCLE_CEIL(tRFCab));
WRITE_PARAM_ALL_REG(table, emc_rp, GET_CYCLE_CEIL(tRPpb));
WRITE_PARAM_ALL_REG(table, emc_txsr, MIN(GET_CYCLE_CEIL(tXSR), static_cast<u32>(0x3fe)));
WRITE_PARAM_ALL_REG(table, emc_txsrdll, MIN(GET_CYCLE_CEIL(tXSR), static_cast<u32>(0x3fe)));
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, GET_CYCLE_CEIL(7.425) + 2);
WRITE_PARAM_ALL_REG(table, emc_tpd, GET_CYCLE_CEIL(tXP));
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, 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);
const u32 dyn_self_ref_control = (static_cast<u32>(7605.0 / tCK_avg) + 260) | (table->burst_regs.emc_dyn_self_ref_control & 0xffff0000);
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.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, 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;
/* 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 = 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;
table->burst_mc_regs.mc_emem_arb_timing_ras = CEIL(GET_CYCLE_CEIL(tRAS) / MC_ARB_DIV) - 2;
table->burst_mc_regs.mc_emem_arb_timing_faw = CEIL(GET_CYCLE_CEIL(tFAW) / MC_ARB_DIV) - 1;
table->burst_mc_regs.mc_emem_arb_timing_rrd = CEIL(GET_CYCLE_CEIL(tRRD) / MC_ARB_DIV) - 1;
table->burst_mc_regs.mc_emem_arb_timing_rfcpb = CEIL(GET_CYCLE_CEIL(tRFCpb) / MC_ARB_DIV) - 1;
table->burst_mc_regs.mc_emem_arb_timing_rap2pre = CEIL(tR2P / MC_ARB_DIV);
table->burst_mc_regs.mc_emem_arb_timing_wap2pre = CEIL(tW2P / MC_ARB_DIV) + MC_ARB_SFA;
if (table->burst_mc_regs.mc_emem_arb_timing_r2r > 1) {
table->burst_mc_regs.mc_emem_arb_timing_r2r = CEIL(table->burst_regs.emc_rext / 4) - 1 + MC_ARB_SFA;
}
table->burst_mc_regs.mc_emem_arb_timing_r2w = CEIL(tR2W / MC_ARB_DIV) - 1 + MC_ARB_SFA;
table->burst_mc_regs.mc_emem_arb_timing_w2r = CEIL(tW2R / MC_ARB_DIV) - 1 + MC_ARB_SFA;
u32 da_turns = 0;
da_turns |= u8(table->burst_mc_regs.mc_emem_arb_timing_r2w / 2) << 16;
da_turns |= u8(table->burst_mc_regs.mc_emem_arb_timing_w2r / 2) << 24;
table->burst_mc_regs.mc_emem_arb_da_turns = da_turns;
u32 da_covers = 0;
u8 r_cover = (table->burst_mc_regs.mc_emem_arb_timing_rap2pre + table->burst_mc_regs.mc_emem_arb_timing_rp + table->burst_mc_regs.mc_emem_arb_timing_rcd) / 2;
u8 w_cover = (table->burst_mc_regs.mc_emem_arb_timing_wap2pre + table->burst_mc_regs.mc_emem_arb_timing_rp + table->burst_mc_regs.mc_emem_arb_timing_rcd) / 2;
da_covers |= (table->burst_mc_regs.mc_emem_arb_timing_rc / 2);
da_covers |= (r_cover << 8);
da_covers |= (w_cover << 16);
table->burst_mc_regs.mc_emem_arb_da_covers = da_covers;
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);
u32 mpcorer_ptsa_rate = MIN(static_cast<u32>(227), (table->rate_khz / 1600000) * 208);
table->la_scale_regs.mc_mll_mpcorer_ptsa_rate = mpcorer_ptsa_rate;
u32 ftop_ptsa_rate = MIN(static_cast<u32>(31), (table->rate_khz / 1600000) * 24);
table->la_scale_regs.mc_ftop_ptsa_rate = ftop_ptsa_rate;
u32 grant_decrement = MIN(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 / (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_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->emc_cfg_2 = 0x11083D;
table->min_volt = std::min(static_cast<u32>(1050), 900 + C.emcDvbShift * 25);
}
/* Probably more intuitive to point to 40800 rather than 1600000, but oh well. */
Result MemFreqMtcTable(u32 *ptr) {
if (GET_MAX_OF_ARR(maxEmcClocks) <= EmcClkOSLimit) {
R_SKIP();
}
u32 khz_list[] = { 40800, 68000, 102000, 204000, 408000, 665600, 800000, 1065600, 1331200, 1600000 };
std::sort(maxEmcClocks, maxEmcClocks + std::size(maxEmcClocks));
u32 khz_list_size = std::size(khz_list);
// Generate list for mtc table pointers
EristaMtcTable *table_list[khz_list_size];
for (u32 i = 0; i < khz_list_size; i++) {
u32 mtcIndex = khz_list_size - 1 - i;
u8 *table = reinterpret_cast<u8 *>(ptr) - offsetof(EristaMtcTable, rate_khz) - i * sizeof(EristaMtcTable);
table_list[mtcIndex] = reinterpret_cast<EristaMtcTable *>(table);
R_UNLESS(table_list[mtcIndex]->rate_khz == khz_list[mtcIndex], ldr::ResultInvalidMtcTable());
R_UNLESS(table_list[mtcIndex]->rev == MTC_TABLE_REV, ldr::ResultInvalidMtcTable());
}
/* If we oc ram at all, tables are always shifted by at least 1. */
u32 tableShifts = 1;
for (u32 i = 0; i < std::size(maxEmcClocks) - 1; ++i) {
/* Duplicated mtc tables may cause pcv to not select frequencies properly, causing issues. */
if (maxEmcClocks[i] != maxEmcClocks[i + 1] && maxEmcClocks[i] > EmcClkOSLimit) {
++tableShifts;
} else {
maxEmcClocks[i] = 0;
}
}
/* Erista has extra, useless mtc tables, such as 40.8 Mhz, overwrite them to make room for oc freqs. */
/* More than 3 tables can be overwritten, but 3 is plenty. */
std::memmove(table_list[0], table_list[tableShifts], sizeof(EristaMtcTable) * (khz_list_size - tableShifts));
/* Since we're not scaling r/w latency properly on Erista, we first overwrite the tables with the 1600 MHz table before scaling it. */
for (u32 i = 0; i < tableShifts; ++i) {
std::memcpy(table_list[khz_list_size - i - 1], table_list[khz_list_size - tableShifts - 1], sizeof(EristaMtcTable));
}
for (u32 i = tableShifts, j = 0; i > 0 && j < std::size(maxEmcClocks); ++j) {
if (!maxEmcClocks[j]) {
continue;
}
table_list[khz_list_size - i]->rate_khz = maxEmcClocks[j];
MemMtcTableAutoAdjust(table_list[khz_list_size - i]);
--i;
}
R_SUCCEED();
}
Result MemFreqMax(u32 *ptr) {
if (GET_MAX_OF_ARR(maxEmcClocks) <= EmcClkOSLimit) {
R_SKIP();
}
PATCH_OFFSET(ptr, GET_MAX_OF_ARR(maxEmcClocks));
R_SUCCEED();
}
Result GpuFreqPllMax(u32 *ptr) {
clk_pll_param *entry = reinterpret_cast<clk_pll_param *>(ptr);
// All zero except for freq
@@ -181,570 +431,31 @@ 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))
// patch out 1305MHz limit on erista, don't use this!
// Result GpuFreqPllLimit(u32 *ptr) {
// u32 prev_freq = *(ptr - 1);
/* 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;
// }
// if (prev_freq != 128000 && prev_freq != 1300000 && prev_freq != 76800) {
// R_THROW(ldr::ResultInvalidGpuPllEntry());
// }
// 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);
// }
// PATCH_OFFSET(ptr, 3600000);
// 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. */
void MemMtcTableAutoAdjust(EristaMtcTable *table) {
(void) table;
// using namespace pcv::erista;
//
/* #define WRITE_PARAM_ALL_REG(TABLE, PARAM, VALUE) // note: add backslashes to make the macro definition work
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) / (1000000.0 / 1600000.0)))
//
// /* 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));
//
// /* Primary timings. */
// WRITE_PARAM_ALL_REG(table, emc_rd_rcd, GET_CYCLE(tRCD));
// WRITE_PARAM_ALL_REG(table, emc_wr_rcd, GET_CYCLE(tRCD));
// WRITE_PARAM_ALL_REG(table, emc_ras, GET_CYCLE(tRAS));
// WRITE_PARAM_ALL_REG(table, emc_rp, GET_CYCLE(tRPpb));
//
// /* Secondary timings. */
// WRITE_PARAM_ALL_REG(table, emc_rrd, GET_CYCLE(tRRD));
// WRITE_PARAM_ALL_REG(table, emc_rfc, GET_CYCLE(tRFCab));
// WRITE_PARAM_ALL_REG(table, emc_rfcpb, GET_CYCLE(tRFCpb));
// WRITE_PARAM_ALL_REG(table, emc_r2w, tR2W);
// WRITE_PARAM_ALL_REG(table, emc_w2r, tW2R);
// WRITE_PARAM_ALL_REG(table, emc_r2p, (u32) 0xC);
// WRITE_PARAM_ALL_REG(table, emc_w2p, (u32) 0x2D);
//
// WRITE_PARAM_ALL_REG(table, emc_rext, rext);
// WRITE_PARAM_ALL_REG(table, emc_wext, wext);
//
// WRITE_PARAM_ALL_REG(table, emc_trpab, GET_CYCLE(tRPab));
// WRITE_PARAM_ALL_REG(table, emc_tfaw, GET_CYCLE(tFAW));
// WRITE_PARAM_ALL_REG(table, emc_rc, GET_CYCLE(tRC));
//
// WRITE_PARAM_ALL_REG(table, emc_tckesr, GET_CYCLE(tSR));
// WRITE_PARAM_ALL_REG(table, emc_tcke, GET_CYCLE(tXP) + 1);
// WRITE_PARAM_ALL_REG(table, emc_tpd, GET_CYCLE(tXP));
// WRITE_PARAM_ALL_REG(table, emc_tclkstop, GET_CYCLE(tXP) + 8);
//
// WRITE_PARAM_ALL_REG(table, emc_txsr, MIN(GET_CYCLE(tXSR), (u32) 1022));
// WRITE_PARAM_ALL_REG(table, emc_txsrdll, MIN(GET_CYCLE(tXSR), (u32) 1022));
//
// const u32 dyn_self_ref_control = (((u32)(7605.0 / tCK_avg)) + 260U) | (table->burst_regs.emc_dyn_self_ref_control & 0xffff0000U);
// WRITE_PARAM_ALL_REG(table, emc_dyn_self_ref_control, dyn_self_ref_control);
//
// WRITE_PARAM_ALL_REG(table, emc_rw2pden, tRW2PDEN);
// WRITE_PARAM_ALL_REG(table, emc_pdex2wr, GET_CYCLE(10.0));
// WRITE_PARAM_ALL_REG(table, emc_pdex2rd, GET_CYCLE(10.0));
//
// WRITE_PARAM_ALL_REG(table, emc_pchg2pden, GET_CYCLE(1.75));
// WRITE_PARAM_ALL_REG(table, emc_ar2pden, GET_CYCLE(1.75));
// WRITE_PARAM_ALL_REG(table, emc_pdex2cke, GET_CYCLE(1.75));
// WRITE_PARAM_ALL_REG(table, emc_act2pden, GET_CYCLE(14.0));
// WRITE_PARAM_ALL_REG(table, emc_cke2pden, GET_CYCLE(5.0));
// WRITE_PARAM_ALL_REG(table, emc_pdex2mrr, GET_CYCLE(pdex2mrr));
//
// WRITE_PARAM_ALL_REG(table, emc_refresh, refresh_raw);
// WRITE_PARAM_ALL_REG(table, emc_pre_refresh_req_cnt, (u32) (refresh_raw / 4));
// WRITE_PARAM_ALL_REG(table, emc_trefbw, trefbw);
//
// 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_cfg = (int)(((double) C.eristaEmcMaxClock / 33300.0) * 0.25);
// 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_rap2pre = 3;
// table->burst_mc_regs.mc_emem_arb_timing_wap2pre = 11;
// 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);
//
// u32 mc_r2r = table->burst_mc_regs.mc_emem_arb_timing_r2r;
// if (mc_r2r > 1) {
// mc_r2r = (uint)(((double)(long)((double)rext * 0.25) - 1.0) + 2.0);
// table->burst_mc_regs.mc_emem_arb_timing_r2r = mc_r2r;
// }
//
// u32 mc_w2w = table->burst_mc_regs.mc_emem_arb_timing_w2w;
// if (mc_w2w > 1) {
// mc_w2w = (uint)(((double)(long)((double)wext / 4.0) - 1.0) + 2.0);
// table->burst_mc_regs.mc_emem_arb_timing_w2w = mc_w2w;
// }
//
// table->burst_mc_regs.mc_emem_arb_da_turns = ((mc_tW2R >> 1) << 0x18) | ((mc_tR2W >> 1) << 0x10) | ((mc_r2r >> 1) << 8) | ((mc_w2w >> 1));
// 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);
// table->la_scale_regs.mc_mll_mpcorer_ptsa_rate = MIN((u32)((C.eristaEmcMaxClock / 1600000) * 0xd0U), (u32)0x115);
// table->la_scale_regs.mc_ftop_ptsa_rate = MIN((u32)((C.eristaEmcMaxClock / 1600000) * 0x18U), (u32)0x1f);
// table->la_scale_regs.mc_ptsa_grant_decrement = MIN((u32)((C.eristaEmcMaxClock / 1600000) * 0x1203U), (u32)0x17ff);
//
// u32 mc_latency_allowance = 0;
// if (C.eristaEmcMaxClock / 1000 != 0) {
// mc_latency_allowance = 204800 / (C.eristaEmcMaxClock / 1000);
// }
//
// const u32 mc_latency_allowance2 = mc_latency_allowance & 0xFF;
// const u32 mc_latency_allowance3 = (mc_latency_allowance & 0xFF) << 0x10;
// table->la_scale_regs.mc_latency_allowance_xusb_0 = (table->la_scale_regs.mc_latency_allowance_xusb_0 & 0xff00ffffU) | mc_latency_allowance3;
// table->la_scale_regs.mc_latency_allowance_sdmmc_0 = (table->la_scale_regs.mc_latency_allowance_sdmmc_0 & 0xff00ffffU) | mc_latency_allowance3;
// table->la_scale_regs.mc_latency_allowance_xusb_1 = (table->la_scale_regs.mc_latency_allowance_xusb_1 & 0xff00ffffU) | mc_latency_allowance3;
// table->la_scale_regs.mc_latency_allowance_tsec_0 = (table->la_scale_regs.mc_latency_allowance_tsec_0 & 0xff00ffffU) | mc_latency_allowance3;
// table->la_scale_regs.mc_latency_allowance_sdmmca_0 = (table->la_scale_regs.mc_latency_allowance_sdmmca_0 & 0xff00ffffU) | mc_latency_allowance3;
// table->la_scale_regs.mc_latency_allowance_sdmmcaa_0 = (table->la_scale_regs.mc_latency_allowance_sdmmcaa_0 & 0xff00ffffU) | mc_latency_allowance3;
// table->la_scale_regs.mc_latency_allowance_sdmmcab_0 = (table->la_scale_regs.mc_latency_allowance_sdmmcab_0 & 0xff00ffffU) | mc_latency_allowance3;
// table->la_scale_regs.mc_latency_allowance_ppcs_1 = (table->la_scale_regs.mc_latency_allowance_ppcs_1 & 0xff00ffffU) | mc_latency_allowance3;
// table->la_scale_regs.mc_latency_allowance_mpcore_0 = (table->la_scale_regs.mc_latency_allowance_mpcore_0 & 0xff00ffffU) | mc_latency_allowance3;
// table->la_scale_regs.mc_latency_allowance_avpc_0 = (table->la_scale_regs.mc_latency_allowance_avpc_0 & 0xff00ffffU) | mc_latency_allowance3;
//
// u32 mc_latency_allowance_hc_0 = 0;
// if (C.eristaEmcMaxClock / 1000 != 0) {
// mc_latency_allowance_hc_0 = 35200 / (C.eristaEmcMaxClock / 1000);
// }
//
// table->la_scale_regs.mc_latency_allowance_nvdec_0 = (table->la_scale_regs.mc_latency_allowance_nvdec_0 & 0xff00ffffU) | mc_latency_allowance3;
// table->la_scale_regs.mc_latency_allowance_hc_0 = (table->la_scale_regs.mc_latency_allowance_hc_0 & 0xffffff00U) | mc_latency_allowance_hc_0;
//
// table->la_scale_regs.mc_latency_allowance_isp2_1 = (table->la_scale_regs.mc_latency_allowance_isp2_1 & 0xff00ff00U) | mc_latency_allowance3 | mc_latency_allowance2;
// table->la_scale_regs.mc_latency_allowance_hc_1 = (table->la_scale_regs.mc_latency_allowance_hc_1 & 0xffffff00U) | mc_latency_allowance2;
//
// u32 mc_latency_allowance_gpu_0 = 0;
// if (C.eristaEmcMaxClock / 1000 != 0) {
// mc_latency_allowance_gpu_0 = 40000 / (C.eristaEmcMaxClock / 1000);
// }
//
// table->la_scale_regs.mc_latency_allowance_gpu_0 = ((mc_latency_allowance_gpu_0 | table->la_scale_regs.mc_latency_allowance_gpu_0) & 0xff00ff00U) | mc_latency_allowance3;
//
// u32 mc_latency_allowance_gpu2_0 = 0;
// if (C.eristaEmcMaxClock / 1000 != 0) {
// mc_latency_allowance_gpu2_0 = 40000 / (C.eristaEmcMaxClock / 1000);
// }
//
// table->la_scale_regs.mc_latency_allowance_gpu2_0 = ((mc_latency_allowance_gpu2_0 | table->la_scale_regs.mc_latency_allowance_gpu2_0) & 0xff00ff00U) | mc_latency_allowance3;
//
// u32 mc_latency_allowance_nvenc_0 = 0;
// if (C.eristaEmcMaxClock / 1000 != 0) {
// mc_latency_allowance_nvenc_0 = 38400 / (C.eristaEmcMaxClock / 1000);
// }
//
// table->la_scale_regs.mc_latency_allowance_nvenc_0 = ((mc_latency_allowance_nvenc_0 | table->la_scale_regs.mc_latency_allowance_nvenc_0) & 0xff00ff00U) | mc_latency_allowance3;
//
// u32 mc_latency_allowance_vic_0 = 0;
// if (C.eristaEmcMaxClock / 1000 != 0) {
// mc_latency_allowance_vic_0 = 0xb540 / (C.eristaEmcMaxClock / 1000);
// }
//
// table->la_scale_regs.mc_latency_allowance_vic_0 = ((mc_latency_allowance_vic_0 | table->la_scale_regs.mc_latency_allowance_vic_0) & 0xff00ff00U) | mc_latency_allowance3;
// table->la_scale_regs.mc_latency_allowance_vi2_0 = (table->la_scale_regs.mc_latency_allowance_vi2_0 & 0xffffff00U) | mc_latency_allowance2;
//
// table->burst_mc_regs.mc_emem_arb_timing_rfcpb = GET_CYCLE(tRFCpb) >> 2;
//
// if (C.hpMode) {
// WRITE_PARAM_ALL_REG(table, emc_cfg, 0x13200000);
// }
//
// table->dram_timings.t_rp = tRFCpb;
// table->dram_timings.t_rfc = tRFCab;
// table->emc_cfg_2 = 0x11083d;
// #undef GET_CYCLE
}
Result MemFreqMtcTable(u32 *ptr) {
u32 khz_list[] = {1600000, 1331200, 1065600, 800000, 665600, 408000, 204000, 102000, 68000, 40800};
u32 khz_list_size = sizeof(khz_list) / sizeof(u32);
// Generate list for mtc table pointers
EristaMtcTable *table_list[khz_list_size];
for (u32 i = 0; i < khz_list_size; i++) {
u8 *table = reinterpret_cast<u8 *>(ptr) - offsetof(EristaMtcTable, rate_khz) - i * sizeof(EristaMtcTable);
table_list[i] = reinterpret_cast<EristaMtcTable *>(table);
R_UNLESS(table_list[i]->rate_khz == khz_list[i], ldr::ResultInvalidMtcTable());
R_UNLESS(table_list[i]->rev == MTC_TABLE_REV, ldr::ResultInvalidMtcTable());
}
if (C.eristaEmcMaxClock <= 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));
MemMtcTableAutoAdjust(table_list[0]);
PATCH_OFFSET(ptr, C.eristaEmcMaxClock);
R_SUCCEED();
}
Result MemFreqMax(u32 *ptr) {
if (C.eristaEmcMaxClock <= EmcClkOSLimit)
R_SKIP();
PATCH_OFFSET(ptr, C.eristaEmcMaxClock);
R_SUCCEED();
}
// R_SUCCEED();
// }
void Patch(uintptr_t mapped_nso, size_t nso_size) {
u32 CpuCvbDefaultMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(CpuCvbTableDefault)->freq);
u32 GpuCvbDefaultMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(GpuCvbTableDefault)->freq);
PatcherEntry<u32> patches[] = {
{"CPU Freq Table", CpuFreqCvbTable<false>, 1, nullptr, CpuCvbDefaultMaxFreq},
{"CPU Volt DVFS", &CpuVoltDvfs, 1, nullptr, 825},
{"CPU Volt Thermals", &CpuVoltThermals, 1, nullptr, 825},
{"CPU Volt Dfll", &CpuVoltDfll, 1, nullptr, 0xFFD0EAFF},
{"GPU Volt DVFS", &GpuVoltDVFS, 1, nullptr, 810},
{"GPU Volt Thermals", &GpuVoltThermals, 1, nullptr, 810},
{"GPU Freq Table", GpuFreqCvbTable<false>, 1, nullptr, GpuCvbDefaultMaxFreq},
{"CPU Freq Table", CpuFreqCvbTable<false>, 1, nullptr, static_cast<u32>(GetDvfsTableLastEntry(CpuCvbTableDefault)->freq)},
{"CPU Volt DVFS", &CpuVoltDvfs, 1, nullptr, CpuVminOfficial},
{"CPU Volt Thermals", &CpuVoltThermals, 1, nullptr, CpuVminOfficial},
{"CPU Volt Dfll", &CpuVoltDfll, 1, nullptr, 0xFFEAD0FF},
{"GPU Volt DVFS", &GpuVoltDVFS, 1, nullptr, GpuVminOfficial},
{"GPU Volt Thermals", &GpuVoltThermals, 1, nullptr, GpuVminOfficial},
{"GPU Freq Table", GpuFreqCvbTable<false>, 1, nullptr, static_cast<u32>(GetDvfsTableLastEntry(GpuCvbTableDefault)->freq)},
{"GPU Freq Asm", &GpuFreqMaxAsm, 2, &GpuMaxClockPatternFn},
{"GPU Freq PLL", &GpuFreqPllLimit, 1, nullptr, GpuClkPllLimit},
{"GPU PLL Max", &GpuFreqPllMax, 1, nullptr, GpuClkPllMax},
// {"GPU PLL Limit", &GpuFreqPllLimit, 4, nullptr, GpuClkPllLimit},
{"MEM Freq Mtc", &MemFreqMtcTable, 0, nullptr, EmcClkOSLimit},
{"MEM Freq Max", &MemFreqMax, 0, nullptr, EmcClkOSLimit},
{"MEM Freq PLLM", &MemFreqPllmLimit, 2, nullptr, EmcClkPllmLimit},
@@ -763,8 +474,13 @@ namespace ams::ldr::oc::pcv::erista {
for (auto &entry : patches) {
LOGGING("%s Count: %zu", entry.description, entry.patched_count);
if (R_FAILED(entry.CheckResult())) {
#if defined(AMS_BUILD_FOR_AUDITING) || defined(AMS_BUILD_FOR_DEBUGGING)
panic::SmcError(panic::Patch);
#endif
CRASH(entry.description);
}
}
}
}

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);
@@ -267,7 +266,6 @@ namespace ams::ldr::oc::pcv::mariko {
break;
}
switch (C.marikoCpuUVHigh) {
case 1:
PATCH_OFFSET(&(entry->tune1_high), 0);
@@ -417,6 +415,8 @@ namespace ams::ldr::oc::pcv::mariko {
u32 trefbw = refresh_raw + 0x40;
trefbw = MIN(trefbw, static_cast<u32>(0x3FFF));
const u32 dyn_self_ref_control = (static_cast<u32>(7605.0 / tCK_avg) + 260) | (table->burst_regs.emc_dyn_self_ref_control & 0xffff0000);
CalculateTimings();
WRITE_PARAM_ALL_REG(table, emc_rd_rcd, GET_CYCLE_CEIL(tRCD));
@@ -432,9 +432,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);
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);
@@ -448,16 +448,14 @@ namespace ams::ldr::oc::pcv::mariko {
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);
const u32 dyn_self_ref_control = (static_cast<u32>(7605.0 / tCK_avg) + 260) | (table->burst_regs.emc_dyn_self_ref_control & 0xffff0000);
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);
@@ -482,16 +480,15 @@ namespace ams::ldr::oc::pcv::mariko {
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);
WRITE_PARAM_ALL_REG(table, emc_cmd_brlshft_2, 0x24)
WRITE_PARAM_ALL_REG(table, emc_cmd_brlshft_3, 0x24)
// WRITE_PARAM_ALL_REG(table, emc_mrs_wait_cnt, 0x07FF003C);
// WRITE_PARAM_ALL_REG(table, emc_mrs_wait_cnt2, 0x02DE002A);
/* TODO: Check this out again at some point. */
WRITE_PARAM_ALL_REG(table, emc_cmd_brlshft_2, 0x24);
WRITE_PARAM_ALL_REG(table, emc_cmd_brlshft_3, 0x24);
/* 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.marikoEmcMaxClock / (33.3 * 1000) / MC_ARB_DIV;
table->burst_mc_regs.mc_emem_arb_cfg = C.marikoEmcMaxClock / (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;
@@ -503,7 +500,7 @@ namespace ams::ldr::oc::pcv::mariko {
table->burst_mc_regs.mc_emem_arb_timing_wap2pre = CEIL(tW2P / MC_ARB_DIV) + MC_ARB_SFA;
/* Two consecutive reads between two different dram modules. */
/* Only be above 1 for 8gb ram. */
/* Only above 1 for 8gb ram. */
if (table->burst_mc_regs.mc_emem_arb_timing_r2r > 1) {
table->burst_mc_regs.mc_emem_arb_timing_r2r = CEIL(table->burst_regs.emc_rext / 4) - 1 + MC_ARB_SFA;
}
@@ -551,41 +548,34 @@ 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;
table->dram_timings.rl = RL_DBI;
table->emc_mrw2 = 0x8802003F;
table->dram_timings.rl = RL;
table->emc_mrw2 = (table->emc_mrw2 & ~0xFFu) | static_cast<u32>(mrw2);
table->emc_cfg_2 = 0x11083D;
}
// WRITE_PARAM_ALL_REG(table, emc_pdex2wr, GET_CYCLE(10.0));
// WRITE_PARAM_ALL_REG(table, emc_pdex2rd, GET_CYCLE(10.0));
// WRITE_PARAM_ALL_REG(table, emc_pchg2pden, GET_CYCLE(1.75));
// WRITE_PARAM_ALL_REG(table, emc_ar2pden, GET_CYCLE(1.75));
// WRITE_PARAM_ALL_REG(table, emc_pdex2cke, GET_CYCLE(1.75));
// WRITE_PARAM_ALL_REG(table, emc_act2pden, GET_CYCLE(14.0));
// WRITE_PARAM_ALL_REG(table, emc_cke2pden, GET_CYCLE(5.0));
void MemMtcPllmbDivisor(MarikoMtcTable *table) {
constexpr u32 PllOscInKHz = 38400;
constexpr u32 PllOscHalfKHz = 19200;
@@ -664,9 +654,8 @@ namespace ams::ldr::oc::pcv::mariko {
// Copy unmodified 1600000 table to tmp
std::memcpy(reinterpret_cast<void *>(tmp), reinterpret_cast<void *>(table_max), sizeof(MarikoMtcTable));
// Adjust max freq mtc timing parameters with reference to 1331200 table
/* TODO: Implement mariko */
/* Adjust timings properly according to the new frequency. */
MemMtcTableAutoAdjust(table_max);
MemMtcPllmbDivisor(table_max);
@@ -695,6 +684,7 @@ namespace ams::ldr::oc::pcv::mariko {
#define DVB_VOLT(zero, one, two) std::min(zero + voltAdd, 1050), std::min(one + voltAdd, 1025), std::min(two + voltAdd, 1000),
/* TODO: More fine tuned values? */
if (C.marikoEmcMaxClock < 1862400) {
std::memcpy(new_start, default_end, sizeof(emc_dvb_dvfs_table_t));
} else if (C.marikoEmcMaxClock < 2131200) {
@@ -776,10 +766,14 @@ namespace ams::ldr::oc::pcv::mariko {
PATCH_OFFSET(ptr, emc_uv);
i2cInitialize();
I2cSet_U8(I2cDevice_Max77812_2, 0x25, (emc_uv - uv_min) / uv_step);
Result resultI2C = I2cSet_U8(I2cDevice_Max77812_2, 0x25, (emc_uv - uv_min) / uv_step);
i2cExit();
R_SUCCEED();
if (R_SUCCEEDED(resultI2C)) {
R_SUCCEED();
}
return resultI2C;
}
void Patch(uintptr_t mapped_nso, size_t nso_size) {
@@ -818,6 +812,10 @@ namespace ams::ldr::oc::pcv::mariko {
for (auto &entry : patches) {
LOGGING("%s Count: %zu", entry.description, entry.patched_count);
if (R_FAILED(entry.CheckResult())) {
#if defined(AMS_BUILD_FOR_AUDITING) || defined(AMS_BUILD_FOR_DEBUGGING)
panic::SmcError(panic::Patch);
#endif
CRASH(entry.description);
}
}

View File

@@ -1,7 +1,7 @@
/*
* Copyright (C) Switch-OC-Suite
*
* Copyright (c) Souldbminer and Horizon OC Contributors
* 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,
@@ -18,118 +18,113 @@
#include "ptm.hpp"
namespace ams::ldr::oc::ptm {
namespace ams::ldr::hoc::ptm {
Result CpuPtmBoost(perf_conf_entry* entry) {
Result CpuPtmBoost(perf_conf_entry* entry) {
#ifdef ATMOSPHERE_IS_STRATOSPHERE
bool isMariko = (spl::GetSocType() == spl::SocType_Mariko);
#else
bool isMariko = true;
#endif
#ifdef ATMOSPHERE_IS_STRATOSPHERE
bool isMariko = (spl::GetSocType() == spl::SocType_Mariko);
#else
bool isMariko = true;
#endif
if (!C.eristaCpuBoostClock || !C.marikoCpuBoostClock) {
R_SUCCEED();
}
u32 cpuPtmBoostNew = isMariko ? C.marikoCpuBoostClock * 1000 : C.eristaCpuBoostClock * 1000;
PATCH_OFFSET(&(entry->cpu_freq_1), cpuPtmBoostNew);
PATCH_OFFSET(&(entry->cpu_freq_2), cpuPtmBoostNew);
if (!C.eristaCpuBoostClock || !C.marikoCpuBoostClock)
R_SUCCEED();
u32 cpuPtmBoostNew = isMariko ? C.marikoCpuBoostClock * 1000 : C.eristaCpuBoostClock * 1000;
PATCH_OFFSET(&(entry->cpu_freq_1), cpuPtmBoostNew);
PATCH_OFFSET(&(entry->cpu_freq_2), cpuPtmBoostNew);
R_SUCCEED();
}
Result MemPtm(perf_conf_entry* entry) {
PATCH_OFFSET(&(entry->emc_freq_1), memPtmLimit);
PATCH_OFFSET(&(entry->emc_freq_2), memPtmLimit);
R_SUCCEED();
}
bool PtmEntryIsValid(perf_conf_entry* entry) {
return (entry->cpu_freq_1 == entry->cpu_freq_2 &&
entry->gpu_freq_1 == entry->gpu_freq_2 &&
entry->emc_freq_1 == entry->emc_freq_2);
}
bool PtmTablePatternFn(u32* ptr) {
perf_conf_entry* entry = reinterpret_cast<perf_conf_entry *>(ptr);
if (!PtmEntryIsValid(entry))
return false;
return entry->cpu_freq_1 == cpuPtmDefault;
}
void Patch(uintptr_t mapped_nso, size_t nso_size) {
perf_conf_entry* confTable = nullptr;
for (uintptr_t ptr = mapped_nso;
ptr <= mapped_nso + nso_size - sizeof(perf_conf_entry) * entryCnt;
ptr += sizeof(u32))
{
u32* ptr32 = reinterpret_cast<u32 *>(ptr);
if (PtmTablePatternFn(ptr32)) {
confTable = reinterpret_cast<perf_conf_entry *>(ptr);
break;
}
}
if (!confTable) {
CRASH("confTable not found!");
Result MemPtm(perf_conf_entry* entry) {
PATCH_OFFSET(&(entry->emc_freq_1), memPtmLimit);
PATCH_OFFSET(&(entry->emc_freq_2), memPtmLimit);
R_SUCCEED();
}
PatcherEntry<perf_conf_entry> cpuPtmBoostPatch = { "CPU Ptm Boost", &CpuPtmBoost, 2, };
PatcherEntry<perf_conf_entry> memPtmPatch = { "MEM Ptm", &MemPtm, 16, };
#ifdef ATMOSPHERE_IS_STRATOSPHERE
bool isMariko = (spl::GetSocType() == spl::SocType_Mariko);
#else
bool isMariko = true;
#endif
for (u32 i = 0; i < entryCnt; i++) {
perf_conf_entry* entry = confTable + i;
bool PtmEntryIsValid(perf_conf_entry* entry) {
return (entry->cpu_freq_1 == entry->cpu_freq_2 && entry->gpu_freq_1 == entry->gpu_freq_2 && entry->emc_freq_1 == entry->emc_freq_2);
}
bool PtmTablePatternFn(u32* ptr) {
perf_conf_entry* entry = reinterpret_cast<perf_conf_entry *>(ptr);
if (!PtmEntryIsValid(entry)) {
LOGGING("@%p", &entry);
CRASH("Invalid ptm confTable entry");
return false;
}
switch (entry->cpu_freq_1) {
case cpuPtmBoost:
cpuPtmBoostPatch.Apply(entry);
return entry->cpu_freq_1 == cpuPtmDefault;
}
void Patch(uintptr_t mapped_nso, size_t nso_size) {
perf_conf_entry* confTable = nullptr;
for (uintptr_t ptr = mapped_nso; ptr <= mapped_nso + nso_size - sizeof(perf_conf_entry) * entryCnt; ptr += sizeof(u32)) {
u32* ptr32 = reinterpret_cast<u32 *>(ptr);
if (PtmTablePatternFn(ptr32)) {
confTable = reinterpret_cast<perf_conf_entry *>(ptr);
break;
case cpuPtmDefault:
case cpuPtmDevOC:
break;
default:
LOGGING("%u (0x%08x) @%p", entry->cpu_freq_1, entry->conf_id, &(entry->cpu_freq_1));
CRASH("Unknown CPU Freq");
}
}
switch (entry->emc_freq_1) {
case memPtmLimit:
case memPtmAlt:
case memPtmClamp:
if (isMariko) {
memPtmPatch.Apply(entry);
}
break;
default:
LOGGING("%u (0x%08x) @%p", entry->emc_freq_1, entry->conf_id, &(entry->emc_freq_2));
CRASH("Unknown MEM Freq");
if (!confTable) {
CRASH("confTable not found!");
}
PatcherEntry<perf_conf_entry> cpuPtmBoostPatch = { "CPU Ptm Boost", &CpuPtmBoost, 2, };
PatcherEntry<perf_conf_entry> memPtmPatch = { "MEM Ptm", &MemPtm, 16, };
#ifdef ATMOSPHERE_IS_STRATOSPHERE
bool isMariko = (spl::GetSocType() == spl::SocType_Mariko);
#else
bool isMariko = true;
#endif
for (u32 i = 0; i < entryCnt; i++) {
perf_conf_entry *entry = confTable + i;
if (!PtmEntryIsValid(entry)) {
LOGGING("@%p", &entry);
CRASH("Invalid ptm confTable entry");
}
switch (entry->cpu_freq_1) {
case cpuPtmBoost:
cpuPtmBoostPatch.Apply(entry);
break;
case cpuPtmDefault:
case cpuPtmDevOC:
break;
default:
LOGGING("%u (0x%08x) @%p", entry->cpu_freq_1, entry->conf_id, &(entry->cpu_freq_1));
CRASH("Unknown CPU Freq");
}
switch (entry->emc_freq_1) {
case memPtmLimit:
case memPtmAlt:
case memPtmClamp:
if (isMariko) {
memPtmPatch.Apply(entry);
}
break;
default:
LOGGING("%u (0x%08x) @%p", entry->emc_freq_1, entry->conf_id, &(entry->emc_freq_2));
CRASH("Unknown MEM Freq");
}
}
LOGGING("%s Count: %zu", cpuPtmBoostPatch.description, cpuPtmBoostPatch.patched_count);
if (R_FAILED(cpuPtmBoostPatch.CheckResult()))
CRASH(cpuPtmBoostPatch.description);
if (isMariko) {
LOGGING("%s Count: %zu", memPtmPatch.description, memPtmPatch.patched_count);
if (R_FAILED(memPtmPatch.CheckResult()))
CRASH(memPtmPatch.description);
}
}
LOGGING("%s Count: %zu", cpuPtmBoostPatch.description, cpuPtmBoostPatch.patched_count);
if (R_FAILED(cpuPtmBoostPatch.CheckResult()))
CRASH(cpuPtmBoostPatch.description);
if (isMariko) {
LOGGING("%s Count: %zu", memPtmPatch.description, memPtmPatch.patched_count);
if (R_FAILED(memPtmPatch.CheckResult()))
CRASH(memPtmPatch.description);
}
}
}

View File

@@ -1,7 +1,7 @@
/*
* Copyright (C) Switch-OC-Suite
*
* Copyright (c) Souldbminer and Horizon OC Contributors
* 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,
@@ -20,28 +20,28 @@
#include "../oc_common.hpp"
namespace ams::ldr::oc::ptm {
namespace ams::ldr::hoc::ptm {
typedef struct {
u32 conf_id;
u32 cpu_freq_1; // min-max pair?
u32 cpu_freq_2;
u32 gpu_freq_1;
u32 gpu_freq_2;
u32 emc_freq_1;
u32 emc_freq_2;
u32 padding;
} perf_conf_entry;
typedef struct {
u32 conf_id;
u32 cpu_freq_1; // min-max pair?
u32 cpu_freq_2;
u32 gpu_freq_1;
u32 gpu_freq_2;
u32 emc_freq_1;
u32 emc_freq_2;
u32 padding;
} perf_conf_entry;
constexpr u32 entryCnt = 16;
constexpr u32 cpuPtmDefault = 1020'000'000;
constexpr u32 cpuPtmDevOC = 1224'000'000;
constexpr u32 cpuPtmBoost = 1785'000'000;
constexpr u32 entryCnt = 16;
constexpr u32 cpuPtmDefault = 1020'000'000;
constexpr u32 cpuPtmDevOC = 1224'000'000;
constexpr u32 cpuPtmBoost = 1785'000'000;
constexpr u32 memPtmLimit = 1600'000'000;
constexpr u32 memPtmAlt = 1331'200'000;
constexpr u32 memPtmClamp = 1065'600'000;
constexpr u32 memPtmLimit = 1600'000'000;
constexpr u32 memPtmAlt = 1331'200'000;
constexpr u32 memPtmClamp = 1065'600'000;
void Patch(uintptr_t mapped_nso, size_t nso_size);
void Patch(uintptr_t mapped_nso, size_t nso_size);
}

View File

@@ -38,7 +38,7 @@ include $(DEVKITPRO)/libnx/switch_rules
# NACP building is skipped as well.
#---------------------------------------------------------------------------------
APP_TITLE := Horizon OC Monitor
APP_VERSION := 1.3.2+r4-hoc
APP_VERSION := 1.3.2+r4-hoc-r2
TARGET := $(notdir $(CURDIR))
BUILD := build
SOURCES := source

View File

@@ -83,7 +83,7 @@ Result nvdecCheck = 1;
Result nvencCheck = 1;
Result nvjpgCheck = 1;
Result nifmCheck = 1;
Result sysclkCheck = 1;
Result sysclkCheck = 0;
Result pwmDutyCycleCheck = 1;
//Wi-Fi
@@ -572,21 +572,19 @@ void Misc(void*) {
}
// Get sys-clk data
if (R_SUCCEEDED(sysclkCheck)) {
SysClkContext sysclkCTX;
if (R_SUCCEEDED(sysclkIpcGetCurrentContext(&sysclkCTX))) {
realCPU_Hz = sysclkCTX.realFreqs[SysClkModule_CPU];
realGPU_Hz = sysclkCTX.realFreqs[SysClkModule_GPU];
realRAM_Hz = sysclkCTX.realFreqs[SysClkModule_MEM];
partLoad[SysClkPartLoad_EMC] = sysclkCTX.partLoad[SysClkPartLoad_EMC];
partLoad[SysClkPartLoad_EMCCpu] = sysclkCTX.partLoad[SysClkPartLoad_EMCCpu];
realCPU_mV = sysclkCTX.voltages[HocClkVoltage_CPU];
realGPU_mV = sysclkCTX.voltages[HocClkVoltage_GPU];
realVDD2_mV = sysclkCTX.voltages[HocClkVoltage_EMCVDD2];
realVDDQ_mV = sysclkCTX.voltages[HocClkVoltage_EMCVDDQ_MarikoOnly];
realSOC_mV = sysclkCTX.voltages[HocClkVoltage_SOC];
}
SysClkContext sysclkCTX;
if (R_SUCCEEDED(sysclkIpcGetCurrentContext(&sysclkCTX))) {
realCPU_Hz = sysclkCTX.realFreqs[SysClkModule_CPU];
realGPU_Hz = sysclkCTX.realFreqs[SysClkModule_GPU];
realRAM_Hz = sysclkCTX.realFreqs[SysClkModule_MEM];
partLoad[SysClkPartLoad_EMC] = sysclkCTX.partLoad[SysClkPartLoad_EMC];
partLoad[SysClkPartLoad_EMCCpu] = sysclkCTX.partLoad[SysClkPartLoad_EMCCpu];
realCPU_mV = sysclkCTX.voltages[HocClkVoltage_CPU];
realGPU_mV = sysclkCTX.voltages[HocClkVoltage_GPU];
realVDD2_mV = sysclkCTX.voltages[HocClkVoltage_EMCVDD2];
realVDDQ_mV = sysclkCTX.voltages[HocClkVoltage_EMCVDDQ_MarikoOnly];
realSOC_mV = sysclkCTX.voltages[HocClkVoltage_SOC];
}
// Temperatures
@@ -687,7 +685,7 @@ void Misc2(void*) {
void Misc3(void*) {
const bool isUsingEOS = usingEOS();
// Initialize voltage reading if needed
bool canReadVoltages = false;
if (!isUsingEOS && realVoltsPolling) {
@@ -696,24 +694,10 @@ void Misc3(void*) {
realVoltsPolling = false;
}
}
do {
mutexLock(&mutex_Misc);
// Get sys-clk data
if (R_SUCCEEDED(sysclkCheck)) {
SysClkContext sysclkCTX;
if (R_SUCCEEDED(sysclkIpcGetCurrentContext(&sysclkCTX))) {
partLoad[SysClkPartLoad_EMC] = sysclkCTX.partLoad[SysClkPartLoad_EMC];
partLoad[SysClkPartLoad_EMCCpu] = sysclkCTX.partLoad[SysClkPartLoad_EMCCpu];
realCPU_mV = sysclkCTX.voltages[HocClkVoltage_CPU];
realGPU_mV = sysclkCTX.voltages[HocClkVoltage_GPU];
realSOC_mV = sysclkCTX.voltages[HocClkVoltage_SOC];
realVDD2_mV = sysclkCTX.voltages[HocClkVoltage_EMCVDD2];
realVDDQ_mV = sysclkCTX.voltages[HocClkVoltage_EMCVDDQ_MarikoOnly];
}
}
// Temperatures
if (R_SUCCEEDED(i2cCheck)) {
Tmp451GetSocTemp(&SOC_temperatureF);
@@ -722,7 +706,7 @@ void Misc3(void*) {
if (R_SUCCEEDED(tcCheck)) {
tcGetSkinTemperatureMilliC(&skin_temperaturemiliC);
}
// Fan
if (R_SUCCEEDED(pwmCheck)) {
double temp = 0;
@@ -736,16 +720,21 @@ void Misc3(void*) {
}
}
}
// GPU Load
if (R_SUCCEEDED(nvCheck)) {
nvIoctl(fd, NVGPU_GPU_IOCTL_PMU_GET_GPU_LOAD, &GPU_Load_u);
}
SysClkContext sysclkCTX;
if (R_SUCCEEDED(sysclkIpcGetCurrentContext(&sysclkCTX))) {
partLoad[SysClkPartLoad_EMC] = sysclkCTX.partLoad[SysClkPartLoad_EMC];
}
mutexUnlock(&mutex_Misc);
} while (!leventWait(&threadexit, 1'000'000'000)); // 1 second timeout
// Cleanup voltage reading if initialized
if (canReadVoltages) {
rgltrExit();
@@ -2469,4 +2458,4 @@ ALWAYS_INLINE void GetConfigSettings(ResolutionSettings* settings) {
convertToUpper(key);
settings->disableScreenshots = (key != "FALSE");
}
}
}

View File

@@ -446,14 +446,6 @@ public:
if (SaltySD) {
LoadSharedMemoryAndRefreshRate();
}
if (sysclkIpcRunning() && R_SUCCEEDED(sysclkIpcInitialize())) {
uint32_t sysClkApiVer = 0;
sysclkIpcGetAPIVersion(&sysClkApiVer);
if (sysClkApiVer < 4) {
sysclkIpcExit();
}
else sysclkCheck = 0;
}
if (R_SUCCEEDED(splInitialize())) {
u64 sku = 0;
splGetConfig(SplConfigItem_HardwareType, &sku);
@@ -466,16 +458,14 @@ public:
}
}
splExit();
sysclkIpcInitialize();
});
Hinted = envIsSyscallHinted(0x6F);
}
virtual void exitServices() override {
CloseThreads();
if (R_SUCCEEDED(sysclkCheck)) {
sysclkIpcExit();
}
sysclkIpcExit();
shmemClose(&_sharedmemory);
//Exit services
clkrstExit();
@@ -530,14 +520,6 @@ public:
if (SaltySD) {
LoadSharedMemory();
}
if (sysclkIpcRunning() && R_SUCCEEDED(sysclkIpcInitialize())) {
uint32_t sysClkApiVer = 0;
sysclkIpcGetAPIVersion(&sysClkApiVer);
if (sysClkApiVer < 4) {
sysclkIpcExit();
}
else sysclkCheck = 0;
}
if (R_SUCCEEDED(splInitialize())) {
u64 sku = 0;
splGetConfig(SplConfigItem_HardwareType, &sku);
@@ -550,6 +532,7 @@ public:
}
}
splExit();
sysclkIpcInitialize();
});
Hinted = envIsSyscallHinted(0x6F);
}
@@ -557,9 +540,7 @@ public:
virtual void exitServices() override {
CloseThreads();
shmemClose(&_sharedmemory);
if (R_SUCCEEDED(sysclkCheck)) {
sysclkIpcExit();
}
sysclkIpcExit();
//Exit services
clkrstExit();
pcvExit();
@@ -617,14 +598,6 @@ public:
if (SaltySD) {
LoadSharedMemory();
}
if (sysclkIpcRunning() && R_SUCCEEDED(sysclkIpcInitialize())) {
uint32_t sysClkApiVer = 0;
sysclkIpcGetAPIVersion(&sysClkApiVer);
if (sysClkApiVer < 4) {
sysclkIpcExit();
}
else sysclkCheck = 0;
}
if (R_SUCCEEDED(splInitialize())) {
u64 sku = 0;
splGetConfig(SplConfigItem_HardwareType, &sku);
@@ -637,6 +610,7 @@ public:
}
}
splExit();
sysclkIpcInitialize();
});
Hinted = envIsSyscallHinted(0x6F);
@@ -645,9 +619,7 @@ public:
virtual void exitServices() override {
CloseThreads();
shmemClose(&_sharedmemory);
if (R_SUCCEEDED(sysclkCheck)) {
sysclkIpcExit();
}
sysclkIpcExit();
// Exit services
clkrstExit();
pcvExit();
@@ -707,14 +679,6 @@ public:
if (SaltySD) {
LoadSharedMemoryAndRefreshRate();
}
if (sysclkIpcRunning() && R_SUCCEEDED(sysclkIpcInitialize())) {
uint32_t sysClkApiVer = 0;
sysclkIpcGetAPIVersion(&sysClkApiVer);
if (sysClkApiVer < 4) {
sysclkIpcExit();
}
else sysclkCheck = 0;
}
if (R_SUCCEEDED(splInitialize())) {
u64 sku = 0;
splGetConfig(SplConfigItem_HardwareType, &sku);
@@ -727,6 +691,7 @@ public:
}
}
splExit();
sysclkIpcInitialize();
});
Hinted = envIsSyscallHinted(0x6F);
}
@@ -734,9 +699,7 @@ public:
virtual void exitServices() override {
CloseThreads();
shmemClose(&_sharedmemory);
if (R_SUCCEEDED(sysclkCheck)) {
sysclkIpcExit();
}
sysclkIpcExit();
clkrstExit();
pcvExit();
tsExit();
@@ -790,14 +753,6 @@ public:
if (SaltySD) {
LoadSharedMemoryAndRefreshRate();
}
if (sysclkIpcRunning() && R_SUCCEEDED(sysclkIpcInitialize())) {
uint32_t sysClkApiVer = 0;
sysclkIpcGetAPIVersion(&sysClkApiVer);
if (sysClkApiVer < 4) {
sysclkIpcExit();
}
else sysclkCheck = 0;
}
if (R_SUCCEEDED(splInitialize())) {
u64 sku = 0;
splGetConfig(SplConfigItem_HardwareType, &sku);
@@ -810,6 +765,7 @@ public:
}
}
splExit();
sysclkIpcInitialize();
});
Hinted = envIsSyscallHinted(0x6F);
}
@@ -817,9 +773,7 @@ public:
virtual void exitServices() override {
CloseThreads();
shmemClose(&_sharedmemory);
if (R_SUCCEEDED(sysclkCheck)) {
sysclkIpcExit();
}
sysclkIpcExit();
clkrstExit();
pcvExit();
tsExit();
@@ -873,14 +827,6 @@ public:
if (SaltySD) {
LoadSharedMemoryAndRefreshRate();
}
if (sysclkIpcRunning() && R_SUCCEEDED(sysclkIpcInitialize())) {
uint32_t sysClkApiVer = 0;
sysclkIpcGetAPIVersion(&sysClkApiVer);
if (sysClkApiVer < 4) {
sysclkIpcExit();
}
else sysclkCheck = 0;
}
if (R_SUCCEEDED(splInitialize())) {
u64 sku = 0;
splGetConfig(SplConfigItem_HardwareType, &sku);
@@ -893,6 +839,7 @@ public:
}
}
splExit();
sysclkIpcInitialize();
});
Hinted = envIsSyscallHinted(0x6F);
}
@@ -900,9 +847,7 @@ public:
virtual void exitServices() override {
CloseThreads();
shmemClose(&_sharedmemory);
if (R_SUCCEEDED(sysclkCheck)) {
sysclkIpcExit();
}
sysclkIpcExit();
clkrstExit();
pcvExit();
tsExit();

File diff suppressed because it is too large Load Diff

View File

@@ -233,12 +233,10 @@ public:
else if (realRAM_Hz && settings.showDeltas && (settings.showRealFreqs || settings.showTargetFreqs)) {
renderer->drawString(DeltaRAM_c, false, COMMON_MARGIN + deltaOffset, height_offset, 15, (settings.textColor));
}
if (R_SUCCEEDED(sysclkCheck)) {
static std::vector<std::string> PartLoadColoredChars = {"CPU", "GPU"};
//static auto loadLabelWidth = renderer->getTextDimensions("Load: ", false, 15).first;
renderer->drawString("Load", false, COMMON_MARGIN, height_offset+15, 15, (settings.catColor2));
renderer->drawStringWithColoredSections(RAM_load_c, false, PartLoadColoredChars, COMMON_MARGIN + valueOffset, height_offset+15, 15, (settings.textColor), settings.catColor2);
}
static std::vector<std::string> PartLoadColoredChars = {"CPU", "GPU"};
//static auto loadLabelWidth = renderer->getTextDimensions("Load: ", false, 15).first;
renderer->drawString("Load", false, COMMON_MARGIN, height_offset+15, 15, (settings.catColor2));
renderer->drawStringWithColoredSections(RAM_load_c, false, PartLoadColoredChars, COMMON_MARGIN + valueOffset, height_offset+15, 15, (settings.textColor), settings.catColor2);
}
if (R_SUCCEEDED(Hinted)) {
//static auto textWidth = renderer->getTextDimensions("Total \nApplication \nApplet \nSystem \nSystem Unsafe ", false, 15).first;

View File

@@ -354,7 +354,7 @@ public:
else
width = renderer->getTextDimensions("100%@4444.4444 mV", false, fontsize).first;
}
} else if (key == "GPU" || (key == "RAM" && settings.showRAMLoad && R_SUCCEEDED(sysclkCheck))) {
} else if (key == "GPU" || (key == "RAM" && settings.showRAMLoad)) {
//dimensions = renderer->drawString("100.0%@4444.4", false, 0, 0, fontsize, renderer->a(0x0000));
if (!settings.showRAMLoadCPUGPU) {
@@ -370,7 +370,7 @@ public:
width = renderer->getTextDimensions("100%[100%,100%]@4444.4444 mV", false, fontsize).first;
}
}
} else if (key == "RAM" && (!settings.showRAMLoad || R_FAILED(sysclkCheck))) {
} else if (key == "RAM" && (!settings.showRAMLoad)) {
//dimensions = renderer->drawString("44444444MB@4444.4", false, 0, 0, fontsize, renderer->a(0x0000));
if (!settings.realVolts) {
width = renderer->getTextDimensions("100%@4444.4", false, fontsize).first;
@@ -993,51 +993,33 @@ public:
} else {
unsigned PartLoadInt;
if (R_SUCCEEDED(sysclkCheck)) {
PartLoadInt = partLoad[SysClkPartLoad_EMC] / 10;
if (settings.showRAMLoadCPUGPU) {
unsigned ramCpuLoadInt = partLoad[SysClkPartLoad_EMCCpu] / 10;
int RAM_GPU_Load = partLoad[SysClkPartLoad_EMC] - partLoad[SysClkPartLoad_EMCCpu];
unsigned ramGpuLoadInt = RAM_GPU_Load / 10;
if (settings.realFrequencies && realRAM_Hz) {
snprintf(MINI_RAM_var_compressed_c, sizeof(MINI_RAM_var_compressed_c),
"%u%%[%u%%,%u%%]@%hu.%hhu",
PartLoadInt, ramCpuLoadInt, ramGpuLoadInt,
realRAM_Hz / 1000000, (realRAM_Hz / 100000) % 10);
} else {
snprintf(MINI_RAM_var_compressed_c, sizeof(MINI_RAM_var_compressed_c),
"%u%%[%u%%,%u%%]@%hu.%hhu",
PartLoadInt, ramCpuLoadInt, ramGpuLoadInt,
RAM_Hz / 1000000, (RAM_Hz / 100000) % 10);
}
} else {
if (settings.realFrequencies && realRAM_Hz) {
snprintf(MINI_RAM_var_compressed_c, sizeof(MINI_RAM_var_compressed_c),
"%u%%@%hu.%hhu", PartLoadInt,
realRAM_Hz / 1000000, (realRAM_Hz / 100000) % 10);
} else {
snprintf(MINI_RAM_var_compressed_c, sizeof(MINI_RAM_var_compressed_c),
"%u%%@%hu.%hhu", PartLoadInt,
RAM_Hz / 1000000, (RAM_Hz / 100000) % 10);
}
}
} else {
const uint64_t RAM_Total_all = RAM_Total_application_u + RAM_Total_applet_u +
RAM_Total_system_u + RAM_Total_systemunsafe_u;
const uint64_t RAM_Used_all = RAM_Used_application_u + RAM_Used_applet_u +
RAM_Used_system_u + RAM_Used_systemunsafe_u;
PartLoadInt = (RAM_Total_all > 0) ? (unsigned)((RAM_Used_all * 100) / RAM_Total_all) : 0;
PartLoadInt = partLoad[SysClkPartLoad_EMC] / 10;
if (settings.showRAMLoadCPUGPU) {
unsigned ramCpuLoadInt = partLoad[SysClkPartLoad_EMCCpu] / 10;
int RAM_GPU_Load = partLoad[SysClkPartLoad_EMC] - partLoad[SysClkPartLoad_EMCCpu];
unsigned ramGpuLoadInt = RAM_GPU_Load / 10;
if (settings.realFrequencies && realRAM_Hz) {
snprintf(MINI_RAM_var_compressed_c, sizeof(MINI_RAM_var_compressed_c),
"%u%%@%hu.%hhu", PartLoadInt,
realRAM_Hz / 1000000, (realRAM_Hz / 100000) % 10);
"%u%%[%u%%,%u%%]@%hu.%hhu",
PartLoadInt, ramCpuLoadInt, ramGpuLoadInt,
realRAM_Hz / 1000000, (realRAM_Hz / 100000) % 10);
} else {
snprintf(MINI_RAM_var_compressed_c, sizeof(MINI_RAM_var_compressed_c),
"%u%%@%hu.%hhu", PartLoadInt,
RAM_Hz / 1000000, (RAM_Hz / 100000) % 10);
"%u%%[%u%%,%u%%]@%hu.%hhu",
PartLoadInt, ramCpuLoadInt, ramGpuLoadInt,
RAM_Hz / 1000000, (RAM_Hz / 100000) % 10);
}
} else {
if (settings.realFrequencies && realRAM_Hz) {
snprintf(MINI_RAM_var_compressed_c, sizeof(MINI_RAM_var_compressed_c),
"%u%%@%hu.%hhu", PartLoadInt,
realRAM_Hz / 1000000, (realRAM_Hz / 100000) % 10);
} else {
snprintf(MINI_RAM_var_compressed_c, sizeof(MINI_RAM_var_compressed_c),
"%u%%@%hu.%hhu", PartLoadInt,
RAM_Hz / 1000000, (RAM_Hz / 100000) % 10);
}
}
}

View File

@@ -1,5 +1,21 @@
/*
* --------------------------------------------------------------------------
* 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/>.
*
*/
/* --------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
* wrote this file. As long as you retain this notice you can do whatever you
@@ -8,11 +24,12 @@
* --------------------------------------------------------------------------
*/
#define NX_SERVICE_ASSUME_NON_DOMAIN
#include <sysclk/client/ipc.h>
#include <switch.h>
#include <string.h>
#include <stdatomic.h>
#include <sysclk/client/ipc.h>
static Service g_sysclkSrv;
static atomic_size_t g_refCnt;
@@ -20,7 +37,7 @@ static atomic_size_t g_refCnt;
bool sysclkIpcRunning()
{
Handle handle;
const bool running = R_FAILED(smRegisterService(&handle, smEncodeName(SYSCLK_IPC_SERVICE_NAME), false, 1));
bool running = R_FAILED(smRegisterService(&handle, smEncodeName(SYSCLK_IPC_SERVICE_NAME), false, 1));
if (!running)
{
@@ -62,14 +79,17 @@ Result sysclkIpcGetAPIVersion(u32* out_ver)
Result sysclkIpcGetVersionString(char* out, size_t len)
{
return serviceDispatch(&g_sysclkSrv, SysClkIpcCmd_GetVersionString,
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
.buffer_attrs = { SfBufferAttr_HipcAutoSelect | SfBufferAttr_Out },
.buffers = {{out, len}},
);
}
Result sysclkIpcGetCurrentContext(SysClkContext* out_context)
{
return serviceDispatchOut(&g_sysclkSrv, SysClkIpcCmd_GetCurrentContext, *out_context);
return serviceDispatch(&g_sysclkSrv, SysClkIpcCmd_GetCurrentContext,
.buffer_attrs = { SfBufferAttr_HipcAutoSelect | SfBufferAttr_Out },
.buffers = {{out_context, sizeof(SysClkContext)}},
);
}
Result sysclkIpcGetProfileCount(u64 tid, u8* out_count)
@@ -94,7 +114,10 @@ Result sysclkIpcSetOverride(SysClkModule module, u32 hz)
Result sysclkIpcGetProfiles(u64 tid, SysClkTitleProfileList* out_profiles)
{
return serviceDispatchInOut(&g_sysclkSrv, SysClkIpcCmd_GetProfiles, tid, *out_profiles);
return serviceDispatchIn(&g_sysclkSrv, SysClkIpcCmd_GetProfiles, tid,
.buffer_attrs = { SfBufferAttr_HipcAutoSelect | SfBufferAttr_Out },
.buffers = {{out_profiles, sizeof(SysClkTitleProfileList)}},
);
}
Result sysclkIpcSetProfiles(u64 tid, SysClkTitleProfileList* profiles)
@@ -107,12 +130,18 @@ Result sysclkIpcSetProfiles(u64 tid, SysClkTitleProfileList* profiles)
Result sysclkIpcGetConfigValues(SysClkConfigValueList* out_configValues)
{
return serviceDispatchOut(&g_sysclkSrv, SysClkIpcCmd_GetConfigValues, *out_configValues);
return serviceDispatch(&g_sysclkSrv, SysClkIpcCmd_GetConfigValues,
.buffer_attrs = { SfBufferAttr_HipcAutoSelect | SfBufferAttr_Out },
.buffers = {{out_configValues, sizeof(SysClkConfigValueList)}},
);
}
Result sysclkIpcSetConfigValues(SysClkConfigValueList* configValues)
{
return serviceDispatchIn(&g_sysclkSrv, SysClkIpcCmd_SetConfigValues, *configValues);
return serviceDispatch(&g_sysclkSrv, SysClkIpcCmd_SetConfigValues,
.buffer_attrs = { SfBufferAttr_HipcAutoSelect | SfBufferAttr_In },
.buffers = {{configValues, sizeof(SysClkConfigValueList)}},
);
}
Result sysclkIpcGetFreqList(SysClkModule module, u32* list, u32 maxCount, u32* outCount)
@@ -125,4 +154,16 @@ Result sysclkIpcGetFreqList(SysClkModule module, u32* list, u32 maxCount, u32* o
.buffer_attrs = { SfBufferAttr_HipcAutoSelect | SfBufferAttr_Out },
.buffers = {{list, maxCount * sizeof(u32)}},
);
}
Result hocClkIpcSetKipData()
{
u32 temp = 0;
return serviceDispatchIn(&g_sysclkSrv, HocClkIpcCmd_SetKipData, temp);
}
Result hocClkIpcGetKipData()
{
u32 temp = 0;
return serviceDispatchIn(&g_sysclkSrv, HocClkIpcCmd_GetKipData, temp);
}

View File

@@ -1,287 +0,0 @@
diff --git a/Overlay/Makefile b/Overlay/Makefile
index 9656834..3b2ebd5 100644
--- a/Overlay/Makefile
+++ b/Overlay/Makefile
@@ -38,7 +38,7 @@ include $(DEVKITPRO)/libnx/switch_rules
# NACP building is skipped as well.
#---------------------------------------------------------------------------------
APP_TITLE := ReverseNX-RT
-APP_VERSION := 1.1.1
+APP_VERSION := 1.1.1-OC
TARGET := ReverseNX-RT-ovl
BUILD := build
diff --git a/Overlay/source/main.cpp b/Overlay/source/main.cpp
index 810295c..2b3aa52 100644
--- a/Overlay/source/main.cpp
+++ b/Overlay/source/main.cpp
@@ -1,7 +1,202 @@
#define TESLA_INIT_IMPL // If you have more than one file using the tesla header, only define this in the main one
#include <tesla.hpp> // The Tesla Header
+#include <atomic>
#include "SaltyNX.h"
+class ModeSync {
+public:
+ enum ReverseNXMode {
+ ReverseNX_NotValid = 0,
+ ReverseNX_SystemDefault = 0,
+ ReverseNX_Handheld,
+ ReverseNX_Docked,
+ ReverseNX_Undefined,
+ };
+
+ void SetMode(bool isDefault, bool setDock, char* descBuf, size_t bufSize) {
+ auto changeHandler = [this](ReverseNXMode newMode) {
+ if (this->currentMode == ReverseNX_Undefined || this->currentMode != newMode) {
+ if (R_FAILED(this->ipc->SetMode(newMode))) {
+ this->ipc->ipcStatus = Ipc::IpcStatus_ConnectFailed;
+ return;
+ }
+ this->currentMode = newMode;
+ }
+ };
+
+ tsl::hlp::ScopeGuard updateBufGuard([&] { this->ipc->UpdateStatusDesc(descBuf, bufSize); });
+
+ if (isDefault) {
+ changeHandler(ReverseNX_SystemDefault);
+ return;
+ }
+
+ changeHandler(setDock ? ReverseNX_Docked : ReverseNX_Handheld);
+ }
+
+ ModeSync() {
+ this->ipc = new Ipc;
+ this->ipc->Init();
+ }
+
+ ~ModeSync() {
+ this->ipc->Exit();
+ delete this->ipc;
+ }
+
+protected:
+ struct Ipc {
+ #define API_VER 2
+ #define SERVICE_NAME "sysclkOC"
+
+ enum SysClkIpcCmd {
+ SysClkIpcCmd_GetApiVersion = 0,
+ SysClkIpcCmd_GetConfigValues = 9,
+ SysClkIpcCmd_SetReverseNXRTMode = 11,
+ };
+
+ enum SysClkConfigValue {
+ SysClkConfigValue_SyncReverseNXMode = 4,
+ SysClkConfigValue_EnumMax = 8,
+ };
+
+ struct SysClkConfigValueList {
+ uint64_t values[SysClkConfigValue_EnumMax];
+ };
+
+ enum IpcStatus {
+ IpcStatus_OK,
+
+ IpcStatus_Unknown,
+ IpcStatus_NotRunning,
+ IpcStatus_InitFailed,
+ IpcStatus_ConnectFailed,
+ IpcStatus_UnsupportedVer,
+
+ IpcStatus_Count,
+ };
+
+ static constexpr const char* IpcStatusStr[IpcStatus_Count] = {
+ "",
+
+ "Unknown",
+ "Err: Not running",
+ "Err: Failed to init",
+ "Err: Failed to connect",
+ "Err: Unsupported version",
+ };
+
+ Result Init() {
+ Result rc = 0;
+
+ rc = IpcInitialize();
+
+ rc = GetStatus();
+
+ return rc;
+ }
+
+ void Exit() {
+ if (--refCnt == 0)
+ serviceClose(&service);
+ }
+
+ bool IsServiceRunning() {
+ Handle handle;
+ SmServiceName name = smEncodeName(SERVICE_NAME);
+ if (R_FAILED(smRegisterService(&handle, name, false, 1))) {
+ return true;
+ }
+ svcCloseHandle(handle);
+ smUnregisterService(name);
+ return false;
+ }
+
+ Result IpcInitialize(void) {
+ Result rc = 0;
+ refCnt++;
+
+ if (serviceIsActive(&service))
+ return 0;
+
+ rc = smGetService(&service, SERVICE_NAME);
+
+ if (R_FAILED(rc)) {
+ this->ipcStatus = IpcStatus_InitFailed;
+ rc = this->ipcStatus;
+ this->Exit();
+ return rc;
+ }
+
+ return rc;
+ }
+
+ Result GetApiVersion(u32* outVer) {
+ return serviceDispatchOut(&service, SysClkIpcCmd_GetApiVersion, *outVer);
+ }
+
+ Result GetConfigValues(SysClkConfigValueList* outConfigValues) {
+ return serviceDispatchOut(&service, SysClkIpcCmd_GetConfigValues, *outConfigValues);
+ }
+
+ Result SetMode(ReverseNXMode mode) {
+ return serviceDispatchIn(&service, SysClkIpcCmd_SetReverseNXRTMode, mode);
+ }
+
+ Result GetStatus() {
+ if (!IsServiceRunning()) {
+ this->ipcStatus = IpcStatus_NotRunning;
+ return this->ipcStatus;
+ }
+
+ tsl::hlp::ScopeGuard exitSrvGuard([&] { this->Exit(); });
+
+ uint32_t api_ver;
+ if (R_FAILED(GetApiVersion(&api_ver))) {
+ this->ipcStatus = IpcStatus_ConnectFailed;
+ return this->ipcStatus;
+ }
+
+ if (api_ver != API_VER) {
+ this->ipcStatus = IpcStatus_UnsupportedVer;
+ return this->ipcStatus;
+ }
+
+ SysClkConfigValueList* list = new SysClkConfigValueList;
+ tsl::hlp::ScopeGuard listGuard([&] { delete list; });
+
+ if (R_FAILED(GetConfigValues(list))) {
+ this->ipcStatus = IpcStatus_ConnectFailed;
+ return this->ipcStatus;
+ }
+
+ exitSrvGuard.dismiss();
+
+ shouldSync = bool(list->values[SysClkConfigValue_SyncReverseNXMode]);
+ this->ipcStatus = IpcStatus_OK;
+ return this->ipcStatus;
+ }
+
+ void UpdateStatusDesc(char* buffer, size_t size) {
+ snprintf(buffer, size,
+ "Mode Sync: %s%s",
+ IpcStatusStr[ipcStatus],
+ (ipcStatus == IpcStatus_OK) ? (
+ shouldSync ? "ON" : "OFF"
+ ) : ""
+ );
+ }
+
+ Service service = {};
+ std::atomic<std::size_t> refCnt = 0;
+ IpcStatus ipcStatus = IpcStatus_Unknown;
+ bool shouldSync = false;
+ };
+
+ Ipc* ipc = nullptr;
+ ReverseNXMode currentMode = ReverseNX_Undefined;
+};
+
bool* def = 0;
bool* isDocked = 0;
bool* pluginActive = 0;
@@ -17,6 +212,7 @@ bool plugin = false;
char DockedChar[32];
char SystemChar[32];
char PluginChar[36];
+char SysclkChar[0x40];
uint64_t PID = 0;
Handle remoteSharedMemory = 1;
SharedMemory _sharedmemory = {};
@@ -73,7 +269,7 @@ bool CheckPort () {
class GuiTest : public tsl::Gui {
public:
- GuiTest(u8 arg1, u8 arg2, bool arg3) { }
+ GuiTest(ModeSync* p) : modeSync(p) { }
// Called when this Gui gets loaded to create the UI
// Allocate all elements on the heap. libtesla will make sure to clean them up when not needed anymore
@@ -112,6 +308,7 @@ public:
else {
renderer->drawString(SystemChar, false, x, y+40, 20, renderer->a(0xFFFF));
renderer->drawString(DockedChar, false, x, y+60, 20, renderer->a(0xFFFF));
+ renderer->drawString(SysclkChar, false, x, y+80, 20, renderer->a(0xFFFF));
}
}
}), 100);
@@ -190,6 +387,8 @@ public:
if (_def) sprintf(SystemChar, "Controlled by system: Yes");
else sprintf(SystemChar, "Controlled by system: No");
+
+ modeSync->SetMode(_def, _isDocked, SysclkChar, sizeof(SysclkChar));
}
else i++;
}
@@ -200,6 +399,8 @@ public:
virtual bool handleInput(u64 keysDown, u64 keysHeld, const HidTouchState &touchPos, HidAnalogStickState joyStickPosLeft, HidAnalogStickState joyStickPosRight) override {
return false; // Return true here to singal the inputs have been consumed
}
+
+ ModeSync* modeSync;
};
class OverlayTest : public tsl::Overlay {
@@ -248,9 +449,11 @@ public:
});
+ modeSync = new ModeSync;
} // Called at the start to initialize all services necessary for this Overlay
virtual void exitServices() override {
+ delete modeSync;
shmemClose(&_sharedmemory);
fsdevUnmountDevice("sdmc");
} // Callet at the end to clean up all services previously initialized
@@ -260,8 +463,10 @@ public:
virtual void onHide() override {} // Called before overlay wants to change from visible to invisible state
virtual std::unique_ptr<tsl::Gui> loadInitialGui() override {
- return initially<GuiTest>(1, 2, true); // Initial Gui to load. It's possible to pass arguments to it's constructor like this
+ return initially<GuiTest>(modeSync); // Initial Gui to load. It's possible to pass arguments to it's constructor like this
}
+
+ ModeSync* modeSync = nullptr;
};
int main(int argc, char **argv) {

View File

@@ -1,241 +0,0 @@
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <inttypes.h>
#include <unistd.h>
#include <switch.h>
/* Recompile nx-hbloader with following added in config.json "kernel_capabilities"
{
"type": "map",
"value": {
"address": "0x60006000",
"size": "0x1000",
"is_ro": false,
"is_io": true
}
}
*/
void waitForKey(PadState pad) {
while (appletMainLoop())
{
padUpdate(&pad);
u64 kDown = padGetButtonsDown(&pad);
if (kDown & HidNpadButton_A)
break;
if (kDown & HidNpadButton_Plus || kDown & HidNpadButton_B) {
consoleExit(NULL);
exit(0);
}
consoleUpdate(NULL);
}
}
#define CLK_RST_IO_BASE 0x60006000
#define CLK_RST_IO_SIZE 0x1000
#define REG(OFFSET) (*reinterpret_cast<volatile u32 *>(OFFSET))
#define GET_BITS(VAL, HIGH, LOW) ((VAL & ((1UL << (HIGH + 1UL)) - 1UL)) >> LOW)
#define GET_BIT(VAL, BIT) GET_BITS(VAL, BIT, BIT)
static u64 clkrst_base = 0;
static u64 clkrst_size = 0;
// From jetson nano kernel
typedef enum {
/* divider = 2 */
CLK_PLLX = 5,
CLK_PLLM = 2,
CLK_PLLMB = 37,
/* PLLX & PLLG are backup PLLs for CPU & GPU */
/* divider = 1 */
CLK_CCLK_G = 18, // A57 CPU cluster
CLK_EMC = 36,
} PTO_ID; // PLL Test Output Register ID
/* See if GM20B clock GPC PLL regs are accessible. */
#define PLLX_MISC0 0xE4
#define PLLM_MISC2 0x9C
double ptoGetMHz(PTO_ID pto_id, u32 divider = 1, u32 presel_reg = 0, u32 presel_mask = 0) {
u32 pre_val, val, presel_val;
if (presel_reg) {
val = REG(clkrst_base + presel_reg);
usleep(10);
presel_val = val & presel_mask;
val &= ~presel_mask;
val |= presel_mask;
REG(clkrst_base + presel_reg) = val;
usleep(10);
}
constexpr u32 cycle_count = 16;
pre_val = REG(clkrst_base + 0x60);
val = BIT(23) | BIT(13) | (cycle_count - 1);
val |= pto_id << 14;
REG(clkrst_base + 0x60) = val;
usleep(10);
REG(clkrst_base + 0x60) = val | BIT(10);
usleep(10);
REG(clkrst_base + 0x60) = val;
usleep(10);
REG(clkrst_base + 0x60) = val | BIT(9);
usleep(500);
while(REG(clkrst_base + 0x64) & BIT(31))
;
val = REG(clkrst_base + 0x64);
val &= 0xFFFFFF;
val *= divider;
double rate_mhz = (u64)val * 32768. / cycle_count / 1000. / 1000.;
usleep(10);
REG(clkrst_base + 0x60) = pre_val;
usleep(10);
if (presel_reg) {
val = REG(clkrst_base + presel_reg);
usleep(10);
val &= ~presel_mask;
val |= presel_val;
REG(clkrst_base + presel_reg) = val;
usleep(10);
}
return rate_mhz;
}
int main() {
consoleInit(NULL);
PadState pad;
padConfigureInput(1, HidNpadStyleSet_NpadStandard);
padInitializeDefault(&pad);
// Get clkrst MMIO virtual address
Result rc = svcQueryIoMapping(&clkrst_base, &clkrst_size, CLK_RST_IO_BASE, CLK_RST_IO_SIZE);
if (R_FAILED(rc)) {
printf("[ERROR] svcQueryIoMapping: 0x%X\n", rc);
consoleUpdate(NULL);
waitForKey(pad);
consoleExit(NULL);
}
printf("clkrst_base: 0x%lX\nclkrst_size: 0x%lX\n", clkrst_base, clkrst_size);
{
#define CLKRST_PLLX_BASE 0xE0
u32 pllx_base = REG(clkrst_base + CLKRST_PLLX_BASE);
printf("\n"\
"PLLX_BASE: 0x%X\n"\
"PLLX_ENABLE: %lu\n"\
"PLLX_REF_DIS: %lu\n"\
"PLLX_LOCK: %lu\n"\
"PLLX_DIVP: %lu\n"\
"PLLX_DIVN: %lu\n"\
"PLLX_DIVM: %lu\n",
pllx_base,
GET_BIT(pllx_base, 30),
GET_BIT(pllx_base, 29),
GET_BIT(pllx_base, 27),
GET_BITS(pllx_base, 24, 20),
GET_BITS(pllx_base, 15, 8),
GET_BITS(pllx_base, 7, 0));
}
{
#define CLKRST_PLLX_MISC 0xE4
u32 pllx_misc = REG(clkrst_base + CLKRST_PLLX_MISC);
printf("\n"\
"PLLX_MISC: 0x%X\n"\
"PLLX_FO_G_DISABLE: %lu\n"\
"PLLX_PTS: %lu\n"\
"PLLX_LOCK_ENABLE: %lu\n",
pllx_misc,
GET_BIT(pllx_misc, 28),
GET_BITS(pllx_misc, 23, 22),
GET_BIT(pllx_misc, 18));
}
{
#define CLKRST_PLLMB_SS_CFG 0x780
u32 pllmb_ss_cfg = REG(clkrst_base + CLKRST_PLLMB_SS_CFG);
printf("\n"\
"PLLMB_SS_CFG: 0x%X\n"\
"PLLMB_EN_SDM: %lu\n"\
"PLLMB_EN_SSC: %lu\n",
pllmb_ss_cfg,
GET_BIT(pllmb_ss_cfg, 31),
GET_BIT(pllmb_ss_cfg, 30));
}
{
#define CLKRST_PLLMB_SS_CTRL1 0x784
u32 pllmb_ss_ctrl1 = REG(clkrst_base + CLKRST_PLLMB_SS_CTRL1);
printf("\n"\
"PLLMB_SS_CTRL1: 0x%X\n"\
"PLLMB_SDM_SSC_MAX: %lu\n"\
"PLLMB_SDM_SSC_MIN: %lu\n",
pllmb_ss_ctrl1,
GET_BITS(pllmb_ss_ctrl1, 31, 16),
GET_BITS(pllmb_ss_ctrl1, 15, 0));
}
{
#define CLKRST_PLLM_BASE 0x90
u32 pllm_base = REG(clkrst_base + CLKRST_PLLM_BASE);
printf("\n"\
"PLLM_BASE: 0x%X\n"\
"PLLM_DIVP: %lu\n"\
"PLLM_DIVN: %lu\n"\
"PLLM_DIVM: %lu\n",
pllm_base,
GET_BITS(pllm_base, 24, 20),
GET_BITS(pllm_base, 15, 8),
GET_BITS(pllm_base, 7, 0));
}
{
#define CLKRST_PLLMB_BASE 0x5e8
u32 pllmb_base = REG(clkrst_base + CLKRST_PLLMB_BASE);
printf("\n"\
"PLLMB_BASE: 0x%X\n"\
"PLLMB_DIVP: %lu\n"\
"PLLMB_DIVN: %lu\n"\
"PLLMB_DIVM: %lu\n",
pllmb_base,
GET_BITS(pllmb_base, 24, 20),
GET_BITS(pllmb_base, 15, 8),
GET_BITS(pllmb_base, 7, 0));
}
printf("\n"\
"EMC: %6.1f MHz\n"\
"CCLK_G: %6.1f MHz\n"\
"PLLX: %6.1f MHz\n"\
"PLLM: %6.1f MHz\n"\
"PLLMB: %6.1f MHz\n",
ptoGetMHz(CLK_EMC),
ptoGetMHz(CLK_CCLK_G),
ptoGetMHz(CLK_PLLX, 2, PLLX_MISC0, BIT(22)),
ptoGetMHz(CLK_PLLM, 2, PLLM_MISC2, BIT(8)),
ptoGetMHz(CLK_PLLMB, 2, PLLM_MISC2, BIT(9))
);
waitForKey(pad);
consoleExit(NULL);
return 0;
}

5
Source/rewrite-hoc-clk/.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
/dist
.DS_Store
Thumbs.db
desktop.ini
.vscode

View File

@@ -0,0 +1,17 @@
image: $CI_SERVER_HOST:4567/libretro/infrastructure/libretro-build-libnx-devkitpro:latest
variables:
PACKAGE_FOLDER: "sys-clk"
stages:
- package
nightly:
stage: package
script:
- bash build.sh $PACKAGE_FOLDER
artifacts:
name: $PACKAGE_FOLDER
expire_in: 24 hours
paths:
- $PACKAGE_FOLDER

3
Source/rewrite-hoc-clk/.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "overlay/lib/libultrahand"]
path = overlay/lib/libultrahand
url = https://github.com/ppkantorski/libultrahand

View File

@@ -0,0 +1,7 @@
--------------------------------------------------------------------------
"THE BEER-WARE LICENSE" (Revision 42):
<p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
wrote this file. As long as you retain this notice you can do whatever you
want with this stuff. If you meet any of us some day, and you think this
stuff is worth it, you can buy us a beer in return. - The sys-clk authors
--------------------------------------------------------------------------

View File

@@ -0,0 +1,6 @@
# hoc-clk
Switch sysmodule allowing you to set cpu/gpu/mem clocks according to the running application and docked state.
Modified for Horizon OC
Support is only provided for FW 16.0.0+. This MAY work on older firmwares but support is NOT guaranteed

View File

@@ -0,0 +1,53 @@
from PIL import Image
import argparse
import os
def image_to_rgba8888_array(image_path, output_path):
# Open and convert to RGBA
img = Image.open(image_path).convert('RGBA')
width, height = img.size
# Get pixel data
pixels = img.tobytes()
# Write as C header file
with open(output_path, 'w') as f:
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')
f.write('const unsigned char IMG_DATA[] = {\n ')
for i, byte in enumerate(pixels):
f.write(f'0x{byte:02X}')
if i < len(pixels) - 1:
f.write(', ')
if (i + 1) % 12 == 0:
f.write('\n ')
f.write('\n};\n')
print(f'Converted: {width}x{height} -> {len(pixels)} bytes')
print(f'Output: {output_path}')
def main():
parser = argparse.ArgumentParser(
description='PNG to RGB8888 script'
)
parser.add_argument('input', help='Input image file (e.g. cat.png)')
parser.add_argument(
'-o', '--output',
help='Output header file (default: <input>.h)'
)
args = parser.parse_args()
output_path = args.output
if not output_path:
base, _ = os.path.splitext(args.input)
output_path = base + '.h'
image_to_rgba8888_array(args.input, output_path)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,42 @@
#!/bin/bash
set -e
ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
DIST_DIR="$ROOT_DIR/dist"
CORES="$(nproc --all)"
if [[ -n "$1" ]]; then
DIST_DIR="$1"
fi
echo "DIST_DIR: $DIST_DIR"
echo "CORES: $CORES"
echo "*** sysmodule ***"
TITLE_ID="$(grep -oP '"title_id":\s*"0x\K(\w+)' "$ROOT_DIR/sysmodule/perms.json")"
pushd "$ROOT_DIR/sysmodule"
make -j$CORES
popd > /dev/null
mkdir -p "$DIST_DIR/atmosphere/contents/$TITLE_ID/flags"
cp -vf "$ROOT_DIR/sysmodule/out/horizon-oc.nsp" "$DIST_DIR/atmosphere/contents/$TITLE_ID/exefs.nsp"
>"$DIST_DIR/atmosphere/contents/$TITLE_ID/flags/boot2.flag"
cp -vf "$ROOT_DIR/sysmodule/toolbox.json" "$DIST_DIR/atmosphere/contents/$TITLE_ID/toolbox.json"
echo "*** overlay ***"
pushd "$ROOT_DIR/overlay"
make -j$CORES
popd > /dev/null
mkdir -p "$DIST_DIR/switch/.overlays"
cp -vf "$ROOT_DIR/overlay/out/horizon-oc-overlay.ovl" "$DIST_DIR/switch/.overlays/horizon-oc-overlay.ovl"
echo "*** assets ***"
mkdir -p "$DIST_DIR/config/horizon-oc"
cp -vf "$ROOT_DIR/config.ini.template" "$DIST_DIR/config/horizon-oc/config.ini.template"
cp -vf "$ROOT_DIR/../../README.md" "$DIST_DIR/README.md"
echo "*** lang ***"
cp -r "$ROOT_DIR/overlay/lang/" "$DIST_DIR/config/horizon-oc/lang/"

View File

@@ -0,0 +1,248 @@
/*
* Copyright (c) MasaGratoR
*
* 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 "ipc.h"
Handle saltysd_orig;
Result SaltySD_Connect() {
for (int i = 0; i < 200; i++) {
if (!svcConnectToNamedPort(&saltysd_orig, "SaltySD"))
return 0;
svcSleepThread(1000*1000);
}
return 1;
}
Result SaltySD_Term()
{
Result ret;
IpcCommand c;
ipcInitialize(&c);
ipcSendPid(&c);
struct input
{
u64 magic;
u64 cmd_id;
u64 zero;
u64 reserved[2];
} *raw;
raw = (input*)ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 0;
raw->zero = 0;
ret = ipcDispatch(saltysd_orig);
if (R_SUCCEEDED(ret))
{
IpcParsedCommand r;
ipcParse(&r);
struct output {
u64 magic;
u64 result;
} *resp = (output*)r.Raw;
ret = resp->result;
}
// Session terminated works too.
svcCloseHandle(saltysd_orig);
if (ret == 0xf601) return 0;
return ret;
}
Result SaltySD_CheckIfSharedMemoryAvailable(ptrdiff_t *offset, u64 size)
{
Result ret = 0;
// Send a command
IpcCommand c;
ipcInitialize(&c);
ipcSendPid(&c);
struct input {
u64 magic;
u64 cmd_id;
u64 size;
u32 reserved[2];
} *raw;
raw = (input*)ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 6;
raw->size = size;
ret = ipcDispatch(saltysd_orig);
if (R_SUCCEEDED(ret)) {
IpcParsedCommand r;
ipcParse(&r);
struct output {
u64 magic;
u64 result;
u64 offset;
} *resp = (output*)r.Raw;
ret = resp->result;
if (!ret)
{
*offset = resp->offset;
}
}
return ret;
}
Result SaltySD_GetSharedMemoryHandle(Handle *retrieve)
{
Result ret = 0;
// Send a command
IpcCommand c;
ipcInitialize(&c);
ipcSendPid(&c);
struct input {
u64 magic;
u64 cmd_id;
u32 reserved[4];
} *raw;
raw = (input*)ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 7;
ret = ipcDispatch(saltysd_orig);
if (R_SUCCEEDED(ret)) {
IpcParsedCommand r;
ipcParse(&r);
struct output {
u64 magic;
u64 result;
u64 reserved[2];
} *resp = (output*)r.Raw;
ret = resp->result;
if (!ret)
{
*retrieve = r.Handles[0];
}
}
return ret;
}
Result SaltySD_GetDisplayRefreshRate(uint8_t* refreshRate)
{
Result ret = 0;
// Send a command
IpcCommand c;
ipcInitialize(&c);
ipcSendPid(&c);
struct input {
u64 magic;
u64 cmd_id;
u64 zero;
u64 reserved;
} *raw;
raw = (input*)ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 10;
raw->zero = 0;
ret = ipcDispatch(saltysd_orig);
if (R_SUCCEEDED(ret)) {
IpcParsedCommand r;
ipcParse(&r);
struct output {
u64 magic;
u64 result;
u64 refreshRate;
u64 reserved;
} *resp = (output*)r.Raw;
ret = resp->result;
if (!ret)
{
*refreshRate = (uint8_t)(resp->refreshRate);
}
}
return ret;
}
Result SaltySD_SetDisplayRefreshRate(uint8_t refreshRate)
{
Result ret = 0;
// Send a command
IpcCommand c;
ipcInitialize(&c);
ipcSendPid(&c);
struct input {
u64 magic;
u64 cmd_id;
u64 refreshRate;
u64 reserved;
} *raw;
raw = (input*)ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 11;
raw->refreshRate = refreshRate;
ret = ipcDispatch(saltysd_orig);
if (R_SUCCEEDED(ret)) {
IpcParsedCommand r;
ipcParse(&r);
struct output {
u64 magic;
u64 result;
u64 reserved[2];
} *resp = (output*)r.Raw;
ret = resp->result;
}
return ret;
}

View File

@@ -0,0 +1,252 @@
/*
* 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 <switch.h>
#include <inttypes.h>
#include <string.h>
typedef enum {
BatteryFlag_NoHub = BIT(0), // Hub is disconnected
BatteryFlag_Rail = BIT(8), // At least one Joy-con is charging from rail
BatteryFlag_SPDSRC = BIT(12), // OTG
BatteryFlag_ACC = BIT(16) // Accessory
} BatteryChargeFlags;
typedef enum {
PDState_NewPDO = 1, // Received new Power Data Object
PDState_NoPD = 2, // No Power Delivery source is detected
PDState_AcceptedRDO = 3 // Received and accepted Request Data Object
} BatteryPDControllerState;
// Charger type detection
typedef enum {
ChargerType_None = 0,
ChargerType_PD = 1,
ChargerType_TypeC_1500mA = 2,
ChargerType_TypeC_3000mA = 3,
ChargerType_DCP = 4, // Dedicated Charging Port
ChargerType_CDP = 5, // Charging Downstream Port
ChargerType_SDP = 6, // Standard Downstream Port
ChargerType_Apple_500mA = 7,
ChargerType_Apple_1000mA = 8,
ChargerType_Apple_2000mA = 9
} BatteryChargerType;
typedef enum {
PowerRole_Sink = 1, // Device is receiving power
PowerRole_Source = 2 // Device is providing power
} BatteryPowerRole;
typedef struct {
int32_t InputCurrentLimit; // Input (Sink) current limit in mA
int32_t VBUSCurrentLimit; // Output (Source/VBUS/OTG) current limit in mA
int32_t ChargeCurrentLimit; // Battery charging current limit in mA
int32_t ChargeVoltageLimit; // Battery charging voltage limit in mV
int32_t unk_x10; // Unknown field (possibly enum)
int32_t unk_x14; // Unknown field (possibly flags)
BatteryPDControllerState PDControllerState; // PD Controller State
int32_t BatteryTemperature; // Battery temperature in milli-Celsius
int32_t RawBatteryCharge; // Battery charge in percentmille
int32_t VoltageAvg; // Average voltage in mV
int32_t BatteryAge; // Battery health (capacity full/design) in pcm
BatteryPowerRole PowerRole; // Current power role
BatteryChargerType ChargerType; // Type of charger connected
int32_t ChargerVoltageLimit; // Charger voltage limit in mV
int32_t ChargerCurrentLimit; // Charger current limit in mA
BatteryChargeFlags Flags; // Various status flags
} BatteryChargeInfo;
#define IS_BATTERY_CHARGING_ENABLED(info) (((info)->unk_x14 >> 8) & 1)
Result batteryInfoInitialize(void);
void batteryInfoExit(void);
Result batteryInfoGetChargeInfo(BatteryChargeInfo *out);
Result batteryInfoGetChargePercentage(u32 *out);
Result batteryInfoIsEnoughPowerSupplied(bool *out);
Result batteryInfoEnableCharging(void);
Result batteryInfoDisableCharging(void);
Result batteryInfoEnableFastCharging(void);
Result batteryInfoDisableFastCharging(void);
const char* batteryInfoGetChargerTypeString(BatteryChargerType type);
const char* batteryInfoGetPowerRoleString(BatteryPowerRole role);
const char* batteryInfoGetPDStateString(BatteryPDControllerState state);
static inline int batteryInfoGetTemperatureMiliCelsius(BatteryChargeInfo *info) {
return info->BatteryTemperature;
}
static inline float batteryInfoGetChargePercent(BatteryChargeInfo *info) {
return (float)info->RawBatteryCharge / 1000.0f;
}
static inline float batteryInfoGetBatteryHealthPercent(BatteryChargeInfo *info) {
return (float)info->BatteryAge / 1000.0f;
}
static inline bool batteryInfoIsCharging(BatteryChargeInfo *info) {
return IS_BATTERY_CHARGING_ENABLED(info);
}
static const char* s_chargerTypeStrings[] = {
"None",
"Power Delivery",
"USB-C @ 1.5A",
"USB-C @ 3.0A",
"USB-DCP",
"USB-CDP",
"USB-SDP",
"Apple @ 0.5A",
"Apple @ 1.0A",
"Apple @ 2.0A",
};
static const char* s_powerRoleStrings[] = {
"Unknown",
"Sink",
"Source",
};
static const char* s_pdStateStrings[] = {
"Unknown",
"New PDO Received",
"No PD Source",
"RDO Accepted"
};
// Internal PSM service handle
static Service g_psmService = {0};
static bool g_batteryInfoInitialized = false;
// Internal PSM command implementations
static Result psmGetBatteryChargeInfoFields(BatteryChargeInfo *out) {
if (!g_batteryInfoInitialized)
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
return serviceDispatchOut(&g_psmService, 17, *out);
}
static Result psmEnableBatteryCharging_internal(void) {
if (!g_batteryInfoInitialized)
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
return serviceDispatch(&g_psmService, 2);
}
static Result psmDisableBatteryCharging_internal(void) {
if (!g_batteryInfoInitialized)
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
return serviceDispatch(&g_psmService, 3);
}
static Result psmEnableFastBatteryCharging_internal(void) {
if (!g_batteryInfoInitialized)
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
return serviceDispatch(&g_psmService, 10);
}
static Result psmDisableFastBatteryCharging_internal(void) {
if (!g_batteryInfoInitialized)
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
return serviceDispatch(&g_psmService, 11);
}
Result batteryInfoInitialize(void) {
if (g_batteryInfoInitialized)
return 0;
Result rc = psmInitialize();
if (R_SUCCEEDED(rc)) {
memcpy(&g_psmService, psmGetServiceSession(), sizeof(Service));
g_batteryInfoInitialized = true;
}
return rc;
}
void batteryInfoExit(void) {
if (g_batteryInfoInitialized) {
psmExit();
memset(&g_psmService, 0, sizeof(Service));
g_batteryInfoInitialized = false;
}
}
Result batteryInfoGetChargeInfo(BatteryChargeInfo *out) {
if (!out)
return MAKERESULT(Module_Libnx, LibnxError_BadInput);
return psmGetBatteryChargeInfoFields(out);
}
Result batteryInfoGetChargePercentage(u32 *out) {
if (!g_batteryInfoInitialized)
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
return psmGetBatteryChargePercentage(out);
}
Result batteryInfoIsEnoughPowerSupplied(bool *out) {
if (!g_batteryInfoInitialized)
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
return psmIsEnoughPowerSupplied(out);
}
Result batteryInfoEnableCharging(void) {
return psmEnableBatteryCharging_internal();
}
Result batteryInfoDisableCharging(void) {
return psmDisableBatteryCharging_internal();
}
Result batteryInfoEnableFastCharging(void) {
return psmEnableFastBatteryCharging_internal();
}
Result batteryInfoDisableFastCharging(void) {
return psmDisableFastBatteryCharging_internal();
}
const char* batteryInfoGetChargerTypeString(BatteryChargerType type) {
if (type < 0 || type > ChargerType_Apple_2000mA)
return "Unknown";
return s_chargerTypeStrings[type];
}
const char* batteryInfoGetPowerRoleString(BatteryPowerRole role) {
if (role < PowerRole_Sink || role > PowerRole_Source)
return s_powerRoleStrings[0];
return s_powerRoleStrings[role];
}
const char* batteryInfoGetPDStateString(BatteryPDControllerState state) {
if (state < PDState_NewPDO || state > PDState_AcceptedRDO)
return s_pdStateStrings[0];
return s_pdStateStrings[state];
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright (c) meha3945 (hanai3bi)
*
* 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 <utility>
template<typename F>
class ScopeGuard {
public:
ScopeGuard(F&& f)
: f(f), engaged(true) {};
~ScopeGuard() {
if (engaged)
f();
};
ScopeGuard(ScopeGuard&& rhs)
: f(std::move(rhs.f)) {};
void dismiss() { engaged = false; }
private:
F f;
bool engaged;
};
struct MakeScopeExit {
template<typename F>
ScopeGuard<F> operator+=(F&& f) {
return ScopeGuard<F>(std::move(f));
};
};
#define STRING_CAT2(x, y) x##y
#define STRING_CAT(x, y) STRING_CAT2(x, y)
#define SCOPE_GUARD MakeScopeExit() += [&]() __attribute__((always_inline))
#define SCOPE_EXIT auto STRING_CAT(scope_exit_, __LINE__) = SCOPE_GUARD

View File

@@ -0,0 +1,56 @@
/*
* 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 <stdio.h>
#include <stdint.h>
uint32_t crc32(const uint8_t *data, size_t length) {
uint32_t crc = 0xFFFFFFFF;
for (size_t i = 0; i < length; i++) {
crc ^= data[i];
for (int j = 0; j < 8; j++) {
crc = (crc >> 1) ^ (0xEDB88320 & -(crc & 1));
}
}
return ~crc;
}
uint32_t checksum_file(const char *filename) {
FILE *file = fopen(filename, "rb");
if (!file) {
perror("[crc32] Error opening file");
return 0;
}
uint8_t buffer[1024];
uint32_t crc = 0xFFFFFFFF;
size_t bytes_read;
while ((bytes_read = fread(buffer, 1, sizeof(buffer), file)) > 0) {
for (size_t i = 0; i < bytes_read; i++) {
crc ^= buffer[i];
for (int j = 0; j < 8; j++) {
crc = (crc >> 1) ^ (0xEDB88320 & -(crc & 1));
}
}
}
fclose(file);
return ~crc;
}

View File

@@ -0,0 +1,126 @@
/*
* Copyright (c) Souldbminer, based on reasearch by MasaGratoR and Cooler3D
*
* 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 <stdint.h>
#include <stdbool.h>
#include <stddef.h>
typedef struct {
uint16_t hFrontPorch;
uint8_t hSyncWidth;
uint8_t hBackPorch;
uint8_t vFrontPorch;
uint8_t vSyncWidth;
uint8_t vBackPorch;
uint8_t VIC;
uint32_t pixelClock_kHz;
} DockedTimings;
typedef struct {
uint8_t hSyncWidth;
uint16_t hFrontPorch;
uint8_t hBackPorch;
uint8_t vSyncWidth;
uint16_t vFrontPorch;
uint8_t vBackPorch;
uint32_t pixelClock_kHz;
} HandheldTimings;
typedef struct {
uint8_t min;
uint8_t max;
} MinMaxRefreshRate;
typedef struct {
uint32_t unk0;
uint32_t hActive;
uint32_t vActive;
uint32_t hSyncWidth;
uint32_t vSyncWidth;
uint32_t hFrontPorch;
uint32_t vFrontPorch;
uint32_t hBackPorch;
uint32_t vBackPorch;
uint32_t pclkKHz;
uint32_t bitsPerPixel;
uint32_t vmode;
uint32_t sync;
uint32_t unk1;
uint32_t reserved;
} NvdcMode2;
typedef struct {
NvdcMode2 modes[201];
uint32_t num_modes;
} NvdcModeDB2;
typedef struct {
unsigned int PLLD_DIVM: 8;
unsigned int reserved_1: 3;
unsigned int PLLD_DIVN: 8;
unsigned int reserved_2: 1;
unsigned int PLLD_DIVP: 3;
unsigned int CSI_CLK_SRC: 1;
unsigned int reserved_3: 1;
unsigned int PLL_D: 1;
unsigned int reserved_4: 1;
unsigned int PLLD_LOCK: 1;
unsigned int reserved_5: 1;
unsigned int PLLD_REF_DIS: 1;
unsigned int PLLD_ENABLE: 1;
unsigned int PLLD_BYPASS: 1;
} PLLD_BASE;
typedef struct {
signed int PLLD_SDM_DIN: 16;
unsigned int PLLD_EN_SDM: 1;
unsigned int PLLD_LOCK_OVERRIDE: 1;
unsigned int PLLD_EN_LCKDET: 1;
unsigned int PLLD_FREQLOCK: 1;
unsigned int PLLD_IDDQ: 1;
unsigned int PLLD_ENABLE_CLK: 1;
unsigned int PLLD_KVCO: 1;
unsigned int PLLD_KCP: 2;
unsigned int PLLD_PTS: 2;
unsigned int PLLD_LDPULSE_ADJ: 3;
unsigned int reserved: 2;
} PLLD_MISC;
typedef struct {
uint64_t clkVirtAddr;
uint64_t dsiVirtAddr;
bool isDocked;
bool isLite;
bool isRetroSUPER;
bool isPossiblySpoofedRetro;
bool dontForce60InDocked;
bool matchLowestDocked;
bool displaySync;
bool displaySyncOutOfFocus60;
bool displaySyncDocked;
bool displaySyncDockedOutOfFocus60;
} DisplayRefreshConfig;
bool DisplayRefresh_Initialize(const DisplayRefreshConfig* config);
void DisplayRefresh_SetDockedState(bool isDocked);
bool DisplayRefresh_SetRate(uint32_t new_refreshRate);
bool DisplayRefresh_GetRate(uint32_t* out_refreshRate, bool internal);
uint8_t DisplayRefresh_GetDockedHighestAllowed(void);
void DisplayRefresh_CorrectOledGamma(uint32_t refresh_rate);
void DisplayRefresh_SetAllowedDockedRatesIPC(uint32_t refreshRates, bool is720p);
void DisplayRefresh_Shutdown(void);

View File

@@ -0,0 +1,62 @@
/*
* Copyright (c) 2023 KazushiMe
* Licensed under the GPLv2
*/
#pragma once
#include <switch.h>
// To use i2c service, sm and i2c should be intialized via smInitialize() and i2cInitialize().
Result I2cSet_U8(I2cDevice dev, u8 reg, u8 val);
Result I2cRead_OutU8(I2cDevice dev, u8 reg, u8 *out);
Result I2cRead_OutU16(I2cDevice dev, u8 reg, u16 *out);
// Max17050 fuel gauge
float I2c_Max17050_GetBatteryCurrent();
const u8 MAX17050_CURRENT_REG = 0x0A;
// Buck Converter
typedef enum I2c_BuckConverter_Reg {
I2c_Max77620_SD1VOLT_REG = 0x17, // Used for Erista DDR VDDQ+VDD2 / Mariko VDD2
I2c_Max77621_VOLT_REG = 0x00,
I2c_Max77812_CPUVOLT_REG = 0x26,
I2c_Max77812_GPUVOLT_REG = 0x23,
I2c_Max77812_MEMVOLT_REG = 0x25, // Master 3 (GPU 1 + 2, DRAM 3, CPU 4), used for Mariko VDDQ
} I2c_BuckConverter_Reg;
typedef struct I2c_BuckConverter_Domain {
I2cDevice device;
I2c_BuckConverter_Reg reg;
u8 volt_mask;
u32 uv_step;
u32 uv_min;
u32 uv_max;
u8 por_val;
} I2c_BuckConverter_Domain;
const I2c_BuckConverter_Domain I2c_Erista_CPU = { I2cDevice_Max77621Cpu, I2c_Max77621_VOLT_REG, 0x7F, 6250, 606250, 1400000, };
const I2c_BuckConverter_Domain I2c_Erista_GPU = { I2cDevice_Max77621Gpu, I2c_Max77621_VOLT_REG, 0x7F, 6250, 606250, 1400000, };
const I2c_BuckConverter_Domain I2c_Erista_DRAM = { I2cDevice_Max77620Pmic, I2c_Max77620_SD1VOLT_REG, 0x7F, 12500, 600000, 1250000, };
const I2c_BuckConverter_Domain I2c_Mariko_CPU = { I2cDevice_Max77812_2, I2c_Max77812_CPUVOLT_REG, 0xFF, 5000, 250000, 1525000, 0x78 };
const I2c_BuckConverter_Domain I2c_Mariko_GPU = { I2cDevice_Max77812_2, I2c_Max77812_GPUVOLT_REG, 0xFF, 5000, 250000, 1525000, 0x78 };
const I2c_BuckConverter_Domain I2c_Mariko_DRAM_VDDQ = { I2cDevice_Max77812_2, I2c_Max77812_MEMVOLT_REG, 0xFF, 5000, 250000, 700000, 0x78 };
const I2c_BuckConverter_Domain I2c_Mariko_DRAM_VDD2 = { I2cDevice_Max77620Pmic, I2c_Max77620_SD1VOLT_REG, 0x7F, 12500, 600000, 1250000, };
u32 I2c_BuckConverter_GetMvOut(const I2c_BuckConverter_Domain* domain);
Result I2c_BuckConverter_SetMvOut(const I2c_BuckConverter_Domain* domain, u32 mvolt);
// Bq24193 Battery management
u32 I2c_Bq24193_Convert_Raw_mA(u8 raw);
u8 I2c_Bq24193_Convert_mA_Raw(u32 ma);
Result I2c_Bq24193_GetFastChargeCurrentLimit(u32 *ma);
Result I2c_Bq24193_SetFastChargeCurrentLimit(u32 ma);
const u32 MA_RANGE_MIN = 512;
const u32 MA_RANGE_MAX = 4544;
const u8 BQ24193_CHARGE_CURRENT_CONTROL_REG = 0x2;

View File

@@ -0,0 +1,756 @@
/**
* @file ipc.h
* @brief Inter-process communication handling
* @author plutoo
* @copyright libnx Authors (ISC License)
*/
#pragma once
#include <switch.h>
/// IPC input header magic
#define SFCI_MAGIC 0x49434653
/// IPC output header magic
#define SFCO_MAGIC 0x4f434653
/// IPC invalid object ID
#define IPC_INVALID_OBJECT_ID UINT32_MAX
///@name IPC request building
///@{
/// IPC command (request) structure.
#define IPC_MAX_BUFFERS 8
#define IPC_MAX_OBJECTS 8
typedef enum {
BufferType_Normal=0, ///< Regular buffer.
BufferType_Type1=1, ///< Allows ProcessMemory and shared TransferMemory.
BufferType_Invalid=2,
BufferType_Type3=3 ///< Same as Type1 except remote process is not allowed to use device-mapping.
} BufferType;
typedef enum {
BufferDirection_Send=0,
BufferDirection_Recv=1,
BufferDirection_Exch=2,
} BufferDirection;
typedef enum {
IpcCommandType_Invalid = 0,
IpcCommandType_LegacyRequest = 1,
IpcCommandType_Close = 2,
IpcCommandType_LegacyControl = 3,
IpcCommandType_Request = 4,
IpcCommandType_Control = 5,
IpcCommandType_RequestWithContext = 6,
IpcCommandType_ControlWithContext = 7,
} IpcCommandType;
typedef enum {
DomainMessageType_Invalid = 0,
DomainMessageType_SendMessage = 1,
DomainMessageType_Close = 2,
} DomainMessageType;
/// IPC domain message header.
typedef struct {
u8 Type;
u8 NumObjectIds;
u16 Length;
u32 ThisObjectId;
u32 Pad[2];
} DomainMessageHeader;
/// IPC domain response header.
typedef struct {
u32 NumObjectIds;
u32 Pad[3];
} DomainResponseHeader;
typedef struct {
size_t NumSend; // A
size_t NumRecv; // B
size_t NumExch; // W
const void* Buffers[IPC_MAX_BUFFERS];
size_t BufferSizes[IPC_MAX_BUFFERS];
BufferType BufferTypes[IPC_MAX_BUFFERS];
size_t NumStaticIn; // X
size_t NumStaticOut; // C
const void* Statics[IPC_MAX_BUFFERS];
size_t StaticSizes[IPC_MAX_BUFFERS];
u8 StaticIndices[IPC_MAX_BUFFERS];
bool SendPid;
size_t NumHandlesCopy;
size_t NumHandlesMove;
Handle Handles[IPC_MAX_OBJECTS];
size_t NumObjectIds;
u32 ObjectIds[IPC_MAX_OBJECTS];
} IpcCommand;
/**
* @brief Initializes an IPC command structure.
* @param cmd IPC command structure.
*/
static inline void ipcInitialize(IpcCommand* cmd) {
*cmd = (IpcCommand){};
}
/// IPC buffer descriptor.
typedef struct {
u32 Size; ///< Size of the buffer.
u32 Addr; ///< Lower 32-bits of the address of the buffer
u32 Packed; ///< Packed data (including higher bits of the address)
} IpcBufferDescriptor;
/// IPC static send-buffer descriptor.
typedef struct {
u32 Packed; ///< Packed data (including higher bits of the address)
u32 Addr; ///< Lower 32-bits of the address
} IpcStaticSendDescriptor;
/// IPC static receive-buffer descriptor.
typedef struct {
u32 Addr; ///< Lower 32-bits of the address of the buffer
u32 Packed; ///< Packed data (including higher bits of the address)
} IpcStaticRecvDescriptor;
/**
* @brief Adds a buffer to an IPC command structure.
* @param cmd IPC command structure.
* @param buffer Address of the buffer.
* @param size Size of the buffer.
* @param type Buffer type.
*/
static inline void ipcAddSendBuffer(IpcCommand* cmd, const void* buffer, size_t size, BufferType type) {
size_t off = cmd->NumSend;
cmd->Buffers[off] = buffer;
cmd->BufferSizes[off] = size;
cmd->BufferTypes[off] = type;
cmd->NumSend++;
}
/**
* @brief Adds a receive-buffer to an IPC command structure.
* @param cmd IPC command structure.
* @param buffer Address of the buffer.
* @param size Size of the buffer.
* @param type Buffer type.
*/
static inline void ipcAddRecvBuffer(IpcCommand* cmd, void* buffer, size_t size, BufferType type) {
size_t off = cmd->NumSend + cmd->NumRecv;
cmd->Buffers[off] = buffer;
cmd->BufferSizes[off] = size;
cmd->BufferTypes[off] = type;
cmd->NumRecv++;
}
/**
* @brief Adds an exchange-buffer to an IPC command structure.
* @param cmd IPC command structure.
* @param buffer Address of the buffer.
* @param size Size of the buffer.
* @param type Buffer type.
*/
static inline void ipcAddExchBuffer(IpcCommand* cmd, void* buffer, size_t size, BufferType type) {
size_t off = cmd->NumSend + cmd->NumRecv + cmd->NumExch;
cmd->Buffers[off] = buffer;
cmd->BufferSizes[off] = size;
cmd->BufferTypes[off] = type;
cmd->NumExch++;
}
/**
* @brief Adds a static-buffer to an IPC command structure.
* @param cmd IPC command structure.
* @param buffer Address of the buffer.
* @param size Size of the buffer.
* @param index Index of buffer.
*/
static inline void ipcAddSendStatic(IpcCommand* cmd, const void* buffer, size_t size, u8 index) {
size_t off = cmd->NumStaticIn;
cmd->Statics[off] = buffer;
cmd->StaticSizes[off] = size;
cmd->StaticIndices[off] = index;
cmd->NumStaticIn++;
}
/**
* @brief Adds a static-receive-buffer to an IPC command structure.
* @param cmd IPC command structure.
* @param buffer Address of the buffer.
* @param size Size of the buffer.
* @param index Index of buffer.
*/
static inline void ipcAddRecvStatic(IpcCommand* cmd, void* buffer, size_t size, u8 index) {
size_t off = cmd->NumStaticIn + cmd->NumStaticOut;
cmd->Statics[off] = buffer;
cmd->StaticSizes[off] = size;
cmd->StaticIndices[off] = index;
cmd->NumStaticOut++;
}
/**
* @brief Adds a smart-buffer (buffer + static-buffer pair) to an IPC command structure.
* @param cmd IPC command structure.
* @param pointer_buffer_size Pointer buffer size.
* @param buffer Address of the buffer.
* @param size Size of the buffer.
* @param index Index of buffer.
*/
static inline void ipcAddSendSmart(IpcCommand* cmd, size_t pointer_buffer_size, const void* buffer, size_t size, u8 index) {
if (pointer_buffer_size != 0 && size <= pointer_buffer_size) {
ipcAddSendBuffer(cmd, NULL, 0, BufferType_Normal);
ipcAddSendStatic(cmd, buffer, size, index);
} else {
ipcAddSendBuffer(cmd, buffer, size, BufferType_Normal);
ipcAddSendStatic(cmd, NULL, 0, index);
}
}
/**
* @brief Adds a smart-receive-buffer (buffer + static-receive-buffer pair) to an IPC command structure.
* @param cmd IPC command structure.
* @param pointer_buffer_size Pointer buffer size.
* @param buffer Address of the buffer.
* @param size Size of the buffer.
* @param index Index of buffer.
*/
static inline void ipcAddRecvSmart(IpcCommand* cmd, size_t pointer_buffer_size, void* buffer, size_t size, u8 index) {
if (pointer_buffer_size != 0 && size <= pointer_buffer_size) {
ipcAddRecvBuffer(cmd, NULL, 0, BufferType_Normal);
ipcAddRecvStatic(cmd, buffer, size, index);
} else {
ipcAddRecvBuffer(cmd, buffer, size, BufferType_Normal);
ipcAddRecvStatic(cmd, NULL, 0, index);
}
}
/**
* @brief Tags an IPC command structure to send the PID.
* @param cmd IPC command structure.
*/
static inline void ipcSendPid(IpcCommand* cmd) {
cmd->SendPid = true;
}
/**
* @brief Adds a copy-handle to be sent through an IPC command structure.
* @param cmd IPC command structure.
* @param h Handle to send.
* @remark The receiving process gets a copy of the handle.
*/
static inline void ipcSendHandleCopy(IpcCommand* cmd, Handle h) {
cmd->Handles[cmd->NumHandlesCopy++] = h;
}
/**
* @brief Adds a move-handle to be sent through an IPC command structure.
* @param cmd IPC command structure.
* @param h Handle to send.
* @remark The sending process loses ownership of the handle, which is transferred to the receiving process.
*/
static inline void ipcSendHandleMove(IpcCommand* cmd, Handle h) {
cmd->Handles[cmd->NumHandlesCopy + cmd->NumHandlesMove++] = h;
}
/**
* @brief Prepares the header of an IPC command structure.
* @param cmd IPC command structure.
* @param sizeof_raw Size in bytes of the raw data structure to embed inside the IPC request
* @return Pointer to the raw embedded data structure in the request, ready to be filled out.
*/
static inline void* ipcPrepareHeader(IpcCommand* cmd, size_t sizeof_raw) {
u32* buf = (u32*)armGetTls();
size_t i;
*buf++ = IpcCommandType_Request | (cmd->NumStaticIn << 16) | (cmd->NumSend << 20) | (cmd->NumRecv << 24) | (cmd->NumExch << 28);
u32* fill_in_size_later = buf;
if (cmd->NumStaticOut > 0) {
*buf = (cmd->NumStaticOut + 2) << 10;
}
else {
*buf = 0;
}
if (cmd->SendPid || cmd->NumHandlesCopy > 0 || cmd->NumHandlesMove > 0) {
*buf++ |= 0x80000000;
*buf++ = (!!cmd->SendPid) | (cmd->NumHandlesCopy << 1) | (cmd->NumHandlesMove << 5);
if (cmd->SendPid)
buf += 2;
for (i=0; i<(cmd->NumHandlesCopy + cmd->NumHandlesMove); i++)
*buf++ = cmd->Handles[i];
}
else {
buf++;
}
for (i=0; i<cmd->NumStaticIn; i++, buf+=2) {
IpcStaticSendDescriptor* desc = (IpcStaticSendDescriptor*) buf;
uintptr_t ptr = (uintptr_t) cmd->Statics[i];
desc->Addr = ptr;
desc->Packed = cmd->StaticIndices[i] | (cmd->StaticSizes[i] << 16) |
(((ptr >> 32) & 15) << 12) | (((ptr >> 36) & 15) << 6);
}
for (i=0; i<(cmd->NumSend + cmd->NumRecv + cmd->NumExch); i++, buf+=3) {
IpcBufferDescriptor* desc = (IpcBufferDescriptor*) buf;
desc->Size = cmd->BufferSizes[i];
uintptr_t ptr = (uintptr_t) cmd->Buffers[i];
desc->Addr = ptr;
desc->Packed = cmd->BufferTypes[i] |
(((ptr >> 32) & 15) << 28) | ((ptr >> 36) << 2);
}
u32 padding = ((16 - (((uintptr_t) buf) & 15)) & 15) / 4;
u32* raw = (u32*) (buf + padding);
size_t raw_size = (sizeof_raw/4) + 4;
buf += raw_size;
u16* buf_u16 = (u16*) buf;
for (i=0; i<cmd->NumStaticOut; i++) {
size_t off = cmd->NumStaticIn + i;
size_t sz = (uintptr_t) cmd->StaticSizes[off];
buf_u16[i] = (sz > 0xFFFF) ? 0 : sz;
}
size_t u16s_size = ((2*cmd->NumStaticOut) + 3)/4;
buf += u16s_size;
raw_size += u16s_size;
*fill_in_size_later |= raw_size;
for (i=0; i<cmd->NumStaticOut; i++, buf+=2) {
IpcStaticRecvDescriptor* desc = (IpcStaticRecvDescriptor*) buf;
size_t off = cmd->NumStaticIn + i;
uintptr_t ptr = (uintptr_t) cmd->Statics[off];
desc->Addr = ptr;
desc->Packed = (ptr >> 32) | (cmd->StaticSizes[off] << 16);
}
return (void*) raw;
}
/**
* @brief Dispatches an IPC request.
* @param session IPC session handle.
* @return Result code.
*/
static inline Result ipcDispatch(Handle session) {
return svcSendSyncRequest(session);
}
///@}
///@name IPC response parsing
///@{
/// IPC parsed command (response) structure.
typedef struct {
IpcCommandType CommandType; ///< Type of the command
bool HasPid; ///< true if the 'Pid' field is filled out.
u64 Pid; ///< PID included in the response (only if HasPid is true)
size_t NumHandles; ///< Number of handles copied.
Handle Handles[IPC_MAX_OBJECTS]; ///< Handles.
bool WasHandleCopied[IPC_MAX_OBJECTS]; ///< true if the handle was moved, false if it was copied.
bool IsDomainRequest; ///< true if the the message is a Domain message.
DomainMessageType InMessageType; ///< Type of the domain message.
u32 InMessageLength; ///< Size of rawdata (for domain messages).
u32 InThisObjectId; ///< Object ID to call the command on (for domain messages).
size_t InNumObjectIds; ///< Number of object IDs (for domain messages).
u32 InObjectIds[IPC_MAX_OBJECTS]; ///< Object IDs (for domain messages).
bool IsDomainResponse; ///< true if the the message is a Domain response.
size_t OutNumObjectIds; ///< Number of object IDs (for domain responses).
u32 OutObjectIds[IPC_MAX_OBJECTS]; ///< Object IDs (for domain responses).
size_t NumBuffers; ///< Number of buffers in the response.
void* Buffers[IPC_MAX_BUFFERS]; ///< Pointers to the buffers.
size_t BufferSizes[IPC_MAX_BUFFERS]; ///< Sizes of the buffers.
BufferType BufferTypes[IPC_MAX_BUFFERS]; ///< Types of the buffers.
BufferDirection BufferDirections[IPC_MAX_BUFFERS]; ///< Direction of each buffer.
size_t NumStatics; ///< Number of statics in the response.
void* Statics[IPC_MAX_BUFFERS]; ///< Pointers to the statics.
size_t StaticSizes[IPC_MAX_BUFFERS]; ///< Sizes of the statics.
u8 StaticIndices[IPC_MAX_BUFFERS]; ///< Indices of the statics.
size_t NumStaticsOut; ///< Number of output statics available in the response.
void* Raw; ///< Pointer to the raw embedded data structure in the response.
void* RawWithoutPadding; ///< Pointer to the raw embedded data structure, without padding.
size_t RawSize; ///< Size of the raw embedded data.
} IpcParsedCommand;
/**
* @brief Parse an IPC command response into an IPC parsed command structure.
* @param r IPC parsed command structure to fill in.
* @return Result code.
*/
static inline Result ipcParse(IpcParsedCommand* r) {
u32* buf = (u32*)armGetTls();
u32 ctrl0 = *buf++;
u32 ctrl1 = *buf++;
size_t i;
r->IsDomainRequest = false;
r->IsDomainResponse = false;
r->CommandType = (IpcCommandType) (ctrl0 & 0xffff);
r->HasPid = false;
r->RawSize = (ctrl1 & 0x1ff) * 4;
r->NumHandles = 0;
r->NumStaticsOut = (ctrl1 >> 10) & 15;
if (r->NumStaticsOut >> 1) r->NumStaticsOut--; // Value 2 -> Single descriptor
if (r->NumStaticsOut >> 1) r->NumStaticsOut--; // Value 3+ -> (Value - 2) descriptors
if (ctrl1 & 0x80000000) {
u32 ctrl2 = *buf++;
if (ctrl2 & 1) {
r->HasPid = true;
r->Pid = *buf++;
r->Pid |= ((u64)(*buf++)) << 32;
}
size_t num_handles_copy = ((ctrl2 >> 1) & 15);
size_t num_handles_move = ((ctrl2 >> 5) & 15);
size_t num_handles = num_handles_copy + num_handles_move;
u32* buf_after_handles = buf + num_handles;
if (num_handles > IPC_MAX_OBJECTS)
num_handles = IPC_MAX_OBJECTS;
for (i=0; i<num_handles; i++)
{
r->Handles[i] = *(buf+i);
r->WasHandleCopied[i] = (i < num_handles_copy);
}
r->NumHandles = num_handles;
buf = buf_after_handles;
}
size_t num_statics = (ctrl0 >> 16) & 15;
u32* buf_after_statics = buf + num_statics*2;
if (num_statics > IPC_MAX_BUFFERS)
num_statics = IPC_MAX_BUFFERS;
for (i=0; i<num_statics; i++, buf+=2) {
IpcStaticSendDescriptor* desc = (IpcStaticSendDescriptor*) buf;
u64 packed = (u64) desc->Packed;
r->Statics[i] = (void*) (desc->Addr | (((packed >> 12) & 15) << 32) | (((packed >> 6) & 15) << 36));
r->StaticSizes[i] = packed >> 16;
r->StaticIndices[i] = packed & 63;
}
r->NumStatics = num_statics;
buf = buf_after_statics;
size_t num_bufs_send = (ctrl0 >> 20) & 15;
size_t num_bufs_recv = (ctrl0 >> 24) & 15;
size_t num_bufs_exch = (ctrl0 >> 28) & 15;
size_t num_bufs = num_bufs_send + num_bufs_recv + num_bufs_exch;
r->Raw = (void*)(((uintptr_t)(buf + num_bufs*3) + 15) &~ 15);
r->RawWithoutPadding = (void*)((uintptr_t)(buf + num_bufs*3));
if (num_bufs > IPC_MAX_BUFFERS)
num_bufs = IPC_MAX_BUFFERS;
for (i=0; i<num_bufs; i++, buf+=3) {
IpcBufferDescriptor* desc = (IpcBufferDescriptor*) buf;
u64 packed = (u64) desc->Packed;
r->Buffers[i] = (void*) (desc->Addr | ((packed >> 28) << 32) | (((packed >> 2) & 15) << 36));
r->BufferSizes[i] = desc->Size;
r->BufferTypes[i] = (BufferType) (packed & 3);
if (i < num_bufs_send)
r->BufferDirections[i] = BufferDirection_Send;
else if (i < (num_bufs_send + num_bufs_recv))
r->BufferDirections[i] = BufferDirection_Recv;
else
r->BufferDirections[i] = BufferDirection_Exch;
}
r->NumBuffers = num_bufs;
return 0;
}
/**
* @brief Queries the size of an IPC pointer buffer.
* @param session IPC session handle.
* @param size Output variable in which to store the size.
* @return Result code.
*/
static inline Result ipcQueryPointerBufferSize(Handle session, size_t *size) {
u32* buf = (u32*)armGetTls();
buf[0] = IpcCommandType_Control;
buf[1] = 8;
buf[2] = 0;
buf[3] = 0;
buf[4] = SFCI_MAGIC;
buf[5] = 0;
buf[6] = 3;
buf[7] = 0;
Result rc = ipcDispatch(session);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct ipcQueryPointerBufferSizeResponse {
u64 magic;
u64 result;
u32 size;
} *raw = (struct ipcQueryPointerBufferSizeResponse*)r.Raw;
rc = raw->result;
if (R_SUCCEEDED(rc)) {
*size = raw->size & 0xffff;
}
}
return rc;
}
/**
* @brief Closes the IPC session with proper clean up.
* @param session IPC session handle.
* @return Result code.
*/
static inline Result ipcCloseSession(Handle session) {
u32* buf = (u32*)armGetTls();
buf[0] = IpcCommandType_Close;
buf[1] = 0;
return ipcDispatch(session);
}
/**
* @brief Clones an IPC session.
* @param session IPC session handle.
* @param unk Unknown.
* @param new_session_out Output cloned IPC session handle.
* @return Result code.
*/
static inline Result ipcCloneSession(Handle session, u32 unk, Handle* new_session_out) {
u32* buf = (u32*)armGetTls();
buf[0] = IpcCommandType_Control;
buf[1] = 9;
buf[2] = 0;
buf[3] = 0;
buf[4] = SFCI_MAGIC;
buf[5] = 0;
buf[6] = 4;
buf[7] = 0;
buf[8] = unk;
Result rc = ipcDispatch(session);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct ipcCloneSessionResponse {
u64 magic;
u64 result;
} *raw = (struct ipcCloneSessionResponse*)r.Raw;
rc = raw->result;
if (R_SUCCEEDED(rc) && new_session_out) {
*new_session_out = r.Handles[0];
}
}
return rc;
}
///@}
///@name IPC domain handling
///@{
/**
* @brief Converts an IPC session handle into a domain.
* @param session IPC session handle.
* @param object_id_out Output variable in which to store the object ID.
* @return Result code.
*/
static inline Result ipcConvertSessionToDomain(Handle session, u32* object_id_out) {
u32* buf = (u32*)armGetTls();
buf[0] = IpcCommandType_Control;
buf[1] = 8;
buf[4] = SFCI_MAGIC;
buf[5] = 0;
buf[6] = 0;
buf[7] = 0;
Result rc = ipcDispatch(session);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct ipcConvertSessionToDomainResponse {
u64 magic;
u64 result;
u32 object_id;
} *raw = (struct ipcConvertSessionToDomainResponse*)r.Raw;
rc = raw->result;
if (R_SUCCEEDED(rc)) {
*object_id_out = raw->object_id;
}
}
return rc;
}
/**
* @brief Adds an object ID to be sent through an IPC domain command structure.
* @param cmd IPC domain command structure.
* @param object_id Object ID to send.
*/
static inline void ipcSendObjectId(IpcCommand* cmd, u32 object_id) {
cmd->ObjectIds[cmd->NumObjectIds++] = object_id;
}
/**
* @brief Prepares the header of an IPC command structure (domain version).
* @param cmd IPC command structure.
* @param sizeof_raw Size in bytes of the raw data structure to embed inside the IPC request
* @param object_id Domain object ID.
* @return Pointer to the raw embedded data structure in the request, ready to be filled out.
*/
static inline void* ipcPrepareHeaderForDomain(IpcCommand* cmd, size_t sizeof_raw, u32 object_id) {
void* raw = ipcPrepareHeader(cmd, sizeof_raw + sizeof(DomainMessageHeader) + cmd->NumObjectIds*sizeof(u32));
DomainMessageHeader* hdr = (DomainMessageHeader*) raw;
u32 *object_ids = (u32*)(((uintptr_t) raw) + sizeof(DomainMessageHeader) + sizeof_raw);
hdr->Type = DomainMessageType_SendMessage;
hdr->NumObjectIds = (u8)cmd->NumObjectIds;
hdr->Length = sizeof_raw;
hdr->ThisObjectId = object_id;
hdr->Pad[0] = hdr->Pad[1] = 0;
for(size_t i = 0; i < cmd->NumObjectIds; i++)
object_ids[i] = cmd->ObjectIds[i];
return (void*)(((uintptr_t) raw) + sizeof(DomainMessageHeader));
}
/**
* @brief Parse an IPC command request into an IPC parsed command structure (domain version).
* @param r IPC parsed command structure to fill in.
* @return Result code.
*/
static inline Result ipcParseDomainRequest(IpcParsedCommand* r) {
Result rc = ipcParse(r);
DomainMessageHeader *hdr;
u32 *object_ids;
if(R_FAILED(rc))
return rc;
hdr = (DomainMessageHeader*) r->Raw;
object_ids = (u32*)(((uintptr_t) hdr) + sizeof(DomainMessageHeader) + hdr->Length);
r->Raw = (void*)(((uintptr_t) r->Raw) + sizeof(DomainMessageHeader));
r->IsDomainRequest = true;
r->InMessageType = (DomainMessageType)(hdr->Type);
switch (r->InMessageType) {
case DomainMessageType_SendMessage:
case DomainMessageType_Close:
break;
default:
return MAKERESULT(Module_Libnx, LibnxError_DomainMessageUnknownType);
}
r->InThisObjectId = hdr->ThisObjectId;
r->InNumObjectIds = hdr->NumObjectIds > 8 ? 8 : hdr->NumObjectIds;
if ((uintptr_t)object_ids + sizeof(u32) * r->InNumObjectIds - (uintptr_t)armGetTls() >= 0x100) {
return MAKERESULT(Module_Libnx, LibnxError_DomainMessageTooManyObjectIds);
}
for(size_t i = 0; i < r->InNumObjectIds; i++)
r->InObjectIds[i] = object_ids[i];
return rc;
}
/**
* @brief Parse an IPC command response into an IPC parsed command structure (domain version).
* @param r IPC parsed command structure to fill in.
* @param sizeof_raw Size in bytes of the raw data structure.
* @return Result code.
*/
static inline Result ipcParseDomainResponse(IpcParsedCommand* r, size_t sizeof_raw) {
Result rc = ipcParse(r);
DomainResponseHeader *hdr;
u32 *object_ids;
if(R_FAILED(rc))
return rc;
hdr = (DomainResponseHeader*) r->Raw;
r->Raw = (void*)(((uintptr_t) r->Raw) + sizeof(DomainResponseHeader));
object_ids = (u32*)(((uintptr_t) r->Raw) + sizeof_raw);//Official sw doesn't align this.
r->IsDomainResponse = true;
r->OutNumObjectIds = hdr->NumObjectIds > 8 ? 8 : hdr->NumObjectIds;
if ((uintptr_t)object_ids + sizeof(u32) * r->OutNumObjectIds - (uintptr_t)armGetTls() >= 0x100) {
return MAKERESULT(Module_Libnx, LibnxError_DomainMessageTooManyObjectIds);
}
for(size_t i = 0; i < r->OutNumObjectIds; i++)
r->OutObjectIds[i] = object_ids[i];
return rc;
}
/**
* @brief Closes a domain object by ID.
* @param session IPC session handle.
* @param object_id ID of the object to close.
* @return Result code.
*/
static inline Result ipcCloseObjectById(Handle session, u32 object_id) {
IpcCommand c;
DomainMessageHeader* hdr;
ipcInitialize(&c);
hdr = (DomainMessageHeader*)ipcPrepareHeader(&c, sizeof(DomainMessageHeader));
hdr->Type = DomainMessageType_Close;
hdr->NumObjectIds = 0;
hdr->Length = 0;
hdr->ThisObjectId = object_id;
hdr->Pad[0] = hdr->Pad[1] = 0;
return ipcDispatch(session); // this command has no associated response
}
///@}

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

@@ -0,0 +1,44 @@
/*
* Copyright (c) ppkantorski (bord2death)
*
* 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 <string>
#include <ctime>
#include <cstdio>
static void writeNotification(const std::string& message) {
static const char* flagPath = "sdmc:/config/ultrahand/flags/NOTIFICATIONS.flag";
FILE* flagFile = fopen(flagPath, "r");
if (!flagFile) {
return;
}
fclose(flagFile);
std::string filename = "Horizon OC -" + std::to_string(std::time(nullptr)) + ".notify";
std::string fullPath = "sdmc:/config/ultrahand/notifications/" + filename;
FILE* file = fopen(fullPath.c_str(), "w");
if (file) {
fprintf(file, "{\n");
fprintf(file, " \"text\": \"%s\",\n", message.c_str());
fprintf(file, " \"fontSize\": 28\n");
fprintf(file, "}\n");
fclose(file);
}
}

View File

@@ -0,0 +1,113 @@
/*
* Copyright (c) ppkantorski (bord2death)
*
* 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
/*
* SDx actual min is 625 mV. Multipliers 0/1 reserved.
* SD0 max is 1400 mV
* SD1 max is 1550 mV
* SD2 max is 3787.5 mV
* SD3 max is 3787.5 mV
*/
/*
* Switch Power domains (max77620):
* Name | Usage | uV step | uV min | uV default | uV max | Init
*-------+---------------+---------+--------+------------+---------+------------------
* sd0 | SoC | 12500 | 600000 | 625000 | 1400000 | 1.125V (pkg1.1)
* sd1 | SDRAM | 12500 | 600000 | 1125000 | 1125000 | 1.1V (pkg1.1)
* sd2 | ldo{0-1, 7-8} | 12500 | 600000 | 1325000 | 1350000 | 1.325V (pcv)
* sd3 | 1.8V general | 12500 | 600000 | 1800000 | 1800000 |
* ldo0 | Display Panel | 25000 | 800000 | 1200000 | 1200000 | 1.2V (pkg1.1)
* ldo1 | XUSB, PCIE | 25000 | 800000 | 1050000 | 1050000 | 1.05V (pcv)
* ldo2 | SDMMC1 | 50000 | 800000 | 1800000 | 3300000 |
* ldo3 | GC ASIC | 50000 | 800000 | 3100000 | 3100000 | 3.1V (pcv)
* ldo4 | RTC | 12500 | 800000 | 850000 | 850000 | 0.85V (AO, pcv)
* ldo5 | GC Card | 50000 | 800000 | 1800000 | 1800000 | 1.8V (pcv)
* ldo6 | Touch, ALS | 50000 | 800000 | 2900000 | 2900000 | 2.9V (pcv)
* ldo7 | XUSB | 50000 | 800000 | 1050000 | 1050000 | 1.05V (pcv)
* ldo8 | XUSB, DP, MCU | 50000 | 800000 | 1050000 | 2800000 | 1.05V/2.8V (pcv)
*/
// GPIOs T210: 3: 3.3V, 5: CPU PMIC, 6: GPU PMIC, 7: DSI/VI 1.2V powered by ldo0.
/*
* OTP: T210 - T210B01:
* SD0: 1.0V 1.05V - SoC. EN Based on FPSSRC.
* SD1: 1.15V 1.1V - DRAM for T210. EN Based on FPSSRC.
* SD2: 1.35V 1.35V
* SD3: 1.8V 1.8V
* All powered off?
* LDO0: -- -- - Display
* LDO1: 1.05V 1.05V
* LDO2: -- -- - SD
* LDO3: 3.1V 3.1V - GC ASIC
* LDO4: 1.0V 0.8V - Needed for RTC domain on T210.
* LDO5: 3.1V 3.1V
* LDO6: 2.8V 2.9V - Touch.
* LDO7: 1.05V 1.0V
* LDO8: 1.05V 1.0V
*/
/*
* MAX77620_AME_GPIO: control GPIO modes (bits 0 - 7 correspond to GPIO0 - GPIO7); 0 -> GPIO, 1 -> alt-mode
* MAX77620_REG_GPIOx: 0x9 sets output and enable
*/
typedef enum {
PcvPowerDomain_Max77620_Sd0 = 0,
PcvPowerDomain_Max77620_Sd1 = 1,
PcvPowerDomain_Max77620_Sd2 = 2,
PcvPowerDomain_Max77620_Sd3 = 3,
PcvPowerDomain_Max77620_Ldo0 = 4,
PcvPowerDomain_Max77620_Ldo1 = 5,
PcvPowerDomain_Max77620_Ldo2 = 6,
PcvPowerDomain_Max77620_Ldo3 = 7,
PcvPowerDomain_Max77620_Ldo4 = 8,
PcvPowerDomain_Max77620_Ldo5 = 9,
PcvPowerDomain_Max77620_Ldo6 = 10,
PcvPowerDomain_Max77620_Ldo7 = 11,
PcvPowerDomain_Max77620_Ldo8 = 12,
PcvPowerDomain_Max77621_Cpu = 13,
PcvPowerDomain_Max77621_Gpu = 14,
PcvPowerDomain_Max77812_Cpu = 15,
PcvPowerDomain_Max77812_Gpu = 16,
PcvPowerDomain_Max77812_Dram = 17,
} PowerDomain;
typedef enum {
PcvPowerDomainId_Max77620_Sd0 = 0x3A000080,
PcvPowerDomainId_Max77620_Sd1 = 0x3A000081, // vdd2
PcvPowerDomainId_Max77620_Sd2 = 0x3A000082,
PcvPowerDomainId_Max77620_Sd3 = 0x3A000083,
PcvPowerDomainId_Max77620_Ldo0 = 0x3A0000A0,
PcvPowerDomainId_Max77620_Ldo1 = 0x3A0000A1,
PcvPowerDomainId_Max77620_Ldo2 = 0x3A0000A2,
PcvPowerDomainId_Max77620_Ldo3 = 0x3A0000A3,
PcvPowerDomainId_Max77620_Ldo4 = 0x3A0000A4,
PcvPowerDomainId_Max77620_Ldo5 = 0x3A0000A5,
PcvPowerDomainId_Max77620_Ldo6 = 0x3A0000A6,
PcvPowerDomainId_Max77620_Ldo7 = 0x3A0000A7,
PcvPowerDomainId_Max77620_Ldo8 = 0x3A0000A8,
PcvPowerDomainId_Max77621_Cpu = 0x3A000003,
PcvPowerDomainId_Max77621_Gpu = 0x3A000004,
PcvPowerDomainId_Max77812_Cpu = 0x3A000003,
PcvPowerDomainId_Max77812_Gpu = 0x3A000004,
PcvPowerDomainId_Max77812_Dram = 0x3A000005, // vddq
} PowerDomainId;

View File

@@ -0,0 +1,39 @@
/*
* Copyright (c) MasaGratoR
*
* 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 <switch.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
Service s;
} PwmChannelSession;
Result pwmInitialize(void);
void pwmExit(void);
Service* pwmGetServiceSession(void);
Result pwmOpenSession2(PwmChannelSession *out, u32 device_code);
Result pwmChannelSessionGetDutyCycle(PwmChannelSession *c, double* out);
void pwmChannelSessionClose(PwmChannelSession *c);
#ifdef __cplusplus
} // extern "C"
#endif

View File

@@ -0,0 +1,527 @@
/*
* Copyright (c) Souldbminer, Lightos_ and Horizon OC Contributors
*
* Copyright (c) Linux 4 Tegra & Linux 4 Switch 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
#define EMC_INTSTATUS_0 0x0
#define EMC_INTMASK_0 0x4
#define EMC_DBG_0 0x8
#define EMC_CFG_0 0xC
#define EMC_ADR_CFG_0 0x10
#define EMC_REFCTRL_0 0x20
#define EMC_PIN_0 0x24
#define EMC_TIMING_CONTROL_0 0x28
#define EMC_RC_0 0x2C
#define EMC_RFC_0 0x30
#define EMC_RAS_0 0x34
#define EMC_RP_0 0x38
#define EMC_R2W_0 0x3C
#define EMC_W2R_0 0x40
#define EMC_R2P_0 0x44
#define EMC_W2P_0 0x48
#define EMC_RD_RCD_0 0x4C
#define EMC_WR_RCD_0 0x50
#define EMC_RRD_0 0x54
#define EMC_REXT_0 0x58
#define EMC_WDV_0 0x5C
#define EMC_QUSE_0 0x60
#define EMC_QRST_0 0x64
#define EMC_QSAFE_0 0x68
#define EMC_RDV_0 0x6C
#define EMC_REFRESH_0 0x70
#define EMC_BURST_REFRESH_NUM_0 0x74
#define EMC_PDEX2WR_0 0x78
#define EMC_PDEX2RD_0 0x7C
#define EMC_PCHG2PDEN_0 0x80
#define EMC_ACT2PDEN_0 0x84
#define EMC_AR2PDEN_0 0x88
#define EMC_RW2PDEN_0 0x8C
#define EMC_TXSR_0 0x90
#define EMC_TCKE_0 0x94
#define EMC_TFAW_0 0x98
#define EMC_TRPAB_0 0x9C
#define EMC_TCLKSTABLE_0 0xA0
#define EMC_TCLKSTOP_0 0xA4
#define EMC_TREFBW_0 0xA8
#define EMC_TPPD_0 0xAC
#define EMC_ODT_WRITE_0 0xB0
#define EMC_PDEX2MRR_0 0xB4
#define EMC_WEXT_0 0xB8
#define EMC_RFC_SLR_0 0xC0
#define EMC_MRS_WAIT_CNT2_0 0xC4
#define EMC_MRS_WAIT_CNT_0 0xC8
#define EMC_MRS_0 0xCC
#define EMC_EMRS_0 0xD0
#define EMC_REF_0 0xD4
#define EMC_PRE_0 0xD8
#define EMC_NOP_0 0xDC
#define EMC_SELF_REF_0 0xE0
#define EMC_DPD_0 0xE4
#define EMC_MRW_0 0xE8
#define EMC_MRR_0 0xEC
#define EMC_CMDQ_0 0xF0
#define EMC_MC2EMCQ_0 0xF4
#define EMC_FBIO_SPARE_0 0x100
#define EMC_FBIO_CFG5_0 0x104
#define EMC_FBIO_CFG6_0 0x114
#define EMC_PDEX2CKE_0 0x118
#define EMC_CKE2PDEN_0 0x11C
#define EMC_CFG_RSV_0 0x120
#define EMC_ACPD_CONTROL_0 0x124
#define EMC_MPC_0 0x128
#define EMC_EMRS2_0 0x12C
#define EMC_EMRS3_0 0x130
#define EMC_MRW2_0 0x134
#define EMC_MRW3_0 0x138
#define EMC_MRW4_0 0x13C
#define EMC_CLKEN_OVERRIDE_0 0x140
#define EMC_R2R_0 0x144
#define EMC_W2W_0 0x148
#define EMC_EINPUT_0 0x14C
#define EMC_EINPUT_DURATION_0 0x150
#define EMC_PUTERM_EXTRA_0 0x154
#define EMC_TCKESR_0 0x158
#define EMC_TPD_0 0x15C
#define EMC_AUTO_CAL_CONFIG_0 0x2A4
#define EMC_AUTO_CAL_INTERVAL_0 0x2A8
#define EMC_AUTO_CAL_STATUS_0 0x2AC
#define EMC_REQ_CTRL_0 0x2B0
#define EMC_EMC_STATUS_0 0x2B4
#define EMC_CFG_2_0 0x2B8
#define EMC_CFG_DIG_DLL_0 0x2BC
#define EMC_CFG_DIG_DLL_PERIOD_0 0x2C0
#define EMC_DIG_DLL_STATUS_0 0x2C4
#define EMC_CFG_DIG_DLL_1_0 0x2C8
#define EMC_RDV_MASK_0 0x2CC
#define EMC_WDV_MASK_0 0x2D0
#define EMC_RDV_EARLY_MASK_0 0x2D4
#define EMC_RDV_EARLY_0 0x2D8
#define EMC_AUTO_CAL_CONFIG8_0 0x2DC
#define EMC_ZCAL_INTERVAL_0 0x2E0
#define EMC_ZCAL_WAIT_CNT_0 0x2E4
#define EMC_ZCAL_MRW_CMD_0 0x2E8
#define EMC_ZQ_CAL_0 0x2EC
#define EMC_XM2COMPPADCTRL3_0 0x2F4
#define EMC_AUTO_CAL_VREF_SEL_0_0 0x2F8
#define EMC_AUTO_CAL_VREF_SEL_1_0 0x300
#define EMC_XM2COMPPADCTRL_0 0x30C
#define EMC_FDPD_CTRL_DQ_0 0x310
#define EMC_FDPD_CTRL_CMD_0 0x314
#define EMC_PMACRO_CMD_BRICK_CTRL_FDPD_0 0x318
#define EMC_PMACRO_DATA_BRICK_CTRL_FDPD_0 0x31C
#define EMC_SCRATCH0_0 0x324
#define EMC_PMACRO_BRICK_CTRL_RFU1_0 0x330
#define EMC_PMACRO_BRICK_CTRL_RFU2_0 0x334
#define EMC_CMD_MAPPING_CMD0_0_0 0x380
#define EMC_CMD_MAPPING_CMD0_1_0 0x384
#define EMC_CMD_MAPPING_CMD0_2_0 0x388
#define EMC_CMD_MAPPING_CMD1_0_0 0x38C
#define EMC_CMD_MAPPING_CMD1_1_0 0x390
#define EMC_CMD_MAPPING_CMD1_2_0 0x394
#define EMC_CMD_MAPPING_CMD2_0_0 0x398
#define EMC_CMD_MAPPING_CMD2_1_0 0x39C
#define EMC_CMD_MAPPING_CMD2_2_0 0x3A0
#define EMC_CMD_MAPPING_CMD3_0_0 0x3A4
#define EMC_CMD_MAPPING_CMD3_1_0 0x3A8
#define EMC_CMD_MAPPING_CMD3_2_0 0x3AC
#define EMC_CMD_MAPPING_BYTE_0 0x3B0
#define EMC_TR_TIMING_0_0 0x3B4
#define EMC_TR_CTRL_0_0 0x3B8
#define EMC_TR_CTRL_1_0 0x3BC
#define EMC_SWITCH_BACK_CTRL_0 0x3C0
#define EMC_TR_RDV_0 0x3C4
#define EMC_STALL_THEN_EXE_BEFORE_CLKCHANGE_0 0x3C8
#define EMC_STALL_THEN_EXE_AFTER_CLKCHANGE_0 0x3CC
#define EMC_UNSTALL_RW_AFTER_CLKCHANGE_0 0x3D0
#define EMC_AUTO_CAL_ 0x3D4
#define EMC_SEL_DPD_CTRL_0 0x3D8
#define EMC_PRE_REFRESH_REQ_CNT_0 0x3DC
#define EMC_DYN_SELF_REF_CONTROL_0 0x3E0
#define EMC_TXSRDLL_0 0x3E4
#define EMC_CCFIFO_ADDR_0 0x3E8
#define EMC_CCFIFO_DATA_0 0x3EC
#define EMC_CCFIFO_STATUS_0 0x3F0
#define EMC_TR_QPOP_0 0x3F4
#define EMC_TR_RDV_MASK_0 0x3F8
#define EMC_TR_QSAFE_0 0x3FC
#define EMC_TR_QRST_0 0x400
#define EMC_SWIZZLE_RANK0_BYTE0_0 0x404
#define EMC_SWIZZLE_RANK0_BYTE1_0 0x408
#define EMC_SWIZZLE_RANK0_BYTE2_0 0x40C
#define EMC_SWIZZLE_RANK0_BYTE3_0 0x410
#define EMC_SWIZZLE_RANK1_BYTE0_0 0x418
#define EMC_SWIZZLE_RANK1_BYTE1_0 0x41C
#define EMC_SWIZZLE_RANK1_BYTE2_0 0x420
#define EMC_SWIZZLE_RANK1_BYTE3_0 0x424
#define EMC_ISSUE_QRST_0 0x428
#define EMC_PMC_SCRATCH1_0 0x440
#define EMC_PMC_SCRATCH2_0 0x444
#define EMC_PMC_SCRATCH3_0 0x448
#define EMC_AUTO_CAL_CONFIG2_0 0x458
#define EMC_AUTO_CAL_CONFIG3_0 0x45C
#define EMC_TR_DVFS_0 0x460
#define EMC_AUTO_CAL_CHANNEL_0 0x464
#define EMC_IBDLY_0 0x468
#define EMC_OBDLY_0 0x46C
#define EMC_TXDSRVTTGEN_0 0x480
#define EMC_WE_DURATION_0 0x48C
#define EMC_WS_DURATION_0 0x490
#define EMC_WEV_0 0x494
#define EMC_WSV_0 0x498
#define EMC_CFG_3_0 0x49C
#define EMC_MRW5_0 0x4A0
#define EMC_MRW6_0 0x4A4
#define EMC_MRW7_0 0x4A8
#define EMC_MRW8_0 0x4AC
#define EMC_MRW9_0 0x4B0
#define EMC_MRW10_0 0x4B4
#define EMC_MRW11_0 0x4B8
#define EMC_MRW12_0 0x4BC
#define EMC_MRW13_0 0x4C0
#define EMC_MRW14_0 0x4C4
#define EMC_MRW15_0 0x4D0
#define EMC_CFG_SYNC_0 0x4D4
#define EMC_FDPD_CTRL_CMD_NO_RAMP_0 0x4D8
#define EMC_WDV_CHK_0 0x4E0
#define EMC_CFG_PIPE_2_0 0x554
#define EMC_CFG_PIPE_CLK_0 0x558
#define EMC_CFG_PIPE_1_0 0x55C
#define EMC_CFG_PIPE_0 0x560
#define EMC_QPOP_0 0x564
#define EMC_QUSE_WIDTH_0 0x568
#define EMC_PUTERM_WIDTH_0 0x56C
#define EMC_BGBIAS_CTL0_0 0x570
#define EMC_AUTO_CAL_CONFIG7_0 0x574
#define EMC_XM2COMPPADCTRL2_0 0x578
#define EMC_COMP_PAD_SW_CTRL_0 0x57C
#define EMC_REFCTRL2_0 0x580
#define EMC_FBIO_CFG7_0 0x584
#define EMC_DATA_BRLSHFT_0_0 0x588
#define EMC_DATA_BRLSHFT_1_0 0x58C
#define EMC_RFCPB_0 0x590
#define EMC_DQS_BRLSHFT_0_0 0x594
#define EMC_DQS_BRLSHFT_1_0 0x598
#define EMC_CMD_BRLSHFT_0_0 0x59C
#define EMC_CMD_BRLSHFT_1_0 0x5A0
#define EMC_CMD_BRLSHFT_2_0 0x5A4
#define EMC_CMD_BRLSHFT_3_0 0x5A8
#define EMC_QUSE_BRLSHFT_0_0 0x5AC
#define EMC_AUTO_CAL_CONFIG4_0 0x5B0
#define EMC_AUTO_CAL_CONFIG5_0 0x5B4
#define EMC_QUSE_BRLSHFT_1_0 0x5B8
#define EMC_QUSE_BRLSHFT_2_0 0x5BC
#define EMC_CCDMW_0 0x5C0
#define EMC_QUSE_BRLSHFT_3_0 0x5C4
#define EMC_FBIO_CFG8_0 0x5C8
#define EMC_AUTO_CAL_CONFIG6_0 0x5CC
#define EMC_PROTOBIST_CONFIG_ADR_1_0 0x5D0
#define EMC_PROTOBIST_CONFIG_ADR_2_0 0x5D4
#define EMC_PROTOBIST_MISC_0 0x5D8
#define EMC_PROTOBIST_WDATA_LOWER_0 0x5DC
#define EMC_PROTOBIST_WDATA_UPPER_0 0x5E0
#define EMC_PROTOBIST_RDATA_0 0x5EC
#define EMC_DLL_CFG_0_0 0x5E4
#define EMC_DLL_CFG_1_0 0x5E8
#define EMC_CONFIG_SAMPLE_DELAY_0 0x5F0
#define EMC_CFG_UPDATE_0 0x5F4
#define EMC_PMACRO_QUSE_DDLL_RANK0_0_0 0x600
#define EMC_PMACRO_QUSE_DDLL_RANK0_1_0 0x604
#define EMC_PMACRO_QUSE_DDLL_RANK0_2_0 0x608
#define EMC_PMACRO_QUSE_DDLL_RANK0_3_0 0x60C
#define EMC_PMACRO_QUSE_DDLL_RANK0_4_0 0x610
#define EMC_PMACRO_QUSE_DDLL_RANK0_5_0 0x614
#define EMC_PMACRO_QUSE_DDLL_RANK1_0_0 0x620
#define EMC_PMACRO_QUSE_DDLL_RANK1_1_0 0x624
#define EMC_PMACRO_QUSE_DDLL_RANK1_2_0 0x628
#define EMC_PMACRO_QUSE_DDLL_RANK1_3_0 0x62C
#define EMC_PMACRO_QUSE_DDLL_RANK1_4_0 0x630
#define EMC_PMACRO_QUSE_DDLL_RANK1_5_0 0x634
#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0_0 0x640
#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1_0 0x644
#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2_0 0x648
#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3_0 0x64C
#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_4_0 0x650
#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_5_0 0x654
#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0_0 0x660
#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1_0 0x664
#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2_0 0x668
#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3_0 0x66C
#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_4_0 0x670
#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_5_0 0x674
#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_0_0 0x680
#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_1_0 0x684
#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_2_0 0x688
#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_3_0 0x68C
#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_4_0 0x690
#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_5_0 0x694
#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_0_0 0x6A0
#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_1_0 0x6A4
#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_2_0 0x6A8
#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_3_0 0x6AC
#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_4_0 0x6B0
#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_5_0 0x6B4
#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_0_0 0x6C0
#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_1_0 0x6C4
#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_2_0 0x6C8
#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_3_0 0x6CC
#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_4_0 0x6D0
#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_5_0 0x6D4
#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_0_0 0x6E0
#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_1_0 0x6E4
#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_2_0 0x6E8
#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_3_0 0x6EC
#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_4_0 0x6F0
#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_5_0 0x6F4
#define EMC_PMACRO_AUTOCAL_CFG_0_0 0x700
#define EMC_PMACRO_AUTOCAL_CFG_1_0 0x704
#define EMC_PMACRO_AUTOCAL_CFG_2_0 0x708
#define EMC_PMACRO_TX_PWRD_0_0 0x720
#define EMC_PMACRO_TX_PWRD_1_0 0x724
#define EMC_PMACRO_TX_PWRD_2_0 0x728
#define EMC_PMACRO_TX_PWRD_3_0 0x72C
#define EMC_PMACRO_TX_PWRD_4_0 0x730
#define EMC_PMACRO_TX_PWRD_5_0 0x734
#define EMC_PMACRO_TX_SEL_CLK_SRC_0_0 0x740
#define EMC_PMACRO_TX_SEL_CLK_SRC_1_0 0x744
#define EMC_PMACRO_TX_SEL_CLK_SRC_2_0 0x748
#define EMC_PMACRO_TX_SEL_CLK_SRC_3_0 0x74C
#define EMC_PMACRO_TX_SEL_CLK_SRC_4_0 0x750
#define EMC_PMACRO_TX_SEL_CLK_SRC_5_0 0x754
#define EMC_PMACRO_DDLL_BYPASS_0 0x760
#define EMC_PMACRO_DDLL_PWRD_0_0 0x770
#define EMC_PMACRO_DDLL_PWRD_1_0 0x774
#define EMC_PMACRO_DDLL_PWRD_2_0 0x778
#define EMC_PMACRO_CMD_CTRL_0_0 0x780
#define EMC_PMACRO_CMD_CTRL_1_0 0x784
#define EMC_PMACRO_CMD_CTRL_2_0 0x788
#define MC_REGISTER_BASE 0x70019000
#define MC_REGISTER_REGION_SIZE 0x1000
#define MC_INTSTATUS_0 0x000
#define MC_INTMASK_0 0x004
#define MC_ERR_STATUS_0 0x008
#define MC_ERR_ADR_0 0x00C
#define MC_SMMU_CONFIG_0 0x010
#define MC_SMMU_PTB_ASID_0 0x01C
#define MC_SMMU_PTB_DATA_0 0x020
#define MC_SMMU_TLB_FLUSH_0 0x030
#define MC_SMMU_PTC_FLUSH_0_0 0x034
#define MC_EMEM_CFG_0 0x050
#define MC_EMEM_ADR_CFG_0 0x054
#define MC_EMEM_ARB_CFG_0 0x090
#define MC_EMEM_ARB_OUTSTANDING_REQ_0 0x094
#define MC_EMEM_ARB_TIMING_RCD_0 0x098
#define MC_EMEM_ARB_TIMING_RP_0 0x09C
#define MC_EMEM_ARB_TIMING_RC_0 0x0A0
#define MC_EMEM_ARB_TIMING_RAS_0 0x0A4
#define MC_EMEM_ARB_TIMING_FAW_0 0x0A8
#define MC_EMEM_ARB_TIMING_RRD_0 0x0AC
#define MC_EMEM_ARB_TIMING_RAP2PRE_0 0x0B0
#define MC_EMEM_ARB_TIMING_WAP2PRE_0 0x0B4
#define MC_EMEM_ARB_TIMING_R2R_0 0x0B8
#define MC_EMEM_ARB_TIMING_W2W_0 0x0BC
#define MC_EMEM_ARB_TIMING_R2W_0 0x0C0
#define MC_EMEM_ARB_TIMING_W2R_0 0x0C4
#define MC_EMEM_ARB_MISC2_0 0x0C8
#define MC_EMEM_ARB_DA_TURNS_0 0x0D0
#define MC_EMEM_ARB_DA_COVERS_0 0x0D4
#define MC_EMEM_ARB_MISC0_0 0x0D8
#define MC_EMEM_ARB_MISC1_0 0x0DC
#define MC_TIMING_CONTROL_0 0xFC
#define MC_EMEM_ARB_RING1_THROTTLE_0 0x0E0
#define MC_CLIENT_HOTRESET_CTRL_0 0x200
#define MC_CLIENT_HOTRESET_STATUS_0 0x204
#define MC_SMMU_AFI_ASID_0 0x238
#define MC_SMMU_DC_ASID_0 0x240
#define MC_SMMU_DCB_ASID_0 0x244
#define MC_SMMU_HC_ASID_0 0x250
#define MC_SMMU_HDA_ASID_0 0x254
#define MC_SMMU_ISP2_ASID_0 0x258
#define MC_SMMU_MSENC_NVENC_ASID_0 0x264
#define MC_SMMU_NV_ASID_0 0x268
#define MC_SMMU_NV2_ASID_0 0x26C
#define MC_SMMU_PPCS_ASID_0 0x270
#define MC_SMMU_SATA_ASID_0 0x274
#define MC_SMMU_VI_ASID_0 0x280
#define MC_SMMU_VIC_ASID_0 0x284
#define MC_SMMU_XUSB_HOST_ASID_0 0x288
#define MC_SMMU_XUSB_DEV_ASID_0 0x28C
#define MC_SMMU_TSEC_ASID_0 0x294
#define MC_LATENCY_ALLOWANCE_AVPC_0 0x2E4
#define MC_LATENCY_ALLOWANCE_DC_0 0x2E8
#define MC_LATENCY_ALLOWANCE_DC_1 0x2EC
#define MC_LATENCY_ALLOWANCE_DCB_0 0x2F4
#define MC_LATENCY_ALLOWANCE_DCB_1 0x2F8
#define MC_LATENCY_ALLOWANCE_HC_0 0x310
#define MC_LATENCY_ALLOWANCE_HC_1 0x314
#define MC_LATENCY_ALLOWANCE_MPCORE_0 0x320
#define MC_LATENCY_ALLOWANCE_NVENC_0 0x328
#define MC_LATENCY_ALLOWANCE_PPCS_0 0x344
#define MC_LATENCY_ALLOWANCE_PPCS_1 0x348
#define MC_LATENCY_ALLOWANCE_ISP2_0 0x370
#define MC_LATENCY_ALLOWANCE_ISP2_1 0x374
#define MC_LATENCY_ALLOWANCE_XUSB_0 0x37C
#define MC_LATENCY_ALLOWANCE_XUSB_1 0x380
#define MC_LATENCY_ALLOWANCE_TSEC_0 0x390
#define MC_LATENCY_ALLOWANCE_VIC_0 0x394
#define MC_LATENCY_ALLOWANCE_VI2_0 0x398
#define MC_LATENCY_ALLOWANCE_GPU_0 0x3AC
#define MC_LATENCY_ALLOWANCE_SDMMCA_0 0x3B8
#define MC_LATENCY_ALLOWANCE_SDMMCAA_0 0x3BC
#define MC_LATENCY_ALLOWANCE_SDMMC_0 0x3C0
#define MC_LATENCY_ALLOWANCE_SDMMCAB_0 0x3C4
#define MC_LATENCY_ALLOWANCE_NVDEC_0 0x3D8
#define MC_LATENCY_ALLOWANCE_GPU2_0 0x3E8
#define MC_DIS_PTSA_RATE_0 0x41C
#define MC_DIS_PTSA_MIN_0 0x420
#define MC_DIS_PTSA_MAX_0 0x424
#define MC_DISB_PTSA_RATE_0 0x428
#define MC_DISB_PTSA_MIN_0 0x42C
#define MC_DISB_PTSA_MAX_0 0x430
#define MC_VE_PTSA_RATE_0 0x434
#define MC_VE_PTSA_MIN_0 0x438
#define MC_VE_PTSA_MAX_0 0x43C
#define MC_MLL_MPCORER_PTSA_RATE_0 0x44C
#define MC_RING1_PTSA_RATE_0 0x47C
#define MC_RING1_PTSA_MIN_0 0x480
#define MC_RING1_PTSA_MAX_0 0x484
#define MC_PCX_PTSA_RATE_0 0x4AC
#define MC_PCX_PTSA_MIN_0 0x4B0
#define MC_PCX_PTSA_MAX_0 0x4B4
#define MC_MSE_PTSA_RATE_0 0x4C4
#define MC_MSE_PTSA_MIN_0 0x4C8
#define MC_MSE_PTSA_MAX_0 0x4CC
#define MC_AHB_PTSA_RATE_0 0x4DC
#define MC_AHB_PTSA_MIN_0 0x4E0
#define MC_AHB_PTSA_MAX_0 0x4E4
#define MC_APB_PTSA_RATE_0 0x4E8
#define MC_APB_PTSA_MIN_0 0x4EC
#define MC_APB_PTSA_MAX_0 0x4F0
#define MC_FTOP_PTSA_RATE_0 0x50C
#define MC_HOST_PTSA_RATE_0 0x518
#define MC_HOST_PTSA_MIN_0 0x51C
#define MC_HOST_PTSA_MAX_0 0x520
#define MC_USBX_PTSA_RATE_0 0x524
#define MC_USBX_PTSA_MIN_0 0x528
#define MC_USBX_PTSA_MAX_0 0x52C
#define MC_USBD_PTSA_RATE_0 0x530
#define MC_USBD_PTSA_MIN_0 0x534
#define MC_USBD_PTSA_MAX_0 0x538
#define MC_GK_PTSA_RATE_0 0x53C
#define MC_GK_PTSA_MIN_0 0x540
#define MC_GK_PTSA_MAX_0 0x544
#define MC_AUD_PTSA_RATE_0 0x548
#define MC_AUD_PTSA_MIN_0 0x54C
#define MC_AUD_PTSA_MAX_0 0x550
#define MC_VICPC_PTSA_RATE_0 0x554
#define MC_VICPC_PTSA_MIN_0 0x558
#define MC_VICPC_PTSA_MAX_0 0x55C
#define MC_JPG_PTSA_RATE_0 0x584
#define MC_JPG_PTSA_MIN_0 0x588
#define MC_JPG_PTSA_MAX_0 0x58C
#define MC_GK2_PTSA_RATE_0 0x610
#define MC_GK2_PTSA_MIN_0 0x614
#define MC_GK2_PTSA_MAX_0 0x618
#define MC_SDM_PTSA_RATE_0 0x61C
#define MC_SDM_PTSA_MIN_0 0x620
#define MC_SDM_PTSA_MAX_0 0x624
#define MC_HDAPC_PTSA_RATE_0 0x628
#define MC_HDAPC_PTSA_MIN_0 0x62C
#define MC_HDAPC_PTSA_MAX_0 0x630
#define MC_SEC_CARVEOUT_BOM_0 0x670
#define MC_SEC_CARVEOUT_SIZE_MB_0 0x674
#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0A_0 0x690
#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0AB_0 0x694
#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0B_0 0x698
#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0BB_0 0x69C
#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0C_0 0x6A0
#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0CB_0 0x6A4
#define MC_EMEM_ARB_TIMING_RFCPB_0 0x6C0
#define MC_EMEM_ARB_TIMING_CCDMW_0 0x6C4
#define MC_EMEM_ARB_REFPB_HP_CTRL_0 0x6F0
#define MC_EMEM_ARB_REFPB_BANK_CTRL_0 0x6F4
#define MC_PTSA_GRANT_DECREMENT_0 0x960
#define MC_CLIENT_HOTRESET_CTRL_1 0x970
#define MC_CLIENT_HOTRESET_STATUS_1 0x974
#define MC_SMMU_PTC_FLUSH_1 0x9B8
#define MC_SMMU_DC1_ASID_0 0xA88
#define MC_SMMU_SDMMC1A_ASID_0 0xA94
#define MC_SMMU_SDMMC2A_ASID_0 0xA98
#define MC_SMMU_SDMMC3A_ASID_0 0xA9C
#define MC_SMMU_SDMMC4A_ASID_0 0xAA0
#define MC_SMMU_ISP2B_ASID_0 0xAA4
#define MC_SMMU_GPU_ASID_0 0xAA8
#define MC_SMMU_GPUB_ASID_0 0xAAC
#define MC_SMMU_PPCS2_ASID_0 0xAB0
#define MC_SMMU_NVDEC_ASID_0 0xAB4
#define MC_SMMU_APE_ASID_0 0xAB8
#define MC_SMMU_SE_ASID_0 0xABC
#define MC_SMMU_NVJPG_ASID_0 0xAC0
#define MC_SMMU_HC1_ASID_0 0xAC4
#define MC_SMMU_SE1_ASID_0 0xAC8
#define MC_SMMU_AXIAP_ASID_0 0xACC
#define MC_SMMU_ETR_ASID_0 0xAD0
#define MC_SMMU_TSECB_ASID_0 0xAD4
#define MC_SMMU_TSEC1_ASID_0 0xAD8
#define MC_SMMU_TSECB1_ASID_0 0xADC
#define MC_SMMU_NVDEC1_ASID_0 0xAE0
#define MC_EMEM_ARB_DHYST_CTRL_0 0xBCC
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_0 0xBD0
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_1 0xBD4
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_2 0xBD8
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_3 0xBDC
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_4 0xBE0
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_5 0xBE4
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_6 0xBE8
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_7 0xBEC
#define MC_ERR_GENERALIZED_CARVEOUT_STATUS_0 0xC00
#define MC_SECURITY_CARVEOUT2_BOM_0 0xC5C
#define MC_SECURITY_CARVEOUT3_BOM_0 0xCAC
#define CLDVFS_REGION_BASE 0x70110000
#define CLDVFS_REGION_SIZE 0x1000
#define CL_DVFS_CTRL_0 0x0
#define CL_DVFS_CONFIG_0 0x4
#define CL_DVFS_PARAMS_0 0x8
#define CL_DVFS_TUNE0_0 0xC
#define CL_DVFS_TUNE1_0 0x10
#define CL_DVFS_FREQ_REQ_0 0x14
#define CL_DVFS_SCALE_RAMP_0 0x18
#define CL_DVFS_DROOP_CTRL_0 0x1C
#define CL_DVFS_OUTPUT_CFG_0 0x20
#define CL_DVFS_OUTPUT_FORCE_0 0x24
#define CL_DVFS_MONITOR_CTRL_0 0x28
#define CL_DVFS_MONITOR_DATA_0 0x2C
#define CL_DVFS_I2C_CFG_0 0x40
#define CL_DVFS_I2C_VDD_REG_ADDR_0 0x44
#define CL_DVFS_I2C_STS_0 0x48
#define CL_DVFS_INTR_STS_0 0x5C
#define CL_DVFS_INTR_EN_0 0x60
#define DVFS_DFLL_THROTTLE_CTRL_0 0x64
#define DVFS_DFLL_THROTTLE_LIGHT_0 0x68
#define DVFS_DFLL_THROTTLE_MEDIUM_0 0x6C
#define DVFS_DFLL_THROTTLE_HEAVY_0 0x70
#define DVFS_CC4_HVC_0 0x74
#define CL_DVFS_MONITOR_DATA_0 0x2C
#define CL_DVFS_I2C_CFG_0 0x40
#define CL_DVFS_I2C_VDD_REG_ADDR_0 0x44
#define CL_DVFS_I2C_STS_0 0x48
#define CL_DVFS_INTR_STS_0 0x5C
#define CL_DVFS_I2C_CLK_DIVISOR_REGISTER_0 0x16C

View File

@@ -0,0 +1,38 @@
/*
* Copyright (c) ppkantorski (bord2death)
*
* 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 <switch.h>
#include "pcv_types.h"
typedef struct {
Service s;
} RgltrSession;
Result rgltrInitialize(void);
void rgltrExit(void);
Service* rgltrGetServiceSession(void);
Result rgltrOpenSession(RgltrSession* session_out, PowerDomainId module_id);
void rgltrCloseSession(RgltrSession* session);
Result rgltrGetVoltage(RgltrSession* session, u32 *out_volt);
Result rgltrGetPowerModuleNumLimit(u32 *out);
Result rgltrGetVoltageEnabled(RgltrSession* session, u32 *out);
Result rgltrRequestVoltage(RgltrSession* session, u32 microvolt);
Result rgltrCancelVoltageRequest(RgltrSession* session);

View File

@@ -0,0 +1,32 @@
/*
* Copyright (c) ppkantorski (bord2death)
*
* 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 <switch.h> // for Service, Result, hosversionBefore(), smGetService(), serviceClose(), etc.
#include "rgltr.h" // for RgltrSession, PowerDomainId, etc.
extern Service g_rgltrSrv;
Result rgltrInitialize(void);
void rgltrExit(void);
Result rgltrOpenSession(RgltrSession* session_out, PowerDomainId module_id);
Result rgltrGetVoltage(RgltrSession* session, u32* out_volt);
void rgltrCloseSession(RgltrSession* session);

View File

@@ -0,0 +1,82 @@
/*
* Copyright (c) MasaGratoR
*
* 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
#ifdef __cplusplus
extern "C" {
#endif
#include <switch/types.h>
#include <switch/result.h>
#include <switch/kernel/mutex.h>
#include <switch/sf/service.h>
#include <switch/services/sm.h>
typedef struct ServiceGuard {
Mutex mutex;
u32 refCount;
} ServiceGuard;
NX_INLINE bool serviceGuardBeginInit(ServiceGuard* g)
{
mutexLock(&g->mutex);
return (g->refCount++) == 0;
}
NX_INLINE Result serviceGuardEndInit(ServiceGuard* g, Result rc, void (*cleanupFunc)(void))
{
if (R_FAILED(rc)) {
cleanupFunc();
--g->refCount;
}
mutexUnlock(&g->mutex);
return rc;
}
NX_INLINE void serviceGuardExit(ServiceGuard* g, void (*cleanupFunc)(void))
{
mutexLock(&g->mutex);
if (g->refCount && (--g->refCount) == 0)
cleanupFunc();
mutexUnlock(&g->mutex);
}
#define NX_GENERATE_SERVICE_GUARD_PARAMS(name, _paramdecl, _parampass) \
\
static ServiceGuard g_##name##Guard; \
NX_INLINE Result _##name##Initialize _paramdecl; \
static void _##name##Cleanup(void); \
\
Result name##Initialize _paramdecl \
{ \
Result rc = 0; \
if (serviceGuardBeginInit(&g_##name##Guard)) \
rc = _##name##Initialize _parampass; \
return serviceGuardEndInit(&g_##name##Guard, rc, _##name##Cleanup); \
} \
\
void name##Exit(void) \
{ \
serviceGuardExit(&g_##name##Guard, _##name##Cleanup); \
}
#define NX_GENERATE_SERVICE_GUARD(name) NX_GENERATE_SERVICE_GUARD_PARAMS(name, (void), ())
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,55 @@
/*
* 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/>.
*
*/
/* --------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
* wrote this file. As long as you retain this notice you can do whatever you
* want with this stuff. If you meet any of us some day, and you think this
* stuff is worth it, you can buy us a beer in return. - The sys-clk authors
* --------------------------------------------------------------------------
*/
#pragma once
#include <cstdint>
#include <switch.h> // include libnx
#ifdef __cplusplus
#include "cpp_util.hpp"
extern "C" {
#endif
// typedef std::uint32_t Result;
// typedef std::uint32_t u32;
// typedef std::int32_t s32;
// typedef std::uint64_t u64;
// typedef std::int64_t s64;
// typedef std::uint8_t u8;
// typedef std::int16_t s16;
// typedef std::uint16_t u16;
#include "sysclk/ipc.h"
#include "sysclk/board.h"
#include "sysclk/clock_manager.h"
#include "sysclk/apm.h"
#include "sysclk/config.h"
#include "sysclk/errors.h"
#include "sysclk/psm_ext.h"
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,39 @@
/*
* 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/>.
*
*/
/* --------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
* wrote this file. As long as you retain this notice you can do whatever you
* want with this stuff. If you meet any of us some day, and you think this
* stuff is worth it, you can buy us a beer in return. - The sys-clk authors
* --------------------------------------------------------------------------
*/
#pragma once
#include "board.h"
typedef struct {
uint32_t id;
uint32_t cpu_hz;
uint32_t gpu_hz;
uint32_t mem_hz;
} SysClkApmConfiguration;
extern SysClkApmConfiguration sysclk_g_apm_configurations[];

View File

@@ -0,0 +1,270 @@
/*
* 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/>.
*
*/
/* --------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
* wrote this file. As long as you retain this notice you can do whatever you
* want with this stuff. If you meet any of us some day, and you think this
* stuff is worth it, you can buy us a beer in return. - The sys-clk authors
* --------------------------------------------------------------------------
*/
#pragma once
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <switch/types.h>
typedef enum
{
SysClkSocType_Erista = 0,
SysClkSocType_Mariko,
SysClkSocType_EnumMax
} SysClkSocType;
typedef enum
{
HorizonOCConsoleType_Icosa = 0,
HorizonOCConsoleType_Copper,
HorizonOCConsoleType_Hoag,
HorizonOCConsoleType_Iowa,
HorizonOCConsoleType_Calcio,
HorizonOCConsoleType_Aula,
HorizonOCConsoleType_EnumMax,
} HorizonOCConsoleType;
typedef enum {
HocClkVoltage_SOC = 0,
HocClkVoltage_EMCVDD2,
HocClkVoltage_CPU,
HocClkVoltage_GPU,
HocClkVoltage_EMCVDDQ_MarikoOnly,
HocClkVoltage_Display,
HocClkVoltage_Battery,
HocClkVoltage_EnumMax,
} HocClkVoltage;
typedef enum
{
SysClkProfile_Handheld = 0,
SysClkProfile_HandheldCharging,
SysClkProfile_HandheldChargingUSB,
SysClkProfile_HandheldChargingOfficial,
SysClkProfile_Docked,
SysClkProfile_EnumMax
} SysClkProfile;
typedef enum
{
SysClkModule_CPU = 0,
SysClkModule_GPU,
SysClkModule_MEM,
HorizonOCModule_Governor,
HorizonOCModule_Display,
SysClkModule_EnumMax,
} SysClkModule;
typedef enum
{
SysClkThermalSensor_SOC = 0,
SysClkThermalSensor_PCB,
SysClkThermalSensor_Skin,
HorizonOCThermalSensor_Battery,
HorizonOCThermalSensor_PMIC,
SysClkThermalSensor_EnumMax
} SysClkThermalSensor;
typedef enum
{
SysClkPowerSensor_Now = 0,
SysClkPowerSensor_Avg,
SysClkPowerSensor_EnumMax
} SysClkPowerSensor;
typedef enum
{
SysClkPartLoad_EMC = 0,
SysClkPartLoad_EMCCpu,
HocClkPartLoad_GPU,
HocClkPartLoad_CPUMax,
HocClkPartLoad_BAT,
HocClkPartLoad_FAN,
SysClkPartLoad_EnumMax
} SysClkPartLoad;
typedef enum {
HorizonOCSpeedo_CPU = 0,
HorizonOCSpeedo_GPU,
HorizonOCSpeedo_SOC,
HorizonOCSpeedo_EnumMax,
} HorizonOCSpeedo;
typedef enum {
GPUUVLevel_NoUV = 0,
GPUUVLevel_SLT,
GPUUVLevel_HiOPT,
GPUUVLevel_EnumMax,
} GPUUndervoltLevel;
enum {
DVFSMode_Disabled = 0,
DVFSMode_Hijack,
// DVFSMode_OfficialService,
// DVFSMode_Hack,
DVFSMode_EnumMax,
};
typedef enum {
GpuSchedulingMode_DoNotOverride = 0,
GpuSchedulingMode_Enabled,
GpuSchedulingMode_Disabled,
GpuSchedulingMode_EnumMax,
} GpuSchedulingMode;
typedef enum {
GpuSchedulingOverrideMethod_Ini = 0,
GpuSchedulingOverrideMethod_NvService,
GpuSchedulingOverrideMethod_EnumMax,
} GpuSchedulingOverrideMethod;
typedef enum {
ComponentGovernor_DoNotOverride = 0,
ComponentGovernor_Disabled = 1,
ComponentGovernor_Enabled = 2,
ComponentGovernor_EnumMax,
} ComponentGovernorState;
typedef enum {
RamDisplayMode_VDD2VDDQ = 0,
RamDisplayMode_VDD2Usage,
RamDisplayMode_VDDQUsage,
RamDisplayMode_EnumMax,
} RamDisplayMode;
#define SYSCLK_ENUM_VALID(n, v) ((v) < n##_EnumMax)
// Packed u32
// Bits 0-7 - CPU
// Bits 8-15 - GPU
// Bits 16-23 - VRR
// Bits 24-32 - unused
inline u32 GovernorStatePack(u8 cpu, u8 gpu, u8 vrr) {
return (u32)cpu | ((u32)gpu << 8) | ((u32)vrr << 16);
}
inline u8 GovernorStateCpu(u32 p) {
return (u8)(p & 0xFF);
}
inline u8 GovernorStateGpu(u32 p) {
return (u8)((p >> 8) & 0xFF);
}
inline u8 GovernorStateVrr(u32 p) {
return (u8)((p >> 16) & 0xFF);
}
static inline const char* sysclkFormatModule(SysClkModule module, bool pretty)
{
switch(module)
{
case SysClkModule_CPU:
return pretty ? "CPU" : "cpu";
case SysClkModule_GPU:
return pretty ? "GPU" : "gpu";
case SysClkModule_MEM:
return pretty ? "Memory" : "mem";
case HorizonOCModule_Display:
return pretty ? "Display" : "display";
case HorizonOCModule_Governor:
return pretty ? "Governor" : "governor";
default:
return "null";
}
}
static inline const char* sysclkFormatThermalSensor(SysClkThermalSensor thermSensor, bool pretty)
{
switch(thermSensor)
{
case SysClkThermalSensor_SOC:
return pretty ? "SOC" : "soc";
case SysClkThermalSensor_PCB:
return pretty ? "PCB" : "pcb";
case SysClkThermalSensor_Skin:
return pretty ? "Skin" : "skin";
case HorizonOCThermalSensor_Battery:
return pretty ? "BAT" : "battery";
case HorizonOCThermalSensor_PMIC:
return pretty ? "PMIC" : "pmic";
default:
return NULL;
}
}
static inline const char* sysclkFormatPowerSensor(SysClkPowerSensor powSensor, bool pretty)
{
switch(powSensor)
{
case SysClkPowerSensor_Now:
return pretty ? "Now" : "now";
case SysClkPowerSensor_Avg:
return pretty ? "Avg" : "avg";
default:
return NULL;
}
}
static inline const char* sysclkFormatProfile(SysClkProfile profile, bool pretty)
{
switch(profile)
{
case SysClkProfile_Docked:
return pretty ? "Docked" : "docked";
case SysClkProfile_Handheld:
return pretty ? "Handheld" : "handheld";
case SysClkProfile_HandheldCharging:
return pretty ? "Charging" : "handheld_charging";
case SysClkProfile_HandheldChargingUSB:
return pretty ? "USB Charger" : "handheld_charging_usb";
case SysClkProfile_HandheldChargingOfficial:
return pretty ? "PD Charger" : "handheld_charging_official";
default:
return NULL;
}
}
static inline const char* hocClkFormatVoltage(HocClkVoltage voltage, bool pretty)
{
switch(voltage)
{
case HocClkVoltage_CPU:
return pretty ? "CPU" : "cpu";
case HocClkVoltage_GPU:
return pretty ? "GPU" : "gpu";
case HocClkVoltage_EMCVDD2:
return pretty ? "VDD2" : "emcvdd2";
case HocClkVoltage_EMCVDDQ_MarikoOnly:
return pretty ? "VDDQ" : "vddq";
case HocClkVoltage_SOC:
return pretty ? "SOC" : "soc";
case HocClkVoltage_Display:
return pretty ? "Display" : "display";
default:
return NULL;
}
}

View File

@@ -0,0 +1,57 @@
/*
* 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/>.
*
*/
/* --------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
* wrote this file. As long as you retain this notice you can do whatever you
* want with this stuff. If you meet any of us some day, and you think this
* stuff is worth it, you can buy us a beer in return. - The sys-clk authors
* --------------------------------------------------------------------------
*/
#pragma once
#include "types.h"
#include "../config.h"
#include "../board.h"
#include "../ipc.h"
bool sysclkIpcRunning();
Result sysclkIpcInitialize(void);
void sysclkIpcExit(void);
Result sysclkIpcGetAPIVersion(u32* out_ver);
Result sysclkIpcGetVersionString(char* out, size_t len);
Result sysclkIpcGetCurrentContext(SysClkContext* out_context);
Result sysclkIpcGetProfileCount(u64 tid, u8* out_count);
Result sysclkIpcSetEnabled(bool enabled);
Result sysclkIpcExitCmd();
Result sysclkIpcSetOverride(SysClkModule module, u32 hz);
Result sysclkIpcGetProfiles(u64 tid, SysClkTitleProfileList* out_profiles);
Result sysclkIpcSetProfiles(u64 tid, SysClkTitleProfileList* profiles);
Result sysclkIpcGetConfigValues(SysClkConfigValueList* out_configValues);
Result sysclkIpcSetConfigValues(SysClkConfigValueList* configValues);
Result sysclkIpcGetFreqList(SysClkModule module, u32* list, u32 maxCount, u32* outCount);
Result hocClkIpcSetKipData();
Result hocClkIpcGetKipData();
static inline Result sysclkIpcRemoveOverride(SysClkModule module)
{
return sysclkIpcSetOverride(module, 0);
}

View File

@@ -0,0 +1,46 @@
/*
* 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/>.
*
*/
/* --------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
* wrote this file. As long as you retain this notice you can do whatever you
* want with this stuff. If you meet any of us some day, and you think this
* stuff is worth it, you can buy us a beer in return. - The sys-clk authors
* --------------------------------------------------------------------------
*/
#pragma once
#ifdef __SWITCH__
#include <switch/types.h>
#include <switch/result.h>
#else
#define R_FAILED(res) ((res) != 0)
#define R_SUCCEEDED(res) ((res) == 0)
typedef std::uint32_t Result;
typedef std::uint32_t u32;
typedef std::int32_t s32;
typedef std::uint64_t u64;
typedef std::uint8_t u8;
#endif

View File

@@ -0,0 +1,66 @@
/*
* 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/>.
*
*/
/* --------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
* wrote this file. As long as you retain this notice you can do whatever you
* want with this stuff. If you meet any of us some day, and you think this
* stuff is worth it, you can buy us a beer in return. - The sys-clk authors
* --------------------------------------------------------------------------
*/
#pragma once
#include <stdint.h>
#include "board.h"
typedef struct
{
uint64_t applicationId;
SysClkProfile profile;
uint32_t freqs[SysClkModule_EnumMax];
uint32_t realFreqs[SysClkModule_EnumMax];
uint32_t overrideFreqs[SysClkModule_EnumMax];
uint32_t temps[SysClkThermalSensor_EnumMax];
int32_t power[SysClkPowerSensor_EnumMax];
uint32_t partLoad[SysClkPartLoad_EnumMax];
uint32_t voltages[HocClkVoltage_EnumMax];
u16 speedos[HorizonOCSpeedo_EnumMax];
u16 iddq[HorizonOCSpeedo_EnumMax];
GpuSchedulingMode gpuSchedulingMode;
bool isSysDockInstalled;
bool isSaltyNXInstalled;
u8 maxDisplayFreq;
u8 dramID;
bool isDram8GB;
u8 fps;
u16 resolutionHeight;
} SysClkContext;
typedef struct
{
union {
uint32_t mhz[+SysClkProfile_EnumMax * +SysClkModule_EnumMax];
uint32_t mhzMap[+SysClkProfile_EnumMax][+SysClkModule_EnumMax];
};
} SysClkTitleProfileList;
#define SYSCLK_FREQ_LIST_MAX 32
#define GLOBAL_PROFILE_ID 0xA111111111111111

View File

@@ -0,0 +1,594 @@
/*
* 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/>.
*
*/
/* --------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
* wrote this file. As long as you retain this notice you can do whatever you
* want with this stuff. If you meet any of us some day, and you think this
* stuff is worth it, you can buy us a beer in return. - The sys-clk authors
* --------------------------------------------------------------------------
*/
#pragma once
#include <stdint.h>
#include <stddef.h>
typedef enum {
SysClkConfigValue_PollingIntervalMs = 0,
SysClkConfigValue_TempLogIntervalMs,
SysClkConfigValue_FreqLogIntervalMs,
SysClkConfigValue_PowerLogIntervalMs,
SysClkConfigValue_CsvWriteIntervalMs,
HocClkConfigValue_UncappedClocks,
HocClkConfigValue_OverwriteBoostMode,
HocClkConfigValue_EristaMaxCpuClock,
HocClkConfigValue_MarikoMaxCpuClock,
HocClkConfigValue_ThermalThrottle,
HocClkConfigValue_ThermalThrottleThreshold,
HocClkConfigValue_HandheldTDP,
HocClkConfigValue_HandheldTDPLimit,
HocClkConfigValue_LiteTDPLimit,
HorizonOCConfigValue_BatteryChargeCurrent,
HorizonOCConfigValue_OverwriteRefreshRate,
HorizonOCConfigValue_MaxDisplayClockH,
HorizonOCConfigValue_DVFSMode,
HorizonOCConfigValue_DVFSOffset,
HorizonOCConfigValue_LiveCpuUv,
HorizonOCConfigValue_EnableExperimentalSettings,
HorizonOCConfigValue_GPUScheduling,
HorizonOCConfigValue_GPUSchedulingMethod,
HorizonOCConfigValue_RAMVoltUsageDisplayMode,
HorizonOCConfigValue_CpuGovernorMinimumFreq,
KipConfigValue_custRev,
// KipConfigValue_mtcConf,
KipConfigValue_hpMode,
KipConfigValue_commonEmcMemVolt,
KipConfigValue_eristaEmcMaxClock,
KipConfigValue_eristaEmcMaxClock1,
KipConfigValue_eristaEmcMaxClock2,
KipConfigValue_marikoEmcMaxClock,
KipConfigValue_marikoEmcVddqVolt,
KipConfigValue_emcDvbShift,
KipConfigValue_t1_tRCD,
KipConfigValue_t2_tRP,
KipConfigValue_t3_tRAS,
KipConfigValue_t4_tRRD,
KipConfigValue_t5_tRFC,
KipConfigValue_t6_tRTW,
KipConfigValue_t7_tWTR,
KipConfigValue_t8_tREFI,
KipConfigValue_mem_burst_read_latency,
KipConfigValue_mem_burst_write_latency,
KipConfigValue_eristaCpuUV,
KipConfigValue_eristaCpuVmin,
KipConfigValue_eristaCpuMaxVolt,
KipConfigValue_eristaCpuUnlock,
KipConfigValue_marikoCpuUVLow,
KipConfigValue_marikoCpuUVHigh,
KipConfigValue_tableConf,
KipConfigValue_marikoCpuLowVmin,
KipConfigValue_marikoCpuHighVmin,
KipConfigValue_marikoCpuMaxVolt,
KipConfigValue_marikoCpuMaxClock,
KipConfigValue_eristaCpuBoostClock,
KipConfigValue_marikoCpuBoostClock,
KipConfigValue_eristaGpuUV,
KipConfigValue_eristaGpuVmin,
KipConfigValue_marikoGpuUV,
KipConfigValue_marikoGpuVmin,
KipConfigValue_marikoGpuVmax,
KipConfigValue_commonGpuVoltOffset,
KipConfigValue_gpuSpeedo,
KipConfigValue_g_volt_76800,
KipConfigValue_g_volt_153600,
KipConfigValue_g_volt_230400,
KipConfigValue_g_volt_307200,
KipConfigValue_g_volt_384000,
KipConfigValue_g_volt_460800,
KipConfigValue_g_volt_537600,
KipConfigValue_g_volt_614400,
KipConfigValue_g_volt_691200,
KipConfigValue_g_volt_768000,
KipConfigValue_g_volt_844800,
KipConfigValue_g_volt_921600,
KipConfigValue_g_volt_998400,
KipConfigValue_g_volt_1075200,
KipConfigValue_g_volt_1152000,
KipConfigValue_g_volt_1228800,
KipConfigValue_g_volt_1267200,
KipConfigValue_g_volt_1305600,
KipConfigValue_g_volt_1344000,
KipConfigValue_g_volt_1382400,
KipConfigValue_g_volt_1420800,
KipConfigValue_g_volt_1459200,
KipConfigValue_g_volt_1497600,
KipConfigValue_g_volt_1536000,
KipConfigValue_g_volt_e_76800,
KipConfigValue_g_volt_e_115200,
KipConfigValue_g_volt_e_153600,
KipConfigValue_g_volt_e_192000,
KipConfigValue_g_volt_e_230400,
KipConfigValue_g_volt_e_268800,
KipConfigValue_g_volt_e_307200,
KipConfigValue_g_volt_e_345600,
KipConfigValue_g_volt_e_384000,
KipConfigValue_g_volt_e_422400,
KipConfigValue_g_volt_e_460800,
KipConfigValue_g_volt_e_499200,
KipConfigValue_g_volt_e_537600,
KipConfigValue_g_volt_e_576000,
KipConfigValue_g_volt_e_614400,
KipConfigValue_g_volt_e_652800,
KipConfigValue_g_volt_e_691200,
KipConfigValue_g_volt_e_729600,
KipConfigValue_g_volt_e_768000,
KipConfigValue_g_volt_e_806400,
KipConfigValue_g_volt_e_844800,
KipConfigValue_g_volt_e_883200,
KipConfigValue_g_volt_e_921600,
KipConfigValue_g_volt_e_960000,
KipConfigValue_g_volt_e_998400,
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,
} SysClkConfigValue;
typedef struct {
uint64_t values[SysClkConfigValue_EnumMax];
} SysClkConfigValueList;
static inline const char* sysclkFormatConfigValue(SysClkConfigValue val, bool pretty)
{
switch(val)
{
case SysClkConfigValue_PollingIntervalMs:
return pretty ? "Polling Interval (ms)" : "poll_interval_ms";
case SysClkConfigValue_TempLogIntervalMs:
return pretty ? "Temperature logging interval (ms)" : "temp_log_interval_ms";
case SysClkConfigValue_FreqLogIntervalMs:
return pretty ? "Frequency logging interval (ms)" : "freq_log_interval_ms";
case SysClkConfigValue_PowerLogIntervalMs:
return pretty ? "Power logging interval (ms)" : "power_log_interval_ms";
case SysClkConfigValue_CsvWriteIntervalMs:
return pretty ? "CSV write interval (ms)" : "csv_write_interval_ms";
case HocClkConfigValue_UncappedClocks:
return pretty ? "Uncapped Clocks" : "uncapped_clocks";
case HocClkConfigValue_OverwriteBoostMode:
return pretty ? "Overwrite Boost Mode" : "ow_boost";
case HocClkConfigValue_EristaMaxCpuClock:
return pretty ? "CPU Max Clock" : "cpu_max_e";
case HocClkConfigValue_MarikoMaxCpuClock:
return pretty ? "CPU Max Display Clock" : "cpu_max_m";
case HocClkConfigValue_ThermalThrottle:
return pretty ? "Thermal Throttle" : "thermal_throttle";
case HocClkConfigValue_ThermalThrottleThreshold:
return pretty ? "Thermal Throttle Threshold" : "thermal_throttle_threshold";
case HocClkConfigValue_HandheldTDP:
return pretty ? "Handheld TDP" : "handheld_tdp";
case HocClkConfigValue_HandheldTDPLimit:
return pretty ? "Handheld TDP Limit" : "tdp_limit";
case HocClkConfigValue_LiteTDPLimit:
return pretty ? "Handheld TDP Limit" : "tdp_limit_l";
case HorizonOCConfigValue_BatteryChargeCurrent:
return pretty ? "Battery Charge Current" : "bat_charge_current";
case HorizonOCConfigValue_OverwriteRefreshRate:
return pretty ? "Display Refresh Rate Changing" : "drr_changing";
case HorizonOCConfigValue_MaxDisplayClockH:
return pretty ? "Max Display Clock (Handheld)" : "drr_max_clock";
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";
case HorizonOCConfigValue_GPUSchedulingMethod:
return pretty ? "GPU Scheduling Method" : "gpu_sched_method";
case HorizonOCConfigValue_LiveCpuUv:
return pretty ? "Live CPU Undervolt" : "live_cpu_uv";
case HorizonOCConfigValue_EnableExperimentalSettings:
return pretty ? "Enable Experimental Settings" : "enable_experimental_settings";
case HorizonOCConfigValue_RAMVoltUsageDisplayMode:
return pretty ? "RAM Voltage / Usage Display Mode" : "ram_volt_usage_display_mode";
case HorizonOCConfigValue_CpuGovernorMinimumFreq:
return pretty ? "CPU Governor Minimum Frequency" : "cpu_gov_min_freq";
// 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_hpMode:
return pretty ? "HP Mode" : "kip_hp_mode";
// EMC
case KipConfigValue_commonEmcMemVolt:
return pretty ? "Common EMC/MEM Voltage" : "common_emc_mem_volt";
case KipConfigValue_eristaEmcMaxClock:
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:
return pretty ? "Mariko EMC VDDQ Voltage" : "mariko_emc_vddq_volt";
case KipConfigValue_emcDvbShift:
return pretty ? "EMC DVB Shift" : "emc_dvb_shift";
// Memory timings
case KipConfigValue_t1_tRCD:
return pretty ? "t1 - tRCD" : "t1_trcd";
case KipConfigValue_t2_tRP:
return pretty ? "t2 - tRP" : "t2_trp";
case KipConfigValue_t3_tRAS:
return pretty ? "t3 - tRAS" : "t3_tras";
case KipConfigValue_t4_tRRD:
return pretty ? "t4 - tRRD" : "t4_trrd";
case KipConfigValue_t5_tRFC:
return pretty ? "t5 - tRFC" : "t5_trfc";
case KipConfigValue_t6_tRTW:
return pretty ? "t6 - tRTW" : "t6_trtw";
case KipConfigValue_t7_tWTR:
return pretty ? "t7 - tWTR" : "t7_twtr";
case KipConfigValue_t8_tREFI:
return pretty ? "t8 - tREFI" : "t8_trefi";
case KipConfigValue_mem_burst_read_latency:
return pretty ? "Memory Burst Read Latency" : "mem_burst_read_latency";
case KipConfigValue_mem_burst_write_latency:
return pretty ? "Memory Burst Write Latency" : "mem_burst_write_latency";
// CPU Erista
case KipConfigValue_eristaCpuUV:
return pretty ? "Erista CPU Undervolt" : "erista_cpu_uv";
case KipConfigValue_eristaCpuVmin:
return pretty ? "Erista CPU vMin" : "erista_cpu_vmin";
case KipConfigValue_eristaCpuMaxVolt:
return pretty ? "Erista CPU Max Voltage" : "erista_cpu_max_volt";
case KipConfigValue_eristaCpuUnlock:
return pretty ? "Erista CPU Unlock" : "erista_cpu_unlock";
// CPU Mariko
case KipConfigValue_marikoCpuUVLow:
return pretty ? "Mariko CPU Undervolt (Low)" : "mariko_cpu_uv_low";
case KipConfigValue_marikoCpuUVHigh:
return pretty ? "Mariko CPU Undervolt (High)" : "mariko_cpu_uv_high";
case KipConfigValue_tableConf:
return pretty ? "Table Config" : "kip_table_conf";
case KipConfigValue_marikoCpuLowVmin:
return pretty ? "Mariko CPU Low Vmin" : "mariko_cpu_low_vmin";
case KipConfigValue_marikoCpuHighVmin:
return pretty ? "Mariko CPU High Vmin" : "mariko_cpu_high_vmin";
case KipConfigValue_marikoCpuMaxVolt:
return pretty ? "Mariko CPU Max Voltage" : "mariko_cpu_max_volt";
case KipConfigValue_eristaCpuBoostClock:
return pretty ? "Erista CPU Boost Clock" : "erista_cpu_boost_clock";
case KipConfigValue_marikoCpuBoostClock:
return pretty ? "Mariko CPU Boost Clock" : "mariko_cpu_boost_clock";
case KipConfigValue_marikoCpuMaxClock:
return pretty ? "Mariko CPU Max Clock" : "mariko_cpu_max_clock";
// GPU Erista
case KipConfigValue_eristaGpuUV:
return pretty ? "Erista GPU Undervolt" : "erista_gpu_uv";
case KipConfigValue_eristaGpuVmin:
return pretty ? "Erista GPU Vmin" : "erista_gpu_vmin";
// GPU Mariko
case KipConfigValue_marikoGpuUV:
return pretty ? "Mariko GPU Undervolt" : "mariko_gpu_uv";
case KipConfigValue_marikoGpuVmin:
return pretty ? "Mariko GPU Vmin" : "mariko_gpu_vmin";
case KipConfigValue_marikoGpuVmax:
return pretty ? "Mariko GPU Vmax" : "mariko_gpu_vmax";
case KipConfigValue_commonGpuVoltOffset:
return pretty ? "Common GPU Voltage Offset" : "common_gpu_volt_offset";
case KipConfigValue_gpuSpeedo:
return pretty ? "GPU Speedo" : "gpu_speedo";
// Mariko GPU voltages (24)
case KipConfigValue_g_volt_76800: return pretty ? "Mariko GPU Volt 76 MHz" : "g_volt_76800";
case KipConfigValue_g_volt_153600: return pretty ? "Mariko GPU Volt 153 MHz" : "g_volt_153600";
case KipConfigValue_g_volt_230400: return pretty ? "Mariko GPU Volt 230 MHz" : "g_volt_230400";
case KipConfigValue_g_volt_307200: return pretty ? "Mariko GPU Volt 307 MHz" : "g_volt_307200";
case KipConfigValue_g_volt_384000: return pretty ? "Mariko GPU Volt 384 MHz" : "g_volt_384000";
case KipConfigValue_g_volt_460800: return pretty ? "Mariko GPU Volt 460 MHz" : "g_volt_460800";
case KipConfigValue_g_volt_537600: return pretty ? "Mariko GPU Volt 537 MHz" : "g_volt_537600";
case KipConfigValue_g_volt_614400: return pretty ? "Mariko GPU Volt 614 MHz" : "g_volt_614400";
case KipConfigValue_g_volt_691200: return pretty ? "Mariko GPU Volt 691 MHz" : "g_volt_691200";
case KipConfigValue_g_volt_768000: return pretty ? "Mariko GPU Volt 768 MHz" : "g_volt_768000";
case KipConfigValue_g_volt_844800: return pretty ? "Mariko GPU Volt 844 MHz" : "g_volt_844800";
case KipConfigValue_g_volt_921600: return pretty ? "Mariko GPU Volt 921 MHz" : "g_volt_921600";
case KipConfigValue_g_volt_998400: return pretty ? "Mariko GPU Volt 998 MHz" : "g_volt_998400";
case KipConfigValue_g_volt_1075200: return pretty ? "Mariko GPU Volt 1075 MHz" : "g_volt_1075200";
case KipConfigValue_g_volt_1152000: return pretty ? "Mariko GPU Volt 1152 MHz" : "g_volt_1152000";
case KipConfigValue_g_volt_1228800: return pretty ? "Mariko GPU Volt 1228 MHz" : "g_volt_1228800";
case KipConfigValue_g_volt_1267200: return pretty ? "Mariko GPU Volt 1267 MHz" : "g_volt_1267200";
case KipConfigValue_g_volt_1305600: return pretty ? "Mariko GPU Volt 1305 MHz" : "g_volt_1305600";
case KipConfigValue_g_volt_1344000: return pretty ? "Mariko GPU Volt 1344 MHz" : "g_volt_1344000";
case KipConfigValue_g_volt_1382400: return pretty ? "Mariko GPU Volt 1382 MHz" : "g_volt_1382400";
case KipConfigValue_g_volt_1420800: return pretty ? "Mariko GPU Volt 1420 MHz" : "g_volt_1420800";
case KipConfigValue_g_volt_1459200: return pretty ? "Mariko GPU Volt 1459 MHz" : "g_volt_1459200";
case KipConfigValue_g_volt_1497600: return pretty ? "Mariko GPU Volt 1497 MHz" : "g_volt_1497600";
case KipConfigValue_g_volt_1536000: return pretty ? "Mariko GPU Volt 1536 MHz" : "g_volt_1536000";
// Erista GPU voltages (27)
case KipConfigValue_g_volt_e_76800: return pretty ? "Erista GPU Volt 76 MHz" : "g_volt_e_76800";
case KipConfigValue_g_volt_e_115200: return pretty ? "Erista GPU Volt 115 MHz" : "g_volt_e_115200";
case KipConfigValue_g_volt_e_153600: return pretty ? "Erista GPU Volt 153 MHz" : "g_volt_e_153600";
case KipConfigValue_g_volt_e_192000: return pretty ? "Erista GPU Volt 192 MHz" : "g_volt_e_192000";
case KipConfigValue_g_volt_e_230400: return pretty ? "Erista GPU Volt 230 MHz" : "g_volt_e_230400";
case KipConfigValue_g_volt_e_268800: return pretty ? "Erista GPU Volt 268 MHz" : "g_volt_e_268800";
case KipConfigValue_g_volt_e_307200: return pretty ? "Erista GPU Volt 307 MHz" : "g_volt_e_307200";
case KipConfigValue_g_volt_e_345600: return pretty ? "Erista GPU Volt 345 MHz" : "g_volt_e_345600";
case KipConfigValue_g_volt_e_384000: return pretty ? "Erista GPU Volt 384 MHz" : "g_volt_e_384000";
case KipConfigValue_g_volt_e_422400: return pretty ? "Erista GPU Volt 422 MHz" : "g_volt_e_422400";
case KipConfigValue_g_volt_e_460800: return pretty ? "Erista GPU Volt 460 MHz" : "g_volt_e_460800";
case KipConfigValue_g_volt_e_499200: return pretty ? "Erista GPU Volt 499 MHz" : "g_volt_e_499200";
case KipConfigValue_g_volt_e_537600: return pretty ? "Erista GPU Volt 537 MHz" : "g_volt_e_537600";
case KipConfigValue_g_volt_e_576000: return pretty ? "Erista GPU Volt 576 MHz" : "g_volt_e_576000";
case KipConfigValue_g_volt_e_614400: return pretty ? "Erista GPU Volt 614 MHz" : "g_volt_e_614400";
case KipConfigValue_g_volt_e_652800: return pretty ? "Erista GPU Volt 652 MHz" : "g_volt_e_652800";
case KipConfigValue_g_volt_e_691200: return pretty ? "Erista GPU Volt 691 MHz" : "g_volt_e_691200";
case KipConfigValue_g_volt_e_729600: return pretty ? "Erista GPU Volt 729 MHz" : "g_volt_e_729600";
case KipConfigValue_g_volt_e_768000: return pretty ? "Erista GPU Volt 768 MHz" : "g_volt_e_768000";
case KipConfigValue_g_volt_e_806400: return pretty ? "Erista GPU Volt 806 MHz" : "g_volt_e_806400";
case KipConfigValue_g_volt_e_844800: return pretty ? "Erista GPU Volt 844 MHz" : "g_volt_e_844800";
case KipConfigValue_g_volt_e_883200: return pretty ? "Erista GPU Volt 883 MHz" : "g_volt_e_883200";
case KipConfigValue_g_volt_e_921600: return pretty ? "Erista GPU Volt 921 MHz" : "g_volt_e_921600";
case KipConfigValue_g_volt_e_960000: return pretty ? "Erista GPU Volt 960 MHz" : "g_volt_e_960000";
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:
return pretty ? "Is First Load" : "is_first_load";
default:
return pretty ? "[cfg] no enum format string" : "err_no_format_string";
}
}
static inline uint64_t sysclkDefaultConfigValue(SysClkConfigValue val)
{
switch(val)
{
case SysClkConfigValue_PollingIntervalMs:
return 300ULL;
case SysClkConfigValue_TempLogIntervalMs:
case SysClkConfigValue_FreqLogIntervalMs:
case SysClkConfigValue_PowerLogIntervalMs:
case SysClkConfigValue_CsvWriteIntervalMs:
case HocClkConfigValue_UncappedClocks:
case HocClkConfigValue_OverwriteBoostMode:
case HorizonOCConfigValue_BatteryChargeCurrent:
case HorizonOCConfigValue_OverwriteRefreshRate:
case HorizonOCConfigValue_GPUScheduling:
case HorizonOCConfigValue_LiveCpuUv:
case HorizonOCConfigValue_GPUSchedulingMethod:
return 0ULL;
case HocClkConfigValue_EristaMaxCpuClock:
return 1785ULL;
case HocClkConfigValue_MarikoMaxCpuClock:
return 1963ULL;
case HocClkConfigValue_ThermalThrottle:
case HocClkConfigValue_HandheldTDP:
case HocClkConfigValue_IsFirstLoad:
case HorizonOCConfigValue_DVFSMode:
return 1ULL;
case HocClkConfigValue_ThermalThrottleThreshold:
return 70ULL;
case HocClkConfigValue_HandheldTDPLimit:
return 9600ULL; // 8600mW will trigger on erista stock, so raise it a bit
case HocClkConfigValue_LiteTDPLimit:
return 6400ULL; // 0.5C
case HorizonOCConfigValue_CpuGovernorMinimumFreq:
return 612000000ULL; // 612MHz
case HorizonOCConfigValue_MaxDisplayClockH:
return 60ULL;
default:
return 0ULL;
}
}
static inline uint64_t sysclkValidConfigValue(SysClkConfigValue val, uint64_t input)
{
switch(val)
{
case HocClkConfigValue_EristaMaxCpuClock:
case HocClkConfigValue_MarikoMaxCpuClock:
case HocClkConfigValue_ThermalThrottleThreshold:
case HocClkConfigValue_HandheldTDPLimit:
case HocClkConfigValue_LiteTDPLimit:
case SysClkConfigValue_PollingIntervalMs:
case HorizonOCConfigValue_MaxDisplayClockH:
return input > 0;
case SysClkConfigValue_TempLogIntervalMs:
case SysClkConfigValue_FreqLogIntervalMs:
case SysClkConfigValue_PowerLogIntervalMs:
case SysClkConfigValue_CsvWriteIntervalMs:
case HocClkConfigValue_UncappedClocks:
case HocClkConfigValue_OverwriteBoostMode:
case HocClkConfigValue_ThermalThrottle:
case HocClkConfigValue_HandheldTDP:
case HorizonOCConfigValue_OverwriteRefreshRate:
case HocClkConfigValue_IsFirstLoad:
case HorizonOCConfigValue_EnableExperimentalSettings:
case HorizonOCConfigValue_LiveCpuUv:
case HorizonOCConfigValue_GPUSchedulingMethod:
return (input & 0x1) == input;
case KipConfigValue_custRev:
// 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:
case KipConfigValue_t1_tRCD:
case KipConfigValue_t2_tRP:
case KipConfigValue_t3_tRAS:
case KipConfigValue_t4_tRRD:
case KipConfigValue_t5_tRFC:
case KipConfigValue_t6_tRTW:
case KipConfigValue_t7_tWTR:
case KipConfigValue_t8_tREFI:
case KipConfigValue_mem_burst_read_latency:
case KipConfigValue_mem_burst_write_latency:
case KipConfigValue_eristaCpuUV:
case KipConfigValue_eristaCpuMaxVolt:
case KipConfigValue_marikoCpuUVLow:
case KipConfigValue_marikoCpuUVHigh:
case KipConfigValue_tableConf:
case KipConfigValue_marikoCpuLowVmin:
case KipConfigValue_marikoCpuHighVmin:
case KipConfigValue_marikoCpuMaxVolt:
case KipConfigValue_eristaCpuBoostClock:
case KipConfigValue_marikoCpuBoostClock:
case KipConfigValue_marikoCpuMaxClock:
case KipConfigValue_eristaGpuUV:
case KipConfigValue_eristaGpuVmin:
case KipConfigValue_marikoGpuUV:
case KipConfigValue_marikoGpuVmin:
case KipConfigValue_marikoGpuVmax:
case KipConfigValue_commonGpuVoltOffset:
case KipConfigValue_gpuSpeedo:
case KipConfigValue_g_volt_76800:
case KipConfigValue_g_volt_153600:
case KipConfigValue_g_volt_230400:
case KipConfigValue_g_volt_307200:
case KipConfigValue_g_volt_384000:
case KipConfigValue_g_volt_460800:
case KipConfigValue_g_volt_537600:
case KipConfigValue_g_volt_614400:
case KipConfigValue_g_volt_691200:
case KipConfigValue_g_volt_768000:
case KipConfigValue_g_volt_844800:
case KipConfigValue_g_volt_921600:
case KipConfigValue_g_volt_998400:
case KipConfigValue_g_volt_1075200:
case KipConfigValue_g_volt_1152000:
case KipConfigValue_g_volt_1228800:
case KipConfigValue_g_volt_1267200:
case KipConfigValue_g_volt_1305600:
case KipConfigValue_g_volt_1344000:
case KipConfigValue_g_volt_1382400:
case KipConfigValue_g_volt_1420800:
case KipConfigValue_g_volt_1459200:
case KipConfigValue_g_volt_1497600:
case KipConfigValue_g_volt_1536000:
case KipConfigValue_g_volt_e_76800:
case KipConfigValue_g_volt_e_115200:
case KipConfigValue_g_volt_e_153600:
case KipConfigValue_g_volt_e_192000:
case KipConfigValue_g_volt_e_230400:
case KipConfigValue_g_volt_e_268800:
case KipConfigValue_g_volt_e_307200:
case KipConfigValue_g_volt_e_345600:
case KipConfigValue_g_volt_e_384000:
case KipConfigValue_g_volt_e_422400:
case KipConfigValue_g_volt_e_460800:
case KipConfigValue_g_volt_e_499200:
case KipConfigValue_g_volt_e_537600:
case KipConfigValue_g_volt_e_576000:
case KipConfigValue_g_volt_e_614400:
case KipConfigValue_g_volt_e_652800:
case KipConfigValue_g_volt_e_691200:
case KipConfigValue_g_volt_e_729600:
case KipConfigValue_g_volt_e_768000:
case KipConfigValue_g_volt_e_806400:
case KipConfigValue_g_volt_e_844800:
case KipConfigValue_g_volt_e_883200:
case KipConfigValue_g_volt_e_921600:
case KipConfigValue_g_volt_e_960000:
case KipConfigValue_g_volt_e_998400:
case KipConfigValue_g_volt_e_1036800:
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:
case HorizonOCConfigValue_RAMVoltUsageDisplayMode:
case HorizonOCConfigValue_CpuGovernorMinimumFreq:
return true;
case HorizonOCConfigValue_BatteryChargeCurrent:
return ((input >= 1024) && (input <= 3072)) || !input;
default:
return false;
}
}

View File

@@ -0,0 +1,39 @@
/*
* 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/>.
*
*/
/* --------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
* wrote this file. As long as you retain this notice you can do whatever you
* want with this stuff. If you meet any of us some day, and you think this
* stuff is worth it, you can buy us a beer in return. - The sys-clk authors
* --------------------------------------------------------------------------
*/
#pragma once
#define SYSCLK_ERROR_MODULE 388
#define SYSCLK_ERROR(desc) ((SYSCLK_ERROR_MODULE & 0x1FF) | (SysClkError_##desc & 0x1FFF)<<9)
typedef enum
{
SysClkError_Generic = 0,
SysClkError_ConfigNotLoaded = 1,
SysClkError_ConfigSaveFailed = 2,
// HocClkError_SocThermFail = 3,
} SysClkError;

View File

@@ -0,0 +1,72 @@
/*
* 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/>.
*
*/
/* --------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
* wrote this file. As long as you retain this notice you can do whatever you
* want with this stuff. If you meet any of us some day, and you think this
* stuff is worth it, you can buy us a beer in return. - The sys-clk authors
* --------------------------------------------------------------------------
*/
#pragma once
#include <stdint.h>
#include "board.h"
#include "clock_manager.h"
#define SYSCLK_IPC_API_VERSION 1
#define SYSCLK_IPC_SERVICE_NAME "hoc:clk"
enum SysClkIpcCmd
{
SysClkIpcCmd_GetApiVersion = 0,
SysClkIpcCmd_GetVersionString = 1,
SysClkIpcCmd_GetCurrentContext = 2,
SysClkIpcCmd_Exit = 3,
SysClkIpcCmd_GetProfileCount = 4,
SysClkIpcCmd_GetProfiles = 5,
SysClkIpcCmd_SetProfiles = 6,
SysClkIpcCmd_SetEnabled = 7,
SysClkIpcCmd_SetOverride = 8,
SysClkIpcCmd_GetConfigValues = 9,
SysClkIpcCmd_SetConfigValues = 10,
SysClkIpcCmd_GetFreqList = 11,
HocClkIpcCmd_SetKipData = 12,
HocClkIpcCmd_GetKipData = 13,
};
typedef struct
{
uint64_t tid;
SysClkTitleProfileList profiles;
} SysClkIpc_SetProfiles_Args;
typedef struct
{
SysClkModule module;
uint32_t hz;
} SysClkIpc_SetOverride_Args;
typedef struct
{
SysClkModule module;
uint32_t maxCount;
} SysClkIpc_GetFreqList_Args;

View File

@@ -0,0 +1,94 @@
/*
* Copyright (c) KazushiMe
*
* 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 <switch.h>
typedef enum {
PsmPDC_NewPDO = 1, //Received new Power Data Object
PsmPDC_NoPD = 2, //No Power Delivery source is detected
PsmPDC_AcceptedRDO = 3 //Received and accepted Request Data Object
} PsmChargeInfoPDC; //BM92T series
typedef enum {
PsmPowerRole_Sink = 1,
PsmPowerRole_Source = 2
} PsmPowerRole;
const char* PsmPowerRoleToStr(PsmPowerRole role);
typedef enum {
PsmInfoChargerType_None = 0,
PsmInfoChargerType_PD = 1,
PsmInfoChargerType_TypeC_1500mA = 2,
PsmInfoChargerType_TypeC_3000mA = 3,
PsmInfoChargerType_DCP = 4,
PsmInfoChargerType_CDP = 5,
PsmInfoChargerType_SDP = 6,
PsmInfoChargerType_Apple_500mA = 7,
PsmInfoChargerType_Apple_1000mA = 8,
PsmInfoChargerType_Apple_2000mA = 9
} PsmInfoChargerType;
const char* PsmInfoChargerTypeToStr(PsmInfoChargerType type);
typedef enum {
PsmFlags_NoHub = BIT(0), //If hub is disconnected
PsmFlags_Rail = BIT(8), //At least one Joy-con is charging from rail
PsmFlags_SPDSRC = BIT(12), //OTG
PsmFlags_ACC = BIT(16) //Accessory
} PsmChargeInfoFlags;
typedef struct {
int32_t InputCurrentLimit; //Input (Sink) current limit in mA
int32_t VBUSCurrentLimit; //Output (Source/VBUS/OTG) current limit in mA
int32_t ChargeCurrentLimit; //Battery charging current limit in mA (512mA when Docked, 768mA when BatteryTemperature < 17.0 C)
int32_t ChargeVoltageLimit; //Battery charging voltage limit in mV (3952mV when BatteryTemperature >= 51.0 C)
int32_t unk_x10; //Possibly an emum, getting the same value as PowerRole in all tested cases
int32_t unk_x14; //Possibly flags
PsmChargeInfoPDC PDCState; //Power Delivery Controller State
int32_t BatteryTemperature; //Battery temperature in milli C
int32_t RawBatteryCharge; //Raw battery charged capacity per cent-mille (i.e. 100% = 100000 pcm)
int32_t VoltageAvg; //Voltage avg in mV (more in Notes)
int32_t BatteryAge; //Battery age (capacity full / capacity design) per cent-mille (i.e. 100% = 100000 pcm)
PsmPowerRole PowerRole;
PsmInfoChargerType ChargerType;
int32_t ChargerVoltageLimit; //Charger and external device voltage limit in mV
int32_t ChargerCurrentLimit; //Charger and external device current limit in mA
PsmChargeInfoFlags Flags; //Unknown flags
} PsmChargeInfo;
typedef enum {
Psm_EnableBatteryCharging = 2,
Psm_DisableBatteryCharging = 3,
Psm_EnableFastBatteryCharging = 10,
Psm_DisableFastBatteryCharging = 11,
Psm_GetBatteryChargeInfoFields = 17,
} IPsmServerCmd;
bool PsmIsChargerConnected(const PsmChargeInfo* info);
bool PsmIsCharging(const PsmChargeInfo* info);
typedef enum {
PsmBatteryState_Discharging,
PsmBatteryState_ChargingPaused,
PsmBatteryState_FastCharging
} PsmBatteryState;
PsmBatteryState PsmGetBatteryState(const PsmChargeInfo* info);
const char* PsmGetBatteryStateIcon(const PsmChargeInfo* info);

View File

@@ -0,0 +1,49 @@
/*
* 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/>.
*
*/
/* --------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
* wrote this file. As long as you retain this notice you can do whatever you
* want with this stuff. If you meet any of us some day, and you think this
* stuff is worth it, you can buy us a beer in return. - The sys-clk authors
* --------------------------------------------------------------------------
*/
#include <sysclk/apm.h>
SysClkApmConfiguration sysclk_g_apm_configurations[] = {
{0x00010000, 1020000000, 384000000, 1600000000},
{0x00010001, 1020000000, 768000000, 1600000000},
{0x00010002, 1224000000, 691200000, 1600000000},
{0x00020000, 1020000000, 230400000, 1600000000},
{0x00020001, 1020000000, 307200000, 1600000000},
{0x00020002, 1224000000, 230400000, 1600000000},
{0x00020003, 1020000000, 307200000, 1331200000},
{0x00020004, 1020000000, 384000000, 1331200000},
{0x00020005, 1020000000, 307200000, 1065600000},
{0x00020006, 1020000000, 384000000, 1065600000},
{0x92220007, 1020000000, 460800000, 1600000000},
{0x92220008, 1020000000, 460800000, 1331200000},
{0x92220009, 1785000000, 76800000, 1600000000},
{0x9222000A, 1785000000, 76800000, 1331200000},
{0x9222000B, 1020000000, 76800000, 1600000000},
{0x9222000C, 1020000000, 76800000, 1331200000},
{0, 0, 0, 0},
};

View File

@@ -0,0 +1,169 @@
/*
* 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/>.
*
*/
/* --------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
* wrote this file. As long as you retain this notice you can do whatever you
* want with this stuff. If you meet any of us some day, and you think this
* stuff is worth it, you can buy us a beer in return. - The sys-clk authors
* --------------------------------------------------------------------------
*/
#define NX_SERVICE_ASSUME_NON_DOMAIN
#include <switch.h>
#include <string.h>
#include <stdatomic.h>
#include <sysclk/client/ipc.h>
static Service g_sysclkSrv;
static atomic_size_t g_refCnt;
bool sysclkIpcRunning()
{
Handle handle;
bool running = R_FAILED(smRegisterService(&handle, smEncodeName(SYSCLK_IPC_SERVICE_NAME), false, 1));
if (!running)
{
smUnregisterService(smEncodeName(SYSCLK_IPC_SERVICE_NAME));
}
return running;
}
Result sysclkIpcInitialize(void)
{
Result rc = 0;
g_refCnt++;
if (serviceIsActive(&g_sysclkSrv))
return 0;
rc = smGetService(&g_sysclkSrv, SYSCLK_IPC_SERVICE_NAME);
if (R_FAILED(rc)) sysclkIpcExit();
return rc;
}
void sysclkIpcExit(void)
{
if (--g_refCnt == 0)
{
serviceClose(&g_sysclkSrv);
}
}
Result sysclkIpcGetAPIVersion(u32* out_ver)
{
return serviceDispatchOut(&g_sysclkSrv, SysClkIpcCmd_GetApiVersion, *out_ver);
}
Result sysclkIpcGetVersionString(char* out, size_t len)
{
return serviceDispatch(&g_sysclkSrv, SysClkIpcCmd_GetVersionString,
.buffer_attrs = { SfBufferAttr_HipcAutoSelect | SfBufferAttr_Out },
.buffers = {{out, len}},
);
}
Result sysclkIpcGetCurrentContext(SysClkContext* out_context)
{
return serviceDispatch(&g_sysclkSrv, SysClkIpcCmd_GetCurrentContext,
.buffer_attrs = { SfBufferAttr_HipcAutoSelect | SfBufferAttr_Out },
.buffers = {{out_context, sizeof(SysClkContext)}},
);
}
Result sysclkIpcGetProfileCount(u64 tid, u8* out_count)
{
return serviceDispatchInOut(&g_sysclkSrv, SysClkIpcCmd_GetProfileCount, tid, *out_count);
}
Result sysclkIpcSetEnabled(bool enabled)
{
u8 enabledRaw = (u8)enabled;
return serviceDispatchIn(&g_sysclkSrv, SysClkIpcCmd_SetEnabled, enabledRaw);
}
Result sysclkIpcSetOverride(SysClkModule module, u32 hz)
{
SysClkIpc_SetOverride_Args args = {
.module = module,
.hz = hz
};
return serviceDispatchIn(&g_sysclkSrv, SysClkIpcCmd_SetOverride, args);
}
Result sysclkIpcGetProfiles(u64 tid, SysClkTitleProfileList* out_profiles)
{
return serviceDispatchIn(&g_sysclkSrv, SysClkIpcCmd_GetProfiles, tid,
.buffer_attrs = { SfBufferAttr_HipcAutoSelect | SfBufferAttr_Out },
.buffers = {{out_profiles, sizeof(SysClkTitleProfileList)}},
);
}
Result sysclkIpcSetProfiles(u64 tid, SysClkTitleProfileList* profiles)
{
SysClkIpc_SetProfiles_Args args;
args.tid = tid;
memcpy(&args.profiles, profiles, sizeof(SysClkTitleProfileList));
return serviceDispatchIn(&g_sysclkSrv, SysClkIpcCmd_SetProfiles, args);
}
Result sysclkIpcGetConfigValues(SysClkConfigValueList* out_configValues)
{
return serviceDispatch(&g_sysclkSrv, SysClkIpcCmd_GetConfigValues,
.buffer_attrs = { SfBufferAttr_HipcAutoSelect | SfBufferAttr_Out },
.buffers = {{out_configValues, sizeof(SysClkConfigValueList)}},
);
}
Result sysclkIpcSetConfigValues(SysClkConfigValueList* configValues)
{
return serviceDispatch(&g_sysclkSrv, SysClkIpcCmd_SetConfigValues,
.buffer_attrs = { SfBufferAttr_HipcAutoSelect | SfBufferAttr_In },
.buffers = {{configValues, sizeof(SysClkConfigValueList)}},
);
}
Result sysclkIpcGetFreqList(SysClkModule module, u32* list, u32 maxCount, u32* outCount)
{
SysClkIpc_GetFreqList_Args args = {
.module = module,
.maxCount = maxCount
};
return serviceDispatchInOut(&g_sysclkSrv, SysClkIpcCmd_GetFreqList, args, *outCount,
.buffer_attrs = { SfBufferAttr_HipcAutoSelect | SfBufferAttr_Out },
.buffers = {{list, maxCount * sizeof(u32)}},
);
}
Result hocClkIpcSetKipData()
{
u32 temp = 0;
return serviceDispatchIn(&g_sysclkSrv, HocClkIpcCmd_SetKipData, temp);
}
Result hocClkIpcGetKipData()
{
u32 temp = 0;
return serviceDispatchIn(&g_sysclkSrv, HocClkIpcCmd_GetKipData, temp);
}

View File

@@ -0,0 +1,720 @@
/*
* Copyright (c) Souldbminer, based on reasearch by MasaGratoR and Cooler3D
*
* 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 "display_refresh_rate.h"
#include <string.h>
#include <math.h>
#include <stdarg.h>
#include <switch.h>
#define DSI_CLOCK_HZ 234000000llu
#define NVDISP_GET_MODE2 0x803C021B
#define NVDISP_SET_MODE2 0x403C021C
#define NVDISP_VALIDATE_MODE2 0xC03C021D
#define NVDISP_GET_MODE_DB2 0xEF20021E
#define NVDISP_GET_PANEL_DATA 0xC01C0226
#define MAX_REFRESH_RATE 72
static DisplayRefreshConfig g_config = {0};
static bool g_initialized = false;
static uint8_t g_dockedHighestRefreshRate = 60;
static uint8_t g_dockedLinkRate = 10;
static bool g_wasRetroSuperTurnedOff = false;
static uint32_t g_lastVActive = 1080;
static bool g_canChangeRefreshRateDocked = false;
static uint8_t g_lastVActiveSet = 0;
static const uint8_t g_dockedRefreshRates[] = {40, 45, 50, 55, 60, 70, 72, 75, 80, 90, 95, 100, 110, 120, 130, 140, 144, 150, 160, 165, 170, 180, 190, 200, 210, 220, 230, 240};
// Calculate with this tool:
// https://tomverbeure.github.io/video_timings_calculator?horiz_pixels=1920&vert_pixels=1080&refresh_rate=240&margins=false&interlaced=false&bpc=8&color_fmt=rgb444&video_opt=false&custom_hblank=80&custom_vblank=6
/*
typedef struct {
uint16_t hFrontPorch;
uint8_t hSyncWidth;
uint8_t hBackPorch;
uint8_t vFrontPorch;
uint8_t vSyncWidth;
uint8_t vBackPorch;
uint8_t VIC;
uint32_t pixelClock_kHz;
} DockedTimings;
*/
static const DockedTimings g_dockedTimings1080p[] = {
{8, 32, 40, 7, 8, 6, 0, 88080}, // 40Hz
{8, 32, 40, 9, 8, 6, 0, 99270}, // 45Hz
{528, 44, 148, 4, 5, 36, 31, 148500}, // 50Hz
{8, 32, 40, 15, 8, 6, 0, 121990}, // 55Hz
{88, 44, 148, 4, 5, 36, 16, 148500}, // 60Hz
{8, 32, 40, 22, 8, 6, 0, 156240}, // 70Hz
{8, 32, 40, 23, 8, 6, 0, 160848}, // 72Hz
{8, 32, 40, 25, 8, 6, 0, 167850}, // 75Hz
{8, 32, 40, 28, 8, 6, 0, 179520}, // 80Hz
{8, 32, 40, 33, 8, 6, 0, 202860}, // 90Hz
{8, 32, 40, 36, 8, 6, 0, 214700}, // 95Hz
{528, 44, 148, 4, 5, 36, 64, 297000}, // 100Hz
{8, 32, 40, 44, 8, 6, 0, 250360}, // 110Hz
{88, 44, 148, 4, 5, 36, 63, 297000}, // 120Hz
{8, 32, 40, 55, 8, 6, 0, 298750}, //130Hz CVT-RBv2
{8, 32, 40, 61, 8, 6, 0, 323400}, //140Hz CVT-RBv2
{8, 32, 40, 63, 8, 6, 0, 333216}, //144Hz CVT-RBv2
{8, 32, 40, 67, 8, 6, 0, 348300}, //150Hz CVT-RBv2
{8, 32, 40, 72, 8, 6, 0, 373120}, //160Hz CVT-RBv2
{8, 32, 40, 75, 8, 6, 0, 385770}, //165Hz CVT-RBv2
{8, 32, 40, 78, 8, 6, 0, 398480}, //170Hz CVT-RBv2
{8, 32, 40, 84, 8, 6, 0, 424080}, //180Hz CVT-RBv2
{8, 32, 40, 90, 8, 6, 0, 449920}, //190Hz CVT-RBv2
{8, 32, 40, 96, 8, 6, 0, 476000}, //200Hz CVT-RBv2
{8, 32, 40, 102, 8, 6, 0, 502320}, //210Hz CVT-RBv2
{8, 32, 40, 108, 8, 6, 0, 528880}, //220Hz CVT-RBv2
{8, 32, 40, 114, 8, 6, 0, 555680}, //230Hz CVT-RBv2
{8, 32, 40, 121, 8, 6, 0, 583200}, //240Hz CVT-RBv2
// technically you can go to 476hz, but in practice, why would you?
};
static const HandheldTimings g_handheldTimingsRETRO[] = {
{72, 136, 72, 1, 660, 9, 78000},
{72, 136, 72, 1, 443, 9, 77985},
{72, 136, 72, 1, 270, 9, 78000},
{72, 136, 72, 1, 128, 9, 77990},
{72, 136, 72, 1, 10, 9, 78000}
};
static const MinMaxRefreshRate g_handheldModeRefreshRate = {40, 80};
static uint8_t _getDockedRefreshRateIterator(uint32_t refreshRate) {
for (size_t i = 0; i < sizeof(g_dockedRefreshRates) / sizeof(g_dockedRefreshRates[0]); i++) {
if (g_dockedRefreshRates[i] == refreshRate) return i;
}
return 0xFF;
}
static void _changeOledElvssSettings(const uint32_t* offsets, const uint32_t* value, uint32_t size, uint32_t start) {
if (!g_config.dsiVirtAddr || !value || !size) return;
volatile uint32_t* dsi = (uint32_t*)g_config.dsiVirtAddr;
#define DSI_VIDEO_MODE_CONTROL 0x4E
#define DSI_WR_DATA 0xA
#define DSI_TRIGGER 0x13
#define MIPI_DSI_DCS_SHORT_WRITE_PARAM 0x15
#define MIPI_DSI_DCS_LONG_WRITE 0x39
#define MIPI_DCS_PRIV_SM_SET_REG_OFFSET 0xB0
#define MIPI_DCS_PRIV_SM_SET_ELVSS 0xB1
dsi[DSI_VIDEO_MODE_CONTROL] = true;
svcSleepThread(20000000);
dsi[DSI_WR_DATA] = MIPI_DSI_DCS_LONG_WRITE | (5 << 8);
dsi[DSI_WR_DATA] = 0x5A5A5AE2;
dsi[DSI_WR_DATA] = 0x5A;
dsi[DSI_TRIGGER] = 0;
for (size_t i = start; i < size; i++) {
dsi[DSI_WR_DATA] = ((MIPI_DCS_PRIV_SM_SET_REG_OFFSET | ((offsets[i] % 0x100) << 8)) << 8) | MIPI_DSI_DCS_SHORT_WRITE_PARAM;
dsi[DSI_TRIGGER] = 0;
dsi[DSI_WR_DATA] = ((MIPI_DCS_PRIV_SM_SET_ELVSS | (value[i] << 8)) << 8) | MIPI_DSI_DCS_SHORT_WRITE_PARAM;
dsi[DSI_TRIGGER] = 0;
}
dsi[DSI_WR_DATA] = MIPI_DSI_DCS_LONG_WRITE | (5 << 8);
dsi[DSI_WR_DATA] = 0xA55A5AE2;
dsi[DSI_WR_DATA] = 0xA5;
dsi[DSI_TRIGGER] = 0;
dsi[DSI_VIDEO_MODE_CONTROL] = false;
svcSleepThread(20000000);
}
void DisplayRefresh_SetDockedState(bool isDocked) {
g_config.isDocked = isDocked;
}
bool DisplayRefresh_Initialize(const DisplayRefreshConfig* config) {
if (!config) return false;
g_config = *config;
g_initialized = true;
return true;
}
void DisplayRefresh_CorrectOledGamma(uint32_t refresh_rate) {
static uint32_t last_refresh_rate = 60;
static int counter = 0;
if (g_config.isDocked || refresh_rate < 45 || refresh_rate > 60) {
last_refresh_rate = 60;
return;
}
if (counter != 9) {
counter++;
return;
}
counter = 0;
uint32_t offsets[] = {0x1A, 0x24, 0x25};
uint32_t values[] = {2, 0, 0x83};
if (refresh_rate == 60) {
if (last_refresh_rate == 60) return;
} else if (refresh_rate == 45) {
if (last_refresh_rate == 45) return;
uint32_t vals[] = {4, 1, 0};
memcpy(values, vals, sizeof(vals));
} else if (refresh_rate == 50) {
if (last_refresh_rate == 50) return;
uint32_t vals[] = {3, 1, 0};
memcpy(values, vals, sizeof(vals));
} else if (refresh_rate == 55) {
if (last_refresh_rate == 55) return;
uint32_t vals[] = {3, 1, 0};
memcpy(values, vals, sizeof(vals));
} else {
return;
}
for (int i = 0; i < 5; i++) {
_changeOledElvssSettings(offsets, values, 3, 0);
}
last_refresh_rate = refresh_rate;
}
void DisplayRefresh_SetAllowedDockedRatesIPC(uint32_t refreshRates, bool is720p) {
// Function kept for API compatibility but does nothing
(void)refreshRates;
(void)is720p;
}
uint8_t DisplayRefresh_GetDockedHighestAllowed(void) {
return (g_dockedHighestRefreshRate > 60) ? g_dockedHighestRefreshRate : 60;
}
static void _getDockedHighestRefreshRate(uint32_t fd_in) {
uint8_t highestRefreshRate = 60;
uint32_t fd = fd_in;
if(!fd) nvOpen(&fd, "/dev/nvdisp-disp1");
NvdcModeDB2 db2 = {0};
int rc = nvIoctl(fd, NVDISP_GET_MODE_DB2, &db2);
if (rc == 0) {
for (size_t i = 0; i < db2.num_modes; i++) {
if (db2.modes[i].hActive < 1920 || db2.modes[i].vActive < 1080)
continue;
uint32_t v_total = db2.modes[i].vActive + db2.modes[i].vSyncWidth + db2.modes[i].vFrontPorch + db2.modes[i].vBackPorch;
uint32_t h_total = db2.modes[i].hActive + db2.modes[i].hSyncWidth + db2.modes[i].hFrontPorch + db2.modes[i].hBackPorch;
double refreshRate = round((double)(db2.modes[i].pclkKHz * 1000) / (double)(v_total * h_total));
if (highestRefreshRate < (uint8_t)refreshRate)
highestRefreshRate = (uint8_t)refreshRate;
}
} else {
g_dockedHighestRefreshRate = 60;
}
const size_t numRates = sizeof(g_dockedRefreshRates) / sizeof(g_dockedRefreshRates[0]);
if (highestRefreshRate > g_dockedRefreshRates[numRates - 1])
highestRefreshRate = g_dockedRefreshRates[numRates - 1];
NvdcMode2 display_b = {0};
rc = nvIoctl(fd, NVDISP_GET_MODE2, &display_b);
struct dpaux_read_0x100 {
uint32_t cmd;
uint32_t addr;
uint32_t size;
struct {
unsigned char link_rate;
unsigned int lane_count: 5;
unsigned int unk1: 2;
unsigned int isFramingEnhanced: 1;
unsigned char downspread;
unsigned char training_pattern;
unsigned char lane_pattern[4];
unsigned char unk2[8];
} set;
} dpaux = {6, 0x100, 0x10};
rc = nvIoctl(fd, NVDISP_GET_PANEL_DATA, &dpaux);
if (rc == 0) {
g_dockedLinkRate = dpaux.set.link_rate;
// if (display_b.hActive == 1920 && display_b.vActive == 1080 && highestRefreshRate > 75 && dpaux.set.link_rate < 20 && )
// highestRefreshRate = 75;
}
if (!fd_in) nvClose(fd);
g_dockedHighestRefreshRate = highestRefreshRate;
}
static bool _setPLLDHandheldRefreshRate(uint32_t new_refreshRate) {
if (!g_config.clkVirtAddr) return false;
uint32_t fd = 0;
if (nvOpen(&fd, "/dev/nvdisp-disp0")) {
return false;
}
struct dpaux_read {
uint32_t cmd;
uint32_t addr;
uint32_t size;
struct {
unsigned int rev_minor : 4;
unsigned int rev_major : 4;
unsigned char link_rate;
unsigned int lane_count: 5;
unsigned int unk1: 2;
unsigned int isFramingEnhanced: 1;
unsigned char unk2[13];
} DPCD;
} dpaux = {6, 0, 0x10};
int rc = nvIoctl(fd, NVDISP_GET_PANEL_DATA, &dpaux);
nvClose(fd);
if (rc != 0x75c) return false;
PLLD_BASE base = {0};
PLLD_MISC misc = {0};
memcpy(&base, (void*)(g_config.clkVirtAddr + 0xD0), 4);
memcpy(&misc, (void*)(g_config.clkVirtAddr + 0xDC), 4);
uint32_t value = ((base.PLLD_DIVN / base.PLLD_DIVM) * 10) / 4;
if (value == 0 || value == 80) return false;
if (new_refreshRate > g_handheldModeRefreshRate.max) {
new_refreshRate = g_handheldModeRefreshRate.max;
} else if (new_refreshRate < g_handheldModeRefreshRate.min) {
bool skip = false;
for (size_t i = 2; i <= 4; i++) {
if (new_refreshRate * i == 60) {
skip = true;
new_refreshRate = 60;
break;
}
}
if (!skip) {
for (size_t i = 2; i <= 4; i++) {
if (((new_refreshRate * i) >= g_handheldModeRefreshRate.min) && ((new_refreshRate * i) <= g_handheldModeRefreshRate.max)) {
skip = true;
new_refreshRate *= i;
break;
}
}
}
if (!skip) new_refreshRate = 60;
}
uint32_t pixelClock = (9375 * ((4096 * ((2 * base.PLLD_DIVN) + 1)) + misc.PLLD_SDM_DIN)) / (8 * base.PLLD_DIVM);
uint16_t refreshRateNow = pixelClock / (DSI_CLOCK_HZ / 60);
if (refreshRateNow == new_refreshRate) {
return true;
}
uint8_t base_refreshRate = new_refreshRate - (new_refreshRate % 5);
base.PLLD_DIVN = (4 * base_refreshRate) / 10;
base.PLLD_DIVM = 1;
uint64_t expected_pixel_clock = (DSI_CLOCK_HZ * new_refreshRate) / 60;
misc.PLLD_SDM_DIN = ((8 * base.PLLD_DIVM * expected_pixel_clock) / 9375) - (4096 * ((2 * base.PLLD_DIVN) + 1));
memcpy((void*)(g_config.clkVirtAddr + 0xD0), &base, 4);
memcpy((void*)(g_config.clkVirtAddr + 0xDC), &misc, 4);
return true;
}
static bool _setNvDispDockedRefreshRate(uint32_t new_refreshRate) {
if (g_config.isLite || !g_canChangeRefreshRateDocked)
return false;
uint32_t fd = 0;
if (nvOpen(&fd, "/dev/nvdisp-disp1")) {
return false;
}
NvdcMode2 display_b = {0};
int rc = nvIoctl(fd, NVDISP_GET_MODE2, &display_b);
if (rc != 0) {
nvClose(fd);
return false;
}
if (!display_b.pclkKHz) {
nvClose(fd);
return false;
}
if (!((display_b.vActive == 480 && display_b.hActive == 720) ||
(display_b.vActive == 720 && display_b.hActive == 1280) ||
(display_b.vActive == 1080 && display_b.hActive == 1920))) {
nvClose(fd);
return false;
}
if (display_b.vActive != g_lastVActiveSet) {
g_lastVActiveSet = display_b.vActive;
}
uint32_t h_total = display_b.hActive + display_b.hFrontPorch + display_b.hSyncWidth + display_b.hBackPorch;
uint32_t v_total = display_b.vActive + display_b.vFrontPorch + display_b.vSyncWidth + display_b.vBackPorch;
uint32_t refreshRateNow = ((display_b.pclkKHz) * 1000 + 999) / (h_total * v_total);
int8_t itr = -1;
const size_t numRates = sizeof(g_dockedRefreshRates) / sizeof(g_dockedRefreshRates[0]);
// Find closest matching refresh rate
if ((new_refreshRate <= 60) && ((60 % new_refreshRate) == 0)) {
itr = _getDockedRefreshRateIterator(60);
}
if (itr == -1) {
for (size_t i = 0; i < numRates; i++) {
uint8_t val = g_dockedRefreshRates[i];
if ((val % new_refreshRate) == 0) {
itr = i;
break;
}
}
}
if (itr == -1) {
if (!g_config.matchLowestDocked) {
itr = _getDockedRefreshRateIterator(60);
} else {
for (size_t i = 0; i < numRates; i++) {
if (new_refreshRate < g_dockedRefreshRates[i]) {
itr = i;
break;
}
}
}
}
if (itr == -1) itr = _getDockedRefreshRateIterator(60);
// Clamp to highest allowed refresh rate
if (g_dockedRefreshRates[itr] > g_dockedHighestRefreshRate) {
for (int8_t i = itr; i >= 0; i--) {
if (g_dockedRefreshRates[i] <= g_dockedHighestRefreshRate) {
itr = i;
break;
}
}
}
if (refreshRateNow == g_dockedRefreshRates[itr]) {
nvClose(fd);
return true;
}
if (itr >= 0 && itr < (int8_t)numRates) {
if (display_b.vActive == 720) {
uint32_t clock = ((h_total * v_total) * g_dockedRefreshRates[itr]) / 1000;
display_b.pclkKHz = clock;
} else {
display_b.hFrontPorch = g_dockedTimings1080p[itr].hFrontPorch;
display_b.hSyncWidth = g_dockedTimings1080p[itr].hSyncWidth;
display_b.hBackPorch = g_dockedTimings1080p[itr].hBackPorch;
display_b.vFrontPorch = g_dockedTimings1080p[itr].vFrontPorch;
display_b.vSyncWidth = g_dockedTimings1080p[itr].vSyncWidth;
display_b.vBackPorch = g_dockedTimings1080p[itr].vBackPorch;
display_b.pclkKHz = g_dockedTimings1080p[itr].pixelClock_kHz;
display_b.vmode = (g_dockedRefreshRates[itr] >= 100 ? 0x400000 : 0x200000);
display_b.unk1 = (g_dockedRefreshRates[itr] >= 100 ? 0x80 : 0);
display_b.sync = 3;
display_b.bitsPerPixel = 24;
}
rc = nvIoctl(fd, NVDISP_VALIDATE_MODE2, &display_b);
if (rc == 0) {
rc = nvIoctl(fd, NVDISP_SET_MODE2, &display_b);
}
}
nvClose(fd);
return true;
}
static bool _setNvDispHandheldRefreshRate(uint32_t new_refreshRate) {
if (!g_config.isRetroSUPER) return false;
if (!g_config.displaySync) {
g_wasRetroSuperTurnedOff = false;
} else if (g_wasRetroSuperTurnedOff) {
svcSleepThread(2000000000);
g_wasRetroSuperTurnedOff = false;
}
svcSleepThread(1000000000);
uint32_t fd = 0;
if (nvOpen(&fd, "/dev/nvdisp-disp0")) {
return false;
}
NvdcMode2 display_b = {0};
int rc = nvIoctl(fd, NVDISP_GET_MODE2, &display_b);
if (rc != 0) {
nvClose(fd);
return false;
}
if (!display_b.pclkKHz) {
nvClose(fd);
return false;
}
if ((display_b.vActive == 1280 && display_b.hActive == 720) == false) {
nvClose(fd);
return false;
}
uint32_t h_total = display_b.hActive + display_b.hFrontPorch + display_b.hSyncWidth + display_b.hBackPorch;
uint32_t v_total = display_b.vActive + display_b.vFrontPorch + display_b.vSyncWidth + display_b.vBackPorch;
uint32_t refreshRateNow = ((display_b.pclkKHz) * 1000 + 999) / (h_total * v_total);
if (new_refreshRate > g_handheldModeRefreshRate.max) {
new_refreshRate = g_handheldModeRefreshRate.max;
} else if (new_refreshRate < g_handheldModeRefreshRate.min) {
bool skip = false;
for (size_t i = 2; i <= 4; i++) {
if (new_refreshRate * i == 60) {
skip = true;
new_refreshRate = 60;
break;
}
}
if (!skip) {
for (size_t i = 2; i <= (sizeof(g_handheldTimingsRETRO) / sizeof(g_handheldTimingsRETRO[0])); i++) {
if (((new_refreshRate * i) >= g_handheldModeRefreshRate.min) && ((new_refreshRate * i) <= g_handheldModeRefreshRate.max)) {
skip = true;
new_refreshRate *= i;
break;
}
}
}
if (!skip) new_refreshRate = 60;
}
if (new_refreshRate == refreshRateNow) {
nvClose(fd);
return true;
}
uint32_t itr = (new_refreshRate - 40) / 5;
display_b.hFrontPorch = g_handheldTimingsRETRO[itr].hFrontPorch;
display_b.hSyncWidth = g_handheldTimingsRETRO[itr].hSyncWidth;
display_b.hBackPorch = g_handheldTimingsRETRO[itr].hBackPorch;
display_b.vFrontPorch = g_handheldTimingsRETRO[itr].vFrontPorch;
display_b.vSyncWidth = g_handheldTimingsRETRO[itr].vSyncWidth;
display_b.vBackPorch = g_handheldTimingsRETRO[itr].vBackPorch;
display_b.pclkKHz = g_handheldTimingsRETRO[itr].pixelClock_kHz;
rc = nvIoctl(fd, NVDISP_VALIDATE_MODE2, &display_b);
if (rc == 0) {
for (size_t i = 0; i < 5; i++) {
nvIoctl(fd, NVDISP_SET_MODE2, &display_b);
}
}
nvClose(fd);
return true;
}
bool DisplayRefresh_SetRate(uint32_t new_refreshRate) {
if (!new_refreshRate || !g_initialized) return false;
uint32_t fd = 0;
if (g_config.isLite && g_config.isPossiblySpoofedRetro) {
g_config.isRetroSUPER = false; // Would check flag file here in original, but i dont care lol
}
if (g_config.isRetroSUPER && !g_config.isDocked) {
return _setNvDispHandheldRefreshRate(new_refreshRate);
}
else if ((!g_config.isRetroSUPER && g_config.isLite) || R_FAILED(nvOpen(&fd, "/dev/nvdisp-disp1"))) {
if (_setPLLDHandheldRefreshRate(new_refreshRate) == false)
return false;
}
else {
struct dpaux_read {
uint32_t cmd;
uint32_t addr;
uint32_t size;
struct {
unsigned int rev_minor : 4;
unsigned int rev_major : 4;
unsigned char link_rate;
unsigned int lane_count: 5;
unsigned int unk1: 2;
unsigned int isFramingEnhanced: 1;
unsigned char unk2[13];
} DPCD;
} dpaux = {6, 0, 0x10};
int rc = nvIoctl(fd, NVDISP_GET_PANEL_DATA, &dpaux);
nvClose(fd);
if (rc != 0) {
if (!g_config.isRetroSUPER) {
return _setPLLDHandheldRefreshRate(new_refreshRate);
} else {
return _setNvDispHandheldRefreshRate(new_refreshRate);
}
} else {
if(g_config.isDocked)
return _setNvDispDockedRefreshRate(new_refreshRate);
else
return true;
}
}
return false;
}
bool DisplayRefresh_GetRate(uint32_t* out_refreshRate, bool internal) {
if (!out_refreshRate || !g_initialized || !g_config.clkVirtAddr) return false;
static uint32_t value = 60;
if (g_config.isRetroSUPER && !g_config.isDocked) {
uint32_t fd = 0;
PLLD_BASE temp = {0};
PLLD_MISC misc = {0};
memcpy(&temp, (void*)(g_config.clkVirtAddr + 0xD0), 4);
memcpy(&misc, (void*)(g_config.clkVirtAddr + 0xDC), 4);
value = ((temp.PLLD_DIVN / temp.PLLD_DIVM) * 10) / 4;
if (value != 0 && value != 80) {
if (!nvOpen(&fd, "/dev/nvdisp-disp0")) {
NvdcMode2 display_b = {0};
if (nvIoctl(fd, NVDISP_GET_MODE2, &display_b) == 0) {
uint32_t h_total = display_b.hActive + display_b.hFrontPorch + display_b.hSyncWidth + display_b.hBackPorch;
uint32_t v_total = display_b.vActive + display_b.vFrontPorch + display_b.vSyncWidth + display_b.vBackPorch;
uint32_t pixelClock = display_b.pclkKHz * 1000 + 999;
value = pixelClock / (h_total * v_total);
}
nvClose(fd);
} else {
return false;
}
} else {
g_wasRetroSuperTurnedOff = true;
}
}
else if ((!g_config.isPossiblySpoofedRetro) || (g_config.isPossiblySpoofedRetro && !g_config.isRetroSUPER)) {
PLLD_BASE temp = {0};
PLLD_MISC misc = {0};
memcpy(&temp, (void*)(g_config.clkVirtAddr + 0xD0), 4);
memcpy(&misc, (void*)(g_config.clkVirtAddr + 0xDC), 4);
value = ((temp.PLLD_DIVN / temp.PLLD_DIVM) * 10) / 4;
if (value == 0 || value == 80) {
// Docked mode
if (g_config.isLite) return false;
g_config.isDocked = true;
if (!g_canChangeRefreshRateDocked) {
uint32_t fd = 0;
if (!nvOpen(&fd, "/dev/nvdisp-disp1")) {
struct dpaux_read_0x100 {
uint32_t cmd;
uint32_t addr;
uint32_t size;
struct {
unsigned char link_rate;
unsigned int lane_count: 5;
unsigned int unk1: 2;
unsigned int isFramingEnhanced: 1;
unsigned char downspread;
unsigned char training_pattern;
unsigned char lane_pattern[4];
unsigned char unk2[8];
} set;
} dpaux = {6, 0x100, 0x10};
int rc = nvIoctl(fd, NVDISP_GET_PANEL_DATA, &dpaux);
nvClose(fd);
if (rc == 0) {
_getDockedHighestRefreshRate(0);
g_canChangeRefreshRateDocked = true;
} else {
svcSleepThread(1000000000);
return false;
}
} else {
return false;
}
}
if(internal) {
*out_refreshRate = value;
return true;
}
uint32_t fd = 0;
if (!nvOpen(&fd, "/dev/nvdisp-disp1")) {
NvdcMode2 display_b = {0};
if (nvIoctl(fd, NVDISP_GET_MODE2, &display_b) == 0) {
if (!display_b.pclkKHz) {
nvClose(fd);
return false;
}
if (g_lastVActive != display_b.vActive) {
g_lastVActive = display_b.vActive;
_getDockedHighestRefreshRate(fd);
}
uint32_t h_total = display_b.hActive + display_b.hFrontPorch + display_b.hSyncWidth + display_b.hBackPorch;
uint32_t v_total = display_b.vActive + display_b.vFrontPorch + display_b.vSyncWidth + display_b.vBackPorch;
uint32_t pixelClock = display_b.pclkKHz * 1000 + 999;
value = pixelClock / (h_total * v_total);
} else {
value = 60;
}
nvClose(fd);
} else {
value = 60;
}
}
else if (!g_config.isRetroSUPER) {
// Handheld mode
g_config.isDocked = false;
g_canChangeRefreshRateDocked = false;
uint32_t pixelClock = (9375 * ((4096 * ((2 * temp.PLLD_DIVN) + 1)) + misc.PLLD_SDM_DIN)) / (8 * temp.PLLD_DIVM);
value = pixelClock / (DSI_CLOCK_HZ / 60);
}
else {
return false;
}
}
*out_refreshRate = value;
return true;
}
void DisplayRefresh_Shutdown(void) {
g_initialized = false;
memset(&g_config, 0, sizeof(g_config));
}

View File

@@ -0,0 +1,202 @@
/*
* Copyright (c) KazushiMe
*
* 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 "i2c.h"
Result I2cSet_U8(I2cDevice dev, u8 reg, u8 val) {
// ams::fatal::srv::StopSoundTask::StopSound()
// I2C Bus Communication Reference: https://www.ti.com/lit/an/slva704/slva704.pdf
struct {
u8 reg;
u8 val;
} __attribute__((packed)) cmd;
I2cSession _session;
Result res = i2cOpenSession(&_session, dev);
if (res)
return res;
cmd.reg = reg;
cmd.val = val;
res = i2csessionSendAuto(&_session, &cmd, sizeof(cmd), I2cTransactionOption_All);
i2csessionClose(&_session);
return res;
}
Result I2cRead_OutU8(I2cDevice dev, u8 reg, u8 *out) {
struct { u8 reg; } __attribute__((packed)) cmd;
struct { u8 val; } __attribute__((packed)) rec;
I2cSession _session;
Result res = i2cOpenSession(&_session, dev);
if (res)
return res;
cmd.reg = reg;
res = i2csessionSendAuto(&_session, &cmd, sizeof(cmd), I2cTransactionOption_All);
if (res) {
i2csessionClose(&_session);
return res;
}
res = i2csessionReceiveAuto(&_session, &rec, sizeof(rec), I2cTransactionOption_All);
i2csessionClose(&_session);
if (res) {
return res;
}
*out = rec.val;
return 0;
}
Result I2cRead_OutU16(I2cDevice dev, u8 reg, u16 *out) {
struct { u8 reg; } __attribute__((packed)) cmd;
struct { u16 val; } __attribute__((packed)) rec;
I2cSession _session;
Result res = i2cOpenSession(&_session, dev);
if (res)
return res;
cmd.reg = reg;
res = i2csessionSendAuto(&_session, &cmd, sizeof(cmd), I2cTransactionOption_All);
if (res) {
i2csessionClose(&_session);
return res;
}
res = i2csessionReceiveAuto(&_session, &rec, sizeof(rec), I2cTransactionOption_All);
i2csessionClose(&_session);
if (res) {
return res;
}
*out = rec.val;
return 0;
}
float I2c_Max17050_GetBatteryCurrent() {
u16 val;
Result res = I2cRead_OutU16(I2cDevice_Max17050, MAX17050_CURRENT_REG, &val);
if (res)
return 0.f;
const float SenseResistor = 5.; // in uOhm
const float CGain = 1.99993;
return (s16)val * (1.5625 / (SenseResistor * CGain));
}
u32 I2c_BuckConverter_MultiplierToMvOut(const I2c_BuckConverter_Domain* domain, u8 multiplier) {
return (domain->uv_min + domain->uv_step * multiplier) / 1000;
}
u8 I2c_BuckConverter_MvOutToMultiplier(const I2c_BuckConverter_Domain* domain, u32 mvolt) {
u32 uvolt = mvolt * 1000;
if (uvolt < domain->uv_min)
uvolt = domain->uv_min;
if (uvolt > domain->uv_max)
uvolt = domain->uv_max;
return (uvolt - domain->uv_min) / domain->uv_step;
}
u32 I2c_BuckConverter_GetMvOut(const I2c_BuckConverter_Domain* domain) {
u8 val;
// Retry 5 times if received POR value
for (int i = 0; i < 5; i++) {
if (R_FAILED(I2cRead_OutU8(domain->device, domain->reg, &val)))
return 0u;
// Wait 1us
svcSleepThread(1E3);
if (!domain->por_val || val != domain->por_val)
break;
}
return I2c_BuckConverter_MultiplierToMvOut(domain, val & domain->volt_mask);
}
Result I2c_BuckConverter_SetMvOut(const I2c_BuckConverter_Domain* domain, u32 mvolt) {
u8 val;
Result res = I2cRead_OutU8(domain->device, domain->reg, &val);
if (R_FAILED(res))
return res;
u8 multiplier = I2c_BuckConverter_MvOutToMultiplier(domain, mvolt);
val &= ~domain->volt_mask;
val |= multiplier & domain->volt_mask;
res = I2cSet_U8(domain->device, domain->reg, val);
if (R_FAILED(res))
return res;
// 5ms Ramp delay
svcSleepThread(5E6);
u8 new_val;
res = I2cRead_OutU8(domain->device, domain->reg, &new_val);
if (R_FAILED(res))
return res;
if (new_val != val)
return -1;
return 0;
}
u8 I2c_Bq24193_Convert_mA_Raw(u32 ma) {
// Adjustment is required
u8 raw = 0;
if (ma > MA_RANGE_MAX) // capping
ma = MA_RANGE_MAX;
bool pct20 = ma <= (MA_RANGE_MIN - 64);
if (pct20) {
ma = ma * 5;
raw |= 0x1;
}
ma -= ma % 100; // round to 100
ma -= (MA_RANGE_MIN - 64); // ceiling
raw |= (ma >> 6) << 2;
return raw;
};
u32 I2c_Bq24193_Convert_Raw_mA(u8 raw) {
// No adjustment is allowed
u32 ma = (((raw >> 2)) << 6) + MA_RANGE_MIN;
bool pct20 = raw & 1;
if (pct20)
ma = ma * 20 / 100;
return ma;
};
Result I2c_Bq24193_GetFastChargeCurrentLimit(u32 *ma) {
u8 raw;
Result res = I2cRead_OutU8(I2cDevice_Bq24193, BQ24193_CHARGE_CURRENT_CONTROL_REG, &raw);
if (res)
return res;
*ma = I2c_Bq24193_Convert_Raw_mA(raw);
return 0;
}
Result I2c_Bq24193_SetFastChargeCurrentLimit(u32 ma) {
u8 raw = I2c_Bq24193_Convert_mA_Raw(ma);
return I2cSet_U8(I2cDevice_Bq24193, BQ24193_CHARGE_CURRENT_CONTROL_REG, raw);
}

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

@@ -0,0 +1,67 @@
/*
* Copyright (c) KazushiMe
*
* 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 <sysclk/psm_ext.h>
const char* PsmPowerRoleToStr(PsmPowerRole role) {
switch (role) {
case PsmPowerRole_Sink: return "Sink";
case PsmPowerRole_Source: return "Source";
default: return "Unknown";
}
}
const char* PsmInfoChargerTypeToStr(PsmInfoChargerType type) {
switch (type) {
case PsmInfoChargerType_None: return "None";
case PsmInfoChargerType_PD: return "USB-C PD";
case PsmInfoChargerType_TypeC_1500mA:
case PsmInfoChargerType_TypeC_3000mA: return "USB-C";
case PsmInfoChargerType_DCP: return "USB DCP";
case PsmInfoChargerType_CDP: return "USB CDP";
case PsmInfoChargerType_SDP: return "USB SDP";
case PsmInfoChargerType_Apple_500mA:
case PsmInfoChargerType_Apple_1000mA:
case PsmInfoChargerType_Apple_2000mA: return "Apple";
default: return "Unknown";
}
}
bool PsmIsChargerConnected(const PsmChargeInfo* info) {
return info->ChargerType != PsmInfoChargerType_None;
}
bool PsmIsCharging(const PsmChargeInfo* info) {
return PsmIsChargerConnected(info) && ((info->unk_x14 >> 8) & 1);
}
PsmBatteryState PsmGetBatteryState(const PsmChargeInfo* info) {
if (!PsmIsChargerConnected(info))
return PsmBatteryState_Discharging;
if (!PsmIsCharging(info))
return PsmBatteryState_ChargingPaused;
return PsmBatteryState_FastCharging;
}
const char* PsmGetBatteryStateIcon(const PsmChargeInfo* info) {
switch (PsmGetBatteryState(info)) {
case PsmBatteryState_Discharging: return "\u25c0"; // ◀
case PsmBatteryState_ChargingPaused:return "| |";
case PsmBatteryState_FastCharging: return "\u25b6"; // ▶
default: return "?";
}
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright (c) MasaGratoR
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#define NX_SERVICE_ASSUME_NON_DOMAIN
#include <switch.h>
#include "service_guard.h"
#include "pwm.h"
static Service g_pwmSrv;
NX_GENERATE_SERVICE_GUARD(pwm);
Result _pwmInitialize(void) {
return smGetService(&g_pwmSrv, "pwm");
}
void _pwmCleanup(void) {
serviceClose(&g_pwmSrv);
}
Service* pwmGetServiceSession(void) {
return &g_pwmSrv;
}
Result pwmOpenSession2(PwmChannelSession *out, u32 device_code) {
return serviceDispatchIn(&g_pwmSrv, 2, device_code,
.out_num_objects = 1,
.out_objects = &out->s,
);
}
Result pwmChannelSessionGetDutyCycle(PwmChannelSession *c, double* out) {
return serviceDispatchOut(&c->s, 7, *out);
}
void pwmChannelSessionClose(PwmChannelSession *controller) {
serviceClose(&controller->s);
}

View File

@@ -0,0 +1,66 @@
/*
* Copyright (c) ppkantorski (bord2death)
*
* 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 <switch.h>
#include "rgltr.h"
#include "rgltr_services.h" // for extern Service g_rgltrSrv, etc.
// Global service handle
Service g_rgltrSrv;
Result rgltrInitialize(void) {
if (hosversionBefore(8, 0, 0)) {
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
}
return smGetService(&g_rgltrSrv, "rgltr");
}
void rgltrExit(void) {
serviceClose(&g_rgltrSrv);
}
Result rgltrOpenSession(RgltrSession* session_out, PowerDomainId module_id) {
const u32 in = (u32)module_id;
return serviceDispatchIn(
&g_rgltrSrv,
0,
in,
.out_num_objects = 1,
.out_objects = &session_out->s
);
}
Result rgltrGetVoltage(RgltrSession* session, u32* out_volt) {
u32 temp = 0;
Result rc = serviceDispatchOut(&session->s, 4, temp);
if (R_SUCCEEDED(rc)) {
*out_volt = temp;
}
return rc;
}
Result rgltrRequestVoltage(RgltrSession* session, u32 microvolt) {
return serviceDispatchIn(&session->s, 5, microvolt);
}
Result rgltrCancelVoltageRequest(RgltrSession* session) {
return serviceDispatch(&session->s, 6);
}
void rgltrCloseSession(RgltrSession* session) {
serviceClose(&session->s);
}

View File

@@ -0,0 +1,19 @@
[values]
; Defines how often sys-clk log temperatures, in milliseconds (set 0 to disable)
temp_log_interval_ms=0
; Defines how often sys-clk writes to the CSV, in milliseconds (set 0 to disable)
csv_write_interval_ms=0
; Example #1: BOTW
; Overclock CPU when docked
; Overclock MEM to docked clocks when handheld
;[01007EF00011E000]
;docked_cpu=1224
;handheld_mem=1600
; Example #2: Picross
; Underclock to save battery
;[0100BA0003EEA000]
;handheld_cpu=816
;handheld_gpu=153
;handheld_mem=800

View File

@@ -0,0 +1,2 @@
/out
/build

View File

@@ -15,63 +15,47 @@ include $(DEVKITPRO)/libnx/switch_rules
# SOURCES is a list of directories containing source code
# DATA is a list of directories containing data files
# INCLUDES is a list of directories containing header files
# ROMFS is the directory containing data to be added to RomFS, relative to the Makefile (Optional)
#
# NO_ICON: if set to anything, do not use icon.
# NO_NACP: if set to anything, no .nacp file is generated.
# APP_TITLE is the name of the app stored in the .nacp file (Optional)
# APP_AUTHOR is the author of the app stored in the .nacp file (Optional)
# APP_VERSION is the version of the app stored in the .nacp file (Optional)
# APP_TITLEID is the titleID of the app stored in the .nacp file (Optional)
# ICON is the filename of the icon (.jpg), relative to the project folder.
# If not set, it attempts to use one of the following (in this order):
# - <Project name>.jpg
# - icon.jpg
# - <libnx folder>/default_icon.jpg
#
# CONFIG_JSON is the filename of the NPDM config file (.json), relative to the project folder.
# If not set, it attempts to use one of the following (in this order):
# - <Project name>.json
# - config.json
# If a JSON file is provided or autodetected, an ExeFS PFS0 (.nsp) is built instead
# of a homebrew executable (.nro). This is intended to be used for sysmodules.
# NACP building is skipped as well.
# EXEFS_SRC is the optional input directory containing data copied into exefs, if anything this normally should only contain "main.npdm".
#---------------------------------------------------------------------------------
APP_TITLE := Tesla Example
APP_VERSION := 1.3.0
TARGET := $(notdir $(CURDIR))
TARGET := horizon-oc
BUILD := build
SOURCES := source
OUTDIR := out
RESOURCES := res
SOURCES := src src/nx/ipc ../common/src
DATA := data
INCLUDES := ../include
INCLUDES := ../common/include
EXEFS_SRC := exefs_src
LIBNAMES := minIni nxExt
NO_ICON := 1
#---------------------------------------------------------------------------------
# version control constants
#---------------------------------------------------------------------------------
TARGET_VERSION := $(shell git describe --dirty --always --tags)
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
DEFINES := -DDISABLE_IPC -DTARGET="\"$(TARGET)\"" -DTARGET_VERSION="\"$(TARGET_VERSION)\""
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__
CXXFLAGS := $(CFLAGS) -fno-exceptions -std=c++20
CXXFLAGS := $(CFLAGS) -fno-rtti -std=gnu++17
ASFLAGS := -g $(ARCH)
LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
LIBS := -lnx
LIBS := $(foreach lib,$(LIBNAMES),-l$(lib)) -lnx
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(PORTLIBS) $(LIBNX)
LIBDIRS := $(PORTLIBS) $(LIBNX) $(foreach lib,$(LIBNAMES),$(TOPDIR)/lib/$(lib))
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
@@ -80,7 +64,7 @@ LIBDIRS := $(PORTLIBS) $(LIBNX)
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export OUTPUT := $(CURDIR)/$(TARGET)
export OUTPUT := $(CURDIR)/$(OUTDIR)/$(TARGET)
export TOPDIR := $(CURDIR)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
@@ -107,10 +91,8 @@ else
endif
#---------------------------------------------------------------------------------
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
export OFILES := $(addsuffix .o,$(BINFILES)) \
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
@@ -118,86 +100,59 @@ export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
ifeq ($(strip $(CONFIG_JSON)),)
jsons := $(wildcard *.json)
ifneq (,$(findstring $(TARGET).json,$(jsons)))
export APP_JSON := $(TOPDIR)/$(TARGET).json
else
ifneq (,$(findstring config.json,$(jsons)))
export APP_JSON := $(TOPDIR)/config.json
endif
endif
else
export APP_JSON := $(TOPDIR)/$(CONFIG_JSON)
endif
export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC)
ifeq ($(strip $(ICON)),)
icons := $(wildcard *.jpg)
ifneq (,$(findstring $(TARGET).jpg,$(icons)))
export APP_ICON := $(TOPDIR)/$(TARGET).jpg
else
ifneq (,$(findstring icon.jpg,$(icons)))
export APP_ICON := $(TOPDIR)/icon.jpg
endif
endif
else
export APP_ICON := $(TOPDIR)/$(ICON)
endif
export APP_JSON := $(TOPDIR)/perms.json
ifeq ($(strip $(NO_ICON)),)
export NROFLAGS += --icon=$(APP_ICON)
endif
ifeq ($(strip $(NO_NACP)),)
export NROFLAGS += --nacp=$(CURDIR)/$(TARGET).nacp
endif
ifneq ($(APP_TITLEID),)
export NACPFLAGS += --titleid=$(APP_TITLEID)
endif
ifneq ($(ROMFS),)
export NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS)
endif
.PHONY: $(BUILD) clean all
.PHONY: $(BUILD) clean clean-libs clean-build all libs
#---------------------------------------------------------------------------------
all: $(BUILD)
libs:
@$(foreach lib,$(LIBNAMES),$(MAKE) --no-print-directory -C $(TOPDIR)/lib/$(lib) && ) true
$(BUILD):
$(LIBNAMES):
@echo $@
$(BUILD): libs
@[ -d $@ ] || mkdir -p $@
@[ -d $(OUTDIR) ] || mkdir -p $(OUTDIR)
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#---------------------------------------------------------------------------------
clean:
@rm -fr $(BUILD) $(TARGET).ovl $(TARGET).nro $(TARGET).nacp $(TARGET).elf
clean-libs:
@echo clean libs $(LIBNAMES) ...
@$(foreach lib,$(LIBNAMES),$(MAKE) -C $(TOPDIR)/lib/$(lib) clean && ) true
clean-build:
@echo clean build ...
@rm -fr $(BUILD) $(TARGET).kip $(TARGET).nsp $(TARGET).npdm $(TARGET).nso $(TARGET).elf $(OUTDIR)
clean: clean-libs clean-build
#---------------------------------------------------------------------------------
else
.PHONY: all
.PHONY: all $(LIBFILES)
DEPENDS := $(OFILES:.o=.d)
LIBFILES := $(foreach lib,$(LIBNAMES),$(TOPDIR)/lib/$(lib)/lib/lib$(lib).a)
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
all : $(OUTPUT).ovl
$(OUTPUT).ovl : $(OUTPUT).elf $(OUTPUT).nacp
@elf2nro $< $@ $(NROFLAGS)
@echo "built ... $(notdir $(OUTPUT).ovl)"
all: $(OUTPUT).nsp
$(OUTPUT).elf : $(OFILES)
$(OUTPUT).nsp: $(OUTPUT).nso $(OUTPUT).npdm
$(OFILES_SRC) : $(HFILES_BIN)
$(OUTPUT).elf: $(OFILES) $(LIBFILES)
#---------------------------------------------------------------------------------
# you need a rule like this for each extension you use as binary data
#---------------------------------------------------------------------------------
%.bin.o %_bin.h : %.bin
%.bin.o : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)

View File

@@ -0,0 +1,13 @@
# Editor files
*.swp
*~
# Objects
*.o
*.a
*.so
# Lib
lib
release
debug

View File

@@ -0,0 +1,12 @@
; DO NOT EDIT (unless you know what you are doing)
;
; This subdirectory is a git "subrepo", and this file is maintained by the
; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme
;
[subrepo]
remote = https://github.com/compuphase/minIni
branch = master
commit = 8ce144c3c287fa4e59f8ed4c405cd8b7e29f189b
parent = f32c0b1bca87a6d7e55fb341f8db9ef33b13819f
method = merge
cmdver = 0.4.0

View File

@@ -0,0 +1,189 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
EXCEPTION TO THE APACHE 2.0 LICENSE
As a special exception to the Apache License 2.0 (and referring to the
definitions in Section 1 of this license), you may link, statically or
dynamically, the "Work" to other modules to produce an executable file
containing portions of the "Work", and distribute that executable file
in "Object" form under the terms of your choice, without any of the
additional requirements listed in Section 4 of the Apache License 2.0.
This exception applies only to redistributions in "Object" form (not
"Source" form) and only if no modifications have been made to the "Work".
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.

View File

@@ -0,0 +1,133 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITPRO)),)
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
endif
include $(DEVKITPRO)/libnx/switch_rules
#---------------------------------------------------------------------------------
# TARGET is the name of the output
# SOURCES is a list of directories containing source code
# DATA is a list of directories containing data files
# INCLUDES is a list of directories containing header files
#---------------------------------------------------------------------------------
TARGET := $(notdir $(CURDIR))
SOURCES := dev
DATA := data
INCLUDES := dev
SRC_H_FILES :=
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIC -ftls-model=local-exec
CFLAGS := -g -Wall -Werror \
-ffunction-sections \
-fdata-sections \
$(ARCH) \
$(BUILD_CFLAGS)
CFLAGS += $(INCLUDE)
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
ASFLAGS := -g $(ARCH)
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(PORTLIBS) $(LIBNX)
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
CFILES := minIni.c
CPPFILES :=
SFILES :=
BINFILES :=
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#---------------------------------------------------------------------------------
export LD := $(CC)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export LD := $(CXX)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
export HFILES := $(addsuffix .h,$(subst .,_,$(BINFILES)))
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
.PHONY: clean all lib/lib$(TARGET).a
#---------------------------------------------------------------------------------
all: lib/lib$(TARGET).a
lib:
@[ -d $@ ] || mkdir -p $@
release:
@[ -d $@ ] || mkdir -p $@
debug:
@[ -d $@ ] || mkdir -p $@
lib/lib$(TARGET).a : lib release $(SOURCES) $(INCLUDES)
@$(MAKE) BUILD=release OUTPUT=$(CURDIR)/$@ \
BUILD_CFLAGS="-DNDEBUG=1 -O2" \
DEPSDIR=$(CURDIR)/release \
--no-print-directory -C release \
-f $(CURDIR)/Makefile
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr release debug lib
#---------------------------------------------------------------------------------
else
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
$(OUTPUT) : $(OFILES)
$(OFILES_SRC) : $(HFILES)
#---------------------------------------------------------------------------------
%_bin.h %.bin.o : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
-include $(DEPENDS)
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

View File

@@ -0,0 +1,12 @@
minIni is a programmer's library to read and write "INI" files in embedded
systems. The library takes little resources and can be configured for various
kinds of file I/O libraries.
The method for portable INI file management in minIni is, in part based, on the
article "Multiplatform .INI Files" by Joseph J. Graf in the March 1994 issue of
Dr. Dobb's Journal.
The C++ class in minIni.h was contributed by Steven Van Ingelgem.
The option to compile minIni as a read-only library was contributed by Luca
Bassanello.

View File

@@ -0,0 +1,170 @@
# minIni
minIni is a portable and configurable library for reading and writing ".INI" files. At 830 lines of commented source
code
(version 1.2), minIni truly is a "mini" INI file parser, especially considering its features.
The library does not require the file I/O functions from the standard C/C++ library, but instead lets you configure
the file I/O interface to use via macros. minIni uses limited stack space and does not use dynamic memory (malloc and
friends) at all.
Some minor variations on standard INI files are supported too, notably minIni supports INI files that lack sections.
# Acknowledgement
minIni is derived from an earlier INI file parser (which I wrote) for desktop systems.
In turn, that earlier parser was a re-write of the code from the article "Multiplatform .INI Files" by Joseph J. Graf
in the March 1994 issue of Dr. Dobb's Journal. In other words, minIni has its roots in the work of Joseph Graf (even
though the code has been almost completely re-written).
# Features
minIni is a programmer's library to read and write "INI" files in embedded systems. minIni takes little resources,
can be configured for various kinds of file I/O libraries and provides functionality for reading, writing and
deleting keys from an INI file.
Although the main feature of minIni is that it is small and minimal, it has a few other features:
* minIni supports reading keys that are outside a section, and it thereby supports configuration files that do not use sections (but that are otherwise compatible with INI files).
* You may use a colon to separate key and value; the colon is equivalent to the equal sign. That is, the strings "Name: Value" and "Name=Value" have the same meaning.
* The hash character ("#") is an alternative for the semicolon to start a comment. Trailing comments (i.e. behind a key/value pair on a line) are allowed.
* Leading and trailing white space around key names and values is ignored.
* When writing a value that contains a comment character (";" or "#"), that value will automatically be put between double quotes; when reading the value, these quotes are removed. When a double-quote itself appears in the setting, these characters are escaped.
* Section and key enumeration are supported.
* You can optionally set the line termination (for text files) that minIni will use. (This is a compile-time setting, not a run-time setting.)
* Since writing speed is much lower than reading speed in Flash memory (SD/MMC cards, USB memory sticks), minIni minimizes "file writes" at the expense of double "file reads".
* The memory footprint is deterministic. There is no dynamic memory allocation.
## INI file reading paradigms
There are two approaches to reading settings from an INI file. One way is to call a function, such as
GetProfileString() for every section and key that you need. This is especially convenient if there is a large
INI file, but you only need a few settings from that file at any time &mdash;especially if the INI file can also
change while your program runs. This is the approach that the Microsoft Windows API uses.
The above procedure is quite inefficient, however, when you need to retrieve quite a few settings in a row from
the INI file &mdash;especially if the INI file is not cached in memory (which it isn't, in minIni). A different approach
to getting settings from an INI file is to call a "parsing" function and let that function call the application
back with the section and key names plus the associated data. XML parsing libraries often use this approach; see
for example the Expat library.
minIni supports both approaches. For reading a single setting, use functions like ini_gets(). For the callback
approach, implement a callback and call ini_browse(). See the minIni manual for details.
# INI file syntax
INI files are best known from Microsoft Windows, but they are also used with applications that run on other
platforms (although their file extension is sometimes ".cfg" instead of ".ini").
INI files have a simple syntax with name/value pairs in a plain text file. The name must be unique (per section)
and the value must fit on a single line. INI files are commonly separated into sections &mdash;in minIni, this is
optional. A section is a name between square brackets, like "[Network]" in the example below.
```
[Network]
hostname=My Computer
address=dhcp
dns = 192.168.1.1
```
In the API and in this documentation, the "name" for a setting is denoted as the key for the setting. The key
and the value are separated by an equal sign ("="). minIni supports the colon (":") as an alternative to the
equal sign for the key/value delimiter.
Leading a trailing spaces around values or key names are removed. If you need to include leading and/or trailing
spaces in a value, put the value between double quotes. The ini_gets() function (from the minIni library, see the
minIni manual) strips off the double quotes from the returned value. Function ini_puts() adds double quotes if
the value to write contains trailing white space (or special characters).
minIni ignores spaces around the "=" or ":" delimiters, but it does not ignore spaces between the brackets in a
section name. In other words, it is best not to put spaces behind the opening bracket "[" or before the closing
bracket "]" of a section name.
Comments in the INI must start with a semicolon (";") or a hash character ("#"), and run to the end of the line.
A comment can be a line of its own, or it may follow a key/value pair (the "#" character and trailing comments
are extensions of minIni).
For more details on the format, please see http://en.wikipedia.org/wiki/INI_file.
# Adapting minIni to a file system
The minIni library must be configured for a platform with the help of a so- called "glue file". This glue file
contains macros (and possibly functions) that map file reading and writing functions used by the minIni library
to those provided by the operating system. The glue file must be called "minGlue.h".
To get you started, the minIni distribution comes with the following example glue files:
* a glue file that maps to the standard C/C++ library (specifically the file I/O functions from the "stdio" package),
* a glue file for Microchip's "Memory Disk Drive File System Library" (see http://www.microchip.com/),
* a glue file for the FAT library provided with the CCS PIC compiler (see http://www.ccsinfo.com/)
* a glue file for the EFS Library (EFSL, http://www.efsl.be/),
* and a glue file for the FatFs and Petit-FatFs libraries (http://elm-chan.org/fsw/ff/00index_e.html).
The minIni library does not rely on the availability of a standard C library, because embedded operating systems
may have limited support for file I/O. Even on full operating systems, separating the file I/O from the INI format
parsing carries advantages, because it allows you to cache the INI file and thereby enhance performance.
The glue file must specify the type that identifies a file, whether it is a handle or a pointer. For the standard
C/C++ file I/O library, this would be:
```C
#define INI_FILETYPE FILE*
```
If you are not using the standard C/C++ file I/O library, chances are that you need a different handle or
"structure" to identify the storage than the ubiquitous "FILE*" type. For example, the glue file for the FatFs
library uses the following declaration:
```C
#define INI_FILETYPE FIL
```
The minIni functions declare variables of this INI_FILETYPE type and pass these variables to sub-functions
(including the glue interface functions) by reference.
For "write support", another type that must be defined is for variables that hold the "current position" in a
file. For the standard C/C++ I/O library, this is "fpos_t".
Another item that needs to be configured is the buffer size. The functions in the minIni library allocate this
buffer on the stack, so the buffer size is directly related to the stack usage. In addition, the buffer size
determines the maximum line length that is supported in the INI file and the maximum path name length for the
temporary file. For example, minGlue.h could contain the definition:
```C
#define INI_BUFFERSIZE 512
```
The above macro limits the line length of the INI files supported by minIni to 512 characters.
The temporary file is only used when writing to INI files. The minIni routines copy/change the INI file to a
temporary file and then rename that temporary file to the original file. This approach uses the least amount of
memory. The path name of the temporary file is the same as the input file, but with the last character set to a
tilde ("~").
Below is an example of a glue file (this is the one that maps to the C/C++ "stdio" library).
```C
#include <stdio.h>
#define INI_FILETYPE FILE*
#define ini_openread(filename,file) ((*(file) = fopen((filename),"r")) != NULL)
#define ini_openwrite(filename,file) ((*(file) = fopen((filename),"w")) != NULL)
#define ini_close(file) (fclose(*(file)) == 0)
#define ini_read(buffer,size,file) (fgets((buffer),(size),*(file)) != NULL)
#define ini_write(buffer,file) (fputs((buffer),*(file)) >= 0)
#define ini_rename(source,dest) (rename((source), (dest)) == 0)
#define ini_remove(filename) (remove(filename) == 0)
#define INI_FILEPOS fpos_t
#define ini_tell(file,pos) (fgetpos(*(file), (pos)) == 0)
#define ini_seek(file,pos) (fsetpos(*(file), (pos)) == 0)
```
As you can see, a glue file is mostly a set of macros that wraps one function definition around another.
The glue file may contain more settings, for support of rational numbers, to explicitly set the line termination
character(s), or to disable write support (for example). See the manual that comes with the archive for the details.

View File

@@ -0,0 +1,37 @@
/* Glue functions for the minIni library, based on the FatFs and Petit-FatFs
* libraries, see http://elm-chan.org/fsw/ff/00index_e.html
*
* By CompuPhase, 2008-2012
* This "glue file" is in the public domain. It is distributed without
* warranties or conditions of any kind, either express or implied.
*
* (The FatFs and Petit-FatFs libraries are copyright by ChaN and licensed at
* its own terms.)
*/
#define INI_BUFFERSIZE 256 /* maximum line length, maximum path length */
/* You must set _USE_STRFUNC to 1 or 2 in the include file ff.h (or tff.h)
* to enable the "string functions" fgets() and fputs().
*/
#include "ff.h" /* include tff.h for Tiny-FatFs */
#define INI_FILETYPE FIL
#define ini_openread(filename,file) (f_open((file), (filename), FA_READ+FA_OPEN_EXISTING) == FR_OK)
#define ini_openwrite(filename,file) (f_open((file), (filename), FA_WRITE+FA_CREATE_ALWAYS) == FR_OK)
#define ini_close(file) (f_close(file) == FR_OK)
#define ini_read(buffer,size,file) f_gets((buffer), (size),(file))
#define ini_write(buffer,file) f_puts((buffer), (file))
#define ini_remove(filename) (f_unlink(filename) == FR_OK)
#define INI_FILEPOS DWORD
#define ini_tell(file,pos) (*(pos) = f_tell((file)))
#define ini_seek(file,pos) (f_lseek((file), *(pos)) == FR_OK)
static int ini_rename(TCHAR *source, const TCHAR *dest)
{
/* Function f_rename() does not allow drive letters in the destination file */
char *drive = strchr(dest, ':');
drive = (drive == NULL) ? dest : drive + 1;
return (f_rename(source, drive) == FR_OK);
}

View File

@@ -0,0 +1,64 @@
/* minIni glue functions for FAT library by CCS, Inc. (as provided with their
* PIC MCU compiler)
*
* By CompuPhase, 2011-2012
* This "glue file" is in the public domain. It is distributed without
* warranties or conditions of any kind, either express or implied.
*
* (The FAT library is copyright (c) 2007 Custom Computer Services, and
* licensed at its own terms.)
*/
#define INI_BUFFERSIZE 256 /* maximum line length, maximum path length */
#ifndef FAT_PIC_C
#error FAT library must be included before this module
#endif
#define const /* keyword not supported by CCS */
#define INI_FILETYPE FILE
#define ini_openread(filename,file) (fatopen((filename), "r", (file)) == GOODEC)
#define ini_openwrite(filename,file) (fatopen((filename), "w", (file)) == GOODEC)
#define ini_close(file) (fatclose((file)) == 0)
#define ini_read(buffer,size,file) (fatgets((buffer), (size), (file)) != NULL)
#define ini_write(buffer,file) (fatputs((buffer), (file)) == GOODEC)
#define ini_remove(filename) (rm_file((filename)) == 0)
#define INI_FILEPOS fatpos_t
#define ini_tell(file,pos) (fatgetpos((file), (pos)) == 0)
#define ini_seek(file,pos) (fatsetpos((file), (pos)) == 0)
#ifndef INI_READONLY
/* CCS FAT library lacks a rename function, so instead we copy the file to the
* new name and delete the old file
*/
static int ini_rename(char *source, char *dest)
{
FILE fr, fw;
int n;
if (fatopen(source, "r", &fr) != GOODEC)
return 0;
if (rm_file(dest) != 0)
return 0;
if (fatopen(dest, "w", &fw) != GOODEC)
return 0;
/* With some "insider knowledge", we can save some memory: the "source"
* parameter holds a filename that was built from the "dest" parameter. It
* was built in a local buffer with the size INI_BUFFERSIZE. We can reuse
* this buffer for copying the file.
*/
while (n=fatread(source, 1, INI_BUFFERSIZE, &fr))
fatwrite(source, 1, n, &fw);
fatclose(&fr);
fatclose(&fw);
/* Now we need to delete the source file. However, we have garbled the buffer
* that held the filename of the source. So we need to build it again.
*/
ini_tempname(source, dest, INI_BUFFERSIZE);
return rm_file(source) == 0;
}
#endif

View File

@@ -0,0 +1,63 @@
/* Glue functions for the minIni library, based on the EFS Library, see
* http://www.efsl.be/
*
* By CompuPhase, 2008-2012
* This "glue file" is in the public domain. It is distributed without
* warranties or conditions of any kind, either express or implied.
*
* (EFSL is copyright 2005-2006 Lennart Ysboodt and Michael De Nil, and
* licensed under the GPL with an exception clause for static linking.)
*/
#define INI_BUFFERSIZE 256 /* maximum line length, maximum path length */
#define INI_LINETERM "\r\n" /* set line termination explicitly */
#include "efs.h"
extern EmbeddedFileSystem g_efs;
#define INI_FILETYPE EmbeddedFile
#define ini_openread(filename,file) (file_fopen((file), &g_efs.myFs, (char*)(filename), 'r') == 0)
#define ini_openwrite(filename,file) (file_fopen((file), &g_efs.myFs, (char*)(filename), 'w') == 0)
#define ini_close(file) file_fclose(file)
#define ini_read(buffer,size,file) (file_read((file), (size), (buffer)) > 0)
#define ini_write(buffer,file) (file_write((file), strlen(buffer), (char*)(buffer)) > 0)
#define ini_remove(filename) rmfile(&g_efs.myFs, (char*)(filename))
#define INI_FILEPOS euint32
#define ini_tell(file,pos) (*(pos) = (file)->FilePtr))
#define ini_seek(file,pos) file_setpos((file), (*pos))
#if ! defined INI_READONLY
/* EFSL lacks a rename function, so instead we copy the file to the new name
* and delete the old file
*/
static int ini_rename(char *source, const char *dest)
{
EmbeddedFile fr, fw;
int n;
if (file_fopen(&fr, &g_efs.myFs, source, 'r') != 0)
return 0;
if (rmfile(&g_efs.myFs, (char*)dest) != 0)
return 0;
if (file_fopen(&fw, &g_efs.myFs, (char*)dest, 'w') != 0)
return 0;
/* With some "insider knowledge", we can save some memory: the "source"
* parameter holds a filename that was built from the "dest" parameter. It
* was built in buffer and this buffer has the size INI_BUFFERSIZE. We can
* reuse this buffer for copying the file.
*/
while (n=file_read(&fr, INI_BUFFERSIZE, source))
file_write(&fw, n, source);
file_fclose(&fr);
file_fclose(&fw);
/* Now we need to delete the source file. However, we have garbled the buffer
* that held the filename of the source. So we need to build it again.
*/
ini_tempname(source, dest, INI_BUFFERSIZE);
return rmfile(&g_efs.myFs, source) == 0;
}
#endif

View File

@@ -0,0 +1,26 @@
/* Glue functions for the minIni library, based on the "FAT Filing System"
* library by embedded-code.com
*
* By CompuPhase, 2008-2012
* This "glue file" is in the public domain. It is distributed without
* warranties or conditions of any kind, either express or implied.
*
* (The "FAT Filing System" library itself is copyright embedded-code.com, and
* licensed at its own terms.)
*/
#define INI_BUFFERSIZE 256 /* maximum line length, maximum path length */
#include <mem-ffs.h>
#define INI_FILETYPE FFS_FILE*
#define ini_openread(filename,file) ((*(file) = ffs_fopen((filename),"r")) != NULL)
#define ini_openwrite(filename,file) ((*(file) = ffs_fopen((filename),"w")) != NULL)
#define ini_close(file) (ffs_fclose(*(file)) == 0)
#define ini_read(buffer,size,file) (ffs_fgets((buffer),(size),*(file)) != NULL)
#define ini_write(buffer,file) (ffs_fputs((buffer),*(file)) >= 0)
#define ini_rename(source,dest) (ffs_rename((source), (dest)) == 0)
#define ini_remove(filename) (ffs_remove(filename) == 0)
#define INI_FILEPOS long
#define ini_tell(file,pos) (ffs_fgetpos(*(file), (pos)) == 0)
#define ini_seek(file,pos) (ffs_fsetpos(*(file), (pos)) == 0)

View File

@@ -0,0 +1,58 @@
/* minIni glue functions for Microchip's "Memory Disk Drive" file system
* library, as presented in Microchip application note AN1045.
*
* By CompuPhase, 2011-2014
* This "glue file" is in the public domain. It is distributed without
* warranties or conditions of any kind, either express or implied.
*
* (The "Microchip Memory Disk Drive File System" is copyright (c) Microchip
* Technology Incorporated, and licensed at its own terms.)
*/
#define INI_BUFFERSIZE 256 /* maximum line length, maximum path length */
#include "MDD File System\fsio.h"
#include <string.h>
#define INI_FILETYPE FSFILE*
#define ini_openread(filename,file) ((*(file) = FSfopen((filename),FS_READ)) != NULL)
#define ini_openwrite(filename,file) ((*(file) = FSfopen((filename),FS_WRITE)) != NULL)
#define ini_openrewrite(filename,file) ((*(file) = fopen((filename),FS_READPLUS)) != NULL)
#define ini_close(file) (FSfclose(*(file)) == 0)
#define ini_write(buffer,file) (FSfwrite((buffer), 1, strlen(buffer), (*file)) > 0)
#define ini_remove(filename) (FSremove((filename)) == 0)
#define INI_FILEPOS long int
#define ini_tell(file,pos) (*(pos) = FSftell(*(file)))
#define ini_seek(file,pos) (FSfseek(*(file), *(pos), SEEK_SET) == 0)
/* Since the Memory Disk Drive file system library reads only blocks of files,
* the function to read a text line does so by "over-reading" a block of the
* of the maximum size and truncating it behind the end-of-line.
*/
static int ini_read(char *buffer, int size, INI_FILETYPE *file)
{
size_t numread = size;
char *eol;
if ((numread = FSfread(buffer, 1, size, *file)) == 0)
return 0; /* at EOF */
if ((eol = strchr(buffer, '\n')) == NULL)
eol = strchr(buffer, '\r');
if (eol != NULL) {
/* terminate the buffer */
*++eol = '\0';
/* "unread" the data that was read too much */
FSfseek(*file, - (int)(numread - (size_t)(eol - buffer)), SEEK_CUR);
} /* if */
return 1;
}
#ifndef INI_READONLY
static int ini_rename(const char *source, const char *dest)
{
FSFILE* ftmp = FSfopen((source), FS_READ);
FSrename((dest), ftmp);
return FSfclose(ftmp) == 0;
}
#endif

View File

@@ -0,0 +1,31 @@
/* Glue functions for the minIni library, based on the C/C++ stdio library
*
* Or better said: this file contains macros that maps the function interface
* used by minIni to the standard C/C++ file I/O functions.
*
* By CompuPhase, 2008-2014
* This "glue file" is in the public domain. It is distributed without
* warranties or conditions of any kind, either express or implied.
*/
/* map required file I/O types and functions to the standard C library */
#include <stdio.h>
#define INI_FILETYPE FILE*
#define ini_openread(filename,file) ((*(file) = fopen((filename),"rb")) != NULL)
#define ini_openwrite(filename,file) ((*(file) = fopen((filename),"wb")) != NULL)
#define ini_openrewrite(filename,file) ((*(file) = fopen((filename),"r+b")) != NULL)
#define ini_close(file) (fclose(*(file)) == 0)
#define ini_read(buffer,size,file) (fgets((buffer),(size),*(file)) != NULL)
#define ini_write(buffer,file) (fputs((buffer),*(file)) >= 0)
#define ini_rename(source,dest) (rename((source), (dest)) == 0)
#define ini_remove(filename) (remove(filename) == 0)
#define INI_FILEPOS long int
#define ini_tell(file,pos) (*(pos) = ftell(*(file)))
#define ini_seek(file,pos) (fseek(*(file), *(pos), SEEK_SET) == 0)
/* for floating-point support, define additional types and functions */
#define INI_REAL float
#define ini_ftoa(string,value) sprintf((string),"%f",(value))
#define ini_atof(string) (INI_REAL)strtod((string),NULL)

Some files were not shown because too many files have changed in this diff Show More