Compare commits
124 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
be09b68532 | ||
|
|
50eff41351 | ||
|
|
4b78198f33 | ||
|
|
dfb5640bfe | ||
|
|
f139f9c56f | ||
|
|
4f4df9ccd1 | ||
|
|
bafc6f4a1d | ||
|
|
b1110caed1 | ||
|
|
e7f72b711a | ||
|
|
0ddc1c71a8 | ||
|
|
4e7c39d6a0 | ||
|
|
72a81e7c2a | ||
|
|
2e9a89aa20 | ||
|
|
ca68818efe | ||
|
|
3b9bf65071 | ||
|
|
50d4cbbda1 | ||
|
|
f911fab9f2 | ||
|
|
aae7689bf5 | ||
|
|
7d908c9ac5 | ||
|
|
2fb37db707 | ||
|
|
c8052e5b50 | ||
|
|
de830df7e7 | ||
|
|
04907e2823 | ||
|
|
4f5fcf9fbd | ||
|
|
ec890c7c97 |
134
Makefile
134
Makefile
@@ -4,102 +4,110 @@ endif
|
|||||||
|
|
||||||
include $(DEVKITARM)/base_rules
|
include $(DEVKITARM)/base_rules
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
IPL_LOAD_ADDR := 0x40008000
|
||||||
|
NYX_STORAGE_ADDR := 0xED000000
|
||||||
|
IPL_MAGIC := 0x43544349 #"ICTC"
|
||||||
|
BLVERSION_MAJOR := 5
|
||||||
|
BLVERSION_MINOR := 0
|
||||||
|
BLVERSION_HOTFX := 2
|
||||||
|
|
||||||
|
BL_RESERVED := 0
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
|
||||||
TARGET := hekate
|
TARGET := hekate
|
||||||
BLVERSION_MAJOR := 4
|
BUILDDIR := build
|
||||||
BLVERSION_MINOR := 6
|
OUTPUTDIR := output
|
||||||
BUILD := build
|
|
||||||
OUTPUT := output
|
|
||||||
SOURCEDIR = bootloader
|
SOURCEDIR = bootloader
|
||||||
VPATH = $(dir $(wildcard ./$(SOURCEDIR)/*/)) $(dir $(wildcard ./$(SOURCEDIR)/*/*/))
|
VPATH = $(dir $(wildcard ./$(SOURCEDIR)/*/)) $(dir $(wildcard ./$(SOURCEDIR)/*/*/))
|
||||||
|
|
||||||
OBJS = $(addprefix $(BUILD)/$(TARGET)/, \
|
# Main and graphics.
|
||||||
|
OBJS = $(addprefix $(BUILDDIR)/$(TARGET)/, \
|
||||||
start.o \
|
start.o \
|
||||||
main.o \
|
main.o heap.o \
|
||||||
fe_emmc_tools.o \
|
gfx.o tui.o \
|
||||||
fe_info.o \
|
fe_emmc_tools.o fe_info.o fe_tools.o \
|
||||||
fe_tools.o \
|
|
||||||
config.o \
|
|
||||||
btn.o \
|
|
||||||
clock.o \
|
|
||||||
cluster.o \
|
|
||||||
fuse.o \
|
|
||||||
gpio.o \
|
|
||||||
heap.o \
|
|
||||||
hos.o \
|
|
||||||
hos_config.o \
|
|
||||||
secmon_exo.o \
|
|
||||||
i2c.o \
|
|
||||||
kfuse.o \
|
|
||||||
bq24193.o \
|
|
||||||
max7762x.o \
|
|
||||||
max17050.o \
|
|
||||||
mc.o \
|
|
||||||
nx_emmc.o \
|
|
||||||
sdmmc.o \
|
|
||||||
sdmmc_driver.o \
|
|
||||||
sdram.o \
|
|
||||||
tui.o \
|
|
||||||
util.o \
|
|
||||||
di.o \
|
|
||||||
gfx.o \
|
|
||||||
pinmux.o \
|
|
||||||
pkg1.o \
|
|
||||||
pkg2.o \
|
|
||||||
se.o \
|
|
||||||
tsec.o \
|
|
||||||
uart.o \
|
|
||||||
hw_init.o \
|
|
||||||
dirlist.o \
|
|
||||||
ini.o \
|
|
||||||
ianos.o \
|
|
||||||
smmu.o \
|
|
||||||
max77620-rtc.o \
|
|
||||||
)
|
)
|
||||||
|
|
||||||
OBJS += $(addprefix $(BUILD)/$(TARGET)/, \
|
# Hardware.
|
||||||
|
OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \
|
||||||
|
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 \
|
||||||
|
)
|
||||||
|
|
||||||
|
# Utilities.
|
||||||
|
OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \
|
||||||
|
btn.o dirlist.o ianos.o util.o \
|
||||||
|
config.o ini.o \
|
||||||
|
)
|
||||||
|
|
||||||
|
# Horizon.
|
||||||
|
OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \
|
||||||
|
hos.o hos_config.o pkg1.o pkg2.o pkg2_ini_kippatch.o fss.o secmon_exo.o sept.o \
|
||||||
|
)
|
||||||
|
|
||||||
|
# Libraries.
|
||||||
|
OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \
|
||||||
lz.o blz.o \
|
lz.o blz.o \
|
||||||
diskio.o ff.o ffunicode.o ffsystem.o \
|
diskio.o ff.o ffunicode.o ffsystem.o \
|
||||||
elfload.o elfreloc_arm.o \
|
elfload.o elfreloc_arm.o \
|
||||||
)
|
)
|
||||||
|
|
||||||
CUSTOMDEFINES := -DBLVERSIONMJ=$(BLVERSION_MAJOR) -DBLVERSIONMN=$(BLVERSION_MINOR) -DMENU_LOGO_ENABLE
|
################################################################################
|
||||||
#CUSTOMDEFINES += -DDEBUG
|
|
||||||
|
CUSTOMDEFINES := -DIPL_LOAD_ADDR=$(IPL_LOAD_ADDR) -DNYX_STORAGE_ADDR=$(NYX_STORAGE_ADDR) -DBL_MAGIC=$(IPL_MAGIC)
|
||||||
|
CUSTOMDEFINES += -DBL_VER_MJ=$(BLVERSION_MAJOR) -DBL_VER_MN=$(BLVERSION_MINOR) -DBL_VER_HF=$(BLVERSION_HOTFX) -DBL_RESERVED=$(BL_RESERVED)
|
||||||
|
#CUSTOMDEFINES += -DMENU_LOGO_ENABLE
|
||||||
|
|
||||||
# 0: UART_A, 1: UART_B.
|
# 0: UART_A, 1: UART_B.
|
||||||
#CUSTOMDEFINES += -DDEBUG_UART_PORT=0
|
#CUSTOMDEFINES += -DDEBUG_UART_PORT=0
|
||||||
|
|
||||||
|
#CUSTOMDEFINES += -DDEBUG
|
||||||
|
|
||||||
ARCH := -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork
|
ARCH := -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork
|
||||||
CFLAGS = $(ARCH) -O2 -nostdlib -ffunction-sections -fdata-sections -fomit-frame-pointer -fno-inline -std=gnu11 -Wall $(CUSTOMDEFINES)
|
CFLAGS = $(ARCH) -O2 -nostdlib -ffunction-sections -fdata-sections -fomit-frame-pointer -fno-inline -std=gnu11 -Wall $(CUSTOMDEFINES)
|
||||||
LDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections
|
LDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections -Xlinker --defsym=IPL_LOAD_ADDR=$(IPL_LOAD_ADDR)
|
||||||
|
|
||||||
MODULEDIRS := $(wildcard modules/*)
|
MODULEDIRS := $(wildcard modules/*)
|
||||||
|
NYXDIR := $(wildcard nyx)
|
||||||
|
|
||||||
.PHONY: all clean $(MODULEDIRS)
|
################################################################################
|
||||||
|
|
||||||
|
.PHONY: all clean $(MODULEDIRS) $(NYXDIR)
|
||||||
|
|
||||||
all: $(TARGET).bin
|
all: $(TARGET).bin
|
||||||
@echo -n "Payload size is "
|
@echo -n "Payload size is "
|
||||||
@wc -c < $(OUTPUT)/$(TARGET).bin
|
@wc -c < $(OUTPUTDIR)/$(TARGET).bin
|
||||||
@echo "Max size is 126296 Bytes."
|
@echo "Max size is 126296 Bytes."
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
@rm -rf $(OBJS)
|
@rm -rf $(OBJS)
|
||||||
@rm -rf $(BUILD)
|
@rm -rf $(BUILDDIR)
|
||||||
@rm -rf $(OUTPUT)
|
@rm -rf $(OUTPUTDIR)
|
||||||
|
|
||||||
$(MODULEDIRS):
|
$(MODULEDIRS):
|
||||||
$(MAKE) -C $@ $(MAKECMDGOALS)
|
$(MAKE) -C $@ $(MAKECMDGOALS) -$(MAKEFLAGS)
|
||||||
|
|
||||||
$(TARGET).bin: $(BUILD)/$(TARGET)/$(TARGET).elf $(MODULEDIRS)
|
$(NYXDIR):
|
||||||
$(OBJCOPY) -S -O binary $< $(OUTPUT)/$@
|
$(MAKE) -C $@ $(MAKECMDGOALS) -$(MAKEFLAGS)
|
||||||
@printf ICTC$(BLVERSION_MAJOR)$(BLVERSION_MINOR) >> $(OUTPUT)/$@
|
|
||||||
|
|
||||||
$(BUILD)/$(TARGET)/$(TARGET).elf: $(OBJS)
|
$(TARGET).bin: $(BUILDDIR)/$(TARGET)/$(TARGET).elf $(MODULEDIRS) $(NYXDIR)
|
||||||
|
$(OBJCOPY) -S -O binary $< $(OUTPUTDIR)/$@
|
||||||
|
@printf ICTC49 >> $(OUTPUTDIR)/$@
|
||||||
|
|
||||||
|
$(BUILDDIR)/$(TARGET)/$(TARGET).elf: $(OBJS)
|
||||||
$(CC) $(LDFLAGS) -T $(SOURCEDIR)/link.ld $^ -o $@
|
$(CC) $(LDFLAGS) -T $(SOURCEDIR)/link.ld $^ -o $@
|
||||||
|
|
||||||
$(BUILD)/$(TARGET)/%.o: %.c
|
$(BUILDDIR)/$(TARGET)/%.o: %.c
|
||||||
$(CC) $(CFLAGS) -c $< -o $@
|
$(CC) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
$(BUILD)/$(TARGET)/%.o: %.S
|
$(BUILDDIR)/$(TARGET)/%.o: %.S
|
||||||
@mkdir -p "$(BUILD)"
|
@mkdir -p "$(BUILDDIR)"
|
||||||
@mkdir -p "$(BUILD)/$(TARGET)"
|
@mkdir -p "$(BUILDDIR)/$(TARGET)"
|
||||||
@mkdir -p "$(OUTPUT)"
|
@mkdir -p "$(OUTPUTDIR)"
|
||||||
$(CC) $(CFLAGS) -c $< -o $@
|
$(CC) $(CFLAGS) -c $< -o $@
|
||||||
|
|||||||
55
README.md
55
README.md
@@ -1,6 +1,6 @@
|
|||||||
# hekate - CTCaer mod
|
# hekate - CTCaer mod
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
Custom Nintendo Switch bootloader, firmware patcher, and more.
|
Custom Nintendo Switch bootloader, firmware patcher, and more.
|
||||||
@@ -9,17 +9,30 @@ Custom Nintendo Switch bootloader, firmware patcher, and more.
|
|||||||
## Bootloader folders and files
|
## Bootloader folders and files
|
||||||
|
|
||||||
| Folder/File | Description |
|
| Folder/File | Description |
|
||||||
| -------------------- | --------------------------------------------------------------------- |
|
| ------------------------ | --------------------------------------------------------------------- |
|
||||||
| bootloader | Main folder. |
|
| bootloader | Main folder. |
|
||||||
| \|__ bootlogo.bmp | It is used when custom is on and no logopath found. Can be skipped. |
|
| \|__ 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. |
|
| \|__ hekate_ipl.ini | Main bootloader configuration and boot entries. |
|
||||||
|
| \|__ patches.ini | Add external patches. If not found `patches_template.ini` will be loaded. Can be skipped. |
|
||||||
| \|__ update.bin | If newer, it is loaded at boot. For modchips. Can be skipped. |
|
| \|__ 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/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. |
|
| bootloader/sys/ | For system modules. |
|
||||||
|
| \|__ emummc.kipm | emuMMC KIP1 module. Important! |
|
||||||
| \|__ libsys_lp0.bso | LP0 (sleep mode) 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/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 |
|
| bootloader/libtools/ | Future reserved |
|
||||||
|
|
||||||
|
**Note**: Sept files for booting 7.0.0 and up are expected at /sept folder at root of sd card.
|
||||||
|
|
||||||
|
|
||||||
## Bootloader configuration
|
## Bootloader configuration
|
||||||
|
|
||||||
@@ -29,33 +42,59 @@ 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.
|
There are four possible type of entries. "**[ ]**": Boot entry, "**{ }**": Caption, "**#**": Comment, "*newline*": .ini cosmetic newline.
|
||||||
|
|
||||||
|
|
||||||
### Configuration keys/values when boot entry is **config**:
|
### Global Configuration keys/values when boot entry is **config**:
|
||||||
|
|
||||||
| Config option | Description |
|
| Config option | Description |
|
||||||
| ------------------ | ---------------------------------------------------------- |
|
| ------------------ | ---------------------------------------------------------- |
|
||||||
| autoboot=0 | 0: Disable, #: Boot entry number to auto boot. |
|
| 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. |
|
| bootwait=3 | 0: Disable (It also disables bootlogo. Having **VOL-** pressed since injection goes to menu.), #: Time to wait for **VOL-** to enter menu. |
|
||||||
| customlogo=0 | 0: Use default hekate bootlogo, 1: Use bootlogo.bmp. |
|
|
||||||
| verification=2 | 0: Disable Backup/Restore verification, 1: Sparse (block based, fast and not 100% reliable), 2: Full (sha256 based, slow and 100% reliable). |
|
| 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.|
|
| 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. |
|
||||||
| backlight=100 | Screen backlight level. 0-255. |
|
| backlight=100 | Screen backlight level. 0-255. |
|
||||||
|
|
||||||
|
|
||||||
### Possible boot entry key/value combinations:
|
### Possible boot entry key/value combinations:
|
||||||
|
|
||||||
| Config option | Description |
|
| 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. |
|
| 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 |
|
| warmboot={SD path} | Replaces the warmboot binary |
|
||||||
| secmon={SD path} | Replaces the security monitor binary |
|
| secmon={SD path} | Replaces the security monitor binary |
|
||||||
| kernel={SD path} | Replaces the kernel binary |
|
| kernel={SD path} | Replaces the kernel binary |
|
||||||
| kip1={SD path} | Replaces/Adds kernel initial process. Multiple can be set. |
|
| 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. |
|
| kip1={SD folder}/* | Loads every .kip/.kip1 inside a folder. Compatible with single kip1 keys. |
|
||||||
| kip1patch=patchname| Enables a kip1 patch. Specify with multiple lines and/or as CSV. Implemented patches right now are nosigchk,nogc |
|
| 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) |
|
| fullsvcperm=1 | Disables SVC verification (full services permission) |
|
||||||
| debugmode=1 | Enables Debug mode |
|
| debugmode=1 | Enables Debug mode. Obsolete when used with exosphere as secmon. |
|
||||||
| atmosphere=1 | Enables Atmosphère patching |
|
| atmosphere=1 | Enables Atmosphère patching. |
|
||||||
|
| nouserexceptions=1 | Disables usermode exception handlers 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. |
|
||||||
| payload={SD path} | Payload launching. Tools, Linux, CFW bootloaders, etc. |
|
| payload={SD path} | Payload launching. Tools, Linux, CFW bootloaders, etc. |
|
||||||
|
| icon={SD path} | Force Nyx to use the icon defined here. If this is not found, it will check for a bmp named as the boot entry ([Test 2] -> `bootloader/res/Test 2.bmp`). Otherwise default will be used. |
|
||||||
|
|
||||||
|
**Note1**: When using the wildcard (`/*`) with `kip1` you can still use the normal `kip1` after that to load extra single kips.
|
||||||
|
|
||||||
|
**Note2**: When using FSS0 it parses exosphere, warmboot and all core kips. You can override the first 2 by using `secmon`/`warmboot` after defining `fss0`.
|
||||||
|
You can define `kip1` to load an extra kip or many via the wildcard (`/*`) usage.
|
||||||
|
|
||||||
|
**Warning**: Never define core kips when using `fss0` and make sure that the folder (when using `/*`), does not include them. This is in case the kips are incompatible between them.
|
||||||
|
|
||||||
|
|
||||||
|
### Payload storage:
|
||||||
|
|
||||||
|
Hekate now has a new 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. |
|
||||||
|
| '0x95' autoboot | If `Force AutoBoot`: 0: Force go to menu, else boot that entry. |
|
||||||
|
| '0x96' autoboot_list | If `Force AutoBoot` and `autoboot` then it boots from ini folder. |
|
||||||
|
| '0x97' extra_cfg | bit7: Force Nyx to run `Dump pkg1/2. |
|
||||||
|
| '0x98' rsvd[128] | Reserved. |
|
||||||
|
|
||||||
|
|
||||||
You can find a template [Here](./res/hekate_ipl_template.ini)
|
You can find a template [Here](./res/hekate_ipl_template.ini)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 CTCaer
|
* Copyright (c) 2018-2019 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -17,37 +17,40 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "../utils/btn.h"
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "../libs/fatfs/ff.h"
|
|
||||||
#include "ini.h"
|
#include "ini.h"
|
||||||
#include "../utils/list.h"
|
|
||||||
#include "../gfx/tui.h"
|
|
||||||
#include "../utils/util.h"
|
|
||||||
#include "../gfx/gfx.h"
|
#include "../gfx/gfx.h"
|
||||||
|
#include "../gfx/tui.h"
|
||||||
extern gfx_ctxt_t gfx_ctxt;
|
#include "../libs/fatfs/ff.h"
|
||||||
extern gfx_con_t gfx_con;
|
#include "../soc/t210.h"
|
||||||
//TODO: Create more macros (info, header, debug, etc) with different colors and utilize them for consistency.
|
#include "../storage/sdmmc.h"
|
||||||
#define EPRINTF(text) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFF0000, 0xFFCCCCCC)
|
#include "../utils/btn.h"
|
||||||
#define EPRINTFARGS(text, args...) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFF0000, args, 0xFFCCCCCC)
|
#include "../utils/list.h"
|
||||||
|
#include "../utils/util.h"
|
||||||
|
|
||||||
extern hekate_config h_cfg;
|
extern hekate_config h_cfg;
|
||||||
extern int sd_mount();
|
extern bool sd_mount();
|
||||||
extern int sd_unmount();
|
extern void sd_unmount();
|
||||||
|
|
||||||
void set_default_configuration()
|
void set_default_configuration()
|
||||||
{
|
{
|
||||||
h_cfg.autoboot = 0;
|
h_cfg.autoboot = 0;
|
||||||
h_cfg.autoboot_list = 0;
|
h_cfg.autoboot_list = 0;
|
||||||
h_cfg.bootwait = 3;
|
h_cfg.bootwait = 3;
|
||||||
h_cfg.customlogo = 0;
|
h_cfg.verification = 1;
|
||||||
h_cfg.verification = 2;
|
|
||||||
h_cfg.se_keygen_done = 0;
|
h_cfg.se_keygen_done = 0;
|
||||||
h_cfg.sbar_time_keeping = 0;
|
h_cfg.sbar_time_keeping = 0;
|
||||||
h_cfg.backlight = 100;
|
h_cfg.backlight = 100;
|
||||||
h_cfg.autohosoff = 0;
|
h_cfg.autohosoff = 0;
|
||||||
|
h_cfg.autonogc = 1;
|
||||||
|
h_cfg.brand = NULL;
|
||||||
|
h_cfg.tagline = NULL;
|
||||||
h_cfg.errors = 0;
|
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 = 0xFFFFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
int create_config_entry()
|
int create_config_entry()
|
||||||
@@ -55,7 +58,7 @@ int create_config_entry()
|
|||||||
if (!sd_mount())
|
if (!sd_mount())
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
char lbuf[16];
|
char lbuf[32];
|
||||||
FIL fp;
|
FIL fp;
|
||||||
bool mainIniFound = false;
|
bool mainIniFound = false;
|
||||||
|
|
||||||
@@ -93,9 +96,6 @@ int create_config_entry()
|
|||||||
f_puts("\nbootwait=", &fp);
|
f_puts("\nbootwait=", &fp);
|
||||||
itoa(h_cfg.bootwait, lbuf, 10);
|
itoa(h_cfg.bootwait, lbuf, 10);
|
||||||
f_puts(lbuf, &fp);
|
f_puts(lbuf, &fp);
|
||||||
f_puts("\ncustomlogo=", &fp);
|
|
||||||
itoa(h_cfg.customlogo, lbuf, 10);
|
|
||||||
f_puts(lbuf, &fp);
|
|
||||||
f_puts("\nverification=", &fp);
|
f_puts("\nverification=", &fp);
|
||||||
itoa(h_cfg.verification, lbuf, 10);
|
itoa(h_cfg.verification, lbuf, 10);
|
||||||
f_puts(lbuf, &fp);
|
f_puts(lbuf, &fp);
|
||||||
@@ -105,6 +105,19 @@ int create_config_entry()
|
|||||||
f_puts("\nautohosoff=", &fp);
|
f_puts("\nautohosoff=", &fp);
|
||||||
itoa(h_cfg.autohosoff, lbuf, 10);
|
itoa(h_cfg.autohosoff, lbuf, 10);
|
||||||
f_puts(lbuf, &fp);
|
f_puts(lbuf, &fp);
|
||||||
|
f_puts("\nautonogc=", &fp);
|
||||||
|
itoa(h_cfg.autonogc, 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);
|
f_puts("\n", &fp);
|
||||||
|
|
||||||
if (mainIniFound)
|
if (mainIniFound)
|
||||||
@@ -150,16 +163,28 @@ int create_config_entry()
|
|||||||
f_close(&fp);
|
f_close(&fp);
|
||||||
sd_unmount();
|
sd_unmount();
|
||||||
|
|
||||||
if (mainIniFound)
|
|
||||||
ini_free(&ini_sections);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma GCC push_options
|
||||||
|
#pragma GCC optimize ("Os")
|
||||||
|
|
||||||
|
static void _save_config()
|
||||||
|
{
|
||||||
|
gfx_clear_grey(0x1B);
|
||||||
|
gfx_con_setpos(0, 0);
|
||||||
|
|
||||||
|
if (!create_config_entry())
|
||||||
|
gfx_puts("\nConfiguration was saved!\n");
|
||||||
|
else
|
||||||
|
EPRINTF("\nConfiguration saving failed!");
|
||||||
|
gfx_puts("\nPress any key...");
|
||||||
|
}
|
||||||
|
|
||||||
static void _config_autoboot_list(void *ent)
|
static void _config_autoboot_list(void *ent)
|
||||||
{
|
{
|
||||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
gfx_clear_grey(0x1B);
|
||||||
gfx_con_setpos(&gfx_con, 0, 0);
|
gfx_con_setpos(0, 0);
|
||||||
|
|
||||||
u32 *temp_autoboot = NULL;
|
u32 *temp_autoboot = NULL;
|
||||||
|
|
||||||
@@ -216,21 +241,13 @@ static void _config_autoboot_list(void *ent)
|
|||||||
}
|
}
|
||||||
|
|
||||||
memset(&ments[i], 0, sizeof(ment_t));
|
memset(&ments[i], 0, sizeof(ment_t));
|
||||||
menu_t menu = {ments, "Select a list entry to auto boot", 0, 0};
|
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)
|
if (temp_autoboot != NULL)
|
||||||
{
|
{
|
||||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
|
||||||
gfx_con_setpos(&gfx_con, 0, 0);
|
|
||||||
|
|
||||||
h_cfg.autoboot = *(u32 *)temp_autoboot;
|
h_cfg.autoboot = *(u32 *)temp_autoboot;
|
||||||
h_cfg.autoboot_list = 1;
|
h_cfg.autoboot_list = 1;
|
||||||
// Save choice to ini file.
|
_save_config();
|
||||||
if (!create_config_entry())
|
|
||||||
gfx_puts(&gfx_con, "\nConfiguration was saved!\n");
|
|
||||||
else
|
|
||||||
EPRINTF("\nConfiguration saving failed!");
|
|
||||||
gfx_puts(&gfx_con, "\nPress any key...");
|
|
||||||
|
|
||||||
ment_t *tmp = (ment_t *)ent;
|
ment_t *tmp = (ment_t *)ent;
|
||||||
tmp->data = NULL;
|
tmp->data = NULL;
|
||||||
@@ -240,7 +257,7 @@ static void _config_autoboot_list(void *ent)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
EPRINTF("Could not open 'bootloader/hekate_ipl.ini'.\nMake sure it exists in SD Card!.");
|
EPRINTF("Could not open 'bootloader/hekate_ipl.ini'.\nMake sure it exists!.");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -251,15 +268,14 @@ out2:;
|
|||||||
free(ments);
|
free(ments);
|
||||||
free(boot_values);
|
free(boot_values);
|
||||||
free(boot_text);
|
free(boot_text);
|
||||||
ini_free(&ini_sections);
|
|
||||||
|
|
||||||
sd_unmount();
|
sd_unmount();
|
||||||
}
|
}
|
||||||
|
|
||||||
void config_autoboot()
|
void config_autoboot()
|
||||||
{
|
{
|
||||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
gfx_clear_grey(0x1B);
|
||||||
gfx_con_setpos(&gfx_con, 0, 0);
|
gfx_con_setpos(0, 0);
|
||||||
|
|
||||||
u32 *temp_autoboot = NULL;
|
u32 *temp_autoboot = NULL;
|
||||||
|
|
||||||
@@ -341,27 +357,19 @@ void config_autoboot()
|
|||||||
|
|
||||||
memset(&ments[i], 0, sizeof(ment_t));
|
memset(&ments[i], 0, sizeof(ment_t));
|
||||||
menu_t menu = {ments, "Disable or select entry to auto boot", 0, 0};
|
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)
|
if (temp_autoboot != NULL)
|
||||||
{
|
{
|
||||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
|
||||||
gfx_con_setpos(&gfx_con, 0, 0);
|
|
||||||
|
|
||||||
h_cfg.autoboot = *(u32 *)temp_autoboot;
|
h_cfg.autoboot = *(u32 *)temp_autoboot;
|
||||||
h_cfg.autoboot_list = 0;
|
h_cfg.autoboot_list = 0;
|
||||||
// Save choice to ini file.
|
_save_config();
|
||||||
if (!create_config_entry())
|
|
||||||
gfx_puts(&gfx_con, "\nConfiguration was saved!\n");
|
|
||||||
else
|
|
||||||
EPRINTF("\nConfiguration saving failed!");
|
|
||||||
gfx_puts(&gfx_con, "\nPress any key...");
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
goto out2;
|
goto out2;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
EPRINTF("Could not open 'bootloader/hekate_ipl.ini'.\nMake sure it exists in SD Card!.");
|
EPRINTF("Could not open 'bootloader/hekate_ipl.ini'.\nMake sure it exists!.");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -372,7 +380,6 @@ out2:;
|
|||||||
free(ments);
|
free(ments);
|
||||||
free(boot_values);
|
free(boot_values);
|
||||||
free(boot_text);
|
free(boot_text);
|
||||||
ini_free(&ini_sections);
|
|
||||||
|
|
||||||
sd_unmount();
|
sd_unmount();
|
||||||
|
|
||||||
@@ -382,8 +389,8 @@ out2:;
|
|||||||
|
|
||||||
void config_bootdelay()
|
void config_bootdelay()
|
||||||
{
|
{
|
||||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
gfx_clear_grey(0x1B);
|
||||||
gfx_con_setpos(&gfx_con, 0, 0);
|
gfx_con_setpos(0, 0);
|
||||||
|
|
||||||
u32 delay_entries = 6;
|
u32 delay_entries = 6;
|
||||||
|
|
||||||
@@ -424,19 +431,11 @@ void config_bootdelay()
|
|||||||
memset(&ments[i + 2], 0, sizeof(ment_t));
|
memset(&ments[i + 2], 0, sizeof(ment_t));
|
||||||
menu_t menu = {ments, "Time delay for entering bootloader menu", 0, 0};
|
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)
|
if (temp_bootwait != NULL)
|
||||||
{
|
{
|
||||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
|
||||||
gfx_con_setpos(&gfx_con, 0, 0);
|
|
||||||
|
|
||||||
h_cfg.bootwait = *(u32 *)temp_bootwait;
|
h_cfg.bootwait = *(u32 *)temp_bootwait;
|
||||||
// Save choice to ini file.
|
_save_config();
|
||||||
if (!create_config_entry())
|
|
||||||
gfx_puts(&gfx_con, "\nConfiguration was saved!\n");
|
|
||||||
else
|
|
||||||
EPRINTF("\nConfiguration saving failed!");
|
|
||||||
gfx_puts(&gfx_con, "\nPress any key...");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free(ments);
|
free(ments);
|
||||||
@@ -448,68 +447,10 @@ void config_bootdelay()
|
|||||||
btn_wait();
|
btn_wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
void config_customlogo()
|
|
||||||
{
|
|
||||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
|
||||||
gfx_con_setpos(&gfx_con, 0, 0);
|
|
||||||
|
|
||||||
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 5);
|
|
||||||
u32 *cb_values = (u32 *)malloc(sizeof(u32) * 2);
|
|
||||||
|
|
||||||
for (u32 j = 0; j < 2; j++)
|
|
||||||
{
|
|
||||||
cb_values[j] = j;
|
|
||||||
ments[j + 2].type = MENT_DATA;
|
|
||||||
ments[j + 2].data = &cb_values[j];
|
|
||||||
}
|
|
||||||
|
|
||||||
ments[0].type = MENT_BACK;
|
|
||||||
ments[0].caption = "Back";
|
|
||||||
|
|
||||||
ments[1].type = MENT_CHGLINE;
|
|
||||||
|
|
||||||
if (h_cfg.customlogo)
|
|
||||||
{
|
|
||||||
ments[2].caption = " Disable";
|
|
||||||
ments[3].caption = "*Enable";
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ments[2].caption = "*Disable";
|
|
||||||
ments[3].caption = " Enable";
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(&ments[4], 0, sizeof(ment_t));
|
|
||||||
menu_t menu = {ments, "Custom bootlogo", 0, 0};
|
|
||||||
|
|
||||||
u32 *temp_customlogo = (u32 *)tui_do_menu(&gfx_con, &menu);
|
|
||||||
if (temp_customlogo != NULL)
|
|
||||||
{
|
|
||||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
|
||||||
gfx_con_setpos(&gfx_con, 0, 0);
|
|
||||||
|
|
||||||
h_cfg.customlogo = *(u32 *)temp_customlogo;
|
|
||||||
// Save choice to ini file.
|
|
||||||
if (!create_config_entry())
|
|
||||||
gfx_puts(&gfx_con, "\nConfiguration was saved!\n");
|
|
||||||
else
|
|
||||||
EPRINTF("\nConfiguration saving failed!");
|
|
||||||
gfx_puts(&gfx_con, "\nPress any key...");
|
|
||||||
}
|
|
||||||
|
|
||||||
free(ments);
|
|
||||||
free(cb_values);
|
|
||||||
|
|
||||||
if (temp_customlogo == NULL)
|
|
||||||
return;
|
|
||||||
btn_wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
void config_verification()
|
void config_verification()
|
||||||
{
|
{
|
||||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
gfx_clear_grey(0x1B);
|
||||||
gfx_con_setpos(&gfx_con, 0, 0);
|
gfx_con_setpos(0, 0);
|
||||||
|
|
||||||
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 6);
|
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 6);
|
||||||
u32 *vr_values = (u32 *)malloc(sizeof(u32) * 3);
|
u32 *vr_values = (u32 *)malloc(sizeof(u32) * 3);
|
||||||
@@ -527,40 +468,27 @@ void config_verification()
|
|||||||
|
|
||||||
ments[1].type = MENT_CHGLINE;
|
ments[1].type = MENT_CHGLINE;
|
||||||
|
|
||||||
memcpy(vr_text, " Disable (Fastest)", 19);
|
memcpy(vr_text, " Disable (Fastest - Unsafe)", 28);
|
||||||
memcpy(vr_text + 64, " Sparse (Fast - Not reliable)", 32);
|
memcpy(vr_text + 64, " Sparse (Fast - Safe)", 23);
|
||||||
memcpy(vr_text + 128, " Full (Slow - 100% reliable)", 32);
|
memcpy(vr_text + 128, " Full (Slow - Safe)", 23);
|
||||||
|
|
||||||
for (u32 i = 0; i < 3; i++)
|
for (u32 i = 0; i < 3; i++)
|
||||||
{
|
{
|
||||||
if (h_cfg.verification != i)
|
if (h_cfg.verification != i)
|
||||||
{
|
|
||||||
vr_text[64 * i] = ' ';
|
vr_text[64 * i] = ' ';
|
||||||
ments[2 + i].caption = vr_text + (i * 64);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
vr_text[64 * i] = '*';
|
vr_text[64 * i] = '*';
|
||||||
ments[2 + i].caption = vr_text + (i * 64);
|
ments[2 + i].caption = vr_text + (i * 64);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
memset(&ments[5], 0, sizeof(ment_t));
|
memset(&ments[5], 0, sizeof(ment_t));
|
||||||
menu_t menu = {ments, "Backup & Restore verification", 0, 0};
|
menu_t menu = {ments, "Backup & Restore verification", 0, 0};
|
||||||
|
|
||||||
u32 *temp_verification = (u32 *)tui_do_menu(&gfx_con, &menu);
|
u32 *temp_verification = (u32 *)tui_do_menu(&menu);
|
||||||
if (temp_verification != NULL)
|
if (temp_verification != NULL)
|
||||||
{
|
{
|
||||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
|
||||||
gfx_con_setpos(&gfx_con, 0, 0);
|
|
||||||
|
|
||||||
h_cfg.verification = *(u32 *)temp_verification;
|
h_cfg.verification = *(u32 *)temp_verification;
|
||||||
// Save choice to ini file.
|
_save_config();
|
||||||
if (!create_config_entry())
|
|
||||||
gfx_puts(&gfx_con, "\nConfiguration was saved!\n");
|
|
||||||
else
|
|
||||||
EPRINTF("\nConfiguration saving failed!");
|
|
||||||
gfx_puts(&gfx_con, "\nPress any key...");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free(ments);
|
free(ments);
|
||||||
@@ -574,8 +502,8 @@ void config_verification()
|
|||||||
|
|
||||||
void config_backlight()
|
void config_backlight()
|
||||||
{
|
{
|
||||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
gfx_clear_grey(0x1B);
|
||||||
gfx_con_setpos(&gfx_con, 0, 0);
|
gfx_con_setpos(0, 0);
|
||||||
|
|
||||||
u32 bri_entries = 11;
|
u32 bri_entries = 11;
|
||||||
|
|
||||||
@@ -604,7 +532,6 @@ void config_backlight()
|
|||||||
bri_text[i * 32 + 1] = i + '0';
|
bri_text[i * 32 + 1] = i + '0';
|
||||||
memcpy(bri_text + i * 32 + 2, "0%", 3);
|
memcpy(bri_text + i * 32 + 2, "0%", 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
memcpy(bri_text + i * 32 + 1, "100%", 5);
|
memcpy(bri_text + i * 32 + 1, "100%", 5);
|
||||||
|
|
||||||
@@ -616,19 +543,11 @@ void config_backlight()
|
|||||||
memset(&ments[i + 1], 0, sizeof(ment_t));
|
memset(&ments[i + 1], 0, sizeof(ment_t));
|
||||||
menu_t menu = {ments, "Backlight brightness", 0, 0};
|
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)
|
if (temp_backlight != NULL)
|
||||||
{
|
{
|
||||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
|
||||||
gfx_con_setpos(&gfx_con, 0, 0);
|
|
||||||
|
|
||||||
h_cfg.backlight = (*(u32 *)temp_backlight) * 2;
|
h_cfg.backlight = (*(u32 *)temp_backlight) * 2;
|
||||||
//Save choice to ini file.
|
_save_config();
|
||||||
if (!create_config_entry())
|
|
||||||
gfx_puts(&gfx_con, "\nConfiguration was saved!\n");
|
|
||||||
else
|
|
||||||
EPRINTF("\nConfiguration saving failed!");
|
|
||||||
gfx_puts(&gfx_con, "\nPress any key...");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free(ments);
|
free(ments);
|
||||||
@@ -642,8 +561,8 @@ void config_backlight()
|
|||||||
|
|
||||||
void config_auto_hos_poweroff()
|
void config_auto_hos_poweroff()
|
||||||
{
|
{
|
||||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
gfx_clear_grey(0x1B);
|
||||||
gfx_con_setpos(&gfx_con, 0, 0);
|
gfx_con_setpos(0, 0);
|
||||||
|
|
||||||
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 6);
|
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 6);
|
||||||
u32 *hp_values = (u32 *)malloc(sizeof(u32) * 3);
|
u32 *hp_values = (u32 *)malloc(sizeof(u32) * 3);
|
||||||
@@ -682,19 +601,11 @@ void config_auto_hos_poweroff()
|
|||||||
memset(&ments[5], 0, sizeof(ment_t));
|
memset(&ments[5], 0, sizeof(ment_t));
|
||||||
menu_t menu = {ments, "Power off if woke up from HOS", 0, 0};
|
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)
|
if (temp_autohosoff != NULL)
|
||||||
{
|
{
|
||||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
|
||||||
gfx_con_setpos(&gfx_con, 0, 0);
|
|
||||||
|
|
||||||
h_cfg.autohosoff = *(u32 *)temp_autohosoff;
|
h_cfg.autohosoff = *(u32 *)temp_autohosoff;
|
||||||
// Save choice to ini file.
|
_save_config();
|
||||||
if (!create_config_entry())
|
|
||||||
gfx_puts(&gfx_con, "\nConfiguration was saved!\n");
|
|
||||||
else
|
|
||||||
EPRINTF("\nConfiguration saving failed!");
|
|
||||||
gfx_puts(&gfx_con, "\nPress any key...");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free(ments);
|
free(ments);
|
||||||
@@ -704,3 +615,54 @@ void config_auto_hos_poweroff()
|
|||||||
return;
|
return;
|
||||||
btn_wait();
|
btn_wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void config_nogc()
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
|
for (u32 j = 0; j < 2; j++)
|
||||||
|
{
|
||||||
|
cb_values[j] = j;
|
||||||
|
ments[j + 2].type = MENT_DATA;
|
||||||
|
ments[j + 2].data = &cb_values[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
ments[0].type = MENT_BACK;
|
||||||
|
ments[0].caption = "Back";
|
||||||
|
|
||||||
|
ments[1].type = MENT_CHGLINE;
|
||||||
|
|
||||||
|
if (h_cfg.autonogc)
|
||||||
|
{
|
||||||
|
ments[2].caption = " Disable";
|
||||||
|
ments[3].caption = "*Auto";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ments[2].caption = "*Disable";
|
||||||
|
ments[3].caption = " Auto";
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&ments[4], 0, sizeof(ment_t));
|
||||||
|
menu_t menu = {ments, "No Gamecard", 0, 0};
|
||||||
|
|
||||||
|
u32 *temp_nogc = (u32 *)tui_do_menu(&menu);
|
||||||
|
if (temp_nogc != NULL)
|
||||||
|
{
|
||||||
|
h_cfg.autonogc = *(u32 *)temp_nogc;
|
||||||
|
_save_config();
|
||||||
|
}
|
||||||
|
|
||||||
|
free(ments);
|
||||||
|
free(cb_values);
|
||||||
|
|
||||||
|
if (temp_nogc == NULL)
|
||||||
|
return;
|
||||||
|
btn_wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma GCC pop_options
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 CTCaer
|
* Copyright (c) 2018-2019 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -25,14 +25,19 @@ typedef struct _hekate_config
|
|||||||
u32 autoboot;
|
u32 autoboot;
|
||||||
u32 autoboot_list;
|
u32 autoboot_list;
|
||||||
u32 bootwait;
|
u32 bootwait;
|
||||||
u32 customlogo;
|
|
||||||
u32 verification;
|
u32 verification;
|
||||||
u32 backlight;
|
u32 backlight;
|
||||||
u32 autohosoff;
|
u32 autohosoff;
|
||||||
u32 errors;
|
u32 autonogc;
|
||||||
|
char *brand;
|
||||||
|
char *tagline;
|
||||||
// Global temporary config.
|
// Global temporary config.
|
||||||
int se_keygen_done;
|
bool se_keygen_done;
|
||||||
|
bool sept_run;
|
||||||
|
bool emummc_force_disable;
|
||||||
|
bool rcm_patched;
|
||||||
u32 sbar_time_keeping;
|
u32 sbar_time_keeping;
|
||||||
|
u32 errors;
|
||||||
} hekate_config;
|
} hekate_config;
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
@@ -44,9 +49,9 @@ void set_default_configuration();
|
|||||||
int create_config_entry();
|
int create_config_entry();
|
||||||
void config_autoboot();
|
void config_autoboot();
|
||||||
void config_bootdelay();
|
void config_bootdelay();
|
||||||
void config_customlogo();
|
|
||||||
void config_verification();
|
void config_verification();
|
||||||
void config_backlight();
|
void config_backlight();
|
||||||
void config_auto_hos_poweroff();
|
void config_auto_hos_poweroff();
|
||||||
|
void config_nogc();
|
||||||
|
|
||||||
#endif /* _CONFIG_H_ */
|
#endif /* _CONFIG_H_ */
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* 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
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -24,11 +24,48 @@
|
|||||||
|
|
||||||
static char *_strdup(char *str)
|
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);
|
char *res = (char *)malloc(strlen(str) + 1);
|
||||||
strcpy(res, str);
|
strcpy(res, str);
|
||||||
|
|
||||||
|
// Remove trailing space.
|
||||||
|
if (strlen(res) && res[strlen(res) - 1] == ' ')
|
||||||
|
res[strlen(res) - 1] = 0;
|
||||||
|
|
||||||
return res;
|
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++)
|
||||||
|
;
|
||||||
|
lbuf[i] = 0;
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
ini_sec_t *_ini_create_section(link_t *dst, ini_sec_t *csec, char *name, u8 type)
|
||||||
|
{
|
||||||
|
if (csec)
|
||||||
|
{
|
||||||
|
list_append(dst, &csec->link);
|
||||||
|
csec = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
csec = (ini_sec_t *)malloc(sizeof(ini_sec_t));
|
||||||
|
csec->name = _strdup(name);
|
||||||
|
csec->type = type;
|
||||||
|
|
||||||
|
return csec;
|
||||||
|
}
|
||||||
|
|
||||||
int ini_parse(link_t *dst, char *ini_path, bool is_dir)
|
int ini_parse(link_t *dst, char *ini_path, bool is_dir)
|
||||||
{
|
{
|
||||||
u32 lblen;
|
u32 lblen;
|
||||||
@@ -43,6 +80,7 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
|
|||||||
|
|
||||||
memcpy(filename, ini_path, pathlen + 1);
|
memcpy(filename, ini_path, pathlen + 1);
|
||||||
|
|
||||||
|
// Get all ini filenames.
|
||||||
if (is_dir)
|
if (is_dir)
|
||||||
{
|
{
|
||||||
filelist = dirlist(filename, "*.ini", false);
|
filelist = dirlist(filename, "*.ini", false);
|
||||||
@@ -57,6 +95,7 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
|
|||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
// Copy ini filename in path string.
|
||||||
if (is_dir)
|
if (is_dir)
|
||||||
{
|
{
|
||||||
if (filelist[k * 256])
|
if (filelist[k * 256])
|
||||||
@@ -68,6 +107,7 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Open ini.
|
||||||
if (f_open(&fp, filename, FA_READ) != FR_OK)
|
if (f_open(&fp, filename, FA_READ) != FR_OK)
|
||||||
{
|
{
|
||||||
free(filelist);
|
free(filelist);
|
||||||
@@ -89,75 +129,31 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
|
|||||||
|
|
||||||
if (lblen > 2 && lbuf[0] == '[') // Create new section.
|
if (lblen > 2 && lbuf[0] == '[') // Create new section.
|
||||||
{
|
{
|
||||||
if (csec)
|
_find_section_name(lbuf, lblen, ']');
|
||||||
{
|
|
||||||
list_append(dst, &csec->link);
|
|
||||||
csec = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 i;
|
csec = _ini_create_section(dst, csec, &lbuf[1], INI_CHOICE);
|
||||||
for (i = 0; i < lblen && lbuf[i] != ']' && lbuf[i] != '\n' && lbuf[i] != '\r'; i++)
|
|
||||||
;
|
|
||||||
lbuf[i] = 0;
|
|
||||||
|
|
||||||
csec = (ini_sec_t *)malloc(sizeof(ini_sec_t));
|
|
||||||
csec->name = _strdup(&lbuf[1]);
|
|
||||||
csec->type = INI_CHOICE;
|
|
||||||
list_init(&csec->kvs);
|
list_init(&csec->kvs);
|
||||||
}
|
}
|
||||||
else if (lblen > 2 && lbuf[0] == '{') //Create new caption.
|
else if (lblen > 2 && lbuf[0] == '{') //Create new caption.
|
||||||
{
|
{
|
||||||
if (csec)
|
_find_section_name(lbuf, lblen, '}');
|
||||||
{
|
|
||||||
list_append(dst, &csec->link);
|
|
||||||
csec = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 i;
|
csec = _ini_create_section(dst, csec, &lbuf[1], INI_CAPTION);
|
||||||
for (i = 0; i < lblen && lbuf[i] != '}' && lbuf[i] != '\n' && lbuf[i] != '\r'; i++)
|
|
||||||
;
|
|
||||||
lbuf[i] = 0;
|
|
||||||
|
|
||||||
csec = (ini_sec_t *)malloc(sizeof(ini_sec_t));
|
|
||||||
csec->name = _strdup(&lbuf[1]);
|
|
||||||
csec->type = INI_CAPTION;
|
|
||||||
csec->color = 0xFF0AB9E6;
|
csec->color = 0xFF0AB9E6;
|
||||||
}
|
}
|
||||||
else if (lblen > 2 && lbuf[0] == '#') //Create empty lines and comments.
|
else if (lblen > 2 && lbuf[0] == '#') //Create empty lines and comments.
|
||||||
{
|
{
|
||||||
if (csec)
|
_find_section_name(lbuf, lblen, '\0');
|
||||||
{
|
|
||||||
list_append(dst, &csec->link);
|
|
||||||
csec = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 i;
|
csec = _ini_create_section(dst, csec, &lbuf[1], INI_COMMENT);
|
||||||
for (i = 0; i < lblen && lbuf[i] != '\n' && lbuf[i] != '\r'; i++)
|
|
||||||
;
|
|
||||||
lbuf[i] = 0;
|
|
||||||
|
|
||||||
csec = (ini_sec_t *)malloc(sizeof(ini_sec_t));
|
|
||||||
csec->name = _strdup(&lbuf[1]);
|
|
||||||
csec->type = INI_COMMENT;
|
|
||||||
}
|
}
|
||||||
else if (lblen < 2)
|
else if (lblen < 2)
|
||||||
{
|
{
|
||||||
if (csec)
|
csec = _ini_create_section(dst, csec, NULL, INI_NEWLINE);
|
||||||
{
|
|
||||||
list_append(dst, &csec->link);
|
|
||||||
csec = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
csec = (ini_sec_t *)malloc(sizeof(ini_sec_t));
|
|
||||||
csec->name = NULL;
|
|
||||||
csec->type = INI_NEWLINE;
|
|
||||||
}
|
}
|
||||||
else if (csec && csec->type == INI_CHOICE) //Extract key/value.
|
else if (csec && csec->type == INI_CHOICE) //Extract key/value.
|
||||||
{
|
{
|
||||||
u32 i;
|
u32 i = _find_section_name(lbuf, lblen, '=');
|
||||||
for (i = 0; i < lblen && lbuf[i] != '=' && lbuf[i] != '\n' && lbuf[i] != '\r'; i++)
|
|
||||||
;
|
|
||||||
lbuf[i] = 0;
|
|
||||||
|
|
||||||
ini_kv_t *kv = (ini_kv_t *)malloc(sizeof(ini_kv_t));
|
ini_kv_t *kv = (ini_kv_t *)malloc(sizeof(ini_kv_t));
|
||||||
kv->key = _strdup(&lbuf[0]);
|
kv->key = _strdup(&lbuf[0]);
|
||||||
@@ -169,8 +165,11 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
|
|||||||
f_close(&fp);
|
f_close(&fp);
|
||||||
|
|
||||||
if (csec)
|
if (csec)
|
||||||
|
{
|
||||||
list_append(dst, &csec->link);
|
list_append(dst, &csec->link);
|
||||||
|
if (is_dir)
|
||||||
|
csec = NULL;
|
||||||
|
}
|
||||||
} while (is_dir);
|
} while (is_dir);
|
||||||
|
|
||||||
free(filename);
|
free(filename);
|
||||||
@@ -179,82 +178,16 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
|
|||||||
return 1;
|
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 *ini_check_payload_section(ini_sec_t *cfg)
|
||||||
{
|
{
|
||||||
char *path = NULL;
|
|
||||||
|
|
||||||
if (cfg == NULL)
|
if (cfg == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg->kvs, link)
|
LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg->kvs, link)
|
||||||
{
|
{
|
||||||
if (!strcmp("payload", kv->key))
|
if (!strcmp("payload", kv->key))
|
||||||
{
|
return kv->val;
|
||||||
if (!path)
|
|
||||||
path = _strdup(kv->val);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (path)
|
|
||||||
return path;
|
|
||||||
else
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,9 +44,6 @@ typedef struct _ini_sec_t
|
|||||||
} ini_sec_t;
|
} ini_sec_t;
|
||||||
|
|
||||||
int ini_parse(link_t *dst, char *ini_path, bool is_dir);
|
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);
|
char *ini_check_payload_section(ini_sec_t *cfg);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
* Copyright (c) 2018 Rajko Stojadinovic
|
* 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
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -31,129 +31,119 @@
|
|||||||
#include "../utils/btn.h"
|
#include "../utils/btn.h"
|
||||||
#include "../utils/util.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_t sd_sdmmc;
|
||||||
extern sdmmc_storage_t sd_storage;
|
extern sdmmc_storage_t sd_storage;
|
||||||
extern FATFS sd_fs;
|
extern FATFS sd_fs;
|
||||||
extern hekate_config h_cfg;
|
extern hekate_config h_cfg;
|
||||||
extern gfx_ctxt_t gfx_ctxt;
|
|
||||||
extern gfx_con_t gfx_con;
|
|
||||||
|
|
||||||
extern bool sd_mount();
|
extern bool sd_mount();
|
||||||
extern void sd_unmount();
|
extern void sd_unmount();
|
||||||
extern void emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage);
|
extern void emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage);
|
||||||
|
|
||||||
//TODO: Create more macros (info, header, debug, etc) with different colors and utilize them for consistency.
|
#pragma GCC push_options
|
||||||
#define EPRINTF(text) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFF0000, 0xFFCCCCCC)
|
#pragma GCC optimize ("Os")
|
||||||
#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)
|
|
||||||
|
|
||||||
static int _dump_emmc_verify(sdmmc_storage_t *storage, u32 lba_curr, char *outFilename, emmc_part_t *part)
|
static int _dump_emmc_verify(sdmmc_storage_t *storage, u32 lba_curr, char *outFilename, emmc_part_t *part)
|
||||||
{
|
{
|
||||||
FIL fp;
|
FIL fp;
|
||||||
|
u8 sparseShouldVerify = 4;
|
||||||
u32 btn = 0;
|
u32 btn = 0;
|
||||||
u32 prevPct = 200;
|
u32 prevPct = 200;
|
||||||
|
u32 sdFileSector = 0;
|
||||||
int res = 0;
|
int res = 0;
|
||||||
|
|
||||||
u8 hashEm[0x20];
|
u8 hashEm[SHA256_SZ];
|
||||||
u8 hashSd[0x20];
|
u8 hashSd[SHA256_SZ];
|
||||||
|
|
||||||
if (f_open(&fp, outFilename, FA_READ) == FR_OK)
|
if (f_open(&fp, outFilename, FA_READ) == FR_OK)
|
||||||
{
|
{
|
||||||
u32 totalSectorsVer = (u32)((u64)f_size(&fp) >> (u64)9);
|
u32 totalSectorsVer = (u32)((u64)f_size(&fp) >> (u64)9);
|
||||||
|
|
||||||
u32 numSectorsPerIter = 0;
|
u8 *bufEm = (u8 *)EMMC_BUF_ALIGNED;
|
||||||
if (totalSectorsVer > 0x200000)
|
u8 *bufSd = (u8 *)SDXC_BUF_ALIGNED;
|
||||||
numSectorsPerIter = 8192; //4MB Cache
|
|
||||||
else
|
|
||||||
numSectorsPerIter = 512; //256KB Cache
|
|
||||||
|
|
||||||
u8 *bufEm = (u8 *)calloc(numSectorsPerIter, NX_EMMC_BLOCKSIZE);
|
|
||||||
u8 *bufSd = (u8 *)calloc(numSectorsPerIter, NX_EMMC_BLOCKSIZE);
|
|
||||||
|
|
||||||
u32 pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);
|
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;
|
u32 num = 0;
|
||||||
while (totalSectorsVer > 0)
|
while (totalSectorsVer > 0)
|
||||||
{
|
{
|
||||||
num = MIN(totalSectorsVer, numSectorsPerIter);
|
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 (!sdmmc_storage_read(storage, lba_curr, num, bufEm))
|
if (!sdmmc_storage_read(storage, lba_curr, num, bufEm))
|
||||||
{
|
{
|
||||||
gfx_con.fntsz = 16;
|
gfx_con.fntsz = 16;
|
||||||
EPRINTFARGS("\nFailed to read %d blocks (@LBA %08X),\nfrom eMMC!\n\nVerification failed..\n",
|
EPRINTFARGS("\nFailed to read %d blocks (@LBA %08X),\nfrom eMMC!\n\nVerification failed..\n",
|
||||||
num, lba_curr);
|
num, lba_curr);
|
||||||
|
|
||||||
free(bufEm);
|
|
||||||
free(bufSd);
|
|
||||||
f_close(&fp);
|
f_close(&fp);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
f_lseek(&fp, (u64)sdFileSector << (u64)9);
|
||||||
if (f_read(&fp, bufSd, num << 9, NULL))
|
if (f_read(&fp, bufSd, num << 9, NULL))
|
||||||
{
|
{
|
||||||
gfx_con.fntsz = 16;
|
gfx_con.fntsz = 16;
|
||||||
EPRINTFARGS("\nFailed to read %d blocks (@LBA %08X),\nfrom sd card!\n\nVerification failed..\n", num, lba_curr);
|
EPRINTFARGS("\nFailed to read %d blocks (@LBA %08X),\nfrom sd card!\n\nVerification failed..\n", num, lba_curr);
|
||||||
|
|
||||||
free(bufEm);
|
|
||||||
free(bufSd);
|
|
||||||
f_close(&fp);
|
f_close(&fp);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (h_cfg.verification)
|
se_calc_sha256(hashEm, bufEm, num << 9);
|
||||||
{
|
se_calc_sha256(hashSd, bufSd, num << 9);
|
||||||
case 1:
|
|
||||||
res = memcmp32sparse((u32 *)bufEm, (u32 *)bufSd, num << 9);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
default:
|
|
||||||
se_calc_sha256(&hashEm, bufEm, num << 9);
|
|
||||||
se_calc_sha256(&hashSd, bufSd, num << 9);
|
|
||||||
res = memcmp(hashEm, hashSd, 0x10);
|
res = memcmp(hashEm, hashSd, 0x10);
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (res)
|
if (res)
|
||||||
{
|
{
|
||||||
gfx_con.fntsz = 16;
|
gfx_con.fntsz = 16;
|
||||||
EPRINTFARGS("\nSD card and eMMC data (@LBA %08X),\ndo not match!\n\nVerification failed..\n", lba_curr);
|
EPRINTFARGS("\nSD and eMMC data (@LBA %08X),\ndo not match!\n\nVerification failed..\n", lba_curr);
|
||||||
|
|
||||||
free(bufEm);
|
|
||||||
free(bufSd);
|
|
||||||
f_close(&fp);
|
f_close(&fp);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);
|
pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);
|
||||||
if (pct != prevPct)
|
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;
|
prevPct = pct;
|
||||||
}
|
}
|
||||||
|
|
||||||
lba_curr += num;
|
lba_curr += num;
|
||||||
totalSectorsVer -= num;
|
totalSectorsVer -= num;
|
||||||
|
sdFileSector += num;
|
||||||
|
sparseShouldVerify++;
|
||||||
|
|
||||||
btn = btn_wait_timeout(0, BTN_VOL_DOWN | BTN_VOL_UP);
|
btn = btn_wait_timeout(0, BTN_VOL_DOWN | BTN_VOL_UP);
|
||||||
if ((btn & BTN_VOL_DOWN) && (btn & BTN_VOL_UP))
|
if ((btn & BTN_VOL_DOWN) && (btn & BTN_VOL_UP))
|
||||||
{
|
{
|
||||||
gfx_con.fntsz = 16;
|
gfx_con.fntsz = 16;
|
||||||
WPRINTF("\n\nThe verification was cancelled!");
|
WPRINTF("\n\nVerification was cancelled!");
|
||||||
EPRINTF("\nPress any key...\n");
|
gfx_con.fntsz = 8;
|
||||||
msleep(1500);
|
msleep(1000);
|
||||||
|
|
||||||
free(bufEm);
|
|
||||||
free(bufSd);
|
|
||||||
f_close(&fp);
|
f_close(&fp);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(bufEm);
|
|
||||||
free(bufSd);
|
|
||||||
f_close(&fp);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -165,6 +155,17 @@ static int _dump_emmc_verify(sdmmc_storage_t *storage, u32 lba_curr, char *outFi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _update_filename(char *outFilename, u32 sdPathLen, u32 numSplitParts, u32 currPartIdx)
|
||||||
|
{
|
||||||
|
if (numSplitParts >= 10 && currPartIdx < 10)
|
||||||
|
{
|
||||||
|
outFilename[sdPathLen] = '0';
|
||||||
|
itoa(currPartIdx, &outFilename[sdPathLen + 1], 10);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
itoa(currPartIdx, &outFilename[sdPathLen], 10);
|
||||||
|
}
|
||||||
|
|
||||||
static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
|
static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
|
||||||
{
|
{
|
||||||
static const u32 FAT32_FILESIZE_LIMIT = 0xFFFFFFFF;
|
static const u32 FAT32_FILESIZE_LIMIT = 0xFFFFFFFF;
|
||||||
@@ -187,7 +188,7 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
|
|||||||
memcpy(partialIdxFilename, "partial.idx", 12);
|
memcpy(partialIdxFilename, "partial.idx", 12);
|
||||||
|
|
||||||
gfx_con.fntsz = 8;
|
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,
|
sd_fs.free_clst * sd_fs.csize >> SECTORS_TO_MIB_COEFF,
|
||||||
totalSectors >> SECTORS_TO_MIB_COEFF);
|
totalSectors >> SECTORS_TO_MIB_COEFF);
|
||||||
|
|
||||||
@@ -195,14 +196,14 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
|
|||||||
if ((sd_storage.csd.capacity >> (20 - sd_storage.csd.read_blkbits)) <= 8192)
|
if ((sd_storage.csd.capacity >> (20 - sd_storage.csd.read_blkbits)) <= 8192)
|
||||||
multipartSplitSize = (1u << 30);
|
multipartSplitSize = (1u << 30);
|
||||||
// Maximum parts fitting the free space available.
|
// Maximum parts fitting the free space available.
|
||||||
maxSplitParts = (sd_fs.free_clst * sd_fs.csize) / (multipartSplitSize / 512);
|
maxSplitParts = (sd_fs.free_clst * sd_fs.csize) / (multipartSplitSize / NX_EMMC_BLOCKSIZE);
|
||||||
|
|
||||||
// Check if the USER partition or the RAW eMMC fits the sd card free space.
|
// Check if the USER partition or the RAW eMMC fits the sd card free space.
|
||||||
if (totalSectors > (sd_fs.free_clst * sd_fs.csize))
|
if (totalSectors > (sd_fs.free_clst * sd_fs.csize))
|
||||||
{
|
{
|
||||||
isSmallSdCard = true;
|
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 total backup size.%k\n", 0xFFFFBA00, 0xFFCCCCCC);
|
||||||
|
|
||||||
if (!maxSplitParts)
|
if (!maxSplitParts)
|
||||||
{
|
{
|
||||||
@@ -215,7 +216,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.
|
// 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))
|
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;
|
partialDumpInProgress = true;
|
||||||
// Force partial dumping, even if the card is larger.
|
// Force partial dumping, even if the card is larger.
|
||||||
@@ -236,42 +237,22 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
|
|||||||
maxSplitParts += currPartIdx;
|
maxSplitParts += currPartIdx;
|
||||||
}
|
}
|
||||||
else if (isSmallSdCard)
|
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.
|
// 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;
|
u32 multipartSplitSectors = multipartSplitSize / NX_EMMC_BLOCKSIZE;
|
||||||
numSplitParts = (totalSectors + multipartSplitSectors - 1) / multipartSplitSectors;
|
numSplitParts = (totalSectors + multipartSplitSectors - 1) / multipartSplitSectors;
|
||||||
|
|
||||||
outFilename[sdPathLen++] = '.';
|
outFilename[sdPathLen++] = '.';
|
||||||
|
|
||||||
if (!partialDumpInProgress)
|
|
||||||
{
|
|
||||||
outFilename[sdPathLen] = '0';
|
|
||||||
if (numSplitParts >= 10)
|
|
||||||
{
|
|
||||||
outFilename[sdPathLen + 1] = '0';
|
|
||||||
outFilename[sdPathLen + 2] = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
outFilename[sdPathLen + 1] = 0;
|
|
||||||
}
|
|
||||||
// Continue from where we left, if Partial Backup in progress.
|
// Continue from where we left, if Partial Backup in progress.
|
||||||
else
|
_update_filename(outFilename, sdPathLen, numSplitParts, partialDumpInProgress ? currPartIdx : 0);
|
||||||
{
|
|
||||||
if (numSplitParts >= 10 && currPartIdx < 10)
|
|
||||||
{
|
|
||||||
outFilename[sdPathLen] = '0';
|
|
||||||
itoa(currPartIdx, &outFilename[sdPathLen + 1], 10);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
itoa(currPartIdx, &outFilename[sdPathLen], 10);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FIL fp;
|
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))
|
if (!f_open(&fp, outFilename, FA_READ))
|
||||||
{
|
{
|
||||||
f_close(&fp);
|
f_close(&fp);
|
||||||
@@ -284,10 +265,10 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
|
|||||||
if (!(btn_wait() & BTN_POWER))
|
if (!(btn_wait() & BTN_POWER))
|
||||||
return 0;
|
return 0;
|
||||||
gfx_con.fntsz = 8;
|
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_con_setpos(gfx_con.savedx, gfx_con.savedy);
|
||||||
gfx_printf(&gfx_con, "Filename: %s\n\n", outFilename);
|
gfx_printf("Filename: %s\n\n", outFilename);
|
||||||
res = f_open(&fp, outFilename, FA_CREATE_ALWAYS | FA_WRITE);
|
res = f_open(&fp, outFilename, FA_CREATE_ALWAYS | FA_WRITE);
|
||||||
if (res)
|
if (res)
|
||||||
{
|
{
|
||||||
@@ -297,12 +278,7 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 numSectorsPerIter = 0;
|
u8 *buf = (u8 *)MIXD_BUF_ALIGNED;
|
||||||
if (totalSectors > 0x200000)
|
|
||||||
numSectorsPerIter = 8192;
|
|
||||||
else
|
|
||||||
numSectorsPerIter = 512;
|
|
||||||
u8 *buf = (u8 *)calloc(numSectorsPerIter, NX_EMMC_BLOCKSIZE);
|
|
||||||
|
|
||||||
u32 lba_curr = part->lba_start;
|
u32 lba_curr = part->lba_start;
|
||||||
u32 lbaStartPart = part->lba_start;
|
u32 lbaStartPart = part->lba_start;
|
||||||
@@ -318,7 +294,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.
|
lbaStartPart = lba_curr; // Update the start LBA for verification.
|
||||||
}
|
}
|
||||||
u64 totalSize = (u64)((u64)totalSectors << 9);
|
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);
|
f_lseek(&fp, totalSize);
|
||||||
else
|
else
|
||||||
f_lseek(&fp, MIN(totalSize, multipartSplitSize));
|
f_lseek(&fp, MIN(totalSize, multipartSplitSize));
|
||||||
@@ -341,18 +317,11 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
|
|||||||
{
|
{
|
||||||
EPRINTF("\nPress any key and try again...\n");
|
EPRINTF("\nPress any key and try again...\n");
|
||||||
|
|
||||||
free(buf);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (numSplitParts >= 10 && currPartIdx < 10)
|
_update_filename(outFilename, sdPathLen, numSplitParts, currPartIdx);
|
||||||
{
|
|
||||||
outFilename[sdPathLen] = '0';
|
|
||||||
itoa(currPartIdx, &outFilename[sdPathLen + 1], 10);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
itoa(currPartIdx, &outFilename[sdPathLen], 10);
|
|
||||||
|
|
||||||
// Always create partial.idx before next part, in case a fatal error occurs.
|
// Always create partial.idx before next part, in case a fatal error occurs.
|
||||||
if (isSmallSdCard)
|
if (isSmallSdCard)
|
||||||
@@ -368,28 +337,26 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
|
|||||||
gfx_con.fntsz = 16;
|
gfx_con.fntsz = 16;
|
||||||
EPRINTF("\nError creating partial.idx file.\n");
|
EPRINTF("\nError creating partial.idx file.\n");
|
||||||
|
|
||||||
free(buf);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// More parts to backup that do not currently fit the sd card free space or fatal error.
|
// More parts to backup that do not currently fit the sd card free space or fatal error.
|
||||||
if (currPartIdx >= maxSplitParts)
|
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\
|
2. Remove SD Card and move files to free space.\n\
|
||||||
Don\'t move the partial.idx file!\n\
|
Don\'t move the partial.idx file!\n\
|
||||||
3. Re-insert SD Card.\n\
|
3. Re-insert SD Card.\n\
|
||||||
4. Select the SAME option again to continue.\n");
|
4. Select the SAME option again to continue.\n");
|
||||||
gfx_con.fntsz = 16;
|
gfx_con.fntsz = 16;
|
||||||
|
|
||||||
free(buf);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create next part.
|
// Create next part.
|
||||||
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
|
gfx_con_setpos(gfx_con.savedx, gfx_con.savedy);
|
||||||
gfx_printf(&gfx_con, "Filename: %s\n\n", outFilename);
|
gfx_printf("Filename: %s\n\n", outFilename);
|
||||||
lbaStartPart = lba_curr;
|
lbaStartPart = lba_curr;
|
||||||
res = f_open(&fp, outFilename, FA_CREATE_ALWAYS | FA_WRITE);
|
res = f_open(&fp, outFilename, FA_CREATE_ALWAYS | FA_WRITE);
|
||||||
if (res)
|
if (res)
|
||||||
@@ -397,9 +364,9 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
|
|||||||
gfx_con.fntsz = 16;
|
gfx_con.fntsz = 16;
|
||||||
EPRINTFARGS("Error (%d) creating file %s.\n", res, outFilename);
|
EPRINTFARGS("Error (%d) creating file %s.\n", res, outFilename);
|
||||||
|
|
||||||
free(buf);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bytesWritten = 0;
|
bytesWritten = 0;
|
||||||
|
|
||||||
totalSize = (u64)((u64)totalSectors << 9);
|
totalSize = (u64)((u64)totalSectors << 9);
|
||||||
@@ -408,7 +375,7 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
|
|||||||
}
|
}
|
||||||
|
|
||||||
retryCount = 0;
|
retryCount = 0;
|
||||||
num = MIN(totalSectors, numSectorsPerIter);
|
num = MIN(totalSectors, NUM_SECTORS_PER_ITER);
|
||||||
while (!sdmmc_storage_read(storage, lba_curr, num, buf))
|
while (!sdmmc_storage_read(storage, lba_curr, num, buf))
|
||||||
{
|
{
|
||||||
EPRINTFARGS("Error reading %d blocks @ LBA %08X,\nfrom eMMC (try %d), retrying...",
|
EPRINTFARGS("Error reading %d blocks @ LBA %08X,\nfrom eMMC (try %d), retrying...",
|
||||||
@@ -422,7 +389,6 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
|
|||||||
num, lba_curr);
|
num, lba_curr);
|
||||||
EPRINTF("\nPress any key and try again...\n");
|
EPRINTF("\nPress any key and try again...\n");
|
||||||
|
|
||||||
free(buf);
|
|
||||||
f_close(&fp);
|
f_close(&fp);
|
||||||
f_unlink(outFilename);
|
f_unlink(outFilename);
|
||||||
|
|
||||||
@@ -436,7 +402,6 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
|
|||||||
EPRINTFARGS("\nFatal error (%d) when writing to SD Card", res);
|
EPRINTFARGS("\nFatal error (%d) when writing to SD Card", res);
|
||||||
EPRINTF("\nPress any key and try again...\n");
|
EPRINTF("\nPress any key and try again...\n");
|
||||||
|
|
||||||
free(buf);
|
|
||||||
f_close(&fp);
|
f_close(&fp);
|
||||||
f_unlink(outFilename);
|
f_unlink(outFilename);
|
||||||
|
|
||||||
@@ -445,7 +410,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);
|
pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);
|
||||||
if (pct != prevPct)
|
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;
|
prevPct = pct;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -468,17 +433,15 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
|
|||||||
EPRINTF("\nPress any key...\n");
|
EPRINTF("\nPress any key...\n");
|
||||||
msleep(1500);
|
msleep(1500);
|
||||||
|
|
||||||
free(buf);
|
|
||||||
f_close(&fp);
|
f_close(&fp);
|
||||||
f_unlink(outFilename);
|
f_unlink(outFilename);
|
||||||
|
|
||||||
return 0;
|
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.
|
// Backup operation ended successfully.
|
||||||
free(buf);
|
|
||||||
f_close(&fp);
|
f_close(&fp);
|
||||||
|
|
||||||
if (h_cfg.verification)
|
if (h_cfg.verification)
|
||||||
@@ -491,7 +454,7 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
tui_pbar(&gfx_con, 0, gfx_con.y, 100, 0xFF96FF00, 0xFF155500);
|
tui_pbar(0, gfx_con.y, 100, 0xFF96FF00, 0xFF155500);
|
||||||
}
|
}
|
||||||
|
|
||||||
gfx_con.fntsz = 16;
|
gfx_con.fntsz = 16;
|
||||||
@@ -499,9 +462,9 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
|
|||||||
if (isSmallSdCard)
|
if (isSmallSdCard)
|
||||||
{
|
{
|
||||||
f_unlink(partialIdxFilename);
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -519,14 +482,14 @@ static void _dump_emmc_selected(emmcPartType_t dumpType)
|
|||||||
{
|
{
|
||||||
int res = 0;
|
int res = 0;
|
||||||
u32 timer = 0;
|
u32 timer = 0;
|
||||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||||
tui_sbar(&gfx_con, true);
|
tui_sbar(true);
|
||||||
gfx_con_setpos(&gfx_con, 0, 0);
|
gfx_con_setpos(0, 0);
|
||||||
|
|
||||||
if (!sd_mount())
|
if (!sd_mount())
|
||||||
goto out;
|
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.
|
// Get SD Card free space for Partial Backup.
|
||||||
f_getfree("", &sd_fs.free_clst, NULL);
|
f_getfree("", &sd_fs.free_clst, NULL);
|
||||||
|
|
||||||
@@ -539,7 +502,7 @@ static void _dump_emmc_selected(emmcPartType_t dumpType)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
char sdPath[80];
|
char sdPath[OUT_FILENAME_SZ];
|
||||||
// Create Restore folders, if they do not exist.
|
// Create Restore folders, if they do not exist.
|
||||||
emmcsn_path_impl(sdPath, "/restore", "", &storage);
|
emmcsn_path_impl(sdPath, "/restore", "", &storage);
|
||||||
emmcsn_path_impl(sdPath, "/restore/partitions", "", &storage);
|
emmcsn_path_impl(sdPath, "/restore/partitions", "", &storage);
|
||||||
@@ -559,7 +522,7 @@ static void _dump_emmc_selected(emmcPartType_t dumpType)
|
|||||||
bootPart.name[4] = (u8)('0' + i);
|
bootPart.name[4] = (u8)('0' + i);
|
||||||
bootPart.name[5] = 0;
|
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);
|
bootPart.name, bootPart.lba_start, bootPart.lba_end, 0xFFCCCCCC);
|
||||||
|
|
||||||
sdmmc_storage_set_mmc_partition(&storage, i + 1);
|
sdmmc_storage_set_mmc_partition(&storage, i + 1);
|
||||||
@@ -584,7 +547,7 @@ static void _dump_emmc_selected(emmcPartType_t dumpType)
|
|||||||
if ((dumpType & PART_SYSTEM) == 0 && strcmp(part->name, "USER"))
|
if ((dumpType & PART_SYSTEM) == 0 && strcmp(part->name, "USER"))
|
||||||
continue;
|
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);
|
part->name, part->lba_start, part->lba_end, 0xFFCCCCCC);
|
||||||
|
|
||||||
emmcsn_path_impl(sdPath, "/partitions", part->name, &storage);
|
emmcsn_path_impl(sdPath, "/partitions", part->name, &storage);
|
||||||
@@ -607,7 +570,7 @@ static void _dump_emmc_selected(emmcPartType_t dumpType)
|
|||||||
rawPart.lba_end = RAW_AREA_NUM_SECTORS - 1;
|
rawPart.lba_end = RAW_AREA_NUM_SECTORS - 1;
|
||||||
strcpy(rawPart.name, "rawnand.bin");
|
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);
|
rawPart.name, rawPart.lba_start, rawPart.lba_end, 0xFFCCCCCC);
|
||||||
|
|
||||||
emmcsn_path_impl(sdPath, "", rawPart.name, &storage);
|
emmcsn_path_impl(sdPath, "", rawPart.name, &storage);
|
||||||
@@ -616,14 +579,14 @@ static void _dump_emmc_selected(emmcPartType_t dumpType)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gfx_putc(&gfx_con, '\n');
|
gfx_putc('\n');
|
||||||
timer = get_tmr_s() - timer;
|
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);
|
sdmmc_storage_end(&storage);
|
||||||
if (res && h_cfg.verification)
|
if (res && h_cfg.verification)
|
||||||
gfx_printf(&gfx_con, "\n%kFinished and verified!%k\nPress any key...\n", 0xFF96FF00, 0xFFCCCCCC);
|
gfx_printf("\n%kFinished and verified!%k\nPress any key...\n", 0xFF96FF00, 0xFFCCCCCC);
|
||||||
else if (res)
|
else if (res)
|
||||||
gfx_printf(&gfx_con, "\nFinished! Press any key...\n");
|
gfx_printf("\nFinished! Press any key...\n");
|
||||||
|
|
||||||
out:
|
out:
|
||||||
sd_unmount();
|
sd_unmount();
|
||||||
@@ -635,21 +598,77 @@ void dump_emmc_user() { _dump_emmc_selected(PART_USER); }
|
|||||||
void dump_emmc_boot() { _dump_emmc_selected(PART_BOOT); }
|
void dump_emmc_boot() { _dump_emmc_selected(PART_BOOT); }
|
||||||
void dump_emmc_rawnand() { _dump_emmc_selected(PART_RAW); }
|
void dump_emmc_rawnand() { _dump_emmc_selected(PART_RAW); }
|
||||||
|
|
||||||
static int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
|
static int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part, bool allow_multi_part)
|
||||||
{
|
{
|
||||||
static const u32 SECTORS_TO_MIB_COEFF = 11;
|
static const u32 SECTORS_TO_MIB_COEFF = 11;
|
||||||
|
|
||||||
u32 totalSectors = part->lba_end - part->lba_start + 1;
|
u32 totalSectors = part->lba_end - part->lba_start + 1;
|
||||||
|
u32 currPartIdx = 0;
|
||||||
|
u32 numSplitParts = 0;
|
||||||
u32 lbaStartPart = part->lba_start;
|
u32 lbaStartPart = part->lba_start;
|
||||||
int res = 0;
|
int res = 0;
|
||||||
char *outFilename = sd_path;
|
char *outFilename = sd_path;
|
||||||
|
u32 sdPathLen = strlen(sd_path);
|
||||||
|
u64 fileSize = 0;
|
||||||
|
u64 totalCheckFileSize = 0;
|
||||||
gfx_con.fntsz = 8;
|
gfx_con.fntsz = 8;
|
||||||
|
|
||||||
FIL fp;
|
FIL fp;
|
||||||
gfx_printf(&gfx_con, "\nFilename: %s\n", outFilename);
|
FILINFO fno;
|
||||||
|
|
||||||
|
gfx_con_getpos(&gfx_con.savedx, &gfx_con.savedy);
|
||||||
|
|
||||||
|
bool use_multipart = false;
|
||||||
|
|
||||||
|
if (allow_multi_part)
|
||||||
|
{
|
||||||
|
// Check to see if there is a combined file and if so then use that.
|
||||||
|
if (f_stat(outFilename, &fno))
|
||||||
|
{
|
||||||
|
// If not, check if there are partial files and the total size matches.
|
||||||
|
gfx_printf("No single file, checking for part files...\n");
|
||||||
|
|
||||||
|
outFilename[sdPathLen++] = '.';
|
||||||
|
|
||||||
|
// Stat total size of the part files.
|
||||||
|
while ((u32)((u64)totalCheckFileSize >> (u64)9) != totalSectors)
|
||||||
|
{
|
||||||
|
_update_filename(outFilename, sdPathLen, 99, numSplitParts);
|
||||||
|
|
||||||
|
gfx_con_setpos(gfx_con.savedx, gfx_con.savedy);
|
||||||
|
gfx_printf("\nFilename: %s\n", outFilename);
|
||||||
|
|
||||||
|
if (f_stat(outFilename, &fno))
|
||||||
|
{
|
||||||
|
WPRINTFARGS("Error (%d) file not found '%s'. Aborting...\n", res, outFilename);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
totalCheckFileSize += (u64)fno.fsize;
|
||||||
|
|
||||||
|
numSplitParts++;
|
||||||
|
}
|
||||||
|
|
||||||
|
gfx_printf("\n%X sectors total.\n", (u32)((u64)totalCheckFileSize >> (u64)9));
|
||||||
|
|
||||||
|
if ((u32)((u64)totalCheckFileSize >> (u64)9) != totalSectors)
|
||||||
|
{
|
||||||
|
gfx_con.fntsz = 16;
|
||||||
|
EPRINTF("Size of SD Card split backups does not match,\neMMC's selected part size.\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
use_multipart = true;
|
||||||
|
_update_filename(outFilename, sdPathLen, numSplitParts, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
res = f_open(&fp, outFilename, FA_READ);
|
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)
|
||||||
{
|
{
|
||||||
if (res != FR_NO_FILE)
|
if (res != FR_NO_FILE)
|
||||||
@@ -660,8 +679,7 @@ static int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
//TODO: Should we keep this check?
|
else if (!use_multipart && (((u32)((u64)f_size(&fp) >> (u64)9)) != totalSectors)) // Check total restore size vs emmc size.
|
||||||
else if (((u32)((u64)f_size(&fp) >> (u64)9)) != totalSectors)
|
|
||||||
{
|
{
|
||||||
gfx_con.fntsz = 16;
|
gfx_con.fntsz = 16;
|
||||||
EPRINTF("Size of the SD Card backup does not match,\neMMC's selected part size.\n");
|
EPRINTF("Size of the SD Card backup does not match,\neMMC's selected part size.\n");
|
||||||
@@ -670,15 +688,13 @@ static int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
gfx_printf(&gfx_con, "\nTotal restore size: %d MiB.\n\n", ((u32)((u64)f_size(&fp) >> (u64)9)) >> SECTORS_TO_MIB_COEFF);
|
{
|
||||||
|
fileSize = (u64)f_size(&fp);
|
||||||
|
gfx_printf("\nTotal restore size: %d MiB.\n\n",
|
||||||
|
(u32)((use_multipart ? (u64)totalCheckFileSize : fileSize) >> (u64)9) >> SECTORS_TO_MIB_COEFF);
|
||||||
|
}
|
||||||
|
|
||||||
u32 numSectorsPerIter = 0;
|
u8 *buf = (u8 *)MIXD_BUF_ALIGNED;
|
||||||
if (totalSectors > 0x200000)
|
|
||||||
numSectorsPerIter = 8192; //4MB Cache
|
|
||||||
else
|
|
||||||
numSectorsPerIter = 512; //256KB Cache
|
|
||||||
|
|
||||||
u8 *buf = (u8 *)calloc(numSectorsPerIter, NX_EMMC_BLOCKSIZE);
|
|
||||||
|
|
||||||
u32 lba_curr = part->lba_start;
|
u32 lba_curr = part->lba_start;
|
||||||
u32 bytesWritten = 0;
|
u32 bytesWritten = 0;
|
||||||
@@ -687,10 +703,53 @@ static int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part
|
|||||||
|
|
||||||
u32 num = 0;
|
u32 num = 0;
|
||||||
u32 pct = 0;
|
u32 pct = 0;
|
||||||
|
|
||||||
|
gfx_con_getpos(&gfx_con.savedx, &gfx_con.savedy);
|
||||||
|
|
||||||
while (totalSectors > 0)
|
while (totalSectors > 0)
|
||||||
{
|
{
|
||||||
|
// If we have more than one part, check the size for the split parts and make sure that the bytes written is not more than that.
|
||||||
|
if (numSplitParts != 0 && bytesWritten >= fileSize)
|
||||||
|
{
|
||||||
|
// If we have more bytes written then close the file pointer and increase the part index we are using
|
||||||
|
f_close(&fp);
|
||||||
|
memset(&fp, 0, sizeof(fp));
|
||||||
|
currPartIdx++;
|
||||||
|
|
||||||
|
if (h_cfg.verification)
|
||||||
|
{
|
||||||
|
// Verify part.
|
||||||
|
if (_dump_emmc_verify(storage, lbaStartPart, outFilename, part))
|
||||||
|
{
|
||||||
|
EPRINTF("\nPress any key and try again...\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_update_filename(outFilename, sdPathLen, numSplitParts, currPartIdx);
|
||||||
|
|
||||||
|
// Read from next part.
|
||||||
|
gfx_con_setpos(gfx_con.savedx, gfx_con.savedy);
|
||||||
|
gfx_printf("Filename: %s\n\n", outFilename);
|
||||||
|
|
||||||
|
lbaStartPart = lba_curr;
|
||||||
|
|
||||||
|
// Try to open the next file part
|
||||||
|
res = f_open(&fp, outFilename, FA_READ);
|
||||||
|
if (res)
|
||||||
|
{
|
||||||
|
gfx_con.fntsz = 16;
|
||||||
|
EPRINTFARGS("Error (%d) opening file %s.\n", res, outFilename);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
fileSize = (u64)f_size(&fp);
|
||||||
|
bytesWritten = 0;
|
||||||
|
}
|
||||||
|
|
||||||
retryCount = 0;
|
retryCount = 0;
|
||||||
num = MIN(totalSectors, numSectorsPerIter);
|
num = MIN(totalSectors, NUM_SECTORS_PER_ITER);
|
||||||
|
|
||||||
res = f_read(&fp, buf, NX_EMMC_BLOCKSIZE * num, NULL);
|
res = f_read(&fp, buf, NX_EMMC_BLOCKSIZE * num, NULL);
|
||||||
if (res)
|
if (res)
|
||||||
@@ -699,7 +758,6 @@ static int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part
|
|||||||
EPRINTFARGS("\nFatal error (%d) when reading from SD Card", res);
|
EPRINTFARGS("\nFatal error (%d) when reading from SD Card", res);
|
||||||
EPRINTF("\nYour device may be in an inoperative state!\n\nPress any key and try again now...\n");
|
EPRINTF("\nYour device may be in an inoperative state!\n\nPress any key and try again now...\n");
|
||||||
|
|
||||||
free(buf);
|
|
||||||
f_close(&fp);
|
f_close(&fp);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -716,7 +774,6 @@ static int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part
|
|||||||
num, lba_curr);
|
num, lba_curr);
|
||||||
EPRINTF("\nYour device may be in an inoperative state!\n\nPress any key and try again...\n");
|
EPRINTF("\nYour device may be in an inoperative state!\n\nPress any key and try again...\n");
|
||||||
|
|
||||||
free(buf);
|
|
||||||
f_close(&fp);
|
f_close(&fp);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -724,7 +781,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);
|
pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);
|
||||||
if (pct != prevPct)
|
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;
|
prevPct = pct;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -732,10 +789,9 @@ static int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part
|
|||||||
totalSectors -= num;
|
totalSectors -= num;
|
||||||
bytesWritten += num * NX_EMMC_BLOCKSIZE;
|
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.
|
// Restore operation ended successfully.
|
||||||
free(buf);
|
|
||||||
f_close(&fp);
|
f_close(&fp);
|
||||||
|
|
||||||
if (h_cfg.verification)
|
if (h_cfg.verification)
|
||||||
@@ -748,11 +804,11 @@ static int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
tui_pbar(&gfx_con, 0, gfx_con.y, 100, 0xFF96FF00, 0xFF155500);
|
tui_pbar(0, gfx_con.y, 100, 0xFF96FF00, 0xFF155500);
|
||||||
}
|
}
|
||||||
|
|
||||||
gfx_con.fntsz = 16;
|
gfx_con.fntsz = 16;
|
||||||
gfx_puts(&gfx_con, "\n\n");
|
gfx_puts("\n\n");
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -761,33 +817,33 @@ static void _restore_emmc_selected(emmcPartType_t restoreType)
|
|||||||
{
|
{
|
||||||
int res = 0;
|
int res = 0;
|
||||||
u32 timer = 0;
|
u32 timer = 0;
|
||||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||||
tui_sbar(&gfx_con, true);
|
tui_sbar(true);
|
||||||
gfx_con_setpos(&gfx_con, 0, 0);
|
gfx_con_setpos(0, 0);
|
||||||
|
|
||||||
gfx_printf(&gfx_con, "%kThis is a dangerous operation\nand may render your device inoperative!\n\n", 0xFFFFDD00);
|
gfx_printf("%kThis may render your device inoperative!\n\n", 0xFFFFDD00);
|
||||||
gfx_printf(&gfx_con, "Are you really sure?\n\n%k", 0xFFCCCCCC);
|
gfx_printf("Are you really sure?\n\n%k", 0xFFCCCCCC);
|
||||||
if ((restoreType & PART_BOOT) || (restoreType & PART_GP_ALL))
|
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)
|
if (restoreType & PART_BOOT)
|
||||||
gfx_puts(&gfx_con, "boot ");
|
gfx_puts("boot ");
|
||||||
gfx_puts(&gfx_con, "partitions that it can find.\n");
|
gfx_puts("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("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 value = 10;
|
u8 failsafe_wait = 10;
|
||||||
while (value > 0)
|
while (failsafe_wait > 0)
|
||||||
{
|
{
|
||||||
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
|
gfx_con_setpos(gfx_con.savedx, gfx_con.savedy);
|
||||||
gfx_printf(&gfx_con, "%kWait... (%ds) %k", 0xFF888888, value, 0xFFCCCCCC);
|
gfx_printf("%kWait... (%ds) %k", 0xFF888888, failsafe_wait, 0xFFCCCCCC);
|
||||||
msleep(1000);
|
msleep(1000);
|
||||||
value--;
|
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();
|
u32 btn = btn_wait();
|
||||||
if (!(btn & BTN_POWER))
|
if (!(btn & BTN_POWER))
|
||||||
@@ -805,7 +861,7 @@ static void _restore_emmc_selected(emmcPartType_t restoreType)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
char sdPath[80];
|
char sdPath[OUT_FILENAME_SZ];
|
||||||
|
|
||||||
timer = get_tmr_s();
|
timer = get_tmr_s();
|
||||||
if (restoreType & PART_BOOT)
|
if (restoreType & PART_BOOT)
|
||||||
@@ -822,13 +878,13 @@ static void _restore_emmc_selected(emmcPartType_t restoreType)
|
|||||||
bootPart.name[4] = (u8)('0' + i);
|
bootPart.name[4] = (u8)('0' + i);
|
||||||
bootPart.name[5] = 0;
|
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);
|
bootPart.name, bootPart.lba_start, bootPart.lba_end, 0xFFCCCCCC);
|
||||||
|
|
||||||
sdmmc_storage_set_mmc_partition(&storage, i + 1);
|
sdmmc_storage_set_mmc_partition(&storage, i + 1);
|
||||||
|
|
||||||
emmcsn_path_impl(sdPath, "/restore", bootPart.name, &storage);
|
emmcsn_path_impl(sdPath, "/restore", bootPart.name, &storage);
|
||||||
res = _restore_emmc_part(sdPath, &storage, &bootPart);
|
res = _restore_emmc_part(sdPath, &storage, &bootPart, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -840,11 +896,11 @@ static void _restore_emmc_selected(emmcPartType_t restoreType)
|
|||||||
nx_emmc_gpt_parse(&gpt, &storage);
|
nx_emmc_gpt_parse(&gpt, &storage);
|
||||||
LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link)
|
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);
|
part->name, part->lba_start, part->lba_end, 0xFFCCCCCC);
|
||||||
|
|
||||||
emmcsn_path_impl(sdPath, "/restore/partitions/", part->name, &storage);
|
emmcsn_path_impl(sdPath, "/restore/partitions/", part->name, &storage);
|
||||||
res = _restore_emmc_part(sdPath, &storage, part);
|
res = _restore_emmc_part(sdPath, &storage, part, false);
|
||||||
}
|
}
|
||||||
nx_emmc_gpt_free(&gpt);
|
nx_emmc_gpt_free(&gpt);
|
||||||
}
|
}
|
||||||
@@ -860,22 +916,22 @@ static void _restore_emmc_selected(emmcPartType_t restoreType)
|
|||||||
rawPart.lba_end = RAW_AREA_NUM_SECTORS - 1;
|
rawPart.lba_end = RAW_AREA_NUM_SECTORS - 1;
|
||||||
strcpy(rawPart.name, "rawnand.bin");
|
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);
|
rawPart.name, rawPart.lba_start, rawPart.lba_end, 0xFFCCCCCC);
|
||||||
|
|
||||||
emmcsn_path_impl(sdPath, "/restore", rawPart.name, &storage);
|
emmcsn_path_impl(sdPath, "/restore", rawPart.name, &storage);
|
||||||
res = _restore_emmc_part(sdPath, &storage, &rawPart);
|
res = _restore_emmc_part(sdPath, &storage, &rawPart, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gfx_putc(&gfx_con, '\n');
|
gfx_putc('\n');
|
||||||
timer = get_tmr_s() - timer;
|
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);
|
sdmmc_storage_end(&storage);
|
||||||
if (res && h_cfg.verification)
|
if (res && h_cfg.verification)
|
||||||
gfx_printf(&gfx_con, "\n%kFinished and verified!%k\nPress any key...\n", 0xFF96FF00, 0xFFCCCCCC);
|
gfx_printf("\n%kFinished and verified!%k\nPress any key...\n", 0xFF96FF00, 0xFFCCCCCC);
|
||||||
else if (res)
|
else if (res)
|
||||||
gfx_printf(&gfx_con, "\nFinished! Press any key...\n");
|
gfx_printf("\nFinished! Press any key...\n");
|
||||||
|
|
||||||
out:
|
out:
|
||||||
sd_unmount();
|
sd_unmount();
|
||||||
@@ -885,3 +941,5 @@ out:
|
|||||||
void restore_emmc_boot() { _restore_emmc_selected(PART_BOOT); }
|
void restore_emmc_boot() { _restore_emmc_selected(PART_BOOT); }
|
||||||
void restore_emmc_rawnand() { _restore_emmc_selected(PART_RAW); }
|
void restore_emmc_rawnand() { _restore_emmc_selected(PART_RAW); }
|
||||||
void restore_emmc_gpp_parts() { _restore_emmc_selected(PART_GP_ALL); }
|
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 naehrwert
|
||||||
* Copyright (c) 2018 CTCaer
|
* Copyright (c) 2018-2019 CTCaer
|
||||||
* Copyright (c) 2018 balika011
|
* Copyright (c) 2018 balika011
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
@@ -38,8 +38,6 @@
|
|||||||
#include "../utils/btn.h"
|
#include "../utils/btn.h"
|
||||||
#include "../utils/util.h"
|
#include "../utils/util.h"
|
||||||
|
|
||||||
extern gfx_ctxt_t gfx_ctxt;
|
|
||||||
extern gfx_con_t gfx_con;
|
|
||||||
extern sdmmc_storage_t sd_storage;
|
extern sdmmc_storage_t sd_storage;
|
||||||
extern FATFS sd_fs;
|
extern FATFS sd_fs;
|
||||||
|
|
||||||
@@ -48,19 +46,13 @@ extern void sd_unmount();
|
|||||||
extern int sd_save_to_file(void *buf, u32 size, const char *filename);
|
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);
|
extern void emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage);
|
||||||
|
|
||||||
//TODO: Create more macros (info, header, debug, etc) with different colors and utilize them for consistency.
|
|
||||||
#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)
|
|
||||||
|
|
||||||
#pragma GCC push_options
|
#pragma GCC push_options
|
||||||
#pragma GCC optimize ("Os")
|
#pragma GCC optimize ("Os")
|
||||||
|
|
||||||
void print_fuseinfo()
|
void print_fuseinfo()
|
||||||
{
|
{
|
||||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||||
gfx_con_setpos(&gfx_con, 0, 0);
|
gfx_con_setpos(0, 0);
|
||||||
|
|
||||||
u32 burntFuses = 0;
|
u32 burntFuses = 0;
|
||||||
for (u32 i = 0; i < 32; i++)
|
for (u32 i = 0; i < 32; i++)
|
||||||
@@ -69,26 +61,26 @@ void print_fuseinfo()
|
|||||||
burntFuses++;
|
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)
|
switch (fuse_read_odm(4) & 3)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
gfx_printf(&gfx_con, "Retail\n");
|
gfx_printf("Retail\n");
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
gfx_printf(&gfx_con, "Dev\n");
|
gfx_printf("Dev\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
gfx_printf(&gfx_con, "Sdram ID: %d\n", (fuse_read_odm(4) >> 3) & 0x1F);
|
gfx_printf("Sdram ID: %d\n", (fuse_read_odm(4) >> 3) & 0x1F);
|
||||||
gfx_printf(&gfx_con, "Burnt fuses: %d / 64\n", burntFuses);
|
gfx_printf("Burnt fuses: %d / 64\n", burntFuses);
|
||||||
gfx_printf(&gfx_con, "Secure key: %08X%08X%08X%08X\n\n\n",
|
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_KEY0)), byte_swap_32(FUSE(FUSE_PRIVATE_KEY1)),
|
||||||
byte_swap_32(FUSE(FUSE_PRIVATE_KEY2)), byte_swap_32(FUSE(FUSE_PRIVATE_KEY3)));
|
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_printf("%k(Unlocked) fuse cache:\n\n%k", 0xFF00DDFF, 0xFFCCCCCC);
|
||||||
gfx_hexdump(&gfx_con, 0x7000F900, (u8 *)0x7000F900, 0x2FC);
|
gfx_hexdump(0x7000F900, (u8 *)0x7000F900, 0x300);
|
||||||
|
|
||||||
gfx_puts(&gfx_con, "Press 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();
|
u32 btn = btn_wait();
|
||||||
if (btn & BTN_POWER)
|
if (btn & BTN_POWER)
|
||||||
@@ -96,9 +88,16 @@ void print_fuseinfo()
|
|||||||
if (sd_mount())
|
if (sd_mount())
|
||||||
{
|
{
|
||||||
char path[64];
|
char path[64];
|
||||||
emmcsn_path_impl(path, "/dumps", "fuses.bin", NULL);
|
emmcsn_path_impl(path, "/dumps", "fuse_cached.bin", NULL);
|
||||||
if (!sd_save_to_file((u8 *)0x7000F900, 0x2FC, path))
|
if (!sd_save_to_file((u8 *)0x7000F900, 0x300, path))
|
||||||
gfx_puts(&gfx_con, "\nDone!\n");
|
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();
|
sd_unmount();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,17 +107,17 @@ void print_fuseinfo()
|
|||||||
|
|
||||||
void print_kfuseinfo()
|
void print_kfuseinfo()
|
||||||
{
|
{
|
||||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||||
gfx_con_setpos(&gfx_con, 0, 0);
|
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];
|
u32 buf[KFUSE_NUM_WORDS];
|
||||||
if (!kfuse_read(buf))
|
if (!kfuse_read(buf))
|
||||||
EPRINTF("CRC fail.");
|
EPRINTF("CRC fail.");
|
||||||
else
|
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();
|
u32 btn = btn_wait();
|
||||||
if (btn & BTN_POWER)
|
if (btn & BTN_POWER)
|
||||||
@@ -128,7 +127,7 @@ void print_kfuseinfo()
|
|||||||
char path[64];
|
char path[64];
|
||||||
emmcsn_path_impl(path, "/dumps", "kfuses.bin", NULL);
|
emmcsn_path_impl(path, "/dumps", "kfuses.bin", NULL);
|
||||||
if (!sd_save_to_file((u8 *)buf, KFUSE_NUM_WORDS * 4, path))
|
if (!sd_save_to_file((u8 *)buf, KFUSE_NUM_WORDS * 4, path))
|
||||||
gfx_puts(&gfx_con, "\nDone!\n");
|
gfx_puts("\nDone!\n");
|
||||||
sd_unmount();
|
sd_unmount();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,8 +137,8 @@ void print_kfuseinfo()
|
|||||||
|
|
||||||
void print_mmc_info()
|
void print_mmc_info()
|
||||||
{
|
{
|
||||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||||
gfx_con_setpos(&gfx_con, 0, 0);
|
gfx_con_setpos(0, 0);
|
||||||
|
|
||||||
static const u32 SECTORS_TO_MIB_COEFF = 11;
|
static const u32 SECTORS_TO_MIB_COEFF = 11;
|
||||||
|
|
||||||
@@ -156,12 +155,12 @@ void print_mmc_info()
|
|||||||
u16 card_type;
|
u16 card_type;
|
||||||
u32 speed = 0;
|
u32 speed = 0;
|
||||||
|
|
||||||
gfx_printf(&gfx_con, "%kCID:%k\n", 0xFF00DDFF, 0xFFCCCCCC);
|
gfx_printf("%kCID:%k\n", 0xFF00DDFF, 0xFFCCCCCC);
|
||||||
switch (storage.csd.mmca_vsn)
|
switch (storage.csd.mmca_vsn)
|
||||||
{
|
{
|
||||||
case 0: /* MMC v1.0 - v1.2 */
|
case 0: /* MMC v1.0 - v1.2 */
|
||||||
case 1: /* MMC v1.4 */
|
case 1: /* MMC v1.4 */
|
||||||
gfx_printf(&gfx_con,
|
gfx_printf(
|
||||||
" Vendor ID: %03X\n"
|
" Vendor ID: %03X\n"
|
||||||
" Model: %c%c%c%c%c%c%c\n"
|
" Model: %c%c%c%c%c%c%c\n"
|
||||||
" HW rev: %X\n"
|
" HW rev: %X\n"
|
||||||
@@ -177,7 +176,7 @@ void print_mmc_info()
|
|||||||
case 2: /* MMC v2.0 - v2.2 */
|
case 2: /* MMC v2.0 - v2.2 */
|
||||||
case 3: /* MMC v3.1 - v3.3 */
|
case 3: /* MMC v3.1 - v3.3 */
|
||||||
case 4: /* MMC v4 */
|
case 4: /* MMC v4 */
|
||||||
gfx_printf(&gfx_con,
|
gfx_printf(
|
||||||
" Vendor ID: %X\n"
|
" Vendor ID: %X\n"
|
||||||
" Card/BGA: %X\n"
|
" Card/BGA: %X\n"
|
||||||
" OEM ID: %02X\n"
|
" OEM ID: %02X\n"
|
||||||
@@ -199,7 +198,7 @@ void print_mmc_info()
|
|||||||
EPRINTF("Unknown CSD structure.");
|
EPRINTF("Unknown CSD structure.");
|
||||||
else
|
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);
|
0xFF00DDFF, storage.ext_csd.ext_struct, 0xFFCCCCCC);
|
||||||
card_type = storage.ext_csd.card_type;
|
card_type = storage.ext_csd.card_type;
|
||||||
u8 card_type_support[96];
|
u8 card_type_support[96];
|
||||||
@@ -237,7 +236,7 @@ void print_mmc_info()
|
|||||||
}
|
}
|
||||||
card_type_support[pos_type] = 0;
|
card_type_support[pos_type] = 0;
|
||||||
|
|
||||||
gfx_printf(&gfx_con,
|
gfx_printf(
|
||||||
" Spec Version: %02X\n"
|
" Spec Version: %02X\n"
|
||||||
" Extended Rev: 1.%d\n"
|
" Extended Rev: 1.%d\n"
|
||||||
" Dev Version: %d\n"
|
" Dev Version: %d\n"
|
||||||
@@ -250,26 +249,26 @@ void print_mmc_info()
|
|||||||
storage.csd.capacity == (4096 * 512) ? "High" : "Low", speed & 0xFFFF, (speed >> 16) & 0xFFFF,
|
storage.csd.capacity == (4096 * 512) ? "High" : "Low", speed & 0xFFFF, (speed >> 16) & 0xFFFF,
|
||||||
storage.csd.busspeed);
|
storage.csd.busspeed);
|
||||||
gfx_con.fntsz = 8;
|
gfx_con.fntsz = 8;
|
||||||
gfx_printf(&gfx_con, "%s", card_type_support);
|
gfx_printf("%s", card_type_support);
|
||||||
gfx_con.fntsz = 16;
|
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 boot_size = storage.ext_csd.boot_mult << 17;
|
||||||
u32 rpmb_size = storage.ext_csd.rpmb_mult << 17;
|
u32 rpmb_size = storage.ext_csd.rpmb_mult << 17;
|
||||||
gfx_printf(&gfx_con, "%keMMC Partitions:%k\n", 0xFF00DDFF, 0xFFCCCCCC);
|
gfx_printf("%keMMC Partitions:%k\n", 0xFF00DDFF, 0xFFCCCCCC);
|
||||||
gfx_printf(&gfx_con, " 1: %kBOOT0 %k\n Size: %5d KiB (LBA Sectors: 0x%07X)\n", 0xFF96FF00, 0xFFCCCCCC,
|
gfx_printf(" 1: %kBOOT0 %k\n Size: %5d KiB (LBA Sectors: 0x%07X)\n", 0xFF96FF00, 0xFFCCCCCC,
|
||||||
boot_size / 1024, boot_size / 1024 / 512);
|
boot_size / 1024, boot_size / 512);
|
||||||
gfx_put_small_sep(&gfx_con);
|
gfx_put_small_sep();
|
||||||
gfx_printf(&gfx_con, " 2: %kBOOT1 %k\n Size: %5d KiB (LBA Sectors: 0x%07X)\n", 0xFF96FF00, 0xFFCCCCCC,
|
gfx_printf(" 2: %kBOOT1 %k\n Size: %5d KiB (LBA Sectors: 0x%07X)\n", 0xFF96FF00, 0xFFCCCCCC,
|
||||||
boot_size / 1024, boot_size / 1024 / 512);
|
boot_size / 1024, boot_size / 512);
|
||||||
gfx_put_small_sep(&gfx_con);
|
gfx_put_small_sep();
|
||||||
gfx_printf(&gfx_con, " 3: %kRPMB %k\n Size: %5d KiB (LBA Sectors: 0x%07X)\n", 0xFF96FF00, 0xFFCCCCCC,
|
gfx_printf(" 3: %kRPMB %k\n Size: %5d KiB (LBA Sectors: 0x%07X)\n", 0xFF96FF00, 0xFFCCCCCC,
|
||||||
rpmb_size / 1024, rpmb_size / 1024 / 512);
|
rpmb_size / 1024, rpmb_size / 512);
|
||||||
gfx_put_small_sep(&gfx_con);
|
gfx_put_small_sep();
|
||||||
gfx_printf(&gfx_con, " 0: %kGPP (USER) %k\n Size: %5d MiB (LBA Sectors: 0x%07X)\n\n", 0xFF96FF00, 0xFFCCCCCC,
|
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);
|
storage.sec_cnt >> SECTORS_TO_MIB_COEFF, storage.sec_cnt);
|
||||||
gfx_put_small_sep(&gfx_con);
|
gfx_put_small_sep();
|
||||||
gfx_printf(&gfx_con, "%kGPP (eMMC USER) partition table:%k\n", 0xFF00DDFF, 0xFFCCCCCC);
|
gfx_printf("%kGPP (eMMC USER) partition table:%k\n", 0xFF00DDFF, 0xFFCCCCCC);
|
||||||
|
|
||||||
sdmmc_storage_set_mmc_partition(&storage, 0);
|
sdmmc_storage_set_mmc_partition(&storage, 0);
|
||||||
LIST_INIT(gpt);
|
LIST_INIT(gpt);
|
||||||
@@ -277,10 +276,10 @@ void print_mmc_info()
|
|||||||
int gpp_idx = 0;
|
int gpp_idx = 0;
|
||||||
LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link)
|
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,
|
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);
|
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);
|
nx_emmc_gpt_free(&gpt);
|
||||||
}
|
}
|
||||||
@@ -296,15 +295,15 @@ void print_sdcard_info()
|
|||||||
{
|
{
|
||||||
static const u32 SECTORS_TO_MIB_COEFF = 11;
|
static const u32 SECTORS_TO_MIB_COEFF = 11;
|
||||||
|
|
||||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||||
gfx_con_setpos(&gfx_con, 0, 0);
|
gfx_con_setpos(0, 0);
|
||||||
|
|
||||||
if (sd_mount())
|
if (sd_mount())
|
||||||
{
|
{
|
||||||
u32 capacity;
|
u32 capacity;
|
||||||
|
|
||||||
gfx_printf(&gfx_con, "%kCard IDentification:%k\n", 0xFF00DDFF, 0xFFCCCCCC);
|
gfx_printf("%kCard IDentification:%k\n", 0xFF00DDFF, 0xFFCCCCCC);
|
||||||
gfx_printf(&gfx_con,
|
gfx_printf(
|
||||||
" Vendor ID: %02x\n"
|
" Vendor ID: %02x\n"
|
||||||
" OEM ID: %c%c\n"
|
" OEM ID: %c%c\n"
|
||||||
" Model: %c%c%c%c%c\n"
|
" Model: %c%c%c%c%c\n"
|
||||||
@@ -318,9 +317,9 @@ void print_sdcard_info()
|
|||||||
sd_storage.cid.hwrev, sd_storage.cid.fwrev, sd_storage.cid.serial,
|
sd_storage.cid.hwrev, sd_storage.cid.fwrev, sd_storage.cid.serial,
|
||||||
sd_storage.cid.month, sd_storage.cid.year);
|
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);
|
gfx_printf("%kCard-Specific Data V%d.0:%k\n", 0xFF00DDFF, sd_storage.csd.structure + 1, 0xFFCCCCCC);
|
||||||
capacity = sd_storage.csd.capacity >> (20 - sd_storage.csd.read_blkbits);
|
capacity = sd_storage.csd.capacity >> (20 - sd_storage.csd.read_blkbits);
|
||||||
gfx_printf(&gfx_con,
|
gfx_printf(
|
||||||
" Cmd Classes: %02X\n"
|
" Cmd Classes: %02X\n"
|
||||||
" Capacity: %d MiB\n"
|
" Capacity: %d MiB\n"
|
||||||
" Bus Width: %d\n"
|
" Bus Width: %d\n"
|
||||||
@@ -335,9 +334,9 @@ void print_sdcard_info()
|
|||||||
sd_storage.ssr.speed_class, sd_storage.ssr.uhs_grade, sd_storage.ssr.video_class,
|
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);
|
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);
|
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,
|
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_fs.free_clst * sd_fs.csize >> SECTORS_TO_MIB_COEFF, (sd_fs.csize > 1) ? (sd_fs.csize >> 1) : 512);
|
||||||
sd_unmount();
|
sd_unmount();
|
||||||
@@ -348,11 +347,10 @@ void print_sdcard_info()
|
|||||||
|
|
||||||
void print_tsec_key()
|
void print_tsec_key()
|
||||||
{
|
{
|
||||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||||
gfx_con_setpos(&gfx_con, 0, 0);
|
gfx_con_setpos(0, 0);
|
||||||
|
|
||||||
u32 retries = 0;
|
u32 retries = 0;
|
||||||
u32 key_ver_max = 3;
|
|
||||||
|
|
||||||
tsec_ctxt_t tsec_ctxt;
|
tsec_ctxt_t tsec_ctxt;
|
||||||
sdmmc_storage_t storage;
|
sdmmc_storage_t storage;
|
||||||
@@ -368,40 +366,43 @@ void print_tsec_key()
|
|||||||
const pkg1_id_t *pkg1_id = pkg1_identify(pkg1);
|
const pkg1_id_t *pkg1_id = pkg1_identify(pkg1);
|
||||||
if (!pkg1_id)
|
if (!pkg1_id)
|
||||||
{
|
{
|
||||||
EPRINTFARGS("Unknown package1 version for reading\nTSEC firmware (= '%s').",
|
EPRINTF("Unknown pkg1 version for reading\nTSEC firmware.");
|
||||||
(char *)pkg1 + 0x10);
|
|
||||||
goto out_wait;
|
goto out_wait;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 keys[0x10 * 3];
|
u8 keys[0x10 * 2];
|
||||||
|
memset(keys, 0x00, 0x20);
|
||||||
|
|
||||||
tsec_ctxt.size = 0xF00;
|
|
||||||
tsec_ctxt.fw = (u8 *)pkg1 + pkg1_id->tsec_off;
|
tsec_ctxt.fw = (u8 *)pkg1 + pkg1_id->tsec_off;
|
||||||
tsec_ctxt.pkg1 = pkg1;
|
tsec_ctxt.pkg1 = pkg1;
|
||||||
tsec_ctxt.pkg11_off = pkg1_id->pkg11_off;
|
tsec_ctxt.pkg11_off = pkg1_id->pkg11_off;
|
||||||
tsec_ctxt.secmon_base = pkg1_id->secmon_base;
|
tsec_ctxt.secmon_base = pkg1_id->secmon_base;
|
||||||
|
|
||||||
if (pkg1_id->kb >= KB_FIRMWARE_VERSION_620)
|
if (pkg1_id->kb <= KB_FIRMWARE_VERSION_600)
|
||||||
{
|
tsec_ctxt.size = 0xF00;
|
||||||
|
else if (pkg1_id->kb == KB_FIRMWARE_VERSION_620)
|
||||||
tsec_ctxt.size = 0x2900;
|
tsec_ctxt.size = 0x2900;
|
||||||
|
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)
|
||||||
|
{
|
||||||
u8 *tsec_paged = (u8 *)page_alloc(3);
|
u8 *tsec_paged = (u8 *)page_alloc(3);
|
||||||
memcpy(tsec_paged, (void *)tsec_ctxt.fw, tsec_ctxt.size);
|
memcpy(tsec_paged, (void *)tsec_ctxt.fw, tsec_ctxt.size);
|
||||||
tsec_ctxt.fw = tsec_paged;
|
tsec_ctxt.fw = tsec_paged;
|
||||||
|
|
||||||
key_ver_max = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (u32 i = 1; i <= key_ver_max; i++)
|
|
||||||
{
|
|
||||||
tsec_ctxt.key_ver = i;
|
|
||||||
int res = 0;
|
int res = 0;
|
||||||
|
|
||||||
while (tsec_query(keys + ((i - 1) * 0x10), pkg1_id->kb, &tsec_ctxt) < 0)
|
while (tsec_query(keys, pkg1_id->kb, &tsec_ctxt) < 0)
|
||||||
{
|
{
|
||||||
if (pkg1_id->kb <= KB_FIRMWARE_VERSION_600)
|
memset(keys, 0x00, 0x20);
|
||||||
memset(keys + ((i - 1) * 0x10), 0x00, 0x10);
|
|
||||||
else
|
|
||||||
memset(keys, 0x00, 0x30);
|
|
||||||
|
|
||||||
retries++;
|
retries++;
|
||||||
|
|
||||||
@@ -412,41 +413,25 @@ void print_tsec_key()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pkg1_id->kb <= KB_FIRMWARE_VERSION_600)
|
gfx_printf("%kTSEC key: %k", 0xFF00DDFF, 0xFFCCCCCC);
|
||||||
{
|
|
||||||
gfx_printf(&gfx_con, "%kTSEC key %d: %k", 0xFF00DDFF, i, 0xFFCCCCCC);
|
|
||||||
|
|
||||||
if (res >= 0)
|
if (res >= 0)
|
||||||
{
|
{
|
||||||
for (u32 j = 0; j < 0x10; j++)
|
for (u32 j = 0; j < 0x10; j++)
|
||||||
gfx_printf(&gfx_con, "%02X", keys[((i - 1) * 0x10) + j]);
|
gfx_printf("%02X", keys[j]);
|
||||||
}
|
|
||||||
else
|
|
||||||
EPRINTFARGS("ERROR %X", res);
|
if (pkg1_id->kb == KB_FIRMWARE_VERSION_620)
|
||||||
gfx_putc(&gfx_con, '\n');
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
gfx_printf(&gfx_con, "%kTSEC key: %k", 0xFF00DDFF, 0xFFCCCCCC);
|
|
||||||
|
|
||||||
if (res >= 0)
|
|
||||||
{
|
{
|
||||||
|
gfx_printf("\n%kTSEC root: %k", 0xFF00DDFF, 0xFFCCCCCC);
|
||||||
for (u32 j = 0; j < 0x10; j++)
|
for (u32 j = 0; j < 0x10; j++)
|
||||||
gfx_printf(&gfx_con, "%02X", keys[j]);
|
gfx_printf("%02X", keys[0x10 + j]);
|
||||||
gfx_putc(&gfx_con, '\n');
|
}
|
||||||
|
|
||||||
gfx_printf(&gfx_con, "%kTSEC root: %k", 0xFF00DDFF, 0xFFCCCCCC);
|
|
||||||
for (u32 j = 0; j < 0x10; j++)
|
|
||||||
gfx_printf(&gfx_con, "%02X", keys[0x10 + j]);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
EPRINTFARGS("ERROR %X", res);
|
EPRINTFARGS("ERROR %X\n", res);
|
||||||
gfx_putc(&gfx_con, '\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
gfx_puts("\n\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
|
||||||
|
|
||||||
gfx_puts(&gfx_con, "\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
|
|
||||||
|
|
||||||
u32 btn = btn_wait();
|
u32 btn = btn_wait();
|
||||||
if (btn & BTN_POWER)
|
if (btn & BTN_POWER)
|
||||||
@@ -455,8 +440,8 @@ void print_tsec_key()
|
|||||||
{
|
{
|
||||||
char path[64];
|
char path[64];
|
||||||
emmcsn_path_impl(path, "/dumps", "tsec_keys.bin", NULL);
|
emmcsn_path_impl(path, "/dumps", "tsec_keys.bin", NULL);
|
||||||
if (!sd_save_to_file(keys, 0x10 * 3, path))
|
if (!sd_save_to_file(keys, 0x10 * 2, path))
|
||||||
gfx_puts(&gfx_con, "\nDone!\n");
|
gfx_puts("\nDone!\n");
|
||||||
sd_unmount();
|
sd_unmount();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -474,127 +459,124 @@ void print_fuel_gauge_info()
|
|||||||
{
|
{
|
||||||
int value = 0;
|
int value = 0;
|
||||||
|
|
||||||
gfx_printf(&gfx_con, "%kFuel Gauge IC Info:\n%k", 0xFF00DDFF, 0xFFCCCCCC);
|
gfx_printf("%kFuel Gauge IC Info:\n%k", 0xFF00DDFF, 0xFFCCCCCC);
|
||||||
|
|
||||||
max17050_get_property(MAX17050_Age, &value);
|
|
||||||
gfx_printf(&gfx_con, "Age: %3d%\n", value);
|
|
||||||
|
|
||||||
max17050_get_property(MAX17050_RepSOC, &value);
|
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);
|
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);
|
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);
|
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);
|
max17050_get_property(MAX17050_Current, &value);
|
||||||
if (value >= 0)
|
if (value >= 0)
|
||||||
gfx_printf(&gfx_con, "Current now: %d mA\n", value / 1000);
|
gfx_printf("Current now: %d mA\n", value / 1000);
|
||||||
else
|
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);
|
max17050_get_property(MAX17050_AvgCurrent, &value);
|
||||||
if (value >= 0)
|
if (value >= 0)
|
||||||
gfx_printf(&gfx_con, "Current average: %d mA\n", value / 1000);
|
gfx_printf("Current average: %d mA\n", value / 1000);
|
||||||
else
|
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);
|
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);
|
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);
|
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);
|
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);
|
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);
|
max17050_get_property(MAX17050_TEMP, &value);
|
||||||
if (value >= 0)
|
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
|
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()
|
void print_battery_charger_info()
|
||||||
{
|
{
|
||||||
int value = 0;
|
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);
|
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);
|
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);
|
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);
|
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);
|
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);
|
bq24193_get_property(BQ24193_ChargeStatus, &value);
|
||||||
gfx_printf(&gfx_con, "Charge status: ");
|
gfx_printf("Charge status: ");
|
||||||
switch (value)
|
switch (value)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
gfx_printf(&gfx_con, "Not charging\n");
|
gfx_printf("Not charging\n");
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
gfx_printf(&gfx_con, "Pre-charging\n");
|
gfx_printf("Pre-charging\n");
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
gfx_printf(&gfx_con, "Fast charging\n");
|
gfx_printf("Fast charging\n");
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
gfx_printf(&gfx_con, "Charge terminated\n");
|
gfx_printf("Charge terminated\n");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
gfx_printf(&gfx_con, "Unknown (%d)\n", value);
|
gfx_printf("Unknown (%d)\n", value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
bq24193_get_property(BQ24193_TempStatus, &value);
|
bq24193_get_property(BQ24193_TempStatus, &value);
|
||||||
gfx_printf(&gfx_con, "Temperature status: ");
|
gfx_printf("Temperature status: ");
|
||||||
switch (value)
|
switch (value)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
gfx_printf(&gfx_con, "Normal\n");
|
gfx_printf("Normal\n");
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
gfx_printf(&gfx_con, "Warm\n");
|
gfx_printf("Warm\n");
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
gfx_printf(&gfx_con, "Cool\n");
|
gfx_printf("Cool\n");
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
gfx_printf(&gfx_con, "Cold\n");
|
gfx_printf("Cold\n");
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
gfx_printf(&gfx_con, "Hot\n");
|
gfx_printf("Hot\n");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
gfx_printf(&gfx_con, "Unknown (%d)\n", value);
|
gfx_printf("Unknown (%d)\n", value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_battery_info()
|
void print_battery_info()
|
||||||
{
|
{
|
||||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||||
gfx_con_setpos(&gfx_con, 0, 0);
|
gfx_con_setpos(0, 0);
|
||||||
|
|
||||||
print_fuel_gauge_info();
|
print_fuel_gauge_info();
|
||||||
|
|
||||||
@@ -602,17 +584,17 @@ void print_battery_info()
|
|||||||
|
|
||||||
u8 *buf = (u8 *)malloc(0x100 * 2);
|
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)
|
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);
|
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();
|
u32 btn = btn_wait();
|
||||||
|
|
||||||
@@ -625,7 +607,7 @@ void print_battery_info()
|
|||||||
if (sd_save_to_file((u8 *)buf, 0x200, path))
|
if (sd_save_to_file((u8 *)buf, 0x200, path))
|
||||||
EPRINTF("\nError creating fuel.bin file.");
|
EPRINTF("\nError creating fuel.bin file.");
|
||||||
else
|
else
|
||||||
gfx_puts(&gfx_con, "\nDone!\n");
|
gfx_puts("\nDone!\n");
|
||||||
sd_unmount();
|
sd_unmount();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -636,24 +618,24 @@ void print_battery_info()
|
|||||||
|
|
||||||
void _ipatch_process(u32 offset, u32 value)
|
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;
|
u8 lo = value & 0xff;
|
||||||
switch (value >> 8)
|
switch (value >> 8)
|
||||||
{
|
{
|
||||||
case 0x20:
|
case 0x20:
|
||||||
gfx_printf(&gfx_con, " MOVS R0, #0x%02X", lo);
|
gfx_printf(" MOVS R0, #0x%02X", lo);
|
||||||
break;
|
break;
|
||||||
case 0xDF:
|
case 0xDF:
|
||||||
gfx_printf(&gfx_con, " SVC #0x%02X", lo);
|
gfx_printf(" SVC #0x%02X", lo);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
gfx_puts(&gfx_con, "\n");
|
gfx_puts("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void bootrom_ipatches_info()
|
void bootrom_ipatches_info()
|
||||||
{
|
{
|
||||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||||
gfx_con_setpos(&gfx_con, 0, 0);
|
gfx_con_setpos(0, 0);
|
||||||
|
|
||||||
static const u32 BOOTROM_SIZE = 0x18000;
|
static const u32 BOOTROM_SIZE = 0x18000;
|
||||||
|
|
||||||
@@ -661,7 +643,7 @@ void bootrom_ipatches_info()
|
|||||||
if (res != 0)
|
if (res != 0)
|
||||||
EPRINTFARGS("Failed to read ipatches. Error: %d", res);
|
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();
|
u32 btn = btn_wait();
|
||||||
if (btn & BTN_POWER)
|
if (btn & BTN_POWER)
|
||||||
@@ -676,20 +658,14 @@ void bootrom_ipatches_info()
|
|||||||
{
|
{
|
||||||
emmcsn_path_impl(path, "/dumps", "evp_thunks.bin", NULL);
|
emmcsn_path_impl(path, "/dumps", "evp_thunks.bin", NULL);
|
||||||
if (!sd_save_to_file((u8 *)iram_evp_thunks, iram_evp_thunks_len, path))
|
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
|
else
|
||||||
EPRINTFARGS("Failed to read evp_thunks. Error: %d", res);
|
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);
|
emmcsn_path_impl(path, "/dumps", "bootrom_patched.bin", NULL);
|
||||||
if (!sd_save_to_file((u8 *)BOOTROM_BASE, BOOTROM_SIZE, path))
|
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];
|
u32 ipatch_backup[14];
|
||||||
memcpy(ipatch_backup, (void *)IPATCH_BASE, sizeof(ipatch_backup));
|
memcpy(ipatch_backup, (void *)IPATCH_BASE, sizeof(ipatch_backup));
|
||||||
@@ -697,7 +673,7 @@ void bootrom_ipatches_info()
|
|||||||
|
|
||||||
emmcsn_path_impl(path, "/dumps", "bootrom_unpatched.bin", NULL);
|
emmcsn_path_impl(path, "/dumps", "bootrom_unpatched.bin", NULL);
|
||||||
if (!sd_save_to_file((u8 *)BOOTROM_BASE, BOOTROM_SIZE, path))
|
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));
|
memcpy((void*)IPATCH_BASE, ipatch_backup, sizeof(ipatch_backup));
|
||||||
|
|
||||||
@@ -709,4 +685,3 @@ void bootrom_ipatches_info()
|
|||||||
}
|
}
|
||||||
|
|
||||||
#pragma GCC pop_options
|
#pragma GCC pop_options
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
* Copyright (c) 2018 CTCaer
|
* Copyright (c) 2018-2019 CTCaer
|
||||||
* Copyright (c) 2018 Reisyukaku
|
* Copyright (c) 2018 Reisyukaku
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
@@ -26,34 +26,35 @@
|
|||||||
#include "../hos/hos.h"
|
#include "../hos/hos.h"
|
||||||
#include "../hos/pkg1.h"
|
#include "../hos/pkg1.h"
|
||||||
#include "../hos/pkg2.h"
|
#include "../hos/pkg2.h"
|
||||||
|
#include "../hos/sept.h"
|
||||||
#include "../libs/fatfs/ff.h"
|
#include "../libs/fatfs/ff.h"
|
||||||
#include "../mem/heap.h"
|
#include "../mem/heap.h"
|
||||||
#include "../power/max7762x.h"
|
#include "../power/max7762x.h"
|
||||||
#include "../sec/se.h"
|
#include "../sec/se.h"
|
||||||
#include "../storage/nx_emmc.h"
|
#include "../storage/nx_emmc.h"
|
||||||
#include "../storage/sdmmc.h"
|
#include "../storage/sdmmc.h"
|
||||||
|
#include "../soc/fuse.h"
|
||||||
#include "../utils/btn.h"
|
#include "../utils/btn.h"
|
||||||
#include "../utils/util.h"
|
#include "../utils/util.h"
|
||||||
|
|
||||||
|
extern boot_cfg_t b_cfg;
|
||||||
extern hekate_config h_cfg;
|
extern hekate_config h_cfg;
|
||||||
extern gfx_ctxt_t gfx_ctxt;
|
|
||||||
extern gfx_con_t gfx_con;
|
|
||||||
extern sdmmc_storage_t sd_storage;
|
|
||||||
|
|
||||||
extern bool sd_mount();
|
extern bool sd_mount();
|
||||||
extern void sd_unmount();
|
extern void sd_unmount();
|
||||||
extern int sd_save_to_file(void *buf, u32 size, const char *filename);
|
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);
|
extern void emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage);
|
||||||
|
|
||||||
//TODO: Create more macros (info, header, debug, etc) with different colors and utilize them for consistency.
|
#pragma GCC push_options
|
||||||
#define EPRINTF(text) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFF0000, 0xFFCCCCCC)
|
#pragma GCC optimize ("Os")
|
||||||
#define EPRINTFARGS(text, args...) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFF0000, args, 0xFFCCCCCC)
|
|
||||||
|
|
||||||
void dump_packages12()
|
void dump_packages12()
|
||||||
{
|
{
|
||||||
if (!sd_mount())
|
if (!sd_mount())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
char path[64];
|
||||||
|
|
||||||
u8 *pkg1 = (u8 *)calloc(1, 0x40000);
|
u8 *pkg1 = (u8 *)calloc(1, 0x40000);
|
||||||
u8 *warmboot = (u8 *)calloc(1, 0x40000);
|
u8 *warmboot = (u8 *)calloc(1, 0x40000);
|
||||||
u8 *secmon = (u8 *)calloc(1, 0x40000);
|
u8 *secmon = (u8 *)calloc(1, 0x40000);
|
||||||
@@ -63,8 +64,8 @@ void dump_packages12()
|
|||||||
|
|
||||||
tsec_ctxt_t tsec_ctxt;
|
tsec_ctxt_t tsec_ctxt;
|
||||||
|
|
||||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||||
gfx_con_setpos(&gfx_con, 0, 0);
|
gfx_con_setpos(0, 0);
|
||||||
|
|
||||||
sdmmc_storage_t storage;
|
sdmmc_storage_t storage;
|
||||||
sdmmc_t sdmmc;
|
sdmmc_t sdmmc;
|
||||||
@@ -78,31 +79,50 @@ void dump_packages12()
|
|||||||
// Read package1.
|
// Read package1.
|
||||||
sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1);
|
sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1);
|
||||||
const pkg1_id_t *pkg1_id = pkg1_identify(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)
|
if (!pkg1_id)
|
||||||
{
|
{
|
||||||
gfx_con.fntsz = 8;
|
EPRINTF("Unknown pkg1 version for reading\nTSEC firmware.");
|
||||||
EPRINTFARGS("Unknown package1 version for reading\nTSEC firmware (= '%s').", (char *)pkg1 + 0x10);
|
// 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;
|
goto out_free;
|
||||||
}
|
}
|
||||||
|
const pk11_hdr_t *hdr = (pk11_hdr_t *)(pkg1 + pkg1_id->pkg11_off + 0x20);
|
||||||
|
|
||||||
kb = pkg1_id->kb;
|
kb = pkg1_id->kb;
|
||||||
|
|
||||||
if (!h_cfg.se_keygen_done || kb >= KB_FIRMWARE_VERSION_620)
|
if (!h_cfg.se_keygen_done)
|
||||||
{
|
{
|
||||||
tsec_ctxt.key_ver = 1;
|
|
||||||
tsec_ctxt.fw = (void *)pkg1 + pkg1_id->tsec_off;
|
tsec_ctxt.fw = (void *)pkg1 + pkg1_id->tsec_off;
|
||||||
tsec_ctxt.pkg1 = (void *)pkg1;
|
tsec_ctxt.pkg1 = (void *)pkg1;
|
||||||
tsec_ctxt.pkg11_off = pkg1_id->pkg11_off;
|
tsec_ctxt.pkg11_off = pkg1_id->pkg11_off;
|
||||||
tsec_ctxt.secmon_base = pkg1_id->secmon_base;
|
tsec_ctxt.secmon_base = pkg1_id->secmon_base;
|
||||||
|
|
||||||
|
if (kb >= KB_FIRMWARE_VERSION_700 && !h_cfg.sept_run)
|
||||||
|
{
|
||||||
|
b_cfg.autoboot = 0;
|
||||||
|
b_cfg.autoboot_list = 0;
|
||||||
|
|
||||||
|
gfx_printf("sept will run to get the keys.\nThen rerun this option.");
|
||||||
|
btn_wait();
|
||||||
|
|
||||||
|
if (!reboot_to_sept((u8 *)tsec_ctxt.fw, kb))
|
||||||
|
{
|
||||||
|
gfx_printf("Failed to run sept\n");
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Read keyblob.
|
// Read keyblob.
|
||||||
u8 *keyblob = (u8 *)calloc(NX_EMMC_BLOCKSIZE, 1);
|
u8 *keyblob = (u8 *)calloc(NX_EMMC_BLOCKSIZE, 1);
|
||||||
sdmmc_storage_read(&storage, 0x180000 / NX_EMMC_BLOCKSIZE + kb, 1, keyblob);
|
sdmmc_storage_read(&storage, 0x180000 / NX_EMMC_BLOCKSIZE + kb, 1, keyblob);
|
||||||
|
|
||||||
// Decrypt.
|
// Decrypt.
|
||||||
keygen(keyblob, kb, &tsec_ctxt);
|
keygen(keyblob, kb, &tsec_ctxt, NULL);
|
||||||
|
if (kb <= KB_FIRMWARE_VERSION_600)
|
||||||
h_cfg.se_keygen_done = 1;
|
h_cfg.se_keygen_done = 1;
|
||||||
free(keyblob);
|
free(keyblob);
|
||||||
}
|
}
|
||||||
@@ -110,41 +130,43 @@ void dump_packages12()
|
|||||||
if (kb <= KB_FIRMWARE_VERSION_600)
|
if (kb <= KB_FIRMWARE_VERSION_600)
|
||||||
pkg1_decrypt(pkg1_id, pkg1);
|
pkg1_decrypt(pkg1_id, pkg1);
|
||||||
|
|
||||||
|
if (kb <= KB_FIRMWARE_VERSION_620)
|
||||||
|
{
|
||||||
pkg1_unpack(warmboot, secmon, loader, pkg1_id, pkg1);
|
pkg1_unpack(warmboot, secmon, loader, pkg1_id, pkg1);
|
||||||
|
|
||||||
// Display info.
|
// Display info.
|
||||||
gfx_printf(&gfx_con, "%kNX Bootloader size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, hdr->ldr_size);
|
gfx_printf("%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("%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("%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("%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("%kWarmboot size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, hdr->wb_size);
|
||||||
|
|
||||||
char path[64];
|
|
||||||
// Dump package1.1.
|
// Dump package1.1.
|
||||||
emmcsn_path_impl(path, "/pkg1", "pkg1_decr.bin", &storage);
|
emmcsn_path_impl(path, "/pkg1", "pkg1_decr.bin", &storage);
|
||||||
if (sd_save_to_file(pkg1, 0x40000, path))
|
if (sd_save_to_file(pkg1, 0x40000, path))
|
||||||
goto out_free;
|
goto out_free;
|
||||||
gfx_puts(&gfx_con, "\nFull package1 dumped to pkg1_decr.bin\n");
|
gfx_puts("\npkg1 dumped to pkg1_decr.bin\n");
|
||||||
|
|
||||||
// Dump nxbootloader.
|
// Dump nxbootloader.
|
||||||
emmcsn_path_impl(path, "/pkg1", "nxloader.bin", &storage);
|
emmcsn_path_impl(path, "/pkg1", "nxloader.bin", &storage);
|
||||||
if (sd_save_to_file(loader, hdr->ldr_size, path))
|
if (sd_save_to_file(loader, hdr->ldr_size, path))
|
||||||
goto out_free;
|
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.
|
// Dump secmon.
|
||||||
emmcsn_path_impl(path, "/pkg1", "secmon.bin", &storage);
|
emmcsn_path_impl(path, "/pkg1", "secmon.bin", &storage);
|
||||||
if (sd_save_to_file(secmon, hdr->sm_size, path))
|
if (sd_save_to_file(secmon, hdr->sm_size, path))
|
||||||
goto out_free;
|
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.
|
// Dump warmboot.
|
||||||
emmcsn_path_impl(path, "/pkg1", "warmboot.bin", &storage);
|
emmcsn_path_impl(path, "/pkg1", "warmboot.bin", &storage);
|
||||||
if (sd_save_to_file(warmboot, hdr->wb_size, path))
|
if (sd_save_to_file(warmboot, hdr->wb_size, path))
|
||||||
goto out_free;
|
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.
|
// Dump package2.1.
|
||||||
sdmmc_storage_set_mmc_partition(&storage, 0);
|
sdmmc_storage_set_mmc_partition(&storage, 0);
|
||||||
@@ -168,34 +190,44 @@ void dump_packages12()
|
|||||||
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);
|
pkg2_size_aligned / NX_EMMC_BLOCKSIZE, pkg2);
|
||||||
// Decrypt package2 and parse KIP1 blobs in INI1 section.
|
// 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.
|
// Display info.
|
||||||
u32 kernel_crc32 = crc32c(pkg2_hdr->data, pkg2_hdr->sec_size[PKG2_SEC_KERNEL]);
|
gfx_printf("%kKernel size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, pkg2_hdr->sec_size[PKG2_SEC_KERNEL]);
|
||||||
gfx_printf(&gfx_con, "\n%kKernel CRC32C: %k0x%08X\n\n", 0xFFC7EA46, 0xFFCCCCCC, kernel_crc32);
|
gfx_printf("%kINI1 size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, pkg2_hdr->sec_size[PKG2_SEC_INI1]);
|
||||||
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]);
|
|
||||||
|
|
||||||
// Dump pkg2.1.
|
// Dump pkg2.1.
|
||||||
emmcsn_path_impl(path, "/pkg2", "pkg2_decr.bin", &storage);
|
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))
|
if (sd_save_to_file(pkg2, pkg2_hdr->sec_size[PKG2_SEC_KERNEL] + pkg2_hdr->sec_size[PKG2_SEC_INI1], path))
|
||||||
goto out;
|
goto out;
|
||||||
gfx_puts(&gfx_con, "\nFull package2 dumped to pkg2_decr.bin\n");
|
gfx_puts("\npkg2 dumped to pkg2_decr.bin\n");
|
||||||
|
|
||||||
// Dump kernel.
|
// Dump kernel.
|
||||||
emmcsn_path_impl(path, "/pkg2", "kernel.bin", &storage);
|
emmcsn_path_impl(path, "/pkg2", "kernel.bin", &storage);
|
||||||
if (sd_save_to_file(pkg2_hdr->data, pkg2_hdr->sec_size[PKG2_SEC_KERNEL], path))
|
if (sd_save_to_file(pkg2_hdr->data, pkg2_hdr->sec_size[PKG2_SEC_KERNEL], path))
|
||||||
goto out;
|
goto out;
|
||||||
gfx_puts(&gfx_con, "Kernel dumped to kernel.bin\n");
|
gfx_puts("Kernel dumped to kernel.bin\n");
|
||||||
|
|
||||||
// Dump INI1.
|
// Dump INI1.
|
||||||
emmcsn_path_impl(path, "/pkg2", "ini1.bin", &storage);
|
emmcsn_path_impl(path, "/pkg2", "ini1.bin", &storage);
|
||||||
if (sd_save_to_file(pkg2_hdr->data + pkg2_hdr->sec_size[PKG2_SEC_KERNEL],
|
u32 ini1_off = pkg2_hdr->sec_size[PKG2_SEC_KERNEL];
|
||||||
pkg2_hdr->sec_size[PKG2_SEC_INI1], path))
|
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 (sd_save_to_file(pkg2_hdr->data + ini1_off, ini1_size, path))
|
||||||
goto out;
|
goto out;
|
||||||
gfx_puts(&gfx_con, "INI1 kip1 package dumped to ini1.bin\n");
|
gfx_puts("INI1 dumped to ini1.bin\n");
|
||||||
|
|
||||||
gfx_puts(&gfx_con, "\nDone. Press any key...\n");
|
gfx_puts("\nDone. Press any key...\n");
|
||||||
|
|
||||||
out:
|
out:
|
||||||
nx_emmc_gpt_free(&gpt);
|
nx_emmc_gpt_free(&gpt);
|
||||||
@@ -221,8 +253,8 @@ void _toggle_autorcm(bool enable)
|
|||||||
|
|
||||||
u8 randomXor = 0;
|
u8 randomXor = 0;
|
||||||
|
|
||||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||||
gfx_con_setpos(&gfx_con, 0, 0);
|
gfx_con_setpos(0, 0);
|
||||||
|
|
||||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
|
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
|
||||||
{
|
{
|
||||||
@@ -234,6 +266,12 @@ void _toggle_autorcm(bool enable)
|
|||||||
sdmmc_storage_set_mmc_partition(&storage, 1);
|
sdmmc_storage_set_mmc_partition(&storage, 1);
|
||||||
|
|
||||||
int i, sect = 0;
|
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++)
|
for (i = 0; i < 4; i++)
|
||||||
{
|
{
|
||||||
sect = (0x200 + (0x4000 * i)) / NX_EMMC_BLOCKSIZE;
|
sect = (0x200 + (0x4000 * i)) / NX_EMMC_BLOCKSIZE;
|
||||||
@@ -249,7 +287,7 @@ void _toggle_autorcm(bool enable)
|
|||||||
tempbuf[0x10] ^= randomXor;
|
tempbuf[0x10] ^= randomXor;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
tempbuf[0x10] = 0xF7;
|
tempbuf[0x10] = corr_mod_byte0;
|
||||||
sdmmc_storage_write(&storage, sect, 1, tempbuf);
|
sdmmc_storage_write(&storage, sect, 1, tempbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,10 +295,10 @@ void _toggle_autorcm(bool enable)
|
|||||||
sdmmc_storage_end(&storage);
|
sdmmc_storage_end(&storage);
|
||||||
|
|
||||||
if (enable)
|
if (enable)
|
||||||
gfx_printf(&gfx_con, "%kAutoRCM mode enabled!%k", 0xFFFFBA00, 0xFFCCCCCC);
|
gfx_printf("%kAutoRCM mode enabled!%k", 0xFFFFBA00, 0xFFCCCCCC);
|
||||||
else
|
else
|
||||||
gfx_printf(&gfx_con, "%kAutoRCM mode disabled!%k", 0xFF96FF00, 0xFFCCCCCC);
|
gfx_printf("%kAutoRCM mode disabled!%k", 0xFF96FF00, 0xFFCCCCCC);
|
||||||
gfx_printf(&gfx_con, "\n\nPress any key...\n");
|
gfx_printf("\n\nPress any key...\n");
|
||||||
|
|
||||||
out:
|
out:
|
||||||
btn_wait();
|
btn_wait();
|
||||||
@@ -271,8 +309,18 @@ void _disable_autorcm() { _toggle_autorcm(false); }
|
|||||||
|
|
||||||
void menu_autorcm()
|
void menu_autorcm()
|
||||||
{
|
{
|
||||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
gfx_clear_grey(0x1B);
|
||||||
gfx_con_setpos(&gfx_con, 0, 0);
|
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.
|
// Do a simple check on the main BCT.
|
||||||
sdmmc_storage_t storage;
|
sdmmc_storage_t storage;
|
||||||
@@ -291,8 +339,16 @@ void menu_autorcm()
|
|||||||
sdmmc_storage_set_mmc_partition(&storage, 1);
|
sdmmc_storage_set_mmc_partition(&storage, 1);
|
||||||
sdmmc_storage_read(&storage, 0x200 / NX_EMMC_BLOCKSIZE, 1, tempbuf);
|
sdmmc_storage_read(&storage, 0x200 / NX_EMMC_BLOCKSIZE, 1, tempbuf);
|
||||||
|
|
||||||
|
if ((fuse_read_odm(4) & 3) != 3)
|
||||||
|
{
|
||||||
if (tempbuf[0x10] != 0xF7)
|
if (tempbuf[0x10] != 0xF7)
|
||||||
disabled = false;
|
disabled = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (tempbuf[0x10] != 0x37)
|
||||||
|
disabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
free(tempbuf);
|
free(tempbuf);
|
||||||
sdmmc_storage_end(&storage);
|
sdmmc_storage_end(&storage);
|
||||||
@@ -327,7 +383,7 @@ void menu_autorcm()
|
|||||||
memset(&ments[5], 0, sizeof(ment_t));
|
memset(&ments[5], 0, sizeof(ment_t));
|
||||||
menu_t menu = {ments, "This corrupts your BOOT0!", 0, 0};
|
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)
|
int _fix_attributes(char *path, u32 *total, u32 hos_folder, u32 check_first_run)
|
||||||
@@ -394,6 +450,10 @@ int _fix_attributes(char *path, u32 *total, u32 hos_folder, u32 check_first_run)
|
|||||||
*total = *total + 1;
|
*total = *total + 1;
|
||||||
f_chmod(path, AM_ARC, AM_ARC);
|
f_chmod(path, AM_ARC, AM_ARC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update status bar.
|
||||||
|
tui_sbar(false);
|
||||||
|
|
||||||
// Enter the directory.
|
// Enter the directory.
|
||||||
res = _fix_attributes(path, total, hos_folder, 0);
|
res = _fix_attributes(path, total, hos_folder, 0);
|
||||||
if (res != FR_OK)
|
if (res != FR_OK)
|
||||||
@@ -408,8 +468,8 @@ int _fix_attributes(char *path, u32 *total, u32 hos_folder, u32 check_first_run)
|
|||||||
|
|
||||||
void _fix_sd_attr(u32 type)
|
void _fix_sd_attr(u32 type)
|
||||||
{
|
{
|
||||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||||
gfx_con_setpos(&gfx_con, 0, 0);
|
gfx_con_setpos(0, 0);
|
||||||
|
|
||||||
char path[256];
|
char path[256];
|
||||||
char label[16];
|
char label[16];
|
||||||
@@ -430,9 +490,9 @@ void _fix_sd_attr(u32 type)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
gfx_printf(&gfx_con, "Traversing all %s files!\nThis may take some time, please wait...\n\n", label);
|
gfx_printf("Traversing all %s files!\nThis may take some time...\n\n", label);
|
||||||
_fix_attributes(path, &total, type, type);
|
_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();
|
sd_unmount();
|
||||||
}
|
}
|
||||||
btn_wait();
|
btn_wait();
|
||||||
@@ -441,22 +501,10 @@ void _fix_sd_attr(u32 type)
|
|||||||
void fix_sd_all_attr() { _fix_sd_attr(0); }
|
void fix_sd_all_attr() { _fix_sd_attr(0); }
|
||||||
void fix_sd_nin_attr() { _fix_sd_attr(1); }
|
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()
|
/* void fix_fuel_gauge_configuration()
|
||||||
{
|
{
|
||||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||||
gfx_con_setpos(&gfx_con, 0, 0);
|
gfx_con_setpos(0, 0);
|
||||||
|
|
||||||
int battVoltage, avgCurrent;
|
int battVoltage, avgCurrent;
|
||||||
|
|
||||||
@@ -470,23 +518,23 @@ void fix_battery_desync()
|
|||||||
EPRINTF("You need to be connected to a wall adapter,\nto apply this fix!");
|
EPRINTF("You need to be connected to a wall adapter,\nto apply this fix!");
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
gfx_printf(&gfx_con, "%kAre you really sure?\nThis will reset your fuel gauge completely!\n", 0xFFFFDD00);
|
gfx_printf("%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("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();
|
u32 btn = btn_wait();
|
||||||
if (btn & BTN_POWER)
|
if (btn & BTN_POWER)
|
||||||
{
|
{
|
||||||
max17050_fix_configuration();
|
max17050_fix_configuration();
|
||||||
msleep(1000);
|
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;
|
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)
|
while (value < 46)
|
||||||
{
|
{
|
||||||
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
|
gfx_con_setpos(gfx_con.savedx, gfx_con.savedy);
|
||||||
gfx_printf(&gfx_con, "%2ds elapsed", value);
|
gfx_printf("%2ds elapsed", value);
|
||||||
msleep(1000);
|
msleep(1000);
|
||||||
value++;
|
value++;
|
||||||
}
|
}
|
||||||
@@ -508,31 +556,31 @@ void fix_battery_desync()
|
|||||||
{
|
{
|
||||||
int avgCurrent;
|
int avgCurrent;
|
||||||
|
|
||||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||||
gfx_con_setpos(&gfx_con, 0, 0);
|
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"
|
"%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);
|
"\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();
|
u32 btn = btn_wait();
|
||||||
if (btn & BTN_POWER)
|
if (btn & BTN_POWER)
|
||||||
{
|
{
|
||||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||||
gfx_con_setpos(&gfx_con, 0, 0);
|
gfx_con_setpos(0, 0);
|
||||||
gfx_printf(&gfx_con, "%kKeep the USB cable connected!%k\n\n", 0xFFFFDD00, 0xFFCCCCCC);
|
gfx_printf("%kKeep the USB cable connected!%k\n\n", 0xFFFFDD00, 0xFFCCCCCC);
|
||||||
gfx_con_getpos(&gfx_con, &gfx_con.savedx, &gfx_con.savedy);
|
gfx_con_getpos(&gfx_con.savedx, &gfx_con.savedy);
|
||||||
|
|
||||||
u8 value = 30;
|
u8 value = 30;
|
||||||
while (value > 0)
|
while (value > 0)
|
||||||
{
|
{
|
||||||
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
|
gfx_con_setpos(gfx_con.savedx, gfx_con.savedy);
|
||||||
gfx_printf(&gfx_con, "%kWait... (%ds) %k", 0xFF888888, value, 0xFFCCCCCC);
|
gfx_printf("%kWait... (%ds) %k", 0xFF888888, value, 0xFFCCCCCC);
|
||||||
msleep(1000);
|
msleep(1000);
|
||||||
value--;
|
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.
|
//Check if still connected.
|
||||||
max17050_get_property(MAX17050_AvgCurrent, &avgCurrent);
|
max17050_get_property(MAX17050_AvgCurrent, &avgCurrent);
|
||||||
@@ -542,7 +590,7 @@ void fix_battery_desync()
|
|||||||
{
|
{
|
||||||
// Apply fix.
|
// Apply fix.
|
||||||
bq24193_fake_battery_removal();
|
bq24193_fake_battery_removal();
|
||||||
gfx_printf(&gfx_con, "Done! \n"
|
gfx_printf("Done! \n"
|
||||||
"%k1. Remove the USB cable\n"
|
"%k1. Remove the USB cable\n"
|
||||||
"2. Press POWER for 15s.\n"
|
"2. Press POWER for 15s.\n"
|
||||||
"3. Reconnect the USB to power-on!%k\n", 0xFFFFDD00, 0xFFCCCCCC);
|
"3. Reconnect the USB to power-on!%k\n", 0xFFFFDD00, 0xFFCCCCCC);
|
||||||
@@ -552,60 +600,4 @@ void fix_battery_desync()
|
|||||||
}
|
}
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
/*
|
#pragma GCC pop_options
|
||||||
#include "../modules/hekate_libsys_minerva/mtc.h"
|
|
||||||
#include "../ianos/ianos.h"
|
|
||||||
#include "../soc/fuse.h"
|
|
||||||
mtc_config_t mtc_cfg;
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|||||||
@@ -23,6 +23,5 @@ void fix_sd_all_attr();
|
|||||||
void fix_sd_nin_attr();
|
void fix_sd_nin_attr();
|
||||||
void fix_battery_desync();
|
void fix_battery_desync();
|
||||||
void menu_autorcm();
|
void menu_autorcm();
|
||||||
//void minerva();
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* 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
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -18,14 +18,16 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "di.h"
|
#include "di.h"
|
||||||
|
#include "../gfx/gfx.h"
|
||||||
|
#include "../power/max77620.h"
|
||||||
|
#include "../power/max7762x.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 "../soc/t210.h"
|
||||||
#include "../utils/util.h"
|
#include "../utils/util.h"
|
||||||
#include "../soc/i2c.h"
|
|
||||||
#include "../soc/pmc.h"
|
|
||||||
#include "../power/max77620.h"
|
|
||||||
#include "../soc/gpio.h"
|
|
||||||
#include "../soc/pinmux.h"
|
|
||||||
#include "../soc/clock.h"
|
|
||||||
|
|
||||||
#include "di.inl"
|
#include "di.inl"
|
||||||
|
|
||||||
@@ -42,57 +44,64 @@ static void _display_dsi_wait(u32 timeout, u32 off, u32 mask)
|
|||||||
void display_init()
|
void display_init()
|
||||||
{
|
{
|
||||||
// Power on.
|
// Power on.
|
||||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_LDO0_CFG, 0xD0); // Configure to 1.2V.
|
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, 0x09);
|
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.
|
// Enable Display Interface specific clocks.
|
||||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = 0x1010000;
|
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = 0x1010000; // Clear reset DSI, MIPI_CAL.
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = 0x1010000;
|
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = 0x1010000; // Set enable clock DSI, MIPI_CAL.
|
||||||
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;
|
|
||||||
|
|
||||||
// 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_DPD_REQ) = 0x40000000;
|
||||||
PMC(APBDEV_PMC_IO_DPD2_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_EN) &= ~PINMUX_TRISTATE;
|
||||||
PINMUX_AUX(PINMUX_AUX_NFC_INT) &= ~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_PWM) &= ~PINMUX_TRISTATE;
|
||||||
PINMUX_AUX(PINMUX_AUX_LCD_BL_EN) &= ~PINMUX_TRISTATE;
|
PINMUX_AUX(PINMUX_AUX_LCD_BL_EN) &= ~PINMUX_TRISTATE;
|
||||||
PINMUX_AUX(PINMUX_AUX_LCD_RST) &= ~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.
|
// Set Backlight +-5V pins mode and direction
|
||||||
gpio_output_enable(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_OUTPUT_ENABLE); // Backlight +-5V.
|
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.
|
gpio_write(GPIO_PORT_I, GPIO_PIN_0, GPIO_HIGH); // Backlight +5V enable.
|
||||||
|
|
||||||
usleep(10000);
|
usleep(10000);
|
||||||
|
|
||||||
gpio_write(GPIO_PORT_I, GPIO_PIN_1, GPIO_HIGH); // Backlight -5V enable.
|
gpio_write(GPIO_PORT_I, GPIO_PIN_1, GPIO_HIGH); // Backlight -5V enable.
|
||||||
|
|
||||||
usleep(10000);
|
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_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;
|
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);
|
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 *)DISPLAY_A_BASE, _display_config_2, 94);
|
||||||
exec_cfg((u32 *)DSI_BASE, _display_config_3, 61);
|
exec_cfg((u32 *)DSI_BASE, _display_config_3, 61);
|
||||||
|
|
||||||
usleep(10000);
|
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);
|
usleep(60000);
|
||||||
|
|
||||||
|
// Setups DSI packet configuration and request display id.
|
||||||
DSI(_DSIREG(DSI_BTA_TIMING)) = 0x50204;
|
DSI(_DSIREG(DSI_BTA_TIMING)) = 0x50204;
|
||||||
DSI(_DSIREG(DSI_WR_DATA)) = 0x337; // MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE
|
DSI(_DSIREG(DSI_WR_DATA)) = 0x337; // MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE
|
||||||
DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST;
|
DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST;
|
||||||
@@ -121,19 +130,22 @@ void display_init()
|
|||||||
|
|
||||||
usleep(20000);
|
usleep(20000);
|
||||||
|
|
||||||
|
// Configure PLLD for DISP1.
|
||||||
exec_cfg((u32 *)CLOCK_BASE, _display_config_6, 3);
|
exec_cfg((u32 *)CLOCK_BASE, _display_config_6, 3);
|
||||||
|
|
||||||
|
// Finalize DSI configuration.
|
||||||
exec_cfg((u32 *)DSI_BASE, _display_config_5, 21);
|
exec_cfg((u32 *)DSI_BASE, _display_config_5, 21);
|
||||||
DISPLAY_A(_DIREG(DC_DISP_DISP_CLOCK_CONTROL)) = 4;
|
DISPLAY_A(_DIREG(DC_DISP_DISP_CLOCK_CONTROL)) = 4;
|
||||||
exec_cfg((u32 *)DSI_BASE, _display_config_7, 10);
|
exec_cfg((u32 *)DSI_BASE, _display_config_7, 10);
|
||||||
|
|
||||||
usleep(10000);
|
usleep(10000);
|
||||||
|
|
||||||
|
// Calibrate display communication pads.
|
||||||
exec_cfg((u32 *)MIPI_CAL_BASE, _display_config_8, 6);
|
exec_cfg((u32 *)MIPI_CAL_BASE, _display_config_8, 6);
|
||||||
exec_cfg((u32 *)DSI_BASE, _display_config_9, 4);
|
exec_cfg((u32 *)DSI_BASE, _display_config_9, 4);
|
||||||
exec_cfg((u32 *)MIPI_CAL_BASE, _display_config_10, 16);
|
exec_cfg((u32 *)MIPI_CAL_BASE, _display_config_10, 16);
|
||||||
|
|
||||||
usleep(10000);
|
usleep(10000);
|
||||||
|
|
||||||
|
// Enable video display controller.
|
||||||
exec_cfg((u32 *)DISPLAY_A_BASE, _display_config_11, 113);
|
exec_cfg((u32 *)DISPLAY_A_BASE, _display_config_11, 113);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,11 +153,10 @@ void display_backlight_pwm_init()
|
|||||||
{
|
{
|
||||||
clock_enable_pwm();
|
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.
|
gpio_config(GPIO_PORT_V, GPIO_PIN_0, GPIO_MODE_SPIO); // Backlight power mode.
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void display_backlight(bool enable)
|
void display_backlight(bool enable)
|
||||||
@@ -155,7 +166,7 @@ void display_backlight(bool enable)
|
|||||||
|
|
||||||
void display_backlight_brightness(u32 brightness, u32 step_delay)
|
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)
|
if (brightness == old_value)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -166,7 +177,7 @@ void display_backlight_brightness(u32 brightness, u32 step_delay)
|
|||||||
{
|
{
|
||||||
for (u32 i = old_value; i < brightness + 1; i++)
|
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);
|
usleep(step_delay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -174,12 +185,12 @@ void display_backlight_brightness(u32 brightness, u32 step_delay)
|
|||||||
{
|
{
|
||||||
for (u32 i = old_value; i > brightness; i--)
|
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);
|
usleep(step_delay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!brightness)
|
if (!brightness)
|
||||||
PWM(PWM_CONTROLLER_PWM_CSR) = 0;
|
PWM(PWM_CONTROLLER_PWM_CSR_0) = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void display_end()
|
void display_end()
|
||||||
@@ -190,13 +201,14 @@ void display_end()
|
|||||||
DSI(_DSIREG(DSI_WR_DATA)) = 0x2805; // MIPI_DCS_SET_DISPLAY_OFF
|
DSI(_DSIREG(DSI_WR_DATA)) = 0x2805; // MIPI_DCS_SET_DISPLAY_OFF
|
||||||
|
|
||||||
DISPLAY_A(_DIREG(DC_CMD_STATE_ACCESS)) = READ_MUX | WRITE_MUX;
|
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 *)DISPLAY_A_BASE, _display_config_12, 17);
|
||||||
exec_cfg((u32 *)DSI_BASE, _display_config_13, 16);
|
exec_cfg((u32 *)DSI_BASE, _display_config_13, 16);
|
||||||
|
|
||||||
usleep(10000);
|
usleep(10000);
|
||||||
|
|
||||||
|
// De-initialize display panel.
|
||||||
if (_display_ver == 0x10)
|
if (_display_ver == 0x10)
|
||||||
exec_cfg((u32 *)DSI_BASE, _display_config_14, 22);
|
exec_cfg((u32 *)DSI_BASE, _display_config_14, 22);
|
||||||
|
|
||||||
@@ -205,31 +217,31 @@ void display_end()
|
|||||||
|
|
||||||
usleep(50000);
|
usleep(50000);
|
||||||
|
|
||||||
|
// Disable display and backlight pins.
|
||||||
gpio_write(GPIO_PORT_V, GPIO_PIN_2, GPIO_LOW); //Backlight Reset disable.
|
gpio_write(GPIO_PORT_V, GPIO_PIN_2, GPIO_LOW); //Backlight Reset disable.
|
||||||
|
|
||||||
usleep(10000);
|
usleep(10000);
|
||||||
|
|
||||||
gpio_write(GPIO_PORT_I, GPIO_PIN_1, GPIO_LOW); //Backlight -5V disable.
|
gpio_write(GPIO_PORT_I, GPIO_PIN_1, GPIO_LOW); //Backlight -5V disable.
|
||||||
|
|
||||||
usleep(10000);
|
usleep(10000);
|
||||||
|
|
||||||
gpio_write(GPIO_PORT_I, GPIO_PIN_0, GPIO_LOW); //Backlight +5V disable.
|
gpio_write(GPIO_PORT_I, GPIO_PIN_0, GPIO_LOW); //Backlight +5V disable.
|
||||||
|
|
||||||
usleep(10000);
|
usleep(10000);
|
||||||
|
|
||||||
// Disable clocks.
|
// Disable Display Interface specific clocks.
|
||||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_SET) = 0x1010000;
|
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_SET) = 0x1010000; // Set reset clock DSI, MIPI_CAL.
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_CLR) = 0x1010000;
|
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_CLR) = 0x1010000; // Clear enable clock DSI, MIPI_CAL.
|
||||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = 0x18000000;
|
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = 0x18000000; // Set reset DISP1, HOST1X.
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = 0x18000000;
|
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_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;
|
DSI(_DSIREG(DSI_POWER_CONTROL)) = 0;
|
||||||
|
|
||||||
|
// Switch to automatic function mode.
|
||||||
gpio_config(GPIO_PORT_V, GPIO_PIN_0, GPIO_MODE_SPIO); // Backlight PWM.
|
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) & ~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)
|
void display_color_screen(u32 color)
|
||||||
@@ -242,7 +254,6 @@ void display_color_screen(u32 color)
|
|||||||
DISPLAY_A(_DIREG(DC_WIN_CD_WIN_OPTIONS)) = 0;
|
DISPLAY_A(_DIREG(DC_WIN_CD_WIN_OPTIONS)) = 0;
|
||||||
DISPLAY_A(_DIREG(DC_DISP_BLEND_BACKGROUND_COLOR)) = color;
|
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;
|
DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = (DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) & 0xFFFFFFFE) | GENERAL_ACT_REQ;
|
||||||
|
|
||||||
usleep(35000);
|
usleep(35000);
|
||||||
|
|
||||||
display_backlight(true);
|
display_backlight(true);
|
||||||
@@ -251,11 +262,11 @@ void display_color_screen(u32 color)
|
|||||||
u32 *display_init_framebuffer()
|
u32 *display_init_framebuffer()
|
||||||
{
|
{
|
||||||
// Sanitize framebuffer area.
|
// Sanitize framebuffer area.
|
||||||
memset((u32 *)0xC0000000, 0, 0x3C0000);
|
memset((u32 *)FB_ADDRESS, 0, 0x3C0000);
|
||||||
// This configures the framebuffer @ 0xC0000000 with a resolution of 1280x720 (line stride 768).
|
// 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);
|
exec_cfg((u32 *)DISPLAY_A_BASE, cfg_display_framebuffer, 32);
|
||||||
|
|
||||||
usleep(35000);
|
usleep(35000);
|
||||||
|
|
||||||
return (u32 *)0xC0000000;
|
return (u32 *)FB_ADDRESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,8 @@
|
|||||||
|
|
||||||
#include "../utils/types.h"
|
#include "../utils/types.h"
|
||||||
|
|
||||||
|
#define FB_ADDRESS 0xC0000000
|
||||||
|
|
||||||
/*! Display registers. */
|
/*! Display registers. */
|
||||||
#define _DIREG(reg) ((reg) * 4)
|
#define _DIREG(reg) ((reg) * 4)
|
||||||
|
|
||||||
@@ -233,7 +235,7 @@
|
|||||||
#define UV_LINE_STRIDE(x) (((x) & 0xffff) << 16)
|
#define UV_LINE_STRIDE(x) (((x) & 0xffff) << 16)
|
||||||
#define DC_WIN_DV_CONTROL 0x70E
|
#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_START_ADDR 0x800
|
||||||
#define DC_WINBUF_ADDR_H_OFFSET 0x806
|
#define DC_WINBUF_ADDR_H_OFFSET 0x806
|
||||||
#define DC_WINBUF_ADDR_V_OFFSET 0x808
|
#define DC_WINBUF_ADDR_V_OFFSET 0x808
|
||||||
@@ -333,7 +335,7 @@
|
|||||||
#define DSI_PAD_CONTROL_VS1_PDIO_CLK (1 << 8)
|
#define DSI_PAD_CONTROL_VS1_PDIO_CLK (1 << 8)
|
||||||
#define DSI_PAD_CONTROL_VS1_PDIO(x) (((x) & 0xf) << 0)
|
#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_VIDEO_MODE_CONTROL 0x4E
|
||||||
|
|
||||||
#define DSI_PAD_CONTROL_1 0x4F
|
#define DSI_PAD_CONTROL_1 0x4F
|
||||||
@@ -350,9 +352,6 @@
|
|||||||
|
|
||||||
#define MIPI_CAL_MIPI_BIAS_PAD_CFG2 0x60
|
#define MIPI_CAL_MIPI_BIAS_PAD_CFG2 0x60
|
||||||
|
|
||||||
/*! Display backlight related PWM registers. */
|
|
||||||
#define PWM_CONTROLLER_PWM_CSR 0x00
|
|
||||||
|
|
||||||
void display_init();
|
void display_init();
|
||||||
void display_backlight_pwm_init();
|
void display_backlight_pwm_init();
|
||||||
void display_end();
|
void display_end();
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ static const cfg_op_t _display_config_2[94] = {
|
|||||||
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||||
{DC_WIN_WIN_OPTIONS, 0},
|
{DC_WIN_WIN_OPTIONS, 0},
|
||||||
{DC_DISP_DISP_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_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_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_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||||
{DC_WIN_WIN_OPTIONS, 0},
|
{DC_WIN_WIN_OPTIONS, 0},
|
||||||
{DC_DISP_DISP_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_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_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ},
|
||||||
{DC_CMD_STATE_ACCESS, 0},
|
{DC_CMD_STATE_ACCESS, 0},
|
||||||
@@ -455,7 +455,7 @@ static const cfg_op_t _display_config_12[17] = {
|
|||||||
{DC_CMD_STATE_ACCESS, 0},
|
{DC_CMD_STATE_ACCESS, 0},
|
||||||
{DC_CMD_INT_ENABLE, 0},
|
{DC_CMD_INT_ENABLE, 0},
|
||||||
{DC_CMD_CONT_SYNCPT_VSYNC, 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_UPDATE},
|
||||||
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
|
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
|
||||||
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
|
{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_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_WIN_BUFFER_CONTROL, 0},
|
||||||
{DC_WINBUF_SURFACE_KIND, 0}, //Regular surface.
|
{DC_WINBUF_SURFACE_KIND, 0}, //Regular surface.
|
||||||
{DC_WINBUF_START_ADDR, 0xC0000000}, //Framebuffer address.
|
{DC_WINBUF_START_ADDR, FB_ADDRESS}, //Framebuffer address.
|
||||||
{DC_WINBUF_ADDR_H_OFFSET, 0},
|
{DC_WINBUF_ADDR_H_OFFSET, 0},
|
||||||
{DC_WINBUF_ADDR_V_OFFSET, 0},
|
{DC_WINBUF_ADDR_V_OFFSET, 0},
|
||||||
{DC_WIN_WIN_OPTIONS, 0},
|
{DC_WIN_WIN_OPTIONS, 0},
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* 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
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -117,73 +117,73 @@ static const u8 _gfx_font[] = {
|
|||||||
0x00, 0x00, 0x00, 0x4C, 0x32, 0x00, 0x00, 0x00 // Char 126 (~)
|
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;
|
gfx_ctxt.fb = fb;
|
||||||
ctxt->width = width;
|
gfx_ctxt.width = width;
|
||||||
ctxt->height = height;
|
gfx_ctxt.height = height;
|
||||||
ctxt->stride = stride;
|
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++)
|
for (u32 i = 0; i < gfx_ctxt.width * gfx_ctxt.height; i++)
|
||||||
ctxt->fb[i] = color;
|
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;
|
gfx_con.gfx_ctxt = &gfx_ctxt;
|
||||||
con->fntsz = 16;
|
gfx_con.fntsz = 16;
|
||||||
con->x = 0;
|
gfx_con.x = 0;
|
||||||
con->y = 0;
|
gfx_con.y = 0;
|
||||||
con->savedx = 0;
|
gfx_con.savedx = 0;
|
||||||
con->savedy = 0;
|
gfx_con.savedy = 0;
|
||||||
con->fgcol = 0xFFCCCCCC;
|
gfx_con.fgcol = 0xFFCCCCCC;
|
||||||
con->fillbg = 0;
|
gfx_con.fillbg = 1;
|
||||||
con->bgcol = 0xFF1B1B1B;
|
gfx_con.bgcol = 0xFF1B1B1B;
|
||||||
con->mute = 0;
|
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;
|
gfx_con.fgcol = fgcol;
|
||||||
con->fillbg = fillbg;
|
gfx_con.fillbg = fillbg;
|
||||||
con->bgcol = bgcol;
|
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;
|
*x = gfx_con.x;
|
||||||
*y = con->y;
|
*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;
|
gfx_con.x = x;
|
||||||
con->y = y;
|
gfx_con.y = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gfx_putc(gfx_con_t *con, char c)
|
void gfx_putc(char c)
|
||||||
{
|
{
|
||||||
// Duplicate code for performance reasons.
|
// Duplicate code for performance reasons.
|
||||||
switch (con->fntsz)
|
switch (gfx_con.fntsz)
|
||||||
{
|
{
|
||||||
case 16:
|
case 16:
|
||||||
if (c >= 32 && c <= 126)
|
if (c >= 32 && c <= 126)
|
||||||
{
|
{
|
||||||
u8 *cbuf = (u8 *)&_gfx_font[8 * (c - 32)];
|
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)
|
||||||
{
|
{
|
||||||
@@ -194,33 +194,33 @@ void gfx_putc(gfx_con_t *con, char c)
|
|||||||
{
|
{
|
||||||
if (v & 1)
|
if (v & 1)
|
||||||
{
|
{
|
||||||
*fb = con->fgcol;
|
*fb = gfx_con.fgcol;
|
||||||
fb++;
|
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++;
|
||||||
*fb = con->bgcol;
|
*fb = gfx_con.bgcol;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
fb++;
|
fb++;
|
||||||
v >>= 1;
|
v >>= 1;
|
||||||
fb++;
|
fb++;
|
||||||
}
|
}
|
||||||
fb += con->gfx_ctxt->stride - 16;
|
fb += gfx_ctxt.stride - 16;
|
||||||
v = *cbuf;
|
v = *cbuf;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
con->x += 16;
|
gfx_con.x += 16;
|
||||||
}
|
}
|
||||||
else if (c == '\n')
|
else if (c == '\n')
|
||||||
{
|
{
|
||||||
con->x = 0;
|
gfx_con.x = 0;
|
||||||
con->y +=16;
|
gfx_con.y +=16;
|
||||||
if (con->y > con->gfx_ctxt->height - 16)
|
if (gfx_con.y > gfx_ctxt.height - 16)
|
||||||
con->y = 0;
|
gfx_con.y = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
@@ -228,45 +228,45 @@ void gfx_putc(gfx_con_t *con, char c)
|
|||||||
if (c >= 32 && c <= 126)
|
if (c >= 32 && c <= 126)
|
||||||
{
|
{
|
||||||
u8 *cbuf = (u8 *)&_gfx_font[8 * (c - 32)];
|
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++)
|
for (u32 i = 0; i < 8; i++)
|
||||||
{
|
{
|
||||||
u8 v = *cbuf++;
|
u8 v = *cbuf++;
|
||||||
for (u32 j = 0; j < 8; j++)
|
for (u32 j = 0; j < 8; j++)
|
||||||
{
|
{
|
||||||
if (v & 1)
|
if (v & 1)
|
||||||
*fb = con->fgcol;
|
*fb = gfx_con.fgcol;
|
||||||
else if (con->fillbg)
|
else if (gfx_con.fillbg)
|
||||||
*fb = con->bgcol;
|
*fb = gfx_con.bgcol;
|
||||||
v >>= 1;
|
v >>= 1;
|
||||||
fb++;
|
fb++;
|
||||||
}
|
}
|
||||||
fb += con->gfx_ctxt->stride - 8;
|
fb += gfx_ctxt.stride - 8;
|
||||||
}
|
}
|
||||||
con->x += 8;
|
gfx_con.x += 8;
|
||||||
}
|
}
|
||||||
else if (c == '\n')
|
else if (c == '\n')
|
||||||
{
|
{
|
||||||
con->x = 0;
|
gfx_con.x = 0;
|
||||||
con->y += 8;
|
gfx_con.y += 8;
|
||||||
if (con->y > con->gfx_ctxt->height - 8)
|
if (gfx_con.y > gfx_ctxt.height - 8)
|
||||||
con->y = 0;
|
gfx_con.y = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void gfx_puts(gfx_con_t *con, const char *s)
|
void gfx_puts(const char *s)
|
||||||
{
|
{
|
||||||
if (!s || con->mute)
|
if (!s || gfx_con.mute)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (; *s; s++)
|
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];
|
char buf[65];
|
||||||
static const char digits[] = "0123456789ABCDEFghijklmnopqrstuvwxyz";
|
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;
|
u8 prevFontSize = gfx_con.fntsz;
|
||||||
con->fntsz = 8;
|
gfx_con.fntsz = 8;
|
||||||
gfx_putc(con, '\n');
|
gfx_putc('\n');
|
||||||
con->fntsz = prevFontSize;
|
gfx_con.fntsz = prevFontSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gfx_put_big_sep(gfx_con_t *con)
|
void gfx_put_big_sep()
|
||||||
{
|
{
|
||||||
u8 prevFontSize = con->fntsz;
|
u8 prevFontSize = gfx_con.fntsz;
|
||||||
con->fntsz = 16;
|
gfx_con.fntsz = 16;
|
||||||
gfx_putc(con, '\n');
|
gfx_putc('\n');
|
||||||
con->fntsz = prevFontSize;
|
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;
|
return;
|
||||||
|
|
||||||
va_list ap;
|
va_list ap;
|
||||||
@@ -348,40 +348,40 @@ void gfx_printf(gfx_con_t *con, const char *fmt, ...)
|
|||||||
switch(*fmt)
|
switch(*fmt)
|
||||||
{
|
{
|
||||||
case 'c':
|
case 'c':
|
||||||
gfx_putc(con, va_arg(ap, u32));
|
gfx_putc(va_arg(ap, u32));
|
||||||
break;
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
gfx_puts(con, va_arg(ap, char *));
|
gfx_puts(va_arg(ap, char *));
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
_gfx_putn(con, va_arg(ap, u32), 10, fill, fcnt);
|
_gfx_putn(va_arg(ap, u32), 10, fill, fcnt);
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
case 'P':
|
case 'P':
|
||||||
case 'x':
|
case 'x':
|
||||||
case 'X':
|
case 'X':
|
||||||
_gfx_putn(con, va_arg(ap, u32), 16, fill, fcnt);
|
_gfx_putn(va_arg(ap, u32), 16, fill, fcnt);
|
||||||
break;
|
break;
|
||||||
case 'k':
|
case 'k':
|
||||||
con->fgcol = va_arg(ap, u32);
|
gfx_con.fgcol = va_arg(ap, u32);
|
||||||
break;
|
break;
|
||||||
case 'K':
|
case 'K':
|
||||||
con->bgcol = va_arg(ap, u32);
|
gfx_con.bgcol = va_arg(ap, u32);
|
||||||
con->fillbg = 1;
|
gfx_con.fillbg = 1;
|
||||||
break;
|
break;
|
||||||
case '%':
|
case '%':
|
||||||
gfx_putc(con, '%');
|
gfx_putc('%');
|
||||||
break;
|
break;
|
||||||
case '\0':
|
case '\0':
|
||||||
goto out;
|
goto out;
|
||||||
default:
|
default:
|
||||||
gfx_putc(con, '%');
|
gfx_putc('%');
|
||||||
gfx_putc(con, *fmt);
|
gfx_putc(*fmt);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
gfx_putc(con, *fmt);
|
gfx_putc(*fmt);
|
||||||
fmt++;
|
fmt++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -389,33 +389,33 @@ void gfx_printf(gfx_con_t *con, const char *fmt, ...)
|
|||||||
va_end(ap);
|
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;
|
return;
|
||||||
|
|
||||||
u8 prevFontSize = con->fntsz;
|
u8 prevFontSize = gfx_con.fntsz;
|
||||||
con->fntsz = 8;
|
gfx_con.fntsz = 8;
|
||||||
for(u32 i = 0; i < len; i++)
|
for(u32 i = 0; i < len; i++)
|
||||||
{
|
{
|
||||||
if(i % 0x10 == 0)
|
if(i % 0x10 == 0)
|
||||||
{
|
{
|
||||||
if(i != 0)
|
if(i != 0)
|
||||||
{
|
{
|
||||||
gfx_puts(con, "| ");
|
gfx_puts("| ");
|
||||||
for(u32 j = 0; j < 0x10; j++)
|
for(u32 j = 0; j < 0x10; j++)
|
||||||
{
|
{
|
||||||
u8 c = buf[i - 0x10 + j];
|
u8 c = buf[i - 0x10 + j];
|
||||||
if(c >= 32 && c <= 126)
|
if(c >= 32 && c <= 126)
|
||||||
gfx_putc(con, c);
|
gfx_putc(c);
|
||||||
else
|
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)
|
if (i == len - 1)
|
||||||
{
|
{
|
||||||
int ln = len % 0x10 != 0;
|
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;
|
k = (len & 0xF) - 1;
|
||||||
for (u32 j = 0; j < 0x10 - k; j++)
|
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++)
|
for(u32 j = 0; j < (ln ? k : k + 1); j++)
|
||||||
{
|
{
|
||||||
u8 c = buf[i - k + j];
|
u8 c = buf[i - k + j];
|
||||||
if(c >= 32 && c <= 126)
|
if(c >= 32 && c <= 126)
|
||||||
gfx_putc(con, c);
|
gfx_putc(c);
|
||||||
else
|
else
|
||||||
gfx_putc(con, '.');
|
gfx_putc('.');
|
||||||
}
|
}
|
||||||
gfx_putc(con, '\n');
|
gfx_putc('\n');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
gfx_putc(con, '\n');
|
gfx_putc('\n');
|
||||||
con->fntsz = prevFontSize;
|
gfx_con.fntsz = prevFontSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int abs(int x)
|
static int abs(int x)
|
||||||
@@ -449,12 +449,12 @@ static int abs(int x)
|
|||||||
return 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 dx = abs(x1 - x0), sx = x0 < x1 ? 1 : -1;
|
||||||
int dy = abs(y1 - y0), sy = y0 < y1 ? 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)
|
while (1)
|
||||||
{
|
{
|
||||||
gfx_set_pixel(ctxt, x0, y0, color);
|
gfx_set_pixel(x0, y0, color);
|
||||||
if (x0 == x1 && y0 == y1)
|
if (x0 == x1 && y0 == y1)
|
||||||
break;
|
break;
|
||||||
e2 = err;
|
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;
|
u32 pos = 0;
|
||||||
for (u32 y = pos_y; y < (pos_y + size_y); y++)
|
for (u32 y = pos_y; y < (pos_y + size_y); y++)
|
||||||
{
|
{
|
||||||
for (u32 x = pos_x; x < (pos_x + size_x); x++)
|
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++;
|
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;
|
u32 pos = 0;
|
||||||
for (u32 y = pos_y; y < (pos_y + size_y); y++)
|
for (u32 y = pos_y; y < (pos_y + size_y); y++)
|
||||||
{
|
{
|
||||||
for (u32 x = pos_x; x < (pos_x + size_x); x++)
|
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;
|
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;
|
u32 *ptr = (u32 *)buf;
|
||||||
for (u32 y = pos_y; y < (pos_y + size_y); y++)
|
for (u32 y = pos_y; y < (pos_y + size_y); y++)
|
||||||
for (u32 x = pos_x; x < (pos_x + size_x); x++)
|
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 y = pos_y; y < (pos_y + size_y); y++)
|
||||||
{
|
{
|
||||||
for (u32 x = pos_x; x < (pos_x + size_x); x++)
|
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,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
* Copyright (C) 2018 CTCaer
|
* Copyright (C) 2018-2019 CTCaer
|
||||||
* Copyright (C) 2018 M4xw
|
* Copyright (C) 2018 M4xw
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
@@ -21,26 +21,35 @@
|
|||||||
|
|
||||||
#include "../../common/common_gfx.h"
|
#include "../../common/common_gfx.h"
|
||||||
|
|
||||||
void gfx_init_ctxt(gfx_ctxt_t *ctxt, u32 *fb, u32 width, u32 height, u32 stride);
|
#define EPRINTF(text) gfx_printf("%k"text"%k\n", 0xFFFF0000, 0xFFCCCCCC)
|
||||||
void gfx_clear_grey(gfx_ctxt_t *ctxt, u8 color);
|
#define EPRINTFARGS(text, args...) gfx_printf("%k"text"%k\n", 0xFFFF0000, args, 0xFFCCCCCC)
|
||||||
void gfx_clear_partial_grey(gfx_ctxt_t *ctxt, u8 color, u32 pos_x, u32 height);
|
#define WPRINTF(text) gfx_printf("%k"text"%k\n", 0xFFFFDD00, 0xFFCCCCCC)
|
||||||
void gfx_clear_color(gfx_ctxt_t *ctxt, u32 color);
|
#define WPRINTFARGS(text, args...) gfx_printf("%k"text"%k\n", 0xFFFFDD00, args, 0xFFCCCCCC)
|
||||||
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_set_pixel(gfx_ctxt_t *ctxt, u32 x, u32 y, u32 color);
|
void gfx_init_ctxt(u32 *fb, u32 width, u32 height, u32 stride);
|
||||||
void gfx_line(gfx_ctxt_t *ctxt, int x0, int y0, int x1, int y1, u32 color);
|
void gfx_clear_grey(u8 color);
|
||||||
void gfx_put_small_sep(gfx_con_t *con);
|
void gfx_clear_partial_grey(u8 color, u32 pos_x, u32 height);
|
||||||
void gfx_put_big_sep(gfx_con_t *con);
|
void gfx_clear_color(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_con_init();
|
||||||
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_con_setcol(u32 fgcol, int fillbg, u32 bgcol);
|
||||||
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_con_getpos(u32 *x, u32 *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_con_setpos(u32 x, u32 y);
|
||||||
|
void gfx_putc(char c);
|
||||||
|
void gfx_puts(const char *s);
|
||||||
|
void gfx_printf(const char *fmt, ...);
|
||||||
|
void gfx_hexdump(u32 base, const u8 *buf, u32 len);
|
||||||
|
|
||||||
|
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;
|
||||||
|
gfx_con_t gfx_con;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -32,7 +32,7 @@ extern u8 *Kc_MENU_LOGO;
|
|||||||
|
|
||||||
extern hekate_config h_cfg;
|
extern hekate_config h_cfg;
|
||||||
|
|
||||||
void tui_sbar(gfx_con_t *con, bool force_update)
|
void tui_sbar(bool force_update)
|
||||||
{
|
{
|
||||||
u32 cx, cy;
|
u32 cx, cy;
|
||||||
|
|
||||||
@@ -41,78 +41,78 @@ void tui_sbar(gfx_con_t *con, bool force_update)
|
|||||||
if (timePassed < 5)
|
if (timePassed < 5)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
u8 prevFontSize = con->fntsz;
|
u8 prevFontSize = gfx_con.fntsz;
|
||||||
con->fntsz = 16;
|
gfx_con.fntsz = 16;
|
||||||
h_cfg.sbar_time_keeping = get_tmr_s();
|
h_cfg.sbar_time_keeping = get_tmr_s();
|
||||||
|
|
||||||
u32 battPercent = 0;
|
u32 battPercent = 0;
|
||||||
int battVoltCurr = 0;
|
int battVoltCurr = 0;
|
||||||
|
|
||||||
gfx_con_getpos(con, &cx, &cy);
|
gfx_con_getpos(&cx, &cy);
|
||||||
gfx_con_setpos(con, 0, 1260);
|
gfx_con_setpos(0, 1260);
|
||||||
|
|
||||||
max17050_get_property(MAX17050_RepSOC, (int *)&battPercent);
|
max17050_get_property(MAX17050_RepSOC, (int *)&battPercent);
|
||||||
max17050_get_property(MAX17050_VCELL, &battVoltCurr);
|
max17050_get_property(MAX17050_VCELL, &battVoltCurr);
|
||||||
|
|
||||||
gfx_clear_partial_grey(con->gfx_ctxt, 0x30, 1256, 24);
|
gfx_clear_partial_grey(0x30, 1256, 24);
|
||||||
gfx_printf(con, "%K%k Battery: %d.%d%% (%d mV) - Charge:", 0xFF303030, 0xFF888888,
|
gfx_printf("%K%k Battery: %d.%d%% (%d mV) - Charge:", 0xFF303030, 0xFF888888,
|
||||||
(battPercent >> 8) & 0xFF, (battPercent & 0xFF) / 26, battVoltCurr);
|
(battPercent >> 8) & 0xFF, (battPercent & 0xFF) / 26, battVoltCurr);
|
||||||
|
|
||||||
max17050_get_property(MAX17050_AvgCurrent, &battVoltCurr);
|
max17050_get_property(MAX17050_Current, &battVoltCurr);
|
||||||
|
|
||||||
if (battVoltCurr >= 0)
|
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);
|
0xFF008800, battVoltCurr / 1000, 0xFFCCCCCC, 0xFF1B1B1B);
|
||||||
else
|
else
|
||||||
gfx_printf(con, " %k-%d mA%k%K\n",
|
gfx_printf(" %k-%d mA%k%K\n",
|
||||||
0xFF880000, (~battVoltCurr) / 1000, 0xFFCCCCCC, 0xFF1B1B1B);
|
0xFF880000, (~battVoltCurr) / 1000, 0xFFCCCCCC, 0xFF1B1B1B);
|
||||||
con->fntsz = prevFontSize;
|
gfx_con.fntsz = prevFontSize;
|
||||||
gfx_con_setpos(con, cx, cy);
|
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;
|
u32 cx, cy;
|
||||||
if (val > 200)
|
if (val > 200)
|
||||||
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;
|
x += 7 * gfx_con.fntsz;
|
||||||
|
|
||||||
for (int i = 0; i < (con->fntsz >> 3) * 6; i++)
|
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(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 + 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.
|
// 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;
|
int idx = 0, prev_idx = 0, cnt = 0x7FFFFFFF;
|
||||||
|
|
||||||
gfx_clear_partial_grey(con->gfx_ctxt, 0x1B, 0, 1256);
|
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||||
tui_sbar(con, true);
|
tui_sbar(true);
|
||||||
|
|
||||||
#ifdef MENU_LOGO_ENABLE
|
#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);
|
X_MENU_LOGO, Y_MENU_LOGO, X_POS_MENU_LOGO, Y_POS_MENU_LOGO);
|
||||||
#endif //MENU_LOGO_ENABLE
|
#endif //MENU_LOGO_ENABLE
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
gfx_con_setcol(con, 0xFFCCCCCC, 1, 0xFF1B1B1B);
|
gfx_con_setcol(0xFFCCCCCC, 1, 0xFF1B1B1B);
|
||||||
gfx_con_setpos(con, menu->x, menu->y);
|
gfx_con_setpos(menu->x, menu->y);
|
||||||
gfx_printf(con, "[%s]\n\n", menu->caption);
|
gfx_printf("[%s]\n\n", menu->caption);
|
||||||
|
|
||||||
// Skip caption or seperator lines selection.
|
// Skip caption or seperator lines selection.
|
||||||
while (menu->ents[idx].type == MENT_CAPTION ||
|
while (menu->ents[idx].type == MENT_CAPTION ||
|
||||||
@@ -143,30 +143,30 @@ void *tui_do_menu(gfx_con_t *con, menu_t *menu)
|
|||||||
for (cnt = 0; menu->ents[cnt].type != MENT_END; cnt++)
|
for (cnt = 0; menu->ents[cnt].type != MENT_END; cnt++)
|
||||||
{
|
{
|
||||||
if (cnt == idx)
|
if (cnt == idx)
|
||||||
gfx_con_setcol(con, 0xFF1B1B1B, 1, 0xFFCCCCCC);
|
gfx_con_setcol(0xFF1B1B1B, 1, 0xFFCCCCCC);
|
||||||
else
|
else
|
||||||
gfx_con_setcol(con, 0xFFCCCCCC, 1, 0xFF1B1B1B);
|
gfx_con_setcol(0xFFCCCCCC, 1, 0xFF1B1B1B);
|
||||||
if (menu->ents[cnt].type == MENT_CAPTION)
|
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)
|
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)
|
if(menu->ents[cnt].type == MENT_MENU)
|
||||||
gfx_printf(con, "%k...", 0xFF0099EE);
|
gfx_printf("%k...", 0xFF0099EE);
|
||||||
gfx_printf(con, " \n");
|
gfx_printf(" \n");
|
||||||
}
|
}
|
||||||
gfx_con_setcol(con, 0xFFCCCCCC, 1, 0xFF1B1B1B);
|
gfx_con_setcol(0xFFCCCCCC, 1, 0xFF1B1B1B);
|
||||||
gfx_putc(con, '\n');
|
gfx_putc('\n');
|
||||||
|
|
||||||
// Print help and battery status.
|
// Print help and battery status.
|
||||||
gfx_con_setpos(con, 0, 1127);
|
gfx_con_setpos(0, 1127);
|
||||||
if (h_cfg.errors)
|
if (h_cfg.errors)
|
||||||
{
|
{
|
||||||
gfx_printf(con, "%k Warning: %k", 0xFF800000, 0xFF555555);
|
gfx_printf("%k Warning: %k", 0xFF800000, 0xFF555555);
|
||||||
if (h_cfg.errors & ERR_LIBSYS_LP0)
|
if (h_cfg.errors & ERR_LIBSYS_LP0)
|
||||||
gfx_printf(con, "Sleep mode library is missing!\n");
|
gfx_printf("Sleep mode library is missing!\n");
|
||||||
}
|
}
|
||||||
gfx_con_setpos(con, 0, 1191);
|
gfx_con_setpos(0, 1191);
|
||||||
gfx_printf(con, "%k VOL: Move up/down\n PWR: Select option%k", 0xFF555555, 0xFFCCCCCC);
|
gfx_printf("%k VOL: Move up/down\n PWR: Select option%k", 0xFF555555, 0xFFCCCCCC);
|
||||||
|
|
||||||
display_backlight_brightness(h_cfg.backlight, 1000);
|
display_backlight_brightness(h_cfg.backlight, 1000);
|
||||||
|
|
||||||
@@ -196,7 +196,7 @@ void *tui_do_menu(gfx_con_t *con, menu_t *menu)
|
|||||||
ent->handler(ent->data);
|
ent->handler(ent->data);
|
||||||
break;
|
break;
|
||||||
case MENT_MENU:
|
case MENT_MENU:
|
||||||
return tui_do_menu(con, ent->menu);
|
return tui_do_menu(ent->menu);
|
||||||
break;
|
break;
|
||||||
case MENT_DATA:
|
case MENT_DATA:
|
||||||
return ent->data;
|
return ent->data;
|
||||||
@@ -212,14 +212,14 @@ void *tui_do_menu(gfx_con_t *con, menu_t *menu)
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
con->fntsz = 16;
|
gfx_con.fntsz = 16;
|
||||||
gfx_clear_partial_grey(con->gfx_ctxt, 0x1B, 0, 1256);
|
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||||
#ifdef MENU_LOGO_ENABLE
|
#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);
|
X_MENU_LOGO, Y_MENU_LOGO, X_POS_MENU_LOGO, Y_POS_MENU_LOGO);
|
||||||
#endif //MENU_LOGO_ENABLE
|
#endif //MENU_LOGO_ENABLE
|
||||||
}
|
}
|
||||||
tui_sbar(con, false);
|
tui_sbar(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|||||||
@@ -59,8 +59,8 @@ typedef struct _menu_t
|
|||||||
#define MDEF_CAPTION(caption, color) { MENT_CAPTION, caption, color }
|
#define MDEF_CAPTION(caption, color) { MENT_CAPTION, caption, color }
|
||||||
#define MDEF_CHGLINE() {MENT_CHGLINE}
|
#define MDEF_CHGLINE() {MENT_CHGLINE}
|
||||||
|
|
||||||
void tui_sbar(gfx_con_t *con, bool force_update);
|
void tui_sbar(bool force_update);
|
||||||
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);
|
||||||
void *tui_do_menu(gfx_con_t *con, menu_t *menu);
|
void *tui_do_menu(menu_t *menu);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
149
bootloader/hos/fss.c
Normal file
149
bootloader/hos/fss.c
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
/*
|
||||||
|
* Atmosphère Fusée Secondary Storage parser.
|
||||||
|
*
|
||||||
|
* 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 "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;
|
||||||
|
|
||||||
|
#define FSS0_MAGIC 0x30535346
|
||||||
|
#define CNT_TYPE_FSP 0
|
||||||
|
#define CNT_TYPE_EXO 1
|
||||||
|
#define CNT_TYPE_WBT 2
|
||||||
|
#define CNT_TYPE_RBT 3
|
||||||
|
#define CNT_TYPE_SP1 4
|
||||||
|
#define CNT_TYPE_SP2 5
|
||||||
|
#define CNT_TYPE_KIP 6
|
||||||
|
#define CNT_TYPE_BMP 7
|
||||||
|
#define CNT_TYPE_EMC 8
|
||||||
|
|
||||||
|
typedef struct _fss_t
|
||||||
|
{
|
||||||
|
u32 magic;
|
||||||
|
u32 size;
|
||||||
|
u32 crt0_off;
|
||||||
|
u32 cnt_off;
|
||||||
|
u32 cnt_count;
|
||||||
|
u32 hos_ver;
|
||||||
|
u32 version;
|
||||||
|
u32 git_rev;
|
||||||
|
} fss_t;
|
||||||
|
|
||||||
|
typedef struct _fss_content_t
|
||||||
|
{
|
||||||
|
u32 offset;
|
||||||
|
u32 size;
|
||||||
|
u32 type;
|
||||||
|
u32 rsvd1;
|
||||||
|
char name[0x10];
|
||||||
|
} fss_content_t;
|
||||||
|
|
||||||
|
int parse_fss(launch_ctxt_t *ctxt, const char *value)
|
||||||
|
{
|
||||||
|
FIL fp;
|
||||||
|
|
||||||
|
bool stock = false;
|
||||||
|
|
||||||
|
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, value, FA_READ) != FR_OK)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ctxt->atmosphere = true;
|
||||||
|
|
||||||
|
void *fss = malloc(f_size(&fp));
|
||||||
|
// Read header.
|
||||||
|
f_read(&fp, fss, 0x400, NULL);
|
||||||
|
|
||||||
|
u32 fss_entry = *(u32 *)(fss + 4);
|
||||||
|
fss_t *fss_meta = (fss_t *)(fss + fss_entry);
|
||||||
|
|
||||||
|
if (fss_meta->magic == FSS0_MAGIC)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
|
fss_content_t *curr_fss_cnt = (fss_content_t *)(fss + fss_meta->cnt_off);
|
||||||
|
void *content;
|
||||||
|
for (u32 i = 0; i < fss_meta->cnt_count; i++)
|
||||||
|
{
|
||||||
|
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:
|
||||||
|
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;
|
||||||
|
// TODO: add more types?
|
||||||
|
// case CNT_TYPE_SP1:
|
||||||
|
// case CNT_TYPE_SP2:
|
||||||
|
}
|
||||||
|
|
||||||
|
f_lseek(&fp, curr_fss_cnt[i].offset);
|
||||||
|
f_read(&fp, content, curr_fss_cnt[i].size, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
gfx_printf("Done!\n");
|
||||||
|
f_close(&fp);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
f_close(&fp);
|
||||||
|
free(fss);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
24
bootloader/hos/fss.h
Normal file
24
bootloader/hos/fss.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* 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 _FSS_H_
|
||||||
|
#define _FSS_H_
|
||||||
|
|
||||||
|
#include "hos.h"
|
||||||
|
|
||||||
|
int parse_fss(launch_ctxt_t *ctxt, const char *value);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
* Copyright (c) 2018 st4rk
|
* Copyright (c) 2018 st4rk
|
||||||
* Copyright (c) 2018 Ced2911
|
* Copyright (c) 2018 Ced2911
|
||||||
* Copyright (c) 2018 CTCaer
|
* Copyright (c) 2018-2019 CTCaer
|
||||||
* Copyright (c) 2018 balika011
|
* Copyright (c) 2018 balika011
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
@@ -22,34 +22,55 @@
|
|||||||
|
|
||||||
#include "hos.h"
|
#include "hos.h"
|
||||||
#include "hos_config.h"
|
#include "hos_config.h"
|
||||||
|
#include "sept.h"
|
||||||
#include "secmon_exo.h"
|
#include "secmon_exo.h"
|
||||||
#include "../config/config.h"
|
#include "../config/config.h"
|
||||||
#include "../gfx/di.h"
|
#include "../gfx/di.h"
|
||||||
#include "../mem/heap.h"
|
#include "../mem/heap.h"
|
||||||
#include "../mem/mc.h"
|
#include "../mem/mc.h"
|
||||||
|
#include "../mem/minerva.h"
|
||||||
#include "../sec/se.h"
|
#include "../sec/se.h"
|
||||||
#include "../sec/se_t210.h"
|
#include "../sec/se_t210.h"
|
||||||
#include "../sec/tsec.h"
|
#include "../sec/tsec.h"
|
||||||
|
#include "../soc/bpmp.h"
|
||||||
#include "../soc/cluster.h"
|
#include "../soc/cluster.h"
|
||||||
#include "../soc/fuse.h"
|
#include "../soc/fuse.h"
|
||||||
#include "../soc/pmc.h"
|
#include "../soc/pmc.h"
|
||||||
#include "../soc/smmu.h"
|
#include "../soc/smmu.h"
|
||||||
#include "../soc/t210.h"
|
#include "../soc/t210.h"
|
||||||
|
#include "../storage/emummc.h"
|
||||||
#include "../storage/nx_emmc.h"
|
#include "../storage/nx_emmc.h"
|
||||||
#include "../storage/sdmmc.h"
|
#include "../storage/sdmmc.h"
|
||||||
#include "../utils/util.h"
|
#include "../utils/util.h"
|
||||||
|
|
||||||
#include "../gfx/gfx.h"
|
#include "../gfx/gfx.h"
|
||||||
extern gfx_ctxt_t gfx_ctxt;
|
|
||||||
extern gfx_con_t gfx_con;
|
|
||||||
|
|
||||||
extern hekate_config h_cfg;
|
extern hekate_config h_cfg;
|
||||||
|
|
||||||
extern void sd_unmount();
|
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 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.
|
||||||
|
#define SECMON_MB_ADDR 0x40002EF8
|
||||||
|
#define SECMON7_MB_ADDR 0x400000F8
|
||||||
|
typedef struct _secmon_mailbox_t
|
||||||
|
{
|
||||||
|
// < 4.0.0 Signals - 0: Not ready, 1: BCT ready, 2: DRAM and pkg2 ready, 3: Continue boot.
|
||||||
|
// >= 4.0.0 Signals - 0: Not ready, 1: BCT ready, 2: DRAM ready, 4: pkg2 ready and continue boot.
|
||||||
|
u32 in;
|
||||||
|
// Non-zero: Secmon ready.
|
||||||
|
u32 out;
|
||||||
|
} secmon_mailbox_t;
|
||||||
|
|
||||||
static const u8 keyblob_keyseeds[][0x10] = {
|
static const u8 keyblob_keyseeds[][0x10] = {
|
||||||
{ 0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3 }, //1.0.0
|
{ 0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3 }, //1.0.0
|
||||||
{ 0x0C, 0x25, 0x61, 0x5D, 0x68, 0x4C, 0xEB, 0x42, 0x1C, 0x23, 0x79, 0xEA, 0x82, 0x25, 0x12, 0xAC }, //3.0.0
|
{ 0x0C, 0x25, 0x61, 0x5D, 0x68, 0x4C, 0xEB, 0x42, 0x1C, 0x23, 0x79, 0xEA, 0x82, 0x25, 0x12, 0xAC }, //3.0.0
|
||||||
@@ -68,7 +89,7 @@ static const u8 master_keyseed_retail[0x10] =
|
|||||||
static const u8 console_keyseed[0x10] =
|
static const u8 console_keyseed[0x10] =
|
||||||
{ 0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78 };
|
{ 0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78 };
|
||||||
|
|
||||||
static const u8 key8_keyseed[] =
|
const u8 package2_keyseed[] =
|
||||||
{ 0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7 };
|
{ 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] =
|
||||||
@@ -80,6 +101,12 @@ static const u8 master_keyseed_620[0x10] =
|
|||||||
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 };
|
{ 0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28 };
|
||||||
|
|
||||||
|
static void _hos_crit_error(const char *text)
|
||||||
|
{
|
||||||
|
display_backlight_brightness(h_cfg.backlight, 1000);
|
||||||
|
gfx_con.mute = false;
|
||||||
|
gfx_printf("%k%s%k\n", 0xFFFF0000, text, 0xFFCCCCCC);
|
||||||
|
}
|
||||||
|
|
||||||
static void _se_lock(bool lock_se)
|
static void _se_lock(bool lock_se)
|
||||||
{
|
{
|
||||||
@@ -97,20 +124,20 @@ static void _se_lock(bool lock_se)
|
|||||||
}
|
}
|
||||||
|
|
||||||
memset((void *)IPATCH_BASE, 0, 14 * sizeof(u32));
|
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.
|
// 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("SE(SE_SECURITY_0) = %08X\n", SE(SE_SECURITY_0));
|
||||||
gfx_printf(&gfx_con, "SE(0x4) = %08X\n", SE(0x4));
|
gfx_printf("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("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_RSA_KEYTABLE_ACCESS_LOCK_OFFSET) = %08X\n", SE(SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET));
|
||||||
for(u32 i = 0; i < 16; i++)
|
for(u32 i = 0; i < 16; i++)
|
||||||
gfx_printf(&gfx_con, "%02X ", SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + i * 4) & 0xFF);
|
gfx_printf("%02X ", SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + i * 4) & 0xFF);
|
||||||
gfx_putc(&gfx_con, '\n');
|
gfx_putc('\n');
|
||||||
for(u32 i = 0; i < 2; i++)
|
for(u32 i = 0; i < 2; i++)
|
||||||
gfx_printf(&gfx_con, "%02X ", SE(SE_RSA_KEYTABLE_ACCESS_REG_OFFSET + i * 4) & 0xFF);
|
gfx_printf("%02X ", SE(SE_RSA_KEYTABLE_ACCESS_REG_OFFSET + i * 4) & 0xFF);
|
||||||
gfx_putc(&gfx_con, '\n');
|
gfx_putc('\n');
|
||||||
gfx_hexdump(&gfx_con, SE_BASE, (void *)SE_BASE, 0x400);*/
|
gfx_hexdump(SE_BASE, (void *)SE_BASE, 0x400);*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void _pmc_scratch_lock(u32 kb)
|
void _pmc_scratch_lock(u32 kb)
|
||||||
@@ -129,9 +156,7 @@ void _pmc_scratch_lock(u32 kb)
|
|||||||
PMC(APBDEV_PMC_SEC_DISABLE7) = 0xFFFFFFFF;
|
PMC(APBDEV_PMC_SEC_DISABLE7) = 0xFFFFFFFF;
|
||||||
PMC(APBDEV_PMC_SEC_DISABLE8) = 0xFFAAFFFF;
|
PMC(APBDEV_PMC_SEC_DISABLE8) = 0xFFAAFFFF;
|
||||||
break;
|
break;
|
||||||
case KB_FIRMWARE_VERSION_400:
|
default:
|
||||||
case KB_FIRMWARE_VERSION_500:
|
|
||||||
case KB_FIRMWARE_VERSION_600:
|
|
||||||
PMC(APBDEV_PMC_SEC_DISABLE2) |= 0x3FCFFFF;
|
PMC(APBDEV_PMC_SEC_DISABLE2) |= 0x3FCFFFF;
|
||||||
PMC(APBDEV_PMC_SEC_DISABLE4) |= 0x3F3FFFFF;
|
PMC(APBDEV_PMC_SEC_DISABLE4) |= 0x3F3FFFFF;
|
||||||
PMC(APBDEV_PMC_SEC_DISABLE5) = 0xFFFFFFFF;
|
PMC(APBDEV_PMC_SEC_DISABLE5) = 0xFFFFFFFF;
|
||||||
@@ -144,7 +169,6 @@ void _pmc_scratch_lock(u32 kb)
|
|||||||
|
|
||||||
void _sysctr0_reset()
|
void _sysctr0_reset()
|
||||||
{
|
{
|
||||||
SYSCTR0(SYSCTR0_CNTFID0) = 19200000;
|
|
||||||
SYSCTR0(SYSCTR0_CNTCR) = 0;
|
SYSCTR0(SYSCTR0_CNTCR) = 0;
|
||||||
SYSCTR0(SYSCTR0_COUNTERID0) = 0;
|
SYSCTR0(SYSCTR0_COUNTERID0) = 0;
|
||||||
SYSCTR0(SYSCTR0_COUNTERID1) = 0;
|
SYSCTR0(SYSCTR0_COUNTERID1) = 0;
|
||||||
@@ -160,25 +184,34 @@ void _sysctr0_reset()
|
|||||||
SYSCTR0(SYSCTR0_COUNTERID11) = 0;
|
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];
|
u8 tmp[0x20];
|
||||||
u32 retries = 0;
|
u32 retries = 0;
|
||||||
|
|
||||||
tsec_ctxt->size = 0xF00;
|
|
||||||
|
|
||||||
if (kb > KB_FIRMWARE_VERSION_MAX)
|
if (kb > KB_FIRMWARE_VERSION_MAX)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// Get TSEC key.
|
if (kb <= KB_FIRMWARE_VERSION_600)
|
||||||
if (kb >= KB_FIRMWARE_VERSION_620)
|
tsec_ctxt->size = 0xF00;
|
||||||
{
|
else if (kb == KB_FIRMWARE_VERSION_620)
|
||||||
tsec_ctxt->size = 0x2900;
|
tsec_ctxt->size = 0x2900;
|
||||||
|
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)
|
||||||
|
{
|
||||||
u8 *tsec_paged = (u8 *)page_alloc(3);
|
u8 *tsec_paged = (u8 *)page_alloc(3);
|
||||||
memcpy(tsec_paged, (void *)tsec_ctxt->fw, tsec_ctxt->size);
|
memcpy(tsec_paged, (void *)tsec_ctxt->fw, tsec_ctxt->size);
|
||||||
tsec_ctxt->fw = tsec_paged;
|
tsec_ctxt->fw = tsec_paged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get TSEC key.
|
||||||
|
if (kb <= KB_FIRMWARE_VERSION_620)
|
||||||
|
{
|
||||||
while (tsec_query(tmp, kb, tsec_ctxt) < 0)
|
while (tsec_query(tmp, kb, tsec_ctxt) < 0)
|
||||||
{
|
{
|
||||||
memset(tmp, 0x00, 0x20);
|
memset(tmp, 0x00, 0x20);
|
||||||
@@ -187,23 +220,46 @@ int keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt)
|
|||||||
// We rely on racing conditions, make sure we cover even the unluckiest cases.
|
// We rely on racing conditions, make sure we cover even the unluckiest cases.
|
||||||
if (retries > 15)
|
if (retries > 15)
|
||||||
{
|
{
|
||||||
gfx_printf(&gfx_con, "%k\nFailed to get TSEC keys. Please try again.%k\n\n", 0xFFFF0000, 0xFFCCCCCC);
|
_hos_crit_error("\nFailed to get TSEC keys. Please try again.");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (kb >= KB_FIRMWARE_VERSION_620)
|
if (kb >= KB_FIRMWARE_VERSION_700)
|
||||||
|
se_aes_unwrap_key(8, 12, package2_keyseed);
|
||||||
|
else if (kb == KB_FIRMWARE_VERSION_620)
|
||||||
{
|
{
|
||||||
// Set TSEC key.
|
// Set TSEC key.
|
||||||
se_aes_key_set(12, tmp, 0x10);
|
se_aes_key_set(12, tmp, 0x10);
|
||||||
// Set TSEC root key.
|
// Set TSEC root key.
|
||||||
se_aes_key_set(13, tmp + 0x10, 0x10);
|
se_aes_key_set(13, tmp + 0x10, 0x10);
|
||||||
|
|
||||||
|
if (!(emu_cfg.enabled && !h_cfg.emummc_force_disable) && hos_ctxt->stock)
|
||||||
|
{
|
||||||
// Package2 key.
|
// Package2 key.
|
||||||
se_aes_key_set(8, tmp + 0x10, 0x10);
|
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_620);
|
||||||
se_aes_unwrap_key(8, 8, master_keyseed_retail);
|
se_aes_unwrap_key(8, 8, master_keyseed_retail);
|
||||||
se_aes_unwrap_key(8, 8, key8_keyseed);
|
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
|
else
|
||||||
{
|
{
|
||||||
@@ -264,7 +320,7 @@ int keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt)
|
|||||||
|
|
||||||
// Package2 key.
|
// Package2 key.
|
||||||
se_key_acc_ctrl(8, 0x15);
|
se_key_acc_ctrl(8, 0x15);
|
||||||
se_aes_unwrap_key(8, 12, key8_keyseed);
|
se_aes_unwrap_key(8, 12, package2_keyseed);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@@ -276,23 +332,23 @@ static int _read_emmc_pkg1(launch_ctxt_t *ctxt)
|
|||||||
sdmmc_storage_t storage;
|
sdmmc_storage_t storage;
|
||||||
sdmmc_t sdmmc;
|
sdmmc_t sdmmc;
|
||||||
|
|
||||||
sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4);
|
emummc_storage_init_mmc(&storage, &sdmmc);
|
||||||
|
|
||||||
// Read package1.
|
// Read package1.
|
||||||
ctxt->pkg1 = (void *)malloc(0x40000);
|
ctxt->pkg1 = (void *)malloc(0x40000);
|
||||||
sdmmc_storage_set_mmc_partition(&storage, 1);
|
emummc_storage_set_mmc_partition(&storage, 1);
|
||||||
sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, ctxt->pkg1);
|
emummc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, ctxt->pkg1);
|
||||||
ctxt->pkg1_id = pkg1_identify(ctxt->pkg1);
|
ctxt->pkg1_id = pkg1_identify(ctxt->pkg1);
|
||||||
if (!ctxt->pkg1_id)
|
if (!ctxt->pkg1_id)
|
||||||
{
|
{
|
||||||
gfx_printf(&gfx_con, "%kUnknown pkg1,\nVersion (= '%s').%k\n", 0xFFFF0000, (char *)ctxt->pkg1 + 0x10, 0xFFCCCCCC);
|
_hos_crit_error("Unknown pkg1 version.");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
gfx_printf(&gfx_con, "Identified pkg1 ('%s'),\nKeyblob version %d\n\n", (char *)(ctxt->pkg1 + 0x10), ctxt->pkg1_id->kb);
|
gfx_printf("Identified pkg1 and Keyblob %d\n\n", ctxt->pkg1_id->kb);
|
||||||
|
|
||||||
// Read the correct keyblob.
|
// Read the correct keyblob.
|
||||||
ctxt->keyblob = (u8 *)calloc(NX_EMMC_BLOCKSIZE, 1);
|
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;
|
res = 1;
|
||||||
|
|
||||||
@@ -307,9 +363,9 @@ static u8 *_read_emmc_pkg2(launch_ctxt_t *ctxt)
|
|||||||
sdmmc_storage_t storage;
|
sdmmc_storage_t storage;
|
||||||
sdmmc_t sdmmc;
|
sdmmc_t sdmmc;
|
||||||
|
|
||||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
|
if (!emummc_storage_init_mmc(&storage, &sdmmc))
|
||||||
return NULL;
|
return NULL;
|
||||||
sdmmc_storage_set_mmc_partition(&storage, 0);
|
emummc_storage_set_mmc_partition(&storage, 0);
|
||||||
|
|
||||||
// Parse eMMC GPT.
|
// Parse eMMC GPT.
|
||||||
LIST_INIT(gpt);
|
LIST_INIT(gpt);
|
||||||
@@ -360,41 +416,76 @@ static void _free_launch_components(launch_ctxt_t *ctxt)
|
|||||||
|
|
||||||
int hos_launch(ini_sec_t *cfg)
|
int hos_launch(ini_sec_t *cfg)
|
||||||
{
|
{
|
||||||
|
minerva_change_freq(FREQ_1600);
|
||||||
launch_ctxt_t ctxt;
|
launch_ctxt_t ctxt;
|
||||||
tsec_ctxt_t tsec_ctxt;
|
tsec_ctxt_t tsec_ctxt;
|
||||||
|
volatile secmon_mailbox_t *secmon_mb;
|
||||||
|
|
||||||
memset(&ctxt, 0, sizeof(launch_ctxt_t));
|
memset(&ctxt, 0, sizeof(launch_ctxt_t));
|
||||||
|
memset(&tsec_ctxt, 0, sizeof(tsec_ctxt_t));
|
||||||
list_init(&ctxt.kip1_list);
|
list_init(&ctxt.kip1_list);
|
||||||
|
|
||||||
|
ctxt.cfg = cfg;
|
||||||
|
|
||||||
if (!gfx_con.mute)
|
if (!gfx_con.mute)
|
||||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
gfx_clear_grey(0x1B);
|
||||||
gfx_con_setpos(&gfx_con, 0, 0);
|
gfx_con_setpos(0, 0);
|
||||||
|
|
||||||
// Try to parse config if present.
|
gfx_printf("Initializing...\n\n");
|
||||||
if (cfg && !_parse_boot_config(&ctxt, cfg))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
gfx_printf(&gfx_con, "Initializing...\n\n");
|
|
||||||
|
|
||||||
// Read package1 and the correct keyblob.
|
// Read package1 and the correct keyblob.
|
||||||
if (!_read_emmc_pkg1(&ctxt))
|
if (!_read_emmc_pkg1(&ctxt))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
gfx_printf(&gfx_con, "Loaded pkg1 and keyblob\n");
|
// 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("Loaded pkg1 & keyblob\n");
|
||||||
|
|
||||||
// Generate keys.
|
// Generate keys.
|
||||||
if (!h_cfg.se_keygen_done || ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_620)
|
if (!h_cfg.se_keygen_done)
|
||||||
{
|
{
|
||||||
tsec_ctxt.key_ver = 1;
|
|
||||||
tsec_ctxt.fw = (u8 *)ctxt.pkg1 + ctxt.pkg1_id->tsec_off;
|
tsec_ctxt.fw = (u8 *)ctxt.pkg1 + ctxt.pkg1_id->tsec_off;
|
||||||
tsec_ctxt.pkg1 = ctxt.pkg1;
|
tsec_ctxt.pkg1 = ctxt.pkg1;
|
||||||
tsec_ctxt.pkg11_off = ctxt.pkg1_id->pkg11_off;
|
tsec_ctxt.pkg11_off = ctxt.pkg1_id->pkg11_off;
|
||||||
tsec_ctxt.secmon_base = ctxt.pkg1_id->secmon_base;
|
tsec_ctxt.secmon_base = ctxt.pkg1_id->secmon_base;
|
||||||
|
|
||||||
if (!keygen(ctxt.keyblob, ctxt.pkg1_id->kb, &tsec_ctxt))
|
if (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_700 && !h_cfg.sept_run)
|
||||||
|
{
|
||||||
|
_hos_crit_error("Failed to run sept");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!keygen(ctxt.keyblob, ctxt.pkg1_id->kb, &tsec_ctxt, &ctxt))
|
||||||
return 0;
|
return 0;
|
||||||
DPRINTF("Generated keys\n");
|
DPRINTF("Generated keys\n");
|
||||||
|
if (ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_600)
|
||||||
h_cfg.se_keygen_done = 1;
|
h_cfg.se_keygen_done = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -404,9 +495,16 @@ int hos_launch(ini_sec_t *cfg)
|
|||||||
if (ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_600)
|
if (ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_600)
|
||||||
pkg1_decrypt(ctxt.pkg1_id, ctxt.pkg1);
|
pkg1_decrypt(ctxt.pkg1_id, ctxt.pkg1);
|
||||||
|
|
||||||
|
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);
|
pkg1_unpack((void *)ctxt.pkg1_id->warmboot_base, (void *)ctxt.pkg1_id->secmon_base, NULL, ctxt.pkg1_id, ctxt.pkg1);
|
||||||
|
gfx_printf("Decrypted & unpacked pkg1\n");
|
||||||
gfx_printf(&gfx_con, "Decrypted and unpacked pkg1\n");
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_hos_crit_error("No mandatory secmon or warmboot provided!");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replace 'warmboot.bin' if requested.
|
// Replace 'warmboot.bin' if requested.
|
||||||
@@ -414,9 +512,14 @@ int hos_launch(ini_sec_t *cfg)
|
|||||||
memcpy((void *)ctxt.pkg1_id->warmboot_base, ctxt.warmboot, ctxt.warmboot_size);
|
memcpy((void *)ctxt.pkg1_id->warmboot_base, ctxt.warmboot, ctxt.warmboot_size);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_700)
|
||||||
|
{
|
||||||
|
_hos_crit_error("No warmboot provided!");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
// Else we patch it to allow downgrading.
|
// Else we patch it to allow downgrading.
|
||||||
patch_t *warmboot_patchset = ctxt.pkg1_id->warmboot_patchset;
|
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++)
|
for (u32 i = 0; warmboot_patchset[i].off != 0xFFFFFFFF; i++)
|
||||||
*(vu32 *)(ctxt.pkg1_id->warmboot_base + warmboot_patchset[i].off) = warmboot_patchset[i].val;
|
*(vu32 *)(ctxt.pkg1_id->warmboot_base + warmboot_patchset[i].off) = warmboot_patchset[i].val;
|
||||||
}
|
}
|
||||||
@@ -427,36 +530,36 @@ int hos_launch(ini_sec_t *cfg)
|
|||||||
// Replace 'SecureMonitor' if requested.
|
// Replace 'SecureMonitor' if requested.
|
||||||
if (ctxt.secmon)
|
if (ctxt.secmon)
|
||||||
memcpy((void *)ctxt.pkg1_id->secmon_base, ctxt.secmon, ctxt.secmon_size);
|
memcpy((void *)ctxt.pkg1_id->secmon_base, ctxt.secmon, ctxt.secmon_size);
|
||||||
else
|
else if (ctxt.pkg1_id->secmon_patchset)
|
||||||
{
|
{
|
||||||
// Else we patch it to allow for an unsigned package2 and patched kernel.
|
// Else we patch it to allow for an unsigned package2 and patched kernel.
|
||||||
patch_t *secmon_patchset = ctxt.pkg1_id->secmon_patchset;
|
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++)
|
for (u32 i = 0; secmon_patchset[i].off != 0xFFFFFFFF; i++)
|
||||||
*(vu32 *)(ctxt.pkg1_id->secmon_base + secmon_patchset[i].off) = secmon_patchset[i].val;
|
*(vu32 *)(ctxt.pkg1_id->secmon_base + secmon_patchset[i].off) = secmon_patchset[i].val;
|
||||||
}
|
}
|
||||||
|
|
||||||
gfx_printf(&gfx_con, "Loaded warmboot.bin and secmon\n");
|
gfx_printf("Loaded warmboot and secmon\n");
|
||||||
|
|
||||||
// Read package2.
|
// Read package2.
|
||||||
u8 *bootConfigBuf = _read_emmc_pkg2(&ctxt);
|
u8 *bootConfigBuf = _read_emmc_pkg2(&ctxt);
|
||||||
if (!bootConfigBuf)
|
if (!bootConfigBuf)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
gfx_printf(&gfx_con, "Read pkg2\n");
|
gfx_printf("Read pkg2\n");
|
||||||
|
|
||||||
// Decrypt package2 and parse KIP1 blobs in INI1 section.
|
// 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)
|
if (!pkg2_hdr)
|
||||||
{
|
{
|
||||||
gfx_printf(&gfx_con, "Pkg2 decryption failed!\n");
|
_hos_crit_error("Pkg2 decryption failed!");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
LIST_INIT(kip1_info);
|
LIST_INIT(kip1_info);
|
||||||
pkg2_parse_kips(&kip1_info, pkg2_hdr);
|
pkg2_parse_kips(&kip1_info, pkg2_hdr, &ctxt.new_pkg2);
|
||||||
|
|
||||||
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.
|
// Use the kernel included in package2 in case we didn't load one already.
|
||||||
if (!ctxt.kernel)
|
if (!ctxt.kernel)
|
||||||
@@ -464,16 +567,28 @@ int hos_launch(ini_sec_t *cfg)
|
|||||||
ctxt.kernel = pkg2_hdr->data;
|
ctxt.kernel = pkg2_hdr->data;
|
||||||
ctxt.kernel_size = pkg2_hdr->sec_size[PKG2_SEC_KERNEL];
|
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);
|
u8 kernel_hash[0x20];
|
||||||
ctxt.pkg2_kernel_id = pkg2_identify(kernel_crc32);
|
// 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.
|
// 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;
|
kernel_patch_t *kernel_patchset = ctxt.pkg2_kernel_id->kernel_patchset;
|
||||||
if (kernel_patchset != NULL)
|
if (kernel_patchset != NULL)
|
||||||
{
|
{
|
||||||
gfx_printf(&gfx_con, "%kPatching kernel%k\n", 0xFFFFBA00, 0xFFCCCCCC);
|
gfx_printf("%kPatching kernel%k\n", 0xFFFFBA00, 0xFFCCCCCC);
|
||||||
u32 *temp;
|
u32 *temp;
|
||||||
for (u32 i = 0; kernel_patchset[i].id != 0xFFFFFFFF; i++)
|
for (u32 i = 0; kernel_patchset[i].id != 0xFFFFFFFF; i++)
|
||||||
{
|
{
|
||||||
@@ -495,7 +610,7 @@ int hos_launch(ini_sec_t *cfg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Merge extra KIP1s into loaded ones.
|
// Merge extra KIP1s into loaded ones.
|
||||||
gfx_printf(&gfx_con, "%kPatching kernel initial processes%k\n", 0xFFFFBA00, 0xFFCCCCCC);
|
gfx_printf("%kPatching kips%k\n", 0xFFFFBA00, 0xFFCCCCCC);
|
||||||
LIST_FOREACH_ENTRY(merge_kip_t, mki, &ctxt.kip1_list, link)
|
LIST_FOREACH_ENTRY(merge_kip_t, mki, &ctxt.kip1_list, link)
|
||||||
pkg2_merge_kip(&kip1_info, (pkg2_kip1_t *)mki->kip1);
|
pkg2_merge_kip(&kip1_info, (pkg2_kip1_t *)mki->kip1);
|
||||||
|
|
||||||
@@ -503,7 +618,7 @@ int hos_launch(ini_sec_t *cfg)
|
|||||||
const char* unappliedPatch = pkg2_patch_kips(&kip1_info, ctxt.kip1_patches);
|
const char* unappliedPatch = pkg2_patch_kips(&kip1_info, ctxt.kip1_patches);
|
||||||
if (unappliedPatch != NULL)
|
if (unappliedPatch != NULL)
|
||||||
{
|
{
|
||||||
gfx_printf(&gfx_con, "%kREQUESTED PATCH '%s' NOT APPLIED!%k\n", 0xFFFF0000, unappliedPatch, 0xFFCCCCCC);
|
EHPRINTFARGS("Failed to apply '%s'!", unappliedPatch);
|
||||||
sd_unmount(); // Just exiting is not enough until pkg2_patch_kips stops modifying the string passed into it.
|
sd_unmount(); // Just exiting is not enough until pkg2_patch_kips stops modifying the string passed into it.
|
||||||
|
|
||||||
_free_launch_components(&ctxt);
|
_free_launch_components(&ctxt);
|
||||||
@@ -511,14 +626,14 @@ int hos_launch(ini_sec_t *cfg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Rebuild and encrypt package2.
|
// Rebuild and encrypt package2.
|
||||||
pkg2_build_encrypt((void *)0xA9800000, 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 and loaded pkg2\n");
|
gfx_printf("Rebuilt & loaded pkg2\n");
|
||||||
|
|
||||||
// Unmount SD card.
|
// Unmount SD card.
|
||||||
sd_unmount();
|
sd_unmount();
|
||||||
|
|
||||||
gfx_printf(&gfx_con, "\n%kBooting...%k\n", 0xFF96FF00, 0xFFCCCCCC);
|
gfx_printf("\n%kBooting...%k\n", 0xFF96FF00, 0xFFCCCCCC);
|
||||||
|
|
||||||
// Clear pkg1/pkg2 keys.
|
// Clear pkg1/pkg2 keys.
|
||||||
se_aes_key_clear(8);
|
se_aes_key_clear(8);
|
||||||
@@ -547,7 +662,7 @@ int hos_launch(ini_sec_t *cfg)
|
|||||||
case KB_FIRMWARE_VERSION_600:
|
case KB_FIRMWARE_VERSION_600:
|
||||||
se_key_acc_ctrl(12, 0xFF);
|
se_key_acc_ctrl(12, 0xFF);
|
||||||
se_key_acc_ctrl(15, 0xFF);
|
se_key_acc_ctrl(15, 0xFF);
|
||||||
case KB_FIRMWARE_VERSION_620:
|
default:
|
||||||
bootStateDramPkg2 = 2;
|
bootStateDramPkg2 = 2;
|
||||||
bootStatePkg2Continue = 4;
|
bootStatePkg2Continue = 4;
|
||||||
break;
|
break;
|
||||||
@@ -570,7 +685,7 @@ int hos_launch(ini_sec_t *cfg)
|
|||||||
|
|
||||||
// Config Exosphère if booting full Atmosphère.
|
// Config Exosphère if booting full Atmosphère.
|
||||||
if (ctxt.atmosphere && ctxt.secmon)
|
if (ctxt.atmosphere && ctxt.secmon)
|
||||||
config_exosphere(ctxt.pkg1_id->id, ctxt.pkg1_id->kb, ctxt.debugmode);
|
config_exosphere(&ctxt);
|
||||||
|
|
||||||
// Finalize MC carveout.
|
// Finalize MC carveout.
|
||||||
if (ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_301)
|
if (ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_301)
|
||||||
@@ -583,40 +698,50 @@ int hos_launch(ini_sec_t *cfg)
|
|||||||
if (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_620)
|
if (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_620)
|
||||||
_sysctr0_reset();
|
_sysctr0_reset();
|
||||||
|
|
||||||
// Free allocated memory.
|
|
||||||
ini_free_section(cfg);
|
|
||||||
_free_launch_components(&ctxt);
|
|
||||||
|
|
||||||
// < 4.0.0 pkg1.1 locks PMC scratches.
|
// < 4.0.0 pkg1.1 locks PMC scratches.
|
||||||
//_pmc_scratch_lock(ctxt.pkg1_id->kb);
|
//_pmc_scratch_lock(ctxt.pkg1_id->kb);
|
||||||
|
|
||||||
// < 4.0.0 Signals - 0: Not ready, 1: BCT ready, 2: DRAM and pkg2 ready, 3: Continue boot.
|
// Set secmon mailbox address.
|
||||||
// >= 4.0.0 Signals - 0: Not ready, 1: BCT ready, 2: DRAM ready, 4: pkg2 ready and continue boot.
|
if (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_700)
|
||||||
vu32 *mb_in = (vu32 *)0x40002EF8;
|
secmon_mb = (secmon_mailbox_t *)SECMON7_MB_ADDR;
|
||||||
// Non-zero: Secmon ready.
|
else
|
||||||
vu32 *mb_out = (vu32 *)0x40002EFC;
|
secmon_mb = (secmon_mailbox_t *)SECMON_MB_ADDR;
|
||||||
|
|
||||||
// Start from DRAM ready signal.
|
// Start from DRAM ready signal and reset outgoing value.
|
||||||
*mb_in = bootStateDramPkg2;
|
secmon_mb->in = bootStateDramPkg2;
|
||||||
*mb_out = 0;
|
secmon_mb->out = 0;
|
||||||
|
|
||||||
|
// Free allocated memory.
|
||||||
|
_free_launch_components(&ctxt);
|
||||||
|
|
||||||
// Disable display. This must be executed before secmon to provide support for all fw versions.
|
// Disable display. This must be executed before secmon to provide support for all fw versions.
|
||||||
display_end();
|
display_end();
|
||||||
|
|
||||||
|
// 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_800);
|
||||||
|
|
||||||
|
// 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.
|
// Wait for secmon to get ready.
|
||||||
if (smmu_is_used())
|
if (smmu_is_used())
|
||||||
smmu_exit();
|
smmu_exit();
|
||||||
else
|
else
|
||||||
cluster_boot_cpu0(ctxt.pkg1_id->secmon_base);
|
cluster_boot_cpu0(ctxt.pkg1_id->secmon_base);
|
||||||
while (!*mb_out)
|
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.
|
// Signal pkg2 ready and continue boot.
|
||||||
*mb_in = bootStatePkg2Continue;
|
secmon_mb->in = bootStatePkg2Continue;
|
||||||
|
|
||||||
// Halt ourselves in waitevent state and resume if there's JTAG activity.
|
// Halt ourselves in waitevent state and resume if there's JTAG activity.
|
||||||
while (1)
|
while (true)
|
||||||
FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = 0x50000000;
|
bpmp_halt();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,10 @@
|
|||||||
#define KB_FIRMWARE_VERSION_500 4
|
#define KB_FIRMWARE_VERSION_500 4
|
||||||
#define KB_FIRMWARE_VERSION_600 5
|
#define KB_FIRMWARE_VERSION_600 5
|
||||||
#define KB_FIRMWARE_VERSION_620 6
|
#define KB_FIRMWARE_VERSION_620 6
|
||||||
#define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_620
|
#define KB_FIRMWARE_VERSION_700 7
|
||||||
|
#define KB_FIRMWARE_VERSION_810 8
|
||||||
|
#define KB_FIRMWARE_VERSION_900 9
|
||||||
|
#define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_900
|
||||||
|
|
||||||
#define HOS_PKG11_MAGIC 0x31314B50
|
#define HOS_PKG11_MAGIC 0x31314B50
|
||||||
|
|
||||||
@@ -50,6 +53,7 @@ typedef struct _launch_ctxt_t
|
|||||||
void *pkg2;
|
void *pkg2;
|
||||||
u32 pkg2_size;
|
u32 pkg2_size;
|
||||||
|
|
||||||
|
bool new_pkg2;
|
||||||
void *kernel;
|
void *kernel;
|
||||||
u32 kernel_size;
|
u32 kernel_size;
|
||||||
link_t kip1_list;
|
link_t kip1_list;
|
||||||
@@ -57,7 +61,12 @@ typedef struct _launch_ctxt_t
|
|||||||
|
|
||||||
bool svcperm;
|
bool svcperm;
|
||||||
bool debugmode;
|
bool debugmode;
|
||||||
|
bool stock;
|
||||||
bool atmosphere;
|
bool atmosphere;
|
||||||
|
bool exo_no_user_exceptions;
|
||||||
|
bool emuMMC;
|
||||||
|
|
||||||
|
ini_sec_t *cfg;
|
||||||
} launch_ctxt_t;
|
} launch_ctxt_t;
|
||||||
|
|
||||||
typedef struct _merge_kip_t
|
typedef struct _merge_kip_t
|
||||||
@@ -67,6 +76,6 @@ typedef struct _merge_kip_t
|
|||||||
} merge_kip_t;
|
} merge_kip_t;
|
||||||
|
|
||||||
int hos_launch(ini_sec_t *cfg);
|
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
|
#endif
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* 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
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -19,55 +19,48 @@
|
|||||||
|
|
||||||
#include "hos.h"
|
#include "hos.h"
|
||||||
#include "hos_config.h"
|
#include "hos_config.h"
|
||||||
|
#include "fss.h"
|
||||||
#include "../libs/fatfs/ff.h"
|
#include "../libs/fatfs/ff.h"
|
||||||
#include "../mem/heap.h"
|
#include "../mem/heap.h"
|
||||||
#include "../utils/dirlist.h"
|
#include "../utils/dirlist.h"
|
||||||
|
|
||||||
#include "../gfx/gfx.h"
|
#include "../gfx/gfx.h"
|
||||||
extern gfx_con_t gfx_con;
|
|
||||||
|
|
||||||
//#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__)
|
//#define DPRINTF(...) gfx_printf(__VA_ARGS__)
|
||||||
#define DPRINTF(...)
|
#define DPRINTF(...)
|
||||||
|
|
||||||
|
extern void *sd_file_read(const char *path, u32 *fsize);
|
||||||
|
|
||||||
static int _config_warmboot(launch_ctxt_t *ctxt, const char *value)
|
static int _config_warmboot(launch_ctxt_t *ctxt, const char *value)
|
||||||
{
|
{
|
||||||
FIL fp;
|
ctxt->warmboot = sd_file_read(value, &ctxt->warmboot_size);
|
||||||
if (f_open(&fp, value, FA_READ) != FR_OK)
|
if (!ctxt->warmboot)
|
||||||
return 0;
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _config_secmon(launch_ctxt_t *ctxt, const char *value)
|
static int _config_secmon(launch_ctxt_t *ctxt, const char *value)
|
||||||
{
|
{
|
||||||
FIL fp;
|
ctxt->secmon = sd_file_read(value, &ctxt->secmon_size);
|
||||||
if (f_open(&fp, value, FA_READ) != FR_OK)
|
if (!ctxt->secmon)
|
||||||
return 0;
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _config_kernel(launch_ctxt_t *ctxt, const char *value)
|
static int _config_kernel(launch_ctxt_t *ctxt, const char *value)
|
||||||
{
|
{
|
||||||
FIL fp;
|
ctxt->kernel = sd_file_read(value, &ctxt->kernel_size);
|
||||||
if (f_open(&fp, value, FA_READ) != FR_OK)
|
if (!ctxt->kernel)
|
||||||
return 0;
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _config_kip1(launch_ctxt_t *ctxt, const char *value)
|
static int _config_kip1(launch_ctxt_t *ctxt, const char *value)
|
||||||
{
|
{
|
||||||
FIL fp;
|
u32 size;
|
||||||
|
|
||||||
if (!memcmp(value + strlen(value) - 1, "*", 1))
|
if (!memcmp(value + strlen(value) - 1, "*", 1))
|
||||||
{
|
{
|
||||||
@@ -90,18 +83,18 @@ static int _config_kip1(launch_ctxt_t *ctxt, const char *value)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
memcpy(dir + dirlen, &filelist[i * 256], strlen(&filelist[i * 256]) + 1);
|
memcpy(dir + dirlen, &filelist[i * 256], strlen(&filelist[i * 256]) + 1);
|
||||||
if (f_open(&fp, dir, FA_READ))
|
|
||||||
|
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(dir);
|
||||||
free(filelist);
|
free(filelist);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
merge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t));
|
DPRINTF("Loaded kip1 from SD (size %08X)\n", size);
|
||||||
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);
|
|
||||||
list_append(&ctxt->kip1_list, &mkip1->link);
|
list_append(&ctxt->kip1_list, &mkip1->link);
|
||||||
|
|
||||||
i++;
|
i++;
|
||||||
@@ -113,50 +106,22 @@ static int _config_kip1(launch_ctxt_t *ctxt, const char *value)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (f_open(&fp, value, FA_READ))
|
|
||||||
return 0;
|
|
||||||
merge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t));
|
merge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t));
|
||||||
mkip1->kip1 = malloc(f_size(&fp));
|
mkip1->kip1 = sd_file_read(value, &size);
|
||||||
f_read(&fp, mkip1->kip1, f_size(&fp), NULL);
|
if (!mkip1->kip1)
|
||||||
DPRINTF("Loaded kip1 from SD (size %08X)\n", f_size(&fp));
|
{
|
||||||
f_close(&fp);
|
free(mkip1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
DPRINTF("Loaded kip1 from SD (size %08X)\n", size);
|
||||||
list_append(&ctxt->kip1_list, &mkip1->link);
|
list_append(&ctxt->kip1_list, &mkip1->link);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _config_svcperm(launch_ctxt_t *ctxt, const char *value)
|
int config_kip1patch(launch_ctxt_t *ctxt, const char *value)
|
||||||
{
|
|
||||||
if (*value == '1')
|
|
||||||
{
|
|
||||||
DPRINTF("Disabled SVC verification\n");
|
|
||||||
ctxt->svcperm = true;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _config_debugmode(launch_ctxt_t *ctxt, const char *value)
|
|
||||||
{
|
|
||||||
if (*value == '1')
|
|
||||||
{
|
|
||||||
DPRINTF("Enabled Debug mode\n");
|
|
||||||
ctxt->debugmode = true;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _config_atmosphere(launch_ctxt_t *ctxt, const char *value)
|
|
||||||
{
|
|
||||||
if (*value == '1')
|
|
||||||
{
|
|
||||||
DPRINTF("Enabled atmosphere patching\n");
|
|
||||||
ctxt->atmosphere = true;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _config_kip1patch(launch_ctxt_t *ctxt, const char *value)
|
|
||||||
{
|
{
|
||||||
if (value == NULL)
|
if (value == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -186,6 +151,61 @@ static int _config_kip1patch(launch_ctxt_t *ctxt, const char *value)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int _config_svcperm(launch_ctxt_t *ctxt, const char *value)
|
||||||
|
{
|
||||||
|
if (*value == '1')
|
||||||
|
{
|
||||||
|
DPRINTF("Disabled SVC verification\n");
|
||||||
|
ctxt->svcperm = true;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _config_debugmode(launch_ctxt_t *ctxt, const char *value)
|
||||||
|
{
|
||||||
|
if (*value == '1')
|
||||||
|
{
|
||||||
|
DPRINTF("Enabled Debug mode\n");
|
||||||
|
ctxt->debugmode = true;
|
||||||
|
}
|
||||||
|
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')
|
||||||
|
{
|
||||||
|
DPRINTF("Enabled atmosphere patching\n");
|
||||||
|
ctxt->atmosphere = true;
|
||||||
|
}
|
||||||
|
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_fss(launch_ctxt_t *ctxt, const char *value)
|
||||||
|
{
|
||||||
|
return parse_fss(ctxt, value);
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct _cfg_handler_t
|
typedef struct _cfg_handler_t
|
||||||
{
|
{
|
||||||
const char *key;
|
const char *key;
|
||||||
@@ -197,25 +217,30 @@ static const cfg_handler_t _config_handlers[] = {
|
|||||||
{ "secmon", _config_secmon },
|
{ "secmon", _config_secmon },
|
||||||
{ "kernel", _config_kernel },
|
{ "kernel", _config_kernel },
|
||||||
{ "kip1", _config_kip1 },
|
{ "kip1", _config_kip1 },
|
||||||
{ "kip1patch", _config_kip1patch },
|
{ "kip1patch", config_kip1patch },
|
||||||
{ "fullsvcperm", _config_svcperm },
|
{ "fullsvcperm", _config_svcperm },
|
||||||
{ "debugmode", _config_debugmode },
|
{ "debugmode", _config_debugmode },
|
||||||
|
{ "stock", _config_stock },
|
||||||
{ "atmosphere", _config_atmosphere },
|
{ "atmosphere", _config_atmosphere },
|
||||||
|
{ "nouserexceptions", _config_dis_exo_user_exceptions },
|
||||||
|
{ "fss0", _config_fss },
|
||||||
{ NULL, NULL },
|
{ 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++)
|
for(u32 i = 0; _config_handlers[i].key; i++)
|
||||||
{
|
{
|
||||||
if (!strcmp(_config_handlers[i].key, kv->key))
|
if (!strcmp(_config_handlers[i].key, kv->key))
|
||||||
if (!_config_handlers[i].handler(ctxt, kv->val))
|
if (!_config_handlers[i].handler(ctxt, kv->val))
|
||||||
|
{
|
||||||
|
EPRINTFARGS("Error while loading %s:\n%s", kv->key, kv->val);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,8 @@
|
|||||||
|
|
||||||
#include "hos.h"
|
#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
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
* Copyright (c) 2018 st4rk
|
* Copyright (c) 2018 st4rk
|
||||||
* Copyright (c) 2018 CTCaer
|
* Copyright (c) 2018-2019 CTCaer
|
||||||
* Copyright (c) 2018 balika011
|
* Copyright (c) 2018 balika011
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
@@ -20,8 +20,9 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "pkg1.h"
|
#include "pkg1.h"
|
||||||
#include "../utils/aarch64_util.h"
|
#include "../gfx/gfx.h"
|
||||||
#include "../sec/se.h"
|
#include "../sec/se.h"
|
||||||
|
#include "../utils/aarch64_util.h"
|
||||||
|
|
||||||
#define _NOPv7() 0xE320F000
|
#define _NOPv7() 0xE320F000
|
||||||
|
|
||||||
@@ -71,15 +72,15 @@ PATCHSET_DEF(_secmon_6_patchset,
|
|||||||
{ 0xDC8 + 0x820, _NOP() }, //package2 structure.
|
{ 0xDC8 + 0x820, _NOP() }, //package2 structure.
|
||||||
{ 0xDC8 + 0x82C, _NOP() }, //Version.
|
{ 0xDC8 + 0x82C, _NOP() }, //Version.
|
||||||
{ 0xDC8 + 0xE90, _NOP() }, //Header signature.
|
{ 0xDC8 + 0xE90, _NOP() }, //Header signature.
|
||||||
{ 0xDC8 + 0x112C, _NOP() }, //Sections SHA2.
|
{ 0xDC8 + 0x112C, _NOP() } //Sections SHA2.
|
||||||
// Fix sleep mode for debug.
|
// Fix sleep mode for debug.
|
||||||
{ 0x1A68 + 0x3854, 0x94000E45 }, //gpio_config_for_uart.
|
// { 0x1A68 + 0x3854, 0x94000E45 }, //gpio_config_for_uart.
|
||||||
{ 0x1A68 + 0x3858, 0x97FFFC0F }, //clkrst_reboot_uarta.
|
// { 0x1A68 + 0x3858, 0x97FFFC0F }, //clkrst_reboot_uarta.
|
||||||
{ 0x1A68 + 0x385C, 0x52A00021 }, //MOV W1, #0x10000 ; baudrate.
|
// { 0x1A68 + 0x385C, 0x52A00021 }, //MOV W1, #0x10000 ; baudrate.
|
||||||
{ 0x1A68 + 0x3860, 0x2A1F03E0 }, //MOV W0, WZR ; uart_port -> A.
|
// { 0x1A68 + 0x3860, 0x2A1F03E0 }, //MOV W0, WZR ; uart_port -> A.
|
||||||
{ 0x1A68 + 0x3864, 0x72984001 }, //MOVK W1, #0xC200 ; baudrate.
|
// { 0x1A68 + 0x3864, 0x72984001 }, //MOVK W1, #0xC200 ; baudrate.
|
||||||
{ 0x1A68 + 0x3868, 0x94000C8C }, //uart_configure.
|
// { 0x1A68 + 0x3868, 0x94000C8C }, //uart_configure.
|
||||||
{ 0x1A68 + 0x3A6C, _NOP() } // warmboot UARTA cfg.
|
// { 0x1A68 + 0x3A6C, _NOP() } // warmboot UARTA cfg.
|
||||||
);
|
);
|
||||||
|
|
||||||
PATCHSET_DEF(_secmon_620_patchset,
|
PATCHSET_DEF(_secmon_620_patchset,
|
||||||
@@ -87,15 +88,15 @@ PATCHSET_DEF(_secmon_620_patchset,
|
|||||||
{ 0xDC8 + 0x604, _NOP() }, //package2 structure.
|
{ 0xDC8 + 0x604, _NOP() }, //package2 structure.
|
||||||
{ 0xDC8 + 0x610, _NOP() }, //Version.
|
{ 0xDC8 + 0x610, _NOP() }, //Version.
|
||||||
{ 0xDC8 + 0xC74, _NOP() }, //Header signature.
|
{ 0xDC8 + 0xC74, _NOP() }, //Header signature.
|
||||||
{ 0xDC8 + 0xF10, _NOP() }, //Sections SHA2.
|
{ 0xDC8 + 0xF10, _NOP() } //Sections SHA2.
|
||||||
// Fix sleep mode for debug.
|
// Fix sleep mode for debug.
|
||||||
{ 0x2AC8 + 0x3854, 0x94000F42 }, //gpio_config_for_uart.
|
// { 0x2AC8 + 0x3854, 0x94000F42 }, //gpio_config_for_uart.
|
||||||
{ 0x2AC8 + 0x3858, 0x97FFFC0F }, //clkrst_reboot_uarta.
|
// { 0x2AC8 + 0x3858, 0x97FFFC0F }, //clkrst_reboot_uarta.
|
||||||
{ 0x2AC8 + 0x385C, 0x52A00021 }, //MOV W1, #0x10000 ; baudrate.
|
// { 0x2AC8 + 0x385C, 0x52A00021 }, //MOV W1, #0x10000 ; baudrate.
|
||||||
{ 0x2AC8 + 0x3860, 0x2A1F03E0 }, //MOV W0, WZR ; uart_port -> A.
|
// { 0x2AC8 + 0x3860, 0x2A1F03E0 }, //MOV W0, WZR ; uart_port -> A.
|
||||||
{ 0x2AC8 + 0x3864, 0x72984001 }, //MOVK W1, #0xC200 ; baudrate.
|
// { 0x2AC8 + 0x3864, 0x72984001 }, //MOVK W1, #0xC200 ; baudrate.
|
||||||
{ 0x2AC8 + 0x3868, 0x94000D89 }, //uart_configure.
|
// { 0x2AC8 + 0x3868, 0x94000D89 }, //uart_configure.
|
||||||
{ 0x2AC8 + 0x3A6C, _NOP() } // warmboot UARTA cfg.
|
// { 0x2AC8 + 0x3A6C, _NOP() } // warmboot UARTA cfg.
|
||||||
);
|
);
|
||||||
|
|
||||||
PATCHSET_DEF(_warmboot_1_patchset,
|
PATCHSET_DEF(_warmboot_1_patchset,
|
||||||
@@ -116,20 +117,6 @@ PATCHSET_DEF(_warmboot_4_patchset,
|
|||||||
{ 0x558, _NOPv7() } // Segment id check.
|
{ 0x558, _NOPv7() } // Segment id check.
|
||||||
);
|
);
|
||||||
|
|
||||||
PATCHSET_DEF(_warmboot_5_patchset,
|
|
||||||
{ 0x544, _NOPv7() }, // Fuse check.
|
|
||||||
{ 0x558, _NOPv7() } // Segment id check.
|
|
||||||
);
|
|
||||||
|
|
||||||
PATCHSET_DEF(_warmboot_6_patchset,
|
|
||||||
{ 0x544, _NOPv7() }, // Fuse check.
|
|
||||||
{ 0x558, _NOPv7() } // Segment id check.
|
|
||||||
);
|
|
||||||
|
|
||||||
PATCHSET_DEF(_warmboot_620_patchset,
|
|
||||||
{ 0x544, _NOPv7() }, // Fuse check.
|
|
||||||
{ 0x558, _NOPv7() } // Segment id check.
|
|
||||||
);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* package1.1 header: <wb, ldr, sm>
|
* package1.1 header: <wb, ldr, sm>
|
||||||
@@ -142,6 +129,7 @@ PATCHSET_DEF(_warmboot_620_patchset,
|
|||||||
* 5.0: {ldr, sm, wb} { 1, 2, 0 }
|
* 5.0: {ldr, sm, wb} { 1, 2, 0 }
|
||||||
* 6.0: {ldr, sm, wb} { 1, 2, 0 }
|
* 6.0: {ldr, sm, wb} { 1, 2, 0 }
|
||||||
* 6.2: {ldr, sm, wb} { 1, 2, 0 }
|
* 6.2: {ldr, sm, wb} { 1, 2, 0 }
|
||||||
|
* 7.0: {ldr, sm, wb} { 1, 2, 0 }
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static const pkg1_id_t _pkg1_ids[] = {
|
static const pkg1_id_t _pkg1_ids[] = {
|
||||||
@@ -150,15 +138,24 @@ static const pkg1_id_t _pkg1_ids[] = {
|
|||||||
{ "20170519101410", 1, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_3_patchset, _warmboot_3_patchset }, //3.0.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
|
{ "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
|
{ "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_5_patchset }, //5.0.0 - 5.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_6_patchset }, //6.0.0 - 6.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_620_patchset }, //6.2.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
|
||||||
{ NULL } //End.
|
{ NULL } //End.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const pkg1_id_t *pkg1_identify(u8 *pkg1)
|
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("Found pkg1 ('%s').\n\n", build_date);
|
||||||
|
|
||||||
for (u32 i = 0; _pkg1_ids[i].id; i++)
|
for (u32 i = 0; _pkg1_ids[i].id; i++)
|
||||||
if (!memcmp(pkg1 + 0x10, _pkg1_ids[i].id, 12))
|
if (!memcmp(pkg1 + 0x10, _pkg1_ids[i].id, 12))
|
||||||
return &_pkg1_ids[i];
|
return &_pkg1_ids[i];
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* 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
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -27,6 +27,12 @@
|
|||||||
#define PKG2_SEC_INI1 1
|
#define PKG2_SEC_INI1 1
|
||||||
|
|
||||||
#define INI1_MAGIC 0x31494E49
|
#define INI1_MAGIC 0x31494E49
|
||||||
|
#define PKG2_NEWKERN_GET_INI1 0x44
|
||||||
|
#define PKG2_NEWKERN_START 0x800
|
||||||
|
|
||||||
|
u32 pkg2_newkern_ini1_val;
|
||||||
|
u32 pkg2_newkern_ini1_start;
|
||||||
|
u32 pkg2_newkern_ini1_end;
|
||||||
|
|
||||||
typedef struct _kernel_patch_t
|
typedef struct _kernel_patch_t
|
||||||
{
|
{
|
||||||
@@ -111,40 +117,41 @@ typedef struct _pkg2_kip1_info_t
|
|||||||
|
|
||||||
typedef struct _pkg2_kernel_id_t
|
typedef struct _pkg2_kernel_id_t
|
||||||
{
|
{
|
||||||
u32 crc32c_id;
|
u8 hash[8];
|
||||||
kernel_patch_t *kernel_patchset;
|
kernel_patch_t *kernel_patchset;
|
||||||
} pkg2_kernel_id_t;
|
} pkg2_kernel_id_t;
|
||||||
|
|
||||||
typedef struct _kip1_patch_t
|
typedef struct _kip1_patch_t
|
||||||
{
|
{
|
||||||
u32 offset; //section+offset of patch to apply
|
u32 offset; // section+offset of patch to apply.
|
||||||
u32 length; //in bytes, 0 means last patch
|
u32 length; // In bytes, 0 means last patch.
|
||||||
const char* srcData; //that must match
|
char* srcData; // That must match.
|
||||||
const char* dstData; //that it gets replaced by
|
char* dstData; // That it gets replaced by.
|
||||||
} kip1_patch_t;
|
} kip1_patch_t;
|
||||||
|
|
||||||
typedef struct _kip1_patchset_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_patch_t* patches; // NULL means not necessary.
|
||||||
} kip1_patchset_t;
|
} kip1_patchset_t;
|
||||||
|
|
||||||
typedef struct _kip1_id_t
|
typedef struct _kip1_id_t
|
||||||
{
|
{
|
||||||
const char* name;
|
const char* name;
|
||||||
u8 hash[16];
|
u8 hash[8];
|
||||||
kip1_patchset_t* patchset;
|
kip1_patchset_t* patchset;
|
||||||
} kip1_id_t;
|
} kip1_id_t;
|
||||||
|
|
||||||
void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2);
|
void pkg2_get_newkern_info(u8 *kern_data);
|
||||||
|
void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2);
|
||||||
int pkg2_has_kip(link_t *info, u64 tid);
|
int pkg2_has_kip(link_t *info, u64 tid);
|
||||||
void pkg2_replace_kip(link_t *info, u64 tid, pkg2_kip1_t *kip1);
|
void pkg2_replace_kip(link_t *info, u64 tid, pkg2_kip1_t *kip1);
|
||||||
void pkg2_add_kip(link_t *info, 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);
|
void pkg2_merge_kip(link_t *info, pkg2_kip1_t *kip1);
|
||||||
const char* pkg2_patch_kips(link_t *info, char* patchNames);
|
const char* pkg2_patch_kips(link_t *info, char* patchNames);
|
||||||
|
|
||||||
const pkg2_kernel_id_t *pkg2_identify(u32 id);
|
const pkg2_kernel_id_t *pkg2_identify(u8 *hash);
|
||||||
pkg2_hdr_t *pkg2_decrypt(void *data);
|
pkg2_hdr_t *pkg2_decrypt(void *data, u8 kb);
|
||||||
void pkg2_build_encrypt(void *dst, void *kernel, u32 kernel_size, link_t *kips_info);
|
void pkg2_build_encrypt(void *dst, void *kernel, u32 kernel_size, link_t *kips_info, bool new_pkg2);
|
||||||
|
|
||||||
#endif
|
#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 CTCaer
|
* Copyright (c) 2018-2019 CTCaer
|
||||||
|
* Copyright (c) 2019 Atmosphère-NX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -15,32 +16,140 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "hos.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"
|
#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
|
||||||
|
{
|
||||||
|
u32 magic;
|
||||||
|
u32 fwno;
|
||||||
|
u32 flags;
|
||||||
|
u32 reserved[5];
|
||||||
|
exo_emummc_config_t emummc_cfg;
|
||||||
|
} exo_cfg_t;
|
||||||
|
|
||||||
|
typedef struct _atm_meta_t
|
||||||
|
{
|
||||||
|
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];
|
||||||
|
} atm_fatal_error_ctx;
|
||||||
|
|
||||||
|
#define ATM_FATAL_ERR_CTX_ADDR 0x4003E000
|
||||||
|
#define ATM_FATAL_MAGIC 0x31454641 // AFE1
|
||||||
|
|
||||||
|
#define ATM_WB_HEADER_OFF 0x244
|
||||||
|
#define ATM_WB_MAGIC 0x30544257
|
||||||
|
|
||||||
// Exosphère mailbox defines.
|
// Exosphère mailbox defines.
|
||||||
#define EXO_MAGIC_ADDR 0x40002E40
|
#define EXO_CFG_ADDR 0x8000F000
|
||||||
#define EXO_MAGIC_VAL 0x31434258
|
#define EXO_MAGIC_VAL 0x304F5845
|
||||||
#define EXO_FWNO_ADDR 0x40002E44
|
|
||||||
#define EXO_FLAGS_ADDR 0x40002E48
|
|
||||||
#define EXO_FLAG_620_KGN (1 << 0)
|
|
||||||
#define EXO_FLAG_DBG_PRIV (1 << 1)
|
#define EXO_FLAG_DBG_PRIV (1 << 1)
|
||||||
#define EXO_FLAG_DBG_USER (1 << 2)
|
#define EXO_FLAG_DBG_USER (1 << 2)
|
||||||
|
#define EXO_FLAG_NO_USER_EXC (1 << 3)
|
||||||
|
|
||||||
void config_exosphere(const char *id, u32 kb, bool debug)
|
void config_exosphere(launch_ctxt_t *ctxt)
|
||||||
{
|
{
|
||||||
u32 exoFwNo = 0;
|
u32 exoFwNo = 0;
|
||||||
u32 exoFlags = 0;
|
u32 exoFlags = 0;
|
||||||
|
u32 kb = ctxt->pkg1_id->kb;
|
||||||
|
|
||||||
vu32 *mb_exo_magic = (vu32 *)EXO_MAGIC_ADDR;
|
memset((exo_cfg_t *)EXO_CFG_ADDR, 0, sizeof(exo_cfg_t));
|
||||||
vu32 *mb_exo_fw_no = (vu32 *)EXO_FWNO_ADDR;
|
|
||||||
vu32 *mb_exo_flags = (vu32 *)EXO_FLAGS_ADDR;
|
volatile exo_cfg_t *exo_cfg = (exo_cfg_t *)EXO_CFG_ADDR;
|
||||||
|
|
||||||
switch (kb)
|
switch (kb)
|
||||||
{
|
{
|
||||||
case KB_FIRMWARE_VERSION_100_200:
|
case KB_FIRMWARE_VERSION_100_200:
|
||||||
if (!strcmp(id, "20161121183008"))
|
if (!strcmp(ctxt->pkg1_id->id, "20161121183008"))
|
||||||
exoFwNo = 1;
|
exoFwNo = 1;
|
||||||
else
|
else
|
||||||
exoFwNo = 2;
|
exoFwNo = 2;
|
||||||
@@ -50,17 +159,142 @@ void config_exosphere(const char *id, u32 kb, bool debug)
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
exoFwNo = kb + 1;
|
exoFwNo = kb + 1;
|
||||||
|
if (!strcmp(ctxt->pkg1_id->id, "20190314172056") || (kb >= KB_FIRMWARE_VERSION_810))
|
||||||
|
exoFwNo++; // ATM_TARGET_FW_800/810/900.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kb >= KB_FIRMWARE_VERSION_620)
|
// To avoid problems, make private debug mode always on if not semi-stock.
|
||||||
exoFlags |= EXO_FLAG_620_KGN;
|
if (!ctxt->stock || (emu_cfg.enabled && !h_cfg.emummc_force_disable))
|
||||||
|
|
||||||
if (debug)
|
|
||||||
exoFlags |= EXO_FLAG_DBG_PRIV;
|
exoFlags |= EXO_FLAG_DBG_PRIV;
|
||||||
|
|
||||||
|
// Disable proper failure handling.
|
||||||
|
if (ctxt->exo_no_user_exceptions)
|
||||||
|
exoFlags |= EXO_FLAG_NO_USER_EXC;
|
||||||
|
|
||||||
// Set mailbox values.
|
// Set mailbox values.
|
||||||
*mb_exo_magic = EXO_MAGIC_VAL;
|
exo_cfg->magic = EXO_MAGIC_VAL;
|
||||||
*mb_exo_fw_no = exoFwNo;
|
|
||||||
*mb_exo_flags = exoFlags;
|
exo_cfg->fwno = exoFwNo;
|
||||||
|
|
||||||
|
exo_cfg->flags = exoFlags;
|
||||||
|
|
||||||
|
// If warmboot is lp0fw, add in RSA modulus.
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
wb_cfg->fwno = exoFwNo;
|
||||||
|
|
||||||
|
sdmmc_storage_t storage;
|
||||||
|
sdmmc_t sdmmc;
|
||||||
|
|
||||||
|
// Set warmboot binary rsa modulus.
|
||||||
|
u8 *rsa_mod = (u8 *)malloc(512);
|
||||||
|
|
||||||
|
sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4);
|
||||||
|
sdmmc_storage_set_mmc_partition(&storage, 1);
|
||||||
|
sdmmc_storage_read(&storage, 1, 1, rsa_mod);
|
||||||
|
sdmmc_storage_end(&storage);
|
||||||
|
|
||||||
|
// Patch AutoRCM out.
|
||||||
|
if ((fuse_read_odm(4) & 3) != 3)
|
||||||
|
rsa_mod[0x10] = 0xF7;
|
||||||
|
else
|
||||||
|
rsa_mod[0x10] = 0x37;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
if (rpt->magic != 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);
|
||||||
|
|
||||||
|
if (sd_mount())
|
||||||
|
{
|
||||||
|
// Save context to the SD card.
|
||||||
|
char filepath[0x40];
|
||||||
|
f_mkdir("atmosphere/fatal_errors");
|
||||||
|
memcpy(filepath, "/atmosphere/fatal_errors/report_", 33);
|
||||||
|
itoa((u32)((u64)rpt->report_identifier >> 32), filepath + strlen(filepath), 16);
|
||||||
|
itoa((u32)(rpt->report_identifier), filepath + strlen(filepath), 16);
|
||||||
|
memcpy(filepath + strlen(filepath), ".bin", 5);
|
||||||
|
|
||||||
|
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 CTCaer
|
* Copyright (C) 2018-2019 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include "../utils/types.h"
|
#include "../utils/types.h"
|
||||||
|
|
||||||
void config_exosphere(const char *id, u32 kb, bool debug);
|
void config_exosphere(launch_ctxt_t *ctxt);
|
||||||
|
void secmon_exo_check_panic();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
227
bootloader/hos/sept.c
Normal file
227
bootloader/hos/sept.c
Normal file
@@ -0,0 +1,227 @@
|
|||||||
|
/*
|
||||||
|
* 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 "hos.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"
|
||||||
|
#include "../utils/types.h"
|
||||||
|
|
||||||
|
#include "../gfx/gfx.h"
|
||||||
|
|
||||||
|
#define RELOC_META_OFF 0x7C
|
||||||
|
#define PATCHED_RELOC_SZ 0x94
|
||||||
|
|
||||||
|
#define WB_RST_ADDR 0x40010ED0
|
||||||
|
#define WB_RST_SIZE 0x30
|
||||||
|
|
||||||
|
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
|
||||||
|
0x10, 0x10, 0xB0, 0xE3, // MOVS R1, #0x10
|
||||||
|
0x00, 0x10, 0x80, 0xE5, // STR R1, [R0]
|
||||||
|
0xFE, 0xFF, 0xFF, 0xEA, // LOOP
|
||||||
|
0x50, 0xE4, 0x00, 0x70, // #0x7000E450
|
||||||
|
0x00, 0xE4, 0x00, 0x70 // #0x7000E400
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SEPT_PRI_ADDR 0x4003F000
|
||||||
|
|
||||||
|
#define SEPT_PK1T_ADDR 0xC0400000
|
||||||
|
#define SEPT_TCSZ_ADDR (SEPT_PK1T_ADDR - 0x4)
|
||||||
|
#define SEPT_STG1_ADDR (SEPT_PK1T_ADDR + 0x2E100)
|
||||||
|
#define SEPT_STG2_ADDR (SEPT_PK1T_ADDR + 0x60E0)
|
||||||
|
#define SEPT_PKG_SZ (0x2F100 + WB_RST_SIZE)
|
||||||
|
|
||||||
|
extern boot_cfg_t b_cfg;
|
||||||
|
extern hekate_config h_cfg;
|
||||||
|
extern const volatile ipl_ver_meta_t ipl_ver;
|
||||||
|
|
||||||
|
extern void *sd_file_read(char *path);
|
||||||
|
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);
|
||||||
|
|
||||||
|
extern sdmmc_t sd_sdmmc;
|
||||||
|
extern sdmmc_storage_t sd_storage;
|
||||||
|
|
||||||
|
void check_sept()
|
||||||
|
{
|
||||||
|
// Check if non-hekate payload is used for sept and restore it.
|
||||||
|
if (h_cfg.sept_run)
|
||||||
|
{
|
||||||
|
if (!f_stat("sept/payload.bak", NULL))
|
||||||
|
{
|
||||||
|
f_unlink("sept/payload.bin");
|
||||||
|
f_rename("sept/payload.bak", "sept/payload.bin");
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 *pkg1 = (u8 *)calloc(1, 0x40000);
|
||||||
|
|
||||||
|
sdmmc_storage_t storage;
|
||||||
|
sdmmc_t sdmmc;
|
||||||
|
if (!emummc_storage_init_mmc(&storage, &sdmmc))
|
||||||
|
{
|
||||||
|
EPRINTF("Failed to init eMMC.");
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
emummc_storage_set_mmc_partition(&storage, 1);
|
||||||
|
|
||||||
|
// Read package1.
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
gfx_con.fntsz = 16;
|
||||||
|
EPRINTF("Unknown pkg1 version.");
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pkg1_id->kb >= KB_FIRMWARE_VERSION_700 && !h_cfg.sept_run)
|
||||||
|
{
|
||||||
|
sdmmc_storage_end(&storage);
|
||||||
|
reboot_to_sept((u8 *)pkg1 + pkg1_id->tsec_off, pkg1_id->kb);
|
||||||
|
}
|
||||||
|
|
||||||
|
out_free:
|
||||||
|
free(pkg1);
|
||||||
|
sdmmc_storage_end(&storage);
|
||||||
|
}
|
||||||
|
|
||||||
|
int reboot_to_sept(const u8 *tsec_fw, u32 kb)
|
||||||
|
{
|
||||||
|
FIL fp;
|
||||||
|
|
||||||
|
// 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, tsec_fw_size);
|
||||||
|
*(vu32 *)SEPT_TCSZ_ADDR = tsec_fw_size;
|
||||||
|
|
||||||
|
// Copy sept-primary.
|
||||||
|
if (f_open(&fp, "sept/sept-primary.bin", FA_READ))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (f_read(&fp, (u8 *)SEPT_STG1_ADDR, f_size(&fp), NULL))
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
|
b_cfg.boot_cfg |= (BOOT_CFG_AUTOBOOT_EN | BOOT_CFG_SEPT_RUN);
|
||||||
|
|
||||||
|
bool update_sept_payload = true;
|
||||||
|
if (!f_open(&fp, "sept/payload.bin", FA_READ | FA_WRITE))
|
||||||
|
{
|
||||||
|
ipl_ver_meta_t tmp_ver;
|
||||||
|
f_lseek(&fp, PATCHED_RELOC_SZ + sizeof(boot_cfg_t));
|
||||||
|
f_read(&fp, &tmp_ver, sizeof(ipl_ver_meta_t), NULL);
|
||||||
|
|
||||||
|
if (tmp_ver.magic == ipl_ver.magic)
|
||||||
|
{
|
||||||
|
if (tmp_ver.version == ipl_ver.version)
|
||||||
|
{
|
||||||
|
// Save auto boot config to sept payload, if any.
|
||||||
|
boot_cfg_t *tmp_cfg = malloc(sizeof(boot_cfg_t));
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
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_open(&fp, "sept/payload.bin", FA_WRITE | FA_CREATE_ALWAYS);
|
||||||
|
f_write(&fp, (u8 *)reloc->start, reloc->end - reloc->start, NULL);
|
||||||
|
f_close(&fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
sd_unmount();
|
||||||
|
|
||||||
|
u32 pk1t_sept = SEPT_PK1T_ADDR - (ALIGN(PATCHED_RELOC_SZ, 0x10) + WB_RST_SIZE);
|
||||||
|
|
||||||
|
void (*sept)() = (void *)pk1t_sept;
|
||||||
|
|
||||||
|
reloc_patcher(WB_RST_ADDR, pk1t_sept, SEPT_PKG_SZ);
|
||||||
|
|
||||||
|
// Patch SDRAM init to perform an SVC immediately after second write.
|
||||||
|
PMC(APBDEV_PMC_SCRATCH45) = 0x2E38DFFF;
|
||||||
|
PMC(APBDEV_PMC_SCRATCH46) = 0x6001DC28;
|
||||||
|
// Set SVC handler to jump to sept-primary in IRAM.
|
||||||
|
PMC(APBDEV_PMC_SCRATCH33) = SEPT_PRI_ADDR;
|
||||||
|
PMC(APBDEV_PMC_SCRATCH40) = 0x6000F208;
|
||||||
|
|
||||||
|
reconfig_hw_workaround(false, 0);
|
||||||
|
|
||||||
|
(*sept)();
|
||||||
|
|
||||||
|
error:
|
||||||
|
gfx_con.mute = false;
|
||||||
|
EPRINTF("Failed to run sept\n");
|
||||||
|
|
||||||
|
btn_wait();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
25
bootloader/hos/sept.h
Normal file
25
bootloader/hos/sept.h
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* 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 _SEPT_H_
|
||||||
|
#define _SEPT_H_
|
||||||
|
|
||||||
|
#include "../utils/types.h"
|
||||||
|
|
||||||
|
void check_sept();
|
||||||
|
int reboot_to_sept(const u8 *tsec_fw, u32 kb);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 M4xw
|
* 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
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -27,11 +27,9 @@
|
|||||||
#define IRAM_LIB_ADDR 0x4002B000
|
#define IRAM_LIB_ADDR 0x4002B000
|
||||||
#define DRAM_LIB_ADDR 0xE0000000
|
#define DRAM_LIB_ADDR 0xE0000000
|
||||||
|
|
||||||
extern gfx_ctxt_t gfx_ctxt;
|
|
||||||
extern gfx_con_t gfx_con;
|
|
||||||
extern heap_t _heap;
|
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 bool sd_mount();
|
||||||
extern void sd_unmount();
|
extern void sd_unmount();
|
||||||
|
|
||||||
@@ -67,62 +65,31 @@ static bool _ianos_read_cb(el_ctx *ctx, void *dest, size_t numberBytes, size_t o
|
|||||||
return true;
|
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.
|
//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 (sdmount)
|
||||||
{
|
{
|
||||||
if (!sd_mount())
|
if (!sd_mount())
|
||||||
{
|
|
||||||
res = 0xFFFF;
|
|
||||||
goto elfLoadFinalOut;
|
goto elfLoadFinalOut;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fileBuf = sd_file_read(path);
|
fileBuf = sd_file_read(path, NULL);
|
||||||
|
|
||||||
if (sdmount)
|
if (sdmount)
|
||||||
sd_unmount();
|
sd_unmount();
|
||||||
|
|
||||||
if (!fileBuf)
|
if (!fileBuf)
|
||||||
{
|
|
||||||
res = 1;
|
|
||||||
goto elfLoadFinalOut;
|
goto elfLoadFinalOut;
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
el_ctx ctx;
|
el_ctx ctx;
|
||||||
ctx.pread = _ianos_read_cb;
|
ctx.pread = _ianos_read_cb;
|
||||||
|
|
||||||
if (el_init(&ctx))
|
if (el_init(&ctx))
|
||||||
{
|
|
||||||
res = 2;
|
|
||||||
goto elfLoadFinalOut;
|
goto elfLoadFinalOut;
|
||||||
}
|
|
||||||
|
|
||||||
// Set our relocated library's buffer.
|
// Set our relocated library's buffer.
|
||||||
switch (type & 0xFFFF)
|
switch (type & 0xFFFF)
|
||||||
@@ -133,43 +100,32 @@ int ianos_loader(bool sdmount, char *path, elfType_t type, void *moduleConfig)
|
|||||||
sd_unmount();
|
sd_unmount();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
elfBuf = memalign(ctx.align, ctx.memsz);
|
elfBuf = malloc(ctx.memsz); // Aligned to 0x10 by default.
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!elfBuf)
|
if (!elfBuf)
|
||||||
{
|
|
||||||
res = 3;
|
|
||||||
goto elfLoadFinalOut;
|
goto elfLoadFinalOut;
|
||||||
}
|
|
||||||
|
|
||||||
// Load and relocate library.
|
// Load and relocate library.
|
||||||
ctx.base_load_vaddr = ctx.base_load_paddr = (uintptr_t)elfBuf;
|
ctx.base_load_vaddr = ctx.base_load_paddr = (uintptr_t)elfBuf;
|
||||||
if (el_load(&ctx, _ianos_alloc_cb))
|
if (el_load(&ctx, _ianos_alloc_cb))
|
||||||
{
|
|
||||||
res = 4;
|
|
||||||
goto elfFreeOut;
|
goto elfFreeOut;
|
||||||
}
|
|
||||||
|
|
||||||
if (el_relocate(&ctx))
|
if (el_relocate(&ctx))
|
||||||
{
|
|
||||||
res = 5;
|
|
||||||
goto elfFreeOut;
|
goto elfFreeOut;
|
||||||
}
|
|
||||||
|
|
||||||
// Launch.
|
// 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;
|
moduleEntrypoint_t ep = (moduleEntrypoint_t)epaddr;
|
||||||
|
|
||||||
_ianos_call_ep(ep, moduleConfig);
|
_ianos_call_ep(ep, moduleConfig);
|
||||||
|
|
||||||
elfFreeOut:
|
elfFreeOut:
|
||||||
if ((u32)elfBuf >= 0x90000000 && (u32)elfBuf <= DRAM_LIB_ADDR)
|
|
||||||
free(elfBuf);
|
|
||||||
free(fileBuf);
|
free(fileBuf);
|
||||||
elfBuf = NULL;
|
elfBuf = NULL;
|
||||||
fileBuf = NULL;
|
fileBuf = NULL;
|
||||||
|
|
||||||
elfLoadFinalOut:
|
elfLoadFinalOut:
|
||||||
|
|
||||||
return res;
|
return epaddr;
|
||||||
}
|
}
|
||||||
@@ -29,6 +29,6 @@ typedef enum
|
|||||||
KEEP_IN_RAM = (1 << 31) // Shared library mask.
|
KEEP_IN_RAM = (1 << 31) // Shared library mask.
|
||||||
} elfType_t;
|
} 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
|
#endif
|
||||||
@@ -26,9 +26,8 @@
|
|||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
#include "../../gfx/gfx.h"
|
#include "../../gfx/gfx.h"
|
||||||
extern gfx_con_t gfx_con;
|
|
||||||
#define EL_DEBUG(format, ...) \
|
#define EL_DEBUG(format, ...) \
|
||||||
gfx_printf(&gfx_con, format __VA_OPT__(, ) __VA_ARGS__)
|
gfx_printf(format __VA_OPT__(, ) __VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
#define EL_DEBUG(...) \
|
#define EL_DEBUG(...) \
|
||||||
do \
|
do \
|
||||||
|
|||||||
@@ -11,8 +11,14 @@
|
|||||||
#include "diskio.h" /* FatFs lower layer API */
|
#include "diskio.h" /* FatFs lower layer API */
|
||||||
#include "../../storage/sdmmc.h"
|
#include "../../storage/sdmmc.h"
|
||||||
|
|
||||||
|
#define SDMMC_UPPER_BUFFER 0xB8000000
|
||||||
|
#define DRAM_START 0x80000000
|
||||||
|
|
||||||
extern sdmmc_storage_t sd_storage;
|
extern sdmmc_storage_t sd_storage;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* Get Drive Status */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
DSTATUS disk_status (
|
DSTATUS disk_status (
|
||||||
BYTE pdrv /* Physical drive nmuber to identify the drive */
|
BYTE pdrv /* Physical drive nmuber to identify the drive */
|
||||||
)
|
)
|
||||||
@@ -20,6 +26,9 @@ DSTATUS disk_status (
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* Inidialize a Drive */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
DSTATUS disk_initialize (
|
DSTATUS disk_initialize (
|
||||||
BYTE pdrv /* Physical drive nmuber to identify the drive */
|
BYTE pdrv /* Physical drive nmuber to identify the drive */
|
||||||
)
|
)
|
||||||
@@ -27,6 +36,9 @@ DSTATUS disk_initialize (
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* Read Sector(s) */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
DRESULT disk_read (
|
DRESULT disk_read (
|
||||||
BYTE pdrv, /* Physical drive nmuber to identify the drive */
|
BYTE pdrv, /* Physical drive nmuber to identify the drive */
|
||||||
BYTE *buff, /* Data buffer to store read data */
|
BYTE *buff, /* Data buffer to store read data */
|
||||||
@@ -34,9 +46,9 @@ DRESULT disk_read (
|
|||||||
UINT count /* Number of sectors to read */
|
UINT count /* Number of sectors to read */
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if ((u32)buff >= 0x90000000)
|
if ((u32)buff >= DRAM_START)
|
||||||
return sdmmc_storage_read(&sd_storage, sector, count, buff) ? RES_OK : RES_ERROR;
|
return sdmmc_storage_read(&sd_storage, sector, count, buff) ? RES_OK : RES_ERROR;
|
||||||
u8 *buf = (u8 *)0x98000000; //TODO: define this somewhere.
|
u8 *buf = (u8 *)SDMMC_UPPER_BUFFER;
|
||||||
if (sdmmc_storage_read(&sd_storage, sector, count, buf))
|
if (sdmmc_storage_read(&sd_storage, sector, count, buf))
|
||||||
{
|
{
|
||||||
memcpy(buff, buf, 512 * count);
|
memcpy(buff, buf, 512 * count);
|
||||||
@@ -45,6 +57,9 @@ DRESULT disk_read (
|
|||||||
return RES_ERROR;
|
return RES_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* Write Sector(s) */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
DRESULT disk_write (
|
DRESULT disk_write (
|
||||||
BYTE pdrv, /* Physical drive nmuber to identify the drive */
|
BYTE pdrv, /* Physical drive nmuber to identify the drive */
|
||||||
const BYTE *buff, /* Data to be written */
|
const BYTE *buff, /* Data to be written */
|
||||||
@@ -52,15 +67,18 @@ DRESULT disk_write (
|
|||||||
UINT count /* Number of sectors to write */
|
UINT count /* Number of sectors to write */
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if ((u32)buff >= 0x90000000)
|
if ((u32)buff >= DRAM_START)
|
||||||
return sdmmc_storage_write(&sd_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR;
|
return sdmmc_storage_write(&sd_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR;
|
||||||
u8 *buf = (u8 *)0x98000000; //TODO: define this somewhere.
|
u8 *buf = (u8 *)SDMMC_UPPER_BUFFER; //TODO: define this somewhere.
|
||||||
memcpy(buf, buff, 512 * count);
|
memcpy(buf, buff, 512 * count);
|
||||||
if (sdmmc_storage_write(&sd_storage, sector, count, buf))
|
if (sdmmc_storage_write(&sd_storage, sector, count, buf))
|
||||||
return RES_OK;
|
return RES_OK;
|
||||||
return RES_ERROR;
|
return RES_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* Miscellaneous Functions */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
DRESULT disk_ioctl (
|
DRESULT disk_ioctl (
|
||||||
BYTE pdrv, /* Physical drive nmuber (0..) */
|
BYTE pdrv, /* Physical drive nmuber (0..) */
|
||||||
BYTE cmd, /* Control code */
|
BYTE cmd, /* Control code */
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ extern "C" {
|
|||||||
|
|
||||||
#include "../../utils/types.h"
|
#include "../../utils/types.h"
|
||||||
|
|
||||||
|
|
||||||
/* Status of Disk Functions */
|
/* Status of Disk Functions */
|
||||||
typedef BYTE DSTATUS;
|
typedef BYTE DSTATUS;
|
||||||
|
|
||||||
@@ -46,11 +45,11 @@ DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);
|
|||||||
/* Command code for disk_ioctrl fucntion */
|
/* Command code for disk_ioctrl fucntion */
|
||||||
|
|
||||||
/* Generic command (Used by FatFs) */
|
/* Generic command (Used by FatFs) */
|
||||||
#define CTRL_SYNC 0 /* Complete pending write process (needed at _FS_READONLY == 0) */
|
#define CTRL_SYNC 0 /* Complete pending write process (needed at FF_FS_READONLY == 0) */
|
||||||
#define GET_SECTOR_COUNT 1 /* Get media size (needed at _USE_MKFS == 1) */
|
#define GET_SECTOR_COUNT 1 /* Get media size (needed at FF_USE_MKFS == 1) */
|
||||||
#define GET_SECTOR_SIZE 2 /* Get sector size (needed at _MAX_SS != _MIN_SS) */
|
#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 _USE_MKFS == 1) */
|
#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 _USE_TRIM == 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) */
|
/* Generic command (Not used by FatFs) */
|
||||||
#define CTRL_POWER 5 /* Get/Set power status */
|
#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, 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
|
/ FatFs module is an open source software. Redistribution and use of FatFs in
|
||||||
/ source and binary forms, with or without modification, are permitted provided
|
/ source and binary forms, with or without modification, are permitted provided
|
||||||
@@ -23,11 +38,9 @@
|
|||||||
|
|
||||||
#include "ff.h" /* Declarations of FatFs API */
|
#include "ff.h" /* Declarations of FatFs API */
|
||||||
#include "diskio.h" /* Declarations of device I/O functions */
|
#include "diskio.h" /* Declarations of device I/O functions */
|
||||||
|
|
||||||
#include "../../gfx/gfx.h"
|
#include "../../gfx/gfx.h"
|
||||||
extern gfx_ctxt_t gfx_ctxt;
|
|
||||||
extern gfx_con_t gfx_con;
|
#define EFSPRINTF(text, ...) print_error(); gfx_printf("%k"text"%k\n", 0xFFFFFF00, 0xFFFFFFFF);
|
||||||
#define EFSPRINTF(text, ...) print_error(); gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFFFF00, 0xFFFFFFFF);
|
|
||||||
//#define EFSPRINTF(...)
|
//#define EFSPRINTF(...)
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------
|
/*--------------------------------------------------------------------------
|
||||||
@@ -36,11 +49,20 @@ extern gfx_con_t gfx_con;
|
|||||||
|
|
||||||
---------------------------------------------------------------------------*/
|
---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
#if FF_DEFINED != 63463 /* Revision ID */
|
#if FF_DEFINED != 86604 /* Revision ID */
|
||||||
#error Wrong include file (ff.h).
|
#error Wrong include file (ff.h).
|
||||||
#endif
|
#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 */
|
/* Character code support macros */
|
||||||
#define IsUpper(c) ((c) >= 'A' && (c) <= 'Z')
|
#define IsUpper(c) ((c) >= 'A' && (c) <= 'Z')
|
||||||
#define IsLower(c) ((c) >= 'a' && (c) <= 'z')
|
#define IsLower(c) ((c) >= 'a' && (c) <= 'z')
|
||||||
@@ -50,18 +72,18 @@ extern gfx_con_t gfx_con;
|
|||||||
#define IsSurrogateL(c) ((c) >= 0xDC00 && (c) <= 0xDFFF)
|
#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 */
|
/* 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_SEEKEND 0x20 /* Seek to end of the file on file open */
|
||||||
#define FA_MODIFIED 0x40 /* File has been modified */
|
#define FA_MODIFIED 0x40 /* File has been modified */
|
||||||
#define FA_DIRTY 0x80 /* FIL.buf[] needs to be written-back */
|
#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] */
|
/* Name status flags in fn[11] */
|
||||||
#define NSFLAG 11 /* Index of the name status byte */
|
#define NSFLAG 11 /* Index of the name status byte */
|
||||||
#define NS_LOSS 0x01 /* Out of 8.3 format */
|
#define NS_LOSS 0x01 /* Out of 8.3 format */
|
||||||
@@ -74,13 +96,13 @@ extern gfx_con_t gfx_con;
|
|||||||
#define NS_NONAME 0x80 /* Not followed */
|
#define NS_NONAME 0x80 /* Not followed */
|
||||||
|
|
||||||
|
|
||||||
/* Limits and boundaries */
|
/* exFAT directory entry types */
|
||||||
#define MAX_DIR 0x200000 /* Max size of FAT directory */
|
#define ET_BITMAP 0x81 /* Allocation bitmap */
|
||||||
#define MAX_DIR_EX 0x10000000 /* Max size of exFAT directory */
|
#define ET_UPCASE 0x82 /* Up-case table */
|
||||||
#define MAX_FAT12 0xFF5 /* Max FAT12 clusters (differs from specs, but right for real DOS/Windows behavior) */
|
#define ET_VLABEL 0x83 /* Volume label */
|
||||||
#define MAX_FAT16 0xFFF5 /* Max FAT16 clusters (differs from specs, but right for real DOS/Windows behavior) */
|
#define ET_FILEDIR 0x85 /* File and directory */
|
||||||
#define MAX_FAT32 0x0FFFFFF5 /* Max FAT32 clusters (not specified, practical limit) */
|
#define ET_STREAM 0xC0 /* Stream extension */
|
||||||
#define MAX_EXFAT 0x7FFFFFFD /* Max exFAT clusters (differs from specs, implementation limit) */
|
#define ET_FILENAME 0xC1 /* Name extension */
|
||||||
|
|
||||||
|
|
||||||
/* FatFs refers the FAT structure as simple byte array instead of structure member
|
/* FatFs refers the FAT structure as simple byte array instead of structure member
|
||||||
@@ -528,6 +550,7 @@ static WCHAR LfnBuf[FF_MAX_LFN + 1]; /* LFN working buffer */
|
|||||||
#define CODEPAGE CodePage
|
#define CODEPAGE CodePage
|
||||||
static WORD CodePage; /* Current code page */
|
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 *ExCvt, *DbcTbl; /* Pointer to current SBCS up-case table and DBCS code range table below */
|
||||||
|
|
||||||
static const BYTE Ct437[] = TBL_CT437;
|
static const BYTE Ct437[] = TBL_CT437;
|
||||||
static const BYTE Ct720[] = TBL_CT720;
|
static const BYTE Ct720[] = TBL_CT720;
|
||||||
static const BYTE Ct737[] = TBL_CT737;
|
static const BYTE Ct737[] = TBL_CT737;
|
||||||
@@ -575,7 +598,7 @@ static const BYTE DbcTbl[] = MKCVTBL(TBL_DC, FF_CODE_PAGE);
|
|||||||
|
|
||||||
void print_error()
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1109,7 +1132,7 @@ static FRESULT sync_fs ( /* Returns FR_OK or FR_DISK_ERR */
|
|||||||
if (res == FR_OK) {
|
if (res == FR_OK) {
|
||||||
if (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) { /* FAT32: Update FSInfo sector if needed */
|
if (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) { /* FAT32: Update FSInfo sector if needed */
|
||||||
/* Create FSInfo structure */
|
/* 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_word(fs->win + BS_55AA, 0xAA55);
|
||||||
st_dword(fs->win + FSI_LeadSig, 0x41615252);
|
st_dword(fs->win + FSI_LeadSig, 0x41615252);
|
||||||
st_dword(fs->win + FSI_StrucSig, 0x61417272);
|
st_dword(fs->win + FSI_StrucSig, 0x61417272);
|
||||||
@@ -1309,7 +1332,7 @@ static DWORD find_bitmap ( /* 0:Not found, 2..:Cluster block found, 0xFFFFFFFF:D
|
|||||||
if (clst >= fs->n_fatent - 2) clst = 0;
|
if (clst >= fs->n_fatent - 2) clst = 0;
|
||||||
scl = val = clst; ctr = 0;
|
scl = val = clst; ctr = 0;
|
||||||
for (;;) {
|
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);
|
i = val / 8 % SS(fs); bm = 1 << (val % 8);
|
||||||
do {
|
do {
|
||||||
do {
|
do {
|
||||||
@@ -1347,7 +1370,7 @@ static FRESULT change_bitmap (
|
|||||||
|
|
||||||
|
|
||||||
clst -= 2; /* The first bit corresponds to cluster #2 */
|
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) */
|
sect = fs->bitbase + clst / 8 / SS(fs); /* Sector address */
|
||||||
i = clst / 8 % SS(fs); /* Byte offset in the sector */
|
i = clst / 8 % SS(fs); /* Byte offset in the sector */
|
||||||
bm = 1 << (clst % 8); /* Bit mask in the byte */
|
bm = 1 << (clst % 8); /* Bit mask in the byte */
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@@ -1422,7 +1445,7 @@ static FRESULT fill_last_frag (
|
|||||||
static FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */
|
static FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */
|
||||||
FFOBJID* obj, /* Corresponding object */
|
FFOBJID* obj, /* Corresponding object */
|
||||||
DWORD clst, /* Cluster to remove a chain from */
|
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;
|
FRESULT res = FR_OK;
|
||||||
@@ -1660,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 */
|
if (sync_window(fs) != FR_OK) return FR_DISK_ERR; /* Flush disk access window */
|
||||||
sect = clst2sect(fs, clst); /* Top of the cluster */
|
sect = clst2sect(fs, clst); /* Top of the cluster */
|
||||||
fs->winsect = sect; /* Set window to 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 */
|
#if FF_USE_LFN == 3 /* Quick table clear by using multi-secter write */
|
||||||
/* Allocate a temporary buffer */
|
/* 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) ;
|
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) ;
|
||||||
@@ -1890,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 */
|
for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */
|
||||||
uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */
|
uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */
|
||||||
if (wc != 0) {
|
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 */
|
return 0; /* Not matched */
|
||||||
}
|
}
|
||||||
wc = uc;
|
wc = uc;
|
||||||
@@ -1926,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 */
|
for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */
|
||||||
uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */
|
uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */
|
||||||
if (wc != 0) {
|
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 */
|
lfnbuf[i++] = wc = uc; /* Store it */
|
||||||
} else {
|
} else {
|
||||||
if (uc != 0xFFFF) return 0; /* Check filler */
|
if (uc != 0xFFFF) return 0; /* Check filler */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dir[LDIR_Ord] & LLEF) { /* Put terminator if it is the last LFN part */
|
if (dir[LDIR_Ord] & LLEF && wc != 0) { /* Put terminator if it is the last LFN part and not terminated */
|
||||||
if (i >= FF_MAX_LFN) return 0; /* Buffer overflow? */
|
if (i >= FF_MAX_LFN + 1) return 0; /* Buffer overflow? */
|
||||||
lfnbuf[i] = 0;
|
lfnbuf[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2170,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 */
|
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);
|
res = move_window(dp->obj.fs, dp->sect);
|
||||||
if (res != FR_OK) return res;
|
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);
|
mem_cpy(dirb + 0 * SZDIRE, dp->dir, SZDIRE);
|
||||||
sz_ent = (dirb[XDIR_NumSec] + 1) * SZDIRE;
|
sz_ent = (dirb[XDIR_NumSec] + 1) * SZDIRE;
|
||||||
if (sz_ent < 3 * SZDIRE || sz_ent > 19 * SZDIRE) return FR_INT_ERR;
|
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);
|
res = dir_next(dp, 0);
|
||||||
if (res == FR_NO_FILE) res = FR_INT_ERR; /* It cannot be */
|
if (res == FR_NO_FILE) res = FR_INT_ERR; /* It cannot be */
|
||||||
if (res != FR_OK) return res;
|
if (res != FR_OK) return res;
|
||||||
res = move_window(dp->obj.fs, dp->sect);
|
res = move_window(dp->obj.fs, dp->sect);
|
||||||
if (res != FR_OK) return res;
|
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);
|
mem_cpy(dirb + 1 * SZDIRE, dp->dir, SZDIRE);
|
||||||
if (MAXDIRB(dirb[XDIR_NumName]) > sz_ent) return FR_INT_ERR;
|
if (MAXDIRB(dirb[XDIR_NumName]) > sz_ent) return FR_INT_ERR;
|
||||||
|
|
||||||
/* Load C1 entries */
|
/* Load file-name entries */
|
||||||
i = 2 * SZDIRE; /* C1 offset to load */
|
i = 2 * SZDIRE; /* Name offset to load */
|
||||||
do {
|
do {
|
||||||
res = dir_next(dp, 0);
|
res = dir_next(dp, 0);
|
||||||
if (res == FR_NO_FILE) res = FR_INT_ERR; /* It cannot be */
|
if (res == FR_NO_FILE) res = FR_INT_ERR; /* It cannot be */
|
||||||
if (res != FR_OK) return res;
|
if (res != FR_OK) return res;
|
||||||
res = move_window(dp->obj.fs, dp->sect);
|
res = move_window(dp->obj.fs, dp->sect);
|
||||||
if (res != FR_OK) return res;
|
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);
|
if (i < MAXDIRB(FF_MAX_LFN)) mem_cpy(dirb + i, dp->dir, SZDIRE);
|
||||||
} while ((i += SZDIRE) < sz_ent);
|
} while ((i += SZDIRE) < sz_ent);
|
||||||
|
|
||||||
@@ -2301,16 +2324,16 @@ static void create_xdir (
|
|||||||
WCHAR wc;
|
WCHAR wc;
|
||||||
|
|
||||||
|
|
||||||
/* Create 85,C0 entry */
|
/* Create file-directory and stream-extension entry */
|
||||||
mem_set(dirb, 0, 2 * SZDIRE);
|
mem_set(dirb, 0, 2 * SZDIRE);
|
||||||
dirb[0 * SZDIRE + XDIR_Type] = 0x85; /* 85 entry */
|
dirb[0 * SZDIRE + XDIR_Type] = ET_FILEDIR;
|
||||||
dirb[1 * SZDIRE + XDIR_Type] = 0xC0; /* C0 entry */
|
dirb[1 * SZDIRE + XDIR_Type] = ET_STREAM;
|
||||||
|
|
||||||
/* Create C1 entries */
|
/* Create file-name entries */
|
||||||
i = SZDIRE * 2; /* Top of C1 entries */
|
i = SZDIRE * 2; /* Top of file_name entries */
|
||||||
nlen = nc1 = 0; wc = 1;
|
nlen = nc1 = 0; wc = 1;
|
||||||
do {
|
do {
|
||||||
dirb[i++] = 0xC1; dirb[i++] = 0; /* Entry type C1 */
|
dirb[i++] = ET_FILENAME; dirb[i++] = 0;
|
||||||
do { /* Fill name field */
|
do { /* Fill name field */
|
||||||
if (wc != 0 && (wc = lfn[nlen]) != 0) nlen++; /* Get a character if exist */
|
if (wc != 0 && (wc = lfn[nlen]) != 0) nlen++; /* Get a character if exist */
|
||||||
st_word(dirb + i, wc); /* Store it */
|
st_word(dirb + i, wc); /* Store it */
|
||||||
@@ -2334,8 +2357,8 @@ static void create_xdir (
|
|||||||
/* Read an object from the directory */
|
/* Read an object from the directory */
|
||||||
/*-----------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
#define dir_read_file(dp) dir_read(dp, 0)
|
#define DIR_READ_FILE(dp) dir_read(dp, 0)
|
||||||
#define dir_read_label(dp) dir_read(dp, 1)
|
#define DIR_READ_LABEL(dp) dir_read(dp, 1)
|
||||||
|
|
||||||
static FRESULT dir_read (
|
static FRESULT dir_read (
|
||||||
DIR* dp, /* Pointer to the directory object */
|
DIR* dp, /* Pointer to the directory object */
|
||||||
@@ -2344,7 +2367,7 @@ static FRESULT dir_read (
|
|||||||
{
|
{
|
||||||
FRESULT res = FR_NO_FILE;
|
FRESULT res = FR_NO_FILE;
|
||||||
FATFS *fs = dp->obj.fs;
|
FATFS *fs = dp->obj.fs;
|
||||||
BYTE a, c;
|
BYTE attr, b;
|
||||||
#if FF_USE_LFN
|
#if FF_USE_LFN
|
||||||
BYTE ord = 0xFF, sum = 0xFF;
|
BYTE ord = 0xFF, sum = 0xFF;
|
||||||
#endif
|
#endif
|
||||||
@@ -2352,16 +2375,16 @@ static FRESULT dir_read (
|
|||||||
while (dp->sect) {
|
while (dp->sect) {
|
||||||
res = move_window(fs, dp->sect);
|
res = move_window(fs, dp->sect);
|
||||||
if (res != FR_OK) break;
|
if (res != FR_OK) break;
|
||||||
c = dp->dir[DIR_Name]; /* Test for the entry type */
|
b = dp->dir[DIR_Name]; /* Test for the entry type */
|
||||||
if (c == 0) {
|
if (b == 0) {
|
||||||
res = FR_NO_FILE; break; /* Reached to end of the directory */
|
res = FR_NO_FILE; break; /* Reached to end of the directory */
|
||||||
}
|
}
|
||||||
#if FF_FS_EXFAT
|
#if FF_FS_EXFAT
|
||||||
if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */
|
if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */
|
||||||
if (FF_USE_LABEL && vol) {
|
if (FF_USE_LABEL && vol) {
|
||||||
if (c == 0x83) break; /* Volume label entry? */
|
if (b == ET_VLABEL) break; /* Volume label entry? */
|
||||||
} else {
|
} 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 */
|
dp->blk_ofs = dp->dptr; /* Get location of the block */
|
||||||
res = load_xdir(dp); /* Load the entry block */
|
res = load_xdir(dp); /* Load the entry block */
|
||||||
if (res == FR_OK) {
|
if (res == FR_OK) {
|
||||||
@@ -2373,19 +2396,19 @@ static FRESULT dir_read (
|
|||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
{ /* On the FAT/FAT32 volume */
|
{ /* 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 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;
|
ord = 0xFF;
|
||||||
} else {
|
} else {
|
||||||
if (a == AM_LFN) { /* An LFN entry is found */
|
if (attr == AM_LFN) { /* An LFN entry is found */
|
||||||
if (c & LLEF) { /* Is it start of an LFN sequence? */
|
if (b & LLEF) { /* Is it start of an LFN sequence? */
|
||||||
sum = dp->dir[LDIR_Chksum];
|
sum = dp->dir[LDIR_Chksum];
|
||||||
c &= (BYTE)~LLEF; ord = c;
|
b &= (BYTE)~LLEF; ord = b;
|
||||||
dp->blk_ofs = dp->dptr;
|
dp->blk_ofs = dp->dptr;
|
||||||
}
|
}
|
||||||
/* Check LFN validity and capture it */
|
/* 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 */
|
} else { /* An SFN entry is found */
|
||||||
if (ord != 0 || sum != sum_sfn(dp->dir)) { /* Is there a valid LFN? */
|
if (ord != 0 || sum != sum_sfn(dp->dir)) { /* Is there a valid LFN? */
|
||||||
dp->blk_ofs = 0xFFFFFFFF; /* It has no LFN. */
|
dp->blk_ofs = 0xFFFFFFFF; /* It has no LFN. */
|
||||||
@@ -2394,7 +2417,7 @@ static FRESULT dir_read (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else /* Non LFN configuration */
|
#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;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -2434,7 +2457,7 @@ static FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */
|
|||||||
UINT di, ni;
|
UINT di, ni;
|
||||||
WORD hash = xname_sum(fs->lfnbuf); /* Hash value of the name to find */
|
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 FF_MAX_LFN < 255
|
||||||
if (fs->dirbuf[XDIR_NumName] > FF_MAX_LFN) continue; /* Skip comparison if inaccessible object name */
|
if (fs->dirbuf[XDIR_NumName] > FF_MAX_LFN) continue; /* Skip comparison if inaccessible object name */
|
||||||
#endif
|
#endif
|
||||||
@@ -2513,17 +2536,17 @@ static FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too
|
|||||||
#if FF_FS_EXFAT
|
#if FF_FS_EXFAT
|
||||||
if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */
|
if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */
|
||||||
nent = (nlen + 14) / 15 + 2; /* Number of entries to allocate (85+C0+C1s) */
|
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;
|
if (res != FR_OK) return res;
|
||||||
dp->blk_ofs = dp->dptr - SZDIRE * (nent - 1); /* Set the allocated entry block offset */
|
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;
|
dp->obj.stat &= ~4;
|
||||||
res = fill_first_frag(&dp->obj); /* Fill the first fragment on the FAT if needed */
|
res = fill_first_frag(&dp->obj); /* Fill the first fragment on the FAT if needed */
|
||||||
if (res != FR_OK) return res;
|
if (res != FR_OK) return res;
|
||||||
res = fill_last_frag(&dp->obj, dp->clust, 0xFFFFFFFF); /* Fill the last fragment on the FAT if needed */
|
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 (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;
|
DIR dj;
|
||||||
|
|
||||||
res = load_obj_xdir(&dj, &dp->obj); /* Load the object status */
|
res = load_obj_xdir(&dj, &dp->obj); /* Load the object status */
|
||||||
@@ -2655,6 +2678,7 @@ static void get_fileinfo (
|
|||||||
{
|
{
|
||||||
UINT si, di;
|
UINT si, di;
|
||||||
#if FF_USE_LFN
|
#if FF_USE_LFN
|
||||||
|
BYTE lcf;
|
||||||
WCHAR wc, hs;
|
WCHAR wc, hs;
|
||||||
FATFS *fs = dp->obj.fs;
|
FATFS *fs = dp->obj.fs;
|
||||||
#else
|
#else
|
||||||
@@ -2715,9 +2739,10 @@ static void get_fileinfo (
|
|||||||
if (di == 0) { /* If LFN and SFN both are invalid, this object is inaccesible */
|
if (di == 0) { /* If LFN and SFN both are invalid, this object is inaccesible */
|
||||||
fno->fname[di++] = '?';
|
fno->fname[di++] = '?';
|
||||||
} else {
|
} 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];
|
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;
|
fno->fname[di] = (TCHAR)wc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3274,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;
|
if (SS(fs) > FF_MAX_SS || SS(fs) < FF_MIN_SS || (SS(fs) & (SS(fs) - 1))) return FR_DISK_ERR;
|
||||||
#endif
|
#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;
|
bsect = 0;
|
||||||
fmt = check_fs(fs, bsect); /* Load sector 0 and check if it is an FAT-VBR as SFD */
|
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 */
|
if (fmt == 2 || (fmt < 2 && LD2PT(vol) != 0)) { /* Not an FAT-VBR or forced partition number */
|
||||||
@@ -3303,13 +3328,12 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */
|
|||||||
#if FF_FS_EXFAT
|
#if FF_FS_EXFAT
|
||||||
if (fmt == 1) {
|
if (fmt == 1) {
|
||||||
QWORD maxlba;
|
QWORD maxlba;
|
||||||
|
DWORD so, cv, bcl;
|
||||||
|
|
||||||
for (i = BPB_ZeroedEx; i < BPB_ZeroedEx + 53 && fs->win[i] == 0; i++) ; /* Check zero filler */
|
for (i = BPB_ZeroedEx; i < BPB_ZeroedEx + 53 && fs->win[i] == 0; i++) ; /* Check zero filler */
|
||||||
if (i < BPB_ZeroedEx + 53)
|
if (i < BPB_ZeroedEx + 53) return FR_NO_FILESYSTEM;
|
||||||
return FR_NO_FILESYSTEM;
|
|
||||||
|
|
||||||
if (ld_word(fs->win + BPB_FSVerEx) != 0x100)
|
if (ld_word(fs->win + BPB_FSVerEx) != 0x100) return FR_NO_FILESYSTEM; /* Check exFAT version (must be version 1.0) */
|
||||||
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) */
|
if (1 << fs->win[BPB_BytsPerSecEx] != SS(fs)) { /* (BPB_BytsPerSecEx must be equal to the physical sector size) */
|
||||||
EFSPRINTF("EXSPS");
|
EFSPRINTF("EXSPS");
|
||||||
@@ -3317,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 */
|
maxlba = ld_qword(fs->win + BPB_TotSecEx) + bsect; /* Last LBA + 1 of the volume */
|
||||||
if (maxlba >= 0x100000000)
|
if (maxlba >= 0x100000000) return FR_NO_FILESYSTEM; /* (It cannot be handled in 32-bit LBA) */
|
||||||
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 */
|
fs->fsize = ld_dword(fs->win + BPB_FatSzEx); /* Number of sectors per FAT */
|
||||||
|
|
||||||
@@ -3329,35 +3352,49 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */
|
|||||||
}
|
}
|
||||||
|
|
||||||
fs->csize = 1 << fs->win[BPB_SecPerClusEx]; /* Cluster size */
|
fs->csize = 1 << fs->win[BPB_SecPerClusEx]; /* Cluster size */
|
||||||
if (fs->csize == 0) {
|
if (fs->csize == 0) return FR_NO_FILESYSTEM; /* (Must be 1..32768) */
|
||||||
return FR_NO_FILESYSTEM; /* (Must be 1..32768) */
|
|
||||||
}
|
|
||||||
|
|
||||||
nclst = ld_dword(fs->win + BPB_NumClusEx); /* Number of clusters */
|
nclst = ld_dword(fs->win + BPB_NumClusEx); /* Number of clusters */
|
||||||
if (nclst > MAX_EXFAT)
|
if (nclst > MAX_EXFAT) return FR_NO_FILESYSTEM; /* (Too many clusters) */
|
||||||
return FR_NO_FILESYSTEM; /* (Too many clusters) */
|
|
||||||
fs->n_fatent = nclst + 2;
|
fs->n_fatent = nclst + 2;
|
||||||
|
|
||||||
/* Boundaries and Limits */
|
/* Boundaries and Limits */
|
||||||
fs->volbase = bsect;
|
fs->volbase = bsect;
|
||||||
fs->database = bsect + ld_dword(fs->win + BPB_DataOfsEx);
|
fs->database = bsect + ld_dword(fs->win + BPB_DataOfsEx);
|
||||||
fs->fatbase = bsect + ld_dword(fs->win + BPB_FatOfsEx);
|
fs->fatbase = bsect + ld_dword(fs->win + BPB_FatOfsEx);
|
||||||
if (maxlba < (QWORD)fs->database + nclst * fs->csize)
|
if (maxlba < (QWORD)fs->database + nclst * fs->csize) return FR_NO_FILESYSTEM; /* (Volume size must not be smaller than the size requiered) */
|
||||||
return FR_NO_FILESYSTEM; /* (Volume size must not be smaller than the size required) */
|
|
||||||
fs->dirbase = ld_dword(fs->win + BPB_RootClusEx);
|
fs->dirbase = ld_dword(fs->win + BPB_RootClusEx);
|
||||||
|
|
||||||
/* Check if bitmap location is in assumption (at the first cluster) */
|
/* Get bitmap location and check if it is contiguous (implementation assumption) */
|
||||||
if (move_window(fs, clst2sect(fs, fs->dirbase)) != FR_OK) {
|
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");
|
EFSPRINTF("EXBM1C");
|
||||||
return FR_DISK_ERR;
|
return FR_DISK_ERR;
|
||||||
}
|
}
|
||||||
for (i = 0; i < SS(fs); i += SZDIRE) {
|
so++;
|
||||||
if (fs->win[i] == 0x81 && ld_dword(fs->win + i + 20) == 2) break; /* 81 entry with cluster #2? */
|
|
||||||
}
|
}
|
||||||
if (i == SS(fs)) {
|
if (fs->win[i] == ET_BITMAP) break; /* Is it a bitmap entry? */
|
||||||
|
i = (i + SZDIRE) % SS(fs); /* Next entry */
|
||||||
|
}
|
||||||
|
bcl = ld_dword(fs->win + i + 20); /* Bitmap cluster */
|
||||||
|
if (bcl < 2 || bcl >= fs->n_fatent) {
|
||||||
EFSPRINTF("EXBMM");
|
EFSPRINTF("EXBMM");
|
||||||
return FR_NO_FILESYSTEM;
|
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
|
#if !FF_FS_READONLY
|
||||||
fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Initialize cluster allocation information */
|
fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Initialize cluster allocation information */
|
||||||
#endif
|
#endif
|
||||||
@@ -3375,38 +3412,31 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */
|
|||||||
fs->fsize = fasize;
|
fs->fsize = fasize;
|
||||||
|
|
||||||
fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FATs */
|
fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FATs */
|
||||||
if (fs->n_fats != 1 && fs->n_fats != 2)
|
if (fs->n_fats != 1 && fs->n_fats != 2) return FR_NO_FILESYSTEM; /* (Must be 1 or 2) */
|
||||||
return FR_NO_FILESYSTEM; /* (Must be 1 or 2) */
|
|
||||||
fasize *= fs->n_fats; /* Number of sectors for FAT area */
|
fasize *= fs->n_fats; /* Number of sectors for FAT area */
|
||||||
|
|
||||||
fs->csize = fs->win[BPB_SecPerClus]; /* Cluster size */
|
fs->csize = fs->win[BPB_SecPerClus]; /* Cluster size */
|
||||||
if (fs->csize == 0 || (fs->csize & (fs->csize - 1)))
|
if (fs->csize == 0 || (fs->csize & (fs->csize - 1))) return FR_NO_FILESYSTEM; /* (Must be power of 2) */
|
||||||
return FR_NO_FILESYSTEM; /* (Must be power of 2) */
|
|
||||||
|
|
||||||
fs->n_rootdir = ld_word(fs->win + BPB_RootEntCnt); /* Number of root directory entries */
|
fs->n_rootdir = ld_word(fs->win + BPB_RootEntCnt); /* Number of root directory entries */
|
||||||
if (fs->n_rootdir % (SS(fs) / SZDIRE))
|
if (fs->n_rootdir % (SS(fs) / SZDIRE)) return FR_NO_FILESYSTEM; /* (Must be sector aligned) */
|
||||||
return FR_NO_FILESYSTEM; /* (Must be sector aligned) */
|
|
||||||
|
|
||||||
tsect = ld_word(fs->win + BPB_TotSec16); /* Number of sectors on the volume */
|
tsect = ld_word(fs->win + BPB_TotSec16); /* Number of sectors on the volume */
|
||||||
if (tsect == 0) tsect = ld_dword(fs->win + BPB_TotSec32);
|
if (tsect == 0) tsect = ld_dword(fs->win + BPB_TotSec32);
|
||||||
|
|
||||||
nrsv = ld_word(fs->win + BPB_RsvdSecCnt); /* Number of reserved sectors */
|
nrsv = ld_word(fs->win + BPB_RsvdSecCnt); /* Number of reserved sectors */
|
||||||
if (nrsv == 0)
|
if (nrsv == 0) return FR_NO_FILESYSTEM; /* (Must not be 0) */
|
||||||
return FR_NO_FILESYSTEM; /* (Must not be 0) */
|
|
||||||
|
|
||||||
/* Determine the FAT sub type */
|
/* Determine the FAT sub type */
|
||||||
sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZDIRE); /* RSV + FAT + DIR */
|
sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZDIRE); /* RSV + FAT + DIR */
|
||||||
if (tsect < sysect)
|
if (tsect < sysect) return FR_NO_FILESYSTEM; /* (Invalid volume size) */
|
||||||
return FR_NO_FILESYSTEM; /* (Invalid volume size) */
|
|
||||||
nclst = (tsect - sysect) / fs->csize; /* Number of clusters */
|
nclst = (tsect - sysect) / fs->csize; /* Number of clusters */
|
||||||
if (nclst == 0)
|
if (nclst == 0) return FR_NO_FILESYSTEM; /* (Invalid volume size) */
|
||||||
return FR_NO_FILESYSTEM; /* (Invalid volume size) */
|
|
||||||
fmt = 0;
|
fmt = 0;
|
||||||
if (nclst <= MAX_FAT32) fmt = FS_FAT32;
|
if (nclst <= MAX_FAT32) fmt = FS_FAT32;
|
||||||
if (nclst <= MAX_FAT16) fmt = FS_FAT16;
|
if (nclst <= MAX_FAT16) fmt = FS_FAT16;
|
||||||
if (nclst <= MAX_FAT12) fmt = FS_FAT12;
|
if (nclst <= MAX_FAT12) fmt = FS_FAT12;
|
||||||
if (fmt == 0)
|
if (fmt == 0) return FR_NO_FILESYSTEM;
|
||||||
return FR_NO_FILESYSTEM;
|
|
||||||
|
|
||||||
/* Boundaries and Limits */
|
/* Boundaries and Limits */
|
||||||
fs->n_fatent = nclst + 2; /* Number of FAT entries */
|
fs->n_fatent = nclst + 2; /* Number of FAT entries */
|
||||||
@@ -3414,21 +3444,17 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */
|
|||||||
fs->fatbase = bsect + nrsv; /* FAT start sector */
|
fs->fatbase = bsect + nrsv; /* FAT start sector */
|
||||||
fs->database = bsect + sysect; /* Data start sector */
|
fs->database = bsect + sysect; /* Data start sector */
|
||||||
if (fmt == FS_FAT32) {
|
if (fmt == FS_FAT32) {
|
||||||
if (ld_word(fs->win + BPB_FSVer32) != 0)
|
if (ld_word(fs->win + BPB_FSVer32) != 0) return FR_NO_FILESYSTEM; /* (Must be FAT32 revision 0.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 (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 */
|
fs->dirbase = ld_dword(fs->win + BPB_RootClus32); /* Root directory start cluster */
|
||||||
szbfat = fs->n_fatent * 4; /* (Needed FAT size) */
|
szbfat = fs->n_fatent * 4; /* (Needed FAT size) */
|
||||||
} else {
|
} else {
|
||||||
if (fs->n_rootdir == 0)
|
if (fs->n_rootdir == 0) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must not be 0) */
|
||||||
return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must not be 0) */
|
|
||||||
fs->dirbase = fs->fatbase + fasize; /* Root directory start sector */
|
fs->dirbase = fs->fatbase + fasize; /* Root directory start sector */
|
||||||
szbfat = (fmt == FS_FAT16) ? /* (Needed FAT size) */
|
szbfat = (fmt == FS_FAT16) ? /* (Needed FAT size) */
|
||||||
fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1);
|
fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1);
|
||||||
}
|
}
|
||||||
if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs))
|
if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) return FR_NO_FILESYSTEM; /* (BPB_FATSz must not be less than the size needed) */
|
||||||
return FR_NO_FILESYSTEM; /* (BPB_FATSz must not be less than the size needed) */
|
|
||||||
|
|
||||||
#if !FF_FS_READONLY
|
#if !FF_FS_READONLY
|
||||||
/* Get FSInfo if available */
|
/* Get FSInfo if available */
|
||||||
@@ -3724,7 +3750,7 @@ FRESULT f_open (
|
|||||||
fp->fptr = 0; /* Set file pointer top of the file */
|
fp->fptr = 0; /* Set file pointer top of the file */
|
||||||
#if !FF_FS_READONLY
|
#if !FF_FS_READONLY
|
||||||
#if !FF_FS_TINY
|
#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
|
#endif
|
||||||
if ((mode & FA_SEEKEND) && fp->obj.objsize > 0) { /* Seek to end of file if FA_OPEN_APPEND is specified */
|
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 */
|
fp->fptr = fp->obj.objsize; /* Offset to seek */
|
||||||
@@ -3779,17 +3805,16 @@ FRESULT f_read (
|
|||||||
UINT rcnt, cc, csect;
|
UINT rcnt, cc, csect;
|
||||||
BYTE *rbuff = (BYTE*)buff;
|
BYTE *rbuff = (BYTE*)buff;
|
||||||
|
|
||||||
|
UINT br_tmp;
|
||||||
|
if (!br)
|
||||||
|
br = &br_tmp;
|
||||||
*br = 0; /* Clear read byte counter */
|
*br = 0; /* Clear read byte counter */
|
||||||
res = validate(&fp->obj, &fs); /* Check validity of the file object */
|
res = validate(&fp->obj, &fs); /* Check validity of the file object */
|
||||||
if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) {
|
if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) {
|
||||||
EFSPRINTF("FOV");
|
EFSPRINTF("FOV");
|
||||||
LEAVE_FF(fs, res); /* Check validity */
|
LEAVE_FF(fs, res); /* Check validity */
|
||||||
}
|
}
|
||||||
if (!(fp->flag & FA_READ)) {
|
if (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */
|
||||||
EFSPRINTF("NOACCESS");
|
|
||||||
LEAVE_FF(fs, FR_DENIED); /* Check access mode */
|
|
||||||
}
|
|
||||||
remain = fp->obj.objsize - fp->fptr;
|
remain = fp->obj.objsize - fp->fptr;
|
||||||
if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */
|
if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */
|
||||||
|
|
||||||
@@ -3821,9 +3846,7 @@ FRESULT f_read (
|
|||||||
fp->clust = clst; /* Update current cluster */
|
fp->clust = clst; /* Update current cluster */
|
||||||
}
|
}
|
||||||
sect = clst2sect(fs, fp->clust); /* Get current sector */
|
sect = clst2sect(fs, fp->clust); /* Get current sector */
|
||||||
if (sect == 0) {
|
if (sect == 0) ABORT(fs, FR_INT_ERR);
|
||||||
ABORT(fs, FR_INT_ERR);
|
|
||||||
}
|
|
||||||
sect += csect;
|
sect += csect;
|
||||||
cc = btr / SS(fs); /* When remaining bytes >= sector size, */
|
cc = btr / SS(fs); /* When remaining bytes >= sector size, */
|
||||||
if (cc > 0) { /* Read maximum contiguous sectors directly */
|
if (cc > 0) { /* Read maximum contiguous sectors directly */
|
||||||
@@ -3901,17 +3924,16 @@ FRESULT f_write (
|
|||||||
UINT wcnt, cc, csect;
|
UINT wcnt, cc, csect;
|
||||||
const BYTE *wbuff = (const BYTE*)buff;
|
const BYTE *wbuff = (const BYTE*)buff;
|
||||||
|
|
||||||
|
UINT bw_tmp;
|
||||||
|
if (!bw)
|
||||||
|
bw = &bw_tmp;
|
||||||
*bw = 0; /* Clear write byte counter */
|
*bw = 0; /* Clear write byte counter */
|
||||||
res = validate(&fp->obj, &fs); /* Check validity of the file object */
|
res = validate(&fp->obj, &fs); /* Check validity of the file object */
|
||||||
if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) {
|
if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) {
|
||||||
EFSPRINTF("FOV");
|
EFSPRINTF("FOV");
|
||||||
LEAVE_FF(fs, res); /* Check validity */
|
LEAVE_FF(fs, res); /* Check validity */
|
||||||
}
|
}
|
||||||
if (!(fp->flag & FA_WRITE)) {
|
if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */
|
||||||
EFSPRINTF("NOACCESS");
|
|
||||||
LEAVE_FF(fs, FR_DENIED); /* Check access mode */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check fptr wrap-around (file size cannot reach 4 GiB at FAT volume) */
|
/* 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) {
|
if ((!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) && (DWORD)(fp->fptr + btw) < (DWORD)fp->fptr) {
|
||||||
@@ -3957,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 */
|
if (fs->winsect == fp->sect && sync_window(fs) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Write-back sector cache */
|
||||||
#else
|
#else
|
||||||
if (fp->flag & FA_DIRTY) { /* Write-back sector cache */
|
if (fp->flag & FA_DIRTY) { /* Write-back sector cache */
|
||||||
if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK)
|
if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);
|
||||||
ABORT(fs, FR_DISK_ERR);
|
|
||||||
fp->flag &= (BYTE)~FA_DIRTY;
|
fp->flag &= (BYTE)~FA_DIRTY;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
sect = clst2sect(fs, fp->clust); /* Get current sector */
|
sect = clst2sect(fs, fp->clust); /* Get current sector */
|
||||||
if (sect == 0) {
|
if (sect == 0) ABORT(fs, FR_INT_ERR);
|
||||||
ABORT(fs, FR_INT_ERR);
|
|
||||||
}
|
|
||||||
sect += csect;
|
sect += csect;
|
||||||
cc = btw / SS(fs); /* When remaining bytes >= sector size, */
|
cc = btw / SS(fs); /* When remaining bytes >= sector size, */
|
||||||
if (cc > 0) { /* Write maximum contiguous sectors directly */
|
if (cc > 0) { /* Write maximum contiguous sectors directly */
|
||||||
@@ -4000,8 +4019,9 @@ FRESULT f_write (
|
|||||||
#else
|
#else
|
||||||
if (fp->sect != sect && /* Fill sector cache with file data */
|
if (fp->sect != sect && /* Fill sector cache with file data */
|
||||||
fp->fptr < fp->obj.objsize &&
|
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);
|
ABORT(fs, FR_DISK_ERR);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
fp->sect = sect;
|
fp->sect = sect;
|
||||||
}
|
}
|
||||||
@@ -4238,15 +4258,16 @@ FRESULT f_getcwd (
|
|||||||
TCHAR *tp = buff;
|
TCHAR *tp = buff;
|
||||||
#if FF_VOLUMES >= 2
|
#if FF_VOLUMES >= 2
|
||||||
UINT vl;
|
UINT vl;
|
||||||
#endif
|
|
||||||
#if FF_STR_VOLUME_ID
|
#if FF_STR_VOLUME_ID
|
||||||
const char *vp;
|
const char *vp;
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
FILINFO fno;
|
FILINFO fno;
|
||||||
DEF_NAMBUF
|
DEF_NAMBUF
|
||||||
|
|
||||||
|
|
||||||
/* Get logical drive */
|
/* Get logical drive */
|
||||||
|
buff[0] = 0; /* Set null string to get current volume */
|
||||||
res = find_volume((const TCHAR**)&buff, &fs, 0); /* Get current volume */
|
res = find_volume((const TCHAR**)&buff, &fs, 0); /* Get current volume */
|
||||||
if (res == FR_OK) {
|
if (res == FR_OK) {
|
||||||
dj.obj.fs = fs;
|
dj.obj.fs = fs;
|
||||||
@@ -4265,7 +4286,7 @@ FRESULT f_getcwd (
|
|||||||
res = dir_sdi(&dj, 0);
|
res = dir_sdi(&dj, 0);
|
||||||
if (res != FR_OK) break;
|
if (res != FR_OK) break;
|
||||||
do { /* Find the entry links to the child directory */
|
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 (res != FR_OK) break;
|
||||||
if (ccl == ld_clust(fs, dj.dir)) break; /* Found the entry */
|
if (ccl == ld_clust(fs, dj.dir)) break; /* Found the entry */
|
||||||
res = dir_next(&dj, 0);
|
res = dir_next(&dj, 0);
|
||||||
@@ -4597,7 +4618,7 @@ FRESULT f_readdir (
|
|||||||
res = dir_sdi(dp, 0); /* Rewind the directory object */
|
res = dir_sdi(dp, 0); /* Rewind the directory object */
|
||||||
} else {
|
} else {
|
||||||
INIT_NAMBUF(fs);
|
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_NO_FILE) res = FR_OK; /* Ignore end of directory */
|
||||||
if (res == FR_OK) { /* A valid entry is found */
|
if (res == FR_OK) { /* A valid entry is found */
|
||||||
get_fileinfo(dp, fno); /* Get the object information */
|
get_fileinfo(dp, fno); /* Get the object information */
|
||||||
@@ -4720,7 +4741,7 @@ FRESULT f_getfree (
|
|||||||
/* Get logical drive */
|
/* Get logical drive */
|
||||||
res = find_volume(&path, &fs, 0);
|
res = find_volume(&path, &fs, 0);
|
||||||
if (res == FR_OK) {
|
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 free_clst is valid, return it without full FAT scan */
|
||||||
if (fs->free_clst <= fs->n_fatent - 2) {
|
if (fs->free_clst <= fs->n_fatent - 2) {
|
||||||
*nclst = fs->free_clst;
|
*nclst = fs->free_clst;
|
||||||
@@ -4742,7 +4763,7 @@ FRESULT f_getfree (
|
|||||||
UINT b;
|
UINT b;
|
||||||
|
|
||||||
clst = fs->n_fatent - 2; /* Number of clusters */
|
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 */
|
i = 0; /* Offset in the sector */
|
||||||
do { /* Counts numbuer of bits with zero in the bitmap */
|
do { /* Counts numbuer of bits with zero in the bitmap */
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
@@ -4905,7 +4926,7 @@ FRESULT f_unlink (
|
|||||||
#endif
|
#endif
|
||||||
res = dir_sdi(&sdj, 0);
|
res = dir_sdi(&sdj, 0);
|
||||||
if (res == FR_OK) {
|
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_OK) res = FR_DENIED; /* Not empty? */
|
||||||
if (res == FR_NO_FILE) res = FR_OK; /* Empty? */
|
if (res == FR_NO_FILE) res = FR_OK; /* Empty? */
|
||||||
}
|
}
|
||||||
@@ -4945,47 +4966,43 @@ FRESULT f_mkdir (
|
|||||||
DIR dj;
|
DIR dj;
|
||||||
FFOBJID sobj;
|
FFOBJID sobj;
|
||||||
FATFS *fs;
|
FATFS *fs;
|
||||||
BYTE *dir;
|
|
||||||
DWORD dcl, pcl, tm;
|
DWORD dcl, pcl, tm;
|
||||||
DEF_NAMBUF
|
DEF_NAMBUF
|
||||||
|
|
||||||
|
|
||||||
/* Get logical drive */
|
res = find_volume(&path, &fs, FA_WRITE); /* Get logical drive */
|
||||||
res = find_volume(&path, &fs, FA_WRITE);
|
|
||||||
if (res == FR_OK) {
|
if (res == FR_OK) {
|
||||||
dj.obj.fs = fs;
|
dj.obj.fs = fs;
|
||||||
INIT_NAMBUF(fs);
|
INIT_NAMBUF(fs);
|
||||||
res = follow_path(&dj, path); /* Follow the file path */
|
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 (res == FR_OK) res = FR_EXIST; /* Name collision? */
|
||||||
if (FF_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) {
|
if (FF_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) { /* Invalid name? */
|
||||||
res = FR_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 */
|
sobj.fs = fs; /* New object id to create a new chain */
|
||||||
dcl = create_chain(&sobj, 0); /* Allocate a cluster for the new directory */
|
dcl = create_chain(&sobj, 0); /* Allocate a cluster for the new directory */
|
||||||
res = FR_OK;
|
res = FR_OK;
|
||||||
if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster */
|
if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster? */
|
||||||
if (dcl == 1) res = FR_INT_ERR;
|
if (dcl == 1) res = FR_INT_ERR; /* Any insanity? */
|
||||||
if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR;
|
if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR; /* Disk error? */
|
||||||
if (res == FR_OK) res = sync_window(fs); /* Flush FAT */
|
|
||||||
tm = GET_FATTIME();
|
tm = GET_FATTIME();
|
||||||
if (res == FR_OK) { /* Initialize the new directory table */
|
if (res == FR_OK) {
|
||||||
res = dir_clear(fs, dcl); /* Clean up the new 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) */
|
if (res == FR_OK) {
|
||||||
dir = fs->win;
|
if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { /* Create dot entries (FAT only) */
|
||||||
mem_set(dir + DIR_Name, ' ', 11); /* Create "." entry */
|
mem_set(fs->win + DIR_Name, ' ', 11); /* Create "." entry */
|
||||||
dir[DIR_Name] = '.';
|
fs->win[DIR_Name] = '.';
|
||||||
dir[DIR_Attr] = AM_DIR;
|
fs->win[DIR_Attr] = AM_DIR;
|
||||||
st_dword(dir + DIR_ModTime, tm);
|
st_dword(fs->win + DIR_ModTime, tm);
|
||||||
st_clust(fs, dir, dcl);
|
st_clust(fs, fs->win, dcl);
|
||||||
mem_cpy(dir + SZDIRE, dir, SZDIRE); /* Create ".." entry */
|
mem_cpy(fs->win + SZDIRE, fs->win, SZDIRE); /* Create ".." entry */
|
||||||
dir[SZDIRE + 1] = '.'; pcl = dj.obj.sclust;
|
fs->win[SZDIRE + 1] = '.'; pcl = dj.obj.sclust;
|
||||||
st_clust(fs, dir + SZDIRE, pcl);
|
st_clust(fs, fs->win + SZDIRE, pcl);
|
||||||
fs->wflag = 1;
|
fs->wflag = 1;
|
||||||
}
|
}
|
||||||
|
res = dir_register(&dj); /* Register the object to the parent directoy */
|
||||||
}
|
}
|
||||||
if (res == FR_OK) {
|
|
||||||
res = dir_register(&dj); /* Register the object to the directoy */
|
|
||||||
}
|
}
|
||||||
if (res == FR_OK) {
|
if (res == FR_OK) {
|
||||||
#if FF_FS_EXFAT
|
#if FF_FS_EXFAT
|
||||||
@@ -5000,17 +5017,16 @@ FRESULT f_mkdir (
|
|||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
dir = dj.dir;
|
st_dword(dj.dir + DIR_ModTime, tm); /* Created time */
|
||||||
st_dword(dir + DIR_ModTime, tm); /* Created time */
|
st_clust(fs, dj.dir, dcl); /* Table start cluster */
|
||||||
st_clust(fs, dir, dcl); /* Table start cluster */
|
dj.dir[DIR_Attr] = AM_DIR; /* Attribute */
|
||||||
dir[DIR_Attr] = AM_DIR; /* Attribute */
|
|
||||||
fs->wflag = 1;
|
fs->wflag = 1;
|
||||||
}
|
}
|
||||||
if (res == FR_OK) {
|
if (res == FR_OK) {
|
||||||
res = sync_fs(fs);
|
res = sync_fs(fs);
|
||||||
}
|
}
|
||||||
} else {
|
} 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();
|
FREE_NAMBUF();
|
||||||
@@ -5250,7 +5266,7 @@ FRESULT f_getlabel (
|
|||||||
dj.obj.fs = fs; dj.obj.sclust = 0; /* Open root directory */
|
dj.obj.fs = fs; dj.obj.sclust = 0; /* Open root directory */
|
||||||
res = dir_sdi(&dj, 0);
|
res = dir_sdi(&dj, 0);
|
||||||
if (res == FR_OK) {
|
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 (res == FR_OK) {
|
||||||
#if FF_FS_EXFAT
|
#if FF_FS_EXFAT
|
||||||
if (fs->fs_type == FS_EXFAT) {
|
if (fs->fs_type == FS_EXFAT) {
|
||||||
@@ -5395,7 +5411,7 @@ FRESULT f_setlabel (
|
|||||||
dj.obj.fs = fs; dj.obj.sclust = 0; /* Open root directory */
|
dj.obj.fs = fs; dj.obj.sclust = 0; /* Open root directory */
|
||||||
res = dir_sdi(&dj, 0);
|
res = dir_sdi(&dj, 0);
|
||||||
if (res == FR_OK) {
|
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 (res == FR_OK) {
|
||||||
if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) {
|
if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) {
|
||||||
dj.dir[XDIR_NumLabel] = (BYTE)di; /* Change the volume label */
|
dj.dir[XDIR_NumLabel] = (BYTE)di; /* Change the volume label */
|
||||||
@@ -5417,7 +5433,7 @@ FRESULT f_setlabel (
|
|||||||
if (res == FR_OK) {
|
if (res == FR_OK) {
|
||||||
mem_set(dj.dir, 0, SZDIRE); /* Clean the entry */
|
mem_set(dj.dir, 0, SZDIRE); /* Clean the entry */
|
||||||
if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) {
|
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;
|
dj.dir[XDIR_NumLabel] = (BYTE)di;
|
||||||
mem_cpy(dj.dir + XDIR_Label, dirvn, 22);
|
mem_cpy(dj.dir + XDIR_Label, dirvn, 22);
|
||||||
} else {
|
} else {
|
||||||
@@ -5722,7 +5738,7 @@ FRESULT f_mkfs (
|
|||||||
b_fat = b_vol + 32; /* FAT start at offset 32 */
|
b_fat = b_vol + 32; /* FAT start at offset 32 */
|
||||||
sz_fat = ((sz_vol / au + 2) * 4 + ss - 1) / ss; /* Number of FAT sectors */
|
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 */
|
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 */
|
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 <16) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too few clusters? */
|
||||||
if (n_clst > MAX_EXFAT) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too many clusters? */
|
if (n_clst > MAX_EXFAT) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too many clusters? */
|
||||||
@@ -5803,11 +5819,11 @@ FRESULT f_mkfs (
|
|||||||
|
|
||||||
/* Initialize the root directory */
|
/* Initialize the root directory */
|
||||||
mem_set(buf, 0, szb_buf);
|
mem_set(buf, 0, szb_buf);
|
||||||
buf[SZDIRE * 0 + 0] = 0x83; /* 83 entry (volume label) */
|
buf[SZDIRE * 0 + 0] = ET_VLABEL; /* Volume label entry */
|
||||||
buf[SZDIRE * 1 + 0] = 0x81; /* 81 entry (allocation bitmap) */
|
buf[SZDIRE * 1 + 0] = ET_BITMAP; /* Bitmap entry */
|
||||||
st_dword(buf + SZDIRE * 1 + 20, 2); /* cluster */
|
st_dword(buf + SZDIRE * 1 + 20, 2); /* cluster */
|
||||||
st_dword(buf + SZDIRE * 1 + 24, szb_bit); /* size */
|
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 + 4, sum); /* sum */
|
||||||
st_dword(buf + SZDIRE * 2 + 20, 2 + tbl[0]); /* cluster */
|
st_dword(buf + SZDIRE * 2 + 20, 2 + tbl[0]); /* cluster */
|
||||||
st_dword(buf + SZDIRE * 2 + 24, szb_case); /* size */
|
st_dword(buf + SZDIRE * 2 + 24, szb_case); /* size */
|
||||||
@@ -6295,8 +6311,7 @@ typedef struct { /* Putchar output buffer and work area */
|
|||||||
} putbuff;
|
} putbuff;
|
||||||
|
|
||||||
|
|
||||||
static
|
static void putc_bfd ( /* Buffered write with code conversion */
|
||||||
void putc_bfd ( /* Buffered write with code conversion */
|
|
||||||
putbuff* pb,
|
putbuff* pb,
|
||||||
TCHAR c
|
TCHAR c
|
||||||
)
|
)
|
||||||
@@ -6407,7 +6422,7 @@ void putc_bfd ( /* Buffered write with code conversion */
|
|||||||
#else /* Write it in ANSI/OEM */
|
#else /* Write it in ANSI/OEM */
|
||||||
if (hs != 0) return;
|
if (hs != 0) return;
|
||||||
wc = ff_uni2oem(wc, CODEPAGE); /* UTF-16 ==> ANSI/OEM */
|
wc = ff_uni2oem(wc, CODEPAGE); /* UTF-16 ==> ANSI/OEM */
|
||||||
if (wc == 0) return;;
|
if (wc == 0) return;
|
||||||
if (wc >= 0x100) {
|
if (wc >= 0x100) {
|
||||||
pb->buf[i++] = (BYTE)(wc >> 8); nc++;
|
pb->buf[i++] = (BYTE)(wc >> 8); nc++;
|
||||||
}
|
}
|
||||||
@@ -6427,8 +6442,7 @@ void putc_bfd ( /* Buffered write with code conversion */
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static
|
static int putc_flush ( /* Flush left characters in the buffer */
|
||||||
int putc_flush ( /* Flush left characters in the buffer */
|
|
||||||
putbuff* pb
|
putbuff* pb
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@@ -6441,8 +6455,7 @@ int putc_flush ( /* Flush left characters in the buffer */
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static
|
static void putc_init ( /* Initialize write buffer */
|
||||||
void putc_init ( /* Initialize write buffer */
|
|
||||||
putbuff* pb,
|
putbuff* pb,
|
||||||
FIL* fp
|
FIL* fp
|
||||||
)
|
)
|
||||||
@@ -6634,4 +6647,3 @@ FRESULT f_setcp (
|
|||||||
return FR_OK;
|
return FR_OK;
|
||||||
}
|
}
|
||||||
#endif /* FF_CODE_PAGE == 0 */
|
#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.
|
/ Copyright (C) 2018, ChaN, all right reserved.
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#ifndef FF_DEFINED
|
#ifndef FF_DEFINED
|
||||||
#define FF_DEFINED 63463 /* Revision ID */
|
#define FF_DEFINED 86604 /* Revision ID */
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -95,8 +95,9 @@ typedef DWORD FSIZE_t;
|
|||||||
/* Filesystem object structure (FATFS) */
|
/* Filesystem object structure (FATFS) */
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
BYTE fs_type; /* Filesystem type (0:N/A) */
|
BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */
|
||||||
BYTE pdrv; /* Physical drive number */
|
BYTE fs_type; /* Filesystem type (0:not mounted) */
|
||||||
|
BYTE pdrv; /* Associated physical drive */
|
||||||
BYTE n_fats; /* Number of FATs (1 or 2) */
|
BYTE n_fats; /* Number of FATs (1 or 2) */
|
||||||
BYTE wflag; /* win[] flag (b0:dirty) */
|
BYTE wflag; /* win[] flag (b0:dirty) */
|
||||||
BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */
|
BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */
|
||||||
@@ -133,8 +134,10 @@ typedef struct {
|
|||||||
DWORD fatbase; /* FAT base sector */
|
DWORD fatbase; /* FAT base sector */
|
||||||
DWORD dirbase; /* Root directory base sector/cluster */
|
DWORD dirbase; /* Root directory base sector/cluster */
|
||||||
DWORD database; /* Data base sector */
|
DWORD database; /* Data base sector */
|
||||||
|
#if FF_FS_EXFAT
|
||||||
|
DWORD bitbase; /* Allocation bitmap base sector */
|
||||||
|
#endif
|
||||||
DWORD winsect; /* Current sector appearing in the win[] */
|
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;
|
} FATFS;
|
||||||
|
|
||||||
|
|
||||||
@@ -145,7 +148,7 @@ typedef struct {
|
|||||||
FATFS* fs; /* Pointer to the hosting volume of this object */
|
FATFS* fs; /* Pointer to the hosting volume of this object */
|
||||||
WORD id; /* Hosting volume mount ID */
|
WORD id; /* Hosting volume mount ID */
|
||||||
BYTE attr; /* Object attribute */
|
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) */
|
DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */
|
||||||
FSIZE_t objsize; /* Object size (valid when sclust != 0) */
|
FSIZE_t objsize; /* Object size (valid when sclust != 0) */
|
||||||
#if FF_FS_EXFAT
|
#if FF_FS_EXFAT
|
||||||
@@ -165,6 +168,9 @@ typedef struct {
|
|||||||
/* File object structure (FIL) */
|
/* File object structure (FIL) */
|
||||||
|
|
||||||
typedef struct {
|
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) */
|
FFOBJID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */
|
||||||
BYTE flag; /* File status flags */
|
BYTE flag; /* File status flags */
|
||||||
BYTE err; /* Abort flag (error code) */
|
BYTE err; /* Abort flag (error code) */
|
||||||
@@ -178,9 +184,6 @@ typedef struct {
|
|||||||
#if FF_USE_FASTSEEK
|
#if FF_USE_FASTSEEK
|
||||||
DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */
|
DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */
|
||||||
#endif
|
#endif
|
||||||
#if !FF_FS_TINY
|
|
||||||
BYTE buf[FF_MAX_SS]; /* File private data read/write window */
|
|
||||||
#endif
|
|
||||||
} FIL;
|
} 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_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */
|
||||||
FRESULT f_setlabel (const TCHAR* label); /* Set 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_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_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_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 */
|
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
|
/ Function Configurations
|
||||||
@@ -232,14 +232,14 @@
|
|||||||
|
|
||||||
#define FF_FS_EXFAT 1
|
#define FF_FS_EXFAT 1
|
||||||
/* This option switches support for exFAT filesystem. (0:Disable or 1:Enable)
|
/* 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. */
|
/ Note that enabling exFAT discards ANSI C (C89) compatibility. */
|
||||||
|
|
||||||
|
|
||||||
#define FF_FS_NORTC 1
|
#define FF_FS_NORTC 1
|
||||||
#define FF_NORTC_MON 1
|
#define FF_NORTC_MON 1
|
||||||
#define FF_NORTC_MDAY 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
|
/* 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
|
/ 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
|
/ the timestamp function. Every object modified by FatFs will have a fixed timestamp
|
||||||
@@ -262,6 +262,7 @@
|
|||||||
/ lock control is independent of re-entrancy. */
|
/ lock control is independent of re-entrancy. */
|
||||||
|
|
||||||
|
|
||||||
|
/* #include <somertos.h> // O/S definitions */
|
||||||
#define FF_FS_REENTRANT 0
|
#define FF_FS_REENTRANT 0
|
||||||
#define FF_FS_TIMEOUT 1000
|
#define FF_FS_TIMEOUT 1000
|
||||||
#define FF_SYNC_t HANDLE
|
#define FF_SYNC_t HANDLE
|
||||||
@@ -282,8 +283,6 @@
|
|||||||
/ SemaphoreHandle_t and etc. A header file for O/S definitions needs to be
|
/ SemaphoreHandle_t and etc. A header file for O/S definitions needs to be
|
||||||
/ included somewhere in the scope of ff.h. */
|
/ included somewhere in the scope of ff.h. */
|
||||||
|
|
||||||
/* #include <windows.h> // O/S definitions */
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*--- End of configuration options ---*/
|
/*--- End of configuration options ---*/
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*------------------------------------------------------------------------*/
|
/*------------------------------------------------------------------------*/
|
||||||
/* Sample Code of OS Dependent Functions for FatFs */
|
/* Sample Code of OS Dependent Functions for FatFs */
|
||||||
/* (C) ChaN, 2017 */
|
/* (C) ChaN, 2018 */
|
||||||
/* (C) CTCaer, 2018 */
|
/* (C) CTCaer, 2018 */
|
||||||
/*------------------------------------------------------------------------*/
|
/*------------------------------------------------------------------------*/
|
||||||
|
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
/* Allocate a memory block */
|
/* 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 */
|
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 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 */
|
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 /
|
/* 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 /
|
/ FatFs is configured for LFN with DBCS. If the system has any Unicode /
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
/ that function to avoid silly memory consumption. /
|
/ 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
|
/ FatFs module is an open source software. Redistribution and use of FatFs in
|
||||||
/ source and binary forms, with or without modification, are permitted provided
|
/ source and binary forms, with or without modification, are permitted provided
|
||||||
@@ -25,16 +25,15 @@
|
|||||||
|
|
||||||
#include "ff.h"
|
#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).
|
#error Wrong include file (ff.h).
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define MERGE2(a, b) a ## b
|
#define MERGE2(a, b) a ## b
|
||||||
#define CVTBL(tbl, cp) MERGE2(tbl, cp)
|
#define CVTBL(tbl, cp) MERGE2(tbl, cp)
|
||||||
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
/*------------------------------------------------------------------------*/
|
||||||
/* Code Conversion Tables */
|
/* Code Conversion Tables */
|
||||||
/*------------------------------------------------------------------------*/
|
/*------------------------------------------------------------------------*/
|
||||||
@@ -623,5 +622,4 @@ DWORD ff_wtoupper ( /* Returns up-converted code point */
|
|||||||
return uni;
|
return uni;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif /* #if FF_USE_LFN */
|
#endif /* #if FF_USE_LFN */
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
ENTRY(_start)
|
ENTRY(_start)
|
||||||
|
|
||||||
SECTIONS {
|
SECTIONS {
|
||||||
PROVIDE(__ipl_start = 0x40008000);
|
PROVIDE(__ipl_start = IPL_LOAD_ADDR);
|
||||||
. = __ipl_start;
|
. = __ipl_start;
|
||||||
.text : {
|
.text : {
|
||||||
|
*(.text._start);
|
||||||
|
*(._boot_cfg);
|
||||||
|
*(._ipl_version);
|
||||||
*(.text*);
|
*(.text*);
|
||||||
}
|
}
|
||||||
.data : {
|
.data : {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -107,23 +107,18 @@ void heap_init(u32 base)
|
|||||||
|
|
||||||
void *malloc(u32 size)
|
void *malloc(u32 size)
|
||||||
{
|
{
|
||||||
return (void *)_heap_alloc(&_heap, size, 0x10);
|
return (void *)_heap_alloc(&_heap, size, sizeof(hnode_t));
|
||||||
}
|
|
||||||
|
|
||||||
void *memalign(u32 align, u32 size)
|
|
||||||
{
|
|
||||||
return (void *)_heap_alloc(&_heap, size, align);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void *calloc(u32 num, u32 size)
|
void *calloc(u32 num, u32 size)
|
||||||
{
|
{
|
||||||
void *res = (void *)_heap_alloc(&_heap, num * size, 0x10);
|
void *res = (void *)_heap_alloc(&_heap, num * size, sizeof(hnode_t));
|
||||||
memset(res, 0, num * size);
|
memset(res, 0, num * size);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void free(void *buf)
|
void free(void *buf)
|
||||||
{
|
{
|
||||||
if ((buf != NULL) || ((u32)buf > (_heap.start - 1)))
|
if ((u32)buf >= _heap.start)
|
||||||
_heap_free(&_heap, (u32)buf);
|
_heap_free(&_heap, (u32)buf);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,5 @@ void heap_init(u32 base);
|
|||||||
void *malloc(u32 size);
|
void *malloc(u32 size);
|
||||||
void *calloc(u32 num, u32 size);
|
void *calloc(u32 num, u32 size);
|
||||||
void free(void *buf);
|
void free(void *buf);
|
||||||
void *memalign(u32 align, u32 size);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ void mc_disable_ahb_redirect()
|
|||||||
void mc_enable()
|
void mc_enable()
|
||||||
{
|
{
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) & 0x1FFFFFFF) | 0x40000000;
|
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;
|
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = (CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) & 0xFDFFFFFF) | 0x2000000;
|
||||||
// Enable MC clock.
|
// Enable MC clock.
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = (CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) & 0xFFFFFFFE) | 1;
|
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = (CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) & 0xFFFFFFFE) | 1;
|
||||||
|
|||||||
88
bootloader/mem/minerva.c
Normal file
88
bootloader/mem/minerva.c
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
void minerva_init()
|
||||||
|
{
|
||||||
|
u32 curr_ram_idx = 0;
|
||||||
|
|
||||||
|
mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg;
|
||||||
|
|
||||||
|
// Set table to ram.
|
||||||
|
mtc_cfg->mtc_table = NULL;
|
||||||
|
mtc_cfg->sdram_id = (fuse_read_odm(4) >> 3) & 0x1F;
|
||||||
|
u32 ep_addr = ianos_loader(false, "bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)mtc_cfg);
|
||||||
|
minerva_cfg = (void *)ep_addr;
|
||||||
|
|
||||||
|
if (!minerva_cfg)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
void minerva_change_freq(minerva_freq_t freq)
|
||||||
|
{
|
||||||
|
if (!minerva_cfg)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg;
|
||||||
|
if (minerva_cfg && (mtc_cfg->rate_from != freq))
|
||||||
|
{
|
||||||
|
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 (minerva_cfg && mtc_cfg->rate_from == FREQ_1600)
|
||||||
|
{
|
||||||
|
mtc_cfg->train_mode = OP_PERIODIC_TRAIN;
|
||||||
|
minerva_cfg(mtc_cfg, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
61
bootloader/mem/minerva.h
Normal file
61
bootloader/mem/minerva.h
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* 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 EMC_PERIODIC_TRAIN_MS 100
|
||||||
|
|
||||||
|
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;
|
||||||
|
} 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 *);
|
||||||
|
void 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,5 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
|
* Copyright (c) 2018 balika011
|
||||||
|
* Copyright (c) 2019 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -23,6 +25,7 @@
|
|||||||
#include "../utils/util.h"
|
#include "../utils/util.h"
|
||||||
#include "../soc/fuse.h"
|
#include "../soc/fuse.h"
|
||||||
#include "../power/max77620.h"
|
#include "../power/max77620.h"
|
||||||
|
#include "../power/max7762x.h"
|
||||||
#include "../soc/clock.h"
|
#include "../soc/clock.h"
|
||||||
|
|
||||||
#define CONFIG_SDRAM_COMPRESS_CFG
|
#define CONFIG_SDRAM_COMPRESS_CFG
|
||||||
@@ -36,7 +39,13 @@
|
|||||||
|
|
||||||
static u32 _get_sdram_id()
|
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)
|
static void _sdram_config(const sdram_params_t *params)
|
||||||
@@ -536,7 +545,7 @@ void sdram_init()
|
|||||||
const sdram_params_t *params = (const sdram_params_t *)sdram_get_params();
|
const sdram_params_t *params = (const sdram_params_t *)sdram_get_params();
|
||||||
|
|
||||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD_CFG2, 0x05);
|
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD_CFG2, 0x05);
|
||||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD1, 40); //40 = (1000 * 1100 - 600000) / 12500 -> 1.1V
|
max77620_regulator_set_voltage(REGULATOR_SD1, 1100000); // Set DRAM voltage.
|
||||||
|
|
||||||
PMC(APBDEV_PMC_VDDP_SEL) = params->pmc_vddp_sel;
|
PMC(APBDEV_PMC_VDDP_SEL) = params->pmc_vddp_sel;
|
||||||
usleep(params->pmc_vddp_sel_wait);
|
usleep(params->pmc_vddp_sel_wait);
|
||||||
|
|||||||
@@ -20,6 +20,9 @@
|
|||||||
#include "../soc/i2c.h"
|
#include "../soc/i2c.h"
|
||||||
#include "../utils/util.h"
|
#include "../utils/util.h"
|
||||||
|
|
||||||
|
#pragma GCC push_options
|
||||||
|
#pragma GCC optimize ("Os")
|
||||||
|
|
||||||
int bq24193_get_property(enum BQ24193_reg_prop prop, int *value)
|
int bq24193_get_property(enum BQ24193_reg_prop prop, int *value)
|
||||||
{
|
{
|
||||||
u8 data;
|
u8 data;
|
||||||
@@ -160,3 +163,5 @@ void bq24193_fake_battery_removal()
|
|||||||
value |= BQ24193_MISC_BATFET_DI_MASK;
|
value |= BQ24193_MISC_BATFET_DI_MASK;
|
||||||
i2c_send_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_Misc, value);
|
i2c_send_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_Misc, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma GCC pop_options
|
||||||
|
|||||||
@@ -43,6 +43,9 @@
|
|||||||
|
|
||||||
#define MAX17050_VMAX_TOLERANCE 50 /* 50 mV */
|
#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)
|
int max17050_get_property(enum MAX17050_reg reg, int *value)
|
||||||
{
|
{
|
||||||
u16 data;
|
u16 data;
|
||||||
@@ -264,3 +267,5 @@ int max17050_fix_configuration()
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma GCC pop_options
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
* Defining registers address and its bit definitions of MAX77620 and MAX20024
|
* 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
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -15,20 +16,68 @@
|
|||||||
|
|
||||||
/* GLOBAL, PMIC, GPIO, FPS, ONOFFC, CID Registers */
|
/* GLOBAL, PMIC, GPIO, FPS, ONOFFC, CID Registers */
|
||||||
#define MAX77620_REG_CNFGGLBL1 0x00
|
#define MAX77620_REG_CNFGGLBL1 0x00
|
||||||
|
#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_LBRSTEN (1 << 0)
|
||||||
|
|
||||||
#define MAX77620_REG_CNFGGLBL2 0x01
|
#define MAX77620_REG_CNFGGLBL2 0x01
|
||||||
#define MAX77620_REG_CNFGGLBL3 0x02
|
#define MAX77620_REG_CNFGGLBL3 0x02
|
||||||
|
#define MAX77620_WDTC_MASK 0x3
|
||||||
|
#define MAX77620_WDTOFFC (1 << 4)
|
||||||
|
#define MAX77620_WDTSLPC (1 << 3)
|
||||||
|
#define MAX77620_WDTEN (1 << 2)
|
||||||
|
#define MAX77620_TWD_MASK 0x3
|
||||||
|
#define MAX77620_TWD_2s 0x0
|
||||||
|
#define MAX77620_TWD_16s 0x1
|
||||||
|
#define MAX77620_TWD_64s 0x2
|
||||||
|
#define MAX77620_TWD_128s 0x3
|
||||||
|
|
||||||
#define MAX77620_REG_CNFG1_32K 0x03
|
#define MAX77620_REG_CNFG1_32K 0x03
|
||||||
|
#define MAX77620_CNFG1_32K_OUT0_EN (1 << 2)
|
||||||
|
|
||||||
#define MAX77620_REG_CNFGBBC 0x04
|
#define MAX77620_REG_CNFGBBC 0x04
|
||||||
|
#define MAX77620_CNFGBBC_ENABLE (1 << 0)
|
||||||
|
#define MAX77620_CNFGBBC_CURRENT_MASK 0x06
|
||||||
|
#define MAX77620_CNFGBBC_CURRENT_SHIFT 1
|
||||||
|
#define MAX77620_CNFGBBC_VOLTAGE_MASK 0x18
|
||||||
|
#define MAX77620_CNFGBBC_VOLTAGE_SHIFT 3
|
||||||
|
#define MAX77620_CNFGBBC_LOW_CURRENT_DISABLE (1 << 5)
|
||||||
|
#define MAX77620_CNFGBBC_RESISTOR_MASK 0xC0
|
||||||
|
#define MAX77620_CNFGBBC_RESISTOR_SHIFT 6
|
||||||
|
#define MAX77620_CNFGBBC_RESISTOR_100 (0 << MAX77620_CNFGBBC_RESISTOR_SHIFT)
|
||||||
|
#define MAX77620_CNFGBBC_RESISTOR_1K (1 << MAX77620_CNFGBBC_RESISTOR_SHIFT)
|
||||||
|
#define MAX77620_CNFGBBC_RESISTOR_3K (2 << MAX77620_CNFGBBC_RESISTOR_SHIFT)
|
||||||
|
#define MAX77620_CNFGBBC_RESISTOR_6K (3 << MAX77620_CNFGBBC_RESISTOR_SHIFT)
|
||||||
|
|
||||||
#define MAX77620_REG_IRQTOP 0x05
|
#define MAX77620_REG_IRQTOP 0x05
|
||||||
|
#define MAX77620_IRQ_TOP_GLBL_MASK (1 << 7)
|
||||||
|
#define MAX77620_IRQ_TOP_SD_MASK (1 << 6)
|
||||||
|
#define MAX77620_IRQ_TOP_LDO_MASK (1 << 5)
|
||||||
|
#define MAX77620_IRQ_TOP_GPIO_MASK (1 << 4)
|
||||||
|
#define MAX77620_IRQ_TOP_RTC_MASK (1 << 3)
|
||||||
|
#define MAX77620_IRQ_TOP_32K_MASK (1 << 2)
|
||||||
|
#define MAX77620_IRQ_TOP_ONOFF_MASK (1 << 1)
|
||||||
|
|
||||||
#define MAX77620_REG_INTLBT 0x06
|
#define MAX77620_REG_INTLBT 0x06
|
||||||
|
#define MAX77620_REG_IRQTOPM 0x0D
|
||||||
|
#define MAX77620_IRQ_LBM_MASK (1 << 3)
|
||||||
|
#define MAX77620_IRQ_TJALRM1_MASK (1 << 2)
|
||||||
|
#define MAX77620_IRQ_TJALRM2_MASK (1 << 1)
|
||||||
|
|
||||||
#define MAX77620_REG_IRQSD 0x07
|
#define MAX77620_REG_IRQSD 0x07
|
||||||
#define MAX77620_REG_IRQ_LVL2_L0_7 0x08
|
#define MAX77620_REG_IRQ_LVL2_L0_7 0x08
|
||||||
#define MAX77620_REG_IRQ_LVL2_L8 0x09
|
#define MAX77620_REG_IRQ_LVL2_L8 0x09
|
||||||
#define MAX77620_REG_IRQ_LVL2_GPIO 0x0A
|
#define MAX77620_REG_IRQ_LVL2_GPIO 0x0A
|
||||||
#define MAX77620_REG_ONOFFIRQ 0x0B
|
#define MAX77620_REG_ONOFFIRQ 0x0B
|
||||||
#define MAX77620_REG_NVERC 0x0C
|
#define MAX77620_REG_NVERC 0x0C
|
||||||
#define MAX77620_REG_IRQTOPM 0x0D
|
|
||||||
#define MAX77620_REG_INTENLBT 0x0E
|
#define MAX77620_REG_INTENLBT 0x0E
|
||||||
|
#define MAX77620_GLBLM_MASK (1 << 0)
|
||||||
|
|
||||||
#define MAX77620_REG_IRQMASKSD 0x0F
|
#define MAX77620_REG_IRQMASKSD 0x0F
|
||||||
#define MAX77620_REG_IRQ_MSK_L0_7 0x10
|
#define MAX77620_REG_IRQ_MSK_L0_7 0x10
|
||||||
#define MAX77620_REG_IRQ_MSK_L8 0x11
|
#define MAX77620_REG_IRQ_MSK_L8 0x11
|
||||||
@@ -43,6 +92,10 @@
|
|||||||
#define MAX77620_REG_SD2 0x18
|
#define MAX77620_REG_SD2 0x18
|
||||||
#define MAX77620_REG_SD3 0x19
|
#define MAX77620_REG_SD3 0x19
|
||||||
#define MAX77620_REG_SD4 0x1A
|
#define MAX77620_REG_SD4 0x1A
|
||||||
|
#define MAX77620_SDX_VOLT_MASK 0xFF
|
||||||
|
#define MAX77620_SD0_VOLT_MASK 0x3F
|
||||||
|
#define MAX77620_SD1_VOLT_MASK 0x7F
|
||||||
|
#define MAX77620_LDO_VOLT_MASK 0x3F
|
||||||
#define MAX77620_REG_DVSSD0 0x1B
|
#define MAX77620_REG_DVSSD0 0x1B
|
||||||
#define MAX77620_REG_DVSSD1 0x1C
|
#define MAX77620_REG_DVSSD1 0x1C
|
||||||
#define MAX77620_REG_SD0_CFG 0x1D
|
#define MAX77620_REG_SD0_CFG 0x1D
|
||||||
@@ -69,19 +122,25 @@
|
|||||||
#define MAX77620_REG_LDO7_CFG2 0x32
|
#define MAX77620_REG_LDO7_CFG2 0x32
|
||||||
#define MAX77620_REG_LDO8_CFG 0x33
|
#define MAX77620_REG_LDO8_CFG 0x33
|
||||||
#define MAX77620_REG_LDO8_CFG2 0x34
|
#define MAX77620_REG_LDO8_CFG2 0x34
|
||||||
|
#define MAX77620_LDO_POWER_MODE_MASK 0xC0
|
||||||
|
#define MAX77620_LDO_POWER_MODE_SHIFT 6
|
||||||
|
#define MAX77620_POWER_MODE_NORMAL 3
|
||||||
|
#define MAX77620_POWER_MODE_LPM 2
|
||||||
|
#define MAX77620_POWER_MODE_GLPM 1
|
||||||
|
#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 << 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)
|
||||||
|
#define MAX77620_LDO_CFG2_SS_SLOW 0
|
||||||
|
|
||||||
#define MAX77620_REG_LDO_CFG3 0x35
|
#define MAX77620_REG_LDO_CFG3 0x35
|
||||||
|
|
||||||
#define MAX77620_LDO_SLEW_RATE_MASK 0x1
|
|
||||||
|
|
||||||
/* LDO Configuration 3 */
|
|
||||||
#define MAX77620_TRACK4_MASK (1 << 5)
|
#define MAX77620_TRACK4_MASK (1 << 5)
|
||||||
#define MAX77620_TRACK4_SHIFT 5
|
#define MAX77620_TRACK4_SHIFT 5
|
||||||
|
|
||||||
/* Voltage */
|
#define MAX77620_LDO_SLEW_RATE_MASK 0x1
|
||||||
#define MAX77620_SDX_VOLT_MASK 0xFF
|
|
||||||
#define MAX77620_SD0_VOLT_MASK 0x3F
|
|
||||||
#define MAX77620_SD1_VOLT_MASK 0x7F
|
|
||||||
#define MAX77620_LDO_VOLT_MASK 0x3F
|
|
||||||
|
|
||||||
#define MAX77620_REG_GPIO0 0x36
|
#define MAX77620_REG_GPIO0 0x36
|
||||||
#define MAX77620_REG_GPIO1 0x37
|
#define MAX77620_REG_GPIO1 0x37
|
||||||
@@ -94,8 +153,39 @@
|
|||||||
#define MAX77620_REG_PUE_GPIO 0x3E
|
#define MAX77620_REG_PUE_GPIO 0x3E
|
||||||
#define MAX77620_REG_PDE_GPIO 0x3F
|
#define MAX77620_REG_PDE_GPIO 0x3F
|
||||||
#define MAX77620_REG_AME_GPIO 0x40
|
#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_REG_ONOFFCNFG1 0x41
|
||||||
|
#define MAX77620_ONOFFCNFG1_SFT_RST (1 << 7)
|
||||||
|
#define MAX77620_ONOFFCNFG1_MRT_MASK 0x38
|
||||||
|
#define MAX77620_ONOFFCNFG1_MRT_SHIFT 0x3
|
||||||
|
#define MAX77620_ONOFFCNFG1_SLPEN (1 << 2)
|
||||||
|
#define MAX77620_ONOFFCNFG1_PWR_OFF (1 << 1)
|
||||||
|
#define MAX20024_ONOFFCNFG1_CLRSE 0x18
|
||||||
|
|
||||||
#define MAX77620_REG_ONOFFCNFG2 0x42
|
#define MAX77620_REG_ONOFFCNFG2 0x42
|
||||||
|
#define MAX77620_ONOFFCNFG2_SFT_RST_WK (1 << 7)
|
||||||
|
#define MAX77620_ONOFFCNFG2_WD_RST_WK (1 << 6)
|
||||||
|
#define MAX77620_ONOFFCNFG2_SLP_LPM_MSK (1 << 5)
|
||||||
|
#define MAX77620_ONOFFCNFG2_WK_ALARM1 (1 << 2)
|
||||||
|
#define MAX77620_ONOFFCNFG2_WK_EN0 (1 << 0)
|
||||||
|
|
||||||
/* FPS Registers */
|
/* FPS Registers */
|
||||||
#define MAX77620_REG_FPS_CFG0 0x43
|
#define MAX77620_REG_FPS_CFG0 0x43
|
||||||
@@ -116,23 +206,18 @@
|
|||||||
#define MAX77620_REG_FPS_SD3 0x52
|
#define MAX77620_REG_FPS_SD3 0x52
|
||||||
#define MAX77620_REG_FPS_SD4 0x53
|
#define MAX77620_REG_FPS_SD4 0x53
|
||||||
#define MAX77620_REG_FPS_NONE 0
|
#define MAX77620_REG_FPS_NONE 0
|
||||||
|
|
||||||
#define MAX77620_FPS_SRC_MASK 0xC0
|
#define MAX77620_FPS_SRC_MASK 0xC0
|
||||||
#define MAX77620_FPS_SRC_SHIFT 6
|
#define MAX77620_FPS_SRC_SHIFT 6
|
||||||
#define MAX77620_FPS_PU_PERIOD_MASK 0x38
|
#define MAX77620_FPS_PU_PERIOD_MASK 0x38
|
||||||
#define MAX77620_FPS_PU_PERIOD_SHIFT 3
|
#define MAX77620_FPS_PU_PERIOD_SHIFT 3
|
||||||
#define MAX77620_FPS_PD_PERIOD_MASK 0x07
|
#define MAX77620_FPS_PD_PERIOD_MASK 0x07
|
||||||
#define MAX77620_FPS_PD_PERIOD_SHIFT 0
|
#define MAX77620_FPS_PD_PERIOD_SHIFT 0
|
||||||
#define MAX77620_FPS_TIME_PERIOD_MASK 0x38
|
|
||||||
#define MAX77620_FPS_TIME_PERIOD_SHIFT 3
|
|
||||||
#define MAX77620_FPS_EN_SRC_MASK 0x06
|
|
||||||
#define MAX77620_FPS_EN_SRC_SHIFT 1
|
|
||||||
#define MAX77620_FPS_ENFPS_SW_MASK 0x01
|
|
||||||
#define MAX77620_FPS_ENFPS_SW 0x01
|
|
||||||
|
|
||||||
/* Minimum and maximum FPS period time (in microseconds) are
|
/* Minimum and maximum FPS period time (in microseconds) are
|
||||||
* different for MAX77620 and Max20024.
|
* different for MAX77620 and Max20024.
|
||||||
*/
|
*/
|
||||||
|
#define MAX77620_FPS_COUNT 3
|
||||||
|
|
||||||
#define MAX77620_FPS_PERIOD_MIN_US 40
|
#define MAX77620_FPS_PERIOD_MIN_US 40
|
||||||
#define MAX20024_FPS_PERIOD_MIN_US 20
|
#define MAX20024_FPS_PERIOD_MIN_US 20
|
||||||
|
|
||||||
@@ -142,6 +227,13 @@
|
|||||||
#define MAX77620_REG_FPS_GPIO1 0x54
|
#define MAX77620_REG_FPS_GPIO1 0x54
|
||||||
#define MAX77620_REG_FPS_GPIO2 0x55
|
#define MAX77620_REG_FPS_GPIO2 0x55
|
||||||
#define MAX77620_REG_FPS_GPIO3 0x56
|
#define MAX77620_REG_FPS_GPIO3 0x56
|
||||||
|
#define MAX77620_FPS_TIME_PERIOD_MASK 0x38
|
||||||
|
#define MAX77620_FPS_TIME_PERIOD_SHIFT 3
|
||||||
|
#define MAX77620_FPS_EN_SRC_MASK 0x06
|
||||||
|
#define MAX77620_FPS_EN_SRC_SHIFT 1
|
||||||
|
#define MAX77620_FPS_ENFPS_SW_MASK 0x01
|
||||||
|
#define MAX77620_FPS_ENFPS_SW 0x01
|
||||||
|
|
||||||
#define MAX77620_REG_FPS_RSO 0x57
|
#define MAX77620_REG_FPS_RSO 0x57
|
||||||
#define MAX77620_REG_CID0 0x58
|
#define MAX77620_REG_CID0 0x58
|
||||||
#define MAX77620_REG_CID1 0x59
|
#define MAX77620_REG_CID1 0x59
|
||||||
@@ -185,48 +277,6 @@
|
|||||||
#define MAX77620_SD_CFG1_FSRADE_SD_DISABLE 0
|
#define MAX77620_SD_CFG1_FSRADE_SD_DISABLE 0
|
||||||
#define MAX77620_SD_CFG1_FSRADE_SD_ENABLE (1 << 0)
|
#define MAX77620_SD_CFG1_FSRADE_SD_ENABLE (1 << 0)
|
||||||
|
|
||||||
/* LDO_CNFG2 */
|
|
||||||
#define MAX77620_LDO_POWER_MODE_MASK 0xC0
|
|
||||||
#define MAX77620_LDO_POWER_MODE_SHIFT 6
|
|
||||||
#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_ENABLE (1 << 1)
|
|
||||||
#define MAX77620_LDO_CFG2_SS_MASK (1 << 0)
|
|
||||||
#define MAX77620_LDO_CFG2_SS_FAST (1 << 0)
|
|
||||||
#define MAX77620_LDO_CFG2_SS_SLOW 0
|
|
||||||
|
|
||||||
#define MAX77620_IRQ_TOP_GLBL_MASK (1 << 7)
|
|
||||||
#define MAX77620_IRQ_TOP_SD_MASK (1 << 6)
|
|
||||||
#define MAX77620_IRQ_TOP_LDO_MASK (1 << 5)
|
|
||||||
#define MAX77620_IRQ_TOP_GPIO_MASK (1 << 4)
|
|
||||||
#define MAX77620_IRQ_TOP_RTC_MASK (1 << 3)
|
|
||||||
#define MAX77620_IRQ_TOP_32K_MASK (1 << 2)
|
|
||||||
#define MAX77620_IRQ_TOP_ONOFF_MASK (1 << 1)
|
|
||||||
|
|
||||||
#define MAX77620_IRQ_LBM_MASK (1 << 3)
|
|
||||||
#define MAX77620_IRQ_TJALRM1_MASK (1 << 2)
|
|
||||||
#define MAX77620_IRQ_TJALRM2_MASK (1 << 1)
|
|
||||||
|
|
||||||
#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_EDGE0 (1 << 0)
|
||||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE1 (1 << 1)
|
#define MAX77620_IRQ_LVL2_GPIO_EDGE1 (1 << 1)
|
||||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE2 (1 << 2)
|
#define MAX77620_IRQ_LVL2_GPIO_EDGE2 (1 << 2)
|
||||||
@@ -236,54 +286,6 @@
|
|||||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE6 (1 << 6)
|
#define MAX77620_IRQ_LVL2_GPIO_EDGE6 (1 << 6)
|
||||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE7 (1 << 7)
|
#define MAX77620_IRQ_LVL2_GPIO_EDGE7 (1 << 7)
|
||||||
|
|
||||||
#define MAX77620_CNFG1_32K_OUT0_EN (1 << 2)
|
|
||||||
|
|
||||||
#define MAX77620_ONOFFCNFG1_SFT_RST (1 << 7)
|
|
||||||
#define MAX77620_ONOFFCNFG1_MRT_MASK 0x38
|
|
||||||
#define MAX77620_ONOFFCNFG1_MRT_SHIFT 0x3
|
|
||||||
#define MAX77620_ONOFFCNFG1_SLPEN (1 << 2)
|
|
||||||
#define MAX77620_ONOFFCNFG1_PWR_OFF (1 << 1)
|
|
||||||
#define MAX20024_ONOFFCNFG1_CLRSE 0x18
|
|
||||||
|
|
||||||
#define MAX77620_ONOFFCNFG2_SFT_RST_WK (1 << 7)
|
|
||||||
#define MAX77620_ONOFFCNFG2_WD_RST_WK (1 << 6)
|
|
||||||
#define MAX77620_ONOFFCNFG2_SLP_LPM_MSK (1 << 5)
|
|
||||||
#define MAX77620_ONOFFCNFG2_WK_ALARM1 (1 << 2)
|
|
||||||
#define MAX77620_ONOFFCNFG2_WK_EN0 (1 << 0)
|
|
||||||
|
|
||||||
#define MAX77620_GLBLM_MASK (1 << 0)
|
|
||||||
|
|
||||||
#define MAX77620_WDTC_MASK 0x3
|
|
||||||
#define MAX77620_WDTOFFC (1 << 4)
|
|
||||||
#define MAX77620_WDTSLPC (1 << 3)
|
|
||||||
#define MAX77620_WDTEN (1 << 2)
|
|
||||||
|
|
||||||
#define MAX77620_TWD_MASK 0x3
|
|
||||||
#define MAX77620_TWD_2s 0x0
|
|
||||||
#define MAX77620_TWD_16s 0x1
|
|
||||||
#define MAX77620_TWD_64s 0x2
|
|
||||||
#define MAX77620_TWD_128s 0x3
|
|
||||||
|
|
||||||
#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_LBRSTEN (1 << 0)
|
|
||||||
|
|
||||||
/* CNFG BBC registers */
|
|
||||||
#define MAX77620_CNFGBBC_ENABLE (1 << 0)
|
|
||||||
#define MAX77620_CNFGBBC_CURRENT_MASK 0x06
|
|
||||||
#define MAX77620_CNFGBBC_CURRENT_SHIFT 1
|
|
||||||
#define MAX77620_CNFGBBC_VOLTAGE_MASK 0x18
|
|
||||||
#define MAX77620_CNFGBBC_VOLTAGE_SHIFT 3
|
|
||||||
#define MAX77620_CNFGBBC_LOW_CURRENT_DISABLE (1 << 5)
|
|
||||||
#define MAX77620_CNFGBBC_RESISTOR_MASK 0xC0
|
|
||||||
#define MAX77620_CNFGBBC_RESISTOR_SHIFT 6
|
|
||||||
|
|
||||||
#define MAX77620_FPS_COUNT 3
|
|
||||||
|
|
||||||
/* Interrupts */
|
/* Interrupts */
|
||||||
enum {
|
enum {
|
||||||
MAX77620_IRQ_TOP_GLBL, /* Low-Battery */
|
MAX77620_IRQ_TOP_GLBL, /* Low-Battery */
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
|
* Copyright (c) 2019 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -27,12 +28,15 @@ typedef struct _max77620_regulator_t
|
|||||||
u8 type;
|
u8 type;
|
||||||
const char *name;
|
const char *name;
|
||||||
u8 reg_sd;
|
u8 reg_sd;
|
||||||
|
|
||||||
u32 mv_step;
|
u32 mv_step;
|
||||||
u32 mv_min;
|
u32 mv_min;
|
||||||
u32 mv_default;
|
u32 mv_default;
|
||||||
u32 mv_max;
|
u32 mv_max;
|
||||||
|
|
||||||
u8 volt_addr;
|
u8 volt_addr;
|
||||||
u8 cfg_addr;
|
u8 cfg_addr;
|
||||||
|
|
||||||
u8 volt_mask;
|
u8 volt_mask;
|
||||||
u8 enable_mask;
|
u8 enable_mask;
|
||||||
u8 enable_shift;
|
u8 enable_shift;
|
||||||
@@ -45,19 +49,19 @@ typedef struct _max77620_regulator_t
|
|||||||
} max77620_regulator_t;
|
} max77620_regulator_t;
|
||||||
|
|
||||||
static const max77620_regulator_t _pmic_regulators[] = {
|
static const max77620_regulator_t _pmic_regulators[] = {
|
||||||
{ REGULATOR_SD, "sd0", 0x16, 12500, 600000, 625000, 1400000, MAX77620_REG_SD0, MAX77620_REG_SD0_CFG, 0x3F, 0x30, 4, 0x80, 0x4F, 1, 7, 1 },
|
{ REGULATOR_SD, "sd0", 0x16, 12500, 600000, 625000, 1400000, MAX77620_REG_SD0, MAX77620_REG_SD0_CFG, MAX77620_SD0_VOLT_MASK, MAX77620_SD_POWER_MODE_MASK, MAX77620_SD_POWER_MODE_SHIFT, 0x80, MAX77620_REG_FPS_SD0, 1, 7, 1 },
|
||||||
{ REGULATOR_SD, "sd1", 0x17, 12500, 600000, 1125000, 1125000, MAX77620_REG_SD1, MAX77620_REG_SD1_CFG, 0x3F, 0x30, 4, 0x40, 0x50, 0, 1, 5 },
|
{ REGULATOR_SD, "sd1", 0x17, 12500, 600000, 1125000, 1125000, MAX77620_REG_SD1, MAX77620_REG_SD1_CFG, MAX77620_SD1_VOLT_MASK, MAX77620_SD_POWER_MODE_MASK, MAX77620_SD_POWER_MODE_SHIFT, 0x40, MAX77620_REG_FPS_SD1, 0, 1, 5 },
|
||||||
{ REGULATOR_SD, "sd2", 0x18, 12500, 600000, 1325000, 1350000, MAX77620_REG_SD2, MAX77620_REG_SD2_CFG, 0xFF, 0x30, 4, 0x20, 0x51, 1, 5, 2 },
|
{ REGULATOR_SD, "sd2", 0x18, 12500, 600000, 1325000, 1350000, MAX77620_REG_SD2, MAX77620_REG_SD2_CFG, MAX77620_SDX_VOLT_MASK, MAX77620_SD_POWER_MODE_MASK, MAX77620_SD_POWER_MODE_SHIFT, 0x20, MAX77620_REG_FPS_SD2, 1, 5, 2 },
|
||||||
{ REGULATOR_SD, "sd3", 0x19, 12500, 600000, 1800000, 1800000, MAX77620_REG_SD3, MAX77620_REG_SD3_CFG, 0xFF, 0x30, 4, 0x10, 0x52, 0, 3, 3 },
|
{ REGULATOR_SD, "sd3", 0x19, 12500, 600000, 1800000, 1800000, MAX77620_REG_SD3, MAX77620_REG_SD3_CFG, MAX77620_SDX_VOLT_MASK, MAX77620_SD_POWER_MODE_MASK, MAX77620_SD_POWER_MODE_SHIFT, 0x10, MAX77620_REG_FPS_SD3, 0, 3, 3 },
|
||||||
{ REGULATOR_LDO, "ldo0", 0x00, 25000, 800000, 1200000, 1200000, MAX77620_REG_LDO0_CFG, MAX77620_REG_LDO0_CFG2, 0x3F, 0xC0, 6, 0x00, 0x46, 3, 7, 0 },
|
{ REGULATOR_LDO, "ldo0", 0x00, 25000, 800000, 1200000, 1200000, MAX77620_REG_LDO0_CFG, MAX77620_REG_LDO0_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO0, 3, 7, 0 },
|
||||||
{ REGULATOR_LDO, "ldo1", 0x00, 25000, 800000, 1050000, 1050000, MAX77620_REG_LDO1_CFG, MAX77620_REG_LDO1_CFG2, 0x3F, 0xC0, 6, 0x00, 0x47, 3, 7, 0 },
|
{ REGULATOR_LDO, "ldo1", 0x00, 25000, 800000, 1050000, 1050000, MAX77620_REG_LDO1_CFG, MAX77620_REG_LDO1_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO1, 3, 7, 0 },
|
||||||
{ REGULATOR_LDO, "ldo2", 0x00, 50000, 800000, 1800000, 3300000, MAX77620_REG_LDO2_CFG, MAX77620_REG_LDO2_CFG2, 0x3F, 0xC0, 6, 0x00, 0x48, 3, 7, 0 },
|
{ REGULATOR_LDO, "ldo2", 0x00, 50000, 800000, 1800000, 3300000, MAX77620_REG_LDO2_CFG, MAX77620_REG_LDO2_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO2, 3, 7, 0 },
|
||||||
{ REGULATOR_LDO, "ldo3", 0x00, 50000, 800000, 3100000, 3100000, MAX77620_REG_LDO3_CFG, MAX77620_REG_LDO3_CFG2, 0x3F, 0xC0, 6, 0x00, 0x49, 3, 7, 0 },
|
{ REGULATOR_LDO, "ldo3", 0x00, 50000, 800000, 3100000, 3100000, MAX77620_REG_LDO3_CFG, MAX77620_REG_LDO3_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO3, 3, 7, 0 },
|
||||||
{ REGULATOR_LDO, "ldo4", 0x00, 12500, 800000, 850000, 850000, MAX77620_REG_LDO4_CFG, MAX77620_REG_LDO4_CFG2, 0x3F, 0xC0, 6, 0x00, 0x4A, 0, 7, 1 },
|
{ REGULATOR_LDO, "ldo4", 0x00, 12500, 800000, 850000, 850000, MAX77620_REG_LDO4_CFG, MAX77620_REG_LDO4_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO4, 0, 7, 1 },
|
||||||
{ REGULATOR_LDO, "ldo5", 0x00, 50000, 800000, 1800000, 1800000, MAX77620_REG_LDO5_CFG, MAX77620_REG_LDO5_CFG2, 0x3F, 0xC0, 6, 0x00, 0x4B, 3, 7, 0 },
|
{ REGULATOR_LDO, "ldo5", 0x00, 50000, 800000, 1800000, 1800000, MAX77620_REG_LDO5_CFG, MAX77620_REG_LDO5_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO5, 3, 7, 0 },
|
||||||
{ REGULATOR_LDO, "ldo6", 0x00, 50000, 800000, 2900000, 2900000, MAX77620_REG_LDO6_CFG, MAX77620_REG_LDO6_CFG2, 0x3F, 0xC0, 6, 0x00, 0x4C, 3, 7, 0 },
|
{ REGULATOR_LDO, "ldo6", 0x00, 50000, 800000, 2900000, 2900000, MAX77620_REG_LDO6_CFG, MAX77620_REG_LDO6_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO6, 3, 7, 0 },
|
||||||
{ REGULATOR_LDO, "ldo7", 0x00, 50000, 800000, 1050000, 1050000, MAX77620_REG_LDO7_CFG, MAX77620_REG_LDO7_CFG2, 0x3F, 0xC0, 6, 0x00, 0x4D, 1, 4, 3 },
|
{ REGULATOR_LDO, "ldo7", 0x00, 50000, 800000, 1050000, 1050000, MAX77620_REG_LDO7_CFG, MAX77620_REG_LDO7_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO7, 1, 4, 3 },
|
||||||
{ REGULATOR_LDO, "ldo8", 0x00, 50000, 800000, 1050000, 1050000, MAX77620_REG_LDO8_CFG, MAX77620_REG_LDO8_CFG2, 0x3F, 0xC0, 6, 0x00, 0x4E, 3, 7, 0 }
|
{ 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 }
|
||||||
};
|
};
|
||||||
|
|
||||||
int max77620_regulator_get_status(u32 id)
|
int max77620_regulator_get_status(u32 id)
|
||||||
@@ -79,7 +83,8 @@ int max77620_regulator_config_fps(u32 id)
|
|||||||
|
|
||||||
const max77620_regulator_t *reg = &_pmic_regulators[id];
|
const max77620_regulator_t *reg = &_pmic_regulators[id];
|
||||||
|
|
||||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, reg->fps_addr, (reg->fps_src << 6) | (reg->pu_period << 3) | (reg->pd_period));
|
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, reg->fps_addr,
|
||||||
|
(reg->fps_src << MAX77620_FPS_SRC_SHIFT) | (reg->pu_period << MAX77620_FPS_PU_PERIOD_SHIFT) | (reg->pd_period));
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -91,7 +96,7 @@ int max77620_regulator_set_voltage(u32 id, u32 mv)
|
|||||||
|
|
||||||
const max77620_regulator_t *reg = &_pmic_regulators[id];
|
const max77620_regulator_t *reg = &_pmic_regulators[id];
|
||||||
|
|
||||||
if (mv < reg->mv_default || mv > reg->mv_max)
|
if (mv < reg->mv_min || mv > reg->mv_max)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
u32 mult = (mv + reg->mv_step - 1 - reg->mv_min) / reg->mv_step;
|
u32 mult = (mv + reg->mv_step - 1 - reg->mv_min) / reg->mv_step;
|
||||||
@@ -113,7 +118,7 @@ int max77620_regulator_enable(u32 id, int enable)
|
|||||||
u32 addr = reg->type == REGULATOR_SD ? reg->cfg_addr : reg->volt_addr;
|
u32 addr = reg->type == REGULATOR_SD ? reg->cfg_addr : reg->volt_addr;
|
||||||
u8 val = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, addr);
|
u8 val = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, addr);
|
||||||
if (enable)
|
if (enable)
|
||||||
val = (val & ~reg->enable_mask) | ((3 << reg->enable_shift) & reg->enable_mask);
|
val = (val & ~reg->enable_mask) | ((MAX77620_POWER_MODE_NORMAL << reg->enable_shift) & reg->enable_mask);
|
||||||
else
|
else
|
||||||
val &= ~reg->enable_mask;
|
val &= ~reg->enable_mask;
|
||||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, addr, val);
|
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, addr, val);
|
||||||
@@ -122,6 +127,24 @@ int max77620_regulator_enable(u32 id, int enable)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int max77620_regulator_set_volt_and_flags(u32 id, u32 mv, u8 flags)
|
||||||
|
{
|
||||||
|
if (id > REGULATOR_MAX)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
const max77620_regulator_t *reg = &_pmic_regulators[id];
|
||||||
|
|
||||||
|
if (mv < reg->mv_min || mv > reg->mv_max)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
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);
|
||||||
|
usleep(1000);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
void max77620_config_default()
|
void max77620_config_default()
|
||||||
{
|
{
|
||||||
for (u32 i = 1; i <= REGULATOR_MAX; i++)
|
for (u32 i = 1; i <= REGULATOR_MAX; i++)
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
|
* Copyright (c) 2019 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -23,17 +24,17 @@
|
|||||||
* Switch Power domains (max77620):
|
* Switch Power domains (max77620):
|
||||||
* Name | Usage | uV step | uV min | uV default | uV max | Init
|
* 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)
|
* sd1 | SDRAM | 12500 | 600000 | 1125000 | 1125000 | 1.1V (pkg1.1)
|
||||||
* sd2 | ldo{0-1, 7-8} | 12500 | 600000 | 1325000 | 1350000 | 1.325V (pcv)
|
* sd2 | ldo{0-1, 7-8} | 12500 | 600000 | 1325000 | 1350000 | 1.325V (pcv)
|
||||||
* sd3 | 1.8V general | 12500 | 600000 | 1800000 | 1800000 |
|
* sd3 | 1.8V general | 12500 | 600000 | 1800000 | 1800000 |
|
||||||
* ldo0 | Display Panel | 25000 | 800000 | 1200000 | 1200000 | 1.2V (pkg1.1)
|
* ldo0 | Display Panel | 25000 | 800000 | 1200000 | 1200000 | 1.2V (pkg1.1)
|
||||||
* ldo1 | XUSB, PCIE | 25000 | 800000 | 1050000 | 1050000 | 1.05V (pcv)
|
* ldo1 | XUSB, PCIE | 25000 | 800000 | 1050000 | 1050000 | 1.05V (pcv)
|
||||||
* ldo2 | SDMMC1 | 50000 | 800000 | 1800000 | 3300000 |
|
* ldo2 | SDMMC1 | 50000 | 800000 | 1800000 | 3300000 |
|
||||||
* ldo3 | | 50000 | 800000 | 3100000 | 3100000 |
|
* ldo3 | GC ASIC | 50000 | 800000 | 3100000 | 3100000 | 3.1V (pcv)
|
||||||
* ldo4 | RTC | 12500 | 800000 | 850000 | 850000 |
|
* ldo4 | RTC | 12500 | 800000 | 850000 | 850000 |
|
||||||
* ldo5 | | 50000 | 800000 | 1800000 | 1800000 |
|
* ldo5 | GC ASIC | 50000 | 800000 | 1800000 | 1800000 | 1.8V (pcv)
|
||||||
* ldo6 | | 50000 | 800000 | 2900000 | 2900000 |
|
* ldo6 | Touch, ALS | 50000 | 800000 | 2900000 | 2900000 | 2.9V
|
||||||
* ldo7 | XUSB | 50000 | 800000 | 1050000 | 1050000 |
|
* ldo7 | XUSB | 50000 | 800000 | 1050000 | 1050000 |
|
||||||
* ldo8 | XUSB, DC | 50000 | 800000 | 1050000 | 1050000 |
|
* ldo8 | XUSB, DC | 50000 | 800000 | 1050000 | 1050000 |
|
||||||
*/
|
*/
|
||||||
@@ -70,6 +71,8 @@
|
|||||||
/* MAX77621_VOUT */
|
/* MAX77621_VOUT */
|
||||||
#define MAX77621_VOUT_ENABLE (1 << 7)
|
#define MAX77621_VOUT_ENABLE (1 << 7)
|
||||||
#define MAX77621_VOUT_MASK 0x7F
|
#define MAX77621_VOUT_MASK 0x7F
|
||||||
|
#define MAX77621_VOUT_0_95V 0x37
|
||||||
|
#define MAX77621_VOUT_1_09V 0x4F
|
||||||
|
|
||||||
/* MAX77621_VOUT_DVC_DVS */
|
/* MAX77621_VOUT_DVC_DVS */
|
||||||
#define MAX77621_DVS_VOUT_MASK 0x7F
|
#define MAX77621_DVS_VOUT_MASK 0x7F
|
||||||
@@ -108,6 +111,7 @@ int max77620_regulator_get_status(u32 id);
|
|||||||
int max77620_regulator_config_fps(u32 id);
|
int max77620_regulator_config_fps(u32 id);
|
||||||
int max77620_regulator_set_voltage(u32 id, u32 mv);
|
int max77620_regulator_set_voltage(u32 id, u32 mv);
|
||||||
int max77620_regulator_enable(u32 id, int enable);
|
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_config_default();
|
||||||
void max77620_low_battery_monitor_config();
|
void max77620_low_battery_monitor_config();
|
||||||
|
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ void max77620_rtc_get_time(rtc_time_t *time)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get date.
|
// 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->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;
|
time->year = (i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_YEAR_REG) & 0x7F) + 2000;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ typedef struct _rtc_time_t {
|
|||||||
u8 sec;
|
u8 sec;
|
||||||
u8 min;
|
u8 min;
|
||||||
u8 hour;
|
u8 hour;
|
||||||
u8 date;
|
u8 day;
|
||||||
u8 month;
|
u8 month;
|
||||||
u16 year;
|
u16 year;
|
||||||
} rtc_time_t;
|
} rtc_time_t;
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#include "../sec/se.h"
|
#include "../sec/se.h"
|
||||||
#include "../mem/heap.h"
|
#include "../mem/heap.h"
|
||||||
|
#include "../soc/bpmp.h"
|
||||||
#include "../soc/t210.h"
|
#include "../soc/t210.h"
|
||||||
#include "../sec/se_t210.h"
|
#include "../sec/se_t210.h"
|
||||||
#include "../utils/util.h"
|
#include "../utils/util.h"
|
||||||
@@ -36,7 +37,7 @@ static void _gf256_mul_x(void *block)
|
|||||||
u8 *pdata = (u8 *)block;
|
u8 *pdata = (u8 *)block;
|
||||||
u32 carry = 0;
|
u32 carry = 0;
|
||||||
|
|
||||||
for (u32 i = 0xF; i >= 0; i--)
|
for (int i = 0xF; i >= 0; i--)
|
||||||
{
|
{
|
||||||
u8 b = pdata[i];
|
u8 b = pdata[i];
|
||||||
pdata[i] = (b << 1) | carry;
|
pdata[i] = (b << 1) | carry;
|
||||||
@@ -91,10 +92,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_ERR_STATUS_0) = SE(SE_ERR_STATUS_0);
|
||||||
SE(SE_INT_STATUS_REG_OFFSET) = SE(SE_INT_STATUS_REG_OFFSET);
|
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);
|
||||||
|
|
||||||
|
SE(SE_OPERATION_REG_OFFSET) = SE_OPERATION(op);
|
||||||
int res = _se_wait();
|
int res = _se_wait();
|
||||||
|
|
||||||
|
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY);
|
||||||
|
|
||||||
if (src)
|
if (src)
|
||||||
free(ll_src);
|
free(ll_src);
|
||||||
if (dst)
|
if (dst)
|
||||||
@@ -173,7 +178,7 @@ int se_aes_unwrap_key(u32 ks_dst, u32 ks_src, const void *input)
|
|||||||
return _se_execute(OP_START, NULL, 0, input, 0x10);
|
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)
|
if (enc)
|
||||||
{
|
{
|
||||||
@@ -185,8 +190,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_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_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_DECRYPT);
|
||||||
}
|
}
|
||||||
SE(SE_BLOCK_COUNT_REG_OFFSET) = 0;
|
SE(SE_BLOCK_COUNT_REG_OFFSET) = (src_size >> 4) - 1;
|
||||||
return _se_execute(OP_START, dst, 0x10, src, 0x10);
|
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)
|
int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size, void *ctr)
|
||||||
@@ -270,15 +280,15 @@ int se_calc_sha256(void *dst, const void *src, u32 src_size)
|
|||||||
int res;
|
int res;
|
||||||
// Setup config for SHA256, size = BITS(src_size).
|
// 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_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) = 1;
|
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) = (u32)(src_size << 3);
|
||||||
SE(0x208) = 0;
|
SE(SE_SHA_MSG_LENGTH_REG_OFFSET + 4 * 1) = 0;
|
||||||
SE(0x20C) = 0;
|
SE(SE_SHA_MSG_LENGTH_REG_OFFSET + 4 * 2) = 0;
|
||||||
SE(0x210) = 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) = (u32)(src_size << 3);
|
||||||
SE(0x218) = 0;
|
SE(SE_SHA_MSG_LEFT_REG_OFFSET + 4 * 1) = 0;
|
||||||
SE(0x21C) = 0;
|
SE(SE_SHA_MSG_LEFT_REG_OFFSET + 4 * 2) = 0;
|
||||||
SE(0x220) = 0;
|
SE(SE_SHA_MSG_LEFT_REG_OFFSET + 4 * 3) = 0;
|
||||||
|
|
||||||
// Trigger the operation.
|
// Trigger the operation.
|
||||||
res = _se_execute(OP_START, NULL, 0, src, src_size);
|
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_set(u32 ks, void *key, u32 size);
|
||||||
void se_aes_key_clear(u32 ks);
|
void se_aes_key_clear(u32 ks);
|
||||||
int se_aes_unwrap_key(u32 ks_dst, u32 ks_src, const void *input);
|
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_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_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);
|
int se_calc_sha256(void *dst, const void *src, u32 src_size);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
* Copyright (c) 2018 CTCaer
|
* Copyright (c) 2018-2019 CTCaer
|
||||||
* Copyright (c) 2018 balika011
|
* Copyright (c) 2018 balika011
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
@@ -21,6 +21,7 @@
|
|||||||
#include "../sec/tsec.h"
|
#include "../sec/tsec.h"
|
||||||
#include "../sec/tsec_t210.h"
|
#include "../sec/tsec_t210.h"
|
||||||
#include "../sec/se_t210.h"
|
#include "../sec/se_t210.h"
|
||||||
|
#include "../soc/bpmp.h"
|
||||||
#include "../soc/clock.h"
|
#include "../soc/clock.h"
|
||||||
#include "../soc/smmu.h"
|
#include "../soc/smmu.h"
|
||||||
#include "../soc/t210.h"
|
#include "../soc/t210.h"
|
||||||
@@ -29,8 +30,7 @@
|
|||||||
#include "../utils/util.h"
|
#include "../utils/util.h"
|
||||||
#include "../hos/hos.h"
|
#include "../hos/hos.h"
|
||||||
|
|
||||||
/* #include "../gfx/gfx.h"
|
// #include "../gfx/gfx.h"
|
||||||
extern gfx_con_t gfx_con; */
|
|
||||||
|
|
||||||
static int _tsec_dma_wait_idle()
|
static int _tsec_dma_wait_idle()
|
||||||
{
|
{
|
||||||
@@ -66,8 +66,12 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
|
|||||||
u32 *pdir, *car, *fuse, *pmc, *flowctrl, *se, *mc, *iram, *evec;
|
u32 *pdir, *car, *fuse, *pmc, *flowctrl, *se, *mc, *iram, *evec;
|
||||||
u32 *pkg11_magic_off;
|
u32 *pkg11_magic_off;
|
||||||
|
|
||||||
|
bpmp_mmu_disable();
|
||||||
|
bpmp_clk_rate_set(BPMP_CLK_NORMAL);
|
||||||
|
|
||||||
// Enable clocks.
|
// Enable clocks.
|
||||||
clock_enable_host1x();
|
clock_enable_host1x();
|
||||||
|
usleep(2);
|
||||||
clock_enable_tsec();
|
clock_enable_tsec();
|
||||||
clock_enable_sor_safe();
|
clock_enable_sor_safe();
|
||||||
clock_enable_sor0();
|
clock_enable_sor0();
|
||||||
@@ -97,15 +101,15 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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_600)
|
if (kb == KB_FIRMWARE_VERSION_620)
|
||||||
|
TSEC(TSEC_DMATRFBASE) = (u32)tsec_ctxt->fw >> 8;
|
||||||
|
else
|
||||||
{
|
{
|
||||||
fwbuf = (u8 *)malloc(0x2000);
|
fwbuf = (u8 *)malloc(0x4000);
|
||||||
u8 *fwbuf_aligned = (u8 *)ALIGN((u32)fwbuf + 0x1000, 0x100);
|
u8 *fwbuf_aligned = (u8 *)ALIGN((u32)fwbuf, 0x100);
|
||||||
memcpy(fwbuf_aligned, tsec_ctxt->fw, tsec_ctxt->size);
|
memcpy(fwbuf_aligned, tsec_ctxt->fw, tsec_ctxt->size);
|
||||||
TSEC(TSEC_DMATRFBASE) = (u32)fwbuf_aligned >> 8;
|
TSEC(TSEC_DMATRFBASE) = (u32)fwbuf_aligned >> 8;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
TSEC(TSEC_DMATRFBASE) = (u32)tsec_ctxt->fw >> 8;
|
|
||||||
|
|
||||||
for (u32 addr = 0; addr < tsec_ctxt->size; addr += 0x100)
|
for (u32 addr = 0; addr < tsec_ctxt->size; addr += 0x100)
|
||||||
{
|
{
|
||||||
@@ -116,7 +120,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kb >= KB_FIRMWARE_VERSION_620)
|
if (kb == KB_FIRMWARE_VERSION_620)
|
||||||
{
|
{
|
||||||
// Init SMMU translation for TSEC.
|
// Init SMMU translation for TSEC.
|
||||||
pdir = smmu_init_for_tsec();
|
pdir = smmu_init_for_tsec();
|
||||||
@@ -172,47 +176,13 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Execute firmware.
|
// Execute firmware.
|
||||||
HOST1X(0x3300) = 0x34C2E1DA;
|
HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0x34C2E1DA;
|
||||||
TSEC(TSEC_STATUS) = 0;
|
TSEC(TSEC_STATUS) = 0;
|
||||||
TSEC(TSEC_BOOTKEYVER) = tsec_ctxt->key_ver;
|
TSEC(TSEC_BOOTKEYVER) = 1; // HOS uses key version 1.
|
||||||
TSEC(TSEC_BOOTVEC) = 0;
|
TSEC(TSEC_BOOTVEC) = 0;
|
||||||
TSEC(TSEC_CPUCTL) = TSEC_CPUCTL_STARTCPU;
|
TSEC(TSEC_CPUCTL) = TSEC_CPUCTL_STARTCPU;
|
||||||
|
|
||||||
if (kb <= KB_FIRMWARE_VERSION_600)
|
if (kb == KB_FIRMWARE_VERSION_620)
|
||||||
{
|
|
||||||
if (!_tsec_dma_wait_idle())
|
|
||||||
{
|
|
||||||
res = -3;
|
|
||||||
goto out_free;
|
|
||||||
}
|
|
||||||
u32 timeout = get_tmr_ms() + 2000;
|
|
||||||
while (!TSEC(TSEC_STATUS))
|
|
||||||
if (get_tmr_ms() > timeout)
|
|
||||||
{
|
|
||||||
res = -4;
|
|
||||||
goto out_free;
|
|
||||||
}
|
|
||||||
if (TSEC(TSEC_STATUS) != 0xB0B0B0B0)
|
|
||||||
{
|
|
||||||
res = -5;
|
|
||||||
goto out_free;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Fetch result.
|
|
||||||
HOST1X(0x3300) = 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);
|
|
||||||
buf[2] = SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_MSB);
|
|
||||||
buf[3] = SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_LSB);
|
|
||||||
SOR1(SOR_NV_PDISP_SOR_DP_HDCP_BKSV_LSB) = 0;
|
|
||||||
SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_BKSV_LSB) = 0;
|
|
||||||
SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_MSB) = 0;
|
|
||||||
SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_LSB) = 0;
|
|
||||||
|
|
||||||
memcpy(tsec_keys, &buf, 0x10);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
u32 start = get_tmr_us();
|
u32 start = get_tmr_us();
|
||||||
u32 k = se[SE_KEYTABLE_DATA0_REG_OFFSET / 4];
|
u32 k = se[SE_KEYTABLE_DATA0_REG_OFFSET / 4];
|
||||||
@@ -223,10 +193,11 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
|
|||||||
{
|
{
|
||||||
smmu_flush_all();
|
smmu_flush_all();
|
||||||
|
|
||||||
if (k == se[SE_KEYTABLE_DATA0_REG_OFFSET / 4])
|
if (k != se[SE_KEYTABLE_DATA0_REG_OFFSET / 4])
|
||||||
continue;
|
{
|
||||||
k = se[SE_KEYTABLE_DATA0_REG_OFFSET / 4];
|
k = se[SE_KEYTABLE_DATA0_REG_OFFSET / 4];
|
||||||
key[kidx++] = k;
|
key[kidx++] = k;
|
||||||
|
}
|
||||||
|
|
||||||
// Failsafe.
|
// Failsafe.
|
||||||
if ((u32)get_tmr_us() - start > 125000)
|
if ((u32)get_tmr_us() - start > 125000)
|
||||||
@@ -250,16 +221,50 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
|
|||||||
smmu_deinit_for_tsec();
|
smmu_deinit_for_tsec();
|
||||||
|
|
||||||
// for (int i = 0; i < kidx; i++)
|
// 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);
|
// 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(" MC %08X %08X %08X\n", MC(MC_INTSTATUS), errst, MC(MC_ERR_ADR));
|
||||||
// gfx_printf(&gfx_con, " type: %02X\n", errst >> 28);
|
// gfx_printf(" type: %02X\n", errst >> 28);
|
||||||
// gfx_printf(&gfx_con, " smmu: %02X\n", (errst >> 25) & 3);
|
// gfx_printf(" smmu: %02X\n", (errst >> 25) & 3);
|
||||||
// gfx_printf(&gfx_con, " dir: %s\n", (errst >> 16) & 1 ? "W" : "R");
|
// gfx_printf(" dir: %s\n", (errst >> 16) & 1 ? "W" : "R");
|
||||||
// gfx_printf(&gfx_con, " cid: %02x\n", errst & 0xFF);
|
// gfx_printf(" cid: %02x\n", errst & 0xFF);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!_tsec_dma_wait_idle())
|
||||||
|
{
|
||||||
|
res = -3;
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
u32 timeout = get_tmr_ms() + 2000;
|
||||||
|
while (!TSEC(TSEC_STATUS))
|
||||||
|
if (get_tmr_ms() > timeout)
|
||||||
|
{
|
||||||
|
res = -4;
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
if (TSEC(TSEC_STATUS) != 0xB0B0B0B0)
|
||||||
|
{
|
||||||
|
res = -5;
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
buf[2] = SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_MSB);
|
||||||
|
buf[3] = SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_LSB);
|
||||||
|
SOR1(SOR_NV_PDISP_SOR_DP_HDCP_BKSV_LSB) = 0;
|
||||||
|
SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_BKSV_LSB) = 0;
|
||||||
|
SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_MSB) = 0;
|
||||||
|
SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_LSB) = 0;
|
||||||
|
|
||||||
|
memcpy(tsec_keys, &buf, 0x10);
|
||||||
}
|
}
|
||||||
|
|
||||||
out_free:;
|
out_free:;
|
||||||
@@ -273,7 +278,8 @@ out:;
|
|||||||
clock_disable_sor0();
|
clock_disable_sor0();
|
||||||
clock_disable_sor_safe();
|
clock_disable_sor_safe();
|
||||||
clock_disable_tsec();
|
clock_disable_tsec();
|
||||||
clock_disable_host1x();
|
bpmp_mmu_enable();
|
||||||
|
bpmp_clk_rate_set(BPMP_CLK_SUPER_BOOST);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,6 @@
|
|||||||
|
|
||||||
typedef struct _tsec_ctxt_t
|
typedef struct _tsec_ctxt_t
|
||||||
{
|
{
|
||||||
u32 key_ver;
|
|
||||||
void *fw;
|
void *fw;
|
||||||
u32 size;
|
u32 size;
|
||||||
void *pkg1;
|
void *pkg1;
|
||||||
|
|||||||
249
bootloader/soc/bpmp.c
Normal file
249
bootloader/soc/bpmp.c
Normal file
@@ -0,0 +1,249 @@
|
|||||||
|
/*
|
||||||
|
* BPMP-Lite Cache/MMU and Frequency driver for Tegra X1
|
||||||
|
*
|
||||||
|
* 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 "bpmp.h"
|
||||||
|
#include "clock.h"
|
||||||
|
#include "t210.h"
|
||||||
|
#include "../utils/util.h"
|
||||||
|
|
||||||
|
#define BPMP_CACHE_CONFIG 0x0
|
||||||
|
#define CFG_ENABLE (1 << 0)
|
||||||
|
#define CFG_FORCE_WRITE_THROUGH (1 << 3)
|
||||||
|
#define CFG_DISABLE_WRITE_BUFFER (1 << 10)
|
||||||
|
#define CFG_DISABLE_READ_BUFFER (1 << 11)
|
||||||
|
#define CFG_FULL_LINE_DIRTY (1 << 13)
|
||||||
|
#define CFG_TAG_CHK_ABRT_ON_ERR (1 << 14)
|
||||||
|
#define BPMP_CACHE_LOCK 0x4
|
||||||
|
#define BPMP_CACHE_SIZE 0xC
|
||||||
|
#define BPMP_CACHE_LFSR 0x10
|
||||||
|
#define BPMP_CACHE_TAG_STATUS 0x14
|
||||||
|
#define BPMP_CACHE_CLKEN_OVERRIDE 0x18
|
||||||
|
#define BPMP_CACHE_MAINT_ADDR 0x20
|
||||||
|
#define BPMP_CACHE_MAINT_DATA 0x24
|
||||||
|
#define BPMP_CACHE_MAINT_REQ 0x28
|
||||||
|
#define MAINT_REQ_WAY_BITMAP(x) ((x) << 8)
|
||||||
|
|
||||||
|
#define BPMP_CACHE_INT_MASK 0x40
|
||||||
|
#define BPMP_CACHE_INT_CLEAR 0x44
|
||||||
|
#define INT_CLR_MAINT_DONE (1 << 0)
|
||||||
|
|
||||||
|
#define BPMP_CACHE_INT_RAW_EVENT 0x48
|
||||||
|
#define INT_RAW_EVENT_MAINT_DONE (1 << 0)
|
||||||
|
#define BPMP_CACHE_INT_STATUS 0x4C
|
||||||
|
|
||||||
|
#define 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_SEQ_EN (1 << 1)
|
||||||
|
#define MMU_CFG_TLB_EN (1 << 2)
|
||||||
|
#define MMU_CFG_ABORT_STORE_LAST (1 << 4)
|
||||||
|
#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 BPMP_CACHE_MMU_ABORT_ADDR 0xB8
|
||||||
|
#define BPMP_CACHE_MMU_ACTIVE_ENTRIES 0xBC
|
||||||
|
|
||||||
|
#define BPMP_MMU_SHADOW_ENTRY_BASE (BPMP_CACHE_BASE + 0x400)
|
||||||
|
#define BPMP_MMU_MAIN_ENTRY_BASE (BPMP_CACHE_BASE + 0x800)
|
||||||
|
#define MMU_ENTRY_ADDR_MASK 0xFFFFFFE0
|
||||||
|
|
||||||
|
#define MMU_EN_CACHED (1 << 0)
|
||||||
|
#define MMU_EN_EXEC (1 << 1)
|
||||||
|
#define MMU_EN_READ (1 << 2)
|
||||||
|
#define MMU_EN_WRITE (1 << 3)
|
||||||
|
|
||||||
|
bpmp_mmu_entry_t mmu_entries[] =
|
||||||
|
{
|
||||||
|
{ 0x80000000, 0xFFFFFFFF, MMU_EN_READ | MMU_EN_WRITE | MMU_EN_EXEC | MMU_EN_CACHED, true },
|
||||||
|
{ IPL_LOAD_ADDR, 0x40040000, MMU_EN_READ | MMU_EN_WRITE | MMU_EN_EXEC | MMU_EN_CACHED, true }
|
||||||
|
};
|
||||||
|
|
||||||
|
void bpmp_mmu_maintenance(u32 op)
|
||||||
|
{
|
||||||
|
if (!(BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE))
|
||||||
|
return;
|
||||||
|
|
||||||
|
BPMP_CACHE_CTRL(BPMP_CACHE_INT_CLEAR) = INT_CLR_MAINT_DONE;
|
||||||
|
|
||||||
|
// This is a blocking operation.
|
||||||
|
BPMP_CACHE_CTRL(BPMP_CACHE_MAINT_REQ) = MAINT_REQ_WAY_BITMAP(0xF) | op;
|
||||||
|
|
||||||
|
while(!(BPMP_CACHE_CTRL(BPMP_CACHE_INT_RAW_EVENT) & INT_RAW_EVENT_MAINT_DONE))
|
||||||
|
;
|
||||||
|
|
||||||
|
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->min_addr = entry->min_addr & MMU_ENTRY_ADDR_MASK;
|
||||||
|
mmu_entry->max_addr = entry->max_addr & MMU_ENTRY_ADDR_MASK;
|
||||||
|
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)
|
||||||
|
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);
|
||||||
|
|
||||||
|
// Enable cache.
|
||||||
|
BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) = CFG_ENABLE | CFG_FORCE_WRITE_THROUGH | CFG_TAG_CHK_ABRT_ON_ERR;
|
||||||
|
|
||||||
|
// HW bug. Invalidate cache again.
|
||||||
|
bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bpmp_mmu_disable()
|
||||||
|
{
|
||||||
|
if (!(BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Clean and invalidate cache.
|
||||||
|
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY);
|
||||||
|
|
||||||
|
// Disable cache.
|
||||||
|
BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) = 0;
|
||||||
|
|
||||||
|
// HW bug. Invalidate cache again.
|
||||||
|
bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
const u8 pllc4_divn[] = {
|
||||||
|
0, // BPMP_CLK_NORMAL: 408MHz 0% - 136MHz APB.
|
||||||
|
85, // BPMP_CLK_LOW_BOOST: 544MHz 33% - 136MHz APB.
|
||||||
|
90, // BPMP_CLK_MID_BOOST: 576MHz 41% - 144MHz APB.
|
||||||
|
94 // BPMP_CLK_SUPER_BOOST: 602MHz 48% - 150MHz APB.
|
||||||
|
//95 // BPMP_CLK_SUPER_BOOST: 608MHz 49% - 152MHz APB.
|
||||||
|
};
|
||||||
|
|
||||||
|
bpmp_freq_t bpmp_clock_set = BPMP_CLK_NORMAL;
|
||||||
|
|
||||||
|
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.
|
||||||
|
// Wait a bit for clock source change.
|
||||||
|
msleep(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_PLLC4_MISC) = PLLC4_MISC_EN_LCKDET;
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) = 4 | (pllc4_divn[fid] << 8) | PLL_BASE_ENABLE; // DIVM: 4, DIVP: 1.
|
||||||
|
|
||||||
|
while (!(CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) & PLLC4_BASE_LOCK))
|
||||||
|
;
|
||||||
|
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_PLLC4_OUT) = (1 << 8) | PLLC4_OUT3_CLKEN; // 1.5 div.
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_PLLC4_OUT) |= PLLC4_OUT3_RSTN_CLR; // Get divider out of reset.
|
||||||
|
|
||||||
|
// Wait a bit for PLLC4 to stabilize.
|
||||||
|
msleep(10);
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 3; // PCLK = HCLK / 4.
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003323; // PLLC4_OUT3.
|
||||||
|
|
||||||
|
bpmp_clock_set = fid;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003333; // PLLP_OUT.
|
||||||
|
|
||||||
|
// Wait a bit for clock source change.
|
||||||
|
msleep(10);
|
||||||
|
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 2; // PCLK = HCLK / 3.
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) &= ~PLL_BASE_ENABLE;
|
||||||
|
bpmp_clock_set = BPMP_CLK_NORMAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The following functions halt BPMP to reduce power while sleeping.
|
||||||
|
// They are not as accurate as RTC at big values but they guarantee time+ delay.
|
||||||
|
void bpmp_usleep(u32 us)
|
||||||
|
{
|
||||||
|
u32 delay;
|
||||||
|
|
||||||
|
// Each iteration takes 1us.
|
||||||
|
while (us)
|
||||||
|
{
|
||||||
|
delay = (us > HALT_COP_MAX_CNT) ? HALT_COP_MAX_CNT : us;
|
||||||
|
us -= delay;
|
||||||
|
|
||||||
|
FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_COP_WAIT_EVENT | HALT_COP_USEC | delay;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bpmp_msleep(u32 ms)
|
||||||
|
{
|
||||||
|
u32 delay;
|
||||||
|
|
||||||
|
// Iteration time is variable. ~200 - 1000us.
|
||||||
|
while (ms)
|
||||||
|
{
|
||||||
|
delay = (ms > HALT_COP_MAX_CNT) ? HALT_COP_MAX_CNT : ms;
|
||||||
|
ms -= delay;
|
||||||
|
|
||||||
|
FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_COP_WAIT_EVENT | HALT_COP_MSEC | delay;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bpmp_halt()
|
||||||
|
{
|
||||||
|
FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_COP_WAIT_EVENT | HALT_COP_JTAG;
|
||||||
|
}
|
||||||
54
bootloader/soc/bpmp.h
Normal file
54
bootloader/soc/bpmp.h
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* BPMP-Lite Cache/MMU and Frequency driver for Tegra X1
|
||||||
|
*
|
||||||
|
* 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 _BPMP_H_
|
||||||
|
#define _BPMP_H_
|
||||||
|
|
||||||
|
#include "../utils/types.h"
|
||||||
|
|
||||||
|
#define BPMP_MMU_MAINT_CLEAN_WAY 17
|
||||||
|
#define BPMP_MMU_MAINT_INVALID_WAY 18
|
||||||
|
#define BPMP_MMU_MAINT_CLN_INV_WAY 19
|
||||||
|
|
||||||
|
typedef struct _bpmp_mmu_entry_t
|
||||||
|
{
|
||||||
|
u32 min_addr;
|
||||||
|
u32 max_addr;
|
||||||
|
u32 attr;
|
||||||
|
u32 enable;
|
||||||
|
} bpmp_mmu_entry_t;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
BPMP_CLK_NORMAL, // 408MHz 0% - 136MHz APB.
|
||||||
|
BPMP_CLK_LOW_BOOST, // 544MHz 33% - 136MHz APB.
|
||||||
|
BPMP_CLK_MID_BOOST, // 576MHz 41% - 144MHz APB.
|
||||||
|
BPMP_CLK_SUPER_BOOST, // 608MHz 49% - 152MHz APB.
|
||||||
|
BPMP_CLK_MAX
|
||||||
|
} bpmp_freq_t;
|
||||||
|
|
||||||
|
void bpmp_mmu_maintenance(u32 op);
|
||||||
|
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_set(bpmp_freq_t fid);
|
||||||
|
void bpmp_usleep(u32 us);
|
||||||
|
void bpmp_msleep(u32 ms);
|
||||||
|
void bpmp_halt();
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -22,57 +22,58 @@
|
|||||||
/* clock_t: reset, enable, source, index, clk_src, clk_div */
|
/* clock_t: reset, enable, source, index, clk_src, clk_div */
|
||||||
|
|
||||||
static const clock_t _clock_uart[] = {
|
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 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, 0 },
|
/* 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, 0x17, 0, 0 },
|
/* 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 */ { 0 },
|
/* 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 */ { 0 }
|
/* UART E */ { CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_RST_CONTROLLER_CLK_SOURCE_UARTAPE, 20, 0, 2 }
|
||||||
};
|
};
|
||||||
|
|
||||||
static const clock_t _clock_i2c[] = {
|
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 },
|
/* I2C1 */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_I2C1, 12, 6, 0 }, // 0, 19 }, // 100KHz
|
||||||
/* I2C2 */ { 0 },
|
/* I2C2 */ { 0 },
|
||||||
/* I2C3 */ { 0 },
|
/* I2C3 */ { 0 },
|
||||||
/* I2C4 */ { 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 },
|
/* I2C5 */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_I2C5, 15, 6, 0 }, // 0, 4 }, // 400KHz
|
||||||
/* I2C6 */ { 0 }
|
/* I2C6 */ { 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
static clock_t _clock_se = {
|
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 = {
|
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 = {
|
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 = {
|
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 = {
|
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 = {
|
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 = {
|
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 = {
|
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 = {
|
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 = {
|
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 // Freference: 6.2MHz.
|
||||||
};
|
};
|
||||||
|
|
||||||
void clock_enable(const clock_t *clk)
|
void clock_enable(const clock_t *clk)
|
||||||
@@ -123,9 +124,9 @@ void clock_enable_se()
|
|||||||
clock_enable(&_clock_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()
|
void clock_enable_host1x()
|
||||||
@@ -276,12 +277,16 @@ static void _clock_sdmmc_set_reset(u32 id)
|
|||||||
{
|
{
|
||||||
case SDMMC_1:
|
case SDMMC_1:
|
||||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = L_SET_SDMMC1_RST;
|
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = L_SET_SDMMC1_RST;
|
||||||
|
break;
|
||||||
case SDMMC_2:
|
case SDMMC_2:
|
||||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = L_SET_SDMMC2_RST;
|
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = L_SET_SDMMC2_RST;
|
||||||
|
break;
|
||||||
case SDMMC_3:
|
case SDMMC_3:
|
||||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_U_SET) = U_SET_SDMMC3_RST;
|
CLOCK(CLK_RST_CONTROLLER_RST_DEV_U_SET) = U_SET_SDMMC3_RST;
|
||||||
|
break;
|
||||||
case SDMMC_4:
|
case SDMMC_4:
|
||||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = L_SET_SDMMC4_RST;
|
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = L_SET_SDMMC4_RST;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -291,12 +296,16 @@ static void _clock_sdmmc_clear_reset(u32 id)
|
|||||||
{
|
{
|
||||||
case SDMMC_1:
|
case SDMMC_1:
|
||||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = L_CLR_SDMMC1_RST;
|
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = L_CLR_SDMMC1_RST;
|
||||||
|
break;
|
||||||
case SDMMC_2:
|
case SDMMC_2:
|
||||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = L_CLR_SDMMC2_RST;
|
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = L_CLR_SDMMC2_RST;
|
||||||
|
break;
|
||||||
case SDMMC_3:
|
case SDMMC_3:
|
||||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_U_CLR) = U_CLR_SDMMC3_RST;
|
CLOCK(CLK_RST_CONTROLLER_RST_DEV_U_CLR) = U_CLR_SDMMC3_RST;
|
||||||
|
break;
|
||||||
case SDMMC_4:
|
case SDMMC_4:
|
||||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = L_CLR_SDMMC4_RST;
|
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = L_CLR_SDMMC4_RST;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -322,12 +331,16 @@ static void _clock_sdmmc_set_enable(u32 id)
|
|||||||
{
|
{
|
||||||
case SDMMC_1:
|
case SDMMC_1:
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = L_SET_CLK_ENB_SDMMC1;
|
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = L_SET_CLK_ENB_SDMMC1;
|
||||||
|
break;
|
||||||
case SDMMC_2:
|
case SDMMC_2:
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = L_SET_CLK_ENB_SDMMC2;
|
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = L_SET_CLK_ENB_SDMMC2;
|
||||||
|
break;
|
||||||
case SDMMC_3:
|
case SDMMC_3:
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_U_SET) = U_SET_CLK_ENB_SDMMC3;
|
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_U_SET) = U_SET_CLK_ENB_SDMMC3;
|
||||||
|
break;
|
||||||
case SDMMC_4:
|
case SDMMC_4:
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = L_SET_CLK_ENB_SDMMC4;
|
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = L_SET_CLK_ENB_SDMMC4;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -337,59 +350,65 @@ static void _clock_sdmmc_clear_enable(u32 id)
|
|||||||
{
|
{
|
||||||
case SDMMC_1:
|
case SDMMC_1:
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = L_CLR_CLK_ENB_SDMMC1;
|
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = L_CLR_CLK_ENB_SDMMC1;
|
||||||
|
break;
|
||||||
case SDMMC_2:
|
case SDMMC_2:
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = L_CLR_CLK_ENB_SDMMC2;
|
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = L_CLR_CLK_ENB_SDMMC2;
|
||||||
|
break;
|
||||||
case SDMMC_3:
|
case SDMMC_3:
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_U_CLR) = U_CLR_CLK_ENB_SDMMC3;
|
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_U_CLR) = U_CLR_CLK_ENB_SDMMC3;
|
||||||
|
break;
|
||||||
case SDMMC_4:
|
case SDMMC_4:
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = L_CLR_CLK_ENB_SDMMC4;
|
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = L_CLR_CLK_ENB_SDMMC4;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 _clock_sdmmc_table[8] = { 0 };
|
static u32 _clock_sdmmc_table[8] = { 0 };
|
||||||
|
|
||||||
|
#define PLLP_OUT0 0x0
|
||||||
static int _clock_sdmmc_config_clock_source_inner(u32 *pout, u32 id, u32 val)
|
static int _clock_sdmmc_config_clock_source_inner(u32 *pout, u32 id, u32 val)
|
||||||
{
|
{
|
||||||
u32 divisor = 0;
|
u32 divisor = 0;
|
||||||
u32 source = 0;
|
u32 source = PLLP_OUT0;
|
||||||
|
|
||||||
|
// Get IO clock divisor.
|
||||||
switch (val)
|
switch (val)
|
||||||
{
|
{
|
||||||
case 25000:
|
case 25000:
|
||||||
*pout = 24728;
|
*pout = 24728;
|
||||||
divisor = 31;
|
divisor = 31; // 16.5 div.
|
||||||
break;
|
break;
|
||||||
case 26000:
|
case 26000:
|
||||||
*pout = 25500;
|
*pout = 25500;
|
||||||
divisor = 30;
|
divisor = 30; // 16 div.
|
||||||
break;
|
break;
|
||||||
case 40800:
|
case 40800:
|
||||||
*pout = 40800;
|
*pout = 40800;
|
||||||
divisor = 18;
|
divisor = 18; // 10 div.
|
||||||
break;
|
break;
|
||||||
case 50000:
|
case 50000:
|
||||||
*pout = 48000;
|
*pout = 48000;
|
||||||
divisor = 15;
|
divisor = 15; // 8.5 div.
|
||||||
break;
|
break;
|
||||||
case 52000:
|
case 52000:
|
||||||
*pout = 51000;
|
*pout = 51000;
|
||||||
divisor = 14;
|
divisor = 14; // 8 div.
|
||||||
break;
|
break;
|
||||||
case 100000:
|
case 100000:
|
||||||
*pout = 90667;
|
*pout = 90667;
|
||||||
divisor = 7;
|
divisor = 7; // 4.5 div.
|
||||||
break;
|
break;
|
||||||
case 200000:
|
case 200000:
|
||||||
*pout = 163200;
|
*pout = 163200;
|
||||||
divisor = 3;
|
divisor = 3; // 2.5 div.
|
||||||
break;
|
break;
|
||||||
case 208000:
|
case 208000:
|
||||||
*pout = 204000;
|
*pout = 204000;
|
||||||
divisor = 2;
|
divisor = 2; // 2 div.
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
*pout = 24728;
|
*pout = 24728;
|
||||||
divisor = 31;
|
divisor = 31; // 16.5 div.
|
||||||
}
|
}
|
||||||
|
|
||||||
_clock_sdmmc_table[2 * id] = val;
|
_clock_sdmmc_table[2 * id] = val;
|
||||||
@@ -398,16 +417,16 @@ static int _clock_sdmmc_config_clock_source_inner(u32 *pout, u32 id, u32 val)
|
|||||||
switch (id)
|
switch (id)
|
||||||
{
|
{
|
||||||
case SDMMC_1:
|
case SDMMC_1:
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC1) = source | divisor;
|
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC1) = (source << 29) | divisor;
|
||||||
break;
|
break;
|
||||||
case SDMMC_2:
|
case SDMMC_2:
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC2) = source | divisor;
|
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC2) = (source << 29) | divisor;
|
||||||
break;
|
break;
|
||||||
case SDMMC_3:
|
case SDMMC_3:
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC3) = source | divisor;
|
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC3) = (source << 29) | divisor;
|
||||||
break;
|
break;
|
||||||
case SDMMC_4:
|
case SDMMC_4:
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC4) = source | divisor;
|
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC4) = (source << 29) | divisor;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -457,6 +476,7 @@ void clock_sdmmc_get_params(u32 *pout, u16 *pdivisor, u32 type)
|
|||||||
case 5:
|
case 5:
|
||||||
*pout = 25000;
|
*pout = 25000;
|
||||||
*pdivisor = 64;
|
*pdivisor = 64;
|
||||||
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
case 8:
|
case 8:
|
||||||
*pout = 25000;
|
*pout = 25000;
|
||||||
@@ -465,9 +485,11 @@ void clock_sdmmc_get_params(u32 *pout, u16 *pdivisor, u32 type)
|
|||||||
case 7:
|
case 7:
|
||||||
*pout = 50000;
|
*pout = 50000;
|
||||||
*pdivisor = 1;
|
*pdivisor = 1;
|
||||||
|
break;
|
||||||
case 10:
|
case 10:
|
||||||
*pout = 100000;
|
*pout = 100000;
|
||||||
*pdivisor = 1;
|
*pdivisor = 1;
|
||||||
|
break;
|
||||||
case 13:
|
case 13:
|
||||||
*pout = 40800;
|
*pout = 40800;
|
||||||
*pdivisor = 1;
|
*pdivisor = 1;
|
||||||
|
|||||||
@@ -41,6 +41,8 @@
|
|||||||
#define CLK_RST_CONTROLLER_PLLM_MISC2 0x9C
|
#define CLK_RST_CONTROLLER_PLLM_MISC2 0x9C
|
||||||
#define CLK_RST_CONTROLLER_PLLP_BASE 0xA0
|
#define CLK_RST_CONTROLLER_PLLP_BASE 0xA0
|
||||||
#define CLK_RST_CONTROLLER_PLLD_BASE 0xD0
|
#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_BASE 0xE0
|
||||||
#define CLK_RST_CONTROLLER_PLLX_MISC 0xE4
|
#define CLK_RST_CONTROLLER_PLLX_MISC 0xE4
|
||||||
#define CLK_RST_CONTROLLER_PLLE_BASE 0xE8
|
#define CLK_RST_CONTROLLER_PLLE_BASE 0xE8
|
||||||
@@ -50,6 +52,7 @@
|
|||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_PWM 0x110
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_PWM 0x110
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C1 0x124
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C1 0x124
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C5 0x128
|
#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_VI 0x148
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC1 0x150
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC1 0x150
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC2 0x154
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC2 0x154
|
||||||
@@ -57,11 +60,13 @@
|
|||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTA 0x178
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTA 0x178
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTB 0x17C
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTB 0x17C
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X 0x180
|
#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_UARTC 0x1A0
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C3 0x1B8
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C3 0x1B8
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC3 0x1BC
|
#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_CSITE 0x1D4
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC 0x19C
|
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_TSEC 0x1F4
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_TSEC 0x1F4
|
||||||
#define CLK_RST_CONTROLLER_CLK_OUT_ENB_X 0x280
|
#define CLK_RST_CONTROLLER_CLK_OUT_ENB_X 0x280
|
||||||
#define CLK_RST_CONTROLLER_CLK_ENB_X_SET 0x284
|
#define CLK_RST_CONTROLLER_CLK_ENB_X_SET 0x284
|
||||||
@@ -95,9 +100,12 @@
|
|||||||
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRC 0x3A0
|
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRC 0x3A0
|
||||||
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD 0x3A4
|
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD 0x3A4
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT 0x3B4
|
#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_SOR1 0x410
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_SE 0x42C
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_SE 0x42C
|
||||||
#define CLK_RST_CONTROLLER_CLK_ENB_V_SET 0x440
|
#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_SET 0x448
|
||||||
#define CLK_RST_CONTROLLER_CLK_ENB_W_CLR 0x44C
|
#define CLK_RST_CONTROLLER_CLK_ENB_W_CLR 0x44C
|
||||||
#define CLK_RST_CONTROLLER_RST_CPUG_CMPLX_SET 0x450
|
#define CLK_RST_CONTROLLER_RST_CPUG_CMPLX_SET 0x450
|
||||||
@@ -108,16 +116,30 @@
|
|||||||
#define CLK_RST_CONTROLLER_PLLX_MISC_3 0x518
|
#define CLK_RST_CONTROLLER_PLLX_MISC_3 0x518
|
||||||
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRE 0x554
|
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRE 0x554
|
||||||
#define CLK_RST_CONTROLLER_SPARE_REG0 0x55C
|
#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_PLLC4_OUT 0x5E4
|
||||||
#define CLK_RST_CONTROLLER_PLLMB_BASE 0x5E8
|
#define CLK_RST_CONTROLLER_PLLMB_BASE 0x5E8
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP 0x620
|
#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_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_SDMMC_LEGACY_TM 0x694
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_NVENC 0x6A0
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_NVENC 0x6A0
|
||||||
#define CLK_RST_CONTROLLER_SE_SUPER_CLK_DIVIDER 0x704
|
#define CLK_RST_CONTROLLER_SE_SUPER_CLK_DIVIDER 0x704
|
||||||
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTAPE 0x710
|
||||||
|
|
||||||
#define CLK_NO_SOURCE 0x0
|
#define CLK_NO_SOURCE 0x0
|
||||||
|
|
||||||
|
/*! PLL control and status bits */
|
||||||
|
#define PLL_BASE_ENABLE (1 << 30)
|
||||||
|
|
||||||
|
#define PLLC4_MISC_EN_LCKDET (1 << 30)
|
||||||
|
#define PLLC4_BASE_LOCK (1 << 27)
|
||||||
|
#define PLLC4_BASE_IDDQ (1 << 18)
|
||||||
|
#define PLLC4_OUT3_CLKEN (1 << 1)
|
||||||
|
#define PLLC4_OUT3_RSTN_CLR (1 << 0)
|
||||||
|
|
||||||
/*! Generic clock descriptor. */
|
/*! Generic clock descriptor. */
|
||||||
typedef struct _clock_t
|
typedef struct _clock_t
|
||||||
{
|
{
|
||||||
@@ -139,7 +161,7 @@ void clock_enable_uart(u32 idx);
|
|||||||
void clock_enable_i2c(u32 idx);
|
void clock_enable_i2c(u32 idx);
|
||||||
void clock_disable_i2c(u32 idx);
|
void clock_disable_i2c(u32 idx);
|
||||||
void clock_enable_se();
|
void clock_enable_se();
|
||||||
void clock_enable_unk2();
|
void clock_enable_tzram();
|
||||||
void clock_enable_host1x();
|
void clock_enable_host1x();
|
||||||
void clock_disable_host1x();
|
void clock_disable_host1x();
|
||||||
void clock_enable_tsec();
|
void clock_enable_tsec();
|
||||||
|
|||||||
@@ -25,25 +25,28 @@
|
|||||||
|
|
||||||
void _cluster_enable_power()
|
void _cluster_enable_power()
|
||||||
{
|
{
|
||||||
u8 tmp = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_AME_GPIO);
|
u8 tmp = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_AME_GPIO); // Get current pinmuxing
|
||||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_AME_GPIO, tmp & 0xDF);
|
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_AME_GPIO, tmp & ~(1 << 5)); // Disable GPIO5 pinmuxing.
|
||||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO5, MAX77620_CNFG_GPIO_DRV_PUSHPULL | MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH);
|
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO5, MAX77620_CNFG_GPIO_DRV_PUSHPULL | MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH);
|
||||||
|
|
||||||
// Enable cores power.
|
// Enable cores power.
|
||||||
// 1-3.x: MAX77621_NFSR_ENABLE.
|
// 1-3.x: MAX77621_NFSR_ENABLE.
|
||||||
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL1_REG,
|
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.
|
// 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,
|
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);
|
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_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_0_95V);
|
||||||
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_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.
|
u32 part_mask = 1 << part;
|
||||||
if (enable && PMC(APBDEV_PMC_PWRGATE_STATUS) & 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;
|
return 1;
|
||||||
|
|
||||||
u32 i = 5001;
|
u32 i = 5001;
|
||||||
@@ -55,12 +58,13 @@ int _cluster_pmc_enable_partition(u32 part, u32 toggle, bool enable)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
PMC(APBDEV_PMC_PWRGATE_TOGGLE) = toggle | (enable ? 0x100 : 0);
|
// Toggle power gating.
|
||||||
|
PMC(APBDEV_PMC_PWRGATE_TOGGLE) = part | 0x100;
|
||||||
|
|
||||||
i = 5001;
|
i = 5001;
|
||||||
while (i > 0)
|
while (i > 0)
|
||||||
{
|
{
|
||||||
if (PMC(APBDEV_PMC_PWRGATE_STATUS) & part)
|
if ((PMC(APBDEV_PMC_PWRGATE_STATUS) & part_mask) == desired_state)
|
||||||
break;
|
break;
|
||||||
usleep(1);
|
usleep(1);
|
||||||
i--;
|
i--;
|
||||||
@@ -103,11 +107,11 @@ void cluster_boot_cpu0(u32 entry)
|
|||||||
CLOCK(CLK_RST_CONTROLLER_CPU_SOFTRST_CTRL2) &= 0xFFFFF000;
|
CLOCK(CLK_RST_CONTROLLER_CPU_SOFTRST_CTRL2) &= 0xFFFFF000;
|
||||||
|
|
||||||
// Enable CPU rail.
|
// Enable CPU rail.
|
||||||
_cluster_pmc_enable_partition(1, 0, true);
|
_cluster_pmc_enable_partition(0, 1);
|
||||||
// Enable cluster 0 non-CPU.
|
// Enable cluster 0 non-CPU.
|
||||||
_cluster_pmc_enable_partition(0x8000, 15, true);
|
_cluster_pmc_enable_partition(15, 1);
|
||||||
// Enable CE0.
|
// Enable CE0.
|
||||||
_cluster_pmc_enable_partition(0x4000, 14, true);
|
_cluster_pmc_enable_partition(14, 1);
|
||||||
|
|
||||||
// Request and wait for RAM repair.
|
// Request and wait for RAM repair.
|
||||||
FLOW_CTLR(FLOW_CTLR_RAM_REPAIR) = 1;
|
FLOW_CTLR(FLOW_CTLR_RAM_REPAIR) = 1;
|
||||||
@@ -117,10 +121,10 @@ void cluster_boot_cpu0(u32 entry)
|
|||||||
EXCP_VEC(EVP_CPU_RESET_VECTOR) = 0;
|
EXCP_VEC(EVP_CPU_RESET_VECTOR) = 0;
|
||||||
|
|
||||||
// Set reset vector.
|
// 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;
|
SB(SB_AA64_RESET_HIGH) = 0;
|
||||||
// Non-secure reset vector write disable.
|
// Non-secure reset vector write disable.
|
||||||
SB(SB_CSR) = 2;
|
SB(SB_CSR) = SB_CSR_NS_RST_VEC_WR_DIS;
|
||||||
(void)SB(SB_CSR);
|
(void)SB(SB_CSR);
|
||||||
|
|
||||||
// Clear MSELECT reset.
|
// Clear MSELECT reset.
|
||||||
|
|||||||
@@ -19,19 +19,6 @@
|
|||||||
|
|
||||||
#include "../utils/types.h"
|
#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);
|
void cluster_boot_cpu0(u32 entry);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
* Copyright (c) 2018 shuffle2
|
* Copyright (c) 2018 shuffle2
|
||||||
* Copyright (c) 2018 balika011
|
* Copyright (c) 2018 balika011
|
||||||
|
* Copyright (c) 2019 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -68,7 +69,21 @@ void fuse_wait_idle()
|
|||||||
} while (((ctrl >> 16) & 0x1f) != 4);
|
} 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];
|
u32 acc = words[0];
|
||||||
for (u32 i = 1; i < count; i++)
|
for (u32 i = 1; i < count; i++)
|
||||||
@@ -85,10 +100,10 @@ u32 parity32_even(u32 *words, u32 count)
|
|||||||
return (x & 1) ^ (x >> 1);
|
return (x & 1) ^ (x >> 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int patch_hash_one(u32 *word)
|
static int _patch_hash_one(u32 *word)
|
||||||
{
|
{
|
||||||
u32 bits20_31 = *word & 0xfff00000;
|
u32 bits20_31 = *word & 0xfff00000;
|
||||||
u32 parity_bit = parity32_even(&bits20_31, 1);
|
u32 parity_bit = _parity32_even(&bits20_31, 1);
|
||||||
u32 hash = 0;
|
u32 hash = 0;
|
||||||
for (u32 i = 0; i < 12; i++)
|
for (u32 i = 0; i < 12; i++)
|
||||||
{
|
{
|
||||||
@@ -121,9 +136,9 @@ int patch_hash_one(u32 *word)
|
|||||||
return 2;
|
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 bits0_14 = words[0] & 0x7fff;
|
||||||
u32 bit15 = words[0] & 0x8000;
|
u32 bit15 = words[0] & 0x8000;
|
||||||
u32 bits16_19 = words[0] & 0xf0000;
|
u32 bits16_19 = words[0] & 0xf0000;
|
||||||
@@ -193,7 +208,7 @@ int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value))
|
|||||||
u32 total_read = 0;
|
u32 total_read = 0;
|
||||||
|
|
||||||
word_count = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE);
|
word_count = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE);
|
||||||
word_count &= 0x7f;
|
word_count &= 0x7F;
|
||||||
word_addr = 191;
|
word_addr = 191;
|
||||||
|
|
||||||
while (word_count)
|
while (word_count)
|
||||||
@@ -205,26 +220,21 @@ int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value))
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (u32 i = 0; i < word_count; i++)
|
for (u32 i = 0; i < word_count; i++)
|
||||||
{
|
words[i] = fuse_read(word_addr--);
|
||||||
FUSE(FUSE_ADDR) = word_addr--;
|
|
||||||
FUSE(FUSE_CTRL) = (FUSE(FUSE_ADDR) & ~FUSE_CMD_MASK) | FUSE_READ;
|
|
||||||
fuse_wait_idle();
|
|
||||||
words[i] = FUSE(FUSE_RDATA);
|
|
||||||
}
|
|
||||||
|
|
||||||
word0 = words[0];
|
word0 = words[0];
|
||||||
if (patch_hash_multi(words, word_count) >= 2)
|
if (_patch_hash_multi(words, word_count) >= 2)
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
u32 ipatch_count = (words[0] >> 16) & 0xf;
|
u32 ipatch_count = (words[0] >> 16) & 0xF;
|
||||||
if (ipatch_count)
|
if (ipatch_count)
|
||||||
{
|
{
|
||||||
for (u32 i = 0; i < ipatch_count; i++)
|
for (u32 i = 0; i < ipatch_count; i++)
|
||||||
{
|
{
|
||||||
u32 word = words[i + 1];
|
u32 word = words[i + 1];
|
||||||
u32 addr = (word >> 16) * 2;
|
u32 addr = (word >> 16) * 2;
|
||||||
u32 data = word & 0xffff;
|
u32 data = word & 0xFFFF;
|
||||||
|
|
||||||
ipatch(addr, data);
|
ipatch(addr, data);
|
||||||
}
|
}
|
||||||
@@ -232,7 +242,7 @@ int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value))
|
|||||||
words[0] = word0;
|
words[0] = word0;
|
||||||
if ((word0 >> 25) == 0)
|
if ((word0 >> 25) == 0)
|
||||||
break;
|
break;
|
||||||
if (patch_hash_one(&word0) >= 2)
|
if (_patch_hash_one(&word0) >= 2)
|
||||||
{
|
{
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
@@ -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);
|
memset(iram_evp_thunks, 0, *iram_evp_thunks_len);
|
||||||
|
|
||||||
word_count = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE);
|
word_count = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE);
|
||||||
word_count &= 0x7f;
|
word_count &= 0x7F;
|
||||||
word_addr = 191;
|
word_addr = 191;
|
||||||
|
|
||||||
while (word_count)
|
while (word_count)
|
||||||
@@ -267,19 +277,14 @@ int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (u32 i = 0; i < word_count; i++)
|
for (u32 i = 0; i < word_count; i++)
|
||||||
{
|
words[i] = fuse_read(word_addr--);
|
||||||
FUSE(FUSE_ADDR) = word_addr--;
|
|
||||||
FUSE(FUSE_CTRL) = (FUSE(FUSE_ADDR) & ~FUSE_CMD_MASK) | FUSE_READ;
|
|
||||||
fuse_wait_idle();
|
|
||||||
words[i] = FUSE(FUSE_RDATA);
|
|
||||||
}
|
|
||||||
|
|
||||||
word0 = words[0];
|
word0 = words[0];
|
||||||
if (patch_hash_multi(words, word_count) >= 2)
|
if (_patch_hash_multi(words, word_count) >= 2)
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
u32 ipatch_count = (words[0] >> 16) & 0xf;
|
u32 ipatch_count = (words[0] >> 16) & 0xF;
|
||||||
u32 insn_count = word_count - ipatch_count - 1;
|
u32 insn_count = word_count - ipatch_count - 1;
|
||||||
if (insn_count)
|
if (insn_count)
|
||||||
{
|
{
|
||||||
@@ -303,7 +308,7 @@ int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len)
|
|||||||
words[0] = word0;
|
words[0] = word0;
|
||||||
if ((word0 >> 25) == 0)
|
if ((word0 >> 25) == 0)
|
||||||
break;
|
break;
|
||||||
if (patch_hash_one(&word0) >= 2)
|
if (_patch_hash_one(&word0) >= 2)
|
||||||
{
|
{
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
@@ -313,13 +318,32 @@ int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len)
|
|||||||
return 0;
|
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;
|
u32 word0 = fuse_read(word_addr);
|
||||||
FUSE(FUSE_CTRL) = (FUSE(FUSE_ADDR) & ~FUSE_CMD_MASK) | FUSE_READ;
|
u32 ipatch_count = (word0 >> 16) & 0xF;
|
||||||
fuse_wait_idle();
|
|
||||||
words[i] = FUSE(FUSE_RDATA);
|
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,31 @@
|
|||||||
#define FUSE_WRITE_ACCESS_SW 0x30
|
#define FUSE_WRITE_ACCESS_SW 0x30
|
||||||
#define FUSE_PWR_GOOD_SW 0x34
|
#define FUSE_PWR_GOOD_SW 0x34
|
||||||
#define FUSE_SKU_INFO 0x110
|
#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_FIRST_BOOTROM_PATCH_SIZE 0x19c
|
||||||
#define FUSE_PRIVATE_KEY0 0x1A4
|
#define FUSE_PRIVATE_KEY0 0x1A4
|
||||||
#define FUSE_PRIVATE_KEY1 0x1A8
|
#define FUSE_PRIVATE_KEY1 0x1A8
|
||||||
#define FUSE_PRIVATE_KEY2 0x1AC
|
#define FUSE_PRIVATE_KEY2 0x1AC
|
||||||
#define FUSE_PRIVATE_KEY3 0x1B0
|
#define FUSE_PRIVATE_KEY3 0x1B0
|
||||||
|
#define FUSE_PRIVATE_KEY4 0x1B4
|
||||||
|
#define FUSE_RESERVED_SW 0x1C0
|
||||||
|
#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. */
|
/*! Fuse commands. */
|
||||||
#define FUSE_READ 0x1
|
#define FUSE_READ 0x1
|
||||||
@@ -57,6 +77,7 @@ u32 fuse_read_odm(u32 idx);
|
|||||||
void fuse_wait_idle();
|
void fuse_wait_idle();
|
||||||
int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value));
|
int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value));
|
||||||
int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len);
|
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
|
#endif
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* 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
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -18,42 +18,59 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "hw_init.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 "../gfx/di.h"
|
||||||
#include "../mem/mc.h"
|
#include "../mem/mc.h"
|
||||||
|
#include "../mem/minerva.h"
|
||||||
#include "../mem/sdram.h"
|
#include "../mem/sdram.h"
|
||||||
#include "../power/max77620.h"
|
#include "../power/max77620.h"
|
||||||
#include "../power/max7762x.h"
|
#include "../power/max7762x.h"
|
||||||
#include "../sec/se.h"
|
#include "../sec/se.h"
|
||||||
#include "../sec/se_t210.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 "../storage/sdmmc.h"
|
||||||
#include "../utils/util.h"
|
#include "../utils/util.h"
|
||||||
|
|
||||||
extern sdmmc_t sd_sdmmc;
|
extern sdmmc_t sd_sdmmc;
|
||||||
|
extern boot_cfg_t b_cfg;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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()
|
void _config_oscillators()
|
||||||
{
|
{
|
||||||
CLOCK(CLK_RST_CONTROLLER_SPARE_REG0) = (CLOCK(CLK_RST_CONTROLLER_SPARE_REG0) & 0xFFFFFFF3) | 4;
|
CLOCK(CLK_RST_CONTROLLER_SPARE_REG0) = (CLOCK(CLK_RST_CONTROLLER_SPARE_REG0) & 0xFFFFFFF3) | 4; // Set CLK_M_DIVISOR to 2.
|
||||||
SYSCTR0(SYSCTR0_CNTFID0) = 19200000;
|
SYSCTR0(SYSCTR0_CNTFID0) = 19200000; // Set counter frequency.
|
||||||
TMR(TIMERUS_USEC_CFG) = 0x45F; // For 19.2MHz clk_m.
|
TMR(TIMERUS_USEC_CFG) = 0x45F; // For 19.2MHz clk_m.
|
||||||
CLOCK(CLK_RST_CONTROLLER_OSC_CTRL) = 0x50000071;
|
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;
|
|
||||||
PMC(APBDEV_PMC_OSC_EDPD_OVER) = (PMC(APBDEV_PMC_OSC_EDPD_OVER) & 0xFFBFFFFF) | 0x400000;
|
PMC(APBDEV_PMC_OSC_EDPD_OVER) = (PMC(APBDEV_PMC_OSC_EDPD_OVER) & 0xFFFFFF81) | 0xE; // Set LP0 OSC drive strength.
|
||||||
PMC(APBDEV_PMC_CNTRL2) = (PMC(APBDEV_PMC_CNTRL2) & 0xFFFFEFFF) | 0x1000;
|
PMC(APBDEV_PMC_OSC_EDPD_OVER) = (PMC(APBDEV_PMC_OSC_EDPD_OVER) & 0xFFBFFFFF) | PMC_OSC_EDPD_OVER_OSC_CTRL_OVER;
|
||||||
PMC(APBDEV_PMC_SCRATCH188) = (PMC(APBDEV_PMC_SCRATCH188) & 0xFCFFFFFF) | 0x2000000;
|
PMC(APBDEV_PMC_CNTRL2) = (PMC(APBDEV_PMC_CNTRL2) & 0xFFFFEFFF) | PMC_CNTRL2_HOLD_CKE_LOW_EN;
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 0x10;
|
PMC(APBDEV_PMC_SCRATCH188) = (PMC(APBDEV_PMC_SCRATCH188) & 0xFCFFFFFF) | (4 << 23); // LP0 EMC2TMC_CFG_XM2COMP_PU_VREF_SEL_RANGE.
|
||||||
CLOCK(CLK_RST_CONTROLLER_PLLMB_BASE) &= 0xBFFFFFFF;
|
|
||||||
|
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)
|
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_SOURCE_SYS) = 0; // Set SCLK div to 1.
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 2;
|
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()
|
void _config_gpios()
|
||||||
@@ -61,17 +78,22 @@ void _config_gpios()
|
|||||||
PINMUX_AUX(PINMUX_AUX_UART2_TX) = 0;
|
PINMUX_AUX(PINMUX_AUX_UART2_TX) = 0;
|
||||||
PINMUX_AUX(PINMUX_AUX_UART3_TX) = 0;
|
PINMUX_AUX(PINMUX_AUX_UART3_TX) = 0;
|
||||||
|
|
||||||
|
// Set Joy-Con IsAttached direction.
|
||||||
PINMUX_AUX(PINMUX_AUX_GPIO_PE6) = PINMUX_INPUT_ENABLE;
|
PINMUX_AUX(PINMUX_AUX_GPIO_PE6) = PINMUX_INPUT_ENABLE;
|
||||||
PINMUX_AUX(PINMUX_AUX_GPIO_PH6) = PINMUX_INPUT_ENABLE;
|
PINMUX_AUX(PINMUX_AUX_GPIO_PH6) = PINMUX_INPUT_ENABLE;
|
||||||
|
|
||||||
|
// Set pin mode for Joy-Con IsAttached and UARTB/C TX pins.
|
||||||
#if !defined (DEBUG_UART_PORT) || DEBUG_UART_PORT != UART_B
|
#if !defined (DEBUG_UART_PORT) || DEBUG_UART_PORT != UART_B
|
||||||
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_GPIO);
|
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_GPIO);
|
||||||
#endif
|
#endif
|
||||||
#if !defined (DEBUG_UART_PORT) || DEBUG_UART_PORT != UART_C
|
#if !defined (DEBUG_UART_PORT) || DEBUG_UART_PORT != UART_C
|
||||||
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_GPIO);
|
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_GPIO);
|
||||||
#endif
|
#endif
|
||||||
|
// Set Joy-Con IsAttached mode.
|
||||||
gpio_config(GPIO_PORT_E, GPIO_PIN_6, GPIO_MODE_GPIO);
|
gpio_config(GPIO_PORT_E, GPIO_PIN_6, GPIO_MODE_GPIO);
|
||||||
gpio_config(GPIO_PORT_H, 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_G, GPIO_PIN_0, GPIO_OUTPUT_DISABLE);
|
||||||
gpio_output_enable(GPIO_PORT_D, GPIO_PIN_1, 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);
|
gpio_output_enable(GPIO_PORT_E, GPIO_PIN_6, GPIO_OUTPUT_DISABLE);
|
||||||
@@ -86,24 +108,36 @@ void _config_gpios()
|
|||||||
gpio_config(GPIO_PORT_X, GPIO_PIN_7, GPIO_MODE_GPIO);
|
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_6, GPIO_OUTPUT_DISABLE);
|
||||||
gpio_output_enable(GPIO_PORT_X, GPIO_PIN_7, 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_PULL_UP | PINMUX_INPUT_ENABLE;
|
||||||
|
// gpio_config(GPIO_PORT_Y, GPIO_PIN_1, GPIO_MODE_GPIO);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _config_pmc_scratch()
|
void _config_pmc_scratch()
|
||||||
{
|
{
|
||||||
PMC(APBDEV_PMC_SCRATCH20) &= 0xFFF3FFFF;
|
PMC(APBDEV_PMC_SCRATCH20) &= 0xFFF3FFFF; // Unset Debug console from Customer Option.
|
||||||
PMC(APBDEV_PMC_SCRATCH190) &= 0xFFFFFFFE;
|
PMC(APBDEV_PMC_SCRATCH190) &= 0xFFFFFFFE; // Unset DATA_DQ_E_IVREF EMC_PMACRO_DATA_PAD_TX_CTRL
|
||||||
PMC(APBDEV_PMC_SECURE_SCRATCH21) |= 0x10;
|
PMC(APBDEV_PMC_SECURE_SCRATCH21) |= PMC_FUSE_PRIVATEKEYDISABLE_TZ_STICKY_BIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _mbist_workaround()
|
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.
|
||||||
|
|
||||||
|
// 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_CLK_SOURCE_SOR1) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) | 0x8000) & 0xFFFFBFFF;
|
||||||
CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) |= 0x40800000u;
|
// Enabled PLLD and set csi to PLLD for test pattern generation.
|
||||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_Y_CLR) = 0x40;
|
CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) |= 0x40800000;
|
||||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_X_CLR) = 0x40000;
|
|
||||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = 0x18000000;
|
// 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);
|
usleep(2);
|
||||||
|
|
||||||
|
// I2S channels to master and disable SLCG.
|
||||||
I2S(I2S1_CTRL) |= I2S_CTRL_MASTER_EN;
|
I2S(I2S1_CTRL) |= I2S_CTRL_MASTER_EN;
|
||||||
I2S(I2S1_CG) &= ~I2S_CG_SLCG_ENABLE;
|
I2S(I2S1_CG) &= ~I2S_CG_SLCG_ENABLE;
|
||||||
I2S(I2S2_CTRL) |= I2S_CTRL_MASTER_EN;
|
I2S(I2S2_CTRL) |= I2S_CTRL_MASTER_EN;
|
||||||
@@ -114,33 +148,45 @@ void _mbist_workaround()
|
|||||||
I2S(I2S4_CG) &= ~I2S_CG_SLCG_ENABLE;
|
I2S(I2S4_CG) &= ~I2S_CG_SLCG_ENABLE;
|
||||||
I2S(I2S5_CTRL) |= I2S_CTRL_MASTER_EN;
|
I2S(I2S5_CTRL) |= I2S_CTRL_MASTER_EN;
|
||||||
I2S(I2S5_CG) &= ~I2S_CG_SLCG_ENABLE;
|
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;
|
VIC(0x8C) = 0xFFFFFFFF;
|
||||||
usleep(2);
|
usleep(2);
|
||||||
|
|
||||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_Y_SET) = 0x40;
|
// Set per-clock reset.
|
||||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = 0x18000000;
|
CLOCK(CLK_RST_CONTROLLER_RST_DEV_Y_SET) = 0x40; // Set reset APE.
|
||||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_X_SET) = 0x40000;
|
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = 0x18000000; // Set reset DISP1, HOST1x.
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) = 0xC0;
|
CLOCK(CLK_RST_CONTROLLER_RST_DEV_X_SET) = 0x40000; // Set reset VIC.
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) = 0x80000130;
|
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_U) = 0x1F00200;
|
// Enable specific clocks and disable all others.
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) = 0x80400808;
|
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) = 0xC0; // Enable clock PMC, FUSE.
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_W) = 0x402000FC;
|
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) = 0x80000130; // Enable clock RTC, TMR, GPIO, BPMP_CACHE.
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_X) = 0x23000780;
|
//CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) = 0x80400130; // Keep USB data ON.
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) = 0x300;
|
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_OVRA) = 0;
|
||||||
CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRB) = 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_OVRC) = 0;
|
||||||
CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD) = 0;
|
CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD) = 0;
|
||||||
CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRE) = 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;
|
// Set child clock sources.
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI) & 0x1FFFFFFF) | 0x80000000;
|
CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) &= 0x1F7FFFFF; // Disable PLLD and set reference clock and csi clock.
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X) & 0x1FFFFFFF) | 0x80000000;
|
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_NVENC) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_NVENC) & 0x1FFFFFFF) | 0x80000000;
|
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()
|
void _config_se_brom()
|
||||||
|
{
|
||||||
|
// Skip SBK/SSK if sept was run.
|
||||||
|
if (!(b_cfg.boot_cfg & BOOT_CFG_SEPT_RUN))
|
||||||
{
|
{
|
||||||
// Bootrom part we skipped.
|
// Bootrom part we skipped.
|
||||||
u32 sbk[4] = {
|
u32 sbk[4] = {
|
||||||
@@ -155,13 +201,14 @@ void _config_se_brom()
|
|||||||
// Lock SBK from being read.
|
// Lock SBK from being read.
|
||||||
SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + 14 * 4) = 0x7E;
|
SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + 14 * 4) = 0x7E;
|
||||||
|
|
||||||
// This memset needs to happen here, else TZRAM will behave weirdly later on.
|
|
||||||
memset((void *)TZRAM_BASE, 0, 0x10000);
|
|
||||||
PMC(APBDEV_PMC_CRYPTO_OP) = 0;
|
|
||||||
SE(SE_INT_STATUS_REG_OFFSET) = 0x1F;
|
|
||||||
|
|
||||||
// Lock SSK (although it's not set and unused anyways).
|
// Lock SSK (although it's not set and unused anyways).
|
||||||
SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + 15 * 4) = 0x7E;
|
SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + 15 * 4) = 0x7E;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This memset needs to happen here, else TZRAM will behave weirdly later on.
|
||||||
|
memset((void *)TZRAM_BASE, 0, 0x10000);
|
||||||
|
PMC(APBDEV_PMC_CRYPTO_OP) = PMC_CRYPTO_OP_SE_ENABLE;
|
||||||
|
SE(SE_INT_STATUS_REG_OFFSET) = 0x1F;
|
||||||
|
|
||||||
// Clear the boot reason to avoid problems later
|
// Clear the boot reason to avoid problems later
|
||||||
PMC(APBDEV_PMC_SCRATCH200) = 0x0;
|
PMC(APBDEV_PMC_SCRATCH200) = 0x0;
|
||||||
@@ -169,13 +216,59 @@ void _config_se_brom()
|
|||||||
APB_MISC(APB_MISC_PP_STRAPPING_OPT_A) = (APB_MISC(APB_MISC_PP_STRAPPING_OPT_A) & 0xF0) | (7 << 10);
|
APB_MISC(APB_MISC_PP_STRAPPING_OPT_A) = (APB_MISC(APB_MISC_PP_STRAPPING_OPT_A) & 0xF0) | (7 << 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _config_regulators()
|
||||||
|
{
|
||||||
|
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_CNFGBBC, MAX77620_CNFGBBC_RESISTOR_1K);
|
||||||
|
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1,
|
||||||
|
(1 << 6) | (1 << 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+
|
||||||
|
|
||||||
|
// Set vdd_core voltage to 1.125V
|
||||||
|
max77620_regulator_set_voltage(REGULATOR_SD0, 1125000);
|
||||||
|
|
||||||
|
// Fix CPU/GPU after a Linux 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);
|
||||||
|
|
||||||
|
// Disable low battery shutdown monitor.
|
||||||
|
max77620_low_battery_monitor_config();
|
||||||
|
}
|
||||||
|
|
||||||
void config_hw()
|
void config_hw()
|
||||||
{
|
{
|
||||||
// Bootrom stuff we skipped by going through rcm.
|
// Bootrom stuff we skipped by going through rcm.
|
||||||
_config_se_brom();
|
_config_se_brom();
|
||||||
//FUSE(FUSE_PRIVATEKEYDISABLE) = 0x11;
|
//FUSE(FUSE_PRIVATEKEYDISABLE) = 0x11;
|
||||||
SYSREG(AHB_AHB_SPARE_REG) &= 0xFFFFFF9F;
|
SYSREG(AHB_AHB_SPARE_REG) &= 0xFFFFFF9F; // Unset APB2JTAG_OVERRIDE_EN and OBS_OVERRIDE_EN.
|
||||||
PMC(APBDEV_PMC_SCRATCH49) = ((PMC(APBDEV_PMC_SCRATCH49) >> 1) << 1) & 0xFFFFFFFD;
|
PMC(APBDEV_PMC_SCRATCH49) = PMC(APBDEV_PMC_SCRATCH49) & 0xFFFFFFFC;
|
||||||
|
|
||||||
_mbist_workaround();
|
_mbist_workaround();
|
||||||
clock_enable_se();
|
clock_enable_se();
|
||||||
@@ -201,36 +294,29 @@ void config_hw()
|
|||||||
clock_enable_i2c(I2C_1);
|
clock_enable_i2c(I2C_1);
|
||||||
clock_enable_i2c(I2C_5);
|
clock_enable_i2c(I2C_5);
|
||||||
|
|
||||||
clock_enable_unk2();
|
clock_enable_tzram();
|
||||||
|
|
||||||
i2c_init(I2C_1);
|
i2c_init(I2C_1);
|
||||||
i2c_init(I2C_5);
|
i2c_init(I2C_5);
|
||||||
|
|
||||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_CNFGBBC, 0x40);
|
_config_regulators();
|
||||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1, 0x78); // PWR delay for forced shutdown off.
|
|
||||||
|
|
||||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG0, 0x38);
|
|
||||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG1, 0x3A);
|
|
||||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG2, 0x38);
|
|
||||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_LDO4, 0xF);
|
|
||||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_LDO8, 0xC7);
|
|
||||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_SD0, 0x4F);
|
|
||||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_SD1, 0x29);
|
|
||||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_SD3, 0x1B);
|
|
||||||
|
|
||||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_GPIO3, 0x22); // 3.x+
|
|
||||||
|
|
||||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD0, 42); //42 = (1125000uV - 600000) / 12500 -> 1.125V
|
|
||||||
|
|
||||||
_config_pmc_scratch(); // Missing from 4.x+
|
_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();
|
sdram_init();
|
||||||
|
|
||||||
|
bpmp_mmu_enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
void reconfig_hw_workaround(bool extra_reconfig, u32 magic)
|
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);
|
||||||
|
|
||||||
// Re-enable clocks to Audio Processing Engine as a workaround to hanging.
|
// 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_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.
|
||||||
@@ -247,10 +333,6 @@ void reconfig_hw_workaround(bool extra_reconfig, u32 magic)
|
|||||||
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO);
|
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO);
|
||||||
gpio_config(GPIO_PORT_E, GPIO_PIN_6, GPIO_MODE_SPIO);
|
gpio_config(GPIO_PORT_E, GPIO_PIN_6, GPIO_MODE_SPIO);
|
||||||
gpio_config(GPIO_PORT_H, GPIO_PIN_6, GPIO_MODE_SPIO);
|
gpio_config(GPIO_PORT_H, GPIO_PIN_6, GPIO_MODE_SPIO);
|
||||||
|
|
||||||
// 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Power off display.
|
// Power off display.
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ static int _i2c_send_pkt(u32 idx, u32 x, u8 *buf, u32 size)
|
|||||||
vu32 *base = (vu32 *)i2c_addrs[idx];
|
vu32 *base = (vu32 *)i2c_addrs[idx];
|
||||||
base[I2C_CMD_ADDR0] = x << 1; //Set x (send mode).
|
base[I2C_CMD_ADDR0] = x << 1; //Set x (send mode).
|
||||||
base[I2C_CMD_DATA1] = tmp; //Set value.
|
base[I2C_CMD_DATA1] = tmp; //Set value.
|
||||||
base[I2C_CNFG] = (2 * size - 2) | 0x2800; //Set size and send mode.
|
base[I2C_CNFG] = ((size - 1) << 1) | 0x2800; //Set size and send mode.
|
||||||
_i2c_wait(base); //Kick transaction.
|
_i2c_wait(base); //Kick transaction.
|
||||||
|
|
||||||
base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFFDFF) | 0x200;
|
base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFFDFF) | 0x200;
|
||||||
@@ -66,7 +66,7 @@ static int _i2c_recv_pkt(u32 idx, u8 *buf, u32 size, u32 x)
|
|||||||
|
|
||||||
vu32 *base = (vu32 *)i2c_addrs[idx];
|
vu32 *base = (vu32 *)i2c_addrs[idx];
|
||||||
base[I2C_CMD_ADDR0] = (x << 1) | 1; // Set x (recv mode).
|
base[I2C_CMD_ADDR0] = (x << 1) | 1; // Set x (recv mode).
|
||||||
base[I2C_CNFG] = (size - 1) << 1 | 0x2840; // Set size and recv mode.
|
base[I2C_CNFG] = ((size - 1) << 1) | 0x2840; // Set size and recv mode.
|
||||||
_i2c_wait(base); // Kick transaction.
|
_i2c_wait(base); // Kick transaction.
|
||||||
|
|
||||||
base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFFDFF) | 0x200;
|
base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFFDFF) | 0x200;
|
||||||
|
|||||||
@@ -18,6 +18,9 @@
|
|||||||
#include "../soc/clock.h"
|
#include "../soc/clock.h"
|
||||||
#include "../soc/t210.h"
|
#include "../soc/t210.h"
|
||||||
|
|
||||||
|
#pragma GCC push_options
|
||||||
|
#pragma GCC optimize ("Os")
|
||||||
|
|
||||||
int kfuse_read(u32 *buf)
|
int kfuse_read(u32 *buf)
|
||||||
{
|
{
|
||||||
int res = 0;
|
int res = 0;
|
||||||
@@ -40,3 +43,5 @@ out:;
|
|||||||
clock_disable_kfuse();
|
clock_disable_kfuse();
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma GCC pop_options
|
||||||
|
|||||||
@@ -38,18 +38,37 @@
|
|||||||
#define PINMUX_AUX_SDMMC3_DAT1 0x28
|
#define PINMUX_AUX_SDMMC3_DAT1 0x28
|
||||||
#define PINMUX_AUX_SDMMC3_DAT2 0x2C
|
#define PINMUX_AUX_SDMMC3_DAT2 0x2C
|
||||||
#define PINMUX_AUX_SDMMC3_DAT3 0x30
|
#define PINMUX_AUX_SDMMC3_DAT3 0x30
|
||||||
|
#define PINMUX_AUX_SATA_LED_ACTIVE 0x4C
|
||||||
#define PINMUX_AUX_DMIC3_CLK 0xB4
|
#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_UART2_TX 0xF4
|
||||||
#define PINMUX_AUX_UART3_TX 0x104
|
#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_EN 0x1B4
|
||||||
#define PINMUX_AUX_WIFI_RST 0x1B8
|
#define PINMUX_AUX_WIFI_RST 0x1B8
|
||||||
|
#define PINMUX_AUX_AP_WAKE_NFC 0x1CC
|
||||||
#define PINMUX_AUX_NFC_EN 0x1D0
|
#define PINMUX_AUX_NFC_EN 0x1D0
|
||||||
#define PINMUX_AUX_NFC_INT 0x1D4
|
#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_PWM 0x1FC
|
||||||
#define PINMUX_AUX_LCD_BL_EN 0x200
|
#define PINMUX_AUX_LCD_BL_EN 0x200
|
||||||
#define PINMUX_AUX_LCD_RST 0x204
|
#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_PE6 0x248
|
||||||
#define PINMUX_AUX_GPIO_PH6 0x250
|
#define PINMUX_AUX_GPIO_PH6 0x250
|
||||||
|
#define PINMUX_AUX_GPIO_PK3 0x260
|
||||||
#define PINMUX_AUX_GPIO_PZ1 0x280
|
#define PINMUX_AUX_GPIO_PZ1 0x280
|
||||||
/*! 0:UART-A, 1:UART-B, 3:UART-C, 3:UART-D */
|
/*! 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_TX(x) (0xE4 + 0x10 * (x))
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
#define APBDEV_PMC_PWRGATE_TOGGLE 0x30
|
#define APBDEV_PMC_PWRGATE_TOGGLE 0x30
|
||||||
#define APBDEV_PMC_PWRGATE_STATUS 0x38
|
#define APBDEV_PMC_PWRGATE_STATUS 0x38
|
||||||
#define APBDEV_PMC_NO_IOPOWER 0x44
|
#define APBDEV_PMC_NO_IOPOWER 0x44
|
||||||
|
#define PMC_NO_IOPOWER_SDMMC1_IO_EN (1 << 12)
|
||||||
#define APBDEV_PMC_SCRATCH0 0x50
|
#define APBDEV_PMC_SCRATCH0 0x50
|
||||||
#define APBDEV_PMC_SCRATCH1 0x54
|
#define APBDEV_PMC_SCRATCH1 0x54
|
||||||
#define APBDEV_PMC_SCRATCH20 0xA0
|
#define APBDEV_PMC_SCRATCH20 0xA0
|
||||||
@@ -32,12 +33,19 @@
|
|||||||
#define PMC_PWR_DET_SDMMC1_IO_EN (1 << 12)
|
#define PMC_PWR_DET_SDMMC1_IO_EN (1 << 12)
|
||||||
#define APBDEV_PMC_DDR_PWR 0xE8
|
#define APBDEV_PMC_DDR_PWR 0xE8
|
||||||
#define APBDEV_PMC_CRYPTO_OP 0xF4
|
#define APBDEV_PMC_CRYPTO_OP 0xF4
|
||||||
|
#define PMC_CRYPTO_OP_SE_ENABLE 0
|
||||||
|
#define PMC_CRYPTO_OP_SE_DISABLE 1
|
||||||
|
#define APBDEV_PMC_SCRATCH33 0x120
|
||||||
|
#define APBDEV_PMC_SCRATCH40 0x13C
|
||||||
#define APBDEV_PMC_OSC_EDPD_OVER 0x1A4
|
#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_RST_STATUS 0x1B4
|
||||||
#define APBDEV_PMC_IO_DPD_REQ 0x1B8
|
#define APBDEV_PMC_IO_DPD_REQ 0x1B8
|
||||||
#define APBDEV_PMC_IO_DPD2_REQ 0x1C0
|
#define APBDEV_PMC_IO_DPD2_REQ 0x1C0
|
||||||
#define APBDEV_PMC_VDDP_SEL 0x1CC
|
#define APBDEV_PMC_VDDP_SEL 0x1CC
|
||||||
#define APBDEV_PMC_DDR_CFG 0x1D0
|
#define APBDEV_PMC_DDR_CFG 0x1D0
|
||||||
|
#define APBDEV_PMC_SCRATCH45 0x234
|
||||||
|
#define APBDEV_PMC_SCRATCH46 0x238
|
||||||
#define APBDEV_PMC_SCRATCH49 0x244
|
#define APBDEV_PMC_SCRATCH49 0x244
|
||||||
#define APBDEV_PMC_TSC_MULT 0x2B4
|
#define APBDEV_PMC_TSC_MULT 0x2B4
|
||||||
#define APBDEV_PMC_SEC_DISABLE2 0x2C4
|
#define APBDEV_PMC_SEC_DISABLE2 0x2C4
|
||||||
@@ -45,9 +53,11 @@
|
|||||||
#define APBDEV_PMC_REG_SHORT 0x2CC
|
#define APBDEV_PMC_REG_SHORT 0x2CC
|
||||||
#define APBDEV_PMC_SEC_DISABLE3 0x2D8
|
#define APBDEV_PMC_SEC_DISABLE3 0x2D8
|
||||||
#define APBDEV_PMC_SECURE_SCRATCH21 0x334
|
#define APBDEV_PMC_SECURE_SCRATCH21 0x334
|
||||||
|
#define PMC_FUSE_PRIVATEKEYDISABLE_TZ_STICKY_BIT 0x10
|
||||||
#define APBDEV_PMC_SECURE_SCRATCH32 0x360
|
#define APBDEV_PMC_SECURE_SCRATCH32 0x360
|
||||||
#define APBDEV_PMC_SECURE_SCRATCH49 0x3A4
|
#define APBDEV_PMC_SECURE_SCRATCH49 0x3A4
|
||||||
#define APBDEV_PMC_CNTRL2 0x440
|
#define APBDEV_PMC_CNTRL2 0x440
|
||||||
|
#define PMC_CNTRL2_HOLD_CKE_LOW_EN 0x1000
|
||||||
#define APBDEV_PMC_IO_DPD3_REQ 0x45C
|
#define APBDEV_PMC_IO_DPD3_REQ 0x45C
|
||||||
#define APBDEV_PMC_IO_DPD4_REQ 0x464
|
#define APBDEV_PMC_IO_DPD4_REQ 0x464
|
||||||
#define APBDEV_PMC_UTMIP_PAD_CFG1 0x4C4
|
#define APBDEV_PMC_UTMIP_PAD_CFG1 0x4C4
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include "../utils/types.h"
|
#include "../utils/types.h"
|
||||||
|
|
||||||
#define BOOTROM_BASE 0x100000
|
#define BOOTROM_BASE 0x100000
|
||||||
|
#define IRAM_BASE 0x40000000
|
||||||
#define HOST1X_BASE 0x50000000
|
#define HOST1X_BASE 0x50000000
|
||||||
#define BPMP_CACHE_BASE 0x50040000
|
#define BPMP_CACHE_BASE 0x50040000
|
||||||
#define DISPLAY_A_BASE 0x54200000
|
#define DISPLAY_A_BASE 0x54200000
|
||||||
@@ -100,15 +101,22 @@
|
|||||||
#define CL_DVFS(off) _REG(CL_DVFS_BASE, off)
|
#define CL_DVFS(off) _REG(CL_DVFS_BASE, off)
|
||||||
#define TEST_REG(off) _REG(0x0, 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. */
|
/*! EVP registers. */
|
||||||
#define EVP_CPU_RESET_VECTOR 0x100
|
#define EVP_CPU_RESET_VECTOR 0x100
|
||||||
|
|
||||||
/*! Misc registers. */
|
/*! Misc registers. */
|
||||||
#define APB_MISC_PP_STRAPPING_OPT_A 0x08
|
#define APB_MISC_PP_STRAPPING_OPT_A 0x08
|
||||||
#define APB_MISC_PP_PINMUX_GLOBAL 0x40
|
#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_LCD_BL_PWM_CFGPADCTRL 0xA34
|
||||||
#define APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL 0xA98
|
#define APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL 0xA98
|
||||||
#define APB_MISC_GP_EMMC4_PAD_CFGPADCTRL 0xAB4
|
#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_EN_CFGPADCTRL 0xB64
|
||||||
#define APB_MISC_GP_WIFI_RST_CFGPADCTRL 0xB68
|
#define APB_MISC_GP_WIFI_RST_CFGPADCTRL 0xB68
|
||||||
|
|
||||||
@@ -118,7 +126,10 @@
|
|||||||
|
|
||||||
/*! Secure boot registers. */
|
/*! Secure boot registers. */
|
||||||
#define SB_CSR 0x0
|
#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_RESET_LOW 0x30
|
||||||
|
#define SB_AA64_RST_AARCH64_MODE_EN (1 << 0)
|
||||||
#define SB_AA64_RESET_HIGH 0x34
|
#define SB_AA64_RESET_HIGH 0x34
|
||||||
|
|
||||||
/*! SOR registers. */
|
/*! SOR registers. */
|
||||||
@@ -179,4 +190,34 @@
|
|||||||
#define I2S_CG_SLCG_ENABLE (1 << 0)
|
#define I2S_CG_SLCG_ENABLE (1 << 0)
|
||||||
#define I2S_CTRL_MASTER_EN (1 << 10)
|
#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
|
#endif
|
||||||
|
|||||||
@@ -22,9 +22,8 @@
|
|||||||
#define UART_A 0
|
#define UART_A 0
|
||||||
#define UART_B 1
|
#define UART_B 1
|
||||||
#define UART_C 2
|
#define UART_C 2
|
||||||
//TODO: define clock inits for those.
|
#define UART_D 3
|
||||||
/*#define UART_D 3
|
#define UART_E 4
|
||||||
#define UART_E 4*/
|
|
||||||
|
|
||||||
#define BAUD_115200 115200
|
#define BAUD_115200 115200
|
||||||
|
|
||||||
@@ -34,15 +33,29 @@
|
|||||||
#define UART_TX_FIFO_FULL 0x100
|
#define UART_TX_FIFO_FULL 0x100
|
||||||
#define UART_RX_FIFO_EMPTY 0x200
|
#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_DLAB 0x80
|
||||||
|
#define UART_LCR_STOP 0x4
|
||||||
#define UART_LCR_WORD_LENGTH_8 0x3
|
#define UART_LCR_WORD_LENGTH_8 0x3
|
||||||
|
|
||||||
#define UART_LSR_RDR 0x1
|
#define UART_LSR_RDR 0x1
|
||||||
#define UART_LSR_THRE 0x20
|
#define UART_LSR_THRE 0x20
|
||||||
#define UART_LSR_TMTY 0x40
|
#define UART_LSR_TMTY 0x40
|
||||||
|
#define UART_LSR_FIFOE 0x80
|
||||||
|
|
||||||
#define UART_IIR_FCR_TX_CLR 0x4
|
#define UART_IIR_FCR_TX_CLR 0x4
|
||||||
#define UART_IIR_FCR_RX_CLR 0x2
|
#define UART_IIR_FCR_RX_CLR 0x2
|
||||||
#define UART_IIR_FCR_EN_FIFO 0x1
|
#define UART_IIR_FCR_EN_FIFO 0x1
|
||||||
|
|
||||||
|
#define UART_MCR_RTS 0x2
|
||||||
|
#define UART_MCR_DTR 0x1
|
||||||
|
|
||||||
typedef struct _uart_t
|
typedef struct _uart_t
|
||||||
{
|
{
|
||||||
/* 0x00 */ vu32 UART_THR_DLAB;
|
/* 0x00 */ vu32 UART_THR_DLAB;
|
||||||
|
|||||||
264
bootloader/storage/emummc.c
Normal file
264
bootloader/storage/emummc.c
Normal file
@@ -0,0 +1,264 @@
|
|||||||
|
/*
|
||||||
|
* 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))
|
||||||
|
{
|
||||||
|
EPRINTF("Failed to init eMMC.");
|
||||||
|
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (h_cfg.emummc_force_disable)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
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 1;
|
||||||
|
|
||||||
|
out:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
@@ -17,6 +17,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "nx_emmc.h"
|
#include "nx_emmc.h"
|
||||||
|
#include "emummc.h"
|
||||||
#include "../mem/heap.h"
|
#include "../mem/heap.h"
|
||||||
#include "../utils/list.h"
|
#include "../utils/list.h"
|
||||||
|
|
||||||
@@ -24,7 +25,7 @@ void nx_emmc_gpt_parse(link_t *gpt, sdmmc_storage_t *storage)
|
|||||||
{
|
{
|
||||||
u8 *buf = (u8 *)malloc(NX_GPT_NUM_BLOCKS * NX_EMMC_BLOCKSIZE);
|
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;
|
gpt_header_t *hdr = (gpt_header_t *)buf;
|
||||||
for (u32 i = 0; i < hdr->num_part_ents; i++)
|
for (u32 i = 0; i < hdr->num_part_ents; i++)
|
||||||
@@ -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.
|
// The last LBA is inclusive.
|
||||||
if (part->lba_start + sector_off > part->lba_end)
|
if (part->lba_start + sector_off > part->lba_end)
|
||||||
return 0;
|
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)
|
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_start;
|
||||||
u32 lba_end;
|
u32 lba_end;
|
||||||
u64 attrs;
|
u64 attrs;
|
||||||
s8 name[37];
|
char name[37];
|
||||||
link_t link;
|
link_t link;
|
||||||
} emmc_part_t;
|
} emmc_part_t;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* 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
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -19,13 +19,11 @@
|
|||||||
#include "sdmmc.h"
|
#include "sdmmc.h"
|
||||||
#include "mmc.h"
|
#include "mmc.h"
|
||||||
#include "sd.h"
|
#include "sd.h"
|
||||||
#include "../utils/util.h"
|
#include "../gfx/gfx.h"
|
||||||
#include "../mem/heap.h"
|
#include "../mem/heap.h"
|
||||||
|
#include "../utils/util.h"
|
||||||
|
|
||||||
/*#include "gfx.h"
|
//#define DPRINTF(...) gfx_printf(__VA_ARGS__)
|
||||||
extern gfx_ctxt_t gfx_ctxt;
|
|
||||||
extern gfx_con_t gfx_con;
|
|
||||||
#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__)*/
|
|
||||||
#define DPRINTF(...)
|
#define DPRINTF(...)
|
||||||
|
|
||||||
static inline u32 unstuff_bits(u32 *resp, u32 start, u32 size)
|
static inline u32 unstuff_bits(u32 *resp, u32 start, u32 size)
|
||||||
@@ -71,6 +69,7 @@ static int _sdmmc_storage_execute_cmd_type1_ex(sdmmc_storage_t *storage, u32 *re
|
|||||||
if (_sdmmc_storage_check_result(*resp))
|
if (_sdmmc_storage_check_result(*resp))
|
||||||
if (expected_state == 0x10 || R1_CURRENT_STATE(*resp) == expected_state)
|
if (expected_state == 0x10 || R1_CURRENT_STATE(*resp) == expected_state)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,6 +83,7 @@ static int _sdmmc_storage_go_idle_state(sdmmc_storage_t *storage)
|
|||||||
{
|
{
|
||||||
sdmmc_cmd_t cmd;
|
sdmmc_cmd_t cmd;
|
||||||
sdmmc_init_cmd(&cmd, MMC_GO_IDLE_STATE, 0, SDMMC_RSP_TYPE_0, 0);
|
sdmmc_init_cmd(&cmd, MMC_GO_IDLE_STATE, 0, SDMMC_RSP_TYPE_0, 0);
|
||||||
|
|
||||||
return sdmmc_execute_cmd(storage->sdmmc, &cmd, 0, 0);
|
return sdmmc_execute_cmd(storage->sdmmc, &cmd, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,7 +93,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);
|
sdmmc_init_cmd(&cmd, MMC_ALL_SEND_CID, 0, SDMMC_RSP_TYPE_2, 0);
|
||||||
if (!sdmmc_execute_cmd(storage->sdmmc, &cmd, 0, 0))
|
if (!sdmmc_execute_cmd(storage->sdmmc, &cmd, 0, 0))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
sdmmc_get_rsp(storage->sdmmc, buf, 0x10, SDMMC_RSP_TYPE_2);
|
sdmmc_get_rsp(storage->sdmmc, buf, 0x10, SDMMC_RSP_TYPE_2);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,7 +110,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);
|
sdmmc_init_cmd(&cmdbuf, MMC_SEND_CSD, storage->rca << 16, SDMMC_RSP_TYPE_2, 0);
|
||||||
if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, 0, 0))
|
if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, 0, 0))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
sdmmc_get_rsp(storage->sdmmc, buf, 0x10, SDMMC_RSP_TYPE_2);
|
sdmmc_get_rsp(storage->sdmmc, buf, 0x10, SDMMC_RSP_TYPE_2);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,8 +150,10 @@ static int _sdmmc_storage_readwrite_ex(sdmmc_storage_t *storage, u32 *blkcnt_out
|
|||||||
u32 tmp = 0;
|
u32 tmp = 0;
|
||||||
sdmmc_stop_transmission(storage->sdmmc, &tmp);
|
sdmmc_stop_transmission(storage->sdmmc, &tmp);
|
||||||
_sdmmc_storage_get_status(storage, &tmp, 0);
|
_sdmmc_storage_get_status(storage, &tmp, 0);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,7 +161,9 @@ int sdmmc_storage_end(sdmmc_storage_t *storage)
|
|||||||
{
|
{
|
||||||
if (!_sdmmc_storage_go_idle_state(storage))
|
if (!_sdmmc_storage_go_idle_state(storage))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
sdmmc_end(storage->sdmmc);
|
sdmmc_end(storage->sdmmc);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,6 +185,7 @@ static int _sdmmc_storage_readwrite(sdmmc_storage_t *storage, u32 sector, u32 nu
|
|||||||
|
|
||||||
msleep(100);
|
msleep(100);
|
||||||
} while (retries);
|
} while (retries);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out:;
|
out:;
|
||||||
@@ -185,6 +194,7 @@ out:;
|
|||||||
num_sectors -= blkcnt;
|
num_sectors -= blkcnt;
|
||||||
bbuf += 512 * blkcnt;
|
bbuf += 512 * blkcnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,14 +245,17 @@ static int _mmc_storage_get_op_cond(sdmmc_storage_t *storage, u32 power)
|
|||||||
u32 cond = 0;
|
u32 cond = 0;
|
||||||
if (!_mmc_storage_get_op_cond_inner(storage, &cond, power))
|
if (!_mmc_storage_get_op_cond_inner(storage, &cond, power))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (cond & MMC_CARD_BUSY)
|
if (cond & MMC_CARD_BUSY)
|
||||||
{
|
{
|
||||||
if (cond & 0x40000000)
|
if (cond & 0x40000000)
|
||||||
storage->has_sector_access = 1;
|
storage->has_sector_access = 1;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (get_tmr_ms() > timeout)
|
if (get_tmr_ms() > timeout)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
usleep(1000);
|
usleep(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -372,6 +385,7 @@ static int _mmc_storage_switch_buswidth(sdmmc_storage_t *storage, u32 bus_width)
|
|||||||
if (_sdmmc_storage_check_status(storage))
|
if (_sdmmc_storage_check_status(storage))
|
||||||
{
|
{
|
||||||
sdmmc_set_bus_width(storage->sdmmc, bus_width);
|
sdmmc_set_bus_width(storage->sdmmc, bus_width);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -382,14 +396,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)))
|
if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (check && !_sdmmc_storage_check_status(storage))
|
if (check && !_sdmmc_storage_check_status(storage))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!sdmmc_setup_clock(storage->sdmmc, 2))
|
if (!sdmmc_setup_clock(storage->sdmmc, 2))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
DPRINTF("[MMC] switched to HS\n");
|
DPRINTF("[MMC] switched to HS\n");
|
||||||
storage->csd.busspeed = 52;
|
storage->csd.busspeed = 52;
|
||||||
|
|
||||||
if (check || _sdmmc_storage_check_status(storage))
|
if (check || _sdmmc_storage_check_status(storage))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -397,12 +416,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)))
|
if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!sdmmc_setup_clock(storage->sdmmc, 3))
|
if (!sdmmc_setup_clock(storage->sdmmc, 3))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!sdmmc_config_tuning(storage->sdmmc, 3, MMC_SEND_TUNING_BLOCK_HS200))
|
if (!sdmmc_config_tuning(storage->sdmmc, 3, MMC_SEND_TUNING_BLOCK_HS200))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
DPRINTF("[MMC] switched to HS200\n");
|
DPRINTF("[MMC] switched to HS200\n");
|
||||||
storage->csd.busspeed = 200;
|
storage->csd.busspeed = 200;
|
||||||
|
|
||||||
return _sdmmc_storage_check_status(storage);
|
return _sdmmc_storage_check_status(storage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -410,30 +433,36 @@ static int _mmc_storage_enable_HS400(sdmmc_storage_t *storage)
|
|||||||
{
|
{
|
||||||
if (!_mmc_storage_enable_HS200(storage))
|
if (!_mmc_storage_enable_HS200(storage))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
sdmmc_get_venclkctl(storage->sdmmc);
|
sdmmc_get_venclkctl(storage->sdmmc);
|
||||||
|
|
||||||
if (!_mmc_storage_enable_HS(storage, 0))
|
if (!_mmc_storage_enable_HS(storage, 0))
|
||||||
return 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)))
|
if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_BUS_WIDTH, EXT_CSD_DDR_BUS_WIDTH_8)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400)))
|
if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!sdmmc_setup_clock(storage->sdmmc, 4))
|
if (!sdmmc_setup_clock(storage->sdmmc, 4))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
DPRINTF("[MMC] switched to HS400\n");
|
DPRINTF("[MMC] switched to HS400\n");
|
||||||
storage->csd.busspeed = 400;
|
storage->csd.busspeed = 400;
|
||||||
|
|
||||||
return _sdmmc_storage_check_status(storage);
|
return _sdmmc_storage_check_status(storage);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _mmc_storage_enable_highspeed(sdmmc_storage_t *storage, u32 card_type, u32 type)
|
static int _mmc_storage_enable_highspeed(sdmmc_storage_t *storage, u32 card_type, u32 type)
|
||||||
{
|
{
|
||||||
//TODO: this should be a config item.
|
//TODO: this should be a config item.
|
||||||
//---v
|
// --v
|
||||||
if (!1 || sdmmc_get_voltage(storage->sdmmc) != SDMMC_POWER_1_8)
|
if (!1 || sdmmc_get_voltage(storage->sdmmc) != SDMMC_POWER_1_8)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_8 &&
|
if (sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_8 &&
|
||||||
card_type & EXT_CSD_CARD_TYPE_HS400_1_8V &&
|
card_type & EXT_CSD_CARD_TYPE_HS400_1_8V && type == 4)
|
||||||
type == 4)
|
|
||||||
return _mmc_storage_enable_HS400(storage);
|
return _mmc_storage_enable_HS400(storage);
|
||||||
|
|
||||||
if (sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_8 ||
|
if (sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_8 ||
|
||||||
@@ -445,6 +474,7 @@ static int _mmc_storage_enable_highspeed(sdmmc_storage_t *storage, u32 card_type
|
|||||||
out:;
|
out:;
|
||||||
if (card_type & EXT_CSD_CARD_TYPE_HS_52)
|
if (card_type & EXT_CSD_CARD_TYPE_HS_52)
|
||||||
return _mmc_storage_enable_HS(storage, 1);
|
return _mmc_storage_enable_HS(storage, 1);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -452,6 +482,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)))
|
if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_SET_BITS, EXT_CSD_BKOPS_EN, EXT_CSD_BKOPS_LEVEL_2)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return _sdmmc_storage_check_status(storage);
|
return _sdmmc_storage_check_status(storage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -521,7 +552,7 @@ int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
|
|||||||
free(ext_csd);
|
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
|
_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.
|
/* 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().
|
Disable it for now until BKOPS disable added to power down sequence at sdmmc_storage_end().
|
||||||
@@ -532,7 +563,9 @@ int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
|
|||||||
DPRINTF("[MMC] BKOPS enabled\n");
|
DPRINTF("[MMC] BKOPS enabled\n");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
DPRINTF("[MMC] BKOPS disabled\n");
|
DPRINTF("[MMC] BKOPS disabled\n");
|
||||||
|
}
|
||||||
|
|
||||||
if (!_mmc_storage_enable_highspeed(storage, storage->ext_csd.card_type, type))
|
if (!_mmc_storage_enable_highspeed(storage, storage->ext_csd.card_type, type))
|
||||||
return 0;
|
return 0;
|
||||||
@@ -547,8 +580,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)))
|
if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_PART_CONFIG, partition)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!_sdmmc_storage_check_status(storage))
|
if (!_sdmmc_storage_check_status(storage))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
storage->partition = partition;
|
storage->partition = partition;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -562,6 +597,7 @@ static int _sd_storage_execute_app_cmd(sdmmc_storage_t *storage, u32 expected_st
|
|||||||
u32 tmp;
|
u32 tmp;
|
||||||
if (!_sdmmc_storage_execute_cmd_type1_ex(storage, &tmp, MMC_APP_CMD, storage->rca << 16, 0, expected_state, mask))
|
if (!_sdmmc_storage_execute_cmd_type1_ex(storage, &tmp, MMC_APP_CMD, storage->rca << 16, 0, expected_state, mask))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return sdmmc_execute_cmd(storage->sdmmc, cmd, req, blkcnt_out);
|
return sdmmc_execute_cmd(storage->sdmmc, cmd, req, blkcnt_out);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -569,6 +605,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))
|
if (!_sdmmc_storage_execute_cmd_type1(storage, MMC_APP_CMD, storage->rca << 16, 0, R1_STATE_TRAN))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return _sdmmc_storage_execute_cmd_type1_ex(storage, resp, cmd, arg, check_busy, expected_state, 0);
|
return _sdmmc_storage_execute_cmd_type1_ex(storage, resp, cmd, arg, check_busy, expected_state, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -600,6 +637,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);
|
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))
|
if (!_sd_storage_execute_app_cmd(storage, 0x10, is_version_1 ? 0x400000 : 0, &cmdbuf, 0, 0))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return sdmmc_get_rsp(storage->sdmmc, cond, 4, SDMMC_RSP_TYPE_3);
|
return sdmmc_get_rsp(storage->sdmmc, cond, 4, SDMMC_RSP_TYPE_3);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -715,7 +753,7 @@ int _sd_storage_get_scr(sdmmc_storage_t *storage, u8 *buf)
|
|||||||
storage->raw_scr[i] = buf[i + 3];
|
storage->raw_scr[i] = buf[i + 3];
|
||||||
}
|
}
|
||||||
_sd_storage_parse_scr(storage);
|
_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);
|
return _sdmmc_storage_check_result(tmp);
|
||||||
}
|
}
|
||||||
@@ -800,10 +838,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))
|
if (!_sd_storage_switch(storage, buf, SD_SWITCH_CHECK, 0, hs_type))
|
||||||
return 0;
|
return 0;
|
||||||
|
DPRINTF("[SD] SD supports switch to (U)HS check\n");
|
||||||
|
|
||||||
u32 type_out = buf[16] & 0xF;
|
u32 type_out = buf[16] & 0xF;
|
||||||
if (type_out != hs_type)
|
if (type_out != hs_type)
|
||||||
return 0;
|
return 0;
|
||||||
|
DPRINTF("[SD] SD supports selected (U)HS mode\n");
|
||||||
|
|
||||||
if ((((u16)buf[0] << 8) | buf[1]) < 0x320)
|
if ((((u16)buf[0] << 8) | buf[1]) < 0x320)
|
||||||
{
|
{
|
||||||
@@ -827,12 +867,13 @@ int _sd_storage_enable_highspeed_low_volt(sdmmc_storage_t *storage, u32 type, u8
|
|||||||
|
|
||||||
if (!_sd_storage_switch_get(storage, buf))
|
if (!_sd_storage_switch_get(storage, buf))
|
||||||
return 0;
|
return 0;
|
||||||
//gfx_hexdump(&gfx_con, 0, (u8 *)buf, 64);
|
//gfx_hexdump(0, (u8 *)buf, 64);
|
||||||
|
|
||||||
u32 hs_type = 0;
|
u32 hs_type = 0;
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case 11:
|
case 11: // SDR104.
|
||||||
|
// Fall through if not supported.
|
||||||
if (buf[13] & SD_MODE_UHS_SDR104)
|
if (buf[13] & SD_MODE_UHS_SDR104)
|
||||||
{
|
{
|
||||||
type = 11;
|
type = 11;
|
||||||
@@ -841,8 +882,7 @@ int _sd_storage_enable_highspeed_low_volt(sdmmc_storage_t *storage, u32 type, u8
|
|||||||
storage->csd.busspeed = 104;
|
storage->csd.busspeed = 104;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
//Fall through.
|
case 10: // SDR50.
|
||||||
case 10:
|
|
||||||
if (buf[13] & SD_MODE_UHS_SDR50)
|
if (buf[13] & SD_MODE_UHS_SDR50)
|
||||||
{
|
{
|
||||||
type = 10;
|
type = 10;
|
||||||
@@ -851,7 +891,7 @@ int _sd_storage_enable_highspeed_low_volt(sdmmc_storage_t *storage, u32 type, u8
|
|||||||
storage->csd.busspeed = 50;
|
storage->csd.busspeed = 50;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 8:
|
case 8: // SDR12.
|
||||||
if (!(buf[13] & SD_MODE_UHS_SDR12))
|
if (!(buf[13] & SD_MODE_UHS_SDR12))
|
||||||
return 0;
|
return 0;
|
||||||
type = 8;
|
type = 8;
|
||||||
@@ -866,10 +906,13 @@ int _sd_storage_enable_highspeed_low_volt(sdmmc_storage_t *storage, u32 type, u8
|
|||||||
|
|
||||||
if (!_sd_storage_enable_highspeed(storage, hs_type, buf))
|
if (!_sd_storage_enable_highspeed(storage, hs_type, buf))
|
||||||
return 0;
|
return 0;
|
||||||
|
DPRINTF("[SD] SD card accepted UHS\n");
|
||||||
if (!sdmmc_setup_clock(storage->sdmmc, type))
|
if (!sdmmc_setup_clock(storage->sdmmc, type))
|
||||||
return 0;
|
return 0;
|
||||||
|
DPRINTF("[SD] setup clock\n");
|
||||||
if (!sdmmc_config_tuning(storage->sdmmc, type, MMC_SEND_TUNING_BLOCK))
|
if (!sdmmc_config_tuning(storage->sdmmc, type, MMC_SEND_TUNING_BLOCK))
|
||||||
return 0;
|
return 0;
|
||||||
|
DPRINTF("[SD] config tuning\n");
|
||||||
return _sdmmc_storage_check_status(storage);
|
return _sdmmc_storage_check_status(storage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -877,14 +920,16 @@ int _sd_storage_enable_highspeed_high_volt(sdmmc_storage_t *storage, u8 *buf)
|
|||||||
{
|
{
|
||||||
if (!_sd_storage_switch_get(storage, buf))
|
if (!_sd_storage_switch_get(storage, buf))
|
||||||
return 0;
|
return 0;
|
||||||
//gfx_hexdump(&gfx_con, 0, (u8 *)buf, 64);
|
//gfx_hexdump(0, (u8 *)buf, 64);
|
||||||
if (!(buf[13] & 2))
|
if (!(buf[13] & SD_MODE_HIGH_SPEED))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (!_sd_storage_enable_highspeed(storage, 1, buf))
|
if (!_sd_storage_enable_highspeed(storage, 1, buf))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!_sdmmc_storage_check_status(storage))
|
if (!_sdmmc_storage_check_status(storage))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return sdmmc_setup_clock(storage->sdmmc, 7);
|
return sdmmc_setup_clock(storage->sdmmc, 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -965,7 +1010,7 @@ static int _sd_storage_get_ssr(sdmmc_storage_t *storage, u8 *buf)
|
|||||||
storage->raw_ssr[i] = buf[i + 3];
|
storage->raw_ssr[i] = buf[i + 3];
|
||||||
}
|
}
|
||||||
_sd_storage_parse_ssr(storage);
|
_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);
|
return _sdmmc_storage_check_result(tmp);
|
||||||
}
|
}
|
||||||
@@ -1009,10 +1054,20 @@ 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 sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type)
|
||||||
{
|
{
|
||||||
int is_version_1 = 0;
|
int is_version_1 = 0;
|
||||||
|
|
||||||
|
// 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));
|
memset(storage, 0, sizeof(sdmmc_storage_t));
|
||||||
storage->sdmmc = sdmmc;
|
storage->sdmmc = sdmmc;
|
||||||
|
|
||||||
@@ -1059,7 +1114,7 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
|
|||||||
storage->sec_cnt = storage->csd.c_size << 10;
|
storage->sec_cnt = storage->csd.c_size << 10;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
DPRINTF("[SD] Unknown CSD structure %d\n", storage->csd.structure);
|
DPRINTF("[SD] unknown CSD structure %d\n", storage->csd.structure);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1090,7 +1145,7 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//gfx_hexdump(&gfx_con, 0, storage->raw_scr, 8);
|
//gfx_hexdump(0, storage->raw_scr, 8);
|
||||||
DPRINTF("[SD] got scr\n");
|
DPRINTF("[SD] got scr\n");
|
||||||
|
|
||||||
// Check if card supports a wider bus and if it's not SD Version 1.X
|
// Check if card supports a wider bus and if it's not SD Version 1.X
|
||||||
@@ -1105,7 +1160,9 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
|
|||||||
DPRINTF("[SD] switched to wide bus width\n");
|
DPRINTF("[SD] switched to wide bus width\n");
|
||||||
}
|
}
|
||||||
else
|
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 (storage->is_low_voltage)
|
||||||
{
|
{
|
||||||
@@ -1114,7 +1171,7 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
|
|||||||
free(buf);
|
free(buf);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
DPRINTF("[SD] enabled highspeed (low voltage)\n");
|
DPRINTF("[SD] enabled UHS\n");
|
||||||
}
|
}
|
||||||
else if (type != 6 && (storage->scr.sda_vsn & 0xF) != 0)
|
else if (type != 6 && (storage->scr.sda_vsn & 0xF) != 0)
|
||||||
{
|
{
|
||||||
@@ -1123,7 +1180,7 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
|
|||||||
free(buf);
|
free(buf);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
DPRINTF("[SD] enabled highspeed (high voltage)\n");
|
DPRINTF("[SD] enabled HS\n");
|
||||||
storage->csd.busspeed = 25;
|
storage->csd.busspeed = 25;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1131,7 +1188,9 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
|
|||||||
|
|
||||||
// Parse additional card info from sd status.
|
// Parse additional card info from sd status.
|
||||||
if (_sd_storage_get_ssr(storage, buf))
|
if (_sd_storage_get_ssr(storage, buf))
|
||||||
|
{
|
||||||
DPRINTF("[SD] got sd status\n");
|
DPRINTF("[SD] got sd status\n");
|
||||||
|
}
|
||||||
|
|
||||||
free(buf);
|
free(buf);
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
@@ -21,6 +21,8 @@
|
|||||||
#include "../utils/types.h"
|
#include "../utils/types.h"
|
||||||
#include "sdmmc_driver.h"
|
#include "sdmmc_driver.h"
|
||||||
|
|
||||||
|
u32 sd_power_cycle_time_start;
|
||||||
|
|
||||||
typedef struct _mmc_cid
|
typedef struct _mmc_cid
|
||||||
{
|
{
|
||||||
u32 manfid;
|
u32 manfid;
|
||||||
@@ -107,6 +109,7 @@ int sdmmc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, vo
|
|||||||
int sdmmc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf);
|
int sdmmc_storage_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_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);
|
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_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);
|
int sdmmc_storage_init_gc(sdmmc_storage_t *storage, sdmmc_t *sdmmc);
|
||||||
|
|
||||||
|
|||||||
@@ -17,20 +17,19 @@
|
|||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "sdmmc.h"
|
|
||||||
#include "../utils/util.h"
|
|
||||||
#include "../soc/clock.h"
|
|
||||||
#include "mmc.h"
|
#include "mmc.h"
|
||||||
|
#include "sdmmc.h"
|
||||||
|
#include "../gfx/gfx.h"
|
||||||
#include "../power/max7762x.h"
|
#include "../power/max7762x.h"
|
||||||
#include "../soc/t210.h"
|
#include "../soc/bpmp.h"
|
||||||
#include "../soc/pmc.h"
|
#include "../soc/clock.h"
|
||||||
#include "../soc/pinmux.h"
|
|
||||||
#include "../soc/gpio.h"
|
#include "../soc/gpio.h"
|
||||||
|
#include "../soc/pinmux.h"
|
||||||
|
#include "../soc/pmc.h"
|
||||||
|
#include "../soc/t210.h"
|
||||||
|
#include "../utils/util.h"
|
||||||
|
|
||||||
/*#include "gfx.h"
|
//#define DPRINTF(...) gfx_printf(__VA_ARGS__)
|
||||||
extern gfx_ctxt_t gfx_ctxt;
|
|
||||||
extern gfx_con_t gfx_con;
|
|
||||||
#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__)*/
|
|
||||||
#define DPRINTF(...)
|
#define DPRINTF(...)
|
||||||
|
|
||||||
/*! SCMMC controller base addresses. */
|
/*! SCMMC controller base addresses. */
|
||||||
@@ -118,11 +117,12 @@ static int _sdmmc_config_ven_ceata_clk(sdmmc_t *sdmmc, u32 id)
|
|||||||
|
|
||||||
if (id == 4)
|
if (id == 4)
|
||||||
sdmmc->regs->venceatactl = (sdmmc->regs->venceatactl & 0xFFFFC0FF) | 0x2800;
|
sdmmc->regs->venceatactl = (sdmmc->regs->venceatactl & 0xFFFFC0FF) | 0x2800;
|
||||||
sdmmc->regs->field_1C0 &= 0xFFFDFFFF;
|
sdmmc->regs->ventunctl0 &= 0xFFFDFFFF;
|
||||||
if (id == 4)
|
if (id == 4)
|
||||||
{
|
{
|
||||||
if (!sdmmc->venclkctl_set)
|
if (!sdmmc->venclkctl_set)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
tap_val = sdmmc->venclkctl_tap;
|
tap_val = sdmmc->venclkctl_tap;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -170,11 +170,11 @@ static int _sdmmc_wait_type4(sdmmc_t *sdmmc)
|
|||||||
sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
sdmmc->regs->field_1B0 |= 0x80000000;
|
sdmmc->regs->vendllcal |= 0x80000000;
|
||||||
_sdmmc_get_clkcon(sdmmc);
|
_sdmmc_get_clkcon(sdmmc);
|
||||||
|
|
||||||
u32 timeout = get_tmr_ms() + 5;
|
u32 timeout = get_tmr_ms() + 5;
|
||||||
while (sdmmc->regs->field_1B0 & 0x80000000)
|
while (sdmmc->regs->vendllcal & 0x80000000)
|
||||||
{
|
{
|
||||||
if (get_tmr_ms() > timeout)
|
if (get_tmr_ms() > timeout)
|
||||||
{
|
{
|
||||||
@@ -184,7 +184,7 @@ static int _sdmmc_wait_type4(sdmmc_t *sdmmc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
timeout = get_tmr_ms() + 10;
|
timeout = get_tmr_ms() + 10;
|
||||||
while (sdmmc->regs->field_1BC & 0x80000000)
|
while (sdmmc->regs->dllcfgstatus & 0x80000000)
|
||||||
{
|
{
|
||||||
if (get_tmr_ms() > timeout)
|
if (get_tmr_ms() > timeout)
|
||||||
{
|
{
|
||||||
@@ -233,7 +233,7 @@ int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type)
|
|||||||
sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180;
|
sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180;
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
//Non standard
|
// Non standard.
|
||||||
sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | HS400_BUS_SPEED;
|
sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | HS400_BUS_SPEED;
|
||||||
sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180;
|
sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180;
|
||||||
break;
|
break;
|
||||||
@@ -511,13 +511,17 @@ static int _sdmmc_config_tuning_once(sdmmc_t *sdmmc, u32 cmd)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
_sdmmc_setup_read_small_block(sdmmc);
|
_sdmmc_setup_read_small_block(sdmmc);
|
||||||
|
|
||||||
sdmmc->regs->norintstsen |= TEGRA_MMC_NORINTSTSEN_BUFFER_READ_READY;
|
sdmmc->regs->norintstsen |= TEGRA_MMC_NORINTSTSEN_BUFFER_READ_READY;
|
||||||
sdmmc->regs->norintsts = sdmmc->regs->norintsts;
|
sdmmc->regs->norintsts = sdmmc->regs->norintsts;
|
||||||
sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||||
|
|
||||||
_sdmmc_parse_cmd_48(sdmmc, cmd);
|
_sdmmc_parse_cmd_48(sdmmc, cmd);
|
||||||
_sdmmc_get_clkcon(sdmmc);
|
_sdmmc_get_clkcon(sdmmc);
|
||||||
usleep(1);
|
usleep(1);
|
||||||
|
|
||||||
_sdmmc_reset(sdmmc);
|
_sdmmc_reset(sdmmc);
|
||||||
|
|
||||||
sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||||
_sdmmc_get_clkcon(sdmmc);
|
_sdmmc_get_clkcon(sdmmc);
|
||||||
|
|
||||||
@@ -533,10 +537,13 @@ static int _sdmmc_config_tuning_once(sdmmc_t *sdmmc, u32 cmd)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_sdmmc_reset(sdmmc);
|
_sdmmc_reset(sdmmc);
|
||||||
|
|
||||||
sdmmc->regs->norintstsen &= 0xFFDF;
|
sdmmc->regs->norintstsen &= 0xFFDF;
|
||||||
_sdmmc_get_clkcon(sdmmc);
|
_sdmmc_get_clkcon(sdmmc);
|
||||||
usleep((1000 * 8 + sdmmc->divisor - 1) / sdmmc->divisor);
|
usleep((1000 * 8 + sdmmc->divisor - 1) / sdmmc->divisor);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -563,9 +570,9 @@ int sdmmc_config_tuning(sdmmc_t *sdmmc, u32 type, u32 cmd)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
sdmmc->regs->field_1C0 = (sdmmc->regs->field_1C0 & 0xFFFF1FFF) | flag;
|
sdmmc->regs->ventunctl0 = (sdmmc->regs->ventunctl0 & 0xFFFF1FFF) | flag; // Tries.
|
||||||
sdmmc->regs->field_1C0 = (sdmmc->regs->field_1C0 & 0xFFFFE03F) | 0x40;
|
sdmmc->regs->ventunctl0 = (sdmmc->regs->ventunctl0 & 0xFFFFE03F) | 0x40; // Multiplier.
|
||||||
sdmmc->regs->field_1C0 |= 0x20000;
|
sdmmc->regs->ventunctl0 |= 0x20000;
|
||||||
sdmmc->regs->hostctl2 |= SDHCI_CTRL_EXEC_TUNING;
|
sdmmc->regs->hostctl2 |= SDHCI_CTRL_EXEC_TUNING;
|
||||||
|
|
||||||
for (u32 i = 0; i < max; i++)
|
for (u32 i = 0; i < max; i++)
|
||||||
@@ -577,6 +584,7 @@ int sdmmc_config_tuning(sdmmc_t *sdmmc, u32 type, u32 cmd)
|
|||||||
|
|
||||||
if (sdmmc->regs->hostctl2 & SDHCI_CTRL_TUNED_CLK)
|
if (sdmmc->regs->hostctl2 & SDHCI_CTRL_TUNED_CLK)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -746,11 +754,14 @@ static int _sdmmc_stop_transmission_inner(sdmmc_t *sdmmc, u32 *rsp)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
_sdmmc_enable_interrupts(sdmmc);
|
_sdmmc_enable_interrupts(sdmmc);
|
||||||
|
|
||||||
cmd.cmd = MMC_STOP_TRANSMISSION;
|
cmd.cmd = MMC_STOP_TRANSMISSION;
|
||||||
cmd.arg = 0;
|
cmd.arg = 0;
|
||||||
cmd.rsp_type = SDMMC_RSP_TYPE_1;
|
cmd.rsp_type = SDMMC_RSP_TYPE_1;
|
||||||
cmd.check_busy = 1;
|
cmd.check_busy = 1;
|
||||||
|
|
||||||
_sdmmc_parse_cmdbuf(sdmmc, &cmd, false);
|
_sdmmc_parse_cmdbuf(sdmmc, &cmd, false);
|
||||||
|
|
||||||
int res = _sdmmc_wait_request(sdmmc);
|
int res = _sdmmc_wait_request(sdmmc);
|
||||||
_sdmmc_mask_interrupts(sdmmc);
|
_sdmmc_mask_interrupts(sdmmc);
|
||||||
|
|
||||||
@@ -758,6 +769,7 @@ static int _sdmmc_stop_transmission_inner(sdmmc_t *sdmmc, u32 *rsp)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
_sdmmc_cache_rsp(sdmmc, rsp, 4, SDMMC_RSP_TYPE_1);
|
_sdmmc_cache_rsp(sdmmc, rsp, 4, SDMMC_RSP_TYPE_1);
|
||||||
|
|
||||||
return _sdmmc_wait_prnsts_type1(sdmmc);
|
return _sdmmc_wait_prnsts_type1(sdmmc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -777,6 +789,7 @@ int sdmmc_stop_transmission(sdmmc_t *sdmmc, u32 *rsp)
|
|||||||
|
|
||||||
int res = _sdmmc_stop_transmission_inner(sdmmc, rsp);
|
int res = _sdmmc_stop_transmission_inner(sdmmc, rsp);
|
||||||
usleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor);
|
usleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor);
|
||||||
|
|
||||||
if (should_disable_sd_clock)
|
if (should_disable_sd_clock)
|
||||||
sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||||
|
|
||||||
@@ -817,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;
|
trnmode |= TEGRA_MMC_TRNMOD_DATA_XFER_DIR_SEL_READ;
|
||||||
if (req->is_auto_cmd12)
|
if (req->is_auto_cmd12)
|
||||||
trnmode = (trnmode & 0xFFF3) | TEGRA_MMC_TRNMOD_AUTO_CMD12;
|
trnmode = (trnmode & 0xFFF3) | TEGRA_MMC_TRNMOD_AUTO_CMD12;
|
||||||
|
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY);
|
||||||
sdmmc->regs->trnmod = trnmode;
|
sdmmc->regs->trnmod = trnmode;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@@ -841,7 +854,10 @@ static int _sdmmc_update_dma(sdmmc_t *sdmmc)
|
|||||||
if (res < 0)
|
if (res < 0)
|
||||||
break;
|
break;
|
||||||
if (intr & TEGRA_MMC_NORINTSTS_XFER_COMPLETE)
|
if (intr & TEGRA_MMC_NORINTSTS_XFER_COMPLETE)
|
||||||
|
{
|
||||||
|
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY);
|
||||||
return 1; // Transfer complete.
|
return 1; // Transfer complete.
|
||||||
|
}
|
||||||
if (intr & TEGRA_MMC_NORINTSTS_DMA_INTERRUPT)
|
if (intr & TEGRA_MMC_NORINTSTS_DMA_INTERRUPT)
|
||||||
{
|
{
|
||||||
// Update DMA.
|
// Update DMA.
|
||||||
@@ -906,6 +922,7 @@ static int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_
|
|||||||
{
|
{
|
||||||
if (blkcnt_out)
|
if (blkcnt_out)
|
||||||
*blkcnt_out = blkcnt;
|
*blkcnt_out = blkcnt;
|
||||||
|
|
||||||
if (req->is_auto_cmd12)
|
if (req->is_auto_cmd12)
|
||||||
sdmmc->rsp3 = sdmmc->regs->rspreg3;
|
sdmmc->rsp3 = sdmmc->regs->rspreg3;
|
||||||
}
|
}
|
||||||
@@ -925,6 +942,8 @@ static int _sdmmc_config_sdmmc1()
|
|||||||
gpio_config(GPIO_PORT_Z, GPIO_PIN_1, GPIO_MODE_GPIO);
|
gpio_config(GPIO_PORT_Z, GPIO_PIN_1, GPIO_MODE_GPIO);
|
||||||
gpio_output_enable(GPIO_PORT_Z, GPIO_PIN_1, GPIO_OUTPUT_DISABLE);
|
gpio_output_enable(GPIO_PORT_Z, GPIO_PIN_1, GPIO_OUTPUT_DISABLE);
|
||||||
usleep(100);
|
usleep(100);
|
||||||
|
|
||||||
|
// Check if SD card is inserted.
|
||||||
if(!!gpio_read(GPIO_PORT_Z, GPIO_PIN_1))
|
if(!!gpio_read(GPIO_PORT_Z, GPIO_PIN_1))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@@ -938,7 +957,7 @@ static int _sdmmc_config_sdmmc1()
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Configure SDMMC1 pinmux.
|
// Configure SDMMC1 pinmux.
|
||||||
APB_MISC(APB_MISC_GP_SDMMC1_CLK_LPBK_CONTROL) = 1;
|
APB_MISC(APB_MISC_GP_SDMMC1_CLK_LPBK_CONTROL) = 1; // Enable deep loopback for SDMMC1 CLK pad.
|
||||||
PINMUX_AUX(PINMUX_AUX_SDMMC1_CLK) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED;
|
PINMUX_AUX(PINMUX_AUX_SDMMC1_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_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;
|
PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT3) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_PULL_UP;
|
||||||
@@ -1002,25 +1021,30 @@ int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type, int n
|
|||||||
sdmmc->clock_stopped = 0;
|
sdmmc->clock_stopped = 0;
|
||||||
|
|
||||||
//TODO: make this skip-able.
|
//TODO: make this skip-able.
|
||||||
sdmmc->regs->field_1F0 |= 0x80000;
|
sdmmc->regs->iospare |= 0x80000;
|
||||||
sdmmc->regs->field_1AC &= 0xFFFFFFFB;
|
sdmmc->regs->veniotrimctl &= 0xFFFFFFFB;
|
||||||
static const u32 trim_values[] = { 2, 8, 3, 8 };
|
static const u32 trim_values[] = { 2, 8, 3, 8 };
|
||||||
sdmmc->regs->venclkctl = (sdmmc->regs->venclkctl & 0xE0FFFFFF) | (trim_values[sdmmc->id] << 24);
|
sdmmc->regs->venclkctl = (sdmmc->regs->venclkctl & 0xE0FFFFFF) | (trim_values[sdmmc->id] << 24);
|
||||||
sdmmc->regs->sdmemcmppadctl = (sdmmc->regs->sdmemcmppadctl & 0xF) | 7;
|
sdmmc->regs->sdmemcmppadctl = (sdmmc->regs->sdmemcmppadctl & 0xF) | 7;
|
||||||
if (!_sdmmc_autocal_config_offset(sdmmc, power))
|
if (!_sdmmc_autocal_config_offset(sdmmc, power))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
_sdmmc_autocal_execute(sdmmc, power);
|
_sdmmc_autocal_execute(sdmmc, power);
|
||||||
|
|
||||||
if (_sdmmc_enable_internal_clock(sdmmc))
|
if (_sdmmc_enable_internal_clock(sdmmc))
|
||||||
{
|
{
|
||||||
sdmmc_set_bus_width(sdmmc, bus_width);
|
sdmmc_set_bus_width(sdmmc, bus_width);
|
||||||
_sdmmc_set_voltage(sdmmc, power);
|
_sdmmc_set_voltage(sdmmc, power);
|
||||||
|
|
||||||
if (sdmmc_setup_clock(sdmmc, type))
|
if (sdmmc_setup_clock(sdmmc, type))
|
||||||
{
|
{
|
||||||
sdmmc_sd_clock_ctrl(sdmmc, no_sd);
|
sdmmc_sd_clock_ctrl(sdmmc, no_sd);
|
||||||
_sdmmc_sd_clock_enable(sdmmc);
|
_sdmmc_sd_clock_enable(sdmmc);
|
||||||
_sdmmc_get_clkcon(sdmmc);
|
_sdmmc_get_clkcon(sdmmc);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1038,7 +1062,9 @@ void sdmmc_end(sdmmc_t *sdmmc)
|
|||||||
if (sdmmc->id == SDMMC_1)
|
if (sdmmc->id == SDMMC_1)
|
||||||
{
|
{
|
||||||
gpio_output_enable(GPIO_PORT_E, GPIO_PIN_4, GPIO_OUTPUT_DISABLE);
|
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);
|
_sdmmc_get_clkcon(sdmmc);
|
||||||
@@ -1075,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);
|
int res = _sdmmc_execute_cmd_inner(sdmmc, cmd, req, blkcnt_out);
|
||||||
usleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor);
|
usleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor);
|
||||||
|
|
||||||
if (should_disable_sd_clock)
|
if (should_disable_sd_clock)
|
||||||
sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||||
|
|
||||||
@@ -1091,6 +1118,14 @@ int sdmmc_enable_low_voltage(sdmmc_t *sdmmc)
|
|||||||
|
|
||||||
_sdmmc_get_clkcon(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);
|
max77620_regulator_set_voltage(REGULATOR_LDO2, 1800000);
|
||||||
PMC(APBDEV_PMC_PWR_DET_VAL) &= ~(1 << 12);
|
PMC(APBDEV_PMC_PWR_DET_VAL) &= ~(1 << 12);
|
||||||
|
|
||||||
@@ -1104,7 +1139,7 @@ int sdmmc_enable_low_voltage(sdmmc_t *sdmmc)
|
|||||||
{
|
{
|
||||||
sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||||
_sdmmc_get_clkcon(sdmmc);
|
_sdmmc_get_clkcon(sdmmc);
|
||||||
msleep(1);
|
usleep(1000);
|
||||||
if ((sdmmc->regs->prnsts & 0xF00000) == 0xF00000)
|
if ((sdmmc->regs->prnsts & 0xF00000) == 0xF00000)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,18 +115,18 @@ typedef struct _t210_sdmmc_t
|
|||||||
vu32 vendebouncecnt;
|
vu32 vendebouncecnt;
|
||||||
vu32 venmiscctl;
|
vu32 venmiscctl;
|
||||||
vu32 res6[34];
|
vu32 res6[34];
|
||||||
vu32 field_1AC;
|
vu32 veniotrimctl;
|
||||||
vu32 field_1B0;
|
vu32 vendllcal;
|
||||||
vu8 res7[8];
|
vu8 res7[8];
|
||||||
vu32 field_1BC;
|
vu32 dllcfgstatus;
|
||||||
vu32 field_1C0;
|
vu32 ventunctl0;
|
||||||
vu32 field_1C4;
|
vu32 field_1C4;
|
||||||
vu8 field_1C8[24];
|
vu8 field_1C8[24];
|
||||||
vu32 sdmemcmppadctl;
|
vu32 sdmemcmppadctl;
|
||||||
vu32 autocalcfg;
|
vu32 autocalcfg;
|
||||||
vu32 autocalintval;
|
vu32 autocalintval;
|
||||||
vu32 autocalsts;
|
vu32 autocalsts;
|
||||||
vu32 field_1F0;
|
vu32 iospare;
|
||||||
} t210_sdmmc_t;
|
} t210_sdmmc_t;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -22,21 +22,21 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "../power/max77620.h"
|
#include "../power/max77620.h"
|
||||||
|
|
||||||
u32 btn_read()
|
u8 btn_read()
|
||||||
{
|
{
|
||||||
u32 res = 0;
|
u8 res = 0;
|
||||||
if (!gpio_read(GPIO_PORT_X, GPIO_PIN_7))
|
if (!gpio_read(GPIO_PORT_X, GPIO_PIN_7))
|
||||||
res |= BTN_VOL_DOWN;
|
res |= BTN_VOL_DOWN;
|
||||||
if (!gpio_read(GPIO_PORT_X, GPIO_PIN_6))
|
if (!gpio_read(GPIO_PORT_X, GPIO_PIN_6))
|
||||||
res |= BTN_VOL_UP;
|
res |= BTN_VOL_UP;
|
||||||
if (i2c_recv_byte(4, MAX77620_I2C_ADDR, 0x15) & 0x4)
|
if (i2c_recv_byte(4, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFSTAT) & 0x4)
|
||||||
res |= BTN_POWER;
|
res |= BTN_POWER;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 btn_wait()
|
u8 btn_wait()
|
||||||
{
|
{
|
||||||
u32 res = 0, btn = btn_read();
|
u8 res = 0, btn = btn_read();
|
||||||
bool pwr = false;
|
bool pwr = false;
|
||||||
|
|
||||||
//Power button down, raise a filter.
|
//Power button down, raise a filter.
|
||||||
@@ -59,16 +59,18 @@ u32 btn_wait()
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 btn_wait_timeout(u32 time_ms, u32 mask)
|
u8 btn_wait_timeout(u32 time_ms, u8 mask)
|
||||||
{
|
{
|
||||||
u32 timeout = get_tmr_ms() + time_ms;
|
u32 timeout = get_tmr_ms() + time_ms;
|
||||||
u32 res = btn_read() & mask;
|
u8 res = btn_read() & mask;
|
||||||
|
|
||||||
do
|
while (get_tmr_ms() < timeout)
|
||||||
{
|
{
|
||||||
if (!(res & mask))
|
if (res == mask)
|
||||||
|
break;
|
||||||
|
else
|
||||||
res = btn_read() & mask;
|
res = btn_read() & mask;
|
||||||
} while (get_tmr_ms() < timeout);
|
};
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,12 +20,12 @@
|
|||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
#define BTN_POWER 0x1
|
#define BTN_POWER (1 << 0)
|
||||||
#define BTN_VOL_DOWN 0x2
|
#define BTN_VOL_DOWN (1 << 1)
|
||||||
#define BTN_VOL_UP 0x4
|
#define BTN_VOL_UP (1 << 2)
|
||||||
|
|
||||||
u32 btn_read();
|
u8 btn_read();
|
||||||
u32 btn_wait();
|
u8 btn_wait();
|
||||||
u32 btn_wait_timeout(u32 time_ms, u32 mask);
|
u8 btn_wait_timeout(u32 time_ms, u8 mask);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ char *dirlist(const char *directory, const char *pattern, bool includeHiddenFile
|
|||||||
int res = 0;
|
int res = 0;
|
||||||
u32 i = 0, j = 0, k = 0;
|
u32 i = 0, j = 0, k = 0;
|
||||||
DIR dir;
|
DIR dir;
|
||||||
static FILINFO fno;
|
FILINFO fno;
|
||||||
|
|
||||||
char *dir_entries = (char *)calloc(max_entries, 256);
|
char *dir_entries = (char *)calloc(max_entries, 256);
|
||||||
char *temp = (char *)calloc(1, 256);
|
char *temp = (char *)calloc(1, 256);
|
||||||
@@ -74,6 +74,7 @@ char *dirlist(const char *directory, const char *pattern, bool includeHiddenFile
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reorder ini files by ASCII ordering.
|
||||||
for (i = 0; i < k - 1 ; i++)
|
for (i = 0; i < k - 1 ; i++)
|
||||||
{
|
{
|
||||||
for (j = i + 1; j < k; j++)
|
for (j = i + 1; j < k; j++)
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
#define OFFSET_OF(t, m) ((u32)&((t *)NULL)->m)
|
#define OFFSET_OF(t, m) ((u32)&((t *)NULL)->m)
|
||||||
#define CONTAINER_OF(mp, t, mn) ((t *)((u32)mp - OFFSET_OF(t, mn)))
|
#define CONTAINER_OF(mp, t, mn) ((t *)((u32)mp - OFFSET_OF(t, mn)))
|
||||||
|
|
||||||
typedef char s8;
|
typedef signed char s8;
|
||||||
typedef short s16;
|
typedef short s16;
|
||||||
typedef short SHORT;
|
typedef short SHORT;
|
||||||
typedef int s32;
|
typedef int s32;
|
||||||
@@ -51,4 +51,48 @@ typedef int bool;
|
|||||||
#define true 1
|
#define true 1
|
||||||
#define false 0
|
#define false 0
|
||||||
|
|
||||||
|
#define BOOT_CFG_AUTOBOOT_EN (1 << 0)
|
||||||
|
#define BOOT_CFG_FROM_LAUNCH (1 << 1)
|
||||||
|
#define BOOT_CFG_FROM_ID (1 << 2)
|
||||||
|
#define BOOT_CFG_SEPT_RUN (1 << 7)
|
||||||
|
|
||||||
|
#define EXTRA_CFG_KEYS (1 << 0)
|
||||||
|
#define EXTRA_CFG_PAYLOAD (1 << 1)
|
||||||
|
#define EXTRA_CFG_MODULE (1 << 2)
|
||||||
|
|
||||||
|
#define EXTRA_CFG_NYX_RELOAD (1 << 6)
|
||||||
|
#define EXTRA_CFG_NYX_DUMP (1 << 7)
|
||||||
|
|
||||||
|
typedef struct __attribute__((__packed__)) _boot_cfg_t
|
||||||
|
{
|
||||||
|
u8 boot_cfg;
|
||||||
|
u8 autoboot;
|
||||||
|
u8 autoboot_list;
|
||||||
|
u8 extra_cfg;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
char id[8];
|
||||||
|
};
|
||||||
|
u8 xt_str[0x80];
|
||||||
|
};
|
||||||
|
} boot_cfg_t;
|
||||||
|
|
||||||
|
typedef struct __attribute__((__packed__)) _ipl_ver_meta_t
|
||||||
|
{
|
||||||
|
u32 magic;
|
||||||
|
u32 version;
|
||||||
|
u16 rsvd0;
|
||||||
|
u16 rsvd1;
|
||||||
|
} ipl_ver_meta_t;
|
||||||
|
|
||||||
|
typedef struct __attribute__((__packed__)) _reloc_meta_t
|
||||||
|
{
|
||||||
|
u32 start;
|
||||||
|
u32 stack;
|
||||||
|
u32 end;
|
||||||
|
u32 ep;
|
||||||
|
} reloc_meta_t;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -16,8 +16,18 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "../gfx/di.h"
|
||||||
|
#include "../power/max77620.h"
|
||||||
|
#include "../rtc/max77620-rtc.h"
|
||||||
|
#include "../soc/bpmp.h"
|
||||||
|
#include "../soc/i2c.h"
|
||||||
|
#include "../soc/pmc.h"
|
||||||
#include "../soc/t210.h"
|
#include "../soc/t210.h"
|
||||||
|
|
||||||
|
#define USE_RTC_TIMER
|
||||||
|
|
||||||
|
extern void sd_unmount();
|
||||||
|
|
||||||
u32 get_tmr_s()
|
u32 get_tmr_s()
|
||||||
{
|
{
|
||||||
return RTC(APBDEV_RTC_SECONDS);
|
return RTC(APBDEV_RTC_SECONDS);
|
||||||
@@ -26,8 +36,8 @@ u32 get_tmr_s()
|
|||||||
u32 get_tmr_ms()
|
u32 get_tmr_ms()
|
||||||
{
|
{
|
||||||
// The registers must be read with the following order:
|
// The registers must be read with the following order:
|
||||||
// -> RTC_MILLI_SECONDS (0x10) -> RTC_SHADOW_SECONDS (0xC)
|
// RTC_MILLI_SECONDS (0x10) -> RTC_SHADOW_SECONDS (0xC)
|
||||||
return (RTC(APBDEV_RTC_MILLI_SECONDS) | (RTC(APBDEV_RTC_SHADOW_SECONDS) << 10));
|
return (RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000));
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 get_tmr_us()
|
u32 get_tmr_us()
|
||||||
@@ -35,19 +45,32 @@ u32 get_tmr_us()
|
|||||||
return TMR(TIMERUS_CNTR_1US); //TIMERUS_CNTR_1US
|
return TMR(TIMERUS_CNTR_1US); //TIMERUS_CNTR_1US
|
||||||
}
|
}
|
||||||
|
|
||||||
void msleep(u32 milliseconds)
|
void msleep(u32 ms)
|
||||||
{
|
{
|
||||||
u32 start = RTC(APBDEV_RTC_MILLI_SECONDS) | (RTC(APBDEV_RTC_SHADOW_SECONDS) << 10);
|
#ifdef USE_RTC_TIMER
|
||||||
while (((RTC(APBDEV_RTC_MILLI_SECONDS) | (RTC(APBDEV_RTC_SHADOW_SECONDS) << 10)) - start) <= milliseconds)
|
u32 start = RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000);
|
||||||
|
// Casting to u32 is important!
|
||||||
|
while (((u32)(RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000)) - start) <= ms)
|
||||||
;
|
;
|
||||||
|
#else
|
||||||
|
bpmp_msleep(ms);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void usleep(u32 microseconds)
|
void usleep(u32 us)
|
||||||
{
|
{
|
||||||
|
#ifdef USE_RTC_TIMER
|
||||||
u32 start = TMR(TIMERUS_CNTR_1US);
|
u32 start = TMR(TIMERUS_CNTR_1US);
|
||||||
// Casting to u32 is important!
|
|
||||||
while ((u32)(TMR(TIMERUS_CNTR_1US) - start) <= microseconds)
|
// Check if timer is at upper limits and use BPMP sleep so it doesn't wake up immediately.
|
||||||
|
if ((start + us) < start)
|
||||||
|
bpmp_usleep(us);
|
||||||
|
else
|
||||||
|
while ((u32)(TMR(TIMERUS_CNTR_1US) - start) <= us) // Casting to u32 is important!
|
||||||
;
|
;
|
||||||
|
#else
|
||||||
|
bpmp_usleep(us);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops)
|
void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops)
|
||||||
@@ -56,44 +79,54 @@ void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops)
|
|||||||
base[ops[i].off] = ops[i].val;
|
base[ops[i].off] = ops[i].val;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CRC32C_POLY 0x82F63B78
|
void panic(u32 val)
|
||||||
u32 crc32c(const void *buf, u32 len)
|
|
||||||
{
|
{
|
||||||
const u8 *cbuf = (const u8 *)buf;
|
// Set panic code.
|
||||||
u32 crc = 0xFFFFFFFF;
|
PMC(APBDEV_PMC_SCRATCH200) = val;
|
||||||
while (len--)
|
//PMC(APBDEV_PMC_CRYPTO_OP) = PMC_CRYPTO_OP_SE_DISABLE;
|
||||||
{
|
TMR(TIMER_WDT4_UNLOCK_PATTERN) = TIMER_MAGIC_PTRN;
|
||||||
crc ^= *cbuf++;
|
TMR(TIMER_TMR9_TMR_PTV) = TIMER_EN | TIMER_PER_EN;
|
||||||
for (int i = 0; i < 8; i++)
|
TMR(TIMER_WDT4_CONFIG) = TIMER_SRC(9) | TIMER_PER(1) | TIMER_PMCRESET_EN;
|
||||||
crc = crc & 1 ? (crc >> 1) ^ CRC32C_POLY : crc >> 1;
|
TMR(TIMER_WDT4_COMMAND) = TIMER_START_CNT;
|
||||||
}
|
|
||||||
return ~crc;
|
while (true)
|
||||||
|
usleep(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 memcmp32sparse(const u32 *buf1, const u32 *buf2, u32 len)
|
void reboot_normal()
|
||||||
{
|
{
|
||||||
u32 len32 = len / 4;
|
bpmp_mmu_disable();
|
||||||
|
|
||||||
if (!(len32 % 32))
|
sd_unmount();
|
||||||
{
|
display_end();
|
||||||
while (len32)
|
|
||||||
{
|
panic(0x21); // Bypass fuse programming in package1.
|
||||||
len32 -= 32;
|
|
||||||
if(buf1[len32] != buf2[len32])
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
while (len32)
|
|
||||||
{
|
|
||||||
len32 -= 32;
|
|
||||||
if(buf1[len32] != buf2[len32])
|
|
||||||
return 1;
|
|
||||||
if (len32 < 32)
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
void reboot_rcm()
|
||||||
|
{
|
||||||
|
bpmp_mmu_disable();
|
||||||
|
|
||||||
|
sd_unmount();
|
||||||
|
display_end();
|
||||||
|
|
||||||
|
PMC(APBDEV_PMC_SCRATCH0) = 2; // Reboot into rcm.
|
||||||
|
PMC(APBDEV_PMC_CNTRL) |= PMC_CNTRL_MAIN_RST;
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
bpmp_halt();
|
||||||
|
}
|
||||||
|
|
||||||
|
void power_off()
|
||||||
|
{
|
||||||
|
sd_unmount();
|
||||||
|
display_end();
|
||||||
|
|
||||||
|
// Stop the alarm, in case we injected and powered off too fast.
|
||||||
|
max77620_rtc_stop_alarm();
|
||||||
|
|
||||||
|
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1, MAX77620_ONOFFCNFG1_PWR_OFF);
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
bpmp_halt();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,9 +19,13 @@
|
|||||||
#define _UTIL_H_
|
#define _UTIL_H_
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
#include "../mem/minerva.h"
|
||||||
|
|
||||||
#define byte_swap_32(num) ((num >> 24) & 0xff) | ((num << 8) & 0xff0000) | \
|
#define NYX_CFG_DUMP (1 << 7)
|
||||||
((num >> 8 )& 0xff00) | ((num << 24) & 0xff000000)
|
#define NYX_CFG_MINERVA (1 << 8)
|
||||||
|
|
||||||
|
#define byte_swap_32(num) (((num >> 24) & 0xff) | ((num << 8) & 0xff0000) | \
|
||||||
|
((num >> 8 )& 0xff00) | ((num << 24) & 0xff000000))
|
||||||
|
|
||||||
typedef struct _cfg_op_t
|
typedef struct _cfg_op_t
|
||||||
{
|
{
|
||||||
@@ -29,16 +33,25 @@ typedef struct _cfg_op_t
|
|||||||
u32 val;
|
u32 val;
|
||||||
} cfg_op_t;
|
} cfg_op_t;
|
||||||
|
|
||||||
|
typedef struct _nyx_storage_t
|
||||||
|
{
|
||||||
|
u32 version;
|
||||||
|
u32 cfg;
|
||||||
|
u8 irama[0x8000];
|
||||||
|
u8 hekate[0x30000];
|
||||||
|
u8 rsvd[0x800000];
|
||||||
|
mtc_config_t mtc_cfg;
|
||||||
|
} nyx_storage_t;
|
||||||
|
|
||||||
u32 get_tmr_us();
|
u32 get_tmr_us();
|
||||||
u32 get_tmr_ms();
|
u32 get_tmr_ms();
|
||||||
u32 get_tmr_s();
|
u32 get_tmr_s();
|
||||||
void usleep(u32 ticks);
|
void usleep(u32 us);
|
||||||
void msleep(u32 milliseconds);
|
void msleep(u32 ms);
|
||||||
|
void panic(u32 val);
|
||||||
|
void reboot_normal();
|
||||||
|
void reboot_rcm();
|
||||||
|
void power_off();
|
||||||
void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops);
|
void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops);
|
||||||
u32 crc32c(const void *buf, u32 len);
|
|
||||||
|
|
||||||
/* This is a faster implementation of memcmp that checks two u32 values */
|
|
||||||
/* every 128 Bytes block. Intented only for Backup and Restore */
|
|
||||||
u32 memcmp32sparse(const u32 *buf1, const u32 *buf2, u32 len);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -3856,9 +3856,9 @@ u32 _minerva_do_periodic_compensation(emc_table_t *mtc_table_entry)
|
|||||||
if (channel1_enabled)
|
if (channel1_enabled)
|
||||||
_wait_emc_status(EMC_EMC_STATUS, IN_SELF_REFRESH_MASK, 0, channel1_enabled);
|
_wait_emc_status(EMC_EMC_STATUS, IN_SELF_REFRESH_MASK, 0, channel1_enabled);
|
||||||
|
|
||||||
_wait_emc_status(EMC_EMC_STATUS, REQ_FIFO_EMPTY, 0, EMC_CH0); //v1.6
|
//_wait_emc_status(EMC_EMC_STATUS, REQ_FIFO_EMPTY, 0, EMC_CH0); //v1.6
|
||||||
if (channel1_enabled)
|
//if (channel1_enabled)
|
||||||
_wait_emc_status(EMC_EMC_STATUS, REQ_FIFO_EMPTY, 0, channel1_enabled); //v1.6
|
// _wait_emc_status(EMC_EMC_STATUS, REQ_FIFO_EMPTY, 0, channel1_enabled); //v1.6
|
||||||
|
|
||||||
u32 emc_cfg_update = EMC(EMC_CFG_UPDATE);
|
u32 emc_cfg_update = EMC(EMC_CFG_UPDATE);
|
||||||
EMC(EMC_CFG_UPDATE) = (emc_cfg_update & 0xFFFFF9FF) | 0x400;
|
EMC(EMC_CFG_UPDATE) = (emc_cfg_update & 0xFFFFF9FF) | 0x400;
|
||||||
|
|||||||
117
nyx/Makefile
Normal file
117
nyx/Makefile
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
ifeq ($(strip $(DEVKITARM)),)
|
||||||
|
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
|
||||||
|
endif
|
||||||
|
|
||||||
|
include $(DEVKITARM)/base_rules
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
NYX_LOAD_ADDR := 0x40003000
|
||||||
|
NYX_RES_ADDR := 0xEE000000
|
||||||
|
NYX_STORAGE_ADDR := 0xED000000
|
||||||
|
NYX_MAGIC := 0x43544347 #"GCTC"
|
||||||
|
BLVERSION_MAJOR := 0
|
||||||
|
BLVERSION_MINOR := 8
|
||||||
|
BLVERSION_HOTFX := 2
|
||||||
|
|
||||||
|
BL_RESERVED := 0
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
TARGET := nyx
|
||||||
|
BUILDDIR := ./../build
|
||||||
|
OUTPUTDIR := ./../output
|
||||||
|
SOURCEDIR = nyx_gui
|
||||||
|
VPATH = $(dir $(wildcard ./$(SOURCEDIR)/*/)) $(dir $(wildcard ./$(SOURCEDIR)/*/*/))
|
||||||
|
VPATH += $(dir $(wildcard ./$(SOURCEDIR)/*/*/*/)) $(dir $(wildcard ./$(SOURCEDIR)/*/*/*/*/))
|
||||||
|
|
||||||
|
# Main and graphics.
|
||||||
|
OBJS = $(addprefix $(BUILDDIR)/$(TARGET)/, \
|
||||||
|
start.o \
|
||||||
|
nyx.o heap.o \
|
||||||
|
gfx.o \
|
||||||
|
gui.o gui_info.o gui_tools.o gui_options.o gui_emmc_tools.o gui_emummc_tools.o \
|
||||||
|
fe_emummc_tools.o fe_emmc_tools.o \
|
||||||
|
)
|
||||||
|
|
||||||
|
# Hardware.
|
||||||
|
OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \
|
||||||
|
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 \
|
||||||
|
bq24193.o max17050.o max7762x.o max77620-rtc.o \
|
||||||
|
touch.o tmp451.o fan.o \
|
||||||
|
hw_init.o \
|
||||||
|
)
|
||||||
|
|
||||||
|
# Utilities.
|
||||||
|
OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \
|
||||||
|
btn.o dirlist.o ianos.o util.o \
|
||||||
|
config.o ini.o \
|
||||||
|
sprintf.o \
|
||||||
|
)
|
||||||
|
|
||||||
|
# Horizon.
|
||||||
|
OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \
|
||||||
|
nx_emmc.o \
|
||||||
|
hos.o pkg1.o pkg2.o sept.o \
|
||||||
|
)
|
||||||
|
|
||||||
|
# Libraries.
|
||||||
|
OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \
|
||||||
|
diskio.o ff.o ffunicode.o ffsystem.o \
|
||||||
|
elfload.o elfreloc_arm.o \
|
||||||
|
lv_group.o lv_indev.o lv_obj.o lv_refr.o lv_style.o lv_vdb.o \
|
||||||
|
lv_draw.o lv_draw_rbasic.o lv_draw_vbasic.o lv_draw_arc.o lv_draw_img.o \
|
||||||
|
lv_draw_label.o lv_draw_line.o lv_draw_rect.o lv_draw_triangle.o \
|
||||||
|
lv_hal_disp.o lv_hal_indev.o lv_hal_tick.o \
|
||||||
|
interui_20.o interui_30.o ubuntu_mono.o hekate_symbol_20.o hekate_symbol_30.o hekate_symbol_120.o lv_font_builtin.o \
|
||||||
|
lv_anim.o lv_area.o lv_circ.o lv_color.o lv_font.o lv_ll.o lv_math.o lv_mem.o lv_task.o lv_txt.o lv_gc.o \
|
||||||
|
lv_bar.o lv_btn.o lv_btnm.o lv_cb.o lv_cont.o lv_ddlist.o lv_img.o lv_kb.o lv_label.o lv_line.o lv_list.o lv_lmeter.o lv_mbox.o \
|
||||||
|
lv_page.o lv_roller.o lv_slider.o lv_sw.o lv_tabview.o lv_ta.o lv_win.o lv_log.o lv_imgbtn.o \
|
||||||
|
lv_theme.o lv_theme_hekate.o \
|
||||||
|
)
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
CUSTOMDEFINES := -DNYX_RES_ADDR=$(NYX_RES_ADDR) -DNYX_STORAGE_ADDR=$(NYX_STORAGE_ADDR)
|
||||||
|
CUSTOMDEFINES += -DNYX_LOAD_ADDR=$(NYX_LOAD_ADDR) -DBL_MAGIC=$(NYX_MAGIC)
|
||||||
|
CUSTOMDEFINES += -DBL_VER_MJ=$(BLVERSION_MAJOR) -DBL_VER_MN=$(BLVERSION_MINOR) -DBL_VER_HF=$(BLVERSION_HOTFX) -DBL_RESERVED=$(BL_RESERVED)
|
||||||
|
|
||||||
|
# 0: UART_A, 1: UART_B.
|
||||||
|
#CUSTOMDEFINES += -DDEBUG_UART_PORT=1
|
||||||
|
|
||||||
|
#CUSTOMDEFINES += -DDEBUG
|
||||||
|
|
||||||
|
ARCH := -march=armv4t -mtune=arm7tdmi -mthumb-interwork
|
||||||
|
CFLAGS = $(ARCH) -O2 -nostdlib -ffunction-sections -fdata-sections -flto -fomit-frame-pointer -fno-inline -fno-strict-aliasing -std=gnu11 -Wall $(CUSTOMDEFINES)
|
||||||
|
CFLAGS += -g
|
||||||
|
LDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections -Xlinker --defsym=NYX_LOAD_ADDR=$(NYX_LOAD_ADDR)
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
.PHONY: all clean
|
||||||
|
|
||||||
|
all: $(TARGET).bin
|
||||||
|
@echo -n "Nyx size is "
|
||||||
|
@wc -c < $(OUTPUTDIR)/$(TARGET).bin
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@rm -rf $(OBJS)
|
||||||
|
@rm -rf $(BUILDDIR)
|
||||||
|
@rm -rf $(OUTPUTDIR)
|
||||||
|
|
||||||
|
$(TARGET).bin: $(BUILDDIR)/$(TARGET)/$(TARGET).elf
|
||||||
|
$(OBJCOPY) -S -O binary $< $(OUTPUTDIR)/$@
|
||||||
|
|
||||||
|
$(BUILDDIR)/$(TARGET)/$(TARGET).elf: $(OBJS)
|
||||||
|
$(CC) $(LDFLAGS) -T $(SOURCEDIR)/link.ld $^ -o $@
|
||||||
|
|
||||||
|
$(BUILDDIR)/$(TARGET)/%.o: %.c
|
||||||
|
$(CC) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
$(BUILDDIR)/$(TARGET)/%.o: %.S
|
||||||
|
@mkdir -p "$(BUILDDIR)"
|
||||||
|
@mkdir -p "$(BUILDDIR)/$(TARGET)"
|
||||||
|
@mkdir -p "$(OUTPUTDIR)"
|
||||||
|
$(CC) $(CFLAGS) -c $< -o $@
|
||||||
12
nyx/README_RES.md
Normal file
12
nyx/README_RES.md
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# Nyx - Background - Icons
|
||||||
|
|
||||||
|
The background for Nyx, must be a 1280 x 720 32-bit BMP. Alpha blending is taken into account. For that reason, if a solid background is required, that value must be 0xFF. There are sites that can produce the correct bmp.
|
||||||
|
|
||||||
|
The icons supported are 192 x 192 32-bit BMP. You can utilize transparency at will and make nice mixes with the button background.
|
||||||
|
|
||||||
|
|
||||||
|
## How to configure
|
||||||
|
|
||||||
|
The background must go to /bootloader/res/background.bmp
|
||||||
|
|
||||||
|
The icons can be utilized either via `[boot entries names]` -> `boot entries names.bmp` or by using `icon={sd path}`, which should point at a bmp.
|
||||||
172
nyx/nyx_gui/config/config.c
Normal file
172
nyx/nyx_gui/config/config.c
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "ini.h"
|
||||||
|
#include "../gfx/gfx.h"
|
||||||
|
#include "../libs/fatfs/ff.h"
|
||||||
|
#include "../soc/fuse.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 bool sd_mount();
|
||||||
|
extern void sd_unmount(bool deinit);
|
||||||
|
|
||||||
|
#pragma GCC push_options
|
||||||
|
#pragma GCC target ("thumb")
|
||||||
|
|
||||||
|
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.autonogc = 1;
|
||||||
|
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 = fuse_check_patched_rcm();
|
||||||
|
h_cfg.emummc_force_disable = false;
|
||||||
|
|
||||||
|
sd_power_cycle_time_start = 0xFFFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
int create_config_entry()
|
||||||
|
{
|
||||||
|
if (!sd_mount())
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
char lbuf[32];
|
||||||
|
FIL fp;
|
||||||
|
bool mainIniFound = false;
|
||||||
|
|
||||||
|
LIST_INIT(ini_sections);
|
||||||
|
|
||||||
|
if (ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false))
|
||||||
|
mainIniFound = true;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
u8 res = f_open(&fp, "bootloader/hekate_ipl.ini", FA_READ);
|
||||||
|
if (res == FR_NO_FILE || res == FR_NO_PATH)
|
||||||
|
{
|
||||||
|
f_mkdir("bootloader");
|
||||||
|
f_mkdir("bootloader/ini");
|
||||||
|
f_mkdir("bootloader/payloads");
|
||||||
|
f_mkdir("bootloader/sys");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!res)
|
||||||
|
f_close(&fp);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f_open(&fp, "bootloader/hekate_ipl.ini", FA_WRITE | FA_CREATE_ALWAYS) != FR_OK)
|
||||||
|
return 1;
|
||||||
|
// Add config entry.
|
||||||
|
f_puts("[config]\nautoboot=", &fp);
|
||||||
|
itoa(h_cfg.autoboot, lbuf, 10);
|
||||||
|
f_puts(lbuf, &fp);
|
||||||
|
f_puts("\nautoboot_list=", &fp);
|
||||||
|
itoa(h_cfg.autoboot_list, lbuf, 10);
|
||||||
|
f_puts(lbuf, &fp);
|
||||||
|
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);
|
||||||
|
f_puts("\nautohosoff=", &fp);
|
||||||
|
itoa(h_cfg.autohosoff, lbuf, 10);
|
||||||
|
f_puts(lbuf, &fp);
|
||||||
|
f_puts("\nautonogc=", &fp);
|
||||||
|
itoa(h_cfg.autonogc, 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)
|
||||||
|
{
|
||||||
|
// Re-construct existing entries.
|
||||||
|
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link)
|
||||||
|
{
|
||||||
|
if (!strcmp(ini_sec->name, "config"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
switch (ini_sec->type)
|
||||||
|
{
|
||||||
|
case INI_CHOICE: // Re-construct Boot entry [ ].
|
||||||
|
f_puts("[", &fp);
|
||||||
|
f_puts(ini_sec->name, &fp);
|
||||||
|
f_puts("]\n", &fp);
|
||||||
|
// Re-construct boot entry's config.
|
||||||
|
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)
|
||||||
|
{
|
||||||
|
f_puts(kv->key, &fp);
|
||||||
|
f_puts("=", &fp);
|
||||||
|
f_puts(kv->val, &fp);
|
||||||
|
f_puts("\n", &fp);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case INI_CAPTION: // Re-construct caption entry { }.
|
||||||
|
f_puts("{", &fp);
|
||||||
|
f_puts(ini_sec->name, &fp);
|
||||||
|
f_puts("}\n", &fp);
|
||||||
|
break;
|
||||||
|
case INI_NEWLINE: // Re-construct cosmetic newline \n.
|
||||||
|
f_puts("\n", &fp);
|
||||||
|
break;
|
||||||
|
case INI_COMMENT: // Re-construct comment entry #.
|
||||||
|
f_puts("#", &fp);
|
||||||
|
f_puts(ini_sec->name, &fp);
|
||||||
|
f_puts("\n", &fp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
f_close(&fp);
|
||||||
|
sd_unmount(false);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma GCC pop_options
|
||||||
51
nyx/nyx_gui/config/config.h
Normal file
51
nyx/nyx_gui/config/config.h
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _CONFIG_H_
|
||||||
|
#define _CONFIG_H_
|
||||||
|
|
||||||
|
#include "../utils/types.h"
|
||||||
|
|
||||||
|
typedef struct _hekate_config
|
||||||
|
{
|
||||||
|
// Non-volatile config.
|
||||||
|
u32 autoboot;
|
||||||
|
u32 autoboot_list;
|
||||||
|
u32 bootwait;
|
||||||
|
u32 verification;
|
||||||
|
u32 backlight;
|
||||||
|
u32 autohosoff;
|
||||||
|
u32 autonogc;
|
||||||
|
char *brand;
|
||||||
|
char *tagline;
|
||||||
|
// Global temporary config.
|
||||||
|
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();
|
||||||
|
|
||||||
|
#endif /* _CONFIG_H_ */
|
||||||
193
nyx/nyx_gui/config/ini.c
Normal file
193
nyx/nyx_gui/config/ini.c
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "ini.h"
|
||||||
|
#include "../libs/fatfs/ff.h"
|
||||||
|
#include "../mem/heap.h"
|
||||||
|
#include "../utils/dirlist.h"
|
||||||
|
|
||||||
|
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++)
|
||||||
|
;
|
||||||
|
lbuf[i] = 0;
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
ini_sec_t *_ini_create_section(link_t *dst, ini_sec_t *csec, char *name, u8 type)
|
||||||
|
{
|
||||||
|
if (csec)
|
||||||
|
{
|
||||||
|
list_append(dst, &csec->link);
|
||||||
|
csec = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
csec = (ini_sec_t *)malloc(sizeof(ini_sec_t));
|
||||||
|
csec->name = _strdup(name);
|
||||||
|
csec->type = type;
|
||||||
|
|
||||||
|
return csec;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ini_parse(link_t *dst, char *ini_path, bool is_dir)
|
||||||
|
{
|
||||||
|
u32 lblen;
|
||||||
|
u32 pathlen = strlen(ini_path);
|
||||||
|
u32 k = 0;
|
||||||
|
char lbuf[512];
|
||||||
|
char *filelist = NULL;
|
||||||
|
FIL fp;
|
||||||
|
ini_sec_t *csec = NULL;
|
||||||
|
|
||||||
|
char *filename = (char *)malloc(256);
|
||||||
|
|
||||||
|
memcpy(filename, ini_path, pathlen + 1);
|
||||||
|
|
||||||
|
// Get all ini filenames.
|
||||||
|
if (is_dir)
|
||||||
|
{
|
||||||
|
filelist = dirlist(filename, "*.ini", false, false);
|
||||||
|
if (!filelist)
|
||||||
|
{
|
||||||
|
free(filename);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
memcpy(filename + pathlen, "/", 2);
|
||||||
|
pathlen++;
|
||||||
|
}
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
// Copy ini filename in path string.
|
||||||
|
if (is_dir)
|
||||||
|
{
|
||||||
|
if (filelist[k * 256])
|
||||||
|
{
|
||||||
|
memcpy(filename + pathlen, &filelist[k * 256], strlen(&filelist[k * 256]) + 1);
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open ini.
|
||||||
|
if (f_open(&fp, filename, FA_READ) != FR_OK)
|
||||||
|
{
|
||||||
|
free(filelist);
|
||||||
|
free(filename);
|
||||||
|
|
||||||
|
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_section_name(lbuf, lblen, ']');
|
||||||
|
|
||||||
|
csec = _ini_create_section(dst, csec, &lbuf[1], INI_CHOICE);
|
||||||
|
list_init(&csec->kvs);
|
||||||
|
}
|
||||||
|
else if (lblen > 2 && lbuf[0] == '{') //Create new 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.
|
||||||
|
{
|
||||||
|
_find_section_name(lbuf, lblen, '\0');
|
||||||
|
|
||||||
|
csec = _ini_create_section(dst, csec, &lbuf[1], INI_COMMENT);
|
||||||
|
}
|
||||||
|
else if (lblen < 2)
|
||||||
|
{
|
||||||
|
csec = _ini_create_section(dst, csec, NULL, INI_NEWLINE);
|
||||||
|
}
|
||||||
|
else if (csec && csec->type == INI_CHOICE) //Extract key/value.
|
||||||
|
{
|
||||||
|
u32 i = _find_section_name(lbuf, lblen, '=');
|
||||||
|
|
||||||
|
ini_kv_t *kv = (ini_kv_t *)malloc(sizeof(ini_kv_t));
|
||||||
|
kv->key = _strdup(&lbuf[0]);
|
||||||
|
kv->val = _strdup(&lbuf[i + 1]);
|
||||||
|
list_append(&csec->kvs, &kv->link);
|
||||||
|
}
|
||||||
|
} while (!f_eof(&fp));
|
||||||
|
|
||||||
|
f_close(&fp);
|
||||||
|
|
||||||
|
if (csec)
|
||||||
|
{
|
||||||
|
list_append(dst, &csec->link);
|
||||||
|
if (is_dir)
|
||||||
|
csec = NULL;
|
||||||
|
}
|
||||||
|
} while (is_dir);
|
||||||
|
|
||||||
|
free(filename);
|
||||||
|
free(filelist);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *ini_check_payload_section(ini_sec_t *cfg)
|
||||||
|
{
|
||||||
|
if (cfg == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg->kvs, link)
|
||||||
|
{
|
||||||
|
if (!strcmp("payload", kv->key))
|
||||||
|
return kv->val;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
50
nyx/nyx_gui/config/ini.h
Normal file
50
nyx/nyx_gui/config/ini.h
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018 naehrwert
|
||||||
|
* 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,
|
||||||
|
* 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 _INI_H_
|
||||||
|
#define _INI_H_
|
||||||
|
|
||||||
|
#include "../utils/types.h"
|
||||||
|
#include "../utils/list.h"
|
||||||
|
|
||||||
|
#define INI_CHOICE 3
|
||||||
|
#define INI_CAPTION 5
|
||||||
|
#define INI_CHGLINE 6
|
||||||
|
#define INI_NEWLINE 0xFE
|
||||||
|
#define INI_COMMENT 0xFF
|
||||||
|
|
||||||
|
typedef struct _ini_kv_t
|
||||||
|
{
|
||||||
|
char *key;
|
||||||
|
char *val;
|
||||||
|
link_t link;
|
||||||
|
} ini_kv_t;
|
||||||
|
|
||||||
|
typedef struct _ini_sec_t
|
||||||
|
{
|
||||||
|
char *name;
|
||||||
|
link_t kvs;
|
||||||
|
link_t link;
|
||||||
|
u32 type;
|
||||||
|
u32 color;
|
||||||
|
} ini_sec_t;
|
||||||
|
|
||||||
|
int ini_parse(link_t *dst, char *ini_path, bool is_dir);
|
||||||
|
char *ini_check_payload_section(ini_sec_t *cfg);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
1460
nyx/nyx_gui/frontend/fe_emmc_tools.c
Normal file
1460
nyx/nyx_gui/frontend/fe_emmc_tools.c
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user