Compare commits

...

131 Commits

Author SHA1 Message Date
CTCaer
3f10cc774b Bump hekate to v5.1.2 and Nyx to v0.8.5
Additionally disable archive bit fix tool in hekate main to shave binary size.
The archive bit fix in Nyx is the only maintained one and so the only one that should be used.
2020-03-03 04:42:01 +02:00
CTCaer
ac92ca220f fan: Better thermal logic based on HOS patterns 2020-03-03 04:37:59 +02:00
CTCaer
ab8801d0de touch: Add edge compensation
Switch touch panels have a 10-15px offset around the edges.
(10-1269, 10-709) / (15-1264, 15-704)
This allows touch driver to report a max of 0-1279, 0-719.
2020-03-03 04:28:12 +02:00
CTCaer
f3802ec464 lists: Fix list member iteration with no entries 2020-03-03 04:24:38 +02:00
CTCaer
bc7a7bcfa0 info: Allow dumping of battery characterization table 2020-03-03 04:22:59 +02:00
CTCaer
6a52d44da6 heap: Fix edge case of reusing first node
There is an edge case fixed where the whole would be freed and this would make use of a nullptr.

Additionally, remove usage of reserved names for vars and add comments on how it works.
2020-03-03 04:16:20 +02:00
CTCaer
03a8a11933 Small fixes and changes
- Allow printing of more log on HOS boot when LOGS are OFF.
- A small name refactoring
- Add battery warning symbol when battery < 3200mV
2020-03-03 04:11:13 +02:00
CTCaer
c474e35732 hos: 9.2.0 support 2020-03-03 03:32:45 +02:00
CTCaer
4c1f67d022 Fix build errors 2020-01-19 15:22:59 +02:00
CTCaer
91759aba95 r2p/update: Fix check for the 'if not forced' case
This fixes the following case:
When force is 0 and the payload is not hekate, the function jumps to the 'is old' check.

This skips the is magic value check and only does the version check.

In case the foreign payload has a low value on that offset, it causes an overwrite which is unneeded.
2020-01-17 09:35:16 +02:00
CTCaer
5a9bbaf900 fss0: Fix parsing Sept from fusee-secondary 2020-01-17 09:27:53 +02:00
CTCaer
01a767cbfa fss0: Fix heap corruption when sept is loaded from fss 2020-01-17 09:26:13 +02:00
CTCaer
8552a7282c ini: Fix heap corruption caused by backlight option
Additionally, name all text size values so it doesn't happen again in the future.
2020-01-17 09:22:28 +02:00
CTCaer
2a161b572b sdmmc: Set power cycle wait to 0 at boot 2020-01-17 09:19:58 +02:00
CTCaer
422852795f ini: Remove \r stripping as is done by FatFS 2020-01-17 09:18:31 +02:00
CTCaer
4d53f21387 mtc: Clear init magic on chainload
Fixes a hang caused when rebooting 2 payload from L4T with old hekate in vendor partition.

L4T does not overwrite the nyx storage where the Minerva configuration is stored.
This makes new Minerva parse the wrong tables from old hekate and eventually hang the RAM, which causes an exception on BPMP.
2020-01-14 23:41:15 +02:00
CTCaer
9263e2192f nyx: Fix low battery voltage color 2020-01-07 06:50:33 +02:00
CTCaer
c99a87dd09 clock: Move PLLC config from bpmp.c to clock.c 2020-01-07 06:46:22 +02:00
CTCaer
009db77426 bpmp: Switch to PLLC for SCLK/BPMP clock source 2020-01-07 06:26:29 +02:00
CTCaer
4e5ded7cb3 Merge pull request #340 from cclauss/patch-1
Fix compatibility with python 3
2020-01-07 06:14:51 +02:00
Christian Clauss
50f31cad14 import sys for lines 17 and 34 2020-01-04 18:05:42 +01:00
CTCaer
2f43145131 uart: Add invert, get/set IIR and fifo empty functions 2019-12-16 22:16:40 +02:00
CTCaer
e3fca2bce5 uart: Add timeout and len report to uart receive 2019-12-16 22:15:21 +02:00
CTCaer
da112a0ae9 uart: Proper uart init 2019-12-16 22:12:09 +02:00
CTCaer
90060d1d83 mtc: Don't rely on clean BSS for Minerva lib 2019-12-16 22:06:13 +02:00
CTCaer
1ccce5f1a2 gfx: Fix off-by-one in right half of 16px rendering 2019-12-16 21:49:54 +02:00
CTCaer
8584493c7f sept: Add support for loading sept from fss0
If `fss0=` key is detected, sept will be loaded from fusee-secondary.bin instead of `sept/sept_*`.

This will negate missing sept and failed to decrypt pkg2 errors, when booting HOS, for users that forget to update sept folder.
2019-12-16 00:53:22 +02:00
CTCaer
9b2d906648 hos: Add message for possible cause of unk pkg1 2019-12-14 22:43:00 +02:00
CTCaer
2aaa0331ac rtc: Add epoch convertion functions
Thanks @shchmue for the HOS conversion
2019-12-14 22:27:07 +02:00
CTCaer
7604239237 bpmp: Update driver to latest 2019-12-14 22:21:42 +02:00
CTCaer
562a6fb61d Bump hekate to v5.1.1 and Nyx to v0.8.4 2019-12-12 00:24:13 +02:00
CTCaer
938562cc0a Add info in readme about auto updating update.bin 2019-12-12 00:23:04 +02:00
CTCaer
1e4d63731b nyx: Fix about screen 2nd pane left margin 2019-12-12 00:20:14 +02:00
CTCaer
8ff01301cb btn: Fix bootwait=0 for real 2019-12-12 00:15:08 +02:00
CTCaer
a664118fc7 r2p: Update r2p payload
2 modes:
- With updater2p; Forces the reboot to payload binary to be hekate
- Without; Checks if hekate and then if old
2019-12-12 00:13:32 +02:00
CTCaer
87d376654b util: Update update.bin if old 2019-12-12 00:07:18 +02:00
CTCaer
c6e92311f9 Add error printing for issues with libraries
It will now show erros for the following:
- Missing or old libsys_minerva.bso (DRAM training).
- Missing libsys_lp0.bso (LP0 sleep mode).
- Missing or old Nyx version
2019-12-11 11:22:11 +02:00
CTCaer
24d30a40f9 hos: Add Atmosphere's system mem increase patches 2019-12-10 19:20:02 +02:00
CTCaer
ae283aef59 util: Always return result if not a single press req
This also fixes issues with 0 time out.
2019-12-10 13:49:28 +02:00
CTCaer
e4f7928513 minerva: Fix compatibility check for hekate main
Init now also returns status.
2019-12-09 22:27:01 +02:00
CTCaer
bd8a5ece58 heap: Fix type for heap monitor memset size 2019-12-09 19:30:45 +02:00
CTCaer
d0850516ab Bump hekate to v5.1.0 and Nyx to v0.8.3 2019-12-08 18:59:00 +02:00
CTCaer
4c5a78de6f hos: Fix pkg2 keygen with newer sept
This change also adds support for older sept binaries.
2019-12-08 18:32:09 +02:00
CTCaer
97d3b745d9 exo: Add support for user access to PMU flag 2019-12-08 03:02:17 +02:00
CTCaer
c12c696e53 hos: Add 9.1.0 support 2019-12-08 03:01:21 +02:00
CTCaer
f256bd5909 Move all I/DRAM addresses into a memory map
Many addresses were moved around to pack the memory usage!
2019-12-08 02:23:03 +02:00
CTCaer
0290892b23 nyx hw reconfig: Add fan and 5V regulators deinit
Additionally re-arrange minerva and mmu after these.
2019-12-08 01:41:57 +02:00
CTCaer
643a8ea8f9 fan: Update driver
Make use of 5V regulator driver and fixe some bugs
2019-12-08 01:38:12 +02:00
CTCaer
a6d8854499 power: Add 5V regulator driver 2019-12-08 01:36:35 +02:00
CTCaer
96bafd8bd7 nyx: Use color when battery voltage < 3200mV
For status bar and Battery Info.
2019-12-08 01:32:26 +02:00
CTCaer
65ee728939 nyx: Enable fan when temps are high 2019-12-08 01:26:26 +02:00
CTCaer
e1748a0727 nyx: Boost eMMC backup/restore verification times
This change allows SE to start verifying the first buffer while the 2nd is populated. Effectively cutting verification down to almost half.
2019-12-08 01:20:05 +02:00
CTCaer
6734513d47 Add missing dependencies for 2 previous commits
- hos/mtc: Add FSP WAR and boost HOS booting times
- autoboot: Support VOL-+ combo for fastboot
2019-12-08 01:15:35 +02:00
CTCaer
dbe6ed4060 autoboot: Fix custom bootlogo for boot via id 2019-12-08 01:11:13 +02:00
CTCaer
943477fdde autoboot: Support VOL-+ combo for fastboot
This is conditional:
In order to not cancel booting while trying to enter fastboot in android, the combo MUST be initiated with `VOL+` (hold) -> `VOL-` (hold)
2019-12-07 23:37:07 +02:00
CTCaer
35e853fd03 touch: Change I2C4 pinmuxing as per HOS 2019-12-07 23:23:01 +02:00
CTCaer
7e26be6587 lvgl: Optimize color blending
The manual optimization done dramatically increases performance in software color blending.
Isolated gains reach 20-30%.

Color blending calculates 2 +1 color channels instead of the expensive 1+1+1 calculations.

This is as best as it gets without going in asm optimizations.
2019-12-07 20:47:19 +02:00
CTCaer
733da0f4d5 nyx: Remove compiler flags to gain extra perf
- Removing no-inline produces 30-50% performance gains on specific real time sensitive functions used for rendering.
On overall, this will give 5-10% observed performance gains.

- Strict aliasing produces some extra small gains.
2019-12-07 20:35:17 +02:00
Kostas Missos
a357395cc6 nyx: Remove LTO in order to increase performance
Perf gains from removing LTO linker flag amounts to actually more than 5% average in real usage scenarios in Nyx.
(These include overall timings with static waits included. So basically as observed by user.)

Gains observed, on many isolated cases, were between 15-35%.

Additionally, this will make compiling fast again.
2019-12-07 20:26:51 +02:00
Kostas Missos
48c15a8fde nyx: Release the shackles 2019-12-07 20:16:38 +02:00
Kostas Missos
edc2b12f0f chainloader: Only unmount if trying to update
This will speed up boot times for some sd cards up to 500ms when running update.bin is not needed (old or same version).
2019-12-07 02:40:56 +02:00
Kostas Missos
0b45a5a11a bpmp: Reduce freq to 589MHz
3 users had issues with 602MHz.
This will probably bring the SoC binning compatibility to 100%.

Additionally, make it easy to change default boost frequency.

The tiny loss in perf, will be mitigated in Nyx. (It's actually even faster)
2019-12-07 02:01:29 +02:00
Kostas Missos
bc7dec2e61 bpmp: Add forcable maintenance
+ Fix build issues
2019-12-07 01:47:44 +02:00
CTCaer
9811ba53e0 pmic: Enable Low Battery Shutdown for 2.8V
There's an increasing ammount of users that kill their batteries when forgetting their devices into AutoRCM / RCM mode.

This will now force a shutdown the moment the battery reaches 2.8V. Even if device is inside RCM mode.

Notice: We might need to increase the limit.
2019-12-04 22:06:34 +02:00
CTCaer
a16b1af698 pmic: Always ensure that values were written 2019-12-04 22:02:17 +02:00
CTCaer
641a57a4f6 hos/mtc: Add FSP WAR and boost HOS booting times
By implementing FSP WAR we can allow HOS to boot in 1600MHz and be able to switch frequency without hanging.
2019-12-04 21:59:58 +02:00
CTCaer
84328aa676 minerva: Make use of new minerva
- Training and switch is now faster
- Compatibility checks: New Minerva does not allow old binaries. New binaries do not allow old Minerva
- MTC table is now in a safe region
- Periodic training period increased to every 250ms
2019-12-04 21:56:45 +02:00
CTCaer
66c4f30bdf minerva: Update to v1.2 and use only integers
Additionally remove support for DRAM types that Switch platform does not have.

This will reduce periodic training cost to 30us from 6ms.
2019-12-04 21:46:33 +02:00
CTCaer
dd8ec0d28b clock: Always wait 2us before deasserting reset 2019-12-04 21:32:51 +02:00
CTCaer
0b1eebefe1 Small refactor and bugfixes 2019-12-04 21:31:39 +02:00
CTCaer
168de9ddd8 sdmmc: Ensure aligned DMA buffers 2019-12-04 19:42:25 +02:00
CTCaer
c24d943122 tui: Always print an error when Nyx is missing 2019-12-04 19:39:15 +02:00
CTCaer
b61b212218 lvgl heap: Align addresses & sizes to cache line size 2019-12-04 19:04:11 +02:00
CTCaer
ec10b572d1 heap: Quality updates to heap management
- Allow reuse of unused sections that fit exactly to selected allocation size. Decreases fragmentation dramatically.
- Always allocate and align mapped memory to selected alignment. Avoids having fragmented unused maps that are not aligned.
- Use a static alignment based on BPMP and generally average cache line size. Boosts performance when MMU is used.
2019-12-04 19:02:28 +02:00
CTCaer
d1e50c558e sdram: Refactor and fix some bugs in init 2019-12-04 18:53:36 +02:00
CTCaer
9476e0ab45 kip patches: Allow double defined patchset names
This fixes an issue when NOGC patch was defined 2 times when user wants it forced via `kip1patch=nogc` and AutoNOGC was also procced via fuses.
2019-12-04 18:48:00 +02:00
CTCaer
ccf36fd2cb ext kip patches: Disallow empty patches
Allow the patch loop to end via empty source data as per original spec and error out on 0 length if source data is not null.

emuMMC force decompression patch safely avoids that.
2019-12-04 18:44:59 +02:00
CTCaer
9a082c1b18 hos: Improve errors more for HOS launch 2019-12-04 17:46:12 +02:00
CTCaer
2c1da3a97d se: Upgrade SE and allow SHA calc continue
- Allow SHA to calculate sizes > 16MB and refactor sha function
- Name various registers and magic numbers
- Fix various key access bugs

In a later commit this new design will boost verification times significantly and also allow full SHA256 hashes.
2019-12-04 17:18:16 +02:00
CTCaer
29a51124fd Simplify string ops with already compiled-in functions 2019-12-04 15:56:53 +02:00
Kostas Missos
74452074f6 Modernize readme and hekate_ipl_template.ini
Adds more info on how the configs work.
2019-10-31 16:31:16 +02:00
Kostas Missos
598073e50c ext patches: Remove patches_template.ini load
Remove patches_template.ini load.
- It has useless patches, which some times, users confuse them for "bad" patches, even though they aren't.
- No one reads on how it works and it's constantly mishandled when there's no patches.ini (which completely overrides it).
- It was not supposed to be edited.

Also release will not include it anymore.
Template will still exist for demonstrating the syntax of `patches.ini`

This commit also corrects the patches.ini encoding note as ASCII.
2019-10-31 16:26:46 +02:00
CTCaer
58b57a7b14 Merge pull request #300 from shchmue/dev
heap: Prevent node chain collapse on free
2019-10-25 20:31:38 +03:00
shchmue
426c86182d heap: Prevent node chain collapse on free 2019-10-25 11:20:38 -06:00
CTCaer
65fbdfddbf kfuse: Ensure that kfuse is ready 100% for tsec 2019-10-22 18:57:51 +03:00
Kostas Missos
7c42f72b8a refactor: Remove all unwanted whitespace 2019-10-18 18:02:06 +03:00
CTCaer
9104b85143 hos: Improve boot error display 2019-10-09 00:42:13 +03:00
CTCaer
2857fcca52 pmic: Restore forced power off timeout back to 5s 2019-09-23 16:41:37 +03:00
CTCaer
6433dbd1ee readme: Add info for id key 2019-09-14 22:06:18 +03:00
CTCaer
fe339120e2 Bump hekate to v5.0.2 and Nyx to v0.8.2
Also rip hekate main's menu logo.

(It will be back :P)
2019-09-12 23:55:48 +03:00
CTCaer
6a261e356f hos: Update NOGC for LAFW v3
And also add emuMMC reverse protection by disabling GC when 9.0.0 fuses are burnt and emuMMC is lower than this.

This avoids fatals on boot.
2019-09-12 23:53:46 +03:00
CTCaer
e24bb44adf hos: Add full 9.0.0 support 2019-09-12 23:41:08 +03:00
CTCaer
40afcfd686 hos: Support pkg2 encrypted with newer mkeys 2019-09-12 23:39:47 +03:00
CTCaer
658c3c112f hos: automatically find new kernel ini1 offset 2019-09-12 23:37:00 +03:00
CTCaer
3b16b086f8 pkg2: Remove duplicate patches 2019-09-12 23:29:25 +03:00
CTCaer
8033ba461f SE: Boost its speed while BPMP cache is on
Plus add se_aes_crypt_ecb().

Thanks @shchmue for pointing out that speed bump
2019-09-12 23:27:04 +03:00
CTCaer
4dcb2c6343 autoboot: Allow critical info to be shown
This is part of the big refactoring which had all HOS fatal errors.
2019-09-12 23:22:42 +03:00
CTCaer
95a6f2b763 sdram: Support fully burnt ODM fuses 2019-09-12 23:21:12 +03:00
CTCaer
8cef81c901 nyx: Fix some inconsistencies with transparency 2019-09-12 23:20:38 +03:00
CTCaer
08d212d4da FatFS: Update to R0.13c (p4) and fix some crit issues 2019-09-12 23:18:39 +03:00
CTCaer
252a57ef6a util: Utilize BPMP sleep when usleep is out of bounds 2019-09-12 23:12:17 +03:00
CTCaer
23e246f224 i2c: Add missing clocks + more refactoring 2019-09-12 23:11:17 +03:00
CTCaer
3028568019 pmc-ccplex: Have proper Power Domain toggling 2019-09-12 23:09:38 +03:00
CTCaer
a8d529cf6a Refactoring and comment adding 2019-09-12 23:08:38 +03:00
CTCaer
c5b64a2b58 tsec: Don't disable HOST1x clock because it's used
Tsec keys function always disabled host1x clock after running.
This interferes with display interface and disables further window frame syncing.
Display_end code already handles disable and reset of said clock.

It also fixes an ancient bug that was mitigated by removing the 5 frame sync on HOST1X_SYNC_SYNCPT_9 at channel 0:
5fd9daa364 (diff-6b0c56eab8515465d559ff0ea73a22c3L152)
2019-09-11 02:19:41 +03:00
CTCaer
4c09454bca nyx options: Do not hide delay time if AutoBoot is off 2019-09-10 23:53:45 +03:00
CTCaer
787c682f0f readme: Add nouserexceptions key 2019-09-10 23:44:33 +03:00
CTCaer
29b86ce92b nyx: Refactor Options to a separate object 2019-09-10 23:35:17 +03:00
Kostas Missos
50ebcee45d nyx: Fix stray color tags (lvgl heap corruption) 2019-09-10 17:05:52 +03:00
Kostas Missos
b74b449601 hos: Add exosphere no user exceptions handle cfg 2019-09-09 17:00:13 +03:00
Kostas Missos
718e502983 Add more register names + refactoring 2019-09-09 16:56:37 +03:00
Kostas Missos
c1e072986d Fix build issues 2019-09-09 15:48:49 +03:00
CTCaer
8045d7992b hwinit: FIx CPU/GPU on warmboot reboot from Linux
Thanks @Stary2001 for all the testing!
2019-09-01 03:55:43 +03:00
CTCaer
02826dd9a6 sdmmc: Streamline power cycle wait for Sandisks U1 2019-08-28 02:39:43 +03:00
CTCaer
c50e61f961 nyx: Support fixing archive bits for emuMMC 2019-08-28 02:27:13 +03:00
CTCaer
deb9c94bcd nyx: Check if split restore files are 4MB aligned
This is a mitigation for cluster version of FastFS.
During a split restore, it is allowed only once to write a cluster that is not full.
2019-08-28 02:25:48 +03:00
CTCaer
6cc3d9df67 nyx: Fix eMMC split restore when < 10 parts
Now it properly follows the double digit scheme.
(rawnand.bin.##)
2019-08-28 02:23:46 +03:00
CTCaer
92a60a1e89 nyx: Various fixes 2019-08-28 02:20:48 +03:00
CTCaer
d0b0164077 ianos: Remove error unneeded printing 2019-08-28 02:09:05 +03:00
CTCaer
f3d071ca69 mem: Remove memalign
It doesn't do what it should anyway.
2019-08-28 02:08:12 +03:00
CTCaer
9533dea124 nyx: Update AutoRCM status on eMMC restore 2019-08-28 02:06:19 +03:00
CTCaer
6159d94e5d nyx: Fix autoboot list for inis 2019-08-28 01:58:12 +03:00
CTCaer
565956482a hos: Fix SaltyNX on emuMMC
This actually fixes the send process id patch that SaltyNX depends on.

Why it only breaks on emuMMC is unknown.
2019-08-28 01:55:19 +03:00
CTCaer
f622d57f6b utils: Fix ms timer accuracy
Additionally add BPMP delay timers for future use.
2019-08-28 01:33:38 +03:00
CTCaer
6cc0711382 autoboot: Fix force boot from ID 2019-08-28 01:12:34 +03:00
CTCaer
3472e7e7fb Various bugfixes 2019-08-28 01:08:57 +03:00
CTCaer
e07dde1c58 Merge pull request #280 from Guillem96/patch-1
gui: Fix setting minerva periodic training task ready
2019-08-19 20:33:24 +03:00
Guillem Orellana Trullols
03130ad900 Setting minerva periodic training task ready
System status bar is not yet declared at this point, so the task that should be flagged as ready is minerva periodic training.
2019-08-19 15:27:30 +02:00
CTCaer
31db2735ce autoboot: Add forced boot from ID
By using the key `id=` with a max 7 ASCII id, hekate will search all inis automatically and pinpoint the boot entry with that id.
After that it forces a boot from this one.
2019-08-16 22:00:32 +03:00
CTCaer
6ec871ad5f Merge pull request #265 from friedkeenan/master
Fix building with -C
2019-07-09 18:44:06 +03:00
friedkeenan
0fc17cccfb Fix building with -C 2019-07-08 14:17:15 -05:00
242 changed files with 7646 additions and 5091 deletions

View File

@@ -7,13 +7,8 @@ include $(DEVKITARM)/base_rules
################################################################################
IPL_LOAD_ADDR := 0x40008000
NYX_STORAGE_ADDR := 0xED000000
IPL_MAGIC := 0x43544349 #"ICTC"
BLVERSION_MAJOR := 5
BLVERSION_MINOR := 0
BLVERSION_HOTFX := 1
BL_RESERVED := 0
include ./Versions.inc
################################################################################
@@ -60,9 +55,10 @@ OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \
################################################################################
CUSTOMDEFINES := -DIPL_LOAD_ADDR=$(IPL_LOAD_ADDR) -DNYX_STORAGE_ADDR=$(NYX_STORAGE_ADDR) -DBL_MAGIC=$(IPL_MAGIC)
CUSTOMDEFINES += -DBL_VER_MJ=$(BLVERSION_MAJOR) -DBL_VER_MN=$(BLVERSION_MINOR) -DBL_VER_HF=$(BLVERSION_HOTFX) -DBL_RESERVED=$(BL_RESERVED)
CUSTOMDEFINES += -DMENU_LOGO_ENABLE
CUSTOMDEFINES := -DIPL_LOAD_ADDR=$(IPL_LOAD_ADDR) -DBL_MAGIC=$(IPL_MAGIC)
CUSTOMDEFINES += -DBL_VER_MJ=$(BLVERSION_MAJOR) -DBL_VER_MN=$(BLVERSION_MINOR) -DBL_VER_HF=$(BLVERSION_HOTFX) -DBL_RESERVED=$(BLVERSION_RSVD)
CUSTOMDEFINES += -DNYX_VER_MJ=$(NYXVERSION_MAJOR) -DNYX_VER_MN=$(NYXVERSION_MINOR) -DNYX_VER_HF=$(NYXVERSION_HOTFX) -DNYX_RESERVED=$(NYXVERSION_RSVD)
#CUSTOMDEFINES += -DMENU_LOGO_ENABLE
# 0: UART_A, 1: UART_B.
#CUSTOMDEFINES += -DDEBUG_UART_PORT=0
@@ -91,10 +87,10 @@ clean:
@rm -rf $(OUTPUTDIR)
$(MODULEDIRS):
$(MAKE) -C $@ $(MAKECMDGOALS)$(MAKEFLAGS)
$(MAKE) -C $@ $(MAKECMDGOALS) -$(MAKEFLAGS)
$(NYXDIR):
$(MAKE) -C $@ $(MAKECMDGOALS)$(MAKEFLAGS)
$(MAKE) -C $@ $(MAKECMDGOALS) -$(MAKEFLAGS)
$(TARGET).bin: $(BUILDDIR)/$(TARGET)/$(TARGET).elf $(MODULEDIRS) $(NYXDIR)
$(OBJCOPY) -S -O binary $< $(OUTPUTDIR)/$@

View File

@@ -13,8 +13,8 @@ Custom Nintendo Switch bootloader, firmware patcher, and more.
| bootloader | Main folder. |
| \|__ bootlogo.bmp | It is used when custom is on and no logopath found. Can be skipped. |
| \|__ hekate_ipl.ini | Main bootloader configuration and boot entries. |
| \|__ patches.ini | Add external patches. Can be skipped |
| \|__ update.bin | If newer, it is loaded at boot. For modchips. Can be skipped. |
| \|__ patches.ini | Add external patches. Can be skipped. A template can be found [here](./res/patches_template.ini) |
| \|__ update.bin | If newer, it is loaded at boot. For modchips. Auto updated. Can be skipped. |
| bootloader/ini/ | For individual inis. 'More configs...' menu. Autoboot is supported. |
| bootloader/res/ | Nyx user resources. Icons and more. |
| \|__ background.bmp | Nyx - custom background. |
@@ -30,6 +30,7 @@ Custom Nintendo Switch bootloader, firmware patcher, and more.
| bootloader/screenshots/ | Folder where Nyx screenshots are saved |
| bootloader/payloads/ | For payloads. 'Payloads...' menu. Autoboot only supported by including them into an ini. All CFW bootloaders, tools, Linux payloads are supported. |
| bootloader/libtools/ | Future reserved |
| sept | Sept folder. This must be always get updated via the Atmosphère release zip. Needed for tools and booting HOS on 7.0.0 and up. Unused for booting HOS if `fss0=` key is defined. |
**Note**: Sept files for booting 7.0.0 and up are expected at /sept folder at root of sd card.
@@ -42,6 +43,9 @@ The bootloader can be configured via 'bootloader/hekate_ipl.ini' (if it is prese
There are four possible type of entries. "**[ ]**": Boot entry, "**{ }**": Caption, "**#**": Comment, "*newline*": .ini cosmetic newline.
You can find a template [Here](./res/hekate_ipl_template.ini)
### Global Configuration keys/values when boot entry is **config**:
| Config option | Description |
@@ -52,6 +56,7 @@ There are four possible type of entries. "**[ ]**": Boot entry, "**{ }**": Capti
| verification=2 | 0: Disable Backup/Restore verification, 1: Sparse (block based, fast and not 100% reliable), 2: Full (sha256 based, slow and 100% reliable). |
| autohosoff=1 | 0: Disable, 1: If woke up from HOS via an RTC alarm, shows logo, then powers off completely, 2: No logo, immediately powers off.|
| autonogc=1 | 0: Disable, 1: Automatically applies nogc patch if unburnt fuses found and a >= 4.0.0 HOS is booted. |
| updater2p=0 | 0: Disable, 1: Force updates (if needed) the reboot2payload binary to be hekate. |
| backlight=100 | Screen backlight level. 0-255. |
@@ -59,20 +64,23 @@ There are four possible type of entries. "**[ ]**": Boot entry, "**{ }**": Capti
| Config option | Description |
| ---------------------- | ---------------------------------------------------------- |
| logopath={SD path} | If global customlogo is 1 and logopath empty, bootlogo.bmp will be used. If logopath exists, it will load the specified bitmap. |
| warmboot={SD path} | Replaces the warmboot binary |
| secmon={SD path} | Replaces the security monitor binary |
| kernel={SD path} | Replaces the kernel binary |
| kip1={SD path} | Replaces/Adds kernel initial process. Multiple can be set. |
| kip1={SD folder}/* | Loads every .kip/.kip1 inside a folder. Compatible with single kip1 keys. |
| fss0={SD path} | Takes a fusee-secondary binary and extracts all needed parts from it. |
| kip1patch=patchname | Enables a kip1 patch. Specify with multiple lines and/or as CSV. Current available patches nosigchk. |
| fss0={SD path} | Takes a fusee-secondary binary and `extracts` all needed parts from it. kips, exosphere, warmboot and sept. |
| kip1patch=patchname | Enables a kip1 patch. Specify with multiple lines and/or as CSV. If not found, an error will show up |
| fullsvcperm=1 | Disables SVC verification (full services permission) |
| debugmode=1 | Enables Debug mode. Obsolete when used with exosphere as secmon. |
| atmosphere=1 | Enables Atmosphère patching. |
| nouserexceptions=1 | Disables usermode exception handlers when paired with Exosphère. |
| userpmu=1 | Allows user access to PMU when paired with Exosphère. |
| emummc_force_disable=1 | Disabled emuMMC if it's enabled. |
| stock=1 | Disables unneeded kernel patching when running stock or semi-stock. `If emuMMC is enabled, emummc_force_disabled=1` is required to run completely stock. |
| id=idname | Identifies boot entry for forced boot via id. Max 7 chars. |
| payload={SD path} | Payload launching. Tools, Linux, CFW bootloaders, etc. |
| logopath={SD path} | If no logopath, `bootloader/bootlogo.bmp` will be used if exists. If logopath exists, it will load the specified bitmap. |
| icon={SD path} | Force Nyx to use the icon defined here. If this is not found, it will check for a bmp named as the boot entry ([Test 2] -> `bootloader/res/Test 2.bmp`). Otherwise default will be used. |
**Note1**: When using the wildcard (`/*`) with `kip1` you can still use the normal `kip1` after that to load extra single kips.
@@ -80,24 +88,24 @@ There are four possible type of entries. "**[ ]**": Boot entry, "**{ }**": Capti
**Note2**: When using FSS0 it parses exosphere, warmboot and all core kips. You can override the first 2 by using `secmon`/`warmboot` after defining `fss0`.
You can define `kip1` to load an extra kip or many via the wildcard (`/*`) usage.
**Warning**: Never define core kips when using `fss0` and make sure that the folder (when using `/*`), does not include them. This is in case the kips are incompatible between them.
**Warning**: Never define *fss0 core* kips when using `fss0` and make sure that the folder (when using `/*`), does not include them.
This is in case the kips are incompatible between them. If compatible, you can override `fss0` kips with no issues (useful for testing with intermediate kip changes).
### Payload storage:
Hekate now has a new storage in the binary that helps it configure it outside of BPMP enviroment:
hekate has a boot storage in the binary that helps it configure it outside of BPMP enviroment:
| Offset / Name | Description |
| -------------------- | ----------------------------------------------------------------- |
| '0x94' boot_cfg | bit0: Force AutoBoot, bit1: Show launch log, bit2: sept run. |
| '0x94' boot_cfg | bit0: Force AutoBoot, bit1: Show launch log, bit2: Boot from ID, bit7: sept run. |
| '0x95' autoboot | If `Force AutoBoot`: 0: Force go to menu, else boot that entry. |
| '0x96' autoboot_list | If `Force AutoBoot` and `autoboot` then it boots from ini folder. |
| '0x97' extra_cfg | bit7: Force Nyx to run `Dump pkg1/2. |
| '0x98' rsvd[128] | Reserved. |
| '0x97' extra_cfg | bit7: Force Nyx to run `Dump pkg1/2`. |
| '0x98' id[8] | When Boot from ID is set, it will search all inis automatically and find the boot entry with that id and boot it. Must be NULL terminated. |
| '0x98' xt_str[128] | Depends on the set cfg bits. |
You can find a template [Here](./res/hekate_ipl_template.ini)
If the main .ini is not found, it is created on the first hekate boot.
@@ -111,7 +119,8 @@ Greetings to: fincs, hexkyz, SciresM, Shiny Quagsire, WinterMute.
Open source and free packages used:
- FatFs R0.13a, Copyright (C) 2017, ChaN
- bcl-1.2.0, Copyright (C) 2003-2006, Marcus Geelnard
- Atmosphère (SE sha256, prc id kernel patches), Copyright (C) 2018, Atmosphère-NX
- Atmosphère (Exosphere types/panic, prc id kernel patches),
Copyright (C) 2018-2019, Atmosphère-NX
- elfload, Copyright (C) 2014 Owen Shepherd, Copyright (C) 2018 M4xw
___

View File

@@ -1,6 +1,6 @@
# hekate - Bootlogo
The bootlogo can be any size with a maximum of 720 x 1280.
The bootlogo can be any size with a maximum of 720 x 1280.
When it's smaller than 720 x 1280, it is automatically centered and the background takes the color of the first pixel.

11
Versions.inc Normal file
View File

@@ -0,0 +1,11 @@
# IPL Version.
BLVERSION_MAJOR := 5
BLVERSION_MINOR := 1
BLVERSION_HOTFX := 2
BLVERSION_RSVD := 0
# Nyx Version.
NYXVERSION_MAJOR := 0
NYXVERSION_MINOR := 8
NYXVERSION_HOTFX := 5
NYXVERSION_RSVD := 0

View File

@@ -23,6 +23,7 @@
#include "../gfx/tui.h"
#include "../libs/fatfs/ff.h"
#include "../soc/t210.h"
#include "../storage/sdmmc.h"
#include "../utils/btn.h"
#include "../utils/list.h"
#include "../utils/util.h"
@@ -42,13 +43,15 @@ void set_default_configuration()
h_cfg.backlight = 100;
h_cfg.autohosoff = 0;
h_cfg.autonogc = 1;
h_cfg.updater2p = 0;
h_cfg.brand = NULL;
h_cfg.tagline = NULL;
h_cfg.errors = 0;
h_cfg.sept_run = EMC(EMC_SCRATCH0) & EMC_SEPT_RUN;
h_cfg.rcm_patched = true;
h_cfg.sd_timeoff = 0;
h_cfg.emummc_force_disable = false;
sd_power_cycle_time_start = 0;
}
int create_config_entry()
@@ -56,7 +59,7 @@ int create_config_entry()
if (!sd_mount())
return 1;
char lbuf[16];
char lbuf[32];
FIL fp;
bool mainIniFound = false;
@@ -106,6 +109,9 @@ int create_config_entry()
f_puts("\nautonogc=", &fp);
itoa(h_cfg.autonogc, lbuf, 10);
f_puts(lbuf, &fp);
f_puts("\nupdater2p=", &fp);
itoa(h_cfg.updater2p, lbuf, 10);
f_puts(lbuf, &fp);
if (h_cfg.brand)
{
f_puts("\nbrand=", &fp);
@@ -225,8 +231,7 @@ static void _config_autoboot_list(void *ent)
else
boot_text[(i - 1) * 512] = '*';
memcpy(boot_text + (i - 1) * 512 + 1, ini_sec->name, strlen(ini_sec->name) + 1);
boot_text[strlen(ini_sec->name) + (i - 1) * 512 + 1] = 0;
strcpy(boot_text + (i - 1) * 512 + 1, ini_sec->name);
ments[i].caption = &boot_text[(i - 1) * 512];
}
ments[i].type = ini_sec->type;
@@ -280,10 +285,11 @@ void config_autoboot()
LIST_INIT(ini_sections);
u8 max_entries = 30;
u32 boot_text_size = 512;
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 5));
u32 *boot_values = (u32 *)malloc(sizeof(u32) * max_entries);
char *boot_text = (char *)malloc(512 * max_entries);
char *boot_text = (char *)malloc(boot_text_size * max_entries);
for (u32 j = 0; j < max_entries; j++)
boot_values[j] = j;
@@ -329,13 +335,12 @@ void config_autoboot()
else
{
if (h_cfg.autoboot != (i - 4) || h_cfg.autoboot_list)
boot_text[(i - 4) * 512] = ' ';
boot_text[(i - 4) * boot_text_size] = ' ';
else
boot_text[(i - 4) * 512] = '*';
memcpy(boot_text + (i - 4) * 512 + 1, ini_sec->name, strlen(ini_sec->name) + 1);
boot_text[strlen(ini_sec->name) + (i - 4) * 512 + 1] = 0;
ments[i].caption = &boot_text[(i - 4) * 512];
boot_text[(i - 4) * boot_text_size] = '*';
strcpy(boot_text + (i - 4) * boot_text_size + 1, ini_sec->name);
ments[i].caption = &boot_text[(i - 4) * boot_text_size];
}
ments[i].type = ini_sec->type;
ments[i].data = &boot_values[i - 4];
@@ -391,10 +396,11 @@ void config_bootdelay()
gfx_con_setpos(0, 0);
u32 delay_entries = 6;
u32 delay_text_size = 32;
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (delay_entries + 3));
u32 *delay_values = (u32 *)malloc(sizeof(u32) * delay_entries);
char *delay_text = (char *)malloc(32 * delay_entries);
char *delay_text = (char *)malloc(delay_text_size * delay_entries);
for (u32 j = 0; j < delay_entries; j++)
delay_values[j] = j;
@@ -415,14 +421,14 @@ void config_bootdelay()
for (i = 1; i < delay_entries; i++)
{
if (h_cfg.bootwait != i)
delay_text[i * 32] = ' ';
delay_text[i * delay_text_size] = ' ';
else
delay_text[i * 32] = '*';
delay_text[i * 32 + 1] = i + '0';
memcpy(delay_text + i * 32 + 2, " seconds", 9);
delay_text[i * delay_text_size] = '*';
delay_text[i * delay_text_size + 1] = i + '0';
strcpy(delay_text + i * delay_text_size + 2, " seconds");
ments[i + 2].type = MENT_DATA;
ments[i + 2].caption = delay_text + i * 32;
ments[i + 2].caption = delay_text + (i * delay_text_size);
ments[i + 2].data = &delay_values[i];
}
@@ -450,9 +456,11 @@ void config_verification()
gfx_clear_grey(0x1B);
gfx_con_setpos(0, 0);
u32 vr_text_size = 64;
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 6);
u32 *vr_values = (u32 *)malloc(sizeof(u32) * 3);
char *vr_text = (char *)malloc(64 * 3);
char *vr_text = (char *)malloc(vr_text_size * 3);
for (u32 j = 0; j < 3; j++)
{
@@ -466,17 +474,17 @@ void config_verification()
ments[1].type = MENT_CHGLINE;
memcpy(vr_text, " Disable (Fastest - Unsafe)", 28);
memcpy(vr_text + 64, " Sparse (Fast - Safe)", 23);
memcpy(vr_text + 128, " Full (Slow - Safe)", 23);
strcpy(vr_text, " Disable (Fastest - Unsafe)");
strcpy(vr_text + 64, " Sparse (Fast - Safe)");
strcpy(vr_text + 128, " Full (Slow - Safe)");
for (u32 i = 0; i < 3; i++)
{
if (h_cfg.verification != i)
vr_text[64 * i] = ' ';
vr_text[vr_text_size * i] = ' ';
else
vr_text[64 * i] = '*';
ments[2 + i].caption = vr_text + (i * 64);
vr_text[vr_text_size * i] = '*';
ments[2 + i].caption = vr_text + (i * vr_text_size);
}
memset(&ments[5], 0, sizeof(ment_t));
@@ -503,11 +511,12 @@ void config_backlight()
gfx_clear_grey(0x1B);
gfx_con_setpos(0, 0);
u32 bri_text_size = 8;
u32 bri_entries = 11;
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (bri_entries + 3));
u32 *bri_values = (u32 *)malloc(sizeof(u32) * bri_entries);
char *bri_text = (char *)malloc(8 * bri_entries);
char *bri_text = (char *)malloc(bri_text_size * bri_entries);
for (u32 j = 1; j < bri_entries; j++)
bri_values[j] = j * 10;
@@ -521,20 +530,20 @@ void config_backlight()
for (i = 1; i < bri_entries; i++)
{
if ((h_cfg.backlight / 20) != i)
bri_text[i * 32] = ' ';
bri_text[i * bri_text_size] = ' ';
else
bri_text[i * 32] = '*';
bri_text[i * bri_text_size] = '*';
if (i < 10)
{
bri_text[i * 32 + 1] = i + '0';
memcpy(bri_text + i * 32 + 2, "0%", 3);
bri_text[i * bri_text_size + 1] = i + '0';
strcpy(bri_text + i * bri_text_size + 2, "0%");
}
else
memcpy(bri_text + i * 32 + 1, "100%", 5);
strcpy(bri_text + i * bri_text_size + 1, "100%");
ments[i + 1].type = MENT_DATA;
ments[i + 1].caption = bri_text + i * 32;
ments[i + 1].caption = bri_text + (i * bri_text_size);
ments[i + 1].data = &bri_values[i];
}

View File

@@ -29,23 +29,18 @@ typedef struct _hekate_config
u32 backlight;
u32 autohosoff;
u32 autonogc;
u32 updater2p;
char *brand;
char *tagline;
// Global temporary config.
bool se_keygen_done;
u32 sbar_time_keeping;
u32 errors;
int sept_run;
bool rcm_patched;
u32 sd_timeoff;
bool sept_run;
bool emummc_force_disable;
bool rcm_patched;
u32 sbar_time_keeping;
u32 errors;
} hekate_config;
typedef enum
{
ERR_LIBSYS_LP0 = (1 << 0),
} hsysmodule_t;
void set_default_configuration();
int create_config_entry();
void config_autoboot();

View File

@@ -1,6 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (C) 2018-2019 CTCaer
* Copyright (c) 2018-2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -35,7 +35,7 @@ static char *_strdup(char *str)
strcpy(res, str);
// Remove trailing space.
if (res[strlen(res) - 1] == ' ' && strlen(res))
if (strlen(res) && res[strlen(res) - 1] == ' ')
res[strlen(res) - 1] = 0;
return res;
@@ -44,7 +44,8 @@ static char *_strdup(char *str)
u32 _find_section_name(char *lbuf, u32 lblen, char schar)
{
u32 i;
for (i = 0; i < lblen && lbuf[i] != schar && lbuf[i] != '\n' && lbuf[i] != '\r'; i++)
// Depends on 'FF_USE_STRFUNC 2' that removes \r.
for (i = 0; i < lblen && lbuf[i] != schar && lbuf[i] != '\n'; i++)
;
lbuf[i] = 0;
@@ -78,7 +79,7 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
char *filename = (char *)malloc(256);
memcpy(filename, ini_path, pathlen + 1);
strcpy(filename, ini_path);
// Get all ini filenames.
if (is_dir)
@@ -89,7 +90,7 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
free(filename);
return 0;
}
memcpy(filename + pathlen, "/", 2);
strcpy(filename + pathlen, "/");
pathlen++;
}
@@ -100,7 +101,7 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
{
if (filelist[k * 256])
{
memcpy(filename + pathlen, &filelist[k * 256], strlen(&filelist[k * 256]) + 1);
strcpy(filename + pathlen, &filelist[k * 256]);
k++;
}
else
@@ -123,8 +124,8 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
f_gets(lbuf, 512, &fp);
lblen = strlen(lbuf);
// Remove trailing newline.
if (lbuf[lblen - 1] == '\n' || lbuf[lblen - 1] == '\r')
// Remove trailing newline. Depends on 'FF_USE_STRFUNC 2' that removes \r.
if (lblen && lbuf[lblen - 1] == '\n')
lbuf[lblen - 1] = 0;
if (lblen > 2 && lbuf[0] == '[') // Create new section.
@@ -134,24 +135,22 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
csec = _ini_create_section(dst, csec, &lbuf[1], INI_CHOICE);
list_init(&csec->kvs);
}
else if (lblen > 2 && lbuf[0] == '{') //Create new caption.
else if (lblen > 1 && lbuf[0] == '{') // Create new caption. Support empty caption '{}'.
{
_find_section_name(lbuf, lblen, '}');
csec = _ini_create_section(dst, csec, &lbuf[1], INI_CAPTION);
csec->color = 0xFF0AB9E6;
}
else if (lblen > 2 && lbuf[0] == '#') //Create empty lines and comments.
else if (lblen > 2 && lbuf[0] == '#') // Create comment.
{
_find_section_name(lbuf, lblen, '\0');
csec = _ini_create_section(dst, csec, &lbuf[1], INI_COMMENT);
}
else if (lblen < 2)
else if (lblen < 2) // Create empty line.
{
csec = _ini_create_section(dst, csec, NULL, INI_NEWLINE);
}
else if (csec && csec->type == INI_CHOICE) //Extract key/value.
else if (csec && csec->type == INI_CHOICE) // Extract key/value.
{
u32 i = _find_section_name(lbuf, lblen, '=');
@@ -180,22 +179,14 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
char *ini_check_payload_section(ini_sec_t *cfg)
{
char *path = NULL;
if (cfg == NULL)
return NULL;
LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg->kvs, link)
{
if (!strcmp("payload", kv->key))
{
if (!path)
path = _strdup(kv->val);
}
return kv->val;
}
if (path)
return path;
else
return NULL;
return NULL;
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (C) 2018 CTCaer
* Copyright (c) 2018 CTCaer
*
* 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

@@ -20,6 +20,7 @@
#include <stdlib.h>
#include "fe_emmc_tools.h"
#include "../../common/memory_map.h"
#include "../config/config.h"
#include "../gfx/gfx.h"
#include "../gfx/tui.h"
@@ -31,10 +32,6 @@
#include "../utils/btn.h"
#include "../utils/util.h"
#define EMMC_BUF_ALIGNED 0xB5000000
#define SDXC_BUF_ALIGNED 0xB6000000
#define MIXD_BUF_ALIGNED 0xB7000000
#define NUM_SECTORS_PER_ITER 8192 // 4MB Cache.
#define OUT_FILENAME_SZ 128
#define SHA256_SZ 0x20
@@ -77,7 +74,7 @@ static int _dump_emmc_verify(sdmmc_storage_t *storage, u32 lba_curr, char *outFi
while (totalSectorsVer > 0)
{
num = MIN(totalSectorsVer, NUM_SECTORS_PER_ITER);
// Check every time or every 4.
// Every 4 protects from fake sd, sector corruption and frequent I/O corruption.
// Full provides all that, plus protection from extremely rare I/O corruption.
@@ -88,7 +85,7 @@ static int _dump_emmc_verify(sdmmc_storage_t *storage, u32 lba_curr, char *outFi
gfx_con.fntsz = 16;
EPRINTFARGS("\nFailed to read %d blocks (@LBA %08X),\nfrom eMMC!\n\nVerification failed..\n",
num, lba_curr);
f_close(&fp);
return 1;
}
@@ -97,7 +94,7 @@ static int _dump_emmc_verify(sdmmc_storage_t *storage, u32 lba_curr, char *outFi
{
gfx_con.fntsz = 16;
EPRINTFARGS("\nFailed to read %d blocks (@LBA %08X),\nfrom sd card!\n\nVerification failed..\n", num, lba_curr);
f_close(&fp);
return 1;
}
@@ -110,7 +107,7 @@ static int _dump_emmc_verify(sdmmc_storage_t *storage, u32 lba_curr, char *outFi
{
gfx_con.fntsz = 16;
EPRINTFARGS("\nSD and eMMC data (@LBA %08X),\ndo not match!\n\nVerification failed..\n", lba_curr);
f_close(&fp);
return 1;
}
@@ -185,7 +182,7 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
FIL partialIdxFp;
char partialIdxFilename[12];
memcpy(partialIdxFilename, "partial.idx", 12);
strcpy(partialIdxFilename, "partial.idx");
gfx_con.fntsz = 8;
gfx_printf("\nSD Card free space: %d MiB, Total backup size %d MiB\n\n",
@@ -203,7 +200,7 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
{
isSmallSdCard = true;
gfx_printf("%k\nSD card free space is smaller than total backup size.%k\n", 0xFFFFBA00, 0xFFCCCCCC);
gfx_printf("%k\nSD card free space is smaller than backup size.%k\n", 0xFFFFBA00, 0xFFCCCCCC);
if (!maxSplitParts)
{
@@ -518,7 +515,7 @@ static void _dump_emmc_selected(emmcPartType_t dumpType)
bootPart.lba_end = (BOOT_PART_SIZE / NX_EMMC_BLOCKSIZE) - 1;
for (i = 0; i < 2; i++)
{
memcpy(bootPart.name, "BOOT", 5);
strcpy(bootPart.name, "BOOT");
bootPart.name[4] = (u8)('0' + i);
bootPart.name[5] = 0;
@@ -874,7 +871,7 @@ static void _restore_emmc_selected(emmcPartType_t restoreType)
bootPart.lba_end = (BOOT_PART_SIZE / NX_EMMC_BLOCKSIZE) - 1;
for (i = 0; i < 2; i++)
{
memcpy(bootPart.name, "BOOT", 4);
strcpy(bootPart.name, "BOOT");
bootPart.name[4] = (u8)('0' + i);
bootPart.name[5] = 0;

View File

@@ -47,7 +47,7 @@ extern int sd_save_to_file(void *buf, u32 size, const char *filename);
extern void emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage);
#pragma GCC push_options
#pragma GCC optimize ("Os")
#pragma GCC optimize ("Os")
void print_fuseinfo()
{
@@ -201,40 +201,33 @@ void print_mmc_info()
gfx_printf("%kExtended CSD V1.%d:%k\n",
0xFF00DDFF, storage.ext_csd.ext_struct, 0xFFCCCCCC);
card_type = storage.ext_csd.card_type;
u8 card_type_support[96];
u8 pos_type = 0;
char card_type_support[96];
card_type_support[0] = 0;
if (card_type & EXT_CSD_CARD_TYPE_HS_26)
{
memcpy(card_type_support, "HS26", 4);
strcat(card_type_support, "HS26");
speed = (26 << 16) | 26;
pos_type += 4;
}
if (card_type & EXT_CSD_CARD_TYPE_HS_52)
{
memcpy(card_type_support + pos_type, ", HS52", 6);
strcat(card_type_support, ", HS52");
speed = (52 << 16) | 52;
pos_type += 6;
}
if (card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
{
memcpy(card_type_support + pos_type, ", DDR52_1.8V", 12);
strcat(card_type_support, ", DDR52_1.8V");
speed = (52 << 16) | 104;
pos_type += 12;
}
if (card_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
{
memcpy(card_type_support + pos_type, ", HS200_1.8V", 12);
strcat(card_type_support, ", HS200_1.8V");
speed = (200 << 16) | 200;
pos_type += 12;
}
if (card_type & EXT_CSD_CARD_TYPE_HS400_1_8V)
{
memcpy(card_type_support + pos_type, ", HS400_1.8V", 12);
strcat(card_type_support, ", HS400_1.8V");
speed = (200 << 16) | 400;
pos_type += 12;
}
card_type_support[pos_type] = 0;
gfx_printf(
" Spec Version: %02X\n"
@@ -300,8 +293,6 @@ void print_sdcard_info()
if (sd_mount())
{
u32 capacity;
gfx_printf("%kCard IDentification:%k\n", 0xFF00DDFF, 0xFFCCCCCC);
gfx_printf(
" Vendor ID: %02x\n"
@@ -318,7 +309,6 @@ void print_sdcard_info()
sd_storage.cid.month, sd_storage.cid.year);
gfx_printf("%kCard-Specific Data V%d.0:%k\n", 0xFF00DDFF, sd_storage.csd.structure + 1, 0xFFCCCCCC);
capacity = sd_storage.csd.capacity >> (20 - sd_storage.csd.read_blkbits);
gfx_printf(
" Cmd Classes: %02X\n"
" Capacity: %d MiB\n"
@@ -329,7 +319,7 @@ void print_sdcard_info()
" Video Class: V%d\n"
" App perf class: A%d\n"
" Write Protect: %d\n\n",
sd_storage.csd.cmdclass, capacity,
sd_storage.csd.cmdclass, sd_storage.sec_cnt >> 11,
sd_storage.ssr.bus_width, sd_storage.csd.busspeed, sd_storage.csd.busspeed * 2,
sd_storage.ssr.speed_class, sd_storage.ssr.uhs_grade, sd_storage.ssr.video_class,
sd_storage.ssr.app_class, sd_storage.csd.write_protect);
@@ -419,7 +409,6 @@ void print_tsec_key()
{
for (u32 j = 0; j < 0x10; j++)
gfx_printf("%02X", keys[j]);
if (pkg1_id->kb == KB_FIRMWARE_VERSION_620)
{
@@ -638,13 +627,13 @@ void bootrom_ipatches_info()
gfx_con_setpos(0, 0);
static const u32 BOOTROM_SIZE = 0x18000;
u32 res = fuse_read_ipatch(_ipatch_process);
if (res != 0)
EPRINTFARGS("Failed to read ipatches. Error: %d", res);
gfx_puts("\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
u32 btn = btn_wait();
if (btn & BTN_POWER)
{
@@ -662,21 +651,21 @@ void bootrom_ipatches_info()
}
else
EPRINTFARGS("Failed to read evp_thunks. Error: %d", res);
emmcsn_path_impl(path, "/dumps", "bootrom_patched.bin", NULL);
if (!sd_save_to_file((u8 *)BOOTROM_BASE, BOOTROM_SIZE, path))
gfx_puts("\nbootrom_patched.bin saved!\n");
u32 ipatch_backup[14];
memcpy(ipatch_backup, (void *)IPATCH_BASE, sizeof(ipatch_backup));
memset((void*)IPATCH_BASE, 0, sizeof(ipatch_backup));
emmcsn_path_impl(path, "/dumps", "bootrom_unpatched.bin", NULL);
if (!sd_save_to_file((u8 *)BOOTROM_BASE, BOOTROM_SIZE, path))
gfx_puts("\nbootrom_unpatched.bin saved!\n");
memcpy((void*)IPATCH_BASE, ipatch_backup, sizeof(ipatch_backup));
sd_unmount();
}

View File

@@ -109,7 +109,7 @@ void dump_packages12()
gfx_printf("sept will run to get the keys.\nThen rerun this option.");
btn_wait();
if (!reboot_to_sept((u8 *)tsec_ctxt.fw, kb))
if (!reboot_to_sept((u8 *)tsec_ctxt.fw, kb, NULL))
{
gfx_printf("Failed to run sept\n");
goto out_free;
@@ -133,13 +133,13 @@ void dump_packages12()
if (kb <= KB_FIRMWARE_VERSION_620)
{
pkg1_unpack(warmboot, secmon, loader, pkg1_id, pkg1);
// Display info.
gfx_printf("%kNX Bootloader size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, hdr->ldr_size);
gfx_printf("%kSecure monitor addr: %k0x%05X\n", 0xFFC7EA46, 0xFFCCCCCC, pkg1_id->secmon_base);
gfx_printf("%kSecure monitor size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, hdr->sm_size);
gfx_printf("%kWarmboot addr: %k0x%05X\n", 0xFFC7EA46, 0xFFCCCCCC, pkg1_id->warmboot_base);
gfx_printf("%kWarmboot size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, hdr->wb_size);
@@ -148,19 +148,19 @@ void dump_packages12()
if (sd_save_to_file(pkg1, 0x40000, path))
goto out_free;
gfx_puts("\npkg1 dumped to pkg1_decr.bin\n");
// Dump nxbootloader.
emmcsn_path_impl(path, "/pkg1", "nxloader.bin", &storage);
if (sd_save_to_file(loader, hdr->ldr_size, path))
goto out_free;
gfx_puts("NX Bootloader dumped to nxloader.bin\n");
// Dump secmon.
emmcsn_path_impl(path, "/pkg1", "secmon.bin", &storage);
if (sd_save_to_file(secmon, hdr->sm_size, path))
goto out_free;
gfx_puts("Secure Monitor dumped to secmon.bin\n");
// Dump warmboot.
emmcsn_path_impl(path, "/pkg1", "warmboot.bin", &storage);
if (sd_save_to_file(warmboot, hdr->wb_size, path))
@@ -187,10 +187,10 @@ void dump_packages12()
// Read in package2.
u32 pkg2_size_aligned = ALIGN(pkg2_size, NX_EMMC_BLOCKSIZE);
pkg2 = malloc(pkg2_size_aligned);
nx_emmc_part_read(&storage, pkg2_part, 0x4000 / NX_EMMC_BLOCKSIZE,
nx_emmc_part_read(&storage, pkg2_part, 0x4000 / NX_EMMC_BLOCKSIZE,
pkg2_size_aligned / NX_EMMC_BLOCKSIZE, pkg2);
// Decrypt package2 and parse KIP1 blobs in INI1 section.
pkg2_hdr_t *pkg2_hdr = pkg2_decrypt(pkg2);
pkg2_hdr_t *pkg2_hdr = pkg2_decrypt(pkg2, kb);
if (!pkg2_hdr)
{
gfx_printf("Pkg2 decryption failed!\n");
@@ -219,8 +219,9 @@ void dump_packages12()
u32 ini1_size = pkg2_hdr->sec_size[PKG2_SEC_INI1];
if (!ini1_size)
{
ini1_off = *(u32 *)(pkg2_hdr->data + PKG2_NEWKERN_INI1_START);
ini1_size = *(u32 *)(pkg2_hdr->data + PKG2_NEWKERN_INI1_END) - *(u32 *)(pkg2_hdr->data + PKG2_NEWKERN_INI1_START);
pkg2_get_newkern_info(pkg2_hdr->data);
ini1_off = pkg2_newkern_ini1_start;
ini1_size = pkg2_newkern_ini1_end - pkg2_newkern_ini1_start;
}
if (sd_save_to_file(pkg2_hdr->data + ini1_off, ini1_size, path))
goto out;
@@ -479,13 +480,13 @@ void _fix_sd_attr(u32 type)
switch (type)
{
case 0:
memcpy(path, "/", 2);
memcpy(label, "SD Card", 8);
strcpy(path, "/");
strcpy(label, "SD Card");
break;
case 1:
default:
memcpy(path, "/Nintendo", 10);
memcpy(label, "Nintendo folder", 16);
strcpy(path, "/Nintendo");
strcpy(label, "Nintendo folder");
break;
}

View File

@@ -47,54 +47,61 @@ void display_init()
max77620_regulator_set_volt_and_flags(REGULATOR_LDO0, 1200000, MAX77620_POWER_MODE_NORMAL); // Configure to 1.2V.
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO7, MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH | MAX77620_CNFG_GPIO_DRV_PUSHPULL);
// Enable MIPI CAL, DSI, DISP1, HOST1X, UART_FST_MIPI_CAL, DSIA LP clocks.
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = 0x1010000;
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = 0x1010000;
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = 0x18000000;
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = 0x18000000;
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = 0x20000;
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIP_CAL) = 0xA;
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_SET) = 0x80000;
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP) = 0xA;
// Enable Display Interface specific clocks.
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = 0x1010000; // Clear reset DSI, MIPI_CAL.
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = 0x1010000; // Set enable clock DSI, MIPI_CAL.
// DPD idle.
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = 0x18000000; // Clear reset DISP1, HOST1X.
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = 0x18000000; // Set enable clock DISP1, HOST1X.
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = 0x20000; // Set enable clock UART_FST_MIPI_CAL.
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIPI_CAL) = 10; // Set PLLP_OUT3 and div 6 (17MHz).
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_SET) = 0x80000; // Set enable clock DSIA_LP.
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP) = 10; // Set PLLP_OUT and div 6 (68MHz).
// Disable deap power down.
PMC(APBDEV_PMC_IO_DPD_REQ) = 0x40000000;
PMC(APBDEV_PMC_IO_DPD2_REQ) = 0x40000000;
// Config pins.
// Config LCD and Backlight pins.
PINMUX_AUX(PINMUX_AUX_NFC_EN) &= ~PINMUX_TRISTATE;
PINMUX_AUX(PINMUX_AUX_NFC_INT) &= ~PINMUX_TRISTATE;
PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) &= ~PINMUX_TRISTATE;
PINMUX_AUX(PINMUX_AUX_LCD_BL_EN) &= ~PINMUX_TRISTATE;
PINMUX_AUX(PINMUX_AUX_LCD_RST) &= ~PINMUX_TRISTATE;
gpio_config(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_MODE_GPIO); // Backlight +-5V.
gpio_output_enable(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_OUTPUT_ENABLE); // Backlight +-5V.
// Set Backlight +-5V pins mode and direction
gpio_config(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_MODE_GPIO);
gpio_output_enable(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_OUTPUT_ENABLE);
// Enable Backlight power.
gpio_write(GPIO_PORT_I, GPIO_PIN_0, GPIO_HIGH); // Backlight +5V enable.
usleep(10000);
gpio_write(GPIO_PORT_I, GPIO_PIN_1, GPIO_HIGH); // Backlight -5V enable.
usleep(10000);
gpio_config(GPIO_PORT_V, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2, GPIO_MODE_GPIO); // Backlight PWM, Enable, Reset.
// Configure Backlight pins (PWM, EN, RST).
gpio_config(GPIO_PORT_V, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2, GPIO_MODE_GPIO);
gpio_output_enable(GPIO_PORT_V, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2, GPIO_OUTPUT_ENABLE);
gpio_write(GPIO_PORT_V, GPIO_PIN_1, GPIO_HIGH); // Backlight Enable enable.
gpio_write(GPIO_PORT_V, GPIO_PIN_1, GPIO_HIGH); // Enable Backlight EN.
// Config display interface and display.
// Power up supply regulator for display interface.
MIPI_CAL(MIPI_CAL_MIPI_BIAS_PAD_CFG2) = 0;
// Set DISP1 clock source and parrent clock.
exec_cfg((u32 *)CLOCK_BASE, _display_config_1, 4);
// Setup display communication interfaces.
exec_cfg((u32 *)DISPLAY_A_BASE, _display_config_2, 94);
exec_cfg((u32 *)DSI_BASE, _display_config_3, 61);
usleep(10000);
gpio_write(GPIO_PORT_V, GPIO_PIN_2, GPIO_HIGH); // Backlight Reset enable.
// Enable Backlight Reset.
gpio_write(GPIO_PORT_V, GPIO_PIN_2, GPIO_HIGH);
usleep(60000);
// Setups DSI packet configuration and request display id.
DSI(_DSIREG(DSI_BTA_TIMING)) = 0x50204;
DSI(_DSIREG(DSI_WR_DATA)) = 0x337; // MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE
DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST;
@@ -123,19 +130,22 @@ void display_init()
usleep(20000);
// Configure PLLD for DISP1.
exec_cfg((u32 *)CLOCK_BASE, _display_config_6, 3);
// Finalize DSI configuration.
exec_cfg((u32 *)DSI_BASE, _display_config_5, 21);
DISPLAY_A(_DIREG(DC_DISP_DISP_CLOCK_CONTROL)) = 4;
exec_cfg((u32 *)DSI_BASE, _display_config_7, 10);
usleep(10000);
// Calibrate display communication pads.
exec_cfg((u32 *)MIPI_CAL_BASE, _display_config_8, 6);
exec_cfg((u32 *)DSI_BASE, _display_config_9, 4);
exec_cfg((u32 *)MIPI_CAL_BASE, _display_config_10, 16);
usleep(10000);
// Enable video display controller.
exec_cfg((u32 *)DISPLAY_A_BASE, _display_config_11, 113);
}
@@ -143,11 +153,10 @@ void display_backlight_pwm_init()
{
clock_enable_pwm();
PWM(PWM_CONTROLLER_PWM_CSR_0) = (1 << 31); // Enable PWM
PWM(PWM_CONTROLLER_PWM_CSR_0) = PWM_CSR_EN; // Enable PWM and set it to 25KHz PFM.
PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) >> 2) << 2 | 1; // PWM clock source.
PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) & 0xFFFFFFFC) | 1; // PWM clock source.
gpio_config(GPIO_PORT_V, GPIO_PIN_0, GPIO_MODE_SPIO); // Backlight power mode.
}
void display_backlight(bool enable)
@@ -168,7 +177,7 @@ void display_backlight_brightness(u32 brightness, u32 step_delay)
{
for (u32 i = old_value; i < brightness + 1; i++)
{
PWM(PWM_CONTROLLER_PWM_CSR_0) = (1 << 31) | (i << 16); // Enable PWM
PWM(PWM_CONTROLLER_PWM_CSR_0) = PWM_CSR_EN | (i << 16); // Enable PWM and set it to 25KHz PFM.
usleep(step_delay);
}
}
@@ -176,7 +185,7 @@ void display_backlight_brightness(u32 brightness, u32 step_delay)
{
for (u32 i = old_value; i > brightness; i--)
{
PWM(PWM_CONTROLLER_PWM_CSR_0) = (1 << 31) | (i << 16); // Enable PWM
PWM(PWM_CONTROLLER_PWM_CSR_0) = PWM_CSR_EN | (i << 16); // Enable PWM and set it to 25KHz PFM.
usleep(step_delay);
}
}
@@ -192,13 +201,14 @@ void display_end()
DSI(_DSIREG(DSI_WR_DATA)) = 0x2805; // MIPI_DCS_SET_DISPLAY_OFF
DISPLAY_A(_DIREG(DC_CMD_STATE_ACCESS)) = READ_MUX | WRITE_MUX;
DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = 0;
DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = 0; // Disable host cmd packet.
// De-initialize video controller.
exec_cfg((u32 *)DISPLAY_A_BASE, _display_config_12, 17);
exec_cfg((u32 *)DSI_BASE, _display_config_13, 16);
usleep(10000);
// De-initialize display panel.
if (_display_ver == 0x10)
exec_cfg((u32 *)DSI_BASE, _display_config_14, 22);
@@ -207,31 +217,31 @@ void display_end()
usleep(50000);
// Disable display and backlight pins.
gpio_write(GPIO_PORT_V, GPIO_PIN_2, GPIO_LOW); //Backlight Reset disable.
usleep(10000);
gpio_write(GPIO_PORT_I, GPIO_PIN_1, GPIO_LOW); //Backlight -5V disable.
usleep(10000);
gpio_write(GPIO_PORT_I, GPIO_PIN_0, GPIO_LOW); //Backlight +5V disable.
usleep(10000);
// Disable clocks.
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_SET) = 0x1010000;
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_CLR) = 0x1010000;
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = 0x18000000;
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = 0x18000000;
// Disable Display Interface specific clocks.
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_SET) = 0x1010000; // Set reset clock DSI, MIPI_CAL.
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_CLR) = 0x1010000; // Clear enable clock DSI, MIPI_CAL.
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = 0x18000000; // Set reset DISP1, HOST1X.
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = 0x18000000; // Clear enable DISP1, HOST1X.
// Power down pads.
DSI(_DSIREG(DSI_PAD_CONTROL_0)) = DSI_PAD_CONTROL_VS1_PULLDN_CLK | DSI_PAD_CONTROL_VS1_PULLDN(0xF) | DSI_PAD_CONTROL_VS1_PDIO_CLK | DSI_PAD_CONTROL_VS1_PDIO(0xF);
DSI(_DSIREG(DSI_POWER_CONTROL)) = 0;
// Switch to automatic function mode.
gpio_config(GPIO_PORT_V, GPIO_PIN_0, GPIO_MODE_SPIO); // Backlight PWM.
PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) & ~PINMUX_TRISTATE) | PINMUX_TRISTATE;
PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) >> 2) << 2 | 1;
PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) & 0xFFFFFFFC)| 1;
}
void display_color_screen(u32 color)
@@ -244,7 +254,6 @@ void display_color_screen(u32 color)
DISPLAY_A(_DIREG(DC_WIN_CD_WIN_OPTIONS)) = 0;
DISPLAY_A(_DIREG(DC_DISP_BLEND_BACKGROUND_COLOR)) = color;
DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = (DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) & 0xFFFFFFFE) | GENERAL_ACT_REQ;
usleep(35000);
display_backlight(true);
@@ -253,11 +262,12 @@ void display_color_screen(u32 color)
u32 *display_init_framebuffer()
{
// Sanitize framebuffer area.
memset((u32 *)FB_ADDRESS, 0, 0x3C0000);
// This configures the framebuffer @ 0xC0000000 with a resolution of 1280x720 (line stride 720).
exec_cfg((u32 *)DISPLAY_A_BASE, cfg_display_framebuffer, 32);
memset((u32 *)IPL_FB_ADDRESS, 0, 0x3C0000);
// This configures the framebuffer @ IPL_FB_ADDRESS with a resolution of 1280x720 (line stride 720).
exec_cfg((u32 *)DISPLAY_A_BASE, cfg_display_framebuffer, 32);
usleep(35000);
return (u32 *)FB_ADDRESS;
return (u32 *)IPL_FB_ADDRESS;
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (C) 2018 CTCaer
* Copyright (c) 2018 CTCaer
*
* 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,10 +18,9 @@
#ifndef _DI_H_
#define _DI_H_
#include "../../common/memory_map.h"
#include "../utils/types.h"
#define FB_ADDRESS 0xC0000000
/*! Display registers. */
#define _DIREG(reg) ((reg) * 4)
@@ -235,7 +234,7 @@
#define UV_LINE_STRIDE(x) (((x) & 0xffff) << 16)
#define DC_WIN_DV_CONTROL 0x70E
// The following registers are A/B/C shadows of the 0xBC0/0xDC0/0xFC0 registers (see DISPLAY_WINDOW_HEADER).
/*! The following registers are A/B/C shadows of the 0xBC0/0xDC0/0xFC0 registers (see DISPLAY_WINDOW_HEADER). */
#define DC_WINBUF_START_ADDR 0x800
#define DC_WINBUF_ADDR_H_OFFSET 0x806
#define DC_WINBUF_ADDR_V_OFFSET 0x808

View File

@@ -1,6 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (C) 2018 CTCaer
* Copyright (c) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -415,7 +415,7 @@ static const cfg_op_t _display_config_11[113] = {
{DC_DISP_SYNC_WIDTH, 0x10048},
{DC_DISP_BACK_PORCH, 0x90048},
{DC_DISP_ACTIVE, 0x50002D0},
{DC_DISP_FRONT_PORCH, 0xA0088}, // Sources say that this should be above the DC_DISP_ACTIVE cmd.
{DC_DISP_FRONT_PORCH, 0xA0088}, // Sources say that this should be above the DC_DISP_ACTIVE cmd.
/* End of Display timings */
{DC_DISP_SHIFT_CLOCK_OPTIONS, SC1_H_QUALIFIER_NONE | SC0_H_QUALIFIER_NONE},
{DC_COM_PIN_OUTPUT_ENABLE(1), 0},
@@ -548,7 +548,7 @@ static const cfg_op_t cfg_display_framebuffer[32] = {
{DC_WIN_LINE_STRIDE, UV_LINE_STRIDE(720 * 2) | LINE_STRIDE(720 * 4)}, //768*2x768*4 (= 0x600 x 0xC00) bytes, see TRM for alignment requirements.
{DC_WIN_BUFFER_CONTROL, 0},
{DC_WINBUF_SURFACE_KIND, 0}, //Regular surface.
{DC_WINBUF_START_ADDR, FB_ADDRESS}, //Framebuffer address.
{DC_WINBUF_START_ADDR, IPL_FB_ADDRESS}, // Framebuffer address.
{DC_WINBUF_ADDR_H_OFFSET, 0},
{DC_WINBUF_ADDR_V_OFFSET, 0},
{DC_WIN_WIN_OPTIONS, 0},

View File

@@ -1,6 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (C) 2018-2019 CTCaer
* Copyright (c) 2018-2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -127,12 +127,12 @@ void gfx_init_ctxt(u32 *fb, u32 width, u32 height, u32 stride)
void gfx_clear_grey(u8 color)
{
memset(gfx_ctxt.fb, color, 0x3C0000);
memset(gfx_ctxt.fb, color, gfx_ctxt.width * gfx_ctxt.height * 4);
}
void gfx_clear_color(u32 color)
{
for (u32 i = 0; i < gfx_ctxt.height * gfx_ctxt.stride; i++)
for (u32 i = 0; i < gfx_ctxt.width * gfx_ctxt.height; i++)
gfx_ctxt.fb[i] = color;
}
@@ -185,9 +185,9 @@ void gfx_putc(char c)
u8 *cbuf = (u8 *)&_gfx_font[8 * (c - 32)];
u32 *fb = gfx_ctxt.fb + gfx_con.x + gfx_con.y * gfx_ctxt.stride;
for (u32 i = 0; i < 16; i+=2)
for (u32 i = 0; i < 16; i += 2)
{
u8 v = *cbuf++;
u8 v = *cbuf;
for (u32 k = 0; k < 2; k++)
{
for (u32 j = 0; j < 8; j++)
@@ -212,6 +212,7 @@ void gfx_putc(char c)
fb += gfx_ctxt.stride - 16;
v = *cbuf;
}
cbuf++;
}
gfx_con.x += 16;
}
@@ -254,10 +255,9 @@ void gfx_putc(char c)
}
break;
}
}
void gfx_puts(const char *s)
void gfx_puts(char *s)
{
if (!s || gfx_con.mute)
return;

View File

@@ -1,7 +1,7 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (C) 2018-2019 CTCaer
* Copyright (C) 2018 M4xw
* Copyright (c) 2018-2019 CTCaer
* Copyright (c) 2018 M4xw
*
* 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,8 +26,6 @@
#define WPRINTF(text) gfx_printf("%k"text"%k\n", 0xFFFFDD00, 0xFFCCCCCC)
#define WPRINTFARGS(text, args...) gfx_printf("%k"text"%k\n", 0xFFFFDD00, args, 0xFFCCCCCC)
#define FB_ADDRESS 0xC0000000
void gfx_init_ctxt(u32 *fb, u32 width, u32 height, u32 stride);
void gfx_clear_grey(u8 color);
void gfx_clear_partial_grey(u8 color, u32 pos_x, u32 height);
@@ -37,7 +35,7 @@ void gfx_con_setcol(u32 fgcol, int fillbg, u32 bgcol);
void gfx_con_getpos(u32 *x, u32 *y);
void gfx_con_setpos(u32 x, u32 y);
void gfx_putc(char c);
void gfx_puts(const char *s);
void gfx_puts(char *s);
void gfx_printf(const char *fmt, ...);
void gfx_hexdump(u32 base, const u8 *buf, u32 len);

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 CTCaer
* Copyright (c) 2018 CTCaer
*
* 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

@@ -83,7 +83,7 @@ void tui_pbar(int x, int y, u32 val, u32 fgcol, u32 bgcol)
gfx_printf("%k[%3d%%]%k", fgcol, val, 0xFFCCCCCC);
x += 7 * gfx_con.fntsz;
for (int i = 0; i < (gfx_con.fntsz >> 3) * 6; i++)
{
gfx_line(x, y + i + 1, x + 3 * val, y + i + 1, fgcol);
@@ -157,14 +157,9 @@ void *tui_do_menu(menu_t *menu)
gfx_con_setcol(0xFFCCCCCC, 1, 0xFF1B1B1B);
gfx_putc('\n');
// Print help and battery status.
// Print errors, help and battery status.
gfx_con_setpos(0, 1127);
if (h_cfg.errors)
{
gfx_printf("%k Warning: %k", 0xFF800000, 0xFF555555);
if (h_cfg.errors & ERR_LIBSYS_LP0)
gfx_printf("Sleep mode library is missing!\n");
}
gfx_printf("%k Warning: %k Nyx is missing!", 0xFF800000, 0xFF555555);
gfx_con_setpos(0, 1191);
gfx_printf("%k VOL: Move up/down\n PWR: Select option%k", 0xFF555555, 0xFFCCCCCC);

View File

@@ -1,6 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (C) 2018 CTCaer
* Copyright (c) 2018 CTCaer
*
* 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

@@ -30,6 +30,9 @@
extern hekate_config h_cfg;
extern void *sd_file_read(const char *path, u32 *fsize);
extern bool is_ipl_updated(void *buf, char *path, bool force);
#define FSS0_MAGIC 0x30535346
#define CNT_TYPE_FSP 0
#define CNT_TYPE_EXO 1
@@ -62,27 +65,54 @@ typedef struct _fss_content_t
char name[0x10];
} fss_content_t;
int parse_fss(launch_ctxt_t *ctxt, const char *value)
static void _update_r2p(const char *path)
{
char *r2p_path = malloc(256);
u32 path_len = strlen(path);
strcpy(r2p_path, path);
while(path_len)
{
if ((r2p_path[path_len - 1] == '/') || (r2p_path[path_len - 1] == 0x5C))
{
r2p_path[path_len] = 0;
strcat(r2p_path, "reboot_payload.bin");
u8 *r2p_payload = sd_file_read(r2p_path, NULL);
is_ipl_updated(r2p_payload, r2p_path, h_cfg.updater2p ? true : false);
free(r2p_payload);
break;
}
path_len--;
}
free(r2p_path);
}
int parse_fss(launch_ctxt_t *ctxt, const char *path, fss0_sept_t *sept_ctxt)
{
FIL fp;
bool stock = false;
int sept_used = 0;
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ctxt->cfg->kvs, link)
if (!sept_ctxt)
{
if (!strcmp("stock", kv->key))
if (kv->val[0] == '1')
stock = true;
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ctxt->cfg->kvs, link)
{
if (!strcmp("stock", kv->key))
if (kv->val[0] == '1')
stock = true;
}
if (ctxt->pkg1_id->kb <= KB_FIRMWARE_VERSION_620 && (!emu_cfg.enabled || h_cfg.emummc_force_disable))
return 1;
}
if (stock && ctxt->pkg1_id->kb <= KB_FIRMWARE_VERSION_620 && (!emu_cfg.enabled || h_cfg.emummc_force_disable))
return 1;
if (f_open(&fp, value, FA_READ) != FR_OK)
if (f_open(&fp, path, FA_READ) != FR_OK)
return 0;
ctxt->atmosphere = true;
void *fss = malloc(f_size(&fp));
// Read header.
f_read(&fp, fss, 0x400, NULL);
@@ -98,6 +128,12 @@ int parse_fss(launch_ctxt_t *ctxt, const char *value)
fss_meta->version >> 24, (fss_meta->version >> 16) & 0xFF, (fss_meta->version >> 8) & 0xFF, fss_meta->git_rev,
fss_meta->hos_ver >> 24, (fss_meta->hos_ver >> 16) & 0xFF, (fss_meta->hos_ver >> 8) & 0xFF);
if (!sept_ctxt)
{
ctxt->atmosphere = true;
ctxt->fss0_hosver = fss_meta->hos_ver;
}
fss_content_t *curr_fss_cnt = (fss_content_t *)(fss + fss_meta->cnt_off);
void *content;
for (u32 i = 0; i < fss_meta->cnt_count; i++)
@@ -107,43 +143,79 @@ int parse_fss(launch_ctxt_t *ctxt, const char *value)
continue;
// Load content to launch context.
switch (curr_fss_cnt[i].type)
if (!sept_ctxt)
{
case CNT_TYPE_KIP:
if (stock)
switch (curr_fss_cnt[i].type)
{
case CNT_TYPE_KIP:
if (stock)
continue;
merge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t));
mkip1->kip1 = content;
list_append(&ctxt->kip1_list, &mkip1->link);
DPRINTF("Loaded %s.kip1 from FSS0 (size %08X)\n", curr_fss_cnt[i].name, curr_fss_cnt[i].size);
break;
case CNT_TYPE_EXO:
ctxt->secmon_size = curr_fss_cnt[i].size;
ctxt->secmon = content;
break;
case CNT_TYPE_WBT:
ctxt->warmboot_size = curr_fss_cnt[i].size;
ctxt->warmboot = content;
break;
default:
continue;
merge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t));
mkip1->kip1 = content;
list_append(&ctxt->kip1_list, &mkip1->link);
DPRINTF("Loaded %s.kip1 from FSS0 (size %08X)\n", curr_fss_cnt[i].name, curr_fss_cnt[i].size);
break;
case CNT_TYPE_EXO:
ctxt->secmon_size = curr_fss_cnt[i].size;
ctxt->secmon = content;
break;
case CNT_TYPE_WBT:
ctxt->warmboot_size = curr_fss_cnt[i].size;
ctxt->warmboot = content;
break;
default:
continue;
// TODO: add more types?
// case CNT_TYPE_SP1:
// case CNT_TYPE_SP2:
}
}
else
{
// Load content to launch context.
switch (curr_fss_cnt[i].type)
{
case CNT_TYPE_SP1:
f_lseek(&fp, curr_fss_cnt[i].offset);
f_read(&fp, sept_ctxt->sept_primary, curr_fss_cnt[i].size, NULL);
continue;
case CNT_TYPE_SP2:
if (!memcmp(curr_fss_cnt[i].name, (sept_ctxt->kb < KB_FIRMWARE_VERSION_810) ? "septsecondary00" : "septsecondary01", 15))
{
f_lseek(&fp, curr_fss_cnt[i].offset);
f_read(&fp, sept_ctxt->sept_secondary, curr_fss_cnt[i].size, NULL);
sept_used = 1;
goto out;
}
continue;
default:
continue;
}
}
f_lseek(&fp, curr_fss_cnt[i].offset);
f_read(&fp, content, curr_fss_cnt[i].size, NULL);
}
out:
gfx_printf("Done!\n");
f_close(&fp);
return 1;
_update_r2p(path);
return (!sept_ctxt ? 1 : sept_used);
}
f_close(&fp);
free(fss);
return 0;
}
}
int load_sept_from_ffs0(fss0_sept_t *sept_ctxt)
{
LIST_FOREACH_ENTRY(ini_kv_t, kv, &sept_ctxt->cfg_sec->kvs, link)
{
if (!strcmp("fss0", kv->key))
return parse_fss(NULL, kv->val, sept_ctxt);
}
return 0;
}

View File

@@ -19,6 +19,16 @@
#include "hos.h"
int parse_fss(launch_ctxt_t *ctxt, const char *value);
typedef struct _fss0_sept_t
{
u32 kb;
ini_sec_t *cfg_sec;
void *sept_primary;
void *sept_secondary;
} fss0_sept_t;
int parse_fss(launch_ctxt_t *ctxt, const char *path, fss0_sept_t *sept_ctxt);
int load_sept_from_ffs0(fss0_sept_t *sept_ctxt);
#endif

View File

@@ -52,10 +52,6 @@ extern bool sd_mount();
//#define DPRINTF(...) gfx_printf(__VA_ARGS__)
#define DPRINTF(...)
#define EHPRINTF(text) \
({ display_backlight_brightness(h_cfg.backlight, 1000); \
gfx_con.mute = false; \
gfx_printf("%k"text"%k\n", 0xFFFF0000, 0xFFCCCCCC); })
#define EHPRINTFARGS(text, args...) \
({ display_backlight_brightness(h_cfg.backlight, 1000); \
gfx_con.mute = false; \
@@ -93,36 +89,43 @@ static const u8 master_keyseed_retail[0x10] =
static const u8 console_keyseed[0x10] =
{ 0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78 };
static const u8 package2_keyseed[] =
const u8 package2_keyseed[] =
{ 0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7 };
static const u8 master_keyseed_4xx_5xx_610[0x10] =
static const u8 master_keyseed_4xx_5xx_610[0x10] =
{ 0x2D, 0xC1, 0xF4, 0x8D, 0xF3, 0x5B, 0x69, 0x33, 0x42, 0x10, 0xAC, 0x65, 0xDA, 0x90, 0x46, 0x66 };
static const u8 master_keyseed_620[0x10] =
{ 0x37, 0x4B, 0x77, 0x29, 0x59, 0xB4, 0x04, 0x30, 0x81, 0xF6, 0xE5, 0x8C, 0x6D, 0x36, 0x17, 0x9A };
static const u8 console_keyseed_4xx_5xx[0x10] =
static const u8 console_keyseed_4xx_5xx[0x10] =
{ 0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28 };
static void _hos_crit_error(const char *text)
{
gfx_con.mute = false;
gfx_printf("%k%s%k\n", 0xFFFF0000, text, 0xFFCCCCCC);
display_backlight_brightness(h_cfg.backlight, 1000);
}
static void _se_lock(bool lock_se)
{
if (lock_se)
{
for (u32 i = 0; i < 16; i++)
se_key_acc_ctrl(i, 0x15);
se_key_acc_ctrl(i, SE_KEY_TBL_DIS_KEYREAD_FLAG | SE_KEY_TBL_DIS_OIVREAD_FLAG | SE_KEY_TBL_DIS_UIVREAD_FLAG);
for (u32 i = 0; i < 2; i++)
se_rsa_acc_ctrl(i, 1);
SE(0x4) = 0; // Make this reg secure only.
se_rsa_acc_ctrl(i, SE_RSA_KEY_TBL_DIS_KEYREAD_FLAG);
SE(SE_TZRAM_SECURITY_0) = 0; // Make SE TZRAM secure only.
SE(SE_KEY_TABLE_ACCESS_LOCK_OFFSET) = 0; // Make all key access regs secure only.
SE(SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET) = 0; // Make all RSA access regs secure only.
SE(SE_SECURITY_0) &= 0xFFFFFFFB; // Make access lock regs secure only.
}
memset((void *)IPATCH_BASE, 0, 14 * sizeof(u32));
SB(SB_CSR) = 0x10; // Protected IROM enable.
SB(SB_CSR) = SB_CSR_PIROM_DISABLE;
// This is useful for documenting the bits in the SE config registers, so we can keep it around.
/*gfx_printf("SE(SE_SECURITY_0) = %08X\n", SE(SE_SECURITY_0));
@@ -167,7 +170,6 @@ void _pmc_scratch_lock(u32 kb)
void _sysctr0_reset()
{
SYSCTR0(SYSCTR0_CNTFID0) = 19200000;
SYSCTR0(SYSCTR0_CNTCR) = 0;
SYSCTR0(SYSCTR0_COUNTERID0) = 0;
SYSCTR0(SYSCTR0_COUNTERID1) = 0;
@@ -185,7 +187,7 @@ void _sysctr0_reset()
int keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt, launch_ctxt_t *hos_ctxt)
{
u8 tmp[0x30];
u8 tmp[0x20];
u32 retries = 0;
if (kb > KB_FIRMWARE_VERSION_MAX)
@@ -219,7 +221,7 @@ int keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt, launch_ctxt_t *hos_ctxt)
// We rely on racing conditions, make sure we cover even the unluckiest cases.
if (retries > 15)
{
EHPRINTF("\nFailed to get TSEC keys. Please try again.\n");
_hos_crit_error("\nFailed to get TSEC keys. Please try again.");
return 0;
}
}
@@ -253,7 +255,7 @@ int keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt, launch_ctxt_t *hos_ctxt)
se_aes_unwrap_key(13, 13, master_keyseed_620);
se_aes_unwrap_key(12, 13, master_keyseed_retail);
se_aes_unwrap_key(10, 13, master_keyseed_4xx_5xx_610);
// Package2 key.
se_aes_unwrap_key(8, 12, package2_keyseed);
@@ -262,8 +264,8 @@ int keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt, launch_ctxt_t *hos_ctxt)
}
else
{
se_key_acc_ctrl(13, 0x15);
se_key_acc_ctrl(14, 0x15);
se_key_acc_ctrl(13, SE_KEY_TBL_DIS_KEYREAD_FLAG | SE_KEY_TBL_DIS_OIVREAD_FLAG | SE_KEY_TBL_DIS_UIVREAD_FLAG);
se_key_acc_ctrl(14, SE_KEY_TBL_DIS_KEYREAD_FLAG | SE_KEY_TBL_DIS_OIVREAD_FLAG | SE_KEY_TBL_DIS_UIVREAD_FLAG);
// Set TSEC key.
se_aes_key_set(13, tmp, 0x10);
@@ -318,7 +320,7 @@ int keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt, launch_ctxt_t *hos_ctxt)
}
// Package2 key.
se_key_acc_ctrl(8, 0x15);
se_key_acc_ctrl(8, SE_KEY_TBL_DIS_KEYREAD_FLAG | SE_KEY_TBL_DIS_OIVREAD_FLAG | SE_KEY_TBL_DIS_UIVREAD_FLAG);
se_aes_unwrap_key(8, 12, package2_keyseed);
}
@@ -327,11 +329,20 @@ int keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt, launch_ctxt_t *hos_ctxt)
static int _read_emmc_pkg1(launch_ctxt_t *ctxt)
{
int res = 0;
sdmmc_storage_t storage;
sdmmc_t sdmmc;
emummc_storage_init_mmc(&storage, &sdmmc);
int res = emummc_storage_init_mmc(&storage, &sdmmc);
if (res)
{
if (res == 2)
_hos_crit_error("Failed to init eMMC");
else
_hos_crit_error("Failed to init emuMMC");
return 0;
}
// Read package1.
ctxt->pkg1 = (void *)malloc(0x40000);
@@ -340,7 +351,9 @@ static int _read_emmc_pkg1(launch_ctxt_t *ctxt)
ctxt->pkg1_id = pkg1_identify(ctxt->pkg1);
if (!ctxt->pkg1_id)
{
EHPRINTF("Unknown pkg1 version.");
_hos_crit_error("Unknown pkg1 version.");
EHPRINTFARGS("%sNot yet supported HOS version!",
(emu_cfg.enabled && !h_cfg.emummc_force_disable) ? "Is emuMMC corrupt?\nOr " : "");
goto out;
}
gfx_printf("Identified pkg1 and Keyblob %d\n\n", ctxt->pkg1_id->kb);
@@ -362,14 +375,24 @@ static u8 *_read_emmc_pkg2(launch_ctxt_t *ctxt)
sdmmc_storage_t storage;
sdmmc_t sdmmc;
if (!emummc_storage_init_mmc(&storage, &sdmmc))
int res = emummc_storage_init_mmc(&storage, &sdmmc);
if (res)
{
if (res == 2)
_hos_crit_error("Failed to init eMMC");
else
_hos_crit_error("Failed to init emuMMC");
return NULL;
}
emummc_storage_set_mmc_partition(&storage, 0);
// Parse eMMC GPT.
LIST_INIT(gpt);
nx_emmc_gpt_parse(&gpt, &storage);
DPRINTF("Parsed GPT\n");
DPRINTF("Parsed GPT\n");
// Find package2 partition.
emmc_part_t *pkg2_part = nx_emmc_part_find(&gpt, "BCPKG2-1-Normal-Main");
if (!pkg2_part)
@@ -382,7 +405,7 @@ static u8 *_read_emmc_pkg2(launch_ctxt_t *ctxt)
nx_emmc_part_read(&storage, pkg2_part, BCT_SIZE / NX_EMMC_BLOCKSIZE, 1, bctBuf);
u32 *hdr = (u32 *)(bctBuf + 0x100);
u32 pkg2_size = hdr[0] ^ hdr[2] ^ hdr[3];
DPRINTF("pkg2 size on emmc is %08X\n", pkg2_size);
DPRINTF("pkg2 size on emmc is %08X\n", pkg2_size);
// Read in Boot Config.
memset(bctBuf, 0, BCT_SIZE);
@@ -390,10 +413,10 @@ static u8 *_read_emmc_pkg2(launch_ctxt_t *ctxt)
// Read in package2.
u32 pkg2_size_aligned = ALIGN(pkg2_size, NX_EMMC_BLOCKSIZE);
DPRINTF("pkg2 size aligned is %08X\n", pkg2_size_aligned);
DPRINTF("pkg2 size aligned is %08X\n", pkg2_size_aligned);
ctxt->pkg2 = malloc(pkg2_size_aligned);
ctxt->pkg2_size = pkg2_size;
nx_emmc_part_read(&storage, pkg2_part, BCT_SIZE / NX_EMMC_BLOCKSIZE,
nx_emmc_part_read(&storage, pkg2_part, BCT_SIZE / NX_EMMC_BLOCKSIZE,
pkg2_size_aligned / NX_EMMC_BLOCKSIZE, ctxt->pkg2);
out:;
nx_emmc_gpt_free(&gpt);
@@ -439,7 +462,7 @@ int hos_launch(ini_sec_t *cfg)
// Try to parse config if present.
if (ctxt.cfg && !parse_boot_config(&ctxt))
{
EHPRINTF("Wrong ini cfg or missing files!");
_hos_crit_error("Wrong ini cfg or missing files!");
return 0;
}
@@ -448,7 +471,7 @@ int hos_launch(ini_sec_t *cfg)
{
if (ctxt.stock)
{
EHPRINTF("Stock emuMMC is not supported yet!");
_hos_crit_error("Stock emuMMC is not supported yet!");
return 0;
}
@@ -456,8 +479,13 @@ int hos_launch(ini_sec_t *cfg)
config_kip1patch(&ctxt, "emummc");
}
// Check if fuses lower than 4.0.0 and if yes apply NO Gamecard patch.
if (h_cfg.autonogc && !(fuse_read_odm(7) & ~0xF) && ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_400)
// Check if fuses lower than 4.0.0 or 9.0.0 and if yes apply NO Gamecard patch.
// Additionally check if running emuMMC and disable GC if v3 fuses are burnt and HOS is <= 8.1.0.
if ((h_cfg.autonogc &&
((!(fuse_read_odm(7) & ~0xF) && (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_400)) || // LAFW v2.
(!(fuse_read_odm(7) & ~0x3FF) && (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_900)))) // LAFW v3.
|| ((emu_cfg.enabled && !h_cfg.emummc_force_disable) &&
((fuse_read_odm(7) & 0x400) && (ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_810))))
config_kip1patch(&ctxt, "nogc");
gfx_printf("Loaded pkg1 & keyblob\n");
@@ -472,13 +500,13 @@ int hos_launch(ini_sec_t *cfg)
if (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_700 && !h_cfg.sept_run)
{
gfx_printf("Failed to run sept\n");
_hos_crit_error("Failed to run sept");
return 0;
}
if (!keygen(ctxt.keyblob, ctxt.pkg1_id->kb, &tsec_ctxt, &ctxt))
return 0;
DPRINTF("Generated keys\n");
gfx_printf("Generated keys\n");
if (ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_600)
h_cfg.se_keygen_done = 1;
}
@@ -496,7 +524,7 @@ int hos_launch(ini_sec_t *cfg)
}
else
{
EHPRINTF("No mandatory secmon or warmboot provided!");
_hos_crit_error("No mandatory secmon or warmboot provided!");
return 0;
}
}
@@ -508,7 +536,7 @@ int hos_launch(ini_sec_t *cfg)
{
if (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_700)
{
EHPRINTF("No warmboot provided!");
_hos_crit_error("No warmboot provided!");
return 0;
}
// Else we patch it to allow downgrading.
@@ -543,10 +571,12 @@ int hos_launch(ini_sec_t *cfg)
gfx_printf("Read pkg2\n");
// Decrypt package2 and parse KIP1 blobs in INI1 section.
pkg2_hdr_t *pkg2_hdr = pkg2_decrypt(ctxt.pkg2);
pkg2_hdr_t *pkg2_hdr = pkg2_decrypt(ctxt.pkg2, ctxt.pkg1_id->kb);
if (!pkg2_hdr)
{
gfx_printf("Pkg2 decryption failed!\n");
_hos_crit_error("Pkg2 decryption failed!");
if (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_700)
EPRINTF("Is Sept updated?");
return 0;
}
@@ -569,16 +599,16 @@ int hos_launch(ini_sec_t *cfg)
se_calc_sha256(kernel_hash, ctxt.kernel, ctxt.kernel_size);
else
se_calc_sha256(kernel_hash, ctxt.kernel + PKG2_NEWKERN_START,
*(u32 *)(ctxt.kernel + PKG2_NEWKERN_INI1_START) - PKG2_NEWKERN_START);
pkg2_newkern_ini1_start - PKG2_NEWKERN_START);
ctxt.pkg2_kernel_id = pkg2_identify(kernel_hash);
if (!ctxt.pkg2_kernel_id)
{
EHPRINTF("Failed to identify kernel!");
_hos_crit_error("Failed to identify kernel!");
return 0;
}
// In case a kernel patch option is set; allows to disable SVC verification or/and enable debug mode.
kernel_patch_t *kernel_patchset = ctxt.pkg2_kernel_id->kernel_patchset;
if (kernel_patchset != NULL)
@@ -614,7 +644,6 @@ int hos_launch(ini_sec_t *cfg)
if (unappliedPatch != NULL)
{
EHPRINTFARGS("Failed to apply '%s'!", unappliedPatch);
sd_unmount(); // Just exiting is not enough until pkg2_patch_kips stops modifying the string passed into it.
_free_launch_components(&ctxt);
return 0; // MUST stop here, because if user requests 'nogc' but it's not applied, their GC controller gets updated!
@@ -625,6 +654,9 @@ int hos_launch(ini_sec_t *cfg)
gfx_printf("Rebuilt & loaded pkg2\n");
// Unmount SD card.
sd_unmount();
gfx_printf("\n%kBooting...%k\n", 0xFF96FF00, 0xFFCCCCCC);
// Clear pkg1/pkg2 keys.
@@ -634,7 +666,7 @@ int hos_launch(ini_sec_t *cfg)
// Finalize per firmware keys.
int bootStateDramPkg2 = 0;
int bootStatePkg2Continue = 0;
switch (ctxt.pkg1_id->kb)
{
case KB_FIRMWARE_VERSION_100_200:
@@ -644,16 +676,16 @@ int hos_launch(ini_sec_t *cfg)
PMC(APBDEV_PMC_SECURE_SCRATCH32) = 0xE3; // Warmboot 3.0.0 PA address id.
else if (ctxt.pkg1_id->kb == KB_FIRMWARE_VERSION_301)
PMC(APBDEV_PMC_SECURE_SCRATCH32) = 0x104; // Warmboot 3.0.1/.2 PA address id.
se_key_acc_ctrl(12, 0xFF);
se_key_acc_ctrl(13, 0xFF);
se_key_acc_ctrl(12, SE_KEY_TBL_DIS_KEY_ACCESS_FLAG | SE_KEY_TBL_DIS_KEY_LOCK_FLAG);
se_key_acc_ctrl(13, SE_KEY_TBL_DIS_KEY_ACCESS_FLAG | SE_KEY_TBL_DIS_KEY_LOCK_FLAG);
bootStateDramPkg2 = 2;
bootStatePkg2Continue = 3;
break;
case KB_FIRMWARE_VERSION_400:
case KB_FIRMWARE_VERSION_500:
case KB_FIRMWARE_VERSION_600:
se_key_acc_ctrl(12, 0xFF);
se_key_acc_ctrl(15, 0xFF);
se_key_acc_ctrl(12, SE_KEY_TBL_DIS_KEY_ACCESS_FLAG | SE_KEY_TBL_DIS_KEY_LOCK_FLAG);
se_key_acc_ctrl(15, SE_KEY_TBL_DIS_KEY_ACCESS_FLAG | SE_KEY_TBL_DIS_KEY_LOCK_FLAG);
default:
bootStateDramPkg2 = 2;
bootStatePkg2Continue = 4;
@@ -677,10 +709,7 @@ int hos_launch(ini_sec_t *cfg)
// Config Exosphère if booting full Atmosphère.
if (ctxt.atmosphere && ctxt.secmon)
config_exosphere(ctxt.pkg1_id->id, ctxt.pkg1_id->kb, (void *)ctxt.pkg1_id->warmboot_base, ctxt.stock);
// Unmount SD card.
sd_unmount();
config_exosphere(&ctxt);
// Finalize MC carveout.
if (ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_301)
@@ -718,7 +747,10 @@ int hos_launch(ini_sec_t *cfg)
// Flush cache and disable MMU.
bpmp_mmu_disable();
bpmp_clk_rate_set(BPMP_CLK_NORMAL);
minerva_change_freq(FREQ_800);
minerva_change_freq(FREQ_1600);
// emuMMC: Some cards (Sandisk U1), do not like a fast power cycle. Wait min 100ms.
sdmmc_storage_init_wait_sd();
// Wait for secmon to get ready.
if (smmu_is_used())
@@ -726,14 +758,14 @@ int hos_launch(ini_sec_t *cfg)
else
cluster_boot_cpu0(ctxt.pkg1_id->secmon_base);
while (!secmon_mb->out)
usleep(1); // This only works when in IRAM or with a trained DRAM.
; // A usleep(1) only works when in IRAM or with a trained DRAM.
// Signal pkg2 ready and continue boot.
secmon_mb->in = bootStatePkg2Continue;
// Halt ourselves in waitevent state and resume if there's JTAG activity.
while (true)
FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = 0x50000000;
bpmp_halt();
return 0;
}

View File

@@ -32,7 +32,9 @@
#define KB_FIRMWARE_VERSION_620 6
#define KB_FIRMWARE_VERSION_700 7
#define KB_FIRMWARE_VERSION_810 8
#define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_810
#define KB_FIRMWARE_VERSION_900 9
#define KB_FIRMWARE_VERSION_910 10
#define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_910
#define HOS_PKG11_MAGIC 0x31314B50
@@ -51,17 +53,20 @@ typedef struct _launch_ctxt_t
void *pkg2;
u32 pkg2_size;
bool new_pkg2;
bool new_pkg2;
void *kernel;
u32 kernel_size;
link_t kip1_list;
char* kip1_patches;
u32 fss0_hosver;
bool svcperm;
bool debugmode;
bool stock;
bool atmosphere;
bool exo_no_user_exceptions;
bool exo_user_pmu;
bool emuMMC;
ini_sec_t *cfg;

View File

@@ -36,7 +36,7 @@ static int _config_warmboot(launch_ctxt_t *ctxt, const char *value)
ctxt->warmboot = sd_file_read(value, &ctxt->warmboot_size);
if (!ctxt->warmboot)
return 0;
return 1;
}
@@ -65,13 +65,13 @@ static int _config_kip1(launch_ctxt_t *ctxt, const char *value)
if (!memcmp(value + strlen(value) - 1, "*", 1))
{
char *dir = (char *)malloc(256);
memcpy(dir, value, strlen(value) + 1);
strcpy(dir, value);
u32 dirlen = 0;
dir[strlen(dir) - 2] = 0;
char *filelist = dirlist(dir, "*.kip*", false);
memcpy(dir + strlen(dir), "/", 2);
strcat(dir, "/");
dirlen = strlen(dir);
u32 i = 0;
@@ -82,7 +82,7 @@ static int _config_kip1(launch_ctxt_t *ctxt, const char *value)
if (!filelist[i * 256])
break;
memcpy(dir + dirlen, &filelist[i * 256], strlen(&filelist[i * 256]) + 1);
strcpy(dir + dirlen, &filelist[i * 256]);
merge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t));
mkip1->kip1 = sd_file_read(dir, &size);
@@ -191,9 +191,29 @@ static int _config_atmosphere(launch_ctxt_t *ctxt, const char *value)
return 1;
}
static int _config_dis_exo_user_exceptions(launch_ctxt_t *ctxt, const char *value)
{
if (*value == '1')
{
DPRINTF("Disabled exosphere user exception handlers\n");
ctxt->exo_no_user_exceptions = true;
}
return 1;
}
static int _config_exo_user_pmu_access(launch_ctxt_t *ctxt, const char *value)
{
if (*value == '1')
{
DPRINTF("Enabled user access to PMU\n");
ctxt->exo_user_pmu = true;
}
return 1;
}
static int _config_fss(launch_ctxt_t *ctxt, const char *value)
{
return parse_fss(ctxt, value);
return parse_fss(ctxt, value, NULL);
}
typedef struct _cfg_handler_t
@@ -212,6 +232,8 @@ static const cfg_handler_t _config_handlers[] = {
{ "debugmode", _config_debugmode },
{ "stock", _config_stock },
{ "atmosphere", _config_atmosphere },
{ "nouserexceptions", _config_dis_exo_user_exceptions },
{ "userpmu", _config_exo_user_pmu_access },
{ "fss0", _config_fss },
{ NULL, NULL },
};

View File

@@ -21,6 +21,7 @@
#include "pkg1.h"
#include "../gfx/gfx.h"
#include "../mem/heap.h"
#include "../sec/se.h"
#include "../utils/aarch64_util.h"
@@ -133,18 +134,20 @@ PATCHSET_DEF(_warmboot_4_patchset,
*/
static const pkg1_id_t _pkg1_ids[] = {
{ "20161121183008", 0, 0x1900, 0x3FE0, { 2, 1, 0 }, SM_100_ADR, 0x8000D000, true, _secmon_1_patchset, _warmboot_1_patchset }, //1.0.0 (Patched relocator)
{ "20170210155124", 0, 0x1900, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_2_patchset, _warmboot_2_patchset }, //2.0.0 - 2.3.0
{ "20170519101410", 1, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_3_patchset, _warmboot_3_patchset }, //3.0.0
{ "20170710161758", 2, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_3_patchset, _warmboot_3_patchset }, //3.0.1 - 3.0.2
{ "20170921172629", 3, 0x1800, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003B000, false, _secmon_4_patchset, _warmboot_4_patchset }, //4.0.0 - 4.1.0
{ "20180220163747", 4, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003B000, false, _secmon_5_patchset, _warmboot_4_patchset }, //5.0.0 - 5.1.0
{ "20180802162753", 5, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003D800, false, _secmon_6_patchset, _warmboot_4_patchset }, //6.0.0 - 6.1.0
{ "20181107105733", 6, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x4002B000, 0x4003D800, false, _secmon_620_patchset, _warmboot_4_patchset }, //6.2.0
{ "20181218175730", 7, 0x0F00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //7.0.0
{ "20190208150037", 7, 0x0F00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //7.0.1
{ "20190314172056", 7, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //8.0.0 - 8.0.1
{ "20190531152432", 8, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //8.1.0
{ "20161121183008", 0, 0x1900, 0x3FE0, { 2, 1, 0 }, SM_100_ADR, 0x8000D000, true, _secmon_1_patchset, _warmboot_1_patchset }, //1.0.0 (Patched relocator)
{ "20170210155124", 0, 0x1900, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_2_patchset, _warmboot_2_patchset }, //2.0.0 - 2.3.0
{ "20170519101410", 1, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_3_patchset, _warmboot_3_patchset }, //3.0.0
{ "20170710161758", 2, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_3_patchset, _warmboot_3_patchset }, //3.0.1 - 3.0.2
{ "20170921172629", 3, 0x1800, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003B000, false, _secmon_4_patchset, _warmboot_4_patchset }, //4.0.0 - 4.1.0
{ "20180220163747", 4, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003B000, false, _secmon_5_patchset, _warmboot_4_patchset }, //5.0.0 - 5.1.0
{ "20180802162753", 5, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003D800, false, _secmon_6_patchset, _warmboot_4_patchset }, //6.0.0 - 6.1.0
{ "20181107105733", 6, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x4002B000, 0x4003D800, false, _secmon_620_patchset, _warmboot_4_patchset }, //6.2.0
{ "20181218175730", 7, 0x0F00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //7.0.0
{ "20190208150037", 7, 0x0F00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //7.0.1
{ "20190314172056", 7, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //8.0.0 - 8.0.1
{ "20190531152432", 8, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //8.1.0
{ "20190809135709", 9, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //9.0.0 - 9.0.1
{ "20191021113848", 10, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //9.1.0
{ NULL } //End.
};

View File

@@ -18,6 +18,7 @@
#include <string.h>
#include "hos.h"
#include "pkg2.h"
#include "pkg2_ini_kippatch.h"
@@ -32,6 +33,8 @@
#include "../gfx/gfx.h"
extern hekate_config h_cfg;
extern const u8 package2_keyseed[];
extern void *sd_file_read(const char *path, u32 *fsize);
#ifdef KIP1_PATCH_DEBUG
@@ -55,6 +58,7 @@ extern void *sd_file_read(const char *path, u32 *fsize);
#define FREE_CODE_OFF_1ST_600 0x5EE00
#define FREE_CODE_OFF_1ST_700 0x5FEC0
#define FREE_CODE_OFF_1ST_800 0x607F0
#define FREE_CODE_OFF_1ST_900 0x65780
#define ID_SND_OFF_100 0x23CC0
#define ID_SND_OFF_200 0x3F134
@@ -65,6 +69,7 @@ extern void *sd_file_read(const char *path, u32 *fsize);
#define ID_SND_OFF_600 0x2BB8C
#define ID_SND_OFF_700 0x2D044
#define ID_SND_OFF_800 0x2F1FC
#define ID_SND_OFF_900 0x329A0
#define ID_RCV_OFF_100 0x219F0
#define ID_RCV_OFF_200 0x3D1A8
@@ -75,6 +80,7 @@ extern void *sd_file_read(const char *path, u32 *fsize);
#define ID_RCV_OFF_600 0x29B6C
#define ID_RCV_OFF_700 0x2B23C
#define ID_RCV_OFF_800 0x2D424
#define ID_RCV_OFF_900 0x309B4
static u32 PRC_ID_SND_100[] =
{
@@ -168,6 +174,20 @@ static u32 PRC_ID_RCV_700[] =
#define FREE_CODE_OFF_2ND_800 (FREE_CODE_OFF_1ST_800 + sizeof(PRC_ID_SND_700) + sizeof(u32))
static u32 PRC_ID_SND_900[] =
{
0xA9BF2FEA, 0xF94037EB, 0x2A1603EA, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9,
0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF94002E8, 0xF9401D08, 0xAA1703E0,
0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0
};
#define FREE_CODE_OFF_2ND_900 (FREE_CODE_OFF_1ST_900 + sizeof(PRC_ID_SND_900) + sizeof(u32))
static u32 PRC_ID_RCV_900[] =
{
0xA9BF2FEA, 0xF9404BEB, 0x2A1703EA, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9,
0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF9400368, 0xF9401D08, 0xAA1B03E0,
0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0
};
// Include kernel patches here, so we can utilize pkg1 id
KERNEL_PATCHSET_DEF(_kernel_1_patchset,
{ SVC_VERIFY_DS, 0x3764C, _NOP(), NULL }, // Disable SVC verifications
@@ -244,6 +264,7 @@ KERNEL_PATCHSET_DEF(_kernel_5_patchset,
{ SVC_VERIFY_DS, 0x45E6C, _NOP(), NULL }, // Disable SVC verifications
{ DEBUG_MODE_EN, 0x5513C, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch
// Atmosphère kernel patches.
{ ATM_SYSM_INCR, 0x54E30, _MOVZW(8, 0x1E00, LSL16), NULL }, // System memory pool increase.
{ ATM_GEN_PATCH, ID_SND_OFF_500, _B(ID_SND_OFF_500, FREE_CODE_OFF_1ST_500), NULL}, // Send process id branch.
{ ATM_ARR_PATCH, FREE_CODE_OFF_1ST_500, sizeof(PRC_ID_SND_500) >> 2, PRC_ID_SND_500}, // Send process id code.
{ ATM_GEN_PATCH, FREE_CODE_OFF_1ST_500 + sizeof(PRC_ID_SND_500), // Branch back and skip 2 instructions.
@@ -259,6 +280,7 @@ KERNEL_PATCHSET_DEF(_kernel_6_patchset,
{ SVC_VERIFY_DS, 0x47EA0, _NOP(), NULL }, // Disable SVC verifications
{ DEBUG_MODE_EN, 0x57548, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch
// Atmosphère kernel patches.
{ ATM_SYSM_INCR, 0x57330, _MOVZW(8, 0x1D80, LSL16), NULL }, // System memory pool increase.
{ ATM_GEN_PATCH, ID_SND_OFF_600, _B(ID_SND_OFF_600, FREE_CODE_OFF_1ST_600), NULL}, // Send process id branch.
{ ATM_ARR_PATCH, FREE_CODE_OFF_1ST_600, sizeof(PRC_ID_SND_600) >> 2, PRC_ID_SND_600}, // Send process id code.
{ ATM_GEN_PATCH, FREE_CODE_OFF_1ST_600 + sizeof(PRC_ID_SND_600), // Branch back and skip 4 instructions.
@@ -274,6 +296,7 @@ KERNEL_PATCHSET_DEF(_kernel_7_patchset,
{ SVC_VERIFY_DS, 0x49E5C, _NOP(), NULL }, // Disable SVC verifications
{ DEBUG_MODE_EN, 0x581B0, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch
// Atmosphère kernel patches.
{ ATM_SYSM_INCR, 0x57F98, _MOVZW(8, 0x1D80, LSL16), NULL }, // System memory pool increase.
{ ATM_GEN_PATCH, ID_SND_OFF_700, _B(ID_SND_OFF_700, FREE_CODE_OFF_1ST_700), NULL}, // Send process id branch.
{ ATM_ARR_PATCH, FREE_CODE_OFF_1ST_700, sizeof(PRC_ID_SND_700) >> 2, PRC_ID_SND_700}, // Send process id code.
{ ATM_GEN_PATCH, FREE_CODE_OFF_1ST_700 + sizeof(PRC_ID_SND_700), // Branch back and skip 4 instructions.
@@ -289,16 +312,33 @@ KERNEL_PATCHSET_DEF(_kernel_8_patchset,
{ SVC_VERIFY_DS, 0x4D15C, _NOP(), NULL }, // Disable SVC verifications
{ DEBUG_MODE_EN, 0x5BFAC, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch
// Atmosphère kernel patches.
{ ATM_SYSM_INCR, 0x5F9A4, _MOVZW(19, 0x1D80, LSL16), NULL }, // System memory pool increase.
{ ATM_GEN_PATCH, ID_SND_OFF_800, _B(ID_SND_OFF_800, FREE_CODE_OFF_1ST_800), NULL}, // Send process id branch.
{ ATM_ARR_PATCH, FREE_CODE_OFF_1ST_800, sizeof(PRC_ID_RCV_700) >> 2, PRC_ID_RCV_700}, // Send process id code.
{ ATM_GEN_PATCH, FREE_CODE_OFF_1ST_800 + sizeof(PRC_ID_RCV_700), // Branch back and skip 4 instructions.
_B(FREE_CODE_OFF_1ST_800 + sizeof(PRC_ID_RCV_700), ID_SND_OFF_800 + sizeof(u32) * 4), NULL},
{ ATM_ARR_PATCH, FREE_CODE_OFF_1ST_800, sizeof(PRC_ID_SND_700) >> 2, PRC_ID_SND_700}, // Send process id code.
{ ATM_GEN_PATCH, FREE_CODE_OFF_1ST_800 + sizeof(PRC_ID_SND_700), // Branch back and skip 4 instructions.
_B(FREE_CODE_OFF_1ST_800 + sizeof(PRC_ID_SND_700), ID_SND_OFF_800 + sizeof(u32) * 4), NULL},
{ ATM_GEN_PATCH, ID_RCV_OFF_800, _B(ID_RCV_OFF_800, FREE_CODE_OFF_2ND_800), NULL}, // Receive process id branch.
{ ATM_ARR_PATCH, FREE_CODE_OFF_2ND_800, sizeof(PRC_ID_RCV_700) >> 2, PRC_ID_RCV_700}, // Receive process id code.
{ ATM_GEN_PATCH, FREE_CODE_OFF_2ND_800 + sizeof(PRC_ID_RCV_700), // Branch back and skip 4 instructions.
_B(FREE_CODE_OFF_2ND_800 + sizeof(PRC_ID_RCV_700), ID_RCV_OFF_800 + sizeof(u32) * 4), NULL}
);
KERNEL_PATCHSET_DEF(_kernel_9_patchset,
{ SVC_GENERIC, 0x43DFC, _NOP(), NULL }, // Allow same process on svcControlCodeMemory.
{ SVC_VERIFY_DS, 0x50628, _NOP(), NULL }, // Disable SVC verifications
{ DEBUG_MODE_EN, 0x609E8, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch
// Atmosphère kernel patches.
{ ATM_SYSM_INCR, 0x6493C, _MOVZW(19, 0x1D80, LSL16), NULL }, // System memory pool increase.
{ ATM_GEN_PATCH, ID_SND_OFF_900, _B(ID_SND_OFF_900, FREE_CODE_OFF_1ST_900), NULL}, // Send process id branch.
{ ATM_ARR_PATCH, FREE_CODE_OFF_1ST_900, sizeof(PRC_ID_SND_900) >> 2, PRC_ID_SND_900}, // Send process id code.
{ ATM_GEN_PATCH, FREE_CODE_OFF_1ST_900 + sizeof(PRC_ID_SND_900), // Branch back and skip 4 instructions.
_B(FREE_CODE_OFF_1ST_900 + sizeof(PRC_ID_SND_900), ID_SND_OFF_900 + sizeof(u32) * 4), NULL},
{ ATM_GEN_PATCH, ID_RCV_OFF_900, _B(ID_RCV_OFF_900, FREE_CODE_OFF_2ND_900), NULL}, // Receive process id branch.
{ ATM_ARR_PATCH, FREE_CODE_OFF_2ND_900, sizeof(PRC_ID_RCV_900) >> 2, PRC_ID_RCV_900}, // Receive process id code.
{ ATM_GEN_PATCH, FREE_CODE_OFF_2ND_900 + sizeof(PRC_ID_RCV_900), // Branch back and skip 4 instructions.
_B(FREE_CODE_OFF_2ND_900 + sizeof(PRC_ID_RCV_900), ID_RCV_OFF_900 + sizeof(u32) * 4), NULL}
);
// Kernel sha256 hashes.
static const pkg2_kernel_id_t _pkg2_kernel_ids[] =
{
@@ -309,25 +349,27 @@ static const pkg2_kernel_id_t _pkg2_kernel_ids[] =
{ "\xe6\xc0\xb7\xe3\x2f\xf9\x44\x51", _kernel_4_patchset }, //4.0.0 - 4.1.0
{ "\xb2\x38\x61\xa8\xe1\xe2\xe4\xe4", _kernel_5_patchset }, //5.0.0 - 5.1.0
{ "\x85\x97\x40\xf6\xc0\x3e\x3d\x44", _kernel_6_patchset }, //6.0.0 - 6.2.0
{ "\xa2\x5e\x47\x0c\x8e\x6d\x2f\xd7", _kernel_7_patchset }, //7.0.0
{ "\xf1\x5e\xc8\x34\xfd\x68\xf0\xf0", _kernel_8_patchset } //8.0.0. Kernel only.
{ "\xa2\x5e\x47\x0c\x8e\x6d\x2f\xd7", _kernel_7_patchset }, //7.0.0 - 7.0.1
{ "\xf1\x5e\xc8\x34\xfd\x68\xf0\xf0", _kernel_8_patchset }, //8.0.0 - 8.1.0. Kernel only.
{ "\x69\x00\x39\xdf\x21\x56\x70\x6b", _kernel_9_patchset }, //9.0.0 - 9.1.0. Kernel only.
{ "\xa2\xe3\xad\x1c\x98\xd8\x7a\x62", _kernel_9_patchset }, //9.2.0. Kernel only.
};
enum kip_offset_section
{
KIP_TEXT = 0,
KIP_RODATA = 1,
KIP_DATA = 2,
KIP_BSS = 3,
KIP_TEXT = 0,
KIP_RODATA = 1,
KIP_DATA = 2,
KIP_BSS = 3,
KIP_UNKSEC1 = 4,
KIP_UNKSEC2 = 5
};
#define KIP_PATCH_SECTION_SHIFT (29)
#define KIP_PATCH_SECTION_MASK (7 << KIP_PATCH_SECTION_SHIFT)
#define KIP_PATCH_OFFSET_MASK (~KIP_PATCH_SECTION_MASK)
#define KIP_PATCH_SECTION_SHIFT (29)
#define KIP_PATCH_SECTION_MASK (7 << KIP_PATCH_SECTION_SHIFT)
#define KIP_PATCH_OFFSET_MASK (~KIP_PATCH_SECTION_MASK)
#define GET_KIP_PATCH_SECTION(x) ((x >> KIP_PATCH_SECTION_SHIFT) & 7)
#define GET_KIP_PATCH_OFFSET(x) (x & KIP_PATCH_OFFSET_MASK)
#define GET_KIP_PATCH_OFFSET(x) (x & KIP_PATCH_OFFSET_MASK)
#define KPS(x) ((u32)(x) << KIP_PATCH_SECTION_SHIFT)
static kip1_patch_t _fs_emummc[] =
@@ -343,34 +385,6 @@ static kip1_patchset_t _fs_patches_100[] =
{ NULL, NULL }
};
static kip1_patchset_t _fs_patches_200[] =
{
{ "nogc", NULL },
{ "emummc", _fs_emummc },
{ NULL, NULL }
};
static kip1_patchset_t _fs_patches_210[] =
{
{ "nogc", NULL },
{ "emummc", _fs_emummc },
{ NULL, NULL }
};
static kip1_patchset_t _fs_patches_300[] =
{
{ "nogc", NULL },
{ "emummc", _fs_emummc },
{ NULL, NULL }
};
static kip1_patchset_t _fs_patches_30x[] =
{
{ "nogc", NULL },
{ "emummc", _fs_emummc },
{ NULL, NULL }
};
static kip1_patch_t _fs_nogc_40x[] =
{
{ KPS(KIP_TEXT) | 0xA3458, 4, "\x14\x40\x80\x72", "\x14\x80\x80\x72" },
@@ -511,19 +525,47 @@ static kip1_patchset_t _fs_patches_800_exfat[] =
{ NULL, NULL }
};
static kip1_patch_t _fs_nogc_900[] =
{
{ KPS(KIP_TEXT) | 0x129420, 8, "\xF4\x4F\xBE\xA9\xFD\x7B\x01\xA9", "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" },
{ KPS(KIP_TEXT) | 0x143268, 4, "\x14\x40\x80\x52", "\x14\x80\x80\x52" },
{ 0, 0, NULL, NULL }
};
static kip1_patchset_t _fs_patches_900[] =
{
{ "nogc", _fs_nogc_900 },
{ "emummc", _fs_emummc },
{ NULL, NULL }
};
static kip1_patch_t _fs_nogc_910[] =
{
{ KPS(KIP_TEXT) | 0x129430, 8, "\xF4\x4F\xBE\xA9\xFD\x7B\x01\xA9", "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" },
{ KPS(KIP_TEXT) | 0x143278, 4, "\x14\x40\x80\x52", "\x14\x80\x80\x52" },
{ 0, 0, NULL, NULL }
};
static kip1_patchset_t _fs_patches_910[] =
{
{ "nogc", _fs_nogc_910 },
{ "emummc", _fs_emummc },
{ NULL, NULL }
};
// SHA256 hashes.
static kip1_id_t _kip_ids[] =
static kip1_id_t _kip_ids[] =
{
{ "FS", "\xde\x9f\xdd\xa4\x08\x5d\xd5\xfe", _fs_patches_100 }, // FS 1.0.0
{ "FS", "\xfc\x3e\x80\x99\x1d\xca\x17\x96", _fs_patches_100 }, // FS 1.0.0 exfat
{ "FS", "\xcd\x7b\xbe\x18\xd6\x13\x0b\x28", _fs_patches_200 }, // FS 2.0.0
{ "FS", "\xe7\x66\x92\xdf\xaa\x04\x20\xe9", _fs_patches_200 }, // FS 2.0.0 exfat
{ "FS", "\x0d\x70\x05\x62\x7b\x07\x76\x7c", _fs_patches_210 }, // FS 2.1.0
{ "FS", "\xdb\xd8\x5f\xca\xcc\x19\x3d\xa8", _fs_patches_210 }, // FS 2.1.0 exfat
{ "FS", "\xa8\x6d\xa5\xe8\x7e\xf1\x09\x7b", _fs_patches_300 }, // FS 3.0.0
{ "FS", "\x98\x1c\x57\xe7\xf0\x2f\x70\xf7", _fs_patches_300 }, // FS 3.0.0 exfat
{ "FS", "\x57\x39\x7c\x06\x3f\x10\xb6\x31", _fs_patches_30x }, // FS 3.0.1
{ "FS", "\x07\x30\x99\xd7\xc6\xad\x7d\x89", _fs_patches_30x }, // FS 3.0.1 exfat
{ "FS", "\xcd\x7b\xbe\x18\xd6\x13\x0b\x28", _fs_patches_100 }, // FS 2.0.0
{ "FS", "\xe7\x66\x92\xdf\xaa\x04\x20\xe9", _fs_patches_100 }, // FS 2.0.0 exfat
{ "FS", "\x0d\x70\x05\x62\x7b\x07\x76\x7c", _fs_patches_100 }, // FS 2.1.0
{ "FS", "\xdb\xd8\x5f\xca\xcc\x19\x3d\xa8", _fs_patches_100 }, // FS 2.1.0 exfat
{ "FS", "\xa8\x6d\xa5\xe8\x7e\xf1\x09\x7b", _fs_patches_100 }, // FS 3.0.0
{ "FS", "\x98\x1c\x57\xe7\xf0\x2f\x70\xf7", _fs_patches_100 }, // FS 3.0.0 exfat
{ "FS", "\x57\x39\x7c\x06\x3f\x10\xb6\x31", _fs_patches_100 }, // FS 3.0.1
{ "FS", "\x07\x30\x99\xd7\xc6\xad\x7d\x89", _fs_patches_100 }, // FS 3.0.1 exfat
{ "FS", "\x06\xe9\x07\x19\x59\x5a\x01\x0c", _fs_patches_40x }, // FS 4.0.1
{ "FS", "\x54\x9b\x0f\x8d\x6f\x72\xc4\xe9", _fs_patches_40x }, // FS 4.0.1 exfat
{ "FS", "\x80\x96\xaf\x7c\x6a\x35\xaa\x82", _fs_patches_410 }, // FS 4.1.0
@@ -541,7 +583,11 @@ static kip1_id_t _kip_ids[] =
{ "FS", "\xB2\xF5\x17\x6B\x35\x48\x36\x4D", _fs_patches_800 }, // FS 8.0.0
{ "FS", "\xDB\xD9\x41\xC0\xC5\x3C\x52\xCC", _fs_patches_800_exfat }, // FS 8.0.0 exfat
{ "FS", "\x6B\x09\xB6\x7B\x29\xC0\x20\x24", _fs_patches_800 }, // FS 8.1.0
{ "FS", "\xB4\xCA\xE1\xF2\x49\x65\xD9\x2E", _fs_patches_800_exfat } // FS 8.1.0 exfat
{ "FS", "\xB4\xCA\xE1\xF2\x49\x65\xD9\x2E", _fs_patches_800_exfat }, // FS 8.1.0 exfat
{ "FS", "\x46\x87\x40\x76\x1E\x19\x3E\xB7", _fs_patches_900 }, // FS 9.0.0
{ "FS", "\x7C\x95\x13\x76\xE5\xC1\x2D\xF8", _fs_patches_900 }, // FS 9.0.0 exfat
{ "FS", "\xB5\xE7\xA6\x4C\x6F\x5C\x4F\xE3", _fs_patches_910 }, // FS 9.1.0
{ "FS", "\xF1\x96\xD1\x44\xD0\x44\x45\xB6", _fs_patches_910 } // FS 9.1.0 exfat
};
static void parse_external_kip_patches()
@@ -550,10 +596,6 @@ static void parse_external_kip_patches()
char path[64];
strcpy(path, "bootloader/patches.ini");
// If patches.ini not found, try to load from template.
if (f_stat(path, NULL))
strcpy(path, "bootloader/patches_template.ini");
LIST_INIT(ini_kip_sections);
if (ini_patch_parse(&ini_kip_sections, path))
{
@@ -564,7 +606,7 @@ static void parse_external_kip_patches()
if (!strcmp(curr_kip->name, ini_psec->name) && !memcmp(curr_kip->hash, ini_psec->hash, 8))
{
kip1_patchset_t *patchsets = (kip1_patchset_t *)calloc(sizeof(kip1_patchset_t), 8);
kip1_patchset_t *patchsets = (kip1_patchset_t *)calloc(sizeof(kip1_patchset_t), 8); // Max 8 patchsets per kip.
u32 curr_patchset_idx;
for(curr_patchset_idx = 0; curr_kip->patchset[curr_patchset_idx].name != NULL; curr_patchset_idx++)
@@ -578,7 +620,7 @@ static void parse_external_kip_patches()
u32 curr_patch_idx = 0;
// Parse patches and glue them together to a patchset.
kip1_patch_t *patches = calloc(sizeof(kip1_patch_t), 16);
kip1_patch_t *patches = calloc(sizeof(kip1_patch_t), 16); // Max 16 patches per set.
LIST_FOREACH_ENTRY(ini_patchset_t, pt, &ini_psec->pts, link)
{
if (first_ext_patch)
@@ -590,11 +632,12 @@ static void parse_external_kip_patches()
}
else
{
// Check if new patchset name is found and create a new set.
if (strcmp(pt->name, patchsets[curr_patchset_idx].name))
{
curr_patchset_idx++;
curr_patch_idx = 0;
patches = calloc(sizeof(kip1_patch_t), 16);
patches = calloc(sizeof(kip1_patch_t), 16); // Max 16 patches per set.
patchsets[curr_patchset_idx].name = malloc(strlen(pt->name) + 1);
strcpy(patchsets[curr_patchset_idx].name, pt->name);
@@ -612,7 +655,9 @@ static void parse_external_kip_patches()
memcpy(patches[curr_patch_idx].srcData, pt->srcData, pt->length);
memcpy(patches[curr_patch_idx].dstData, pt->dstData, pt->length);
}
else
patches[curr_patch_idx].srcData = malloc(1); // Empty patches check. Keep everything else as 0.
curr_patch_idx++;
}
curr_patchset_idx++;
@@ -645,14 +690,24 @@ static u32 _pkg2_calc_kip1_size(pkg2_kip1_t *kip1)
return size;
}
void pkg2_get_newkern_info(u8 *kern_data)
{
u32 info_op = *(u32 *)(kern_data + PKG2_NEWKERN_GET_INI1);
pkg2_newkern_ini1_val = ((info_op & 0xFFFF) >> 3) + PKG2_NEWKERN_GET_INI1; // Parse ADR and PC.
pkg2_newkern_ini1_start = *(u32 *)(kern_data + pkg2_newkern_ini1_val);
pkg2_newkern_ini1_end = *(u32 *)(kern_data + pkg2_newkern_ini1_val + 0x8);
}
void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2)
{
u8 *ptr;
// Check for new pkg2 type.
if (!pkg2->sec_size[PKG2_SEC_INI1])
{
u32 kernel_ini1_off = *(u32 *)(pkg2->data + PKG2_NEWKERN_INI1_START);
ptr = pkg2->data + kernel_ini1_off;
pkg2_get_newkern_info(pkg2->data);
ptr = pkg2->data + pkg2_newkern_ini1_start;
*new_pkg2 = true;
}
else
@@ -720,19 +775,19 @@ int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp)
pkg2_kip1_t hdr;
memcpy(&hdr, ki->kip1, sizeof(hdr));
unsigned int newKipSize = sizeof(hdr);
for (u32 sectIdx = 0; sectIdx < KIP1_NUM_SECTIONS; sectIdx++)
{
u32 sectCompBit = 1u << sectIdx;
// For compressed, cant get actual decompressed size without doing it, so use safe "output size".
if (sectIdx < 3 && (sectsToDecomp & sectCompBit) && (hdr.flags & sectCompBit))
if (sectIdx < 3 && (sectsToDecomp & sectCompBit) && (hdr.flags & sectCompBit))
newKipSize += hdr.sections[sectIdx].size_decomp;
else
newKipSize += hdr.sections[sectIdx].size_comp;
}
pkg2_kip1_t* newKip = malloc(newKipSize);
pkg2_kip1_t* newKip = malloc(newKipSize);
unsigned char* dstDataPtr = newKip->data;
const unsigned char* srcDataPtr = ki->kip1->data;
for (u32 sectIdx = 0; sectIdx < KIP1_NUM_SECTIONS; sectIdx++)
@@ -756,7 +811,8 @@ int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp)
gfx_printf("Decomping %s KIP1 sect %d of size %d...\n", (const char*)hdr.name, sectIdx, compSize);
if (blz_uncompress_srcdest(srcDataPtr, compSize, dstDataPtr, outputSize) == 0)
{
gfx_printf("%kERROR decomping sect %d of %s KIP!%k\n", 0xFFFF0000, sectIdx, (char*)hdr.name, 0xFFCCCCCC);
gfx_con.mute = false;
gfx_printf("%kERROR decomping sect %d of %s KIP!%k\n", 0xFFFF0000, sectIdx, (char*)hdr.name, 0xFFCCCCCC);
free(newKip);
return 1;
@@ -811,7 +867,7 @@ static int _kipm_inject(const char *kipm_path, char *target_name, pkg2_kip1_info
{
if(!currSectIdx) // .text.
{
memcpy(ki->kip1->data + inject_size, fs_kip->data + new_offset, fs_kip->sections[0].size_comp);
memcpy(ki->kip1->data + inject_size, fs_kip->data, fs_kip->sections[0].size_comp);
ki->kip1->sections[0].size_decomp += inject_size;
ki->kip1->sections[0].size_comp += inject_size;
}
@@ -938,7 +994,7 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
{
if (!se_calc_sha256(shaBuf, ki->kip1, ki->size))
memset(shaBuf, 0, sizeof(shaBuf));
}
}
if (memcmp(shaBuf, _kip_ids[currKipIdx].hash, sizeof(_kip_ids[0].hash)) != 0)
continue;
@@ -961,7 +1017,7 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
for (const kip1_patch_t* currPatch=currPatchset->patches; currPatch != NULL && (currPatch->length != 0); currPatch++)
bitsAffected |= 1u << GET_KIP_PATCH_SECTION(currPatch->offset);
}
}
}
currPatchset++;
}
@@ -990,13 +1046,20 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
continue;
u32 appliedMask = 1u << currEnabIdx;
if (currPatchset->patches == NULL || !strcmp(currPatchset->name, "emummc"))
if (!strcmp(currPatchset->name, "emummc"))
{
emummc_patch_selected = true;
patchesApplied |= appliedMask;
break;
}
if (currPatchset->patches == NULL)
{
gfx_printf("Patch '%s' not necessary for %s KIP1\n", currPatchset->name, (const char*)ki->kip1->name);
patchesApplied |= appliedMask;
if (!strcmp(currPatchset->name, "emummc"))
emummc_patch_selected = true;
break;
}
@@ -1006,15 +1069,25 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
if (bitsAffected & (1u << currSectIdx))
{
gfx_printf("Applying patch '%s' on %s KIP1 sect %d\n", currPatchset->name, (const char*)ki->kip1->name, currSectIdx);
for (const kip1_patch_t* currPatch = currPatchset->patches; currPatch != NULL && currPatch->length != 0; currPatch++)
for (const kip1_patch_t* currPatch = currPatchset->patches; currPatch != NULL && currPatch->srcData != 0; currPatch++)
{
if (GET_KIP_PATCH_SECTION(currPatch->offset) != currSectIdx)
continue;
u32 currOffset = GET_KIP_PATCH_OFFSET(currPatch->offset);
if (memcmp(&kipSectData[currOffset], currPatch->srcData, currPatch->length) != 0)
if (!currPatch->length)
{
gfx_printf("%kDATA MISMATCH FOR PATCH AT OFFSET 0x%x!!!%k\n", 0xFFFF0000, currOffset, 0xFFCCCCCC);
gfx_con.mute = false;
gfx_printf("%kPatch is empty!%k\n", 0xFFFF0000, 0xFFCCCCCC);
return currPatchset->name; // MUST stop here as it's not probably intended.
}
u32 currOffset = GET_KIP_PATCH_OFFSET(currPatch->offset);
// If source is does not match and is not already patched, throw an error.
if ((memcmp(&kipSectData[currOffset], currPatch->srcData, currPatch->length) != 0) &&
(memcmp(&kipSectData[currOffset], currPatch->dstData, currPatch->length) != 0))
{
gfx_con.mute = false;
gfx_printf("%kPatch data mismatch at 0x%x!%k\n", 0xFFFF0000, currOffset, 0xFFCCCCCC);
return currPatchset->name; // MUST stop here as kip is likely corrupt.
}
else
@@ -1026,13 +1099,13 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
}
kipSectData += ki->kip1->sections[currSectIdx].size_comp;
}
patchesApplied |= appliedMask;
break;
}
currPatchset++;
}
if (!strncmp(_kip_ids[currKipIdx].name, "FS", 2) && emummc_patch_selected)
if (emummc_patch_selected && !strncmp(_kip_ids[currKipIdx].name, "FS", 2))
{
emummc_patch_selected = false;
emu_cfg.fs_ver = currKipIdx;
@@ -1057,10 +1130,37 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
return NULL;
}
pkg2_hdr_t *pkg2_decrypt(void *data)
static const u8 mkey_keyseed_8xx[][0x10] =
{
// Master key 8 encrypted with 9. (8.1.0 with 9.0.0)
{ 0x4D, 0xD9, 0x98, 0x42, 0x45, 0x0D, 0xB1, 0x3C, 0x52, 0x0C, 0x9A, 0x44, 0xBB, 0xAD, 0xAF, 0x80 },
// Master key 9 encrypted with 10. (9.0.0 with 9.1.0)
{ 0xB8, 0x96, 0x9E, 0x4A, 0x00, 0x0D, 0xD6, 0x28, 0xB3, 0xD1, 0xDB, 0x68, 0x5F, 0xFB, 0xE1, 0x2A }
};
static bool _pkg2_key_unwrap_validate(pkg2_hdr_t *tmp_test, pkg2_hdr_t *hdr, u8 src_slot, u8 *mkey, const u8 *key_seed)
{
u8 *pdata = (u8 *)data;
// Decrypt older encrypted mkey.
se_aes_crypt_ecb(src_slot, 0, mkey, 0x10, key_seed, 0x10);
// Set and unwrap pkg2 key.
se_aes_key_clear(9);
se_aes_key_set(9, mkey, 0x10);
se_aes_unwrap_key(9, 9, package2_keyseed);
// Decrypt header.
se_aes_crypt_ctr(9, tmp_test, sizeof(pkg2_hdr_t), hdr, sizeof(pkg2_hdr_t), hdr);
// Return if header is valid.
return (tmp_test->magic == PKG2_MAGIC);
}
pkg2_hdr_t *pkg2_decrypt(void *data, u8 kb)
{
pkg2_hdr_t mkey_test;
u8 *pdata = (u8 *)data;
u8 keyslot = 8;
// Skip signature.
pdata += 0x100;
@@ -1069,8 +1169,60 @@ pkg2_hdr_t *pkg2_decrypt(void *data)
// Skip header.
pdata += sizeof(pkg2_hdr_t);
//! Check if we need to decrypt with newer mkeys. Valid for sept for 8.1.0 and up.
se_aes_crypt_ctr(8, &mkey_test, sizeof(pkg2_hdr_t), hdr, sizeof(pkg2_hdr_t), hdr);
if (mkey_test.magic == PKG2_MAGIC)
goto key_found;
// Decrypt older pkg2 via new mkeys.
if ((kb >= KB_FIRMWARE_VERSION_810) && (kb < KB_FIRMWARE_VERSION_MAX))
{
u8 tmp_mkey[0x10];
u8 decr_slot = 12; // Sept mkey.
u8 mkey_seeds_cnt = sizeof(mkey_keyseed_8xx) / 0x10;
u8 mkey_seeds_idx = mkey_seeds_cnt; // Real index + 1.
u8 mkey_seeds_min_idx = mkey_seeds_cnt - (KB_FIRMWARE_VERSION_MAX - kb);
while (mkey_seeds_cnt)
{
// Decrypt and validate mkey.
int res = _pkg2_key_unwrap_validate(&mkey_test, hdr, decr_slot,
tmp_mkey, mkey_keyseed_8xx[mkey_seeds_idx - 1]);
if (res)
{
keyslot = 9;
goto key_found;
}
else
{
// Set current mkey in order to decrypt a lower mkey.
mkey_seeds_idx--;
se_aes_key_clear(9);
se_aes_key_set(9, tmp_mkey, 0x10);
decr_slot = 9; // Temp key.
// Check if we tried last key for that pkg2 version.
// And start with a lower mkey in case sept is older.
if (mkey_seeds_idx == mkey_seeds_min_idx)
{
mkey_seeds_cnt--;
mkey_seeds_idx = mkey_seeds_cnt;
decr_slot = 12; // Sept mkey.
}
// Out of keys. pkg2 is latest or process failed.
if (!mkey_seeds_cnt)
se_aes_key_clear(9);
}
}
}
key_found:
// Decrypt header.
se_aes_crypt_ctr(8, hdr, sizeof(pkg2_hdr_t), hdr, sizeof(pkg2_hdr_t), hdr);
se_aes_crypt_ctr(keyslot, hdr, sizeof(pkg2_hdr_t), hdr, sizeof(pkg2_hdr_t), hdr);
//gfx_hexdump((u32)hdr, hdr, 0x100);
if (hdr->magic != PKG2_MAGIC)
@@ -1082,12 +1234,15 @@ DPRINTF("sec %d has size %08X\n", i, hdr->sec_size[i]);
if (!hdr->sec_size[i])
continue;
se_aes_crypt_ctr(8, pdata, hdr->sec_size[i], pdata, hdr->sec_size[i], &hdr->sec_ctr[i * 0x10]);
se_aes_crypt_ctr(keyslot, pdata, hdr->sec_size[i], pdata, hdr->sec_size[i], &hdr->sec_ctr[i * 0x10]);
//gfx_hexdump((u32)pdata, pdata, 0x100);
pdata += hdr->sec_size[i];
}
if (keyslot != 8)
se_aes_key_clear(9);
return hdr;
}
@@ -1149,7 +1304,7 @@ DPRINTF("kernel @ %08X (%08X)\n", (u32)kernel, kernel_size);
else
{
// Set new INI1 offset to kernel.
*(u32 *)(pdst + PKG2_NEWKERN_INI1_START) = kernel_size;
*(u32 *)(pdst + pkg2_newkern_ini1_val) = kernel_size;
kernel_size += _pkg2_ini1_build(pdst + kernel_size, hdr, kips_info, new_pkg2);
hdr->sec_off[PKG2_SEC_KERNEL] = 0x60000;
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (C) 2018-2019 CTCaer
* Copyright (c) 2018-2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -27,9 +27,12 @@
#define PKG2_SEC_INI1 1
#define INI1_MAGIC 0x31494E49
#define PKG2_NEWKERN_INI1_START 0x168
#define PKG2_NEWKERN_INI1_END 0x170
#define PKG2_NEWKERN_START 0x800
#define PKG2_NEWKERN_GET_INI1 0x44
#define PKG2_NEWKERN_START 0x800
u32 pkg2_newkern_ini1_val;
u32 pkg2_newkern_ini1_start;
u32 pkg2_newkern_ini1_end;
typedef struct _kernel_patch_t
{
@@ -51,10 +54,11 @@ enum
SVC_GENERIC = 0,
// Generic instruction patches.
SVC_VERIFY_DS = 0x10,
DEBUG_MODE_EN,
ATM_GEN_PATCH,
DEBUG_MODE_EN = 0x11,
ATM_GEN_PATCH = 0x12,
ATM_SYSM_INCR = ATM_GEN_PATCH,
// >4 bytes patches. Value is a pointer of a u32 array.
ATM_ARR_PATCH,
ATM_ARR_PATCH = 0x13,
};
typedef struct _pkg2_hdr_t
@@ -139,15 +143,16 @@ typedef struct _kip1_id_t
kip1_patchset_t* patchset;
} kip1_id_t;
void pkg2_get_newkern_info(u8 *kern_data);
void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2);
int pkg2_has_kip(link_t *info, u64 tid);
int pkg2_has_kip(link_t *info, u64 tid);
void pkg2_replace_kip(link_t *info, u64 tid, pkg2_kip1_t *kip1);
void pkg2_add_kip(link_t *info, pkg2_kip1_t *kip1);
void pkg2_merge_kip(link_t *info, pkg2_kip1_t *kip1);
const char* pkg2_patch_kips(link_t *info, char* patchNames);
const pkg2_kernel_id_t *pkg2_identify(u8 *hash);
pkg2_hdr_t *pkg2_decrypt(void *data);
pkg2_hdr_t *pkg2_decrypt(void *data, u8 kb);
void pkg2_build_encrypt(void *dst, void *kernel, u32 kernel_size, link_t *kips_info, bool new_pkg2);
#endif

View File

@@ -28,7 +28,7 @@ static u8 *_htoa(u8 *result, const char *ptr, u8 byte_len)
tmp = (ch - 'A' + 10);
else if (ch >= 'a' && ch <= 'f')
tmp = (ch - 'a' + 10);
if (shift)
*dst = (tmp << 4) & 0xF0;
else

View File

@@ -131,14 +131,17 @@ typedef struct _atm_fatal_error_ctx
// Exosphère mailbox defines.
#define EXO_CFG_ADDR 0x8000F000
#define EXO_MAGIC_VAL 0x304F5845
#define EXO_FLAG_DBG_PRIV (1 << 1)
#define EXO_FLAG_DBG_USER (1 << 2)
#define EXO_MAGIC_VAL 0x304F5845
#define EXO_FLAG_DBG_PRIV (1 << 1)
#define EXO_FLAG_DBG_USER (1 << 2)
#define EXO_FLAG_NO_USER_EXC (1 << 3)
#define EXO_FLAG_USER_PMU (1 << 4)
void config_exosphere(const char *id, u32 kb, void *warmboot, bool stock)
void config_exosphere(launch_ctxt_t *ctxt)
{
u32 exoFwNo = 0;
u32 exoFlags = 0;
u32 kb = ctxt->pkg1_id->kb;
memset((exo_cfg_t *)EXO_CFG_ADDR, 0, sizeof(exo_cfg_t));
@@ -147,7 +150,7 @@ void config_exosphere(const char *id, u32 kb, void *warmboot, bool stock)
switch (kb)
{
case KB_FIRMWARE_VERSION_100_200:
if (!strcmp(id, "20161121183008"))
if (!strcmp(ctxt->pkg1_id->id, "20161121183008"))
exoFwNo = 1;
else
exoFwNo = 2;
@@ -157,15 +160,23 @@ void config_exosphere(const char *id, u32 kb, void *warmboot, bool stock)
break;
default:
exoFwNo = kb + 1;
if (!strcmp(id, "20190314172056") || !strcmp(id, "20190531152432"))
exoFwNo++; // ATM_TARGET_FW_800/810.
if (!strcmp(ctxt->pkg1_id->id, "20190314172056") || (kb >= KB_FIRMWARE_VERSION_810))
exoFwNo++; // ATM_TARGET_FW_800/810/900.
break;
}
// To avoid problems, make private debug mode always on if not semi-stock.
if (!stock || (emu_cfg.enabled && !h_cfg.emummc_force_disable))
if (!ctxt->stock || (emu_cfg.enabled && !h_cfg.emummc_force_disable))
exoFlags |= EXO_FLAG_DBG_PRIV;
// Disable proper failure handling.
if (ctxt->exo_no_user_exceptions)
exoFlags |= EXO_FLAG_NO_USER_EXC;
// Enable user access to PMU.
if (ctxt->exo_user_pmu)
exoFlags |= EXO_FLAG_USER_PMU;
// Set mailbox values.
exo_cfg->magic = EXO_MAGIC_VAL;
@@ -174,7 +185,7 @@ void config_exosphere(const char *id, u32 kb, void *warmboot, bool stock)
exo_cfg->flags = exoFlags;
// If warmboot is lp0fw, add in RSA modulus.
volatile wb_cfg_t *wb_cfg = (wb_cfg_t *)(warmboot + ATM_WB_HEADER_OFF);
volatile wb_cfg_t *wb_cfg = (wb_cfg_t *)(ctxt->pkg1_id->warmboot_base + ATM_WB_HEADER_OFF);
if (wb_cfg->magic == ATM_WB_MAGIC)
{
@@ -197,7 +208,7 @@ void config_exosphere(const char *id, u32 kb, void *warmboot, bool stock)
else
rsa_mod[0x10] = 0x37;
memcpy(warmboot + 0x10, rsa_mod + 0x10, 0x100);
memcpy((void *)(ctxt->pkg1_id->warmboot_base + 0x10), rsa_mod + 0x10, 0x100);
}
if (emu_cfg.enabled && !h_cfg.emummc_force_disable)
@@ -212,9 +223,9 @@ void config_exosphere(const char *id, u32 kb, void *warmboot, bool stock)
else
strcpy((char *)exo_cfg->emummc_cfg.file_cfg.path, emu_cfg.path);
if (emu_cfg.nintendo_path && !stock)
if (emu_cfg.nintendo_path && !ctxt->stock)
strcpy((char *)exo_cfg->emummc_cfg.nintendo_path, emu_cfg.nintendo_path);
else if (stock)
else if (ctxt->stock)
strcpy((char *)exo_cfg->emummc_cfg.nintendo_path, "Nintendo");
else
exo_cfg->emummc_cfg.nintendo_path[0] = 0;
@@ -260,21 +271,18 @@ void secmon_exo_check_panic()
WPRINTFARGS("Title ID: %08X%08X", (u32)((u64)rpt->title_id >> 32), (u32)rpt->title_id);
WPRINTFARGS("Error Desc: %s (0x%x)\n", get_error_desc(rpt->error_desc), rpt->error_desc);
if (sd_mount())
{
// Save context to the SD card.
char filepath[0x40];
f_mkdir("atmosphere/fatal_errors");
memcpy(filepath, "/atmosphere/fatal_errors/report_", 33);
itoa((u32)((u64)rpt->report_identifier >> 32), filepath + strlen(filepath), 16);
itoa((u32)(rpt->report_identifier), filepath + strlen(filepath), 16);
memcpy(filepath + strlen(filepath), ".bin", 5);
// Save context to the SD card.
char filepath[0x40];
f_mkdir("atmosphere/fatal_errors");
strcpy(filepath, "/atmosphere/fatal_errors/report_");
itoa((u32)((u64)rpt->report_identifier >> 32), filepath + strlen(filepath), 16);
itoa((u32)(rpt->report_identifier), filepath + strlen(filepath), 16);
strcat(filepath, ".bin");
sd_save_to_file((void *)rpt, sizeof(atm_fatal_error_ctx), filepath);
sd_save_to_file((void *)rpt, sizeof(atm_fatal_error_ctx), filepath);
gfx_con.fntsz = 8;
WPRINTFARGS("Report saved to %s\n", filepath);
}
gfx_con.fntsz = 8;
WPRINTFARGS("Report saved to %s\n", filepath);
// Change magic to invalid, to prevent double-display of error/bootlooping.
rpt->magic = 0x0;

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2018-2019 CTCaer
* Copyright (c) 2018-2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -19,7 +19,7 @@
#include "../utils/types.h"
void config_exosphere(const char *id, u32 kb, void *warmboot, bool stock);
void config_exosphere(launch_ctxt_t *ctxt);
void secmon_exo_check_panic();
#endif

View File

@@ -17,6 +17,7 @@
#include <string.h>
#include "hos.h"
#include "fss.h"
#include "sept.h"
#include "../config/config.h"
#include "../gfx/di.h"
@@ -44,7 +45,7 @@ u8 warmboot_reboot[] = {
0x14, 0x00, 0x9F, 0xE5, // LDR R0, =0x7000E450
0x01, 0x10, 0xB0, 0xE3, // MOVS R1, #1
0x00, 0x10, 0x80, 0xE5, // STR R1, [R0]
0x0C, 0x00, 0x9F, 0xE5, // LDR R0, =0x7000E400
0x0C, 0x00, 0x9F, 0xE5, // LDR R0, =0x7000E400
0x10, 0x10, 0xB0, 0xE3, // MOVS R1, #0x10
0x00, 0x10, 0x80, 0xE5, // STR R1, [R0]
0xFE, 0xFF, 0xFF, 0xEA, // LOOP
@@ -73,7 +74,7 @@ extern void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size);
extern sdmmc_t sd_sdmmc;
extern sdmmc_storage_t sd_storage;
void check_sept()
void check_sept(ini_sec_t *cfg_sec)
{
// Check if non-hekate payload is used for sept and restore it.
if (h_cfg.sept_run)
@@ -83,7 +84,7 @@ void check_sept()
f_unlink("sept/payload.bin");
f_rename("sept/payload.bak", "sept/payload.bin");
}
return;
}
@@ -91,11 +92,17 @@ void check_sept()
sdmmc_storage_t storage;
sdmmc_t sdmmc;
if (!emummc_storage_init_mmc(&storage, &sdmmc))
int res = emummc_storage_init_mmc(&storage, &sdmmc);
if (res)
{
EPRINTF("Failed to init eMMC.");
if (res == 2)
EPRINTF("Failed to init eMMC");
else
EPRINTF("Failed to init emuMMC");
goto out_free;
}
emummc_storage_set_mmc_partition(&storage, 1);
// Read package1.
@@ -111,7 +118,7 @@ void check_sept()
if (pkg1_id->kb >= KB_FIRMWARE_VERSION_700 && !h_cfg.sept_run)
{
sdmmc_storage_end(&storage);
reboot_to_sept((u8 *)pkg1 + pkg1_id->tsec_off, pkg1_id->kb);
reboot_to_sept((u8 *)pkg1 + pkg1_id->tsec_off, pkg1_id->kb, cfg_sec);
}
out_free:
@@ -119,9 +126,10 @@ out_free:
sdmmc_storage_end(&storage);
}
int reboot_to_sept(const u8 *tsec_fw, u32 kb)
int reboot_to_sept(const u8 *tsec_fw, u32 kb, ini_sec_t *cfg_sec)
{
FIL fp;
bool fss0_sept_used = false;
// Copy warmboot reboot code and TSEC fw.
u32 tsec_fw_size = 0x3000;
@@ -130,37 +138,51 @@ int reboot_to_sept(const u8 *tsec_fw, u32 kb)
memcpy((u8 *)(SEPT_PK1T_ADDR - WB_RST_SIZE), (u8 *)warmboot_reboot, sizeof(warmboot_reboot));
memcpy((void *)SEPT_PK1T_ADDR, tsec_fw, tsec_fw_size);
*(vu32 *)SEPT_TCSZ_ADDR = tsec_fw_size;
// Copy sept-primary.
if (f_open(&fp, "sept/sept-primary.bin", FA_READ))
goto error;
if (f_read(&fp, (u8 *)SEPT_STG1_ADDR, f_size(&fp), NULL))
if (cfg_sec)
{
f_close(&fp);
goto error;
}
f_close(&fp);
fss0_sept_t sept_ctxt;
sept_ctxt.kb = kb;
sept_ctxt.cfg_sec = cfg_sec;
sept_ctxt.sept_primary = (void *)SEPT_STG1_ADDR;
sept_ctxt.sept_secondary = (void *)SEPT_STG2_ADDR;
// Copy sept-secondary.
if (kb < KB_FIRMWARE_VERSION_810)
{
if (f_open(&fp, "sept/sept-secondary_00.enc", FA_READ))
if (f_open(&fp, "sept/sept-secondary.enc", FA_READ)) // Try the deprecated version.
goto error;
fss0_sept_used = load_sept_from_ffs0(&sept_ctxt);
}
else
if (!fss0_sept_used)
{
if (f_open(&fp, "sept/sept-secondary_01.enc", FA_READ))
// Copy sept-primary.
if (f_open(&fp, "sept/sept-primary.bin", FA_READ))
goto error;
}
if (f_read(&fp, (u8 *)SEPT_STG2_ADDR, f_size(&fp), NULL))
{
if (f_read(&fp, (u8 *)SEPT_STG1_ADDR, f_size(&fp), NULL))
{
f_close(&fp);
goto error;
}
f_close(&fp);
// Copy sept-secondary.
if (kb < KB_FIRMWARE_VERSION_810)
{
if (f_open(&fp, "sept/sept-secondary_00.enc", FA_READ))
if (f_open(&fp, "sept/sept-secondary.enc", FA_READ)) // Try the deprecated version.
goto error;
}
else
{
if (f_open(&fp, "sept/sept-secondary_01.enc", FA_READ))
goto error;
}
if (f_read(&fp, (u8 *)SEPT_STG2_ADDR, f_size(&fp), NULL))
{
f_close(&fp);
goto error;
}
f_close(&fp);
goto error;
}
f_close(&fp);
b_cfg.boot_cfg |= (BOOT_CFG_AUTOBOOT_EN | BOOT_CFG_SEPT_RUN);
@@ -218,8 +240,8 @@ int reboot_to_sept(const u8 *tsec_fw, u32 kb)
(*sept)();
error:
gfx_con.mute = false;
EPRINTF("Failed to run sept\n");
display_backlight_brightness(h_cfg.backlight, 1000);
btn_wait();

View File

@@ -19,7 +19,7 @@
#include "../utils/types.h"
void check_sept();
int reboot_to_sept(const u8 *tsec_fw, u32 kb);
void check_sept(ini_sec_t *cfg_sec);
int reboot_to_sept(const u8 *tsec_fw, u32 kb, ini_sec_t *cfg_sec);
#endif

View File

@@ -65,41 +65,15 @@ static bool _ianos_read_cb(el_ctx *ctx, void *dest, size_t numberBytes, size_t o
return true;
}
void ianos_print_error(int errorno)
{
switch (errorno)
{
case 1:
gfx_printf("Can't find library!\n");
break;
case 2:
gfx_printf("Cant init ELF context!\n");
break;
case 3:
gfx_printf("Cant alloc memory!\n");
break;
case 4:
gfx_printf("Error loading ELF!\n");
break;
case 5:
gfx_printf("Error relocating ELF!\n");
break;
}
}
//TODO: Support shared libraries.
uintptr_t ianos_loader(bool sdmount, char *path, elfType_t type, void *moduleConfig)
{
uintptr_t epaddr = 0;
int res = 0;
if (sdmount)
{
if (!sd_mount())
{
res = 0xFFFF;
goto elfLoadFinalOut;
}
}
fileBuf = sd_file_read(path, NULL);
@@ -108,20 +82,14 @@ uintptr_t ianos_loader(bool sdmount, char *path, elfType_t type, void *moduleCon
sd_unmount();
if (!fileBuf)
{
res = 1;
goto elfLoadFinalOut;
}
el_ctx ctx;
ctx.pread = _ianos_read_cb;
if (el_init(&ctx))
{
res = 2;
goto elfLoadFinalOut;
}
// Set our relocated library's buffer.
switch (type & 0xFFFF)
@@ -132,28 +100,19 @@ uintptr_t ianos_loader(bool sdmount, char *path, elfType_t type, void *moduleCon
sd_unmount();
break;
default:
elfBuf = memalign(ctx.align, ctx.memsz);
elfBuf = malloc(ctx.memsz); // Aligned to 0x10 by default.
}
if (!elfBuf)
{
res = 3;
goto elfLoadFinalOut;
}
// Load and relocate library.
ctx.base_load_vaddr = ctx.base_load_paddr = (uintptr_t)elfBuf;
if (el_load(&ctx, _ianos_alloc_cb))
{
res = 4;
goto elfFreeOut;
}
if (el_relocate(&ctx))
{
res = 5;
goto elfFreeOut;
}
// Launch.
epaddr = ctx.ehdr.e_entry + (uintptr_t)elfBuf;
@@ -165,7 +124,6 @@ elfFreeOut:
free(fileBuf);
elfBuf = NULL;
fileBuf = NULL;
ianos_print_error(res);
elfLoadFinalOut:

View File

@@ -33,24 +33,24 @@ const blz_footer *blz_get_footer(const unsigned char *compData, unsigned int com
}
// From https://github.com/SciresM/hactool/blob/master/kip.c which is exactly how kernel does it, thanks SciresM!
int blz_uncompress_inplace(unsigned char *dataBuf, unsigned int compSize, const blz_footer *footer)
int blz_uncompress_inplace(unsigned char *dataBuf, unsigned int compSize, const blz_footer *footer)
{
u32 addl_size = footer->addl_size;
u32 header_size = footer->header_size;
u32 cmp_and_hdr_size = footer->cmp_and_hdr_size;
unsigned char* cmp_start = &dataBuf[compSize] - cmp_and_hdr_size;
u32 cmp_ofs = cmp_and_hdr_size - header_size;
u32 out_ofs = cmp_and_hdr_size + addl_size;
while (out_ofs)
while (out_ofs)
{
unsigned char control = cmp_start[--cmp_ofs];
for (unsigned int i=0; i<8; i++)
for (unsigned int i=0; i<8; i++)
{
if (control & 0x80)
if (control & 0x80)
{
if (cmp_ofs < 2)
if (cmp_ofs < 2)
return 0; // Out of bounds.
cmp_ofs -= 2;
@@ -65,17 +65,17 @@ int blz_uncompress_inplace(unsigned char *dataBuf, unsigned int compSize, const
for (unsigned int j = 0; j < seg_size; j++)
cmp_start[out_ofs + j] = cmp_start[out_ofs + j + seg_ofs];
}
else
else
{
// Copy directly.
if (cmp_ofs < 1)
if (cmp_ofs < 1)
return 0; //out of bounds
cmp_start[--out_ofs] = cmp_start[--cmp_ofs];
}
control <<= 1;
if (out_ofs == 0) // Blz works backwards, so if it reaches byte 0, it's done.
return 1;
return 1;
}
}

View File

@@ -14,7 +14,7 @@
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include <string.h>
#include "elfload.h"

View File

@@ -75,7 +75,7 @@ typedef struct el_ctx
// Section Header Str Table
Elf_Shdr shstr;
Elf_Shdr symtab;
/* Offset of dynamic table (0 if not ET_DYN) */
Elf_Off dynoff;
/* Size of dynamic table (0 if not ET_DYN) */

View File

@@ -8,12 +8,12 @@
/*-----------------------------------------------------------------------*/
#include <string.h>
#include "../../../common/memory_map.h"
#include "diskio.h" /* FatFs lower layer API */
#include "../../storage/sdmmc.h"
#define SDMMC_UPPER_BUFFER 0xB8000000
#define DRAM_START 0x80000000
extern sdmmc_storage_t sd_storage;
/*-----------------------------------------------------------------------*/
@@ -46,7 +46,8 @@ DRESULT disk_read (
UINT count /* Number of sectors to read */
)
{
if ((u32)buff >= DRAM_START)
// Ensure that buffer resides in DRAM and it's DMA aligned.
if (((u32)buff >= DRAM_START) && !((u32)buff % 8))
return sdmmc_storage_read(&sd_storage, sector, count, buff) ? RES_OK : RES_ERROR;
u8 *buf = (u8 *)SDMMC_UPPER_BUFFER;
if (sdmmc_storage_read(&sd_storage, sector, count, buf))
@@ -67,9 +68,10 @@ DRESULT disk_write (
UINT count /* Number of sectors to write */
)
{
if ((u32)buff >= DRAM_START)
// Ensure that buffer resides in DRAM and it's DMA aligned.
if (((u32)buff >= DRAM_START) && !((u32)buff % 8))
return sdmmc_storage_write(&sd_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR;
u8 *buf = (u8 *)SDMMC_UPPER_BUFFER; //TODO: define this somewhere.
u8 *buf = (u8 *)SDMMC_UPPER_BUFFER;
memcpy(buf, buff, 512 * count);
if (sdmmc_storage_write(&sd_storage, sector, count, buf))
return RES_OK;

View File

@@ -1,10 +1,25 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2019 CTCaer
*
* 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/>.
*/
/*----------------------------------------------------------------------------/
/ FatFs - Generic FAT Filesystem Module R0.13c (p3) /
/ FatFs - Generic FAT Filesystem Module R0.13c (p4) /
/-----------------------------------------------------------------------------/
/
/ Copyright (C) 2018, ChaN, all right reserved.
/ Copyright (c) 2018 naehrwert
/ Copyright (C) 2018-2019 CTCaer
/
/ FatFs module is an open source software. Redistribution and use of FatFs in
/ source and binary forms, with or without modification, are permitted provided
@@ -3472,7 +3487,7 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */
#if FF_USE_LFN == 1
fs->lfnbuf = LfnBuf; /* Static LFN working buffer */
#if FF_FS_EXFAT
fs->dirbuf = DirBuf; /* Static directory block scratchpad buuffer */
fs->dirbuf = DirBuf; /* Static directory block scratchpad buffer */
#endif
#endif
#if FF_FS_RPATH != 0
@@ -4243,9 +4258,9 @@ FRESULT f_getcwd (
TCHAR *tp = buff;
#if FF_VOLUMES >= 2
UINT vl;
#endif
#if FF_STR_VOLUME_ID
const char *vp;
#endif
#endif
FILINFO fno;
DEF_NAMBUF
@@ -6632,4 +6647,3 @@ FRESULT f_setcp (
return FR_OK;
}
#endif /* FF_CODE_PAGE == 0 */

View File

@@ -95,6 +95,7 @@ typedef DWORD FSIZE_t;
/* Filesystem object structure (FATFS) */
typedef struct {
BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */
BYTE fs_type; /* Filesystem type (0:not mounted) */
BYTE pdrv; /* Associated physical drive */
BYTE n_fats; /* Number of FATs (1 or 2) */
@@ -137,7 +138,6 @@ typedef struct {
DWORD bitbase; /* Allocation bitmap base sector */
#endif
DWORD winsect; /* Current sector appearing in the win[] */
BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */
} FATFS;
@@ -168,6 +168,9 @@ typedef struct {
/* File object structure (FIL) */
typedef struct {
#if !FF_FS_TINY
BYTE buf[FF_MAX_SS]; /* File private data read/write window */
#endif
FFOBJID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */
BYTE flag; /* File status flags */
BYTE err; /* Abort flag (error code) */
@@ -178,9 +181,6 @@ typedef struct {
DWORD dir_sect; /* Sector number containing the directory entry (not used at exFAT) */
BYTE* dir_ptr; /* Pointer to the directory entry in the win[] (not used at exFAT) */
#endif
#if !FF_FS_TINY
BYTE buf[FF_MAX_SS]; /* File private data read/write window */
#endif
#if FF_USE_FASTSEEK
DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */
#endif
@@ -279,7 +279,7 @@ FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get numbe
FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */
FRESULT f_setlabel (const TCHAR* label); /* Set volume label */
FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */
FRESULT f_expand (FIL* fp, FSIZE_t fsz, BYTE opt); /* Allocate a contiguous block to the file */
FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */
FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */
FRESULT f_fdisk (BYTE pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */

View File

@@ -34,7 +34,6 @@
#define MERGE2(a, b) a ## b
#define CVTBL(tbl, cp) MERGE2(tbl, cp)
/*------------------------------------------------------------------------*/
/* Code Conversion Tables */
/*------------------------------------------------------------------------*/
@@ -623,5 +622,4 @@ DWORD ff_wtoupper ( /* Returns up-converted code point */
return uni;
}
#endif /* #if FF_USE_LFN */

View File

@@ -19,6 +19,8 @@
#include <string.h>
#include <stdlib.h>
#include "../common/memory_map.h"
#include "config/config.h"
#include "gfx/di.h"
#include "gfx/gfx.h"
@@ -81,6 +83,7 @@ bool sd_mount()
if (!sdmmc_storage_init_sd(&sd_storage, &sd_sdmmc, SDMMC_1, SDMMC_BUS_WIDTH_4, 11))
{
gfx_con.mute = false;
EPRINTF("Failed to init SD card.\nMake sure that it is inserted.\nOr that SD reader is properly seated!");
}
else
@@ -94,6 +97,7 @@ bool sd_mount()
}
else
{
gfx_con.mute = false;
EPRINTFARGS("Failed to mount SD card (FatFS Error %d).\nMake sure that a FAT partition exists..", res);
}
}
@@ -248,19 +252,42 @@ void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size)
}
}
bool is_ipl_updated(void *buf)
bool is_ipl_updated(void *buf, char *path, bool force)
{
ipl_ver_meta_t *update_ft = (ipl_ver_meta_t *)(buf + PATCHED_RELOC_SZ + sizeof(boot_cfg_t));
ipl_ver_meta_t *update_ft = (ipl_ver_meta_t *)(buf + PATCHED_RELOC_SZ + sizeof(boot_cfg_t));
if (update_ft->magic == ipl_ver.magic)
bool magic_valid = update_ft->magic == ipl_ver.magic;
bool force_update = force && !magic_valid;
bool is_valid_old = magic_valid && (byte_swap_32(update_ft->version) < byte_swap_32(ipl_ver.version));
// Check if newer version.
if (!force && magic_valid)
if (byte_swap_32(update_ft->version) > byte_swap_32(ipl_ver.version))
return false;
// Update if old or broken.
if (force_update || is_valid_old)
{
if (byte_swap_32(update_ft->version) <= byte_swap_32(ipl_ver.version))
return true;
return false;
FIL fp;
volatile reloc_meta_t *reloc = (reloc_meta_t *)(IPL_LOAD_ADDR + RELOC_META_OFF);
boot_cfg_t *tmp_cfg = malloc(sizeof(boot_cfg_t));
memset(tmp_cfg, 0, sizeof(boot_cfg_t));
f_open(&fp, path, FA_WRITE | FA_CREATE_ALWAYS);
f_write(&fp, (u8 *)reloc->start, reloc->end - reloc->start, NULL);
// Write needed tag in case injected ipl uses old versioning.
f_write(&fp, "ICTC49", 6, NULL);
// Reset boot storage configuration.
f_lseek(&fp, PATCHED_RELOC_SZ);
f_write(&fp, tmp_cfg, sizeof(boot_cfg_t), NULL);
f_close(&fp);
free(tmp_cfg);
}
else
return true;
return true;
}
int launch_payload(char *path, bool update)
@@ -268,8 +295,6 @@ int launch_payload(char *path, bool update)
if (!update)
gfx_clear_grey(0x1B);
gfx_con_setpos(0, 0);
if (!path)
return 1;
if (sd_mount())
{
@@ -277,9 +302,8 @@ int launch_payload(char *path, bool update)
if (f_open(&fp, path, FA_READ))
{
EPRINTFARGS("Payload file is missing!\n(%s)", path);
sd_unmount();
return 1;
goto out;
}
// Read and copy the payload to our chosen address
@@ -294,16 +318,14 @@ int launch_payload(char *path, bool update)
if (f_read(&fp, buf, size, NULL))
{
f_close(&fp);
sd_unmount();
return 1;
goto out;
}
f_close(&fp);
free(path);
if (update && is_ipl_updated(buf))
return 1;
if (update && is_ipl_updated(buf, path, false))
goto out;
sd_unmount();
@@ -322,11 +344,12 @@ int launch_payload(char *path, bool update)
reconfig_hw_workaround(true, 0);
}
// Some cards (Sandisk U1), do not like a fast power cycle. Wait min 100ms.
sdmmc_storage_init_wait_sd();
void (*ext_payload_ptr)() = (void *)EXT_PAYLOAD_ADDR;
void (*update_ptr)() = (void *)RCM_PAYLOAD_ADDR;
msleep(100);
// Launch our payload.
if (!update)
(*ext_payload_ptr)();
@@ -337,6 +360,10 @@ int launch_payload(char *path, bool update)
}
}
out:
if (!update)
sd_unmount();
return 1;
}
@@ -391,12 +418,12 @@ void launch_tools()
i++;
}
}
if (i > 0)
{
memset(&ments[i + 2], 0, sizeof(ment_t));
menu_t menu = { ments, "Choose a file to launch", 0, 0 };
file_sec = (char *)tui_do_menu(&menu);
if (!file_sec)
@@ -405,6 +432,7 @@ void launch_tools()
free(dir);
free(filelist);
sd_unmount();
return;
}
}
@@ -419,18 +447,14 @@ void launch_tools()
free(ments);
goto out;
}
if (file_sec)
{
memcpy(dir + strlen(dir), "/", 2);
memcpy(dir + strlen(dir), file_sec, strlen(file_sec) + 1);
if (launch_payload(dir, false))
{
EPRINTF("Failed to launch payload.");
free(dir);
}
launch_payload(dir, false);
EPRINTF("Failed to launch payload.");
}
out:
@@ -508,7 +532,7 @@ void ini_list_launcher()
payload_path = ini_check_payload_section(cfg_sec);
if (cfg_sec && !payload_path)
check_sept();
check_sept(cfg_sec);
if (!cfg_sec)
{
@@ -530,11 +554,9 @@ void ini_list_launcher()
if (payload_path)
{
if (launch_payload(payload_path, false))
{
EPRINTF("Failed to launch payload.");
free(payload_path);
}
launch_payload(payload_path, false);
EPRINTF("Failed to launch payload.");
free(payload_path);
}
else if (!hos_launch(cfg_sec))
{
@@ -637,7 +659,7 @@ void launch_firmware()
}
if (cfg_sec && !payload_path)
check_sept();
check_sept(cfg_sec);
if (!cfg_sec)
{
@@ -664,11 +686,9 @@ void launch_firmware()
if (payload_path)
{
if (launch_payload(payload_path, false))
{
EPRINTF("Failed to launch payload.");
free(payload_path);
}
launch_payload(payload_path, false);
EPRINTF("Failed to launch payload.");
free(payload_path);
}
else if (!hos_launch(cfg_sec))
EPRINTF("Failed to launch firmware.");
@@ -681,16 +701,21 @@ out:
btn_wait();
}
#define NYX_VER_OFF 0x9C
void nyx_load_run()
{
sd_mount();
u8 *nyx = sd_file_read("bootloader/sys/nyx.bin", false);
u8 *nyx = sd_file_read("bootloader/sys/nyx.bin", NULL);
if (!nyx)
return;
sd_unmount();
u32 expected_nyx_ver = ((NYX_VER_MJ + '0') << 24) | ((NYX_VER_MN + '0') << 16) | ((NYX_VER_HF + '0') << 8);
u32 nyx_ver = byte_swap_32(*(u32 *)(nyx + NYX_VER_OFF));
gfx_clear_grey(0x1B);
u8 *BOOTLOGO = (void *)malloc(0x4000);
blz_uncompress_srcdest(BOOTLOGO_BLZ, SZ_BOOTLOGO_BLZ, BOOTLOGO, SZ_BOOTLOGO);
@@ -698,16 +723,29 @@ void nyx_load_run()
free(BOOTLOGO);
display_backlight_brightness(h_cfg.backlight, 1000);
// Check if Nyx version is old.
if (nyx_ver < expected_nyx_ver)
{
h_cfg.errors |= ERR_SYSOLD_NYX;
gfx_con_setpos(0, 0);
WPRINTF("Old Nyx GUI found! There will be dragons!\n");
WPRINTF("\nUpdate your bootloader folder!\n\n");
WPRINTF("Press any key...");
msleep(2000);
btn_wait();
}
nyx_str->info.errors = h_cfg.errors;
nyx_str->cfg = 0;
if (b_cfg.extra_cfg & EXTRA_CFG_NYX_DUMP)
{
b_cfg.extra_cfg &= ~(EXTRA_CFG_NYX_DUMP);
nyx_str->cfg |= NYX_CFG_DUMP;
}
if (nyx_str->mtc_cfg.mtc_table)
nyx_str->cfg |= NYX_CFG_MINERVA;
nyx_str->version = ipl_ver.version - 0x303030;
nyx_str->version = ipl_ver.version - 0x303030; // Convert ASCII to numbers.
//memcpy((u8 *)nyx_str->irama, (void *)IRAM_BASE, 0x8000);
volatile reloc_meta_t *reloc = (reloc_meta_t *)(IPL_LOAD_ADDR + RELOC_META_OFF);
@@ -720,20 +758,45 @@ void nyx_load_run()
minerva_periodic_training();
// Some cards (Sandisk U1), do not like a fast power cycle. Wait min 100ms.
u32 sd_poweroff_time = (u32)get_tmr_ms() - h_cfg.sd_timeoff;
if (sd_poweroff_time < 100)
msleep(100 - sd_poweroff_time);
sdmmc_storage_init_wait_sd();
(*nyx_ptr)();
}
void auto_launch_firmware()
static ini_sec_t *get_ini_sec_from_id(ini_sec_t *ini_sec, char **bootlogoCustomEntry)
{
ini_sec_t *cfg_sec = NULL;
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)
{
if (!strcmp("id", kv->key))
{
if (b_cfg.id[0] && kv->val[0] && !strcmp(b_cfg.id, kv->val))
cfg_sec = ini_sec;
else
break;
}
if (!strcmp("logopath", kv->key))
*bootlogoCustomEntry = kv->val;
if (!strcmp("emummc_force_disable", kv->key))
h_cfg.emummc_force_disable = atoi(kv->val);
}
if (!cfg_sec)
{
*bootlogoCustomEntry = NULL;
h_cfg.emummc_force_disable = false;
}
return cfg_sec;
}
static void _auto_launch_firmware()
{
if(b_cfg.extra_cfg & EXTRA_CFG_NYX_DUMP)
{
if (!h_cfg.sept_run)
EMC(EMC_SCRATCH0) |= EMC_HEKA_UPD;
check_sept();
check_sept(NULL);
}
if (!h_cfg.sept_run)
@@ -742,6 +805,9 @@ void auto_launch_firmware()
u8 *BOOTLOGO = NULL;
char *payload_path = NULL;
u32 btn = 0;
bool boot_from_id = (b_cfg.boot_cfg & BOOT_CFG_FROM_ID) && (b_cfg.boot_cfg & BOOT_CFG_AUTOBOOT_EN);
if (boot_from_id)
b_cfg.id[7] = 0;
struct _bmp_data
{
@@ -799,6 +865,8 @@ void auto_launch_firmware()
h_cfg.autohosoff = atoi(kv->val);
else if (!strcmp("autonogc", kv->key))
h_cfg.autonogc = atoi(kv->val);
else if (!strcmp("updater2p", kv->key))
h_cfg.updater2p = atoi(kv->val);
else if (!strcmp("brand", kv->key))
{
h_cfg.brand = malloc(strlen(kv->val) + 1);
@@ -827,7 +895,9 @@ void auto_launch_firmware()
continue;
}
if (h_cfg.autoboot == boot_entry_id && configEntry)
if (boot_from_id)
cfg_sec = get_ini_sec_from_id(ini_sec, &bootlogoCustomEntry);
else if (h_cfg.autoboot == boot_entry_id && configEntry)
{
cfg_sec = ini_sec;
LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg_sec->kvs, link)
@@ -837,8 +907,9 @@ void auto_launch_firmware()
if (!strcmp("emummc_force_disable", kv->key))
h_cfg.emummc_force_disable = atoi(kv->val);
}
break;
}
if (cfg_sec)
break;
boot_entry_id++;
}
}
@@ -846,8 +917,12 @@ void auto_launch_firmware()
if (h_cfg.autohosoff && !(b_cfg.boot_cfg & BOOT_CFG_AUTOBOOT_EN))
check_power_off_from_hos();
if (h_cfg.autoboot_list)
if (h_cfg.autoboot_list || (boot_from_id && !cfg_sec))
{
if (boot_from_id && cfg_sec)
goto skip_list;
cfg_sec = NULL;
boot_entry_id = 1;
bootlogoCustomEntry = NULL;
@@ -860,7 +935,9 @@ void auto_launch_firmware()
if (!strcmp(ini_sec_list->name, "config"))
continue;
if (h_cfg.autoboot == boot_entry_id)
if (boot_from_id)
cfg_sec = get_ini_sec_from_id(ini_sec_list, &bootlogoCustomEntry);
else if (h_cfg.autoboot == boot_entry_id)
{
h_cfg.emummc_force_disable = false;
cfg_sec = ini_sec_list;
@@ -871,26 +948,23 @@ void auto_launch_firmware()
if (!strcmp("emummc_force_disable", kv->key))
h_cfg.emummc_force_disable = atoi(kv->val);
}
break;
}
if (cfg_sec)
break;
boot_entry_id++;
}
}
}
}
skip_list:
// Add missing configuration entry.
if (!configEntry)
create_config_entry();
if (!h_cfg.autoboot)
goto out; // Auto boot is disabled.
if (!cfg_sec)
goto out; // No configurations.
goto out; // No configurations or auto boot is disabled.
}
else
goto out; // Can't load hekate_ipl.ini.
@@ -969,7 +1043,7 @@ void auto_launch_firmware()
// Wait before booting. If VOL- is pressed go into bootloader menu.
if (!h_cfg.sept_run && !(b_cfg.boot_cfg & BOOT_CFG_FROM_LAUNCH))
{
btn = btn_wait_timeout(h_cfg.bootwait * 1000, BTN_VOL_DOWN);
btn = btn_wait_timeout(h_cfg.bootwait * 1000, BTN_VOL_DOWN | BTN_SINGLE);
if (btn & BTN_VOL_DOWN)
goto out;
@@ -979,19 +1053,27 @@ void auto_launch_firmware()
if (payload_path)
{
if (launch_payload(payload_path, false))
free(payload_path);
launch_payload(payload_path, false);
free(payload_path);
}
else
{
check_sept();
check_sept(cfg_sec);
hos_launch(cfg_sec);
EPRINTF("\nFailed to launch HOS!");
gfx_printf("\nPress any key...\n");
msleep(500);
btn_wait();
}
out:
gfx_con.mute = false;
b_cfg.boot_cfg &= ~(BOOT_CFG_AUTOBOOT_EN | BOOT_CFG_FROM_LAUNCH);
// Clear boot reasons from binary.
if (b_cfg.boot_cfg & BOOT_CFG_FROM_ID)
memset(b_cfg.xt_str, 0, sizeof(b_cfg.xt_str));
b_cfg.boot_cfg &= ~(BOOT_CFG_AUTOBOOT_EN | BOOT_CFG_FROM_LAUNCH | BOOT_CFG_FROM_ID);
h_cfg.emummc_force_disable = false;
nyx_load_run();
@@ -999,7 +1081,7 @@ out:
sd_unmount();
}
void patched_rcm_protection()
static void _patched_rcm_protection()
{
sdmmc_storage_t storage;
sdmmc_t sdmmc;
@@ -1041,7 +1123,28 @@ void patched_rcm_protection()
sdmmc_storage_end(&storage);
}
void about()
static void _show_errors()
{
if (h_cfg.errors)
{
gfx_clear_grey(0x1B);
gfx_con_setpos(0, 0);
display_backlight_brightness(h_cfg.backlight, 1000);
if (h_cfg.errors & ERR_LIBSYS_LP0)
WPRINTF("Missing LP0 (sleep mode) library!\n");
if (h_cfg.errors & ERR_SYSOLD_MTC)
WPRINTF("Missing or old Minerva library!\n");
WPRINTF("\nUpdate your bootloader folder!\n\n");
WPRINTF("Press any key...");
msleep(2000);
btn_wait();
}
}
static void _about()
{
static const char credits[] =
"\nhekate (c) 2018 naehrwert, st4rk\n\n"
@@ -1058,8 +1161,8 @@ void about()
" Copyright (c) 2018, ChaN\n\n"
" - bcl-1.2.0,\n"
" Copyright (c) 2003-2006, Marcus Geelnard\n\n"
" - Atmosphere (SE sha256, prc id patches),\n"
" Copyright (c) 2018, Atmosphere-NX\n\n"
" - Atmosphere (Exo st/types, prc id patches),\n"
" Copyright (c) 2018-2019, Atmosphere-NX\n\n"
" - elfload,\n"
" Copyright (c) 2014, Owen Shepherd\n"
" Copyright (c) 2018, M4xw\n"
@@ -1166,8 +1269,8 @@ ment_t ment_tools[] = {
MDEF_CHGLINE(),
MDEF_CAPTION("-------- Misc --------", 0xFF0AB9E6),
MDEF_HANDLER("Dump package1/2", dump_packages12),
MDEF_HANDLER("Fix archive bit (except Nintendo)", fix_sd_all_attr),
MDEF_HANDLER("Fix archive bit (Nintendo only)", fix_sd_nin_attr),
//MDEF_HANDLER("Fix archive bit (except Nintendo)", fix_sd_all_attr),
//MDEF_HANDLER("Fix archive bit (Nintendo only)", fix_sd_nin_attr),
//MDEF_HANDLER("Fix fuel gauge configuration", fix_fuel_gauge_configuration),
//MDEF_HANDLER("Reset all battery cfg", reset_pmic_fuel_gauge_charger_config),
MDEF_CHGLINE(),
@@ -1189,15 +1292,11 @@ ment_t ment_top[] = {
MDEF_HANDLER("Reboot (RCM)", reboot_rcm),
MDEF_HANDLER("Power off", power_off),
MDEF_CAPTION("---------------", 0xFF444444),
MDEF_HANDLER("About", about),
MDEF_HANDLER("About", _about),
MDEF_END()
};
menu_t menu_top = { ment_top, "hekate - CTCaer mod v5.0.1", 0, 0 };
#define IPL_STACK_TOP 0x90010000
#define IPL_HEAP_START 0x90020000
#define IPL_HEAP_END 0xB5000000
menu_t menu_top = { ment_top, "hekate - CTCaer mod v5.1.2", 0, 0 };
extern void pivot_stack(u32 stack_top);
@@ -1206,10 +1305,10 @@ void ipl_main()
// Do initial HW configuration. This is compatible with consecutive reruns without a reset.
config_hw();
//Pivot the stack so we have enough space.
// Pivot the stack so we have enough space.
pivot_stack(IPL_STACK_TOP);
//Tegra/Horizon configuration goes to 0x80000000+, package2 goes to 0xA9800000, we place our heap in between.
// Tegra/Horizon configuration goes to 0x80000000+, package2 goes to 0xA9800000, we place our heap in between.
heap_init(IPL_HEAP_START);
#ifdef DEBUG_UART_PORT
@@ -1225,9 +1324,10 @@ void ipl_main()
// Save sdram lp0 config.
if (!ianos_loader(false, "bootloader/sys/libsys_lp0.bso", DRAM_LIB, (void *)sdram_get_params_patched()))
h_cfg.errors |= ERR_LIBSYS_LP0;
minerva_init();
minerva_change_freq(FREQ_1600);
// Train DRAM and switch to max frequency.
if (minerva_init())
h_cfg.errors |= ERR_SYSOLD_MTC;
display_init();
@@ -1245,25 +1345,29 @@ void ipl_main()
//display_backlight_brightness(h_cfg.backlight, 1000);
// Overclock BPMP.
bpmp_clk_rate_set(BPMP_CLK_SUPER_BOOST);
bpmp_clk_rate_set(BPMP_CLK_DEFAULT_BOOST);
// Check if we had a panic while in CFW.
secmon_exo_check_panic();
// Check if RCM is patched and protect from a possible brick.
patched_rcm_protection();
_patched_rcm_protection();
// Load emuMMC configuration from SD.
emummc_load_cfg();
// Show library errors.
_show_errors();
// Load saved configuration and auto boot if enabled.
auto_launch_firmware();
_auto_launch_firmware();
minerva_change_freq(FREQ_800);
while (true)
tui_do_menu(&menu_top);
// Halt BPMP if we managed to get out of execution.
while (true)
;
bpmp_halt();
}

File diff suppressed because it is too large Load Diff

View File

@@ -17,6 +17,7 @@
#include <string.h>
#include "heap.h"
#include "../gfx/gfx.h"
#include "../../common/common_heap.h"
static void _heap_create(heap_t *heap, u32 start)
@@ -25,12 +26,13 @@ static void _heap_create(heap_t *heap, u32 start)
heap->first = NULL;
}
static u32 _heap_alloc(heap_t *heap, u32 size, u32 alignment)
// Node info is before node address.
static u32 _heap_alloc(heap_t *heap, u32 size)
{
hnode_t *node, *new;
int search = 1;
hnode_t *node, *new_node;
size = ALIGN(size, alignment);
// Align to cache line size.
size = ALIGN(size, sizeof(hnode_t));
if (!heap->first)
{
@@ -45,36 +47,55 @@ static u32 _heap_alloc(heap_t *heap, u32 size, u32 alignment)
}
node = heap->first;
while (search)
while (true)
{
if (!node->used && size + sizeof(hnode_t) < node->size)
// Check if there's available unused node.
if (!node->used && (size <= node->size))
{
new = (hnode_t *)((u32)node + sizeof(hnode_t) + size);
// Size and offset of the new unused node.
u32 new_size = node->size - size;
new_node = (hnode_t *)((u32)node + sizeof(hnode_t) + size);
// If there's aligned unused space from the old node,
// create a new one and set the leftover size.
if (new_size >= (sizeof(hnode_t) << 2))
{
new_node->size = new_size - sizeof(hnode_t);
new_node->used = 0;
new_node->next = node->next;
// Check that we are not on first node.
if (new_node->next)
new_node->next->prev = new_node;
new_node->prev = node;
node->next = new_node;
}
else // Unused node size is just enough.
size += new_size;
new->size = node->size - sizeof(hnode_t) - size;
node->size = size;
node->used = 1;
new->used = 0;
new->next = node->next;
new->prev = node;
node->next = new;
return (u32)node + sizeof(hnode_t);
}
// No unused node found, try the next one.
if (node->next)
node = node->next;
else
search = 0;
break;
}
new = (hnode_t *)((u32)node + sizeof(hnode_t) + node->size);
new->used = 1;
new->size = size;
new->prev = node;
new->next = NULL;
node->next = new;
// No unused node found, create a new one.
new_node = (hnode_t *)((u32)node + sizeof(hnode_t) + node->size);
new_node->used = 1;
new_node->size = size;
new_node->prev = node;
new_node->next = NULL;
node->next = new_node;
return (u32)new + sizeof(hnode_t);
return (u32)new_node + sizeof(hnode_t);
}
static void _heap_free(heap_t *heap, u32 addr)
@@ -90,6 +111,7 @@ static void _heap_free(heap_t *heap, u32 addr)
{
node->prev->size += node->size + sizeof(hnode_t);
node->prev->next = node->next;
if (node->next)
node->next->prev = node->prev;
}
@@ -107,17 +129,12 @@ void heap_init(u32 base)
void *malloc(u32 size)
{
return (void *)_heap_alloc(&_heap, size, 0x10);
}
void *memalign(u32 align, u32 size)
{
return (void *)_heap_alloc(&_heap, size, align);
return (void *)_heap_alloc(&_heap, size);
}
void *calloc(u32 num, u32 size)
{
void *res = (void *)_heap_alloc(&_heap, num * size, 0x10);
void *res = (void *)_heap_alloc(&_heap, num * size);
memset(res, 0, num * size);
return res;
}
@@ -127,3 +144,30 @@ void free(void *buf)
if ((u32)buf >= _heap.start)
_heap_free(&_heap, (u32)buf);
}
void heap_monitor(heap_monitor_t *mon, bool print_node_stats)
{
u32 count = 0;
memset(mon, 0, sizeof(heap_monitor_t));
hnode_t *node = _heap.first;
while (true)
{
if (node->used)
mon->used += node->size + sizeof(hnode_t);
else
mon->total += node->size + sizeof(hnode_t);
if (print_node_stats)
gfx_printf("%3d - %d, addr: 0x%08X, size: 0x%X\n",
count, node->used, (u32)node + sizeof(hnode_t), node->size);
count++;
if (node->next)
node = node->next;
else
break;
}
mon->total += mon->used;
}

View File

@@ -18,11 +18,12 @@
#define _HEAP_H_
#include "../utils/types.h"
#include "../../common/common_heap.h"
void heap_init(u32 base);
void *malloc(u32 size);
void *calloc(u32 num, u32 size);
void free(void *buf);
void *memalign(u32 align, u32 size);
void heap_monitor(heap_monitor_t *mon, bool print_node_stats);
#endif

View File

@@ -127,7 +127,7 @@ void mc_disable_ahb_redirect()
void mc_enable()
{
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) & 0x1FFFFFFF) | 0x40000000;
// Enable MIPI CAL clock.
// Enable EMC clock.
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = (CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) & 0xFDFFFFFF) | 0x2000000;
// Enable MC clock.
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = (CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) & 0xFFFFFFFE) | 1;

View File

@@ -28,20 +28,27 @@
extern volatile nyx_storage_t *nyx_str;
void minerva_init()
u32 minerva_init()
{
u32 curr_ram_idx = 0;
minerva_cfg = NULL;
mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg;
// Set table to ram.
mtc_cfg->mtc_table = NULL;
// Set table to nyx storage.
mtc_cfg->mtc_table = (emc_table_t *)&nyx_str->mtc_table;
mtc_cfg->sdram_id = (fuse_read_odm(4) >> 3) & 0x1F;
mtc_cfg->init_done = MTC_NEW_MAGIC; // Initialize mtc table.
u32 ep_addr = ianos_loader(false, "bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)mtc_cfg);
minerva_cfg = (void *)ep_addr;
// Ensure that Minerva is new.
if (mtc_cfg->init_done == MTC_INIT_MAGIC)
minerva_cfg = (void *)ep_addr;
if (!minerva_cfg)
return;
return 1;
// Get current frequency
for (curr_ram_idx = 0; curr_ram_idx < 10; curr_ram_idx++)
@@ -58,14 +65,26 @@ void minerva_init()
minerva_cfg(mtc_cfg, NULL);
mtc_cfg->rate_to = 1600000;
minerva_cfg(mtc_cfg, NULL);
// FSP WAR.
mtc_cfg->train_mode = OP_SWITCH;
mtc_cfg->rate_to = 800000;
minerva_cfg(mtc_cfg, NULL);
// Switch to max.
mtc_cfg->rate_to = 1600000;
minerva_cfg(mtc_cfg, NULL);
return 0;
}
void minerva_change_freq(minerva_freq_t freq)
{
if (!minerva_cfg)
return;
mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg;
if (minerva_cfg && (mtc_cfg->rate_from != freq))
if (mtc_cfg->rate_from != freq)
{
mtc_cfg->rate_to = freq;
mtc_cfg->train_mode = OP_SWITCH;
@@ -77,8 +96,9 @@ void minerva_periodic_training()
{
if (!minerva_cfg)
return;
mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg;
if (minerva_cfg && mtc_cfg->rate_from == FREQ_1600)
if (mtc_cfg->rate_from == FREQ_1600)
{
mtc_cfg->train_mode = OP_PERIODIC_TRAIN;
minerva_cfg(mtc_cfg, NULL);

View File

@@ -20,7 +20,10 @@
#include "mtc_table.h"
#include "../utils/types.h"
#define EMC_PERIODIC_TRAIN_MS 100
#define MTC_INIT_MAGIC 0x3043544D
#define MTC_NEW_MAGIC 0x5243544D
#define EMC_PERIODIC_TRAIN_MS 250
typedef struct
{
@@ -35,6 +38,7 @@ typedef struct
bool emc_2X_clk_src_is_pllmb;
bool fsp_for_src_freq;
bool train_ram_patterns;
bool init_done;
} mtc_config_t;
enum train_mode_t
@@ -54,7 +58,7 @@ typedef enum
} minerva_freq_t;
void (*minerva_cfg)(mtc_config_t *mtc_cfg, void *);
void minerva_init();
u32 minerva_init();
void minerva_change_freq(minerva_freq_t freq);
void minerva_periodic_training();

View File

@@ -22,7 +22,7 @@
#include "../utils/types.h"
typedef struct
typedef struct
{
s32 pll_osc_in;
s32 pll_out;
@@ -257,7 +257,7 @@ typedef struct
} burst_regs_t;
typedef struct
typedef struct
{
u32 burst_regs[221];
u32 burst_reg_per_ch[8];
@@ -266,7 +266,7 @@ typedef struct
u32 shadow_regs_rdwr_train[221];
} burst_regs_table_t;
typedef struct
typedef struct
{
u32 ptfv_dqsosc_movavg_c0d0u0_idx;
u32 ptfv_dqsosc_movavg_c0d0u1_idx;

View File

@@ -16,17 +16,18 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "../soc/i2c.h"
#include "../soc/t210.h"
#include "mc.h"
#include "emc.h"
#include "sdram_param_t210.h"
#include "../soc/pmc.h"
#include "../utils/util.h"
#include "../soc/fuse.h"
#include "../../common/memory_map.h"
#include "../power/max77620.h"
#include "../power/max7762x.h"
#include "../soc/clock.h"
#include "../soc/fuse.h"
#include "../soc/i2c.h"
#include "../soc/pmc.h"
#include "../soc/t210.h"
#include "../utils/util.h"
#define CONFIG_SDRAM_COMPRESS_CFG
@@ -39,24 +40,42 @@
static u32 _get_sdram_id()
{
return (fuse_read_odm(4) & 0x38) >> 3;
u32 sdram_id = (fuse_read_odm(4) & 0x38) >> 3;
// Check if id is proper.
if (sdram_id > 7)
sdram_id = 0;
return sdram_id;
}
static void _sdram_config(const sdram_params_t *params)
{
PMC(APBDEV_PMC_IO_DPD3_REQ) = (((4 * params->emc_pmc_scratch1 >> 2) + 0x80000000) ^ 0xFFFF) & 0xC000FFFF;
// Program DPD3/DPD4 regs (coldboot path).
// Enable sel_dpd on unused pins.
u32 dpd_req = (params->emc_pmc_scratch1 & 0x3FFFFFFF) | 0x80000000;
PMC(APBDEV_PMC_IO_DPD3_REQ) = (dpd_req ^ 0xFFFF) & 0xC000FFFF;
usleep(params->pmc_io_dpd3_req_wait);
u32 req = (4 * params->emc_pmc_scratch2 >> 2) + 0x80000000;
PMC(APBDEV_PMC_IO_DPD4_REQ) = (req >> 16 << 16) ^ 0x3FFF0000;
// Disable e_dpd_vttgen.
dpd_req = (params->emc_pmc_scratch2 & 0x3FFFFFFF) | 0x80000000;
PMC(APBDEV_PMC_IO_DPD4_REQ) = (dpd_req & 0xFFFF0000) ^ 0x3FFF0000;
usleep(params->pmc_io_dpd4_req_wait);
PMC(APBDEV_PMC_IO_DPD4_REQ) = (req ^ 0xFFFF) & 0xC000FFFF;
// Disable e_dpd_bg.
PMC(APBDEV_PMC_IO_DPD4_REQ) = (dpd_req ^ 0xFFFF) & 0xC000FFFF;
usleep(params->pmc_io_dpd4_req_wait);
PMC(APBDEV_PMC_WEAK_BIAS) = 0;
usleep(1);
// Start clocks.
CLOCK(CLK_RST_CONTROLLER_PLLM_MISC1) = params->pllm_setup_control;
CLOCK(CLK_RST_CONTROLLER_PLLM_MISC2) = 0;
// u32 tmp = (params->pllm_feedback_divider << 8) | params->pllm_input_divider | ((params->pllm_post_divider & 0xFFFF) << 20);
// CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = tmp;
// CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = tmp | 0x40000000;
CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = (params->pllm_feedback_divider << 8) | params->pllm_input_divider | 0x40000000 | ((params->pllm_post_divider & 0xFFFF) << 20);
u32 wait_end = get_tmr_us() + 300;
@@ -66,24 +85,35 @@ static void _sdram_config(const sdram_params_t *params)
goto break_nosleep;
}
usleep(10);
break_nosleep:
break_nosleep:
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = ((params->mc_emem_arb_misc0 >> 11) & 0x10000) | (params->emc_clock_source & 0xFFFEFFFF);
if (params->emc_clock_source_dll)
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL) = params->emc_clock_source_dll;
if (params->clear_clock2_mc1)
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_CLR) = 0x40000000;
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = 0x2000001;
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = 0x4000;
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = 0x2000001;
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = 0x2000001; // Enable EMC and MEM clocks.
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = 0x4000; // Enable EMC_DLL clock.
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = 0x2000001; // Clear EMC and MEM resets.
// Set pad macros.
EMC(EMC_PMACRO_VTTGEN_CTRL_0) = params->emc_pmacro_vttgen_ctrl0;
EMC(EMC_PMACRO_VTTGEN_CTRL_1) = params->emc_pmacro_vttgen_ctrl1;
EMC(EMC_PMACRO_VTTGEN_CTRL_2) = params->emc_pmacro_vttgen_ctrl2;
EMC(EMC_TIMING_CONTROL) = 1;
usleep(1);
EMC(EMC_TIMING_CONTROL) = 1; // Trigger timing update so above writes take place.
usleep(10); // Ensure the regulators settle.
// Select EMC write mux.
EMC(EMC_DBG) = (params->emc_dbg_write_mux << 1) | params->emc_dbg;
// Patch 2 using BCT spare variables.
if (params->emc_bct_spare2)
*(vu32 *)params->emc_bct_spare2 = params->emc_bct_spare3;
// Program CMD mapping. Required before brick mapping, else
// we can't guarantee CK will be differential at all times.
EMC(EMC_FBIO_CFG7) = params->emc_fbio_cfg7;
EMC(EMC_CMD_MAPPING_CMD0_0) = params->emc_cmd_mapping_cmd0_0;
EMC(EMC_CMD_MAPPING_CMD0_1) = params->emc_cmd_mapping_cmd0_1;
@@ -98,25 +128,40 @@ break_nosleep:
EMC(EMC_CMD_MAPPING_CMD3_1) = params->emc_cmd_mapping_cmd3_1;
EMC(EMC_CMD_MAPPING_CMD3_2) = params->emc_cmd_mapping_cmd3_2;
EMC(EMC_CMD_MAPPING_BYTE) = params->emc_cmd_mapping_byte;
// Program brick mapping.
EMC(EMC_PMACRO_BRICK_MAPPING_0) = params->emc_pmacro_brick_mapping0;
EMC(EMC_PMACRO_BRICK_MAPPING_1) = params->emc_pmacro_brick_mapping1;
EMC(EMC_PMACRO_BRICK_MAPPING_2) = params->emc_pmacro_brick_mapping2;
EMC(EMC_PMACRO_BRICK_CTRL_RFU1) = (params->emc_pmacro_brick_ctrl_rfu1 & 0x1120112) | 0x1EED1EED;
// This is required to do any reads from the pad macros.
EMC(EMC_CONFIG_SAMPLE_DELAY) = params->emc_config_sample_delay;
EMC(EMC_FBIO_CFG8) = params->emc_fbio_cfg8;
// Set swizzle for Rank 0.
EMC(EMC_SWIZZLE_RANK0_BYTE0) = params->emc_swizzle_rank0_byte0;
EMC(EMC_SWIZZLE_RANK0_BYTE1) = params->emc_swizzle_rank0_byte1;
EMC(EMC_SWIZZLE_RANK0_BYTE2) = params->emc_swizzle_rank0_byte2;
EMC(EMC_SWIZZLE_RANK0_BYTE3) = params->emc_swizzle_rank0_byte3;
// Set swizzle for Rank 1.
EMC(EMC_SWIZZLE_RANK1_BYTE0) = params->emc_swizzle_rank1_byte0;
EMC(EMC_SWIZZLE_RANK1_BYTE1) = params->emc_swizzle_rank1_byte1;
EMC(EMC_SWIZZLE_RANK1_BYTE2) = params->emc_swizzle_rank1_byte2;
EMC(EMC_SWIZZLE_RANK1_BYTE3) = params->emc_swizzle_rank1_byte3;
// Patch 4 using BCT spare variables.
if (params->emc_bct_spare6)
*(vu32 *)params->emc_bct_spare6 = params->emc_bct_spare7;
// Set pad controls.
EMC(EMC_XM2COMPPADCTRL) = params->emc_xm2_comp_pad_ctrl;
EMC(EMC_XM2COMPPADCTRL2) = params->emc_xm2_comp_pad_ctrl2;
EMC(EMC_XM2COMPPADCTRL3) = params->emc_xm2_comp_pad_ctrl3;
// Program Autocal controls with shadowed register fields.
EMC(EMC_AUTO_CAL_CONFIG2) = params->emc_auto_cal_config2;
EMC(EMC_AUTO_CAL_CONFIG3) = params->emc_auto_cal_config3;
EMC(EMC_AUTO_CAL_CONFIG4) = params->emc_auto_cal_config4;
@@ -124,6 +169,7 @@ break_nosleep:
EMC(EMC_AUTO_CAL_CONFIG6) = params->emc_auto_cal_config6;
EMC(EMC_AUTO_CAL_CONFIG7) = params->emc_auto_cal_config7;
EMC(EMC_AUTO_CAL_CONFIG8) = params->emc_auto_cal_config8;
EMC(EMC_PMACRO_RX_TERM) = params->emc_pmacro_rx_term;
EMC(EMC_PMACRO_DQ_TX_DRV) = params->emc_pmacro_dq_tx_drive;
EMC(EMC_PMACRO_CA_TX_DRV) = params->emc_pmacro_ca_tx_drive;
@@ -131,9 +177,11 @@ break_nosleep:
EMC(EMC_PMACRO_AUTOCAL_CFG_COMMON) = params->emc_pmacro_auto_cal_common;
EMC(EMC_AUTO_CAL_CHANNEL) = params->emc_auto_cal_channel;
EMC(EMC_PMACRO_ZCTRL) = params->emc_pmacro_zcrtl;
EMC(EMC_DLL_CFG_0) = params->emc_dll_cfg0;
EMC(EMC_DLL_CFG_1) = params->emc_dll_cfg1;
EMC(EMC_CFG_DIG_DLL_1) = params->emc_cfg_dig_dll_1;
EMC(EMC_DATA_BRLSHFT_0) = params->emc_data_brlshft0;
EMC(EMC_DATA_BRLSHFT_1) = params->emc_data_brlshft1;
EMC(EMC_DQS_BRLSHFT_0) = params->emc_dqs_brlshft0;
@@ -146,8 +194,10 @@ break_nosleep:
EMC(EMC_QUSE_BRLSHFT_1) = params->emc_quse_brlshft1;
EMC(EMC_QUSE_BRLSHFT_2) = params->emc_quse_brlshft2;
EMC(EMC_QUSE_BRLSHFT_3) = params->emc_quse_brlshft3;
EMC(EMC_PMACRO_BRICK_CTRL_RFU1) = (params->emc_pmacro_brick_ctrl_rfu1 & 0x1BF01BF) | 0x1E401E40;
EMC(EMC_PMACRO_PAD_CFG_CTRL) = params->emc_pmacro_pad_cfg_ctrl;
EMC(EMC_PMACRO_CMD_BRICK_CTRL_FDPD) = params->emc_pmacro_cmd_brick_ctrl_fdpd;
EMC(EMC_PMACRO_BRICK_CTRL_RFU2) = params->emc_pmacro_brick_ctrl_rfu2 & 0xFF7FFF7F;
EMC(EMC_PMACRO_DATA_BRICK_CTRL_FDPD) = params->emc_pmacro_data_brick_ctrl_fdpd;
@@ -158,6 +208,7 @@ break_nosleep:
EMC(EMC_PMACRO_DATA_RX_TERM_MODE) = params->emc_pmacro_data_rx_term_mode;
EMC(EMC_PMACRO_CMD_RX_TERM_MODE) = params->emc_pmacro_cmd_rx_term_mode;
EMC(EMC_PMACRO_CMD_PAD_TX_CTRL) = params->emc_pmacro_cmd_pad_tx_ctrl;
EMC(EMC_CFG_3) = params->emc_cfg3;
EMC(EMC_PMACRO_TX_PWRD_0) = params->emc_pmacro_tx_pwrd0;
EMC(EMC_PMACRO_TX_PWRD_1) = params->emc_pmacro_tx_pwrd1;
@@ -183,6 +234,7 @@ break_nosleep:
EMC(EMC_PMACRO_IB_VREF_DQS_0) = params->emc_pmacro_ib_vref_dqs_0;
EMC(EMC_PMACRO_IB_VREF_DQS_1) = params->emc_pmacro_ib_vref_dqs_1;
EMC(EMC_PMACRO_IB_RXRT) = params->emc_pmacro_ib_rxrt;
EMC(EMC_PMACRO_QUSE_DDLL_RANK0_0) = params->emc_pmacro_quse_ddll_rank0_0;
EMC(EMC_PMACRO_QUSE_DDLL_RANK0_1) = params->emc_pmacro_quse_ddll_rank0_1;
EMC(EMC_PMACRO_QUSE_DDLL_RANK0_2) = params->emc_pmacro_quse_ddll_rank0_2;
@@ -196,6 +248,7 @@ break_nosleep:
EMC(EMC_PMACRO_QUSE_DDLL_RANK1_4) = params->emc_pmacro_quse_ddll_rank1_4;
EMC(EMC_PMACRO_QUSE_DDLL_RANK1_5) = params->emc_pmacro_quse_ddll_rank1_5;
EMC(EMC_PMACRO_BRICK_CTRL_RFU1) = params->emc_pmacro_brick_ctrl_rfu1;
EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0) = params->emc_pmacro_ob_ddll_long_dq_rank0_0;
EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1) = params->emc_pmacro_ob_ddll_long_dq_rank0_1;
EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2) = params->emc_pmacro_ob_ddll_long_dq_rank0_2;
@@ -208,6 +261,7 @@ break_nosleep:
EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3) = params->emc_pmacro_ob_ddll_long_dq_rank1_3;
EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_4) = params->emc_pmacro_ob_ddll_long_dq_rank1_4;
EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_5) = params->emc_pmacro_ob_ddll_long_dq_rank1_5;
EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_0) = params->emc_pmacro_ob_ddll_long_dqs_rank0_0;
EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_1) = params->emc_pmacro_ob_ddll_long_dqs_rank0_1;
EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_2) = params->emc_pmacro_ob_ddll_long_dqs_rank0_2;
@@ -228,6 +282,7 @@ break_nosleep:
EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_1) = params->emc_pmacro_ib_ddll_long_dqs_rank1_1;
EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_2) = params->emc_pmacro_ib_ddll_long_dqs_rank1_2;
EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_3) = params->emc_pmacro_ib_ddll_long_dqs_rank1_3;
EMC(EMC_PMACRO_DDLL_LONG_CMD_0) = params->emc_pmacro_ddll_long_cmd_0;
EMC(EMC_PMACRO_DDLL_LONG_CMD_1) = params->emc_pmacro_ddll_long_cmd_1;
EMC(EMC_PMACRO_DDLL_LONG_CMD_2) = params->emc_pmacro_ddll_long_cmd_2;
@@ -236,10 +291,17 @@ break_nosleep:
EMC(EMC_PMACRO_DDLL_SHORT_CMD_0) = params->emc_pmacro_ddll_short_cmd_0;
EMC(EMC_PMACRO_DDLL_SHORT_CMD_1) = params->emc_pmacro_ddll_short_cmd_1;
EMC(EMC_PMACRO_DDLL_SHORT_CMD_2) = params->emc_pmacro_ddll_short_cmd_2;
// Common pad macro (cpm).
EMC(EMC_PMACRO_COMMON_PAD_TX_CTRL) = (params->emc_pmacro_common_pad_tx_ctrl & 1) | 0xE;
// Patch 3 using BCT spare variables.
if (params->emc_bct_spare4)
*(vu32 *)params->emc_bct_spare4 = params->emc_bct_spare5;
EMC(EMC_TIMING_CONTROL) = 1;
EMC(EMC_TIMING_CONTROL) = 1; // Trigger timing update so above writes take place.
// Initialize MC VPR settings.
MC(MC_VIDEO_PROTECT_BOM) = params->mc_video_protect_bom;
MC(MC_VIDEO_PROTECT_BOM_ADR_HI) = params->mc_video_protect_bom_adr_hi;
MC(MC_VIDEO_PROTECT_SIZE_MB) = params->mc_video_protect_size_mb;
@@ -247,20 +309,32 @@ break_nosleep:
MC(MC_VIDEO_PROTECT_VPR_OVERRIDE1) = params->mc_video_protect_vpr_override1;
MC(MC_VIDEO_PROTECT_GPU_OVERRIDE_0) = params->mc_video_protect_gpu_override0;
MC(MC_VIDEO_PROTECT_GPU_OVERRIDE_1) = params->mc_video_protect_gpu_override1;
// Program SDRAM geometry parameters.
MC(MC_EMEM_ADR_CFG) = params->mc_emem_adr_cfg;
MC(MC_EMEM_ADR_CFG_DEV0) = params->mc_emem_adr_cfg_dev0;
MC(MC_EMEM_ADR_CFG_DEV1) = params->mc_emem_adr_cfg_dev1;
MC(MC_EMEM_ADR_CFG_CHANNEL_MASK) = params->mc_emem_adr_cfg_channel_mask;
// Program bank swizzling.
MC(MC_EMEM_ADR_CFG_BANK_MASK_0) = params->mc_emem_adr_cfg_bank_mask0;
MC(MC_EMEM_ADR_CFG_BANK_MASK_1) = params->mc_emem_adr_cfg_bank_mask1;
MC(MC_EMEM_ADR_CFG_BANK_MASK_2) = params->mc_emem_adr_cfg_bank_mask2;
// Program external memory aperture (base and size).
MC(MC_EMEM_CFG) = params->mc_emem_cfg;
// Program SEC carveout (base and size).
MC(MC_SEC_CARVEOUT_BOM) = params->mc_sec_carveout_bom;
MC(MC_SEC_CARVEOUT_ADR_HI) = params->mc_sec_carveout_adr_hi;
MC(MC_SEC_CARVEOUT_SIZE_MB) = params->mc_sec_carveout_size_mb;
// Program MTS carveout (base and size).
MC(MC_MTS_CARVEOUT_BOM) = params->mc_mts_carveout_bom;
MC(MC_MTS_CARVEOUT_ADR_HI) = params->mc_mts_carveout_adr_hi;
MC(MC_MTS_CARVEOUT_SIZE_MB) = params->mc_mts_carveout_size_mb;
// Program the memory arbiter.
MC(MC_EMEM_ARB_CFG) = params->mc_emem_arb_cfg;
MC(MC_EMEM_ARB_OUTSTANDING_REQ) = params->mc_emem_arb_outstanding_req;
MC(MC_EMEM_ARB_REFPB_HP_CTRL) = params->emc_emem_arb_refpb_hp_ctrl;
@@ -289,21 +363,38 @@ break_nosleep:
MC(MC_EMEM_ARB_OVERRIDE_1) = params->mc_emem_arb_override1;
MC(MC_EMEM_ARB_RSV) = params->mc_emem_arb_rsv;
MC(MC_DA_CONFIG0) = params->mc_da_cfg0;
MC(MC_TIMING_CONTROL) = 1;
MC(MC_TIMING_CONTROL) = 1; // Trigger MC timing update.
// Program second-level clock enable overrides.
MC(MC_CLKEN_OVERRIDE) = params->mc_clken_override;
// Program statistics gathering.
MC(MC_STAT_CONTROL) = params->mc_stat_control;
// Program SDRAM geometry parameters.
EMC(EMC_ADR_CFG) = params->emc_adr_cfg;
// Program second-level clock enable overrides.
EMC(EMC_CLKEN_OVERRIDE) = params->emc_clken_override;
// Program EMC pad auto calibration.
EMC(EMC_PMACRO_AUTOCAL_CFG_0) = params->emc_pmacro_auto_cal_cfg0;
EMC(EMC_PMACRO_AUTOCAL_CFG_1) = params->emc_pmacro_auto_cal_cfg1;
EMC(EMC_PMACRO_AUTOCAL_CFG_2) = params->emc_pmacro_auto_cal_cfg2;
EMC(EMC_AUTO_CAL_VREF_SEL_0) = params->emc_auto_cal_vref_sel0;
EMC(EMC_AUTO_CAL_VREF_SEL_1) = params->emc_auto_cal_vref_sel1;
EMC(EMC_AUTO_CAL_INTERVAL) = params->emc_auto_cal_interval;
EMC(EMC_AUTO_CAL_CONFIG) = params->emc_auto_cal_config;
usleep(params->emc_auto_cal_wait);
// Patch 5 using BCT spare variables.
if (params->emc_bct_spare8)
*(vu32 *)params->emc_bct_spare8 = params->emc_bct_spare9;
// Program EMC timing configuration.
EMC(EMC_CFG_2) = params->emc_cfg2;
EMC(EMC_CFG_PIPE) = params->emc_cfg_pipe;
EMC(EMC_CFG_PIPE_1) = params->emc_cfg_pipe1;
@@ -348,9 +439,11 @@ break_nosleep:
EMC(EMC_EINPUT_DURATION) = params->emc_einput_duration;
EMC(EMC_PUTERM_EXTRA) = params->emc_puterm_extra;
EMC(EMC_PUTERM_WIDTH) = params->emc_puterm_width;
EMC(EMC_PMACRO_COMMON_PAD_TX_CTRL) = params->emc_pmacro_common_pad_tx_ctrl;
EMC(EMC_DBG) = params->emc_dbg;
EMC(EMC_QRST) = params->emc_qrst;
EMC(EMC_ISSUE_QRST) = 1;
EMC(EMC_ISSUE_QRST) = 0;
EMC(EMC_QSAFE) = params->emc_qsafe;
EMC(EMC_RDV) = params->emc_rdv;
@@ -383,6 +476,8 @@ break_nosleep:
EMC(EMC_ODT_WRITE) = params->emc_odt_write;
EMC(EMC_CFG_DIG_DLL) = params->emc_cfg_dig_dll;
EMC(EMC_CFG_DIG_DLL_PERIOD) = params->emc_cfg_dig_dll_period;
// Don't write CFG_ADR_EN (bit 1) here - lock bit written later.
EMC(EMC_FBIO_SPARE) = params->emc_fbio_spare & 0xFFFFFFFD;
EMC(EMC_CFG_RSV) = params->emc_cfg_rsv;
EMC(EMC_PMC_SCRATCH1) = params->emc_pmc_scratch1;
@@ -390,70 +485,104 @@ break_nosleep:
EMC(EMC_PMC_SCRATCH3) = params->emc_pmc_scratch3;
EMC(EMC_ACPD_CONTROL) = params->emc_acpd_control;
EMC(EMC_TXDSRVTTGEN) = params->emc_txdsrvttgen;
// Set pipe bypass enable bits before sending any DRAM commands.
EMC(EMC_CFG) = (params->emc_cfg & 0xE) | 0x3C00000;
// Patch BootROM.
if (params->boot_rom_patch_control & (1 << 31))
{
*(vu32 *)(APB_MISC_BASE + params->boot_rom_patch_control * 4) = params->boot_rom_patch_data;
MC(MC_TIMING_CONTROL) = 1;
MC(MC_TIMING_CONTROL) = 1; // Trigger MC timing update.
}
PMC(APBDEV_PMC_IO_DPD3_REQ) = ((4 * params->emc_pmc_scratch1 >> 2) + 0x40000000) & 0xCFFF0000;
// Release SEL_DPD_CMD.
PMC(APBDEV_PMC_IO_DPD3_REQ) = ((params->emc_pmc_scratch1 & 0x3FFFFFFF) | 0x40000000) & 0xCFFF0000;
usleep(params->pmc_io_dpd3_req_wait);
// Set autocal interval if not configured.
if (!params->emc_auto_cal_interval)
EMC(EMC_AUTO_CAL_CONFIG) = params->emc_auto_cal_config | 0x200;
EMC(EMC_PMACRO_BRICK_CTRL_RFU2) = params->emc_pmacro_brick_ctrl_rfu2;
// ZQ CAL setup (not actually issuing ZQ CAL now).
if (params->emc_zcal_warm_cold_boot_enables & 1)
{
if (params->memory_type == 2)
EMC(EMC_ZCAL_WAIT_CNT) = 8 * params->emc_zcal_wait_cnt;
EMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt << 3;
if (params->memory_type == 3)
{
EMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt;
EMC(EMC_ZCAL_MRW_CMD) = params->emc_zcal_mrw_cmd;
}
}
EMC(EMC_TIMING_CONTROL) = 1;
EMC(EMC_TIMING_CONTROL) = 1; // Trigger timing update so above writes take place.
usleep(params->emc_timing_control_wait);
// Deassert HOLD_CKE_LOW.
PMC(APBDEV_PMC_DDR_CNTRL) &= 0xFFF8007F;
usleep(params->pmc_ddr_ctrl_wait);
if (params->memory_type == 2)
// Set clock enable signal.
u32 pin_gpio_cfg = (params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12);
if (params->memory_type == 2 || params->memory_type == 3)
{
EMC(EMC_PIN) = (params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12);
EMC(EMC_PIN) = pin_gpio_cfg;
(void)EMC(EMC_PIN);
usleep(params->emc_pin_extra_wait + 200);
EMC(EMC_PIN) = ((params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12)) + 256;
usleep(params->emc_pin_extra_wait + 500);
EMC(EMC_PIN) = pin_gpio_cfg | 0x100;
(void)EMC(EMC_PIN);
}
if (params->memory_type == 3)
{
EMC(EMC_PIN) = (params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12);
usleep(params->emc_pin_extra_wait + 200);
EMC(EMC_PIN) = ((params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12)) + 256;
usleep(params->emc_pin_extra_wait + 2000);
}
EMC(EMC_PIN) = ((params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12)) + 0x101;
else if (params->memory_type == 2)
usleep(params->emc_pin_extra_wait + 500);
// Enable clock enable signal.
EMC(EMC_PIN) = pin_gpio_cfg | 0x101;
(void)EMC(EMC_PIN);
usleep(params->emc_pin_program_wait);
// Send NOP (trigger just needs to be non-zero).
if (params->memory_type != 3)
EMC(EMC_NOP) = (params->emc_dev_select << 30) + 1;
// On coldboot w/LPDDR2/3, wait 200 uSec after asserting CKE high.
if (params->memory_type == 1)
usleep(params->emc_pin_extra_wait + 200);
// Init zq calibration,
if (params->memory_type == 3)
{
// Patch 6 using BCT spare variables.
if (params->emc_bct_spare10)
*(vu32 *)params->emc_bct_spare10 = params->emc_bct_spare11;
// Write mode registers.
EMC(EMC_MRW2) = params->emc_mrw2;
EMC(EMC_MRW) = params->emc_mrw1;
EMC(EMC_MRW3) = params->emc_mrw3;
EMC(EMC_MRW4) = params->emc_mrw4;
EMC(EMC_MRW6) = params->emc_mrw6;
EMC(EMC_MRW14) = params->emc_mrw14;
EMC(EMC_MRW8) = params->emc_mrw8;
EMC(EMC_MRW12) = params->emc_mrw12;
EMC(EMC_MRW9) = params->emc_mrw9;
EMC(EMC_MRW13) = params->emc_mrw13;
if (params->emc_zcal_warm_cold_boot_enables & 1)
{
// Issue ZQCAL start, device 0.
EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev0;
usleep(params->emc_zcal_init_wait);
// Issue ZQCAL latch.
EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev0 ^ 3;
// Same for device 1.
if (!(params->emc_dev_select & 2))
{
EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev1;
@@ -462,42 +591,64 @@ break_nosleep:
}
}
}
// Set package and DPD pad control.
PMC(APBDEV_PMC_DDR_CFG) = params->pmc_ddr_cfg;
// Start periodic ZQ calibration (LPDDRx only).
if (params->memory_type - 1 <= 2)
{
EMC(EMC_ZCAL_INTERVAL) = params->emc_zcal_interval;
EMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt;
EMC(EMC_ZCAL_MRW_CMD) = params->emc_zcal_mrw_cmd;
}
// Patch 7 using BCT spare variables.
if (params->emc_bct_spare12)
*(vu32 *)params->emc_bct_spare12 = params->emc_bct_spare13;
EMC(EMC_TIMING_CONTROL) = 1;
EMC(EMC_TIMING_CONTROL) = 1; // Trigger timing update so above writes take place.
if (params->emc_extra_refresh_num)
EMC(EMC_REF) = ((1 << params->emc_extra_refresh_num << 8) - 0xFD) | (params->emc_pin_gpio << 30);
EMC(EMC_REF) = (((1 << params->emc_extra_refresh_num) - 1) << 8) | (params->emc_dev_select << 30) | 3;
// Enable refresh.
EMC(EMC_REFCTRL) = params->emc_dev_select | 0x80000000;
EMC(EMC_DYN_SELF_REF_CONTROL) = params->emc_dyn_self_ref_control;
EMC(EMC_CFG_UPDATE) = params->emc_cfg_update;
EMC(EMC_CFG) = params->emc_cfg;
EMC(EMC_FDPD_CTRL_DQ) = params->emc_fdpd_ctrl_dq;
EMC(EMC_FDPD_CTRL_CMD) = params->emc_fdpd_ctrl_cmd;
EMC(EMC_SEL_DPD_CTRL) = params->emc_sel_dpd_ctrl;
// Write addr swizzle lock bit.
EMC(EMC_FBIO_SPARE) = params->emc_fbio_spare | 2;
EMC(EMC_TIMING_CONTROL) = 1;
EMC(EMC_TIMING_CONTROL) = 1; // Re-trigger timing to latch power saving functions.
// Enable EMC pipe clock gating.
EMC(EMC_CFG_PIPE_CLK) = params->emc_cfg_pipe_clk;
// Depending on freqency, enable CMD/CLK fdpd.
EMC(EMC_FDPD_CTRL_CMD_NO_RAMP) = params->emc_fdpd_ctrl_cmd_no_ramp;
SYSREG(AHB_ARBITRATION_XBAR_CTRL) = (SYSREG(AHB_ARBITRATION_XBAR_CTRL) & 0xFFFEFFFF) | ((params->ahb_arbitration_xbar_ctrl_meminit_done & 0xFFFF) << 16);
// Enable arbiter.
SYSREG(AHB_ARBITRATION_XBAR_CTRL) = (SYSREG(AHB_ARBITRATION_XBAR_CTRL) & 0xFFFEFFFF) | (params->ahb_arbitration_xbar_ctrl_meminit_done << 16);
// Lock carveouts per BCT cfg.
MC(MC_VIDEO_PROTECT_REG_CTRL) = params->mc_video_protect_write_access;
MC(MC_SEC_CARVEOUT_REG_CTRL) = params->mc_sec_carveout_protect_write_access;
MC(MC_MTS_CARVEOUT_REG_CTRL) = params->mc_mts_carveout_reg_ctrl;
MC(MC_EMEM_CFG_ACCESS_CTRL) = 1; //Disable write access to a bunch of EMC registers.
//Disable write access to a bunch of EMC registers.
MC(MC_EMEM_CFG_ACCESS_CTRL) = 1;
}
sdram_params_t *sdram_get_params()
{
//TODO: sdram_id should be in [0, 7].
#ifdef CONFIG_SDRAM_COMPRESS_CFG
u8 *buf = (u8 *)0x40030000;
u8 *buf = (u8 *)SDRAM_PARAMS_ADDR;
LZ_Uncompress(_dram_cfg_lz, buf, sizeof(_dram_cfg_lz));
return (sdram_params_t *)&buf[sizeof(sdram_params_t) * _get_sdram_id()];
#else
@@ -529,25 +680,42 @@ sdram_params_t *sdram_get_params_patched()
// Disable Warmboot signature check.
sdram_params->boot_rom_patch_control = (1 << 31) | (((IPATCH_BASE + 4) - APB_MISC_BASE) / 4);
sdram_params->boot_rom_patch_data = IPATCH_CONFIG(0x10459E, 0x2000);
/*
// Disable SBK lock.
sdram_params->emc_bct_spare8 = (IPATCH_BASE + 7 * 4);
sdram_params->emc_bct_spare9 = IPATCH_CONFIG(0x10210E, 0x2000);
// Disable bootrom read lock.
sdram_params->emc_bct_spare10 = (IPATCH_BASE + 10 * 4);
sdram_params->emc_bct_spare11 = IPATCH_CONFIG(0x100FDC, 0xF000);
sdram_params->emc_bct_spare12 = (IPATCH_BASE + 11 * 4);
sdram_params->emc_bct_spare13 = IPATCH_CONFIG(0x100FDE, 0xE320);
*/
return sdram_params;
}
void sdram_init()
{
//TODO: sdram_id should be in [0,4].
const sdram_params_t *params = (const sdram_params_t *)sdram_get_params();
// Set DRAM voltage.
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD_CFG2, 0x05);
max77620_regulator_set_voltage(REGULATOR_SD1, 1100000);
// VDDP Select.
PMC(APBDEV_PMC_VDDP_SEL) = params->pmc_vddp_sel;
usleep(params->pmc_vddp_sel_wait);
// Set DDR pad voltage.
PMC(APBDEV_PMC_DDR_PWR) = PMC(APBDEV_PMC_DDR_PWR);
// Turn on MEM IO Power.
PMC(APBDEV_PMC_NO_IOPOWER) = params->pmc_no_io_power;
PMC(APBDEV_PMC_REG_SHORT) = params->pmc_reg_short;
PMC(APBDEV_PMC_DDR_CNTRL) = params->pmc_ddr_ctrl;
// Patch 1 using BCT spare variables
if (params->emc_bct_spare0)
*(vu32 *)params->emc_bct_spare0 = params->emc_bct_spare1;

View File

@@ -1,7 +1,7 @@
/*
* Copyright (c) 2013-2015, NVIDIA CORPORATION. All rights reserved.
* Copyright 2014 Google Inc.
* Copyright (C) 2018 CTCaer
* Copyright (c) 2018 CTCaer
*
* 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 @@
/*
* Battery charger driver for Nintendo Switch's TI BQ24193
*
* Copyright (C) 2018 CTCaer
* Copyright (c) 2018 CTCaer
*
* 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,6 +20,9 @@
#include "../soc/i2c.h"
#include "../utils/util.h"
#pragma GCC push_options
#pragma GCC optimize ("Os")
int bq24193_get_property(enum BQ24193_reg_prop prop, int *value)
{
u8 data;
@@ -88,7 +91,7 @@ int bq24193_get_property(enum BQ24193_reg_prop prop, int *value)
break;
case BQ24193_ChargeVoltageLimit: // Charge voltage limit (mV).
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_ChrgVolt);
data = (data & BQ24193_CHRGVOLT_VREG) >> 2;
data = (data & BQ24193_CHRGVOLT_VREG) >> 2;
*value += ((data >> 0) & 1) ? 16 : 0;
*value += ((data >> 1) & 1) ? 32 : 0;
*value += ((data >> 2) & 1) ? 64 : 0;
@@ -160,3 +163,5 @@ void bq24193_fake_battery_removal()
value |= BQ24193_MISC_BATFET_DI_MASK;
i2c_send_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_Misc, value);
}
#pragma GCC pop_options

View File

@@ -1,7 +1,7 @@
/*
* Battery charger driver for Nintendo Switch's TI BQ24193
*
* Copyright (C) 2018 CTCaer
* Copyright (c) 2018 CTCaer
*
* 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,9 +1,9 @@
/*
* Fuel gauge driver for Nintendo Switch's Maxim 17050
*
* Copyright (C) 2011 Samsung Electronics
* Copyright (c) 2011 Samsung Electronics
* MyungJoo Ham <myungjoo.ham@samsung.com>
* Copyright (C) 2018 CTCaer
* Copyright (c) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -43,6 +43,9 @@
#define MAX17050_VMAX_TOLERANCE 50 /* 50 mV */
#pragma GCC push_options
#pragma GCC optimize ("Os")
int max17050_get_property(enum MAX17050_reg reg, int *value)
{
u16 data;
@@ -259,8 +262,10 @@ int max17050_fix_configuration()
/* Init complete, Clear the POR bit */
//_max17050_set_por_bit(0); // Should we? Or let the switch to reconfigure POR?
// Sets POR, BI, BR.
// Sets POR, BI, BR.
_max17050_set_por_bit(0x8801);
return 0;
}
#pragma GCC pop_options

View File

@@ -2,9 +2,9 @@
* Fuel gauge driver for Nintendo Switch's Maxim 17050
* Note that Maxim 8966 and 8997 are mfd and this is its subdevice.
*
* Copyright (C) 2011 Samsung Electronics
* Copyright (c) 2011 Samsung Electronics
* MyungJoo Ham <myungjoo.ham@samsung.com>
* Copyright (C) 2018 CTCaer
* Copyright (c) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -96,14 +96,17 @@ enum MAX17050_reg {
MAX17050_K_empty0 = 0x3B,
MAX17050_TaskPeriod = 0x3C,
MAX17050_FSTAT = 0x3D,
MAX17050_TIMER = 0x3E,
MAX17050_SHDNTIMER = 0x3F,
MAX17050_QRTbl30 = 0x42,
MAX17050_dQacc = 0x45,
MAX17050_dPacc = 0x46,
MAX17050_VFSOC0 = 0x48,
Max17050_QH0 = 0x4C,
MAX17050_QH = 0x4D,
MAX17050_QL = 0x4E,
@@ -111,6 +114,8 @@ enum MAX17050_reg {
MAX17050_MaxVolt = 0x51, // Custom ID. Not to be sent to i2c.
MAX17050_VFSOC0Enable = 0x60,
MAX17050_MODELEnable1 = 0x62,
MAX17050_MODELEnable2 = 0x63,
MAX17050_MODELChrTbl = 0x80,

View File

@@ -1,7 +1,7 @@
/*
* Defining registers address and its bit definitions of MAX77620 and MAX20024
*
* Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved.
* Copyright (c) 2016 NVIDIA CORPORATION. All rights reserved.
* Copyright (c) 2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
@@ -19,9 +19,19 @@
#define MAX77620_CNFGGLBL1_LBDAC_EN (1 << 7)
#define MAX77620_CNFGGLBL1_MPPLD (1 << 6)
#define MAX77620_CNFGGLBL1_LBHYST ((1 << 5) | (1 << 4))
#define MAX77620_CNFGGLBL1_LBHYST_N (1 << 4)
#define MAX77620_CNFGGLBL1_LBDAC 0x0E
#define MAX77620_CNFGGLBL1_LBDAC_N (1 << 1)
#define MAX77620_CNFGGLBL1_LBHYST_100 (0 << 4)
#define MAX77620_CNFGGLBL1_LBHYST_200 (1 << 4)
#define MAX77620_CNFGGLBL1_LBHYST_300 (2 << 4)
#define MAX77620_CNFGGLBL1_LBHYST_400 (3 << 4)
#define MAX77620_CNFGGLBL1_LBDAC_MASK 0x0E
#define MAX77620_CNFGGLBL1_LBDAC_2700 (0 << 1)
#define MAX77620_CNFGGLBL1_LBDAC_2800 (1 << 1)
#define MAX77620_CNFGGLBL1_LBDAC_2900 (2 << 1)
#define MAX77620_CNFGGLBL1_LBDAC_3000 (3 << 1)
#define MAX77620_CNFGGLBL1_LBDAC_3100 (4 << 1)
#define MAX77620_CNFGGLBL1_LBDAC_3200 (5 << 1)
#define MAX77620_CNFGGLBL1_LBDAC_3300 (6 << 1)
#define MAX77620_CNFGGLBL1_LBDAC_3400 (7 << 1)
#define MAX77620_CNFGGLBL1_LBRSTEN (1 << 0)
#define MAX77620_REG_CNFGGLBL2 0x01
@@ -130,7 +140,7 @@
#define MAX77620_POWER_MODE_DISABLE 0
#define MAX20024_LDO_CFG2_MPOK_MASK (1 << 2)
#define MAX77620_LDO_CFG2_ADE_MASK (1 << 1)
#define MAX77620_LDO_CFG2_ADE_DISABLE 0
#define MAX77620_LDO_CFG2_ADE_DISABLE (0 << 1)
#define MAX77620_LDO_CFG2_ADE_ENABLE (1 << 1)
#define MAX77620_LDO_CFG2_SS_MASK (1 << 0)
#define MAX77620_LDO_CFG2_SS_FAST (1 << 0)
@@ -153,6 +163,24 @@
#define MAX77620_REG_PUE_GPIO 0x3E
#define MAX77620_REG_PDE_GPIO 0x3F
#define MAX77620_REG_AME_GPIO 0x40
#define MAX77620_CNFG_GPIO_DRV_MASK (1 << 0)
#define MAX77620_CNFG_GPIO_DRV_PUSHPULL (1 << 0)
#define MAX77620_CNFG_GPIO_DRV_OPENDRAIN (0 << 0)
#define MAX77620_CNFG_GPIO_DIR_MASK (1 << 1)
#define MAX77620_CNFG_GPIO_DIR_INPUT (1 << 1)
#define MAX77620_CNFG_GPIO_DIR_OUTPUT (0 << 1)
#define MAX77620_CNFG_GPIO_INPUT_VAL_MASK (1 << 2)
#define MAX77620_CNFG_GPIO_OUTPUT_VAL_MASK (1 << 3)
#define MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH (1 << 3)
#define MAX77620_CNFG_GPIO_OUTPUT_VAL_LOW (0 << 3)
#define MAX77620_CNFG_GPIO_INT_MASK (0x3 << 4)
#define MAX77620_CNFG_GPIO_INT_FALLING (1 << 4)
#define MAX77620_CNFG_GPIO_INT_RISING (1 << 5)
#define MAX77620_CNFG_GPIO_DBNC_MASK (0x3 << 6)
#define MAX77620_CNFG_GPIO_DBNC_None (0x0 << 6)
#define MAX77620_CNFG_GPIO_DBNC_8ms (0x1 << 6)
#define MAX77620_CNFG_GPIO_DBNC_16ms (0x2 << 6)
#define MAX77620_CNFG_GPIO_DBNC_32ms (0x3 << 6)
#define MAX77620_REG_ONOFFCNFG1 0x41
#define MAX77620_ONOFFCNFG1_SFT_RST (1 << 7)
@@ -259,25 +287,6 @@
#define MAX77620_SD_CFG1_FSRADE_SD_DISABLE 0
#define MAX77620_SD_CFG1_FSRADE_SD_ENABLE (1 << 0)
#define MAX77620_CNFG_GPIO_DRV_MASK (1 << 0)
#define MAX77620_CNFG_GPIO_DRV_PUSHPULL (1 << 0)
#define MAX77620_CNFG_GPIO_DRV_OPENDRAIN 0
#define MAX77620_CNFG_GPIO_DIR_MASK (1 << 1)
#define MAX77620_CNFG_GPIO_DIR_INPUT (1 << 1)
#define MAX77620_CNFG_GPIO_DIR_OUTPUT 0
#define MAX77620_CNFG_GPIO_INPUT_VAL_MASK (1 << 2)
#define MAX77620_CNFG_GPIO_OUTPUT_VAL_MASK (1 << 3)
#define MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH (1 << 3)
#define MAX77620_CNFG_GPIO_OUTPUT_VAL_LOW 0
#define MAX77620_CNFG_GPIO_INT_MASK (0x3 << 4)
#define MAX77620_CNFG_GPIO_INT_FALLING (1 << 4)
#define MAX77620_CNFG_GPIO_INT_RISING (1 << 5)
#define MAX77620_CNFG_GPIO_DBNC_MASK (0x3 << 6)
#define MAX77620_CNFG_GPIO_DBNC_None (0x0 << 6)
#define MAX77620_CNFG_GPIO_DBNC_8ms (0x1 << 6)
#define MAX77620_CNFG_GPIO_DBNC_16ms (0x2 << 6)
#define MAX77620_CNFG_GPIO_DBNC_32ms (0x3 << 6)
#define MAX77620_IRQ_LVL2_GPIO_EDGE0 (1 << 0)
#define MAX77620_IRQ_LVL2_GPIO_EDGE1 (1 << 1)
#define MAX77620_IRQ_LVL2_GPIO_EDGE2 (1 << 2)

View File

@@ -64,6 +64,16 @@ static const max77620_regulator_t _pmic_regulators[] = {
{ REGULATOR_LDO, "ldo8", 0x00, 50000, 800000, 1050000, 1050000, MAX77620_REG_LDO8_CFG, MAX77620_REG_LDO8_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO8, 3, 7, 0 }
};
static void _max77620_try_set_reg(u8 reg, u8 val)
{
u8 tmp;
do
{
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, reg, val);
tmp = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, reg);
} while (val != tmp);
}
int max77620_regulator_get_status(u32 id)
{
if (id > REGULATOR_MAX)
@@ -83,7 +93,7 @@ int max77620_regulator_config_fps(u32 id)
const max77620_regulator_t *reg = &_pmic_regulators[id];
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, reg->fps_addr,
_max77620_try_set_reg(reg->fps_addr,
(reg->fps_src << MAX77620_FPS_SRC_SHIFT) | (reg->pu_period << MAX77620_FPS_PU_PERIOD_SHIFT) | (reg->pd_period));
return 1;
@@ -102,7 +112,7 @@ int max77620_regulator_set_voltage(u32 id, u32 mv)
u32 mult = (mv + reg->mv_step - 1 - reg->mv_min) / reg->mv_step;
u8 val = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, reg->volt_addr);
val = (val & ~reg->volt_mask) | (mult & reg->volt_mask);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, reg->volt_addr, val);
_max77620_try_set_reg(reg->volt_addr, val);
usleep(1000);
return 1;
@@ -121,12 +131,13 @@ int max77620_regulator_enable(u32 id, int enable)
val = (val & ~reg->enable_mask) | ((MAX77620_POWER_MODE_NORMAL << reg->enable_shift) & reg->enable_mask);
else
val &= ~reg->enable_mask;
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, addr, val);
_max77620_try_set_reg(addr, val);
usleep(1000);
return 1;
}
// LDO only.
int max77620_regulator_set_volt_and_flags(u32 id, u32 mv, u8 flags)
{
if (id > REGULATOR_MAX)
@@ -139,7 +150,7 @@ int max77620_regulator_set_volt_and_flags(u32 id, u32 mv, u8 flags)
u32 mult = (mv + reg->mv_step - 1 - reg->mv_min) / reg->mv_step;
u8 val = ((flags << reg->enable_shift) & ~reg->volt_mask) | (mult & reg->volt_mask);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, reg->volt_addr, val);
_max77620_try_set_reg(reg->volt_addr, val);
usleep(1000);
return 1;
@@ -155,11 +166,12 @@ void max77620_config_default()
if (_pmic_regulators[i].fps_src != MAX77620_FPS_SRC_NONE)
max77620_regulator_enable(i, 1);
}
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD_CFG2, 4);
_max77620_try_set_reg(MAX77620_REG_SD_CFG2, 4);
}
void max77620_low_battery_monitor_config()
{
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_CNFGGLBL1,
MAX77620_CNFGGLBL1_LBDAC_EN | MAX77620_CNFGGLBL1_LBHYST_N | MAX77620_CNFGGLBL1_LBDAC_N);
_max77620_try_set_reg(MAX77620_REG_CNFGGLBL1,
MAX77620_CNFGGLBL1_LBDAC_EN | MAX77620_CNFGGLBL1_MPPLD |
MAX77620_CNFGGLBL1_LBHYST_200 | MAX77620_CNFGGLBL1_LBDAC_2800);
}

View File

@@ -24,16 +24,16 @@
* Switch Power domains (max77620):
* Name | Usage | uV step | uV min | uV default | uV max | Init
*-------+---------------+---------+--------+------------+---------+------------------
* sd0 | core | 12500 | 600000 | 625000 | 1400000 | 1.125V (pkg1.1)
* 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)
* ldo3 | GC ASIC | 50000 | 800000 | 3100000 | 3100000 | 3.1V (pcv)
* ldo4 | RTC | 12500 | 800000 | 850000 | 850000 |
* ldo5 | GC ASIC | 50000 | 800000 | 1800000 | 1800000 | 1.8V (pcv)
* ldo5 | GC Card | 50000 | 800000 | 1800000 | 1800000 | 1.8V (pcv)
* ldo6 | Touch, ALS | 50000 | 800000 | 2900000 | 2900000 | 2.9V
* ldo7 | XUSB | 50000 | 800000 | 1050000 | 1050000 |
* ldo8 | XUSB, DC | 50000 | 800000 | 1050000 | 1050000 |
@@ -71,6 +71,8 @@
/* MAX77621_VOUT */
#define MAX77621_VOUT_ENABLE (1 << 7)
#define MAX77621_VOUT_MASK 0x7F
#define MAX77621_VOUT_0_95V 0x37
#define MAX77621_VOUT_1_09V 0x4F
/* MAX77621_VOUT_DVC_DVS */
#define MAX77621_DVS_VOUT_MASK 0x7F

View File

@@ -1,7 +1,8 @@
/*
* PMIC Real Time Clock driver for Nintendo Switch's MAX77620-RTC
*
* Copyright (c) 2018 CTCaer
* Copyright (c) 2018-2019 CTCaer
* Copyright (c) 2019 shchmue
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -36,7 +37,7 @@ void max77620_rtc_get_time(rtc_time_t *time)
time->min = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_MIN_REG) & 0x7F;
time->hour = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_HOUR_REG) & 0x1F;
if (!(val & MAX77620_RTC_24H) && time->hour & MAX77620_RTC_HOUR_PM_MASK)
time->hour = (time->hour & 0xF) + 12;
@@ -52,7 +53,7 @@ void max77620_rtc_get_time(rtc_time_t *time)
}
// Get date.
time->date = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_DATE_REG) & 0x1f;
time->day = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_DATE_REG) & 0x1f;
time->month = (i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_MONTH_REG) & 0xF) - 1;
time->year = (i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_YEAR_REG) & 0x7F) + 2000;
}
@@ -75,3 +76,94 @@ void max77620_rtc_stop_alarm()
// Update RTC clock from RTC regs.
i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_UPDATE0_REG, MAX77620_RTC_WRITE_UPDATE);
}
void max77620_rtc_epoch_to_date(u32 epoch, rtc_time_t *time)
{
u32 tmp, edays, year, month, day;
// Set time.
time->sec = epoch % 60;
epoch /= 60;
time->min = epoch % 60;
epoch /= 60;
time->hour = epoch % 24;
epoch /= 24;
// Calculate base date values.
tmp = (u32)(((u64)4 * epoch + 102032) / 146097 + 15);
tmp = (u32)((u64)epoch + 2442113 + tmp - (tmp >> 2));
year = (20 * tmp - 2442) / 7305;
edays = tmp - 365 * year - (year >> 2);
month = edays * 1000 / 30601;
day = edays - month * 30 - month * 601 / 1000;
// Month/Year offset.
if(month < 14)
{
year -= 4716;
month--;
}
else
{
year -= 4715;
month -= 13;
}
// Set date.
time->year = year;
time->month = month;
time->day = day;
// Set weekday.
time->weekday = 0; //! TODO.
}
u32 max77620_rtc_date_to_epoch(const rtc_time_t *time, bool hos_encoding)
{
u32 year, month, epoch;
//Year
year = time->year;
//Month of year
month = time->month;
if (!hos_encoding)
{
// Month/Year offset.
if(month < 3)
{
month += 12;
year--;
}
}
else
{
year -= 2000;
month++;
// Month/Year offset.
if(month < 3)
{
month += 9;
year--;
}
else
month -= 3;
}
epoch = (365 * year) + (year >> 2) - (year / 100) + (year / 400); // Years to days.
if (!hos_encoding)
{
epoch += (30 * month) + (3 * (month + 1) / 5) + time->day; // Months to days.
epoch -= 719561; // Epoch time is 1/1/1970.
}
else
epoch += (30 * month) + ((3 * month + 2) / 5) + 59 + time->day; // Months to days.
epoch *= 86400; // Days to seconds.
epoch += (3600 * time->hour) + (60 * time->min) + time->sec; // Add hours, minutes and seconds.
return epoch;
}

View File

@@ -64,12 +64,14 @@ typedef struct _rtc_time_t {
u8 sec;
u8 min;
u8 hour;
u8 date;
u8 day;
u8 month;
u16 year;
} rtc_time_t;
void max77620_rtc_get_time(rtc_time_t *time);
void max77620_rtc_stop_alarm();
void max77620_rtc_epoch_to_date(u32 epoch, rtc_time_t *time);
u32 max77620_rtc_date_to_epoch(const rtc_time_t *time, bool hos_encoding);
#endif /* _MFD_MAX77620_RTC_H_ */

View File

@@ -1,7 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 CTCaer
* Copyright (c) 2018 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,
@@ -66,16 +65,14 @@ static int _se_wait()
while (!(SE(SE_INT_STATUS_REG_OFFSET) & SE_INT_OP_DONE(INT_SET)))
;
if (SE(SE_INT_STATUS_REG_OFFSET) & SE_INT_ERROR(INT_SET) ||
SE(SE_STATUS_0) & 3 ||
SE(SE_ERR_STATUS_0) != 0)
SE(SE_STATUS_0) & SE_STATUS_0_STATE_WAIT_IN ||
SE(SE_ERR_STATUS_0) != SE_ERR_STATUS_0_SE_NS_ACCESS_CLEAR)
return 0;
return 1;
}
static int _se_execute(u32 op, void *dst, u32 dst_size, const void *src, u32 src_size)
{
bpmp_mmu_disable();
se_ll_t *ll_dst = NULL, *ll_src = NULL;
if (dst)
@@ -94,17 +91,19 @@ static int _se_execute(u32 op, void *dst, u32 dst_size, const void *src, u32 src
SE(SE_ERR_STATUS_0) = SE(SE_ERR_STATUS_0);
SE(SE_INT_STATUS_REG_OFFSET) = SE(SE_INT_STATUS_REG_OFFSET);
SE(SE_OPERATION_REG_OFFSET) = SE_OPERATION(op);
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false);
SE(SE_OPERATION_REG_OFFSET) = SE_OPERATION(op);
int res = _se_wait();
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false);
if (src)
free(ll_src);
if (dst)
free(ll_dst);
bpmp_mmu_enable();
return res;
}
@@ -121,7 +120,7 @@ static int _se_execute_one_block(u32 op, void *dst, u32 dst_size, const void *sr
memcpy(block, src, src_size);
int res = _se_execute(op, block, 0x10, block, 0x10);
memcpy(dst, block, dst_size);
free(block);
return res;
}
@@ -135,17 +134,19 @@ static void _se_aes_ctr_set(void *ctr)
void se_rsa_acc_ctrl(u32 rs, u32 flags)
{
if (flags & 0x7F)
SE(SE_RSA_KEYTABLE_ACCESS_REG_OFFSET + 4 * rs) = (((flags >> 4) & 4) | (flags & 3)) ^ 7;
if (flags & 0x80)
if (flags & SE_RSA_KEY_TBL_DIS_KEY_ALL_FLAG)
SE(SE_RSA_KEYTABLE_ACCESS_REG_OFFSET + 4 * rs) =
((flags >> SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG_SHIFT) & SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG) |
((flags & SE_RSA_KEY_TBL_DIS_KEY_READ_UPDATE_FLAG) ^ SE_RSA_KEY_TBL_DIS_KEY_ALL_COMMON_FLAG);
if (flags & SE_RSA_KEY_TBL_DIS_KEY_LOCK_FLAG)
SE(SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET) &= ~(1 << rs);
}
void se_key_acc_ctrl(u32 ks, u32 flags)
{
if (flags & 0x7F)
if (flags & SE_KEY_TBL_DIS_KEY_ACCESS_FLAG)
SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + 4 * ks) = ~flags;
if (flags & 0x80)
if (flags & SE_KEY_TBL_DIS_KEY_LOCK_FLAG)
SE(SE_KEY_TABLE_ACCESS_LOCK_OFFSET) &= ~(1 << ks);
}
@@ -178,7 +179,7 @@ int se_aes_unwrap_key(u32 ks_dst, u32 ks_src, const void *input)
return _se_execute(OP_START, NULL, 0, input, 0x10);
}
int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src)
int se_aes_crypt_ecb(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size)
{
if (enc)
{
@@ -190,8 +191,13 @@ int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src)
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_DEC_ALG(ALG_AES_DEC) | SE_CONFIG_DST(DST_MEMORY);
SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_DECRYPT);
}
SE(SE_BLOCK_COUNT_REG_OFFSET) = 0;
return _se_execute(OP_START, dst, 0x10, src, 0x10);
SE(SE_BLOCK_COUNT_REG_OFFSET) = (src_size >> 4) - 1;
return _se_execute(OP_START, dst, dst_size, src, src_size);
}
int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src)
{
return se_aes_crypt_ecb(ks, enc, dst, 0x10, src, 0x10);
}
int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size, void *ctr)
@@ -275,15 +281,15 @@ int se_calc_sha256(void *dst, const void *src, u32 src_size)
int res;
// Setup config for SHA256, size = BITS(src_size).
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_MODE(MODE_SHA256) | SE_CONFIG_ENC_ALG(ALG_SHA) | SE_CONFIG_DST(DST_HASHREG);
SE(SE_SHA_CONFIG_REG_OFFSET) = SHA_ENABLE;
SE(SE_SHA_MSG_LENGTH_REG_OFFSET) = (u32)(src_size << 3);
SE(SE_SHA_MSG_LENGTH_REG_OFFSET + 4 * 1) = 0;
SE(SE_SHA_MSG_LENGTH_REG_OFFSET + 4 * 2) = 0;
SE(SE_SHA_MSG_LENGTH_REG_OFFSET + 4 * 3) = 0;
SE(SE_SHA_MSG_LEFT_REG_OFFSET) = (u32)(src_size << 3);
SE(SE_SHA_MSG_LEFT_REG_OFFSET + 4 * 1) = 0;
SE(SE_SHA_MSG_LEFT_REG_OFFSET + 4 * 2) = 0;
SE(SE_SHA_MSG_LEFT_REG_OFFSET + 4 * 3) = 0;
SE(SE_SHA_CONFIG_REG_OFFSET) = SHA_INIT_HASH;
SE(SE_SHA_MSG_LENGTH_0_REG_OFFSET) = (u32)(src_size << 3);
SE(SE_SHA_MSG_LENGTH_1_REG_OFFSET) = 0;
SE(SE_SHA_MSG_LENGTH_2_REG_OFFSET) = 0;
SE(SE_SHA_MSG_LENGTH_3_REG_OFFSET) = 0;
SE(SE_SHA_MSG_LEFT_0_REG_OFFSET) = (u32)(src_size << 3);
SE(SE_SHA_MSG_LEFT_1_REG_OFFSET) = 0;
SE(SE_SHA_MSG_LEFT_2_REG_OFFSET) = 0;
SE(SE_SHA_MSG_LEFT_3_REG_OFFSET) = 0;
// Trigger the operation.
res = _se_execute(OP_START, NULL, 0, src, src_size);

View File

@@ -24,6 +24,7 @@ void se_key_acc_ctrl(u32 ks, u32 flags);
void se_aes_key_set(u32 ks, void *key, u32 size);
void se_aes_key_clear(u32 ks);
int se_aes_unwrap_key(u32 ks_dst, u32 ks_src, const void *input);
int se_aes_crypt_ecb(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size);
int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src);
int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size, void *ctr);
int se_calc_sha256(void *dst, const void *src, u32 src_size);

View File

@@ -36,6 +36,8 @@
#define SE_SECURITY_0 0x000
#define SE_KEY_SCHED_READ_SHIFT 3
#define SE_TZRAM_SECURITY_0 0x004
#define SE_CONFIG_REG_OFFSET 0x014
#define SE_CONFIG_ENC_ALG_SHIFT 12
#define SE_CONFIG_DEC_ALG_SHIFT 8
@@ -209,8 +211,12 @@
#define SE_INT_OP_DONE(x) (x << SE_INT_OP_DONE_SHIFT)
#define SE_INT_ERROR_SHIFT 16
#define SE_INT_ERROR(x) (x << SE_INT_ERROR_SHIFT)
#define SE_STATUS_0 0x800
#define SE_STATUS_0_STATE_WAIT_IN 3
#define SE_ERR_STATUS_0 0x804
#define SE_ERR_STATUS_0_SE_NS_ACCESS_CLEAR 0
#define SE_CRYPTO_KEYTABLE_DST_REG_OFFSET 0X330
#define SE_CRYPTO_KEYTABLE_DST_WORD_QUAD_SHIFT 0
@@ -231,11 +237,17 @@
#define SE_SPARE_0_REG_OFFSET 0x80c
#define SE_SHA_CONFIG_REG_OFFSET 0x200
#define SHA_DISABLE 0
#define SHA_ENABLE 1
#define SHA_CONTINUE 0
#define SHA_INIT_HASH 1
#define SE_SHA_MSG_LENGTH_REG_OFFSET 0x204
#define SE_SHA_MSG_LEFT_REG_OFFSET 0x214
#define SE_SHA_MSG_LENGTH_0_REG_OFFSET 0x204
#define SE_SHA_MSG_LENGTH_1_REG_OFFSET 0x208
#define SE_SHA_MSG_LENGTH_2_REG_OFFSET 0x20C
#define SE_SHA_MSG_LENGTH_3_REG_OFFSET 0x210
#define SE_SHA_MSG_LEFT_0_REG_OFFSET 0x214
#define SE_SHA_MSG_LEFT_1_REG_OFFSET 0x218
#define SE_SHA_MSG_LEFT_2_REG_OFFSET 0x21C
#define SE_SHA_MSG_LEFT_3_REG_OFFSET 0x220
#define SE_HASH_RESULT_REG_COUNT 16
#define SE_HASH_RESULT_REG_OFFSET 0x030
@@ -254,13 +266,24 @@
TEGRA_SE_RNG_DT_SIZE)
#define TEGRA_SE_AES_CMAC_DIGEST_SIZE 16
#define TEGRA_SE_RSA512_DIGEST_SIZE 64
#define TEGRA_SE_RSA512_DIGEST_SIZE 64
#define TEGRA_SE_RSA1024_DIGEST_SIZE 128
#define TEGRA_SE_RSA1536_DIGEST_SIZE 192
#define TEGRA_SE_RSA2048_DIGEST_SIZE 256
#define SE_KEY_TABLE_ACCESS_LOCK_OFFSET 0x280
#define SE_KEY_TBL_DIS_KEY_LOCK_FLAG 0x80
#define SE_KEY_TABLE_ACCESS_REG_OFFSET 0x284
#define SE_KEY_TBL_DIS_KEYREAD_FLAG (1 << 0)
#define SE_KEY_TBL_DIS_KEYUPDATE_FLAG (1 << 1)
#define SE_KEY_TBL_DIS_OIVREAD_FLAG (1 << 2)
#define SE_KEY_TBL_DIS_OIVUPDATE_FLAG (1 << 3)
#define SE_KEY_TBL_DIS_UIVREAD_FLAG (1 << 4)
#define SE_KEY_TBL_DIS_UIVUPDATE_FLAG (1 << 5)
#define SE_KEY_TBL_DIS_KEYUSE_FLAG (1 << 6)
#define SE_KEY_TBL_DIS_KEY_ACCESS_FLAG 0x7F
#define SE_KEY_READ_DISABLE_SHIFT 0
#define SE_KEY_UPDATE_DISABLE_SHIFT 1
@@ -312,7 +335,16 @@
#define TEGRA_SE_RSA_KEYSLOT_COUNT 2
#define SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET 0x40C
#define SE_RSA_KEY_TBL_DIS_KEY_LOCK_FLAG 0x80
#define SE_RSA_KEYTABLE_ACCESS_REG_OFFSET 0x410
#define SE_RSA_KEY_TBL_DIS_KEYREAD_FLAG (1 << 0)
#define SE_RSA_KEY_TBL_DIS_KEYUPDATE_FLAG (1 << 1)
#define SE_RSA_KEY_TBL_DIS_KEY_READ_UPDATE_FLAG (SE_RSA_KEY_TBL_DIS_KEYREAD_FLAG | SE_RSA_KEY_TBL_DIS_KEYUPDATE_FLAG)
#define SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG (1 << 2)
#define SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG_SHIFT (1 << 2)
#define SE_RSA_KEY_TBL_DIS_KEY_ALL_COMMON_FLAG 7
#define SE_RSA_KEY_TBL_DIS_KEY_ALL_FLAG 0x7F
#define SE_RSA_KEYTABLE_ADDR 0x420
#define SE_RSA_KEYTABLE_DATA 0x424

View File

@@ -23,6 +23,7 @@
#include "../sec/se_t210.h"
#include "../soc/bpmp.h"
#include "../soc/clock.h"
#include "../soc/kfuse.h"
#include "../soc/smmu.h"
#include "../soc/t210.h"
#include "../mem/heap.h"
@@ -69,15 +70,18 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
bpmp_mmu_disable();
bpmp_clk_rate_set(BPMP_CLK_NORMAL);
//Enable clocks.
// Enable clocks.
clock_enable_host1x();
usleep(2);
clock_enable_tsec();
clock_enable_sor_safe();
clock_enable_sor0();
clock_enable_sor1();
clock_enable_kfuse();
//Configure Falcon.
kfuse_wait_ready();
// Configure Falcon.
TSEC(TSEC_DMACTL) = 0;
TSEC(TSEC_IRQMSET) =
TSEC_IRQMSET_EXT(0xFF) |
@@ -99,7 +103,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
goto out;
}
//Load firmware or emulate memio environment for newer TSEC fw.
// Load firmware or emulate memio environment for newer TSEC fw.
if (kb == KB_FIRMWARE_VERSION_620)
TSEC(TSEC_DMATRFBASE) = (u32)tsec_ctxt->fw >> 8;
else
@@ -154,7 +158,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
se = page_alloc(1);
memcpy(se, (void *)SE_BASE, 0x1000);
smmu_map(pdir, SE_BASE, (u32)se, 1, _READABLE | _WRITABLE | _NONSECURE);
// Memory controller.
mc = page_alloc(1);
memcpy(mc, (void *)MC_BASE, 0x1000);
@@ -174,8 +178,8 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
smmu_map(pdir, EXCP_VEC_BASE, (u32)evec, 1, _READABLE | _WRITABLE | _NONSECURE);
}
//Execute firmware.
HOST1X(0x3300) = 0x34C2E1DA;
// Execute firmware.
HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0x34C2E1DA;
TSEC(TSEC_STATUS) = 0;
TSEC(TSEC_BOOTKEYVER) = 1; // HOS uses key version 1.
TSEC(TSEC_BOOTVEC) = 0;
@@ -208,7 +212,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
res = -6;
smmu_deinit_for_tsec();
goto out;
goto out_free;
}
// Give some extra time to make sure PKG1.1 is decrypted.
@@ -216,7 +220,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
memcpy(tsec_keys, &key, 0x20);
memcpy(tsec_ctxt->pkg1, iram, 0x30000);
smmu_deinit_for_tsec();
// for (int i = 0; i < kidx; i++)
@@ -251,8 +255,8 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
goto out_free;
}
//Fetch result.
HOST1X(0x3300) = 0;
// Fetch result.
HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0;
u32 buf[4];
buf[0] = SOR1(SOR_NV_PDISP_SOR_DP_HDCP_BKSV_LSB);
buf[1] = SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_BKSV_LSB);
@@ -271,15 +275,14 @@ out_free:;
out:;
//Disable clocks.
// Disable clocks.
clock_disable_kfuse();
clock_disable_sor1();
clock_disable_sor0();
clock_disable_sor_safe();
clock_disable_tsec();
clock_disable_host1x();
bpmp_mmu_enable();
bpmp_clk_rate_set(BPMP_CLK_SUPER_BOOST);
bpmp_clk_rate_set(BPMP_CLK_DEFAULT_BOOST);
return res;
}

View File

@@ -19,76 +19,122 @@
#include "bpmp.h"
#include "clock.h"
#include "t210.h"
#include "../../common/memory_map.h"
#include "../utils/util.h"
#define BPMP_MMU_CACHE_LINE_SIZE 0x20
#define BPMP_CACHE_CONFIG 0x0
#define CFG_ENABLE (1 << 0)
#define CFG_ENABLE_CACHE (1 << 0)
#define CFG_ENABLE_SKEW_ASSOC (1 << 1)
#define CFG_DISABLE_RANDOM_ALLOC (1 << 2)
#define CFG_FORCE_WRITE_THROUGH (1 << 3)
#define CFG_NEVER_ALLOCATE (1 << 6)
#define CFG_ENABLE_INTERRUPT (1 << 7)
#define CFG_MMU_TAG_MODE(x) (x << 8)
#define TAG_MODE_PARALLEL 0
#define TAG_MODE_TAG_FIRST 1
#define TAG_MODE_MMU_FIRST 2
#define CFG_DISABLE_WRITE_BUFFER (1 << 10)
#define CFG_DISABLE_READ_BUFFER (1 << 11)
#define CFG_ENABLE_HANG_DETECT (1 << 12)
#define CFG_FULL_LINE_DIRTY (1 << 13)
#define CFG_TAG_CHK_ABRT_ON_ERR (1 << 14)
#define CFG_TAG_CHK_CLR_ERR (1 << 15)
#define CFG_DISABLE_SAMELINE (1 << 16)
#define CFG_OBS_BUS_EN (1 << 31)
#define BPMP_CACHE_LOCK 0x4
#define LOCK_LINE(x) (1 << x)
#define BPMP_CACHE_SIZE 0xC
#define BPMP_CACHE_LFSR 0x10
#define BPMP_CACHE_TAG_STATUS 0x14
#define TAG_STATUS_TAG_CHECK_ERROR (1 << 0)
#define TAG_STATUS_CONFLICT_ADDR_MASK 0xFFFFFFE0
#define BPMP_CACHE_CLKEN_OVERRIDE 0x18
#define CLKEN_OVERRIDE_WR_MCCIF_CLKEN (1 << 0)
#define CLKEN_OVERRIDE_RD_MCCIF_CLKEN (1 << 1)
#define BPMP_CACHE_MAINT_ADDR 0x20
#define BPMP_CACHE_MAINT_DATA 0x24
#define BPMP_CACHE_MAINT_REQ 0x28
#define MAINT_REQ_WAY_BITMAP(x) ((x) << 8)
#define BPMP_CACHE_INT_MASK 0x40
#define BPMP_CACHE_INT_CLEAR 0x44
#define INT_CLR_MAINT_DONE (1 << 0)
#define BPMP_CACHE_INT_RAW_EVENT 0x48
#define INT_RAW_EVENT_MAINT_DONE (1 << 0)
#define BPMP_CACHE_INT_STATUS 0x4C
#define INT_MAINT_DONE (1 << 0)
#define INT_MAINT_ERROR (1 << 1)
#define BPMP_CACHE_RB_CFG 0x80
#define BPMP_CACHE_WB_CFG 0x84
#define BPMP_CACHE_MMU_FALLBACK_ENTRY 0xA0
#define BPMP_CACHE_MMU_SHADOW_COPY_MASK 0xA4
#define BPMP_CACHE_MMU_CFG 0xAC
#define MMU_CFG_BLOCK_MAIN_ENTRY_WR (1 << 0)
#define MMU_CFG_SEQ_EN (1 << 1)
#define MMU_CFG_TLB_EN (1 << 2)
#define MMU_CFG_SEG_CHECK_ALL_ENTRIES (1 << 3)
#define MMU_CFG_ABORT_STORE_LAST (1 << 4)
#define MMU_CFG_CLR_ABORT (1 << 5)
#define BPMP_CACHE_MMU_CMD 0xB0
#define MMU_CMD_NOP 0
#define MMU_CMD_INIT 1
#define MMU_CMD_COPY_SHADOW 2
#define BPMP_CACHE_MMU_ABORT_STAT 0xB4
#define ABORT_STAT_UNIT_MASK 0x7
#define ABORT_STAT_UNIT_NONE 0
#define ABORT_STAT_UNIT_CACHE 1
#define ABORT_STAT_UNIT_SEQ 2
#define ABORT_STAT_UNIT_TLB 3
#define ABORT_STAT_UNIT_SEG 4
#define ABORT_STAT_UNIT_FALLBACK 5
#define ABORT_STAT_OVERLAP (1 << 3)
#define ABORT_STAT_ENTRY (0x1F << 4)
#define ABORT_STAT_TYPE_MASK (3 << 16)
#define ABORT_STAT_TYPE_EXE (0 << 16)
#define ABORT_STAT_TYPE_RD (1 << 16)
#define ABORT_STAT_TYPE_WR (2 << 16)
#define ABORT_STAT_SIZE (3 << 18)
#define ABORT_STAT_SEQ (1 << 20)
#define ABORT_STAT_PROT (1 << 21)
#define BPMP_CACHE_MMU_ABORT_ADDR 0xB8
#define BPMP_CACHE_MMU_ACTIVE_ENTRIES 0xBC
#define BPMP_MMU_SHADOW_ENTRY_BASE (BPMP_CACHE_BASE + 0x400)
#define BPMP_MMU_MAIN_ENTRY_BASE (BPMP_CACHE_BASE + 0x800)
#define MMU_ENTRY_ADDR_MASK 0xFFFFFFE0
#define MMU_EN_CACHED (1 << 0)
#define MMU_EN_EXEC (1 << 1)
#define MMU_EN_READ (1 << 2)
#define MMU_EN_WRITE (1 << 3)
#define BPMP_MMU_SHADOW_ENTRY_BASE (BPMP_CACHE_BASE + 0x400)
#define BPMP_MMU_MAIN_ENTRY_BASE (BPMP_CACHE_BASE + 0x800)
#define MMU_EN_CACHED (1 << 0)
#define MMU_EN_EXEC (1 << 1)
#define MMU_EN_READ (1 << 2)
#define MMU_EN_WRITE (1 << 3)
bpmp_mmu_entry_t mmu_entries[] =
{
{ 0x80000000, 0xFFFFFFFF, MMU_EN_READ | MMU_EN_WRITE | MMU_EN_EXEC | MMU_EN_CACHED, true },
{ IPL_LOAD_ADDR, 0x40040000, MMU_EN_READ | MMU_EN_WRITE | MMU_EN_EXEC | MMU_EN_CACHED, true }
{ DRAM_START, 0xFFFFFFFF, MMU_EN_READ | MMU_EN_WRITE | MMU_EN_EXEC | MMU_EN_CACHED, true },
{ IRAM_BASE, 0x4003FFFF, MMU_EN_READ | MMU_EN_WRITE | MMU_EN_EXEC | MMU_EN_CACHED, true }
};
void bpmp_mmu_maintenance(u32 op)
void bpmp_mmu_maintenance(u32 op, bool force)
{
if (!(BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE))
if (!force && !(BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE_CACHE))
return;
BPMP_CACHE_CTRL(BPMP_CACHE_INT_CLEAR) = INT_CLR_MAINT_DONE;
BPMP_CACHE_CTRL(BPMP_CACHE_INT_CLEAR) = INT_MAINT_DONE;
// This is a blocking operation.
BPMP_CACHE_CTRL(BPMP_CACHE_MAINT_REQ) = MAINT_REQ_WAY_BITMAP(0xF) | op;
while(!(BPMP_CACHE_CTRL(BPMP_CACHE_INT_RAW_EVENT) & INT_RAW_EVENT_MAINT_DONE))
while(!(BPMP_CACHE_CTRL(BPMP_CACHE_INT_RAW_EVENT) & INT_MAINT_DONE))
;
BPMP_CACHE_CTRL(BPMP_CACHE_INT_CLEAR) = BPMP_CACHE_CTRL(BPMP_CACHE_INT_RAW_EVENT);
@@ -103,8 +149,8 @@ void bpmp_mmu_set_entry(int idx, bpmp_mmu_entry_t *entry, bool apply)
if (entry->enable)
{
mmu_entry->min_addr = entry->min_addr & MMU_ENTRY_ADDR_MASK;
mmu_entry->max_addr = entry->max_addr & MMU_ENTRY_ADDR_MASK;
mmu_entry->start_addr = ALIGN(entry->start_addr, BPMP_MMU_CACHE_LINE_SIZE);
mmu_entry->end_addr = ALIGN_DOWN(entry->end_addr, BPMP_MMU_CACHE_LINE_SIZE);
mmu_entry->attr = entry->attr;
BPMP_CACHE_CTRL(BPMP_CACHE_MMU_SHADOW_COPY_MASK) |= (1 << idx);
@@ -116,7 +162,7 @@ void bpmp_mmu_set_entry(int idx, bpmp_mmu_entry_t *entry, bool apply)
void bpmp_mmu_enable()
{
if (BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE)
if (BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE_CACHE)
return;
// Init BPMP MMU.
@@ -132,40 +178,64 @@ void bpmp_mmu_enable()
BPMP_CACHE_CTRL(BPMP_CACHE_MMU_CMD) = MMU_CMD_COPY_SHADOW;
// Invalidate cache.
bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY);
bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, true);
// Enable cache.
BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) = CFG_ENABLE | CFG_FORCE_WRITE_THROUGH | CFG_TAG_CHK_ABRT_ON_ERR;
BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) = CFG_ENABLE_CACHE | CFG_FORCE_WRITE_THROUGH |
CFG_MMU_TAG_MODE(TAG_MODE_PARALLEL) | CFG_TAG_CHK_ABRT_ON_ERR;
// HW bug. Invalidate cache again.
bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY);
bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, false);
}
void bpmp_mmu_disable()
{
if (!(BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE))
if (!(BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE_CACHE))
return;
// Clean and invalidate cache.
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY);
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false);
// Enable cache.
// Disable cache.
BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) = 0;
// HW bug. Invalidate cache again.
bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY);
}
const u8 pllc4_divn[] = {
// APB clock affects RTC, PWM, MEMFETCH, APE, USB, SOR PWM,
// I2C host, DC/DSI/DISP. UART gives extra stress.
// 92: 100% success ratio. 93-94: 595-602MHz has 99% success ratio. 95: 608MHz less.
const u8 pll_divn[] = {
0, // BPMP_CLK_NORMAL: 408MHz 0% - 136MHz APB.
85, // BPMP_CLK_LOW_BOOST: 544MHz 33% - 136MHz APB.
90, // BPMP_CLK_MID_BOOST: 576MHz 41% - 144MHz APB.
94 // BPMP_CLK_SUPER_BOOST: 602MHz 48% - 150MHz APB.
//95 // BPMP_CLK_SUPER_BOOST: 608MHz 49% - 152MHz APB.
85, // BPMP_CLK_HIGH_BOOST: 544MHz 33% - 136MHz APB.
90, // BPMP_CLK_SUPER_BOOST: 576MHz 41% - 144MHz APB.
92 // BPMP_CLK_HYPER_BOOST: 589MHz 44% - 147MHz APB.
// Do not use for public releases!
//95 // BPMP_CLK_DEV_BOOST: 608MHz 49% - 152MHz APB.
};
bpmp_freq_t bpmp_clock_set = BPMP_CLK_NORMAL;
void bpmp_clk_rate_get()
{
bool clk_src_is_pllp = ((CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) >> 4) & 7) == 3;
if (clk_src_is_pllp)
bpmp_clock_set = BPMP_CLK_NORMAL;
else
{
bpmp_clock_set = BPMP_CLK_HIGH_BOOST;
u8 pll_divn_curr = (CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) >> 10) & 0xFF;
for (u32 i = 1; i < sizeof(pll_divn); i++)
{
if (pll_divn[i] == pll_divn_curr)
{
bpmp_clock_set = i;
break;
}
}
}
}
void bpmp_clk_rate_set(bpmp_freq_t fid)
{
if (fid > (BPMP_CLK_MAX - 1))
@@ -179,40 +249,60 @@ void bpmp_clk_rate_set(bpmp_freq_t fid)
if (bpmp_clock_set)
{
// Restore to PLLP source during PLLC4 configuration.
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) =
(CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) & 0xFFFF8888) | 0x3333; // PLLP_OUT.
// Wait a bit for clock source change.
msleep(10);
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003333; // PLLP_OUT.
msleep(1); // Wait a bit for clock source change.
}
CLOCK(CLK_RST_CONTROLLER_PLLC4_MISC) = (1 << 30);
CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) = 4 | (pllc4_divn[fid] << 8) | (1 << 30); // DIVM: 4, DIVP: 1.
// Configure and enable PLLC.
clock_enable_pllc(pll_divn[fid]);
while (!(CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) & (1 << 27)))
;
CLOCK(CLK_RST_CONTROLLER_PLLC4_OUT) = (1 << 8) | (1 << 1); // 1.5 div.
CLOCK(CLK_RST_CONTROLLER_PLLC4_OUT) |= 1; // Get divider out of reset.
// Wait a bit for PLLC4 to stabilize.
msleep(10);
CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 3; // PCLK = HCLK / 4.
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) =
(CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) & 0xFFFF8888) | 0x3323; // PLLC4_OUT3.
bpmp_clock_set = fid;
// Set SCLK / HCLK / PCLK.
CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 3; // PCLK = HCLK / (3 + 1). HCLK == SCLK.
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003310; // PLLC_OUT1 for active and CLKM for idle.
}
else
{
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) =
(CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) & 0xFFFF8888) | 0x3333; // PLLP_OUT.
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003330; // PLLP_OUT for active and CLKM for idle.
msleep(1); // Wait a bit for clock source change.
CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 2; // PCLK = HCLK / (2 + 1). HCLK == SCLK.
// Wait a bit for clock source change.
msleep(10);
// Disable PLLC to save power.
clock_disable_pllc();
}
bpmp_clock_set = fid;
}
CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 2; // PCLK = HCLK / 3.
CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) &= ~(1<<30);
bpmp_clock_set = BPMP_CLK_NORMAL;
// The following functions halt BPMP to reduce power while sleeping.
// They are not as accurate as RTC at big values but they guarantee time+ delay.
void bpmp_usleep(u32 us)
{
u32 delay;
// Each iteration takes 1us.
while (us)
{
delay = (us > HALT_COP_MAX_CNT) ? HALT_COP_MAX_CNT : us;
us -= delay;
FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_COP_WAIT_EVENT | HALT_COP_USEC | delay;
}
}
void bpmp_msleep(u32 ms)
{
u32 delay;
// Iteration time is variable. ~200 - 1000us.
while (ms)
{
delay = (ms > HALT_COP_MAX_CNT) ? HALT_COP_MAX_CNT : ms;
ms -= delay;
FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_COP_WAIT_EVENT | HALT_COP_MSEC | delay;
}
}
void bpmp_halt()
{
FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_COP_WAIT_EVENT | HALT_COP_JTAG;
}

View File

@@ -21,14 +21,24 @@
#include "../utils/types.h"
#define BPMP_MMU_MAINT_CLEAN_WAY 17
#define BPMP_MMU_MAINT_INVALID_WAY 18
#define BPMP_MMU_MAINT_CLN_INV_WAY 19
typedef enum
{
BPMP_MMU_MAINT_NOP = 0,
BPMP_MMU_MAINT_CLEAN_PHY = 1,
BPMP_MMU_MAINT_INVALID_PHY = 2,
BPMP_MMU_MAINT_CLEAN_INVALID_PHY = 3,
BPMP_MMU_MAINT_CLEAN_LINE = 9,
BPMP_MMU_MAINT_INVALID_LINE = 10,
BPMP_MMU_MAINT_CLEAN_INVALID_LINE = 11,
BPMP_MMU_MAINT_CLEAN_WAY = 17,
BPMP_MMU_MAINT_INVALID_WAY = 18,
BPMP_MMU_MAINT_CLN_INV_WAY = 19
} bpmp_maintenance_t;
typedef struct _bpmp_mmu_entry_t
{
u32 min_addr;
u32 max_addr;
u32 start_addr;
u32 end_addr;
u32 attr;
u32 enable;
} bpmp_mmu_entry_t;
@@ -36,16 +46,23 @@ typedef struct _bpmp_mmu_entry_t
typedef enum
{
BPMP_CLK_NORMAL, // 408MHz 0% - 136MHz APB.
BPMP_CLK_LOW_BOOST, // 544MHz 33% - 136MHz APB.
BPMP_CLK_MID_BOOST, // 576MHz 41% - 144MHz APB.
BPMP_CLK_SUPER_BOOST, // 608MHz 49% - 152MHz APB.
BPMP_CLK_HIGH_BOOST, // 544MHz 33% - 136MHz APB.
BPMP_CLK_SUPER_BOOST, // 576MHz 41% - 144MHz APB.
BPMP_CLK_HYPER_BOOST, // 589MHz 44% - 147MHz APB.
//BPMP_CLK_DEV_BOOST, // 608MHz 49% - 152MHz APB.
BPMP_CLK_MAX
} bpmp_freq_t;
void bpmp_mmu_maintenance(u32 op);
#define BPMP_CLK_DEFAULT_BOOST BPMP_CLK_HYPER_BOOST
void bpmp_mmu_maintenance(u32 op, bool force);
void bpmp_mmu_set_entry(int idx, bpmp_mmu_entry_t *entry, bool apply);
void bpmp_mmu_enable();
void bpmp_mmu_disable();
void bpmp_clk_rate_get();
void bpmp_clk_rate_set(bpmp_freq_t fid);
void bpmp_usleep(u32 us);
void bpmp_msleep(u32 ms);
void bpmp_halt();
#endif

View File

@@ -19,61 +19,73 @@
#include "../utils/util.h"
#include "../storage/sdmmc.h"
/*
* CLOCK Peripherals:
* L 0 - 31
* H 32 - 63
* U 64 - 95
* V 96 - 127
* W 128 - 159
* X 160 - 191
* Y 192 - 223
*/
/* clock_t: reset, enable, source, index, clk_src, clk_div */
static const clock_t _clock_uart[] = {
/* UART A */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTA, 6, 0, 0 },
/* UART B */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTB, 7, 0, 0 },
/* UART C */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_UARTC, 0x17, 0, 0 },
/* UART D */ { 0 },
/* UART E */ { 0 }
/* UART A */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTA, 6, 0, 2 },
/* UART B */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTB, 7, 0, 2 },
/* UART C */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_UARTC, 23, 0, 2 },
/* UART D */ { CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_UARTD, 1, 0, 2 },
/* UART E */ { CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_RST_CONTROLLER_CLK_SOURCE_UARTAPE, 20, 0, 2 }
};
//I2C default parameters - TLOW: 4, THIGH: 2, DEBOUNCE: 0, FM_DIV: 26.
static const clock_t _clock_i2c[] = {
/* I2C1 */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_I2C1, 0xC, 6, 0 }, // 0, 19 }, // 100KHz
/* I2C2 */ { 0 },
/* I2C3 */ { 0 },
/* I2C4 */ { 0 },
/* I2C5 */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_I2C5, 0xF, 6, 0 }, // 0, 4 }, // 400KHz
/* I2C6 */ { 0 }
/* I2C1 */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_I2C1, 12, 0, 19 }, //20.4MHz -> 100KHz
/* I2C2 */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_I2C2, 22, 0, 4 }, //81.6MHz -> 400KHz
/* I2C3 */ { CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_I2C3, 3, 0, 4 }, //81.6MHz -> 400KHz
/* I2C4 */ { CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_I2C4, 7, 0, 19 }, //20.4MHz -> 100KHz
/* I2C5 */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_I2C5, 15, 0, 4 }, //81.6MHz -> 400KHz
/* I2C6 */ { CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_CLK_SOURCE_I2C6, 6, 0, 19 } //20.4MHz -> 100KHz
};
static clock_t _clock_se = {
CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_SE, 0x1F, 0, 0
CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_SE, 31, 0, 0
};
static clock_t _clock_tzram = {
CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_NO_SOURCE, 0x1E, 0, 0
CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_NO_SOURCE, 30, 0, 0
};
static clock_t _clock_host1x = {
CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X, 0x1C, 4, 3
CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X, 28, 4, 3
};
static clock_t _clock_tsec = {
CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_TSEC, 0x13, 0, 2
CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_TSEC, 19, 0, 2
};
static clock_t _clock_sor_safe = {
CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_NO_SOURCE, 0x1E, 0, 0
CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_NO_SOURCE, 30, 0, 0
};
static clock_t _clock_sor0 = {
CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_NO_SOURCE, 0x16, 0, 0
CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_NO_SOURCE, 22, 0, 0
};
static clock_t _clock_sor1 = {
CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_CLK_SOURCE_SOR1, 0x17, 0, 2
CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_CLK_SOURCE_SOR1, 23, 0, 2
};
static clock_t _clock_kfuse = {
CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_NO_SOURCE, 8, 0, 0
CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_NO_SOURCE, 8, 0, 0
};
static clock_t _clock_cl_dvfs = {
CLK_RST_CONTROLLER_RST_DEVICES_W, CLK_RST_CONTROLLER_CLK_OUT_ENB_W, CLK_NO_SOURCE, 0x1B, 0, 0
CLK_RST_CONTROLLER_RST_DEVICES_W, CLK_RST_CONTROLLER_CLK_OUT_ENB_W, CLK_NO_SOURCE, 27, 0, 0
};
static clock_t _clock_coresight = {
CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_CSITE, 9, 0, 4
CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_CSITE, 9, 0, 4
};
static clock_t _clock_pwm = {
CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_PWM, 0x11, 6, 4
CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_PWM, 17, 6, 4 // Fref: 6.2MHz.
};
void clock_enable(const clock_t *clk)
@@ -87,6 +99,8 @@ void clock_enable(const clock_t *clk)
CLOCK(clk->source) = clk->clk_div | (clk->clk_src << 29);
// Enable.
CLOCK(clk->enable) = (CLOCK(clk->enable) & ~(1 << clk->index)) | (1 << clk->index);
usleep(2);
// Take clock off reset.
CLOCK(clk->reset) &= ~(1 << clk->index);
}
@@ -225,6 +239,51 @@ void clock_disable_pwm()
clock_disable(&_clock_pwm);
}
void clock_enable_pllc(u32 divn)
{
u8 pll_divn_curr = (CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) >> 10) & 0xFF;
// Check if already enabled and configured.
if ((CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) & PLLCX_BASE_ENABLE) && (pll_divn_curr == divn))
return;
// Take PLLC out of reset and set basic misc parameters.
CLOCK(CLK_RST_CONTROLLER_PLLC_MISC) =
((CLOCK(CLK_RST_CONTROLLER_PLLC_MISC) & 0xFFF0000F) & ~PLLC_MISC_RESET) | (0x80000 << 4); // PLLC_EXT_FRU.
CLOCK(CLK_RST_CONTROLLER_PLLC_MISC_2) |= 0xF0 << 8; // PLLC_FLL_LD_MEM.
// Disable PLL and IDDQ in case they are on.
CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) &= ~PLLCX_BASE_ENABLE;
CLOCK(CLK_RST_CONTROLLER_PLLC_MISC_1) &= ~PLLC_MISC1_IDDQ;
usleep(10);
// Set PLLC4 dividers.
CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) = (divn << 10) | 4; // DIVM: 4, DIVP: 1.
// Enable PLLC4 and wait for Phase and Frequency lock.
CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) |= PLLCX_BASE_ENABLE;
while (!(CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) & PLLCX_BASE_LOCK))
;
// Disable PLLC_OUT1, enable reset and set div to 1.5.
CLOCK(CLK_RST_CONTROLLER_PLLC_OUT) = (1 << 8);
// Enable PLLC_OUT1 and bring it out of reset.
CLOCK(CLK_RST_CONTROLLER_PLLC_OUT) |= (PLLC_OUT1_CLKEN | PLLC_OUT1_RSTN_CLR);
msleep(1); // Wait a bit for PLL to stabilize.
}
void clock_disable_pllc()
{
// Disable PLLC and PLLC_OUT1.
CLOCK(CLK_RST_CONTROLLER_PLLC_OUT) &= ~(PLLC_OUT1_CLKEN | PLLC_OUT1_RSTN_CLR);
CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) &= ~PLLCX_BASE_ENABLE;
CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) |= PLLCX_BASE_REF_DIS;
CLOCK(CLK_RST_CONTROLLER_PLLC_MISC_1) |= PLLC_MISC1_IDDQ;
CLOCK(CLK_RST_CONTROLLER_PLLC_MISC) |= PLLC_MISC_RESET;
usleep(10);
}
#define L_SWR_SDMMC1_RST (1 << 14)
#define L_SWR_SDMMC2_RST (1 << 9)
#define L_SWR_SDMMC4_RST (1 << 15)
@@ -366,54 +425,55 @@ static void _clock_sdmmc_clear_enable(u32 id)
static u32 _clock_sdmmc_table[8] = { 0 };
#define PLLP_OUT0 0x0
static int _clock_sdmmc_config_clock_source_inner(u32 *pout, u32 id, u32 val)
static int _clock_sdmmc_config_clock_host(u32 *pout, u32 id, u32 val)
{
u32 divisor = 0;
u32 source = PLLP_OUT0;
// Get IO clock divisor.
switch (val)
{
case 25000:
*pout = 24728;
divisor = 31;
divisor = 31; // 16.5 div.
break;
case 26000:
*pout = 25500;
divisor = 30;
divisor = 30; // 16 div.
break;
case 40800:
*pout = 40800;
divisor = 18;
divisor = 18; // 10 div.
break;
case 50000:
*pout = 48000;
divisor = 15;
divisor = 15; // 8.5 div.
break;
case 52000:
*pout = 51000;
divisor = 14;
divisor = 14; // 8 div.
break;
case 100000:
*pout = 90667;
divisor = 7;
divisor = 7; // 4.5 div.
break;
case 200000:
*pout = 163200;
divisor = 3;
divisor = 3; // 2.5 div.
break;
case 208000:
*pout = 204000;
divisor = 2;
divisor = 2; // 2 div.
break;
default:
*pout = 24728;
divisor = 31;
divisor = 31; // 16.5 div.
}
_clock_sdmmc_table[2 * id] = val;
_clock_sdmmc_table[2 * id + 1] = *pout;
// Set SDMMC clock.
switch (id)
{
case SDMMC_1:
@@ -444,15 +504,16 @@ void clock_sdmmc_config_clock_source(u32 *pout, u32 id, u32 val)
int is_enabled = _clock_sdmmc_is_enabled(id);
if (is_enabled)
_clock_sdmmc_clear_enable(id);
_clock_sdmmc_config_clock_source_inner(pout, id, val);
_clock_sdmmc_config_clock_host(pout, id, val);
if (is_enabled)
_clock_sdmmc_set_enable(id);
_clock_sdmmc_is_reset(id);
}
}
void clock_sdmmc_get_params(u32 *pout, u16 *pdivisor, u32 type)
void clock_sdmmc_get_card_clock_div(u32 *pout, u16 *pdivisor, u32 type)
{
// Get Card clock divisor.
switch (type)
{
case 0:
@@ -513,7 +574,7 @@ void clock_sdmmc_enable(u32 id, u32 val)
if (_clock_sdmmc_is_enabled(id))
_clock_sdmmc_clear_enable(id);
_clock_sdmmc_set_reset(id);
_clock_sdmmc_config_clock_source_inner(&div, id, val);
_clock_sdmmc_config_clock_host(&div, id, val);
_clock_sdmmc_set_enable(id);
_clock_sdmmc_is_reset(id);
usleep((100000 + div - 1) / div);

View File

@@ -35,12 +35,16 @@
#define CLK_RST_CONTROLLER_MISC_CLK_ENB 0x48
#define CLK_RST_CONTROLLER_OSC_CTRL 0x50
#define CLK_RST_CONTROLLER_PLLC_BASE 0x80
#define CLK_RST_CONTROLLER_PLLC_OUT 0x84
#define CLK_RST_CONTROLLER_PLLC_MISC 0x88
#define CLK_RST_CONTROLLER_PLLC_MISC_1 0x8C
#define CLK_RST_CONTROLLER_PLLM_BASE 0x90
#define CLK_RST_CONTROLLER_PLLM_MISC1 0x98
#define CLK_RST_CONTROLLER_PLLM_MISC2 0x9C
#define CLK_RST_CONTROLLER_PLLP_BASE 0xA0
#define CLK_RST_CONTROLLER_PLLD_BASE 0xD0
#define CLK_RST_CONTROLLER_PLLD_MISC1 0xD8
#define CLK_RST_CONTROLLER_PLLD_MISC 0xDC
#define CLK_RST_CONTROLLER_PLLX_BASE 0xE0
#define CLK_RST_CONTROLLER_PLLX_MISC 0xE4
#define CLK_RST_CONTROLLER_PLLE_BASE 0xE8
@@ -50,6 +54,7 @@
#define CLK_RST_CONTROLLER_CLK_SOURCE_PWM 0x110
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C1 0x124
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C5 0x128
#define CLK_RST_CONTROLLER_CLK_SOURCE_DISP1 0x138
#define CLK_RST_CONTROLLER_CLK_SOURCE_VI 0x148
#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC1 0x150
#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC2 0x154
@@ -57,11 +62,13 @@
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTA 0x178
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTB 0x17C
#define CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X 0x180
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C2 0x198
#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC 0x19C
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTC 0x1A0
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C3 0x1B8
#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC3 0x1BC
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTD 0x1C0
#define CLK_RST_CONTROLLER_CLK_SOURCE_CSITE 0x1D4
#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC 0x19C
#define CLK_RST_CONTROLLER_CLK_SOURCE_TSEC 0x1F4
#define CLK_RST_CONTROLLER_CLK_OUT_ENB_X 0x280
#define CLK_RST_CONTROLLER_CLK_ENB_X_SET 0x284
@@ -95,9 +102,13 @@
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRC 0x3A0
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD 0x3A4
#define CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT 0x3B4
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C4 0x3C4
#define CLK_RST_CONTROLLER_CLK_SOURCE_SYS 0x400
#define CLK_RST_CONTROLLER_CLK_SOURCE_SOR1 0x410
#define CLK_RST_CONTROLLER_CLK_SOURCE_SE 0x42C
#define CLK_RST_CONTROLLER_RST_DEV_V_CLR 0x434
#define CLK_RST_CONTROLLER_CLK_ENB_V_SET 0x440
#define CLK_RST_CONTROLLER_CLK_ENB_V_CLR 0x444
#define CLK_RST_CONTROLLER_CLK_ENB_W_SET 0x448
#define CLK_RST_CONTROLLER_CLK_ENB_W_CLR 0x44C
#define CLK_RST_CONTROLLER_RST_CPUG_CMPLX_SET 0x450
@@ -110,17 +121,35 @@
#define CLK_RST_CONTROLLER_SPARE_REG0 0x55C
#define CLK_RST_CONTROLLER_PLLC4_BASE 0x5A4
#define CLK_RST_CONTROLLER_PLLC4_MISC 0x5A8
#define CLK_RST_CONTROLLER_PLLC_MISC_2 0x5D0
#define CLK_RST_CONTROLLER_PLLC4_OUT 0x5E4
#define CLK_RST_CONTROLLER_PLLMB_BASE 0x5E8
#define CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP 0x620
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C6 0x65C
#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL 0x664
#define CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIP_CAL 0x66C
#define CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIPI_CAL 0x66C
#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC_LEGACY_TM 0x694
#define CLK_RST_CONTROLLER_CLK_SOURCE_NVENC 0x6A0
#define CLK_RST_CONTROLLER_SE_SUPER_CLK_DIVIDER 0x704
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTAPE 0x710
#define CLK_NO_SOURCE 0x0
/*! PLL control and status bits */
#define PLLCX_BASE_ENABLE (1 << 30)
#define PLLCX_BASE_REF_DIS (1 << 29)
#define PLLCX_BASE_LOCK (1 << 27)
#define PLLC_MISC_RESET (1 << 30)
#define PLLC_MISC1_IDDQ (1 << 27)
#define PLLC_OUT1_CLKEN (1 << 1)
#define PLLC_OUT1_RSTN_CLR (1 << 0)
#define PLLC4_MISC_EN_LCKDET (1 << 30)
#define PLLC4_BASE_IDDQ (1 << 18)
#define PLLC4_OUT3_CLKEN (1 << 1)
#define PLLC4_OUT3_RSTN_CLR (1 << 0)
/*! Generic clock descriptor. */
typedef struct _clock_t
{
@@ -161,9 +190,11 @@ void clock_enable_coresight();
void clock_disable_coresight();
void clock_enable_pwm();
void clock_disable_pwm();
void clock_enable_pllc(u32 divn);
void clock_disable_pllc();
void clock_sdmmc_config_clock_source(u32 *pout, u32 id, u32 val);
void clock_sdmmc_get_params(u32 *pout, u16 *pdivisor, u32 type);
int clock_sdmmc_is_not_reset_and_enabled(u32 id);
void clock_sdmmc_get_card_clock_div(u32 *pout, u16 *pdivisor, u32 type);
int clock_sdmmc_is_not_reset_and_enabled(u32 id);
void clock_sdmmc_enable(u32 id, u32 val);
void clock_sdmmc_disable(u32 id);

View File

@@ -32,18 +32,21 @@ void _cluster_enable_power()
// Enable cores power.
// 1-3.x: MAX77621_NFSR_ENABLE.
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL1_REG,
MAX77621_AD_ENABLE | MAX77621_NFSR_ENABLE | MAX77621_SNS_ENABLE);
MAX77621_AD_ENABLE | MAX77621_NFSR_ENABLE | MAX77621_SNS_ENABLE | MAX77621_RAMP_12mV_PER_US);
// 1.0.0-3.x: MAX77621_T_JUNCTION_120 | MAX77621_CKKADV_TRIP_DISABLE | MAX77621_INDUCTOR_NOMINAL.
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL2_REG,
MAX77621_T_JUNCTION_120 | MAX77621_WDTMR_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US| MAX77621_INDUCTOR_NOMINAL);
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_REG, MAX77621_VOUT_ENABLE | 0x37);
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_DVC_REG, MAX77621_VOUT_ENABLE | 0x37);
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_0_95V);
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_DVC_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_0_95V);
}
int _cluster_pmc_enable_partition(u32 part, u32 toggle, bool enable)
int _cluster_pmc_enable_partition(u32 part, int enable)
{
// Check if the partition has already been turned on.
if (enable && PMC(APBDEV_PMC_PWRGATE_STATUS) & part)
u32 part_mask = 1 << part;
u32 desired_state = enable << part;
// Check if the partition has the state we want.
if ((PMC(APBDEV_PMC_PWRGATE_STATUS) & part_mask) == desired_state)
return 1;
u32 i = 5001;
@@ -55,12 +58,13 @@ int _cluster_pmc_enable_partition(u32 part, u32 toggle, bool enable)
return 0;
}
PMC(APBDEV_PMC_PWRGATE_TOGGLE) = toggle | (enable ? 0x100 : 0);
// Toggle power gating.
PMC(APBDEV_PMC_PWRGATE_TOGGLE) = part | 0x100;
i = 5001;
while (i > 0)
{
if (PMC(APBDEV_PMC_PWRGATE_STATUS) & part)
if ((PMC(APBDEV_PMC_PWRGATE_STATUS) & part_mask) == desired_state)
break;
usleep(1);
i--;
@@ -76,9 +80,9 @@ void cluster_boot_cpu0(u32 entry)
_cluster_enable_power();
if (!(CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) & 0x40000000))
if (!(CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) & 0x40000000)) // PLLX_ENABLE.
{
CLOCK(CLK_RST_CONTROLLER_PLLX_MISC_3) &= 0xFFFFFFF7;
CLOCK(CLK_RST_CONTROLLER_PLLX_MISC_3) &= 0xFFFFFFF7; // Disable IDDQ.
usleep(2);
CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = 0x80404E02;
CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = 0x404E02;
@@ -103,11 +107,11 @@ void cluster_boot_cpu0(u32 entry)
CLOCK(CLK_RST_CONTROLLER_CPU_SOFTRST_CTRL2) &= 0xFFFFF000;
// Enable CPU rail.
_cluster_pmc_enable_partition(1, 0, true);
_cluster_pmc_enable_partition(0, 1);
// Enable cluster 0 non-CPU.
_cluster_pmc_enable_partition(0x8000, 15, true);
_cluster_pmc_enable_partition(15, 1);
// Enable CE0.
_cluster_pmc_enable_partition(0x4000, 14, true);
_cluster_pmc_enable_partition(14, 1);
// Request and wait for RAM repair.
FLOW_CTLR(FLOW_CTLR_RAM_REPAIR) = 1;
@@ -117,12 +121,15 @@ void cluster_boot_cpu0(u32 entry)
EXCP_VEC(EVP_CPU_RESET_VECTOR) = 0;
// Set reset vector.
SB(SB_AA64_RESET_LOW) = entry | 1;
SB(SB_AA64_RESET_LOW) = entry | SB_AA64_RST_AARCH64_MODE_EN;
SB(SB_AA64_RESET_HIGH) = 0;
// Non-secure reset vector write disable.
SB(SB_CSR) = 2;
SB(SB_CSR) = SB_CSR_NS_RST_VEC_WR_DIS;
(void)SB(SB_CSR);
// Tighten up the security aperture.
// MC(MC_TZ_SECURITY_CTRL) = 1;
// Clear MSELECT reset.
CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_V) &= 0xFFFFFFF7;
// Clear NONCPU reset.

View File

@@ -19,19 +19,6 @@
#include "../utils/types.h"
/*! Flow controller registers. */
#define FLOW_CTLR_HALT_CPU0_EVENTS 0x0
#define FLOW_CTLR_HALT_CPU1_EVENTS 0x14
#define FLOW_CTLR_HALT_CPU2_EVENTS 0x1C
#define FLOW_CTLR_HALT_CPU3_EVENTS 0x24
#define FLOW_CTLR_HALT_COP_EVENTS 0x4
#define FLOW_CTLR_CPU0_CSR 0x8
#define FLOW_CTLR_CPU1_CSR 0x18
#define FLOW_CTLR_CPU2_CSR 0x20
#define FLOW_CTLR_CPU3_CSR 0x28
#define FLOW_CTLR_RAM_REPAIR 0x40
#define FLOW_CTLR_BPMP_CLUSTER_CONTROL 0x98
void cluster_boot_cpu0(u32 entry);
#endif

View File

@@ -218,10 +218,10 @@ int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value))
{
break;
}
for (u32 i = 0; i < word_count; i++)
words[i] = fuse_read(word_addr--);
word0 = words[0];
if (_patch_hash_multi(words, word_count) >= 2)
{
@@ -235,7 +235,7 @@ int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value))
u32 word = words[i + 1];
u32 addr = (word >> 16) * 2;
u32 data = word & 0xFFFF;
ipatch(addr, data);
}
}
@@ -248,7 +248,7 @@ int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value))
}
word_count = word0 >> 25;
}
return 0;
}
@@ -275,10 +275,10 @@ int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len)
{
break;
}
for (u32 i = 0; i < word_count; i++)
words[i] = fuse_read(word_addr--);
word0 = words[0];
if (_patch_hash_multi(words, word_count) >= 2)
{
@@ -314,7 +314,7 @@ int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len)
}
word_count = word0 >> 25;
}
return 0;
}
@@ -331,7 +331,7 @@ bool fuse_check_patched_rcm()
while (word_count)
{
u32 word0 = fuse_read(word_addr);
u32 ipatch_count = (word0 >> 16) & 0xF;
u32 ipatch_count = (word0 >> 16) & 0xF;
for (u32 i = 0; i < ipatch_count; i++)
{

View File

@@ -54,6 +54,7 @@
#define FUSE_PRIVATE_KEY3 0x1B0
#define FUSE_PRIVATE_KEY4 0x1B4
#define FUSE_RESERVED_SW 0x1C0
#define FUSE_SKU_DIRECT_CONFIG 0x1F4
#define FUSE_OPT_VENDOR_CODE 0x200
#define FUSE_OPT_FAB_CODE 0x204
#define FUSE_OPT_LOT_CODE_0 0x208

View File

@@ -40,23 +40,38 @@
extern sdmmc_t sd_sdmmc;
extern boot_cfg_t b_cfg;
extern volatile nyx_storage_t *nyx_str;
/*
* CLK_OSC - 38.4 MHz crystal.
* CLK_M - 19.2 MHz (osc/2).
* CLK_S - 32.768 KHz (from PMIC).
* SCLK - 204MHz init (-> 408MHz -> OC).
* HCLK - 204MHz init (-> 408MHz -> OC).
* PCLK - 68MHz init (-> 136MHz -> OC/4).
*/
void _config_oscillators()
{
CLOCK(CLK_RST_CONTROLLER_SPARE_REG0) = (CLOCK(CLK_RST_CONTROLLER_SPARE_REG0) & 0xFFFFFFF3) | 4;
SYSCTR0(SYSCTR0_CNTFID0) = 19200000;
TMR(TIMERUS_USEC_CFG) = 0x45F; // For 19.2MHz clk_m.
CLOCK(CLK_RST_CONTROLLER_OSC_CTRL) = 0x50000071;
PMC(APBDEV_PMC_OSC_EDPD_OVER) = (PMC(APBDEV_PMC_OSC_EDPD_OVER) & 0xFFFFFF81) | 0xE;
PMC(APBDEV_PMC_OSC_EDPD_OVER) = (PMC(APBDEV_PMC_OSC_EDPD_OVER) & 0xFFBFFFFF) | 0x400000;
PMC(APBDEV_PMC_CNTRL2) = (PMC(APBDEV_PMC_CNTRL2) & 0xFFFFEFFF) | 0x1000;
PMC(APBDEV_PMC_SCRATCH188) = (PMC(APBDEV_PMC_SCRATCH188) & 0xFCFFFFFF) | 0x2000000;
CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 0x10;
CLOCK(CLK_RST_CONTROLLER_PLLMB_BASE) &= 0xBFFFFFFF;
CLOCK(CLK_RST_CONTROLLER_SPARE_REG0) = (CLOCK(CLK_RST_CONTROLLER_SPARE_REG0) & 0xFFFFFFF3) | 4; // Set CLK_M_DIVISOR to 2.
SYSCTR0(SYSCTR0_CNTFID0) = 19200000; // Set counter frequency.
TMR(TIMERUS_USEC_CFG) = 0x45F; // For 19.2MHz clk_m.
CLOCK(CLK_RST_CONTROLLER_OSC_CTRL) = 0x50000071; // Set OSC to 38.4MHz and drive strength.
PMC(APBDEV_PMC_OSC_EDPD_OVER) = (PMC(APBDEV_PMC_OSC_EDPD_OVER) & 0xFFFFFF81) | 0xE; // Set LP0 OSC drive strength.
PMC(APBDEV_PMC_OSC_EDPD_OVER) = (PMC(APBDEV_PMC_OSC_EDPD_OVER) & 0xFFBFFFFF) | PMC_OSC_EDPD_OVER_OSC_CTRL_OVER;
PMC(APBDEV_PMC_CNTRL2) = (PMC(APBDEV_PMC_CNTRL2) & 0xFFFFEFFF) | PMC_CNTRL2_HOLD_CKE_LOW_EN;
PMC(APBDEV_PMC_SCRATCH188) = (PMC(APBDEV_PMC_SCRATCH188) & 0xFCFFFFFF) | (4 << 23); // LP0 EMC2TMC_CFG_XM2COMP_PU_VREF_SEL_RANGE.
CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 0x10; // Set HCLK div to 2 and PCLK div to 1.
CLOCK(CLK_RST_CONTROLLER_PLLMB_BASE) &= 0xBFFFFFFF; // PLLMB disable.
PMC(APBDEV_PMC_TSC_MULT) = (PMC(APBDEV_PMC_TSC_MULT) & 0xFFFF0000) | 0x249F; //0x249F = 19200000 * (16 / 32.768 kHz)
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20004444;
CLOCK(CLK_RST_CONTROLLER_SUPER_SCLK_DIVIDER) = 0x80000000;
CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 2;
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SYS) = 0; // Set SCLK div to 1.
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20004444; // Set clk source to Run and PLLP_OUT2 (204MHz).
CLOCK(CLK_RST_CONTROLLER_SUPER_SCLK_DIVIDER) = 0x80000000; // Enable SUPER_SDIV to 1.
CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 2; // Set HCLK div to 1 and PCLK div to 3.
}
void _config_gpios()
@@ -64,17 +79,22 @@ void _config_gpios()
PINMUX_AUX(PINMUX_AUX_UART2_TX) = 0;
PINMUX_AUX(PINMUX_AUX_UART3_TX) = 0;
PINMUX_AUX(PINMUX_AUX_GPIO_PE6) = PINMUX_INPUT_ENABLE;
PINMUX_AUX(PINMUX_AUX_GPIO_PH6) = PINMUX_INPUT_ENABLE;
// Set Joy-Con IsAttached direction.
PINMUX_AUX(PINMUX_AUX_GPIO_PE6) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE;
PINMUX_AUX(PINMUX_AUX_GPIO_PH6) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE;
// Set pin mode for Joy-Con IsAttached and UARTB/C TX pins.
#if !defined (DEBUG_UART_PORT) || DEBUG_UART_PORT != UART_B
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_GPIO);
#endif
#if !defined (DEBUG_UART_PORT) || DEBUG_UART_PORT != UART_C
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_GPIO);
#endif
// Set Joy-Con IsAttached mode.
gpio_config(GPIO_PORT_E, GPIO_PIN_6, GPIO_MODE_GPIO);
gpio_config(GPIO_PORT_H, GPIO_PIN_6, GPIO_MODE_GPIO);
// Enable input logic for Joy-Con IsAttached and UARTB/C TX pins.
gpio_output_enable(GPIO_PORT_G, GPIO_PIN_0, GPIO_OUTPUT_DISABLE);
gpio_output_enable(GPIO_PORT_D, GPIO_PIN_1, GPIO_OUTPUT_DISABLE);
gpio_output_enable(GPIO_PORT_E, GPIO_PIN_6, GPIO_OUTPUT_DISABLE);
@@ -89,27 +109,36 @@ void _config_gpios()
gpio_config(GPIO_PORT_X, GPIO_PIN_7, GPIO_MODE_GPIO);
gpio_output_enable(GPIO_PORT_X, GPIO_PIN_6, GPIO_OUTPUT_DISABLE);
gpio_output_enable(GPIO_PORT_X, GPIO_PIN_7, GPIO_OUTPUT_DISABLE);
// Configure HOME as inputs.
// PINMUX_AUX(PINMUX_AUX_BUTTON_HOME) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE;
// gpio_config(GPIO_PORT_Y, GPIO_PIN_1, GPIO_MODE_GPIO);
}
void _config_pmc_scratch()
{
PMC(APBDEV_PMC_SCRATCH20) &= 0xFFF3FFFF;
PMC(APBDEV_PMC_SCRATCH190) &= 0xFFFFFFFE;
PMC(APBDEV_PMC_SECURE_SCRATCH21) |= 0x10;
PMC(APBDEV_PMC_SCRATCH20) &= 0xFFF3FFFF; // Unset Debug console from Customer Option.
PMC(APBDEV_PMC_SCRATCH190) &= 0xFFFFFFFE; // Unset DATA_DQ_E_IVREF EMC_PMACRO_DATA_PAD_TX_CTRL
PMC(APBDEV_PMC_SECURE_SCRATCH21) |= PMC_FUSE_PRIVATEKEYDISABLE_TZ_STICKY_BIT;
}
void _mbist_workaround()
{
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) |= (1 << 10); // Enable AHUB clock.
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) |= (1 << 6); // Enable APE clock.
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) |= (1 << 6); // Enable APE clock.
// Set mux output to SOR1 clock switch.
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) | 0x8000) & 0xFFFFBFFF;
CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) |= 0x40800000u;
CLOCK(CLK_RST_CONTROLLER_RST_DEV_Y_CLR) = 0x40;
CLOCK(CLK_RST_CONTROLLER_RST_DEV_X_CLR) = 0x40000;
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = 0x18000000;
// Enabled PLLD and set csi to PLLD for test pattern generation.
CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) |= 0x40800000;
// Clear per-clock resets.
CLOCK(CLK_RST_CONTROLLER_RST_DEV_Y_CLR) = 0x40; // Clear reset APE.
CLOCK(CLK_RST_CONTROLLER_RST_DEV_X_CLR) = 0x40000; // Clear reset VIC.
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = 0x18000000; // Clear reset DISP1, HOST1X.
usleep(2);
// I2S channels to master and disable SLCG.
I2S(I2S1_CTRL) |= I2S_CTRL_MASTER_EN;
I2S(I2S1_CG) &= ~I2S_CG_SLCG_ENABLE;
I2S(I2S2_CTRL) |= I2S_CTRL_MASTER_EN;
@@ -120,30 +149,39 @@ void _mbist_workaround()
I2S(I2S4_CG) &= ~I2S_CG_SLCG_ENABLE;
I2S(I2S5_CTRL) |= I2S_CTRL_MASTER_EN;
I2S(I2S5_CG) &= ~I2S_CG_SLCG_ENABLE;
DISPLAY_A(_DIREG(DC_COM_DSC_TOP_CTL)) |= 4;
DISPLAY_A(_DIREG(DC_COM_DSC_TOP_CTL)) |= 4; // DSC_SLCG_OVERRIDE.
VIC(0x8C) = 0xFFFFFFFF;
usleep(2);
CLOCK(CLK_RST_CONTROLLER_RST_DEV_Y_SET) = 0x40;
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = 0x18000000;
CLOCK(CLK_RST_CONTROLLER_RST_DEV_X_SET) = 0x40000;
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) = 0xC0;
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) = 0x80000130;
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_U) = 0x1F00200;
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) = 0x80400808;
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_W) = 0x402000FC;
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_X) = 0x23000780;
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) = 0x300;
// Set per-clock reset.
CLOCK(CLK_RST_CONTROLLER_RST_DEV_Y_SET) = 0x40; // Set reset APE.
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = 0x18000000; // Set reset DISP1, HOST1x.
CLOCK(CLK_RST_CONTROLLER_RST_DEV_X_SET) = 0x40000; // Set reset VIC.
// Enable specific clocks and disable all others.
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) = 0xC0; // Enable clock PMC, FUSE.
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) = 0x80000130; // Enable clock RTC, TMR, GPIO, BPMP_CACHE.
//CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) = 0x80400130; // Keep USBD ON.
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_U) = 0x1F00200; // Enable clock CSITE, IRAMA, IRAMB, IRAMC, IRAMD, BPMP_CACHE_RAM.
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) = 0x80400808; // Enable clock MSELECT, APB2APE, SPDIF_DOUBLER, SE.
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_W) = 0x402000FC; // Enable clock PCIERX0, PCIERX1, PCIERX2, PCIERX3, PCIERX4, PCIERX5, ENTROPY, MC1.
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_X) = 0x23000780; // Enable clock MC_CAPA, MC_CAPB, MC_CPU, MC_BBC, DBGAPB, HPLL_ADSP, PLLG_REF.
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) = 0x300; // Enable clock MC_CDPA, MC_CCPA.
// Disable clock gate overrides.
CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRA) = 0;
CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRB) = 0;
CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRC) = 0;
CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD) = 0;
CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRE) = 0;
CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) &= 0x1F7FFFFF;
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) &= 0xFFFF3FFF;
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI) & 0x1FFFFFFF) | 0x80000000;
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X) & 0x1FFFFFFF) | 0x80000000;
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_NVENC) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_NVENC) & 0x1FFFFFFF) | 0x80000000;
// Set child clock sources.
CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) &= 0x1F7FFFFF; // Disable PLLD and set reference clock and csi clock.
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) &= 0xFFFF3FFF; // Set SOR1 to automatic muxing of safe clock (24MHz) or SOR1 clk switch.
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI) & 0x1FFFFFFF) | 0x80000000; // Set clock source to PLLP_OUT.
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X) & 0x1FFFFFFF) | 0x80000000; // Set clock source to PLLP_OUT.
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_NVENC) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_NVENC) & 0x1FFFFFFF) | 0x80000000; // Set clock source to PLLP_OUT.
}
void _config_se_brom()
@@ -152,7 +190,7 @@ void _config_se_brom()
if (!(b_cfg.boot_cfg & BOOT_CFG_SEPT_RUN))
{
// Bootrom part we skipped.
u32 sbk[4] = {
u32 sbk[4] = {
FUSE(FUSE_PRIVATE_KEY0),
FUSE(FUSE_PRIVATE_KEY1),
FUSE(FUSE_PRIVATE_KEY2),
@@ -179,19 +217,67 @@ void _config_se_brom()
APB_MISC(APB_MISC_PP_STRAPPING_OPT_A) = (APB_MISC(APB_MISC_PP_STRAPPING_OPT_A) & 0xF0) | (7 << 10);
}
void _config_regulators()
{
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_CNFGBBC, MAX77620_CNFGBBC_RESISTOR_1K);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1,
(1 << 6) | (3 << MAX77620_ONOFFCNFG1_MRT_SHIFT)); // PWR delay for forced shutdown off.
// Configure all Flexible Power Sequencers.
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG0,
(7 << MAX77620_FPS_TIME_PERIOD_SHIFT));
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG1,
(7 << MAX77620_FPS_TIME_PERIOD_SHIFT) | (1 << MAX77620_FPS_EN_SRC_SHIFT));
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG2,
(7 << MAX77620_FPS_TIME_PERIOD_SHIFT));
max77620_regulator_config_fps(REGULATOR_LDO4);
max77620_regulator_config_fps(REGULATOR_LDO8);
max77620_regulator_config_fps(REGULATOR_SD0);
max77620_regulator_config_fps(REGULATOR_SD1);
max77620_regulator_config_fps(REGULATOR_SD3);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_GPIO3,
(4 << MAX77620_FPS_TIME_PERIOD_SHIFT) | (2 << MAX77620_FPS_PD_PERIOD_SHIFT)); // 3.x+
// Set vdd_core voltage to 1.125V.
max77620_regulator_set_voltage(REGULATOR_SD0, 1125000);
// Fix CPU/GPU after a L4T warmboot.
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO5, 2);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO6, 2);
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_REG, MAX77621_VOUT_0_95V); // Disable power.
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_DVC_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_1_09V); // Enable DVS power.
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL1_REG, MAX77621_RAMP_50mV_PER_US);
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL2_REG,
MAX77621_T_JUNCTION_120 | MAX77621_FT_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US_HIST_DIS |
MAX77621_CKKADV_TRIP_150mV_PER_US | MAX77621_INDUCTOR_NOMINAL);
i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_VOUT_REG, MAX77621_VOUT_0_95V); // Disable power.
i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_VOUT_DVC_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_1_09V); // Enable DVS power.
i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_CONTROL1_REG, MAX77621_RAMP_50mV_PER_US);
i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_CONTROL2_REG,
MAX77621_T_JUNCTION_120 | MAX77621_FT_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US_HIST_DIS |
MAX77621_CKKADV_TRIP_150mV_PER_US | MAX77621_INDUCTOR_NOMINAL);
// Enable low battery shutdown monitor for < 2800mV.
max77620_low_battery_monitor_config();
}
void config_hw()
{
// Bootrom stuff we skipped by going through rcm.
_config_se_brom();
//FUSE(FUSE_PRIVATEKEYDISABLE) = 0x11;
SYSREG(AHB_AHB_SPARE_REG) &= 0xFFFFFF9F;
PMC(APBDEV_PMC_SCRATCH49) = ((PMC(APBDEV_PMC_SCRATCH49) >> 1) << 1) & 0xFFFFFFFD;
SYSREG(AHB_AHB_SPARE_REG) &= 0xFFFFFF9F; // Unset APB2JTAG_OVERRIDE_EN and OBS_OVERRIDE_EN.
PMC(APBDEV_PMC_SCRATCH49) = PMC(APBDEV_PMC_SCRATCH49) & 0xFFFFFFFC;
_mbist_workaround();
clock_enable_se();
// Enable fuse clock.
clock_enable_fuse(true);
// Disable fuse programming.
fuse_disable_program();
@@ -216,37 +302,11 @@ void config_hw()
i2c_init(I2C_1);
i2c_init(I2C_5);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_CNFGBBC, MAX77620_CNFGBBC_RESISTOR_1K);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1,
(1 << 6) | (3 << MAX77620_ONOFFCNFG1_MRT_SHIFT)); // PWR delay for forced shutdown off.
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG0,
(7 << MAX77620_FPS_TIME_PERIOD_SHIFT));
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG1,
(7 << MAX77620_FPS_TIME_PERIOD_SHIFT) | (1 << MAX77620_FPS_EN_SRC_SHIFT));
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG2,
(7 << MAX77620_FPS_TIME_PERIOD_SHIFT));
max77620_regulator_config_fps(REGULATOR_LDO4);
max77620_regulator_config_fps(REGULATOR_LDO8);
max77620_regulator_config_fps(REGULATOR_SD0);
max77620_regulator_config_fps(REGULATOR_SD1);
max77620_regulator_config_fps(REGULATOR_SD3);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_GPIO3,
(4 << MAX77620_FPS_TIME_PERIOD_SHIFT) | (2 << MAX77620_FPS_PD_PERIOD_SHIFT)); // 3.x+
max77620_regulator_set_voltage(REGULATOR_SD0, 1125000);
// Fix GPU after warmboot for Linux.
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO5, 2);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO6, 2);
// Disable low battery shutdown monitor.
max77620_low_battery_monitor_config();
_config_regulators();
_config_pmc_scratch(); // Missing from 4.x+
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = (CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) & 0xFFFF8888) | 0x3333;
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003333; // Set SCLK to PLLP_OUT (408MHz).
sdram_init();
@@ -259,10 +319,11 @@ void reconfig_hw_workaround(bool extra_reconfig, u32 magic)
bpmp_mmu_disable();
bpmp_clk_rate_set(BPMP_CLK_NORMAL);
minerva_change_freq(FREQ_204);
nyx_str->mtc_cfg.init_done = 0;
// Re-enable clocks to Audio Processing Engine as a workaround to hanging.
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) |= (1 << 10); // Enable AHUB clock.
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) |= (1 << 6); // Enable APE clock.
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) |= (1 << 6); // Enable APE clock.
if (extra_reconfig)
{

View File

@@ -44,10 +44,10 @@ static int _i2c_send_pkt(u32 idx, u32 x, u8 *buf, u32 size)
memcpy(&tmp, buf, size);
vu32 *base = (vu32 *)i2c_addrs[idx];
base[I2C_CMD_ADDR0] = x << 1; //Set x (send mode).
base[I2C_CMD_DATA1] = tmp; //Set value.
base[I2C_CNFG] = (2 * size - 2) | 0x2800; //Set size and send mode.
_i2c_wait(base); //Kick transaction.
base[I2C_CMD_ADDR0] = x << 1; //Set x (send mode).
base[I2C_CMD_DATA1] = tmp; //Set value.
base[I2C_CNFG] = ((size - 1) << 1) | 0x2800; //Set size and send mode.
_i2c_wait(base); //Kick transaction.
base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFFDFF) | 0x200;
while (base[I2C_STATUS] & 0x100)
@@ -65,9 +65,9 @@ static int _i2c_recv_pkt(u32 idx, u8 *buf, u32 size, u32 x)
return 0;
vu32 *base = (vu32 *)i2c_addrs[idx];
base[I2C_CMD_ADDR0] = (x << 1) | 1; // Set x (recv mode).
base[I2C_CNFG] = (size - 1) << 1 | 0x2840; // Set size and recv mode.
_i2c_wait(base); // Kick transaction.
base[I2C_CMD_ADDR0] = (x << 1) | 1; // Set x (recv mode).
base[I2C_CNFG] = ((size - 1) << 1) | 0x2840; // Set size and recv mode.
_i2c_wait(base); // Kick transaction.
base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFFDFF) | 0x200;
while (base[I2C_STATUS] & 0x100)

View File

@@ -18,16 +18,28 @@
#include "../soc/clock.h"
#include "../soc/t210.h"
#pragma GCC push_options
#pragma GCC optimize ("Os")
int kfuse_wait_ready()
{
// Wait for KFUSE to finish init and verification of data.
while (!(KFUSE(KFUSE_STATE) & KFUSE_STATE_DONE))
;
if (!(KFUSE(KFUSE_STATE) & KFUSE_STATE_CRCPASS))
return 0;
return 1;
}
int kfuse_read(u32 *buf)
{
int res = 0;
clock_enable_kfuse();
while (!(KFUSE(KFUSE_STATE) & KFUSE_STATE_DONE))
;
if (!(KFUSE(KFUSE_STATE) & KFUSE_STATE_CRCPASS))
if (!kfuse_wait_ready())
goto out;
KFUSE(KFUSE_KEYADDR) = KFUSE_KEYADDR_AUTOINC;
@@ -40,3 +52,5 @@ out:;
clock_disable_kfuse();
return res;
}
#pragma GCC pop_options

View File

@@ -36,6 +36,7 @@
#define KFUSE_NUM_WORDS 144
int kfuse_wait_ready();
int kfuse_read(u32 *buf);
#endif

View File

@@ -40,19 +40,32 @@
#define PINMUX_AUX_SDMMC3_DAT3 0x30
#define PINMUX_AUX_SATA_LED_ACTIVE 0x4C
#define PINMUX_AUX_DMIC3_CLK 0xB4
#define PINMUX_AUX_DMIC3_DAT 0xB8
#define PINMUX_AUX_CAM_I2C_SCL 0xD4
#define PINMUX_AUX_CAM_I2C_SDA 0xD8
#define PINMUX_AUX_UART2_TX 0xF4
#define PINMUX_AUX_UART3_TX 0x104
#define PINMUX_AUX_DAP4_DIN 0x148
#define PINMUX_AUX_DAP4_SCLK 0x150
#define PINMUX_AUX_GPIO_X1_AUD 0x18C
#define PINMUX_AUX_GPIO_X3_AUD 0x190
#define PINMUX_AUX_SPDIF_IN 0x1A4
#define PINMUX_AUX_USB_VBUS_EN0 0x1A8
#define PINMUX_AUX_USB_VBUS_EN1 0x1AC
#define PINMUX_AUX_WIFI_EN 0x1B4
#define PINMUX_AUX_WIFI_RST 0x1B8
#define PINMUX_AUX_AP_WAKE_NFC 0x1CC
#define PINMUX_AUX_NFC_EN 0x1D0
#define PINMUX_AUX_NFC_INT 0x1D4
#define PINMUX_AUX_CAM1_PWDN 0x1EC
#define PINMUX_AUX_CAM2_PWDN 0x1F0
#define PINMUX_AUX_LCD_BL_PWM 0x1FC
#define PINMUX_AUX_LCD_BL_EN 0x200
#define PINMUX_AUX_LCD_RST 0x204
#define PINMUX_AUX_LCD_GPIO2 0x20C
#define PINMUX_AUX_TOUCH_INT 0x220
#define PINMUX_AUX_MOTION_INT 0x224
#define PINMUX_AUX_BUTTON_HOME 0x240
#define PINMUX_AUX_GPIO_PE6 0x248
#define PINMUX_AUX_GPIO_PH6 0x250
#define PINMUX_AUX_GPIO_PK3 0x260
@@ -84,7 +97,7 @@
#define PINMUX_OPEN_DRAIN (1 << 11)
#define PINMUX_SCHMT (1 << 12)
#define PINMUX_DRIVE_1X (0 << 13)
#define PINMUX_DRIVE_1X (0 << 13)
#define PINMUX_DRIVE_2X (1 << 13)
#define PINMUX_DRIVE_3X (2 << 13)
#define PINMUX_DRIVE_4X (3 << 13)

View File

@@ -25,6 +25,7 @@
#define APBDEV_PMC_PWRGATE_TOGGLE 0x30
#define APBDEV_PMC_PWRGATE_STATUS 0x38
#define APBDEV_PMC_NO_IOPOWER 0x44
#define PMC_NO_IOPOWER_SDMMC1_IO_EN (1 << 12)
#define APBDEV_PMC_SCRATCH0 0x50
#define APBDEV_PMC_SCRATCH1 0x54
#define APBDEV_PMC_SCRATCH20 0xA0
@@ -37,6 +38,7 @@
#define APBDEV_PMC_SCRATCH33 0x120
#define APBDEV_PMC_SCRATCH40 0x13C
#define APBDEV_PMC_OSC_EDPD_OVER 0x1A4
#define PMC_OSC_EDPD_OVER_OSC_CTRL_OVER 0x400000
#define APBDEV_PMC_RST_STATUS 0x1B4
#define APBDEV_PMC_IO_DPD_REQ 0x1B8
#define APBDEV_PMC_IO_DPD2_REQ 0x1C0
@@ -51,9 +53,11 @@
#define APBDEV_PMC_REG_SHORT 0x2CC
#define APBDEV_PMC_SEC_DISABLE3 0x2D8
#define APBDEV_PMC_SECURE_SCRATCH21 0x334
#define PMC_FUSE_PRIVATEKEYDISABLE_TZ_STICKY_BIT 0x10
#define APBDEV_PMC_SECURE_SCRATCH32 0x360
#define APBDEV_PMC_SECURE_SCRATCH49 0x3A4
#define APBDEV_PMC_CNTRL2 0x440
#define PMC_CNTRL2_HOLD_CKE_LOW_EN 0x1000
#define APBDEV_PMC_IO_DPD3_REQ 0x45C
#define APBDEV_PMC_IO_DPD4_REQ 0x464
#define APBDEV_PMC_UTMIP_PAD_CFG1 0x4C4

View File

@@ -106,7 +106,7 @@ bool smmu_is_used()
void smmu_exit()
{
*(uint32_t *)(smmu_payload + 0x14) = _NOP();
*(u32 *)(smmu_payload + 0x14) = _NOP();
}
u32 *smmu_init_domain4(u32 dev_base, u32 asid)

View File

@@ -101,15 +101,30 @@
#define CL_DVFS(off) _REG(CL_DVFS_BASE, off)
#define TEST_REG(off) _REG(0x0, off)
/* HOST1X registers. */
#define HOST1X_CH0_SYNC_BASE 0x2100
#define HOST1X_CH0_SYNC_SYNCPT_9 (HOST1X_CH0_SYNC_BASE + 0xFA4)
#define HOST1X_CH0_SYNC_SYNCPT_160 (HOST1X_CH0_SYNC_BASE + 0x1200)
/*! EVP registers. */
#define EVP_CPU_RESET_VECTOR 0x100
#define EVP_COP_RESET_VECTOR 0x200
#define EVP_COP_UNDEF_VECTOR 0x204
#define EVP_COP_SWI_VECTOR 0x208
#define EVP_COP_PREFETCH_ABORT_VECTOR 0x20C
#define EVP_COP_DATA_ABORT_VECTOR 0x210
#define EVP_COP_RSVD_VECTOR 0x214
#define EVP_COP_IRQ_VECTOR 0x218
#define EVP_COP_FIQ_VECTOR 0x21C
/*! Misc registers. */
#define APB_MISC_PP_STRAPPING_OPT_A 0x08
#define APB_MISC_PP_PINMUX_GLOBAL 0x40
#define APB_MISC_GP_HIDREV 0x804
#define APB_MISC_GP_LCD_BL_PWM_CFGPADCTRL 0xA34
#define APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL 0xA98
#define APB_MISC_GP_EMMC4_PAD_CFGPADCTRL 0xAB4
#define APB_MISC_GP_EMMC4_PAD_PUPD_CFGPADCTRL 0xABC
#define APB_MISC_GP_WIFI_EN_CFGPADCTRL 0xB64
#define APB_MISC_GP_WIFI_RST_CFGPADCTRL 0xB68
@@ -119,7 +134,10 @@
/*! Secure boot registers. */
#define SB_CSR 0x0
#define SB_CSR_NS_RST_VEC_WR_DIS (1 << 1)
#define SB_CSR_PIROM_DISABLE (1 << 4)
#define SB_AA64_RESET_LOW 0x30
#define SB_AA64_RST_AARCH64_MODE_EN (1 << 0)
#define SB_AA64_RESET_HIGH 0x34
/*! SOR registers. */
@@ -146,7 +164,7 @@
#define SYSCTR0_COUNTERID7 0xFDC
#define SYSCTR0_COUNTERID8 0xFF0
#define SYSCTR0_COUNTERID9 0xFF4
#define SYSCTR0_COUNTERID10 0xFF8
#define SYSCTR0_COUNTERID10 0xFF8
#define SYSCTR0_COUNTERID11 0xFFC
/*! TMR registers. */
@@ -183,10 +201,31 @@
/*! PWM registers. */
#define PWM_CONTROLLER_PWM_CSR_0 0x00
#define PWM_CONTROLLER_PWM_CSR_1 0x10
#define PWM_CSR_EN (1 << 31)
/*! Special registers. */
#define EMC_SCRATCH0 0x324
#define EMC_HEKA_UPD (1 << 30)
#define EMC_SEPT_RUN (1 << 31)
/*! Flow controller registers. */
#define FLOW_CTLR_HALT_COP_EVENTS 0x4
#define HALT_COP_SEC (1 << 23)
#define HALT_COP_MSEC (1 << 24)
#define HALT_COP_USEC (1 << 25)
#define HALT_COP_JTAG (1 << 28)
#define HALT_COP_WAIT_EVENT (1 << 30)
#define HALT_COP_WAIT_IRQ (1 << 31)
#define HALT_COP_MAX_CNT 0xFF
#define FLOW_CTLR_HALT_CPU0_EVENTS 0x0
#define FLOW_CTLR_HALT_CPU1_EVENTS 0x14
#define FLOW_CTLR_HALT_CPU2_EVENTS 0x1C
#define FLOW_CTLR_HALT_CPU3_EVENTS 0x24
#define FLOW_CTLR_CPU0_CSR 0x8
#define FLOW_CTLR_CPU1_CSR 0x18
#define FLOW_CTLR_CPU2_CSR 0x20
#define FLOW_CTLR_CPU3_CSR 0x28
#define FLOW_CTLR_RAM_REPAIR 0x40
#define FLOW_CTLR_BPMP_CLUSTER_CONTROL 0x98
#endif

View File

@@ -31,14 +31,21 @@ void uart_init(u32 idx, u32 baud)
// Misc settings.
u32 rate = (8 * baud + 408000000) / (16 * baud);
uart->UART_IER_DLAB = 0; // Disable interrupts.
uart->UART_MCR = 0; // Disable hardware flow control.
uart->UART_LCR = UART_LCR_DLAB | UART_LCR_WORD_LENGTH_8; // Enable DLAB & set 8n1 mode.
uart->UART_THR_DLAB = (u8)rate; // Divisor latch LSB.
uart->UART_IER_DLAB = (u8)(rate >> 8); // Divisor latch MSB.
uart->UART_LCR = UART_LCR_WORD_LENGTH_8; // Diable DLAB.
uart->UART_LCR = UART_LCR_WORD_LENGTH_8; // Disable DLAB.
(void)uart->UART_SPR;
// Setup and flush fifo.
uart->UART_IIR_FCR = UART_IIR_FCR_EN_FIFO | UART_IIR_FCR_RX_CLR | UART_IIR_FCR_TX_CLR;
uart->UART_IIR_FCR = UART_IIR_FCR_EN_FIFO;
(void)uart->UART_SPR;
usleep(20);
uart->UART_MCR = 0; // Disable hardware flow control.
usleep(96);
uart->UART_IIR_FCR = UART_IIR_FCR_EN_FIFO | UART_IIR_FCR_TX_CLR | UART_IIR_FCR_RX_CLR;
// Wait 3 symbols for baudrate change.
usleep(3 * ((baud + 999999) / baud));
uart_wait_idle(idx, UART_TX_IDLE | UART_RX_IDLE);
}
@@ -58,7 +65,7 @@ void uart_wait_idle(u32 idx, u32 which)
}
}
void uart_send(u32 idx, u8 *buf, u32 len)
void uart_send(u32 idx, const u8 *buf, u32 len)
{
uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]);
@@ -70,14 +77,91 @@ void uart_send(u32 idx, u8 *buf, u32 len)
};
}
void uart_recv(u32 idx, u8 *buf, u32 len)
u32 uart_recv(u32 idx, u8 *buf, u32 len)
{
uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]);
u32 timeout = get_tmr_us() + 1000;
u32 i;
for (i = 0; ; i++)
{
while (!(uart->UART_LSR & UART_LSR_RDR))
{
if (!len)
{
if (timeout < get_tmr_us())
break;
}
else if (len < i)
break;
}
if (timeout < get_tmr_us())
break;
buf[i] = uart->UART_THR_DLAB;
timeout = get_tmr_us() + 1000;
};
return i ? (len ? (i - 1) : i) : 0;
}
void uart_invert(u32 idx, bool enable, u32 invert_mask)
{
uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]);
for (u32 i = 0; i != len; i++)
{
while (!(uart->UART_LSR & UART_LSR_RDR))
;
buf[i] = uart->UART_THR_DLAB;
};
if (enable)
uart->UART_IRDA_CSR |= invert_mask;
else
uart->UART_IRDA_CSR &= ~invert_mask;
(void)uart->UART_SPR;
}
u32 uart_get_IIR(u32 idx)
{
uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]);
return uart->UART_IIR_FCR;
}
void uart_set_IIR(u32 idx)
{
uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]);
uart->UART_IER_DLAB &= ~UART_IER_DLAB_IE_EORD;
(void)uart->UART_SPR;
uart->UART_IER_DLAB |= UART_IER_DLAB_IE_EORD;
(void)uart->UART_SPR;
}
void uart_empty_fifo(u32 idx, u32 which)
{
uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]);
uart->UART_MCR = 0;
(void)uart->UART_SPR;
usleep(96);
uart->UART_IIR_FCR = UART_IIR_FCR_EN_FIFO | UART_IIR_FCR_TX_CLR | UART_IIR_FCR_RX_CLR;
(void)uart->UART_SPR;
usleep(18);
u32 tries = 0;
if (UART_IIR_FCR_TX_CLR & which)
{
while (tries < 10 && uart->UART_LSR & UART_LSR_TMTY)
{
tries++;
usleep(100);
}
tries = 0;
}
if (UART_IIR_FCR_RX_CLR & which)
{
while (tries < 10 && !uart->UART_LSR & UART_LSR_RDR)
{
tries++;
usleep(100);
}
}
}

View File

@@ -22,9 +22,8 @@
#define UART_A 0
#define UART_B 1
#define UART_C 2
//TODO: define clock inits for those.
/*#define UART_D 3
#define UART_E 4*/
#define UART_D 3
#define UART_E 4
#define BAUD_115200 115200
@@ -34,15 +33,29 @@
#define UART_TX_FIFO_FULL 0x100
#define UART_RX_FIFO_EMPTY 0x200
#define UART_INVERT_RXD 0x01
#define UART_INVERT_TXD 0x02
#define UART_INVERT_CTS 0x04
#define UART_INVERT_RTS 0x08
#define UART_IER_DLAB_IE_EORD 0x20
#define UART_LCR_DLAB 0x80
#define UART_LCR_STOP 0x4
#define UART_LCR_WORD_LENGTH_8 0x3
#define UART_LSR_RDR 0x1
#define UART_LSR_THRE 0x20
#define UART_LSR_TMTY 0x40
#define UART_LSR_FIFOE 0x80
#define UART_IIR_FCR_TX_CLR 0x4
#define UART_IIR_FCR_RX_CLR 0x2
#define UART_IIR_FCR_EN_FIFO 0x1
#define UART_MCR_RTS 0x2
#define UART_MCR_DTR 0x1
typedef struct _uart_t
{
/* 0x00 */ vu32 UART_THR_DLAB;
@@ -63,7 +76,11 @@ typedef struct _uart_t
void uart_init(u32 idx, u32 baud);
void uart_wait_idle(u32 idx, u32 which);
void uart_send(u32 idx, u8 *buf, u32 len);
void uart_recv(u32 idx, u8 *buf, u32 len);
void uart_send(u32 idx, const u8 *buf, u32 len);
u32 uart_recv(u32 idx, u8 *buf, u32 len);
void uart_invert(u32 idx, bool enable, u32 invert_mask);
u32 uart_get_IIR(u32 idx);
void uart_set_IIR(u32 idx);
void uart_empty_fifo(u32 idx, u32 which);
#endif

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 CTCaer
* Copyright (c) 2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -92,18 +92,14 @@ static int emummc_raw_get_part_off(int part_idx)
return 2;
}
int emummc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc)
{
FILINFO fno;
if (!sdmmc_storage_init_mmc(storage, sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
{
EPRINTF("Failed to init eMMC.");
return 2;
goto out;
}
if (h_cfg.emummc_force_disable)
return 1;
return 0;
emu_cfg.active_part = 0;
if (!sd_mount())
@@ -116,8 +112,7 @@ int emummc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc)
if (f_stat(emu_cfg.emummc_file_based_path, &fno))
{
gfx_printf("e1\n");
gfx_printf(" %X\n ", emu_cfg.sector);
EPRINTF("Failed to open eMMC folder.");
goto out;
}
f_chmod(emu_cfg.emummc_file_based_path, AM_ARC, AM_ARC);
@@ -125,15 +120,16 @@ int emummc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc)
strcat(emu_cfg.emummc_file_based_path, "/00");
if (f_stat(emu_cfg.emummc_file_based_path, &fno))
{
gfx_printf("e2\n");
EPRINTF("Failed to open emuMMC rawnand.");
goto out;
}
emu_cfg.file_based_part_size = fno.fsize >> 9;
}
return 1;
return 0;
out:
return 0;
return 1;
}
int emummc_storage_end(sdmmc_storage_t *storage)
@@ -171,17 +167,17 @@ int emummc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, v
}
if (f_open(&fp, emu_cfg.emummc_file_based_path, FA_READ))
{
gfx_printf("e3\n");
EPRINTF("Failed to open emuMMC image.");
return 0;
}
f_lseek(&fp, (u64)sector << 9);
if (f_read(&fp, buf, (u64)num_sectors << 9, NULL))
{
gfx_printf("e4\n");
EPRINTF("Failed to read emuMMC image.");
f_close(&fp);
return 0;
}
f_close(&fp);
return 1;
}
@@ -226,7 +222,7 @@ int emummc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors,
f_close(&fp);
return 0;
}
f_close(&fp);
return 1;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 CTCaer
* Copyright (c) 2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -35,7 +35,7 @@ typedef enum {
typedef struct _emummc_cfg_t
{
int enabled;
int enabled;
u64 sector;
u16 id;
char *path;

View File

@@ -31,7 +31,7 @@
#define MMC_ALL_SEND_CID 2 /* bcr R2 */
#define MMC_SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */
#define MMC_SET_DSR 4 /* bc [31:16] RCA */
#define MMC_SLEEP_AWAKE 5 /* ac [31:16] RCA 15:flg R1b */
#define MMC_SLEEP_AWAKE 5 /* ac [31:16] RCA 15:flg R1b */
#define MMC_SWITCH 6 /* ac [31:0] See below R1b */
#define MMC_SELECT_CARD 7 /* ac [31:16] RCA R1 */
#define MMC_SEND_EXT_CSD 8 /* adtc R1 */
@@ -51,7 +51,7 @@
#define MMC_READ_SINGLE_BLOCK 17 /* adtc [31:0] data addr R1 */
#define MMC_READ_MULTIPLE_BLOCK 18 /* adtc [31:0] data addr R1 */
#define MMC_SEND_TUNING_BLOCK 19 /* adtc R1 */
#define MMC_SEND_TUNING_BLOCK_HS200 21 /* adtc R1 */
#define MMC_SEND_TUNING_BLOCK_HS200 21 /* adtc R1 */
/* class 3 */
#define MMC_WRITE_DAT_UNTIL_STOP 20 /* adtc [31:0] data addr R1 */

View File

@@ -36,7 +36,7 @@ void nx_emmc_gpt_parse(link_t *gpt, sdmmc_storage_t *storage)
part->lba_end = ent->lba_end;
part->attrs = ent->attrs;
//HACK
// ASCII conversion. Copy only the LSByte of the UTF-16LE name.
for (u32 i = 0; i < 36; i++)
part->name[i] = ent->name[i];
part->name[36] = 0;

View File

@@ -1,8 +1,8 @@
/*
* include/linux/mmc/sd.h
*
* Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
* Copyright (C) 2018 CTCaer
* Copyright (c) 2005-2007 Pierre Ossman, All Rights Reserved.
* Copyright (c) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -40,7 +40,9 @@
#define SD_ROCR_S18A SD_OCR_S18R /* 1.8V switching accepted by card */
#define SD_OCR_XPC (1 << 28) /* SDXC power control */
#define SD_OCR_CCS (1 << 30) /* Card Capacity Status */
#define SD_OCR_VDD_27_34 (0x7F << 15) /* VDD voltage 2.7 ~ 3.4 */
#define SD_OCR_VDD_32_33 (1 << 20) /* VDD voltage 3.2 ~ 3.3 */
#define SD_OCR_VDD_18 (1 << 7) /* VDD voltage 1.8 */
/*
* SD_SWITCH argument format:

View File

@@ -1,6 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (C) 2018 CTCaer
* Copyright (c) 2018-2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -19,7 +19,7 @@
#include "sdmmc.h"
#include "mmc.h"
#include "sd.h"
#include "../config/config.h"
#include "../../common/memory_map.h"
#include "../gfx/gfx.h"
#include "../mem/heap.h"
#include "../utils/util.h"
@@ -27,8 +27,6 @@
//#define DPRINTF(...) gfx_printf(__VA_ARGS__)
#define DPRINTF(...)
extern hekate_config h_cfg;
static inline u32 unstuff_bits(u32 *resp, u32 start, u32 size)
{
const u32 mask = (size < 32 ? 1 << size : 0) - 1;
@@ -72,6 +70,7 @@ static int _sdmmc_storage_execute_cmd_type1_ex(sdmmc_storage_t *storage, u32 *re
if (_sdmmc_storage_check_result(*resp))
if (expected_state == 0x10 || R1_CURRENT_STATE(*resp) == expected_state)
return 1;
return 0;
}
@@ -85,6 +84,7 @@ static int _sdmmc_storage_go_idle_state(sdmmc_storage_t *storage)
{
sdmmc_cmd_t cmd;
sdmmc_init_cmd(&cmd, MMC_GO_IDLE_STATE, 0, SDMMC_RSP_TYPE_0, 0);
return sdmmc_execute_cmd(storage->sdmmc, &cmd, 0, 0);
}
@@ -94,7 +94,9 @@ static int _sdmmc_storage_get_cid(sdmmc_storage_t *storage, void *buf)
sdmmc_init_cmd(&cmd, MMC_ALL_SEND_CID, 0, SDMMC_RSP_TYPE_2, 0);
if (!sdmmc_execute_cmd(storage->sdmmc, &cmd, 0, 0))
return 0;
sdmmc_get_rsp(storage->sdmmc, buf, 0x10, SDMMC_RSP_TYPE_2);
return 1;
}
@@ -109,7 +111,9 @@ static int _sdmmc_storage_get_csd(sdmmc_storage_t *storage, void *buf)
sdmmc_init_cmd(&cmdbuf, MMC_SEND_CSD, storage->rca << 16, SDMMC_RSP_TYPE_2, 0);
if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, 0, 0))
return 0;
sdmmc_get_rsp(storage->sdmmc, buf, 0x10, SDMMC_RSP_TYPE_2);
return 1;
}
@@ -147,8 +151,10 @@ static int _sdmmc_storage_readwrite_ex(sdmmc_storage_t *storage, u32 *blkcnt_out
u32 tmp = 0;
sdmmc_stop_transmission(storage->sdmmc, &tmp);
_sdmmc_storage_get_status(storage, &tmp, 0);
return 0;
}
return 1;
}
@@ -156,7 +162,9 @@ int sdmmc_storage_end(sdmmc_storage_t *storage)
{
if (!_sdmmc_storage_go_idle_state(storage))
return 0;
sdmmc_end(storage->sdmmc);
return 1;
}
@@ -178,14 +186,16 @@ static int _sdmmc_storage_readwrite(sdmmc_storage_t *storage, u32 sector, u32 nu
msleep(100);
} while (retries);
return 0;
out:;
DPRINTF("readwrite: %08X\n", blkcnt);
DPRINTF("readwrite: %08X\n", blkcnt);
sector += blkcnt;
num_sectors -= blkcnt;
bbuf += 512 * blkcnt;
}
return 1;
}
@@ -211,10 +221,10 @@ static int _mmc_storage_get_op_cond_inner(sdmmc_storage_t *storage, u32 *pout, u
switch (power)
{
case SDMMC_POWER_1_8:
arg = 0x40000080; //Sector access, voltage.
arg = SD_OCR_CCS | SD_OCR_VDD_18;
break;
case SDMMC_POWER_3_3:
arg = 0x403F8000; //Sector access, voltage.
arg = SD_OCR_CCS | SD_OCR_VDD_27_34;
break;
default:
return 0;
@@ -236,14 +246,17 @@ static int _mmc_storage_get_op_cond(sdmmc_storage_t *storage, u32 power)
u32 cond = 0;
if (!_mmc_storage_get_op_cond_inner(storage, &cond, power))
break;
if (cond & MMC_CARD_BUSY)
{
if (cond & 0x40000000)
if (cond & SD_OCR_CCS)
storage->has_sector_access = 1;
return 1;
}
if (get_tmr_ms() > timeout)
break;
usleep(1000);
}
@@ -373,6 +386,7 @@ static int _mmc_storage_switch_buswidth(sdmmc_storage_t *storage, u32 bus_width)
if (_sdmmc_storage_check_status(storage))
{
sdmmc_set_bus_width(storage->sdmmc, bus_width);
return 1;
}
@@ -383,14 +397,19 @@ static int _mmc_storage_enable_HS(sdmmc_storage_t *storage, int check)
{
if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS)))
return 0;
if (check && !_sdmmc_storage_check_status(storage))
return 0;
if (!sdmmc_setup_clock(storage->sdmmc, 2))
return 0;
DPRINTF("[MMC] switched to HS\n");
DPRINTF("[MMC] switched to HS\n");
storage->csd.busspeed = 52;
if (check || _sdmmc_storage_check_status(storage))
return 1;
return 0;
}
@@ -398,12 +417,16 @@ static int _mmc_storage_enable_HS200(sdmmc_storage_t *storage)
{
if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200)))
return 0;
if (!sdmmc_setup_clock(storage->sdmmc, 3))
return 0;
if (!sdmmc_config_tuning(storage->sdmmc, 3, MMC_SEND_TUNING_BLOCK_HS200))
return 0;
DPRINTF("[MMC] switched to HS200\n");
DPRINTF("[MMC] switched to HS200\n");
storage->csd.busspeed = 200;
return _sdmmc_storage_check_status(storage);
}
@@ -411,17 +434,24 @@ static int _mmc_storage_enable_HS400(sdmmc_storage_t *storage)
{
if (!_mmc_storage_enable_HS200(storage))
return 0;
sdmmc_get_venclkctl(storage->sdmmc);
if (!_mmc_storage_enable_HS(storage, 0))
return 0;
if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_BUS_WIDTH, EXT_CSD_DDR_BUS_WIDTH_8)))
return 0;
if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400)))
return 0;
if (!sdmmc_setup_clock(storage->sdmmc, 4))
return 0;
DPRINTF("[MMC] switched to HS400\n");
DPRINTF("[MMC] switched to HS400\n");
storage->csd.busspeed = 400;
return _sdmmc_storage_check_status(storage);
}
@@ -433,8 +463,7 @@ static int _mmc_storage_enable_highspeed(sdmmc_storage_t *storage, u32 card_type
goto out;
if (sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_8 &&
card_type & EXT_CSD_CARD_TYPE_HS400_1_8V &&
type == 4)
card_type & EXT_CSD_CARD_TYPE_HS400_1_8V && type == 4)
return _mmc_storage_enable_HS400(storage);
if (sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_8 ||
@@ -446,6 +475,7 @@ static int _mmc_storage_enable_highspeed(sdmmc_storage_t *storage, u32 card_type
out:;
if (card_type & EXT_CSD_CARD_TYPE_HS_52)
return _mmc_storage_enable_HS(storage, 1);
return 1;
}
@@ -453,6 +483,7 @@ static int _mmc_storage_enable_bkops(sdmmc_storage_t *storage)
{
if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_SET_BITS, EXT_CSD_BKOPS_EN, EXT_CSD_BKOPS_LEVEL_2)))
return 0;
return _sdmmc_storage_check_status(storage);
}
@@ -464,42 +495,42 @@ int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
if (!sdmmc_init(sdmmc, id, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_1, 0, 0))
return 0;
DPRINTF("[MMC] after init\n");
DPRINTF("[MMC] after init\n");
usleep(1000 + (74000 + sdmmc->divisor - 1) / sdmmc->divisor);
if (!_sdmmc_storage_go_idle_state(storage))
return 0;
DPRINTF("[MMC] went to idle state\n");
DPRINTF("[MMC] went to idle state\n");
if (!_mmc_storage_get_op_cond(storage, SDMMC_POWER_1_8))
return 0;
DPRINTF("[MMC] got op cond\n");
DPRINTF("[MMC] got op cond\n");
if (!_sdmmc_storage_get_cid(storage, storage->raw_cid))
return 0;
DPRINTF("[MMC] got cid\n");
DPRINTF("[MMC] got cid\n");
if (!_mmc_storage_set_relative_addr(storage))
return 0;
DPRINTF("[MMC] set relative addr\n");
DPRINTF("[MMC] set relative addr\n");
if (!_sdmmc_storage_get_csd(storage, storage->raw_csd))
return 0;
DPRINTF("[MMC] got csd\n");
DPRINTF("[MMC] got csd\n");
_mmc_storage_parse_csd(storage);
if (!sdmmc_setup_clock(storage->sdmmc, 1))
return 0;
DPRINTF("[MMC] after setup clock\n");
DPRINTF("[MMC] after setup clock\n");
if (!_sdmmc_storage_select_card(storage))
return 0;
DPRINTF("[MMC] card selected\n");
DPRINTF("[MMC] card selected\n");
if (!_sdmmc_storage_set_blocklen(storage, 512))
return 0;
DPRINTF("[MMC] set blocklen to 512\n");
DPRINTF("[MMC] set blocklen to 512\n");
u32 *csd = (u32 *)storage->raw_csd;
//Check system specification version, only version 4.0 and later support below features.
@@ -511,7 +542,7 @@ int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
if (!_mmc_storage_switch_buswidth(storage, bus_width))
return 0;
DPRINTF("[MMC] switched buswidth\n");
DPRINTF("[MMC] switched buswidth\n");
u8 *ext_csd = (u8 *)malloc(512);
if (!_mmc_storage_get_ext_csd(storage, ext_csd))
@@ -520,7 +551,7 @@ int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
return 0;
}
free(ext_csd);
DPRINTF("[MMC] got ext_csd\n");
DPRINTF("[MMC] got ext_csd\n");
_mmc_storage_parse_cid(storage); //This needs to be after csd and ext_csd
//gfx_hexdump(0, ext_csd, 512);
@@ -530,16 +561,16 @@ int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
if (storage->ext_csd.bkops & 0x1 && !(storage->ext_csd.bkops_en & EXT_CSD_BKOPS_LEVEL_2) && 0)
{
_mmc_storage_enable_bkops(storage);
DPRINTF("[MMC] BKOPS enabled\n");
DPRINTF("[MMC] BKOPS enabled\n");
}
else
{
DPRINTF("[MMC] BKOPS disabled\n");
DPRINTF("[MMC] BKOPS disabled\n");
}
if (!_mmc_storage_enable_highspeed(storage, storage->ext_csd.card_type, type))
return 0;
DPRINTF("[MMC] succesfully switched to highspeed mode\n");
DPRINTF("[MMC] succesfully switched to HS mode\n");
sdmmc_sd_clock_ctrl(storage->sdmmc, 1);
@@ -550,8 +581,10 @@ int sdmmc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition)
{
if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_PART_CONFIG, partition)))
return 0;
if (!_sdmmc_storage_check_status(storage))
return 0;
storage->partition = partition;
return 1;
}
@@ -565,6 +598,7 @@ static int _sd_storage_execute_app_cmd(sdmmc_storage_t *storage, u32 expected_st
u32 tmp;
if (!_sdmmc_storage_execute_cmd_type1_ex(storage, &tmp, MMC_APP_CMD, storage->rca << 16, 0, expected_state, mask))
return 0;
return sdmmc_execute_cmd(storage->sdmmc, cmd, req, blkcnt_out);
}
@@ -572,6 +606,7 @@ static int _sd_storage_execute_app_cmd_type1(sdmmc_storage_t *storage, u32 *resp
{
if (!_sdmmc_storage_execute_cmd_type1(storage, MMC_APP_CMD, storage->rca << 16, 0, R1_STATE_TRAN))
return 0;
return _sdmmc_storage_execute_cmd_type1_ex(storage, resp, cmd, arg, check_busy, expected_state, 0);
}
@@ -603,6 +638,7 @@ static int _sd_storage_get_op_cond_once(sdmmc_storage_t *storage, u32 *cond, int
sdmmc_init_cmd(&cmdbuf, SD_APP_OP_COND, arg, SDMMC_RSP_TYPE_3, 0);
if (!_sd_storage_execute_app_cmd(storage, 0x10, is_version_1 ? 0x400000 : 0, &cmdbuf, 0, 0))
return 0;
return sdmmc_get_rsp(storage->sdmmc, cond, 4, SDMMC_RSP_TYPE_3);
}
@@ -630,7 +666,7 @@ static int _sd_storage_get_op_cond(sdmmc_storage_t *storage, int is_version_1, i
return 0;
storage->is_low_voltage = 1;
DPRINTF("-> switched to low voltage\n");
DPRINTF("-> switched to low voltage\n");
}
}
@@ -784,17 +820,17 @@ void _sd_storage_set_current_limit(sdmmc_storage_t *storage, u8 *buf)
switch (pwr)
{
case SD_SET_CURRENT_LIMIT_800:
DPRINTF("[SD] Power limit raised to 800mA\n");
DPRINTF("[SD] power limit raised to 800mA\n");
break;
case SD_SET_CURRENT_LIMIT_600:
DPRINTF("[SD] Power limit raised to 600mA\n");
DPRINTF("[SD] power limit raised to 600mA\n");
break;
case SD_SET_CURRENT_LIMIT_400:
DPRINTF("[SD] Power limit raised to 800mA\n");
DPRINTF("[SD] power limit raised to 800mA\n");
break;
default:
case SD_SET_CURRENT_LIMIT_200:
DPRINTF("[SD] Power limit defaulted to 200mA\n");
DPRINTF("[SD] power limit defaulted to 200mA\n");
break;
}
}
@@ -803,10 +839,12 @@ int _sd_storage_enable_highspeed(sdmmc_storage_t *storage, u32 hs_type, u8 *buf)
{
if (!_sd_storage_switch(storage, buf, SD_SWITCH_CHECK, 0, hs_type))
return 0;
DPRINTF("[SD] SD supports switch to (U)HS check\n");
u32 type_out = buf[16] & 0xF;
if (type_out != hs_type)
return 0;
DPRINTF("[SD] SD supports selected (U)HS mode\n");
if ((((u16)buf[0] << 8) | buf[1]) < 0x320)
{
@@ -820,7 +858,7 @@ int _sd_storage_enable_highspeed(sdmmc_storage_t *storage, u32 hs_type, u8 *buf)
return 1;
}
int _sd_storage_enable_highspeed_low_volt(sdmmc_storage_t *storage, u32 type, u8 *buf)
int _sd_storage_enable_uhs_low_volt(sdmmc_storage_t *storage, u32 type, u8 *buf)
{
// Try to raise the current limit to let the card perform better.
_sd_storage_set_current_limit(storage, buf);
@@ -835,31 +873,31 @@ int _sd_storage_enable_highspeed_low_volt(sdmmc_storage_t *storage, u32 type, u8
u32 hs_type = 0;
switch (type)
{
case 11:
case 11: // SDR104.
// Fall through if not supported.
if (buf[13] & SD_MODE_UHS_SDR104)
{
type = 11;
hs_type = UHS_SDR104_BUS_SPEED;
DPRINTF("[SD] Bus speed set to SDR104\n");
DPRINTF("[SD] bus speed set to SDR104\n");
storage->csd.busspeed = 104;
break;
}
case 10:
case 10: // SDR50.
if (buf[13] & SD_MODE_UHS_SDR50)
{
type = 10;
hs_type = UHS_SDR50_BUS_SPEED;
DPRINTF("[SD] Bus speed set to SDR50\n");
DPRINTF("[SD] bus speed set to SDR50\n");
storage->csd.busspeed = 50;
break;
}
case 8:
case 8: // SDR12.
if (!(buf[13] & SD_MODE_UHS_SDR12))
return 0;
type = 8;
hs_type = UHS_SDR12_BUS_SPEED;
DPRINTF("[SD] Bus speed set to SDR12\n");
DPRINTF("[SD] bus speed set to SDR12\n");
storage->csd.busspeed = 12;
break;
default:
@@ -869,14 +907,17 @@ int _sd_storage_enable_highspeed_low_volt(sdmmc_storage_t *storage, u32 type, u8
if (!_sd_storage_enable_highspeed(storage, hs_type, buf))
return 0;
DPRINTF("[SD] SD card accepted UHS\n");
if (!sdmmc_setup_clock(storage->sdmmc, type))
return 0;
DPRINTF("[SD] setup clock\n");
if (!sdmmc_config_tuning(storage->sdmmc, type, MMC_SEND_TUNING_BLOCK))
return 0;
DPRINTF("[SD] config tuning\n");
return _sdmmc_storage_check_status(storage);
}
int _sd_storage_enable_highspeed_high_volt(sdmmc_storage_t *storage, u8 *buf)
int _sd_storage_enable_hs_high_volt(sdmmc_storage_t *storage, u8 *buf)
{
if (!_sd_storage_switch_get(storage, buf))
return 0;
@@ -886,8 +927,10 @@ int _sd_storage_enable_highspeed_high_volt(sdmmc_storage_t *storage, u8 *buf)
if (!_sd_storage_enable_highspeed(storage, 1, buf))
return 0;
if (!_sdmmc_storage_check_status(storage))
return 0;
return sdmmc_setup_clock(storage->sdmmc, 7);
}
@@ -950,7 +993,7 @@ static int _sd_storage_get_ssr(sdmmc_storage_t *storage, u8 *buf)
if (!(storage->csd.cmdclass & CCC_APP_SPEC))
{
DPRINTF("[SD] ssr: Card lacks mandatory SD Status function\n");
DPRINTF("[SD] ssr: Card lacks mandatory SD Status function\n");
return 0;
}
@@ -1012,49 +1055,55 @@ static void _sd_storage_parse_csd(sdmmc_storage_t *storage)
}
}
void sdmmc_storage_init_wait_sd()
{
u32 sd_poweroff_time = (u32)get_tmr_ms() - sd_power_cycle_time_start;
if (sd_poweroff_time < 100)
msleep(100 - sd_poweroff_time);
}
int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type)
{
int is_version_1 = 0;
// Some cards (Sandisk U1), do not like a fast power cycle. Wait min 100ms.
u32 sd_poweroff_time = (u32)get_tmr_ms() - h_cfg.sd_timeoff;
if (id == SDMMC_1 && (sd_poweroff_time < 100))
msleep(100 - sd_poweroff_time);
u8 *buf = (u8 *)SDMMC_UPPER_BUFFER;
// Some cards (SanDisk U1), do not like a fast power cycle. Wait min 100ms.
sdmmc_storage_init_wait_sd();
memset(storage, 0, sizeof(sdmmc_storage_t));
storage->sdmmc = sdmmc;
if (!sdmmc_init(sdmmc, id, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, 5, 0))
return 0;
DPRINTF("[SD] after init\n");
DPRINTF("[SD] after init\n");
usleep(1000 + (74000 + sdmmc->divisor - 1) / sdmmc->divisor);
if (!_sdmmc_storage_go_idle_state(storage))
return 0;
DPRINTF("[SD] went to idle state\n");
DPRINTF("[SD] went to idle state\n");
is_version_1 = _sd_storage_send_if_cond(storage);
if (is_version_1 == 2)
return 0;
DPRINTF("[SD] after send if cond\n");
DPRINTF("[SD] after send if cond\n");
if (!_sd_storage_get_op_cond(storage, is_version_1, bus_width == SDMMC_BUS_WIDTH_4 && type == 11))
return 0;
DPRINTF("[SD] got op cond\n");
DPRINTF("[SD] got op cond\n");
if (!_sdmmc_storage_get_cid(storage, storage->raw_cid))
return 0;
DPRINTF("[SD] got cid\n");
DPRINTF("[SD] got cid\n");
_sd_storage_parse_cid(storage);
if (!_sd_storage_get_rca(storage))
return 0;
DPRINTF("[SD] got rca (= %04X)\n", storage->rca);
DPRINTF("[SD] got rca (= %04X)\n", storage->rca);
if (!_sdmmc_storage_get_csd(storage, storage->raw_csd))
return 0;
DPRINTF("[SD] got csd\n");
DPRINTF("[SD] got csd\n");
//Parse CSD.
_sd_storage_parse_csd(storage);
@@ -1067,7 +1116,7 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
storage->sec_cnt = storage->csd.c_size << 10;
break;
default:
DPRINTF("[SD] Unknown CSD structure %d\n", storage->csd.structure);
DPRINTF("[SD] unknown CSD structure %d\n", storage->csd.structure);
break;
}
@@ -1075,65 +1124,54 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
{
if (!sdmmc_setup_clock(storage->sdmmc, 6))
return 0;
DPRINTF("[SD] after setup clock\n");
DPRINTF("[SD] after setup clock\n");
}
if (!_sdmmc_storage_select_card(storage))
return 0;
DPRINTF("[SD] card selected\n");
DPRINTF("[SD] card selected\n");
if (!_sdmmc_storage_set_blocklen(storage, 512))
return 0;
DPRINTF("[SD] set blocklen to 512\n");
DPRINTF("[SD] set blocklen to 512\n");
u32 tmp = 0;
if (!_sd_storage_execute_app_cmd_type1(storage, &tmp, SD_APP_SET_CLR_CARD_DETECT, 0, 0, R1_STATE_TRAN))
return 0;
DPRINTF("[SD] cleared card detect\n");
DPRINTF("[SD] cleared card detect\n");
u8 *buf = (u8 *)malloc(512);
if (!_sd_storage_get_scr(storage, buf))
{
free(buf);
return 0;
}
//gfx_hexdump(0, storage->raw_scr, 8);
DPRINTF("[SD] got scr\n");
DPRINTF("[SD] got scr\n");
// Check if card supports a wider bus and if it's not SD Version 1.X
if (bus_width == SDMMC_BUS_WIDTH_4 && (storage->scr.bus_widths & 4) && (storage->scr.sda_vsn & 0xF))
{
if (!_sd_storage_execute_app_cmd_type1(storage, &tmp, SD_APP_SET_BUS_WIDTH, SD_BUS_WIDTH_4, 0, R1_STATE_TRAN))
{
free(buf);
return 0;
}
sdmmc_set_bus_width(storage->sdmmc, SDMMC_BUS_WIDTH_4);
DPRINTF("[SD] switched to wide bus width\n");
DPRINTF("[SD] switched to wide bus width\n");
}
else
{
DPRINTF("[SD] SD does not support wide bus width\n");
DPRINTF("[SD] SD does not support wide bus width\n");
}
if (storage->is_low_voltage)
{
if (!_sd_storage_enable_highspeed_low_volt(storage, type, buf))
{
free(buf);
if (!_sd_storage_enable_uhs_low_volt(storage, type, buf))
return 0;
}
DPRINTF("[SD] enabled highspeed (low voltage)\n");
DPRINTF("[SD] enabled UHS\n");
}
else if (type != 6 && (storage->scr.sda_vsn & 0xF) != 0)
{
if (!_sd_storage_enable_highspeed_high_volt(storage, buf))
{
free(buf);
if (!_sd_storage_enable_hs_high_volt(storage, buf))
return 0;
}
DPRINTF("[SD] enabled highspeed (high voltage)\n");
DPRINTF("[SD] enabled HS\n");
storage->csd.busspeed = 25;
}
@@ -1142,10 +1180,9 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
// Parse additional card info from sd status.
if (_sd_storage_get_ssr(storage, buf))
{
DPRINTF("[SD] got sd status\n");
DPRINTF("[SD] got sd status\n");
}
free(buf);
return 1;
}
@@ -1187,13 +1224,13 @@ int sdmmc_storage_init_gc(sdmmc_storage_t *storage, sdmmc_t *sdmmc)
if (!sdmmc_init(sdmmc, SDMMC_2, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_8, 14, 0))
return 0;
DPRINTF("[gc] after init\n");
DPRINTF("[gc] after init\n");
usleep(1000 + (10000 + sdmmc->divisor - 1) / sdmmc->divisor);
if (!sdmmc_config_tuning(storage->sdmmc, 14, MMC_SEND_TUNING_BLOCK_HS200))
return 0;
DPRINTF("[gc] after tuning\n");
DPRINTF("[gc] after tuning\n");
sdmmc_sd_clock_ctrl(sdmmc, 1);

View File

@@ -1,6 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (C) 2018 CTCaer
* Copyright (c) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -21,6 +21,8 @@
#include "../utils/types.h"
#include "sdmmc_driver.h"
u32 sd_power_cycle_time_start;
typedef struct _mmc_cid
{
u32 manfid;
@@ -107,6 +109,7 @@ int sdmmc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, vo
int sdmmc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf);
int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type);
int sdmmc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition);
void sdmmc_storage_init_wait_sd();
int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type);
int sdmmc_storage_init_gc(sdmmc_storage_t *storage, sdmmc_t *sdmmc);

View File

@@ -19,7 +19,6 @@
#include "mmc.h"
#include "sdmmc.h"
#include "../config/config.h"
#include "../gfx/gfx.h"
#include "../power/max7762x.h"
#include "../soc/bpmp.h"
@@ -33,8 +32,6 @@
//#define DPRINTF(...) gfx_printf(__VA_ARGS__)
#define DPRINTF(...)
extern hekate_config h_cfg;
/*! SCMMC controller base addresses. */
static const u32 _sdmmc_bases[4] = {
0x700B0000,
@@ -125,6 +122,7 @@ static int _sdmmc_config_ven_ceata_clk(sdmmc_t *sdmmc, u32 id)
{
if (!sdmmc->venclkctl_set)
return 0;
tap_val = sdmmc->venclkctl_tap;
}
else
@@ -235,7 +233,7 @@ int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type)
sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180;
break;
case 4:
// Non standard
// Non standard.
sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | HS400_BUS_SPEED;
sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180;
break;
@@ -254,7 +252,7 @@ int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type)
u32 tmp;
u16 divisor;
clock_sdmmc_get_params(&tmp, &divisor, type);
clock_sdmmc_get_card_clock_div(&tmp, &divisor, type);
clock_sdmmc_config_clock_source(&tmp, sdmmc->id, tmp);
sdmmc->divisor = (tmp + divisor - 1) / divisor;
@@ -513,13 +511,17 @@ static int _sdmmc_config_tuning_once(sdmmc_t *sdmmc, u32 cmd)
return 0;
_sdmmc_setup_read_small_block(sdmmc);
sdmmc->regs->norintstsen |= TEGRA_MMC_NORINTSTSEN_BUFFER_READ_READY;
sdmmc->regs->norintsts = sdmmc->regs->norintsts;
sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
_sdmmc_parse_cmd_48(sdmmc, cmd);
_sdmmc_get_clkcon(sdmmc);
usleep(1);
_sdmmc_reset(sdmmc);
sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
_sdmmc_get_clkcon(sdmmc);
@@ -535,10 +537,13 @@ static int _sdmmc_config_tuning_once(sdmmc_t *sdmmc, u32 cmd)
return 1;
}
}
_sdmmc_reset(sdmmc);
sdmmc->regs->norintstsen &= 0xFFDF;
_sdmmc_get_clkcon(sdmmc);
usleep((1000 * 8 + sdmmc->divisor - 1) / sdmmc->divisor);
return 0;
}
@@ -565,8 +570,8 @@ int sdmmc_config_tuning(sdmmc_t *sdmmc, u32 type, u32 cmd)
return 0;
}
sdmmc->regs->ventunctl0 = (sdmmc->regs->ventunctl0 & 0xFFFF1FFF) | flag;
sdmmc->regs->ventunctl0 = (sdmmc->regs->ventunctl0 & 0xFFFFE03F) | 0x40;
sdmmc->regs->ventunctl0 = (sdmmc->regs->ventunctl0 & 0xFFFF1FFF) | flag; // Tries.
sdmmc->regs->ventunctl0 = (sdmmc->regs->ventunctl0 & 0xFFFFE03F) | 0x40; // Multiplier.
sdmmc->regs->ventunctl0 |= 0x20000;
sdmmc->regs->hostctl2 |= SDHCI_CTRL_EXEC_TUNING;
@@ -579,6 +584,7 @@ int sdmmc_config_tuning(sdmmc_t *sdmmc, u32 type, u32 cmd)
if (sdmmc->regs->hostctl2 & SDHCI_CTRL_TUNED_CLK)
return 1;
return 0;
}
@@ -716,7 +722,7 @@ static int _sdmmc_check_mask_interrupt(sdmmc_t *sdmmc, u16 *pout, u16 mask)
sdmmc->regs->norintsts = norintsts & mask;
return SDMMC_MASKINT_MASKED;
}
return SDMMC_MASKINT_NOERROR;
}
@@ -748,18 +754,22 @@ static int _sdmmc_stop_transmission_inner(sdmmc_t *sdmmc, u32 *rsp)
return 0;
_sdmmc_enable_interrupts(sdmmc);
cmd.cmd = MMC_STOP_TRANSMISSION;
cmd.arg = 0;
cmd.rsp_type = SDMMC_RSP_TYPE_1;
cmd.check_busy = 1;
_sdmmc_parse_cmdbuf(sdmmc, &cmd, false);
int res = _sdmmc_wait_request(sdmmc);
_sdmmc_mask_interrupts(sdmmc);
if (!res)
return 0;
_sdmmc_cache_rsp(sdmmc, rsp, 4, SDMMC_RSP_TYPE_1);
return _sdmmc_wait_prnsts_type1(sdmmc);
}
@@ -779,6 +789,7 @@ int sdmmc_stop_transmission(sdmmc_t *sdmmc, u32 *rsp)
int res = _sdmmc_stop_transmission_inner(sdmmc, rsp);
usleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor);
if (should_disable_sd_clock)
sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
@@ -819,7 +830,7 @@ static int _sdmmc_config_dma(sdmmc_t *sdmmc, u32 *blkcnt_out, sdmmc_req_t *req)
trnmode |= TEGRA_MMC_TRNMOD_DATA_XFER_DIR_SEL_READ;
if (req->is_auto_cmd12)
trnmode = (trnmode & 0xFFF3) | TEGRA_MMC_TRNMOD_AUTO_CMD12;
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY);
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false);
sdmmc->regs->trnmod = trnmode;
return 1;
@@ -838,13 +849,13 @@ static int _sdmmc_update_dma(sdmmc_t *sdmmc)
while (1)
{
u16 intr = 0;
res = _sdmmc_check_mask_interrupt(sdmmc, &intr,
res = _sdmmc_check_mask_interrupt(sdmmc, &intr,
TEGRA_MMC_NORINTSTS_XFER_COMPLETE | TEGRA_MMC_NORINTSTS_DMA_INTERRUPT);
if (res < 0)
break;
if (intr & TEGRA_MMC_NORINTSTS_XFER_COMPLETE)
{
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY);
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false);
return 1; // Transfer complete.
}
if (intr & TEGRA_MMC_NORINTSTS_DMA_INTERRUPT)
@@ -890,7 +901,7 @@ static int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_
_sdmmc_parse_cmdbuf(sdmmc, cmd, is_data_present);
int res = _sdmmc_wait_request(sdmmc);
DPRINTF("rsp(%d): %08X, %08X, %08X, %08X\n", res,
DPRINTF("rsp(%d): %08X, %08X, %08X, %08X\n", res,
sdmmc->regs->rspreg0, sdmmc->regs->rspreg1, sdmmc->regs->rspreg2, sdmmc->regs->rspreg3);
if (res)
{
@@ -911,6 +922,7 @@ static int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_
{
if (blkcnt_out)
*blkcnt_out = blkcnt;
if (req->is_auto_cmd12)
sdmmc->rsp3 = sdmmc->regs->rspreg3;
}
@@ -930,6 +942,8 @@ static int _sdmmc_config_sdmmc1()
gpio_config(GPIO_PORT_Z, GPIO_PIN_1, GPIO_MODE_GPIO);
gpio_output_enable(GPIO_PORT_Z, GPIO_PIN_1, GPIO_OUTPUT_DISABLE);
usleep(100);
// Check if SD card is inserted.
if(!!gpio_read(GPIO_PORT_Z, GPIO_PIN_1))
return 0;
@@ -943,7 +957,7 @@ static int _sdmmc_config_sdmmc1()
*/
// Configure SDMMC1 pinmux.
APB_MISC(APB_MISC_GP_SDMMC1_CLK_LPBK_CONTROL) = 1;
APB_MISC(APB_MISC_GP_SDMMC1_CLK_LPBK_CONTROL) = 1; // Enable deep loopback for SDMMC1 CLK pad.
PINMUX_AUX(PINMUX_AUX_SDMMC1_CLK) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED;
PINMUX_AUX(PINMUX_AUX_SDMMC1_CMD) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_PULL_UP;
PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT3) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_PULL_UP;
@@ -1001,7 +1015,7 @@ int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type, int n
u32 clock;
u16 divisor;
clock_sdmmc_get_params(&clock, &divisor, type);
clock_sdmmc_get_card_clock_div(&clock, &divisor, type);
clock_sdmmc_enable(id, clock);
sdmmc->clock_stopped = 0;
@@ -1014,18 +1028,23 @@ int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type, int n
sdmmc->regs->sdmemcmppadctl = (sdmmc->regs->sdmemcmppadctl & 0xF) | 7;
if (!_sdmmc_autocal_config_offset(sdmmc, power))
return 0;
_sdmmc_autocal_execute(sdmmc, power);
if (_sdmmc_enable_internal_clock(sdmmc))
{
sdmmc_set_bus_width(sdmmc, bus_width);
_sdmmc_set_voltage(sdmmc, power);
if (sdmmc_setup_clock(sdmmc, type))
{
sdmmc_sd_clock_ctrl(sdmmc, no_sd);
_sdmmc_sd_clock_enable(sdmmc);
_sdmmc_get_clkcon(sdmmc);
return 1;
}
return 0;
}
return 0;
@@ -1036,7 +1055,7 @@ void sdmmc_end(sdmmc_t *sdmmc)
if (!sdmmc->clock_stopped)
{
_sdmmc_sd_clock_disable(sdmmc);
// Disable SDMMC power.
// Disable SDMMC power.
_sdmmc_set_voltage(sdmmc, SDMMC_POWER_OFF);
// Disable SD card power.
@@ -1044,8 +1063,8 @@ void sdmmc_end(sdmmc_t *sdmmc)
{
gpio_output_enable(GPIO_PORT_E, GPIO_PIN_4, GPIO_OUTPUT_DISABLE);
max77620_regulator_enable(REGULATOR_LDO2, 0);
h_cfg.sd_timeoff = get_tmr_ms(); // Some sandisc U1 cards need 100ms for a power cycle.
msleep(1); // To power cycle, min 1ms without power is needed.
sd_power_cycle_time_start = get_tmr_ms(); // Some sandisc U1 cards need 100ms for a power cycle.
usleep(1000); // To power cycle, min 1ms without power is needed.
}
_sdmmc_get_clkcon(sdmmc);
@@ -1082,6 +1101,7 @@ int sdmmc_execute_cmd(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_t *req, u32 *b
int res = _sdmmc_execute_cmd_inner(sdmmc, cmd, req, blkcnt_out);
usleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor);
if (should_disable_sd_clock)
sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
@@ -1114,12 +1134,12 @@ int sdmmc_enable_low_voltage(sdmmc_t *sdmmc)
_sdmmc_set_voltage(sdmmc, SDMMC_POWER_1_8);
_sdmmc_get_clkcon(sdmmc);
msleep(5);
if (sdmmc->regs->hostctl2 & SDHCI_CTRL_VDD_180)
{
sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
_sdmmc_get_clkcon(sdmmc);
msleep(1);
usleep(1000);
if ((sdmmc->regs->prnsts & 0xF00000) == 0xF00000)
return 1;
}

View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -25,11 +26,12 @@
#define _PAGEOFF(x) ((x) & 0xFFFFF000)
#define _ADRP(r, o) 0x90000000 | ((((o) >> 12) & 0x3) << 29) | ((((o) >> 12) & 0x1FFFFC) << 3) | ((r) & 0x1F)
#define _BL(a, o) 0x94000000 | ((((o) - (a)) >> 2) & 0x3FFFFFF)
#define _B(a, o) 0x14000000 | ((((o) - (a)) >> 2) & 0x3FFFFFF)
#define _MOVKX(r, i, s) 0xF2800000 | (((s) & 0x30) << 17) | (((i) & 0xFFFF) << 5) | ((r) & 0x1F)
#define _MOVZX(r, i, s) 0xD2800000 | (((s) & 0x30) << 17) | (((i) & 0xFFFF) << 5) | ((r) & 0x1F)
#define _ADRP(r, o) (0x90000000 | ((((o) >> 12) & 0x3) << 29) | ((((o) >> 12) & 0x1FFFFC) << 3) | ((r) & 0x1F))
#define _BL(a, o) (0x94000000 | ((((o) - (a)) >> 2) & 0x3FFFFFF))
#define _B(a, o) (0x14000000 | ((((o) - (a)) >> 2) & 0x3FFFFFF))
#define _MOVKX(r, i, s) (0xF2800000 | (((s) & 0x30) << 17) | (((i) & 0xFFFF) << 5) | ((r) & 0x1F))
#define _MOVZX(r, i, s) (0xD2800000 | (((s) & 0x30) << 17) | (((i) & 0xFFFF) << 5) | ((r) & 0x1F))
#define _MOVZW(r, i, s) (0x52800000 | (((s) & 0x30) << 17) | (((i) & 0xFFFF) << 5) | ((r) & 0x1F))
#define _NOP() 0xD503201F
#endif

View File

@@ -1,6 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (C) 2018 CTCaer
* Copyright (c) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -61,16 +61,28 @@ u8 btn_wait()
u8 btn_wait_timeout(u32 time_ms, u8 mask)
{
u8 single_button = mask & BTN_SINGLE;
mask &= ~BTN_SINGLE;
u32 timeout = get_tmr_ms() + time_ms;
u8 res = btn_read() & mask;
u8 res = btn_read();
while (get_tmr_ms() < timeout)
{
if (res == mask)
break;
if ((res & mask) == mask)
{
if (single_button && (res & ~mask)) // Undesired button detected.
res = btn_read();
else
return (res & mask);
}
else
res = btn_read() & mask;
res = btn_read();
};
return res;
// Timed out.
if (!single_button || !time_ms)
return (res & mask);
else
return 0; // Return no button press if single button requested.
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (C) 2018 CTCaer
* Copyright (c) 2018 CTCaer
*
* 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,6 +23,7 @@
#define BTN_POWER (1 << 0)
#define BTN_VOL_DOWN (1 << 1)
#define BTN_VOL_UP (1 << 2)
#define BTN_SINGLE (1 << 7)
u8 btn_read();
u8 btn_wait();

View File

@@ -29,7 +29,7 @@ char *dirlist(const char *directory, const char *pattern, bool includeHiddenFile
u32 i = 0, j = 0, k = 0;
DIR dir;
FILINFO fno;
char *dir_entries = (char *)calloc(max_entries, 256);
char *temp = (char *)calloc(1, 256);
@@ -42,7 +42,7 @@ char *dirlist(const char *directory, const char *pattern, bool includeHiddenFile
break;
if (!(fno.fattrib & AM_DIR) && (fno.fname[0] != '.') && (includeHiddenFiles || !(fno.fattrib & AM_HID)))
{
memcpy(dir_entries + (k * 256), fno.fname, strlen(fno.fname) + 1);
strcpy(dir_entries + (k * 256), fno.fname);
k++;
if (k > (max_entries - 1))
break;
@@ -56,7 +56,7 @@ char *dirlist(const char *directory, const char *pattern, bool includeHiddenFile
{
if (!(fno.fattrib & AM_DIR) && (fno.fname[0] != '.') && (includeHiddenFiles || !(fno.fattrib & AM_HID)))
{
memcpy(dir_entries + (k * 256), fno.fname, strlen(fno.fname) + 1);
strcpy(dir_entries + (k * 256), fno.fname);
k++;
if (k > (max_entries - 1))
break;
@@ -79,11 +79,11 @@ char *dirlist(const char *directory, const char *pattern, bool includeHiddenFile
{
for (j = i + 1; j < k; j++)
{
if (strcmp(&dir_entries[i * 256], &dir_entries[j * 256]) > 0)
if (strcmp(&dir_entries[i * 256], &dir_entries[j * 256]) > 0)
{
memcpy(temp, &dir_entries[i * 256], strlen(&dir_entries[i * 256]) + 1);
memcpy(&dir_entries[i * 256], &dir_entries[j * 256], strlen(&dir_entries[j * 256]) + 1);
memcpy(&dir_entries[j * 256], temp, strlen(temp) + 1);
strcpy(temp, &dir_entries[i * 256]);
strcpy(&dir_entries[i * 256], &dir_entries[j * 256]);
strcpy(&dir_entries[j * 256], temp);
}
}
}

View File

@@ -33,9 +33,10 @@
#define LIST_FOREACH_SAFE(iter, list) \
for(link_t *iter = (list)->next, *safe = iter->next; iter != (list); iter = safe, safe = iter->next)
/*! Iterate over all list members. */
/*! Iterate over all list members and make sure that the list has at least one entry. */
#define LIST_FOREACH_ENTRY(etype, iter, list, mn) \
for(etype *iter = CONTAINER_OF((list)->next, etype, mn); &iter->mn != (list); iter = CONTAINER_OF(iter->mn.next, etype, mn))
if ((list)->next != (list)) \
for(etype *iter = CONTAINER_OF((list)->next, etype, mn); &iter->mn != (list); iter = CONTAINER_OF(iter->mn.next, etype, mn))
typedef struct _link_t
{

View File

@@ -20,6 +20,7 @@
#define NULL ((void *)0)
#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
#define ALIGN_DOWN(x, a) (((x) - ((a) - 1)) & ~((a) - 1))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
@@ -53,6 +54,7 @@ typedef int bool;
#define BOOT_CFG_AUTOBOOT_EN (1 << 0)
#define BOOT_CFG_FROM_LAUNCH (1 << 1)
#define BOOT_CFG_FROM_ID (1 << 2)
#define BOOT_CFG_SEPT_RUN (1 << 7)
#define EXTRA_CFG_KEYS (1 << 0)
@@ -64,11 +66,18 @@ typedef int bool;
typedef struct __attribute__((__packed__)) _boot_cfg_t
{
u8 boot_cfg;
u8 autoboot;
u8 autoboot_list;
u8 extra_cfg;
u8 rsvd[128];
u8 boot_cfg;
u8 autoboot;
u8 autoboot_list;
u8 extra_cfg;
union
{
struct
{
char id[8];
};
u8 xt_str[0x80];
};
} boot_cfg_t;
typedef struct __attribute__((__packed__)) _ipl_ver_meta_t

View File

@@ -1,6 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (C) 2018 CTCaer
* Copyright (c) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -17,6 +17,7 @@
#include "util.h"
#include "../gfx/di.h"
#include "../mem/minerva.h"
#include "../power/max77620.h"
#include "../rtc/max77620-rtc.h"
#include "../soc/bpmp.h"
@@ -24,6 +25,10 @@
#include "../soc/pmc.h"
#include "../soc/t210.h"
#define USE_RTC_TIMER
extern volatile nyx_storage_t *nyx_str;
extern void sd_unmount();
u32 get_tmr_s()
@@ -35,7 +40,7 @@ u32 get_tmr_ms()
{
// The registers must be read with the following order:
// RTC_MILLI_SECONDS (0x10) -> RTC_SHADOW_SECONDS (0xC)
return (RTC(APBDEV_RTC_MILLI_SECONDS) | (RTC(APBDEV_RTC_SHADOW_SECONDS) << 10));
return (RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000));
}
u32 get_tmr_us()
@@ -43,19 +48,32 @@ u32 get_tmr_us()
return TMR(TIMERUS_CNTR_1US); //TIMERUS_CNTR_1US
}
void msleep(u32 milliseconds)
void msleep(u32 ms)
{
u32 start = RTC(APBDEV_RTC_MILLI_SECONDS) | (RTC(APBDEV_RTC_SHADOW_SECONDS) << 10);
while (((RTC(APBDEV_RTC_MILLI_SECONDS) | (RTC(APBDEV_RTC_SHADOW_SECONDS) << 10)) - start) <= milliseconds)
#ifdef USE_RTC_TIMER
u32 start = RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000);
// Casting to u32 is important!
while (((u32)(RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000)) - start) <= ms)
;
#else
bpmp_msleep(ms);
#endif
}
void usleep(u32 microseconds)
void usleep(u32 us)
{
#ifdef USE_RTC_TIMER
u32 start = TMR(TIMERUS_CNTR_1US);
// Casting to u32 is important!
while ((u32)(TMR(TIMERUS_CNTR_1US) - start) <= microseconds)
;
// Check if timer is at upper limits and use BPMP sleep so it doesn't wake up immediately.
if ((start + us) < start)
bpmp_usleep(us);
else
while ((u32)(TMR(TIMERUS_CNTR_1US) - start) <= us) // Casting to u32 is important!
;
#else
bpmp_usleep(us);
#endif
}
void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops)
@@ -73,8 +91,9 @@ void panic(u32 val)
TMR(TIMER_TMR9_TMR_PTV) = TIMER_EN | TIMER_PER_EN;
TMR(TIMER_WDT4_CONFIG) = TIMER_SRC(9) | TIMER_PER(1) | TIMER_PMCRESET_EN;
TMR(TIMER_WDT4_COMMAND) = TIMER_START_CNT;
while (1)
;
while (true)
usleep(1);
}
void reboot_normal()
@@ -84,6 +103,8 @@ void reboot_normal()
sd_unmount();
display_end();
nyx_str->mtc_cfg.init_done = 0;
panic(0x21); // Bypass fuse programming in package1.
}
@@ -94,19 +115,25 @@ void reboot_rcm()
sd_unmount();
display_end();
nyx_str->mtc_cfg.init_done = 0;
PMC(APBDEV_PMC_SCRATCH0) = 2; // Reboot into rcm.
PMC(APBDEV_PMC_CNTRL) |= PMC_CNTRL_MAIN_RST;
while (true)
usleep(1);
bpmp_halt();
}
void power_off()
{
sd_unmount();
display_end();
// Stop the alarm, in case we injected and powered off too fast.
max77620_rtc_stop_alarm();
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1, MAX77620_ONOFFCNFG1_PWR_OFF);
while (true)
bpmp_halt();
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (C) 2018 CTCaer
* Copyright (c) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -21,8 +21,17 @@
#include "types.h"
#include "../mem/minerva.h"
#define NYX_CFG_DUMP (1 << 7)
#define NYX_CFG_MINERVA (1 << 8)
typedef enum
{
NYX_CFG_DUMP = (1 << 7),
} nyx_cfg_t;
typedef enum
{
ERR_LIBSYS_LP0 = (1 << 0),
ERR_SYSOLD_NYX = (1 << 1),
ERR_SYSOLD_MTC = (1 << 2),
} hekate_errors_t;
#define byte_swap_32(num) (((num >> 24) & 0xff) | ((num << 8) & 0xff0000) | \
((num >> 8 )& 0xff00) | ((num << 24) & 0xff000000))
@@ -33,21 +42,29 @@ typedef struct _cfg_op_t
u32 val;
} cfg_op_t;
typedef struct _nyx_info_t
{
u32 rsvd;
u32 errors;
} nyx_info_t;
typedef struct _nyx_storage_t
{
u32 version;
u32 cfg;
u8 irama[0x8000];
u8 hekate[0x30000];
u8 rsvd[0x800000];
u8 rsvd[0x800000 - sizeof(nyx_info_t)];
nyx_info_t info;
mtc_config_t mtc_cfg;
emc_table_t mtc_table;
} nyx_storage_t;
u32 get_tmr_us();
u32 get_tmr_ms();
u32 get_tmr_s();
void usleep(u32 ticks);
void msleep(u32 milliseconds);
void usleep(u32 us);
void msleep(u32 ms);
void panic(u32 val);
void reboot_normal();
void reboot_rcm();

View File

@@ -1,9 +1,9 @@
/*
* Common Gfx Header
* Copyright (c) 2018 naehrwert
* Copyright (C) 2018 CTCaer
* Copyright (C) 2018 M4xw
*
* Copyright (c) 2018 CTCaer
* Copyright (c) 2018 M4xw
*
* 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.

View File

@@ -25,6 +25,7 @@ typedef struct _hnode
u32 size;
struct _hnode *prev;
struct _hnode *next;
u32 align[4]; // Align to arch cache line size.
} hnode_t;
typedef struct _heap
@@ -32,3 +33,9 @@ typedef struct _heap
u32 start;
hnode_t *first;
} heap_t;
typedef struct
{
u32 total;
u32 used;
} heap_monitor_t;

View File

@@ -1,7 +1,7 @@
/*
* Common Module Header
* Copyright (C) 2018 M4xw
*
* Copyright (c) 2018 M4xw
*
* 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.

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