Compare commits
222 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a4c90aeff3 | ||
|
|
bfe13981bc | ||
|
|
ef11dd883a | ||
|
|
da149c296f | ||
|
|
9af4c717a8 | ||
|
|
281e5a138e | ||
|
|
e7f8b2c6c2 | ||
|
|
3d9c64d548 | ||
|
|
5f142b4c86 | ||
|
|
52c506af9a | ||
|
|
dc9c7fd95c | ||
|
|
4ec7befe82 | ||
|
|
dd4dd91152 | ||
|
|
a39ba2cd71 | ||
|
|
9c2202fa39 | ||
|
|
9c6931a17c | ||
|
|
976925c697 | ||
|
|
d50af46b03 | ||
|
|
3405910f4c | ||
|
|
52874f9113 | ||
|
|
91a241dafa | ||
|
|
a8db070755 | ||
|
|
76676f3a2e | ||
|
|
f5040f1e41 | ||
|
|
c9c3c8f716 | ||
|
|
144d6fd3f6 | ||
|
|
9697067466 | ||
|
|
8539095bdb | ||
|
|
95e3159fe9 | ||
|
|
8b74c487eb | ||
|
|
8abda7f259 | ||
|
|
8d5c52f087 | ||
|
|
e6c1d9bf66 | ||
|
|
a52af1bf41 | ||
|
|
3f10cc774b | ||
|
|
ac92ca220f | ||
|
|
ab8801d0de | ||
|
|
f3802ec464 | ||
|
|
bc7a7bcfa0 | ||
|
|
6a52d44da6 | ||
|
|
03a8a11933 | ||
|
|
c474e35732 | ||
|
|
4c1f67d022 | ||
|
|
91759aba95 | ||
|
|
5a9bbaf900 | ||
|
|
01a767cbfa | ||
|
|
8552a7282c | ||
|
|
2a161b572b | ||
|
|
422852795f | ||
|
|
4d53f21387 | ||
|
|
9263e2192f | ||
|
|
c99a87dd09 | ||
|
|
009db77426 | ||
|
|
4e5ded7cb3 | ||
|
|
50f31cad14 | ||
|
|
2f43145131 | ||
|
|
e3fca2bce5 | ||
|
|
da112a0ae9 | ||
|
|
90060d1d83 | ||
|
|
1ccce5f1a2 | ||
|
|
8584493c7f | ||
|
|
9b2d906648 | ||
|
|
2aaa0331ac | ||
|
|
7604239237 | ||
|
|
562a6fb61d | ||
|
|
938562cc0a | ||
|
|
1e4d63731b | ||
|
|
8ff01301cb | ||
|
|
a664118fc7 | ||
|
|
87d376654b | ||
|
|
c6e92311f9 | ||
|
|
24d30a40f9 | ||
|
|
ae283aef59 | ||
|
|
e4f7928513 | ||
|
|
bd8a5ece58 | ||
|
|
d0850516ab | ||
|
|
4c5a78de6f | ||
|
|
97d3b745d9 | ||
|
|
c12c696e53 | ||
|
|
f256bd5909 | ||
|
|
0290892b23 | ||
|
|
643a8ea8f9 | ||
|
|
a6d8854499 | ||
|
|
96bafd8bd7 | ||
|
|
65ee728939 | ||
|
|
e1748a0727 | ||
|
|
6734513d47 | ||
|
|
dbe6ed4060 | ||
|
|
943477fdde | ||
|
|
35e853fd03 | ||
|
|
7e26be6587 | ||
|
|
733da0f4d5 | ||
|
|
a357395cc6 | ||
|
|
48c15a8fde | ||
|
|
edc2b12f0f | ||
|
|
0b45a5a11a | ||
|
|
bc7dec2e61 | ||
|
|
9811ba53e0 | ||
|
|
a16b1af698 | ||
|
|
641a57a4f6 | ||
|
|
84328aa676 | ||
|
|
66c4f30bdf | ||
|
|
dd8ec0d28b | ||
|
|
0b1eebefe1 | ||
|
|
168de9ddd8 | ||
|
|
c24d943122 | ||
|
|
b61b212218 | ||
|
|
ec10b572d1 | ||
|
|
d1e50c558e | ||
|
|
9476e0ab45 | ||
|
|
ccf36fd2cb | ||
|
|
9a082c1b18 | ||
|
|
2c1da3a97d | ||
|
|
29a51124fd | ||
|
|
74452074f6 | ||
|
|
598073e50c | ||
|
|
58b57a7b14 | ||
|
|
426c86182d | ||
|
|
65fbdfddbf | ||
|
|
7c42f72b8a | ||
|
|
9104b85143 | ||
|
|
2857fcca52 | ||
|
|
6433dbd1ee | ||
|
|
fe339120e2 | ||
|
|
6a261e356f | ||
|
|
e24bb44adf | ||
|
|
40afcfd686 | ||
|
|
658c3c112f | ||
|
|
3b16b086f8 | ||
|
|
8033ba461f | ||
|
|
4dcb2c6343 | ||
|
|
95a6f2b763 | ||
|
|
8cef81c901 | ||
|
|
08d212d4da | ||
|
|
252a57ef6a | ||
|
|
23e246f224 | ||
|
|
3028568019 | ||
|
|
a8d529cf6a | ||
|
|
c5b64a2b58 | ||
|
|
4c09454bca | ||
|
|
787c682f0f | ||
|
|
29b86ce92b | ||
|
|
50ebcee45d | ||
|
|
b74b449601 | ||
|
|
718e502983 | ||
|
|
c1e072986d | ||
|
|
8045d7992b | ||
|
|
02826dd9a6 | ||
|
|
c50e61f961 | ||
|
|
deb9c94bcd | ||
|
|
6cc3d9df67 | ||
|
|
92a60a1e89 | ||
|
|
d0b0164077 | ||
|
|
f3d071ca69 | ||
|
|
9533dea124 | ||
|
|
6159d94e5d | ||
|
|
565956482a | ||
|
|
f622d57f6b | ||
|
|
6cc0711382 | ||
|
|
3472e7e7fb | ||
|
|
e07dde1c58 | ||
|
|
03130ad900 | ||
|
|
31db2735ce | ||
|
|
6ec871ad5f | ||
|
|
0fc17cccfb | ||
|
|
101c8bc1d0 | ||
|
|
9b80ec9ac7 | ||
|
|
ac425368e4 | ||
|
|
205dab6cbd | ||
|
|
ac7eb092d5 | ||
|
|
fed15a2f2f | ||
|
|
2bb0dba724 | ||
|
|
078ef1c4f1 | ||
|
|
c40c125462 | ||
|
|
5b919cb12e | ||
|
|
138da26a9a | ||
|
|
18a29c641c | ||
|
|
0862cb1e7e | ||
|
|
f26cfac10d | ||
|
|
08b84384a6 | ||
|
|
d55634638f | ||
|
|
e6d1a31045 | ||
|
|
7cd545a124 | ||
|
|
01e2302f84 | ||
|
|
c41f98039c | ||
|
|
c0b3a4fc54 | ||
|
|
a1a0d8db49 | ||
|
|
03872e814a | ||
|
|
52478833de | ||
|
|
ba0f29bc5c | ||
|
|
f3dcfab095 | ||
|
|
12f8f055eb | ||
|
|
bd7f572989 | ||
|
|
8101fd3f7f | ||
|
|
c5ab4d6abd | ||
|
|
ee884add8c | ||
|
|
03268c4655 | ||
|
|
072bbcabf4 | ||
|
|
7c877c5bce | ||
|
|
6aa1bdd1c6 | ||
|
|
91606334c4 | ||
|
|
25f6e91677 | ||
|
|
36d2da5d79 | ||
|
|
fd0dc04953 | ||
|
|
8eb5ee867d | ||
|
|
5d99f2fcf7 | ||
|
|
e34a7543b1 | ||
|
|
c80fecd080 | ||
|
|
ed047ef5f5 | ||
|
|
a2ba2ecf26 | ||
|
|
07fe94b6d4 | ||
|
|
ca0c0f786c | ||
|
|
b0af57f98a | ||
|
|
5ba4848571 | ||
|
|
2a2db6cb2f | ||
|
|
361f8a3085 | ||
|
|
961768e14e | ||
|
|
491c4efe9c | ||
|
|
ff9671c481 | ||
|
|
da1bb77d8e | ||
|
|
14c50ed7f8 | ||
|
|
61401d733e |
46
Makefile
46
Makefile
@@ -8,11 +8,7 @@ include $(DEVKITARM)/base_rules
|
||||
|
||||
IPL_LOAD_ADDR := 0x40008000
|
||||
IPL_MAGIC := 0x43544349 #"ICTC"
|
||||
BLVERSION_MAJOR := 4
|
||||
BLVERSION_MINOR := 9
|
||||
BLVERSION_HOTFX := 0
|
||||
|
||||
BL_RESERVED := 0
|
||||
include ./Versions.inc
|
||||
|
||||
################################################################################
|
||||
|
||||
@@ -20,7 +16,7 @@ TARGET := hekate
|
||||
BUILDDIR := build
|
||||
OUTPUTDIR := output
|
||||
SOURCEDIR = bootloader
|
||||
VPATH = $(dir $(wildcard ./$(SOURCEDIR)/*/)) $(dir $(wildcard ./$(SOURCEDIR)/*/*/))
|
||||
VPATH = $(dir ./$(SOURCEDIR)/) $(dir $(wildcard ./$(SOURCEDIR)/*/)) $(dir $(wildcard ./$(SOURCEDIR)/*/*/))
|
||||
|
||||
# Main and graphics.
|
||||
OBJS = $(addprefix $(BUILDDIR)/$(TARGET)/, \
|
||||
@@ -32,9 +28,9 @@ OBJS = $(addprefix $(BUILDDIR)/$(TARGET)/, \
|
||||
|
||||
# Hardware.
|
||||
OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \
|
||||
clock.o cluster.o di.o gpio.o i2c.o mc.o sdram.o pinmux.o se.o smmu.o tsec.o uart.o \
|
||||
fuse.o kfuse.o \
|
||||
sdmmc.o sdmmc_driver.o \
|
||||
bpmp.o clock.o cluster.o di.o gpio.o i2c.o mc.o sdram.o pinmux.o se.o smmu.o tsec.o uart.o \
|
||||
fuse.o kfuse.o minerva.o \
|
||||
sdmmc.o sdmmc_driver.o emummc.o nx_emmc.o \
|
||||
bq24193.o max17050.o max7762x.o max77620-rtc.o \
|
||||
hw_init.o \
|
||||
)
|
||||
@@ -47,8 +43,7 @@ OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \
|
||||
|
||||
# Horizon.
|
||||
OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \
|
||||
nx_emmc.o \
|
||||
hos.o hos_config.o pkg1.o pkg2.o fss.o secmon_exo.o sept.o \
|
||||
hos.o hos_config.o pkg1.o pkg2.o pkg2_ini_kippatch.o fss.o secmon_exo.o sept.o \
|
||||
)
|
||||
|
||||
# Libraries.
|
||||
@@ -61,8 +56,9 @@ OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \
|
||||
################################################################################
|
||||
|
||||
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=$(BL_RESERVED)
|
||||
CUSTOMDEFINES += -DMENU_LOGO_ENABLE
|
||||
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
|
||||
@@ -74,15 +70,18 @@ CFLAGS = $(ARCH) -O2 -nostdlib -ffunction-sections -fdata-sections -fomit-frame-
|
||||
LDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections -Xlinker --defsym=IPL_LOAD_ADDR=$(IPL_LOAD_ADDR)
|
||||
|
||||
MODULEDIRS := $(wildcard modules/*)
|
||||
NYXDIR := $(wildcard nyx)
|
||||
|
||||
################################################################################
|
||||
|
||||
.PHONY: all clean $(MODULEDIRS)
|
||||
.PHONY: all clean $(MODULEDIRS) $(NYXDIR)
|
||||
|
||||
all: $(TARGET).bin
|
||||
@echo -n "Payload size is "
|
||||
@wc -c < $(OUTPUTDIR)/$(TARGET).bin
|
||||
@echo "Max size is 126296 Bytes."
|
||||
$(eval BIN_SIZE = $(shell wc -c < $(OUTPUTDIR)/$(TARGET).bin))
|
||||
@echo $(BIN_SIZE)
|
||||
@echo "Max size is 126296 Bytes."
|
||||
@if [ ${BIN_SIZE} -gt 126296 ]; then echo "\e[1;33mPayload size exceeds limit!\e[0m"; fi
|
||||
|
||||
clean:
|
||||
@rm -rf $(OBJS)
|
||||
@@ -90,11 +89,14 @@ clean:
|
||||
@rm -rf $(OUTPUTDIR)
|
||||
|
||||
$(MODULEDIRS):
|
||||
$(MAKE) -C $@ $(MAKECMDGOALS)
|
||||
$(MAKE) -C $@ $(MAKECMDGOALS) -$(MAKEFLAGS)
|
||||
|
||||
$(TARGET).bin: $(BUILDDIR)/$(TARGET)/$(TARGET).elf $(MODULEDIRS)
|
||||
$(NYXDIR):
|
||||
$(MAKE) -C $@ $(MAKECMDGOALS) -$(MAKEFLAGS)
|
||||
|
||||
$(TARGET).bin: $(BUILDDIR)/$(TARGET)/$(TARGET).elf $(MODULEDIRS) $(NYXDIR)
|
||||
$(OBJCOPY) -S -O binary $< $(OUTPUTDIR)/$@
|
||||
@printf ICTC$(BLVERSION_MAJOR)$(BLVERSION_MINOR) >> $(OUTPUTDIR)/$@
|
||||
@printf ICTC49 >> $(OUTPUTDIR)/$@
|
||||
|
||||
$(BUILDDIR)/$(TARGET)/$(TARGET).elf: $(OBJS)
|
||||
$(CC) $(LDFLAGS) -T $(SOURCEDIR)/link.ld $^ -o $@
|
||||
@@ -103,7 +105,11 @@ $(BUILDDIR)/$(TARGET)/%.o: %.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
$(BUILDDIR)/$(TARGET)/%.o: %.S
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
$(OBJS): $(BUILDDIR)/$(TARGET)
|
||||
|
||||
$(BUILDDIR)/$(TARGET):
|
||||
@mkdir -p "$(BUILDDIR)"
|
||||
@mkdir -p "$(BUILDDIR)/$(TARGET)"
|
||||
@mkdir -p "$(OUTPUTDIR)"
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
99
README.md
99
README.md
@@ -1,6 +1,6 @@
|
||||
# hekate - CTCaer mod
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
Custom Nintendo Switch bootloader, firmware patcher, and more.
|
||||
@@ -8,17 +8,29 @@ Custom Nintendo Switch bootloader, firmware patcher, and more.
|
||||
|
||||
## Bootloader folders and files
|
||||
|
||||
| Folder/File | Description |
|
||||
| -------------------- | --------------------------------------------------------------------- |
|
||||
| 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. |
|
||||
| \|__ update.bin | If newer, it is loaded at boot. For modchips. Can be skipped. |
|
||||
| bootloader/ini/ | For individual inis. 'More configs...' menu. Autoboot is supported. |
|
||||
| bootloader/sys/ | For system modules. |
|
||||
| \|__ libsys_lp0.bso | LP0 (sleep mode) module. Important! |
|
||||
| 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 |
|
||||
| Folder/File | Description |
|
||||
| ------------------------ | --------------------------------------------------------------------- |
|
||||
| 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. 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. |
|
||||
| \|__ icon_switch.bmp | Nyx - Default icon for CFWs. |
|
||||
| \|__ icon_payload.bmp | Nyx - Default icon for Payloads. |
|
||||
| \|__ icon_lakka.bmp | Nyx - Default icon for Lakka. |
|
||||
| bootloader/sys/ | For system modules. |
|
||||
| \|__ emummc.kipm | emuMMC KIP1 module. Important! |
|
||||
| \|__ libsys_lp0.bso | LP0 (sleep mode) module. Important! |
|
||||
| \|__ libsys_minerva.bso | Minerva Training Cell. Used for DRAM Frequency training. Important! |
|
||||
| \|__ nyx.bin | Nyx - Our GUI. Important! |
|
||||
| \|__ res.pak | Nyx resources package. Important! |
|
||||
| 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.
|
||||
|
||||
@@ -31,58 +43,70 @@ 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 |
|
||||
| ------------------ | ---------------------------------------------------------- |
|
||||
| autoboot=0 | 0: Disable, #: Boot entry number to auto boot. |
|
||||
| autoboot_list=0 | 0: Read `autoboot` boot entry from hekate_ipl.ini, 1: Read from ini folder (ini files are ASCII ordered). |
|
||||
| bootwait=3 | 0: Disable (It also disables bootlogo. Having **VOL-** pressed since injection goes to menu.), #: Time to wait for **VOL-** to enter menu. |
|
||||
| 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. |
|
||||
|
||||
|
||||
### Possible boot entry key/value combinations:
|
||||
|
||||
| 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. |
|
||||
| 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 |
|
||||
| payload={SD path} | Payload launching. Tools, Linux, CFW bootloaders, etc. |
|
||||
| Config option | Description |
|
||||
| ---------------------- | ---------------------------------------------------------- |
|
||||
| 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. kips, exosphere, warmboot and sept. |
|
||||
| fss0experimental=1 | Enables loading of experimental content from a FSS0 storage |
|
||||
| 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 signle kips.
|
||||
**Note1**: When using the wildcard (`/*`) with `kip1` you can still use the normal `kip1` after that to load extra single kips.
|
||||
|
||||
**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.
|
||||
**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. |
|
||||
| '0x98' autoboot | If `Force AutoBoot`: 0: Force go to menu, else boot that entry. |
|
||||
| '0x9C' autoboot_list | If `Force AutoBoot` and `autoboot` then it boots from ini folder. |
|
||||
| '0xA0' extra_cfg | Reserved. |
|
||||
| '0xA4' rsvd[128] | Reserved. |
|
||||
| '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' 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.
|
||||
|
||||
|
||||
@@ -96,7 +120,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
|
||||
|
||||
___
|
||||
|
||||
@@ -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
11
Versions.inc
Normal file
@@ -0,0 +1,11 @@
|
||||
# IPL Version.
|
||||
BLVERSION_MAJOR := 5
|
||||
BLVERSION_MINOR := 1
|
||||
BLVERSION_HOTFX := 4
|
||||
BLVERSION_RSVD := 0
|
||||
|
||||
# Nyx Version.
|
||||
NYXVERSION_MAJOR := 0
|
||||
NYXVERSION_MINOR := 8
|
||||
NYXVERSION_HOTFX := 7
|
||||
NYXVERSION_RSVD := 0
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 CTCaer
|
||||
* Copyright (c) 2018-2020 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,27 +23,34 @@
|
||||
#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"
|
||||
|
||||
extern hekate_config h_cfg;
|
||||
extern int sd_mount();
|
||||
extern int sd_unmount();
|
||||
extern bool sd_mount();
|
||||
extern void sd_unmount();
|
||||
|
||||
void set_default_configuration()
|
||||
{
|
||||
h_cfg.autoboot = 0;
|
||||
h_cfg.autoboot_list = 0;
|
||||
h_cfg.bootwait = 3;
|
||||
h_cfg.verification = 1;
|
||||
h_cfg.se_keygen_done = 0;
|
||||
h_cfg.sbar_time_keeping = 0;
|
||||
h_cfg.backlight = 100;
|
||||
h_cfg.autohosoff = 0;
|
||||
h_cfg.errors = 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.emummc_force_disable = false;
|
||||
|
||||
sd_power_cycle_time_start = 0;
|
||||
}
|
||||
|
||||
int create_config_entry()
|
||||
@@ -51,7 +58,7 @@ int create_config_entry()
|
||||
if (!sd_mount())
|
||||
return 1;
|
||||
|
||||
char lbuf[16];
|
||||
char lbuf[32];
|
||||
FIL fp;
|
||||
bool mainIniFound = false;
|
||||
|
||||
@@ -89,9 +96,6 @@ int create_config_entry()
|
||||
f_puts("\nbootwait=", &fp);
|
||||
itoa(h_cfg.bootwait, lbuf, 10);
|
||||
f_puts(lbuf, &fp);
|
||||
f_puts("\nverification=", &fp);
|
||||
itoa(h_cfg.verification, lbuf, 10);
|
||||
f_puts(lbuf, &fp);
|
||||
f_puts("\nbacklight=", &fp);
|
||||
itoa(h_cfg.backlight, lbuf, 10);
|
||||
f_puts(lbuf, &fp);
|
||||
@@ -101,6 +105,19 @@ 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);
|
||||
f_puts(h_cfg.brand, &fp);
|
||||
}
|
||||
if (h_cfg.tagline)
|
||||
{
|
||||
f_puts("\ntagline=", &fp);
|
||||
f_puts(h_cfg.tagline, &fp);
|
||||
}
|
||||
f_puts("\n", &fp);
|
||||
|
||||
if (mainIniFound)
|
||||
@@ -146,28 +163,28 @@ int create_config_entry()
|
||||
f_close(&fp);
|
||||
sd_unmount();
|
||||
|
||||
if (mainIniFound)
|
||||
ini_free(&ini_sections);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#pragma GCC push_options
|
||||
#pragma GCC optimize ("Os")
|
||||
|
||||
static void _save_config()
|
||||
{
|
||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
gfx_clear_grey(0x1B);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
if (!create_config_entry())
|
||||
gfx_puts(&gfx_con, "\nConfiguration was saved!\n");
|
||||
gfx_puts("\nConfiguration was saved!\n");
|
||||
else
|
||||
EPRINTF("\nConfiguration saving failed!");
|
||||
gfx_puts(&gfx_con, "\nPress any key...");
|
||||
gfx_puts("\nPress any key...");
|
||||
}
|
||||
|
||||
static void _config_autoboot_list(void *ent)
|
||||
{
|
||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
gfx_clear_grey(0x1B);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
u32 *temp_autoboot = NULL;
|
||||
|
||||
@@ -210,8 +227,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;
|
||||
@@ -225,7 +241,7 @@ static void _config_autoboot_list(void *ent)
|
||||
|
||||
memset(&ments[i], 0, sizeof(ment_t));
|
||||
menu_t menu = {ments, "Select an entry to auto boot", 0, 0};
|
||||
temp_autoboot = (u32 *)tui_do_menu(&gfx_con, &menu);
|
||||
temp_autoboot = (u32 *)tui_do_menu(&menu);
|
||||
if (temp_autoboot != NULL)
|
||||
{
|
||||
h_cfg.autoboot = *(u32 *)temp_autoboot;
|
||||
@@ -251,25 +267,25 @@ out2:;
|
||||
free(ments);
|
||||
free(boot_values);
|
||||
free(boot_text);
|
||||
ini_free(&ini_sections);
|
||||
|
||||
sd_unmount();
|
||||
}
|
||||
|
||||
void config_autoboot()
|
||||
{
|
||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
gfx_clear_grey(0x1B);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
u32 *temp_autoboot = NULL;
|
||||
|
||||
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;
|
||||
@@ -315,13 +331,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];
|
||||
@@ -341,7 +356,7 @@ void config_autoboot()
|
||||
|
||||
memset(&ments[i], 0, sizeof(ment_t));
|
||||
menu_t menu = {ments, "Disable or select entry to auto boot", 0, 0};
|
||||
temp_autoboot = (u32 *)tui_do_menu(&gfx_con, &menu);
|
||||
temp_autoboot = (u32 *)tui_do_menu(&menu);
|
||||
if (temp_autoboot != NULL)
|
||||
{
|
||||
h_cfg.autoboot = *(u32 *)temp_autoboot;
|
||||
@@ -364,7 +379,6 @@ out2:;
|
||||
free(ments);
|
||||
free(boot_values);
|
||||
free(boot_text);
|
||||
ini_free(&ini_sections);
|
||||
|
||||
sd_unmount();
|
||||
|
||||
@@ -374,14 +388,15 @@ out2:;
|
||||
|
||||
void config_bootdelay()
|
||||
{
|
||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
gfx_clear_grey(0x1B);
|
||||
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;
|
||||
@@ -402,21 +417,21 @@ 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];
|
||||
}
|
||||
|
||||
memset(&ments[i + 2], 0, sizeof(ment_t));
|
||||
menu_t menu = {ments, "Time delay for entering bootloader menu", 0, 0};
|
||||
|
||||
u32 *temp_bootwait = (u32 *)tui_do_menu(&gfx_con, &menu);
|
||||
u32 *temp_bootwait = (u32 *)tui_do_menu(&menu);
|
||||
if (temp_bootwait != NULL)
|
||||
{
|
||||
h_cfg.bootwait = *(u32 *)temp_bootwait;
|
||||
@@ -432,69 +447,17 @@ void config_bootdelay()
|
||||
btn_wait();
|
||||
}
|
||||
|
||||
void config_verification()
|
||||
{
|
||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
|
||||
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);
|
||||
|
||||
for (u32 j = 0; j < 3; j++)
|
||||
{
|
||||
vr_values[j] = j;
|
||||
ments[j + 2].type = MENT_DATA;
|
||||
ments[j + 2].data = &vr_values[j];
|
||||
}
|
||||
|
||||
ments[0].type = MENT_BACK;
|
||||
ments[0].caption = "Back";
|
||||
|
||||
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);
|
||||
|
||||
for (u32 i = 0; i < 3; i++)
|
||||
{
|
||||
if (h_cfg.verification != i)
|
||||
vr_text[64 * i] = ' ';
|
||||
else
|
||||
vr_text[64 * i] = '*';
|
||||
ments[2 + i].caption = vr_text + (i * 64);
|
||||
}
|
||||
|
||||
memset(&ments[5], 0, sizeof(ment_t));
|
||||
menu_t menu = {ments, "Backup & Restore verification", 0, 0};
|
||||
|
||||
u32 *temp_verification = (u32 *)tui_do_menu(&gfx_con, &menu);
|
||||
if (temp_verification != NULL)
|
||||
{
|
||||
h_cfg.verification = *(u32 *)temp_verification;
|
||||
_save_config();
|
||||
}
|
||||
|
||||
free(ments);
|
||||
free(vr_values);
|
||||
free(vr_text);
|
||||
|
||||
if (temp_verification == NULL)
|
||||
return;
|
||||
btn_wait();
|
||||
}
|
||||
|
||||
void config_backlight()
|
||||
{
|
||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
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;
|
||||
@@ -508,27 +471,27 @@ 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];
|
||||
}
|
||||
|
||||
memset(&ments[i + 1], 0, sizeof(ment_t));
|
||||
menu_t menu = {ments, "Backlight brightness", 0, 0};
|
||||
|
||||
u32 *temp_backlight = (u32 *)tui_do_menu(&gfx_con, &menu);
|
||||
u32 *temp_backlight = (u32 *)tui_do_menu(&menu);
|
||||
if (temp_backlight != NULL)
|
||||
{
|
||||
h_cfg.backlight = (*(u32 *)temp_backlight) * 2;
|
||||
@@ -546,8 +509,8 @@ void config_backlight()
|
||||
|
||||
void config_auto_hos_poweroff()
|
||||
{
|
||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
gfx_clear_grey(0x1B);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 6);
|
||||
u32 *hp_values = (u32 *)malloc(sizeof(u32) * 3);
|
||||
@@ -586,7 +549,7 @@ void config_auto_hos_poweroff()
|
||||
memset(&ments[5], 0, sizeof(ment_t));
|
||||
menu_t menu = {ments, "Power off if woke up from HOS", 0, 0};
|
||||
|
||||
u32 *temp_autohosoff = (u32 *)tui_do_menu(&gfx_con, &menu);
|
||||
u32 *temp_autohosoff = (u32 *)tui_do_menu(&menu);
|
||||
if (temp_autohosoff != NULL)
|
||||
{
|
||||
h_cfg.autohosoff = *(u32 *)temp_autohosoff;
|
||||
@@ -603,8 +566,8 @@ void config_auto_hos_poweroff()
|
||||
|
||||
void config_nogc()
|
||||
{
|
||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
gfx_clear_grey(0x1B);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 5);
|
||||
u32 *cb_values = (u32 *)malloc(sizeof(u32) * 2);
|
||||
@@ -635,7 +598,7 @@ void config_nogc()
|
||||
memset(&ments[4], 0, sizeof(ment_t));
|
||||
menu_t menu = {ments, "No Gamecard", 0, 0};
|
||||
|
||||
u32 *temp_nogc = (u32 *)tui_do_menu(&gfx_con, &menu);
|
||||
u32 *temp_nogc = (u32 *)tui_do_menu(&menu);
|
||||
if (temp_nogc != NULL)
|
||||
{
|
||||
h_cfg.autonogc = *(u32 *)temp_nogc;
|
||||
@@ -649,3 +612,5 @@ void config_nogc()
|
||||
return;
|
||||
btn_wait();
|
||||
}
|
||||
|
||||
#pragma GCC pop_options
|
||||
|
||||
@@ -25,27 +25,25 @@ typedef struct _hekate_config
|
||||
u32 autoboot;
|
||||
u32 autoboot_list;
|
||||
u32 bootwait;
|
||||
u32 verification;
|
||||
u32 backlight;
|
||||
u32 autohosoff;
|
||||
u32 autonogc;
|
||||
u32 updater2p;
|
||||
char *brand;
|
||||
char *tagline;
|
||||
// Global temporary config.
|
||||
int se_keygen_done;
|
||||
u32 sbar_time_keeping;
|
||||
u32 errors;
|
||||
int sept_run;
|
||||
bool se_keygen_done;
|
||||
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();
|
||||
void config_bootdelay();
|
||||
void config_verification();
|
||||
void config_backlight();
|
||||
void config_auto_hos_poweroff();
|
||||
void config_nogc();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (C) 2018-2019 CTCaer
|
||||
* Copyright (c) 2018-2020 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,
|
||||
@@ -26,16 +26,26 @@ static char *_strdup(char *str)
|
||||
{
|
||||
if (!str)
|
||||
return NULL;
|
||||
|
||||
// Remove starting space.
|
||||
if (str[0] == ' ' && strlen(str))
|
||||
str++;
|
||||
|
||||
char *res = (char *)malloc(strlen(str) + 1);
|
||||
strcpy(res, str);
|
||||
|
||||
// Remove trailing space.
|
||||
if (strlen(res) && res[strlen(res) - 1] == ' ')
|
||||
res[strlen(res) - 1] = 0;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@@ -69,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)
|
||||
@@ -80,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++;
|
||||
}
|
||||
|
||||
@@ -91,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
|
||||
@@ -114,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.
|
||||
@@ -125,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, '=');
|
||||
|
||||
@@ -169,82 +177,16 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ini_free(link_t *dst)
|
||||
{
|
||||
if (!dst->prev || !dst->next)
|
||||
return;
|
||||
|
||||
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, dst, link)
|
||||
{
|
||||
if (ini_sec->type == INI_CHOICE)
|
||||
{
|
||||
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)
|
||||
{
|
||||
free(kv->key);
|
||||
free(kv->val);
|
||||
//free(kv);
|
||||
}
|
||||
}
|
||||
free(ini_sec->name);
|
||||
//free(ini_sec);
|
||||
}
|
||||
|
||||
list_init(dst);
|
||||
}
|
||||
|
||||
ini_sec_t *ini_clone_section(ini_sec_t *cfg)
|
||||
{
|
||||
if (cfg == NULL)
|
||||
return NULL;
|
||||
|
||||
ini_sec_t *csec = (ini_sec_t *)malloc(sizeof(ini_sec_t));
|
||||
list_init(&csec->kvs);
|
||||
|
||||
LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg->kvs, link)
|
||||
{
|
||||
ini_kv_t *kvcfg = (ini_kv_t *)malloc(sizeof(ini_kv_t));
|
||||
kvcfg->key = _strdup(kv->key);
|
||||
kvcfg->val = _strdup(kv->val);
|
||||
list_append(&csec->kvs, &kvcfg->link);
|
||||
}
|
||||
|
||||
return csec;
|
||||
}
|
||||
|
||||
void ini_free_section(ini_sec_t *cfg)
|
||||
{
|
||||
if (cfg == NULL)
|
||||
return;
|
||||
|
||||
LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg->kvs, link)
|
||||
{
|
||||
free(kv->key);
|
||||
free(kv->val);
|
||||
//free(kv);
|
||||
}
|
||||
//free(cfg);
|
||||
|
||||
cfg = NULL;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
@@ -44,9 +44,6 @@ typedef struct _ini_sec_t
|
||||
} ini_sec_t;
|
||||
|
||||
int ini_parse(link_t *dst, char *ini_path, bool is_dir);
|
||||
void ini_free(link_t *dst);
|
||||
ini_sec_t *ini_clone_section(ini_sec_t *cfg);
|
||||
void ini_free_section(ini_sec_t *cfg);
|
||||
char *ini_check_payload_section(ini_sec_t *cfg);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018 Rajko Stojadinovic
|
||||
* 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,
|
||||
@@ -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,9 +32,9 @@
|
||||
#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
|
||||
|
||||
extern sdmmc_t sd_sdmmc;
|
||||
extern sdmmc_storage_t sd_storage;
|
||||
@@ -44,55 +45,56 @@ extern bool sd_mount();
|
||||
extern void sd_unmount();
|
||||
extern void emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage);
|
||||
|
||||
#pragma GCC push_options
|
||||
#pragma GCC optimize ("Os")
|
||||
|
||||
static int _dump_emmc_verify(sdmmc_storage_t *storage, u32 lba_curr, char *outFilename, emmc_part_t *part)
|
||||
{
|
||||
FIL fp;
|
||||
u8 sparseShouldVerify = 0;
|
||||
u8 sparseShouldVerify = 4;
|
||||
u32 btn = 0;
|
||||
u32 prevPct = 200;
|
||||
int res = 0;
|
||||
u32 sdFileSector = 0;
|
||||
int res = 0;
|
||||
|
||||
u8 hashEm[0x20];
|
||||
u8 hashSd[0x20];
|
||||
u8 hashEm[SHA256_SZ];
|
||||
u8 hashSd[SHA256_SZ];
|
||||
|
||||
if (f_open(&fp, outFilename, FA_READ) == FR_OK)
|
||||
{
|
||||
u32 totalSectorsVer = (u32)((u64)f_size(&fp) >> (u64)9);
|
||||
|
||||
const u32 NUM_SECTORS_PER_ITER = 8192; // 4MB Cache.
|
||||
|
||||
u8 *bufEm = (u8 *)EMMC_BUF_ALIGNED;
|
||||
u8 *bufSd = (u8 *)SDXC_BUF_ALIGNED;
|
||||
|
||||
u32 pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);
|
||||
tui_pbar(&gfx_con, 0, gfx_con.y, pct, 0xFF96FF00, 0xFF155500);
|
||||
tui_pbar(0, gfx_con.y, pct, 0xFF96FF00, 0xFF155500);
|
||||
|
||||
u32 num = 0;
|
||||
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.
|
||||
if ((h_cfg.verification & 2) || !(sparseShouldVerify % 4))
|
||||
if (!(sparseShouldVerify % 4))
|
||||
{
|
||||
if (!sdmmc_storage_read(storage, lba_curr, num, bufEm))
|
||||
{
|
||||
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;
|
||||
}
|
||||
f_lseek(&fp, sdFileSector);
|
||||
f_lseek(&fp, (u64)sdFileSector << (u64)9);
|
||||
if (f_read(&fp, bufSd, num << 9, NULL))
|
||||
{
|
||||
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;
|
||||
}
|
||||
@@ -105,31 +107,30 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
sparseShouldVerify++;
|
||||
sdFileSector += NUM_SECTORS_PER_ITER << 9;
|
||||
|
||||
pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);
|
||||
if (pct != prevPct)
|
||||
{
|
||||
tui_pbar(&gfx_con, 0, gfx_con.y, pct, 0xFF96FF00, 0xFF155500);
|
||||
tui_pbar(0, gfx_con.y, pct, 0xFF96FF00, 0xFF155500);
|
||||
prevPct = pct;
|
||||
}
|
||||
|
||||
lba_curr += num;
|
||||
totalSectorsVer -= num;
|
||||
sdFileSector += num;
|
||||
sparseShouldVerify++;
|
||||
|
||||
btn = btn_wait_timeout(0, BTN_VOL_DOWN | BTN_VOL_UP);
|
||||
if ((btn & BTN_VOL_DOWN) && (btn & BTN_VOL_UP))
|
||||
{
|
||||
gfx_con.fntsz = 16;
|
||||
WPRINTF("\n\nVerification was cancelled!");
|
||||
EPRINTF("\nPress any key...\n");
|
||||
gfx_con.fntsz = 8;
|
||||
msleep(1000);
|
||||
|
||||
f_close(&fp);
|
||||
@@ -139,7 +140,7 @@ static int _dump_emmc_verify(sdmmc_storage_t *storage, u32 lba_curr, char *outFi
|
||||
}
|
||||
f_close(&fp);
|
||||
|
||||
tui_pbar(&gfx_con, 0, gfx_con.y, pct, 0xFFCCCCCC, 0xFF555555);
|
||||
tui_pbar(0, gfx_con.y, pct, 0xFFCCCCCC, 0xFF555555);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -151,7 +152,7 @@ static int _dump_emmc_verify(sdmmc_storage_t *storage, u32 lba_curr, char *outFi
|
||||
}
|
||||
}
|
||||
|
||||
void _update_filename(char *outFilename, u32 sdPathLen, u32 numSplitParts, u32 currPartIdx)
|
||||
static void _update_filename(char *outFilename, u32 sdPathLen, u32 numSplitParts, u32 currPartIdx)
|
||||
{
|
||||
if (numSplitParts >= 10 && currPartIdx < 10)
|
||||
{
|
||||
@@ -181,10 +182,10 @@ 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(&gfx_con, "\nSD Card free space: %d MiB, Total backup size %d MiB\n\n",
|
||||
gfx_printf("\nSD Card free space: %d MiB, Total backup size %d MiB\n\n",
|
||||
sd_fs.free_clst * sd_fs.csize >> SECTORS_TO_MIB_COEFF,
|
||||
totalSectors >> SECTORS_TO_MIB_COEFF);
|
||||
|
||||
@@ -199,7 +200,7 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
|
||||
{
|
||||
isSmallSdCard = true;
|
||||
|
||||
gfx_printf(&gfx_con, "%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)
|
||||
{
|
||||
@@ -212,7 +213,7 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
|
||||
// Check if we are continuing a previous raw eMMC or USER partition backup in progress.
|
||||
if (f_open(&partialIdxFp, partialIdxFilename, FA_READ) == FR_OK && totalSectors > (FAT32_FILESIZE_LIMIT / NX_EMMC_BLOCKSIZE))
|
||||
{
|
||||
gfx_printf(&gfx_con, "%kFound Partial Backup in progress. Continuing...%k\n\n", 0xFFAEFD14, 0xFFCCCCCC);
|
||||
gfx_printf("%kFound Partial Backup in progress. Continuing...%k\n\n", 0xFFAEFD14, 0xFFCCCCCC);
|
||||
|
||||
partialDumpInProgress = true;
|
||||
// Force partial dumping, even if the card is larger.
|
||||
@@ -233,10 +234,10 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
|
||||
maxSplitParts += currPartIdx;
|
||||
}
|
||||
else if (isSmallSdCard)
|
||||
gfx_printf(&gfx_con, "%kPartial Backup enabled (with %d MiB parts)...%k\n\n", 0xFFFFBA00, multipartSplitSize >> 20, 0xFFCCCCCC);
|
||||
gfx_printf("%kPartial Backup enabled (with %d MiB parts)...%k\n\n", 0xFFFFBA00, multipartSplitSize >> 20, 0xFFCCCCCC);
|
||||
|
||||
// Check if filesystem is FAT32 or the free space is smaller and backup in parts.
|
||||
if (((sd_fs.fs_type != FS_EXFAT) && totalSectors > (FAT32_FILESIZE_LIMIT / NX_EMMC_BLOCKSIZE)) | isSmallSdCard)
|
||||
if (((sd_fs.fs_type != FS_EXFAT) && totalSectors > (FAT32_FILESIZE_LIMIT / NX_EMMC_BLOCKSIZE)) || isSmallSdCard)
|
||||
{
|
||||
u32 multipartSplitSectors = multipartSplitSize / NX_EMMC_BLOCKSIZE;
|
||||
numSplitParts = (totalSectors + multipartSplitSectors - 1) / multipartSplitSectors;
|
||||
@@ -248,7 +249,7 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
|
||||
}
|
||||
|
||||
FIL fp;
|
||||
gfx_con_getpos(&gfx_con, &gfx_con.savedx, &gfx_con.savedy);
|
||||
gfx_con_getpos(&gfx_con.savedx, &gfx_con.savedy);
|
||||
if (!f_open(&fp, outFilename, FA_READ))
|
||||
{
|
||||
f_close(&fp);
|
||||
@@ -261,10 +262,10 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
|
||||
if (!(btn_wait() & BTN_POWER))
|
||||
return 0;
|
||||
gfx_con.fntsz = 8;
|
||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, gfx_con.savedy, 48);
|
||||
gfx_clear_partial_grey(0x1B, gfx_con.savedy, 48);
|
||||
}
|
||||
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
|
||||
gfx_printf(&gfx_con, "Filename: %s\n\n", outFilename);
|
||||
gfx_con_setpos(gfx_con.savedx, gfx_con.savedy);
|
||||
gfx_printf("Filename: %s\n\n", outFilename);
|
||||
res = f_open(&fp, outFilename, FA_CREATE_ALWAYS | FA_WRITE);
|
||||
if (res)
|
||||
{
|
||||
@@ -274,8 +275,6 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
|
||||
return 0;
|
||||
}
|
||||
|
||||
const u32 NUM_SECTORS_PER_ITER = 8192;
|
||||
|
||||
u8 *buf = (u8 *)MIXD_BUF_ALIGNED;
|
||||
|
||||
u32 lba_curr = part->lba_start;
|
||||
@@ -292,7 +291,7 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
|
||||
lbaStartPart = lba_curr; // Update the start LBA for verification.
|
||||
}
|
||||
u64 totalSize = (u64)((u64)totalSectors << 9);
|
||||
if (!isSmallSdCard && sd_fs.fs_type == FS_EXFAT)
|
||||
if (!isSmallSdCard && (sd_fs.fs_type == FS_EXFAT || totalSize <= FAT32_FILESIZE_LIMIT))
|
||||
f_lseek(&fp, totalSize);
|
||||
else
|
||||
f_lseek(&fp, MIN(totalSize, multipartSplitSize));
|
||||
@@ -308,15 +307,12 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
|
||||
memset(&fp, 0, sizeof(fp));
|
||||
currPartIdx++;
|
||||
|
||||
if (h_cfg.verification)
|
||||
// Verify part.
|
||||
if (_dump_emmc_verify(storage, lbaStartPart, outFilename, part))
|
||||
{
|
||||
// Verify part.
|
||||
if (_dump_emmc_verify(storage, lbaStartPart, outFilename, part))
|
||||
{
|
||||
EPRINTF("\nPress any key and try again...\n");
|
||||
EPRINTF("\nPress any key and try again...\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
_update_filename(outFilename, sdPathLen, numSplitParts, currPartIdx);
|
||||
@@ -341,7 +337,7 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
|
||||
// More parts to backup that do not currently fit the sd card free space or fatal error.
|
||||
if (currPartIdx >= maxSplitParts)
|
||||
{
|
||||
gfx_puts(&gfx_con, "\n\n1. Press any key to unmount SD Card.\n\
|
||||
gfx_puts("\n\n1. Press any key to unmount SD Card.\n\
|
||||
2. Remove SD Card and move files to free space.\n\
|
||||
Don\'t move the partial.idx file!\n\
|
||||
3. Re-insert SD Card.\n\
|
||||
@@ -353,8 +349,8 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
|
||||
}
|
||||
|
||||
// Create next part.
|
||||
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
|
||||
gfx_printf(&gfx_con, "Filename: %s\n\n", outFilename);
|
||||
gfx_con_setpos(gfx_con.savedx, gfx_con.savedy);
|
||||
gfx_printf("Filename: %s\n\n", outFilename);
|
||||
lbaStartPart = lba_curr;
|
||||
res = f_open(&fp, outFilename, FA_CREATE_ALWAYS | FA_WRITE);
|
||||
if (res)
|
||||
@@ -364,6 +360,7 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bytesWritten = 0;
|
||||
|
||||
totalSize = (u64)((u64)totalSectors << 9);
|
||||
@@ -407,7 +404,7 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
|
||||
pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);
|
||||
if (pct != prevPct)
|
||||
{
|
||||
tui_pbar(&gfx_con, 0, gfx_con.y, pct, 0xFFCCCCCC, 0xFF555555);
|
||||
tui_pbar(0, gfx_con.y, pct, 0xFFCCCCCC, 0xFF555555);
|
||||
prevPct = pct;
|
||||
}
|
||||
|
||||
@@ -436,32 +433,29 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
tui_pbar(&gfx_con, 0, gfx_con.y, 100, 0xFFCCCCCC, 0xFF555555);
|
||||
tui_pbar(0, gfx_con.y, 100, 0xFFCCCCCC, 0xFF555555);
|
||||
|
||||
// Backup operation ended successfully.
|
||||
f_close(&fp);
|
||||
|
||||
if (h_cfg.verification)
|
||||
// Verify last part or single file backup.
|
||||
if (_dump_emmc_verify(storage, lbaStartPart, outFilename, part))
|
||||
{
|
||||
// Verify last part or single file backup.
|
||||
if (_dump_emmc_verify(storage, lbaStartPart, outFilename, part))
|
||||
{
|
||||
EPRINTF("\nPress any key and try again...\n");
|
||||
EPRINTF("\nPress any key and try again...\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
tui_pbar(&gfx_con, 0, gfx_con.y, 100, 0xFF96FF00, 0xFF155500);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
tui_pbar(0, gfx_con.y, 100, 0xFF96FF00, 0xFF155500);
|
||||
|
||||
gfx_con.fntsz = 16;
|
||||
// Remove partial backup index file if no fatal errors occurred.
|
||||
if (isSmallSdCard)
|
||||
{
|
||||
f_unlink(partialIdxFilename);
|
||||
gfx_printf(&gfx_con, "%k\n\nYou can now join the files\nand get the complete eMMC RAW GPP backup.", 0xFFCCCCCC);
|
||||
gfx_printf("%k\n\nYou can now join the files\nand get the complete eMMC RAW GPP backup.", 0xFFCCCCCC);
|
||||
}
|
||||
gfx_puts(&gfx_con, "\n\n");
|
||||
gfx_puts("\n\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -479,14 +473,14 @@ static void _dump_emmc_selected(emmcPartType_t dumpType)
|
||||
{
|
||||
int res = 0;
|
||||
u32 timer = 0;
|
||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
||||
tui_sbar(&gfx_con, true);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||
tui_sbar(true);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
if (!sd_mount())
|
||||
goto out;
|
||||
|
||||
gfx_puts(&gfx_con, "Checking for available free space...\n\n");
|
||||
gfx_puts("Checking for available free space...\n\n");
|
||||
// Get SD Card free space for Partial Backup.
|
||||
f_getfree("", &sd_fs.free_clst, NULL);
|
||||
|
||||
@@ -499,7 +493,7 @@ static void _dump_emmc_selected(emmcPartType_t dumpType)
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
char sdPath[80];
|
||||
char sdPath[OUT_FILENAME_SZ];
|
||||
// Create Restore folders, if they do not exist.
|
||||
emmcsn_path_impl(sdPath, "/restore", "", &storage);
|
||||
emmcsn_path_impl(sdPath, "/restore/partitions", "", &storage);
|
||||
@@ -515,11 +509,11 @@ 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;
|
||||
|
||||
gfx_printf(&gfx_con, "%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i,
|
||||
gfx_printf("%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i,
|
||||
bootPart.name, bootPart.lba_start, bootPart.lba_end, 0xFFCCCCCC);
|
||||
|
||||
sdmmc_storage_set_mmc_partition(&storage, i + 1);
|
||||
@@ -544,7 +538,7 @@ static void _dump_emmc_selected(emmcPartType_t dumpType)
|
||||
if ((dumpType & PART_SYSTEM) == 0 && strcmp(part->name, "USER"))
|
||||
continue;
|
||||
|
||||
gfx_printf(&gfx_con, "%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++,
|
||||
gfx_printf("%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++,
|
||||
part->name, part->lba_start, part->lba_end, 0xFFCCCCCC);
|
||||
|
||||
emmcsn_path_impl(sdPath, "/partitions", part->name, &storage);
|
||||
@@ -567,7 +561,7 @@ static void _dump_emmc_selected(emmcPartType_t dumpType)
|
||||
rawPart.lba_end = RAW_AREA_NUM_SECTORS - 1;
|
||||
strcpy(rawPart.name, "rawnand.bin");
|
||||
{
|
||||
gfx_printf(&gfx_con, "%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++,
|
||||
gfx_printf("%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++,
|
||||
rawPart.name, rawPart.lba_start, rawPart.lba_end, 0xFFCCCCCC);
|
||||
|
||||
emmcsn_path_impl(sdPath, "", rawPart.name, &storage);
|
||||
@@ -576,14 +570,12 @@ static void _dump_emmc_selected(emmcPartType_t dumpType)
|
||||
}
|
||||
}
|
||||
|
||||
gfx_putc(&gfx_con, '\n');
|
||||
gfx_putc('\n');
|
||||
timer = get_tmr_s() - timer;
|
||||
gfx_printf(&gfx_con, "Time taken: %dm %ds.\n", timer / 60, timer % 60);
|
||||
gfx_printf("Time taken: %dm %ds.\n", timer / 60, timer % 60);
|
||||
sdmmc_storage_end(&storage);
|
||||
if (res && h_cfg.verification)
|
||||
gfx_printf(&gfx_con, "\n%kFinished and verified!%k\nPress any key...\n", 0xFF96FF00, 0xFFCCCCCC);
|
||||
else if (res)
|
||||
gfx_printf(&gfx_con, "\nFinished! Press any key...\n");
|
||||
if (res)
|
||||
gfx_printf("\n%kFinished and verified!%k\nPress any key...\n", 0xFF96FF00, 0xFFCCCCCC);
|
||||
|
||||
out:
|
||||
sd_unmount();
|
||||
@@ -612,9 +604,10 @@ static int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part
|
||||
|
||||
FIL fp;
|
||||
FILINFO fno;
|
||||
gfx_printf(&gfx_con, "\nFilename: %s\n", outFilename);
|
||||
|
||||
bool use_multipart = false;
|
||||
gfx_con_getpos(&gfx_con.savedx, &gfx_con.savedy);
|
||||
|
||||
bool use_multipart = false;
|
||||
|
||||
if (allow_multi_part)
|
||||
{
|
||||
@@ -622,10 +615,7 @@ static int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part
|
||||
if (f_stat(outFilename, &fno))
|
||||
{
|
||||
// If not, check if there are partial files and the total size matches.
|
||||
gfx_printf(&gfx_con, "\nFile not found, checking for part files.\n");
|
||||
|
||||
// Store console pos, so we dont take too much room.
|
||||
gfx_con_getpos(&gfx_con, &gfx_con.savedx, &gfx_con.savedy);
|
||||
gfx_printf("No single file, checking for part files...\n");
|
||||
|
||||
outFilename[sdPathLen++] = '.';
|
||||
|
||||
@@ -634,8 +624,8 @@ static int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part
|
||||
{
|
||||
_update_filename(outFilename, sdPathLen, 99, numSplitParts);
|
||||
|
||||
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
|
||||
gfx_printf(&gfx_con, "\nFilename: %s\n", outFilename);
|
||||
gfx_con_setpos(gfx_con.savedx, gfx_con.savedy);
|
||||
gfx_printf("\nFilename: %s\n", outFilename);
|
||||
|
||||
if (f_stat(outFilename, &fno))
|
||||
{
|
||||
@@ -648,7 +638,7 @@ static int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part
|
||||
numSplitParts++;
|
||||
}
|
||||
|
||||
gfx_printf(&gfx_con, "\n%X sectors total.\n", (u32)((u64)totalCheckFileSize >> (u64)9));
|
||||
gfx_printf("\n%X sectors total.\n", (u32)((u64)totalCheckFileSize >> (u64)9));
|
||||
|
||||
if ((u32)((u64)totalCheckFileSize >> (u64)9) != totalSectors)
|
||||
{
|
||||
@@ -665,9 +655,9 @@ static int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part
|
||||
}
|
||||
}
|
||||
|
||||
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
|
||||
|
||||
res = f_open(&fp, outFilename, FA_READ);
|
||||
gfx_con_setpos(gfx_con.savedx, gfx_con.savedy);
|
||||
gfx_printf("\nFilename: %s\n", outFilename);
|
||||
if (res)
|
||||
{
|
||||
if (res != FR_NO_FILE)
|
||||
@@ -689,12 +679,10 @@ static int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part
|
||||
else
|
||||
{
|
||||
fileSize = (u64)f_size(&fp);
|
||||
gfx_printf(&gfx_con, "\nTotal restore size: %d MiB.\n\n",
|
||||
((u32)((use_multipart ? ((u64)totalCheckFileSize >> (u64)9) : fileSize) >> (u64)9)) >> SECTORS_TO_MIB_COEFF);
|
||||
gfx_printf("\nTotal restore size: %d MiB.\n\n",
|
||||
(u32)((use_multipart ? (u64)totalCheckFileSize : fileSize) >> (u64)9) >> SECTORS_TO_MIB_COEFF);
|
||||
}
|
||||
|
||||
const u32 NUM_SECTORS_PER_ITER = 8192; // 4MB Cache.
|
||||
|
||||
u8 *buf = (u8 *)MIXD_BUF_ALIGNED;
|
||||
|
||||
u32 lba_curr = part->lba_start;
|
||||
@@ -705,7 +693,7 @@ static int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part
|
||||
u32 num = 0;
|
||||
u32 pct = 0;
|
||||
|
||||
gfx_con_getpos(&gfx_con, &gfx_con.savedx, &gfx_con.savedy);
|
||||
gfx_con_getpos(&gfx_con.savedx, &gfx_con.savedy);
|
||||
|
||||
while (totalSectors > 0)
|
||||
{
|
||||
@@ -717,22 +705,19 @@ static int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part
|
||||
memset(&fp, 0, sizeof(fp));
|
||||
currPartIdx++;
|
||||
|
||||
if (h_cfg.verification)
|
||||
// Verify part.
|
||||
if (_dump_emmc_verify(storage, lbaStartPart, outFilename, part))
|
||||
{
|
||||
// Verify part.
|
||||
if (_dump_emmc_verify(storage, lbaStartPart, outFilename, part))
|
||||
{
|
||||
EPRINTF("\nPress any key and try again...\n");
|
||||
EPRINTF("\nPress any key and try again...\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
_update_filename(outFilename, sdPathLen, numSplitParts, currPartIdx);
|
||||
|
||||
// Read from next part.
|
||||
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
|
||||
gfx_printf(&gfx_con, "Filename: %s\n\n", outFilename);
|
||||
gfx_con_setpos(gfx_con.savedx, gfx_con.savedy);
|
||||
gfx_printf("Filename: %s\n\n", outFilename);
|
||||
|
||||
lbaStartPart = lba_curr;
|
||||
|
||||
@@ -782,7 +767,7 @@ static int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part
|
||||
pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);
|
||||
if (pct != prevPct)
|
||||
{
|
||||
tui_pbar(&gfx_con, 0, gfx_con.y, pct, 0xFFCCCCCC, 0xFF555555);
|
||||
tui_pbar(0, gfx_con.y, pct, 0xFFCCCCCC, 0xFF555555);
|
||||
prevPct = pct;
|
||||
}
|
||||
|
||||
@@ -790,26 +775,23 @@ static int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part
|
||||
totalSectors -= num;
|
||||
bytesWritten += num * NX_EMMC_BLOCKSIZE;
|
||||
}
|
||||
tui_pbar(&gfx_con, 0, gfx_con.y, 100, 0xFFCCCCCC, 0xFF555555);
|
||||
tui_pbar(0, gfx_con.y, 100, 0xFFCCCCCC, 0xFF555555);
|
||||
|
||||
// Restore operation ended successfully.
|
||||
f_close(&fp);
|
||||
|
||||
if (h_cfg.verification)
|
||||
// Verify restored data.
|
||||
if (_dump_emmc_verify(storage, lbaStartPart, outFilename, part))
|
||||
{
|
||||
// Verify restored data.
|
||||
if (_dump_emmc_verify(storage, lbaStartPart, outFilename, part))
|
||||
{
|
||||
EPRINTF("\nPress any key and try again...\n");
|
||||
EPRINTF("\nPress any key and try again...\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
tui_pbar(&gfx_con, 0, gfx_con.y, 100, 0xFF96FF00, 0xFF155500);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
tui_pbar(0, gfx_con.y, 100, 0xFF96FF00, 0xFF155500);
|
||||
|
||||
gfx_con.fntsz = 16;
|
||||
gfx_puts(&gfx_con, "\n\n");
|
||||
gfx_puts("\n\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -818,33 +800,33 @@ static void _restore_emmc_selected(emmcPartType_t restoreType)
|
||||
{
|
||||
int res = 0;
|
||||
u32 timer = 0;
|
||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
||||
tui_sbar(&gfx_con, true);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||
tui_sbar(true);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
gfx_printf(&gfx_con, "%kThis may render your device inoperative!\n\n", 0xFFFFDD00);
|
||||
gfx_printf(&gfx_con, "Are you really sure?\n\n%k", 0xFFCCCCCC);
|
||||
gfx_printf("%kThis may render your device inoperative!\n\n", 0xFFFFDD00);
|
||||
gfx_printf("Are you really sure?\n\n%k", 0xFFCCCCCC);
|
||||
if ((restoreType & PART_BOOT) || (restoreType & PART_GP_ALL))
|
||||
{
|
||||
gfx_puts(&gfx_con, "The mode you selected will only restore\nthe ");
|
||||
gfx_puts("The mode you selected will only restore\nthe ");
|
||||
if (restoreType & PART_BOOT)
|
||||
gfx_puts(&gfx_con, "boot ");
|
||||
gfx_puts(&gfx_con, "partitions that it can find.\n");
|
||||
gfx_puts(&gfx_con, "If it is not found, it will be skipped\nand continue with the next.\n\n");
|
||||
gfx_puts("boot ");
|
||||
gfx_puts("partitions that it can find.\n");
|
||||
gfx_puts("If it is not found, it will be skipped\nand continue with the next.\n\n");
|
||||
}
|
||||
gfx_con_getpos(&gfx_con, &gfx_con.savedx, &gfx_con.savedy);
|
||||
gfx_con_getpos(&gfx_con.savedx, &gfx_con.savedy);
|
||||
|
||||
u8 failsafe_wait = 10;
|
||||
while (failsafe_wait > 0)
|
||||
{
|
||||
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
|
||||
gfx_printf(&gfx_con, "%kWait... (%ds) %k", 0xFF888888, failsafe_wait, 0xFFCCCCCC);
|
||||
gfx_con_setpos(gfx_con.savedx, gfx_con.savedy);
|
||||
gfx_printf("%kWait... (%ds) %k", 0xFF888888, failsafe_wait, 0xFFCCCCCC);
|
||||
msleep(1000);
|
||||
failsafe_wait--;
|
||||
}
|
||||
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
|
||||
gfx_con_setpos(gfx_con.savedx, gfx_con.savedy);
|
||||
|
||||
gfx_puts(&gfx_con, "Press POWER to Continue.\nPress VOL to go to the menu.\n\n\n");
|
||||
gfx_puts("Press POWER to Continue.\nPress VOL to go to the menu.\n\n\n");
|
||||
|
||||
u32 btn = btn_wait();
|
||||
if (!(btn & BTN_POWER))
|
||||
@@ -862,7 +844,7 @@ static void _restore_emmc_selected(emmcPartType_t restoreType)
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
char sdPath[80];
|
||||
char sdPath[OUT_FILENAME_SZ];
|
||||
|
||||
timer = get_tmr_s();
|
||||
if (restoreType & PART_BOOT)
|
||||
@@ -875,11 +857,11 @@ 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;
|
||||
|
||||
gfx_printf(&gfx_con, "%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i,
|
||||
gfx_printf("%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i,
|
||||
bootPart.name, bootPart.lba_start, bootPart.lba_end, 0xFFCCCCCC);
|
||||
|
||||
sdmmc_storage_set_mmc_partition(&storage, i + 1);
|
||||
@@ -897,7 +879,7 @@ static void _restore_emmc_selected(emmcPartType_t restoreType)
|
||||
nx_emmc_gpt_parse(&gpt, &storage);
|
||||
LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link)
|
||||
{
|
||||
gfx_printf(&gfx_con, "%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++,
|
||||
gfx_printf("%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++,
|
||||
part->name, part->lba_start, part->lba_end, 0xFFCCCCCC);
|
||||
|
||||
emmcsn_path_impl(sdPath, "/restore/partitions/", part->name, &storage);
|
||||
@@ -917,7 +899,7 @@ static void _restore_emmc_selected(emmcPartType_t restoreType)
|
||||
rawPart.lba_end = RAW_AREA_NUM_SECTORS - 1;
|
||||
strcpy(rawPart.name, "rawnand.bin");
|
||||
{
|
||||
gfx_printf(&gfx_con, "%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++,
|
||||
gfx_printf("%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++,
|
||||
rawPart.name, rawPart.lba_start, rawPart.lba_end, 0xFFCCCCCC);
|
||||
|
||||
emmcsn_path_impl(sdPath, "/restore", rawPart.name, &storage);
|
||||
@@ -925,14 +907,12 @@ static void _restore_emmc_selected(emmcPartType_t restoreType)
|
||||
}
|
||||
}
|
||||
|
||||
gfx_putc(&gfx_con, '\n');
|
||||
gfx_putc('\n');
|
||||
timer = get_tmr_s() - timer;
|
||||
gfx_printf(&gfx_con, "Time taken: %dm %ds.\n", timer / 60, timer % 60);
|
||||
gfx_printf("Time taken: %dm %ds.\n", timer / 60, timer % 60);
|
||||
sdmmc_storage_end(&storage);
|
||||
if (res && h_cfg.verification)
|
||||
gfx_printf(&gfx_con, "\n%kFinished and verified!%k\nPress any key...\n", 0xFF96FF00, 0xFFCCCCCC);
|
||||
else if (res)
|
||||
gfx_printf(&gfx_con, "\nFinished! Press any key...\n");
|
||||
if (res)
|
||||
gfx_printf("\n%kFinished and verified!%k\nPress any key...\n", 0xFF96FF00, 0xFFCCCCCC);
|
||||
|
||||
out:
|
||||
sd_unmount();
|
||||
@@ -942,3 +922,5 @@ out:
|
||||
void restore_emmc_boot() { _restore_emmc_selected(PART_BOOT); }
|
||||
void restore_emmc_rawnand() { _restore_emmc_selected(PART_RAW); }
|
||||
void restore_emmc_gpp_parts() { _restore_emmc_selected(PART_GP_ALL); }
|
||||
|
||||
#pragma GCC pop_options
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2019 CTCaer
|
||||
* Copyright (c) 2018-2020 CTCaer
|
||||
* Copyright (c) 2018 balika011
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -46,10 +46,13 @@ extern void sd_unmount();
|
||||
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")
|
||||
|
||||
void print_fuseinfo()
|
||||
{
|
||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
u32 burntFuses = 0;
|
||||
for (u32 i = 0; i < 32; i++)
|
||||
@@ -58,26 +61,26 @@ void print_fuseinfo()
|
||||
burntFuses++;
|
||||
}
|
||||
|
||||
gfx_printf(&gfx_con, "\nSKU: %X - ", FUSE(FUSE_SKU_INFO));
|
||||
gfx_printf("\nSKU: %X - ", FUSE(FUSE_SKU_INFO));
|
||||
switch (fuse_read_odm(4) & 3)
|
||||
{
|
||||
case 0:
|
||||
gfx_printf(&gfx_con, "Retail\n");
|
||||
gfx_printf("Retail\n");
|
||||
break;
|
||||
case 3:
|
||||
gfx_printf(&gfx_con, "Dev\n");
|
||||
gfx_printf("Dev\n");
|
||||
break;
|
||||
}
|
||||
gfx_printf(&gfx_con, "Sdram ID: %d\n", (fuse_read_odm(4) >> 3) & 0x1F);
|
||||
gfx_printf(&gfx_con, "Burnt fuses: %d / 64\n", burntFuses);
|
||||
gfx_printf(&gfx_con, "Secure key: %08X%08X%08X%08X\n\n\n",
|
||||
gfx_printf("Sdram ID: %d\n", (fuse_read_odm(4) >> 3) & 0x1F);
|
||||
gfx_printf("Burnt fuses: %d / 64\n", burntFuses);
|
||||
gfx_printf("Secure key: %08X%08X%08X%08X\n\n\n",
|
||||
byte_swap_32(FUSE(FUSE_PRIVATE_KEY0)), byte_swap_32(FUSE(FUSE_PRIVATE_KEY1)),
|
||||
byte_swap_32(FUSE(FUSE_PRIVATE_KEY2)), byte_swap_32(FUSE(FUSE_PRIVATE_KEY3)));
|
||||
|
||||
gfx_printf(&gfx_con, "%k(Unlocked) fuse cache:\n\n%k", 0xFF00DDFF, 0xFFCCCCCC);
|
||||
gfx_hexdump(&gfx_con, 0x7000F900, (u8 *)0x7000F900, 0x2FC);
|
||||
gfx_printf("%k(Unlocked) fuse cache:\n\n%k", 0xFF00DDFF, 0xFFCCCCCC);
|
||||
gfx_hexdump(0x7000F900, (u8 *)0x7000F900, 0x300);
|
||||
|
||||
gfx_puts(&gfx_con, "\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
|
||||
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)
|
||||
@@ -85,9 +88,16 @@ void print_fuseinfo()
|
||||
if (sd_mount())
|
||||
{
|
||||
char path[64];
|
||||
emmcsn_path_impl(path, "/dumps", "fuses.bin", NULL);
|
||||
if (!sd_save_to_file((u8 *)0x7000F900, 0x2FC, path))
|
||||
gfx_puts(&gfx_con, "\nDone!\n");
|
||||
emmcsn_path_impl(path, "/dumps", "fuse_cached.bin", NULL);
|
||||
if (!sd_save_to_file((u8 *)0x7000F900, 0x300, path))
|
||||
gfx_puts("\nfuse_cached.bin saved!\n");
|
||||
|
||||
u32 words[192];
|
||||
fuse_read_array(words);
|
||||
emmcsn_path_impl(path, "/dumps", "fuse_array_raw.bin", NULL);
|
||||
if (!sd_save_to_file((u8 *)words, sizeof(words), path))
|
||||
gfx_puts("\nfuse_array_raw.bin saved!\n");
|
||||
|
||||
sd_unmount();
|
||||
}
|
||||
|
||||
@@ -97,17 +107,17 @@ void print_fuseinfo()
|
||||
|
||||
void print_kfuseinfo()
|
||||
{
|
||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
gfx_printf(&gfx_con, "%kKFuse contents:\n\n%k", 0xFF00DDFF, 0xFFCCCCCC);
|
||||
gfx_printf("%kKFuse contents:\n\n%k", 0xFF00DDFF, 0xFFCCCCCC);
|
||||
u32 buf[KFUSE_NUM_WORDS];
|
||||
if (!kfuse_read(buf))
|
||||
EPRINTF("CRC fail.");
|
||||
else
|
||||
gfx_hexdump(&gfx_con, 0, (u8 *)buf, KFUSE_NUM_WORDS * 4);
|
||||
gfx_hexdump(0, (u8 *)buf, KFUSE_NUM_WORDS * 4);
|
||||
|
||||
gfx_puts(&gfx_con, "\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
|
||||
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)
|
||||
@@ -117,7 +127,7 @@ void print_kfuseinfo()
|
||||
char path[64];
|
||||
emmcsn_path_impl(path, "/dumps", "kfuses.bin", NULL);
|
||||
if (!sd_save_to_file((u8 *)buf, KFUSE_NUM_WORDS * 4, path))
|
||||
gfx_puts(&gfx_con, "\nDone!\n");
|
||||
gfx_puts("\nDone!\n");
|
||||
sd_unmount();
|
||||
}
|
||||
|
||||
@@ -127,8 +137,8 @@ void print_kfuseinfo()
|
||||
|
||||
void print_mmc_info()
|
||||
{
|
||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
static const u32 SECTORS_TO_MIB_COEFF = 11;
|
||||
|
||||
@@ -145,12 +155,12 @@ void print_mmc_info()
|
||||
u16 card_type;
|
||||
u32 speed = 0;
|
||||
|
||||
gfx_printf(&gfx_con, "%kCID:%k\n", 0xFF00DDFF, 0xFFCCCCCC);
|
||||
gfx_printf("%kCID:%k\n", 0xFF00DDFF, 0xFFCCCCCC);
|
||||
switch (storage.csd.mmca_vsn)
|
||||
{
|
||||
case 0: /* MMC v1.0 - v1.2 */
|
||||
case 1: /* MMC v1.4 */
|
||||
gfx_printf(&gfx_con,
|
||||
gfx_printf(
|
||||
" Vendor ID: %03X\n"
|
||||
" Model: %c%c%c%c%c%c%c\n"
|
||||
" HW rev: %X\n"
|
||||
@@ -166,7 +176,7 @@ void print_mmc_info()
|
||||
case 2: /* MMC v2.0 - v2.2 */
|
||||
case 3: /* MMC v3.1 - v3.3 */
|
||||
case 4: /* MMC v4 */
|
||||
gfx_printf(&gfx_con,
|
||||
gfx_printf(
|
||||
" Vendor ID: %X\n"
|
||||
" Card/BGA: %X\n"
|
||||
" OEM ID: %02X\n"
|
||||
@@ -188,45 +198,38 @@ void print_mmc_info()
|
||||
EPRINTF("Unknown CSD structure.");
|
||||
else
|
||||
{
|
||||
gfx_printf(&gfx_con, "%kExtended CSD V1.%d:%k\n",
|
||||
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(&gfx_con,
|
||||
gfx_printf(
|
||||
" Spec Version: %02X\n"
|
||||
" Extended Rev: 1.%d\n"
|
||||
" Dev Version: %d\n"
|
||||
@@ -239,26 +242,26 @@ void print_mmc_info()
|
||||
storage.csd.capacity == (4096 * 512) ? "High" : "Low", speed & 0xFFFF, (speed >> 16) & 0xFFFF,
|
||||
storage.csd.busspeed);
|
||||
gfx_con.fntsz = 8;
|
||||
gfx_printf(&gfx_con, "%s", card_type_support);
|
||||
gfx_printf("%s", card_type_support);
|
||||
gfx_con.fntsz = 16;
|
||||
gfx_printf(&gfx_con, "\n\n", card_type_support);
|
||||
gfx_printf("\n\n", card_type_support);
|
||||
|
||||
u32 boot_size = storage.ext_csd.boot_mult << 17;
|
||||
u32 rpmb_size = storage.ext_csd.rpmb_mult << 17;
|
||||
gfx_printf(&gfx_con, "%keMMC Partitions:%k\n", 0xFF00DDFF, 0xFFCCCCCC);
|
||||
gfx_printf(&gfx_con, " 1: %kBOOT0 %k\n Size: %5d KiB (LBA Sectors: 0x%07X)\n", 0xFF96FF00, 0xFFCCCCCC,
|
||||
boot_size / 1024, boot_size / 1024 / 512);
|
||||
gfx_put_small_sep(&gfx_con);
|
||||
gfx_printf(&gfx_con, " 2: %kBOOT1 %k\n Size: %5d KiB (LBA Sectors: 0x%07X)\n", 0xFF96FF00, 0xFFCCCCCC,
|
||||
boot_size / 1024, boot_size / 1024 / 512);
|
||||
gfx_put_small_sep(&gfx_con);
|
||||
gfx_printf(&gfx_con, " 3: %kRPMB %k\n Size: %5d KiB (LBA Sectors: 0x%07X)\n", 0xFF96FF00, 0xFFCCCCCC,
|
||||
rpmb_size / 1024, rpmb_size / 1024 / 512);
|
||||
gfx_put_small_sep(&gfx_con);
|
||||
gfx_printf(&gfx_con, " 0: %kGPP (USER) %k\n Size: %5d MiB (LBA Sectors: 0x%07X)\n\n", 0xFF96FF00, 0xFFCCCCCC,
|
||||
gfx_printf("%keMMC Partitions:%k\n", 0xFF00DDFF, 0xFFCCCCCC);
|
||||
gfx_printf(" 1: %kBOOT0 %k\n Size: %5d KiB (LBA Sectors: 0x%07X)\n", 0xFF96FF00, 0xFFCCCCCC,
|
||||
boot_size / 1024, boot_size / 512);
|
||||
gfx_put_small_sep();
|
||||
gfx_printf(" 2: %kBOOT1 %k\n Size: %5d KiB (LBA Sectors: 0x%07X)\n", 0xFF96FF00, 0xFFCCCCCC,
|
||||
boot_size / 1024, boot_size / 512);
|
||||
gfx_put_small_sep();
|
||||
gfx_printf(" 3: %kRPMB %k\n Size: %5d KiB (LBA Sectors: 0x%07X)\n", 0xFF96FF00, 0xFFCCCCCC,
|
||||
rpmb_size / 1024, rpmb_size / 512);
|
||||
gfx_put_small_sep();
|
||||
gfx_printf(" 0: %kGPP (USER) %k\n Size: %5d MiB (LBA Sectors: 0x%07X)\n\n", 0xFF96FF00, 0xFFCCCCCC,
|
||||
storage.sec_cnt >> SECTORS_TO_MIB_COEFF, storage.sec_cnt);
|
||||
gfx_put_small_sep(&gfx_con);
|
||||
gfx_printf(&gfx_con, "%kGPP (eMMC USER) partition table:%k\n", 0xFF00DDFF, 0xFFCCCCCC);
|
||||
gfx_put_small_sep();
|
||||
gfx_printf("%kGPP (eMMC USER) partition table:%k\n", 0xFF00DDFF, 0xFFCCCCCC);
|
||||
|
||||
sdmmc_storage_set_mmc_partition(&storage, 0);
|
||||
LIST_INIT(gpt);
|
||||
@@ -266,10 +269,10 @@ void print_mmc_info()
|
||||
int gpp_idx = 0;
|
||||
LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link)
|
||||
{
|
||||
gfx_printf(&gfx_con, " %02d: %k%s%k\n Size: % 5d MiB (LBA Sectors 0x%07X)\n LBA Range: %08X-%08X\n",
|
||||
gfx_printf(" %02d: %k%s%k\n Size: % 5d MiB (LBA Sectors 0x%07X)\n LBA Range: %08X-%08X\n",
|
||||
gpp_idx++, 0xFFAEFD14, part->name, 0xFFCCCCCC, (part->lba_end - part->lba_start + 1) >> SECTORS_TO_MIB_COEFF,
|
||||
part->lba_end - part->lba_start + 1, part->lba_start, part->lba_end);
|
||||
gfx_put_small_sep(&gfx_con);
|
||||
gfx_put_small_sep();
|
||||
}
|
||||
nx_emmc_gpt_free(&gpt);
|
||||
}
|
||||
@@ -285,15 +288,13 @@ void print_sdcard_info()
|
||||
{
|
||||
static const u32 SECTORS_TO_MIB_COEFF = 11;
|
||||
|
||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
if (sd_mount())
|
||||
{
|
||||
u32 capacity;
|
||||
|
||||
gfx_printf(&gfx_con, "%kCard IDentification:%k\n", 0xFF00DDFF, 0xFFCCCCCC);
|
||||
gfx_printf(&gfx_con,
|
||||
gfx_printf("%kCard IDentification:%k\n", 0xFF00DDFF, 0xFFCCCCCC);
|
||||
gfx_printf(
|
||||
" Vendor ID: %02x\n"
|
||||
" OEM ID: %c%c\n"
|
||||
" Model: %c%c%c%c%c\n"
|
||||
@@ -307,9 +308,8 @@ void print_sdcard_info()
|
||||
sd_storage.cid.hwrev, sd_storage.cid.fwrev, sd_storage.cid.serial,
|
||||
sd_storage.cid.month, sd_storage.cid.year);
|
||||
|
||||
gfx_printf(&gfx_con, "%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(&gfx_con,
|
||||
gfx_printf("%kCard-Specific Data V%d.0:%k\n", 0xFF00DDFF, sd_storage.csd.structure + 1, 0xFFCCCCCC);
|
||||
gfx_printf(
|
||||
" Cmd Classes: %02X\n"
|
||||
" Capacity: %d MiB\n"
|
||||
" Bus Width: %d\n"
|
||||
@@ -319,14 +319,14 @@ 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);
|
||||
|
||||
gfx_puts(&gfx_con, "Acquiring FAT volume info...\n\n");
|
||||
gfx_puts("Acquiring FAT volume info...\n\n");
|
||||
f_getfree("", &sd_fs.free_clst, NULL);
|
||||
gfx_printf(&gfx_con, "%kFound %s volume:%k\n Free: %d MiB\n Cluster: %d KiB\n",
|
||||
gfx_printf("%kFound %s volume:%k\n Free: %d MiB\n Cluster: %d KiB\n",
|
||||
0xFF00DDFF, sd_fs.fs_type == FS_EXFAT ? "exFAT" : "FAT32", 0xFFCCCCCC,
|
||||
sd_fs.free_clst * sd_fs.csize >> SECTORS_TO_MIB_COEFF, (sd_fs.csize > 1) ? (sd_fs.csize >> 1) : 512);
|
||||
sd_unmount();
|
||||
@@ -337,8 +337,8 @@ void print_sdcard_info()
|
||||
|
||||
void print_tsec_key()
|
||||
{
|
||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
u32 retries = 0;
|
||||
|
||||
@@ -372,12 +372,14 @@ void print_tsec_key()
|
||||
tsec_ctxt.size = 0xF00;
|
||||
else if (pkg1_id->kb == KB_FIRMWARE_VERSION_620)
|
||||
tsec_ctxt.size = 0x2900;
|
||||
else
|
||||
else if (pkg1_id->kb == KB_FIRMWARE_VERSION_700)
|
||||
{
|
||||
tsec_ctxt.size = 0x3000;
|
||||
// Exit after TSEC key generation.
|
||||
*((vu16 *)((u32)tsec_ctxt.fw + 0x2DB5)) = 0x02F8;
|
||||
}
|
||||
else
|
||||
tsec_ctxt.size = 0x3300;
|
||||
|
||||
if (pkg1_id->kb == KB_FIRMWARE_VERSION_620)
|
||||
{
|
||||
@@ -401,25 +403,24 @@ void print_tsec_key()
|
||||
}
|
||||
}
|
||||
|
||||
gfx_printf(&gfx_con, "%kTSEC key: %k", 0xFF00DDFF, 0xFFCCCCCC);
|
||||
gfx_printf("%kTSEC key: %k", 0xFF00DDFF, 0xFFCCCCCC);
|
||||
|
||||
if (res >= 0)
|
||||
{
|
||||
for (u32 j = 0; j < 0x10; j++)
|
||||
gfx_printf(&gfx_con, "%02X", keys[j]);
|
||||
|
||||
gfx_printf("%02X", keys[j]);
|
||||
|
||||
if (pkg1_id->kb == KB_FIRMWARE_VERSION_620)
|
||||
{
|
||||
gfx_printf(&gfx_con, "\n%kTSEC root: %k", 0xFF00DDFF, 0xFFCCCCCC);
|
||||
gfx_printf("\n%kTSEC root: %k", 0xFF00DDFF, 0xFFCCCCCC);
|
||||
for (u32 j = 0; j < 0x10; j++)
|
||||
gfx_printf(&gfx_con, "%02X", keys[0x10 + j]);
|
||||
gfx_printf("%02X", keys[0x10 + j]);
|
||||
}
|
||||
}
|
||||
else
|
||||
EPRINTFARGS("ERROR %X\n", res);
|
||||
|
||||
gfx_puts(&gfx_con, "\n\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
|
||||
gfx_puts("\n\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
|
||||
|
||||
u32 btn = btn_wait();
|
||||
if (btn & BTN_POWER)
|
||||
@@ -429,7 +430,7 @@ void print_tsec_key()
|
||||
char path[64];
|
||||
emmcsn_path_impl(path, "/dumps", "tsec_keys.bin", NULL);
|
||||
if (!sd_save_to_file(keys, 0x10 * 2, path))
|
||||
gfx_puts(&gfx_con, "\nDone!\n");
|
||||
gfx_puts("\nDone!\n");
|
||||
sd_unmount();
|
||||
}
|
||||
}
|
||||
@@ -447,127 +448,124 @@ void print_fuel_gauge_info()
|
||||
{
|
||||
int value = 0;
|
||||
|
||||
gfx_printf(&gfx_con, "%kFuel Gauge IC Info:\n%k", 0xFF00DDFF, 0xFFCCCCCC);
|
||||
|
||||
max17050_get_property(MAX17050_Age, &value);
|
||||
gfx_printf(&gfx_con, "Age: %3d%\n", value);
|
||||
gfx_printf("%kFuel Gauge IC Info:\n%k", 0xFF00DDFF, 0xFFCCCCCC);
|
||||
|
||||
max17050_get_property(MAX17050_RepSOC, &value);
|
||||
gfx_printf(&gfx_con, "Capacity now: %3d%\n", value >> 8);
|
||||
gfx_printf("Capacity now: %3d%\n", value >> 8);
|
||||
|
||||
max17050_get_property(MAX17050_RepCap, &value);
|
||||
gfx_printf(&gfx_con, "Capacity now: %4d mAh\n", value);
|
||||
gfx_printf("Capacity now: %4d mAh\n", value);
|
||||
|
||||
max17050_get_property(MAX17050_FullCAP, &value);
|
||||
gfx_printf(&gfx_con, "Capacity full: %4d mAh\n", value);
|
||||
gfx_printf("Capacity full: %4d mAh\n", value);
|
||||
|
||||
max17050_get_property(MAX17050_DesignCap, &value);
|
||||
gfx_printf(&gfx_con, "Capacity (design): %4d mAh\n", value);
|
||||
gfx_printf("Capacity (design): %4d mAh\n", value);
|
||||
|
||||
max17050_get_property(MAX17050_Current, &value);
|
||||
if (value >= 0)
|
||||
gfx_printf(&gfx_con, "Current now: %d mA\n", value / 1000);
|
||||
gfx_printf("Current now: %d mA\n", value / 1000);
|
||||
else
|
||||
gfx_printf(&gfx_con, "Current now: -%d mA\n", ~value / 1000);
|
||||
gfx_printf("Current now: -%d mA\n", ~value / 1000);
|
||||
|
||||
max17050_get_property(MAX17050_AvgCurrent, &value);
|
||||
if (value >= 0)
|
||||
gfx_printf(&gfx_con, "Current average: %d mA\n", value / 1000);
|
||||
gfx_printf("Current average: %d mA\n", value / 1000);
|
||||
else
|
||||
gfx_printf(&gfx_con, "Current average: -%d mA\n", ~value / 1000);
|
||||
gfx_printf("Current average: -%d mA\n", ~value / 1000);
|
||||
|
||||
max17050_get_property(MAX17050_VCELL, &value);
|
||||
gfx_printf(&gfx_con, "Voltage now: %4d mV\n", value);
|
||||
gfx_printf("Voltage now: %4d mV\n", value);
|
||||
|
||||
max17050_get_property(MAX17050_OCVInternal, &value);
|
||||
gfx_printf(&gfx_con, "Voltage open-circuit: %4d mV\n", value);
|
||||
gfx_printf("Voltage open-circuit: %4d mV\n", value);
|
||||
|
||||
max17050_get_property(MAX17050_MinVolt, &value);
|
||||
gfx_printf(&gfx_con, "Min voltage reached: %4d mV\n", value);
|
||||
gfx_printf("Min voltage reached: %4d mV\n", value);
|
||||
|
||||
max17050_get_property(MAX17050_MaxVolt, &value);
|
||||
gfx_printf(&gfx_con, "Max voltage reached: %4d mV\n", value);
|
||||
gfx_printf("Max voltage reached: %4d mV\n", value);
|
||||
|
||||
max17050_get_property(MAX17050_V_empty, &value);
|
||||
gfx_printf(&gfx_con, "Empty voltage (design): %4d mV\n", value);
|
||||
gfx_printf("Empty voltage (design): %4d mV\n", value);
|
||||
|
||||
max17050_get_property(MAX17050_TEMP, &value);
|
||||
if (value >= 0)
|
||||
gfx_printf(&gfx_con, "Battery temperature: %d.%d oC\n", value / 10, value % 10);
|
||||
gfx_printf("Battery temperature: %d.%d oC\n", value / 10, value % 10);
|
||||
else
|
||||
gfx_printf(&gfx_con, "Battery temperature: -%d.%d oC\n", ~value / 10, (~value) % 10);
|
||||
gfx_printf("Battery temperature: -%d.%d oC\n", ~value / 10, (~value) % 10);
|
||||
}
|
||||
|
||||
void print_battery_charger_info()
|
||||
{
|
||||
int value = 0;
|
||||
|
||||
gfx_printf(&gfx_con, "%k\n\nBattery Charger IC Info:\n%k", 0xFF00DDFF, 0xFFCCCCCC);
|
||||
gfx_printf("%k\n\nBattery Charger IC Info:\n%k", 0xFF00DDFF, 0xFFCCCCCC);
|
||||
|
||||
bq24193_get_property(BQ24193_InputVoltageLimit, &value);
|
||||
gfx_printf(&gfx_con, "Input voltage limit: %4d mV\n", value);
|
||||
gfx_printf("Input voltage limit: %4d mV\n", value);
|
||||
|
||||
bq24193_get_property(BQ24193_InputCurrentLimit, &value);
|
||||
gfx_printf(&gfx_con, "Input current limit: %4d mA\n", value);
|
||||
gfx_printf("Input current limit: %4d mA\n", value);
|
||||
|
||||
bq24193_get_property(BQ24193_SystemMinimumVoltage, &value);
|
||||
gfx_printf(&gfx_con, "Min voltage limit: %4d mV\n", value);
|
||||
gfx_printf("Min voltage limit: %4d mV\n", value);
|
||||
|
||||
bq24193_get_property(BQ24193_FastChargeCurrentLimit, &value);
|
||||
gfx_printf(&gfx_con, "Fast charge current limit: %4d mA\n", value);
|
||||
gfx_printf("Fast charge current limit: %4d mA\n", value);
|
||||
|
||||
bq24193_get_property(BQ24193_ChargeVoltageLimit, &value);
|
||||
gfx_printf(&gfx_con, "Charge voltage limit: %4d mV\n", value);
|
||||
gfx_printf("Charge voltage limit: %4d mV\n", value);
|
||||
|
||||
bq24193_get_property(BQ24193_ChargeStatus, &value);
|
||||
gfx_printf(&gfx_con, "Charge status: ");
|
||||
gfx_printf("Charge status: ");
|
||||
switch (value)
|
||||
{
|
||||
case 0:
|
||||
gfx_printf(&gfx_con, "Not charging\n");
|
||||
gfx_printf("Not charging\n");
|
||||
break;
|
||||
case 1:
|
||||
gfx_printf(&gfx_con, "Pre-charging\n");
|
||||
gfx_printf("Pre-charging\n");
|
||||
break;
|
||||
case 2:
|
||||
gfx_printf(&gfx_con, "Fast charging\n");
|
||||
gfx_printf("Fast charging\n");
|
||||
break;
|
||||
case 3:
|
||||
gfx_printf(&gfx_con, "Charge terminated\n");
|
||||
gfx_printf("Charge terminated\n");
|
||||
break;
|
||||
default:
|
||||
gfx_printf(&gfx_con, "Unknown (%d)\n", value);
|
||||
gfx_printf("Unknown (%d)\n", value);
|
||||
break;
|
||||
}
|
||||
bq24193_get_property(BQ24193_TempStatus, &value);
|
||||
gfx_printf(&gfx_con, "Temperature status: ");
|
||||
gfx_printf("Temperature status: ");
|
||||
switch (value)
|
||||
{
|
||||
case 0:
|
||||
gfx_printf(&gfx_con, "Normal\n");
|
||||
gfx_printf("Normal\n");
|
||||
break;
|
||||
case 2:
|
||||
gfx_printf(&gfx_con, "Warm\n");
|
||||
gfx_printf("Warm\n");
|
||||
break;
|
||||
case 3:
|
||||
gfx_printf(&gfx_con, "Cool\n");
|
||||
gfx_printf("Cool\n");
|
||||
break;
|
||||
case 5:
|
||||
gfx_printf(&gfx_con, "Cold\n");
|
||||
gfx_printf("Cold\n");
|
||||
break;
|
||||
case 6:
|
||||
gfx_printf(&gfx_con, "Hot\n");
|
||||
gfx_printf("Hot\n");
|
||||
break;
|
||||
default:
|
||||
gfx_printf(&gfx_con, "Unknown (%d)\n", value);
|
||||
gfx_printf("Unknown (%d)\n", value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void print_battery_info()
|
||||
{
|
||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
print_fuel_gauge_info();
|
||||
|
||||
@@ -575,17 +573,17 @@ void print_battery_info()
|
||||
|
||||
u8 *buf = (u8 *)malloc(0x100 * 2);
|
||||
|
||||
gfx_printf(&gfx_con, "%k\n\nBattery Fuel Gauge Registers:\n%k", 0xFF00DDFF, 0xFFCCCCCC);
|
||||
gfx_printf("%k\n\nBattery Fuel Gauge Registers:\n%k", 0xFF00DDFF, 0xFFCCCCCC);
|
||||
|
||||
for (int i = 0; i < 0x200; i += 2)
|
||||
{
|
||||
i2c_recv_buf_small(buf + i, 2, I2C_1, 0x36, i >> 1);
|
||||
i2c_recv_buf_small(buf + i, 2, I2C_1, MAXIM17050_I2C_ADDR, i >> 1);
|
||||
usleep(2500);
|
||||
}
|
||||
|
||||
gfx_hexdump(&gfx_con, 0, (u8 *)buf, 0x200);
|
||||
gfx_hexdump(0, (u8 *)buf, 0x200);
|
||||
|
||||
gfx_puts(&gfx_con, "\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
|
||||
gfx_puts("\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
|
||||
|
||||
u32 btn = btn_wait();
|
||||
|
||||
@@ -598,7 +596,7 @@ void print_battery_info()
|
||||
if (sd_save_to_file((u8 *)buf, 0x200, path))
|
||||
EPRINTF("\nError creating fuel.bin file.");
|
||||
else
|
||||
gfx_puts(&gfx_con, "\nDone!\n");
|
||||
gfx_puts("\nDone!\n");
|
||||
sd_unmount();
|
||||
}
|
||||
|
||||
@@ -609,33 +607,33 @@ void print_battery_info()
|
||||
|
||||
void _ipatch_process(u32 offset, u32 value)
|
||||
{
|
||||
gfx_printf(&gfx_con, "%8x %8x", BOOTROM_BASE + offset, value);
|
||||
gfx_printf("%8x %8x", BOOTROM_BASE + offset, value);
|
||||
u8 lo = value & 0xff;
|
||||
switch (value >> 8)
|
||||
{
|
||||
case 0x20:
|
||||
gfx_printf(&gfx_con, " MOVS R0, #0x%02X", lo);
|
||||
gfx_printf(" MOVS R0, #0x%02X", lo);
|
||||
break;
|
||||
case 0xDF:
|
||||
gfx_printf(&gfx_con, " SVC #0x%02X", lo);
|
||||
gfx_printf(" SVC #0x%02X", lo);
|
||||
break;
|
||||
}
|
||||
gfx_puts(&gfx_con, "\n");
|
||||
gfx_puts("\n");
|
||||
}
|
||||
|
||||
void bootrom_ipatches_info()
|
||||
{
|
||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||
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(&gfx_con, "\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -649,34 +647,30 @@ void bootrom_ipatches_info()
|
||||
{
|
||||
emmcsn_path_impl(path, "/dumps", "evp_thunks.bin", NULL);
|
||||
if (!sd_save_to_file((u8 *)iram_evp_thunks, iram_evp_thunks_len, path))
|
||||
gfx_puts(&gfx_con, "\nevp_thunks.bin saved!\n");
|
||||
gfx_puts("\nevp_thunks.bin saved!\n");
|
||||
}
|
||||
else
|
||||
EPRINTFARGS("Failed to read evp_thunks. Error: %d", res);
|
||||
|
||||
u32 words[0x100];
|
||||
read_raw_ipatch_fuses(words);
|
||||
emmcsn_path_impl(path, "/dumps", "ipatches.bin", NULL);
|
||||
if (!sd_save_to_file((u8 *)words, sizeof(words), path))
|
||||
gfx_puts(&gfx_con, "\nipatches.bin saved!\n");
|
||||
|
||||
|
||||
emmcsn_path_impl(path, "/dumps", "bootrom_patched.bin", NULL);
|
||||
if (!sd_save_to_file((u8 *)BOOTROM_BASE, BOOTROM_SIZE, path))
|
||||
gfx_puts(&gfx_con, "\nbootrom_patched.bin saved!\n");
|
||||
|
||||
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(&gfx_con, "\nbootrom_unpatched.bin saved!\n");
|
||||
|
||||
gfx_puts("\nbootrom_unpatched.bin saved!\n");
|
||||
|
||||
memcpy((void*)IPATCH_BASE, ipatch_backup, sizeof(ipatch_backup));
|
||||
|
||||
|
||||
sd_unmount();
|
||||
}
|
||||
|
||||
btn_wait();
|
||||
}
|
||||
}
|
||||
|
||||
#pragma GCC pop_options
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "../sec/se.h"
|
||||
#include "../storage/nx_emmc.h"
|
||||
#include "../storage/sdmmc.h"
|
||||
#include "../soc/fuse.h"
|
||||
#include "../utils/btn.h"
|
||||
#include "../utils/util.h"
|
||||
|
||||
@@ -44,11 +45,16 @@ extern void sd_unmount();
|
||||
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")
|
||||
|
||||
void dump_packages12()
|
||||
{
|
||||
if (!sd_mount())
|
||||
return;
|
||||
|
||||
char path[64];
|
||||
|
||||
u8 *pkg1 = (u8 *)calloc(1, 0x40000);
|
||||
u8 *warmboot = (u8 *)calloc(1, 0x40000);
|
||||
u8 *secmon = (u8 *)calloc(1, 0x40000);
|
||||
@@ -58,8 +64,8 @@ void dump_packages12()
|
||||
|
||||
tsec_ctxt_t tsec_ctxt;
|
||||
|
||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
sdmmc_storage_t storage;
|
||||
sdmmc_t sdmmc;
|
||||
@@ -73,17 +79,22 @@ void dump_packages12()
|
||||
// Read package1.
|
||||
sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1);
|
||||
const pkg1_id_t *pkg1_id = pkg1_identify(pkg1);
|
||||
const pk11_hdr_t *hdr = (pk11_hdr_t *)(pkg1 + pkg1_id->pkg11_off + 0x20);
|
||||
if (!pkg1_id)
|
||||
{
|
||||
gfx_con.fntsz = 8;
|
||||
EPRINTF("Unknown pkg1 version for reading\nTSEC firmware.");
|
||||
// Dump package1.
|
||||
emmcsn_path_impl(path, "/pkg1", "pkg1_enc.bin", &storage);
|
||||
if (sd_save_to_file(pkg1, 0x40000, path))
|
||||
goto out_free;
|
||||
gfx_puts("\nEnc pkg1 dumped to pkg1_enc.bin\n");
|
||||
|
||||
goto out_free;
|
||||
}
|
||||
const pk11_hdr_t *hdr = (pk11_hdr_t *)(pkg1 + pkg1_id->pkg11_off + 0x20);
|
||||
|
||||
kb = pkg1_id->kb;
|
||||
|
||||
if (!h_cfg.se_keygen_done || kb == KB_FIRMWARE_VERSION_620)
|
||||
if (!h_cfg.se_keygen_done)
|
||||
{
|
||||
tsec_ctxt.fw = (void *)pkg1 + pkg1_id->tsec_off;
|
||||
tsec_ctxt.pkg1 = (void *)pkg1;
|
||||
@@ -95,12 +106,12 @@ void dump_packages12()
|
||||
b_cfg.autoboot = 0;
|
||||
b_cfg.autoboot_list = 0;
|
||||
|
||||
gfx_printf(&gfx_con, "sept will run to get the keys.\nThen rerun this option.");
|
||||
gfx_printf("sept will run to get the keys.\nThen rerun this option.");
|
||||
btn_wait();
|
||||
|
||||
if (!reboot_to_sept((u8 *)tsec_ctxt.fw))
|
||||
if (!reboot_to_sept((u8 *)tsec_ctxt.fw, kb, NULL))
|
||||
{
|
||||
gfx_printf(&gfx_con, "Failed to run sept\n");
|
||||
gfx_printf("Failed to run sept\n");
|
||||
goto out_free;
|
||||
}
|
||||
}
|
||||
@@ -110,53 +121,51 @@ void dump_packages12()
|
||||
sdmmc_storage_read(&storage, 0x180000 / NX_EMMC_BLOCKSIZE + kb, 1, keyblob);
|
||||
|
||||
// Decrypt.
|
||||
keygen(keyblob, kb, &tsec_ctxt);
|
||||
|
||||
h_cfg.se_keygen_done = 1;
|
||||
keygen(keyblob, kb, &tsec_ctxt, NULL);
|
||||
if (kb <= KB_FIRMWARE_VERSION_600)
|
||||
h_cfg.se_keygen_done = 1;
|
||||
free(keyblob);
|
||||
}
|
||||
|
||||
if (kb <= KB_FIRMWARE_VERSION_600)
|
||||
pkg1_decrypt(pkg1_id, pkg1);
|
||||
|
||||
char path[64];
|
||||
|
||||
if (kb <= KB_FIRMWARE_VERSION_620)
|
||||
{
|
||||
pkg1_unpack(warmboot, secmon, loader, pkg1_id, pkg1);
|
||||
|
||||
|
||||
// Display info.
|
||||
gfx_printf(&gfx_con, "%kNX Bootloader size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, hdr->ldr_size);
|
||||
|
||||
gfx_printf(&gfx_con, "%kSecure monitor addr: %k0x%05X\n", 0xFFC7EA46, 0xFFCCCCCC, pkg1_id->secmon_base);
|
||||
gfx_printf(&gfx_con, "%kSecure monitor size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, hdr->sm_size);
|
||||
|
||||
gfx_printf(&gfx_con, "%kWarmboot addr: %k0x%05X\n", 0xFFC7EA46, 0xFFCCCCCC, pkg1_id->warmboot_base);
|
||||
gfx_printf(&gfx_con, "%kWarmboot size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, hdr->wb_size);
|
||||
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);
|
||||
|
||||
// Dump package1.1.
|
||||
emmcsn_path_impl(path, "/pkg1", "pkg1_decr.bin", &storage);
|
||||
if (sd_save_to_file(pkg1, 0x40000, path))
|
||||
goto out_free;
|
||||
gfx_puts(&gfx_con, "\npkg1 dumped to pkg1_decr.bin\n");
|
||||
|
||||
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(&gfx_con, "NX Bootloader dumped to nxloader.bin\n");
|
||||
|
||||
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(&gfx_con, "Secure Monitor dumped to secmon.bin\n");
|
||||
|
||||
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))
|
||||
goto out_free;
|
||||
gfx_puts(&gfx_con, "Warmboot dumped to warmboot.bin\n\n\n");
|
||||
gfx_puts("Warmboot dumped to warmboot.bin\n\n\n");
|
||||
}
|
||||
|
||||
// Dump package2.1.
|
||||
@@ -178,37 +187,55 @@ 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");
|
||||
goto out;
|
||||
}
|
||||
|
||||
// Display info.
|
||||
u32 kernel_crc32 = crc32c(pkg2_hdr->data, pkg2_hdr->sec_size[PKG2_SEC_KERNEL]);
|
||||
gfx_printf(&gfx_con, "\n%kKernel CRC32C: %k0x%08X\n\n", 0xFFC7EA46, 0xFFCCCCCC, kernel_crc32);
|
||||
gfx_printf(&gfx_con, "%kKernel size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, pkg2_hdr->sec_size[PKG2_SEC_KERNEL]);
|
||||
gfx_printf(&gfx_con, "%kINI1 size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, pkg2_hdr->sec_size[PKG2_SEC_INI1]);
|
||||
gfx_printf("%kKernel size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, pkg2_hdr->sec_size[PKG2_SEC_KERNEL]);
|
||||
gfx_printf("%kINI1 size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, pkg2_hdr->sec_size[PKG2_SEC_INI1]);
|
||||
|
||||
// Dump pkg2.1.
|
||||
emmcsn_path_impl(path, "/pkg2", "pkg2_decr.bin", &storage);
|
||||
if (sd_save_to_file(pkg2, pkg2_hdr->sec_size[PKG2_SEC_KERNEL] + pkg2_hdr->sec_size[PKG2_SEC_INI1], path))
|
||||
goto out;
|
||||
gfx_puts(&gfx_con, "\npkg2 dumped to pkg2_decr.bin\n");
|
||||
gfx_puts("\npkg2 dumped to pkg2_decr.bin\n");
|
||||
|
||||
// Dump kernel.
|
||||
emmcsn_path_impl(path, "/pkg2", "kernel.bin", &storage);
|
||||
if (sd_save_to_file(pkg2_hdr->data, pkg2_hdr->sec_size[PKG2_SEC_KERNEL], path))
|
||||
goto out;
|
||||
gfx_puts(&gfx_con, "Kernel dumped to kernel.bin\n");
|
||||
gfx_puts("Kernel dumped to kernel.bin\n");
|
||||
|
||||
// Dump INI1.
|
||||
emmcsn_path_impl(path, "/pkg2", "ini1.bin", &storage);
|
||||
if (sd_save_to_file(pkg2_hdr->data + pkg2_hdr->sec_size[PKG2_SEC_KERNEL],
|
||||
pkg2_hdr->sec_size[PKG2_SEC_INI1], path))
|
||||
u32 ini1_off = pkg2_hdr->sec_size[PKG2_SEC_KERNEL];
|
||||
u32 ini1_size = pkg2_hdr->sec_size[PKG2_SEC_INI1];
|
||||
if (!ini1_size)
|
||||
{
|
||||
pkg2_get_newkern_info(pkg2_hdr->data);
|
||||
ini1_off = pkg2_newkern_ini1_start;
|
||||
ini1_size = pkg2_newkern_ini1_end - pkg2_newkern_ini1_start;
|
||||
}
|
||||
if (ini1_off)
|
||||
{
|
||||
if (sd_save_to_file(pkg2_hdr->data + ini1_off, ini1_size, path))
|
||||
goto out;
|
||||
gfx_puts("INI1 dumped to ini1.bin\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
gfx_puts("Failed to dump INI1!\n");
|
||||
goto out;
|
||||
gfx_puts(&gfx_con, "INI1 dumped to ini1.bin\n");
|
||||
}
|
||||
|
||||
gfx_puts(&gfx_con, "\nDone. Press any key...\n");
|
||||
gfx_puts("\nDone. Press any key...\n");
|
||||
|
||||
out:
|
||||
nx_emmc_gpt_free(&gpt);
|
||||
@@ -234,8 +261,8 @@ void _toggle_autorcm(bool enable)
|
||||
|
||||
u8 randomXor = 0;
|
||||
|
||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
|
||||
{
|
||||
@@ -247,6 +274,12 @@ void _toggle_autorcm(bool enable)
|
||||
sdmmc_storage_set_mmc_partition(&storage, 1);
|
||||
|
||||
int i, sect = 0;
|
||||
u8 corr_mod_byte0;
|
||||
if ((fuse_read_odm(4) & 3) != 3)
|
||||
corr_mod_byte0 = 0xF7;
|
||||
else
|
||||
corr_mod_byte0 = 0x37;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
sect = (0x200 + (0x4000 * i)) / NX_EMMC_BLOCKSIZE;
|
||||
@@ -262,7 +295,7 @@ void _toggle_autorcm(bool enable)
|
||||
tempbuf[0x10] ^= randomXor;
|
||||
}
|
||||
else
|
||||
tempbuf[0x10] = 0xF7;
|
||||
tempbuf[0x10] = corr_mod_byte0;
|
||||
sdmmc_storage_write(&storage, sect, 1, tempbuf);
|
||||
}
|
||||
|
||||
@@ -270,10 +303,10 @@ void _toggle_autorcm(bool enable)
|
||||
sdmmc_storage_end(&storage);
|
||||
|
||||
if (enable)
|
||||
gfx_printf(&gfx_con, "%kAutoRCM mode enabled!%k", 0xFFFFBA00, 0xFFCCCCCC);
|
||||
gfx_printf("%kAutoRCM mode enabled!%k", 0xFFFFBA00, 0xFFCCCCCC);
|
||||
else
|
||||
gfx_printf(&gfx_con, "%kAutoRCM mode disabled!%k", 0xFF96FF00, 0xFFCCCCCC);
|
||||
gfx_printf(&gfx_con, "\n\nPress any key...\n");
|
||||
gfx_printf("%kAutoRCM mode disabled!%k", 0xFF96FF00, 0xFFCCCCCC);
|
||||
gfx_printf("\n\nPress any key...\n");
|
||||
|
||||
out:
|
||||
btn_wait();
|
||||
@@ -284,8 +317,18 @@ void _disable_autorcm() { _toggle_autorcm(false); }
|
||||
|
||||
void menu_autorcm()
|
||||
{
|
||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
gfx_clear_grey(0x1B);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
if (h_cfg.rcm_patched)
|
||||
{
|
||||
gfx_printf("%kThis device is RCM patched and\nAutoRCM function is disabled.\n\n"
|
||||
"In case %kAutoRCM%k is enabled\nthis will %kBRICK%k your device PERMANENTLY!!%k",
|
||||
0xFFFFDD00, 0xFFFF0000, 0xFFFFDD00, 0xFFFF0000, 0xFFFFDD00, 0xFFCCCCCC);
|
||||
btn_wait();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Do a simple check on the main BCT.
|
||||
sdmmc_storage_t storage;
|
||||
@@ -304,8 +347,16 @@ void menu_autorcm()
|
||||
sdmmc_storage_set_mmc_partition(&storage, 1);
|
||||
sdmmc_storage_read(&storage, 0x200 / NX_EMMC_BLOCKSIZE, 1, tempbuf);
|
||||
|
||||
if (tempbuf[0x10] != 0xF7)
|
||||
disabled = false;
|
||||
if ((fuse_read_odm(4) & 3) != 3)
|
||||
{
|
||||
if (tempbuf[0x10] != 0xF7)
|
||||
disabled = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tempbuf[0x10] != 0x37)
|
||||
disabled = false;
|
||||
}
|
||||
|
||||
free(tempbuf);
|
||||
sdmmc_storage_end(&storage);
|
||||
@@ -340,7 +391,7 @@ void menu_autorcm()
|
||||
memset(&ments[5], 0, sizeof(ment_t));
|
||||
menu_t menu = {ments, "This corrupts your BOOT0!", 0, 0};
|
||||
|
||||
tui_do_menu(&gfx_con, &menu);
|
||||
tui_do_menu(&menu);
|
||||
}
|
||||
|
||||
int _fix_attributes(char *path, u32 *total, u32 hos_folder, u32 check_first_run)
|
||||
@@ -407,6 +458,10 @@ int _fix_attributes(char *path, u32 *total, u32 hos_folder, u32 check_first_run)
|
||||
*total = *total + 1;
|
||||
f_chmod(path, AM_ARC, AM_ARC);
|
||||
}
|
||||
|
||||
// Update status bar.
|
||||
tui_sbar(false);
|
||||
|
||||
// Enter the directory.
|
||||
res = _fix_attributes(path, total, hos_folder, 0);
|
||||
if (res != FR_OK)
|
||||
@@ -421,8 +476,8 @@ int _fix_attributes(char *path, u32 *total, u32 hos_folder, u32 check_first_run)
|
||||
|
||||
void _fix_sd_attr(u32 type)
|
||||
{
|
||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
char path[256];
|
||||
char label[16];
|
||||
@@ -433,19 +488,19 @@ 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;
|
||||
}
|
||||
|
||||
gfx_printf(&gfx_con, "Traversing all %s files!\nThis may take some time...\n\n", label);
|
||||
gfx_printf("Traversing all %s files!\nThis may take some time...\n\n", label);
|
||||
_fix_attributes(path, &total, type, type);
|
||||
gfx_printf(&gfx_con, "%kTotal archive bits cleared: %d!%k\n\nDone! Press any key...", 0xFF96FF00, total, 0xFFCCCCCC);
|
||||
gfx_printf("%kTotal archive bits cleared: %d!%k\n\nDone! Press any key...", 0xFF96FF00, total, 0xFFCCCCCC);
|
||||
sd_unmount();
|
||||
}
|
||||
btn_wait();
|
||||
@@ -454,22 +509,10 @@ void _fix_sd_attr(u32 type)
|
||||
void fix_sd_all_attr() { _fix_sd_attr(0); }
|
||||
void fix_sd_nin_attr() { _fix_sd_attr(1); }
|
||||
|
||||
void fix_battery_desync()
|
||||
{
|
||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
|
||||
max77620_low_battery_monitor_config();
|
||||
|
||||
gfx_puts(&gfx_con, "\nDone!\n");
|
||||
|
||||
btn_wait();
|
||||
}
|
||||
|
||||
/* void fix_fuel_gauge_configuration()
|
||||
{
|
||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
int battVoltage, avgCurrent;
|
||||
|
||||
@@ -483,23 +526,23 @@ void fix_battery_desync()
|
||||
EPRINTF("You need to be connected to a wall adapter,\nto apply this fix!");
|
||||
else
|
||||
{
|
||||
gfx_printf(&gfx_con, "%kAre you really sure?\nThis will reset your fuel gauge completely!\n", 0xFFFFDD00);
|
||||
gfx_printf(&gfx_con, "Additionally this will power off your console.\n%k", 0xFFCCCCCC);
|
||||
gfx_printf("%kAre you really sure?\nThis will reset your fuel gauge completely!\n", 0xFFFFDD00);
|
||||
gfx_printf("Additionally this will power off your console.\n%k", 0xFFCCCCCC);
|
||||
|
||||
gfx_puts(&gfx_con, "\nPress POWER to Continue.\nPress VOL to go to the menu.\n\n\n");
|
||||
gfx_puts("\nPress POWER to Continue.\nPress VOL to go to the menu.\n\n\n");
|
||||
|
||||
u32 btn = btn_wait();
|
||||
if (btn & BTN_POWER)
|
||||
{
|
||||
max17050_fix_configuration();
|
||||
msleep(1000);
|
||||
gfx_con_getpos(&gfx_con, &gfx_con.savedx, &gfx_con.savedy);
|
||||
gfx_con_getpos(&gfx_con.savedx, &gfx_con.savedy);
|
||||
u16 value = 0;
|
||||
gfx_printf(&gfx_con, "%kThe console will power off in 45 seconds.\n%k", 0xFFFFDD00, 0xFFCCCCCC);
|
||||
gfx_printf("%kThe console will power off in 45 seconds.\n%k", 0xFFFFDD00, 0xFFCCCCCC);
|
||||
while (value < 46)
|
||||
{
|
||||
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
|
||||
gfx_printf(&gfx_con, "%2ds elapsed", value);
|
||||
gfx_con_setpos(gfx_con.savedx, gfx_con.savedy);
|
||||
gfx_printf("%2ds elapsed", value);
|
||||
msleep(1000);
|
||||
value++;
|
||||
}
|
||||
@@ -521,31 +564,31 @@ void fix_battery_desync()
|
||||
{
|
||||
int avgCurrent;
|
||||
|
||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
gfx_printf(&gfx_con, "%k\nThis will wipe your battery stats completely!\n"
|
||||
gfx_printf("%k\nThis will wipe your battery stats completely!\n"
|
||||
"%kAnd it may not power on without physically\nremoving and re-inserting the battery.\n%k"
|
||||
"\nAre you really sure?%k\n", 0xFFFFDD00, 0xFFFF0000, 0xFFFFDD00, 0xFFCCCCCC);
|
||||
|
||||
gfx_puts(&gfx_con, "\nPress POWER to Continue.\nPress VOL to go to the menu.\n\n\n");
|
||||
gfx_puts("\nPress POWER to Continue.\nPress VOL to go to the menu.\n\n\n");
|
||||
u32 btn = btn_wait();
|
||||
if (btn & BTN_POWER)
|
||||
{
|
||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
gfx_printf(&gfx_con, "%kKeep the USB cable connected!%k\n\n", 0xFFFFDD00, 0xFFCCCCCC);
|
||||
gfx_con_getpos(&gfx_con, &gfx_con.savedx, &gfx_con.savedy);
|
||||
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||
gfx_con_setpos(0, 0);
|
||||
gfx_printf("%kKeep the USB cable connected!%k\n\n", 0xFFFFDD00, 0xFFCCCCCC);
|
||||
gfx_con_getpos(&gfx_con.savedx, &gfx_con.savedy);
|
||||
|
||||
u8 value = 30;
|
||||
while (value > 0)
|
||||
{
|
||||
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
|
||||
gfx_printf(&gfx_con, "%kWait... (%ds) %k", 0xFF888888, value, 0xFFCCCCCC);
|
||||
gfx_con_setpos(gfx_con.savedx, gfx_con.savedy);
|
||||
gfx_printf("%kWait... (%ds) %k", 0xFF888888, value, 0xFFCCCCCC);
|
||||
msleep(1000);
|
||||
value--;
|
||||
}
|
||||
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
|
||||
gfx_con_setpos(gfx_con.savedx, gfx_con.savedy);
|
||||
|
||||
//Check if still connected.
|
||||
max17050_get_property(MAX17050_AvgCurrent, &avgCurrent);
|
||||
@@ -555,7 +598,7 @@ void fix_battery_desync()
|
||||
{
|
||||
// Apply fix.
|
||||
bq24193_fake_battery_removal();
|
||||
gfx_printf(&gfx_con, "Done! \n"
|
||||
gfx_printf("Done! \n"
|
||||
"%k1. Remove the USB cable\n"
|
||||
"2. Press POWER for 15s.\n"
|
||||
"3. Reconnect the USB to power-on!%k\n", 0xFFFFDD00, 0xFFCCCCCC);
|
||||
@@ -565,60 +608,4 @@ void fix_battery_desync()
|
||||
}
|
||||
}*/
|
||||
|
||||
/*
|
||||
#include "../../modules/hekate_libsys_minerva/mtc.h"
|
||||
#include "../ianos/ianos.h"
|
||||
#include "../soc/fuse.h"
|
||||
#include "../soc/clock.h"
|
||||
|
||||
void minerva()
|
||||
{
|
||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
|
||||
u32 curr_ram_idx = 0;
|
||||
|
||||
if (!sd_mount())
|
||||
return;
|
||||
|
||||
gfx_printf(&gfx_con, "-- Minerva Training Cell --\n\n");
|
||||
|
||||
// Set table to ram.
|
||||
mtc_cfg.mtc_table = NULL;
|
||||
mtc_cfg.sdram_id = (fuse_read_odm(4) >> 3) & 0x1F;
|
||||
ianos_loader(false, "bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)&mtc_cfg);
|
||||
|
||||
gfx_printf(&gfx_con, "\nStarting training process..\n\n");
|
||||
|
||||
// Get current frequency
|
||||
for (curr_ram_idx = 0; curr_ram_idx < 10; curr_ram_idx++)
|
||||
{
|
||||
if (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) == mtc_cfg.mtc_table[curr_ram_idx].clk_src_emc)
|
||||
break;
|
||||
}
|
||||
|
||||
// Change DRAM voltage.
|
||||
//i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD1, 42); //40 = (1000 * 1100 - 600000) / 12500 -> 1.1V
|
||||
|
||||
mtc_cfg.rate_from = mtc_cfg.mtc_table[curr_ram_idx].rate_khz;
|
||||
mtc_cfg.rate_to = 800000;
|
||||
mtc_cfg.train_mode = OP_TRAIN_SWITCH;
|
||||
gfx_printf(&gfx_con, "Training and switching %7d -> %7d\n\n", mtc_cfg.mtc_table[curr_ram_idx].rate_khz, 800000);
|
||||
ianos_loader(false, "bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)&mtc_cfg);
|
||||
|
||||
// Thefollowing frequency needs periodic training every 100ms.
|
||||
//msleep(200);
|
||||
|
||||
//mtc_cfg.rate_to = 1600000;
|
||||
//gfx_printf(&gfx_con, "Training and switching %7d -> %7d\n\n", mtc_cfg.current_emc_table->rate_khz, 1600000);
|
||||
//ianos_loader(false, "bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)&mtc_cfg);
|
||||
|
||||
//mtc_cfg.train_mode = OP_PERIODIC_TRAIN;
|
||||
|
||||
sd_unmount();
|
||||
|
||||
gfx_printf(&gfx_con, "Finished!");
|
||||
|
||||
btn_wait();
|
||||
}
|
||||
*/
|
||||
#pragma GCC pop_options
|
||||
|
||||
@@ -23,6 +23,5 @@ void fix_sd_all_attr();
|
||||
void fix_sd_nin_attr();
|
||||
void fix_battery_desync();
|
||||
void menu_autorcm();
|
||||
//void minerva();
|
||||
|
||||
#endif
|
||||
|
||||
@@ -18,15 +18,16 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "di.h"
|
||||
#include "../soc/t210.h"
|
||||
#include "../utils/util.h"
|
||||
#include "../soc/i2c.h"
|
||||
#include "../soc/pmc.h"
|
||||
#include "../gfx/gfx.h"
|
||||
#include "../power/max77620.h"
|
||||
#include "../power/max7762x.h"
|
||||
#include "../soc/gpio.h"
|
||||
#include "../soc/pinmux.h"
|
||||
#include "../soc/clock.h"
|
||||
#include "../soc/gpio.h"
|
||||
#include "../soc/i2c.h"
|
||||
#include "../soc/pinmux.h"
|
||||
#include "../soc/pmc.h"
|
||||
#include "../soc/t210.h"
|
||||
#include "../utils/util.h"
|
||||
|
||||
#include "di.inl"
|
||||
|
||||
@@ -46,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;
|
||||
@@ -122,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);
|
||||
}
|
||||
|
||||
@@ -142,11 +153,10 @@ void display_backlight_pwm_init()
|
||||
{
|
||||
clock_enable_pwm();
|
||||
|
||||
PWM(PWM_CONTROLLER_PWM_CSR) = (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)
|
||||
@@ -156,7 +166,7 @@ void display_backlight(bool enable)
|
||||
|
||||
void display_backlight_brightness(u32 brightness, u32 step_delay)
|
||||
{
|
||||
u32 old_value = (PWM(PWM_CONTROLLER_PWM_CSR) >> 16) & 0xFF;
|
||||
u32 old_value = (PWM(PWM_CONTROLLER_PWM_CSR_0) >> 16) & 0xFF;
|
||||
if (brightness == old_value)
|
||||
return;
|
||||
|
||||
@@ -167,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) = (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);
|
||||
}
|
||||
}
|
||||
@@ -175,12 +185,12 @@ void display_backlight_brightness(u32 brightness, u32 step_delay)
|
||||
{
|
||||
for (u32 i = old_value; i > brightness; i--)
|
||||
{
|
||||
PWM(PWM_CONTROLLER_PWM_CSR) = (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);
|
||||
}
|
||||
}
|
||||
if (!brightness)
|
||||
PWM(PWM_CONTROLLER_PWM_CSR) = 0;
|
||||
PWM(PWM_CONTROLLER_PWM_CSR_0) = 0;
|
||||
}
|
||||
|
||||
void display_end()
|
||||
@@ -191,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);
|
||||
|
||||
@@ -206,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)
|
||||
@@ -243,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);
|
||||
@@ -252,11 +262,12 @@ void display_color_screen(u32 color)
|
||||
u32 *display_init_framebuffer()
|
||||
{
|
||||
// Sanitize framebuffer area.
|
||||
memset((u32 *)0xC0000000, 0, 0x3C0000);
|
||||
// This configures the framebuffer @ 0xC0000000 with a resolution of 1280x720 (line stride 768).
|
||||
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 *)0xC0000000;
|
||||
return (u32 *)IPL_FB_ADDRESS;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,6 +18,7 @@
|
||||
#ifndef _DI_H_
|
||||
#define _DI_H_
|
||||
|
||||
#include "../../common/memory_map.h"
|
||||
#include "../utils/types.h"
|
||||
|
||||
/*! Display registers. */
|
||||
@@ -233,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
|
||||
@@ -333,7 +334,7 @@
|
||||
#define DSI_PAD_CONTROL_VS1_PDIO_CLK (1 << 8)
|
||||
#define DSI_PAD_CONTROL_VS1_PDIO(x) (((x) & 0xf) << 0)
|
||||
|
||||
#define DSI_PAD_CONTROL_CD 0x4c
|
||||
#define DSI_PAD_CONTROL_CD 0x4C
|
||||
#define DSI_VIDEO_MODE_CONTROL 0x4E
|
||||
|
||||
#define DSI_PAD_CONTROL_1 0x4F
|
||||
@@ -350,9 +351,6 @@
|
||||
|
||||
#define MIPI_CAL_MIPI_BIAS_PAD_CFG2 0x60
|
||||
|
||||
/*! Display backlight related PWM registers. */
|
||||
#define PWM_CONTROLLER_PWM_CSR 0x00
|
||||
|
||||
void display_init();
|
||||
void display_backlight_pwm_init();
|
||||
void display_end();
|
||||
|
||||
@@ -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,
|
||||
@@ -122,7 +122,7 @@ static const cfg_op_t _display_config_2[94] = {
|
||||
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{DC_WIN_WIN_OPTIONS, 0},
|
||||
{DC_DISP_DISP_WIN_OPTIONS, 0},
|
||||
{DC_CMD_DISPLAY_COMMAND, 0},
|
||||
{DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_STOP},
|
||||
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE},
|
||||
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ}
|
||||
};
|
||||
@@ -405,7 +405,7 @@ static const cfg_op_t _display_config_11[113] = {
|
||||
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{DC_WIN_WIN_OPTIONS, 0},
|
||||
{DC_DISP_DISP_WIN_OPTIONS, 0},
|
||||
{DC_CMD_DISPLAY_COMMAND, 0},
|
||||
{DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_STOP},
|
||||
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE},
|
||||
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ},
|
||||
{DC_CMD_STATE_ACCESS, 0},
|
||||
@@ -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},
|
||||
@@ -455,7 +455,7 @@ static const cfg_op_t _display_config_12[17] = {
|
||||
{DC_CMD_STATE_ACCESS, 0},
|
||||
{DC_CMD_INT_ENABLE, 0},
|
||||
{DC_CMD_CONT_SYNCPT_VSYNC, 0},
|
||||
{DC_CMD_DISPLAY_COMMAND, 0},
|
||||
{DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_STOP},
|
||||
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
|
||||
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
|
||||
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
|
||||
@@ -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, 0xC0000000}, //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},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (C) 2018 CTCaer
|
||||
* Copyright (c) 2018-2020 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,
|
||||
@@ -117,110 +117,111 @@ static const u8 _gfx_font[] = {
|
||||
0x00, 0x00, 0x00, 0x4C, 0x32, 0x00, 0x00, 0x00 // Char 126 (~)
|
||||
};
|
||||
|
||||
void gfx_init_ctxt(gfx_ctxt_t *ctxt, u32 *fb, u32 width, u32 height, u32 stride)
|
||||
void gfx_init_ctxt(u32 *fb, u32 width, u32 height, u32 stride)
|
||||
{
|
||||
ctxt->fb = fb;
|
||||
ctxt->width = width;
|
||||
ctxt->height = height;
|
||||
ctxt->stride = stride;
|
||||
gfx_ctxt.fb = fb;
|
||||
gfx_ctxt.width = width;
|
||||
gfx_ctxt.height = height;
|
||||
gfx_ctxt.stride = stride;
|
||||
}
|
||||
|
||||
void gfx_clear_grey(gfx_ctxt_t *ctxt, u8 color)
|
||||
void gfx_clear_grey(u8 color)
|
||||
{
|
||||
memset(ctxt->fb, color, 0x3C0000);
|
||||
memset(gfx_ctxt.fb, color, gfx_ctxt.width * gfx_ctxt.height * 4);
|
||||
}
|
||||
|
||||
void gfx_clear_color(gfx_ctxt_t *ctxt, u32 color)
|
||||
void gfx_clear_color(u32 color)
|
||||
{
|
||||
for (u32 i = 0; i < ctxt->height * ctxt->stride; i++)
|
||||
ctxt->fb[i] = color;
|
||||
for (u32 i = 0; i < gfx_ctxt.width * gfx_ctxt.height; i++)
|
||||
gfx_ctxt.fb[i] = color;
|
||||
}
|
||||
|
||||
void gfx_clear_partial_grey(gfx_ctxt_t *ctxt, u8 color, u32 pos_x, u32 height)
|
||||
void gfx_clear_partial_grey(u8 color, u32 pos_x, u32 height)
|
||||
{
|
||||
memset(ctxt->fb + pos_x * ctxt->stride, color, height * 4 * ctxt->stride);
|
||||
memset(gfx_ctxt.fb + pos_x * gfx_ctxt.stride, color, height * 4 * gfx_ctxt.stride);
|
||||
}
|
||||
|
||||
void gfx_con_init(gfx_con_t *con, gfx_ctxt_t *ctxt)
|
||||
void gfx_con_init()
|
||||
{
|
||||
con->gfx_ctxt = ctxt;
|
||||
con->fntsz = 16;
|
||||
con->x = 0;
|
||||
con->y = 0;
|
||||
con->savedx = 0;
|
||||
con->savedy = 0;
|
||||
con->fgcol = 0xFFCCCCCC;
|
||||
con->fillbg = 0;
|
||||
con->bgcol = 0xFF1B1B1B;
|
||||
con->mute = 0;
|
||||
gfx_con.gfx_ctxt = &gfx_ctxt;
|
||||
gfx_con.fntsz = 16;
|
||||
gfx_con.x = 0;
|
||||
gfx_con.y = 0;
|
||||
gfx_con.savedx = 0;
|
||||
gfx_con.savedy = 0;
|
||||
gfx_con.fgcol = 0xFFCCCCCC;
|
||||
gfx_con.fillbg = 1;
|
||||
gfx_con.bgcol = 0xFF1B1B1B;
|
||||
gfx_con.mute = 0;
|
||||
}
|
||||
|
||||
void gfx_con_setcol(gfx_con_t *con, u32 fgcol, int fillbg, u32 bgcol)
|
||||
void gfx_con_setcol(u32 fgcol, int fillbg, u32 bgcol)
|
||||
{
|
||||
con->fgcol = fgcol;
|
||||
con->fillbg = fillbg;
|
||||
con->bgcol = bgcol;
|
||||
gfx_con.fgcol = fgcol;
|
||||
gfx_con.fillbg = fillbg;
|
||||
gfx_con.bgcol = bgcol;
|
||||
}
|
||||
|
||||
void gfx_con_getpos(gfx_con_t *con, u32 *x, u32 *y)
|
||||
void gfx_con_getpos(u32 *x, u32 *y)
|
||||
{
|
||||
*x = con->x;
|
||||
*y = con->y;
|
||||
*x = gfx_con.x;
|
||||
*y = gfx_con.y;
|
||||
}
|
||||
|
||||
void gfx_con_setpos(gfx_con_t *con, u32 x, u32 y)
|
||||
void gfx_con_setpos(u32 x, u32 y)
|
||||
{
|
||||
con->x = x;
|
||||
con->y = y;
|
||||
gfx_con.x = x;
|
||||
gfx_con.y = y;
|
||||
}
|
||||
|
||||
void gfx_putc(gfx_con_t *con, char c)
|
||||
void gfx_putc(char c)
|
||||
{
|
||||
// Duplicate code for performance reasons.
|
||||
switch (con->fntsz)
|
||||
switch (gfx_con.fntsz)
|
||||
{
|
||||
case 16:
|
||||
if (c >= 32 && c <= 126)
|
||||
{
|
||||
u8 *cbuf = (u8 *)&_gfx_font[8 * (c - 32)];
|
||||
u32 *fb = con->gfx_ctxt->fb + con->x + con->y * con->gfx_ctxt->stride;
|
||||
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++)
|
||||
{
|
||||
if (v & 1)
|
||||
{
|
||||
*fb = con->fgcol;
|
||||
*fb = gfx_con.fgcol;
|
||||
fb++;
|
||||
*fb = con->fgcol;
|
||||
*fb = gfx_con.fgcol;
|
||||
}
|
||||
else if (con->fillbg)
|
||||
else if (gfx_con.fillbg)
|
||||
{
|
||||
*fb = con->bgcol;
|
||||
*fb = gfx_con.bgcol;
|
||||
fb++;
|
||||
*fb = con->bgcol;
|
||||
*fb = gfx_con.bgcol;
|
||||
}
|
||||
else
|
||||
fb++;
|
||||
v >>= 1;
|
||||
fb++;
|
||||
}
|
||||
fb += con->gfx_ctxt->stride - 16;
|
||||
fb += gfx_ctxt.stride - 16;
|
||||
v = *cbuf;
|
||||
}
|
||||
cbuf++;
|
||||
}
|
||||
con->x += 16;
|
||||
gfx_con.x += 16;
|
||||
}
|
||||
else if (c == '\n')
|
||||
{
|
||||
con->x = 0;
|
||||
con->y +=16;
|
||||
if (con->y > con->gfx_ctxt->height - 16)
|
||||
con->y = 0;
|
||||
gfx_con.x = 0;
|
||||
gfx_con.y +=16;
|
||||
if (gfx_con.y > gfx_ctxt.height - 16)
|
||||
gfx_con.y = 0;
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
@@ -228,45 +229,44 @@ void gfx_putc(gfx_con_t *con, char c)
|
||||
if (c >= 32 && c <= 126)
|
||||
{
|
||||
u8 *cbuf = (u8 *)&_gfx_font[8 * (c - 32)];
|
||||
u32 *fb = con->gfx_ctxt->fb + con->x + con->y * con->gfx_ctxt->stride;
|
||||
u32 *fb = gfx_ctxt.fb + gfx_con.x + gfx_con.y * gfx_ctxt.stride;
|
||||
for (u32 i = 0; i < 8; i++)
|
||||
{
|
||||
u8 v = *cbuf++;
|
||||
for (u32 j = 0; j < 8; j++)
|
||||
{
|
||||
if (v & 1)
|
||||
*fb = con->fgcol;
|
||||
else if (con->fillbg)
|
||||
*fb = con->bgcol;
|
||||
*fb = gfx_con.fgcol;
|
||||
else if (gfx_con.fillbg)
|
||||
*fb = gfx_con.bgcol;
|
||||
v >>= 1;
|
||||
fb++;
|
||||
}
|
||||
fb += con->gfx_ctxt->stride - 8;
|
||||
fb += gfx_ctxt.stride - 8;
|
||||
}
|
||||
con->x += 8;
|
||||
gfx_con.x += 8;
|
||||
}
|
||||
else if (c == '\n')
|
||||
{
|
||||
con->x = 0;
|
||||
con->y += 8;
|
||||
if (con->y > con->gfx_ctxt->height - 8)
|
||||
con->y = 0;
|
||||
gfx_con.x = 0;
|
||||
gfx_con.y += 8;
|
||||
if (gfx_con.y > gfx_ctxt.height - 8)
|
||||
gfx_con.y = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void gfx_puts(gfx_con_t *con, const char *s)
|
||||
void gfx_puts(char *s)
|
||||
{
|
||||
if (!s || con->mute)
|
||||
if (!s || gfx_con.mute)
|
||||
return;
|
||||
|
||||
for (; *s; s++)
|
||||
gfx_putc(con, *s);
|
||||
gfx_putc(*s);
|
||||
}
|
||||
|
||||
static void _gfx_putn(gfx_con_t *con, u32 v, int base, char fill, int fcnt)
|
||||
static void _gfx_putn(u32 v, int base, char fill, int fcnt)
|
||||
{
|
||||
char buf[65];
|
||||
static const char digits[] = "0123456789ABCDEFghijklmnopqrstuvwxyz";
|
||||
@@ -294,28 +294,28 @@ static void _gfx_putn(gfx_con_t *con, u32 v, int base, char fill, int fcnt)
|
||||
}
|
||||
}
|
||||
|
||||
gfx_puts(con, p);
|
||||
gfx_puts(p);
|
||||
}
|
||||
|
||||
void gfx_put_small_sep(gfx_con_t *con)
|
||||
void gfx_put_small_sep()
|
||||
{
|
||||
u8 prevFontSize = con->fntsz;
|
||||
con->fntsz = 8;
|
||||
gfx_putc(con, '\n');
|
||||
con->fntsz = prevFontSize;
|
||||
u8 prevFontSize = gfx_con.fntsz;
|
||||
gfx_con.fntsz = 8;
|
||||
gfx_putc('\n');
|
||||
gfx_con.fntsz = prevFontSize;
|
||||
}
|
||||
|
||||
void gfx_put_big_sep(gfx_con_t *con)
|
||||
void gfx_put_big_sep()
|
||||
{
|
||||
u8 prevFontSize = con->fntsz;
|
||||
con->fntsz = 16;
|
||||
gfx_putc(con, '\n');
|
||||
con->fntsz = prevFontSize;
|
||||
u8 prevFontSize = gfx_con.fntsz;
|
||||
gfx_con.fntsz = 16;
|
||||
gfx_putc('\n');
|
||||
gfx_con.fntsz = prevFontSize;
|
||||
}
|
||||
|
||||
void gfx_printf(gfx_con_t *con, const char *fmt, ...)
|
||||
void gfx_printf(const char *fmt, ...)
|
||||
{
|
||||
if (con->mute)
|
||||
if (gfx_con.mute)
|
||||
return;
|
||||
|
||||
va_list ap;
|
||||
@@ -348,40 +348,40 @@ void gfx_printf(gfx_con_t *con, const char *fmt, ...)
|
||||
switch(*fmt)
|
||||
{
|
||||
case 'c':
|
||||
gfx_putc(con, va_arg(ap, u32));
|
||||
gfx_putc(va_arg(ap, u32));
|
||||
break;
|
||||
case 's':
|
||||
gfx_puts(con, va_arg(ap, char *));
|
||||
gfx_puts(va_arg(ap, char *));
|
||||
break;
|
||||
case 'd':
|
||||
_gfx_putn(con, va_arg(ap, u32), 10, fill, fcnt);
|
||||
_gfx_putn(va_arg(ap, u32), 10, fill, fcnt);
|
||||
break;
|
||||
case 'p':
|
||||
case 'P':
|
||||
case 'x':
|
||||
case 'X':
|
||||
_gfx_putn(con, va_arg(ap, u32), 16, fill, fcnt);
|
||||
_gfx_putn(va_arg(ap, u32), 16, fill, fcnt);
|
||||
break;
|
||||
case 'k':
|
||||
con->fgcol = va_arg(ap, u32);
|
||||
gfx_con.fgcol = va_arg(ap, u32);
|
||||
break;
|
||||
case 'K':
|
||||
con->bgcol = va_arg(ap, u32);
|
||||
con->fillbg = 1;
|
||||
gfx_con.bgcol = va_arg(ap, u32);
|
||||
gfx_con.fillbg = 1;
|
||||
break;
|
||||
case '%':
|
||||
gfx_putc(con, '%');
|
||||
gfx_putc('%');
|
||||
break;
|
||||
case '\0':
|
||||
goto out;
|
||||
default:
|
||||
gfx_putc(con, '%');
|
||||
gfx_putc(con, *fmt);
|
||||
gfx_putc('%');
|
||||
gfx_putc(*fmt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
gfx_putc(con, *fmt);
|
||||
gfx_putc(*fmt);
|
||||
fmt++;
|
||||
}
|
||||
|
||||
@@ -389,33 +389,33 @@ void gfx_printf(gfx_con_t *con, const char *fmt, ...)
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void gfx_hexdump(gfx_con_t *con, u32 base, const u8 *buf, u32 len)
|
||||
void gfx_hexdump(u32 base, const u8 *buf, u32 len)
|
||||
{
|
||||
if (con->mute)
|
||||
if (gfx_con.mute)
|
||||
return;
|
||||
|
||||
u8 prevFontSize = con->fntsz;
|
||||
con->fntsz = 8;
|
||||
u8 prevFontSize = gfx_con.fntsz;
|
||||
gfx_con.fntsz = 8;
|
||||
for(u32 i = 0; i < len; i++)
|
||||
{
|
||||
if(i % 0x10 == 0)
|
||||
{
|
||||
if(i != 0)
|
||||
{
|
||||
gfx_puts(con, "| ");
|
||||
gfx_puts("| ");
|
||||
for(u32 j = 0; j < 0x10; j++)
|
||||
{
|
||||
u8 c = buf[i - 0x10 + j];
|
||||
if(c >= 32 && c <= 126)
|
||||
gfx_putc(con, c);
|
||||
gfx_putc(c);
|
||||
else
|
||||
gfx_putc(con, '.');
|
||||
gfx_putc('.');
|
||||
}
|
||||
gfx_putc(con, '\n');
|
||||
gfx_putc('\n');
|
||||
}
|
||||
gfx_printf(con, "%08x: ", base + i);
|
||||
gfx_printf("%08x: ", base + i);
|
||||
}
|
||||
gfx_printf(con, "%02x ", buf[i]);
|
||||
gfx_printf("%02x ", buf[i]);
|
||||
if (i == len - 1)
|
||||
{
|
||||
int ln = len % 0x10 != 0;
|
||||
@@ -424,22 +424,22 @@ void gfx_hexdump(gfx_con_t *con, u32 base, const u8 *buf, u32 len)
|
||||
{
|
||||
k = (len & 0xF) - 1;
|
||||
for (u32 j = 0; j < 0x10 - k; j++)
|
||||
gfx_puts(con, " ");
|
||||
gfx_puts(" ");
|
||||
}
|
||||
gfx_puts(con, "| ");
|
||||
gfx_puts("| ");
|
||||
for(u32 j = 0; j < (ln ? k : k + 1); j++)
|
||||
{
|
||||
u8 c = buf[i - k + j];
|
||||
if(c >= 32 && c <= 126)
|
||||
gfx_putc(con, c);
|
||||
gfx_putc(c);
|
||||
else
|
||||
gfx_putc(con, '.');
|
||||
gfx_putc('.');
|
||||
}
|
||||
gfx_putc(con, '\n');
|
||||
gfx_putc('\n');
|
||||
}
|
||||
}
|
||||
gfx_putc(con, '\n');
|
||||
con->fntsz = prevFontSize;
|
||||
gfx_putc('\n');
|
||||
gfx_con.fntsz = prevFontSize;
|
||||
}
|
||||
|
||||
static int abs(int x)
|
||||
@@ -449,12 +449,12 @@ static int abs(int x)
|
||||
return x;
|
||||
}
|
||||
|
||||
void gfx_set_pixel(gfx_ctxt_t *ctxt, u32 x, u32 y, u32 color)
|
||||
void gfx_set_pixel(u32 x, u32 y, u32 color)
|
||||
{
|
||||
ctxt->fb[x + y * ctxt->stride] = color;
|
||||
gfx_ctxt.fb[x + y * gfx_ctxt.stride] = color;
|
||||
}
|
||||
|
||||
void gfx_line(gfx_ctxt_t *ctxt, int x0, int y0, int x1, int y1, u32 color)
|
||||
void gfx_line(int x0, int y0, int x1, int y1, u32 color)
|
||||
{
|
||||
int dx = abs(x1 - x0), sx = x0 < x1 ? 1 : -1;
|
||||
int dy = abs(y1 - y0), sy = y0 < y1 ? 1 : -1;
|
||||
@@ -462,7 +462,7 @@ void gfx_line(gfx_ctxt_t *ctxt, int x0, int y0, int x1, int y1, u32 color)
|
||||
|
||||
while (1)
|
||||
{
|
||||
gfx_set_pixel(ctxt, x0, y0, color);
|
||||
gfx_set_pixel(x0, y0, color);
|
||||
if (x0 == x1 && y0 == y1)
|
||||
break;
|
||||
e2 = err;
|
||||
@@ -479,46 +479,46 @@ void gfx_line(gfx_ctxt_t *ctxt, int x0, int y0, int x1, int y1, u32 color)
|
||||
}
|
||||
}
|
||||
|
||||
void gfx_set_rect_grey(gfx_ctxt_t *ctxt, const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)
|
||||
void gfx_set_rect_grey(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)
|
||||
{
|
||||
u32 pos = 0;
|
||||
for (u32 y = pos_y; y < (pos_y + size_y); y++)
|
||||
{
|
||||
for (u32 x = pos_x; x < (pos_x + size_x); x++)
|
||||
{
|
||||
memset(&ctxt->fb[x + y*ctxt->stride], buf[pos], 4);
|
||||
memset(&gfx_ctxt.fb[x + y*gfx_ctxt.stride], buf[pos], 4);
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void gfx_set_rect_rgb(gfx_ctxt_t *ctxt, const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)
|
||||
void gfx_set_rect_rgb(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)
|
||||
{
|
||||
u32 pos = 0;
|
||||
for (u32 y = pos_y; y < (pos_y + size_y); y++)
|
||||
{
|
||||
for (u32 x = pos_x; x < (pos_x + size_x); x++)
|
||||
{
|
||||
ctxt->fb[x + y*ctxt->stride] = buf[pos + 2] | (buf[pos + 1] << 8) | (buf[pos] << 16);
|
||||
gfx_ctxt.fb[x + y * gfx_ctxt.stride] = buf[pos + 2] | (buf[pos + 1] << 8) | (buf[pos] << 16);
|
||||
pos+=3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gfx_set_rect_argb(gfx_ctxt_t *ctxt, const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)
|
||||
void gfx_set_rect_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)
|
||||
{
|
||||
u32 *ptr = (u32 *)buf;
|
||||
for (u32 y = pos_y; y < (pos_y + size_y); y++)
|
||||
for (u32 x = pos_x; x < (pos_x + size_x); x++)
|
||||
ctxt->fb[x + y * ctxt->stride] = *ptr++;
|
||||
gfx_ctxt.fb[x + y * gfx_ctxt.stride] = *ptr++;
|
||||
}
|
||||
|
||||
void gfx_render_bmp_argb(gfx_ctxt_t *ctxt, const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)
|
||||
void gfx_render_bmp_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)
|
||||
{
|
||||
for (u32 y = pos_y; y < (pos_y + size_y); y++)
|
||||
{
|
||||
for (u32 x = pos_x; x < (pos_x + size_x); x++)
|
||||
ctxt->fb[x + y * ctxt->stride] = buf[(size_y + pos_y - 1 - y ) * size_x + x - pos_x];
|
||||
gfx_ctxt.fb[x + y * gfx_ctxt.stride] = buf[(size_y + pos_y - 1 - y ) * size_x + x - pos_x];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (C) 2018 CTCaer
|
||||
* Copyright (C) 2018 M4xw
|
||||
* Copyright (c) 2018-2020 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,
|
||||
@@ -21,32 +21,32 @@
|
||||
|
||||
#include "../../common/common_gfx.h"
|
||||
|
||||
#define EPRINTF(text) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFF0000, 0xFFCCCCCC)
|
||||
#define EPRINTFARGS(text, args...) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFF0000, args, 0xFFCCCCCC)
|
||||
#define WPRINTF(text) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFFDD00, 0xFFCCCCCC)
|
||||
#define WPRINTFARGS(text, args...) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFFDD00, args, 0xFFCCCCCC)
|
||||
#define EPRINTF(text) gfx_printf("%k"text"%k\n", 0xFFFF0000, 0xFFCCCCCC)
|
||||
#define EPRINTFARGS(text, args...) gfx_printf("%k"text"%k\n", 0xFFFF0000, args, 0xFFCCCCCC)
|
||||
#define WPRINTF(text) gfx_printf("%k"text"%k\n", 0xFFFFDD00, 0xFFCCCCCC)
|
||||
#define WPRINTFARGS(text, args...) gfx_printf("%k"text"%k\n", 0xFFFFDD00, args, 0xFFCCCCCC)
|
||||
|
||||
void gfx_init_ctxt(gfx_ctxt_t *ctxt, u32 *fb, u32 width, u32 height, u32 stride);
|
||||
void gfx_clear_grey(gfx_ctxt_t *ctxt, u8 color);
|
||||
void gfx_clear_partial_grey(gfx_ctxt_t *ctxt, u8 color, u32 pos_x, u32 height);
|
||||
void gfx_clear_color(gfx_ctxt_t *ctxt, u32 color);
|
||||
void gfx_con_init(gfx_con_t *con, gfx_ctxt_t *ctxt);
|
||||
void gfx_con_setcol(gfx_con_t *con, u32 fgcol, int fillbg, u32 bgcol);
|
||||
void gfx_con_getpos(gfx_con_t *con, u32 *x, u32 *y);
|
||||
void gfx_con_setpos(gfx_con_t *con, u32 x, u32 y);
|
||||
void gfx_putc(gfx_con_t *con, char c);
|
||||
void gfx_puts(gfx_con_t *con, const char *s);
|
||||
void gfx_printf(gfx_con_t *con, const char *fmt, ...);
|
||||
void gfx_hexdump(gfx_con_t *con, u32 base, const u8 *buf, u32 len);
|
||||
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);
|
||||
void gfx_clear_color(u32 color);
|
||||
void gfx_con_init();
|
||||
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(char *s);
|
||||
void gfx_printf(const char *fmt, ...);
|
||||
void gfx_hexdump(u32 base, const u8 *buf, u32 len);
|
||||
|
||||
void gfx_set_pixel(gfx_ctxt_t *ctxt, u32 x, u32 y, u32 color);
|
||||
void gfx_line(gfx_ctxt_t *ctxt, int x0, int y0, int x1, int y1, u32 color);
|
||||
void gfx_put_small_sep(gfx_con_t *con);
|
||||
void gfx_put_big_sep(gfx_con_t *con);
|
||||
void gfx_set_rect_grey(gfx_ctxt_t *ctxt, const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
|
||||
void gfx_set_rect_rgb(gfx_ctxt_t *ctxt, const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
|
||||
void gfx_set_rect_argb(gfx_ctxt_t *ctxt, const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
|
||||
void gfx_render_bmp_argb(gfx_ctxt_t *ctxt, const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
|
||||
void gfx_set_pixel(u32 x, u32 y, u32 color);
|
||||
void gfx_line(int x0, int y0, int x1, int y1, u32 color);
|
||||
void gfx_put_small_sep();
|
||||
void gfx_put_big_sep();
|
||||
void gfx_set_rect_grey(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
|
||||
void gfx_set_rect_rgb(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
|
||||
void gfx_set_rect_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
|
||||
void gfx_render_bmp_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
|
||||
|
||||
// Global gfx console and context.
|
||||
gfx_ctxt_t gfx_ctxt;
|
||||
|
||||
@@ -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,
|
||||
@@ -477,4 +477,61 @@ static u8 BOOTLOGO_BLZ[SZ_BOOTLOGO_BLZ] = {
|
||||
0x6C, 0x23, 0x00, 0x00
|
||||
};
|
||||
|
||||
// 21 x 50 @8bpp RGB.
|
||||
#define X_BATTERY_EMPTY 21
|
||||
#define Y_BATTERY_EMPTY_BATT 38
|
||||
#define Y_BATTERY_EMPTY_CHRG 12
|
||||
#define SZ_BATTERY_EMPTY 3150
|
||||
#define SZ_BATTERY_EMPTY_BLZ 740
|
||||
static u8 BATTERY_EMPTY_BLZ[SZ_BATTERY_EMPTY_BLZ] =
|
||||
{
|
||||
0x17, 0xC0, 0x5D, 0x51, 0x79, 0x12, 0x79, 0x48, 0x69, 0x00, 0x0D, 0x46, 0xE3, 0x0F, 0xF0, 0x20,
|
||||
0xF0, 0x35, 0x2E, 0x38, 0x3F, 0x40, 0xEF, 0xCF, 0x00, 0x89, 0x77, 0x00, 0x17, 0x01, 0x14, 0x09,
|
||||
0x90, 0x36, 0xF0, 0xA4, 0xF1, 0x62, 0x01, 0x38, 0xA1, 0x99, 0x84, 0x3E, 0x00, 0x23, 0x1F, 0x04,
|
||||
0x40, 0x3B, 0xF0, 0x5B, 0x4F, 0x00, 0x18, 0x25, 0x20, 0x24, 0x90, 0x57, 0x00, 0x3C, 0xC0, 0x7B,
|
||||
0x00, 0x63, 0x10, 0x31, 0x7C, 0x2B, 0x03, 0x30, 0x3C, 0xF0, 0xA2, 0x00, 0xCE, 0x11, 0x0F, 0x0D,
|
||||
0x21, 0x00, 0x9E, 0xDE, 0x00, 0x06, 0x40, 0x60, 0xF0, 0xB9, 0xA0, 0xEA, 0x70, 0x3C, 0xF0, 0xF5,
|
||||
0x67, 0xD4, 0x3E, 0x01, 0x54, 0x00, 0x00, 0x00, 0x57, 0x70, 0xCD, 0xB1, 0x00, 0x1E, 0xFB, 0xD9,
|
||||
0x15, 0xA0, 0xC9, 0xAE, 0x69, 0x30, 0x3C, 0xD0, 0x30, 0xF0, 0xE4, 0xC1, 0xA7, 0x18, 0x10, 0x0D,
|
||||
0x0C, 0x00, 0x49, 0x3F, 0x04, 0x00, 0x87, 0x75, 0x00, 0xC5, 0xAA, 0x2A, 0x00, 0x09, 0x40, 0xC0,
|
||||
0xD7, 0xBA, 0x24, 0x00, 0x0C, 0xA0, 0x33, 0xF0, 0xF7, 0xD6, 0x0C, 0x00, 0x9C, 0x3C, 0xA0, 0x07,
|
||||
0x06, 0x2A, 0x10, 0x7D, 0x6C, 0x00, 0xBB, 0x09, 0xA2, 0x00, 0xF3, 0xD2, 0x00, 0xE3, 0xC4, 0x0C,
|
||||
0xA0, 0x80, 0x3C, 0xF0, 0x41, 0x38, 0x05, 0x50, 0x3E, 0xF1, 0x03, 0x00, 0x01, 0x19, 0x01, 0x00,
|
||||
0x33, 0x2C, 0x00, 0x71, 0x62, 0x00, 0x00, 0xAF, 0x97, 0x00, 0xEB, 0xCB, 0x03, 0x30, 0x03, 0x30,
|
||||
0x3C, 0x40, 0xE0, 0x81, 0x70, 0x04, 0x40, 0x0F, 0xF0, 0x23, 0xF0, 0x2D, 0x27, 0x00, 0x1C, 0x6B,
|
||||
0x5D, 0x00, 0xA9, 0x92, 0x00, 0xE7, 0xC8, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xDC, 0x00, 0xBF, 0xA5,
|
||||
0x0E, 0xE0, 0x81, 0x0F, 0xF0, 0x19, 0xF0, 0xA5, 0x00, 0x22, 0x00, 0x65, 0x58, 0x00, 0x07, 0x67,
|
||||
0x59, 0x07, 0x70, 0x0F, 0xF0, 0x2A, 0xF0, 0x06, 0x09, 0x45, 0x10, 0x3C, 0x0A, 0x00, 0x00, 0x03,
|
||||
0x30, 0x00, 0x00, 0x49, 0x11, 0x0B, 0x47, 0x0E, 0x10, 0x0B, 0x1B, 0x06, 0x04, 0x3F, 0xF0, 0xD2,
|
||||
0xF0, 0xCD, 0x38, 0xE0, 0x85, 0xF8, 0xF7, 0x3A, 0x26, 0x75, 0x00, 0xD2, 0xF0, 0x33, 0x00, 0x27,
|
||||
0x71, 0x09, 0x06, 0x24, 0x30, 0xBD, 0x2C, 0x1D, 0x15, 0x00, 0xDB, 0x44, 0x33, 0x22, 0x00, 0x00,
|
||||
0x03, 0x30, 0x00, 0x00, 0x57, 0x00, 0x5D, 0x00, 0x18, 0x00, 0xFC, 0xC7, 0x2E, 0x1F, 0x00, 0x00,
|
||||
0x45, 0x00, 0x29, 0x09, 0x06, 0x18, 0x89, 0x30, 0x2F, 0x0B, 0x07, 0xDF, 0x34, 0x23, 0x21, 0xC0,
|
||||
0x81, 0x59, 0x15, 0x0E, 0x3C, 0xC0, 0x2A, 0x00, 0xF5, 0xC7, 0xE1, 0x34, 0x38, 0x23, 0x31, 0x0B,
|
||||
0x07, 0xC9, 0x2F, 0x1F, 0x33, 0x00, 0x80, 0x2D, 0x00, 0x1E, 0x90, 0x4D, 0x12, 0x0C, 0x2D, 0xC0,
|
||||
0x41, 0x0F, 0x23, 0x0A, 0x03, 0x30, 0x00, 0x00, 0xD9, 0x33, 0x22, 0xE7, 0x36, 0x06, 0x24, 0x06,
|
||||
0x00, 0xCB, 0x2F, 0x1F, 0x39, 0x30, 0x15, 0x05, 0x22, 0x03, 0x06, 0x60, 0x0F, 0xF0, 0x21, 0xF0,
|
||||
0x0F, 0x03, 0x02, 0x03, 0x00, 0x8E, 0xF9, 0x3A, 0x3C, 0xA0, 0x0F, 0xF0, 0x27, 0xF0, 0x3C, 0xF0,
|
||||
0x3C, 0xF0, 0x30, 0xF0, 0xFC, 0x3C, 0xF0, 0x3C, 0xF0, 0x0F, 0xF0, 0x27, 0xF0, 0x3C, 0xF0, 0x3C,
|
||||
0xF0, 0x30, 0xF0, 0x3C, 0xF0, 0xFF, 0x3C, 0xF0, 0x0F, 0xF0, 0x27, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0,
|
||||
0x30, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0xFF, 0x0F, 0xF0, 0x27, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x30,
|
||||
0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x0F, 0xF0, 0xFF, 0x27, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x30, 0xF0,
|
||||
0x3C, 0xF0, 0x3C, 0xF0, 0x0F, 0xF0, 0x27, 0xF0, 0xFF, 0x3C, 0xF0, 0x3C, 0xF0, 0x30, 0xF0, 0x3C,
|
||||
0xF0, 0x3C, 0xF0, 0x0F, 0xF0, 0x27, 0xF0, 0x3C, 0xF0, 0xFF, 0x3C, 0xF0, 0x30, 0xF0, 0x3C, 0xF0,
|
||||
0x3C, 0xF0, 0x0F, 0xF0, 0x27, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0xFF, 0x30, 0xF0, 0x3C, 0xF0, 0x3C,
|
||||
0xF0, 0x0F, 0xF0, 0x27, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x30, 0xF0, 0xFF, 0x3C, 0xF0, 0x3C, 0xF0,
|
||||
0x0F, 0xF0, 0x27, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x30, 0xF0, 0x3C, 0xF0, 0xFF, 0x3C, 0xF0, 0x0F,
|
||||
0xF0, 0x27, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x30, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0xFF, 0x0F, 0xF0,
|
||||
0x27, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x30, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x0F, 0xF0, 0xFF, 0x27,
|
||||
0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x30, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x0F, 0xF0, 0x27, 0xF0, 0xFF,
|
||||
0x3C, 0xF0, 0x3C, 0xF0, 0x30, 0xF0, 0x3C, 0xF0, 0x84, 0x90, 0x3F, 0x00, 0x00, 0x00, 0x0F, 0xF0,
|
||||
0xFF, 0x09, 0x90, 0x03, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x02, 0x07, 0x01, 0xB1, 0x40,
|
||||
0x81, 0x20, 0x33, 0x0C, 0x08, 0x00, 0x00, 0x0F, 0xF0, 0xC6, 0x09, 0x90, 0x03, 0x30, 0x00, 0x00,
|
||||
0x0D, 0x03, 0x02, 0x2D, 0x0A, 0x07, 0x07, 0x75, 0x30, 0x39, 0x00, 0x00, 0x00, 0x0F, 0xF0, 0x0F,
|
||||
0xF0, 0x1B, 0xF0, 0x03, 0x00, 0xFE, 0x39, 0x00, 0xB1, 0x29, 0x1B, 0xF3, 0x39, 0x26, 0x00, 0x00,
|
||||
0x81, 0x0F, 0xF0, 0x09, 0x90, 0x03, 0x30, 0x00, 0x00, 0xFE, 0x3B, 0x27, 0xF5, 0x0F, 0x39, 0x26,
|
||||
0xB3, 0x2A, 0x1C, 0x17, 0x05, 0x03, 0x00, 0xFF, 0xE4, 0x02, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,
|
||||
0x6A, 0x09, 0x00, 0x00
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -32,7 +32,7 @@ extern u8 *Kc_MENU_LOGO;
|
||||
|
||||
extern hekate_config h_cfg;
|
||||
|
||||
void tui_sbar(gfx_con_t *con, bool force_update)
|
||||
void tui_sbar(bool force_update)
|
||||
{
|
||||
u32 cx, cy;
|
||||
|
||||
@@ -41,78 +41,78 @@ void tui_sbar(gfx_con_t *con, bool force_update)
|
||||
if (timePassed < 5)
|
||||
return;
|
||||
|
||||
u8 prevFontSize = con->fntsz;
|
||||
con->fntsz = 16;
|
||||
u8 prevFontSize = gfx_con.fntsz;
|
||||
gfx_con.fntsz = 16;
|
||||
h_cfg.sbar_time_keeping = get_tmr_s();
|
||||
|
||||
u32 battPercent = 0;
|
||||
int battVoltCurr = 0;
|
||||
|
||||
gfx_con_getpos(con, &cx, &cy);
|
||||
gfx_con_setpos(con, 0, 1260);
|
||||
gfx_con_getpos(&cx, &cy);
|
||||
gfx_con_setpos(0, 1260);
|
||||
|
||||
max17050_get_property(MAX17050_RepSOC, (int *)&battPercent);
|
||||
max17050_get_property(MAX17050_VCELL, &battVoltCurr);
|
||||
|
||||
gfx_clear_partial_grey(con->gfx_ctxt, 0x30, 1256, 24);
|
||||
gfx_printf(con, "%K%k Battery: %d.%d%% (%d mV) - Charge:", 0xFF303030, 0xFF888888,
|
||||
gfx_clear_partial_grey(0x30, 1256, 24);
|
||||
gfx_printf("%K%k Battery: %d.%d%% (%d mV) - Charge:", 0xFF303030, 0xFF888888,
|
||||
(battPercent >> 8) & 0xFF, (battPercent & 0xFF) / 26, battVoltCurr);
|
||||
|
||||
max17050_get_property(MAX17050_AvgCurrent, &battVoltCurr);
|
||||
max17050_get_property(MAX17050_Current, &battVoltCurr);
|
||||
|
||||
if (battVoltCurr >= 0)
|
||||
gfx_printf(con, " %k+%d mA%k%K\n",
|
||||
gfx_printf(" %k+%d mA%k%K\n",
|
||||
0xFF008800, battVoltCurr / 1000, 0xFFCCCCCC, 0xFF1B1B1B);
|
||||
else
|
||||
gfx_printf(con, " %k-%d mA%k%K\n",
|
||||
gfx_printf(" %k-%d mA%k%K\n",
|
||||
0xFF880000, (~battVoltCurr) / 1000, 0xFFCCCCCC, 0xFF1B1B1B);
|
||||
con->fntsz = prevFontSize;
|
||||
gfx_con_setpos(con, cx, cy);
|
||||
gfx_con.fntsz = prevFontSize;
|
||||
gfx_con_setpos(cx, cy);
|
||||
}
|
||||
|
||||
void tui_pbar(gfx_con_t *con, int x, int y, u32 val, u32 fgcol, u32 bgcol)
|
||||
void tui_pbar(int x, int y, u32 val, u32 fgcol, u32 bgcol)
|
||||
{
|
||||
u32 cx, cy;
|
||||
if (val > 200)
|
||||
val = 200;
|
||||
|
||||
gfx_con_getpos(con, &cx, &cy);
|
||||
gfx_con_getpos(&cx, &cy);
|
||||
|
||||
gfx_con_setpos(con, x, y);
|
||||
gfx_con_setpos(x, y);
|
||||
|
||||
gfx_printf(con, "%k[%3d%%]%k", fgcol, val, 0xFFCCCCCC);
|
||||
gfx_printf("%k[%3d%%]%k", fgcol, val, 0xFFCCCCCC);
|
||||
|
||||
x += 7 * con->fntsz;
|
||||
|
||||
for (int i = 0; i < (con->fntsz >> 3) * 6; i++)
|
||||
x += 7 * gfx_con.fntsz;
|
||||
|
||||
for (int i = 0; i < (gfx_con.fntsz >> 3) * 6; i++)
|
||||
{
|
||||
gfx_line(con->gfx_ctxt, x, y + i + 1, x + 3 * val, y + i + 1, fgcol);
|
||||
gfx_line(con->gfx_ctxt, x + 3 * val, y + i + 1, x + 3 * 100, y + i + 1, bgcol);
|
||||
gfx_line(x, y + i + 1, x + 3 * val, y + i + 1, fgcol);
|
||||
gfx_line(x + 3 * val, y + i + 1, x + 3 * 100, y + i + 1, bgcol);
|
||||
}
|
||||
|
||||
gfx_con_setpos(con, cx, cy);
|
||||
gfx_con_setpos(cx, cy);
|
||||
|
||||
// Update status bar.
|
||||
tui_sbar(con, false);
|
||||
tui_sbar(false);
|
||||
}
|
||||
|
||||
void *tui_do_menu(gfx_con_t *con, menu_t *menu)
|
||||
void *tui_do_menu(menu_t *menu)
|
||||
{
|
||||
int idx = 0, prev_idx = 0, cnt = 0x7FFFFFFF;
|
||||
|
||||
gfx_clear_partial_grey(con->gfx_ctxt, 0x1B, 0, 1256);
|
||||
tui_sbar(con, true);
|
||||
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||
tui_sbar(true);
|
||||
|
||||
#ifdef MENU_LOGO_ENABLE
|
||||
gfx_set_rect_rgb(con->gfx_ctxt, Kc_MENU_LOGO,
|
||||
gfx_set_rect_rgb(Kc_MENU_LOGO,
|
||||
X_MENU_LOGO, Y_MENU_LOGO, X_POS_MENU_LOGO, Y_POS_MENU_LOGO);
|
||||
#endif //MENU_LOGO_ENABLE
|
||||
|
||||
while (true)
|
||||
{
|
||||
gfx_con_setcol(con, 0xFFCCCCCC, 1, 0xFF1B1B1B);
|
||||
gfx_con_setpos(con, menu->x, menu->y);
|
||||
gfx_printf(con, "[%s]\n\n", menu->caption);
|
||||
gfx_con_setcol(0xFFCCCCCC, 1, 0xFF1B1B1B);
|
||||
gfx_con_setpos(menu->x, menu->y);
|
||||
gfx_printf("[%s]\n\n", menu->caption);
|
||||
|
||||
// Skip caption or seperator lines selection.
|
||||
while (menu->ents[idx].type == MENT_CAPTION ||
|
||||
@@ -143,30 +143,25 @@ void *tui_do_menu(gfx_con_t *con, menu_t *menu)
|
||||
for (cnt = 0; menu->ents[cnt].type != MENT_END; cnt++)
|
||||
{
|
||||
if (cnt == idx)
|
||||
gfx_con_setcol(con, 0xFF1B1B1B, 1, 0xFFCCCCCC);
|
||||
gfx_con_setcol(0xFF1B1B1B, 1, 0xFFCCCCCC);
|
||||
else
|
||||
gfx_con_setcol(con, 0xFFCCCCCC, 1, 0xFF1B1B1B);
|
||||
gfx_con_setcol(0xFFCCCCCC, 1, 0xFF1B1B1B);
|
||||
if (menu->ents[cnt].type == MENT_CAPTION)
|
||||
gfx_printf(con, "%k %s", menu->ents[cnt].color, menu->ents[cnt].caption);
|
||||
gfx_printf("%k %s", menu->ents[cnt].color, menu->ents[cnt].caption);
|
||||
else if (menu->ents[cnt].type != MENT_CHGLINE)
|
||||
gfx_printf(con, " %s", menu->ents[cnt].caption);
|
||||
gfx_printf(" %s", menu->ents[cnt].caption);
|
||||
if(menu->ents[cnt].type == MENT_MENU)
|
||||
gfx_printf(con, "%k...", 0xFF0099EE);
|
||||
gfx_printf(con, " \n");
|
||||
gfx_printf("%k...", 0xFF0099EE);
|
||||
gfx_printf(" \n");
|
||||
}
|
||||
gfx_con_setcol(con, 0xFFCCCCCC, 1, 0xFF1B1B1B);
|
||||
gfx_putc(con, '\n');
|
||||
gfx_con_setcol(0xFFCCCCCC, 1, 0xFF1B1B1B);
|
||||
gfx_putc('\n');
|
||||
|
||||
// Print help and battery status.
|
||||
gfx_con_setpos(con, 0, 1127);
|
||||
if (h_cfg.errors)
|
||||
{
|
||||
gfx_printf(con, "%k Warning: %k", 0xFF800000, 0xFF555555);
|
||||
if (h_cfg.errors & ERR_LIBSYS_LP0)
|
||||
gfx_printf(con, "Sleep mode library is missing!\n");
|
||||
}
|
||||
gfx_con_setpos(con, 0, 1191);
|
||||
gfx_printf(con, "%k VOL: Move up/down\n PWR: Select option%k", 0xFF555555, 0xFFCCCCCC);
|
||||
// Print errors, help and battery status.
|
||||
gfx_con_setpos(0, 1127);
|
||||
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);
|
||||
|
||||
display_backlight_brightness(h_cfg.backlight, 1000);
|
||||
|
||||
@@ -196,7 +191,7 @@ void *tui_do_menu(gfx_con_t *con, menu_t *menu)
|
||||
ent->handler(ent->data);
|
||||
break;
|
||||
case MENT_MENU:
|
||||
return tui_do_menu(con, ent->menu);
|
||||
return tui_do_menu(ent->menu);
|
||||
break;
|
||||
case MENT_DATA:
|
||||
return ent->data;
|
||||
@@ -212,14 +207,14 @@ void *tui_do_menu(gfx_con_t *con, menu_t *menu)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
con->fntsz = 16;
|
||||
gfx_clear_partial_grey(con->gfx_ctxt, 0x1B, 0, 1256);
|
||||
gfx_con.fntsz = 16;
|
||||
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||
#ifdef MENU_LOGO_ENABLE
|
||||
gfx_set_rect_rgb(con->gfx_ctxt, Kc_MENU_LOGO,
|
||||
gfx_set_rect_rgb(Kc_MENU_LOGO,
|
||||
X_MENU_LOGO, Y_MENU_LOGO, X_POS_MENU_LOGO, Y_POS_MENU_LOGO);
|
||||
#endif //MENU_LOGO_ENABLE
|
||||
}
|
||||
tui_sbar(con, false);
|
||||
tui_sbar(false);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
@@ -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,
|
||||
@@ -59,8 +59,8 @@ typedef struct _menu_t
|
||||
#define MDEF_CAPTION(caption, color) { MENT_CAPTION, caption, color }
|
||||
#define MDEF_CHGLINE() {MENT_CHGLINE}
|
||||
|
||||
void tui_sbar(gfx_con_t *con, bool force_update);
|
||||
void tui_pbar(gfx_con_t *con, int x, int y, u32 val, u32 fgcol, u32 bgcol);
|
||||
void *tui_do_menu(gfx_con_t *con, menu_t *menu);
|
||||
void tui_sbar(bool force_update);
|
||||
void tui_pbar(int x, int y, u32 val, u32 fgcol, u32 bgcol);
|
||||
void *tui_do_menu(menu_t *menu);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Atmosphère Fusée Secondary Storage parser.
|
||||
*
|
||||
* Copyright (c) 2019 CTCaer
|
||||
* Copyright (c) 2019-2020 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,12 +20,19 @@
|
||||
|
||||
#include "fss.h"
|
||||
#include "hos.h"
|
||||
#include "../config/config.h"
|
||||
#include "../libs/fatfs/ff.h"
|
||||
#include "../mem/heap.h"
|
||||
#include "../storage/emummc.h"
|
||||
|
||||
#include "../gfx/gfx.h"
|
||||
#define DPRINTF(...)
|
||||
|
||||
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
|
||||
@@ -35,6 +42,11 @@
|
||||
#define CNT_TYPE_SP2 5
|
||||
#define CNT_TYPE_KIP 6
|
||||
#define CNT_TYPE_BMP 7
|
||||
#define CNT_TYPE_EMC 8
|
||||
#define CNT_TYPE_KLD 9
|
||||
#define CNT_TYPE_KRN 10
|
||||
|
||||
#define CNT_FLAG0_EXPERIMENTAL (1 << 0)
|
||||
|
||||
typedef struct _fss_t
|
||||
{
|
||||
@@ -52,15 +64,60 @@ typedef struct _fss_content_t
|
||||
{
|
||||
u32 offset;
|
||||
u32 size;
|
||||
u32 type;
|
||||
u8 type;
|
||||
u8 flags0;
|
||||
u8 flags1;
|
||||
u8 flags2;
|
||||
u32 rsvd1;
|
||||
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;
|
||||
if (f_open(&fp, value, FA_READ) != FR_OK)
|
||||
|
||||
bool stock = false;
|
||||
int sept_used = 0;
|
||||
|
||||
if (!sept_ctxt)
|
||||
{
|
||||
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ctxt->cfg->kvs, link)
|
||||
{
|
||||
if (!strcmp("stock", kv->key))
|
||||
if (kv->val[0] == '1')
|
||||
stock = true;
|
||||
}
|
||||
|
||||
if (stock && ctxt->pkg1_id->kb <= KB_FIRMWARE_VERSION_620 && (!emu_cfg.enabled || h_cfg.emummc_force_disable))
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (f_open(&fp, path, FA_READ) != FR_OK)
|
||||
return 0;
|
||||
|
||||
void *fss = malloc(f_size(&fp));
|
||||
@@ -72,56 +129,103 @@ int parse_fss(launch_ctxt_t *ctxt, const char *value)
|
||||
|
||||
if (fss_meta->magic == FSS0_MAGIC)
|
||||
{
|
||||
gfx_printf(&gfx_con, "Found FSS0, Atmosphere %d.%d.%d-%08x\n"
|
||||
gfx_printf("Found FSS0, Atmosphere %d.%d.%d-%08x\n"
|
||||
"Max HOS supported: %d.%d.%d\n"
|
||||
"Unpacking and loading components.. ",
|
||||
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 (int i = 0; i < fss_meta->cnt_count; i++)
|
||||
for (u32 i = 0; i < fss_meta->cnt_count; i++)
|
||||
{
|
||||
content = (void *)(fss + curr_fss_cnt[i].offset);
|
||||
if ((curr_fss_cnt[i].offset + curr_fss_cnt[i].size) > fss_meta->size)
|
||||
continue;
|
||||
|
||||
// Load content to launch context.
|
||||
switch (curr_fss_cnt[i].type)
|
||||
{
|
||||
case CNT_TYPE_KIP:;
|
||||
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:
|
||||
if ((curr_fss_cnt[i].flags0 & CNT_FLAG0_EXPERIMENTAL) && !ctxt->fss0_enable_experimental)
|
||||
continue;
|
||||
// TODO: add more types?
|
||||
// case CNT_TYPE_SP1:
|
||||
// case CNT_TYPE_SP2:
|
||||
|
||||
// Load content to launch context.
|
||||
if (!sept_ctxt)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
gfx_printf(&gfx_con, "Done!\n");
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -28,14 +28,17 @@
|
||||
#include "../gfx/di.h"
|
||||
#include "../mem/heap.h"
|
||||
#include "../mem/mc.h"
|
||||
#include "../mem/minerva.h"
|
||||
#include "../sec/se.h"
|
||||
#include "../sec/se_t210.h"
|
||||
#include "../sec/tsec.h"
|
||||
#include "../soc/bpmp.h"
|
||||
#include "../soc/cluster.h"
|
||||
#include "../soc/fuse.h"
|
||||
#include "../soc/pmc.h"
|
||||
#include "../soc/smmu.h"
|
||||
#include "../soc/t210.h"
|
||||
#include "../storage/emummc.h"
|
||||
#include "../storage/nx_emmc.h"
|
||||
#include "../storage/sdmmc.h"
|
||||
#include "../utils/util.h"
|
||||
@@ -44,10 +47,16 @@
|
||||
extern hekate_config h_cfg;
|
||||
|
||||
extern void sd_unmount();
|
||||
extern bool sd_mount();
|
||||
|
||||
//#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__)
|
||||
//#define DPRINTF(...) gfx_printf(__VA_ARGS__)
|
||||
#define DPRINTF(...)
|
||||
|
||||
#define EHPRINTFARGS(text, args...) \
|
||||
({ display_backlight_brightness(h_cfg.backlight, 1000); \
|
||||
gfx_con.mute = false; \
|
||||
gfx_printf("%k"text"%k\n", 0xFFFF0000, args, 0xFFCCCCCC); })
|
||||
|
||||
#define PKG2_LOAD_ADDR 0xA9800000
|
||||
|
||||
// Secmon mailbox.
|
||||
@@ -80,49 +89,56 @@ 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 };
|
||||
{ 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(&gfx_con, "SE(SE_SECURITY_0) = %08X\n", SE(SE_SECURITY_0));
|
||||
gfx_printf(&gfx_con, "SE(0x4) = %08X\n", SE(0x4));
|
||||
gfx_printf(&gfx_con, "SE(SE_KEY_TABLE_ACCESS_LOCK_OFFSET) = %08X\n", SE(SE_KEY_TABLE_ACCESS_LOCK_OFFSET));
|
||||
gfx_printf(&gfx_con, "SE(SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET) = %08X\n", SE(SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET));
|
||||
/*gfx_printf("SE(SE_SECURITY_0) = %08X\n", SE(SE_SECURITY_0));
|
||||
gfx_printf("SE(0x4) = %08X\n", SE(0x4));
|
||||
gfx_printf("SE(SE_KEY_TABLE_ACCESS_LOCK_OFFSET) = %08X\n", SE(SE_KEY_TABLE_ACCESS_LOCK_OFFSET));
|
||||
gfx_printf("SE(SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET) = %08X\n", SE(SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET));
|
||||
for(u32 i = 0; i < 16; i++)
|
||||
gfx_printf(&gfx_con, "%02X ", SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + i * 4) & 0xFF);
|
||||
gfx_putc(&gfx_con, '\n');
|
||||
gfx_printf("%02X ", SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + i * 4) & 0xFF);
|
||||
gfx_putc('\n');
|
||||
for(u32 i = 0; i < 2; i++)
|
||||
gfx_printf(&gfx_con, "%02X ", SE(SE_RSA_KEYTABLE_ACCESS_REG_OFFSET + i * 4) & 0xFF);
|
||||
gfx_putc(&gfx_con, '\n');
|
||||
gfx_hexdump(&gfx_con, SE_BASE, (void *)SE_BASE, 0x400);*/
|
||||
gfx_printf("%02X ", SE(SE_RSA_KEYTABLE_ACCESS_REG_OFFSET + i * 4) & 0xFF);
|
||||
gfx_putc('\n');
|
||||
gfx_hexdump(SE_BASE, (void *)SE_BASE, 0x400);*/
|
||||
}
|
||||
|
||||
void _pmc_scratch_lock(u32 kb)
|
||||
@@ -132,7 +148,7 @@ void _pmc_scratch_lock(u32 kb)
|
||||
case KB_FIRMWARE_VERSION_100_200:
|
||||
case KB_FIRMWARE_VERSION_300:
|
||||
case KB_FIRMWARE_VERSION_301:
|
||||
PMC(APBDEV_PMC_SEC_DISABLE) = 0x7FFFF3;
|
||||
PMC(APBDEV_PMC_SEC_DISABLE) = 0x7FFFF3;
|
||||
PMC(APBDEV_PMC_SEC_DISABLE2) = 0xFFFFFFFF;
|
||||
PMC(APBDEV_PMC_SEC_DISABLE3) = 0xFFAFFFFF;
|
||||
PMC(APBDEV_PMC_SEC_DISABLE4) = 0xFFFFFFFF;
|
||||
@@ -154,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;
|
||||
@@ -170,7 +185,7 @@ void _sysctr0_reset()
|
||||
SYSCTR0(SYSCTR0_COUNTERID11) = 0;
|
||||
}
|
||||
|
||||
int keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt)
|
||||
int keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt, launch_ctxt_t *hos_ctxt)
|
||||
{
|
||||
u8 tmp[0x20];
|
||||
u32 retries = 0;
|
||||
@@ -182,8 +197,10 @@ int keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt)
|
||||
tsec_ctxt->size = 0xF00;
|
||||
else if (kb == KB_FIRMWARE_VERSION_620)
|
||||
tsec_ctxt->size = 0x2900;
|
||||
else
|
||||
else if (kb == KB_FIRMWARE_VERSION_700)
|
||||
tsec_ctxt->size = 0x3000;
|
||||
else
|
||||
tsec_ctxt->size = 0x3300;
|
||||
|
||||
// Prepare smmu tsec page for 6.2.0.
|
||||
if (kb == KB_FIRMWARE_VERSION_620)
|
||||
@@ -204,7 +221,7 @@ int keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt)
|
||||
// We rely on racing conditions, make sure we cover even the unluckiest cases.
|
||||
if (retries > 15)
|
||||
{
|
||||
EPRINTF("\nFailed to get TSEC keys. Please try again.\n");
|
||||
_hos_crit_error("\nFailed to get TSEC keys. Please try again.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -219,16 +236,36 @@ int keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt)
|
||||
// Set TSEC root key.
|
||||
se_aes_key_set(13, tmp + 0x10, 0x10);
|
||||
|
||||
// Package2 key.
|
||||
se_aes_key_set(8, tmp + 0x10, 0x10);
|
||||
se_aes_unwrap_key(8, 8, master_keyseed_620);
|
||||
se_aes_unwrap_key(8, 8, master_keyseed_retail);
|
||||
se_aes_unwrap_key(8, 8, package2_keyseed);
|
||||
if (!(emu_cfg.enabled && !h_cfg.emummc_force_disable) && hos_ctxt->stock)
|
||||
{
|
||||
// Package2 key.
|
||||
se_aes_key_set(8, tmp + 0x10, 0x10);
|
||||
se_aes_unwrap_key(8, 8, master_keyseed_620);
|
||||
se_aes_unwrap_key(8, 8, master_keyseed_retail);
|
||||
se_aes_unwrap_key(8, 8, package2_keyseed);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Decrypt keyblob and set keyslots
|
||||
se_aes_crypt_block_ecb(12, 0, tmp + 0x20, keyblob_keyseeds[0]);
|
||||
se_aes_unwrap_key(15, 14, tmp + 0x20);
|
||||
se_aes_unwrap_key(14, 15, console_keyseed_4xx_5xx);
|
||||
se_aes_unwrap_key(15, 15, console_keyseed);
|
||||
|
||||
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);
|
||||
|
||||
h_cfg.se_keygen_done = 1;
|
||||
}
|
||||
}
|
||||
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);
|
||||
@@ -283,7 +320,7 @@ int keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_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);
|
||||
}
|
||||
|
||||
@@ -292,27 +329,38 @@ int keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt)
|
||||
|
||||
static int _read_emmc_pkg1(launch_ctxt_t *ctxt)
|
||||
{
|
||||
int res = 0;
|
||||
sdmmc_storage_t storage;
|
||||
sdmmc_t sdmmc;
|
||||
|
||||
sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4);
|
||||
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);
|
||||
sdmmc_storage_set_mmc_partition(&storage, 1);
|
||||
sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, ctxt->pkg1);
|
||||
emummc_storage_set_mmc_partition(&storage, 1);
|
||||
emummc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, ctxt->pkg1);
|
||||
ctxt->pkg1_id = pkg1_identify(ctxt->pkg1);
|
||||
if (!ctxt->pkg1_id)
|
||||
{
|
||||
EPRINTF("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(&gfx_con, "Identified pkg1 and Keyblob %d\n\n", ctxt->pkg1_id->kb);
|
||||
gfx_printf("Identified pkg1 and Keyblob %d\n\n", ctxt->pkg1_id->kb);
|
||||
|
||||
// Read the correct keyblob.
|
||||
ctxt->keyblob = (u8 *)calloc(NX_EMMC_BLOCKSIZE, 1);
|
||||
sdmmc_storage_read(&storage, 0x180000 / NX_EMMC_BLOCKSIZE + ctxt->pkg1_id->kb, 1, ctxt->keyblob);
|
||||
emummc_storage_read(&storage, 0x180000 / NX_EMMC_BLOCKSIZE + ctxt->pkg1_id->kb, 1, ctxt->keyblob);
|
||||
|
||||
res = 1;
|
||||
|
||||
@@ -327,14 +375,24 @@ static u8 *_read_emmc_pkg2(launch_ctxt_t *ctxt)
|
||||
sdmmc_storage_t storage;
|
||||
sdmmc_t sdmmc;
|
||||
|
||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
|
||||
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;
|
||||
sdmmc_storage_set_mmc_partition(&storage, 0);
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -347,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);
|
||||
@@ -355,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);
|
||||
@@ -380,6 +438,7 @@ static void _free_launch_components(launch_ctxt_t *ctxt)
|
||||
|
||||
int hos_launch(ini_sec_t *cfg)
|
||||
{
|
||||
minerva_change_freq(FREQ_1600);
|
||||
launch_ctxt_t ctxt;
|
||||
tsec_ctxt_t tsec_ctxt;
|
||||
volatile secmon_mailbox_t *secmon_mb;
|
||||
@@ -388,28 +447,51 @@ int hos_launch(ini_sec_t *cfg)
|
||||
memset(&tsec_ctxt, 0, sizeof(tsec_ctxt_t));
|
||||
list_init(&ctxt.kip1_list);
|
||||
|
||||
ctxt.cfg = cfg;
|
||||
|
||||
if (!gfx_con.mute)
|
||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
gfx_clear_grey(0x1B);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
// Try to parse config if present.
|
||||
if (cfg && !parse_boot_config(&ctxt, cfg))
|
||||
return 0;
|
||||
|
||||
gfx_printf(&gfx_con, "Initializing...\n\n");
|
||||
gfx_printf("Initializing...\n\n");
|
||||
|
||||
// Read package1 and the correct keyblob.
|
||||
if (!_read_emmc_pkg1(&ctxt))
|
||||
return 0;
|
||||
|
||||
// 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)
|
||||
// Try to parse config if present.
|
||||
if (ctxt.cfg && !parse_boot_config(&ctxt))
|
||||
{
|
||||
_hos_crit_error("Wrong ini cfg or missing files!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Enable emummc patching.
|
||||
if (emu_cfg.enabled && !h_cfg.emummc_force_disable)
|
||||
{
|
||||
if (ctxt.stock)
|
||||
{
|
||||
_hos_crit_error("Stock emuMMC is not supported yet!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ctxt.atmosphere = true; // Set atmosphere patching in case of Stock emuMMC and no fss0.
|
||||
config_kip1patch(&ctxt, "emummc");
|
||||
}
|
||||
|
||||
// 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(&gfx_con, "Loaded pkg1 & keyblob\n");
|
||||
gfx_printf("Loaded pkg1 & keyblob\n");
|
||||
|
||||
// Generate keys.
|
||||
if (!h_cfg.se_keygen_done || ctxt.pkg1_id->kb == KB_FIRMWARE_VERSION_620)
|
||||
if (!h_cfg.se_keygen_done)
|
||||
{
|
||||
tsec_ctxt.fw = (u8 *)ctxt.pkg1 + ctxt.pkg1_id->tsec_off;
|
||||
tsec_ctxt.pkg1 = ctxt.pkg1;
|
||||
@@ -418,15 +500,15 @@ int hos_launch(ini_sec_t *cfg)
|
||||
|
||||
if (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_700 && !h_cfg.sept_run)
|
||||
{
|
||||
gfx_printf(&gfx_con, "Failed to run sept\n");
|
||||
_hos_crit_error("Failed to run sept");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!keygen(ctxt.keyblob, ctxt.pkg1_id->kb, &tsec_ctxt))
|
||||
if (!keygen(ctxt.keyblob, ctxt.pkg1_id->kb, &tsec_ctxt, &ctxt))
|
||||
return 0;
|
||||
DPRINTF("Generated keys\n");
|
||||
|
||||
h_cfg.se_keygen_done = 1;
|
||||
gfx_printf("Generated keys\n");
|
||||
if (ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_600)
|
||||
h_cfg.se_keygen_done = 1;
|
||||
}
|
||||
|
||||
// Decrypt and unpack package1 if we require parts of it.
|
||||
@@ -435,14 +517,14 @@ int hos_launch(ini_sec_t *cfg)
|
||||
if (ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_600)
|
||||
pkg1_decrypt(ctxt.pkg1_id, ctxt.pkg1);
|
||||
|
||||
if (ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_620)
|
||||
if (ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_620 && !(emu_cfg.enabled && !h_cfg.emummc_force_disable))
|
||||
{
|
||||
pkg1_unpack((void *)ctxt.pkg1_id->warmboot_base, (void *)ctxt.pkg1_id->secmon_base, NULL, ctxt.pkg1_id, ctxt.pkg1);
|
||||
gfx_printf(&gfx_con, "Decrypted & unpacked pkg1\n");
|
||||
gfx_printf("Decrypted & unpacked pkg1\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
EPRINTF("No mandatory secmon or warmboot provided!");
|
||||
_hos_crit_error("No mandatory secmon or warmboot provided!");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -454,12 +536,12 @@ int hos_launch(ini_sec_t *cfg)
|
||||
{
|
||||
if (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_700)
|
||||
{
|
||||
EPRINTF("No warmboot provided!");
|
||||
_hos_crit_error("No warmboot provided!");
|
||||
return 0;
|
||||
}
|
||||
// Else we patch it to allow downgrading.
|
||||
patch_t *warmboot_patchset = ctxt.pkg1_id->warmboot_patchset;
|
||||
gfx_printf(&gfx_con, "%kPatching Warmboot%k\n", 0xFFFFBA00, 0xFFCCCCCC);
|
||||
gfx_printf("%kPatching Warmboot%k\n", 0xFFFFBA00, 0xFFCCCCCC);
|
||||
for (u32 i = 0; warmboot_patchset[i].off != 0xFFFFFFFF; i++)
|
||||
*(vu32 *)(ctxt.pkg1_id->warmboot_base + warmboot_patchset[i].off) = warmboot_patchset[i].val;
|
||||
}
|
||||
@@ -474,32 +556,38 @@ int hos_launch(ini_sec_t *cfg)
|
||||
{
|
||||
// Else we patch it to allow for an unsigned package2 and patched kernel.
|
||||
patch_t *secmon_patchset = ctxt.pkg1_id->secmon_patchset;
|
||||
gfx_printf(&gfx_con, "%kPatching Security Monitor%k\n", 0xFFFFBA00, 0xFFCCCCCC);
|
||||
gfx_printf("%kPatching Security Monitor%k\n", 0xFFFFBA00, 0xFFCCCCCC);
|
||||
for (u32 i = 0; secmon_patchset[i].off != 0xFFFFFFFF; i++)
|
||||
*(vu32 *)(ctxt.pkg1_id->secmon_base + secmon_patchset[i].off) = secmon_patchset[i].val;
|
||||
}
|
||||
|
||||
gfx_printf(&gfx_con, "Loaded warmboot and secmon\n");
|
||||
gfx_printf("Loaded warmboot and secmon\n");
|
||||
|
||||
// Read package2.
|
||||
u8 *bootConfigBuf = _read_emmc_pkg2(&ctxt);
|
||||
if (!bootConfigBuf)
|
||||
return 0;
|
||||
|
||||
gfx_printf(&gfx_con, "Read pkg2\n");
|
||||
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(&gfx_con, "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;
|
||||
}
|
||||
|
||||
LIST_INIT(kip1_info);
|
||||
pkg2_parse_kips(&kip1_info, pkg2_hdr);
|
||||
if (!pkg2_parse_kips(&kip1_info, pkg2_hdr, &ctxt.new_pkg2))
|
||||
{
|
||||
_hos_crit_error("INI1 parsing failed!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
gfx_printf(&gfx_con, "Parsed ini1\n");
|
||||
gfx_printf("Parsed ini1\n");
|
||||
|
||||
// Use the kernel included in package2 in case we didn't load one already.
|
||||
if (!ctxt.kernel)
|
||||
@@ -507,16 +595,29 @@ int hos_launch(ini_sec_t *cfg)
|
||||
ctxt.kernel = pkg2_hdr->data;
|
||||
ctxt.kernel_size = pkg2_hdr->sec_size[PKG2_SEC_KERNEL];
|
||||
|
||||
if (ctxt.svcperm || ctxt.debugmode || ctxt.atmosphere)
|
||||
if (!ctxt.stock && (ctxt.svcperm || ctxt.debugmode || ctxt.atmosphere))
|
||||
{
|
||||
u32 kernel_crc32 = crc32c(ctxt.kernel, ctxt.kernel_size);
|
||||
ctxt.pkg2_kernel_id = pkg2_identify(kernel_crc32);
|
||||
u8 kernel_hash[0x20];
|
||||
// Hash only Kernel when it embeds INI1.
|
||||
if (!ctxt.new_pkg2)
|
||||
se_calc_sha256(kernel_hash, ctxt.kernel, ctxt.kernel_size);
|
||||
else
|
||||
se_calc_sha256(kernel_hash, ctxt.kernel + PKG2_NEWKERN_START,
|
||||
pkg2_newkern_ini1_start - PKG2_NEWKERN_START);
|
||||
|
||||
ctxt.pkg2_kernel_id = pkg2_identify(kernel_hash);
|
||||
if (!ctxt.pkg2_kernel_id)
|
||||
{
|
||||
_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)
|
||||
{
|
||||
gfx_printf(&gfx_con, "%kPatching kernel%k\n", 0xFFFFBA00, 0xFFCCCCCC);
|
||||
gfx_printf("%kPatching kernel%k\n", 0xFFFFBA00, 0xFFCCCCCC);
|
||||
u32 *temp;
|
||||
for (u32 i = 0; kernel_patchset[i].id != 0xFFFFFFFF; i++)
|
||||
{
|
||||
@@ -538,7 +639,7 @@ int hos_launch(ini_sec_t *cfg)
|
||||
}
|
||||
|
||||
// Merge extra KIP1s into loaded ones.
|
||||
gfx_printf(&gfx_con, "%kPatching kips%k\n", 0xFFFFBA00, 0xFFCCCCCC);
|
||||
gfx_printf("%kPatching kips%k\n", 0xFFFFBA00, 0xFFCCCCCC);
|
||||
LIST_FOREACH_ENTRY(merge_kip_t, mki, &ctxt.kip1_list, link)
|
||||
pkg2_merge_kip(&kip1_info, (pkg2_kip1_t *)mki->kip1);
|
||||
|
||||
@@ -546,19 +647,21 @@ int hos_launch(ini_sec_t *cfg)
|
||||
const char* unappliedPatch = pkg2_patch_kips(&kip1_info, ctxt.kip1_patches);
|
||||
if (unappliedPatch != NULL)
|
||||
{
|
||||
EPRINTFARGS("Failed to apply '%s'!", unappliedPatch);
|
||||
sd_unmount(); // Just exiting is not enough until pkg2_patch_kips stops modifying the string passed into it.
|
||||
EHPRINTFARGS("Failed to apply '%s'!", unappliedPatch);
|
||||
|
||||
_free_launch_components(&ctxt);
|
||||
return 0; // MUST stop here, because if user requests 'nogc' but it's not applied, their GC controller gets updated!
|
||||
}
|
||||
|
||||
// Rebuild and encrypt package2.
|
||||
pkg2_build_encrypt((void *)PKG2_LOAD_ADDR, ctxt.kernel, ctxt.kernel_size, &kip1_info);
|
||||
pkg2_build_encrypt((void *)PKG2_LOAD_ADDR, ctxt.kernel, ctxt.kernel_size, &kip1_info, ctxt.new_pkg2);
|
||||
|
||||
gfx_printf(&gfx_con, "Rebuilt & loaded pkg2\n");
|
||||
gfx_printf("Rebuilt & loaded pkg2\n");
|
||||
|
||||
gfx_printf(&gfx_con, "\n%kBooting...%k\n", 0xFF96FF00, 0xFFCCCCCC);
|
||||
// Unmount SD card.
|
||||
sd_unmount();
|
||||
|
||||
gfx_printf("\n%kBooting...%k\n", 0xFF96FF00, 0xFFCCCCCC);
|
||||
|
||||
// Clear pkg1/pkg2 keys.
|
||||
se_aes_key_clear(8);
|
||||
@@ -567,7 +670,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:
|
||||
@@ -577,16 +680,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;
|
||||
@@ -610,10 +713,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.pkg1);
|
||||
|
||||
// Unmount SD card.
|
||||
sd_unmount();
|
||||
config_exosphere(&ctxt);
|
||||
|
||||
// Finalize MC carveout.
|
||||
if (ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_301)
|
||||
@@ -640,7 +740,6 @@ int hos_launch(ini_sec_t *cfg)
|
||||
secmon_mb->out = 0;
|
||||
|
||||
// Free allocated memory.
|
||||
ini_free_section(cfg);
|
||||
_free_launch_components(&ctxt);
|
||||
|
||||
// Disable display. This must be executed before secmon to provide support for all fw versions.
|
||||
@@ -649,20 +748,28 @@ int hos_launch(ini_sec_t *cfg)
|
||||
// Clear EMC_SCRATCH0.
|
||||
EMC(EMC_SCRATCH0) = 0;
|
||||
|
||||
// Flush cache and disable MMU.
|
||||
bpmp_mmu_disable();
|
||||
bpmp_clk_rate_set(BPMP_CLK_NORMAL);
|
||||
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())
|
||||
smmu_exit();
|
||||
else
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2020 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,
|
||||
@@ -31,7 +32,10 @@
|
||||
#define KB_FIRMWARE_VERSION_600 5
|
||||
#define KB_FIRMWARE_VERSION_620 6
|
||||
#define KB_FIRMWARE_VERSION_700 7
|
||||
#define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_700
|
||||
#define KB_FIRMWARE_VERSION_810 8
|
||||
#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
|
||||
|
||||
@@ -50,15 +54,24 @@ typedef struct _launch_ctxt_t
|
||||
|
||||
void *pkg2;
|
||||
u32 pkg2_size;
|
||||
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 fss0_enable_experimental;
|
||||
bool emuMMC;
|
||||
|
||||
ini_sec_t *cfg;
|
||||
} launch_ctxt_t;
|
||||
|
||||
typedef struct _merge_kip_t
|
||||
@@ -68,6 +81,6 @@ typedef struct _merge_kip_t
|
||||
} merge_kip_t;
|
||||
|
||||
int hos_launch(ini_sec_t *cfg);
|
||||
int keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt);
|
||||
int keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt, launch_ctxt_t *hos_ctxt);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2019 CTCaer
|
||||
* Copyright (c) 2018-2020 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,
|
||||
@@ -26,59 +26,52 @@
|
||||
|
||||
#include "../gfx/gfx.h"
|
||||
|
||||
//#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__)
|
||||
//#define DPRINTF(...) gfx_printf(__VA_ARGS__)
|
||||
#define DPRINTF(...)
|
||||
|
||||
extern void *sd_file_read(const char *path, u32 *fsize);
|
||||
|
||||
static int _config_warmboot(launch_ctxt_t *ctxt, const char *value)
|
||||
{
|
||||
FIL fp;
|
||||
if (f_open(&fp, value, FA_READ) != FR_OK)
|
||||
ctxt->warmboot = sd_file_read(value, &ctxt->warmboot_size);
|
||||
if (!ctxt->warmboot)
|
||||
return 0;
|
||||
ctxt->warmboot_size = f_size(&fp);
|
||||
ctxt->warmboot = malloc(ctxt->warmboot_size);
|
||||
f_read(&fp, ctxt->warmboot, ctxt->warmboot_size, NULL);
|
||||
f_close(&fp);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _config_secmon(launch_ctxt_t *ctxt, const char *value)
|
||||
{
|
||||
FIL fp;
|
||||
if (f_open(&fp, value, FA_READ) != FR_OK)
|
||||
ctxt->secmon = sd_file_read(value, &ctxt->secmon_size);
|
||||
if (!ctxt->secmon)
|
||||
return 0;
|
||||
ctxt->secmon_size = f_size(&fp);
|
||||
ctxt->secmon = malloc(ctxt->secmon_size);
|
||||
f_read(&fp, ctxt->secmon, ctxt->secmon_size, NULL);
|
||||
f_close(&fp);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _config_kernel(launch_ctxt_t *ctxt, const char *value)
|
||||
{
|
||||
FIL fp;
|
||||
if (f_open(&fp, value, FA_READ) != FR_OK)
|
||||
ctxt->kernel = sd_file_read(value, &ctxt->kernel_size);
|
||||
if (!ctxt->kernel)
|
||||
return 0;
|
||||
ctxt->kernel_size = f_size(&fp);
|
||||
ctxt->kernel = malloc(ctxt->kernel_size);
|
||||
f_read(&fp, ctxt->kernel, ctxt->kernel_size, NULL);
|
||||
f_close(&fp);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _config_kip1(launch_ctxt_t *ctxt, const char *value)
|
||||
{
|
||||
FIL fp;
|
||||
u32 size;
|
||||
|
||||
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;
|
||||
@@ -89,19 +82,19 @@ 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);
|
||||
if (f_open(&fp, dir, FA_READ))
|
||||
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);
|
||||
if (!mkip1->kip1)
|
||||
{
|
||||
free(mkip1);
|
||||
free(dir);
|
||||
free(filelist);
|
||||
|
||||
return 0;
|
||||
}
|
||||
merge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t));
|
||||
mkip1->kip1 = malloc(f_size(&fp));
|
||||
f_read(&fp, mkip1->kip1, f_size(&fp), NULL);
|
||||
DPRINTF("Loaded kip1 from SD (size %08X)\n", f_size(&fp));
|
||||
f_close(&fp);
|
||||
DPRINTF("Loaded kip1 from SD (size %08X)\n", size);
|
||||
list_append(&ctxt->kip1_list, &mkip1->link);
|
||||
|
||||
i++;
|
||||
@@ -113,13 +106,15 @@ static int _config_kip1(launch_ctxt_t *ctxt, const char *value)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (f_open(&fp, value, FA_READ))
|
||||
return 0;
|
||||
merge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t));
|
||||
mkip1->kip1 = malloc(f_size(&fp));
|
||||
f_read(&fp, mkip1->kip1, f_size(&fp), NULL);
|
||||
DPRINTF("Loaded kip1 from SD (size %08X)\n", f_size(&fp));
|
||||
f_close(&fp);
|
||||
mkip1->kip1 = sd_file_read(value, &size);
|
||||
if (!mkip1->kip1)
|
||||
{
|
||||
free(mkip1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
DPRINTF("Loaded kip1 from SD (size %08X)\n", size);
|
||||
list_append(&ctxt->kip1_list, &mkip1->link);
|
||||
}
|
||||
|
||||
@@ -176,6 +171,16 @@ static int _config_debugmode(launch_ctxt_t *ctxt, const char *value)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _config_stock(launch_ctxt_t *ctxt, const char *value)
|
||||
{
|
||||
if (*value == '1')
|
||||
{
|
||||
DPRINTF("Disabled all patching\n");
|
||||
ctxt->stock = true;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _config_atmosphere(launch_ctxt_t *ctxt, const char *value)
|
||||
{
|
||||
if (*value == '1')
|
||||
@@ -186,9 +191,38 @@ 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);
|
||||
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ctxt->cfg->kvs, link)
|
||||
{
|
||||
if (!strcmp("fss0experimental", kv->key))
|
||||
{
|
||||
ctxt->fss0_enable_experimental = *kv->val == '1';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return parse_fss(ctxt, value, NULL);
|
||||
}
|
||||
|
||||
typedef struct _cfg_handler_t
|
||||
@@ -205,23 +239,28 @@ static const cfg_handler_t _config_handlers[] = {
|
||||
{ "kip1patch", config_kip1patch },
|
||||
{ "fullsvcperm", _config_svcperm },
|
||||
{ "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 },
|
||||
};
|
||||
|
||||
int parse_boot_config(launch_ctxt_t *ctxt, ini_sec_t *cfg)
|
||||
int parse_boot_config(launch_ctxt_t *ctxt)
|
||||
{
|
||||
LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg->kvs, link)
|
||||
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ctxt->cfg->kvs, link)
|
||||
{
|
||||
for(u32 i = 0; _config_handlers[i].key; i++)
|
||||
{
|
||||
if (!strcmp(_config_handlers[i].key, kv->key))
|
||||
if (!_config_handlers[i].handler(ctxt, kv->val))
|
||||
{
|
||||
EPRINTFARGS("Error while loading %s:\n%s", kv->key, kv->val);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
#include "hos.h"
|
||||
|
||||
int parse_boot_config(launch_ctxt_t *ctxt, ini_sec_t *cfg);
|
||||
int parse_boot_config(launch_ctxt_t *ctxt);
|
||||
int config_kip1patch(launch_ctxt_t *ctxt, const char *value);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018 st4rk
|
||||
* Copyright (c) 2018-2019 CTCaer
|
||||
* Copyright (c) 2018-2020 CTCaer
|
||||
* Copyright (c) 2018 balika011
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
#include "pkg1.h"
|
||||
#include "../gfx/gfx.h"
|
||||
#include "../mem/heap.h"
|
||||
#include "../sec/se.h"
|
||||
#include "../utils/aarch64_util.h"
|
||||
|
||||
@@ -72,15 +73,15 @@ PATCHSET_DEF(_secmon_6_patchset,
|
||||
{ 0xDC8 + 0x820, _NOP() }, //package2 structure.
|
||||
{ 0xDC8 + 0x82C, _NOP() }, //Version.
|
||||
{ 0xDC8 + 0xE90, _NOP() }, //Header signature.
|
||||
{ 0xDC8 + 0x112C, _NOP() }, //Sections SHA2.
|
||||
{ 0xDC8 + 0x112C, _NOP() } //Sections SHA2.
|
||||
// Fix sleep mode for debug.
|
||||
{ 0x1A68 + 0x3854, 0x94000E45 }, //gpio_config_for_uart.
|
||||
{ 0x1A68 + 0x3858, 0x97FFFC0F }, //clkrst_reboot_uarta.
|
||||
{ 0x1A68 + 0x385C, 0x52A00021 }, //MOV W1, #0x10000 ; baudrate.
|
||||
{ 0x1A68 + 0x3860, 0x2A1F03E0 }, //MOV W0, WZR ; uart_port -> A.
|
||||
{ 0x1A68 + 0x3864, 0x72984001 }, //MOVK W1, #0xC200 ; baudrate.
|
||||
{ 0x1A68 + 0x3868, 0x94000C8C }, //uart_configure.
|
||||
{ 0x1A68 + 0x3A6C, _NOP() } // warmboot UARTA cfg.
|
||||
// { 0x1A68 + 0x3854, 0x94000E45 }, //gpio_config_for_uart.
|
||||
// { 0x1A68 + 0x3858, 0x97FFFC0F }, //clkrst_reboot_uarta.
|
||||
// { 0x1A68 + 0x385C, 0x52A00021 }, //MOV W1, #0x10000 ; baudrate.
|
||||
// { 0x1A68 + 0x3860, 0x2A1F03E0 }, //MOV W0, WZR ; uart_port -> A.
|
||||
// { 0x1A68 + 0x3864, 0x72984001 }, //MOVK W1, #0xC200 ; baudrate.
|
||||
// { 0x1A68 + 0x3868, 0x94000C8C }, //uart_configure.
|
||||
// { 0x1A68 + 0x3A6C, _NOP() } // warmboot UARTA cfg.
|
||||
);
|
||||
|
||||
PATCHSET_DEF(_secmon_620_patchset,
|
||||
@@ -88,15 +89,15 @@ PATCHSET_DEF(_secmon_620_patchset,
|
||||
{ 0xDC8 + 0x604, _NOP() }, //package2 structure.
|
||||
{ 0xDC8 + 0x610, _NOP() }, //Version.
|
||||
{ 0xDC8 + 0xC74, _NOP() }, //Header signature.
|
||||
{ 0xDC8 + 0xF10, _NOP() }, //Sections SHA2.
|
||||
{ 0xDC8 + 0xF10, _NOP() } //Sections SHA2.
|
||||
// Fix sleep mode for debug.
|
||||
{ 0x2AC8 + 0x3854, 0x94000F42 }, //gpio_config_for_uart.
|
||||
{ 0x2AC8 + 0x3858, 0x97FFFC0F }, //clkrst_reboot_uarta.
|
||||
{ 0x2AC8 + 0x385C, 0x52A00021 }, //MOV W1, #0x10000 ; baudrate.
|
||||
{ 0x2AC8 + 0x3860, 0x2A1F03E0 }, //MOV W0, WZR ; uart_port -> A.
|
||||
{ 0x2AC8 + 0x3864, 0x72984001 }, //MOVK W1, #0xC200 ; baudrate.
|
||||
{ 0x2AC8 + 0x3868, 0x94000D89 }, //uart_configure.
|
||||
{ 0x2AC8 + 0x3A6C, _NOP() } // warmboot UARTA cfg.
|
||||
// { 0x2AC8 + 0x3854, 0x94000F42 }, //gpio_config_for_uart.
|
||||
// { 0x2AC8 + 0x3858, 0x97FFFC0F }, //clkrst_reboot_uarta.
|
||||
// { 0x2AC8 + 0x385C, 0x52A00021 }, //MOV W1, #0x10000 ; baudrate.
|
||||
// { 0x2AC8 + 0x3860, 0x2A1F03E0 }, //MOV W0, WZR ; uart_port -> A.
|
||||
// { 0x2AC8 + 0x3864, 0x72984001 }, //MOVK W1, #0xC200 ; baudrate.
|
||||
// { 0x2AC8 + 0x3868, 0x94000D89 }, //uart_configure.
|
||||
// { 0x2AC8 + 0x3A6C, _NOP() } // warmboot UARTA cfg.
|
||||
);
|
||||
|
||||
PATCHSET_DEF(_warmboot_1_patchset,
|
||||
@@ -133,16 +134,21 @@ 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, _warmboot_4_patchset }, //7.0.0
|
||||
{ "20190208150037", 7, 0x0F00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, _warmboot_4_patchset }, //7.0.1
|
||||
{ "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
|
||||
{ "20200303104606", 10, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //10.0.0
|
||||
{ NULL } //End.
|
||||
};
|
||||
|
||||
@@ -151,7 +157,7 @@ const pkg1_id_t *pkg1_identify(u8 *pkg1)
|
||||
char build_date[15];
|
||||
memcpy(build_date, (char *)(pkg1 + 0x10), 14);
|
||||
build_date[14] = 0;
|
||||
gfx_printf(&gfx_con, "Found pkg1 ('%s').\n\n", build_date);
|
||||
gfx_printf("Found pkg1 ('%s').\n\n", build_date);
|
||||
|
||||
for (u32 i = 0; _pkg1_ids[i].id; i++)
|
||||
if (!memcmp(pkg1 + 0x10, _pkg1_ids[i].id, 12))
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (C) 2018 CTCaer
|
||||
* Copyright (c) 2018-2020 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,6 +27,12 @@
|
||||
#define PKG2_SEC_INI1 1
|
||||
|
||||
#define INI1_MAGIC 0x31494E49
|
||||
#define PKG2_NEWKERN_GET_INI1_HEURISTIC 0xD2800015 // Offset of OP + 12 is the INI1 offset.
|
||||
#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
|
||||
{
|
||||
@@ -48,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
|
||||
@@ -111,7 +118,7 @@ typedef struct _pkg2_kip1_info_t
|
||||
|
||||
typedef struct _pkg2_kernel_id_t
|
||||
{
|
||||
u32 crc32c_id;
|
||||
u8 hash[8];
|
||||
kernel_patch_t *kernel_patchset;
|
||||
} pkg2_kernel_id_t;
|
||||
|
||||
@@ -119,32 +126,33 @@ typedef struct _kip1_patch_t
|
||||
{
|
||||
u32 offset; // section+offset of patch to apply.
|
||||
u32 length; // In bytes, 0 means last patch.
|
||||
const char* srcData; // That must match.
|
||||
const char* dstData; // That it gets replaced by.
|
||||
char* srcData; // That must match.
|
||||
char* dstData; // That it gets replaced by.
|
||||
} kip1_patch_t;
|
||||
|
||||
typedef struct _kip1_patchset_t
|
||||
{
|
||||
const char* name; // NULL means end.
|
||||
char* name; // NULL means end.
|
||||
kip1_patch_t* patches; // NULL means not necessary.
|
||||
} kip1_patchset_t;
|
||||
|
||||
typedef struct _kip1_id_t
|
||||
{
|
||||
const char* name;
|
||||
u8 hash[16];
|
||||
u8 hash[8];
|
||||
kip1_patchset_t* patchset;
|
||||
} kip1_id_t;
|
||||
|
||||
void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2);
|
||||
int pkg2_has_kip(link_t *info, u64 tid);
|
||||
void pkg2_get_newkern_info(u8 *kern_data);
|
||||
bool pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2);
|
||||
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(u32 id);
|
||||
pkg2_hdr_t *pkg2_decrypt(void *data);
|
||||
void pkg2_build_encrypt(void *dst, void *kernel, u32 kernel_size, link_t *kips_info);
|
||||
const pkg2_kernel_id_t *pkg2_identify(u8 *hash);
|
||||
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
|
||||
|
||||
165
bootloader/hos/pkg2_ini_kippatch.c
Normal file
165
bootloader/hos/pkg2_ini_kippatch.c
Normal file
@@ -0,0 +1,165 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "pkg2_ini_kippatch.h"
|
||||
#include "../libs/fatfs/ff.h"
|
||||
#include "../mem/heap.h"
|
||||
|
||||
#define KPS(x) ((u32)(x) << 29)
|
||||
|
||||
static u8 *_htoa(u8 *result, const char *ptr, u8 byte_len)
|
||||
{
|
||||
char ch = *ptr;
|
||||
u32 ascii_len = byte_len * 2;
|
||||
if (!result)
|
||||
result = malloc(byte_len);
|
||||
u8 *dst = result;
|
||||
|
||||
while (ch == ' ' || ch == '\t')
|
||||
ch = *(++ptr);
|
||||
|
||||
bool shift = true;
|
||||
while (ascii_len)
|
||||
{
|
||||
u8 tmp = 0;
|
||||
if (ch >= '0' && ch <= '9')
|
||||
tmp = (ch - '0');
|
||||
else if (ch >= 'A' && ch <= 'F')
|
||||
tmp = (ch - 'A' + 10);
|
||||
else if (ch >= 'a' && ch <= 'f')
|
||||
tmp = (ch - 'a' + 10);
|
||||
|
||||
if (shift)
|
||||
*dst = (tmp << 4) & 0xF0;
|
||||
else
|
||||
{
|
||||
*dst |= (tmp & 0x0F);
|
||||
dst++;
|
||||
}
|
||||
|
||||
ascii_len--;
|
||||
ch = *(++ptr);
|
||||
shift = !shift;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static char *_strdup(char *str)
|
||||
{
|
||||
if (!str)
|
||||
return NULL;
|
||||
if (str[0] == ' ' && (strlen(str) > 1))
|
||||
str++;
|
||||
char *res = (char *)malloc(strlen(str) + 1);
|
||||
strcpy(res, str);
|
||||
if (res[strlen(res) - 1] == ' ' && (strlen(res) > 1))
|
||||
res[strlen(res) - 1] = 0;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static u32 _find_patch_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++)
|
||||
;
|
||||
lbuf[i] = 0;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static ini_kip_sec_t *_ini_create_kip_section(link_t *dst, ini_kip_sec_t *ksec, char *name)
|
||||
{
|
||||
if (ksec)
|
||||
{
|
||||
list_append(dst, &ksec->link);
|
||||
ksec = NULL;
|
||||
}
|
||||
|
||||
ksec = (ini_kip_sec_t *)malloc(sizeof(ini_kip_sec_t));
|
||||
u32 i = _find_patch_section_name(name, strlen(name), ':') + 1;
|
||||
ksec->name = _strdup(name);
|
||||
|
||||
// Get hash section.
|
||||
_htoa(ksec->hash, &name[i], 8);
|
||||
|
||||
return ksec;
|
||||
}
|
||||
|
||||
int ini_patch_parse(link_t *dst, char *ini_path)
|
||||
{
|
||||
u32 lblen;
|
||||
char lbuf[512];
|
||||
FIL fp;
|
||||
ini_kip_sec_t *ksec = NULL;
|
||||
|
||||
// Open ini.
|
||||
if (f_open(&fp, ini_path, FA_READ) != FR_OK)
|
||||
return 0;
|
||||
|
||||
do
|
||||
{
|
||||
// Fetch one line.
|
||||
lbuf[0] = 0;
|
||||
f_gets(lbuf, 512, &fp);
|
||||
lblen = strlen(lbuf);
|
||||
|
||||
// Remove trailing newline.
|
||||
if (lbuf[lblen - 1] == '\n' || lbuf[lblen - 1] == '\r')
|
||||
lbuf[lblen - 1] = 0;
|
||||
|
||||
if (lblen > 2 && lbuf[0] == '[') // Create new section.
|
||||
{
|
||||
_find_patch_section_name(lbuf, lblen, ']');
|
||||
|
||||
ksec = _ini_create_kip_section(dst, ksec, &lbuf[1]);
|
||||
list_init(&ksec->pts);
|
||||
}
|
||||
else if (ksec && lbuf[0] == '.') //Extract key/value.
|
||||
{
|
||||
u32 tmp = 0;
|
||||
u32 i = _find_patch_section_name(lbuf, lblen, '=');
|
||||
|
||||
ini_patchset_t *pt = (ini_patchset_t *)malloc(sizeof(ini_patchset_t));
|
||||
|
||||
pt->name = _strdup(&lbuf[1]);
|
||||
|
||||
u8 kip_sidx = lbuf[i + 1] - '0';
|
||||
|
||||
if (kip_sidx < 6)
|
||||
{
|
||||
pt->offset = KPS(kip_sidx);
|
||||
tmp = _find_patch_section_name(&lbuf[i + 3], lblen, ':');
|
||||
pt->offset |= strtol(&lbuf[i + 3], NULL, 16);
|
||||
|
||||
i += tmp + 4;
|
||||
|
||||
tmp = _find_patch_section_name(&lbuf[i], lblen, ':');
|
||||
pt->length = strtol(&lbuf[i], NULL, 16);
|
||||
|
||||
i += tmp + 1;
|
||||
|
||||
tmp = _find_patch_section_name(&lbuf[i], lblen, ',');
|
||||
pt->srcData = _htoa(NULL, &lbuf[i], pt->length);
|
||||
i += tmp + 1;
|
||||
pt->dstData = _htoa(NULL, &lbuf[i], pt->length);
|
||||
}
|
||||
else
|
||||
{
|
||||
pt->offset = 0;
|
||||
pt->length = 0;
|
||||
pt->srcData = NULL;
|
||||
pt->dstData = NULL;
|
||||
}
|
||||
list_append(&ksec->pts, &pt->link);
|
||||
}
|
||||
} while (!f_eof(&fp));
|
||||
|
||||
f_close(&fp);
|
||||
|
||||
if (ksec)
|
||||
list_append(dst, &ksec->link);
|
||||
|
||||
return 1;
|
||||
}
|
||||
43
bootloader/hos/pkg2_ini_kippatch.h
Normal file
43
bootloader/hos/pkg2_ini_kippatch.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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,
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef _INIPATCH_H_
|
||||
#define _INIPATCH_H_
|
||||
|
||||
#include "../utils/types.h"
|
||||
#include "../utils/list.h"
|
||||
|
||||
typedef struct _ini_patchset_t
|
||||
{
|
||||
char *name;
|
||||
u32 offset; // section + offset of patch to apply.
|
||||
u32 length; // In bytes, 0 means last patch.
|
||||
u8 *srcData; // That must match.
|
||||
u8 *dstData; // Gets replaced with.
|
||||
link_t link;
|
||||
} ini_patchset_t;
|
||||
|
||||
typedef struct _ini_kip_sec_t
|
||||
{
|
||||
char *name;
|
||||
u8 hash[8];
|
||||
link_t pts;
|
||||
link_t link;
|
||||
} ini_kip_sec_t;
|
||||
|
||||
int ini_patch_parse(link_t *dst, char *ini_path);
|
||||
|
||||
#endif
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2019 CTCaer
|
||||
* Copyright (c) 2018-2020 CTCaer
|
||||
* Copyright (c) 2019 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,
|
||||
@@ -15,51 +16,142 @@
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "hos.h"
|
||||
#include "../config/config.h"
|
||||
#include "../gfx/di.h"
|
||||
#include "../gfx/gfx.h"
|
||||
#include "../libs/fatfs/ff.h"
|
||||
#include "../mem/heap.h"
|
||||
#include "../soc/fuse.h"
|
||||
#include "../storage/emummc.h"
|
||||
#include "../storage/sdmmc.h"
|
||||
#include "../utils/btn.h"
|
||||
#include "../utils/util.h"
|
||||
#include "../utils/types.h"
|
||||
|
||||
extern hekate_config h_cfg;
|
||||
|
||||
extern bool sd_mount();
|
||||
extern int sd_save_to_file(void *buf, u32 size, const char *filename);
|
||||
|
||||
enum emuMMC_Type
|
||||
{
|
||||
emuMMC_None = 0,
|
||||
emuMMC_Partition,
|
||||
emuMMC_File,
|
||||
emuMMC_MAX
|
||||
};
|
||||
|
||||
/* "EFS0" */
|
||||
#define EMUMMC_MAGIC 0x30534645
|
||||
#define EMUMMC_FILE_PATH_MAX 0x80
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 magic;
|
||||
u32 type;
|
||||
u32 id;
|
||||
u32 fs_ver;
|
||||
} emummc_base_config_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u64 start_sector;
|
||||
} emummc_partition_config_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char path[EMUMMC_FILE_PATH_MAX];
|
||||
} emummc_file_config_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
emummc_base_config_t base_cfg;
|
||||
union
|
||||
{
|
||||
emummc_partition_config_t partition_cfg;
|
||||
emummc_file_config_t file_cfg;
|
||||
};
|
||||
char nintendo_path[EMUMMC_FILE_PATH_MAX];
|
||||
} exo_emummc_config_t;
|
||||
|
||||
typedef struct _exo_cfg_t
|
||||
{
|
||||
vu32 magic;
|
||||
vu32 fwno;
|
||||
vu32 flags;
|
||||
vu32 rsvd;
|
||||
u32 magic;
|
||||
u32 fwno;
|
||||
u32 flags;
|
||||
u32 reserved[5];
|
||||
exo_emummc_config_t emummc_cfg;
|
||||
} exo_cfg_t;
|
||||
|
||||
typedef struct _atm_meta_t
|
||||
{
|
||||
uint32_t magic;
|
||||
uint32_t fwno;
|
||||
u32 magic;
|
||||
u32 fwno;
|
||||
} wb_cfg_t;
|
||||
|
||||
// Atmosphère reboot-to-fatal-error.
|
||||
typedef struct _atm_fatal_error_ctx
|
||||
{
|
||||
u32 magic;
|
||||
u32 error_desc;
|
||||
u64 title_id;
|
||||
union
|
||||
{
|
||||
u64 gprs[32];
|
||||
struct
|
||||
{
|
||||
u64 _gprs[29];
|
||||
u64 fp;
|
||||
u64 lr;
|
||||
u64 sp;
|
||||
};
|
||||
};
|
||||
u64 pc;
|
||||
u64 module_base;
|
||||
u32 pstate;
|
||||
u32 afsr0;
|
||||
u32 afsr1;
|
||||
u32 esr;
|
||||
u64 far;
|
||||
u64 report_identifier; // Normally just system tick.
|
||||
u64 stack_trace_size;
|
||||
u64 stack_dump_size;
|
||||
u64 stack_trace[0x20];
|
||||
u8 stack_dump[0x100];
|
||||
u8 tls[0x100];
|
||||
} atm_fatal_error_ctx;
|
||||
|
||||
#define ATM_FATAL_ERR_CTX_ADDR 0x4003E000
|
||||
#define ATM_FATAL_MAGIC 0x30454641 // AFE0
|
||||
|
||||
#define ATM_WB_HEADER_OFF 0x244
|
||||
#define ATM_WB_MAGIC 0x30544257
|
||||
|
||||
// Exosphère mailbox defines.
|
||||
#define EXO_CFG_DEPR_ADDR 0x40002E40 // Deprecated.
|
||||
#define EXO_CFG_ADDR 0x8000F000
|
||||
#define EXO_MAGIC_DEPR_VAL 0x31434258
|
||||
#define EXO_MAGIC_VAL 0x304F5845
|
||||
#define EXO_FLAG_620_KGN (1 << 0)
|
||||
#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, void *pkg1)
|
||||
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));
|
||||
|
||||
volatile exo_cfg_t *exo_cfg_depr = (exo_cfg_t *)EXO_CFG_DEPR_ADDR;
|
||||
volatile exo_cfg_t *exo_cfg = (exo_cfg_t *)EXO_CFG_ADDR;
|
||||
|
||||
switch (kb)
|
||||
{
|
||||
case KB_FIRMWARE_VERSION_100_200:
|
||||
if (!strcmp(id, "20161121183008"))
|
||||
if (!strcmp(ctxt->pkg1_id->id, "20161121183008"))
|
||||
exoFwNo = 1;
|
||||
else
|
||||
exoFwNo = 2;
|
||||
@@ -69,27 +161,34 @@ void config_exosphere(const char *id, u32 kb, void *warmboot, void *pkg1)
|
||||
break;
|
||||
default:
|
||||
exoFwNo = kb + 1;
|
||||
if (!strcmp(ctxt->pkg1_id->id, "20190314172056") || (kb >= KB_FIRMWARE_VERSION_810))
|
||||
exoFwNo++; // ATM_TARGET_FW_800/810/900/910.
|
||||
if (!strcmp(ctxt->pkg1_id->id, "20200303104606"))
|
||||
exoFwNo++; // ATM_TARGET_FW_1000.
|
||||
break;
|
||||
}
|
||||
|
||||
if (kb == KB_FIRMWARE_VERSION_620)
|
||||
exoFlags |= EXO_FLAG_620_KGN;
|
||||
// To avoid problems, make private debug mode always on if not semi-stock.
|
||||
if (!ctxt->stock || (emu_cfg.enabled && !h_cfg.emummc_force_disable))
|
||||
exoFlags |= EXO_FLAG_DBG_PRIV;
|
||||
|
||||
// To avoid problems, make private debug mode always on.
|
||||
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_depr->magic = EXO_MAGIC_VAL;
|
||||
exo_cfg->magic = EXO_MAGIC_VAL;
|
||||
|
||||
exo_cfg_depr->fwno = exoFwNo;
|
||||
exo_cfg->fwno = exoFwNo;
|
||||
|
||||
exo_cfg_depr->flags = exoFlags;
|
||||
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)
|
||||
{
|
||||
@@ -112,6 +211,96 @@ void config_exosphere(const char *id, u32 kb, void *warmboot, void *pkg1)
|
||||
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)
|
||||
{
|
||||
exo_cfg->emummc_cfg.base_cfg.magic = EMUMMC_MAGIC;
|
||||
exo_cfg->emummc_cfg.base_cfg.type = emu_cfg.sector ? emuMMC_Partition : emuMMC_File;
|
||||
exo_cfg->emummc_cfg.base_cfg.fs_ver = emu_cfg.fs_ver;
|
||||
exo_cfg->emummc_cfg.base_cfg.id = emu_cfg.id;
|
||||
|
||||
if (emu_cfg.sector)
|
||||
exo_cfg->emummc_cfg.partition_cfg.start_sector = emu_cfg.sector;
|
||||
else
|
||||
strcpy((char *)exo_cfg->emummc_cfg.file_cfg.path, emu_cfg.path);
|
||||
|
||||
if (emu_cfg.nintendo_path && !ctxt->stock)
|
||||
strcpy((char *)exo_cfg->emummc_cfg.nintendo_path, emu_cfg.nintendo_path);
|
||||
else if (ctxt->stock)
|
||||
strcpy((char *)exo_cfg->emummc_cfg.nintendo_path, "Nintendo");
|
||||
else
|
||||
exo_cfg->emummc_cfg.nintendo_path[0] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static const char *get_error_desc(u32 error_desc)
|
||||
{
|
||||
switch (error_desc)
|
||||
{
|
||||
case 0x100:
|
||||
return "Instruction Abort";
|
||||
case 0x101:
|
||||
return "Data Abort";
|
||||
case 0x102:
|
||||
return "PC Misalignment";
|
||||
case 0x103:
|
||||
return "SP Misalignment";
|
||||
case 0x104:
|
||||
return "Trap";
|
||||
case 0x106:
|
||||
return "SError";
|
||||
case 0x301:
|
||||
return "Bad SVC";
|
||||
case 0xFFE:
|
||||
return "std::abort()";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
void secmon_exo_check_panic()
|
||||
{
|
||||
volatile atm_fatal_error_ctx *rpt = (atm_fatal_error_ctx *)ATM_FATAL_ERR_CTX_ADDR;
|
||||
|
||||
// Mask magic to maintain compatibility with any AFE version, thanks to additive struct members.
|
||||
if ((rpt->magic & 0xF0FFFFFF) != ATM_FATAL_MAGIC)
|
||||
return;
|
||||
|
||||
gfx_clear_grey(0x1B);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
WPRINTF("Panic occurred while running Atmosphere.\n\n");
|
||||
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);
|
||||
|
||||
// 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);
|
||||
|
||||
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;
|
||||
|
||||
gfx_con.fntsz = 16;
|
||||
gfx_printf("\n\nPress POWER to continue.\n");
|
||||
|
||||
display_backlight_brightness(100, 1000);
|
||||
msleep(1000);
|
||||
|
||||
u32 btn = btn_wait();
|
||||
while (!(btn & BTN_POWER))
|
||||
btn = btn_wait();
|
||||
|
||||
display_backlight_brightness(0, 1000);
|
||||
gfx_con_setpos(0, 0);
|
||||
}
|
||||
|
||||
@@ -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,6 +19,7 @@
|
||||
|
||||
#include "../utils/types.h"
|
||||
|
||||
void config_exosphere(const char *id, u32 kb, void *warmboot, void *pkg1);
|
||||
void config_exosphere(launch_ctxt_t *ctxt);
|
||||
void secmon_exo_check_panic();
|
||||
|
||||
#endif
|
||||
|
||||
@@ -17,14 +17,17 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "hos.h"
|
||||
#include "fss.h"
|
||||
#include "sept.h"
|
||||
#include "../config/config.h"
|
||||
#include "../gfx/di.h"
|
||||
#include "../ianos/ianos.h"
|
||||
#include "../libs/fatfs/ff.h"
|
||||
#include "../mem/heap.h"
|
||||
#include "../soc/hw_init.h"
|
||||
#include "../soc/pmc.h"
|
||||
#include "../soc/t210.h"
|
||||
#include "../storage/emummc.h"
|
||||
#include "../storage/nx_emmc.h"
|
||||
#include "../storage/sdmmc.h"
|
||||
#include "../utils/btn.h"
|
||||
@@ -42,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
|
||||
@@ -63,18 +66,25 @@ extern hekate_config h_cfg;
|
||||
extern const volatile ipl_ver_meta_t ipl_ver;
|
||||
|
||||
extern void *sd_file_read(char *path);
|
||||
extern void sd_mount();
|
||||
extern bool sd_mount();
|
||||
extern void sd_unmount();
|
||||
extern bool is_ipl_updated(void *buf);
|
||||
extern void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size);
|
||||
|
||||
void check_sept()
|
||||
extern sdmmc_t sd_sdmmc;
|
||||
extern sdmmc_storage_t sd_storage;
|
||||
|
||||
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 && !f_stat("sept/payload.bak", NULL))
|
||||
if (h_cfg.sept_run)
|
||||
{
|
||||
f_unlink("sept/payload.bin");
|
||||
f_rename("sept/payload.bak", "sept/payload.bin");
|
||||
if (!f_stat("sept/payload.bak", NULL))
|
||||
{
|
||||
f_unlink("sept/payload.bin");
|
||||
f_rename("sept/payload.bak", "sept/payload.bin");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -82,15 +92,21 @@ void check_sept()
|
||||
|
||||
sdmmc_storage_t storage;
|
||||
sdmmc_t sdmmc;
|
||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
|
||||
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;
|
||||
}
|
||||
sdmmc_storage_set_mmc_partition(&storage, 1);
|
||||
|
||||
emummc_storage_set_mmc_partition(&storage, 1);
|
||||
|
||||
// Read package1.
|
||||
sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1);
|
||||
emummc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1);
|
||||
const pkg1_id_t *pkg1_id = pkg1_identify(pkg1);
|
||||
if (!pkg1_id)
|
||||
{
|
||||
@@ -102,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);
|
||||
reboot_to_sept((u8 *)pkg1 + pkg1_id->tsec_off, pkg1_id->kb, cfg_sec);
|
||||
}
|
||||
|
||||
out_free:
|
||||
@@ -110,36 +126,63 @@ out_free:
|
||||
sdmmc_storage_end(&storage);
|
||||
}
|
||||
|
||||
int reboot_to_sept(const u8 *tsec_fw)
|
||||
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;
|
||||
if (kb > KB_FIRMWARE_VERSION_700)
|
||||
tsec_fw_size = 0x3300;
|
||||
memcpy((u8 *)(SEPT_PK1T_ADDR - WB_RST_SIZE), (u8 *)warmboot_reboot, sizeof(warmboot_reboot));
|
||||
memcpy((void *)SEPT_PK1T_ADDR, tsec_fw, 0x3000);
|
||||
*(vu32 *)SEPT_TCSZ_ADDR = 0x3000;
|
||||
|
||||
// Copy sept-primary.
|
||||
if (f_open(&fp, "sept/sept-primary.bin", FA_READ))
|
||||
goto error;
|
||||
memcpy((void *)SEPT_PK1T_ADDR, tsec_fw, tsec_fw_size);
|
||||
*(vu32 *)SEPT_TCSZ_ADDR = tsec_fw_size;
|
||||
|
||||
if (f_read(&fp, (u8 *)SEPT_STG1_ADDR, f_size(&fp), NULL))
|
||||
if (cfg_sec)
|
||||
{
|
||||
f_close(&fp);
|
||||
goto error;
|
||||
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;
|
||||
|
||||
fss0_sept_used = load_sept_from_ffs0(&sept_ctxt);
|
||||
}
|
||||
f_close(&fp);
|
||||
|
||||
// Copy sept-secondary.
|
||||
if (f_open(&fp, "sept/sept-secondary.enc", FA_READ))
|
||||
goto error;
|
||||
|
||||
if (f_read(&fp, (u8 *)SEPT_STG2_ADDR, f_size(&fp), NULL))
|
||||
if (!fss0_sept_used)
|
||||
{
|
||||
// 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))
|
||||
{
|
||||
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);
|
||||
|
||||
@@ -159,19 +202,22 @@ int reboot_to_sept(const u8 *tsec_fw)
|
||||
memcpy(tmp_cfg, &b_cfg, sizeof(boot_cfg_t));
|
||||
f_lseek(&fp, PATCHED_RELOC_SZ);
|
||||
f_write(&fp, tmp_cfg, sizeof(boot_cfg_t), NULL);
|
||||
f_close(&fp);
|
||||
update_sept_payload = false;
|
||||
}
|
||||
|
||||
f_close(&fp);
|
||||
}
|
||||
else
|
||||
{
|
||||
f_close(&fp);
|
||||
f_rename("sept/payload.bin", "sept/payload.bak"); // Backup foreign payload.
|
||||
|
||||
f_close(&fp);
|
||||
}
|
||||
}
|
||||
|
||||
if (update_sept_payload)
|
||||
{
|
||||
volatile reloc_meta_t *reloc = (reloc_meta_t *)(IPL_LOAD_ADDR + RELOC_META_OFF);
|
||||
f_mkdir("sept");
|
||||
f_open(&fp, "sept/payload.bin", FA_WRITE | FA_CREATE_ALWAYS);
|
||||
f_write(&fp, (u8 *)reloc->start, reloc->end - reloc->start, NULL);
|
||||
f_close(&fp);
|
||||
@@ -192,13 +238,13 @@ int reboot_to_sept(const u8 *tsec_fw)
|
||||
PMC(APBDEV_PMC_SCRATCH33) = SEPT_PRI_ADDR;
|
||||
PMC(APBDEV_PMC_SCRATCH40) = 0x6000F208;
|
||||
|
||||
display_end();
|
||||
reconfig_hw_workaround(false, 0);
|
||||
|
||||
(*sept)();
|
||||
|
||||
error:
|
||||
gfx_con.mute = false;
|
||||
EPRINTF("Failed to run sept\n");
|
||||
display_backlight_brightness(h_cfg.backlight, 1000);
|
||||
|
||||
btn_wait();
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
#include "../utils/types.h"
|
||||
|
||||
void check_sept();
|
||||
int reboot_to_sept(const u8 *tsec_fw);
|
||||
void check_sept(ini_sec_t *cfg_sec);
|
||||
int reboot_to_sept(const u8 *tsec_fw, u32 kb, ini_sec_t *cfg_sec);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 M4xw
|
||||
* 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,
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
extern heap_t _heap;
|
||||
|
||||
extern void *sd_file_read(char *path);
|
||||
extern void *sd_file_read(const char *path, u32 *fsize);
|
||||
extern bool sd_mount();
|
||||
extern void sd_unmount();
|
||||
|
||||
@@ -65,62 +65,31 @@ 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(&gfx_con, "Can't find library!\n");
|
||||
break;
|
||||
case 2:
|
||||
gfx_printf(&gfx_con, "Cant init ELF context!\n");
|
||||
break;
|
||||
case 3:
|
||||
gfx_printf(&gfx_con, "Cant alloc memory!\n");
|
||||
break;
|
||||
case 4:
|
||||
gfx_printf(&gfx_con, "Error loading ELF!\n");
|
||||
break;
|
||||
case 5:
|
||||
gfx_printf(&gfx_con, "Error relocating ELF!\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: Support shared libraries.
|
||||
int ianos_loader(bool sdmount, char *path, elfType_t type, void *moduleConfig)
|
||||
uintptr_t ianos_loader(bool sdmount, char *path, elfType_t type, void *moduleConfig)
|
||||
{
|
||||
int res = 0;
|
||||
uintptr_t epaddr = 0;
|
||||
|
||||
if (sdmount)
|
||||
{
|
||||
if (!sd_mount())
|
||||
{
|
||||
res = 0xFFFF;
|
||||
goto elfLoadFinalOut;
|
||||
}
|
||||
}
|
||||
|
||||
fileBuf = sd_file_read(path);
|
||||
fileBuf = sd_file_read(path, NULL);
|
||||
|
||||
if (sdmount)
|
||||
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)
|
||||
@@ -131,43 +100,32 @@ int ianos_loader(bool sdmount, char *path, elfType_t type, void *moduleConfig)
|
||||
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.
|
||||
uintptr_t epaddr = ctx.ehdr.e_entry + (uintptr_t)elfBuf;
|
||||
epaddr = ctx.ehdr.e_entry + (uintptr_t)elfBuf;
|
||||
moduleEntrypoint_t ep = (moduleEntrypoint_t)epaddr;
|
||||
|
||||
_ianos_call_ep(ep, moduleConfig);
|
||||
|
||||
elfFreeOut:
|
||||
if ((u32)elfBuf >= 0x90000000 && (u32)elfBuf <= DRAM_LIB_ADDR)
|
||||
free(elfBuf);
|
||||
free(fileBuf);
|
||||
elfBuf = NULL;
|
||||
fileBuf = NULL;
|
||||
|
||||
elfLoadFinalOut:
|
||||
|
||||
return res;
|
||||
return epaddr;
|
||||
}
|
||||
@@ -29,6 +29,6 @@ typedef enum
|
||||
KEEP_IN_RAM = (1 << 31) // Shared library mask.
|
||||
} elfType_t;
|
||||
|
||||
int ianos_loader(bool sdmount, char *path, elfType_t type, void* config);
|
||||
uintptr_t ianos_loader(bool sdmount, char *path, elfType_t type, void* config);
|
||||
|
||||
#endif
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#ifdef DEBUG
|
||||
#include "../../gfx/gfx.h"
|
||||
#define EL_DEBUG(format, ...) \
|
||||
gfx_printf(&gfx_con, format __VA_OPT__(, ) __VA_ARGS__)
|
||||
gfx_printf(format __VA_OPT__(, ) __VA_ARGS__)
|
||||
#else
|
||||
#define EL_DEBUG(...) \
|
||||
do \
|
||||
@@ -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) */
|
||||
|
||||
@@ -8,13 +8,17 @@
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "../../../common/memory_map.h"
|
||||
|
||||
#include "diskio.h" /* FatFs lower layer API */
|
||||
#include "../../storage/sdmmc.h"
|
||||
|
||||
#define SDMMC_UPPER_BUFFER 0xB8000000
|
||||
|
||||
extern sdmmc_storage_t sd_storage;
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Get Drive Status */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
DSTATUS disk_status (
|
||||
BYTE pdrv /* Physical drive nmuber to identify the drive */
|
||||
)
|
||||
@@ -22,6 +26,9 @@ DSTATUS disk_status (
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Inidialize a Drive */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
DSTATUS disk_initialize (
|
||||
BYTE pdrv /* Physical drive nmuber to identify the drive */
|
||||
)
|
||||
@@ -29,6 +36,9 @@ DSTATUS disk_initialize (
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Read Sector(s) */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
DRESULT disk_read (
|
||||
BYTE pdrv, /* Physical drive nmuber to identify the drive */
|
||||
BYTE *buff, /* Data buffer to store read data */
|
||||
@@ -36,9 +46,10 @@ DRESULT disk_read (
|
||||
UINT count /* Number of sectors to read */
|
||||
)
|
||||
{
|
||||
if ((u32)buff >= 0x90000000)
|
||||
// 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; //TODO: define this somewhere.
|
||||
u8 *buf = (u8 *)SDMMC_UPPER_BUFFER;
|
||||
if (sdmmc_storage_read(&sd_storage, sector, count, buf))
|
||||
{
|
||||
memcpy(buff, buf, 512 * count);
|
||||
@@ -47,6 +58,9 @@ DRESULT disk_read (
|
||||
return RES_ERROR;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Write Sector(s) */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
DRESULT disk_write (
|
||||
BYTE pdrv, /* Physical drive nmuber to identify the drive */
|
||||
const BYTE *buff, /* Data to be written */
|
||||
@@ -54,15 +68,19 @@ DRESULT disk_write (
|
||||
UINT count /* Number of sectors to write */
|
||||
)
|
||||
{
|
||||
if ((u32)buff >= 0x90000000)
|
||||
// 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;
|
||||
return RES_ERROR;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Miscellaneous Functions */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
DRESULT disk_ioctl (
|
||||
BYTE pdrv, /* Physical drive nmuber (0..) */
|
||||
BYTE cmd, /* Control code */
|
||||
|
||||
@@ -11,7 +11,6 @@ extern "C" {
|
||||
|
||||
#include "../../utils/types.h"
|
||||
|
||||
|
||||
/* Status of Disk Functions */
|
||||
typedef BYTE DSTATUS;
|
||||
|
||||
@@ -46,11 +45,11 @@ DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);
|
||||
/* Command code for disk_ioctrl fucntion */
|
||||
|
||||
/* Generic command (Used by FatFs) */
|
||||
#define CTRL_SYNC 0 /* Complete pending write process (needed at _FS_READONLY == 0) */
|
||||
#define GET_SECTOR_COUNT 1 /* Get media size (needed at _USE_MKFS == 1) */
|
||||
#define GET_SECTOR_SIZE 2 /* Get sector size (needed at _MAX_SS != _MIN_SS) */
|
||||
#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at _USE_MKFS == 1) */
|
||||
#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at _USE_TRIM == 1) */
|
||||
#define CTRL_SYNC 0 /* Complete pending write process (needed at FF_FS_READONLY == 0) */
|
||||
#define GET_SECTOR_COUNT 1 /* Get media size (needed at FF_USE_MKFS == 1) */
|
||||
#define GET_SECTOR_SIZE 2 /* Get sector size (needed at FF_MAX_SS != FF_MIN_SS) */
|
||||
#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at FF_USE_MKFS == 1) */
|
||||
#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at FF_USE_TRIM == 1) */
|
||||
|
||||
/* Generic command (Not used by FatFs) */
|
||||
#define CTRL_POWER 5 /* Get/Set power status */
|
||||
|
||||
@@ -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.13b /
|
||||
/ FatFs - Generic FAT Filesystem Module R0.13c (p4) /
|
||||
/-----------------------------------------------------------------------------/
|
||||
/
|
||||
/ Copyright (C) 2018, ChaN, all right reserved.
|
||||
/ Copyright (c) 2018 naehrwert
|
||||
/ Copyright (C) 2018 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
|
||||
@@ -25,7 +40,7 @@
|
||||
#include "diskio.h" /* Declarations of device I/O functions */
|
||||
#include "../../gfx/gfx.h"
|
||||
|
||||
#define EFSPRINTF(text, ...) print_error(); gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFFFF00, 0xFFFFFFFF);
|
||||
#define EFSPRINTF(text, ...) print_error(); gfx_printf("%k"text"%k\n", 0xFFFFFF00, 0xFFFFFFFF);
|
||||
//#define EFSPRINTF(...)
|
||||
|
||||
/*--------------------------------------------------------------------------
|
||||
@@ -34,11 +49,20 @@
|
||||
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
#if FF_DEFINED != 63463 /* Revision ID */
|
||||
#if FF_DEFINED != 86604 /* Revision ID */
|
||||
#error Wrong include file (ff.h).
|
||||
#endif
|
||||
|
||||
|
||||
/* Limits and boundaries */
|
||||
#define MAX_DIR 0x200000 /* Max size of FAT directory */
|
||||
#define MAX_DIR_EX 0x10000000 /* Max size of exFAT directory */
|
||||
#define MAX_FAT12 0xFF5 /* Max FAT12 clusters (differs from specs, but right for real DOS/Windows behavior) */
|
||||
#define MAX_FAT16 0xFFF5 /* Max FAT16 clusters (differs from specs, but right for real DOS/Windows behavior) */
|
||||
#define MAX_FAT32 0x0FFFFFF5 /* Max FAT32 clusters (not specified, practical limit) */
|
||||
#define MAX_EXFAT 0x7FFFFFFD /* Max exFAT clusters (differs from specs, implementation limit) */
|
||||
|
||||
|
||||
/* Character code support macros */
|
||||
#define IsUpper(c) ((c) >= 'A' && (c) <= 'Z')
|
||||
#define IsLower(c) ((c) >= 'a' && (c) <= 'z')
|
||||
@@ -48,18 +72,18 @@
|
||||
#define IsSurrogateL(c) ((c) >= 0xDC00 && (c) <= 0xDFFF)
|
||||
|
||||
|
||||
/* Additional file attribute bits for internal use */
|
||||
#define AM_VOL 0x08 /* Volume label */
|
||||
#define AM_LFN 0x0F /* LFN entry */
|
||||
#define AM_MASK 0x3F /* Mask of defined bits */
|
||||
|
||||
|
||||
/* Additional file access control and file status flags for internal use */
|
||||
#define FA_SEEKEND 0x20 /* Seek to end of the file on file open */
|
||||
#define FA_MODIFIED 0x40 /* File has been modified */
|
||||
#define FA_DIRTY 0x80 /* FIL.buf[] needs to be written-back */
|
||||
|
||||
|
||||
/* Additional file attribute bits for internal use */
|
||||
#define AM_VOL 0x08 /* Volume label */
|
||||
#define AM_LFN 0x0F /* LFN entry */
|
||||
#define AM_MASK 0x3F /* Mask of defined bits */
|
||||
|
||||
|
||||
/* Name status flags in fn[11] */
|
||||
#define NSFLAG 11 /* Index of the name status byte */
|
||||
#define NS_LOSS 0x01 /* Out of 8.3 format */
|
||||
@@ -72,13 +96,13 @@
|
||||
#define NS_NONAME 0x80 /* Not followed */
|
||||
|
||||
|
||||
/* Limits and boundaries */
|
||||
#define MAX_DIR 0x200000 /* Max size of FAT directory */
|
||||
#define MAX_DIR_EX 0x10000000 /* Max size of exFAT directory */
|
||||
#define MAX_FAT12 0xFF5 /* Max FAT12 clusters (differs from specs, but right for real DOS/Windows behavior) */
|
||||
#define MAX_FAT16 0xFFF5 /* Max FAT16 clusters (differs from specs, but right for real DOS/Windows behavior) */
|
||||
#define MAX_FAT32 0x0FFFFFF5 /* Max FAT32 clusters (not specified, practical limit) */
|
||||
#define MAX_EXFAT 0x7FFFFFFD /* Max exFAT clusters (differs from specs, implementation limit) */
|
||||
/* exFAT directory entry types */
|
||||
#define ET_BITMAP 0x81 /* Allocation bitmap */
|
||||
#define ET_UPCASE 0x82 /* Up-case table */
|
||||
#define ET_VLABEL 0x83 /* Volume label */
|
||||
#define ET_FILEDIR 0x85 /* File and directory */
|
||||
#define ET_STREAM 0xC0 /* Stream extension */
|
||||
#define ET_FILENAME 0xC1 /* Name extension */
|
||||
|
||||
|
||||
/* FatFs refers the FAT structure as simple byte array instead of structure member
|
||||
@@ -526,6 +550,7 @@ static WCHAR LfnBuf[FF_MAX_LFN + 1]; /* LFN working buffer */
|
||||
#define CODEPAGE CodePage
|
||||
static WORD CodePage; /* Current code page */
|
||||
static const BYTE *ExCvt, *DbcTbl; /* Pointer to current SBCS up-case table and DBCS code range table below */
|
||||
|
||||
static const BYTE Ct437[] = TBL_CT437;
|
||||
static const BYTE Ct720[] = TBL_CT720;
|
||||
static const BYTE Ct737[] = TBL_CT737;
|
||||
@@ -573,7 +598,7 @@ static const BYTE DbcTbl[] = MKCVTBL(TBL_DC, FF_CODE_PAGE);
|
||||
|
||||
void print_error()
|
||||
{
|
||||
gfx_printf(&gfx_con, "\n\n\n%k[FatFS] Error: %k", 0xFFFFFF00, 0xFFFFFFFF);
|
||||
gfx_printf("\n\n\n%k[FatFS] Error: %k", 0xFFFFFF00, 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
|
||||
@@ -1107,7 +1132,7 @@ static FRESULT sync_fs ( /* Returns FR_OK or FR_DISK_ERR */
|
||||
if (res == FR_OK) {
|
||||
if (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) { /* FAT32: Update FSInfo sector if needed */
|
||||
/* Create FSInfo structure */
|
||||
mem_set(fs->win, 0, SS(fs));
|
||||
mem_set(fs->win, 0, sizeof fs->win);
|
||||
st_word(fs->win + BS_55AA, 0xAA55);
|
||||
st_dword(fs->win + FSI_LeadSig, 0x41615252);
|
||||
st_dword(fs->win + FSI_StrucSig, 0x61417272);
|
||||
@@ -1307,7 +1332,7 @@ static DWORD find_bitmap ( /* 0:Not found, 2..:Cluster block found, 0xFFFFFFFF:D
|
||||
if (clst >= fs->n_fatent - 2) clst = 0;
|
||||
scl = val = clst; ctr = 0;
|
||||
for (;;) {
|
||||
if (move_window(fs, fs->database + val / 8 / SS(fs)) != FR_OK) return 0xFFFFFFFF; /* (assuming bitmap is located top of the cluster heap) */
|
||||
if (move_window(fs, fs->bitbase + val / 8 / SS(fs)) != FR_OK) return 0xFFFFFFFF;
|
||||
i = val / 8 % SS(fs); bm = 1 << (val % 8);
|
||||
do {
|
||||
do {
|
||||
@@ -1345,9 +1370,9 @@ static FRESULT change_bitmap (
|
||||
|
||||
|
||||
clst -= 2; /* The first bit corresponds to cluster #2 */
|
||||
sect = fs->database + clst / 8 / SS(fs); /* Sector address (assuming bitmap is located top of the cluster heap) */
|
||||
i = clst / 8 % SS(fs); /* Byte offset in the sector */
|
||||
bm = 1 << (clst % 8); /* Bit mask in the byte */
|
||||
sect = fs->bitbase + clst / 8 / SS(fs); /* Sector address */
|
||||
i = clst / 8 % SS(fs); /* Byte offset in the sector */
|
||||
bm = 1 << (clst % 8); /* Bit mask in the byte */
|
||||
for (;;) {
|
||||
if (move_window(fs, sect++) != FR_OK) return FR_DISK_ERR;
|
||||
do {
|
||||
@@ -1420,7 +1445,7 @@ static FRESULT fill_last_frag (
|
||||
static FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */
|
||||
FFOBJID* obj, /* Corresponding object */
|
||||
DWORD clst, /* Cluster to remove a chain from */
|
||||
DWORD pclst /* Previous cluster of clst (0:entire chain) */
|
||||
DWORD pclst /* Previous cluster of clst (0 if entire chain) */
|
||||
)
|
||||
{
|
||||
FRESULT res = FR_OK;
|
||||
@@ -1658,7 +1683,7 @@ static FRESULT dir_clear ( /* Returns FR_OK or FR_DISK_ERR */
|
||||
if (sync_window(fs) != FR_OK) return FR_DISK_ERR; /* Flush disk access window */
|
||||
sect = clst2sect(fs, clst); /* Top of the cluster */
|
||||
fs->winsect = sect; /* Set window to top of the cluster */
|
||||
mem_set(fs->win, 0, SS(fs)); /* Clear window buffer */
|
||||
mem_set(fs->win, 0, sizeof fs->win); /* Clear window buffer */
|
||||
#if FF_USE_LFN == 3 /* Quick table clear by using multi-secter write */
|
||||
/* Allocate a temporary buffer */
|
||||
for (szb = ((DWORD)fs->csize * SS(fs) >= MAX_MALLOC) ? MAX_MALLOC : fs->csize * SS(fs), ibuf = 0; szb > SS(fs) && (ibuf = ff_memalloc(szb)) == 0; szb /= 2) ;
|
||||
@@ -1888,7 +1913,7 @@ static int cmp_lfn ( /* 1:matched, 0:not matched */
|
||||
for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */
|
||||
uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */
|
||||
if (wc != 0) {
|
||||
if (i >= FF_MAX_LFN || ff_wtoupper(uc) != ff_wtoupper(lfnbuf[i++])) { /* Compare it */
|
||||
if (i >= FF_MAX_LFN + 1 || ff_wtoupper(uc) != ff_wtoupper(lfnbuf[i++])) { /* Compare it */
|
||||
return 0; /* Not matched */
|
||||
}
|
||||
wc = uc;
|
||||
@@ -1924,15 +1949,15 @@ static int pick_lfn ( /* 1:succeeded, 0:buffer overflow or invalid LFN entry */
|
||||
for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */
|
||||
uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */
|
||||
if (wc != 0) {
|
||||
if (i >= FF_MAX_LFN) return 0; /* Buffer overflow? */
|
||||
if (i >= FF_MAX_LFN + 1) return 0; /* Buffer overflow? */
|
||||
lfnbuf[i++] = wc = uc; /* Store it */
|
||||
} else {
|
||||
if (uc != 0xFFFF) return 0; /* Check filler */
|
||||
}
|
||||
}
|
||||
|
||||
if (dir[LDIR_Ord] & LLEF) { /* Put terminator if it is the last LFN part */
|
||||
if (i >= FF_MAX_LFN) return 0; /* Buffer overflow? */
|
||||
if (dir[LDIR_Ord] & LLEF && wc != 0) { /* Put terminator if it is the last LFN part and not terminated */
|
||||
if (i >= FF_MAX_LFN + 1) return 0; /* Buffer overflow? */
|
||||
lfnbuf[i] = 0;
|
||||
}
|
||||
|
||||
@@ -2168,33 +2193,33 @@ static FRESULT load_xdir ( /* FR_INT_ERR: invalid entry block */
|
||||
BYTE* dirb = dp->obj.fs->dirbuf; /* Pointer to the on-memory direcotry entry block 85+C0+C1s */
|
||||
|
||||
|
||||
/* Load 85 entry */
|
||||
/* Load file-directory entry */
|
||||
res = move_window(dp->obj.fs, dp->sect);
|
||||
if (res != FR_OK) return res;
|
||||
if (dp->dir[XDIR_Type] != 0x85) return FR_INT_ERR; /* Invalid order */
|
||||
if (dp->dir[XDIR_Type] != ET_FILEDIR) return FR_INT_ERR; /* Invalid order */
|
||||
mem_cpy(dirb + 0 * SZDIRE, dp->dir, SZDIRE);
|
||||
sz_ent = (dirb[XDIR_NumSec] + 1) * SZDIRE;
|
||||
if (sz_ent < 3 * SZDIRE || sz_ent > 19 * SZDIRE) return FR_INT_ERR;
|
||||
|
||||
/* Load C0 entry */
|
||||
/* Load stream-extension entry */
|
||||
res = dir_next(dp, 0);
|
||||
if (res == FR_NO_FILE) res = FR_INT_ERR; /* It cannot be */
|
||||
if (res != FR_OK) return res;
|
||||
res = move_window(dp->obj.fs, dp->sect);
|
||||
if (res != FR_OK) return res;
|
||||
if (dp->dir[XDIR_Type] != 0xC0) return FR_INT_ERR; /* Invalid order */
|
||||
if (dp->dir[XDIR_Type] != ET_STREAM) return FR_INT_ERR; /* Invalid order */
|
||||
mem_cpy(dirb + 1 * SZDIRE, dp->dir, SZDIRE);
|
||||
if (MAXDIRB(dirb[XDIR_NumName]) > sz_ent) return FR_INT_ERR;
|
||||
|
||||
/* Load C1 entries */
|
||||
i = 2 * SZDIRE; /* C1 offset to load */
|
||||
/* Load file-name entries */
|
||||
i = 2 * SZDIRE; /* Name offset to load */
|
||||
do {
|
||||
res = dir_next(dp, 0);
|
||||
if (res == FR_NO_FILE) res = FR_INT_ERR; /* It cannot be */
|
||||
if (res != FR_OK) return res;
|
||||
res = move_window(dp->obj.fs, dp->sect);
|
||||
if (res != FR_OK) return res;
|
||||
if (dp->dir[XDIR_Type] != 0xC1) return FR_INT_ERR; /* Invalid order */
|
||||
if (dp->dir[XDIR_Type] != ET_FILENAME) return FR_INT_ERR; /* Invalid order */
|
||||
if (i < MAXDIRB(FF_MAX_LFN)) mem_cpy(dirb + i, dp->dir, SZDIRE);
|
||||
} while ((i += SZDIRE) < sz_ent);
|
||||
|
||||
@@ -2299,16 +2324,16 @@ static void create_xdir (
|
||||
WCHAR wc;
|
||||
|
||||
|
||||
/* Create 85,C0 entry */
|
||||
/* Create file-directory and stream-extension entry */
|
||||
mem_set(dirb, 0, 2 * SZDIRE);
|
||||
dirb[0 * SZDIRE + XDIR_Type] = 0x85; /* 85 entry */
|
||||
dirb[1 * SZDIRE + XDIR_Type] = 0xC0; /* C0 entry */
|
||||
dirb[0 * SZDIRE + XDIR_Type] = ET_FILEDIR;
|
||||
dirb[1 * SZDIRE + XDIR_Type] = ET_STREAM;
|
||||
|
||||
/* Create C1 entries */
|
||||
i = SZDIRE * 2; /* Top of C1 entries */
|
||||
/* Create file-name entries */
|
||||
i = SZDIRE * 2; /* Top of file_name entries */
|
||||
nlen = nc1 = 0; wc = 1;
|
||||
do {
|
||||
dirb[i++] = 0xC1; dirb[i++] = 0; /* Entry type C1 */
|
||||
dirb[i++] = ET_FILENAME; dirb[i++] = 0;
|
||||
do { /* Fill name field */
|
||||
if (wc != 0 && (wc = lfn[nlen]) != 0) nlen++; /* Get a character if exist */
|
||||
st_word(dirb + i, wc); /* Store it */
|
||||
@@ -2332,8 +2357,8 @@ static void create_xdir (
|
||||
/* Read an object from the directory */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
#define dir_read_file(dp) dir_read(dp, 0)
|
||||
#define dir_read_label(dp) dir_read(dp, 1)
|
||||
#define DIR_READ_FILE(dp) dir_read(dp, 0)
|
||||
#define DIR_READ_LABEL(dp) dir_read(dp, 1)
|
||||
|
||||
static FRESULT dir_read (
|
||||
DIR* dp, /* Pointer to the directory object */
|
||||
@@ -2342,7 +2367,7 @@ static FRESULT dir_read (
|
||||
{
|
||||
FRESULT res = FR_NO_FILE;
|
||||
FATFS *fs = dp->obj.fs;
|
||||
BYTE a, c;
|
||||
BYTE attr, b;
|
||||
#if FF_USE_LFN
|
||||
BYTE ord = 0xFF, sum = 0xFF;
|
||||
#endif
|
||||
@@ -2350,16 +2375,16 @@ static FRESULT dir_read (
|
||||
while (dp->sect) {
|
||||
res = move_window(fs, dp->sect);
|
||||
if (res != FR_OK) break;
|
||||
c = dp->dir[DIR_Name]; /* Test for the entry type */
|
||||
if (c == 0) {
|
||||
b = dp->dir[DIR_Name]; /* Test for the entry type */
|
||||
if (b == 0) {
|
||||
res = FR_NO_FILE; break; /* Reached to end of the directory */
|
||||
}
|
||||
#if FF_FS_EXFAT
|
||||
if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */
|
||||
if (FF_USE_LABEL && vol) {
|
||||
if (c == 0x83) break; /* Volume label entry? */
|
||||
if (b == ET_VLABEL) break; /* Volume label entry? */
|
||||
} else {
|
||||
if (c == 0x85) { /* Start of the file entry block? */
|
||||
if (b == ET_FILEDIR) { /* Start of the file entry block? */
|
||||
dp->blk_ofs = dp->dptr; /* Get location of the block */
|
||||
res = load_xdir(dp); /* Load the entry block */
|
||||
if (res == FR_OK) {
|
||||
@@ -2371,19 +2396,19 @@ static FRESULT dir_read (
|
||||
} else
|
||||
#endif
|
||||
{ /* On the FAT/FAT32 volume */
|
||||
dp->obj.attr = a = dp->dir[DIR_Attr] & AM_MASK; /* Get attribute */
|
||||
dp->obj.attr = attr = dp->dir[DIR_Attr] & AM_MASK; /* Get attribute */
|
||||
#if FF_USE_LFN /* LFN configuration */
|
||||
if (c == DDEM || c == '.' || (int)((a & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */
|
||||
if (b == DDEM || b == '.' || (int)((attr & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */
|
||||
ord = 0xFF;
|
||||
} else {
|
||||
if (a == AM_LFN) { /* An LFN entry is found */
|
||||
if (c & LLEF) { /* Is it start of an LFN sequence? */
|
||||
if (attr == AM_LFN) { /* An LFN entry is found */
|
||||
if (b & LLEF) { /* Is it start of an LFN sequence? */
|
||||
sum = dp->dir[LDIR_Chksum];
|
||||
c &= (BYTE)~LLEF; ord = c;
|
||||
b &= (BYTE)~LLEF; ord = b;
|
||||
dp->blk_ofs = dp->dptr;
|
||||
}
|
||||
/* Check LFN validity and capture it */
|
||||
ord = (c == ord && sum == dp->dir[LDIR_Chksum] && pick_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF;
|
||||
ord = (b == ord && sum == dp->dir[LDIR_Chksum] && pick_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF;
|
||||
} else { /* An SFN entry is found */
|
||||
if (ord != 0 || sum != sum_sfn(dp->dir)) { /* Is there a valid LFN? */
|
||||
dp->blk_ofs = 0xFFFFFFFF; /* It has no LFN. */
|
||||
@@ -2392,7 +2417,7 @@ static FRESULT dir_read (
|
||||
}
|
||||
}
|
||||
#else /* Non LFN configuration */
|
||||
if (c != DDEM && c != '.' && a != AM_LFN && (int)((a & ~AM_ARC) == AM_VOL) == vol) { /* Is it a valid entry? */
|
||||
if (b != DDEM && b != '.' && attr != AM_LFN && (int)((attr & ~AM_ARC) == AM_VOL) == vol) { /* Is it a valid entry? */
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
@@ -2432,7 +2457,7 @@ static FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */
|
||||
UINT di, ni;
|
||||
WORD hash = xname_sum(fs->lfnbuf); /* Hash value of the name to find */
|
||||
|
||||
while ((res = dir_read_file(dp)) == FR_OK) { /* Read an item */
|
||||
while ((res = DIR_READ_FILE(dp)) == FR_OK) { /* Read an item */
|
||||
#if FF_MAX_LFN < 255
|
||||
if (fs->dirbuf[XDIR_NumName] > FF_MAX_LFN) continue; /* Skip comparison if inaccessible object name */
|
||||
#endif
|
||||
@@ -2511,17 +2536,17 @@ static FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too
|
||||
#if FF_FS_EXFAT
|
||||
if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */
|
||||
nent = (nlen + 14) / 15 + 2; /* Number of entries to allocate (85+C0+C1s) */
|
||||
res = dir_alloc(dp, nent); /* Allocate entries */
|
||||
res = dir_alloc(dp, nent); /* Allocate directory entries */
|
||||
if (res != FR_OK) return res;
|
||||
dp->blk_ofs = dp->dptr - SZDIRE * (nent - 1); /* Set the allocated entry block offset */
|
||||
|
||||
if (dp->obj.stat & 4) { /* Has the directory been stretched? */
|
||||
if (dp->obj.stat & 4) { /* Has the directory been stretched by new allocation? */
|
||||
dp->obj.stat &= ~4;
|
||||
res = fill_first_frag(&dp->obj); /* Fill the first fragment on the FAT if needed */
|
||||
if (res != FR_OK) return res;
|
||||
res = fill_last_frag(&dp->obj, dp->clust, 0xFFFFFFFF); /* Fill the last fragment on the FAT if needed */
|
||||
if (res != FR_OK) return res;
|
||||
if (dp->obj.sclust != 0) { /* Is it a sub directory? */
|
||||
if (dp->obj.sclust != 0) { /* Is it a sub-directory? */
|
||||
DIR dj;
|
||||
|
||||
res = load_obj_xdir(&dj, &dp->obj); /* Load the object status */
|
||||
@@ -2653,6 +2678,7 @@ static void get_fileinfo (
|
||||
{
|
||||
UINT si, di;
|
||||
#if FF_USE_LFN
|
||||
BYTE lcf;
|
||||
WCHAR wc, hs;
|
||||
FATFS *fs = dp->obj.fs;
|
||||
#else
|
||||
@@ -2713,9 +2739,10 @@ static void get_fileinfo (
|
||||
if (di == 0) { /* If LFN and SFN both are invalid, this object is inaccesible */
|
||||
fno->fname[di++] = '?';
|
||||
} else {
|
||||
for (si = di = 0; fno->altname[si]; si++, di++) { /* Copy altname[] to fname[] with case information */
|
||||
for (si = di = 0, lcf = NS_BODY; fno->altname[si]; si++, di++) { /* Copy altname[] to fname[] with case information */
|
||||
wc = (WCHAR)fno->altname[si];
|
||||
if (IsUpper(wc) && (dp->dir[DIR_NTres] & ((si >= 9) ? NS_EXT : NS_BODY))) wc += 0x20;
|
||||
if (wc == '.') lcf = NS_EXT;
|
||||
if (IsUpper(wc) && (dp->dir[DIR_NTres] & lcf)) wc += 0x20;
|
||||
fno->fname[di] = (TCHAR)wc;
|
||||
}
|
||||
}
|
||||
@@ -3272,7 +3299,7 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */
|
||||
if (SS(fs) > FF_MAX_SS || SS(fs) < FF_MIN_SS || (SS(fs) & (SS(fs) - 1))) return FR_DISK_ERR;
|
||||
#endif
|
||||
|
||||
/* Find an FAT partition on the drive. Supports only generic partitioning rules, FDISK and SFD. */
|
||||
/* Find an FAT partition on the drive. Supports only generic partitioning rules, FDISK (MBR) and SFD (w/o partition). */
|
||||
bsect = 0;
|
||||
fmt = check_fs(fs, bsect); /* Load sector 0 and check if it is an FAT-VBR as SFD */
|
||||
if (fmt == 2 || (fmt < 2 && LD2PT(vol) != 0)) { /* Not an FAT-VBR or forced partition number */
|
||||
@@ -3301,13 +3328,12 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */
|
||||
#if FF_FS_EXFAT
|
||||
if (fmt == 1) {
|
||||
QWORD maxlba;
|
||||
DWORD so, cv, bcl;
|
||||
|
||||
for (i = BPB_ZeroedEx; i < BPB_ZeroedEx + 53 && fs->win[i] == 0; i++) ; /* Check zero filler */
|
||||
if (i < BPB_ZeroedEx + 53)
|
||||
return FR_NO_FILESYSTEM;
|
||||
if (i < BPB_ZeroedEx + 53) return FR_NO_FILESYSTEM;
|
||||
|
||||
if (ld_word(fs->win + BPB_FSVerEx) != 0x100)
|
||||
return FR_NO_FILESYSTEM; /* Check exFAT version (must be version 1.0) */
|
||||
if (ld_word(fs->win + BPB_FSVerEx) != 0x100) return FR_NO_FILESYSTEM; /* Check exFAT version (must be version 1.0) */
|
||||
|
||||
if (1 << fs->win[BPB_BytsPerSecEx] != SS(fs)) { /* (BPB_BytsPerSecEx must be equal to the physical sector size) */
|
||||
EFSPRINTF("EXSPS");
|
||||
@@ -3315,8 +3341,7 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */
|
||||
}
|
||||
|
||||
maxlba = ld_qword(fs->win + BPB_TotSecEx) + bsect; /* Last LBA + 1 of the volume */
|
||||
if (maxlba >= 0x100000000)
|
||||
return FR_NO_FILESYSTEM; /* (It cannot be handled in 32-bit LBA) */
|
||||
if (maxlba >= 0x100000000) return FR_NO_FILESYSTEM; /* (It cannot be handled in 32-bit LBA) */
|
||||
|
||||
fs->fsize = ld_dword(fs->win + BPB_FatSzEx); /* Number of sectors per FAT */
|
||||
|
||||
@@ -3327,35 +3352,49 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */
|
||||
}
|
||||
|
||||
fs->csize = 1 << fs->win[BPB_SecPerClusEx]; /* Cluster size */
|
||||
if (fs->csize == 0) {
|
||||
return FR_NO_FILESYSTEM; /* (Must be 1..32768) */
|
||||
}
|
||||
if (fs->csize == 0) return FR_NO_FILESYSTEM; /* (Must be 1..32768) */
|
||||
|
||||
nclst = ld_dword(fs->win + BPB_NumClusEx); /* Number of clusters */
|
||||
if (nclst > MAX_EXFAT)
|
||||
return FR_NO_FILESYSTEM; /* (Too many clusters) */
|
||||
if (nclst > MAX_EXFAT) return FR_NO_FILESYSTEM; /* (Too many clusters) */
|
||||
fs->n_fatent = nclst + 2;
|
||||
|
||||
/* Boundaries and Limits */
|
||||
fs->volbase = bsect;
|
||||
fs->database = bsect + ld_dword(fs->win + BPB_DataOfsEx);
|
||||
fs->fatbase = bsect + ld_dword(fs->win + BPB_FatOfsEx);
|
||||
if (maxlba < (QWORD)fs->database + nclst * fs->csize)
|
||||
return FR_NO_FILESYSTEM; /* (Volume size must not be smaller than the size required) */
|
||||
if (maxlba < (QWORD)fs->database + nclst * fs->csize) return FR_NO_FILESYSTEM; /* (Volume size must not be smaller than the size requiered) */
|
||||
fs->dirbase = ld_dword(fs->win + BPB_RootClusEx);
|
||||
|
||||
/* Check if bitmap location is in assumption (at the first cluster) */
|
||||
if (move_window(fs, clst2sect(fs, fs->dirbase)) != FR_OK) {
|
||||
EFSPRINTF("EXBM1C");
|
||||
return FR_DISK_ERR;
|
||||
/* Get bitmap location and check if it is contiguous (implementation assumption) */
|
||||
so = i = 0;
|
||||
for (;;) { /* Find the bitmap entry in the root directory (in only first cluster) */
|
||||
if (i == 0) {
|
||||
if (so >= fs->csize) return FR_NO_FILESYSTEM; /* Not found? */
|
||||
if (move_window(fs, clst2sect(fs, fs->dirbase) + so) != FR_OK) {
|
||||
EFSPRINTF("EXBM1C");
|
||||
return FR_DISK_ERR;
|
||||
}
|
||||
so++;
|
||||
}
|
||||
if (fs->win[i] == ET_BITMAP) break; /* Is it a bitmap entry? */
|
||||
i = (i + SZDIRE) % SS(fs); /* Next entry */
|
||||
}
|
||||
for (i = 0; i < SS(fs); i += SZDIRE) {
|
||||
if (fs->win[i] == 0x81 && ld_dword(fs->win + i + 20) == 2) break; /* 81 entry with cluster #2? */
|
||||
}
|
||||
if (i == SS(fs)) {
|
||||
bcl = ld_dword(fs->win + i + 20); /* Bitmap cluster */
|
||||
if (bcl < 2 || bcl >= fs->n_fatent) {
|
||||
EFSPRINTF("EXBMM");
|
||||
return FR_NO_FILESYSTEM;
|
||||
}
|
||||
fs->bitbase = fs->database + fs->csize * (bcl - 2); /* Bitmap sector */
|
||||
for (;;) { /* Check if bitmap is contiguous */
|
||||
if (move_window(fs, fs->fatbase + bcl / (SS(fs) / 4)) != FR_OK) return FR_DISK_ERR;
|
||||
cv = ld_dword(fs->win + bcl % (SS(fs) / 4) * 4);
|
||||
if (cv == 0xFFFFFFFF) break; /* Last link? */
|
||||
if (cv != ++bcl) {
|
||||
EFSPRINTF("EXBMM");
|
||||
return FR_NO_FILESYSTEM; /* Fragmented? */
|
||||
}
|
||||
}
|
||||
|
||||
#if !FF_FS_READONLY
|
||||
fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Initialize cluster allocation information */
|
||||
#endif
|
||||
@@ -3373,38 +3412,31 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */
|
||||
fs->fsize = fasize;
|
||||
|
||||
fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FATs */
|
||||
if (fs->n_fats != 1 && fs->n_fats != 2)
|
||||
return FR_NO_FILESYSTEM; /* (Must be 1 or 2) */
|
||||
if (fs->n_fats != 1 && fs->n_fats != 2) return FR_NO_FILESYSTEM; /* (Must be 1 or 2) */
|
||||
fasize *= fs->n_fats; /* Number of sectors for FAT area */
|
||||
|
||||
fs->csize = fs->win[BPB_SecPerClus]; /* Cluster size */
|
||||
if (fs->csize == 0 || (fs->csize & (fs->csize - 1)))
|
||||
return FR_NO_FILESYSTEM; /* (Must be power of 2) */
|
||||
if (fs->csize == 0 || (fs->csize & (fs->csize - 1))) return FR_NO_FILESYSTEM; /* (Must be power of 2) */
|
||||
|
||||
fs->n_rootdir = ld_word(fs->win + BPB_RootEntCnt); /* Number of root directory entries */
|
||||
if (fs->n_rootdir % (SS(fs) / SZDIRE))
|
||||
return FR_NO_FILESYSTEM; /* (Must be sector aligned) */
|
||||
if (fs->n_rootdir % (SS(fs) / SZDIRE)) return FR_NO_FILESYSTEM; /* (Must be sector aligned) */
|
||||
|
||||
tsect = ld_word(fs->win + BPB_TotSec16); /* Number of sectors on the volume */
|
||||
if (tsect == 0) tsect = ld_dword(fs->win + BPB_TotSec32);
|
||||
|
||||
nrsv = ld_word(fs->win + BPB_RsvdSecCnt); /* Number of reserved sectors */
|
||||
if (nrsv == 0)
|
||||
return FR_NO_FILESYSTEM; /* (Must not be 0) */
|
||||
if (nrsv == 0) return FR_NO_FILESYSTEM; /* (Must not be 0) */
|
||||
|
||||
/* Determine the FAT sub type */
|
||||
sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZDIRE); /* RSV + FAT + DIR */
|
||||
if (tsect < sysect)
|
||||
return FR_NO_FILESYSTEM; /* (Invalid volume size) */
|
||||
if (tsect < sysect) return FR_NO_FILESYSTEM; /* (Invalid volume size) */
|
||||
nclst = (tsect - sysect) / fs->csize; /* Number of clusters */
|
||||
if (nclst == 0)
|
||||
return FR_NO_FILESYSTEM; /* (Invalid volume size) */
|
||||
if (nclst == 0) return FR_NO_FILESYSTEM; /* (Invalid volume size) */
|
||||
fmt = 0;
|
||||
if (nclst <= MAX_FAT32) fmt = FS_FAT32;
|
||||
if (nclst <= MAX_FAT16) fmt = FS_FAT16;
|
||||
if (nclst <= MAX_FAT12) fmt = FS_FAT12;
|
||||
if (fmt == 0)
|
||||
return FR_NO_FILESYSTEM;
|
||||
if (fmt == 0) return FR_NO_FILESYSTEM;
|
||||
|
||||
/* Boundaries and Limits */
|
||||
fs->n_fatent = nclst + 2; /* Number of FAT entries */
|
||||
@@ -3412,21 +3444,17 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */
|
||||
fs->fatbase = bsect + nrsv; /* FAT start sector */
|
||||
fs->database = bsect + sysect; /* Data start sector */
|
||||
if (fmt == FS_FAT32) {
|
||||
if (ld_word(fs->win + BPB_FSVer32) != 0)
|
||||
return FR_NO_FILESYSTEM; /* (Must be FAT32 revision 0.0) */
|
||||
if (fs->n_rootdir != 0)
|
||||
return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */
|
||||
if (ld_word(fs->win + BPB_FSVer32) != 0) return FR_NO_FILESYSTEM; /* (Must be FAT32 revision 0.0) */
|
||||
if (fs->n_rootdir != 0) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */
|
||||
fs->dirbase = ld_dword(fs->win + BPB_RootClus32); /* Root directory start cluster */
|
||||
szbfat = fs->n_fatent * 4; /* (Needed FAT size) */
|
||||
} else {
|
||||
if (fs->n_rootdir == 0)
|
||||
return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must not be 0) */
|
||||
if (fs->n_rootdir == 0) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must not be 0) */
|
||||
fs->dirbase = fs->fatbase + fasize; /* Root directory start sector */
|
||||
szbfat = (fmt == FS_FAT16) ? /* (Needed FAT size) */
|
||||
fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1);
|
||||
}
|
||||
if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs))
|
||||
return FR_NO_FILESYSTEM; /* (BPB_FATSz must not be less than the size needed) */
|
||||
if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) return FR_NO_FILESYSTEM; /* (BPB_FATSz must not be less than the size needed) */
|
||||
|
||||
#if !FF_FS_READONLY
|
||||
/* Get FSInfo if available */
|
||||
@@ -3722,7 +3750,7 @@ FRESULT f_open (
|
||||
fp->fptr = 0; /* Set file pointer top of the file */
|
||||
#if !FF_FS_READONLY
|
||||
#if !FF_FS_TINY
|
||||
mem_set(fp->buf, 0, FF_MAX_SS); /* Clear sector buffer */
|
||||
mem_set(fp->buf, 0, sizeof fp->buf); /* Clear sector buffer */
|
||||
#endif
|
||||
if ((mode & FA_SEEKEND) && fp->obj.objsize > 0) { /* Seek to end of file if FA_OPEN_APPEND is specified */
|
||||
fp->fptr = fp->obj.objsize; /* Offset to seek */
|
||||
@@ -3777,17 +3805,16 @@ FRESULT f_read (
|
||||
UINT rcnt, cc, csect;
|
||||
BYTE *rbuff = (BYTE*)buff;
|
||||
|
||||
|
||||
UINT br_tmp;
|
||||
if (!br)
|
||||
br = &br_tmp;
|
||||
*br = 0; /* Clear read byte counter */
|
||||
res = validate(&fp->obj, &fs); /* Check validity of the file object */
|
||||
if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) {
|
||||
EFSPRINTF("FOV");
|
||||
LEAVE_FF(fs, res); /* Check validity */
|
||||
}
|
||||
if (!(fp->flag & FA_READ)) {
|
||||
EFSPRINTF("NOACCESS");
|
||||
LEAVE_FF(fs, FR_DENIED); /* Check access mode */
|
||||
}
|
||||
if (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */
|
||||
remain = fp->obj.objsize - fp->fptr;
|
||||
if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */
|
||||
|
||||
@@ -3819,9 +3846,7 @@ FRESULT f_read (
|
||||
fp->clust = clst; /* Update current cluster */
|
||||
}
|
||||
sect = clst2sect(fs, fp->clust); /* Get current sector */
|
||||
if (sect == 0) {
|
||||
ABORT(fs, FR_INT_ERR);
|
||||
}
|
||||
if (sect == 0) ABORT(fs, FR_INT_ERR);
|
||||
sect += csect;
|
||||
cc = btr / SS(fs); /* When remaining bytes >= sector size, */
|
||||
if (cc > 0) { /* Read maximum contiguous sectors directly */
|
||||
@@ -3899,17 +3924,16 @@ FRESULT f_write (
|
||||
UINT wcnt, cc, csect;
|
||||
const BYTE *wbuff = (const BYTE*)buff;
|
||||
|
||||
|
||||
UINT bw_tmp;
|
||||
if (!bw)
|
||||
bw = &bw_tmp;
|
||||
*bw = 0; /* Clear write byte counter */
|
||||
res = validate(&fp->obj, &fs); /* Check validity of the file object */
|
||||
if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) {
|
||||
EFSPRINTF("FOV");
|
||||
LEAVE_FF(fs, res); /* Check validity */
|
||||
}
|
||||
if (!(fp->flag & FA_WRITE)) {
|
||||
EFSPRINTF("NOACCESS");
|
||||
LEAVE_FF(fs, FR_DENIED); /* Check access mode */
|
||||
}
|
||||
if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */
|
||||
|
||||
/* Check fptr wrap-around (file size cannot reach 4 GiB at FAT volume) */
|
||||
if ((!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) && (DWORD)(fp->fptr + btw) < (DWORD)fp->fptr) {
|
||||
@@ -3955,15 +3979,12 @@ FRESULT f_write (
|
||||
if (fs->winsect == fp->sect && sync_window(fs) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Write-back sector cache */
|
||||
#else
|
||||
if (fp->flag & FA_DIRTY) { /* Write-back sector cache */
|
||||
if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK)
|
||||
ABORT(fs, FR_DISK_ERR);
|
||||
if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);
|
||||
fp->flag &= (BYTE)~FA_DIRTY;
|
||||
}
|
||||
#endif
|
||||
sect = clst2sect(fs, fp->clust); /* Get current sector */
|
||||
if (sect == 0) {
|
||||
ABORT(fs, FR_INT_ERR);
|
||||
}
|
||||
if (sect == 0) ABORT(fs, FR_INT_ERR);
|
||||
sect += csect;
|
||||
cc = btw / SS(fs); /* When remaining bytes >= sector size, */
|
||||
if (cc > 0) { /* Write maximum contiguous sectors directly */
|
||||
@@ -3998,8 +4019,9 @@ FRESULT f_write (
|
||||
#else
|
||||
if (fp->sect != sect && /* Fill sector cache with file data */
|
||||
fp->fptr < fp->obj.objsize &&
|
||||
disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK)
|
||||
disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) {
|
||||
ABORT(fs, FR_DISK_ERR);
|
||||
}
|
||||
#endif
|
||||
fp->sect = sect;
|
||||
}
|
||||
@@ -4236,15 +4258,16 @@ 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
|
||||
|
||||
|
||||
/* Get logical drive */
|
||||
buff[0] = 0; /* Set null string to get current volume */
|
||||
res = find_volume((const TCHAR**)&buff, &fs, 0); /* Get current volume */
|
||||
if (res == FR_OK) {
|
||||
dj.obj.fs = fs;
|
||||
@@ -4263,7 +4286,7 @@ FRESULT f_getcwd (
|
||||
res = dir_sdi(&dj, 0);
|
||||
if (res != FR_OK) break;
|
||||
do { /* Find the entry links to the child directory */
|
||||
res = dir_read_file(&dj);
|
||||
res = DIR_READ_FILE(&dj);
|
||||
if (res != FR_OK) break;
|
||||
if (ccl == ld_clust(fs, dj.dir)) break; /* Found the entry */
|
||||
res = dir_next(&dj, 0);
|
||||
@@ -4595,7 +4618,7 @@ FRESULT f_readdir (
|
||||
res = dir_sdi(dp, 0); /* Rewind the directory object */
|
||||
} else {
|
||||
INIT_NAMBUF(fs);
|
||||
res = dir_read_file(dp); /* Read an item */
|
||||
res = DIR_READ_FILE(dp); /* Read an item */
|
||||
if (res == FR_NO_FILE) res = FR_OK; /* Ignore end of directory */
|
||||
if (res == FR_OK) { /* A valid entry is found */
|
||||
get_fileinfo(dp, fno); /* Get the object information */
|
||||
@@ -4718,7 +4741,7 @@ FRESULT f_getfree (
|
||||
/* Get logical drive */
|
||||
res = find_volume(&path, &fs, 0);
|
||||
if (res == FR_OK) {
|
||||
*fatfs = fs; /* Return ptr to the fs object */
|
||||
if (fatfs) *fatfs = fs; /* Return ptr to the fs object */
|
||||
/* If free_clst is valid, return it without full FAT scan */
|
||||
if (fs->free_clst <= fs->n_fatent - 2) {
|
||||
*nclst = fs->free_clst;
|
||||
@@ -4740,7 +4763,7 @@ FRESULT f_getfree (
|
||||
UINT b;
|
||||
|
||||
clst = fs->n_fatent - 2; /* Number of clusters */
|
||||
sect = fs->database; /* Assuming bitmap starts at cluster 2 */
|
||||
sect = fs->bitbase; /* Bitmap sector */
|
||||
i = 0; /* Offset in the sector */
|
||||
do { /* Counts numbuer of bits with zero in the bitmap */
|
||||
if (i == 0) {
|
||||
@@ -4903,7 +4926,7 @@ FRESULT f_unlink (
|
||||
#endif
|
||||
res = dir_sdi(&sdj, 0);
|
||||
if (res == FR_OK) {
|
||||
res = dir_read_file(&sdj); /* Test if the directory is empty */
|
||||
res = DIR_READ_FILE(&sdj); /* Test if the directory is empty */
|
||||
if (res == FR_OK) res = FR_DENIED; /* Not empty? */
|
||||
if (res == FR_NO_FILE) res = FR_OK; /* Empty? */
|
||||
}
|
||||
@@ -4943,47 +4966,43 @@ FRESULT f_mkdir (
|
||||
DIR dj;
|
||||
FFOBJID sobj;
|
||||
FATFS *fs;
|
||||
BYTE *dir;
|
||||
DWORD dcl, pcl, tm;
|
||||
DEF_NAMBUF
|
||||
|
||||
|
||||
/* Get logical drive */
|
||||
res = find_volume(&path, &fs, FA_WRITE);
|
||||
res = find_volume(&path, &fs, FA_WRITE); /* Get logical drive */
|
||||
if (res == FR_OK) {
|
||||
dj.obj.fs = fs;
|
||||
INIT_NAMBUF(fs);
|
||||
res = follow_path(&dj, path); /* Follow the file path */
|
||||
if (res == FR_OK) res = FR_EXIST; /* Any object with same name is already existing */
|
||||
if (FF_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) {
|
||||
if (res == FR_OK) res = FR_EXIST; /* Name collision? */
|
||||
if (FF_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) { /* Invalid name? */
|
||||
res = FR_INVALID_NAME;
|
||||
}
|
||||
if (res == FR_NO_FILE) { /* Can create a new directory */
|
||||
if (res == FR_NO_FILE) { /* It is clear to create a new directory */
|
||||
sobj.fs = fs; /* New object id to create a new chain */
|
||||
dcl = create_chain(&sobj, 0); /* Allocate a cluster for the new directory */
|
||||
res = FR_OK;
|
||||
if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster */
|
||||
if (dcl == 1) res = FR_INT_ERR;
|
||||
if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR;
|
||||
if (res == FR_OK) res = sync_window(fs); /* Flush FAT */
|
||||
if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster? */
|
||||
if (dcl == 1) res = FR_INT_ERR; /* Any insanity? */
|
||||
if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR; /* Disk error? */
|
||||
tm = GET_FATTIME();
|
||||
if (res == FR_OK) { /* Initialize the new directory table */
|
||||
res = dir_clear(fs, dcl); /* Clean up the new table */
|
||||
if (res == FR_OK && (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT)) { /* Create dot entries (FAT only) */
|
||||
dir = fs->win;
|
||||
mem_set(dir + DIR_Name, ' ', 11); /* Create "." entry */
|
||||
dir[DIR_Name] = '.';
|
||||
dir[DIR_Attr] = AM_DIR;
|
||||
st_dword(dir + DIR_ModTime, tm);
|
||||
st_clust(fs, dir, dcl);
|
||||
mem_cpy(dir + SZDIRE, dir, SZDIRE); /* Create ".." entry */
|
||||
dir[SZDIRE + 1] = '.'; pcl = dj.obj.sclust;
|
||||
st_clust(fs, dir + SZDIRE, pcl);
|
||||
fs->wflag = 1;
|
||||
}
|
||||
}
|
||||
if (res == FR_OK) {
|
||||
res = dir_register(&dj); /* Register the object to the directoy */
|
||||
res = dir_clear(fs, dcl); /* Clean up the new table */
|
||||
if (res == FR_OK) {
|
||||
if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { /* Create dot entries (FAT only) */
|
||||
mem_set(fs->win + DIR_Name, ' ', 11); /* Create "." entry */
|
||||
fs->win[DIR_Name] = '.';
|
||||
fs->win[DIR_Attr] = AM_DIR;
|
||||
st_dword(fs->win + DIR_ModTime, tm);
|
||||
st_clust(fs, fs->win, dcl);
|
||||
mem_cpy(fs->win + SZDIRE, fs->win, SZDIRE); /* Create ".." entry */
|
||||
fs->win[SZDIRE + 1] = '.'; pcl = dj.obj.sclust;
|
||||
st_clust(fs, fs->win + SZDIRE, pcl);
|
||||
fs->wflag = 1;
|
||||
}
|
||||
res = dir_register(&dj); /* Register the object to the parent directoy */
|
||||
}
|
||||
}
|
||||
if (res == FR_OK) {
|
||||
#if FF_FS_EXFAT
|
||||
@@ -4998,17 +5017,16 @@ FRESULT f_mkdir (
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
dir = dj.dir;
|
||||
st_dword(dir + DIR_ModTime, tm); /* Created time */
|
||||
st_clust(fs, dir, dcl); /* Table start cluster */
|
||||
dir[DIR_Attr] = AM_DIR; /* Attribute */
|
||||
st_dword(dj.dir + DIR_ModTime, tm); /* Created time */
|
||||
st_clust(fs, dj.dir, dcl); /* Table start cluster */
|
||||
dj.dir[DIR_Attr] = AM_DIR; /* Attribute */
|
||||
fs->wflag = 1;
|
||||
}
|
||||
if (res == FR_OK) {
|
||||
res = sync_fs(fs);
|
||||
}
|
||||
} else {
|
||||
remove_chain(&dj.obj, dcl, 0); /* Could not register, remove cluster chain */
|
||||
remove_chain(&sobj, dcl, 0); /* Could not register, remove the allocated cluster */
|
||||
}
|
||||
}
|
||||
FREE_NAMBUF();
|
||||
@@ -5248,7 +5266,7 @@ FRESULT f_getlabel (
|
||||
dj.obj.fs = fs; dj.obj.sclust = 0; /* Open root directory */
|
||||
res = dir_sdi(&dj, 0);
|
||||
if (res == FR_OK) {
|
||||
res = dir_read_label(&dj); /* Find a volume label entry */
|
||||
res = DIR_READ_LABEL(&dj); /* Find a volume label entry */
|
||||
if (res == FR_OK) {
|
||||
#if FF_FS_EXFAT
|
||||
if (fs->fs_type == FS_EXFAT) {
|
||||
@@ -5393,7 +5411,7 @@ FRESULT f_setlabel (
|
||||
dj.obj.fs = fs; dj.obj.sclust = 0; /* Open root directory */
|
||||
res = dir_sdi(&dj, 0);
|
||||
if (res == FR_OK) {
|
||||
res = dir_read_label(&dj); /* Get volume label entry */
|
||||
res = DIR_READ_LABEL(&dj); /* Get volume label entry */
|
||||
if (res == FR_OK) {
|
||||
if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) {
|
||||
dj.dir[XDIR_NumLabel] = (BYTE)di; /* Change the volume label */
|
||||
@@ -5415,7 +5433,7 @@ FRESULT f_setlabel (
|
||||
if (res == FR_OK) {
|
||||
mem_set(dj.dir, 0, SZDIRE); /* Clean the entry */
|
||||
if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) {
|
||||
dj.dir[XDIR_Type] = 0x83; /* Create 83 entry */
|
||||
dj.dir[XDIR_Type] = ET_VLABEL; /* Create volume label entry */
|
||||
dj.dir[XDIR_NumLabel] = (BYTE)di;
|
||||
mem_cpy(dj.dir + XDIR_Label, dirvn, 22);
|
||||
} else {
|
||||
@@ -5720,7 +5738,7 @@ FRESULT f_mkfs (
|
||||
b_fat = b_vol + 32; /* FAT start at offset 32 */
|
||||
sz_fat = ((sz_vol / au + 2) * 4 + ss - 1) / ss; /* Number of FAT sectors */
|
||||
b_data = (b_fat + sz_fat + sz_blk - 1) & ~(sz_blk - 1); /* Align data area to the erase block boundary */
|
||||
if (b_data >= sz_vol / 2) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume? */
|
||||
if (b_data - b_vol >= sz_vol / 2) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume? */
|
||||
n_clst = (sz_vol - (b_data - b_vol)) / au; /* Number of clusters */
|
||||
if (n_clst <16) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too few clusters? */
|
||||
if (n_clst > MAX_EXFAT) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too many clusters? */
|
||||
@@ -5801,11 +5819,11 @@ FRESULT f_mkfs (
|
||||
|
||||
/* Initialize the root directory */
|
||||
mem_set(buf, 0, szb_buf);
|
||||
buf[SZDIRE * 0 + 0] = 0x83; /* 83 entry (volume label) */
|
||||
buf[SZDIRE * 1 + 0] = 0x81; /* 81 entry (allocation bitmap) */
|
||||
buf[SZDIRE * 0 + 0] = ET_VLABEL; /* Volume label entry */
|
||||
buf[SZDIRE * 1 + 0] = ET_BITMAP; /* Bitmap entry */
|
||||
st_dword(buf + SZDIRE * 1 + 20, 2); /* cluster */
|
||||
st_dword(buf + SZDIRE * 1 + 24, szb_bit); /* size */
|
||||
buf[SZDIRE * 2 + 0] = 0x82; /* 82 entry (up-case table) */
|
||||
buf[SZDIRE * 2 + 0] = ET_UPCASE; /* Up-case table entry */
|
||||
st_dword(buf + SZDIRE * 2 + 4, sum); /* sum */
|
||||
st_dword(buf + SZDIRE * 2 + 20, 2 + tbl[0]); /* cluster */
|
||||
st_dword(buf + SZDIRE * 2 + 24, szb_case); /* size */
|
||||
@@ -6293,8 +6311,7 @@ typedef struct { /* Putchar output buffer and work area */
|
||||
} putbuff;
|
||||
|
||||
|
||||
static
|
||||
void putc_bfd ( /* Buffered write with code conversion */
|
||||
static void putc_bfd ( /* Buffered write with code conversion */
|
||||
putbuff* pb,
|
||||
TCHAR c
|
||||
)
|
||||
@@ -6405,7 +6422,7 @@ void putc_bfd ( /* Buffered write with code conversion */
|
||||
#else /* Write it in ANSI/OEM */
|
||||
if (hs != 0) return;
|
||||
wc = ff_uni2oem(wc, CODEPAGE); /* UTF-16 ==> ANSI/OEM */
|
||||
if (wc == 0) return;;
|
||||
if (wc == 0) return;
|
||||
if (wc >= 0x100) {
|
||||
pb->buf[i++] = (BYTE)(wc >> 8); nc++;
|
||||
}
|
||||
@@ -6425,8 +6442,7 @@ void putc_bfd ( /* Buffered write with code conversion */
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
int putc_flush ( /* Flush left characters in the buffer */
|
||||
static int putc_flush ( /* Flush left characters in the buffer */
|
||||
putbuff* pb
|
||||
)
|
||||
{
|
||||
@@ -6439,8 +6455,7 @@ int putc_flush ( /* Flush left characters in the buffer */
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
void putc_init ( /* Initialize write buffer */
|
||||
static void putc_init ( /* Initialize write buffer */
|
||||
putbuff* pb,
|
||||
FIL* fp
|
||||
)
|
||||
@@ -6632,4 +6647,3 @@ FRESULT f_setcp (
|
||||
return FR_OK;
|
||||
}
|
||||
#endif /* FF_CODE_PAGE == 0 */
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*----------------------------------------------------------------------------/
|
||||
/ FatFs - Generic FAT Filesystem module R0.13b /
|
||||
/ FatFs - Generic FAT Filesystem module R0.13c /
|
||||
/-----------------------------------------------------------------------------/
|
||||
/
|
||||
/ Copyright (C) 2018, ChaN, all right reserved.
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
|
||||
#ifndef FF_DEFINED
|
||||
#define FF_DEFINED 63463 /* Revision ID */
|
||||
#define FF_DEFINED 86604 /* Revision ID */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -95,8 +95,9 @@ typedef DWORD FSIZE_t;
|
||||
/* Filesystem object structure (FATFS) */
|
||||
|
||||
typedef struct {
|
||||
BYTE fs_type; /* Filesystem type (0:N/A) */
|
||||
BYTE pdrv; /* Physical drive number */
|
||||
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) */
|
||||
BYTE wflag; /* win[] flag (b0:dirty) */
|
||||
BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */
|
||||
@@ -133,8 +134,10 @@ typedef struct {
|
||||
DWORD fatbase; /* FAT base sector */
|
||||
DWORD dirbase; /* Root directory base sector/cluster */
|
||||
DWORD database; /* Data base sector */
|
||||
#if FF_FS_EXFAT
|
||||
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;
|
||||
|
||||
|
||||
@@ -145,7 +148,7 @@ typedef struct {
|
||||
FATFS* fs; /* Pointer to the hosting volume of this object */
|
||||
WORD id; /* Hosting volume mount ID */
|
||||
BYTE attr; /* Object attribute */
|
||||
BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:flagmented in this session, b2:sub-directory stretched) */
|
||||
BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:fragmented in this session, b2:sub-directory stretched) */
|
||||
DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */
|
||||
FSIZE_t objsize; /* Object size (valid when sclust != 0) */
|
||||
#if FF_FS_EXFAT
|
||||
@@ -165,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 +184,6 @@ typedef struct {
|
||||
#if FF_USE_FASTSEEK
|
||||
DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */
|
||||
#endif
|
||||
#if !FF_FS_TINY
|
||||
BYTE buf[FF_MAX_SS]; /* File private data read/write window */
|
||||
#endif
|
||||
} FIL;
|
||||
|
||||
|
||||
@@ -276,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 */
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ FatFs - Configuration file
|
||||
/ FatFs Functional Configurations
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define FFCONF_DEF 63463 /* Revision ID */
|
||||
#define FFCONF_DEF 86604 /* Revision ID */
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ Function Configurations
|
||||
@@ -232,14 +232,14 @@
|
||||
|
||||
#define FF_FS_EXFAT 1
|
||||
/* This option switches support for exFAT filesystem. (0:Disable or 1:Enable)
|
||||
/ To enable exFAT, also LFN needs to be enabled.
|
||||
/ To enable exFAT, also LFN needs to be enabled. (FF_USE_LFN >= 1)
|
||||
/ Note that enabling exFAT discards ANSI C (C89) compatibility. */
|
||||
|
||||
|
||||
#define FF_FS_NORTC 1
|
||||
#define FF_NORTC_MON 1
|
||||
#define FF_NORTC_MDAY 1
|
||||
#define FF_NORTC_YEAR 2018
|
||||
#define FF_NORTC_YEAR 2019
|
||||
/* The option FF_FS_NORTC switches timestamp function. If the system does not have
|
||||
/ any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable
|
||||
/ the timestamp function. Every object modified by FatFs will have a fixed timestamp
|
||||
@@ -262,6 +262,7 @@
|
||||
/ lock control is independent of re-entrancy. */
|
||||
|
||||
|
||||
/* #include <somertos.h> // O/S definitions */
|
||||
#define FF_FS_REENTRANT 0
|
||||
#define FF_FS_TIMEOUT 1000
|
||||
#define FF_SYNC_t HANDLE
|
||||
@@ -282,8 +283,6 @@
|
||||
/ SemaphoreHandle_t and etc. A header file for O/S definitions needs to be
|
||||
/ included somewhere in the scope of ff.h. */
|
||||
|
||||
/* #include <windows.h> // O/S definitions */
|
||||
|
||||
|
||||
|
||||
/*--- End of configuration options ---*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Sample Code of OS Dependent Functions for FatFs */
|
||||
/* (C) ChaN, 2017 */
|
||||
/* (C) ChaN, 2018 */
|
||||
/* (C) CTCaer, 2018 */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
/* Allocate a memory block */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
void* ff_memalloc ( /* Returns pointer to the allocated memory block (null on not enough core) */
|
||||
void* ff_memalloc ( /* Returns pointer to the allocated memory block (null if not enough core) */
|
||||
UINT msize /* Number of bytes to allocate */
|
||||
)
|
||||
{
|
||||
@@ -29,7 +29,7 @@ void* ff_memalloc ( /* Returns pointer to the allocated memory block (null on no
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
void ff_memfree (
|
||||
void* mblock /* Pointer to the memory block to free (nothing to do for null) */
|
||||
void* mblock /* Pointer to the memory block to free (nothing to do if null) */
|
||||
)
|
||||
{
|
||||
free(mblock); /* Free the memory block with POSIX API */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Unicode handling functions for FatFs R0.13a */
|
||||
/* Unicode handling functions for FatFs R0.13c */
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* This module will occupy a huge memory in the .const section when the /
|
||||
/ FatFs is configured for LFN with DBCS. If the system has any Unicode /
|
||||
@@ -7,7 +7,7 @@
|
||||
/ that function to avoid silly memory consumption. /
|
||||
/-------------------------------------------------------------------------*/
|
||||
/*
|
||||
/ Copyright (C) 2017, ChaN, all right reserved.
|
||||
/ Copyright (C) 2018, ChaN, all right reserved.
|
||||
/
|
||||
/ FatFs module is an open source software. Redistribution and use of FatFs in
|
||||
/ source and binary forms, with or without modification, are permitted provided
|
||||
@@ -25,16 +25,15 @@
|
||||
|
||||
#include "ff.h"
|
||||
|
||||
#if FF_USE_LFN /* This module is blanked when non-LFN configuration */
|
||||
#if FF_USE_LFN /* This module will be blanked at non-LFN configuration */
|
||||
|
||||
#if FF_DEFINED != 63463 /* Revision ID */
|
||||
#if FF_DEFINED != 86604 /* Revision ID */
|
||||
#error Wrong include file (ff.h).
|
||||
#endif
|
||||
|
||||
#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 */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
1186
bootloader/mem/emc.h
1186
bootloader/mem/emc.h
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2020 CTCaer
|
||||
* Copyright (c) 2018 M4xw
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -17,6 +18,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 +27,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 +48,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 +112,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 +130,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 +145,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;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2020 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,11 +19,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
|
||||
|
||||
@@ -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;
|
||||
|
||||
109
bootloader/mem/minerva.c
Normal file
109
bootloader/mem/minerva.c
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 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,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "minerva.h"
|
||||
#include "../soc/fuse.h"
|
||||
#include "../utils/util.h"
|
||||
|
||||
#include "../soc/clock.h"
|
||||
#include "../ianos/ianos.h"
|
||||
#include "../soc/fuse.h"
|
||||
#include "../soc/t210.h"
|
||||
|
||||
extern volatile nyx_storage_t *nyx_str;
|
||||
|
||||
u32 minerva_init()
|
||||
{
|
||||
u32 curr_ram_idx = 0;
|
||||
|
||||
minerva_cfg = NULL;
|
||||
mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg;
|
||||
memset(mtc_cfg, 0, sizeof(mtc_config_t));
|
||||
|
||||
// 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);
|
||||
|
||||
// Ensure that Minerva is new.
|
||||
if (mtc_cfg->init_done == MTC_INIT_MAGIC)
|
||||
minerva_cfg = (void *)ep_addr;
|
||||
else
|
||||
mtc_cfg->init_done = 0;
|
||||
|
||||
if (!minerva_cfg)
|
||||
return 1;
|
||||
|
||||
// Get current frequency
|
||||
for (curr_ram_idx = 0; curr_ram_idx < 10; curr_ram_idx++)
|
||||
{
|
||||
if (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) == mtc_cfg->mtc_table[curr_ram_idx].clk_src_emc)
|
||||
break;
|
||||
}
|
||||
|
||||
mtc_cfg->rate_from = mtc_cfg->mtc_table[curr_ram_idx].rate_khz;
|
||||
mtc_cfg->rate_to = 204000;
|
||||
mtc_cfg->train_mode = OP_TRAIN;
|
||||
minerva_cfg(mtc_cfg, NULL);
|
||||
mtc_cfg->rate_to = 800000;
|
||||
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 (mtc_cfg->rate_from != freq)
|
||||
{
|
||||
mtc_cfg->rate_to = freq;
|
||||
mtc_cfg->train_mode = OP_SWITCH;
|
||||
minerva_cfg(mtc_cfg, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void minerva_periodic_training()
|
||||
{
|
||||
if (!minerva_cfg)
|
||||
return;
|
||||
|
||||
mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg;
|
||||
if (mtc_cfg->rate_from == FREQ_1600)
|
||||
{
|
||||
mtc_cfg->train_mode = OP_PERIODIC_TRAIN;
|
||||
minerva_cfg(mtc_cfg, NULL);
|
||||
}
|
||||
}
|
||||
65
bootloader/mem/minerva.h
Normal file
65
bootloader/mem/minerva.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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,
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef _FE_MINERVA_H_
|
||||
#define _FE_MINERVA_H_
|
||||
|
||||
#include "mtc_table.h"
|
||||
#include "../utils/types.h"
|
||||
|
||||
#define MTC_INIT_MAGIC 0x3043544D
|
||||
#define MTC_NEW_MAGIC 0x5243544D
|
||||
|
||||
#define EMC_PERIODIC_TRAIN_MS 250
|
||||
|
||||
typedef struct
|
||||
{
|
||||
s32 rate_to;
|
||||
s32 rate_from;
|
||||
emc_table_t *mtc_table;
|
||||
u32 table_entries;
|
||||
emc_table_t *current_emc_table;
|
||||
u32 train_mode;
|
||||
u32 sdram_id;
|
||||
u32 prev_temp;
|
||||
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
|
||||
{
|
||||
OP_SWITCH = 0,
|
||||
OP_TRAIN = 1,
|
||||
OP_TRAIN_SWITCH = 2,
|
||||
OP_PERIODIC_TRAIN = 3,
|
||||
OP_TEMP_COMP = 4
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
FREQ_204 = 204000,
|
||||
FREQ_800 = 800000,
|
||||
FREQ_1600 = 1600000
|
||||
} minerva_freq_t;
|
||||
|
||||
void (*minerva_cfg)(mtc_config_t *mtc_cfg, void *);
|
||||
u32 minerva_init();
|
||||
void minerva_change_freq(minerva_freq_t freq);
|
||||
void minerva_periodic_training();
|
||||
|
||||
#endif
|
||||
560
bootloader/mem/mtc_table.h
Normal file
560
bootloader/mem/mtc_table.h
Normal file
@@ -0,0 +1,560 @@
|
||||
/*
|
||||
* Minerva Training Cell
|
||||
* DRAM Training for Tegra X1 SoC. Supports DDR2/3 and LPDDR3/4.
|
||||
*
|
||||
* Copyright (c) 2018 CTCaer <ctcaer@gmail.com>
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef _MTC_TABLE_H_
|
||||
#define _MTC_TABLE_H_
|
||||
|
||||
#include "../utils/types.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
s32 pll_osc_in;
|
||||
s32 pll_out;
|
||||
u32 pll_feedback_div;
|
||||
u32 pll_input_div;
|
||||
u32 pll_post_div;
|
||||
} pllm_clk_config_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 emc_rc_idx;
|
||||
u32 emc_rfc_idx;
|
||||
u32 emc_rfcpb_idx;
|
||||
u32 emc_refctrl2_idx;
|
||||
u32 emc_rfc_slr_idx;
|
||||
u32 emc_ras_idx;
|
||||
u32 emc_rp_idx;
|
||||
u32 emc_r2w_idx;
|
||||
u32 emc_w2r_idx;
|
||||
u32 emc_r2p_idx;
|
||||
u32 emc_w2p_idx;
|
||||
u32 emc_r2r_idx;
|
||||
u32 emc_tppd_idx;
|
||||
u32 emc_ccdmw_idx;
|
||||
u32 emc_rd_rcd_idx;
|
||||
u32 emc_wr_rcd_idx;
|
||||
u32 emc_rrd_idx;
|
||||
u32 emc_rext_idx;
|
||||
u32 emc_wext_idx;
|
||||
u32 emc_wdv_chk_idx;
|
||||
u32 emc_wdv_idx;
|
||||
u32 emc_wsv_idx;
|
||||
u32 emc_wev_idx;
|
||||
u32 emc_wdv_mask_idx;
|
||||
u32 emc_ws_duration_idx;
|
||||
u32 emc_we_duration_idx;
|
||||
u32 emc_quse_idx;
|
||||
u32 emc_quse_width_idx;
|
||||
u32 emc_ibdly_idx;
|
||||
u32 emc_obdly_idx;
|
||||
u32 emc_einput_idx;
|
||||
u32 emc_mrw6_idx;
|
||||
u32 emc_einput_duration_idx;
|
||||
u32 emc_puterm_extra_idx;
|
||||
u32 emc_puterm_width_idx;
|
||||
u32 emc_qrst_idx;
|
||||
u32 emc_qsafe_idx;
|
||||
u32 emc_rdv_idx;
|
||||
u32 emc_rdv_mask_idx;
|
||||
u32 emc_rdv_early_idx;
|
||||
u32 emc_rdv_early_mask_idx;
|
||||
u32 emc_refresh_idx;
|
||||
u32 emc_burst_refresh_num_idx;
|
||||
u32 emc_pre_refresh_req_cnt_idx;
|
||||
u32 emc_pdex2wr_idx;
|
||||
u32 emc_pdex2rd_idx;
|
||||
u32 emc_pchg2pden_idx;
|
||||
u32 emc_act2pden_idx;
|
||||
u32 emc_ar2pden_idx;
|
||||
u32 emc_rw2pden_idx;
|
||||
u32 emc_cke2pden_idx;
|
||||
u32 emc_pdex2cke_idx;
|
||||
u32 emc_pdex2mrr_idx;
|
||||
u32 emc_txsr_idx;
|
||||
u32 emc_txsrdll_idx;
|
||||
u32 emc_tcke_idx;
|
||||
u32 emc_tckesr_idx;
|
||||
u32 emc_tpd_idx;
|
||||
u32 emc_tfaw_idx;
|
||||
u32 emc_trpab_idx;
|
||||
u32 emc_tclkstable_idx;
|
||||
u32 emc_tclkstop_idx;
|
||||
u32 emc_mrw7_idx;
|
||||
u32 emc_trefbw_idx;
|
||||
u32 emc_odt_write_idx;
|
||||
u32 emc_fbio_cfg5_idx;
|
||||
u32 emc_fbio_cfg7_idx;
|
||||
u32 emc_cfg_dig_dll_idx;
|
||||
u32 emc_cfg_dig_dll_period_idx;
|
||||
u32 emc_pmacro_ib_rxrt_idx;
|
||||
u32 emc_cfg_pipe_1_idx;
|
||||
u32 emc_cfg_pipe_2_idx;
|
||||
u32 emc_pmacro_quse_ddll_rank0_4_idx;
|
||||
u32 emc_pmacro_quse_ddll_rank0_5_idx;
|
||||
u32 emc_pmacro_quse_ddll_rank1_4_idx;
|
||||
u32 emc_pmacro_quse_ddll_rank1_5_idx;
|
||||
u32 emc_mrw8_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dq_rank1_4_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dq_rank1_5_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dqs_rank0_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dqs_rank0_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dqs_rank0_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dqs_rank0_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dqs_rank0_4_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dqs_rank0_5_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dqs_rank1_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dqs_rank1_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dqs_rank1_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dqs_rank1_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dqs_rank1_4_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dqs_rank1_5_idx;
|
||||
u32 emc_pmacro_ddll_long_cmd_0_idx;
|
||||
u32 emc_pmacro_ddll_long_cmd_1_idx;
|
||||
u32 emc_pmacro_ddll_long_cmd_2_idx;
|
||||
u32 emc_pmacro_ddll_long_cmd_3_idx;
|
||||
u32 emc_pmacro_ddll_long_cmd_4_idx;
|
||||
u32 emc_pmacro_ddll_short_cmd_0_idx;
|
||||
u32 emc_pmacro_ddll_short_cmd_1_idx;
|
||||
u32 emc_pmacro_ddll_short_cmd_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_3_idx;
|
||||
u32 emc_txdsrvttgen_idx;
|
||||
u32 emc_fdpd_ctrl_dq_idx;
|
||||
u32 emc_fdpd_ctrl_cmd_idx;
|
||||
u32 emc_fbio_spare_idx;
|
||||
u32 emc_zcal_interval_idx;
|
||||
u32 emc_zcal_wait_cnt_idx;
|
||||
u32 emc_mrs_wait_cnt_idx;
|
||||
u32 emc_mrs_wait_cnt2_idx;
|
||||
u32 emc_auto_cal_channel_idx;
|
||||
u32 emc_dll_cfg_0_idx;
|
||||
u32 emc_dll_cfg_1_idx;
|
||||
u32 emc_pmacro_autocal_cfg_common_idx;
|
||||
u32 emc_pmacro_zctrl_idx;
|
||||
u32 emc_cfg_idx;
|
||||
u32 emc_cfg_pipe_idx;
|
||||
u32 emc_dyn_self_ref_control_idx;
|
||||
u32 emc_qpop_idx;
|
||||
u32 emc_dqs_brlshft_0_idx;
|
||||
u32 emc_dqs_brlshft_1_idx;
|
||||
u32 emc_cmd_brlshft_2_idx;
|
||||
u32 emc_cmd_brlshft_3_idx;
|
||||
u32 emc_pmacro_pad_cfg_ctrl_idx;
|
||||
u32 emc_pmacro_data_pad_rx_ctrl_idx;
|
||||
u32 emc_pmacro_cmd_pad_rx_ctrl_idx;
|
||||
u32 emc_pmacro_data_rx_term_mode_idx;
|
||||
u32 emc_pmacro_cmd_rx_term_mode_idx;
|
||||
u32 emc_pmacro_cmd_pad_tx_ctrl_idx;
|
||||
u32 emc_pmacro_data_pad_tx_ctrl_idx;
|
||||
u32 emc_pmacro_common_pad_tx_ctrl_idx;
|
||||
u32 emc_pmacro_vttgen_ctrl_0_idx;
|
||||
u32 emc_pmacro_vttgen_ctrl_1_idx;
|
||||
u32 emc_pmacro_vttgen_ctrl_2_idx;
|
||||
u32 emc_pmacro_brick_ctrl_rfu1_idx;
|
||||
u32 emc_pmacro_cmd_brick_ctrl_fdpd_idx;
|
||||
u32 emc_pmacro_brick_ctrl_rfu2_idx;
|
||||
u32 emc_pmacro_data_brick_ctrl_fdpd_idx;
|
||||
u32 emc_pmacro_bg_bias_ctrl_0_idx;
|
||||
u32 emc_cfg_3_idx;
|
||||
u32 emc_pmacro_tx_pwrd_0_idx;
|
||||
u32 emc_pmacro_tx_pwrd_1_idx;
|
||||
u32 emc_pmacro_tx_pwrd_2_idx;
|
||||
u32 emc_pmacro_tx_pwrd_3_idx;
|
||||
u32 emc_pmacro_tx_pwrd_4_idx;
|
||||
u32 emc_pmacro_tx_pwrd_5_idx;
|
||||
u32 emc_config_sample_delay_idx;
|
||||
u32 emc_pmacro_tx_sel_clk_src_0_idx;
|
||||
u32 emc_pmacro_tx_sel_clk_src_1_idx;
|
||||
u32 emc_pmacro_tx_sel_clk_src_2_idx;
|
||||
u32 emc_pmacro_tx_sel_clk_src_3_idx;
|
||||
u32 emc_pmacro_tx_sel_clk_src_4_idx;
|
||||
u32 emc_pmacro_tx_sel_clk_src_5_idx;
|
||||
u32 emc_pmacro_ddll_bypass_idx;
|
||||
u32 emc_pmacro_ddll_pwrd_0_idx;
|
||||
u32 emc_pmacro_ddll_pwrd_1_idx;
|
||||
u32 emc_pmacro_ddll_pwrd_2_idx;
|
||||
u32 emc_pmacro_cmd_ctrl_0_idx;
|
||||
u32 emc_pmacro_cmd_ctrl_1_idx;
|
||||
u32 emc_pmacro_cmd_ctrl_2_idx;
|
||||
u32 emc_tr_timing_0_idx;
|
||||
u32 emc_tr_dvfs_idx;
|
||||
u32 emc_tr_ctrl_1_idx;
|
||||
u32 emc_tr_rdv_idx;
|
||||
u32 emc_tr_qpop_idx;
|
||||
u32 emc_tr_rdv_mask_idx;
|
||||
u32 emc_mrw14_idx;
|
||||
u32 emc_tr_qsafe_idx;
|
||||
u32 emc_tr_qrst_idx;
|
||||
u32 emc_training_ctrl_idx;
|
||||
u32 emc_training_settle_idx;
|
||||
u32 emc_training_vref_settle_idx;
|
||||
u32 emc_training_ca_fine_ctrl_idx;
|
||||
u32 emc_training_ca_ctrl_misc_idx;
|
||||
u32 emc_training_ca_ctrl_misc1_idx;
|
||||
u32 emc_training_ca_vref_ctrl_idx;
|
||||
u32 emc_training_quse_cors_ctrl_idx;
|
||||
u32 emc_training_quse_fine_ctrl_idx;
|
||||
u32 emc_training_quse_ctrl_misc_idx;
|
||||
u32 emc_training_quse_vref_ctrl_idx;
|
||||
u32 emc_training_read_fine_ctrl_idx;
|
||||
u32 emc_training_read_ctrl_misc_idx;
|
||||
u32 emc_training_read_vref_ctrl_idx;
|
||||
u32 emc_training_write_fine_ctrl_idx;
|
||||
u32 emc_training_write_ctrl_misc_idx;
|
||||
u32 emc_training_write_vref_ctrl_idx;
|
||||
u32 emc_training_mpc_idx;
|
||||
u32 emc_mrw15_idx;
|
||||
} burst_regs_t;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 burst_regs[221];
|
||||
u32 burst_reg_per_ch[8];
|
||||
u32 shadow_regs_ca_train[221];
|
||||
u32 shadow_regs_quse_train[221];
|
||||
u32 shadow_regs_rdwr_train[221];
|
||||
} burst_regs_table_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 ptfv_dqsosc_movavg_c0d0u0_idx;
|
||||
u32 ptfv_dqsosc_movavg_c0d0u1_idx;
|
||||
u32 ptfv_dqsosc_movavg_c0d1u0_idx;
|
||||
u32 ptfv_dqsosc_movavg_c0d1u1_idx;
|
||||
u32 ptfv_dqsosc_movavg_c1d0u0_idx;
|
||||
u32 ptfv_dqsosc_movavg_c1d0u1_idx;
|
||||
u32 ptfv_dqsosc_movavg_c1d1u0_idx;
|
||||
u32 ptfv_dqsosc_movavg_c1d1u1_idx;
|
||||
u32 ptfv_write_samples_idx;
|
||||
u32 ptfv_dvfs_samples_idx;
|
||||
u32 ptfv_movavg_weight_idx;
|
||||
u32 ptfv_config_ctrl_idx;
|
||||
} ptfv_list_table_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 emc0_mrw10_idx;
|
||||
u32 emc1_mrw10_idx;
|
||||
u32 emc0_mrw11_idx;
|
||||
u32 emc1_mrw11_idx;
|
||||
u32 emc0_mrw12_idx;
|
||||
u32 emc1_mrw12_idx;
|
||||
u32 emc0_mrw13_idx;
|
||||
u32 emc1_mrw13_idx;
|
||||
} burst_reg_per_ch_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 emc_pmacro_ib_ddll_long_dqs_rank0_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_long_dqs_rank0_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_long_dqs_rank0_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_long_dqs_rank0_3_idx;
|
||||
u32 emc_pmacro_ib_ddll_long_dqs_rank1_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_long_dqs_rank1_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_long_dqs_rank1_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_long_dqs_rank1_3_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte0_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte0_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte0_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte1_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte1_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte1_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte2_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte2_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte2_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte3_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte3_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte3_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte4_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte4_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte4_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte5_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte5_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte5_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte6_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte6_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte6_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte7_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte7_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte7_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte0_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte0_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte0_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte1_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte1_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte1_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte2_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte2_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte2_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte3_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte3_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte3_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte4_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte4_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte4_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte5_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte5_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte5_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte6_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte6_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte6_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte7_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte7_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte7_2_idx;
|
||||
u32 emc_pmacro_ib_vref_dqs_0_idx;
|
||||
u32 emc_pmacro_ib_vref_dqs_1_idx;
|
||||
u32 emc_pmacro_ib_vref_dq_0_idx;
|
||||
u32 emc_pmacro_ib_vref_dq_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dq_rank0_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dq_rank0_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dq_rank0_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dq_rank0_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dq_rank0_4_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dq_rank0_5_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dq_rank1_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dq_rank1_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dq_rank1_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dq_rank1_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_2_idx;
|
||||
u32 emc_pmacro_quse_ddll_rank0_0_idx;
|
||||
u32 emc_pmacro_quse_ddll_rank0_1_idx;
|
||||
u32 emc_pmacro_quse_ddll_rank0_2_idx;
|
||||
u32 emc_pmacro_quse_ddll_rank0_3_idx;
|
||||
u32 emc_pmacro_quse_ddll_rank1_0_idx;
|
||||
u32 emc_pmacro_quse_ddll_rank1_1_idx;
|
||||
u32 emc_pmacro_quse_ddll_rank1_2_idx;
|
||||
u32 emc_pmacro_quse_ddll_rank1_3_idx;
|
||||
} trim_regs_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 emc_cmd_brlshft_0_idx;
|
||||
u32 emc_cmd_brlshft_1_idx;
|
||||
u32 emc0_data_brlshft_0_idx;
|
||||
u32 emc1_data_brlshft_0_idx;
|
||||
u32 emc0_data_brlshft_1_idx;
|
||||
u32 emc1_data_brlshft_1_idx;
|
||||
u32 emc_quse_brlshft_0_idx;
|
||||
u32 emc_quse_brlshft_1_idx;
|
||||
u32 emc_quse_brlshft_2_idx;
|
||||
u32 emc_quse_brlshft_3_idx;
|
||||
} trim_perch_regs_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 t_rp;
|
||||
u32 t_fc_lpddr4;
|
||||
u32 t_rfc;
|
||||
u32 t_pdex;
|
||||
u32 rl;
|
||||
} dram_timings_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 emc0_training_opt_dqs_ib_vref_rank0_idx;
|
||||
u32 emc1_training_opt_dqs_ib_vref_rank0_idx;
|
||||
u32 emc0_training_opt_dqs_ib_vref_rank1_idx;
|
||||
u32 emc1_training_opt_dqs_ib_vref_rank1_idx;
|
||||
} vref_perch_regs_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 trim_regs[138];
|
||||
u32 trim_perch_regs[10];
|
||||
u32 vref_perch_regs[4];
|
||||
} trim_regs_table_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 rev;
|
||||
char dvfs_ver[60];
|
||||
u32 rate_khz;
|
||||
u32 min_volt;
|
||||
u32 gpu_min_volt;
|
||||
char clock_src[32];
|
||||
u32 clk_src_emc;
|
||||
u32 needs_training;
|
||||
u32 training_pattern;
|
||||
u32 trained;
|
||||
u32 periodic_training;
|
||||
u32 trained_dram_clktree_c0d0u0;
|
||||
u32 trained_dram_clktree_c0d0u1;
|
||||
u32 trained_dram_clktree_c0d1u0;
|
||||
u32 trained_dram_clktree_c0d1u1;
|
||||
u32 trained_dram_clktree_c1d0u0;
|
||||
u32 trained_dram_clktree_c1d0u1;
|
||||
u32 trained_dram_clktree_c1d1u0;
|
||||
u32 trained_dram_clktree_c1d1u1;
|
||||
u32 current_dram_clktree_c0d0u0;
|
||||
u32 current_dram_clktree_c0d0u1;
|
||||
u32 current_dram_clktree_c0d1u0;
|
||||
u32 current_dram_clktree_c0d1u1;
|
||||
u32 current_dram_clktree_c1d0u0;
|
||||
u32 current_dram_clktree_c1d0u1;
|
||||
u32 current_dram_clktree_c1d1u0;
|
||||
u32 current_dram_clktree_c1d1u1;
|
||||
u32 run_clocks;
|
||||
u32 tree_margin;
|
||||
u32 num_burst;
|
||||
u32 num_burst_per_ch;
|
||||
u32 num_trim;
|
||||
u32 num_trim_per_ch;
|
||||
u32 num_mc_regs;
|
||||
u32 num_up_down;
|
||||
u32 vref_num;
|
||||
u32 training_mod_num;
|
||||
u32 dram_timing_num;
|
||||
|
||||
ptfv_list_table_t ptfv_list;
|
||||
|
||||
burst_regs_t burst_regs;
|
||||
burst_reg_per_ch_t burst_reg_per_ch;
|
||||
burst_regs_t shadow_regs_ca_train;
|
||||
burst_regs_t shadow_regs_quse_train;
|
||||
burst_regs_t shadow_regs_rdwr_train;
|
||||
trim_regs_t trim_regs;
|
||||
trim_perch_regs_t trim_perch_regs;
|
||||
vref_perch_regs_t vref_perch_regs;
|
||||
dram_timings_t dram_timings;
|
||||
|
||||
u32 training_mod_regs[20];
|
||||
u32 save_restore_mod_regs[12];
|
||||
u32 burst_mc_regs[33];
|
||||
u32 la_scale_regs[24];
|
||||
|
||||
u32 min_mrs_wait;
|
||||
u32 emc_mrw;
|
||||
u32 emc_mrw2;
|
||||
u32 emc_mrw3;
|
||||
u32 emc_mrw4;
|
||||
u32 emc_mrw9;
|
||||
u32 emc_mrs;
|
||||
u32 emc_emrs;
|
||||
u32 emc_emrs2;
|
||||
u32 emc_auto_cal_config;
|
||||
u32 emc_auto_cal_config2;
|
||||
u32 emc_auto_cal_config3;
|
||||
u32 emc_auto_cal_config4;
|
||||
u32 emc_auto_cal_config5;
|
||||
u32 emc_auto_cal_config6;
|
||||
u32 emc_auto_cal_config7;
|
||||
u32 emc_auto_cal_config8;
|
||||
u32 emc_cfg_2;
|
||||
u32 emc_sel_dpd_ctrl;
|
||||
u32 emc_fdpd_ctrl_cmd_no_ramp;
|
||||
u32 dll_clk_src;
|
||||
u32 clk_out_enb_x_0_clk_enb_emc_dll;
|
||||
u32 latency;
|
||||
} emc_table_t;
|
||||
|
||||
#endif
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018 balika011
|
||||
* Copyright (c) 2019 CTCaer
|
||||
* Copyright (c) 2019-2020 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,
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
@@ -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-2020 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,
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
void max77620_low_battery_monitor_config(bool enable)
|
||||
{
|
||||
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 | (enable ? MAX77620_CNFGGLBL1_MPPLD : 0) |
|
||||
MAX77620_CNFGGLBL1_LBHYST_200 | MAX77620_CNFGGLBL1_LBDAC_2800);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -111,6 +113,6 @@ int max77620_regulator_set_voltage(u32 id, u32 mv);
|
||||
int max77620_regulator_enable(u32 id, int enable);
|
||||
int max77620_regulator_set_volt_and_flags(u32 id, u32 mv, u8 flags);
|
||||
void max77620_config_default();
|
||||
void max77620_low_battery_monitor_config();
|
||||
void max77620_low_battery_monitor_config(bool enable);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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,
|
||||
@@ -20,6 +19,7 @@
|
||||
|
||||
#include "../sec/se.h"
|
||||
#include "../mem/heap.h"
|
||||
#include "../soc/bpmp.h"
|
||||
#include "../soc/t210.h"
|
||||
#include "../sec/se_t210.h"
|
||||
#include "../utils/util.h"
|
||||
@@ -36,7 +36,7 @@ static void _gf256_mul_x(void *block)
|
||||
u8 *pdata = (u8 *)block;
|
||||
u32 carry = 0;
|
||||
|
||||
for (u32 i = 0xF; i >= 0; i--)
|
||||
for (int i = 0xF; i >= 0; i--)
|
||||
{
|
||||
u8 b = pdata[i];
|
||||
pdata[i] = (b << 1) | carry;
|
||||
@@ -65,8 +65,8 @@ 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;
|
||||
}
|
||||
@@ -91,10 +91,14 @@ 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)
|
||||
@@ -116,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;
|
||||
}
|
||||
@@ -130,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);
|
||||
}
|
||||
|
||||
@@ -173,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)
|
||||
{
|
||||
@@ -185,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)
|
||||
@@ -270,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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -21,7 +21,9 @@
|
||||
#include "../sec/tsec.h"
|
||||
#include "../sec/tsec_t210.h"
|
||||
#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"
|
||||
@@ -65,15 +67,21 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
|
||||
u32 *pdir, *car, *fuse, *pmc, *flowctrl, *se, *mc, *iram, *evec;
|
||||
u32 *pkg11_magic_off;
|
||||
|
||||
//Enable clocks.
|
||||
bpmp_mmu_disable();
|
||||
bpmp_clk_rate_set(BPMP_CLK_NORMAL);
|
||||
|
||||
// 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) |
|
||||
@@ -95,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
|
||||
@@ -150,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);
|
||||
@@ -170,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;
|
||||
@@ -188,10 +196,11 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
|
||||
{
|
||||
smmu_flush_all();
|
||||
|
||||
if (k == se[SE_KEYTABLE_DATA0_REG_OFFSET / 4])
|
||||
continue;
|
||||
k = se[SE_KEYTABLE_DATA0_REG_OFFSET / 4];
|
||||
key[kidx++] = k;
|
||||
if (k != se[SE_KEYTABLE_DATA0_REG_OFFSET / 4])
|
||||
{
|
||||
k = se[SE_KEYTABLE_DATA0_REG_OFFSET / 4];
|
||||
key[kidx++] = k;
|
||||
}
|
||||
|
||||
// Failsafe.
|
||||
if ((u32)get_tmr_us() - start > 125000)
|
||||
@@ -203,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.
|
||||
@@ -211,20 +220,20 @@ 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++)
|
||||
// gfx_printf(&gfx_con, "key %08X\n", key[i]);
|
||||
// gfx_printf("key %08X\n", key[i]);
|
||||
|
||||
// gfx_printf(&gfx_con, "cpuctl (%08X) mbox (%08X)\n", TSEC(TSEC_CPUCTL), TSEC(TSEC_STATUS));
|
||||
// gfx_printf("cpuctl (%08X) mbox (%08X)\n", TSEC(TSEC_CPUCTL), TSEC(TSEC_STATUS));
|
||||
|
||||
// u32 errst = MC(MC_ERR_STATUS);
|
||||
// gfx_printf(&gfx_con, " MC %08X %08X %08X\n", MC(MC_INTSTATUS), errst, MC(MC_ERR_ADR));
|
||||
// gfx_printf(&gfx_con, " type: %02X\n", errst >> 28);
|
||||
// gfx_printf(&gfx_con, " smmu: %02X\n", (errst >> 25) & 3);
|
||||
// gfx_printf(&gfx_con, " dir: %s\n", (errst >> 16) & 1 ? "W" : "R");
|
||||
// gfx_printf(&gfx_con, " cid: %02x\n", errst & 0xFF);
|
||||
// gfx_printf(" MC %08X %08X %08X\n", MC(MC_INTSTATUS), errst, MC(MC_ERR_ADR));
|
||||
// gfx_printf(" type: %02X\n", errst >> 28);
|
||||
// gfx_printf(" smmu: %02X\n", (errst >> 25) & 3);
|
||||
// gfx_printf(" dir: %s\n", (errst >> 16) & 1 ? "W" : "R");
|
||||
// gfx_printf(" cid: %02x\n", errst & 0xFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -246,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);
|
||||
@@ -266,13 +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_DEFAULT_BOOST);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
308
bootloader/soc/bpmp.c
Normal file
308
bootloader/soc/bpmp.c
Normal file
@@ -0,0 +1,308 @@
|
||||
/*
|
||||
* BPMP-Lite Cache/MMU and Frequency driver for Tegra X1
|
||||
*
|
||||
* Copyright (c) 2019-2020 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/>.
|
||||
*/
|
||||
|
||||
#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_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 BPMP_CACHE_INT_RAW_EVENT 0x48
|
||||
#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_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[] =
|
||||
{
|
||||
{ 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, bool force)
|
||||
{
|
||||
if (!force && !(BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE_CACHE))
|
||||
return;
|
||||
|
||||
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_MAINT_DONE))
|
||||
;
|
||||
|
||||
BPMP_CACHE_CTRL(BPMP_CACHE_INT_CLEAR) = BPMP_CACHE_CTRL(BPMP_CACHE_INT_RAW_EVENT);
|
||||
}
|
||||
|
||||
void bpmp_mmu_set_entry(int idx, bpmp_mmu_entry_t *entry, bool apply)
|
||||
{
|
||||
if (idx > 31)
|
||||
return;
|
||||
|
||||
volatile bpmp_mmu_entry_t *mmu_entry = (bpmp_mmu_entry_t *)(BPMP_MMU_SHADOW_ENTRY_BASE + sizeof(bpmp_mmu_entry_t) * idx);
|
||||
|
||||
if (entry->enable)
|
||||
{
|
||||
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);
|
||||
|
||||
if (apply)
|
||||
BPMP_CACHE_CTRL(BPMP_CACHE_MMU_CMD) = MMU_CMD_COPY_SHADOW;
|
||||
}
|
||||
}
|
||||
|
||||
void bpmp_mmu_enable()
|
||||
{
|
||||
if (BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE_CACHE)
|
||||
return;
|
||||
|
||||
// Init BPMP MMU.
|
||||
BPMP_CACHE_CTRL(BPMP_CACHE_MMU_CMD) = MMU_CMD_INIT;
|
||||
BPMP_CACHE_CTRL(BPMP_CACHE_MMU_FALLBACK_ENTRY) = MMU_EN_READ | MMU_EN_WRITE | MMU_EN_EXEC; // RWX for non-defined regions.
|
||||
BPMP_CACHE_CTRL(BPMP_CACHE_MMU_CFG) = MMU_CFG_SEQ_EN | MMU_CFG_TLB_EN | MMU_CFG_ABORT_STORE_LAST;
|
||||
|
||||
// Init BPMP MMU entries.
|
||||
BPMP_CACHE_CTRL(BPMP_CACHE_MMU_SHADOW_COPY_MASK) = 0;
|
||||
for (u32 idx = 0; idx < (sizeof(mmu_entries) / sizeof(bpmp_mmu_entry_t)); idx++)
|
||||
bpmp_mmu_set_entry(idx, &mmu_entries[idx], false);
|
||||
|
||||
BPMP_CACHE_CTRL(BPMP_CACHE_MMU_CMD) = MMU_CMD_COPY_SHADOW;
|
||||
|
||||
// Invalidate cache.
|
||||
bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, true);
|
||||
|
||||
// Enable cache.
|
||||
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, false);
|
||||
}
|
||||
|
||||
void bpmp_mmu_disable()
|
||||
{
|
||||
if (!(BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE_CACHE))
|
||||
return;
|
||||
|
||||
// Clean and invalidate cache.
|
||||
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false);
|
||||
|
||||
// Disable cache.
|
||||
BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) = 0;
|
||||
}
|
||||
|
||||
// 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_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))
|
||||
fid = BPMP_CLK_MAX - 1;
|
||||
|
||||
if (bpmp_clock_set == fid)
|
||||
return;
|
||||
|
||||
if (fid)
|
||||
{
|
||||
if (bpmp_clock_set)
|
||||
{
|
||||
// Restore to PLLP source during PLLC4 configuration.
|
||||
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003333; // PLLP_OUT.
|
||||
msleep(1); // Wait a bit for clock source change.
|
||||
}
|
||||
|
||||
// Configure and enable PLLC.
|
||||
clock_enable_pllc(pll_divn[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) = 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.
|
||||
|
||||
// Disable PLLC to save power.
|
||||
clock_disable_pllc();
|
||||
}
|
||||
bpmp_clock_set = fid;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
68
bootloader/soc/bpmp.h
Normal file
68
bootloader/soc/bpmp.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* BPMP-Lite Cache/MMU and Frequency driver for Tegra X1
|
||||
*
|
||||
* Copyright (c) 2019-2020 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/>.
|
||||
*/
|
||||
|
||||
#ifndef _BPMP_H_
|
||||
#define _BPMP_H_
|
||||
|
||||
#include "../utils/types.h"
|
||||
|
||||
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 start_addr;
|
||||
u32 end_addr;
|
||||
u32 attr;
|
||||
u32 enable;
|
||||
} bpmp_mmu_entry_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
BPMP_CLK_NORMAL, // 408MHz 0% - 136MHz 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;
|
||||
|
||||
#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
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2020 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,60 +20,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 },
|
||||
/* 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 },
|
||||
/* 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_unk2 = {
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_NO_SOURCE, 0x1E, 0, 0
|
||||
|
||||
static clock_t _clock_tzram = {
|
||||
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)
|
||||
@@ -86,6 +100,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);
|
||||
}
|
||||
@@ -123,9 +139,9 @@ void clock_enable_se()
|
||||
clock_enable(&_clock_se);
|
||||
}
|
||||
|
||||
void clock_enable_unk2()
|
||||
void clock_enable_tzram()
|
||||
{
|
||||
clock_enable(&_clock_unk2);
|
||||
clock_enable(&_clock_tzram);
|
||||
}
|
||||
|
||||
void clock_enable_host1x()
|
||||
@@ -224,6 +240,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)
|
||||
@@ -276,12 +337,16 @@ static void _clock_sdmmc_set_reset(u32 id)
|
||||
{
|
||||
case SDMMC_1:
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = L_SET_SDMMC1_RST;
|
||||
break;
|
||||
case SDMMC_2:
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = L_SET_SDMMC2_RST;
|
||||
break;
|
||||
case SDMMC_3:
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_U_SET) = U_SET_SDMMC3_RST;
|
||||
break;
|
||||
case SDMMC_4:
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = L_SET_SDMMC4_RST;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -291,12 +356,16 @@ static void _clock_sdmmc_clear_reset(u32 id)
|
||||
{
|
||||
case SDMMC_1:
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = L_CLR_SDMMC1_RST;
|
||||
break;
|
||||
case SDMMC_2:
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = L_CLR_SDMMC2_RST;
|
||||
break;
|
||||
case SDMMC_3:
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_U_CLR) = U_CLR_SDMMC3_RST;
|
||||
break;
|
||||
case SDMMC_4:
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = L_CLR_SDMMC4_RST;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -322,12 +391,16 @@ static void _clock_sdmmc_set_enable(u32 id)
|
||||
{
|
||||
case SDMMC_1:
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = L_SET_CLK_ENB_SDMMC1;
|
||||
break;
|
||||
case SDMMC_2:
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = L_SET_CLK_ENB_SDMMC2;
|
||||
break;
|
||||
case SDMMC_3:
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_U_SET) = U_SET_CLK_ENB_SDMMC3;
|
||||
break;
|
||||
case SDMMC_4:
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = L_SET_CLK_ENB_SDMMC4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -337,77 +410,84 @@ static void _clock_sdmmc_clear_enable(u32 id)
|
||||
{
|
||||
case SDMMC_1:
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = L_CLR_CLK_ENB_SDMMC1;
|
||||
break;
|
||||
case SDMMC_2:
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = L_CLR_CLK_ENB_SDMMC2;
|
||||
break;
|
||||
case SDMMC_3:
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_U_CLR) = U_CLR_CLK_ENB_SDMMC3;
|
||||
break;
|
||||
case SDMMC_4:
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = L_CLR_CLK_ENB_SDMMC4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static u32 _clock_sdmmc_table[8] = { 0 };
|
||||
|
||||
static int _clock_sdmmc_config_clock_source_inner(u32 *pout, u32 id, u32 val)
|
||||
#define PLLP_OUT0 0x0
|
||||
static int _clock_sdmmc_config_clock_host(u32 *pout, u32 id, u32 val)
|
||||
{
|
||||
u32 divisor = 0;
|
||||
u32 source = 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:
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC1) = source | divisor;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC1) = (source << 29) | divisor;
|
||||
break;
|
||||
case SDMMC_2:
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC2) = source | divisor;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC2) = (source << 29) | divisor;
|
||||
break;
|
||||
case SDMMC_3:
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC3) = source | divisor;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC3) = (source << 29) | divisor;
|
||||
break;
|
||||
case SDMMC_4:
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC4) = source | divisor;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC4) = (source << 29) | divisor;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -425,15 +505,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:
|
||||
@@ -457,6 +538,7 @@ void clock_sdmmc_get_params(u32 *pout, u16 *pdivisor, u32 type)
|
||||
case 5:
|
||||
*pout = 25000;
|
||||
*pdivisor = 64;
|
||||
break;
|
||||
case 6:
|
||||
case 8:
|
||||
*pout = 25000;
|
||||
@@ -465,9 +547,11 @@ void clock_sdmmc_get_params(u32 *pout, u16 *pdivisor, u32 type)
|
||||
case 7:
|
||||
*pout = 50000;
|
||||
*pdivisor = 1;
|
||||
break;
|
||||
case 10:
|
||||
*pout = 100000;
|
||||
*pdivisor = 1;
|
||||
break;
|
||||
case 13:
|
||||
*pout = 40800;
|
||||
*pdivisor = 1;
|
||||
@@ -491,7 +575,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);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2020 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,12 +36,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 +55,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 +63,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 +103,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
|
||||
@@ -108,16 +120,37 @@
|
||||
#define CLK_RST_CONTROLLER_PLLX_MISC_3 0x518
|
||||
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRE 0x554
|
||||
#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
|
||||
{
|
||||
@@ -139,7 +172,7 @@ void clock_enable_uart(u32 idx);
|
||||
void clock_enable_i2c(u32 idx);
|
||||
void clock_disable_i2c(u32 idx);
|
||||
void clock_enable_se();
|
||||
void clock_enable_unk2();
|
||||
void clock_enable_tzram();
|
||||
void clock_enable_host1x();
|
||||
void clock_disable_host1x();
|
||||
void clock_enable_tsec();
|
||||
@@ -158,9 +191,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);
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018 shuffle2
|
||||
* Copyright (c) 2018 balika011
|
||||
* 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,
|
||||
@@ -61,14 +62,28 @@ u32 fuse_read_odm(u32 idx)
|
||||
|
||||
void fuse_wait_idle()
|
||||
{
|
||||
u32 ctrl;
|
||||
do
|
||||
{
|
||||
ctrl = FUSE(FUSE_CTRL);
|
||||
} while (((ctrl >> 16) & 0x1f) != 4);
|
||||
u32 ctrl;
|
||||
do
|
||||
{
|
||||
ctrl = FUSE(FUSE_CTRL);
|
||||
} while (((ctrl >> 16) & 0x1f) != 4);
|
||||
}
|
||||
|
||||
u32 parity32_even(u32 *words, u32 count)
|
||||
u32 fuse_read(u32 addr)
|
||||
{
|
||||
FUSE(FUSE_ADDR) = addr;
|
||||
FUSE(FUSE_CTRL) = (FUSE(FUSE_ADDR) & ~FUSE_CMD_MASK) | FUSE_READ;
|
||||
fuse_wait_idle();
|
||||
return FUSE(FUSE_RDATA);
|
||||
}
|
||||
|
||||
void fuse_read_array(u32 *words)
|
||||
{
|
||||
for (u32 i = 0; i < 192; i++)
|
||||
words[i] = fuse_read(i);
|
||||
}
|
||||
|
||||
static u32 _parity32_even(u32 *words, u32 count)
|
||||
{
|
||||
u32 acc = words[0];
|
||||
for (u32 i = 1; i < count; i++)
|
||||
@@ -81,14 +96,14 @@ u32 parity32_even(u32 *words, u32 count)
|
||||
lo = ((x & 0xf) ^ (x >> 4)) & 3;
|
||||
hi = ((x & 0xf) ^ (x >> 4)) >> 2;
|
||||
x = hi ^ lo;
|
||||
|
||||
|
||||
return (x & 1) ^ (x >> 1);
|
||||
}
|
||||
|
||||
int patch_hash_one(u32 *word)
|
||||
static int _patch_hash_one(u32 *word)
|
||||
{
|
||||
u32 bits20_31 = *word & 0xfff00000;
|
||||
u32 parity_bit = parity32_even(&bits20_31, 1);
|
||||
u32 parity_bit = _parity32_even(&bits20_31, 1);
|
||||
u32 hash = 0;
|
||||
for (u32 i = 0; i < 12; i++)
|
||||
{
|
||||
@@ -121,9 +136,9 @@ int patch_hash_one(u32 *word)
|
||||
return 2;
|
||||
}
|
||||
|
||||
int patch_hash_multi(u32 *words, u32 count)
|
||||
static int _patch_hash_multi(u32 *words, u32 count)
|
||||
{
|
||||
u32 parity_bit = parity32_even(words, count);
|
||||
u32 parity_bit = _parity32_even(words, count);
|
||||
u32 bits0_14 = words[0] & 0x7fff;
|
||||
u32 bit15 = words[0] & 0x8000;
|
||||
u32 bits16_19 = words[0] & 0xf0000;
|
||||
@@ -193,7 +208,7 @@ int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value))
|
||||
u32 total_read = 0;
|
||||
|
||||
word_count = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE);
|
||||
word_count &= 0x7f;
|
||||
word_count &= 0x7F;
|
||||
word_addr = 191;
|
||||
|
||||
while (word_count)
|
||||
@@ -203,42 +218,37 @@ int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
for (u32 i = 0; i < word_count; i++)
|
||||
{
|
||||
FUSE(FUSE_ADDR) = word_addr--;
|
||||
FUSE(FUSE_CTRL) = (FUSE(FUSE_ADDR) & ~FUSE_CMD_MASK) | FUSE_READ;
|
||||
fuse_wait_idle();
|
||||
words[i] = FUSE(FUSE_RDATA);
|
||||
}
|
||||
|
||||
words[i] = fuse_read(word_addr--);
|
||||
|
||||
word0 = words[0];
|
||||
if (patch_hash_multi(words, word_count) >= 2)
|
||||
if (_patch_hash_multi(words, word_count) >= 2)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
u32 ipatch_count = (words[0] >> 16) & 0xf;
|
||||
u32 ipatch_count = (words[0] >> 16) & 0xF;
|
||||
if (ipatch_count)
|
||||
{
|
||||
for (u32 i = 0; i < ipatch_count; i++)
|
||||
{
|
||||
u32 word = words[i + 1];
|
||||
u32 addr = (word >> 16) * 2;
|
||||
u32 data = word & 0xffff;
|
||||
|
||||
u32 data = word & 0xFFFF;
|
||||
|
||||
ipatch(addr, data);
|
||||
}
|
||||
}
|
||||
words[0] = word0;
|
||||
if ((word0 >> 25) == 0)
|
||||
break;
|
||||
if (patch_hash_one(&word0) >= 2)
|
||||
if (_patch_hash_one(&word0) >= 2)
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
word_count = word0 >> 25;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -255,7 +265,7 @@ int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len)
|
||||
memset(iram_evp_thunks, 0, *iram_evp_thunks_len);
|
||||
|
||||
word_count = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE);
|
||||
word_count &= 0x7f;
|
||||
word_count &= 0x7F;
|
||||
word_addr = 191;
|
||||
|
||||
while (word_count)
|
||||
@@ -265,21 +275,16 @@ int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
for (u32 i = 0; i < word_count; i++)
|
||||
{
|
||||
FUSE(FUSE_ADDR) = word_addr--;
|
||||
FUSE(FUSE_CTRL) = (FUSE(FUSE_ADDR) & ~FUSE_CMD_MASK) | FUSE_READ;
|
||||
fuse_wait_idle();
|
||||
words[i] = FUSE(FUSE_RDATA);
|
||||
}
|
||||
|
||||
words[i] = fuse_read(word_addr--);
|
||||
|
||||
word0 = words[0];
|
||||
if (patch_hash_multi(words, word_count) >= 2)
|
||||
if (_patch_hash_multi(words, word_count) >= 2)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
u32 ipatch_count = (words[0] >> 16) & 0xf;
|
||||
u32 ipatch_count = (words[0] >> 16) & 0xF;
|
||||
u32 insn_count = word_count - ipatch_count - 1;
|
||||
if (insn_count)
|
||||
{
|
||||
@@ -303,23 +308,42 @@ int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len)
|
||||
words[0] = word0;
|
||||
if ((word0 >> 25) == 0)
|
||||
break;
|
||||
if (patch_hash_one(&word0) >= 2)
|
||||
if (_patch_hash_one(&word0) >= 2)
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
word_count = word0 >> 25;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void read_raw_ipatch_fuses(u32 *words)
|
||||
bool fuse_check_patched_rcm()
|
||||
{
|
||||
for (u32 i = 0; i < 0x100; i++)
|
||||
// Check if XUSB in use.
|
||||
if (FUSE(FUSE_RESERVED_SW) & (1<<7))
|
||||
return true;
|
||||
|
||||
// Check if RCM is ipatched.
|
||||
u32 word_count = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE) & 0x7F;
|
||||
u32 word_addr = 191;
|
||||
|
||||
while (word_count)
|
||||
{
|
||||
FUSE(FUSE_ADDR) = i;
|
||||
FUSE(FUSE_CTRL) = (FUSE(FUSE_ADDR) & ~FUSE_CMD_MASK) | FUSE_READ;
|
||||
fuse_wait_idle();
|
||||
words[i] = FUSE(FUSE_RDATA);
|
||||
u32 word0 = fuse_read(word_addr);
|
||||
u32 ipatch_count = (word0 >> 16) & 0xF;
|
||||
|
||||
for (u32 i = 0; i < ipatch_count; i++)
|
||||
{
|
||||
u32 word = fuse_read(word_addr - (i + 1));
|
||||
u32 addr = (word >> 16) * 2;
|
||||
if (addr == 0x769A)
|
||||
return true;
|
||||
}
|
||||
|
||||
word_addr -= word_count;
|
||||
word_count = word0 >> 25;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -37,11 +37,32 @@
|
||||
#define FUSE_WRITE_ACCESS_SW 0x30
|
||||
#define FUSE_PWR_GOOD_SW 0x34
|
||||
#define FUSE_SKU_INFO 0x110
|
||||
#define FUSE_CPU_SPEEDO_0_CALIB 0x114
|
||||
#define FUSE_CPU_IDDQ_CALIB 0x118
|
||||
#define FUSE_OPT_FT_REV 0x128
|
||||
#define FUSE_CPU_SPEEDO_1_CALIB 0x12C
|
||||
#define FUSE_CPU_SPEEDO_2_CALIB 0x130
|
||||
#define FUSE_SOC_SPEEDO_0_CALIB 0x134
|
||||
#define FUSE_SOC_SPEEDO_1_CALIB 0x138
|
||||
#define FUSE_SOC_SPEEDO_2_CALIB 0x13C
|
||||
#define FUSE_SOC_IDDQ_CALIB 0x140
|
||||
#define FUSE_OPT_CP_REV 0x190
|
||||
#define FUSE_FIRST_BOOTROM_PATCH_SIZE 0x19c
|
||||
#define FUSE_PRIVATE_KEY0 0x1A4
|
||||
#define FUSE_PRIVATE_KEY1 0x1A8
|
||||
#define FUSE_PRIVATE_KEY2 0x1AC
|
||||
#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
|
||||
#define FUSE_OPT_LOT_CODE_1 0x20C
|
||||
#define FUSE_OPT_WAFER_ID 0x210
|
||||
#define FUSE_OPT_X_COORDINATE 0x214
|
||||
#define FUSE_OPT_Y_COORDINATE 0x218
|
||||
#define FUSE_GPU_IDDQ_CALIB 0x228
|
||||
|
||||
/*! Fuse commands. */
|
||||
#define FUSE_READ 0x1
|
||||
@@ -57,6 +78,7 @@ u32 fuse_read_odm(u32 idx);
|
||||
void fuse_wait_idle();
|
||||
int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value));
|
||||
int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len);
|
||||
void read_raw_ipatch_fuses(u32 *words);
|
||||
void fuse_read_array(u32 *words);
|
||||
bool fuse_check_patched_rcm();
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2019 CTCaer
|
||||
* Copyright (c) 2018-2020 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,43 +18,60 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "hw_init.h"
|
||||
#include "bpmp.h"
|
||||
#include "clock.h"
|
||||
#include "fuse.h"
|
||||
#include "gpio.h"
|
||||
#include "i2c.h"
|
||||
#include "pinmux.h"
|
||||
#include "pmc.h"
|
||||
#include "t210.h"
|
||||
#include "uart.h"
|
||||
#include "../gfx/di.h"
|
||||
#include "../mem/mc.h"
|
||||
#include "../mem/minerva.h"
|
||||
#include "../mem/sdram.h"
|
||||
#include "../power/max77620.h"
|
||||
#include "../power/max7762x.h"
|
||||
#include "../sec/se.h"
|
||||
#include "../sec/se_t210.h"
|
||||
#include "../soc/clock.h"
|
||||
#include "../soc/fuse.h"
|
||||
#include "../soc/gpio.h"
|
||||
#include "../soc/i2c.h"
|
||||
#include "../soc/pinmux.h"
|
||||
#include "../soc/pmc.h"
|
||||
#include "../soc/t210.h"
|
||||
#include "../soc/uart.h"
|
||||
#include "../storage/sdmmc.h"
|
||||
#include "../utils/util.h"
|
||||
|
||||
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()
|
||||
@@ -62,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);
|
||||
@@ -87,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;
|
||||
@@ -118,39 +149,51 @@ 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()
|
||||
{
|
||||
// Enable fuse clock.
|
||||
clock_enable_fuse(true);
|
||||
|
||||
// Skip SBK/SSK if sept was run.
|
||||
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),
|
||||
@@ -177,19 +220,72 @@ 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()
|
||||
{
|
||||
// Disable low battery shutdown monitor.
|
||||
max77620_low_battery_monitor_config(false);
|
||||
|
||||
// Disable SDMMC1 IO power.
|
||||
gpio_output_enable(GPIO_PORT_E, GPIO_PIN_4, GPIO_OUTPUT_DISABLE);
|
||||
max77620_regulator_enable(REGULATOR_LDO2, 0);
|
||||
sd_power_cycle_time_start = get_tmr_ms();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
@@ -209,48 +305,33 @@ void config_hw()
|
||||
clock_enable_i2c(I2C_1);
|
||||
clock_enable_i2c(I2C_5);
|
||||
|
||||
clock_enable_unk2();
|
||||
clock_enable_tzram();
|
||||
|
||||
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);
|
||||
_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();
|
||||
|
||||
bpmp_mmu_enable();
|
||||
}
|
||||
|
||||
void reconfig_hw_workaround(bool extra_reconfig, u32 magic)
|
||||
{
|
||||
// Flush and disable MMU.
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2020 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 +20,7 @@
|
||||
#include "i2c.h"
|
||||
#include "../utils/util.h"
|
||||
|
||||
static u32 i2c_addrs[] = {
|
||||
static const u32 i2c_addrs[] = {
|
||||
0x7000C000, 0x7000C400, 0x7000C500,
|
||||
0x7000C700, 0x7000D000, 0x7000D100
|
||||
};
|
||||
@@ -44,10 +45,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 +66,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)
|
||||
@@ -121,6 +122,11 @@ int i2c_send_buf_small(u32 idx, u32 x, u32 y, u8 *buf, u32 size)
|
||||
return _i2c_send_pkt(idx, x, tmp, size + 1);
|
||||
}
|
||||
|
||||
int i2c_recv_buf(u8 *buf, u32 size, u32 idx, u32 x)
|
||||
{
|
||||
return _i2c_recv_pkt(idx, buf, size, x);
|
||||
}
|
||||
|
||||
int i2c_recv_buf_small(u8 *buf, u32 size, u32 idx, u32 x, u32 y)
|
||||
{
|
||||
int res = _i2c_send_pkt(idx, x, (u8 *)&y, 1);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2020 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,
|
||||
@@ -39,6 +40,7 @@
|
||||
|
||||
void i2c_init(u32 idx);
|
||||
int i2c_send_buf_small(u32 idx, u32 x, u32 y, u8 *buf, u32 size);
|
||||
int i2c_recv_buf(u8 *buf, u32 size, u32 idx, u32 x);
|
||||
int i2c_recv_buf_small(u8 *buf, u32 size, u32 idx, u32 x, u32 y);
|
||||
int i2c_send_byte(u32 idx, u32 x, u32 y, u8 b);
|
||||
u8 i2c_recv_byte(u32 idx, u32 x, u32 y);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
|
||||
#define KFUSE_NUM_WORDS 144
|
||||
|
||||
int kfuse_wait_ready();
|
||||
int kfuse_read(u32 *buf);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -26,31 +26,50 @@
|
||||
#define APB_MISC_GP_VGPIO_GPIO_MUX_SEL 0xB74
|
||||
|
||||
/*! Pinmux registers. */
|
||||
#define PINMUX_AUX_SDMMC1_CLK 0x00
|
||||
#define PINMUX_AUX_SDMMC1_CMD 0x04
|
||||
#define PINMUX_AUX_SDMMC1_DAT3 0x08
|
||||
#define PINMUX_AUX_SDMMC1_DAT2 0x0C
|
||||
#define PINMUX_AUX_SDMMC1_DAT1 0x10
|
||||
#define PINMUX_AUX_SDMMC1_DAT0 0x14
|
||||
#define PINMUX_AUX_SDMMC3_CLK 0x1C
|
||||
#define PINMUX_AUX_SDMMC3_CMD 0x20
|
||||
#define PINMUX_AUX_SDMMC3_DAT0 0x24
|
||||
#define PINMUX_AUX_SDMMC3_DAT1 0x28
|
||||
#define PINMUX_AUX_SDMMC3_DAT2 0x2C
|
||||
#define PINMUX_AUX_SDMMC3_DAT3 0x30
|
||||
#define PINMUX_AUX_DMIC3_CLK 0xB4
|
||||
#define PINMUX_AUX_UART2_TX 0xF4
|
||||
#define PINMUX_AUX_UART3_TX 0x104
|
||||
#define PINMUX_AUX_WIFI_EN 0x1B4
|
||||
#define PINMUX_AUX_WIFI_RST 0x1B8
|
||||
#define PINMUX_AUX_NFC_EN 0x1D0
|
||||
#define PINMUX_AUX_NFC_INT 0x1D4
|
||||
#define PINMUX_AUX_LCD_BL_PWM 0x1FC
|
||||
#define PINMUX_AUX_LCD_BL_EN 0x200
|
||||
#define PINMUX_AUX_LCD_RST 0x204
|
||||
#define PINMUX_AUX_GPIO_PE6 0x248
|
||||
#define PINMUX_AUX_GPIO_PH6 0x250
|
||||
#define PINMUX_AUX_GPIO_PZ1 0x280
|
||||
#define PINMUX_AUX_SDMMC1_CLK 0x00
|
||||
#define PINMUX_AUX_SDMMC1_CMD 0x04
|
||||
#define PINMUX_AUX_SDMMC1_DAT3 0x08
|
||||
#define PINMUX_AUX_SDMMC1_DAT2 0x0C
|
||||
#define PINMUX_AUX_SDMMC1_DAT1 0x10
|
||||
#define PINMUX_AUX_SDMMC1_DAT0 0x14
|
||||
#define PINMUX_AUX_SDMMC3_CLK 0x1C
|
||||
#define PINMUX_AUX_SDMMC3_CMD 0x20
|
||||
#define PINMUX_AUX_SDMMC3_DAT0 0x24
|
||||
#define PINMUX_AUX_SDMMC3_DAT1 0x28
|
||||
#define PINMUX_AUX_SDMMC3_DAT2 0x2C
|
||||
#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
|
||||
#define PINMUX_AUX_GPIO_PZ1 0x280
|
||||
/*! 0:UART-A, 1:UART-B, 3:UART-C, 3:UART-D */
|
||||
#define PINMUX_AUX_UARTX_TX(x) (0xE4 + 0x10 * (x))
|
||||
#define PINMUX_AUX_UARTX_RX(x) (0xE8 + 0x10 * (x))
|
||||
@@ -78,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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "../utils/types.h"
|
||||
|
||||
#define BOOTROM_BASE 0x100000
|
||||
#define IRAM_BASE 0x40000000
|
||||
#define HOST1X_BASE 0x50000000
|
||||
#define BPMP_CACHE_BASE 0x50040000
|
||||
#define DISPLAY_A_BASE 0x54200000
|
||||
@@ -100,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
|
||||
|
||||
@@ -118,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. */
|
||||
@@ -145,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. */
|
||||
@@ -179,9 +198,34 @@
|
||||
#define I2S_CG_SLCG_ENABLE (1 << 0)
|
||||
#define I2S_CTRL_MASTER_EN (1 << 10)
|
||||
|
||||
/*! 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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
261
bootloader/storage/emummc.c
Normal file
261
bootloader/storage/emummc.c
Normal file
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
* 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,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "emummc.h"
|
||||
#include "sdmmc.h"
|
||||
#include "../config/config.h"
|
||||
#include "../config/ini.h"
|
||||
#include "../gfx/gfx.h"
|
||||
#include "../libs/fatfs/ff.h"
|
||||
#include "../mem/heap.h"
|
||||
#include "../utils/list.h"
|
||||
#include "../utils/types.h"
|
||||
|
||||
extern sdmmc_t sd_sdmmc;
|
||||
extern sdmmc_storage_t sd_storage;
|
||||
extern FATFS sd_fs;
|
||||
|
||||
extern hekate_config h_cfg;
|
||||
|
||||
extern bool sd_mount();
|
||||
extern void sd_unmount();
|
||||
|
||||
void emummc_load_cfg()
|
||||
{
|
||||
sd_mount();
|
||||
emu_cfg.enabled = 0;
|
||||
emu_cfg.path = NULL;
|
||||
emu_cfg.nintendo_path = NULL;
|
||||
emu_cfg.sector = 0;
|
||||
emu_cfg.id = 0;
|
||||
emu_cfg.file_based_part_size = 0;
|
||||
emu_cfg.active_part = 0;
|
||||
emu_cfg.fs_ver = 0;
|
||||
emu_cfg.emummc_file_based_path = (char *)malloc(0x80);
|
||||
|
||||
LIST_INIT(ini_sections);
|
||||
if (ini_parse(&ini_sections, "emuMMC/emummc.ini", false))
|
||||
{
|
||||
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link)
|
||||
{
|
||||
if (ini_sec->type == INI_CHOICE)
|
||||
{
|
||||
if (strcmp(ini_sec->name, "emummc"))
|
||||
continue;
|
||||
|
||||
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)
|
||||
{
|
||||
if (!strcmp("enabled", kv->key))
|
||||
emu_cfg.enabled = atoi(kv->val);
|
||||
else if (!strcmp("sector", kv->key))
|
||||
emu_cfg.sector = strtol(kv->val, NULL, 16);
|
||||
else if (!strcmp("id", kv->key))
|
||||
emu_cfg.id = strtol(kv->val, NULL, 16);
|
||||
else if (!strcmp("path", kv->key))
|
||||
emu_cfg.path = kv->val;
|
||||
else if (!strcmp("nintendo_path", kv->key))
|
||||
emu_cfg.nintendo_path = kv->val;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int emummc_raw_get_part_off(int part_idx)
|
||||
{
|
||||
switch (part_idx)
|
||||
{
|
||||
case 0:
|
||||
return 2;
|
||||
case 1:
|
||||
return 0;
|
||||
case 2:
|
||||
return 1;
|
||||
}
|
||||
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))
|
||||
return 2;
|
||||
|
||||
if (h_cfg.emummc_force_disable)
|
||||
return 0;
|
||||
|
||||
emu_cfg.active_part = 0;
|
||||
if (!sd_mount())
|
||||
goto out;
|
||||
|
||||
if (emu_cfg.enabled && !emu_cfg.sector)
|
||||
{
|
||||
strcpy(emu_cfg.emummc_file_based_path, emu_cfg.path);
|
||||
strcat(emu_cfg.emummc_file_based_path, "/eMMC");
|
||||
|
||||
if (f_stat(emu_cfg.emummc_file_based_path, &fno))
|
||||
{
|
||||
EPRINTF("Failed to open eMMC folder.");
|
||||
goto out;
|
||||
}
|
||||
f_chmod(emu_cfg.emummc_file_based_path, AM_ARC, AM_ARC);
|
||||
|
||||
strcat(emu_cfg.emummc_file_based_path, "/00");
|
||||
if (f_stat(emu_cfg.emummc_file_based_path, &fno))
|
||||
{
|
||||
EPRINTF("Failed to open emuMMC rawnand.");
|
||||
goto out;
|
||||
}
|
||||
emu_cfg.file_based_part_size = fno.fsize >> 9;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
return 1;
|
||||
}
|
||||
|
||||
int emummc_storage_end(sdmmc_storage_t *storage)
|
||||
{
|
||||
sd_unmount();
|
||||
sdmmc_storage_end(storage);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int emummc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf)
|
||||
{
|
||||
FIL fp;
|
||||
if (!emu_cfg.enabled || h_cfg.emummc_force_disable)
|
||||
return sdmmc_storage_read(storage, sector, num_sectors, buf);
|
||||
else if (emu_cfg.sector)
|
||||
{
|
||||
sector += emu_cfg.sector;
|
||||
sector += emummc_raw_get_part_off(emu_cfg.active_part) * 0x2000;
|
||||
return sdmmc_storage_read(&sd_storage, sector, num_sectors, buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!emu_cfg.active_part)
|
||||
{
|
||||
u32 file_part = sector / emu_cfg.file_based_part_size;
|
||||
sector = sector % emu_cfg.file_based_part_size;
|
||||
if (file_part >= 10)
|
||||
itoa(file_part, emu_cfg.emummc_file_based_path + strlen(emu_cfg.emummc_file_based_path) - 2, 10);
|
||||
else
|
||||
{
|
||||
emu_cfg.emummc_file_based_path[strlen(emu_cfg.emummc_file_based_path) - 2] = '0';
|
||||
itoa(file_part, emu_cfg.emummc_file_based_path + strlen(emu_cfg.emummc_file_based_path) - 1, 10);
|
||||
}
|
||||
}
|
||||
if (f_open(&fp, emu_cfg.emummc_file_based_path, FA_READ))
|
||||
{
|
||||
EPRINTF("Failed to open emuMMC image.");
|
||||
return 0;
|
||||
}
|
||||
f_lseek(&fp, (u64)sector << 9);
|
||||
if (f_read(&fp, buf, (u64)num_sectors << 9, NULL))
|
||||
{
|
||||
EPRINTF("Failed to read emuMMC image.");
|
||||
f_close(&fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
f_close(&fp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int emummc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf)
|
||||
{
|
||||
FIL fp;
|
||||
if (!emu_cfg.enabled || h_cfg.emummc_force_disable)
|
||||
return sdmmc_storage_write(storage, sector, num_sectors, buf);
|
||||
else if (emu_cfg.sector)
|
||||
{
|
||||
sector += emu_cfg.sector;
|
||||
sector += emummc_raw_get_part_off(emu_cfg.active_part) * 0x2000;
|
||||
return sdmmc_storage_write(&sd_storage, sector, num_sectors, buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!emu_cfg.active_part)
|
||||
{
|
||||
u32 file_part = sector / emu_cfg.file_based_part_size;
|
||||
sector = sector % emu_cfg.file_based_part_size;
|
||||
if (file_part >= 10)
|
||||
itoa(file_part, emu_cfg.emummc_file_based_path + strlen(emu_cfg.emummc_file_based_path) - 2, 10);
|
||||
else
|
||||
{
|
||||
emu_cfg.emummc_file_based_path[strlen(emu_cfg.emummc_file_based_path) - 2] = '0';
|
||||
itoa(file_part, emu_cfg.emummc_file_based_path + strlen(emu_cfg.emummc_file_based_path) - 1, 10);
|
||||
}
|
||||
}
|
||||
if (f_open(&fp, emu_cfg.emummc_file_based_path, FA_WRITE))
|
||||
{
|
||||
gfx_printf("e5\n");
|
||||
return 0;
|
||||
}
|
||||
f_lseek(&fp, (u64)sector << 9);
|
||||
if (f_write(&fp, buf, (u64)num_sectors << 9, NULL))
|
||||
{
|
||||
gfx_printf("e6\n");
|
||||
f_close(&fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
f_close(&fp);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int emummc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition)
|
||||
{
|
||||
emu_cfg.active_part = partition;
|
||||
|
||||
if (!emu_cfg.enabled || h_cfg.emummc_force_disable)
|
||||
sdmmc_storage_set_mmc_partition(storage, partition);
|
||||
else if (emu_cfg.sector)
|
||||
return 1;
|
||||
else
|
||||
{
|
||||
strcpy(emu_cfg.emummc_file_based_path, emu_cfg.path);
|
||||
strcat(emu_cfg.emummc_file_based_path, "/eMMC");
|
||||
|
||||
switch (partition)
|
||||
{
|
||||
case 0:
|
||||
strcat(emu_cfg.emummc_file_based_path, "/00");
|
||||
break;
|
||||
case 1:
|
||||
strcat(emu_cfg.emummc_file_based_path, "/BOOT0");
|
||||
break;
|
||||
case 2:
|
||||
strcat(emu_cfg.emummc_file_based_path, "/BOOT1");
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
59
bootloader/storage/emummc.h
Normal file
59
bootloader/storage/emummc.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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,
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef EMUMMC_H
|
||||
#define EMUMMC_H
|
||||
|
||||
#include "sdmmc.h"
|
||||
#include "../utils/types.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
EMUMMC_TYPE_NONE = 0,
|
||||
EMUMMC_TYPE_PARTITION = 1,
|
||||
EMUMMC_TYPE_FILES = 2,
|
||||
} emummc_type_t;
|
||||
|
||||
typedef enum {
|
||||
EMUMMC_MMC_NAND = 0,
|
||||
EMUMMC_MMC_SD = 1,
|
||||
EMUMMC_MMC_GC = 2,
|
||||
} emummc_mmc_t;
|
||||
|
||||
typedef struct _emummc_cfg_t
|
||||
{
|
||||
int enabled;
|
||||
u64 sector;
|
||||
u16 id;
|
||||
char *path;
|
||||
char *nintendo_path;
|
||||
// Internal.
|
||||
char *emummc_file_based_path;
|
||||
u32 file_based_part_size;
|
||||
u32 active_part;
|
||||
int fs_ver;
|
||||
} emummc_cfg_t;
|
||||
|
||||
emummc_cfg_t emu_cfg;
|
||||
|
||||
void emummc_load_cfg();
|
||||
int emummc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc);
|
||||
int emummc_storage_end(sdmmc_storage_t *storage);
|
||||
int emummc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf);
|
||||
int emummc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf);
|
||||
int emummc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition);
|
||||
|
||||
#endif
|
||||
@@ -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 */
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "nx_emmc.h"
|
||||
#include "emummc.h"
|
||||
#include "../mem/heap.h"
|
||||
#include "../utils/list.h"
|
||||
|
||||
@@ -24,18 +25,18 @@ void nx_emmc_gpt_parse(link_t *gpt, sdmmc_storage_t *storage)
|
||||
{
|
||||
u8 *buf = (u8 *)malloc(NX_GPT_NUM_BLOCKS * NX_EMMC_BLOCKSIZE);
|
||||
|
||||
sdmmc_storage_read(storage, NX_GPT_FIRST_LBA, NX_GPT_NUM_BLOCKS, buf);
|
||||
emummc_storage_read(storage, NX_GPT_FIRST_LBA, NX_GPT_NUM_BLOCKS, buf);
|
||||
|
||||
gpt_header_t *hdr = (gpt_header_t *)buf;
|
||||
for (u32 i = 0; i < hdr->num_part_ents; i++)
|
||||
{
|
||||
gpt_entry_t *ent = (gpt_entry_t *)(buf + (hdr->part_ent_lba - 1) * NX_EMMC_BLOCKSIZE + i * sizeof(gpt_entry_t));
|
||||
emmc_part_t *part = (emmc_part_t *)malloc(sizeof(emmc_part_t));
|
||||
emmc_part_t *part = (emmc_part_t *)calloc(sizeof(emmc_part_t), 1);
|
||||
part->lba_start = ent->lba_start;
|
||||
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;
|
||||
@@ -65,7 +66,7 @@ int nx_emmc_part_read(sdmmc_storage_t *storage, emmc_part_t *part, u32 sector_of
|
||||
// The last LBA is inclusive.
|
||||
if (part->lba_start + sector_off > part->lba_end)
|
||||
return 0;
|
||||
return sdmmc_storage_read(storage, part->lba_start + sector_off, num_sectors, buf);
|
||||
return emummc_storage_read(storage, part->lba_start + sector_off, num_sectors, buf);
|
||||
}
|
||||
|
||||
int nx_emmc_part_write(sdmmc_storage_t *storage, emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf)
|
||||
|
||||
@@ -59,7 +59,7 @@ typedef struct _emmc_part_t
|
||||
u32 lba_start;
|
||||
u32 lba_end;
|
||||
u64 attrs;
|
||||
s8 name[37];
|
||||
char name[37];
|
||||
link_t link;
|
||||
} emmc_part_t;
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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,11 +19,12 @@
|
||||
#include "sdmmc.h"
|
||||
#include "mmc.h"
|
||||
#include "sd.h"
|
||||
#include "../../common/memory_map.h"
|
||||
#include "../gfx/gfx.h"
|
||||
#include "../mem/heap.h"
|
||||
#include "../utils/util.h"
|
||||
|
||||
//#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__)
|
||||
//#define DPRINTF(...) gfx_printf(__VA_ARGS__)
|
||||
#define DPRINTF(...)
|
||||
|
||||
static inline u32 unstuff_bits(u32 *resp, u32 start, u32 size)
|
||||
@@ -69,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;
|
||||
}
|
||||
|
||||
@@ -82,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);
|
||||
}
|
||||
|
||||
@@ -91,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;
|
||||
}
|
||||
|
||||
@@ -106,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;
|
||||
}
|
||||
|
||||
@@ -144,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;
|
||||
}
|
||||
|
||||
@@ -153,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;
|
||||
}
|
||||
|
||||
@@ -175,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;
|
||||
}
|
||||
|
||||
@@ -208,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;
|
||||
@@ -233,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);
|
||||
}
|
||||
|
||||
@@ -370,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;
|
||||
}
|
||||
|
||||
@@ -380,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;
|
||||
}
|
||||
|
||||
@@ -395,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);
|
||||
}
|
||||
|
||||
@@ -408,30 +434,36 @@ 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);
|
||||
}
|
||||
|
||||
static int _mmc_storage_enable_highspeed(sdmmc_storage_t *storage, u32 card_type, u32 type)
|
||||
{
|
||||
//TODO: this should be a config item.
|
||||
//---v
|
||||
// --v
|
||||
if (!1 || sdmmc_get_voltage(storage->sdmmc) != SDMMC_POWER_1_8)
|
||||
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 ||
|
||||
@@ -443,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;
|
||||
}
|
||||
|
||||
@@ -450,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);
|
||||
}
|
||||
|
||||
@@ -461,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.
|
||||
@@ -508,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))
|
||||
@@ -517,9 +551,9 @@ 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(&gfx_con, 0, ext_csd, 512);
|
||||
//gfx_hexdump(0, ext_csd, 512);
|
||||
|
||||
/* When auto BKOPS is enabled the mmc device should be powered all the time until we disable this and check status.
|
||||
Disable it for now until BKOPS disable added to power down sequence at sdmmc_storage_end().
|
||||
@@ -527,14 +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);
|
||||
|
||||
@@ -545,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;
|
||||
}
|
||||
@@ -560,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);
|
||||
}
|
||||
|
||||
@@ -567,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);
|
||||
}
|
||||
|
||||
@@ -598,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);
|
||||
}
|
||||
|
||||
@@ -625,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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -704,7 +745,7 @@ int _sd_storage_get_scr(sdmmc_storage_t *storage, u8 *buf)
|
||||
|
||||
u32 tmp = 0;
|
||||
sdmmc_get_rsp(storage->sdmmc, &tmp, 4, SDMMC_RSP_TYPE_1);
|
||||
//Prepare buffer for unstuff_bits
|
||||
//Prepare buffer for unstuff_bits
|
||||
for (int i = 0; i < 8; i+=4)
|
||||
{
|
||||
storage->raw_scr[i + 3] = buf[i];
|
||||
@@ -713,7 +754,7 @@ int _sd_storage_get_scr(sdmmc_storage_t *storage, u8 *buf)
|
||||
storage->raw_scr[i] = buf[i + 3];
|
||||
}
|
||||
_sd_storage_parse_scr(storage);
|
||||
//gfx_hexdump(&gfx_con, 0, storage->raw_scr, 8);
|
||||
//gfx_hexdump(0, storage->raw_scr, 8);
|
||||
|
||||
return _sdmmc_storage_check_result(tmp);
|
||||
}
|
||||
@@ -779,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;
|
||||
}
|
||||
}
|
||||
@@ -798,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)
|
||||
{
|
||||
@@ -815,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);
|
||||
@@ -825,36 +868,36 @@ int _sd_storage_enable_highspeed_low_volt(sdmmc_storage_t *storage, u32 type, u8
|
||||
|
||||
if (!_sd_storage_switch_get(storage, buf))
|
||||
return 0;
|
||||
//gfx_hexdump(&gfx_con, 0, (u8 *)buf, 64);
|
||||
//gfx_hexdump(0, (u8 *)buf, 64);
|
||||
|
||||
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;
|
||||
}
|
||||
//Fall through.
|
||||
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:
|
||||
@@ -864,25 +907,30 @@ 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;
|
||||
//gfx_hexdump(&gfx_con, 0, (u8 *)buf, 64);
|
||||
if (!(buf[13] & 2))
|
||||
//gfx_hexdump(0, (u8 *)buf, 64);
|
||||
if (!(buf[13] & SD_MODE_HIGH_SPEED))
|
||||
return 1;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -945,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;
|
||||
}
|
||||
|
||||
@@ -963,7 +1011,7 @@ static int _sd_storage_get_ssr(sdmmc_storage_t *storage, u8 *buf)
|
||||
storage->raw_ssr[i] = buf[i + 3];
|
||||
}
|
||||
_sd_storage_parse_ssr(storage);
|
||||
//gfx_hexdump(&gfx_con, 0, storage->raw_ssr, 64);
|
||||
//gfx_hexdump(0, storage->raw_ssr, 64);
|
||||
|
||||
return _sdmmc_storage_check_result(tmp);
|
||||
}
|
||||
@@ -1007,44 +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;
|
||||
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);
|
||||
@@ -1057,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;
|
||||
}
|
||||
|
||||
@@ -1065,63 +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(&gfx_con, 0, storage->raw_scr, 8);
|
||||
DPRINTF("[SD] got scr\n");
|
||||
|
||||
//gfx_hexdump(0, storage->raw_scr, 8);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1129,9 +1179,10 @@ 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;
|
||||
}
|
||||
|
||||
@@ -1173,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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -47,7 +49,7 @@ typedef struct _mmc_csd
|
||||
u32 read_blkbits;
|
||||
u32 write_blkbits;
|
||||
u32 capacity;
|
||||
u8 write_protect;
|
||||
u8 write_protect;
|
||||
u16 busspeed;
|
||||
} mmc_csd_t;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "sdmmc.h"
|
||||
#include "../gfx/gfx.h"
|
||||
#include "../power/max7762x.h"
|
||||
#include "../soc/bpmp.h"
|
||||
#include "../soc/clock.h"
|
||||
#include "../soc/gpio.h"
|
||||
#include "../soc/pinmux.h"
|
||||
@@ -28,7 +29,7 @@
|
||||
#include "../soc/t210.h"
|
||||
#include "../utils/util.h"
|
||||
|
||||
//#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__)
|
||||
//#define DPRINTF(...) gfx_printf(__VA_ARGS__)
|
||||
#define DPRINTF(...)
|
||||
|
||||
/*! SCMMC controller base addresses. */
|
||||
@@ -116,11 +117,12 @@ static int _sdmmc_config_ven_ceata_clk(sdmmc_t *sdmmc, u32 id)
|
||||
|
||||
if (id == 4)
|
||||
sdmmc->regs->venceatactl = (sdmmc->regs->venceatactl & 0xFFFFC0FF) | 0x2800;
|
||||
sdmmc->regs->field_1C0 &= 0xFFFDFFFF;
|
||||
sdmmc->regs->ventunctl0 &= 0xFFFDFFFF;
|
||||
if (id == 4)
|
||||
{
|
||||
if (!sdmmc->venclkctl_set)
|
||||
return 0;
|
||||
|
||||
tap_val = sdmmc->venclkctl_tap;
|
||||
}
|
||||
else
|
||||
@@ -168,11 +170,11 @@ static int _sdmmc_wait_type4(sdmmc_t *sdmmc)
|
||||
sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
}
|
||||
|
||||
sdmmc->regs->field_1B0 |= 0x80000000;
|
||||
sdmmc->regs->vendllcal |= 0x80000000;
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
|
||||
u32 timeout = get_tmr_ms() + 5;
|
||||
while (sdmmc->regs->field_1B0 & 0x80000000)
|
||||
while (sdmmc->regs->vendllcal & 0x80000000)
|
||||
{
|
||||
if (get_tmr_ms() > timeout)
|
||||
{
|
||||
@@ -182,7 +184,7 @@ static int _sdmmc_wait_type4(sdmmc_t *sdmmc)
|
||||
}
|
||||
|
||||
timeout = get_tmr_ms() + 10;
|
||||
while (sdmmc->regs->field_1BC & 0x80000000)
|
||||
while (sdmmc->regs->dllcfgstatus & 0x80000000)
|
||||
{
|
||||
if (get_tmr_ms() > timeout)
|
||||
{
|
||||
@@ -199,7 +201,7 @@ out:;
|
||||
|
||||
int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type)
|
||||
{
|
||||
//Disable the SD clock if it was enabled, and reenable it later.
|
||||
// Disable the SD clock if it was enabled, and reenable it later.
|
||||
bool should_enable_sd_clock = false;
|
||||
if (sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE)
|
||||
{
|
||||
@@ -215,7 +217,7 @@ int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type)
|
||||
case 1:
|
||||
case 5:
|
||||
case 6:
|
||||
sdmmc->regs->hostctl &= 0xFB; //Should this be 0xFFFB (~4) ?
|
||||
sdmmc->regs->hostctl &= 0xFB; // Should this be 0xFFFB (~4) ?
|
||||
sdmmc->regs->hostctl2 &= SDHCI_CTRL_VDD_330;
|
||||
break;
|
||||
case 2:
|
||||
@@ -231,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;
|
||||
@@ -240,7 +242,7 @@ int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type)
|
||||
sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180;
|
||||
break;
|
||||
case 10:
|
||||
//T210 Errata for SDR50, the host must be set to SDR104.
|
||||
// T210 Errata for SDR50, the host must be set to SDR104.
|
||||
sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | UHS_SDR104_BUS_SPEED;
|
||||
sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180;
|
||||
break;
|
||||
@@ -250,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;
|
||||
|
||||
@@ -262,7 +264,7 @@ int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type)
|
||||
divisor = div >> 8;
|
||||
sdmmc->regs->clkcon = (sdmmc->regs->clkcon & 0x3F) | (div << 8) | (divisor << 6);
|
||||
|
||||
//Enable the SD clock again.
|
||||
// Enable the SD clock again.
|
||||
if (should_enable_sd_clock)
|
||||
sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
|
||||
@@ -396,7 +398,7 @@ static int _sdmmc_wait_prnsts_type0(sdmmc_t *sdmmc, u32 wait_dat)
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
|
||||
u32 timeout = get_tmr_ms() + 2000;
|
||||
while(sdmmc->regs->prnsts & 1) //CMD inhibit.
|
||||
while(sdmmc->regs->prnsts & 1) // CMD inhibit.
|
||||
if (get_tmr_ms() > timeout)
|
||||
{
|
||||
_sdmmc_reset(sdmmc);
|
||||
@@ -406,7 +408,7 @@ static int _sdmmc_wait_prnsts_type0(sdmmc_t *sdmmc, u32 wait_dat)
|
||||
if (wait_dat)
|
||||
{
|
||||
timeout = get_tmr_ms() + 2000;
|
||||
while (sdmmc->regs->prnsts & 2) //DAT inhibit.
|
||||
while (sdmmc->regs->prnsts & 2) // DAT inhibit.
|
||||
if (get_tmr_ms() > timeout)
|
||||
{
|
||||
_sdmmc_reset(sdmmc);
|
||||
@@ -422,7 +424,7 @@ static int _sdmmc_wait_prnsts_type1(sdmmc_t *sdmmc)
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
|
||||
u32 timeout = get_tmr_ms() + 2000;
|
||||
while (!(sdmmc->regs->prnsts & 0x100000)) //DAT0 line level.
|
||||
while (!(sdmmc->regs->prnsts & 0x100000)) // DAT0 line level.
|
||||
if (get_tmr_ms() > timeout)
|
||||
{
|
||||
_sdmmc_reset(sdmmc);
|
||||
@@ -509,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);
|
||||
|
||||
@@ -531,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;
|
||||
}
|
||||
|
||||
@@ -561,9 +570,9 @@ int sdmmc_config_tuning(sdmmc_t *sdmmc, u32 type, u32 cmd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
sdmmc->regs->field_1C0 = (sdmmc->regs->field_1C0 & 0xFFFF1FFF) | flag;
|
||||
sdmmc->regs->field_1C0 = (sdmmc->regs->field_1C0 & 0xFFFFE03F) | 0x40;
|
||||
sdmmc->regs->field_1C0 |= 0x20000;
|
||||
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;
|
||||
|
||||
for (u32 i = 0; i < max; i++)
|
||||
@@ -575,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;
|
||||
}
|
||||
|
||||
@@ -664,7 +674,7 @@ static void _sdmmc_autocal_execute(sdmmc_t *sdmmc, u32 power)
|
||||
{
|
||||
if (get_tmr_ms() > timeout)
|
||||
{
|
||||
//In case autocalibration fails, we load suggested standard values.
|
||||
// In case autocalibration fails, we load suggested standard values.
|
||||
_sdmmc_pad_config_fallback(sdmmc, power);
|
||||
sdmmc->regs->autocalcfg &= 0xDFFFFFFF;
|
||||
break;
|
||||
@@ -701,7 +711,7 @@ static int _sdmmc_check_mask_interrupt(sdmmc_t *sdmmc, u16 *pout, u16 mask)
|
||||
if (pout)
|
||||
*pout = norintsts;
|
||||
|
||||
//Check for error interrupt.
|
||||
// Check for error interrupt.
|
||||
if (norintsts & TEGRA_MMC_NORINTSTS_ERR_INTERRUPT)
|
||||
{
|
||||
sdmmc->regs->errintsts = errintsts;
|
||||
@@ -712,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;
|
||||
}
|
||||
|
||||
@@ -744,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);
|
||||
}
|
||||
|
||||
@@ -775,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;
|
||||
|
||||
@@ -791,7 +806,7 @@ static int _sdmmc_config_dma(sdmmc_t *sdmmc, u32 *blkcnt_out, sdmmc_req_t *req)
|
||||
blkcnt = 0xFFFF;
|
||||
u32 admaaddr = (u32)req->buf;
|
||||
|
||||
//Check alignment.
|
||||
// Check alignment.
|
||||
if (admaaddr << 29)
|
||||
return 0;
|
||||
|
||||
@@ -815,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, false);
|
||||
sdmmc->regs->trnmod = trnmode;
|
||||
|
||||
return 1;
|
||||
@@ -834,15 +849,18 @@ 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)
|
||||
return 1; //Transfer complete.
|
||||
{
|
||||
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false);
|
||||
return 1; // Transfer complete.
|
||||
}
|
||||
if (intr & TEGRA_MMC_NORINTSTS_DMA_INTERRUPT)
|
||||
{
|
||||
//Update DMA.
|
||||
// Update DMA.
|
||||
sdmmc->regs->admaaddr = sdmmc->dma_addr_next;
|
||||
sdmmc->regs->admaaddr_hi = 0;
|
||||
sdmmc->dma_addr_next += 0x80000;
|
||||
@@ -883,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)
|
||||
{
|
||||
@@ -904,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;
|
||||
}
|
||||
@@ -917,12 +936,14 @@ static int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_
|
||||
|
||||
static int _sdmmc_config_sdmmc1()
|
||||
{
|
||||
//Configure SD card detect.
|
||||
// Configure SD card detect.
|
||||
PINMUX_AUX(PINMUX_AUX_GPIO_PZ1) = PINMUX_INPUT_ENABLE | PINMUX_PULL_UP | 1; //GPIO control, pull up.
|
||||
APB_MISC(APB_MISC_GP_VGPIO_GPIO_MUX_SEL) = 0;
|
||||
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;
|
||||
|
||||
@@ -935,8 +956,8 @@ static int _sdmmc_config_sdmmc1()
|
||||
* APB_MISC_GP_SDMMCx_CLK_LPBK_CONTROL = SDMMCx_CLK_PAD_E_LPBK for CLK
|
||||
*/
|
||||
|
||||
//Configure SDMMC1 pinmux.
|
||||
APB_MISC(APB_MISC_GP_SDMMC1_CLK_LPBK_CONTROL) = 1;
|
||||
// Configure SDMMC1 pinmux.
|
||||
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;
|
||||
@@ -944,12 +965,12 @@ static int _sdmmc_config_sdmmc1()
|
||||
PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT1) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_PULL_UP;
|
||||
PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT0) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_PULL_UP;
|
||||
|
||||
//Make sure the SDMMC1 controller is powered.
|
||||
// Make sure the SDMMC1 controller is powered.
|
||||
PMC(APBDEV_PMC_NO_IOPOWER) &= ~(1 << 12);
|
||||
//Assume 3.3V SD card voltage.
|
||||
// Assume 3.3V SD card voltage.
|
||||
PMC(APBDEV_PMC_PWR_DET_VAL) |= (1 << 12);
|
||||
|
||||
//Set enable SD card power.
|
||||
// Set enable SD card power.
|
||||
PINMUX_AUX(PINMUX_AUX_DMIC3_CLK) = PINMUX_INPUT_ENABLE | PINMUX_PULL_DOWN | 1; //GPIO control, pull down.
|
||||
gpio_config(GPIO_PORT_E, GPIO_PIN_4, GPIO_MODE_GPIO);
|
||||
gpio_write(GPIO_PORT_E, GPIO_PIN_4, GPIO_HIGH);
|
||||
@@ -957,13 +978,13 @@ static int _sdmmc_config_sdmmc1()
|
||||
|
||||
usleep(1000);
|
||||
|
||||
//Enable SD card power.
|
||||
// Enable SD card power.
|
||||
max77620_regulator_set_voltage(REGULATOR_LDO2, 3300000);
|
||||
max77620_regulator_enable(REGULATOR_LDO2, 1);
|
||||
|
||||
usleep(1000);
|
||||
|
||||
//For good measure.
|
||||
// For good measure.
|
||||
APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) = 0x10000000;
|
||||
|
||||
usleep(1000);
|
||||
@@ -994,31 +1015,36 @@ 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;
|
||||
|
||||
//TODO: make this skip-able.
|
||||
sdmmc->regs->field_1F0 |= 0x80000;
|
||||
sdmmc->regs->field_1AC &= 0xFFFFFFFB;
|
||||
sdmmc->regs->iospare |= 0x80000;
|
||||
sdmmc->regs->veniotrimctl &= 0xFFFFFFFB;
|
||||
static const u32 trim_values[] = { 2, 8, 3, 8 };
|
||||
sdmmc->regs->venclkctl = (sdmmc->regs->venclkctl & 0xE0FFFFFF) | (trim_values[sdmmc->id] << 24);
|
||||
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;
|
||||
@@ -1029,14 +1055,16 @@ 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.
|
||||
if (sdmmc->id == SDMMC_1)
|
||||
{
|
||||
gpio_output_enable(GPIO_PORT_E, GPIO_PIN_4, GPIO_OUTPUT_DISABLE);
|
||||
msleep(1); // To power cycle min 1ms without power is needed.
|
||||
max77620_regulator_enable(REGULATOR_LDO2, 0);
|
||||
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);
|
||||
@@ -1058,7 +1086,7 @@ int sdmmc_execute_cmd(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_t *req, u32 *b
|
||||
if (!sdmmc->sd_clock_enabled)
|
||||
return 0;
|
||||
|
||||
//Recalibrate periodically for SDMMC1.
|
||||
// Recalibrate periodically for SDMMC1.
|
||||
if (sdmmc->id == SDMMC_1 && sdmmc->no_sd)
|
||||
_sdmmc_autocal_execute(sdmmc, sdmmc_get_voltage(sdmmc));
|
||||
|
||||
@@ -1073,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;
|
||||
|
||||
@@ -1089,6 +1118,14 @@ int sdmmc_enable_low_voltage(sdmmc_t *sdmmc)
|
||||
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
|
||||
// Enable schmitt trigger for better duty cycle and low jitter clock.
|
||||
PINMUX_AUX(PINMUX_AUX_SDMMC1_CLK) |= PINMUX_SCHMT;
|
||||
PINMUX_AUX(PINMUX_AUX_SDMMC1_CMD) |= PINMUX_SCHMT;
|
||||
PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT3) |= PINMUX_SCHMT;
|
||||
PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT2) |= PINMUX_SCHMT;
|
||||
PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT1) |= PINMUX_SCHMT;
|
||||
PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT0) |= PINMUX_SCHMT;
|
||||
|
||||
max77620_regulator_set_voltage(REGULATOR_LDO2, 1800000);
|
||||
PMC(APBDEV_PMC_PWR_DET_VAL) &= ~(1 << 12);
|
||||
|
||||
@@ -1097,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;
|
||||
}
|
||||
|
||||
@@ -115,18 +115,18 @@ typedef struct _t210_sdmmc_t
|
||||
vu32 vendebouncecnt;
|
||||
vu32 venmiscctl;
|
||||
vu32 res6[34];
|
||||
vu32 field_1AC;
|
||||
vu32 field_1B0;
|
||||
vu32 veniotrimctl;
|
||||
vu32 vendllcal;
|
||||
vu8 res7[8];
|
||||
vu32 field_1BC;
|
||||
vu32 field_1C0;
|
||||
vu32 dllcfgstatus;
|
||||
vu32 ventunctl0;
|
||||
vu32 field_1C4;
|
||||
vu8 field_1C8[24];
|
||||
vu32 sdmemcmppadctl;
|
||||
vu32 autocalcfg;
|
||||
vu32 autocalintval;
|
||||
vu32 autocalsts;
|
||||
vu32 field_1F0;
|
||||
vu32 iospare;
|
||||
} t210_sdmmc_t;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user