Compare commits
430 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f085cbc4a4 | ||
|
|
d8b6aa3831 | ||
|
|
3e5ef39686 | ||
|
|
bc7c65447d | ||
|
|
a91378b9c1 | ||
|
|
7543234401 | ||
|
|
5b91c54936 | ||
|
|
322280757f | ||
|
|
b1636fbb96 | ||
|
|
cc18a7b146 | ||
|
|
5fe84a78ac | ||
|
|
822e0dcd98 | ||
|
|
a6be3714a3 | ||
|
|
f56d1bad04 | ||
|
|
c7ab404fc1 | ||
|
|
e8f41a03f3 | ||
|
|
8edc9971f9 | ||
|
|
54c36a7e46 | ||
|
|
afb820202d | ||
|
|
0ce973966f | ||
|
|
da8c040c08 | ||
|
|
ee8854fa14 | ||
|
|
11ca71cbc7 | ||
|
|
3794c61ab2 | ||
|
|
dde3ca2d73 | ||
|
|
9850dc305c | ||
|
|
4d1b59c05b | ||
|
|
a0c3323b7c | ||
|
|
c9e53d4b1d | ||
|
|
1a89246e7f | ||
|
|
2094ac2bba | ||
|
|
f9b0ff70f7 | ||
|
|
d2d3597c29 | ||
|
|
4b62b1f69f | ||
|
|
91c2c891fd | ||
|
|
1ba0a7d264 | ||
|
|
5f6bf332d3 | ||
|
|
448cc49cff | ||
|
|
81f0c0a0dc | ||
|
|
95c1046765 | ||
|
|
2a8c27115c | ||
|
|
b6933013be | ||
|
|
a2bb576c03 | ||
|
|
c8d6da5a23 | ||
|
|
f09263d3be | ||
|
|
fdfd383c34 | ||
|
|
39a32fc83d | ||
|
|
c072041039 | ||
|
|
6d75f96ed5 | ||
|
|
ab304c9178 | ||
|
|
abcb1dec46 | ||
|
|
ac4bf9cf2c | ||
|
|
72a51f9506 | ||
|
|
d50a77f861 | ||
|
|
0ecd6b16b0 | ||
|
|
4dcbaa8c2b | ||
|
|
2261dbce83 | ||
|
|
53ff1102df | ||
|
|
b01b49aff4 | ||
|
|
c9a7659d93 | ||
|
|
4f75cd62e5 | ||
|
|
2a74715c3c | ||
|
|
1210c3e689 | ||
|
|
a3f430c224 | ||
|
|
2f7be43ccb | ||
|
|
f5432c734c | ||
|
|
5ca35aa4fc | ||
|
|
2dd474ad26 | ||
|
|
97e45346ea | ||
|
|
6c1ce41900 | ||
|
|
4a57901746 | ||
|
|
c32636b8cb | ||
|
|
190ffdaa5a | ||
|
|
bdd2b40c96 | ||
|
|
53f54cf23b | ||
|
|
474d531788 | ||
|
|
3db55df0a6 | ||
|
|
1483a61f11 | ||
|
|
7b715f7be9 | ||
|
|
56034f9aac | ||
|
|
7e96a4dd3a | ||
|
|
523c81f797 | ||
|
|
f540c8250b | ||
|
|
e89b7f12dd | ||
|
|
279b67fa49 | ||
|
|
11f1f65ed1 | ||
|
|
071dfa9792 | ||
|
|
3cecb03dac | ||
|
|
a7c64f8ba2 | ||
|
|
6749dad1a4 | ||
|
|
91b4c86bbe | ||
|
|
aadb88eeea | ||
|
|
2c4d6552e9 | ||
|
|
c2e8d51115 | ||
|
|
1d69809022 | ||
|
|
093f14923c | ||
|
|
63768ccc99 | ||
|
|
a00f25d2f9 | ||
|
|
54faa38920 | ||
|
|
ae1bb909b6 | ||
|
|
ecb616e411 | ||
|
|
8c762c52e2 | ||
|
|
e14a7d1d4d | ||
|
|
08c81fe1f8 | ||
|
|
63be93be64 | ||
|
|
de4891e133 | ||
|
|
8fd398f213 | ||
|
|
ec53aa86dd | ||
|
|
51985ed2ca | ||
|
|
67ae7b9dcb | ||
|
|
96654d9620 | ||
|
|
ce97b97c8d | ||
|
|
034f680a8e | ||
|
|
7d17e34dee | ||
|
|
d0a16a49b6 | ||
|
|
5442547a59 | ||
|
|
10e7e06048 | ||
|
|
eac6426125 | ||
|
|
88b01994bd | ||
|
|
66780bb4c2 | ||
|
|
7f26981fa1 | ||
|
|
5b0a0070c7 | ||
|
|
0462f3b252 | ||
|
|
9a5cfdff4c | ||
|
|
cb3b1bf6e1 | ||
|
|
b4d2df8111 | ||
|
|
cadb95e3ce | ||
|
|
f148757110 | ||
|
|
6e538cd291 | ||
|
|
62a73ee612 | ||
|
|
4160037c81 | ||
|
|
3fa537e54a | ||
|
|
f35c18a0c2 | ||
|
|
aff137ac34 | ||
|
|
6236b0ab00 | ||
|
|
ae656a0f81 | ||
|
|
6a6648d3b3 | ||
|
|
a4c90aeff3 | ||
|
|
bfe13981bc | ||
|
|
ef11dd883a | ||
|
|
da149c296f | ||
|
|
9af4c717a8 | ||
|
|
281e5a138e | ||
|
|
e7f8b2c6c2 | ||
|
|
3d9c64d548 | ||
|
|
5f142b4c86 | ||
|
|
52c506af9a | ||
|
|
dc9c7fd95c | ||
|
|
4ec7befe82 | ||
|
|
dd4dd91152 | ||
|
|
a39ba2cd71 | ||
|
|
9c2202fa39 | ||
|
|
9c6931a17c | ||
|
|
976925c697 | ||
|
|
d50af46b03 | ||
|
|
3405910f4c | ||
|
|
52874f9113 | ||
|
|
91a241dafa | ||
|
|
a8db070755 | ||
|
|
76676f3a2e | ||
|
|
f5040f1e41 | ||
|
|
c9c3c8f716 | ||
|
|
144d6fd3f6 | ||
|
|
9697067466 | ||
|
|
8539095bdb | ||
|
|
95e3159fe9 | ||
|
|
8b74c487eb | ||
|
|
8abda7f259 | ||
|
|
8d5c52f087 | ||
|
|
e6c1d9bf66 | ||
|
|
a52af1bf41 | ||
|
|
3f10cc774b | ||
|
|
ac92ca220f | ||
|
|
ab8801d0de | ||
|
|
f3802ec464 | ||
|
|
bc7a7bcfa0 | ||
|
|
6a52d44da6 | ||
|
|
03a8a11933 | ||
|
|
c474e35732 | ||
|
|
4c1f67d022 | ||
|
|
91759aba95 | ||
|
|
5a9bbaf900 | ||
|
|
01a767cbfa | ||
|
|
8552a7282c | ||
|
|
2a161b572b | ||
|
|
422852795f | ||
|
|
4d53f21387 | ||
|
|
9263e2192f | ||
|
|
c99a87dd09 | ||
|
|
009db77426 | ||
|
|
4e5ded7cb3 | ||
|
|
50f31cad14 | ||
|
|
2f43145131 | ||
|
|
e3fca2bce5 | ||
|
|
da112a0ae9 | ||
|
|
90060d1d83 | ||
|
|
1ccce5f1a2 | ||
|
|
8584493c7f | ||
|
|
9b2d906648 | ||
|
|
2aaa0331ac | ||
|
|
7604239237 | ||
|
|
562a6fb61d | ||
|
|
938562cc0a | ||
|
|
1e4d63731b | ||
|
|
8ff01301cb | ||
|
|
a664118fc7 | ||
|
|
87d376654b | ||
|
|
c6e92311f9 | ||
|
|
24d30a40f9 | ||
|
|
ae283aef59 | ||
|
|
e4f7928513 | ||
|
|
bd8a5ece58 | ||
|
|
d0850516ab | ||
|
|
4c5a78de6f | ||
|
|
97d3b745d9 | ||
|
|
c12c696e53 | ||
|
|
f256bd5909 | ||
|
|
0290892b23 | ||
|
|
643a8ea8f9 | ||
|
|
a6d8854499 | ||
|
|
96bafd8bd7 | ||
|
|
65ee728939 | ||
|
|
e1748a0727 | ||
|
|
6734513d47 | ||
|
|
dbe6ed4060 | ||
|
|
943477fdde | ||
|
|
35e853fd03 | ||
|
|
7e26be6587 | ||
|
|
733da0f4d5 | ||
|
|
a357395cc6 | ||
|
|
48c15a8fde | ||
|
|
edc2b12f0f | ||
|
|
0b45a5a11a | ||
|
|
bc7dec2e61 | ||
|
|
9811ba53e0 | ||
|
|
a16b1af698 | ||
|
|
641a57a4f6 | ||
|
|
84328aa676 | ||
|
|
66c4f30bdf | ||
|
|
dd8ec0d28b | ||
|
|
0b1eebefe1 | ||
|
|
168de9ddd8 | ||
|
|
c24d943122 | ||
|
|
b61b212218 | ||
|
|
ec10b572d1 | ||
|
|
d1e50c558e | ||
|
|
9476e0ab45 | ||
|
|
ccf36fd2cb | ||
|
|
9a082c1b18 | ||
|
|
2c1da3a97d | ||
|
|
29a51124fd | ||
|
|
74452074f6 | ||
|
|
598073e50c | ||
|
|
58b57a7b14 | ||
|
|
426c86182d | ||
|
|
65fbdfddbf | ||
|
|
7c42f72b8a | ||
|
|
9104b85143 | ||
|
|
2857fcca52 | ||
|
|
6433dbd1ee | ||
|
|
fe339120e2 | ||
|
|
6a261e356f | ||
|
|
e24bb44adf | ||
|
|
40afcfd686 | ||
|
|
658c3c112f | ||
|
|
3b16b086f8 | ||
|
|
8033ba461f | ||
|
|
4dcb2c6343 | ||
|
|
95a6f2b763 | ||
|
|
8cef81c901 | ||
|
|
08d212d4da | ||
|
|
252a57ef6a | ||
|
|
23e246f224 | ||
|
|
3028568019 | ||
|
|
a8d529cf6a | ||
|
|
c5b64a2b58 | ||
|
|
4c09454bca | ||
|
|
787c682f0f | ||
|
|
29b86ce92b | ||
|
|
50ebcee45d | ||
|
|
b74b449601 | ||
|
|
718e502983 | ||
|
|
c1e072986d | ||
|
|
8045d7992b | ||
|
|
02826dd9a6 | ||
|
|
c50e61f961 | ||
|
|
deb9c94bcd | ||
|
|
6cc3d9df67 | ||
|
|
92a60a1e89 | ||
|
|
d0b0164077 | ||
|
|
f3d071ca69 | ||
|
|
9533dea124 | ||
|
|
6159d94e5d | ||
|
|
565956482a | ||
|
|
f622d57f6b | ||
|
|
6cc0711382 | ||
|
|
3472e7e7fb | ||
|
|
e07dde1c58 | ||
|
|
03130ad900 | ||
|
|
31db2735ce | ||
|
|
6ec871ad5f | ||
|
|
0fc17cccfb | ||
|
|
101c8bc1d0 | ||
|
|
9b80ec9ac7 | ||
|
|
ac425368e4 | ||
|
|
205dab6cbd | ||
|
|
ac7eb092d5 | ||
|
|
fed15a2f2f | ||
|
|
2bb0dba724 | ||
|
|
078ef1c4f1 | ||
|
|
c40c125462 | ||
|
|
5b919cb12e | ||
|
|
138da26a9a | ||
|
|
18a29c641c | ||
|
|
0862cb1e7e | ||
|
|
f26cfac10d | ||
|
|
08b84384a6 | ||
|
|
d55634638f | ||
|
|
e6d1a31045 | ||
|
|
7cd545a124 | ||
|
|
01e2302f84 | ||
|
|
c41f98039c | ||
|
|
c0b3a4fc54 | ||
|
|
a1a0d8db49 | ||
|
|
03872e814a | ||
|
|
52478833de | ||
|
|
ba0f29bc5c | ||
|
|
f3dcfab095 | ||
|
|
12f8f055eb | ||
|
|
bd7f572989 | ||
|
|
8101fd3f7f | ||
|
|
c5ab4d6abd | ||
|
|
ee884add8c | ||
|
|
03268c4655 | ||
|
|
072bbcabf4 | ||
|
|
7c877c5bce | ||
|
|
6aa1bdd1c6 | ||
|
|
91606334c4 | ||
|
|
25f6e91677 | ||
|
|
36d2da5d79 | ||
|
|
fd0dc04953 | ||
|
|
8eb5ee867d | ||
|
|
5d99f2fcf7 | ||
|
|
e34a7543b1 | ||
|
|
c80fecd080 | ||
|
|
ed047ef5f5 | ||
|
|
a2ba2ecf26 | ||
|
|
07fe94b6d4 | ||
|
|
ca0c0f786c | ||
|
|
b0af57f98a | ||
|
|
5ba4848571 | ||
|
|
2a2db6cb2f | ||
|
|
361f8a3085 | ||
|
|
961768e14e | ||
|
|
491c4efe9c | ||
|
|
ff9671c481 | ||
|
|
da1bb77d8e | ||
|
|
14c50ed7f8 | ||
|
|
61401d733e | ||
|
|
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 | ||
|
|
4f2bbbf101 | ||
|
|
b677d6cad3 | ||
|
|
b3f8961e45 | ||
|
|
2f37811aba | ||
|
|
5cd596e53c | ||
|
|
4ae42c3a9d | ||
|
|
e105634b0d | ||
|
|
4781dc2ab4 | ||
|
|
e779e53406 | ||
|
|
9f5b97620a | ||
|
|
98d715243a | ||
|
|
e809745120 | ||
|
|
0d9aebda7b | ||
|
|
5ed875ce90 | ||
|
|
30d3c76655 | ||
|
|
949a034500 | ||
|
|
b2893d7fb6 | ||
|
|
9a3fdd944e | ||
|
|
8b8f3c564c | ||
|
|
cd1bb96241 | ||
|
|
8b59ddf3a8 | ||
|
|
09bfed9146 | ||
|
|
cbe75d7769 | ||
|
|
dad380344f | ||
|
|
71b0975730 | ||
|
|
20040ae70f | ||
|
|
22e179d1cf | ||
|
|
1b075c91bd | ||
|
|
1ac7f61f49 | ||
|
|
4b3599b2d8 | ||
|
|
ceabbb0be0 | ||
|
|
471c1e514c | ||
|
|
267a04c4ac | ||
|
|
4eb5b5f91b | ||
|
|
cfef8b4f72 | ||
|
|
683ca6af1d | ||
|
|
14cdcc1497 | ||
|
|
ec1bb508b3 | ||
|
|
cae9044c17 | ||
|
|
5674dad1e9 | ||
|
|
288b5c08db | ||
|
|
fac8db4238 | ||
|
|
04ac8ebd43 | ||
|
|
1392e6eaf4 | ||
|
|
381d5c9236 | ||
|
|
2f43b20124 |
142
Makefile
142
Makefile
@@ -4,91 +4,113 @@ endif
|
||||
|
||||
include $(DEVKITARM)/base_rules
|
||||
|
||||
TARGET := hekate
|
||||
BLVERSION_MAJOR := 4
|
||||
BLVERSION_MINOR := 1
|
||||
BUILD := build
|
||||
OUTPUT := output
|
||||
SOURCEDIR = bootloader
|
||||
VPATH = $(dir $(wildcard ./$(SOURCEDIR)/*/)) $(dir $(wildcard ./$(SOURCEDIR)/*/*/))
|
||||
################################################################################
|
||||
|
||||
OBJS = $(addprefix $(BUILD)/$(TARGET)/, \
|
||||
start.o \
|
||||
main.o \
|
||||
config.o \
|
||||
btn.o \
|
||||
clock.o \
|
||||
cluster.o \
|
||||
fuse.o \
|
||||
gpio.o \
|
||||
heap.o \
|
||||
hos.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 \
|
||||
dirlist.o \
|
||||
ini.o \
|
||||
ianos.o \
|
||||
IPL_LOAD_ADDR := 0x40008000
|
||||
IPL_MAGIC := 0x43544349 #"ICTC"
|
||||
include ./Versions.inc
|
||||
|
||||
################################################################################
|
||||
|
||||
TARGET := hekate
|
||||
BUILDDIR := build
|
||||
OUTPUTDIR := output
|
||||
SOURCEDIR = bootloader
|
||||
VPATH = $(dir ./$(SOURCEDIR)/) $(dir $(wildcard ./$(SOURCEDIR)/*/)) $(dir $(wildcard ./$(SOURCEDIR)/*/*/))
|
||||
|
||||
# Main and graphics.
|
||||
OBJS = $(addprefix $(BUILDDIR)/$(TARGET)/, \
|
||||
start.o exception_handlers.o \
|
||||
main.o heap.o \
|
||||
gfx.o tui.o \
|
||||
fe_emmc_tools.o fe_info.o fe_tools.o \
|
||||
)
|
||||
|
||||
OBJS += $(addprefix $(BUILD)/$(TARGET)/, \
|
||||
# Hardware.
|
||||
OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \
|
||||
bpmp.o clock.o cluster.o di.o gpio.o i2c.o irq.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 nx_sd.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 \
|
||||
diskio.o ff.o ffunicode.o ffsystem.o \
|
||||
elfload.o elfreloc_arm.o \
|
||||
)
|
||||
|
||||
################################################################################
|
||||
|
||||
CUSTOMDEFINES := -DIPL_LOAD_ADDR=$(IPL_LOAD_ADDR) -DBL_MAGIC=$(IPL_MAGIC)
|
||||
CUSTOMDEFINES += -DBL_VER_MJ=$(BLVERSION_MAJOR) -DBL_VER_MN=$(BLVERSION_MINOR) -DBL_VER_HF=$(BLVERSION_HOTFX) -DBL_RESERVED=$(BLVERSION_RSVD)
|
||||
CUSTOMDEFINES += -DNYX_VER_MJ=$(NYXVERSION_MAJOR) -DNYX_VER_MN=$(NYXVERSION_MINOR) -DNYX_VER_HF=$(NYXVERSION_HOTFX) -DNYX_RESERVED=$(NYXVERSION_RSVD)
|
||||
#CUSTOMDEFINES += -DMENU_LOGO_ENABLE
|
||||
|
||||
# 0: UART_A, 1: UART_B.
|
||||
#CUSTOMDEFINES += -DDEBUG_UART_PORT=0
|
||||
|
||||
#CUSTOMDEFINES += -DDEBUG
|
||||
|
||||
ARCH := -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork
|
||||
CUSTOMDEFINES := -DBLVERSIONMJ=$(BLVERSION_MAJOR) -DBLVERSIONMN=$(BLVERSION_MINOR)
|
||||
CUSTOMDEFINES += -DMENU_LOGO_ENABLE #-DDEBUG
|
||||
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/*)
|
||||
NYXDIR := $(wildcard nyx)
|
||||
|
||||
.PHONY: all clean $(MODULEDIRS)
|
||||
################################################################################
|
||||
|
||||
.PHONY: all clean $(MODULEDIRS) $(NYXDIR)
|
||||
|
||||
all: $(TARGET).bin
|
||||
@echo -n "Payload size is "
|
||||
@wc -c < $(OUTPUT)/$(TARGET).bin
|
||||
@echo "Max size is 126296 Bytes."
|
||||
$(eval BIN_SIZE = $(shell wc -c < $(OUTPUTDIR)/$(TARGET).bin))
|
||||
@echo $(BIN_SIZE)
|
||||
@echo "Max size is 126296 Bytes."
|
||||
@if [ ${BIN_SIZE} -gt 126296 ]; then echo "\e[1;33mPayload size exceeds limit!\e[0m"; fi
|
||||
|
||||
clean:
|
||||
@rm -rf $(OBJS)
|
||||
@rm -rf $(BUILD)
|
||||
@rm -rf $(OUTPUT)
|
||||
@rm -rf $(BUILDDIR)
|
||||
@rm -rf $(OUTPUTDIR)
|
||||
|
||||
$(MODULEDIRS):
|
||||
$(MAKE) -C $@ $(MAKECMDGOALS)
|
||||
$(MAKE) -C $@ $(MAKECMDGOALS) -$(MAKEFLAGS)
|
||||
|
||||
$(TARGET).bin: $(BUILD)/$(TARGET)/$(TARGET).elf $(MODULEDIRS)
|
||||
$(OBJCOPY) -S -O binary $< $(OUTPUT)/$@
|
||||
@printf ICTC$(BLVERSION_MAJOR)$(BLVERSION_MINOR) >> $(OUTPUT)/$@
|
||||
$(NYXDIR):
|
||||
$(MAKE) -C $@ $(MAKECMDGOALS) -$(MAKEFLAGS)
|
||||
|
||||
$(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 $@
|
||||
|
||||
$(BUILD)/$(TARGET)/%.o: %.c
|
||||
$(BUILDDIR)/$(TARGET)/%.o: %.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
$(BUILD)/$(TARGET)/%.o: %.S
|
||||
@mkdir -p "$(BUILD)"
|
||||
@mkdir -p "$(BUILD)/$(TARGET)"
|
||||
@mkdir -p "$(OUTPUT)"
|
||||
$(BUILDDIR)/$(TARGET)/%.o: %.S
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
$(OBJS): $(BUILDDIR)/$(TARGET)
|
||||
|
||||
$(BUILDDIR)/$(TARGET):
|
||||
@mkdir -p "$(BUILDDIR)"
|
||||
@mkdir -p "$(BUILDDIR)/$(TARGET)"
|
||||
@mkdir -p "$(OUTPUTDIR)"
|
||||
|
||||
141
README.md
141
README.md
@@ -1,6 +1,6 @@
|
||||
# hekate - CTCaer mod
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
Custom Nintendo Switch bootloader, firmware patcher, and more.
|
||||
@@ -8,17 +8,31 @@ Custom Nintendo Switch bootloader, firmware patcher, and more.
|
||||
|
||||
## Bootloader folders and files
|
||||
|
||||
| Folder/File | Description |
|
||||
| -------------------- | --------------------------------------------------------------------- |
|
||||
| bootloader | Main folder. |
|
||||
| \|__ bootlogo.bmp | It is used when custom is on and no logopath found. Can be skipped. |
|
||||
| \|__ hekate_ipl.ini | Main bootloader configuration and boot entries. |
|
||||
| \|__ update.bin | If newer, it is loaded at boot. For modchips. Can be skipped. |
|
||||
| bootloader/ini/ | For individual inis. 'More configs...' menu. Autoboot is supported. |
|
||||
| bootloader/sys/ | For system modules. |
|
||||
| \|__ libsys_lp0.bso | LP0 (sleep mode) module. Important! |
|
||||
| bootloader/payloads/ | For payloads. 'Payloads...' menu. Autoboot only supported by including them into an ini. All CFW bootloaders, tools, Linux payloads are supported. |
|
||||
| bootloader/libtools/ | Future reserved |
|
||||
| Folder/File | Description |
|
||||
| ------------------------ | --------------------------------------------------------------------- |
|
||||
| bootloader | Main folder. |
|
||||
| \|__ bootlogo.bmp | It is used when custom is on and no logopath found. Can be skipped. |
|
||||
| \|__ hekate_ipl.ini | Main bootloader configuration and boot entries. |
|
||||
| \|__ patches.ini | Add external patches. Can be skipped. A template can be found [here](./res/patches_template.ini) |
|
||||
| \|__ update.bin | If newer, it is loaded at boot. For modchips. Auto updated. Can be skipped. |
|
||||
| bootloader/ini/ | For individual inis. 'More configs...' menu. Autoboot is supported. |
|
||||
| bootloader/res/ | Nyx user resources. Icons and more. |
|
||||
| \|__ background.bmp | Nyx - custom background. |
|
||||
| \|__ icon_switch.bmp | Nyx - Default icon for CFWs. |
|
||||
| \|__ icon_payload.bmp | Nyx - Default icon for Payloads. |
|
||||
| \|__ icon_lakka.bmp | Nyx - Default icon for Lakka. |
|
||||
| bootloader/sys/ | For system modules. |
|
||||
| \|__ emummc.kipm | emuMMC KIP1 module. Important! |
|
||||
| \|__ libsys_lp0.bso | LP0 (sleep mode) module. Important! |
|
||||
| \|__ libsys_minerva.bso | Minerva Training Cell. Used for DRAM Frequency training. Important! |
|
||||
| \|__ nyx.bin | Nyx - Our GUI. Important! |
|
||||
| \|__ res.pak | Nyx resources package. Important! |
|
||||
| bootloader/screenshots/ | Folder where Nyx screenshots are saved |
|
||||
| bootloader/payloads/ | For payloads. 'Payloads...' menu. Autoboot only supported by including them into an ini. All CFW bootloaders, tools, Linux payloads are supported. |
|
||||
| bootloader/libtools/ | Future reserved |
|
||||
| sept | Sept folder. This must be always get updated via the Atmosphère release zip. Needed for tools and booting HOS on 7.0.0 and up. Unused for booting HOS if `fss0=` key is defined. |
|
||||
|
||||
**Note**: Sept files for booting 7.0.0 and up are expected at /sept folder at root of sd card.
|
||||
|
||||
|
||||
## Bootloader configuration
|
||||
@@ -29,50 +43,111 @@ 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.
|
||||
|
||||
|
||||
### Configuration keys/values when boot entry is **config**:
|
||||
You can find a template [Here](./res/hekate_ipl_template.ini)
|
||||
|
||||
|
||||
### Global Configuration keys/values when boot entry is **config**:
|
||||
|
||||
| Config option | Description |
|
||||
| ------------------ | ---------------------------------------------------------- |
|
||||
| autoboot=0 | 0: Disable, #: Boot entry number to auto boot. |
|
||||
| autoboot_list=0 | 0: Read `autoboot` boot entry from hekate_ipl.ini, 1: Read from ini folder (ini files are ASCII ordered). |
|
||||
| bootwait=3 | 0: Disable (It also disables bootlogo. Having **VOL-** pressed since injection goes to menu.), #: Time to wait for **VOL-** to enter menu. |
|
||||
| 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). |
|
||||
| autohosoff=1 | 0: Disable, 1: If woke up from HOS via an RTC alarm, shows logo, then powers off completely, 2: No logo, immediately powers off.|
|
||||
| autonogc=1 | 0: Disable, 1: Automatically applies nogc patch if unburnt fuses found and a >= 4.0.0 HOS is booted. |
|
||||
| updater2p=0 | 0: Disable, 1: Force updates (if needed) the reboot2payload binary to be hekate. |
|
||||
| backlight=100 | Screen backlight level. 0-255. |
|
||||
|
||||
|
||||
### Possible boot entry key/value combinations:
|
||||
### Nyx Global Configuration keys/values for (nyx.ini):
|
||||
|
||||
| Config option | Description |
|
||||
| ------------------ | ---------------------------------------------------------- |
|
||||
| logopath={SD path} | If global customlogo is 1 and logopath empty, bootlogo.bmp will be used. If logopath exists, it will load the specified bitmap. |
|
||||
| warmboot={SD path} | Replaces the warmboot binary |
|
||||
| secmon={SD path} | Replaces the security monitor binary |
|
||||
| kernel={SD path} | Replaces the kernel binary |
|
||||
| kip1={SD path} | Replaces/Adds kernel initial process. Multiple can be set. |
|
||||
| kip1patch=patchname| Enables a kip1 patch. Specify with multiple lines and/or as CSV. Implemented patches right now are nosigchk,nogc |
|
||||
| fullsvcperm=1 | Disables SVC verification (full services permission) |
|
||||
| debugmode=1 | Enables Debug mode |
|
||||
| atmosphere=1 | Enables Atmosphère patching |
|
||||
| payload={SD path} | Payload launching. Tools, Linux, CFW bootloaders, etc. |
|
||||
| themecolor=167 | Sets Nyx color of text highlights. |
|
||||
| timeoff=100 | Sets time offset in HEX. Must be in HOS epoch format |
|
||||
| homescreen=0 | Sets home screen. 0: Home menu, 1: All configs (merges Launch and More configs), 2: Launch, 3: More Configs. |
|
||||
| verification=1 | 0: Disable Backup/Restore verification, 1: Sparse (block based, fast and mostly reliable), 2: Full (sha256 based, slow and 100% reliable). |
|
||||
| umsemmcrw=1 | 1: eMMC/emuMMC UMS will be mounted as writable by default. |
|
||||
|
||||
|
||||
You can find a template [Here](./res/hekate_ipl_template.ini)
|
||||
### Boot entry key/value combinations:
|
||||
|
||||
| Config option | Description |
|
||||
| ---------------------- | ---------------------------------------------------------- |
|
||||
| warmboot={SD path} | Replaces the warmboot binary |
|
||||
| secmon={SD path} | Replaces the security monitor binary |
|
||||
| kernel={SD path} | Replaces the kernel binary |
|
||||
| kip1={SD path} | Replaces/Adds kernel initial process. Multiple can be set. |
|
||||
| kip1={SD folder}/* | Loads every .kip/.kip1 inside a folder. Compatible with single kip1 keys. |
|
||||
| fss0={SD path} | Takes a fusee-secondary binary and `extracts` all needed parts from it. kips, exosphere, warmboot and sept. |
|
||||
| fss0experimental=1 | Enables loading of experimental content from a FSS0 storage |
|
||||
| kip1patch=patchname | Enables a kip1 patch. Specify with multiple lines and/or as CSV. If not found, an error will show up |
|
||||
| fullsvcperm=1 | Disables SVC verification (full services permission) |
|
||||
| debugmode=1 | Enables Debug mode. Obsolete when used with exosphere as secmon. |
|
||||
| atmosphere=1 | Enables Atmosphère patching. |
|
||||
| emupath={SD folder} | Forces emuMMC to use the selected one. (=emuMMC/RAW1, =emuMMC/SD00, etc). emuMMC must be created by hekate because it uses the raw_based/file_based files. |
|
||||
| emummcforce=1 | Forces the use of emuMMC. If emummc.ini is disabled or not found, then it causes an error. |
|
||||
| emummc_force_disable=1 | Disables 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. emuMMC is not supported on stock. If additional KIPs are needed other than OFW's, you can define them with `kip1` key. No kip should be used that relies on Atmosphère patching, because it will hang. If `NOGC` is needed, use `kip1patch=nogc`. |
|
||||
| id=idname | Identifies boot entry for forced boot via id. Max 7 chars. |
|
||||
| payload={SD path} | Payload launching. Tools, Linux, CFW bootloaders, etc. |
|
||||
| logopath={SD path} | If no logopath, `bootloader/bootlogo.bmp` will be used if exists. If logopath exists, it will load the specified bitmap. |
|
||||
| icon={SD path} | Force Nyx to use the icon defined here. If this is not found, it will check for a bmp named as the boot entry ([Test 2] -> `bootloader/res/Test 2.bmp`). Otherwise default will be used. |
|
||||
|
||||
|
||||
### Boot entry key/value Exosphère combinations:
|
||||
|
||||
| Config option | Description |
|
||||
| ---------------------- | ---------------------------------------------------------- |
|
||||
| nouserexceptions=1 | Disables usermode exception handlers when paired with Exosphère. |
|
||||
| userpmu=1 | Enables user access to PMU when paired with Exosphère. |
|
||||
| cal0blank=1 | Overrides Exosphère config `blank_prodinfo_{sys/emu}mmc`. If that key doesn't exist, `exosphere.ini` will be used. |
|
||||
| cal0writesys=1 | Overrides Exosphère config `allow_writing_to_cal_sysmmc`. If that key doesn't exist, `exosphere.ini` 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 *fss0 core* kips when using `fss0` and make sure that the folder (when using `/*`), does not include them.
|
||||
This is in case the kips are incompatible between them. If compatible, you can override `fss0` kips with no issues (useful for testing with intermediate kip changes).
|
||||
|
||||
|
||||
### Payload storage:
|
||||
|
||||
hekate has a boot storage in the binary that helps it configure it outside of BPMP enviroment:
|
||||
|
||||
| Offset / Name | Description |
|
||||
| ----------------------- | ----------------------------------------------------------------- |
|
||||
| '0x94' boot_cfg | bit0: `Force AutoBoot`, bit1: `Show launch log`, bit2: Boot from ID, bit3: `Boot to emuMMC`, bit7: `sept run`. |
|
||||
| '0x95' autoboot | If `Force AutoBoot`: 0: Force go to menu, else boot that entry. |
|
||||
| '0x96' autoboot_list | If `Force AutoBoot` and `autoboot` then it boots from ini folder. |
|
||||
| '0x97' extra_cfg | bit7: Force Nyx to run `Dump pkg1/2`. |
|
||||
| '0x98' xt_str[128] | Depends on the set cfg bits. |
|
||||
| '0x98' id[8] | When `Boot from ID` is set, it will search all inis automatically and find the boot entry with that id and boot it. Must be NULL terminated. |
|
||||
| '0xA0' emummc_path[120] | When `Boot to emuMMC` is set, it will override the current emuMMC (boot entry or emummc.ini). Must be NULL terminated. |
|
||||
|
||||
|
||||
If the main .ini is not found, it is created on the first hekate boot.
|
||||
|
||||
|
||||
```
|
||||
hekate (C) 2018 naehrwert, st4rk
|
||||
CTCaer mod (C) 2018 CTCaer.
|
||||
hekate (c) 2018, naehrwert, st4rk.
|
||||
(c) 2018-2020, CTCaer.
|
||||
|
||||
Nyx GUI (c) 2019-2020, CTCaer.
|
||||
|
||||
Thanks to: derrek, nedwill, plutoo, shuffle2, smea, thexyz, yellows8.
|
||||
Greetings to: fincs, hexkyz, SciresM, Shiny Quagsire, WinterMute.
|
||||
|
||||
Open source and free packages used:
|
||||
- FatFs R0.13a, Copyright (C) 2017, ChaN
|
||||
- bcl-1.2.0, Copyright (C) 2003-2006, Marcus Geelnard
|
||||
- Atmosphère (SE sha256, prc id kernel patches), Copyright (C) 2018, Atmosphère-NX
|
||||
- elfload, Copyright (C) 2014 Owen Shepherd, Copyright (C) 2018 M4xw
|
||||
- FatFs R0.13a, Copyright (c) 2017, ChaN
|
||||
- bcl-1.2.0, Copyright (c) 2003-2006, Marcus Geelnard
|
||||
- Atmosphère (Exosphere types/panic, prc id kernel patches),
|
||||
Copyright (c) 2018-2019, Atmosphère-NX
|
||||
- elfload, Copyright (c) 2014 Owen Shepherd, Copyright (c) 2018 M4xw
|
||||
- Littlev Graphics Library, Copyright (c) 2016 Gabor Kiss-Vamosi
|
||||
|
||||
___
|
||||
.-' `'.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# hekate - Bootlogo
|
||||
|
||||
The bootlogo can be any size with a maximum of 720 x 1280.
|
||||
The bootlogo can be any size with a maximum of 720 x 1280.
|
||||
|
||||
When it's smaller than 720 x 1280, it is automatically centered and the background takes the color of the first pixel.
|
||||
|
||||
|
||||
11
Versions.inc
Normal file
11
Versions.inc
Normal file
@@ -0,0 +1,11 @@
|
||||
# IPL Version.
|
||||
BLVERSION_MAJOR := 5
|
||||
BLVERSION_MINOR := 2
|
||||
BLVERSION_HOTFX := 1
|
||||
BLVERSION_RSVD := 0
|
||||
|
||||
# Nyx Version.
|
||||
NYXVERSION_MAJOR := 0
|
||||
NYXVERSION_MINOR := 9
|
||||
NYXVERSION_HOTFX := 1
|
||||
NYXVERSION_RSVD := 0
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018 CTCaer
|
||||
* Copyright (c) 2018-2020 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -17,36 +17,40 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../utils/btn.h"
|
||||
#include "config.h"
|
||||
#include "../libs/fatfs/ff.h"
|
||||
#include "ini.h"
|
||||
#include "../utils/list.h"
|
||||
#include "../gfx/tui.h"
|
||||
#include "../utils/util.h"
|
||||
#include "../gfx/gfx.h"
|
||||
|
||||
extern gfx_ctxt_t gfx_ctxt;
|
||||
extern gfx_con_t gfx_con;
|
||||
//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)
|
||||
#include "../gfx/tui.h"
|
||||
#include "../libs/fatfs/ff.h"
|
||||
#include "../soc/t210.h"
|
||||
#include "../storage/nx_sd.h"
|
||||
#include "../storage/sdmmc.h"
|
||||
#include "../utils/btn.h"
|
||||
#include "../utils/list.h"
|
||||
#include "../utils/util.h"
|
||||
|
||||
extern hekate_config h_cfg;
|
||||
extern int sd_mount();
|
||||
extern int sd_unmount();
|
||||
|
||||
void set_default_configuration()
|
||||
{
|
||||
h_cfg.autoboot = 0;
|
||||
h_cfg.autoboot_list = 0;
|
||||
h_cfg.bootwait = 3;
|
||||
h_cfg.customlogo = 0;
|
||||
h_cfg.verification = 2;
|
||||
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.updater2p = 0;
|
||||
h_cfg.brand = NULL;
|
||||
h_cfg.tagline = NULL;
|
||||
h_cfg.errors = 0;
|
||||
h_cfg.eks = NULL;
|
||||
h_cfg.sept_run = EMC(EMC_SCRATCH0) & EMC_SEPT_RUN;
|
||||
h_cfg.rcm_patched = true;
|
||||
h_cfg.emummc_force_disable = false;
|
||||
|
||||
sd_power_cycle_time_start = 0;
|
||||
}
|
||||
|
||||
int create_config_entry()
|
||||
@@ -54,7 +58,7 @@ int create_config_entry()
|
||||
if (!sd_mount())
|
||||
return 1;
|
||||
|
||||
char lbuf[16];
|
||||
char lbuf[32];
|
||||
FIL fp;
|
||||
bool mainIniFound = false;
|
||||
|
||||
@@ -92,15 +96,28 @@ int create_config_entry()
|
||||
f_puts("\nbootwait=", &fp);
|
||||
itoa(h_cfg.bootwait, lbuf, 10);
|
||||
f_puts(lbuf, &fp);
|
||||
f_puts("\ncustomlogo=", &fp);
|
||||
itoa(h_cfg.customlogo, 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);
|
||||
f_puts("\nupdater2p=", &fp);
|
||||
itoa(h_cfg.updater2p, lbuf, 10);
|
||||
f_puts(lbuf, &fp);
|
||||
if (h_cfg.brand)
|
||||
{
|
||||
f_puts("\nbrand=", &fp);
|
||||
f_puts(h_cfg.brand, &fp);
|
||||
}
|
||||
if (h_cfg.tagline)
|
||||
{
|
||||
f_puts("\ntagline=", &fp);
|
||||
f_puts(h_cfg.tagline, &fp);
|
||||
}
|
||||
f_puts("\n", &fp);
|
||||
|
||||
if (mainIniFound)
|
||||
@@ -146,16 +163,28 @@ int create_config_entry()
|
||||
f_close(&fp);
|
||||
sd_unmount();
|
||||
|
||||
if (mainIniFound)
|
||||
ini_free(&ini_sections);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void _config_autoboot_list()
|
||||
#pragma GCC push_options
|
||||
#pragma GCC optimize ("Os")
|
||||
|
||||
static void _save_config()
|
||||
{
|
||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
gfx_clear_grey(0x1B);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
if (!create_config_entry())
|
||||
gfx_puts("\nConfiguration was saved!\n");
|
||||
else
|
||||
EPRINTF("\nConfiguration saving failed!");
|
||||
gfx_puts("\nPress any key...");
|
||||
}
|
||||
|
||||
static void _config_autoboot_list(void *ent)
|
||||
{
|
||||
gfx_clear_grey(0x1B);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
u32 *temp_autoboot = NULL;
|
||||
|
||||
@@ -198,8 +227,7 @@ void _config_autoboot_list()
|
||||
|
||||
else
|
||||
boot_text[(i - 1) * 512] = '*';
|
||||
memcpy(boot_text + (i - 1) * 512 + 1, ini_sec->name, strlen(ini_sec->name) + 1);
|
||||
boot_text[strlen(ini_sec->name) + (i - 1) * 512 + 1] = 0;
|
||||
strcpy(boot_text + (i - 1) * 512 + 1, ini_sec->name);
|
||||
ments[i].caption = &boot_text[(i - 1) * 512];
|
||||
}
|
||||
ments[i].type = ini_sec->type;
|
||||
@@ -212,28 +240,23 @@ void _config_autoboot_list()
|
||||
}
|
||||
|
||||
memset(&ments[i], 0, sizeof(ment_t));
|
||||
menu_t menu = {ments, "Select a list entry to auto boot", 0, 0};
|
||||
temp_autoboot = (u32 *)tui_do_menu(&gfx_con, &menu);
|
||||
menu_t menu = {ments, "Select an entry to auto boot", 0, 0};
|
||||
temp_autoboot = (u32 *)tui_do_menu(&menu);
|
||||
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_list = 1;
|
||||
// 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...");
|
||||
_save_config();
|
||||
|
||||
ment_t *tmp = (ment_t *)ent;
|
||||
tmp->data = NULL;
|
||||
}
|
||||
else
|
||||
goto out2;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -244,28 +267,25 @@ out2:;
|
||||
free(ments);
|
||||
free(boot_values);
|
||||
free(boot_text);
|
||||
ini_free(&ini_sections);
|
||||
|
||||
sd_unmount();
|
||||
|
||||
if (temp_autoboot == NULL)
|
||||
return;
|
||||
}
|
||||
|
||||
void config_autoboot()
|
||||
{
|
||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
gfx_clear_grey(0x1B);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
u32 *temp_autoboot = NULL;
|
||||
|
||||
LIST_INIT(ini_sections);
|
||||
|
||||
u8 max_entries = 30;
|
||||
u32 boot_text_size = 512;
|
||||
|
||||
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 5));
|
||||
u32 *boot_values = (u32 *)malloc(sizeof(u32) * max_entries);
|
||||
char *boot_text = (char *)malloc(512 * max_entries);
|
||||
char *boot_text = (char *)malloc(boot_text_size * max_entries);
|
||||
|
||||
for (u32 j = 0; j < max_entries; j++)
|
||||
boot_values[j] = j;
|
||||
@@ -280,20 +300,20 @@ void config_autoboot()
|
||||
|
||||
ments[1].type = MENT_CHGLINE;
|
||||
|
||||
ments[2].type = MENT_CHOICE;
|
||||
ments[2].type = MENT_DATA;
|
||||
if (!h_cfg.autoboot)
|
||||
ments[2].caption = "*Disable";
|
||||
else
|
||||
ments[2].caption = " Disable";
|
||||
ments[2].data = &boot_values[0];
|
||||
|
||||
ments[3].type = MENT_HANDLER;
|
||||
ments[3].type = MENT_HDLR_RE;
|
||||
if (h_cfg.autoboot_list)
|
||||
ments[3].caption = "*More configs...";
|
||||
else
|
||||
ments[3].caption = " More configs...";
|
||||
ments[3].handler = _config_autoboot_list;
|
||||
ments[3].data = NULL;
|
||||
ments[3].data = (void *)0xCAFE;
|
||||
|
||||
ments[4].type = MENT_CHGLINE;
|
||||
|
||||
@@ -311,13 +331,12 @@ void config_autoboot()
|
||||
else
|
||||
{
|
||||
if (h_cfg.autoboot != (i - 4) || h_cfg.autoboot_list)
|
||||
boot_text[(i - 4) * 512] = ' ';
|
||||
boot_text[(i - 4) * boot_text_size] = ' ';
|
||||
|
||||
else
|
||||
boot_text[(i - 4) * 512] = '*';
|
||||
memcpy(boot_text + (i - 4) * 512 + 1, ini_sec->name, strlen(ini_sec->name) + 1);
|
||||
boot_text[strlen(ini_sec->name) + (i - 4) * 512 + 1] = 0;
|
||||
ments[i].caption = &boot_text[(i - 4) * 512];
|
||||
boot_text[(i - 4) * boot_text_size] = '*';
|
||||
strcpy(boot_text + (i - 4) * boot_text_size + 1, ini_sec->name);
|
||||
ments[i].caption = &boot_text[(i - 4) * boot_text_size];
|
||||
}
|
||||
ments[i].type = ini_sec->type;
|
||||
ments[i].data = &boot_values[i - 4];
|
||||
@@ -337,27 +356,19 @@ void config_autoboot()
|
||||
|
||||
memset(&ments[i], 0, sizeof(ment_t));
|
||||
menu_t menu = {ments, "Disable or select entry to auto boot", 0, 0};
|
||||
temp_autoboot = (u32 *)tui_do_menu(&gfx_con, &menu);
|
||||
temp_autoboot = (u32 *)tui_do_menu(&menu);
|
||||
if (temp_autoboot != NULL)
|
||||
{
|
||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
|
||||
h_cfg.autoboot = *(u32 *)temp_autoboot;
|
||||
h_cfg.autoboot_list = 0;
|
||||
// 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...");
|
||||
_save_config();
|
||||
}
|
||||
else
|
||||
goto out2;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -368,7 +379,6 @@ out2:;
|
||||
free(ments);
|
||||
free(boot_values);
|
||||
free(boot_text);
|
||||
ini_free(&ini_sections);
|
||||
|
||||
sd_unmount();
|
||||
|
||||
@@ -378,14 +388,15 @@ out2:;
|
||||
|
||||
void config_bootdelay()
|
||||
{
|
||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
gfx_clear_grey(0x1B);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
u32 delay_entries = 6;
|
||||
u32 delay_text_size = 32;
|
||||
|
||||
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (delay_entries + 3));
|
||||
u32 *delay_values = (u32 *)malloc(sizeof(u32) * delay_entries);
|
||||
char *delay_text = (char *)malloc(32 * delay_entries);
|
||||
char *delay_text = (char *)malloc(delay_text_size * delay_entries);
|
||||
|
||||
for (u32 j = 0; j < delay_entries; j++)
|
||||
delay_values[j] = j;
|
||||
@@ -395,7 +406,7 @@ void config_bootdelay()
|
||||
|
||||
ments[1].type = MENT_CHGLINE;
|
||||
|
||||
ments[2].type = MENT_CHOICE;
|
||||
ments[2].type = MENT_DATA;
|
||||
if (h_cfg.bootwait)
|
||||
ments[2].caption = " 0 seconds (Bootlogo disabled)";
|
||||
else
|
||||
@@ -406,33 +417,25 @@ void config_bootdelay()
|
||||
for (i = 1; i < delay_entries; i++)
|
||||
{
|
||||
if (h_cfg.bootwait != i)
|
||||
delay_text[i * 32] = ' ';
|
||||
delay_text[i * delay_text_size] = ' ';
|
||||
else
|
||||
delay_text[i * 32] = '*';
|
||||
delay_text[i * 32 + 1] = i + '0';
|
||||
memcpy(delay_text + i * 32 + 2, " seconds", 9);
|
||||
delay_text[i * delay_text_size] = '*';
|
||||
delay_text[i * delay_text_size + 1] = i + '0';
|
||||
strcpy(delay_text + i * delay_text_size + 2, " seconds");
|
||||
|
||||
ments[i + 2].type = MENT_CHOICE;
|
||||
ments[i + 2].caption = delay_text + i * 32;
|
||||
ments[i + 2].type = MENT_DATA;
|
||||
ments[i + 2].caption = delay_text + (i * delay_text_size);
|
||||
ments[i + 2].data = &delay_values[i];
|
||||
}
|
||||
|
||||
memset(&ments[i + 2], 0, sizeof(ment_t));
|
||||
menu_t menu = {ments, "Time delay for entering bootloader menu", 0, 0};
|
||||
|
||||
u32 *temp_bootwait = (u32 *)tui_do_menu(&gfx_con, &menu);
|
||||
u32 *temp_bootwait = (u32 *)tui_do_menu(&menu);
|
||||
if (temp_bootwait != NULL)
|
||||
{
|
||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
|
||||
h_cfg.bootwait = *(u32 *)temp_bootwait;
|
||||
// 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...");
|
||||
_save_config();
|
||||
}
|
||||
|
||||
free(ments);
|
||||
@@ -444,140 +447,17 @@ void config_bootdelay()
|
||||
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_CHOICE;
|
||||
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()
|
||||
{
|
||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
|
||||
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 6);
|
||||
u32 *vr_values = (u32 *)malloc(sizeof(u32) * 3);
|
||||
char *vr_text = (char *)malloc(64 * 3);
|
||||
|
||||
for (u32 j = 0; j < 3; j++)
|
||||
{
|
||||
vr_values[j] = j;
|
||||
ments[j + 2].type = MENT_CHOICE;
|
||||
ments[j + 2].data = &vr_values[j];
|
||||
}
|
||||
|
||||
ments[0].type = MENT_BACK;
|
||||
ments[0].caption = "Back";
|
||||
|
||||
ments[1].type = MENT_CHGLINE;
|
||||
|
||||
memcpy(vr_text, " Disable (Fastest)", 19);
|
||||
memcpy(vr_text + 64, " Sparse (Fast - Not reliable)", 32);
|
||||
memcpy(vr_text + 128, " Full (Slow - 100% reliable)", 32);
|
||||
|
||||
for (u32 i = 0; i < 3; i++)
|
||||
{
|
||||
if (h_cfg.verification != i)
|
||||
{
|
||||
vr_text[64 * i] = ' ';
|
||||
ments[2 + i].caption = vr_text + (i * 64);
|
||||
}
|
||||
else
|
||||
{
|
||||
vr_text[64 * i] = '*';
|
||||
ments[2 + i].caption = vr_text + (i * 64);
|
||||
}
|
||||
}
|
||||
|
||||
memset(&ments[5], 0, sizeof(ment_t));
|
||||
menu_t menu = {ments, "Backup & Restore verification", 0, 0};
|
||||
|
||||
u32 *temp_verification = (u32 *)tui_do_menu(&gfx_con, &menu);
|
||||
if (temp_verification != NULL)
|
||||
{
|
||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
|
||||
h_cfg.verification = *(u32 *)temp_verification;
|
||||
// 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(vr_values);
|
||||
free(vr_text);
|
||||
|
||||
if (temp_verification == NULL)
|
||||
return;
|
||||
btn_wait();
|
||||
}
|
||||
|
||||
void config_backlight()
|
||||
{
|
||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
gfx_clear_grey(0x1B);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
u32 bri_text_size = 8;
|
||||
u32 bri_entries = 11;
|
||||
|
||||
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (bri_entries + 3));
|
||||
u32 *bri_values = (u32 *)malloc(sizeof(u32) * bri_entries);
|
||||
char *bri_text = (char *)malloc(8 * bri_entries);
|
||||
char *bri_text = (char *)malloc(bri_text_size * bri_entries);
|
||||
|
||||
for (u32 j = 1; j < bri_entries; j++)
|
||||
bri_values[j] = j * 10;
|
||||
@@ -591,40 +471,31 @@ void config_backlight()
|
||||
for (i = 1; i < bri_entries; i++)
|
||||
{
|
||||
if ((h_cfg.backlight / 20) != i)
|
||||
bri_text[i * 32] = ' ';
|
||||
bri_text[i * bri_text_size] = ' ';
|
||||
else
|
||||
bri_text[i * 32] = '*';
|
||||
|
||||
bri_text[i * bri_text_size] = '*';
|
||||
|
||||
if (i < 10)
|
||||
{
|
||||
bri_text[i * 32 + 1] = i + '0';
|
||||
memcpy(bri_text + i * 32 + 2, "0%", 3);
|
||||
bri_text[i * bri_text_size + 1] = i + '0';
|
||||
strcpy(bri_text + i * bri_text_size + 2, "0%");
|
||||
}
|
||||
|
||||
else
|
||||
memcpy(bri_text + i * 32 + 1, "100%", 5);
|
||||
strcpy(bri_text + i * bri_text_size + 1, "100%");
|
||||
|
||||
ments[i + 1].type = MENT_CHOICE;
|
||||
ments[i + 1].caption = bri_text + i * 32;
|
||||
ments[i + 1].type = MENT_DATA;
|
||||
ments[i + 1].caption = bri_text + (i * bri_text_size);
|
||||
ments[i + 1].data = &bri_values[i];
|
||||
}
|
||||
|
||||
memset(&ments[i + 1], 0, sizeof(ment_t));
|
||||
menu_t menu = {ments, "Backlight brightness", 0, 0};
|
||||
|
||||
u32 *temp_backlight = (u32 *)tui_do_menu(&gfx_con, &menu);
|
||||
u32 *temp_backlight = (u32 *)tui_do_menu(&menu);
|
||||
if (temp_backlight != NULL)
|
||||
{
|
||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
|
||||
h_cfg.backlight = (*(u32 *)temp_backlight) * 2;
|
||||
//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...");
|
||||
_save_config();
|
||||
}
|
||||
|
||||
free(ments);
|
||||
@@ -635,3 +506,111 @@ void config_backlight()
|
||||
return;
|
||||
btn_wait();
|
||||
}
|
||||
|
||||
void config_auto_hos_poweroff()
|
||||
{
|
||||
gfx_clear_grey(0x1B);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 6);
|
||||
u32 *hp_values = (u32 *)malloc(sizeof(u32) * 3);
|
||||
|
||||
for (u32 j = 0; j < 3; j++)
|
||||
{
|
||||
hp_values[j] = j;
|
||||
ments[j + 2].type = MENT_DATA;
|
||||
ments[j + 2].data = &hp_values[j];
|
||||
}
|
||||
|
||||
ments[0].type = MENT_BACK;
|
||||
ments[0].caption = "Back";
|
||||
|
||||
ments[1].type = MENT_CHGLINE;
|
||||
|
||||
if (h_cfg.autohosoff == 1)
|
||||
{
|
||||
ments[2].caption = " Disable";
|
||||
ments[3].caption = "*Enable";
|
||||
ments[4].caption = " Enable (No logo)";
|
||||
}
|
||||
else if (h_cfg.autohosoff >= 2)
|
||||
{
|
||||
ments[2].caption = " Disable";
|
||||
ments[3].caption = " Enable";
|
||||
ments[4].caption = "*Enable (No logo)";
|
||||
}
|
||||
else
|
||||
{
|
||||
ments[2].caption = "*Disable";
|
||||
ments[3].caption = " Enable";
|
||||
ments[4].caption = " Enable (No logo)";
|
||||
}
|
||||
|
||||
memset(&ments[5], 0, sizeof(ment_t));
|
||||
menu_t menu = {ments, "Power off if woke up from HOS", 0, 0};
|
||||
|
||||
u32 *temp_autohosoff = (u32 *)tui_do_menu(&menu);
|
||||
if (temp_autohosoff != NULL)
|
||||
{
|
||||
h_cfg.autohosoff = *(u32 *)temp_autohosoff;
|
||||
_save_config();
|
||||
}
|
||||
|
||||
free(ments);
|
||||
free(hp_values);
|
||||
|
||||
if (temp_autohosoff == NULL)
|
||||
return;
|
||||
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
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -17,33 +17,37 @@
|
||||
#ifndef _CONFIG_H_
|
||||
#define _CONFIG_H_
|
||||
|
||||
#include "../hos/hos.h"
|
||||
#include "../utils/types.h"
|
||||
|
||||
typedef struct _hekate_config
|
||||
{
|
||||
// Non-volatile config.
|
||||
u32 autoboot;
|
||||
u32 autoboot_list;
|
||||
u32 bootwait;
|
||||
u32 customlogo;
|
||||
u32 verification;
|
||||
// Global temporary config.
|
||||
int se_keygen_done;
|
||||
u32 sbar_time_keeping;
|
||||
u32 backlight;
|
||||
u32 errors;
|
||||
u32 autohosoff;
|
||||
u32 autonogc;
|
||||
u32 updater2p;
|
||||
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;
|
||||
hos_eks_mbr_t *eks;
|
||||
} hekate_config;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ERR_LIBSYS_LP0 = (1 << 0),
|
||||
} hsysmodule_t;
|
||||
|
||||
void set_default_configuration();
|
||||
int create_config_entry();
|
||||
void config_autoboot();
|
||||
void config_bootdelay();
|
||||
void config_customlogo();
|
||||
void config_verification();
|
||||
void config_backlight();
|
||||
void config_auto_hos_poweroff();
|
||||
void config_nogc();
|
||||
|
||||
#endif /* _CONFIG_H_ */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (C) 2018 CTCaer
|
||||
* Copyright (c) 2018-2020 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -24,11 +24,46 @@
|
||||
|
||||
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;
|
||||
// Depends on 'FF_USE_STRFUNC 2' that removes \r.
|
||||
for (i = 0; i < lblen && lbuf[i] != schar && lbuf[i] != '\n'; 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 = (ini_sec_t *)calloc(sizeof(ini_sec_t), 1);
|
||||
csec->name = _strdup(name);
|
||||
csec->type = type;
|
||||
|
||||
return csec;
|
||||
}
|
||||
|
||||
int ini_parse(link_t *dst, char *ini_path, bool is_dir)
|
||||
{
|
||||
u32 lblen;
|
||||
@@ -41,33 +76,36 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
|
||||
|
||||
char *filename = (char *)malloc(256);
|
||||
|
||||
memcpy(filename, ini_path, pathlen + 1);
|
||||
strcpy(filename, ini_path);
|
||||
|
||||
// Get all ini filenames.
|
||||
if (is_dir)
|
||||
{
|
||||
filelist = dirlist(filename);
|
||||
filelist = dirlist(filename, "*.ini", false);
|
||||
if (!filelist)
|
||||
{
|
||||
free(filename);
|
||||
return 0;
|
||||
}
|
||||
memcpy(filename + pathlen, "/", 2);
|
||||
strcpy(filename + pathlen, "/");
|
||||
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);
|
||||
strcpy(filename + pathlen, &filelist[k * 256]);
|
||||
k++;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
// Open ini.
|
||||
if (f_open(&fp, filename, FA_READ) != FR_OK)
|
||||
{
|
||||
free(filelist);
|
||||
@@ -83,83 +121,37 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
|
||||
f_gets(lbuf, 512, &fp);
|
||||
lblen = strlen(lbuf);
|
||||
|
||||
// Remove trailing newline.
|
||||
if (lbuf[lblen - 1] == '\n')
|
||||
// Remove trailing newline. Depends on 'FF_USE_STRFUNC 2' that removes \r.
|
||||
if (lblen && lbuf[lblen - 1] == '\n')
|
||||
lbuf[lblen - 1] = 0;
|
||||
|
||||
if (lblen > 2 && lbuf[0] == '[') // Create new section.
|
||||
{
|
||||
if (csec)
|
||||
{
|
||||
list_append(dst, &csec->link);
|
||||
csec = NULL;
|
||||
}
|
||||
_find_section_name(lbuf, lblen, ']');
|
||||
|
||||
u32 i;
|
||||
for (i = 0; i < lblen && lbuf[i] != '\n' && lbuf[i] != ']'; i++)
|
||||
;
|
||||
lbuf[i] = 0;
|
||||
|
||||
csec = (ini_sec_t *)malloc(sizeof(ini_sec_t));
|
||||
csec->name = _strdup(&lbuf[1]);
|
||||
csec->type = INI_CHOICE;
|
||||
csec = _ini_create_section(dst, csec, &lbuf[1], INI_CHOICE);
|
||||
list_init(&csec->kvs);
|
||||
}
|
||||
else if (lblen > 2 && lbuf[0] == '{') //Create new caption.
|
||||
else if (lblen > 1 && lbuf[0] == '{') // Create new caption. Support empty caption '{}'.
|
||||
{
|
||||
if (csec)
|
||||
{
|
||||
list_append(dst, &csec->link);
|
||||
csec = NULL;
|
||||
}
|
||||
_find_section_name(lbuf, lblen, '}');
|
||||
|
||||
u32 i;
|
||||
for (i = 0; i < lblen && lbuf[i] != '\n' && lbuf[i] != '}'; i++)
|
||||
;
|
||||
lbuf[i] = 0;
|
||||
|
||||
csec = (ini_sec_t *)malloc(sizeof(ini_sec_t));
|
||||
csec->name = _strdup(&lbuf[1]);
|
||||
csec->type = INI_CAPTION;
|
||||
csec = _ini_create_section(dst, csec, &lbuf[1], INI_CAPTION);
|
||||
csec->color = 0xFF0AB9E6;
|
||||
}
|
||||
else if (lblen > 2 && lbuf[0] == '#') //Create empty lines and comments.
|
||||
else if (lblen > 2 && lbuf[0] == '#') // Create comment.
|
||||
{
|
||||
if (csec)
|
||||
{
|
||||
list_append(dst, &csec->link);
|
||||
csec = NULL;
|
||||
}
|
||||
|
||||
u32 i;
|
||||
for (i = 0; i < lblen && lbuf[i] != '\n'; i++)
|
||||
;
|
||||
lbuf[i] = 0;
|
||||
|
||||
csec = (ini_sec_t *)malloc(sizeof(ini_sec_t));
|
||||
csec->name = _strdup(&lbuf[1]);
|
||||
csec->type = INI_COMMENT;
|
||||
csec = _ini_create_section(dst, csec, &lbuf[1], INI_COMMENT);
|
||||
}
|
||||
else if (lblen < 2)
|
||||
else if (lblen < 2) // Create empty line.
|
||||
{
|
||||
if (csec)
|
||||
{
|
||||
list_append(dst, &csec->link);
|
||||
csec = NULL;
|
||||
}
|
||||
|
||||
csec = (ini_sec_t *)malloc(sizeof(ini_sec_t));
|
||||
csec->name = NULL;
|
||||
csec->type = INI_NEWLINE;
|
||||
csec = _ini_create_section(dst, csec, NULL, INI_NEWLINE);
|
||||
}
|
||||
else if (csec && csec->type == INI_CHOICE) //Extract key/value.
|
||||
else if (csec && csec->type == INI_CHOICE) // Extract key/value.
|
||||
{
|
||||
u32 i;
|
||||
for (i = 0; i < lblen && lbuf[i] != '\n' && lbuf[i] != '='; i++)
|
||||
;
|
||||
lbuf[i] = 0;
|
||||
u32 i = _find_section_name(lbuf, lblen, '=');
|
||||
|
||||
ini_kv_t *kv = (ini_kv_t *)malloc(sizeof(ini_kv_t));
|
||||
ini_kv_t *kv = (ini_kv_t *)calloc(sizeof(ini_kv_t), 1);
|
||||
kv->key = _strdup(&lbuf[0]);
|
||||
kv->val = _strdup(&lbuf[i + 1]);
|
||||
list_append(&csec->kvs, &kv->link);
|
||||
@@ -169,8 +161,11 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
|
||||
f_close(&fp);
|
||||
|
||||
if (csec)
|
||||
{
|
||||
list_append(dst, &csec->link);
|
||||
|
||||
if (is_dir)
|
||||
csec = NULL;
|
||||
}
|
||||
} while (is_dir);
|
||||
|
||||
free(filename);
|
||||
@@ -179,82 +174,16 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ini_free(link_t *dst)
|
||||
{
|
||||
if (!dst->prev || !dst->next)
|
||||
return;
|
||||
|
||||
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, dst, link)
|
||||
{
|
||||
if (ini_sec->type == INI_CHOICE)
|
||||
{
|
||||
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)
|
||||
{
|
||||
free(kv->key);
|
||||
free(kv->val);
|
||||
//free(kv);
|
||||
}
|
||||
}
|
||||
free(ini_sec->name);
|
||||
//free(ini_sec);
|
||||
}
|
||||
|
||||
list_init(dst);
|
||||
}
|
||||
|
||||
ini_sec_t *ini_clone_section(ini_sec_t *cfg)
|
||||
{
|
||||
if (cfg == NULL)
|
||||
return NULL;
|
||||
|
||||
ini_sec_t *csec = (ini_sec_t *)malloc(sizeof(ini_sec_t));
|
||||
list_init(&csec->kvs);
|
||||
|
||||
LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg->kvs, link)
|
||||
{
|
||||
ini_kv_t *kvcfg = (ini_kv_t *)malloc(sizeof(ini_kv_t));
|
||||
kvcfg->key = _strdup(kv->key);
|
||||
kvcfg->val = _strdup(kv->val);
|
||||
list_append(&csec->kvs, &kvcfg->link);
|
||||
}
|
||||
|
||||
return csec;
|
||||
}
|
||||
|
||||
void ini_free_section(ini_sec_t *cfg)
|
||||
{
|
||||
if (cfg == NULL)
|
||||
return;
|
||||
|
||||
LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg->kvs, link)
|
||||
{
|
||||
free(kv->key);
|
||||
free(kv->val);
|
||||
free(kv);
|
||||
}
|
||||
free(cfg);
|
||||
|
||||
cfg = NULL;
|
||||
}
|
||||
|
||||
char *ini_check_payload_section(ini_sec_t *cfg)
|
||||
{
|
||||
char *path = NULL;
|
||||
|
||||
if (cfg == NULL)
|
||||
return NULL;
|
||||
|
||||
LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg->kvs, link)
|
||||
{
|
||||
if (!strcmp("payload", kv->key))
|
||||
{
|
||||
if (!path)
|
||||
path = _strdup(kv->val);
|
||||
}
|
||||
return kv->val;
|
||||
}
|
||||
|
||||
if (path)
|
||||
return path;
|
||||
else
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (C) 2018 CTCaer
|
||||
* Copyright (c) 2018 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -44,9 +44,6 @@ typedef struct _ini_sec_t
|
||||
} ini_sec_t;
|
||||
|
||||
int ini_parse(link_t *dst, char *ini_path, bool is_dir);
|
||||
void ini_free(link_t *dst);
|
||||
ini_sec_t *ini_clone_section(ini_sec_t *cfg);
|
||||
void ini_free_section(ini_sec_t *cfg);
|
||||
char *ini_check_payload_section(ini_sec_t *cfg);
|
||||
|
||||
#endif
|
||||
|
||||
233
bootloader/exception_handlers.S
Normal file
233
bootloader/exception_handlers.S
Normal file
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Armv7tdmi Status register.
|
||||
*
|
||||
* bit0: Mode 0.
|
||||
* bit1: Mode 1.
|
||||
* bit2: Mode 2.
|
||||
* bit3: Mode 3.
|
||||
* bit4: Mode 4.
|
||||
* bit5: Thumb state.
|
||||
* bit6: FIQ disable.
|
||||
* bit7: IRQ disable.
|
||||
* bit8-27: Reserved.
|
||||
* bit28: Overflow condition.
|
||||
* bit29: Carry/Borrow/Extend condition.
|
||||
* bit30: Zero condition.
|
||||
* bit31: Negative/Less than condition.
|
||||
*
|
||||
* M[4:0] | Mode | Visible Thumb-state registers | Visible ARM-state registers
|
||||
* 10000 | USER | r0–r7, SP, LR, PC, CPSR | r0–r14, PC, CPSR
|
||||
* 10001 | FIQ | r0–r7, SP_fiq, LR_fiq, PC, CPSR, SPSR_fiq | r0–r7, r8_fiq–r14_fiq, PC, CPSR, SPSR_fiq
|
||||
* 10010 | IRQ | r0–r7, SP_irq, LR_irq, PC, CPSR, SPSR_irq | r0–r12, r13_irq, r14_irq, PC, CPSR, SPSR_irq
|
||||
* 10011 | SVC | r0–r7, SP_svc, LR_svc, PC, CPSR, SPSR_svc | r0–r12, r13_svc, r14_svc, PC, CPSR, SPSR_svc
|
||||
* 10111 | ABRT | r0–r7, SP_abt, LR_abt, PC, CPSR, SPSR_abt | r0–r12, r13_abt, r14_abt, PC, CPSR, SPSR_abt
|
||||
* 11011 | UNDF | r0–r7, SP_und, LR_und, PC, CPSR, SPSR_und | r0–r12, r13_und, r14_und, PC, CPSR, SPSR_und
|
||||
* 11111 | SYS | r0–r7, SP, LR, PC, CPSR | r0–r14, PC, CPSR
|
||||
*/
|
||||
|
||||
#define EXCP_EN_ADDR 0x4003FFFC
|
||||
#define EXCP_TYPE_ADDR 0x4003FFF8
|
||||
#define EXCP_LR_ADDR 0x4003FFF4
|
||||
|
||||
#define EXCP_VEC_BASE 0x6000F000
|
||||
#define EVP_COP_RESET_VECTOR 0x200
|
||||
#define EVP_COP_UNDEF_VECTOR 0x204
|
||||
#define EVP_COP_SWI_VECTOR 0x208
|
||||
#define EVP_COP_PREFETCH_ABORT_VECTOR 0x20C
|
||||
#define EVP_COP_DATA_ABORT_VECTOR 0x210
|
||||
#define EVP_COP_RSVD_VECTOR 0x214
|
||||
#define EVP_COP_IRQ_VECTOR 0x218
|
||||
#define EVP_COP_FIQ_VECTOR 0x21C
|
||||
|
||||
#define MODE_USR 0x10
|
||||
#define MODE_FIQ 0x11
|
||||
#define MODE_IRQ 0x12
|
||||
#define MODE_SVC 0x13
|
||||
#define MODE_ABT 0x17
|
||||
#define MODE_UDF 0x1B
|
||||
#define MODE_SYS 0x1F
|
||||
#define MODE_MASK 0x1F
|
||||
|
||||
#define FIQ 0x40
|
||||
#define IRQ 0x80
|
||||
|
||||
.section .text._irq_setup
|
||||
.arm
|
||||
|
||||
.extern ipl_main
|
||||
.type ipl_main, %function
|
||||
|
||||
.extern svc_handler
|
||||
.type svc_handler, %function
|
||||
|
||||
.extern irq_handler
|
||||
.type irq_handler, %function
|
||||
|
||||
.extern fiq_setup
|
||||
.type fiq_setup, %function
|
||||
|
||||
.extern fiq_handler
|
||||
.type fiq_handler, %function
|
||||
|
||||
.globl _irq_setup
|
||||
.type _irq_setup, %function
|
||||
_irq_setup:
|
||||
MRS R0, CPSR
|
||||
BIC R0, R0, #MODE_MASK /* Clear mode bits */
|
||||
ORR R0, R0, #(MODE_SVC | IRQ | FIQ) /* SUPERVISOR mode, IRQ/FIQ disabled */
|
||||
MSR CPSR, R0
|
||||
|
||||
/* Setup IRQ stack pointer */
|
||||
MSR CPSR, #(MODE_IRQ | IRQ | FIQ) /* IRQ mode, IRQ/FIQ disabled */
|
||||
LDR SP, =0x40040000
|
||||
|
||||
/* Setup SYS stack pointer */
|
||||
MSR CPSR, #(MODE_SYS | IRQ | FIQ) /* SYSTEM mode, IRQ/FIQ disabled */
|
||||
LDR SP, =0x4003FF00 /* Will be changed later to DRAM */
|
||||
|
||||
MOV LR, PC
|
||||
BL setup_vectors
|
||||
/*BL fiq_setup*/
|
||||
|
||||
/* Enable interrupts */
|
||||
BL irq_enable_cpu_irq_exceptions
|
||||
|
||||
B ipl_main
|
||||
B .
|
||||
|
||||
_reset:
|
||||
LDR R0, =EXCP_EN_ADDR
|
||||
LDR R1, =0x30505645 /* EVP0 */
|
||||
STR R1, [R0] /* EVP0 in EXCP_EN_ADDR */
|
||||
LDR R0, =EXCP_LR_ADDR
|
||||
MOV R1, LR
|
||||
STR R1, [R0] /* Save LR in EXCP_LR_ADDR */
|
||||
LDR R0, =__bss_start
|
||||
EOR R1, R1, R1
|
||||
LDR R2, =__bss_end
|
||||
SUB R2, R2, R0
|
||||
BL memset
|
||||
B _irq_setup
|
||||
|
||||
_reset_handler:
|
||||
LDR R0, =EXCP_TYPE_ADDR
|
||||
LDR R1, =0x545352 /* RST */
|
||||
STR R1, [R0] /* RST in EXCP_TYPE_ADDR */
|
||||
B _reset
|
||||
|
||||
_undefined_handler:
|
||||
LDR R0, =EXCP_TYPE_ADDR
|
||||
LDR R1, =0x464455 /* UDF */
|
||||
STR R1, [R0] /* UDF in EXCP_TYPE_ADDR */
|
||||
B _reset
|
||||
|
||||
_prefetch_abort_handler:
|
||||
LDR R0, =EXCP_TYPE_ADDR
|
||||
LDR R1, =0x54424150 /* PABT */
|
||||
STR R1, [R0] /* PABT in EXCP_TYPE_ADDR */
|
||||
B _reset
|
||||
|
||||
_data_abort_handler:
|
||||
LDR R0, =EXCP_TYPE_ADDR
|
||||
LDR R1, =0x54424144 /* DABT */
|
||||
STR R1, [R0] /* DABT in EXCP_TYPE_ADDR */
|
||||
B _reset
|
||||
|
||||
.globl irq_enable_cpu_irq_exceptions
|
||||
.type irq_enable_cpu_irq_exceptions, %function
|
||||
irq_enable_cpu_irq_exceptions:
|
||||
MRS R12, CPSR
|
||||
BIC R12, R12, #(IRQ | FIQ) /* IRQ/FIQ enabled */
|
||||
MSR CPSR, R12
|
||||
BX LR
|
||||
|
||||
.globl irq_disable_cpu_irq_exceptions
|
||||
.type irq_disable_cpu_irq_exceptions, %function
|
||||
irq_disable_cpu_irq_exceptions:
|
||||
MRS R12, CPSR
|
||||
ORR R12, R12, #(IRQ | FIQ) /* IRQ/FIQ disabled */
|
||||
MSR CPSR, R12
|
||||
BX LR
|
||||
|
||||
_irq_handler:
|
||||
MOV R13, R0 /* Save R0 in R13_IRQ */
|
||||
SUB R0, LR, #4 /* Put return address in R0_SYS */
|
||||
MOV LR, R1 /* Save R1 in R14_IRQ (LR) */
|
||||
MRS R1, SPSR /* Put the SPSR in R1_SYS */
|
||||
|
||||
MSR CPSR_c, #(MODE_SYS | IRQ) /* SYSTEM mode, IRQ disabled */
|
||||
STMFD SP!, {R0, R1} /* SPSR and PC */
|
||||
STMFD SP!, {R2-R3, R12, LR} /* AAPCS-clobbered registers */
|
||||
MOV R0, SP /* Make SP_SYS visible to IRQ mode */
|
||||
SUB SP, SP, #8 /* Make room for stacking R0 and R1 */
|
||||
|
||||
MSR CPSR_c, #(MODE_IRQ | IRQ) /* IRQ mode, IRQ disabled */
|
||||
STMFD R0!, {R13, R14} /* Finish saving the context (R0, R1) */
|
||||
|
||||
MSR CPSR_c, #(MODE_SYS | IRQ) /* SYSTEM mode, IRQ disabled */
|
||||
LDR R12, =irq_handler
|
||||
MOV LR, PC /* Copy the return address to link register */
|
||||
BX R12 /* Call the C IRQ handler (ARM/THUMB) */
|
||||
|
||||
MSR CPSR_c, #(MODE_SYS | IRQ | FIQ) /* SYSTEM mode, IRQ/FIQ disabled */
|
||||
MOV R0, SP /* Make SP_SYS visible to IRQ mode */
|
||||
ADD SP, SP, #32 /* Fake unstacking 8 registers from SP_SYS */
|
||||
|
||||
MSR CPSR_c, #(MODE_IRQ | IRQ | FIQ) /* IRQ mode, IRQ/FIQ disabled */
|
||||
MOV SP, R0 /* Copy SP_SYS to SP_IRQ */
|
||||
LDR R0, [SP, #28] /* Load the saved SPSR from the stack */
|
||||
MSR SPSR_cxsf, R0 /* Copy it into SPSR_IRQ */
|
||||
|
||||
LDMFD SP, {R0-R3, R12, LR}^ /* Unstack all saved USER/SYSTEM registers */
|
||||
NOP /* Cant access barked registers immediately */
|
||||
LDR LR, [SP, #24] /* Load return address from the SYS stack */
|
||||
MOVS PC, LR /* Return restoring CPSR from SPSR */
|
||||
|
||||
_fiq_handler:
|
||||
BL fiq_handler
|
||||
|
||||
setup_vectors:
|
||||
/* Setup vectors */
|
||||
LDR R0, =EXCP_VEC_BASE
|
||||
|
||||
LDR R1, =_reset_handler
|
||||
STR R1, [R0, #EVP_COP_RESET_VECTOR]
|
||||
|
||||
LDR R1, =_undefined_handler
|
||||
STR R1, [R0, #EVP_COP_UNDEF_VECTOR]
|
||||
|
||||
LDR R1, =_reset_handler
|
||||
STR R1, [R0, #EVP_COP_SWI_VECTOR]
|
||||
|
||||
LDR R1, =_prefetch_abort_handler
|
||||
STR R1, [R0, #EVP_COP_PREFETCH_ABORT_VECTOR]
|
||||
|
||||
LDR R1, =_data_abort_handler
|
||||
STR R1, [R0, #EVP_COP_DATA_ABORT_VECTOR]
|
||||
|
||||
LDR R1, =_reset_handler
|
||||
STR R1, [R0, #EVP_COP_RSVD_VECTOR]
|
||||
|
||||
LDR R1, =_irq_handler
|
||||
STR R1, [R0, #EVP_COP_IRQ_VECTOR]
|
||||
|
||||
LDR R1, =_fiq_handler
|
||||
STR R1, [R0, #EVP_COP_FIQ_VECTOR]
|
||||
|
||||
BX LR
|
||||
922
bootloader/frontend/fe_emmc_tools.c
Normal file
922
bootloader/frontend/fe_emmc_tools.c
Normal file
@@ -0,0 +1,922 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018 Rajko Stojadinovic
|
||||
* 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 "fe_emmc_tools.h"
|
||||
#include "../../common/memory_map.h"
|
||||
#include "../config/config.h"
|
||||
#include "../gfx/gfx.h"
|
||||
#include "../gfx/tui.h"
|
||||
#include "../libs/fatfs/ff.h"
|
||||
#include "../mem/heap.h"
|
||||
#include "../sec/se.h"
|
||||
#include "../storage/nx_emmc.h"
|
||||
#include "../storage/nx_sd.h"
|
||||
#include "../storage/sdmmc.h"
|
||||
#include "../utils/btn.h"
|
||||
#include "../utils/util.h"
|
||||
|
||||
#define NUM_SECTORS_PER_ITER 8192 // 4MB Cache.
|
||||
#define OUT_FILENAME_SZ 128
|
||||
#define SHA256_SZ 0x20
|
||||
|
||||
extern hekate_config h_cfg;
|
||||
|
||||
extern void emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage);
|
||||
|
||||
#pragma GCC push_options
|
||||
#pragma GCC optimize ("Os")
|
||||
|
||||
static int _dump_emmc_verify(sdmmc_storage_t *storage, u32 lba_curr, char *outFilename, emmc_part_t *part)
|
||||
{
|
||||
FIL fp;
|
||||
u8 sparseShouldVerify = 4;
|
||||
u32 btn = 0;
|
||||
u32 prevPct = 200;
|
||||
u32 sdFileSector = 0;
|
||||
int res = 0;
|
||||
|
||||
u8 hashEm[SHA256_SZ];
|
||||
u8 hashSd[SHA256_SZ];
|
||||
|
||||
if (f_open(&fp, outFilename, FA_READ) == FR_OK)
|
||||
{
|
||||
u32 totalSectorsVer = (u32)((u64)f_size(&fp) >> (u64)9);
|
||||
|
||||
u8 *bufEm = (u8 *)EMMC_BUF_ALIGNED;
|
||||
u8 *bufSd = (u8 *)SDXC_BUF_ALIGNED;
|
||||
|
||||
u32 pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);
|
||||
tui_pbar(0, gfx_con.y, pct, 0xFF96FF00, 0xFF155500);
|
||||
|
||||
u32 num = 0;
|
||||
while (totalSectorsVer > 0)
|
||||
{
|
||||
num = MIN(totalSectorsVer, NUM_SECTORS_PER_ITER);
|
||||
|
||||
// Check every time or every 4.
|
||||
// Every 4 protects from fake sd, sector corruption and frequent I/O corruption.
|
||||
// Full provides all that, plus protection from extremely rare I/O corruption.
|
||||
if (!(sparseShouldVerify % 4))
|
||||
{
|
||||
if (!sdmmc_storage_read(storage, lba_curr, num, bufEm))
|
||||
{
|
||||
gfx_con.fntsz = 16;
|
||||
EPRINTFARGS("\nFailed to read %d blocks (@LBA %08X),\nfrom eMMC!\n\nVerification failed..\n",
|
||||
num, lba_curr);
|
||||
|
||||
f_close(&fp);
|
||||
return 1;
|
||||
}
|
||||
f_lseek(&fp, (u64)sdFileSector << (u64)9);
|
||||
if (f_read(&fp, bufSd, num << 9, NULL))
|
||||
{
|
||||
gfx_con.fntsz = 16;
|
||||
EPRINTFARGS("\nFailed to read %d blocks (@LBA %08X),\nfrom sd card!\n\nVerification failed..\n", num, lba_curr);
|
||||
|
||||
f_close(&fp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
se_calc_sha256(hashEm, bufEm, num << 9);
|
||||
se_calc_sha256(hashSd, bufSd, num << 9);
|
||||
res = memcmp(hashEm, hashSd, 0x10);
|
||||
|
||||
if (res)
|
||||
{
|
||||
gfx_con.fntsz = 16;
|
||||
EPRINTFARGS("\nSD and eMMC data (@LBA %08X),\ndo not match!\n\nVerification failed..\n", lba_curr);
|
||||
|
||||
f_close(&fp);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);
|
||||
if (pct != prevPct)
|
||||
{
|
||||
tui_pbar(0, gfx_con.y, pct, 0xFF96FF00, 0xFF155500);
|
||||
prevPct = pct;
|
||||
}
|
||||
|
||||
lba_curr += num;
|
||||
totalSectorsVer -= num;
|
||||
sdFileSector += num;
|
||||
sparseShouldVerify++;
|
||||
|
||||
btn = btn_wait_timeout(0, BTN_VOL_DOWN | BTN_VOL_UP);
|
||||
if ((btn & BTN_VOL_DOWN) && (btn & BTN_VOL_UP))
|
||||
{
|
||||
gfx_con.fntsz = 16;
|
||||
WPRINTF("\n\nVerification was cancelled!");
|
||||
gfx_con.fntsz = 8;
|
||||
msleep(1000);
|
||||
|
||||
f_close(&fp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
f_close(&fp);
|
||||
|
||||
tui_pbar(0, gfx_con.y, pct, 0xFFCCCCCC, 0xFF555555);
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
gfx_con.fntsz = 16;
|
||||
EPRINTF("\nFile not found or could not be loaded.\n\nVerification failed..\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
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 const u32 FAT32_FILESIZE_LIMIT = 0xFFFFFFFF;
|
||||
static const u32 SECTORS_TO_MIB_COEFF = 11;
|
||||
|
||||
u32 multipartSplitSize = (1u << 31);
|
||||
u32 totalSectors = part->lba_end - part->lba_start + 1;
|
||||
u32 currPartIdx = 0;
|
||||
u32 numSplitParts = 0;
|
||||
u32 maxSplitParts = 0;
|
||||
u32 btn = 0;
|
||||
bool isSmallSdCard = false;
|
||||
bool partialDumpInProgress = false;
|
||||
int res = 0;
|
||||
char *outFilename = sd_path;
|
||||
u32 sdPathLen = strlen(sd_path);
|
||||
|
||||
FIL partialIdxFp;
|
||||
char partialIdxFilename[12];
|
||||
strcpy(partialIdxFilename, "partial.idx");
|
||||
|
||||
gfx_con.fntsz = 8;
|
||||
gfx_printf("\nSD Card free space: %d MiB, Total backup size %d MiB\n\n",
|
||||
sd_fs.free_clst * sd_fs.csize >> SECTORS_TO_MIB_COEFF,
|
||||
totalSectors >> SECTORS_TO_MIB_COEFF);
|
||||
|
||||
// 1GB parts for sd cards 8GB and less.
|
||||
if ((sd_storage.csd.capacity >> (20 - sd_storage.csd.read_blkbits)) <= 8192)
|
||||
multipartSplitSize = (1u << 30);
|
||||
// Maximum parts fitting the free space available.
|
||||
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.
|
||||
if (totalSectors > (sd_fs.free_clst * sd_fs.csize))
|
||||
{
|
||||
isSmallSdCard = true;
|
||||
|
||||
gfx_printf("%k\nSD card free space is smaller than backup size.%k\n", 0xFFFFBA00, 0xFFCCCCCC);
|
||||
|
||||
if (!maxSplitParts)
|
||||
{
|
||||
gfx_con.fntsz = 16;
|
||||
EPRINTF("Not enough free space for Partial Backup.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
// Check if we are continuing a previous raw eMMC or USER partition backup in progress.
|
||||
if (f_open(&partialIdxFp, partialIdxFilename, FA_READ) == FR_OK && totalSectors > (FAT32_FILESIZE_LIMIT / NX_EMMC_BLOCKSIZE))
|
||||
{
|
||||
gfx_printf("%kFound Partial Backup in progress. Continuing...%k\n\n", 0xFFAEFD14, 0xFFCCCCCC);
|
||||
|
||||
partialDumpInProgress = true;
|
||||
// Force partial dumping, even if the card is larger.
|
||||
isSmallSdCard = true;
|
||||
|
||||
f_read(&partialIdxFp, &currPartIdx, 4, NULL);
|
||||
f_close(&partialIdxFp);
|
||||
|
||||
if (!maxSplitParts)
|
||||
{
|
||||
gfx_con.fntsz = 16;
|
||||
EPRINTF("Not enough free space for Partial Backup.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Increase maxSplitParts to accommodate previously backed up parts.
|
||||
maxSplitParts += currPartIdx;
|
||||
}
|
||||
else if (isSmallSdCard)
|
||||
gfx_printf("%kPartial Backup enabled (with %d MiB parts)...%k\n\n", 0xFFFFBA00, multipartSplitSize >> 20, 0xFFCCCCCC);
|
||||
|
||||
// Check if filesystem is FAT32 or the free space is smaller and backup in parts.
|
||||
if (((sd_fs.fs_type != FS_EXFAT) && totalSectors > (FAT32_FILESIZE_LIMIT / NX_EMMC_BLOCKSIZE)) || isSmallSdCard)
|
||||
{
|
||||
u32 multipartSplitSectors = multipartSplitSize / NX_EMMC_BLOCKSIZE;
|
||||
numSplitParts = (totalSectors + multipartSplitSectors - 1) / multipartSplitSectors;
|
||||
|
||||
outFilename[sdPathLen++] = '.';
|
||||
|
||||
// Continue from where we left, if Partial Backup in progress.
|
||||
_update_filename(outFilename, sdPathLen, numSplitParts, partialDumpInProgress ? currPartIdx : 0);
|
||||
}
|
||||
|
||||
FIL fp;
|
||||
gfx_con_getpos(&gfx_con.savedx, &gfx_con.savedy);
|
||||
if (!f_open(&fp, outFilename, FA_READ))
|
||||
{
|
||||
f_close(&fp);
|
||||
gfx_con.fntsz = 16;
|
||||
|
||||
WPRINTF("An existing backup has been detected!");
|
||||
WPRINTF("Press POWER to Continue.\nPress VOL to go to the menu.\n");
|
||||
msleep(500);
|
||||
|
||||
if (!(btn_wait() & BTN_POWER))
|
||||
return 0;
|
||||
gfx_con.fntsz = 8;
|
||||
gfx_clear_partial_grey(0x1B, gfx_con.savedy, 48);
|
||||
}
|
||||
gfx_con_setpos(gfx_con.savedx, gfx_con.savedy);
|
||||
gfx_printf("Filename: %s\n\n", outFilename);
|
||||
res = f_open(&fp, outFilename, FA_CREATE_ALWAYS | FA_WRITE);
|
||||
if (res)
|
||||
{
|
||||
gfx_con.fntsz = 16;
|
||||
EPRINTFARGS("Error (%d) creating file %s.\n", res, outFilename);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u8 *buf = (u8 *)MIXD_BUF_ALIGNED;
|
||||
|
||||
u32 lba_curr = part->lba_start;
|
||||
u32 lbaStartPart = part->lba_start;
|
||||
u32 bytesWritten = 0;
|
||||
u32 prevPct = 200;
|
||||
int retryCount = 0;
|
||||
|
||||
// Continue from where we left, if Partial Backup in progress.
|
||||
if (partialDumpInProgress)
|
||||
{
|
||||
lba_curr += currPartIdx * (multipartSplitSize / NX_EMMC_BLOCKSIZE);
|
||||
totalSectors -= currPartIdx * (multipartSplitSize / NX_EMMC_BLOCKSIZE);
|
||||
lbaStartPart = lba_curr; // Update the start LBA for verification.
|
||||
}
|
||||
u64 totalSize = (u64)((u64)totalSectors << 9);
|
||||
if (!isSmallSdCard && (sd_fs.fs_type == FS_EXFAT || totalSize <= FAT32_FILESIZE_LIMIT))
|
||||
f_lseek(&fp, totalSize);
|
||||
else
|
||||
f_lseek(&fp, MIN(totalSize, multipartSplitSize));
|
||||
f_lseek(&fp, 0);
|
||||
|
||||
u32 num = 0;
|
||||
u32 pct = 0;
|
||||
while (totalSectors > 0)
|
||||
{
|
||||
if (numSplitParts != 0 && bytesWritten >= multipartSplitSize)
|
||||
{
|
||||
f_close(&fp);
|
||||
memset(&fp, 0, sizeof(fp));
|
||||
currPartIdx++;
|
||||
|
||||
// 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);
|
||||
|
||||
// Always create partial.idx before next part, in case a fatal error occurs.
|
||||
if (isSmallSdCard)
|
||||
{
|
||||
// Create partial backup index file.
|
||||
if (f_open(&partialIdxFp, partialIdxFilename, FA_CREATE_ALWAYS | FA_WRITE) == FR_OK)
|
||||
{
|
||||
f_write(&partialIdxFp, &currPartIdx, 4, NULL);
|
||||
f_close(&partialIdxFp);
|
||||
}
|
||||
else
|
||||
{
|
||||
gfx_con.fntsz = 16;
|
||||
EPRINTF("\nError creating partial.idx file.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// More parts to backup that do not currently fit the sd card free space or fatal error.
|
||||
if (currPartIdx >= maxSplitParts)
|
||||
{
|
||||
gfx_puts("\n\n1. Press any key to unmount SD Card.\n\
|
||||
2. Remove SD Card and move files to free space.\n\
|
||||
Don\'t move the partial.idx file!\n\
|
||||
3. Re-insert SD Card.\n\
|
||||
4. Select the SAME option again to continue.\n");
|
||||
gfx_con.fntsz = 16;
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Create next part.
|
||||
gfx_con_setpos(gfx_con.savedx, gfx_con.savedy);
|
||||
gfx_printf("Filename: %s\n\n", outFilename);
|
||||
lbaStartPart = lba_curr;
|
||||
res = f_open(&fp, outFilename, FA_CREATE_ALWAYS | FA_WRITE);
|
||||
if (res)
|
||||
{
|
||||
gfx_con.fntsz = 16;
|
||||
EPRINTFARGS("Error (%d) creating file %s.\n", res, outFilename);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bytesWritten = 0;
|
||||
|
||||
totalSize = (u64)((u64)totalSectors << 9);
|
||||
f_lseek(&fp, MIN(totalSize, multipartSplitSize));
|
||||
f_lseek(&fp, 0);
|
||||
}
|
||||
|
||||
retryCount = 0;
|
||||
num = MIN(totalSectors, NUM_SECTORS_PER_ITER);
|
||||
while (!sdmmc_storage_read(storage, lba_curr, num, buf))
|
||||
{
|
||||
EPRINTFARGS("Error reading %d blocks @ LBA %08X,\nfrom eMMC (try %d), retrying...",
|
||||
num, lba_curr, ++retryCount);
|
||||
|
||||
msleep(150);
|
||||
if (retryCount >= 3)
|
||||
{
|
||||
gfx_con.fntsz = 16;
|
||||
EPRINTFARGS("\nFailed to read %d blocks @ LBA %08X\nfrom eMMC. Aborting..\n",
|
||||
num, lba_curr);
|
||||
EPRINTF("\nPress any key and try again...\n");
|
||||
|
||||
f_close(&fp);
|
||||
f_unlink(outFilename);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
res = f_write(&fp, buf, NX_EMMC_BLOCKSIZE * num, NULL);
|
||||
if (res)
|
||||
{
|
||||
gfx_con.fntsz = 16;
|
||||
EPRINTFARGS("\nFatal error (%d) when writing to SD Card", res);
|
||||
EPRINTF("\nPress any key and try again...\n");
|
||||
|
||||
f_close(&fp);
|
||||
f_unlink(outFilename);
|
||||
|
||||
return 0;
|
||||
}
|
||||
pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);
|
||||
if (pct != prevPct)
|
||||
{
|
||||
tui_pbar(0, gfx_con.y, pct, 0xFFCCCCCC, 0xFF555555);
|
||||
prevPct = pct;
|
||||
}
|
||||
|
||||
lba_curr += num;
|
||||
totalSectors -= num;
|
||||
bytesWritten += num * NX_EMMC_BLOCKSIZE;
|
||||
|
||||
// Force a flush after a lot of data if not splitting.
|
||||
if (numSplitParts == 0 && bytesWritten >= multipartSplitSize)
|
||||
{
|
||||
f_sync(&fp);
|
||||
bytesWritten = 0;
|
||||
}
|
||||
|
||||
btn = btn_wait_timeout(0, BTN_VOL_DOWN | BTN_VOL_UP);
|
||||
if ((btn & BTN_VOL_DOWN) && (btn & BTN_VOL_UP))
|
||||
{
|
||||
gfx_con.fntsz = 16;
|
||||
WPRINTF("\n\nThe backup was cancelled!");
|
||||
EPRINTF("\nPress any key...\n");
|
||||
msleep(1500);
|
||||
|
||||
f_close(&fp);
|
||||
f_unlink(outFilename);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
tui_pbar(0, gfx_con.y, 100, 0xFFCCCCCC, 0xFF555555);
|
||||
|
||||
// Backup operation ended successfully.
|
||||
f_close(&fp);
|
||||
|
||||
// Verify last part or single file backup.
|
||||
if (_dump_emmc_verify(storage, lbaStartPart, outFilename, part))
|
||||
{
|
||||
EPRINTF("\nPress any key and try again...\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
tui_pbar(0, gfx_con.y, 100, 0xFF96FF00, 0xFF155500);
|
||||
|
||||
gfx_con.fntsz = 16;
|
||||
// Remove partial backup index file if no fatal errors occurred.
|
||||
if (isSmallSdCard)
|
||||
{
|
||||
f_unlink(partialIdxFilename);
|
||||
gfx_printf("%k\n\nYou can now join the files\nand get the complete eMMC RAW GPP backup.", 0xFFCCCCCC);
|
||||
}
|
||||
gfx_puts("\n\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PART_BOOT = (1 << 0),
|
||||
PART_SYSTEM = (1 << 1),
|
||||
PART_USER = (1 << 2),
|
||||
PART_RAW = (1 << 3),
|
||||
PART_GP_ALL = (1 << 7)
|
||||
} emmcPartType_t;
|
||||
|
||||
static void _dump_emmc_selected(emmcPartType_t dumpType)
|
||||
{
|
||||
int res = 0;
|
||||
u32 timer = 0;
|
||||
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||
tui_sbar(true);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
if (!sd_mount())
|
||||
goto out;
|
||||
|
||||
gfx_puts("Checking for available free space...\n\n");
|
||||
// Get SD Card free space for Partial Backup.
|
||||
f_getfree("", &sd_fs.free_clst, NULL);
|
||||
|
||||
sdmmc_storage_t storage;
|
||||
sdmmc_t sdmmc;
|
||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400))
|
||||
{
|
||||
EPRINTF("Failed to init eMMC.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
char sdPath[OUT_FILENAME_SZ];
|
||||
// Create Restore folders, if they do not exist.
|
||||
emmcsn_path_impl(sdPath, "/restore", "", &storage);
|
||||
emmcsn_path_impl(sdPath, "/restore/partitions", "", &storage);
|
||||
|
||||
timer = get_tmr_s();
|
||||
if (dumpType & PART_BOOT)
|
||||
{
|
||||
const u32 BOOT_PART_SIZE = storage.ext_csd.boot_mult << 17;
|
||||
|
||||
emmc_part_t bootPart;
|
||||
memset(&bootPart, 0, sizeof(bootPart));
|
||||
bootPart.lba_start = 0;
|
||||
bootPart.lba_end = (BOOT_PART_SIZE / NX_EMMC_BLOCKSIZE) - 1;
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
strcpy(bootPart.name, "BOOT");
|
||||
bootPart.name[4] = (u8)('0' + i);
|
||||
bootPart.name[5] = 0;
|
||||
|
||||
gfx_printf("%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i,
|
||||
bootPart.name, bootPart.lba_start, bootPart.lba_end, 0xFFCCCCCC);
|
||||
|
||||
sdmmc_storage_set_mmc_partition(&storage, i + 1);
|
||||
|
||||
emmcsn_path_impl(sdPath, "", bootPart.name, &storage);
|
||||
res = _dump_emmc_part(sdPath, &storage, &bootPart);
|
||||
}
|
||||
}
|
||||
|
||||
if ((dumpType & PART_SYSTEM) || (dumpType & PART_USER) || (dumpType & PART_RAW))
|
||||
{
|
||||
sdmmc_storage_set_mmc_partition(&storage, EMMC_GPP);
|
||||
|
||||
if ((dumpType & PART_SYSTEM) || (dumpType & PART_USER))
|
||||
{
|
||||
LIST_INIT(gpt);
|
||||
nx_emmc_gpt_parse(&gpt, &storage);
|
||||
LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link)
|
||||
{
|
||||
if ((dumpType & PART_USER) == 0 && !strcmp(part->name, "USER"))
|
||||
continue;
|
||||
if ((dumpType & PART_SYSTEM) == 0 && strcmp(part->name, "USER"))
|
||||
continue;
|
||||
|
||||
gfx_printf("%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++,
|
||||
part->name, part->lba_start, part->lba_end, 0xFFCCCCCC);
|
||||
|
||||
emmcsn_path_impl(sdPath, "/partitions", part->name, &storage);
|
||||
res = _dump_emmc_part(sdPath, &storage, part);
|
||||
// If a part failed, don't continue.
|
||||
if (!res)
|
||||
break;
|
||||
}
|
||||
nx_emmc_gpt_free(&gpt);
|
||||
}
|
||||
|
||||
if (dumpType & PART_RAW)
|
||||
{
|
||||
// Get GP partition size dynamically.
|
||||
const u32 RAW_AREA_NUM_SECTORS = storage.sec_cnt;
|
||||
|
||||
emmc_part_t rawPart;
|
||||
memset(&rawPart, 0, sizeof(rawPart));
|
||||
rawPart.lba_start = 0;
|
||||
rawPart.lba_end = RAW_AREA_NUM_SECTORS - 1;
|
||||
strcpy(rawPart.name, "rawnand.bin");
|
||||
{
|
||||
gfx_printf("%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++,
|
||||
rawPart.name, rawPart.lba_start, rawPart.lba_end, 0xFFCCCCCC);
|
||||
|
||||
emmcsn_path_impl(sdPath, "", rawPart.name, &storage);
|
||||
res = _dump_emmc_part(sdPath, &storage, &rawPart);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gfx_putc('\n');
|
||||
timer = get_tmr_s() - timer;
|
||||
gfx_printf("Time taken: %dm %ds.\n", timer / 60, timer % 60);
|
||||
sdmmc_storage_end(&storage);
|
||||
if (res)
|
||||
gfx_printf("\n%kFinished and verified!%k\nPress any key...\n", 0xFF96FF00, 0xFFCCCCCC);
|
||||
|
||||
out:
|
||||
sd_unmount();
|
||||
btn_wait();
|
||||
}
|
||||
|
||||
void dump_emmc_system() { _dump_emmc_selected(PART_SYSTEM); }
|
||||
void dump_emmc_user() { _dump_emmc_selected(PART_USER); }
|
||||
void dump_emmc_boot() { _dump_emmc_selected(PART_BOOT); }
|
||||
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, bool allow_multi_part)
|
||||
{
|
||||
static const u32 SECTORS_TO_MIB_COEFF = 11;
|
||||
|
||||
u32 totalSectors = part->lba_end - part->lba_start + 1;
|
||||
u32 currPartIdx = 0;
|
||||
u32 numSplitParts = 0;
|
||||
u32 lbaStartPart = part->lba_start;
|
||||
int res = 0;
|
||||
char *outFilename = sd_path;
|
||||
u32 sdPathLen = strlen(sd_path);
|
||||
u64 fileSize = 0;
|
||||
u64 totalCheckFileSize = 0;
|
||||
gfx_con.fntsz = 8;
|
||||
|
||||
FIL fp;
|
||||
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);
|
||||
gfx_con_setpos(gfx_con.savedx, gfx_con.savedy);
|
||||
gfx_printf("\nFilename: %s\n", outFilename);
|
||||
if (res)
|
||||
{
|
||||
if (res != FR_NO_FILE)
|
||||
EPRINTFARGS("Error (%d) while opening backup. Continuing...\n", res);
|
||||
else
|
||||
WPRINTFARGS("Error (%d) file not found. Continuing...\n", res);
|
||||
gfx_con.fntsz = 16;
|
||||
|
||||
return 0;
|
||||
}
|
||||
else if (!use_multipart && (((u32)((u64)f_size(&fp) >> (u64)9)) != totalSectors)) // Check total restore size vs emmc size.
|
||||
{
|
||||
gfx_con.fntsz = 16;
|
||||
EPRINTF("Size of the SD Card backup does not match,\neMMC's selected part size.\n");
|
||||
f_close(&fp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
u8 *buf = (u8 *)MIXD_BUF_ALIGNED;
|
||||
|
||||
u32 lba_curr = part->lba_start;
|
||||
u32 bytesWritten = 0;
|
||||
u32 prevPct = 200;
|
||||
int retryCount = 0;
|
||||
|
||||
u32 num = 0;
|
||||
u32 pct = 0;
|
||||
|
||||
gfx_con_getpos(&gfx_con.savedx, &gfx_con.savedy);
|
||||
|
||||
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++;
|
||||
|
||||
// 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;
|
||||
num = MIN(totalSectors, NUM_SECTORS_PER_ITER);
|
||||
|
||||
res = f_read(&fp, buf, NX_EMMC_BLOCKSIZE * num, NULL);
|
||||
if (res)
|
||||
{
|
||||
gfx_con.fntsz = 16;
|
||||
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");
|
||||
|
||||
f_close(&fp);
|
||||
return 0;
|
||||
}
|
||||
while (!sdmmc_storage_write(storage, lba_curr, num, buf))
|
||||
{
|
||||
EPRINTFARGS("Error writing %d blocks @ LBA %08X\nto eMMC (try %d), retrying...",
|
||||
num, lba_curr, ++retryCount);
|
||||
|
||||
msleep(150);
|
||||
if (retryCount >= 3)
|
||||
{
|
||||
gfx_con.fntsz = 16;
|
||||
EPRINTFARGS("\nFailed to write %d blocks @ LBA %08X\nfrom eMMC. Aborting..\n",
|
||||
num, lba_curr);
|
||||
EPRINTF("\nYour device may be in an inoperative state!\n\nPress any key and try again...\n");
|
||||
|
||||
f_close(&fp);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);
|
||||
if (pct != prevPct)
|
||||
{
|
||||
tui_pbar(0, gfx_con.y, pct, 0xFFCCCCCC, 0xFF555555);
|
||||
prevPct = pct;
|
||||
}
|
||||
|
||||
lba_curr += num;
|
||||
totalSectors -= num;
|
||||
bytesWritten += num * NX_EMMC_BLOCKSIZE;
|
||||
}
|
||||
tui_pbar(0, gfx_con.y, 100, 0xFFCCCCCC, 0xFF555555);
|
||||
|
||||
// Restore operation ended successfully.
|
||||
f_close(&fp);
|
||||
|
||||
// Verify restored data.
|
||||
if (_dump_emmc_verify(storage, lbaStartPart, outFilename, part))
|
||||
{
|
||||
EPRINTF("\nPress any key and try again...\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
tui_pbar(0, gfx_con.y, 100, 0xFF96FF00, 0xFF155500);
|
||||
|
||||
gfx_con.fntsz = 16;
|
||||
gfx_puts("\n\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _restore_emmc_selected(emmcPartType_t restoreType)
|
||||
{
|
||||
int res = 0;
|
||||
u32 timer = 0;
|
||||
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||
tui_sbar(true);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
gfx_printf("%kThis may render your device inoperative!\n\n", 0xFFFFDD00);
|
||||
gfx_printf("Are you really sure?\n\n%k", 0xFFCCCCCC);
|
||||
if ((restoreType & PART_BOOT) || (restoreType & PART_GP_ALL))
|
||||
{
|
||||
gfx_puts("The mode you selected will only restore\nthe ");
|
||||
if (restoreType & PART_BOOT)
|
||||
gfx_puts("boot ");
|
||||
gfx_puts("partitions that it can find.\n");
|
||||
gfx_puts("If it is not found, it will be skipped\nand continue with the next.\n\n");
|
||||
}
|
||||
gfx_con_getpos(&gfx_con.savedx, &gfx_con.savedy);
|
||||
|
||||
u8 failsafe_wait = 10;
|
||||
while (failsafe_wait > 0)
|
||||
{
|
||||
gfx_con_setpos(gfx_con.savedx, gfx_con.savedy);
|
||||
gfx_printf("%kWait... (%ds) %k", 0xFF888888, failsafe_wait, 0xFFCCCCCC);
|
||||
msleep(1000);
|
||||
failsafe_wait--;
|
||||
}
|
||||
gfx_con_setpos(gfx_con.savedx, gfx_con.savedy);
|
||||
|
||||
gfx_puts("Press POWER to Continue.\nPress VOL to go to the menu.\n\n\n");
|
||||
|
||||
u32 btn = btn_wait();
|
||||
if (!(btn & BTN_POWER))
|
||||
goto out;
|
||||
|
||||
if (!sd_mount())
|
||||
goto out;
|
||||
|
||||
sdmmc_storage_t storage;
|
||||
sdmmc_t sdmmc;
|
||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400))
|
||||
{
|
||||
EPRINTF("Failed to init eMMC.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
char sdPath[OUT_FILENAME_SZ];
|
||||
|
||||
timer = get_tmr_s();
|
||||
if (restoreType & PART_BOOT)
|
||||
{
|
||||
const u32 BOOT_PART_SIZE = storage.ext_csd.boot_mult << 17;
|
||||
|
||||
emmc_part_t bootPart;
|
||||
memset(&bootPart, 0, sizeof(bootPart));
|
||||
bootPart.lba_start = 0;
|
||||
bootPart.lba_end = (BOOT_PART_SIZE / NX_EMMC_BLOCKSIZE) - 1;
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
strcpy(bootPart.name, "BOOT");
|
||||
bootPart.name[4] = (u8)('0' + i);
|
||||
bootPart.name[5] = 0;
|
||||
|
||||
gfx_printf("%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i,
|
||||
bootPart.name, bootPart.lba_start, bootPart.lba_end, 0xFFCCCCCC);
|
||||
|
||||
sdmmc_storage_set_mmc_partition(&storage, i + 1);
|
||||
|
||||
emmcsn_path_impl(sdPath, "/restore", bootPart.name, &storage);
|
||||
res = _restore_emmc_part(sdPath, &storage, &bootPart, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (restoreType & PART_GP_ALL)
|
||||
{
|
||||
sdmmc_storage_set_mmc_partition(&storage, EMMC_GPP);
|
||||
|
||||
LIST_INIT(gpt);
|
||||
nx_emmc_gpt_parse(&gpt, &storage);
|
||||
LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link)
|
||||
{
|
||||
gfx_printf("%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++,
|
||||
part->name, part->lba_start, part->lba_end, 0xFFCCCCCC);
|
||||
|
||||
emmcsn_path_impl(sdPath, "/restore/partitions/", part->name, &storage);
|
||||
res = _restore_emmc_part(sdPath, &storage, part, false);
|
||||
}
|
||||
nx_emmc_gpt_free(&gpt);
|
||||
}
|
||||
|
||||
if (restoreType & PART_RAW)
|
||||
{
|
||||
// Get GP partition size dynamically.
|
||||
const u32 RAW_AREA_NUM_SECTORS = storage.sec_cnt;
|
||||
|
||||
emmc_part_t rawPart;
|
||||
memset(&rawPart, 0, sizeof(rawPart));
|
||||
rawPart.lba_start = 0;
|
||||
rawPart.lba_end = RAW_AREA_NUM_SECTORS - 1;
|
||||
strcpy(rawPart.name, "rawnand.bin");
|
||||
{
|
||||
gfx_printf("%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++,
|
||||
rawPart.name, rawPart.lba_start, rawPart.lba_end, 0xFFCCCCCC);
|
||||
|
||||
emmcsn_path_impl(sdPath, "/restore", rawPart.name, &storage);
|
||||
res = _restore_emmc_part(sdPath, &storage, &rawPart, true);
|
||||
}
|
||||
}
|
||||
|
||||
gfx_putc('\n');
|
||||
timer = get_tmr_s() - timer;
|
||||
gfx_printf("Time taken: %dm %ds.\n", timer / 60, timer % 60);
|
||||
sdmmc_storage_end(&storage);
|
||||
if (res)
|
||||
gfx_printf("\n%kFinished and verified!%k\nPress any key...\n", 0xFF96FF00, 0xFFCCCCCC);
|
||||
|
||||
out:
|
||||
sd_unmount();
|
||||
btn_wait();
|
||||
}
|
||||
|
||||
void restore_emmc_boot() { _restore_emmc_selected(PART_BOOT); }
|
||||
void restore_emmc_rawnand() { _restore_emmc_selected(PART_RAW); }
|
||||
void restore_emmc_gpp_parts() { _restore_emmc_selected(PART_GP_ALL); }
|
||||
|
||||
#pragma GCC pop_options
|
||||
30
bootloader/frontend/fe_emmc_tools.h
Normal file
30
bootloader/frontend/fe_emmc_tools.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Rajko Stojadinovic
|
||||
* 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 _FE_EMMC_TOOLS_H_
|
||||
#define _FE_EMMC_TOOLS_H_
|
||||
|
||||
void dump_emmc_system();
|
||||
void dump_emmc_user();
|
||||
void dump_emmc_boot();
|
||||
void dump_emmc_rawnand();
|
||||
|
||||
void restore_emmc_boot();
|
||||
void restore_emmc_rawnand();
|
||||
void restore_emmc_gpp_parts();
|
||||
|
||||
#endif
|
||||
655
bootloader/frontend/fe_info.c
Normal file
655
bootloader/frontend/fe_info.c
Normal file
@@ -0,0 +1,655 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2020 CTCaer
|
||||
* Copyright (c) 2018 balika011
|
||||
*
|
||||
* 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 "fe_info.h"
|
||||
#include "../gfx/gfx.h"
|
||||
#include "../hos/hos.h"
|
||||
#include "../hos/pkg1.h"
|
||||
#include "../libs/fatfs/ff.h"
|
||||
#include "../mem/heap.h"
|
||||
#include "../power/bq24193.h"
|
||||
#include "../power/max17050.h"
|
||||
#include "../sec/tsec.h"
|
||||
#include "../soc/fuse.h"
|
||||
#include "../soc/i2c.h"
|
||||
#include "../soc/kfuse.h"
|
||||
#include "../soc/smmu.h"
|
||||
#include "../soc/t210.h"
|
||||
#include "../storage/mmc.h"
|
||||
#include "../storage/nx_emmc.h"
|
||||
#include "../storage/nx_sd.h"
|
||||
#include "../storage/sdmmc.h"
|
||||
#include "../utils/btn.h"
|
||||
#include "../utils/util.h"
|
||||
|
||||
extern void emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage);
|
||||
|
||||
#pragma GCC push_options
|
||||
#pragma GCC optimize ("Os")
|
||||
|
||||
void print_fuseinfo()
|
||||
{
|
||||
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
u32 burntFuses = 0;
|
||||
for (u32 i = 0; i < 32; i++)
|
||||
{
|
||||
if ((fuse_read_odm(7) >> i) & 1)
|
||||
burntFuses++;
|
||||
}
|
||||
|
||||
gfx_printf("\nSKU: %X - ", FUSE(FUSE_SKU_INFO));
|
||||
switch (fuse_read_odm(4) & 3)
|
||||
{
|
||||
case 0:
|
||||
gfx_printf("Retail\n");
|
||||
break;
|
||||
case 3:
|
||||
gfx_printf("Dev\n");
|
||||
break;
|
||||
}
|
||||
gfx_printf("Sdram ID: %d\n", (fuse_read_odm(4) >> 3) & 0x1F);
|
||||
gfx_printf("Burnt fuses: %d / 64\n", burntFuses);
|
||||
gfx_printf("Secure key: %08X%08X%08X%08X\n\n\n",
|
||||
byte_swap_32(FUSE(FUSE_PRIVATE_KEY0)), byte_swap_32(FUSE(FUSE_PRIVATE_KEY1)),
|
||||
byte_swap_32(FUSE(FUSE_PRIVATE_KEY2)), byte_swap_32(FUSE(FUSE_PRIVATE_KEY3)));
|
||||
|
||||
gfx_printf("%k(Unlocked) fuse cache:\n\n%k", 0xFF00DDFF, 0xFFCCCCCC);
|
||||
gfx_hexdump(0x7000F900, (u8 *)0x7000F900, 0x300);
|
||||
|
||||
gfx_puts("\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
|
||||
|
||||
u32 btn = btn_wait();
|
||||
if (btn & BTN_POWER)
|
||||
{
|
||||
if (sd_mount())
|
||||
{
|
||||
char path[64];
|
||||
emmcsn_path_impl(path, "/dumps", "fuse_cached.bin", NULL);
|
||||
if (!sd_save_to_file((u8 *)0x7000F900, 0x300, path))
|
||||
gfx_puts("\nfuse_cached.bin saved!\n");
|
||||
|
||||
u32 words[192];
|
||||
fuse_read_array(words);
|
||||
emmcsn_path_impl(path, "/dumps", "fuse_array_raw.bin", NULL);
|
||||
if (!sd_save_to_file((u8 *)words, sizeof(words), path))
|
||||
gfx_puts("\nfuse_array_raw.bin saved!\n");
|
||||
|
||||
sd_unmount();
|
||||
}
|
||||
|
||||
btn_wait();
|
||||
}
|
||||
}
|
||||
|
||||
void print_kfuseinfo()
|
||||
{
|
||||
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
gfx_printf("%kKFuse contents:\n\n%k", 0xFF00DDFF, 0xFFCCCCCC);
|
||||
u32 buf[KFUSE_NUM_WORDS];
|
||||
if (!kfuse_read(buf))
|
||||
EPRINTF("CRC fail.");
|
||||
else
|
||||
gfx_hexdump(0, (u8 *)buf, KFUSE_NUM_WORDS * 4);
|
||||
|
||||
gfx_puts("\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
|
||||
|
||||
u32 btn = btn_wait();
|
||||
if (btn & BTN_POWER)
|
||||
{
|
||||
if (sd_mount())
|
||||
{
|
||||
char path[64];
|
||||
emmcsn_path_impl(path, "/dumps", "kfuses.bin", NULL);
|
||||
if (!sd_save_to_file((u8 *)buf, KFUSE_NUM_WORDS * 4, path))
|
||||
gfx_puts("\nDone!\n");
|
||||
sd_unmount();
|
||||
}
|
||||
|
||||
btn_wait();
|
||||
}
|
||||
}
|
||||
|
||||
void print_mmc_info()
|
||||
{
|
||||
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
static const u32 SECTORS_TO_MIB_COEFF = 11;
|
||||
|
||||
sdmmc_storage_t storage;
|
||||
sdmmc_t sdmmc;
|
||||
|
||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400))
|
||||
{
|
||||
EPRINTF("Failed to init eMMC.");
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
{
|
||||
u16 card_type;
|
||||
u32 speed = 0;
|
||||
|
||||
gfx_printf("%kCID:%k\n", 0xFF00DDFF, 0xFFCCCCCC);
|
||||
switch (storage.csd.mmca_vsn)
|
||||
{
|
||||
case 2: /* MMC v2.0 - v2.2 */
|
||||
case 3: /* MMC v3.1 - v3.3 */
|
||||
case 4: /* MMC v4 */
|
||||
gfx_printf(
|
||||
" Vendor ID: %X\n"
|
||||
" Card/BGA: %X\n"
|
||||
" OEM ID: %02X\n"
|
||||
" Model: %c%c%c%c%c%c\n"
|
||||
" Prd Rev: %X\n"
|
||||
" S/N: %04X\n"
|
||||
" Month/Year: %02d/%04d\n\n",
|
||||
storage.cid.manfid, storage.cid.card_bga, storage.cid.oemid,
|
||||
storage.cid.prod_name[0], storage.cid.prod_name[1], storage.cid.prod_name[2],
|
||||
storage.cid.prod_name[3], storage.cid.prod_name[4], storage.cid.prod_name[5],
|
||||
storage.cid.prv, storage.cid.serial, storage.cid.month, storage.cid.year);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (storage.csd.structure == 0)
|
||||
EPRINTF("Unknown CSD structure.");
|
||||
else
|
||||
{
|
||||
gfx_printf("%kExtended CSD V1.%d:%k\n",
|
||||
0xFF00DDFF, storage.ext_csd.ext_struct, 0xFFCCCCCC);
|
||||
card_type = storage.ext_csd.card_type;
|
||||
char card_type_support[96];
|
||||
card_type_support[0] = 0;
|
||||
if (card_type & EXT_CSD_CARD_TYPE_HS_26)
|
||||
{
|
||||
strcat(card_type_support, "HS26");
|
||||
speed = (26 << 16) | 26;
|
||||
}
|
||||
if (card_type & EXT_CSD_CARD_TYPE_HS_52)
|
||||
{
|
||||
strcat(card_type_support, ", HS52");
|
||||
speed = (52 << 16) | 52;
|
||||
}
|
||||
if (card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
|
||||
{
|
||||
strcat(card_type_support, ", DDR52_1.8V");
|
||||
speed = (52 << 16) | 104;
|
||||
}
|
||||
if (card_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
|
||||
{
|
||||
strcat(card_type_support, ", HS200_1.8V");
|
||||
speed = (200 << 16) | 200;
|
||||
}
|
||||
if (card_type & EXT_CSD_CARD_TYPE_HS400_1_8V)
|
||||
{
|
||||
strcat(card_type_support, ", HS400_1.8V");
|
||||
speed = (200 << 16) | 400;
|
||||
}
|
||||
|
||||
gfx_printf(
|
||||
" Spec Version: %02X\n"
|
||||
" Extended Rev: 1.%d\n"
|
||||
" Dev Version: %d\n"
|
||||
" Cmd Classes: %02X\n"
|
||||
" Capacity: %s\n"
|
||||
" Max Rate: %d MB/s (%d MHz)\n"
|
||||
" Current Rate: %d MB/s\n"
|
||||
" Type Support: ",
|
||||
storage.csd.mmca_vsn, storage.ext_csd.rev, storage.ext_csd.dev_version, storage.csd.cmdclass,
|
||||
storage.csd.capacity == (4096 * 512) ? "High" : "Low", speed & 0xFFFF, (speed >> 16) & 0xFFFF,
|
||||
storage.csd.busspeed);
|
||||
gfx_con.fntsz = 8;
|
||||
gfx_printf("%s", card_type_support);
|
||||
gfx_con.fntsz = 16;
|
||||
gfx_printf("\n\n", card_type_support);
|
||||
|
||||
u32 boot_size = storage.ext_csd.boot_mult << 17;
|
||||
u32 rpmb_size = storage.ext_csd.rpmb_mult << 17;
|
||||
gfx_printf("%keMMC Partitions:%k\n", 0xFF00DDFF, 0xFFCCCCCC);
|
||||
gfx_printf(" 1: %kBOOT0 %k\n Size: %5d KiB (LBA Sectors: 0x%07X)\n", 0xFF96FF00, 0xFFCCCCCC,
|
||||
boot_size / 1024, boot_size / 512);
|
||||
gfx_put_small_sep();
|
||||
gfx_printf(" 2: %kBOOT1 %k\n Size: %5d KiB (LBA Sectors: 0x%07X)\n", 0xFF96FF00, 0xFFCCCCCC,
|
||||
boot_size / 1024, boot_size / 512);
|
||||
gfx_put_small_sep();
|
||||
gfx_printf(" 3: %kRPMB %k\n Size: %5d KiB (LBA Sectors: 0x%07X)\n", 0xFF96FF00, 0xFFCCCCCC,
|
||||
rpmb_size / 1024, rpmb_size / 512);
|
||||
gfx_put_small_sep();
|
||||
gfx_printf(" 0: %kGPP (USER) %k\n Size: %5d MiB (LBA Sectors: 0x%07X)\n\n", 0xFF96FF00, 0xFFCCCCCC,
|
||||
storage.sec_cnt >> SECTORS_TO_MIB_COEFF, storage.sec_cnt);
|
||||
gfx_put_small_sep();
|
||||
gfx_printf("%kGPP (eMMC USER) partition table:%k\n", 0xFF00DDFF, 0xFFCCCCCC);
|
||||
|
||||
sdmmc_storage_set_mmc_partition(&storage, EMMC_GPP);
|
||||
LIST_INIT(gpt);
|
||||
nx_emmc_gpt_parse(&gpt, &storage);
|
||||
int gpp_idx = 0;
|
||||
LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link)
|
||||
{
|
||||
gfx_printf(" %02d: %k%s%k\n Size: % 5d MiB (LBA Sectors 0x%07X)\n LBA Range: %08X-%08X\n",
|
||||
gpp_idx++, 0xFFAEFD14, part->name, 0xFFCCCCCC, (part->lba_end - part->lba_start + 1) >> SECTORS_TO_MIB_COEFF,
|
||||
part->lba_end - part->lba_start + 1, part->lba_start, part->lba_end);
|
||||
gfx_put_small_sep();
|
||||
}
|
||||
nx_emmc_gpt_free(&gpt);
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
sdmmc_storage_end(&storage);
|
||||
|
||||
btn_wait();
|
||||
}
|
||||
|
||||
void print_sdcard_info()
|
||||
{
|
||||
static const u32 SECTORS_TO_MIB_COEFF = 11;
|
||||
|
||||
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
if (sd_mount())
|
||||
{
|
||||
gfx_printf("%kCard IDentification:%k\n", 0xFF00DDFF, 0xFFCCCCCC);
|
||||
gfx_printf(
|
||||
" Vendor ID: %02x\n"
|
||||
" OEM ID: %c%c\n"
|
||||
" Model: %c%c%c%c%c\n"
|
||||
" HW rev: %X\n"
|
||||
" FW rev: %X\n"
|
||||
" S/N: %08x\n"
|
||||
" Month/Year: %02d/%04d\n\n",
|
||||
sd_storage.cid.manfid, (sd_storage.cid.oemid >> 8) & 0xFF, sd_storage.cid.oemid & 0xFF,
|
||||
sd_storage.cid.prod_name[0], sd_storage.cid.prod_name[1], sd_storage.cid.prod_name[2],
|
||||
sd_storage.cid.prod_name[3], sd_storage.cid.prod_name[4],
|
||||
sd_storage.cid.hwrev, sd_storage.cid.fwrev, sd_storage.cid.serial,
|
||||
sd_storage.cid.month, sd_storage.cid.year);
|
||||
|
||||
gfx_printf("%kCard-Specific Data V%d.0:%k\n", 0xFF00DDFF, sd_storage.csd.structure + 1, 0xFFCCCCCC);
|
||||
gfx_printf(
|
||||
" Cmd Classes: %02X\n"
|
||||
" Capacity: %d MiB\n"
|
||||
" Bus Width: %d\n"
|
||||
" Current Rate: %d MB/s (%d MHz)\n"
|
||||
" Speed Class: %d\n"
|
||||
" UHS Grade: U%d\n"
|
||||
" Video Class: V%d\n"
|
||||
" App perf class: A%d\n"
|
||||
" Write Protect: %d\n\n",
|
||||
sd_storage.csd.cmdclass, sd_storage.sec_cnt >> 11,
|
||||
sd_storage.ssr.bus_width, sd_storage.csd.busspeed, sd_storage.csd.busspeed * 2,
|
||||
sd_storage.ssr.speed_class, sd_storage.ssr.uhs_grade, sd_storage.ssr.video_class,
|
||||
sd_storage.ssr.app_class, sd_storage.csd.write_protect);
|
||||
|
||||
gfx_puts("Acquiring FAT volume info...\n\n");
|
||||
f_getfree("", &sd_fs.free_clst, NULL);
|
||||
gfx_printf("%kFound %s volume:%k\n Free: %d MiB\n Cluster: %d KiB\n",
|
||||
0xFF00DDFF, sd_fs.fs_type == FS_EXFAT ? "exFAT" : "FAT32", 0xFFCCCCCC,
|
||||
sd_fs.free_clst * sd_fs.csize >> SECTORS_TO_MIB_COEFF, (sd_fs.csize > 1) ? (sd_fs.csize >> 1) : 512);
|
||||
sd_unmount();
|
||||
}
|
||||
|
||||
btn_wait();
|
||||
}
|
||||
|
||||
void print_tsec_key()
|
||||
{
|
||||
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
u32 retries = 0;
|
||||
|
||||
tsec_ctxt_t tsec_ctxt;
|
||||
sdmmc_storage_t storage;
|
||||
sdmmc_t sdmmc;
|
||||
|
||||
sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400);
|
||||
|
||||
// Read package1.
|
||||
u8 *pkg1 = (u8 *)malloc(0x40000);
|
||||
sdmmc_storage_set_mmc_partition(&storage, EMMC_BOOT0);
|
||||
sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1);
|
||||
sdmmc_storage_end(&storage);
|
||||
const pkg1_id_t *pkg1_id = pkg1_identify(pkg1);
|
||||
if (!pkg1_id)
|
||||
{
|
||||
EPRINTF("Unknown pkg1 version.");
|
||||
goto out_wait;
|
||||
}
|
||||
|
||||
u8 keys[0x10 * 2];
|
||||
memset(keys, 0x00, 0x20);
|
||||
|
||||
tsec_ctxt.fw = (u8 *)pkg1 + pkg1_id->tsec_off;
|
||||
tsec_ctxt.pkg1 = pkg1;
|
||||
tsec_ctxt.pkg11_off = pkg1_id->pkg11_off;
|
||||
tsec_ctxt.secmon_base = pkg1_id->secmon_base;
|
||||
|
||||
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;
|
||||
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);
|
||||
memcpy(tsec_paged, (void *)tsec_ctxt.fw, tsec_ctxt.size);
|
||||
tsec_ctxt.fw = tsec_paged;
|
||||
}
|
||||
|
||||
int res = 0;
|
||||
|
||||
while (tsec_query(keys, pkg1_id->kb, &tsec_ctxt) < 0)
|
||||
{
|
||||
memset(keys, 0x00, 0x20);
|
||||
|
||||
retries++;
|
||||
|
||||
if (retries > 3)
|
||||
{
|
||||
res = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
gfx_printf("%kTSEC key: %k", 0xFF00DDFF, 0xFFCCCCCC);
|
||||
|
||||
if (res >= 0)
|
||||
{
|
||||
for (u32 j = 0; j < 0x10; j++)
|
||||
gfx_printf("%02X", keys[j]);
|
||||
|
||||
if (pkg1_id->kb == KB_FIRMWARE_VERSION_620)
|
||||
{
|
||||
gfx_printf("\n%kTSEC root: %k", 0xFF00DDFF, 0xFFCCCCCC);
|
||||
for (u32 j = 0; j < 0x10; j++)
|
||||
gfx_printf("%02X", keys[0x10 + j]);
|
||||
}
|
||||
}
|
||||
else
|
||||
EPRINTFARGS("ERROR %X\n", res);
|
||||
|
||||
gfx_puts("\n\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
|
||||
|
||||
u32 btn = btn_wait();
|
||||
if (btn & BTN_POWER)
|
||||
{
|
||||
if (sd_mount())
|
||||
{
|
||||
char path[64];
|
||||
emmcsn_path_impl(path, "/dumps", "tsec_keys.bin", NULL);
|
||||
if (!sd_save_to_file(keys, 0x10 * 2, path))
|
||||
gfx_puts("\nDone!\n");
|
||||
sd_unmount();
|
||||
}
|
||||
}
|
||||
else
|
||||
goto out;
|
||||
|
||||
out_wait:
|
||||
btn_wait();
|
||||
|
||||
out:
|
||||
free(pkg1);
|
||||
}
|
||||
|
||||
void print_fuel_gauge_info()
|
||||
{
|
||||
int value = 0;
|
||||
|
||||
gfx_printf("%kFuel Gauge Info:\n%k", 0xFF00DDFF, 0xFFCCCCCC);
|
||||
|
||||
max17050_get_property(MAX17050_RepSOC, &value);
|
||||
gfx_printf("Capacity now: %3d%\n", value >> 8);
|
||||
|
||||
max17050_get_property(MAX17050_RepCap, &value);
|
||||
gfx_printf("Capacity now: %4d mAh\n", value);
|
||||
|
||||
max17050_get_property(MAX17050_FullCAP, &value);
|
||||
gfx_printf("Capacity full: %4d mAh\n", value);
|
||||
|
||||
max17050_get_property(MAX17050_DesignCap, &value);
|
||||
gfx_printf("Capacity (design): %4d mAh\n", value);
|
||||
|
||||
max17050_get_property(MAX17050_Current, &value);
|
||||
if (value >= 0)
|
||||
gfx_printf("Current now: %d mA\n", value / 1000);
|
||||
else
|
||||
gfx_printf("Current now: -%d mA\n", ~value / 1000);
|
||||
|
||||
max17050_get_property(MAX17050_AvgCurrent, &value);
|
||||
if (value >= 0)
|
||||
gfx_printf("Current average: %d mA\n", value / 1000);
|
||||
else
|
||||
gfx_printf("Current average: -%d mA\n", ~value / 1000);
|
||||
|
||||
max17050_get_property(MAX17050_VCELL, &value);
|
||||
gfx_printf("Voltage now: %4d mV\n", value);
|
||||
|
||||
max17050_get_property(MAX17050_OCVInternal, &value);
|
||||
gfx_printf("Voltage open-circuit: %4d mV\n", value);
|
||||
|
||||
max17050_get_property(MAX17050_MinVolt, &value);
|
||||
gfx_printf("Min voltage reached: %4d mV\n", value);
|
||||
|
||||
max17050_get_property(MAX17050_MaxVolt, &value);
|
||||
gfx_printf("Max voltage reached: %4d mV\n", value);
|
||||
|
||||
max17050_get_property(MAX17050_V_empty, &value);
|
||||
gfx_printf("Empty voltage (design): %4d mV\n", value);
|
||||
|
||||
max17050_get_property(MAX17050_TEMP, &value);
|
||||
if (value >= 0)
|
||||
gfx_printf("Battery temperature: %d.%d oC\n", value / 10, value % 10);
|
||||
else
|
||||
gfx_printf("Battery temperature: -%d.%d oC\n", ~value / 10, (~value) % 10);
|
||||
}
|
||||
|
||||
void print_battery_charger_info()
|
||||
{
|
||||
int value = 0;
|
||||
|
||||
gfx_printf("%k\n\nBattery Charger Info:\n%k", 0xFF00DDFF, 0xFFCCCCCC);
|
||||
|
||||
bq24193_get_property(BQ24193_InputVoltageLimit, &value);
|
||||
gfx_printf("Input voltage limit: %4d mV\n", value);
|
||||
|
||||
bq24193_get_property(BQ24193_InputCurrentLimit, &value);
|
||||
gfx_printf("Input current limit: %4d mA\n", value);
|
||||
|
||||
bq24193_get_property(BQ24193_SystemMinimumVoltage, &value);
|
||||
gfx_printf("Min voltage limit: %4d mV\n", value);
|
||||
|
||||
bq24193_get_property(BQ24193_FastChargeCurrentLimit, &value);
|
||||
gfx_printf("Fast charge current limit: %4d mA\n", value);
|
||||
|
||||
bq24193_get_property(BQ24193_ChargeVoltageLimit, &value);
|
||||
gfx_printf("Charge voltage limit: %4d mV\n", value);
|
||||
|
||||
bq24193_get_property(BQ24193_ChargeStatus, &value);
|
||||
gfx_printf("Charge status: ");
|
||||
switch (value)
|
||||
{
|
||||
case 0:
|
||||
gfx_printf("Not charging\n");
|
||||
break;
|
||||
case 1:
|
||||
gfx_printf("Pre-charging\n");
|
||||
break;
|
||||
case 2:
|
||||
gfx_printf("Fast charging\n");
|
||||
break;
|
||||
case 3:
|
||||
gfx_printf("Charge terminated\n");
|
||||
break;
|
||||
default:
|
||||
gfx_printf("Unknown (%d)\n", value);
|
||||
break;
|
||||
}
|
||||
bq24193_get_property(BQ24193_TempStatus, &value);
|
||||
gfx_printf("Temperature status: ");
|
||||
switch (value)
|
||||
{
|
||||
case 0:
|
||||
gfx_printf("Normal\n");
|
||||
break;
|
||||
case 2:
|
||||
gfx_printf("Warm\n");
|
||||
break;
|
||||
case 3:
|
||||
gfx_printf("Cool\n");
|
||||
break;
|
||||
case 5:
|
||||
gfx_printf("Cold\n");
|
||||
break;
|
||||
case 6:
|
||||
gfx_printf("Hot\n");
|
||||
break;
|
||||
default:
|
||||
gfx_printf("Unknown (%d)\n", value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void print_battery_info()
|
||||
{
|
||||
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
print_fuel_gauge_info();
|
||||
|
||||
print_battery_charger_info();
|
||||
|
||||
u8 *buf = (u8 *)malloc(0x100 * 2);
|
||||
|
||||
gfx_printf("%k\n\nBattery Fuel Gauge Registers:\n%k", 0xFF00DDFF, 0xFFCCCCCC);
|
||||
|
||||
for (int i = 0; i < 0x200; i += 2)
|
||||
{
|
||||
i2c_recv_buf_small(buf + i, 2, I2C_1, MAXIM17050_I2C_ADDR, i >> 1);
|
||||
usleep(2500);
|
||||
}
|
||||
|
||||
gfx_hexdump(0, (u8 *)buf, 0x200);
|
||||
|
||||
gfx_puts("\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
|
||||
|
||||
u32 btn = btn_wait();
|
||||
|
||||
if (btn & BTN_POWER)
|
||||
{
|
||||
if (sd_mount())
|
||||
{
|
||||
char path[64];
|
||||
emmcsn_path_impl(path, "/dumps", "fuel_gauge.bin", NULL);
|
||||
if (sd_save_to_file((u8 *)buf, 0x200, path))
|
||||
EPRINTF("\nError creating fuel.bin file.");
|
||||
else
|
||||
gfx_puts("\nDone!\n");
|
||||
sd_unmount();
|
||||
}
|
||||
|
||||
btn_wait();
|
||||
}
|
||||
free(buf);
|
||||
}
|
||||
|
||||
void _ipatch_process(u32 offset, u32 value)
|
||||
{
|
||||
gfx_printf("%8x %8x", BOOTROM_BASE + offset, value);
|
||||
u8 lo = value & 0xff;
|
||||
switch (value >> 8)
|
||||
{
|
||||
case 0x20:
|
||||
gfx_printf(" MOVS R0, #0x%02X", lo);
|
||||
break;
|
||||
case 0xDF:
|
||||
gfx_printf(" SVC #0x%02X", lo);
|
||||
break;
|
||||
}
|
||||
gfx_puts("\n");
|
||||
}
|
||||
|
||||
void bootrom_ipatches_info()
|
||||
{
|
||||
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
static const u32 BOOTROM_SIZE = 0x18000;
|
||||
|
||||
u32 res = fuse_read_ipatch(_ipatch_process);
|
||||
if (res != 0)
|
||||
EPRINTFARGS("Failed to read ipatches. Error: %d", res);
|
||||
|
||||
gfx_puts("\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
|
||||
|
||||
u32 btn = btn_wait();
|
||||
if (btn & BTN_POWER)
|
||||
{
|
||||
if (sd_mount())
|
||||
{
|
||||
char path[64];
|
||||
u32 iram_evp_thunks[0x200];
|
||||
u32 iram_evp_thunks_len = sizeof(iram_evp_thunks);
|
||||
res = fuse_read_evp_thunk(iram_evp_thunks, &iram_evp_thunks_len);
|
||||
if (res == 0)
|
||||
{
|
||||
emmcsn_path_impl(path, "/dumps", "evp_thunks.bin", NULL);
|
||||
if (!sd_save_to_file((u8 *)iram_evp_thunks, iram_evp_thunks_len, path))
|
||||
gfx_puts("\nevp_thunks.bin saved!\n");
|
||||
}
|
||||
else
|
||||
EPRINTFARGS("Failed to read evp_thunks. Error: %d", res);
|
||||
|
||||
emmcsn_path_impl(path, "/dumps", "bootrom_patched.bin", NULL);
|
||||
if (!sd_save_to_file((u8 *)BOOTROM_BASE, BOOTROM_SIZE, path))
|
||||
gfx_puts("\nbootrom_patched.bin saved!\n");
|
||||
|
||||
u32 ipatch_backup[14];
|
||||
memcpy(ipatch_backup, (void *)IPATCH_BASE, sizeof(ipatch_backup));
|
||||
memset((void*)IPATCH_BASE, 0, sizeof(ipatch_backup));
|
||||
|
||||
emmcsn_path_impl(path, "/dumps", "bootrom_unpatched.bin", NULL);
|
||||
if (!sd_save_to_file((u8 *)BOOTROM_BASE, BOOTROM_SIZE, path))
|
||||
gfx_puts("\nbootrom_unpatched.bin saved!\n");
|
||||
|
||||
memcpy((void*)IPATCH_BASE, ipatch_backup, sizeof(ipatch_backup));
|
||||
|
||||
sd_unmount();
|
||||
}
|
||||
|
||||
btn_wait();
|
||||
}
|
||||
}
|
||||
|
||||
#pragma GCC pop_options
|
||||
@@ -1,5 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018 CTCaer
|
||||
* Copyright (c) 2018 balika011
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -14,21 +16,17 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* TODO: the placement of the relocator is a bit fragile atm, maybe we
|
||||
* should include it in start.S and copy it to some known good
|
||||
* place in IRAM instead. Basically we want it as far back atm
|
||||
* as it might be overwritten during relocation.
|
||||
*/
|
||||
#ifndef _FE_INFO_H_
|
||||
#define _FE_INFO_H_
|
||||
|
||||
.section .text.reloc
|
||||
.arm
|
||||
void print_fuseinfo();
|
||||
void print_kfuseinfo();
|
||||
void print_mmc_info();
|
||||
void print_sdcard_info();
|
||||
void print_tsec_key();
|
||||
void print_fuel_gauge_info();
|
||||
void print_battery_charger_info();
|
||||
void print_battery_info();
|
||||
void bootrom_ipatches_info();
|
||||
|
||||
.globl _reloc_ipl
|
||||
.type _reloc_ipl, %function
|
||||
_reloc_ipl:
|
||||
LDMIA R0!, {R4-R7}
|
||||
STMIA R1!, {R4-R7}
|
||||
SUBS R2, #0x10
|
||||
BNE _reloc_ipl
|
||||
BX R3
|
||||
#endif
|
||||
609
bootloader/frontend/fe_tools.c
Normal file
609
bootloader/frontend/fe_tools.c
Normal file
@@ -0,0 +1,609 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2019 CTCaer
|
||||
* Copyright (c) 2018 Reisyukaku
|
||||
*
|
||||
* 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 "fe_tools.h"
|
||||
#include "../config/config.h"
|
||||
#include "../gfx/gfx.h"
|
||||
#include "../gfx/tui.h"
|
||||
#include "../hos/hos.h"
|
||||
#include "../hos/pkg1.h"
|
||||
#include "../hos/pkg2.h"
|
||||
#include "../hos/sept.h"
|
||||
#include "../libs/fatfs/ff.h"
|
||||
#include "../mem/heap.h"
|
||||
#include "../power/max7762x.h"
|
||||
#include "../sec/se.h"
|
||||
#include "../storage/nx_emmc.h"
|
||||
#include "../storage/nx_sd.h"
|
||||
#include "../storage/sdmmc.h"
|
||||
#include "../soc/fuse.h"
|
||||
#include "../utils/btn.h"
|
||||
#include "../utils/util.h"
|
||||
|
||||
extern boot_cfg_t b_cfg;
|
||||
extern hekate_config h_cfg;
|
||||
|
||||
extern void emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage);
|
||||
|
||||
#pragma GCC push_options
|
||||
#pragma GCC optimize ("Os")
|
||||
|
||||
void dump_packages12()
|
||||
{
|
||||
if (!sd_mount())
|
||||
return;
|
||||
|
||||
char path[64];
|
||||
|
||||
u8 *pkg1 = (u8 *)calloc(1, 0x40000);
|
||||
u8 *warmboot = (u8 *)calloc(1, 0x40000);
|
||||
u8 *secmon = (u8 *)calloc(1, 0x40000);
|
||||
u8 *loader = (u8 *)calloc(1, 0x40000);
|
||||
u8 *pkg2 = NULL;
|
||||
u8 kb = 0;
|
||||
|
||||
tsec_ctxt_t tsec_ctxt;
|
||||
|
||||
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
sdmmc_storage_t storage;
|
||||
sdmmc_t sdmmc;
|
||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400))
|
||||
{
|
||||
EPRINTF("Failed to init eMMC.");
|
||||
goto out_free;
|
||||
}
|
||||
sdmmc_storage_set_mmc_partition(&storage, EMMC_BOOT0);
|
||||
|
||||
// Read package1.
|
||||
sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1);
|
||||
const pkg1_id_t *pkg1_id = pkg1_identify(pkg1);
|
||||
if (!pkg1_id)
|
||||
{
|
||||
EPRINTF("Unknown pkg1 version for reading\nTSEC firmware.");
|
||||
// Dump package1.
|
||||
emmcsn_path_impl(path, "/pkg1", "pkg1_enc.bin", &storage);
|
||||
if (sd_save_to_file(pkg1, 0x40000, path))
|
||||
goto out_free;
|
||||
gfx_puts("\nEnc pkg1 dumped to pkg1_enc.bin\n");
|
||||
|
||||
goto out_free;
|
||||
}
|
||||
const pk11_hdr_t *hdr = (pk11_hdr_t *)(pkg1 + pkg1_id->pkg11_off + 0x20);
|
||||
|
||||
kb = pkg1_id->kb;
|
||||
|
||||
if (!h_cfg.se_keygen_done)
|
||||
{
|
||||
tsec_ctxt.fw = (void *)pkg1 + pkg1_id->tsec_off;
|
||||
tsec_ctxt.pkg1 = (void *)pkg1;
|
||||
tsec_ctxt.pkg11_off = pkg1_id->pkg11_off;
|
||||
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, NULL))
|
||||
{
|
||||
gfx_printf("Failed to run sept\n");
|
||||
goto out_free;
|
||||
}
|
||||
}
|
||||
|
||||
// Read keyblob.
|
||||
u8 *keyblob = (u8 *)calloc(NX_EMMC_BLOCKSIZE, 1);
|
||||
sdmmc_storage_read(&storage, 0x180000 / NX_EMMC_BLOCKSIZE + kb, 1, keyblob);
|
||||
|
||||
// Decrypt.
|
||||
hos_keygen(keyblob, kb, &tsec_ctxt, NULL);
|
||||
if (kb <= KB_FIRMWARE_VERSION_600)
|
||||
h_cfg.se_keygen_done = 1;
|
||||
free(keyblob);
|
||||
}
|
||||
|
||||
if (kb <= KB_FIRMWARE_VERSION_600)
|
||||
pkg1_decrypt(pkg1_id, pkg1);
|
||||
|
||||
if (kb <= KB_FIRMWARE_VERSION_620)
|
||||
{
|
||||
pkg1_unpack(warmboot, secmon, loader, pkg1_id, pkg1);
|
||||
|
||||
// Display info.
|
||||
gfx_printf("%kNX Bootloader size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, hdr->ldr_size);
|
||||
|
||||
gfx_printf("%kSecure monitor addr: %k0x%05X\n", 0xFFC7EA46, 0xFFCCCCCC, pkg1_id->secmon_base);
|
||||
gfx_printf("%kSecure monitor size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, hdr->sm_size);
|
||||
|
||||
gfx_printf("%kWarmboot addr: %k0x%05X\n", 0xFFC7EA46, 0xFFCCCCCC, pkg1_id->warmboot_base);
|
||||
gfx_printf("%kWarmboot size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, hdr->wb_size);
|
||||
|
||||
// Dump package1.1.
|
||||
emmcsn_path_impl(path, "/pkg1", "pkg1_decr.bin", &storage);
|
||||
if (sd_save_to_file(pkg1, 0x40000, path))
|
||||
goto out_free;
|
||||
gfx_puts("\npkg1 dumped to pkg1_decr.bin\n");
|
||||
|
||||
// Dump nxbootloader.
|
||||
emmcsn_path_impl(path, "/pkg1", "nxloader.bin", &storage);
|
||||
if (sd_save_to_file(loader, hdr->ldr_size, path))
|
||||
goto out_free;
|
||||
gfx_puts("NX Bootloader dumped to nxloader.bin\n");
|
||||
|
||||
// Dump secmon.
|
||||
emmcsn_path_impl(path, "/pkg1", "secmon.bin", &storage);
|
||||
if (sd_save_to_file(secmon, hdr->sm_size, path))
|
||||
goto out_free;
|
||||
gfx_puts("Secure Monitor dumped to secmon.bin\n");
|
||||
|
||||
// Dump warmboot.
|
||||
emmcsn_path_impl(path, "/pkg1", "warmboot.bin", &storage);
|
||||
if (sd_save_to_file(warmboot, hdr->wb_size, path))
|
||||
goto out_free;
|
||||
gfx_puts("Warmboot dumped to warmboot.bin\n\n\n");
|
||||
}
|
||||
|
||||
// Dump package2.1.
|
||||
sdmmc_storage_set_mmc_partition(&storage, EMMC_GPP);
|
||||
// Parse eMMC GPT.
|
||||
LIST_INIT(gpt);
|
||||
nx_emmc_gpt_parse(&gpt, &storage);
|
||||
// Find package2 partition.
|
||||
emmc_part_t *pkg2_part = nx_emmc_part_find(&gpt, "BCPKG2-1-Normal-Main");
|
||||
if (!pkg2_part)
|
||||
goto out;
|
||||
|
||||
// Read in package2 header and get package2 real size.
|
||||
u8 *tmp = (u8 *)malloc(NX_EMMC_BLOCKSIZE);
|
||||
nx_emmc_part_read(&storage, pkg2_part, 0x4000 / NX_EMMC_BLOCKSIZE, 1, tmp);
|
||||
u32 *hdr_pkg2_raw = (u32 *)(tmp + 0x100);
|
||||
u32 pkg2_size = hdr_pkg2_raw[0] ^ hdr_pkg2_raw[2] ^ hdr_pkg2_raw[3];
|
||||
free(tmp);
|
||||
// Read in package2.
|
||||
u32 pkg2_size_aligned = ALIGN(pkg2_size, NX_EMMC_BLOCKSIZE);
|
||||
pkg2 = malloc(pkg2_size_aligned);
|
||||
nx_emmc_part_read(&storage, pkg2_part, 0x4000 / NX_EMMC_BLOCKSIZE,
|
||||
pkg2_size_aligned / NX_EMMC_BLOCKSIZE, pkg2);
|
||||
// Decrypt package2 and parse KIP1 blobs in INI1 section.
|
||||
pkg2_hdr_t *pkg2_hdr = pkg2_decrypt(pkg2, kb);
|
||||
if (!pkg2_hdr)
|
||||
{
|
||||
gfx_printf("Pkg2 decryption failed!\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
// Display info.
|
||||
gfx_printf("%kKernel size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, pkg2_hdr->sec_size[PKG2_SEC_KERNEL]);
|
||||
gfx_printf("%kINI1 size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, pkg2_hdr->sec_size[PKG2_SEC_INI1]);
|
||||
|
||||
// Dump pkg2.1.
|
||||
emmcsn_path_impl(path, "/pkg2", "pkg2_decr.bin", &storage);
|
||||
if (sd_save_to_file(pkg2, pkg2_hdr->sec_size[PKG2_SEC_KERNEL] + pkg2_hdr->sec_size[PKG2_SEC_INI1], path))
|
||||
goto out;
|
||||
gfx_puts("\npkg2 dumped to pkg2_decr.bin\n");
|
||||
|
||||
// Dump kernel.
|
||||
emmcsn_path_impl(path, "/pkg2", "kernel.bin", &storage);
|
||||
if (sd_save_to_file(pkg2_hdr->data, pkg2_hdr->sec_size[PKG2_SEC_KERNEL], path))
|
||||
goto out;
|
||||
gfx_puts("Kernel dumped to kernel.bin\n");
|
||||
|
||||
// Dump INI1.
|
||||
emmcsn_path_impl(path, "/pkg2", "ini1.bin", &storage);
|
||||
u32 ini1_off = pkg2_hdr->sec_size[PKG2_SEC_KERNEL];
|
||||
u32 ini1_size = pkg2_hdr->sec_size[PKG2_SEC_INI1];
|
||||
if (!ini1_size)
|
||||
{
|
||||
pkg2_get_newkern_info(pkg2_hdr->data);
|
||||
ini1_off = pkg2_newkern_ini1_start;
|
||||
ini1_size = pkg2_newkern_ini1_end - pkg2_newkern_ini1_start;
|
||||
}
|
||||
if (ini1_off)
|
||||
{
|
||||
if (sd_save_to_file(pkg2_hdr->data + ini1_off, ini1_size, path))
|
||||
goto out;
|
||||
gfx_puts("INI1 dumped to ini1.bin\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
gfx_puts("Failed to dump INI1!\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
gfx_puts("\nDone. Press any key...\n");
|
||||
|
||||
out:
|
||||
nx_emmc_gpt_free(&gpt);
|
||||
out_free:
|
||||
free(pkg1);
|
||||
free(secmon);
|
||||
free(warmboot);
|
||||
free(loader);
|
||||
free(pkg2);
|
||||
sdmmc_storage_end(&storage);
|
||||
sd_unmount();
|
||||
|
||||
if (kb >= KB_FIRMWARE_VERSION_620)
|
||||
se_aes_key_clear(8);
|
||||
|
||||
btn_wait();
|
||||
}
|
||||
|
||||
void _toggle_autorcm(bool enable)
|
||||
{
|
||||
sdmmc_storage_t storage;
|
||||
sdmmc_t sdmmc;
|
||||
|
||||
u8 randomXor = 0;
|
||||
|
||||
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400))
|
||||
{
|
||||
EPRINTF("Failed to init eMMC.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
u8 *tempbuf = (u8 *)malloc(0x200);
|
||||
sdmmc_storage_set_mmc_partition(&storage, EMMC_BOOT0);
|
||||
|
||||
int i, sect = 0;
|
||||
u8 corr_mod_byte0;
|
||||
if ((fuse_read_odm(4) & 3) != 3)
|
||||
corr_mod_byte0 = 0xF7;
|
||||
else
|
||||
corr_mod_byte0 = 0x37;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
sect = (0x200 + (0x4000 * i)) / NX_EMMC_BLOCKSIZE;
|
||||
sdmmc_storage_read(&storage, sect, 1, tempbuf);
|
||||
|
||||
if (enable)
|
||||
{
|
||||
do
|
||||
{
|
||||
randomXor = get_tmr_us() & 0xFF; // Bricmii style of bricking.
|
||||
} while (!randomXor); // Avoid the lottery.
|
||||
|
||||
tempbuf[0x10] ^= randomXor;
|
||||
}
|
||||
else
|
||||
tempbuf[0x10] = corr_mod_byte0;
|
||||
sdmmc_storage_write(&storage, sect, 1, tempbuf);
|
||||
}
|
||||
|
||||
free(tempbuf);
|
||||
sdmmc_storage_end(&storage);
|
||||
|
||||
if (enable)
|
||||
gfx_printf("%kAutoRCM mode enabled!%k", 0xFFFFBA00, 0xFFCCCCCC);
|
||||
else
|
||||
gfx_printf("%kAutoRCM mode disabled!%k", 0xFF96FF00, 0xFFCCCCCC);
|
||||
gfx_printf("\n\nPress any key...\n");
|
||||
|
||||
out:
|
||||
btn_wait();
|
||||
}
|
||||
|
||||
void _enable_autorcm() { _toggle_autorcm(true); }
|
||||
void _disable_autorcm() { _toggle_autorcm(false); }
|
||||
|
||||
void menu_autorcm()
|
||||
{
|
||||
gfx_clear_grey(0x1B);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
if (h_cfg.rcm_patched)
|
||||
{
|
||||
gfx_printf("%kThis device is RCM patched and\nAutoRCM function is disabled.\n\n"
|
||||
"In case %kAutoRCM%k is enabled\nthis will %kBRICK%k your device PERMANENTLY!!%k",
|
||||
0xFFFFDD00, 0xFFFF0000, 0xFFFFDD00, 0xFFFF0000, 0xFFFFDD00, 0xFFCCCCCC);
|
||||
btn_wait();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Do a simple check on the main BCT.
|
||||
sdmmc_storage_t storage;
|
||||
sdmmc_t sdmmc;
|
||||
bool disabled = true;
|
||||
|
||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400))
|
||||
{
|
||||
EPRINTF("Failed to init eMMC.");
|
||||
btn_wait();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
u8 *tempbuf = (u8 *)malloc(0x200);
|
||||
sdmmc_storage_set_mmc_partition(&storage, EMMC_BOOT0);
|
||||
sdmmc_storage_read(&storage, 0x200 / NX_EMMC_BLOCKSIZE, 1, tempbuf);
|
||||
|
||||
if ((fuse_read_odm(4) & 3) != 3)
|
||||
{
|
||||
if (tempbuf[0x10] != 0xF7)
|
||||
disabled = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tempbuf[0x10] != 0x37)
|
||||
disabled = false;
|
||||
}
|
||||
|
||||
free(tempbuf);
|
||||
sdmmc_storage_end(&storage);
|
||||
|
||||
// Create AutoRCM menu.
|
||||
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 6);
|
||||
|
||||
ments[0].type = MENT_BACK;
|
||||
ments[0].caption = "Back";
|
||||
|
||||
ments[1].type = MENT_CHGLINE;
|
||||
|
||||
ments[2].type = MENT_CAPTION;
|
||||
ments[3].type = MENT_CHGLINE;
|
||||
if (disabled)
|
||||
{
|
||||
ments[2].caption = "Status: Disabled!";
|
||||
ments[2].color = 0xFF96FF00;
|
||||
ments[4].caption = "Enable AutoRCM";
|
||||
ments[4].handler = _enable_autorcm;
|
||||
}
|
||||
else
|
||||
{
|
||||
ments[2].caption = "Status: Enabled!";
|
||||
ments[2].color = 0xFFFFBA00;
|
||||
ments[4].caption = "Disable AutoRCM";
|
||||
ments[4].handler = _disable_autorcm;
|
||||
}
|
||||
ments[4].type = MENT_HDLR_RE;
|
||||
ments[4].data = NULL;
|
||||
|
||||
memset(&ments[5], 0, sizeof(ment_t));
|
||||
menu_t menu = {ments, "This corrupts your BOOT0!", 0, 0};
|
||||
|
||||
tui_do_menu(&menu);
|
||||
}
|
||||
|
||||
int _fix_attributes(char *path, u32 *total, u32 hos_folder, u32 check_first_run)
|
||||
{
|
||||
FRESULT res;
|
||||
DIR dir;
|
||||
u32 dirLength = 0;
|
||||
static FILINFO fno;
|
||||
|
||||
if (check_first_run)
|
||||
{
|
||||
// Read file attributes.
|
||||
res = f_stat(path, &fno);
|
||||
if (res != FR_OK)
|
||||
return res;
|
||||
|
||||
// Check if archive bit is set.
|
||||
if (fno.fattrib & AM_ARC)
|
||||
{
|
||||
*(u32 *)total = *(u32 *)total + 1;
|
||||
f_chmod(path, 0, AM_ARC);
|
||||
}
|
||||
}
|
||||
|
||||
// Open directory.
|
||||
res = f_opendir(&dir, path);
|
||||
if (res != FR_OK)
|
||||
return res;
|
||||
|
||||
dirLength = strlen(path);
|
||||
for (;;)
|
||||
{
|
||||
// Clear file or folder path.
|
||||
path[dirLength] = 0;
|
||||
|
||||
// Read a directory item.
|
||||
res = f_readdir(&dir, &fno);
|
||||
|
||||
// Break on error or end of dir.
|
||||
if (res != FR_OK || fno.fname[0] == 0)
|
||||
break;
|
||||
|
||||
// Skip official Nintendo dir if started from root.
|
||||
if (!hos_folder && !strcmp(fno.fname, "Nintendo"))
|
||||
continue;
|
||||
|
||||
// Set new directory or file.
|
||||
memcpy(&path[dirLength], "/", 1);
|
||||
memcpy(&path[dirLength + 1], fno.fname, strlen(fno.fname) + 1);
|
||||
|
||||
// Check if archive bit is set.
|
||||
if (fno.fattrib & AM_ARC)
|
||||
{
|
||||
*total = *total + 1;
|
||||
f_chmod(path, 0, AM_ARC);
|
||||
}
|
||||
|
||||
// Is it a directory?
|
||||
if (fno.fattrib & AM_DIR)
|
||||
{
|
||||
// Set archive bit to NCA folders.
|
||||
if (hos_folder && !strcmp(fno.fname + strlen(fno.fname) - 4, ".nca"))
|
||||
{
|
||||
*total = *total + 1;
|
||||
f_chmod(path, AM_ARC, AM_ARC);
|
||||
}
|
||||
|
||||
// Update status bar.
|
||||
tui_sbar(false);
|
||||
|
||||
// Enter the directory.
|
||||
res = _fix_attributes(path, total, hos_folder, 0);
|
||||
if (res != FR_OK)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
f_closedir(&dir);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void _fix_sd_attr(u32 type)
|
||||
{
|
||||
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
char path[256];
|
||||
char label[16];
|
||||
|
||||
u32 total = 0;
|
||||
if (sd_mount())
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case 0:
|
||||
strcpy(path, "/");
|
||||
strcpy(label, "SD Card");
|
||||
break;
|
||||
case 1:
|
||||
default:
|
||||
strcpy(path, "/Nintendo");
|
||||
strcpy(label, "Nintendo folder");
|
||||
break;
|
||||
}
|
||||
|
||||
gfx_printf("Traversing all %s files!\nThis may take some time...\n\n", label);
|
||||
_fix_attributes(path, &total, type, type);
|
||||
gfx_printf("%kTotal archive bits cleared: %d!%k\n\nDone! Press any key...", 0xFF96FF00, total, 0xFFCCCCCC);
|
||||
sd_unmount();
|
||||
}
|
||||
btn_wait();
|
||||
}
|
||||
|
||||
void fix_sd_all_attr() { _fix_sd_attr(0); }
|
||||
void fix_sd_nin_attr() { _fix_sd_attr(1); }
|
||||
|
||||
/* void fix_fuel_gauge_configuration()
|
||||
{
|
||||
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
int battVoltage, avgCurrent;
|
||||
|
||||
max17050_get_property(MAX17050_VCELL, &battVoltage);
|
||||
max17050_get_property(MAX17050_AvgCurrent, &avgCurrent);
|
||||
|
||||
// Check if still charging. If not, check if battery is >= 95% (4.1V).
|
||||
if (avgCurrent < 0 && battVoltage > 4100)
|
||||
{
|
||||
if ((avgCurrent / 1000) < -10)
|
||||
EPRINTF("You need to be connected to a wall adapter,\nto apply this fix!");
|
||||
else
|
||||
{
|
||||
gfx_printf("%kAre you really sure?\nThis will reset your fuel gauge completely!\n", 0xFFFFDD00);
|
||||
gfx_printf("Additionally this will power off your console.\n%k", 0xFFCCCCCC);
|
||||
|
||||
gfx_puts("\nPress POWER to Continue.\nPress VOL to go to the menu.\n\n\n");
|
||||
|
||||
u32 btn = btn_wait();
|
||||
if (btn & BTN_POWER)
|
||||
{
|
||||
max17050_fix_configuration();
|
||||
msleep(1000);
|
||||
gfx_con_getpos(&gfx_con.savedx, &gfx_con.savedy);
|
||||
u16 value = 0;
|
||||
gfx_printf("%kThe console will power off in 45 seconds.\n%k", 0xFFFFDD00, 0xFFCCCCCC);
|
||||
while (value < 46)
|
||||
{
|
||||
gfx_con_setpos(gfx_con.savedx, gfx_con.savedy);
|
||||
gfx_printf("%2ds elapsed", value);
|
||||
msleep(1000);
|
||||
value++;
|
||||
}
|
||||
msleep(2000);
|
||||
|
||||
power_off();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
EPRINTF("You need a fully charged battery\nand connected to a wall adapter,\nto apply this fix!");
|
||||
|
||||
msleep(500);
|
||||
btn_wait();
|
||||
} */
|
||||
|
||||
/*void reset_pmic_fuel_gauge_charger_config()
|
||||
{
|
||||
int avgCurrent;
|
||||
|
||||
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
gfx_printf("%k\nThis will wipe your battery stats completely!\n"
|
||||
"%kAnd it may not power on without physically\nremoving and re-inserting the battery.\n%k"
|
||||
"\nAre you really sure?%k\n", 0xFFFFDD00, 0xFFFF0000, 0xFFFFDD00, 0xFFCCCCCC);
|
||||
|
||||
gfx_puts("\nPress POWER to Continue.\nPress VOL to go to the menu.\n\n\n");
|
||||
u32 btn = btn_wait();
|
||||
if (btn & BTN_POWER)
|
||||
{
|
||||
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||
gfx_con_setpos(0, 0);
|
||||
gfx_printf("%kKeep the USB cable connected!%k\n\n", 0xFFFFDD00, 0xFFCCCCCC);
|
||||
gfx_con_getpos(&gfx_con.savedx, &gfx_con.savedy);
|
||||
|
||||
u8 value = 30;
|
||||
while (value > 0)
|
||||
{
|
||||
gfx_con_setpos(gfx_con.savedx, gfx_con.savedy);
|
||||
gfx_printf("%kWait... (%ds) %k", 0xFF888888, value, 0xFFCCCCCC);
|
||||
msleep(1000);
|
||||
value--;
|
||||
}
|
||||
gfx_con_setpos(gfx_con.savedx, gfx_con.savedy);
|
||||
|
||||
//Check if still connected.
|
||||
max17050_get_property(MAX17050_AvgCurrent, &avgCurrent);
|
||||
if ((avgCurrent / 1000) < -10)
|
||||
EPRINTF("You need to be connected to a wall adapter\nor PC to apply this fix!");
|
||||
else
|
||||
{
|
||||
// Apply fix.
|
||||
bq24193_fake_battery_removal();
|
||||
gfx_printf("Done! \n"
|
||||
"%k1. Remove the USB cable\n"
|
||||
"2. Press POWER for 15s.\n"
|
||||
"3. Reconnect the USB to power-on!%k\n", 0xFFFFDD00, 0xFFCCCCCC);
|
||||
}
|
||||
msleep(500);
|
||||
btn_wait();
|
||||
}
|
||||
}*/
|
||||
|
||||
#pragma GCC pop_options
|
||||
27
bootloader/frontend/fe_tools.h
Normal file
27
bootloader/frontend/fe_tools.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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 _FE_TOOLS_H_
|
||||
#define _FE_TOOLS_H_
|
||||
|
||||
void dump_packages12();
|
||||
void fix_sd_all_attr();
|
||||
void fix_sd_nin_attr();
|
||||
void fix_battery_desync();
|
||||
void menu_autorcm();
|
||||
|
||||
#endif
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (C) 2018 CTCaer
|
||||
* Copyright (c) 2018-2019 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -18,18 +18,24 @@
|
||||
#include <string.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 "../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"
|
||||
|
||||
static u32 _display_ver = 0;
|
||||
extern volatile nyx_storage_t *nyx_str;
|
||||
|
||||
static u32 _display_id = 0;
|
||||
|
||||
void display_end();
|
||||
|
||||
static void _display_dsi_wait(u32 timeout, u32 off, u32 mask)
|
||||
{
|
||||
@@ -39,67 +45,89 @@ static void _display_dsi_wait(u32 timeout, u32 off, u32 mask)
|
||||
usleep(5);
|
||||
}
|
||||
|
||||
static void _display_dsi_send_cmd(u8 cmd, u32 param, u32 wait)
|
||||
{
|
||||
DSI(_DSIREG(DSI_WR_DATA)) = (param << 8) | cmd;
|
||||
DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST;
|
||||
|
||||
if (wait)
|
||||
usleep(wait);
|
||||
}
|
||||
|
||||
void display_init()
|
||||
{
|
||||
// Check if display is already initialized.
|
||||
if (CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) & 0x18000000)
|
||||
display_end();
|
||||
|
||||
// Power on.
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_LDO0_CFG, 0xD0); // Configure to 1.2V.
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO7, 0x09);
|
||||
max77620_regulator_set_volt_and_flags(REGULATOR_LDO0, 1200000, MAX77620_POWER_MODE_NORMAL); // Configure to 1.2V.
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO7, MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH | MAX77620_CNFG_GPIO_DRV_PUSHPULL);
|
||||
|
||||
// Enable MIPI CAL, DSI, DISP1, HOST1X, UART_FST_MIPI_CAL, DSIA LP clocks.
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = 0x1010000;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = 0x1010000;
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = 0x18000000;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = 0x18000000;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = 0x20000;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIP_CAL) = 0xA;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_SET) = 0x80000;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP) = 0xA;
|
||||
// Enable Display Interface specific clocks.
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = 0x1010000; // Clear reset DSI, MIPI_CAL.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = 0x1010000; // Set enable clock DSI, MIPI_CAL.
|
||||
|
||||
// DPD idle.
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = 0x18000000; // Clear reset DISP1, HOST1X.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = 0x18000000; // Set enable clock DISP1, HOST1X.
|
||||
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = 0x20000; // Set enable clock UART_FST_MIPI_CAL.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIPI_CAL) = 10; // Set PLLP_OUT3 and div 6 (17MHz).
|
||||
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_SET) = 0x80000; // Set enable clock DSIA_LP.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP) = 10; // Set PLLP_OUT and div 6 (68MHz).
|
||||
|
||||
// Disable deep power down.
|
||||
PMC(APBDEV_PMC_IO_DPD_REQ) = 0x40000000;
|
||||
PMC(APBDEV_PMC_IO_DPD2_REQ) = 0x40000000;
|
||||
|
||||
// Config pins.
|
||||
PINMUX_AUX(PINMUX_AUX_NFC_EN) &= ~PINMUX_TRISTATE;
|
||||
PINMUX_AUX(PINMUX_AUX_NFC_INT) &= ~PINMUX_TRISTATE;
|
||||
PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) &= ~PINMUX_TRISTATE;
|
||||
PINMUX_AUX(PINMUX_AUX_LCD_BL_EN) &= ~PINMUX_TRISTATE;
|
||||
PINMUX_AUX(PINMUX_AUX_LCD_RST) &= ~PINMUX_TRISTATE;
|
||||
// Config LCD and Backlight pins.
|
||||
PINMUX_AUX(PINMUX_AUX_NFC_EN) &= ~PINMUX_TRISTATE; // PULL_DOWN
|
||||
PINMUX_AUX(PINMUX_AUX_NFC_INT) &= ~PINMUX_TRISTATE; // PULL_DOWN
|
||||
PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) &= ~PINMUX_TRISTATE; // PULL_DOWN | 1
|
||||
PINMUX_AUX(PINMUX_AUX_LCD_BL_EN) &= ~PINMUX_TRISTATE; // PULL_DOWN
|
||||
PINMUX_AUX(PINMUX_AUX_LCD_RST) &= ~PINMUX_TRISTATE; // PULL_DOWN
|
||||
|
||||
gpio_config(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_MODE_GPIO); // Backlight +-5V.
|
||||
gpio_output_enable(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_OUTPUT_ENABLE); // Backlight +-5V.
|
||||
// Set Backlight +-5V pins mode and direction
|
||||
gpio_config(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_MODE_GPIO);
|
||||
gpio_output_enable(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_OUTPUT_ENABLE);
|
||||
|
||||
// Enable Backlight power.
|
||||
gpio_write(GPIO_PORT_I, GPIO_PIN_0, GPIO_HIGH); // Backlight +5V enable.
|
||||
|
||||
usleep(10000);
|
||||
|
||||
gpio_write(GPIO_PORT_I, GPIO_PIN_1, GPIO_HIGH); // Backlight -5V enable.
|
||||
|
||||
usleep(10000);
|
||||
|
||||
gpio_config(GPIO_PORT_V, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2, GPIO_MODE_GPIO); // Backlight PWM, Enable, Reset.
|
||||
// Configure Backlight pins (PWM, EN, RST).
|
||||
gpio_config(GPIO_PORT_V, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2, GPIO_MODE_GPIO);
|
||||
gpio_output_enable(GPIO_PORT_V, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2, GPIO_OUTPUT_ENABLE);
|
||||
gpio_write(GPIO_PORT_V, GPIO_PIN_1, GPIO_HIGH); // Backlight Enable enable.
|
||||
gpio_write(GPIO_PORT_V, GPIO_PIN_1, GPIO_HIGH); // Enable Backlight EN.
|
||||
|
||||
// Config display interface and display.
|
||||
MIPI_CAL(0x60) = 0;
|
||||
// Power up supply regulator for display interface.
|
||||
MIPI_CAL(_DSIREG(MIPI_CAL_MIPI_BIAS_PAD_CFG2)) = 0;
|
||||
|
||||
exec_cfg((u32 *)CLOCK_BASE, _display_config_1, 4);
|
||||
exec_cfg((u32 *)DISPLAY_A_BASE, _display_config_2, 94);
|
||||
exec_cfg((u32 *)DSI_BASE, _display_config_3, 61);
|
||||
// Set DISP1 clock source and parent clock.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_DISP1) = 0x40000000; // PLLD_OUT.
|
||||
u32 plld_div = (3 << 20) | (20 << 11) | 1; // DIVM: 1, DIVN: 20, DIVP: 3. PLLD_OUT: 768 MHz, PLLD_OUT0 (DSI): 96 MHz.
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) = PLLCX_BASE_ENABLE | PLLCX_BASE_LOCK | plld_div;
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLD_MISC1) = 0x20; // PLLD_SETUP.
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLD_MISC) = 0x2D0AAA; // PLLD_ENABLE_CLK.
|
||||
|
||||
// Setup display communication interfaces.
|
||||
exec_cfg((u32 *)DISPLAY_A_BASE, _display_dc_setup_win_config, 94);
|
||||
exec_cfg((u32 *)DSI_BASE, _display_dsi_init_config, 61);
|
||||
usleep(10000);
|
||||
|
||||
gpio_write(GPIO_PORT_V, GPIO_PIN_2, GPIO_HIGH); // Backlight Reset enable.
|
||||
|
||||
// Enable Backlight Reset.
|
||||
gpio_write(GPIO_PORT_V, GPIO_PIN_2, GPIO_HIGH);
|
||||
usleep(60000);
|
||||
|
||||
// Setups DSI packet configuration and request display id.
|
||||
DSI(_DSIREG(DSI_BTA_TIMING)) = 0x50204;
|
||||
DSI(_DSIREG(DSI_WR_DATA)) = 0x337;
|
||||
DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST;
|
||||
_display_dsi_send_cmd(MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE, 3, 0);
|
||||
_display_dsi_wait(250000, _DSIREG(DSI_TRIGGER), DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO);
|
||||
|
||||
DSI(_DSIREG(DSI_WR_DATA)) = 0x406;
|
||||
DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST;
|
||||
_display_dsi_send_cmd(MIPI_DSI_DCS_READ, MIPI_DCS_GET_DISPLAY_ID, 0);
|
||||
_display_dsi_wait(250000, _DSIREG(DSI_TRIGGER), DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO);
|
||||
|
||||
DSI(_DSIREG(DSI_HOST_CONTROL)) = DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_IMM_BTA | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC;
|
||||
@@ -107,45 +135,81 @@ void display_init()
|
||||
|
||||
usleep(5000);
|
||||
|
||||
_display_ver = DSI(_DSIREG(DSI_RD_DATA));
|
||||
if (_display_ver == 0x10)
|
||||
exec_cfg((u32 *)DSI_BASE, _display_config_4, 43);
|
||||
// MIPI_DCS_GET_DISPLAY_ID reply is a long read, size 3 u32.
|
||||
for (u32 i = 0; i < 3; i++)
|
||||
_display_id = DSI(_DSIREG(DSI_RD_DATA)); // Skip ack and msg type info and get the payload (display id).
|
||||
|
||||
DSI(_DSIREG(DSI_WR_DATA)) = 0x1105;
|
||||
DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST;
|
||||
// Save raw Display ID to Nyx storage.
|
||||
nyx_str->info.disp_id = _display_id;
|
||||
|
||||
usleep(180000);
|
||||
// Decode Display ID.
|
||||
_display_id = ((_display_id >> 8) & 0xFF00) | (_display_id & 0xFF);
|
||||
|
||||
DSI(_DSIREG(DSI_WR_DATA)) = 0x2905;
|
||||
DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST;
|
||||
if ((_display_id & 0xFF) == PANEL_JDI_LPM062M)
|
||||
_display_id = PANEL_JDI_LPM062M;
|
||||
|
||||
usleep(20000);
|
||||
// Initialize display panel.
|
||||
switch (_display_id)
|
||||
{
|
||||
case PANEL_JDI_LPM062M:
|
||||
exec_cfg((u32 *)DSI_BASE, _display_init_config_jdi, 43);
|
||||
_display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, MIPI_DCS_EXIT_SLEEP_MODE, 180000);
|
||||
break;
|
||||
case PANEL_INL_P062CCA_AZ1:
|
||||
case PANEL_AUO_A062TAN01:
|
||||
_display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, MIPI_DCS_EXIT_SLEEP_MODE, 180000);
|
||||
DSI(_DSIREG(DSI_WR_DATA)) = 0x439; // MIPI_DSI_DCS_LONG_WRITE: 4 bytes.
|
||||
DSI(_DSIREG(DSI_WR_DATA)) = 0x9483FFB9; // Enable extension cmd. (Pass: FF 83 94).
|
||||
DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST;
|
||||
usleep(5000);
|
||||
DSI(_DSIREG(DSI_WR_DATA)) = 0x739; // MIPI_DSI_DCS_LONG_WRITE: 7 bytes.
|
||||
if (_display_id == PANEL_INL_P062CCA_AZ1)
|
||||
DSI(_DSIREG(DSI_WR_DATA)) = 0x751548B1; // Set Power control. (Not deep standby, BT5 / XDK, VRH gamma volt adj 53 / x40).
|
||||
else
|
||||
DSI(_DSIREG(DSI_WR_DATA)) = 0x711148B1; // Set Power control. (Not deep standby, BT1 / XDK, VRH gamma volt adj 49 / x40).
|
||||
DSI(_DSIREG(DSI_WR_DATA)) = 0x143209; // (NVRH gamma volt adj 9, Amplifier current small / x30, FS0 freq Fosc/80 / FS1 freq Fosc/32).
|
||||
DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST;
|
||||
usleep(5000);
|
||||
break;
|
||||
case PANEL_INL_P062CCA_AZ2:
|
||||
case PANEL_AUO_A062TAN02:
|
||||
default: // Allow spare part displays to work.
|
||||
_display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, MIPI_DCS_EXIT_SLEEP_MODE, 120000);
|
||||
break;
|
||||
}
|
||||
|
||||
exec_cfg((u32 *)CLOCK_BASE, _display_config_6, 3);
|
||||
exec_cfg((u32 *)DSI_BASE, _display_config_5, 21);
|
||||
DISPLAY_A(_DIREG(DC_DISP_DISP_CLOCK_CONTROL)) = 4;
|
||||
exec_cfg((u32 *)DSI_BASE, _display_config_7, 10);
|
||||
_display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, MIPI_DCS_SET_DISPLAY_ON, 20000);
|
||||
|
||||
// Configure PLLD for DISP1.
|
||||
plld_div = (1 << 20) | (24 << 11) | 1; // DIVM: 1, DIVN: 24, DIVP: 1. PLLD_OUT: 768 MHz, PLLD_OUT0 (DSI): 460.8 MHz.
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) = PLLCX_BASE_ENABLE | PLLCX_BASE_LOCK | plld_div;
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLD_MISC1) = 0x20;
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLD_MISC) = 0x2DFC00; // Use new PLLD_SDM_DIN.
|
||||
|
||||
// Finalize DSI configuration.
|
||||
exec_cfg((u32 *)DSI_BASE, _display_dsi_packet_config, 21);
|
||||
DISPLAY_A(_DIREG(DC_DISP_DISP_CLOCK_CONTROL)) = 4; // PCD1 | div3.
|
||||
exec_cfg((u32 *)DSI_BASE, _display_dsi_mode_config, 10);
|
||||
usleep(10000);
|
||||
|
||||
exec_cfg((u32 *)MIPI_CAL_BASE, _display_config_8, 6);
|
||||
exec_cfg((u32 *)DSI_BASE, _display_config_9, 4);
|
||||
exec_cfg((u32 *)MIPI_CAL_BASE, _display_config_10, 16);
|
||||
|
||||
// Calibrate display communication pads.
|
||||
exec_cfg((u32 *)MIPI_CAL_BASE, _display_mipi_pad_cal_config, 6);
|
||||
exec_cfg((u32 *)DSI_BASE, _display_dsi_pad_cal_config, 4);
|
||||
exec_cfg((u32 *)MIPI_CAL_BASE, _display_mipi_apply_dsi_cal_config, 16);
|
||||
usleep(10000);
|
||||
|
||||
exec_cfg((u32 *)DISPLAY_A_BASE, _display_config_11, 113);
|
||||
// Enable video display controller.
|
||||
exec_cfg((u32 *)DISPLAY_A_BASE, _display_video_disp_controller_enable_config, 113);
|
||||
}
|
||||
|
||||
void display_backlight_pwm_init()
|
||||
{
|
||||
clock_enable_pwm();
|
||||
|
||||
PWM(PWM_CONTROLLER_PWM_CSR) = (1 << 31); // Enable PWM
|
||||
PWM(PWM_CONTROLLER_PWM_CSR_0) = PWM_CSR_EN; // Enable PWM and set it to 25KHz PFM.
|
||||
|
||||
PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) >> 2) << 2 | 1; // PWM clock source.
|
||||
PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) & 0xFFFFFFFC) | 1; // PWM clock source.
|
||||
gpio_config(GPIO_PORT_V, GPIO_PIN_0, GPIO_MODE_SPIO); // Backlight power mode.
|
||||
|
||||
}
|
||||
|
||||
void display_backlight(bool enable)
|
||||
@@ -155,7 +219,7 @@ void display_backlight(bool enable)
|
||||
|
||||
void display_backlight_brightness(u32 brightness, u32 step_delay)
|
||||
{
|
||||
u32 old_value = (PWM(PWM_CONTROLLER_PWM_CSR) >> 16) & 0xFF;
|
||||
u32 old_value = (PWM(PWM_CONTROLLER_PWM_CSR_0) >> 16) & 0xFF;
|
||||
if (brightness == old_value)
|
||||
return;
|
||||
|
||||
@@ -166,7 +230,7 @@ void display_backlight_brightness(u32 brightness, u32 step_delay)
|
||||
{
|
||||
for (u32 i = old_value; i < brightness + 1; i++)
|
||||
{
|
||||
PWM(PWM_CONTROLLER_PWM_CSR) = (1 << 31) | (i << 16); // Enable PWM
|
||||
PWM(PWM_CONTROLLER_PWM_CSR_0) = PWM_CSR_EN | (i << 16); // Enable PWM and set it to 25KHz PFM.
|
||||
usleep(step_delay);
|
||||
}
|
||||
}
|
||||
@@ -174,62 +238,88 @@ void display_backlight_brightness(u32 brightness, u32 step_delay)
|
||||
{
|
||||
for (u32 i = old_value; i > brightness; i--)
|
||||
{
|
||||
PWM(PWM_CONTROLLER_PWM_CSR) = (1 << 31) | (i << 16); // Enable PWM
|
||||
PWM(PWM_CONTROLLER_PWM_CSR_0) = PWM_CSR_EN | (i << 16); // Enable PWM and set it to 25KHz PFM.
|
||||
usleep(step_delay);
|
||||
}
|
||||
}
|
||||
if (!brightness)
|
||||
PWM(PWM_CONTROLLER_PWM_CSR) = 0;
|
||||
PWM(PWM_CONTROLLER_PWM_CSR_0) = 0;
|
||||
}
|
||||
|
||||
void display_end()
|
||||
{
|
||||
display_backlight_brightness(0, 1000);
|
||||
|
||||
DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = 1;
|
||||
DSI(_DSIREG(DSI_WR_DATA)) = 0x2805;
|
||||
DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = DSI_CMD_PKT_VID_ENABLE;
|
||||
DSI(_DSIREG(DSI_WR_DATA)) = 0x2805; // MIPI_DCS_SET_DISPLAY_OFF
|
||||
|
||||
DISPLAY_A(_DIREG(DC_CMD_STATE_ACCESS)) = READ_MUX | WRITE_MUX;
|
||||
DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = 0;
|
||||
|
||||
exec_cfg((u32 *)DISPLAY_A_BASE, _display_config_12, 17);
|
||||
exec_cfg((u32 *)DSI_BASE, _display_config_13, 16);
|
||||
DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = 0; // Disable host cmd packet.
|
||||
|
||||
// De-initialize video controller.
|
||||
exec_cfg((u32 *)DISPLAY_A_BASE, _display_video_disp_controller_disable_config, 17);
|
||||
exec_cfg((u32 *)DSI_BASE, _display_dsi_timing_deinit_config, 16);
|
||||
usleep(10000);
|
||||
|
||||
if (_display_ver == 0x10)
|
||||
exec_cfg((u32 *)DSI_BASE, _display_config_14, 22);
|
||||
// De-initialize display panel.
|
||||
switch (_display_id)
|
||||
{
|
||||
case PANEL_JDI_LPM062M:
|
||||
exec_cfg((u32 *)DSI_BASE, _display_deinit_config_jdi, 22);
|
||||
break;
|
||||
case PANEL_AUO_A062TAN01:
|
||||
exec_cfg((u32 *)DSI_BASE, _display_deinit_config_auo, 37);
|
||||
break;
|
||||
case PANEL_INL_P062CCA_AZ2:
|
||||
case PANEL_AUO_A062TAN02:
|
||||
DSI(_DSIREG(DSI_WR_DATA)) = 0x439; // MIPI_DSI_DCS_LONG_WRITE: 4 bytes.
|
||||
DSI(_DSIREG(DSI_WR_DATA)) = 0x9483FFB9; // Enable extension cmd. (Pass: FF 83 94).
|
||||
DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST;
|
||||
usleep(5000);
|
||||
// Set Power.
|
||||
DSI(_DSIREG(DSI_WR_DATA)) = 0xB39; // MIPI_DSI_DCS_LONG_WRITE: 11 bytes.
|
||||
if (_display_id == PANEL_INL_P062CCA_AZ2)
|
||||
DSI(_DSIREG(DSI_WR_DATA)) = 0x751548B1; // Set Power control. (Not deep standby, BT5 / XDK, VRH gamma volt adj 53 / x40).
|
||||
else
|
||||
DSI(_DSIREG(DSI_WR_DATA)) = 0x711148B1; // Set Power control. (Not deep standby, BT1 / XDK, VRH gamma volt adj 49 / x40).
|
||||
// Set Power control. (NVRH gamma volt adj 9, Amplifier current small / x30, FS0 freq Fosc/80 / FS1 freq Fosc/32, Enter standby / PON / VCOMG).
|
||||
DSI(_DSIREG(DSI_WR_DATA)) = 0x71143209;
|
||||
DSI(_DSIREG(DSI_WR_DATA)) = 0x114D31; // Set Power control. (Unknown).
|
||||
DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST;
|
||||
usleep(5000);
|
||||
break;
|
||||
case PANEL_INL_P062CCA_AZ1:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
DSI(_DSIREG(DSI_WR_DATA)) = 0x1005;
|
||||
DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST;
|
||||
|
||||
usleep(50000);
|
||||
_display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, MIPI_DCS_ENTER_SLEEP_MODE, 50000);
|
||||
|
||||
// Disable display and backlight pins.
|
||||
gpio_write(GPIO_PORT_V, GPIO_PIN_2, GPIO_LOW); //Backlight Reset disable.
|
||||
|
||||
usleep(10000);
|
||||
|
||||
gpio_write(GPIO_PORT_I, GPIO_PIN_1, GPIO_LOW); //Backlight -5V disable.
|
||||
|
||||
usleep(10000);
|
||||
|
||||
gpio_write(GPIO_PORT_I, GPIO_PIN_0, GPIO_LOW); //Backlight +5V disable.
|
||||
|
||||
usleep(10000);
|
||||
|
||||
// Disable clocks.
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_SET) = 0x1010000;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_CLR) = 0x1010000;
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = 0x18000000;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = 0x18000000;
|
||||
// Disable Display Interface specific clocks.
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_SET) = 0x1010000; // Set reset clock DSI, MIPI_CAL.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_CLR) = 0x1010000; // Clear enable clock DSI, MIPI_CAL.
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = 0x18000000; // Set reset DISP1, HOST1X.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = 0x18000000; // Clear enable DISP1, HOST1X.
|
||||
|
||||
// Power down pads.
|
||||
DSI(_DSIREG(DSI_PAD_CONTROL_0)) = DSI_PAD_CONTROL_VS1_PULLDN_CLK | DSI_PAD_CONTROL_VS1_PULLDN(0xF) | DSI_PAD_CONTROL_VS1_PDIO_CLK | DSI_PAD_CONTROL_VS1_PDIO(0xF);
|
||||
DSI(_DSIREG(DSI_POWER_CONTROL)) = 0;
|
||||
|
||||
// Switch to automatic function mode.
|
||||
gpio_config(GPIO_PORT_V, GPIO_PIN_0, GPIO_MODE_SPIO); // Backlight PWM.
|
||||
|
||||
PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) & ~PINMUX_TRISTATE) | PINMUX_TRISTATE;
|
||||
PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) >> 2) << 2 | 1;
|
||||
PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) & 0xFFFFFFFC)| 1;
|
||||
}
|
||||
|
||||
void display_color_screen(u32 color)
|
||||
@@ -242,7 +332,6 @@ void display_color_screen(u32 color)
|
||||
DISPLAY_A(_DIREG(DC_WIN_CD_WIN_OPTIONS)) = 0;
|
||||
DISPLAY_A(_DIREG(DC_DISP_BLEND_BACKGROUND_COLOR)) = color;
|
||||
DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = (DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) & 0xFFFFFFFE) | GENERAL_ACT_REQ;
|
||||
|
||||
usleep(35000);
|
||||
|
||||
display_backlight(true);
|
||||
@@ -251,11 +340,12 @@ void display_color_screen(u32 color)
|
||||
u32 *display_init_framebuffer()
|
||||
{
|
||||
// Sanitize framebuffer area.
|
||||
memset((u32 *)0xC0000000, 0, 0x3C0000);
|
||||
// This configures the framebuffer @ 0xC0000000 with a resolution of 1280x720 (line stride 768).
|
||||
exec_cfg((u32 *)DISPLAY_A_BASE, cfg_display_framebuffer, 32);
|
||||
memset((u32 *)IPL_FB_ADDRESS, 0, 0x3C0000);
|
||||
|
||||
// This configures the framebuffer @ IPL_FB_ADDRESS with a resolution of 1280x720 (line stride 720).
|
||||
exec_cfg((u32 *)DISPLAY_A_BASE, cfg_display_framebuffer, 32);
|
||||
usleep(35000);
|
||||
|
||||
return (u32 *)0xC0000000;
|
||||
return (u32 *)IPL_FB_ADDRESS;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (C) 2018 CTCaer
|
||||
* Copyright (c) 2018-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,
|
||||
@@ -18,11 +18,27 @@
|
||||
#ifndef _DI_H_
|
||||
#define _DI_H_
|
||||
|
||||
#include "../../common/memory_map.h"
|
||||
#include "../utils/types.h"
|
||||
|
||||
/*! Display registers. */
|
||||
#define _DIREG(reg) ((reg) * 4)
|
||||
|
||||
// Display controller scratch registers.
|
||||
#define DC_D_WINBUF_DD_SCRATCH_REGISTER_0 0xED
|
||||
#define DC_D_WINBUF_DD_SCRATCH_REGISTER_1 0xEE
|
||||
#define DC_T_WINBUF_TD_SCRATCH_REGISTER_0 0x16D
|
||||
#define DC_T_WINBUF_TD_SCRATCH_REGISTER_1 0x16E
|
||||
#define DC_COM_SCRATCH_REGISTER_A 0x325
|
||||
#define DC_COM_SCRATCH_REGISTER_B 0x326
|
||||
#define DC_A_WINBUF_AD_SCRATCH_REGISTER_0 0xBED
|
||||
#define DC_A_WINBUF_AD_SCRATCH_REGISTER_1 0xBEE
|
||||
#define DC_B_WINBUF_BD_SCRATCH_REGISTER_0 0xDED
|
||||
#define DC_B_WINBUF_BD_SCRATCH_REGISTER_1 0xDEE
|
||||
#define DC_C_WINBUF_CD_SCRATCH_REGISTER_0 0xFED
|
||||
#define DC_C_WINBUF_CD_SCRATCH_REGISTER_1 0xFEE
|
||||
|
||||
// DC_CMD non-shadowed command/sync registers.
|
||||
#define DC_CMD_GENERAL_INCR_SYNCPT 0x00
|
||||
|
||||
#define DC_CMD_GENERAL_INCR_SYNCPT_CNTRL 0x01
|
||||
@@ -49,6 +65,7 @@
|
||||
#define PM0_ENABLE (1 << 16)
|
||||
#define PM1_ENABLE (1 << 18)
|
||||
|
||||
#define DC_CMD_INT_STATUS 0x37
|
||||
#define DC_CMD_INT_MASK 0x38
|
||||
#define DC_CMD_INT_ENABLE 0x39
|
||||
|
||||
@@ -61,11 +78,13 @@
|
||||
#define WIN_A_ACT_REQ (1 << 1)
|
||||
#define WIN_B_ACT_REQ (1 << 2)
|
||||
#define WIN_C_ACT_REQ (1 << 3)
|
||||
#define WIN_D_ACT_REQ (1 << 4)
|
||||
#define CURSOR_ACT_REQ (1 << 7)
|
||||
#define GENERAL_UPDATE (1 << 8)
|
||||
#define WIN_A_UPDATE (1 << 9)
|
||||
#define WIN_B_UPDATE (1 << 10)
|
||||
#define WIN_C_UPDATE (1 << 11)
|
||||
#define WIN_D_UPDATE (1 << 12)
|
||||
#define CURSOR_UPDATE (1 << 15)
|
||||
#define NC_HOST_TRIG (1 << 24)
|
||||
|
||||
@@ -73,15 +92,38 @@
|
||||
#define WINDOW_A_SELECT (1 << 4)
|
||||
#define WINDOW_B_SELECT (1 << 5)
|
||||
#define WINDOW_C_SELECT (1 << 6)
|
||||
#define WINDOW_D_SELECT (1 << 7)
|
||||
|
||||
#define DC_CMD_REG_ACT_CONTROL 0x043
|
||||
|
||||
// DC_D_WIN_DD window D instance of DC_WIN
|
||||
#define DC_D_WIN_DD_WIN_OPTIONS 0x80
|
||||
#define DC_D_WIN_DD_COLOR_DEPTH 0x83
|
||||
#define DC_D_WIN_DD_POSITION 0x84
|
||||
#define DC_D_WIN_DD_SIZE 0x85
|
||||
#define DC_D_WIN_DD_LINE_STRIDE 0x8A
|
||||
#define DC_D_WIN_DD_BLEND_LAYER_CONTROL 0x96
|
||||
#define DC_D_WIN_DD_BLEND_MATCH_SELECT 0x97
|
||||
#define DC_D_WIN_DD_BLEND_ALPHA_1BIT 0x99
|
||||
|
||||
// DC_D_WINBUF_DD window D instance of DC_WINBUF
|
||||
#define DC_D_WINBUF_DD_START_ADDR 0xC0
|
||||
#define DC_D_WINBUF_DD_ADDR_H_OFFSET 0xC6
|
||||
#define DC_D_WINBUF_DD_ADDR_V_OFFSET 0xC8
|
||||
#define DC_D_WINBUF_DD_START_ADDR_HI 0xCD
|
||||
#define DC_D_WINBUF_DD_MEMFETCH_CONTROL 0xEB
|
||||
|
||||
// DC_T_WIN_TD macro for using DD defines.
|
||||
#define _DC_T(reg) ((reg) + 0x80)
|
||||
|
||||
// DC_COM non-shadowed registers.
|
||||
#define DC_COM_CRC_CONTROL 0x300
|
||||
#define DC_COM_PIN_OUTPUT_ENABLE(x) (0x302 + (x))
|
||||
#define DC_COM_PIN_OUTPUT_POLARITY(x) (0x306 + (x))
|
||||
|
||||
#define DC_COM_DSC_TOP_CTL 0x33E
|
||||
|
||||
// DC_DISP shadowed registers.
|
||||
#define DC_DISP_DISP_WIN_OPTIONS 0x402
|
||||
#define HDMI_ENABLE (1 << 30)
|
||||
#define DSI_ENABLE (1 << 29)
|
||||
@@ -160,6 +202,32 @@
|
||||
#define DE_CONTROL_EARLY (3 << 2)
|
||||
#define DE_CONTROL_ACTIVE_BLANK (4 << 2)
|
||||
|
||||
// Cursor configuration registers.
|
||||
#define DC_DISP_CURSOR_FOREGROUND 0x43C
|
||||
#define DC_DISP_CURSOR_BACKGROUND 0x43D
|
||||
#define CURSOR_COLOR(r,g,b) (((r) & 0xFF) | (((g) & 0xFF) << 8) | (((b) & 0xFF) << 16))
|
||||
|
||||
#define DC_DISP_CURSOR_START_ADDR 0x43E
|
||||
#define CURSOR_CLIPPING(w) ((w) << 28)
|
||||
#define CURSOR_CLIP_WIN_A 1
|
||||
#define CURSOR_CLIP_WIN_B 2
|
||||
#define CURSOR_CLIP_WIN_C 3
|
||||
#define CURSOR_SIZE_32 (0 << 24)
|
||||
#define CURSOR_SIZE_64 (1 << 24)
|
||||
#define CURSOR_SIZE_128 (2 << 24)
|
||||
#define CURSOR_SIZE_256 (3 << 24)
|
||||
#define DC_DISP_CURSOR_POSITION 0x440
|
||||
#define DC_DISP_CURSOR_START_ADDR_HI 0x4EC
|
||||
#define DC_DISP_BLEND_CURSOR_CONTROL 0x4F1
|
||||
#define CURSOR_BLEND_2BIT (0 << 24)
|
||||
#define CURSOR_BLEND_R8G8B8A8 (1 << 24)
|
||||
#define CURSOR_BLEND_SRC_FACTOR(n) ((n) << 8)
|
||||
#define CURSOR_BLEND_DST_FACTOR(n) ((n) << 16)
|
||||
#define CURSOR_BLEND_ZRO 0
|
||||
#define CURSOR_BLEND_K1 1
|
||||
#define CURSOR_BLEND_NK1 2
|
||||
// End of cursor cfg regs.
|
||||
|
||||
#define DC_DISP_DC_MCCIF_FIFOCTRL 0x480
|
||||
#define DC_DISP_SD_BL_PARAMETERS 0x4D7
|
||||
#define DC_DISP_SD_BL_CONTROL 0x4DC
|
||||
@@ -186,6 +254,13 @@
|
||||
#define CSC_ENABLE (1 << 18)
|
||||
#define WIN_ENABLE (1 << 30)
|
||||
|
||||
#define DC_WIN_BUFFER_CONTROL 0x702
|
||||
#define BUFFER_CONTROL_HOST 0
|
||||
#define BUFFER_CONTROL_VI 1
|
||||
#define BUFFER_CONTROL_EPP 2
|
||||
#define BUFFER_CONTROL_MPEGE 3
|
||||
#define BUFFER_CONTROL_SB2D 4
|
||||
|
||||
#define DC_WIN_COLOR_DEPTH 0x703
|
||||
#define WIN_COLOR_DEPTH_P1 0x0
|
||||
#define WIN_COLOR_DEPTH_P2 0x1
|
||||
@@ -210,8 +285,9 @@
|
||||
#define WIN_COLOR_DEPTH_YCbCr422RA 0x18
|
||||
#define WIN_COLOR_DEPTH_YUV422RA 0x19
|
||||
|
||||
#define DC_WIN_BUFFER_CONTROL 0x702
|
||||
#define DC_WIN_POSITION 0x704
|
||||
#define H_POSITION(x) (((x) & 0xFfff) << 0)
|
||||
#define V_POSITION(x) (((x) & 0x1fff) << 16)
|
||||
|
||||
#define DC_WIN_SIZE 0x705
|
||||
#define H_SIZE(x) (((x) & 0x1fff) << 0)
|
||||
@@ -233,11 +309,51 @@
|
||||
#define UV_LINE_STRIDE(x) (((x) & 0xffff) << 16)
|
||||
#define DC_WIN_DV_CONTROL 0x70E
|
||||
|
||||
// The following registers are A/B/C shadows of the 0xBC0/0xDC0/0xFC0 registers (see DISPLAY_WINDOW_HEADER).
|
||||
#define DC_WINBUF_BLEND_LAYER_CONTROL 0x716
|
||||
#define WIN_K1(x) (((x) & 0xff) << 8)
|
||||
#define WIN_K2(x) (((x) & 0xff) << 16)
|
||||
#define WIN_BLEND_ENABLE (0 << 24)
|
||||
#define WIN_BLEND_BYPASS (1 << 24)
|
||||
|
||||
#define DC_WINBUF_BLEND_MATCH_SELECT 0x717
|
||||
#define WIN_BLEND_FACT_SRC_COLOR_MATCH_SEL_ZERO (0 << 0)
|
||||
#define WIN_BLEND_FACT_SRC_COLOR_MATCH_SEL_ONE (1 << 0)
|
||||
#define WIN_BLEND_FACT_SRC_COLOR_MATCH_SEL_K1 (2 << 0)
|
||||
#define WIN_BLEND_FACT_SRC_COLOR_MATCH_SEL_K1_TIMES_DST (3 << 0)
|
||||
#define WIN_BLEND_FACT_SRC_COLOR_MATCH_SEL_NEG_K1_TIMES_DST (4 << 0)
|
||||
#define WIN_BLEND_FACT_SRC_COLOR_MATCH_SEL_K1_TIMES_SRC (5 << 0)
|
||||
|
||||
#define WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_ZERO (0 << 4)
|
||||
#define WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_ONE (1 << 4)
|
||||
#define WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_K1 (2 << 4)
|
||||
#define WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_K2 (3 << 4)
|
||||
#define WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_K1_TIMES_DST (4 << 4)
|
||||
#define WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_NEG_K1_TIMES_DST (5 << 4)
|
||||
#define WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_NEG_K1_TIMES_SRC (6 << 4)
|
||||
#define WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_NEG_K1 (7 << 4)
|
||||
|
||||
#define WIN_BLEND_FACT_SRC_ALPHA_MATCH_SEL_ZERO (0 << 8)
|
||||
#define WIN_BLEND_FACT_SRC_ALPHA_MATCH_SEL_K1 (1 << 8)
|
||||
#define WIN_BLEND_FACT_SRC_ALPHA_MATCH_SEL_K2 (2 << 8)
|
||||
|
||||
#define WIN_BLEND_FACT_DST_ALPHA_MATCH_SEL_ZERO (0 << 12)
|
||||
#define WIN_BLEND_FACT_DST_ALPHA_MATCH_SEL_ONE (1 << 12)
|
||||
#define WIN_BLEND_FACT_DST_ALPHA_MATCH_SEL_NEG_K1_TIMES_SRC (2 << 12)
|
||||
#define WIN_BLEND_FACT_DST_ALPHA_MATCH_SEL_K2 (3 << 12)
|
||||
|
||||
#define DC_WINBUF_BLEND_ALPHA_1BIT 0x719
|
||||
#define WIN_ALPHA_1BIT_WEIGHT0(x) (((x) & 0xff) << 0)
|
||||
#define WIN_ALPHA_1BIT_WEIGHT1(x) (((x) & 0xff) << 8)
|
||||
|
||||
/*! The following registers are A/B/C shadows of the 0xBC0/0xDC0/0xFC0 registers (see DISPLAY_WINDOW_HEADER). */
|
||||
#define DC_WINBUF_START_ADDR 0x800
|
||||
#define DC_WINBUF_ADDR_H_OFFSET 0x806
|
||||
#define DC_WINBUF_ADDR_V_OFFSET 0x808
|
||||
#define DC_WINBUF_SURFACE_KIND 0x80B
|
||||
#define PITCH (0 << 0)
|
||||
#define TILED (1 << 0)
|
||||
#define BLOCK (2 << 0)
|
||||
#define BLOCK_HEIGHT(x) (((x) & 0x7) << 4)
|
||||
|
||||
/*! Display serial interface registers. */
|
||||
#define _DSIREG(reg) ((reg) * 4)
|
||||
@@ -329,8 +445,9 @@
|
||||
#define DSI_PAD_CONTROL_VS1_PDIO_CLK (1 << 8)
|
||||
#define DSI_PAD_CONTROL_VS1_PDIO(x) (((x) & 0xf) << 0)
|
||||
|
||||
#define DSI_PAD_CONTROL_CD 0x4c
|
||||
#define DSI_PAD_CONTROL_CD 0x4C
|
||||
#define DSI_VIDEO_MODE_CONTROL 0x4E
|
||||
#define DSI_CMD_PKT_VID_ENABLE 1
|
||||
|
||||
#define DSI_PAD_CONTROL_1 0x4F
|
||||
#define DSI_PAD_CONTROL_2 0x50
|
||||
@@ -342,11 +459,59 @@
|
||||
#define DSI_PAD_PREEMP_PU(x) (((x) & 0x3) << 0)
|
||||
|
||||
#define DSI_PAD_CONTROL_4 0x52
|
||||
|
||||
#define DSI_INIT_SEQ_DATA_15 0x5F
|
||||
|
||||
/*! Display backlight related PWM registers. */
|
||||
#define PWM_CONTROLLER_PWM_CSR 0x00
|
||||
/*! MIPI registers. */
|
||||
#define MIPI_CAL_MIPI_CAL_CTRL (0x00 / 0x4)
|
||||
#define MIPI_CAL_CIL_MIPI_CAL_STATUS (0x08 / 0x4)
|
||||
#define MIPI_CAL_CILA_MIPI_CAL_CONFIG (0x14 / 0x4)
|
||||
#define MIPI_CAL_CILB_MIPI_CAL_CONFIG (0x18 / 0x4)
|
||||
#define MIPI_CAL_CILC_MIPI_CAL_CONFIG (0x1C / 0x4)
|
||||
#define MIPI_CAL_CILD_MIPI_CAL_CONFIG (0x20 / 0x4)
|
||||
#define MIPI_CAL_CILE_MIPI_CAL_CONFIG (0x24 / 0x4)
|
||||
#define MIPI_CAL_CILF_MIPI_CAL_CONFIG (0x28 / 0x4)
|
||||
#define MIPI_CAL_DSIA_MIPI_CAL_CONFIG (0x38 / 0x4)
|
||||
#define MIPI_CAL_DSIB_MIPI_CAL_CONFIG (0x3C / 0x4)
|
||||
#define MIPI_CAL_DSIC_MIPI_CAL_CONFIG (0x40 / 0x4)
|
||||
#define MIPI_CAL_DSID_MIPI_CAL_CONFIG (0x44 / 0x4)
|
||||
#define MIPI_CAL_MIPI_BIAS_PAD_CFG0 (0x58 / 0x4)
|
||||
#define MIPI_CAL_MIPI_BIAS_PAD_CFG1 (0x5C / 0x4)
|
||||
#define MIPI_CAL_MIPI_BIAS_PAD_CFG2 (0x60 / 0x4)
|
||||
#define MIPI_CAL_DSIA_MIPI_CAL_CONFIG_2 (0x64 / 0x4)
|
||||
#define MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2 (0x68 / 0x4)
|
||||
#define MIPI_CAL_DSIC_MIPI_CAL_CONFIG_2 (0x70 / 0x4)
|
||||
#define MIPI_CAL_DSID_MIPI_CAL_CONFIG_2 (0x74 / 0x4)
|
||||
|
||||
/*! MIPI CMDs. */
|
||||
#define MIPI_DSI_DCS_SHORT_WRITE 0x05
|
||||
#define MIPI_DSI_DCS_READ 0x06
|
||||
#define MIPI_DSI_DCS_SHORT_WRITE_PARAM 0x15
|
||||
#define MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE 0x37
|
||||
#define MIPI_DSI_DCS_LONG_WRITE 0x39
|
||||
|
||||
/*! MIPI DCS CMDs. */
|
||||
#define MIPI_DCS_GET_DISPLAY_ID 0x04
|
||||
#define MIPI_DCS_ENTER_SLEEP_MODE 0x10
|
||||
#define MIPI_DCS_EXIT_SLEEP_MODE 0x11
|
||||
#define MIPI_DCS_SET_DISPLAY_ON 0x29
|
||||
|
||||
/* Switch Panels:
|
||||
* [10] 81 [26]: JDI LPM062M326A
|
||||
* [10] 96 [09]: JDI LAM062M109A
|
||||
* [20] 93 [0F]: InnoLux P062CCA-AZ1 (Rev A1)
|
||||
* [20] XX [10]: InnoLux P062CCA-AZ2 [UNCONFIRMED ID]
|
||||
* [30] 94 [0F]: AUO A062TAN01 (59.06A33.001)
|
||||
* [30] XX [10]: AUO A062TAN02 (59.06A33.002) [UNCONFIRMED ID]
|
||||
*/
|
||||
|
||||
enum
|
||||
{
|
||||
PANEL_JDI_LPM062M = 0x10,
|
||||
PANEL_INL_P062CCA_AZ1 = 0x0F20,
|
||||
PANEL_AUO_A062TAN01 = 0x0F30,
|
||||
PANEL_INL_P062CCA_AZ2 = 0x1020,
|
||||
PANEL_AUO_A062TAN02 = 0x1030
|
||||
};
|
||||
|
||||
void display_init();
|
||||
void display_backlight_pwm_init();
|
||||
@@ -361,5 +526,8 @@ void display_backlight_brightness(u32 brightness, u32 step_delay);
|
||||
|
||||
/*! Init display in full 1280x720 resolution (B8G8R8A8, line stride 768, framebuffer size = 1280*768*4 bytes). */
|
||||
u32 *display_init_framebuffer();
|
||||
void display_init_cursor(void *crs_fb, u32 size);
|
||||
void display_set_pos_cursor(u32 x, u32 y);
|
||||
void display_deinit_cursor();
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (C) 2018 CTCaer
|
||||
* Copyright (c) 2018-2019 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -15,16 +15,8 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
//Clock config.
|
||||
static const cfg_op_t _display_config_1[4] = {
|
||||
{0x4E, 0x40000000}, //CLK_RST_CONTROLLER_CLK_SOURCE_DISP1
|
||||
{0x34, 0x4830A001}, //CLK_RST_CONTROLLER_PLLD_BASE
|
||||
{0x36, 0x20}, //CLK_RST_CONTROLLER_PLLD_MISC1
|
||||
{0x37, 0x2D0AAA} //CLK_RST_CONTROLLER_PLLD_MISC
|
||||
};
|
||||
|
||||
//Display A config.
|
||||
static const cfg_op_t _display_config_2[94] = {
|
||||
static const cfg_op_t _display_dc_setup_win_config[94] = {
|
||||
{DC_CMD_STATE_ACCESS, 0},
|
||||
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
|
||||
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
|
||||
@@ -122,13 +114,13 @@ static const cfg_op_t _display_config_2[94] = {
|
||||
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{DC_WIN_WIN_OPTIONS, 0},
|
||||
{DC_DISP_DISP_WIN_OPTIONS, 0},
|
||||
{DC_CMD_DISPLAY_COMMAND, 0},
|
||||
{DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_STOP},
|
||||
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE},
|
||||
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ}
|
||||
};
|
||||
|
||||
//DSI Init config.
|
||||
static const cfg_op_t _display_config_3[61] = {
|
||||
static const cfg_op_t _display_dsi_init_config[61] = {
|
||||
{DSI_WR_DATA, 0},
|
||||
{DSI_INT_ENABLE, 0},
|
||||
{DSI_INT_STATUS, 0},
|
||||
@@ -192,14 +184,14 @@ static const cfg_op_t _display_config_3[61] = {
|
||||
{DSI_INIT_SEQ_CONTROL, 0}
|
||||
};
|
||||
|
||||
//DSI config (if ver == 0x10).
|
||||
static const cfg_op_t _display_config_4[43] = {
|
||||
{DSI_WR_DATA, 0x439},
|
||||
{DSI_WR_DATA, 0x9483FFB9},
|
||||
//DSI panel config.
|
||||
static const cfg_op_t _display_init_config_jdi[43] = {
|
||||
{DSI_WR_DATA, 0x439}, // MIPI_DSI_DCS_LONG_WRITE: 4 bytes.
|
||||
{DSI_WR_DATA, 0x9483FFB9}, // Enable extension cmd. (Pass: FF 83 94).
|
||||
{DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{DSI_WR_DATA, 0xBD15},
|
||||
{DSI_WR_DATA, 0x00BD15}, // MIPI_DSI_DCS_SHORT_WRITE_PARAM: 0x0BD.
|
||||
{DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{DSI_WR_DATA, 0x1939},
|
||||
{DSI_WR_DATA, 0x1939}, // MIPI_DSI_DCS_LONG_WRITE: 25 bytes.
|
||||
{DSI_WR_DATA, 0xAAAAAAD8},
|
||||
{DSI_WR_DATA, 0xAAAAAAEB},
|
||||
{DSI_WR_DATA, 0xAAEBAAAA},
|
||||
@@ -208,9 +200,9 @@ static const cfg_op_t _display_config_4[43] = {
|
||||
{DSI_WR_DATA, 0xAAEBAAAA},
|
||||
{DSI_WR_DATA, 0xAA},
|
||||
{DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{DSI_WR_DATA, 0x1BD15},
|
||||
{DSI_WR_DATA, 0x01BD15}, // MIPI_DSI_DCS_SHORT_WRITE_PARAM: 0x1BD.
|
||||
{DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{DSI_WR_DATA, 0x2739},
|
||||
{DSI_WR_DATA, 0x2739}, // MIPI_DSI_DCS_LONG_WRITE: 39 bytes.
|
||||
{DSI_WR_DATA, 0xFFFFFFD8},
|
||||
{DSI_WR_DATA, 0xFFFFFFFF},
|
||||
{DSI_WR_DATA, 0xFFFFFFFF},
|
||||
@@ -222,25 +214,25 @@ static const cfg_op_t _display_config_4[43] = {
|
||||
{DSI_WR_DATA, 0xFFFFFFFF},
|
||||
{DSI_WR_DATA, 0xFFFFFF},
|
||||
{DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{DSI_WR_DATA, 0x2BD15},
|
||||
{DSI_WR_DATA, 0x02BD15}, // MIPI_DSI_DCS_SHORT_WRITE_PARAM: 0x2BD.
|
||||
{DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{DSI_WR_DATA, 0xF39},
|
||||
{DSI_WR_DATA, 0xF39}, // MIPI_DSI_DCS_LONG_WRITE: 15 bytes.
|
||||
{DSI_WR_DATA, 0xFFFFFFD8},
|
||||
{DSI_WR_DATA, 0xFFFFFFFF},
|
||||
{DSI_WR_DATA, 0xFFFFFFFF},
|
||||
{DSI_WR_DATA, 0xFFFFFF},
|
||||
{DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{DSI_WR_DATA, 0xBD15},
|
||||
{DSI_WR_DATA, 0x00BD15}, // MIPI_DSI_DCS_SHORT_WRITE_PARAM: 0x0BD.
|
||||
{DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{DSI_WR_DATA, 0x6D915},
|
||||
{DSI_WR_DATA, 0x06D915}, // MIPI_DSI_DCS_SHORT_WRITE_PARAM: 0x6D9.
|
||||
{DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{DSI_WR_DATA, 0x439},
|
||||
{DSI_WR_DATA, 0xB9},
|
||||
{DSI_WR_DATA, 0x439}, // MIPI_DSI_DCS_LONG_WRITE: 4 bytes.
|
||||
{DSI_WR_DATA, 0x000000B9}, // Disable extension cmd.
|
||||
{DSI_TRIGGER, DSI_TRIGGER_HOST}
|
||||
};
|
||||
|
||||
//DSI config.
|
||||
static const cfg_op_t _display_config_5[21] = {
|
||||
//DSI packet config.
|
||||
static const cfg_op_t _display_dsi_packet_config[21] = {
|
||||
{DSI_PAD_CONTROL_1, 0},
|
||||
{DSI_PHY_TIMING_0, 0x6070601},
|
||||
{DSI_PHY_TIMING_1, 0x40A0E05},
|
||||
@@ -264,15 +256,8 @@ static const cfg_op_t _display_config_5[21] = {
|
||||
{DSI_HOST_CONTROL, 0},
|
||||
};
|
||||
|
||||
//Clock config.
|
||||
static const cfg_op_t _display_config_6[3] = {
|
||||
{0x34, 0x4810C001}, //CLK_RST_CONTROLLER_PLLD_BASE
|
||||
{0x36, 0x20}, //CLK_RST_CONTROLLER_PLLD_MISC1
|
||||
{0x37, 0x2DFC00} //CLK_RST_CONTROLLER_PLLD_MISC
|
||||
};
|
||||
|
||||
//DSI config.
|
||||
static const cfg_op_t _display_config_7[10] = {
|
||||
//DSI mode config.
|
||||
static const cfg_op_t _display_dsi_mode_config[10] = {
|
||||
{DSI_TRIGGER, 0},
|
||||
{DSI_CONTROL, 0},
|
||||
{DSI_SOL_DELAY, 6},
|
||||
@@ -286,17 +271,17 @@ static const cfg_op_t _display_config_7[10] = {
|
||||
};
|
||||
|
||||
//MIPI CAL config.
|
||||
static const cfg_op_t _display_config_8[6] = {
|
||||
{0x18, 0},
|
||||
{2, 0xF3F10000},
|
||||
{0x16, 0},
|
||||
{0x18, 0},
|
||||
{0x18, 0x10010},
|
||||
{0x17, 0x300}
|
||||
static const cfg_op_t _display_mipi_pad_cal_config[6] = {
|
||||
{MIPI_CAL_MIPI_BIAS_PAD_CFG2, 0},
|
||||
{MIPI_CAL_CIL_MIPI_CAL_STATUS, 0xF3F10000},
|
||||
{MIPI_CAL_MIPI_BIAS_PAD_CFG0, 0},
|
||||
{MIPI_CAL_MIPI_BIAS_PAD_CFG2, 0},
|
||||
{MIPI_CAL_MIPI_BIAS_PAD_CFG2, 0x10010},
|
||||
{MIPI_CAL_MIPI_BIAS_PAD_CFG1, 0x300}
|
||||
};
|
||||
|
||||
//DSI config.
|
||||
static const cfg_op_t _display_config_9[4] = {
|
||||
static const cfg_op_t _display_dsi_pad_cal_config[4] = {
|
||||
{DSI_PAD_CONTROL_1, 0},
|
||||
{DSI_PAD_CONTROL_2, 0},
|
||||
{DSI_PAD_CONTROL_3, DSI_PAD_PREEMP_PD_CLK(0x3) | DSI_PAD_PREEMP_PU_CLK(0x3) | DSI_PAD_PREEMP_PD(0x03) | DSI_PAD_PREEMP_PU(0x3)},
|
||||
@@ -304,27 +289,27 @@ static const cfg_op_t _display_config_9[4] = {
|
||||
};
|
||||
|
||||
//MIPI CAL config.
|
||||
static const cfg_op_t _display_config_10[16] = {
|
||||
{0xE, 0x200200},
|
||||
{0xF, 0x200200},
|
||||
{0x19, 0x200002},
|
||||
{0x1A, 0x200002},
|
||||
{5, 0},
|
||||
{6, 0},
|
||||
{7, 0},
|
||||
{8, 0},
|
||||
{9, 0},
|
||||
{0xA, 0},
|
||||
{0x10, 0},
|
||||
{0x11, 0},
|
||||
{0x1A, 0},
|
||||
{0x1C, 0},
|
||||
{0x1D, 0},
|
||||
{0, 0x2A000001}
|
||||
static const cfg_op_t _display_mipi_apply_dsi_cal_config[16] = {
|
||||
{MIPI_CAL_DSIA_MIPI_CAL_CONFIG, 0x200200},
|
||||
{MIPI_CAL_DSIB_MIPI_CAL_CONFIG, 0x200200},
|
||||
{MIPI_CAL_DSIA_MIPI_CAL_CONFIG_2, 0x200002},
|
||||
{MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2, 0x200002},
|
||||
{MIPI_CAL_CILA_MIPI_CAL_CONFIG, 0},
|
||||
{MIPI_CAL_CILB_MIPI_CAL_CONFIG, 0},
|
||||
{MIPI_CAL_CILC_MIPI_CAL_CONFIG, 0},
|
||||
{MIPI_CAL_CILD_MIPI_CAL_CONFIG, 0},
|
||||
{MIPI_CAL_CILE_MIPI_CAL_CONFIG, 0},
|
||||
{MIPI_CAL_CILF_MIPI_CAL_CONFIG, 0},
|
||||
{MIPI_CAL_DSIC_MIPI_CAL_CONFIG, 0},
|
||||
{MIPI_CAL_DSID_MIPI_CAL_CONFIG, 0},
|
||||
{MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2, 0},
|
||||
{MIPI_CAL_DSIC_MIPI_CAL_CONFIG_2, 0},
|
||||
{MIPI_CAL_DSID_MIPI_CAL_CONFIG_2, 0},
|
||||
{MIPI_CAL_MIPI_CAL_CTRL, 0x2A000001}
|
||||
};
|
||||
|
||||
//Display A config.
|
||||
static const cfg_op_t _display_config_11[113] = {
|
||||
static const cfg_op_t _display_video_disp_controller_enable_config[113] = {
|
||||
{DC_CMD_STATE_ACCESS, 0},
|
||||
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{DC_WIN_WIN_OPTIONS, 0},
|
||||
@@ -405,7 +390,7 @@ static const cfg_op_t _display_config_11[113] = {
|
||||
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{DC_WIN_WIN_OPTIONS, 0},
|
||||
{DC_DISP_DISP_WIN_OPTIONS, 0},
|
||||
{DC_CMD_DISPLAY_COMMAND, 0},
|
||||
{DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_STOP},
|
||||
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE},
|
||||
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ},
|
||||
{DC_CMD_STATE_ACCESS, 0},
|
||||
@@ -415,7 +400,7 @@ static const cfg_op_t _display_config_11[113] = {
|
||||
{DC_DISP_SYNC_WIDTH, 0x10048},
|
||||
{DC_DISP_BACK_PORCH, 0x90048},
|
||||
{DC_DISP_ACTIVE, 0x50002D0},
|
||||
{DC_DISP_FRONT_PORCH, 0xA0088}, // Sources say that this should be above the DC_DISP_ACTIVE cmd.
|
||||
{DC_DISP_FRONT_PORCH, 0xA0088}, // Sources say that this should be above the DC_DISP_ACTIVE cmd.
|
||||
/* End of Display timings */
|
||||
{DC_DISP_SHIFT_CLOCK_OPTIONS, SC1_H_QUALIFIER_NONE | SC0_H_QUALIFIER_NONE},
|
||||
{DC_COM_PIN_OUTPUT_ENABLE(1), 0},
|
||||
@@ -449,13 +434,13 @@ static const cfg_op_t _display_config_11[113] = {
|
||||
};
|
||||
|
||||
////Display A config.
|
||||
static const cfg_op_t _display_config_12[17] = {
|
||||
static const cfg_op_t _display_video_disp_controller_disable_config[17] = {
|
||||
{DC_DISP_FRONT_PORCH, 0xA0088},
|
||||
{DC_CMD_INT_MASK, 0},
|
||||
{DC_CMD_STATE_ACCESS, 0},
|
||||
{DC_CMD_INT_ENABLE, 0},
|
||||
{DC_CMD_CONT_SYNCPT_VSYNC, 0},
|
||||
{DC_CMD_DISPLAY_COMMAND, 0},
|
||||
{DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_STOP},
|
||||
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
|
||||
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
|
||||
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
|
||||
@@ -470,7 +455,7 @@ static const cfg_op_t _display_config_12[17] = {
|
||||
};
|
||||
|
||||
//DSI config.
|
||||
static const cfg_op_t _display_config_13[16] = {
|
||||
static const cfg_op_t _display_dsi_timing_deinit_config[16] = {
|
||||
{DSI_POWER_CONTROL, 0},
|
||||
{DSI_PAD_CONTROL_1, 0},
|
||||
{DSI_PHY_TIMING_0, 0x6070601},
|
||||
@@ -490,11 +475,11 @@ static const cfg_op_t _display_config_13[16] = {
|
||||
};
|
||||
|
||||
//DSI config (if ver == 0x10).
|
||||
static const cfg_op_t _display_config_14[22] = {
|
||||
{DSI_WR_DATA, 0x439},
|
||||
{DSI_WR_DATA, 0x9483FFB9},
|
||||
static const cfg_op_t _display_deinit_config_jdi[22] = {
|
||||
{DSI_WR_DATA, 0x439}, // MIPI_DSI_DCS_LONG_WRITE: 4 bytes.
|
||||
{DSI_WR_DATA, 0x9483FFB9}, // Enable extension cmd. (Pass: FF 83 94).
|
||||
{DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{DSI_WR_DATA, 0x2139},
|
||||
{DSI_WR_DATA, 0x2139}, // MIPI_DSI_DCS_LONG_WRITE: 33 bytes.
|
||||
{DSI_WR_DATA, 0x191919D5},
|
||||
{DSI_WR_DATA, 0x19191919},
|
||||
{DSI_WR_DATA, 0x19191919},
|
||||
@@ -505,60 +490,107 @@ static const cfg_op_t _display_config_14[22] = {
|
||||
{DSI_WR_DATA, 0x19191919},
|
||||
{DSI_WR_DATA, 0x19},
|
||||
{DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{DSI_WR_DATA, 0xB39},
|
||||
{DSI_WR_DATA, 0x4F0F41B1},
|
||||
{DSI_WR_DATA, 0xB39}, // MIPI_DSI_DCS_LONG_WRITE: 11 bytes.
|
||||
{DSI_WR_DATA, 0x4F0F41B1}, // Set Power control.
|
||||
{DSI_WR_DATA, 0xF179A433},
|
||||
{DSI_WR_DATA, 0x2D81},
|
||||
{DSI_WR_DATA, 0x002D81},
|
||||
{DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{DSI_WR_DATA, 0x439},
|
||||
{DSI_WR_DATA, 0xB9},
|
||||
{DSI_WR_DATA, 0x439}, // MIPI_DSI_DCS_LONG_WRITE: 4 bytes.
|
||||
{DSI_WR_DATA, 0x000000B9}, // Disable extension cmd.
|
||||
{DSI_TRIGGER, DSI_TRIGGER_HOST}
|
||||
};
|
||||
|
||||
static const cfg_op_t _display_deinit_config_auo[37] = {
|
||||
{DSI_WR_DATA, 0x439}, // MIPI_DSI_DCS_LONG_WRITE: 4 bytes.
|
||||
{DSI_WR_DATA, 0x9483FFB9}, // Enable extension cmd. (Pass: FF 83 94).
|
||||
{DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{DSI_WR_DATA, 0x2C39}, // MIPI_DSI_DCS_LONG_WRITE: 44 bytes.
|
||||
{DSI_WR_DATA, 0x191919D5},
|
||||
{DSI_WR_DATA, 0x19191919},
|
||||
{DSI_WR_DATA, 0x19191919},
|
||||
{DSI_WR_DATA, 0x19191919},
|
||||
{DSI_WR_DATA, 0x19191919},
|
||||
{DSI_WR_DATA, 0x19191919},
|
||||
{DSI_WR_DATA, 0x19191919},
|
||||
{DSI_WR_DATA, 0x19191919},
|
||||
{DSI_WR_DATA, 0x19191919},
|
||||
{DSI_WR_DATA, 0x19191919},
|
||||
{DSI_WR_DATA, 0x19191919},
|
||||
{DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{DSI_WR_DATA, 0x2C39}, // MIPI_DSI_DCS_LONG_WRITE: 44 bytes.
|
||||
{DSI_WR_DATA, 0x191919D6},
|
||||
{DSI_WR_DATA, 0x19191919},
|
||||
{DSI_WR_DATA, 0x19191919},
|
||||
{DSI_WR_DATA, 0x19191919},
|
||||
{DSI_WR_DATA, 0x19191919},
|
||||
{DSI_WR_DATA, 0x19191919},
|
||||
{DSI_WR_DATA, 0x19191919},
|
||||
{DSI_WR_DATA, 0x19191919},
|
||||
{DSI_WR_DATA, 0x19191919},
|
||||
{DSI_WR_DATA, 0x19191919},
|
||||
{DSI_WR_DATA, 0x19191919},
|
||||
{DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{DSI_WR_DATA, 0xB39}, // MIPI_DSI_DCS_LONG_WRITE: 11 bytes.
|
||||
{DSI_WR_DATA, 0x711148B1}, // Set Power control. (Not deep standby, BT1 / XDK, VRH gamma volt adj 49 / x40).
|
||||
// Set Power control. (NVRH gamma volt adj 9, Amplifier current small / x30, FS0 freq Fosc/80 / FS1 freq Fosc/32, Enter standby / PON / VCOMG).
|
||||
{DSI_WR_DATA, 0x71143209},
|
||||
{DSI_WR_DATA, 0x114D31}, // Set Power control. (Unknown).
|
||||
{DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{DSI_WR_DATA, 0x439}, // MIPI_DSI_DCS_LONG_WRITE: 4 bytes.
|
||||
{DSI_WR_DATA, 0x000000B9}, // Disable extension cmd.
|
||||
{DSI_TRIGGER, DSI_TRIGGER_HOST}
|
||||
};
|
||||
|
||||
static const cfg_op_t _display_init_config_invert[3] = {
|
||||
{DSI_WR_DATA, 0x239},
|
||||
{DSI_WR_DATA, 0x02C1}, // INV_EN.
|
||||
{DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
};
|
||||
|
||||
//Display A config.
|
||||
static const cfg_op_t cfg_display_one_color[8] = {
|
||||
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, //Enable window A.
|
||||
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{DC_WIN_WIN_OPTIONS, 0},
|
||||
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, //Enable window B.
|
||||
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{DC_WIN_WIN_OPTIONS, 0},
|
||||
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, //Enable window C.
|
||||
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{DC_WIN_WIN_OPTIONS, 0},
|
||||
{DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE
|
||||
{DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY} //DISPLAY_CTRL_MODE: continuous display.
|
||||
{DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE},
|
||||
{DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY} // Continuous display.
|
||||
};
|
||||
|
||||
//Display A config.
|
||||
static const cfg_op_t cfg_display_framebuffer[32] = {
|
||||
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, //Enable window C.
|
||||
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{DC_WIN_WIN_OPTIONS, 0},
|
||||
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, //Enable window B.
|
||||
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{DC_WIN_WIN_OPTIONS, 0},
|
||||
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, //Enable window A.
|
||||
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{DC_WIN_WIN_OPTIONS, 0},
|
||||
{DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE
|
||||
{DC_WIN_COLOR_DEPTH, WIN_COLOR_DEPTH_B8G8R8A8}, //T_A8R8G8B8 //NX Default: T_A8B8G8R8, WIN_COLOR_DEPTH_R8G8B8A8
|
||||
{DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE},
|
||||
{DC_WIN_COLOR_DEPTH, WIN_COLOR_DEPTH_B8G8R8A8}, //NX Default: T_A8B8G8R8, WIN_COLOR_DEPTH_R8G8B8A8
|
||||
{DC_WIN_WIN_OPTIONS, 0},
|
||||
{DC_WIN_WIN_OPTIONS, 0},
|
||||
{DC_WIN_POSITION, 0}, //(0,0)
|
||||
{DC_WIN_H_INITIAL_DDA, 0},
|
||||
{DC_WIN_V_INITIAL_DDA, 0},
|
||||
{DC_WIN_PRESCALED_SIZE, V_PRESCALED_SIZE(1280) | H_PRESCALED_SIZE(2880)}, //Pre-scaled size: 1280x2880 bytes.
|
||||
{DC_WIN_DDA_INC, V_DDA_INC(0x1000) | H_DDA_INC(0x1000)},
|
||||
{DC_WIN_SIZE, V_SIZE(1280) | H_SIZE(720)}, //Window size: 1280 vertical lines x 720 horizontal pixels.
|
||||
{DC_WIN_LINE_STRIDE, UV_LINE_STRIDE(720 * 2) | LINE_STRIDE(720 * 4)}, //768*2x768*4 (= 0x600 x 0xC00) bytes, see TRM for alignment requirements.
|
||||
{DC_WIN_BUFFER_CONTROL, 0},
|
||||
{DC_WINBUF_SURFACE_KIND, 0}, //Regular surface.
|
||||
{DC_WINBUF_START_ADDR, 0xC0000000}, //Framebuffer address.
|
||||
{DC_WIN_PRESCALED_SIZE, V_PRESCALED_SIZE(1280) | H_PRESCALED_SIZE(2880)},
|
||||
{DC_WIN_DDA_INC, V_DDA_INC(0x1000) | H_DDA_INC(0x1000)}, // 1.0x
|
||||
{DC_WIN_SIZE, V_SIZE(1280) | H_SIZE(720)},
|
||||
{DC_WIN_LINE_STRIDE, UV_LINE_STRIDE(720 * 2) | LINE_STRIDE(720 * 4)}, // 720*2x720*4 (= 0x600 x 0xC00) bytes, see TRM for alignment requirements.
|
||||
{DC_WIN_BUFFER_CONTROL, BUFFER_CONTROL_HOST},
|
||||
{DC_WINBUF_SURFACE_KIND, PITCH},
|
||||
{DC_WINBUF_START_ADDR, IPL_FB_ADDRESS}, // Framebuffer address.
|
||||
{DC_WINBUF_ADDR_H_OFFSET, 0},
|
||||
{DC_WINBUF_ADDR_V_OFFSET, 0},
|
||||
{DC_WIN_WIN_OPTIONS, 0},
|
||||
{DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE
|
||||
{DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE},
|
||||
{DC_WIN_WIN_OPTIONS, 0},
|
||||
{DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE
|
||||
{DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE},
|
||||
{DC_WIN_WIN_OPTIONS, 0},
|
||||
{DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE
|
||||
{DC_WIN_WIN_OPTIONS, WIN_ENABLE}, //Enable window AD.
|
||||
{DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY}, //DISPLAY_CTRL_MODE: continuous display.
|
||||
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE}, //General update; window A update.
|
||||
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ} //General activation request; window A activation request.
|
||||
{DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE},
|
||||
{DC_WIN_WIN_OPTIONS, WIN_ENABLE}, // Enable window AD.
|
||||
{DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY}, // Continuous display.
|
||||
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE},
|
||||
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ}
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (C) 2018 CTCaer
|
||||
* Copyright (c) 2018-2020 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -117,110 +117,111 @@ static const u8 _gfx_font[] = {
|
||||
0x00, 0x00, 0x00, 0x4C, 0x32, 0x00, 0x00, 0x00 // Char 126 (~)
|
||||
};
|
||||
|
||||
void gfx_init_ctxt(gfx_ctxt_t *ctxt, u32 *fb, u32 width, u32 height, u32 stride)
|
||||
void gfx_init_ctxt(u32 *fb, u32 width, u32 height, u32 stride)
|
||||
{
|
||||
ctxt->fb = fb;
|
||||
ctxt->width = width;
|
||||
ctxt->height = height;
|
||||
ctxt->stride = stride;
|
||||
gfx_ctxt.fb = fb;
|
||||
gfx_ctxt.width = width;
|
||||
gfx_ctxt.height = height;
|
||||
gfx_ctxt.stride = stride;
|
||||
}
|
||||
|
||||
void gfx_clear_grey(gfx_ctxt_t *ctxt, u8 color)
|
||||
void gfx_clear_grey(u8 color)
|
||||
{
|
||||
memset(ctxt->fb, color, 0x3C0000);
|
||||
memset(gfx_ctxt.fb, color, gfx_ctxt.width * gfx_ctxt.height * 4);
|
||||
}
|
||||
|
||||
void gfx_clear_color(gfx_ctxt_t *ctxt, u32 color)
|
||||
void gfx_clear_color(u32 color)
|
||||
{
|
||||
for (u32 i = 0; i < ctxt->height * ctxt->stride; i++)
|
||||
ctxt->fb[i] = color;
|
||||
for (u32 i = 0; i < gfx_ctxt.width * gfx_ctxt.height; i++)
|
||||
gfx_ctxt.fb[i] = color;
|
||||
}
|
||||
|
||||
void gfx_clear_partial_grey(gfx_ctxt_t *ctxt, u8 color, u32 pos_x, u32 height)
|
||||
void gfx_clear_partial_grey(u8 color, u32 pos_x, u32 height)
|
||||
{
|
||||
memset(ctxt->fb + pos_x * ctxt->stride, color, height * 4 * ctxt->stride);
|
||||
memset(gfx_ctxt.fb + pos_x * gfx_ctxt.stride, color, height * 4 * gfx_ctxt.stride);
|
||||
}
|
||||
|
||||
void gfx_con_init(gfx_con_t *con, gfx_ctxt_t *ctxt)
|
||||
void gfx_con_init()
|
||||
{
|
||||
con->gfx_ctxt = ctxt;
|
||||
con->fntsz = 16;
|
||||
con->x = 0;
|
||||
con->y = 0;
|
||||
con->savedx = 0;
|
||||
con->savedy = 0;
|
||||
con->fgcol = 0xFFCCCCCC;
|
||||
con->fillbg = 0;
|
||||
con->bgcol = 0xFF1B1B1B;
|
||||
con->mute = 0;
|
||||
gfx_con.gfx_ctxt = &gfx_ctxt;
|
||||
gfx_con.fntsz = 16;
|
||||
gfx_con.x = 0;
|
||||
gfx_con.y = 0;
|
||||
gfx_con.savedx = 0;
|
||||
gfx_con.savedy = 0;
|
||||
gfx_con.fgcol = 0xFFCCCCCC;
|
||||
gfx_con.fillbg = 1;
|
||||
gfx_con.bgcol = 0xFF1B1B1B;
|
||||
gfx_con.mute = 0;
|
||||
}
|
||||
|
||||
void gfx_con_setcol(gfx_con_t *con, u32 fgcol, int fillbg, u32 bgcol)
|
||||
void gfx_con_setcol(u32 fgcol, int fillbg, u32 bgcol)
|
||||
{
|
||||
con->fgcol = fgcol;
|
||||
con->fillbg = fillbg;
|
||||
con->bgcol = bgcol;
|
||||
gfx_con.fgcol = fgcol;
|
||||
gfx_con.fillbg = fillbg;
|
||||
gfx_con.bgcol = bgcol;
|
||||
}
|
||||
|
||||
void gfx_con_getpos(gfx_con_t *con, u32 *x, u32 *y)
|
||||
void gfx_con_getpos(u32 *x, u32 *y)
|
||||
{
|
||||
*x = con->x;
|
||||
*y = con->y;
|
||||
*x = gfx_con.x;
|
||||
*y = gfx_con.y;
|
||||
}
|
||||
|
||||
void gfx_con_setpos(gfx_con_t *con, u32 x, u32 y)
|
||||
void gfx_con_setpos(u32 x, u32 y)
|
||||
{
|
||||
con->x = x;
|
||||
con->y = y;
|
||||
gfx_con.x = x;
|
||||
gfx_con.y = y;
|
||||
}
|
||||
|
||||
void gfx_putc(gfx_con_t *con, char c)
|
||||
void gfx_putc(char c)
|
||||
{
|
||||
// Duplicate code for performance reasons.
|
||||
switch (con->fntsz)
|
||||
switch (gfx_con.fntsz)
|
||||
{
|
||||
case 16:
|
||||
if (c >= 32 && c <= 126)
|
||||
{
|
||||
u8 *cbuf = (u8 *)&_gfx_font[8 * (c - 32)];
|
||||
u32 *fb = con->gfx_ctxt->fb + con->x + con->y * con->gfx_ctxt->stride;
|
||||
u32 *fb = gfx_ctxt.fb + gfx_con.x + gfx_con.y * gfx_ctxt.stride;
|
||||
|
||||
for (u32 i = 0; i < 16; i+=2)
|
||||
for (u32 i = 0; i < 16; i += 2)
|
||||
{
|
||||
u8 v = *cbuf++;
|
||||
u8 v = *cbuf;
|
||||
for (u32 k = 0; k < 2; k++)
|
||||
{
|
||||
for (u32 j = 0; j < 8; j++)
|
||||
{
|
||||
if (v & 1)
|
||||
{
|
||||
*fb = con->fgcol;
|
||||
*fb = gfx_con.fgcol;
|
||||
fb++;
|
||||
*fb = con->fgcol;
|
||||
*fb = gfx_con.fgcol;
|
||||
}
|
||||
else if (con->fillbg)
|
||||
else if (gfx_con.fillbg)
|
||||
{
|
||||
*fb = con->bgcol;
|
||||
*fb = gfx_con.bgcol;
|
||||
fb++;
|
||||
*fb = con->bgcol;
|
||||
*fb = gfx_con.bgcol;
|
||||
}
|
||||
else
|
||||
fb++;
|
||||
v >>= 1;
|
||||
fb++;
|
||||
}
|
||||
fb += con->gfx_ctxt->stride - 16;
|
||||
fb += gfx_ctxt.stride - 16;
|
||||
v = *cbuf;
|
||||
}
|
||||
cbuf++;
|
||||
}
|
||||
con->x += 16;
|
||||
gfx_con.x += 16;
|
||||
}
|
||||
else if (c == '\n')
|
||||
{
|
||||
con->x = 0;
|
||||
con->y +=16;
|
||||
if (con->y > con->gfx_ctxt->height - 16)
|
||||
con->y = 0;
|
||||
gfx_con.x = 0;
|
||||
gfx_con.y += 16;
|
||||
if (gfx_con.y > gfx_ctxt.height - 16)
|
||||
gfx_con.y = 0;
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
@@ -228,45 +229,44 @@ void gfx_putc(gfx_con_t *con, char c)
|
||||
if (c >= 32 && c <= 126)
|
||||
{
|
||||
u8 *cbuf = (u8 *)&_gfx_font[8 * (c - 32)];
|
||||
u32 *fb = con->gfx_ctxt->fb + con->x + con->y * con->gfx_ctxt->stride;
|
||||
u32 *fb = gfx_ctxt.fb + gfx_con.x + gfx_con.y * gfx_ctxt.stride;
|
||||
for (u32 i = 0; i < 8; i++)
|
||||
{
|
||||
u8 v = *cbuf++;
|
||||
for (u32 j = 0; j < 8; j++)
|
||||
{
|
||||
if (v & 1)
|
||||
*fb = con->fgcol;
|
||||
else if (con->fillbg)
|
||||
*fb = con->bgcol;
|
||||
*fb = gfx_con.fgcol;
|
||||
else if (gfx_con.fillbg)
|
||||
*fb = gfx_con.bgcol;
|
||||
v >>= 1;
|
||||
fb++;
|
||||
}
|
||||
fb += con->gfx_ctxt->stride - 8;
|
||||
fb += gfx_ctxt.stride - 8;
|
||||
}
|
||||
con->x += 8;
|
||||
gfx_con.x += 8;
|
||||
}
|
||||
else if (c == '\n')
|
||||
{
|
||||
con->x = 0;
|
||||
con->y += 8;
|
||||
if (con->y > con->gfx_ctxt->height - 8)
|
||||
con->y = 0;
|
||||
gfx_con.x = 0;
|
||||
gfx_con.y += 8;
|
||||
if (gfx_con.y > gfx_ctxt.height - 8)
|
||||
gfx_con.y = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void gfx_puts(gfx_con_t *con, const char *s)
|
||||
void gfx_puts(char *s)
|
||||
{
|
||||
if (!s || con->mute)
|
||||
if (!s || gfx_con.mute)
|
||||
return;
|
||||
|
||||
for (; *s; s++)
|
||||
gfx_putc(con, *s);
|
||||
gfx_putc(*s);
|
||||
}
|
||||
|
||||
static void _gfx_putn(gfx_con_t *con, u32 v, int base, char fill, int fcnt)
|
||||
static void _gfx_putn(u32 v, int base, char fill, int fcnt)
|
||||
{
|
||||
char buf[65];
|
||||
static const char digits[] = "0123456789ABCDEFghijklmnopqrstuvwxyz";
|
||||
@@ -294,28 +294,28 @@ static void _gfx_putn(gfx_con_t *con, u32 v, int base, char fill, int fcnt)
|
||||
}
|
||||
}
|
||||
|
||||
gfx_puts(con, p);
|
||||
gfx_puts(p);
|
||||
}
|
||||
|
||||
void gfx_put_small_sep(gfx_con_t *con)
|
||||
void gfx_put_small_sep()
|
||||
{
|
||||
u8 prevFontSize = con->fntsz;
|
||||
con->fntsz = 8;
|
||||
gfx_putc(con, '\n');
|
||||
con->fntsz = prevFontSize;
|
||||
u8 prevFontSize = gfx_con.fntsz;
|
||||
gfx_con.fntsz = 8;
|
||||
gfx_putc('\n');
|
||||
gfx_con.fntsz = prevFontSize;
|
||||
}
|
||||
|
||||
void gfx_put_big_sep(gfx_con_t *con)
|
||||
void gfx_put_big_sep()
|
||||
{
|
||||
u8 prevFontSize = con->fntsz;
|
||||
con->fntsz = 16;
|
||||
gfx_putc(con, '\n');
|
||||
con->fntsz = prevFontSize;
|
||||
u8 prevFontSize = gfx_con.fntsz;
|
||||
gfx_con.fntsz = 16;
|
||||
gfx_putc('\n');
|
||||
gfx_con.fntsz = prevFontSize;
|
||||
}
|
||||
|
||||
void gfx_printf(gfx_con_t *con, const char *fmt, ...)
|
||||
void gfx_printf(const char *fmt, ...)
|
||||
{
|
||||
if (con->mute)
|
||||
if (gfx_con.mute)
|
||||
return;
|
||||
|
||||
va_list ap;
|
||||
@@ -348,40 +348,40 @@ void gfx_printf(gfx_con_t *con, const char *fmt, ...)
|
||||
switch(*fmt)
|
||||
{
|
||||
case 'c':
|
||||
gfx_putc(con, va_arg(ap, u32));
|
||||
gfx_putc(va_arg(ap, u32));
|
||||
break;
|
||||
case 's':
|
||||
gfx_puts(con, va_arg(ap, char *));
|
||||
gfx_puts(va_arg(ap, char *));
|
||||
break;
|
||||
case 'd':
|
||||
_gfx_putn(con, va_arg(ap, u32), 10, fill, fcnt);
|
||||
_gfx_putn(va_arg(ap, u32), 10, fill, fcnt);
|
||||
break;
|
||||
case 'p':
|
||||
case 'P':
|
||||
case 'x':
|
||||
case 'X':
|
||||
_gfx_putn(con, va_arg(ap, u32), 16, fill, fcnt);
|
||||
_gfx_putn(va_arg(ap, u32), 16, fill, fcnt);
|
||||
break;
|
||||
case 'k':
|
||||
con->fgcol = va_arg(ap, u32);
|
||||
gfx_con.fgcol = va_arg(ap, u32);
|
||||
break;
|
||||
case 'K':
|
||||
con->bgcol = va_arg(ap, u32);
|
||||
con->fillbg = 1;
|
||||
gfx_con.bgcol = va_arg(ap, u32);
|
||||
gfx_con.fillbg = 1;
|
||||
break;
|
||||
case '%':
|
||||
gfx_putc(con, '%');
|
||||
gfx_putc('%');
|
||||
break;
|
||||
case '\0':
|
||||
goto out;
|
||||
default:
|
||||
gfx_putc(con, '%');
|
||||
gfx_putc(con, *fmt);
|
||||
gfx_putc('%');
|
||||
gfx_putc(*fmt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
gfx_putc(con, *fmt);
|
||||
gfx_putc(*fmt);
|
||||
fmt++;
|
||||
}
|
||||
|
||||
@@ -389,33 +389,33 @@ void gfx_printf(gfx_con_t *con, const char *fmt, ...)
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void gfx_hexdump(gfx_con_t *con, u32 base, const u8 *buf, u32 len)
|
||||
void gfx_hexdump(u32 base, const u8 *buf, u32 len)
|
||||
{
|
||||
if (con->mute)
|
||||
if (gfx_con.mute)
|
||||
return;
|
||||
|
||||
u8 prevFontSize = con->fntsz;
|
||||
con->fntsz = 8;
|
||||
u8 prevFontSize = gfx_con.fntsz;
|
||||
gfx_con.fntsz = 8;
|
||||
for(u32 i = 0; i < len; i++)
|
||||
{
|
||||
if(i % 0x10 == 0)
|
||||
{
|
||||
if(i != 0)
|
||||
{
|
||||
gfx_puts(con, "| ");
|
||||
gfx_puts("| ");
|
||||
for(u32 j = 0; j < 0x10; j++)
|
||||
{
|
||||
u8 c = buf[i - 0x10 + j];
|
||||
if(c >= 32 && c <= 126)
|
||||
gfx_putc(con, c);
|
||||
gfx_putc(c);
|
||||
else
|
||||
gfx_putc(con, '.');
|
||||
gfx_putc('.');
|
||||
}
|
||||
gfx_putc(con, '\n');
|
||||
gfx_putc('\n');
|
||||
}
|
||||
gfx_printf(con, "%08x: ", base + i);
|
||||
gfx_printf("%08x: ", base + i);
|
||||
}
|
||||
gfx_printf(con, "%02x ", buf[i]);
|
||||
gfx_printf("%02x ", buf[i]);
|
||||
if (i == len - 1)
|
||||
{
|
||||
int ln = len % 0x10 != 0;
|
||||
@@ -424,22 +424,22 @@ void gfx_hexdump(gfx_con_t *con, u32 base, const u8 *buf, u32 len)
|
||||
{
|
||||
k = (len & 0xF) - 1;
|
||||
for (u32 j = 0; j < 0x10 - k; j++)
|
||||
gfx_puts(con, " ");
|
||||
gfx_puts(" ");
|
||||
}
|
||||
gfx_puts(con, "| ");
|
||||
gfx_puts("| ");
|
||||
for(u32 j = 0; j < (ln ? k : k + 1); j++)
|
||||
{
|
||||
u8 c = buf[i - k + j];
|
||||
if(c >= 32 && c <= 126)
|
||||
gfx_putc(con, c);
|
||||
gfx_putc(c);
|
||||
else
|
||||
gfx_putc(con, '.');
|
||||
gfx_putc('.');
|
||||
}
|
||||
gfx_putc(con, '\n');
|
||||
gfx_putc('\n');
|
||||
}
|
||||
}
|
||||
gfx_putc(con, '\n');
|
||||
con->fntsz = prevFontSize;
|
||||
gfx_putc('\n');
|
||||
gfx_con.fntsz = prevFontSize;
|
||||
}
|
||||
|
||||
static int abs(int x)
|
||||
@@ -449,12 +449,12 @@ static int abs(int x)
|
||||
return x;
|
||||
}
|
||||
|
||||
void gfx_set_pixel(gfx_ctxt_t *ctxt, u32 x, u32 y, u32 color)
|
||||
void gfx_set_pixel(u32 x, u32 y, u32 color)
|
||||
{
|
||||
ctxt->fb[x + y * ctxt->stride] = color;
|
||||
gfx_ctxt.fb[x + y * gfx_ctxt.stride] = color;
|
||||
}
|
||||
|
||||
void gfx_line(gfx_ctxt_t *ctxt, int x0, int y0, int x1, int y1, u32 color)
|
||||
void gfx_line(int x0, int y0, int x1, int y1, u32 color)
|
||||
{
|
||||
int dx = abs(x1 - x0), sx = x0 < x1 ? 1 : -1;
|
||||
int dy = abs(y1 - y0), sy = y0 < y1 ? 1 : -1;
|
||||
@@ -462,7 +462,7 @@ void gfx_line(gfx_ctxt_t *ctxt, int x0, int y0, int x1, int y1, u32 color)
|
||||
|
||||
while (1)
|
||||
{
|
||||
gfx_set_pixel(ctxt, x0, y0, color);
|
||||
gfx_set_pixel(x0, y0, color);
|
||||
if (x0 == x1 && y0 == y1)
|
||||
break;
|
||||
e2 = err;
|
||||
@@ -479,46 +479,46 @@ void gfx_line(gfx_ctxt_t *ctxt, int x0, int y0, int x1, int y1, u32 color)
|
||||
}
|
||||
}
|
||||
|
||||
void gfx_set_rect_grey(gfx_ctxt_t *ctxt, const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)
|
||||
void gfx_set_rect_grey(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)
|
||||
{
|
||||
u32 pos = 0;
|
||||
for (u32 y = pos_y; y < (pos_y + size_y); y++)
|
||||
{
|
||||
for (u32 x = pos_x; x < (pos_x + size_x); x++)
|
||||
{
|
||||
memset(&ctxt->fb[x + y*ctxt->stride], buf[pos], 4);
|
||||
memset(&gfx_ctxt.fb[x + y*gfx_ctxt.stride], buf[pos], 4);
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void gfx_set_rect_rgb(gfx_ctxt_t *ctxt, const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)
|
||||
void gfx_set_rect_rgb(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)
|
||||
{
|
||||
u32 pos = 0;
|
||||
for (u32 y = pos_y; y < (pos_y + size_y); y++)
|
||||
{
|
||||
for (u32 x = pos_x; x < (pos_x + size_x); x++)
|
||||
{
|
||||
ctxt->fb[x + y*ctxt->stride] = buf[pos + 2] | (buf[pos + 1] << 8) | (buf[pos] << 16);
|
||||
gfx_ctxt.fb[x + y * gfx_ctxt.stride] = buf[pos + 2] | (buf[pos + 1] << 8) | (buf[pos] << 16);
|
||||
pos+=3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gfx_set_rect_argb(gfx_ctxt_t *ctxt, const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)
|
||||
void gfx_set_rect_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)
|
||||
{
|
||||
u32 *ptr = (u32 *)buf;
|
||||
for (u32 y = pos_y; y < (pos_y + size_y); y++)
|
||||
for (u32 x = pos_x; x < (pos_x + size_x); x++)
|
||||
ctxt->fb[x + y * ctxt->stride] = *ptr++;
|
||||
gfx_ctxt.fb[x + y * gfx_ctxt.stride] = *ptr++;
|
||||
}
|
||||
|
||||
void gfx_render_bmp_argb(gfx_ctxt_t *ctxt, const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)
|
||||
void gfx_render_bmp_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)
|
||||
{
|
||||
for (u32 y = pos_y; y < (pos_y + size_y); y++)
|
||||
{
|
||||
for (u32 x = pos_x; x < (pos_x + size_x); x++)
|
||||
ctxt->fb[x + y * ctxt->stride] = buf[(size_y + pos_y - 1 - y ) * size_x + x - pos_x];
|
||||
gfx_ctxt.fb[x + y * gfx_ctxt.stride] = buf[(size_y + pos_y - 1 - y ) * size_x + x - pos_x];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (C) 2018 CTCaer
|
||||
* Copyright (C) 2018 M4xw
|
||||
* Copyright (c) 2018-2020 CTCaer
|
||||
* Copyright (c) 2018 M4xw
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -21,26 +21,35 @@
|
||||
|
||||
#include "../../common/common_gfx.h"
|
||||
|
||||
void gfx_init_ctxt(gfx_ctxt_t *ctxt, u32 *fb, u32 width, u32 height, u32 stride);
|
||||
void gfx_clear_grey(gfx_ctxt_t *ctxt, u8 color);
|
||||
void gfx_clear_partial_grey(gfx_ctxt_t *ctxt, u8 color, u32 pos_x, u32 height);
|
||||
void gfx_clear_color(gfx_ctxt_t *ctxt, u32 color);
|
||||
void gfx_con_init(gfx_con_t *con, gfx_ctxt_t *ctxt);
|
||||
void gfx_con_setcol(gfx_con_t *con, u32 fgcol, int fillbg, u32 bgcol);
|
||||
void gfx_con_getpos(gfx_con_t *con, u32 *x, u32 *y);
|
||||
void gfx_con_setpos(gfx_con_t *con, u32 x, u32 y);
|
||||
void gfx_putc(gfx_con_t *con, char c);
|
||||
void gfx_puts(gfx_con_t *con, const char *s);
|
||||
void gfx_printf(gfx_con_t *con, const char *fmt, ...);
|
||||
void gfx_hexdump(gfx_con_t *con, u32 base, const u8 *buf, u32 len);
|
||||
#define EPRINTF(text) gfx_printf("%k"text"%k\n", 0xFFFF0000, 0xFFCCCCCC)
|
||||
#define EPRINTFARGS(text, args...) gfx_printf("%k"text"%k\n", 0xFFFF0000, args, 0xFFCCCCCC)
|
||||
#define WPRINTF(text) gfx_printf("%k"text"%k\n", 0xFFFFDD00, 0xFFCCCCCC)
|
||||
#define WPRINTFARGS(text, args...) gfx_printf("%k"text"%k\n", 0xFFFFDD00, args, 0xFFCCCCCC)
|
||||
|
||||
void gfx_set_pixel(gfx_ctxt_t *ctxt, u32 x, u32 y, u32 color);
|
||||
void gfx_line(gfx_ctxt_t *ctxt, int x0, int y0, int x1, int y1, u32 color);
|
||||
void gfx_put_small_sep(gfx_con_t *con);
|
||||
void gfx_put_big_sep(gfx_con_t *con);
|
||||
void gfx_set_rect_grey(gfx_ctxt_t *ctxt, const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
|
||||
void gfx_set_rect_rgb(gfx_ctxt_t *ctxt, const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
|
||||
void gfx_set_rect_argb(gfx_ctxt_t *ctxt, const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
|
||||
void gfx_render_bmp_argb(gfx_ctxt_t *ctxt, const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
|
||||
void gfx_init_ctxt(u32 *fb, u32 width, u32 height, u32 stride);
|
||||
void gfx_clear_grey(u8 color);
|
||||
void gfx_clear_partial_grey(u8 color, u32 pos_x, u32 height);
|
||||
void gfx_clear_color(u32 color);
|
||||
void gfx_con_init();
|
||||
void gfx_con_setcol(u32 fgcol, int fillbg, u32 bgcol);
|
||||
void gfx_con_getpos(u32 *x, u32 *y);
|
||||
void gfx_con_setpos(u32 x, u32 y);
|
||||
void gfx_putc(char c);
|
||||
void gfx_puts(char *s);
|
||||
void gfx_printf(const char *fmt, ...);
|
||||
void gfx_hexdump(u32 base, const u8 *buf, u32 len);
|
||||
|
||||
void gfx_set_pixel(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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -15,13 +15,12 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "di.h"
|
||||
#include "tui.h"
|
||||
#include "../utils/btn.h"
|
||||
#include "../config/config.h"
|
||||
#include "../power/max17050.h"
|
||||
#include "../utils/util.h"
|
||||
#include "../config/config.h"
|
||||
#include "di.h"
|
||||
|
||||
#ifdef MENU_LOGO_ENABLE
|
||||
extern u8 *Kc_MENU_LOGO;
|
||||
@@ -33,7 +32,7 @@ extern u8 *Kc_MENU_LOGO;
|
||||
|
||||
extern hekate_config h_cfg;
|
||||
|
||||
void tui_sbar(gfx_con_t *con, bool force_update)
|
||||
void tui_sbar(bool force_update)
|
||||
{
|
||||
u32 cx, cy;
|
||||
|
||||
@@ -42,78 +41,78 @@ void tui_sbar(gfx_con_t *con, bool force_update)
|
||||
if (timePassed < 5)
|
||||
return;
|
||||
|
||||
u8 prevFontSize = con->fntsz;
|
||||
con->fntsz = 16;
|
||||
u8 prevFontSize = gfx_con.fntsz;
|
||||
gfx_con.fntsz = 16;
|
||||
h_cfg.sbar_time_keeping = get_tmr_s();
|
||||
|
||||
u32 battPercent = 0;
|
||||
int battVoltCurr = 0;
|
||||
|
||||
gfx_con_getpos(con, &cx, &cy);
|
||||
gfx_con_setpos(con, 0, 1260);
|
||||
gfx_con_getpos(&cx, &cy);
|
||||
gfx_con_setpos(0, 1260);
|
||||
|
||||
max17050_get_property(MAX17050_RepSOC, (int *)&battPercent);
|
||||
max17050_get_property(MAX17050_VCELL, &battVoltCurr);
|
||||
|
||||
gfx_clear_partial_grey(con->gfx_ctxt, 0x30, 1256, 24);
|
||||
gfx_printf(con, "%K%k Battery: %d.%d%% (%d mV) - Charge:", 0xFF303030, 0xFF888888,
|
||||
gfx_clear_partial_grey(0x30, 1256, 24);
|
||||
gfx_printf("%K%k Battery: %d.%d%% (%d mV) - Charge:", 0xFF303030, 0xFF888888,
|
||||
(battPercent >> 8) & 0xFF, (battPercent & 0xFF) / 26, battVoltCurr);
|
||||
|
||||
max17050_get_property(MAX17050_AvgCurrent, &battVoltCurr);
|
||||
max17050_get_property(MAX17050_Current, &battVoltCurr);
|
||||
|
||||
if (battVoltCurr >= 0)
|
||||
gfx_printf(con, " %k+%d mA%k%K\n",
|
||||
gfx_printf(" %k+%d mA%k%K\n",
|
||||
0xFF008800, battVoltCurr / 1000, 0xFFCCCCCC, 0xFF1B1B1B);
|
||||
else
|
||||
gfx_printf(con, " %k-%d mA%k%K\n",
|
||||
gfx_printf(" %k-%d mA%k%K\n",
|
||||
0xFF880000, (~battVoltCurr) / 1000, 0xFFCCCCCC, 0xFF1B1B1B);
|
||||
con->fntsz = prevFontSize;
|
||||
gfx_con_setpos(con, cx, cy);
|
||||
gfx_con.fntsz = prevFontSize;
|
||||
gfx_con_setpos(cx, cy);
|
||||
}
|
||||
|
||||
void tui_pbar(gfx_con_t *con, int x, int y, u32 val, u32 fgcol, u32 bgcol)
|
||||
void tui_pbar(int x, int y, u32 val, u32 fgcol, u32 bgcol)
|
||||
{
|
||||
u32 cx, cy;
|
||||
if (val > 200)
|
||||
val = 200;
|
||||
|
||||
gfx_con_getpos(con, &cx, &cy);
|
||||
gfx_con_getpos(&cx, &cy);
|
||||
|
||||
gfx_con_setpos(con, x, y);
|
||||
gfx_con_setpos(x, y);
|
||||
|
||||
gfx_printf(con, "%k[%3d%%]%k", fgcol, val, 0xFFCCCCCC);
|
||||
gfx_printf("%k[%3d%%]%k", fgcol, val, 0xFFCCCCCC);
|
||||
|
||||
x += 7 * con->fntsz;
|
||||
|
||||
for (int i = 0; i < (con->fntsz >> 3) * 6; i++)
|
||||
x += 7 * gfx_con.fntsz;
|
||||
|
||||
for (int i = 0; i < (gfx_con.fntsz >> 3) * 6; i++)
|
||||
{
|
||||
gfx_line(con->gfx_ctxt, x, y + i + 1, x + 3 * val, y + i + 1, fgcol);
|
||||
gfx_line(con->gfx_ctxt, x + 3 * val, y + i + 1, x + 3 * 100, y + i + 1, bgcol);
|
||||
gfx_line(x, y + i + 1, x + 3 * val, y + i + 1, fgcol);
|
||||
gfx_line(x + 3 * val, y + i + 1, x + 3 * 100, y + i + 1, bgcol);
|
||||
}
|
||||
|
||||
gfx_con_setpos(con, cx, cy);
|
||||
gfx_con_setpos(cx, cy);
|
||||
|
||||
// Update status bar.
|
||||
tui_sbar(con, false);
|
||||
tui_sbar(false);
|
||||
}
|
||||
|
||||
void *tui_do_menu(gfx_con_t *con, menu_t *menu)
|
||||
void *tui_do_menu(menu_t *menu)
|
||||
{
|
||||
int idx = 0, prev_idx = 0, cnt = 0x7FFFFFFF;
|
||||
|
||||
gfx_clear_partial_grey(con->gfx_ctxt, 0x1B, 0, 1256);
|
||||
tui_sbar(con, true);
|
||||
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||
tui_sbar(true);
|
||||
|
||||
#ifdef MENU_LOGO_ENABLE
|
||||
gfx_set_rect_rgb(con->gfx_ctxt, Kc_MENU_LOGO,
|
||||
gfx_set_rect_rgb(Kc_MENU_LOGO,
|
||||
X_MENU_LOGO, Y_MENU_LOGO, X_POS_MENU_LOGO, Y_POS_MENU_LOGO);
|
||||
#endif //MENU_LOGO_ENABLE
|
||||
|
||||
while (true)
|
||||
{
|
||||
gfx_con_setcol(con, 0xFFCCCCCC, 1, 0xFF1B1B1B);
|
||||
gfx_con_setpos(con, menu->x, menu->y);
|
||||
gfx_printf(con, "[%s]\n\n", menu->caption);
|
||||
gfx_con_setcol(0xFFCCCCCC, 1, 0xFF1B1B1B);
|
||||
gfx_con_setpos(menu->x, menu->y);
|
||||
gfx_printf("[%s]\n\n", menu->caption);
|
||||
|
||||
// Skip caption or seperator lines selection.
|
||||
while (menu->ents[idx].type == MENT_CAPTION ||
|
||||
@@ -144,30 +143,25 @@ void *tui_do_menu(gfx_con_t *con, menu_t *menu)
|
||||
for (cnt = 0; menu->ents[cnt].type != MENT_END; cnt++)
|
||||
{
|
||||
if (cnt == idx)
|
||||
gfx_con_setcol(con, 0xFF1B1B1B, 1, 0xFFCCCCCC);
|
||||
gfx_con_setcol(0xFF1B1B1B, 1, 0xFFCCCCCC);
|
||||
else
|
||||
gfx_con_setcol(con, 0xFFCCCCCC, 1, 0xFF1B1B1B);
|
||||
gfx_con_setcol(0xFFCCCCCC, 1, 0xFF1B1B1B);
|
||||
if (menu->ents[cnt].type == MENT_CAPTION)
|
||||
gfx_printf(con, "%k %s", menu->ents[cnt].color, menu->ents[cnt].caption);
|
||||
gfx_printf("%k %s", menu->ents[cnt].color, menu->ents[cnt].caption);
|
||||
else if (menu->ents[cnt].type != MENT_CHGLINE)
|
||||
gfx_printf(con, " %s", menu->ents[cnt].caption);
|
||||
gfx_printf(" %s", menu->ents[cnt].caption);
|
||||
if(menu->ents[cnt].type == MENT_MENU)
|
||||
gfx_printf(con, "%k...", 0xFF0099EE);
|
||||
gfx_printf(con, " \n");
|
||||
gfx_printf("%k...", 0xFF0099EE);
|
||||
gfx_printf(" \n");
|
||||
}
|
||||
gfx_con_setcol(con, 0xFFCCCCCC, 1, 0xFF1B1B1B);
|
||||
gfx_putc(con, '\n');
|
||||
gfx_con_setcol(0xFFCCCCCC, 1, 0xFF1B1B1B);
|
||||
gfx_putc('\n');
|
||||
|
||||
// Print help and battery status.
|
||||
gfx_con_setpos(con, 0, 1127);
|
||||
if (h_cfg.errors)
|
||||
{
|
||||
gfx_printf(con, "%k Warning: %k", 0xFF800000, 0xFF555555);
|
||||
if (h_cfg.errors & ERR_LIBSYS_LP0)
|
||||
gfx_printf(con, "Sleep mode library is missing!\n");
|
||||
}
|
||||
gfx_con_setpos(con, 0, 1191);
|
||||
gfx_printf(con, "%k VOL: Move up/down\n PWR: Select option%k", 0xFF555555, 0xFFCCCCCC);
|
||||
// Print errors, help and battery status.
|
||||
gfx_con_setpos(0, 1127);
|
||||
gfx_printf("%k Warning: %k Nyx is missing!", 0xFF800000, 0xFF555555);
|
||||
gfx_con_setpos(0, 1191);
|
||||
gfx_printf("%k VOL: Move up/down\n PWR: Select option%k", 0xFF555555, 0xFFCCCCCC);
|
||||
|
||||
display_backlight_brightness(h_cfg.backlight, 1000);
|
||||
|
||||
@@ -177,11 +171,17 @@ void *tui_do_menu(gfx_con_t *con, menu_t *menu)
|
||||
if (btn & BTN_VOL_DOWN && idx < (cnt - 1))
|
||||
idx++;
|
||||
else if (btn & BTN_VOL_DOWN && idx == (cnt - 1))
|
||||
{
|
||||
idx = 0;
|
||||
prev_idx = -1;
|
||||
}
|
||||
if (btn & BTN_VOL_UP && idx > 0)
|
||||
idx--;
|
||||
else if (btn & BTN_VOL_UP && idx == 0)
|
||||
{
|
||||
idx = cnt - 1;
|
||||
prev_idx = cnt;
|
||||
}
|
||||
if (btn & BTN_POWER)
|
||||
{
|
||||
ment_t *ent = &menu->ents[idx];
|
||||
@@ -191,28 +191,30 @@ void *tui_do_menu(gfx_con_t *con, menu_t *menu)
|
||||
ent->handler(ent->data);
|
||||
break;
|
||||
case MENT_MENU:
|
||||
return tui_do_menu(con, ent->menu);
|
||||
return tui_do_menu(ent->menu);
|
||||
break;
|
||||
case MENT_CHOICE:
|
||||
case MENT_DATA:
|
||||
return ent->data;
|
||||
break;
|
||||
case MENT_BACK:
|
||||
return NULL;
|
||||
break;
|
||||
case MENT_HDLR_RE:
|
||||
ent->handler(ent->data);
|
||||
return NULL;
|
||||
ent->handler(ent);
|
||||
if (!ent->data)
|
||||
return NULL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
con->fntsz = 16;
|
||||
gfx_clear_partial_grey(con->gfx_ctxt, 0x1B, 0, 1256);
|
||||
gfx_con.fntsz = 16;
|
||||
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||
#ifdef MENU_LOGO_ENABLE
|
||||
gfx_set_rect_rgb(con->gfx_ctxt, Kc_MENU_LOGO,
|
||||
gfx_set_rect_rgb(Kc_MENU_LOGO,
|
||||
X_MENU_LOGO, Y_MENU_LOGO, X_POS_MENU_LOGO, Y_POS_MENU_LOGO);
|
||||
#endif //MENU_LOGO_ENABLE
|
||||
}
|
||||
tui_sbar(con, false);
|
||||
tui_sbar(false);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (C) 2018 CTCaer
|
||||
* Copyright (c) 2018 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -24,7 +24,7 @@
|
||||
#define MENT_END 0
|
||||
#define MENT_HANDLER 1
|
||||
#define MENT_MENU 2
|
||||
#define MENT_CHOICE 3
|
||||
#define MENT_DATA 3
|
||||
#define MENT_BACK 4
|
||||
#define MENT_CAPTION 5
|
||||
#define MENT_CHGLINE 6
|
||||
@@ -59,8 +59,8 @@ typedef struct _menu_t
|
||||
#define MDEF_CAPTION(caption, color) { MENT_CAPTION, caption, color }
|
||||
#define MDEF_CHGLINE() {MENT_CHGLINE}
|
||||
|
||||
void tui_sbar(gfx_con_t *con, bool force_update);
|
||||
void tui_pbar(gfx_con_t *con, int x, int y, u32 val, u32 fgcol, u32 bgcol);
|
||||
void *tui_do_menu(gfx_con_t *con, menu_t *menu);
|
||||
void tui_sbar(bool force_update);
|
||||
void tui_pbar(int x, int y, u32 val, u32 fgcol, u32 bgcol);
|
||||
void *tui_do_menu(menu_t *menu);
|
||||
|
||||
#endif
|
||||
|
||||
247
bootloader/hos/fss.c
Normal file
247
bootloader/hos/fss.c
Normal file
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
* Atmosphère Fusée Secondary Storage parser.
|
||||
*
|
||||
* Copyright (c) 2019-2020 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <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 "../storage/nx_sd.h"
|
||||
|
||||
#include "../gfx/gfx.h"
|
||||
#define DPRINTF(...)
|
||||
|
||||
extern hekate_config h_cfg;
|
||||
|
||||
extern bool is_ipl_updated(void *buf, char *path, bool force);
|
||||
|
||||
// FSS0 Magic and Meta header offset.
|
||||
#define FSS0_MAGIC 0x30535346
|
||||
#define FSS0_META_OFFSET 0x4
|
||||
|
||||
// FSS0 Content Types.
|
||||
#define CNT_TYPE_FSP 0
|
||||
#define CNT_TYPE_EXO 1 // Exosphere (Secure Monitor).
|
||||
#define CNT_TYPE_WBT 2 // Warmboot (SC7Exit fw).
|
||||
#define CNT_TYPE_RBT 3 // Rebootstub (Warmboot based reboot fw).
|
||||
#define CNT_TYPE_SP1 4 // Sept Primary (TSEC and Sept Secondary loader).
|
||||
#define CNT_TYPE_SP2 5 // Sept Secondary (Acts as pkg11 and derives keys).
|
||||
#define CNT_TYPE_KIP 6 // KIP1 (Used for replacement or addition).
|
||||
#define CNT_TYPE_BMP 7
|
||||
#define CNT_TYPE_EMC 8
|
||||
#define CNT_TYPE_KLD 9 // Kernel Loader.
|
||||
#define CNT_TYPE_KRN 10 // Kernel.
|
||||
|
||||
// FSS0 Content Flags.
|
||||
#define CNT_FLAG0_EXPERIMENTAL (1 << 0)
|
||||
|
||||
// FSS0 Meta Header.
|
||||
typedef struct _fss_meta_t
|
||||
{
|
||||
u32 magic;
|
||||
u32 size;
|
||||
u32 crt0_off;
|
||||
u32 cnt_off;
|
||||
u32 cnt_count;
|
||||
u32 hos_ver;
|
||||
u32 version;
|
||||
u32 git_rev;
|
||||
} fss_meta_t;
|
||||
|
||||
// FSS0 Content Header.
|
||||
typedef struct _fss_content_t
|
||||
{
|
||||
u32 offset;
|
||||
u32 size;
|
||||
u8 type;
|
||||
u8 flags0;
|
||||
u8 flags1;
|
||||
u8 flags2;
|
||||
u32 rsvd1;
|
||||
char name[0x10];
|
||||
} fss_content_t;
|
||||
|
||||
static void _update_r2p(const char *path)
|
||||
{
|
||||
char *r2p_path = malloc(256);
|
||||
u32 path_len = strlen(path);
|
||||
strcpy(r2p_path, path);
|
||||
|
||||
while(path_len)
|
||||
{
|
||||
if ((r2p_path[path_len - 1] == '/') || (r2p_path[path_len - 1] == 0x5C))
|
||||
{
|
||||
r2p_path[path_len] = 0;
|
||||
strcat(r2p_path, "reboot_payload.bin");
|
||||
u8 *r2p_payload = sd_file_read(r2p_path, NULL);
|
||||
|
||||
is_ipl_updated(r2p_payload, r2p_path, h_cfg.updater2p ? true : false);
|
||||
|
||||
free(r2p_payload);
|
||||
break;
|
||||
}
|
||||
path_len--;
|
||||
}
|
||||
|
||||
free(r2p_path);
|
||||
}
|
||||
|
||||
int parse_fss(launch_ctxt_t *ctxt, const char *path, fss0_sept_t *sept_ctxt)
|
||||
{
|
||||
FIL fp;
|
||||
|
||||
bool stock = false;
|
||||
int sept_used = 0;
|
||||
|
||||
if (!sept_ctxt)
|
||||
{
|
||||
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ctxt->cfg->kvs, link)
|
||||
{
|
||||
if (!strcmp("stock", kv->key))
|
||||
if (kv->val[0] == '1')
|
||||
stock = true;
|
||||
}
|
||||
|
||||
if (stock && ctxt->pkg1_id->kb <= KB_FIRMWARE_VERSION_620 && (!emu_cfg.enabled || h_cfg.emummc_force_disable))
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (f_open(&fp, path, FA_READ) != FR_OK)
|
||||
return 0;
|
||||
|
||||
void *fss = malloc(f_size(&fp));
|
||||
|
||||
// Read first 1024 bytes of the fss file.
|
||||
f_read(&fp, fss, 1024, NULL);
|
||||
|
||||
// Get FSS0 Meta header offset.
|
||||
u32 fss_meta_addr = *(u32 *)(fss + FSS0_META_OFFSET);
|
||||
fss_meta_t *fss_meta = (fss_meta_t *)(fss + fss_meta_addr);
|
||||
|
||||
// Check if valid FSS0 and parse it.
|
||||
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);
|
||||
|
||||
if (!sept_ctxt)
|
||||
{
|
||||
ctxt->atmosphere = true;
|
||||
ctxt->fss0_hosver = fss_meta->hos_ver;
|
||||
}
|
||||
|
||||
// Parse FSS0 contents.
|
||||
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);
|
||||
|
||||
// Check if offset is inside limits.
|
||||
if ((curr_fss_cnt[i].offset + curr_fss_cnt[i].size) > fss_meta->size)
|
||||
continue;
|
||||
|
||||
// If content is experimental and experimental flag is not enabled, skip it.
|
||||
if ((curr_fss_cnt[i].flags0 & CNT_FLAG0_EXPERIMENTAL) && !ctxt->fss0_enable_experimental)
|
||||
continue;
|
||||
|
||||
// Parse content.
|
||||
if (!sept_ctxt)
|
||||
{
|
||||
// Prepare content 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;
|
||||
}
|
||||
|
||||
// Load content to launch context.
|
||||
f_lseek(&fp, curr_fss_cnt[i].offset);
|
||||
f_read(&fp, content, curr_fss_cnt[i].size, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Load sept content directly to launch context.
|
||||
switch (curr_fss_cnt[i].type)
|
||||
{
|
||||
case CNT_TYPE_SP1:
|
||||
f_lseek(&fp, curr_fss_cnt[i].offset);
|
||||
f_read(&fp, sept_ctxt->sept_primary, curr_fss_cnt[i].size, NULL);
|
||||
break;
|
||||
case CNT_TYPE_SP2:
|
||||
if (!memcmp(curr_fss_cnt[i].name, (sept_ctxt->kb < KB_FIRMWARE_VERSION_810) ? "septsecondary00" : "septsecondary01", 15))
|
||||
{
|
||||
f_lseek(&fp, curr_fss_cnt[i].offset);
|
||||
f_read(&fp, sept_ctxt->sept_secondary, curr_fss_cnt[i].size, NULL);
|
||||
sept_used = 1;
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
gfx_printf("Done!\n");
|
||||
f_close(&fp);
|
||||
|
||||
_update_r2p(path);
|
||||
|
||||
return (!sept_ctxt ? 1 : sept_used);
|
||||
}
|
||||
|
||||
f_close(&fp);
|
||||
free(fss);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int load_sept_from_ffs0(fss0_sept_t *sept_ctxt)
|
||||
{
|
||||
LIST_FOREACH_ENTRY(ini_kv_t, kv, &sept_ctxt->cfg_sec->kvs, link)
|
||||
{
|
||||
if (!strcmp("fss0", kv->key))
|
||||
return parse_fss(NULL, kv->val, sept_ctxt);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
34
bootloader/hos/fss.h
Normal file
34
bootloader/hos/fss.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
typedef struct _fss0_sept_t
|
||||
{
|
||||
u32 kb;
|
||||
ini_sec_t *cfg_sec;
|
||||
void *sept_primary;
|
||||
void *sept_secondary;
|
||||
|
||||
} fss0_sept_t;
|
||||
|
||||
int parse_fss(launch_ctxt_t *ctxt, const char *path, fss0_sept_t *sept_ctxt);
|
||||
int load_sept_from_ffs0(fss0_sept_t *sept_ctxt);
|
||||
|
||||
#endif
|
||||
1107
bootloader/hos/hos.c
1107
bootloader/hos/hos.c
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2020 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -17,10 +18,103 @@
|
||||
#ifndef _HOS_H_
|
||||
#define _HOS_H_
|
||||
|
||||
#include "pkg1.h"
|
||||
#include "pkg2.h"
|
||||
#include "../utils/types.h"
|
||||
#include "../config/ini.h"
|
||||
#include "../sec/tsec.h"
|
||||
|
||||
int hos_launch(ini_sec_t *cfg);
|
||||
int keygen(u8 *keyblob, u32 kb, void *tsec_fw);
|
||||
#include <assert.h>
|
||||
|
||||
#define KB_FIRMWARE_VERSION_100_200 0
|
||||
#define KB_FIRMWARE_VERSION_300 1
|
||||
#define KB_FIRMWARE_VERSION_301 2
|
||||
#define KB_FIRMWARE_VERSION_400 3
|
||||
#define KB_FIRMWARE_VERSION_500 4
|
||||
#define KB_FIRMWARE_VERSION_600 5
|
||||
#define KB_FIRMWARE_VERSION_620 6
|
||||
#define KB_FIRMWARE_VERSION_700 7
|
||||
#define KB_FIRMWARE_VERSION_810 8
|
||||
#define KB_FIRMWARE_VERSION_900 9
|
||||
#define KB_FIRMWARE_VERSION_910 10
|
||||
#define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_910
|
||||
|
||||
#define HOS_PKG11_MAGIC 0x31314B50
|
||||
#define HOS_EKS_MAGIC 0x30534B45
|
||||
|
||||
typedef struct _exo_ctxt_t
|
||||
{
|
||||
bool no_user_exceptions;
|
||||
bool user_pmu;
|
||||
bool *cal0_blank;
|
||||
bool *cal0_allow_writes_sys;
|
||||
} exo_ctxt_t;
|
||||
|
||||
typedef struct _hos_eks_keys_t
|
||||
{
|
||||
u8 dkg[0x10];
|
||||
u8 mkk[0x10];
|
||||
u8 fdk[0x10];
|
||||
u8 dkk[0x10];
|
||||
} hos_eks_keys_t;
|
||||
|
||||
typedef struct _hos_eks_mbr_t
|
||||
{
|
||||
u32 magic;
|
||||
u32 enabled;
|
||||
u32 sbk_low[2];
|
||||
hos_eks_keys_t keys[6];
|
||||
u32 magic2;
|
||||
u32 rsvd2[3];
|
||||
} hos_eks_mbr_t;
|
||||
|
||||
static_assert(sizeof(hos_eks_mbr_t) == 416, "HOS EKS storage bigger than MBR!");
|
||||
|
||||
typedef struct _launch_ctxt_t
|
||||
{
|
||||
void *keyblob;
|
||||
|
||||
void *pkg1;
|
||||
const pkg1_id_t *pkg1_id;
|
||||
const pkg2_kernel_id_t *pkg2_kernel_id;
|
||||
|
||||
void *warmboot;
|
||||
u32 warmboot_size;
|
||||
void *secmon;
|
||||
u32 secmon_size;
|
||||
|
||||
void *pkg2;
|
||||
u32 pkg2_size;
|
||||
bool new_pkg2;
|
||||
|
||||
void *kernel;
|
||||
u32 kernel_size;
|
||||
link_t kip1_list;
|
||||
char* kip1_patches;
|
||||
|
||||
u32 fss0_hosver;
|
||||
bool svcperm;
|
||||
bool debugmode;
|
||||
bool stock;
|
||||
bool atmosphere;
|
||||
bool fss0_enable_experimental;
|
||||
bool emummc_forced;
|
||||
|
||||
exo_ctxt_t exo_cfg;
|
||||
|
||||
ini_sec_t *cfg;
|
||||
} launch_ctxt_t;
|
||||
|
||||
typedef struct _merge_kip_t
|
||||
{
|
||||
void *kip1;
|
||||
link_t link;
|
||||
} merge_kip_t;
|
||||
|
||||
void hos_eks_get();
|
||||
void hos_eks_save(u32 kb);
|
||||
void hos_eks_clear(u32 kb);
|
||||
int hos_launch(ini_sec_t *cfg);
|
||||
int hos_keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt, launch_ctxt_t *hos_ctxt);
|
||||
|
||||
#endif
|
||||
|
||||
309
bootloader/hos/hos_config.c
Normal file
309
bootloader/hos/hos_config.c
Normal file
@@ -0,0 +1,309 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2020 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* 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 "hos_config.h"
|
||||
#include "fss.h"
|
||||
#include "../libs/fatfs/ff.h"
|
||||
#include "../mem/heap.h"
|
||||
#include "../storage/nx_sd.h"
|
||||
#include "../utils/dirlist.h"
|
||||
|
||||
#include "../gfx/gfx.h"
|
||||
|
||||
//#define DPRINTF(...) gfx_printf(__VA_ARGS__)
|
||||
#define DPRINTF(...)
|
||||
|
||||
static int _config_warmboot(launch_ctxt_t *ctxt, const char *value)
|
||||
{
|
||||
ctxt->warmboot = sd_file_read(value, &ctxt->warmboot_size);
|
||||
if (!ctxt->warmboot)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _config_secmon(launch_ctxt_t *ctxt, const char *value)
|
||||
{
|
||||
ctxt->secmon = sd_file_read(value, &ctxt->secmon_size);
|
||||
if (!ctxt->secmon)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _config_kernel(launch_ctxt_t *ctxt, const char *value)
|
||||
{
|
||||
ctxt->kernel = sd_file_read(value, &ctxt->kernel_size);
|
||||
if (!ctxt->kernel)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _config_kip1(launch_ctxt_t *ctxt, const char *value)
|
||||
{
|
||||
u32 size;
|
||||
|
||||
if (!memcmp(value + strlen(value) - 1, "*", 1))
|
||||
{
|
||||
char *dir = (char *)malloc(256);
|
||||
strcpy(dir, value);
|
||||
|
||||
u32 dirlen = 0;
|
||||
dir[strlen(dir) - 2] = 0;
|
||||
char *filelist = dirlist(dir, "*.kip*", false);
|
||||
|
||||
strcat(dir, "/");
|
||||
dirlen = strlen(dir);
|
||||
|
||||
u32 i = 0;
|
||||
if (filelist)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (!filelist[i * 256])
|
||||
break;
|
||||
|
||||
strcpy(dir + dirlen, &filelist[i * 256]);
|
||||
|
||||
merge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t));
|
||||
mkip1->kip1 = sd_file_read(dir, &size);
|
||||
if (!mkip1->kip1)
|
||||
{
|
||||
free(mkip1);
|
||||
free(dir);
|
||||
free(filelist);
|
||||
|
||||
return 0;
|
||||
}
|
||||
DPRINTF("Loaded kip1 from SD (size %08X)\n", size);
|
||||
list_append(&ctxt->kip1_list, &mkip1->link);
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
free(dir);
|
||||
free(filelist);
|
||||
}
|
||||
else
|
||||
{
|
||||
merge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t));
|
||||
mkip1->kip1 = sd_file_read(value, &size);
|
||||
if (!mkip1->kip1)
|
||||
{
|
||||
free(mkip1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
DPRINTF("Loaded kip1 from SD (size %08X)\n", size);
|
||||
list_append(&ctxt->kip1_list, &mkip1->link);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int config_kip1patch(launch_ctxt_t *ctxt, const char *value)
|
||||
{
|
||||
if (value == NULL)
|
||||
return 0;
|
||||
|
||||
int valueLen = strlen(value);
|
||||
if (!valueLen)
|
||||
return 0;
|
||||
|
||||
if (ctxt->kip1_patches == NULL)
|
||||
{
|
||||
ctxt->kip1_patches = malloc(valueLen + 1);
|
||||
memcpy(ctxt->kip1_patches, value, valueLen);
|
||||
ctxt->kip1_patches[valueLen] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
char *oldAlloc = ctxt->kip1_patches;
|
||||
int oldSize = strlen(oldAlloc);
|
||||
ctxt->kip1_patches = malloc(oldSize + 1 + valueLen + 1);
|
||||
memcpy(ctxt->kip1_patches, oldAlloc, oldSize);
|
||||
free(oldAlloc);
|
||||
oldAlloc = NULL;
|
||||
ctxt->kip1_patches[oldSize++] = ',';
|
||||
memcpy(&ctxt->kip1_patches[oldSize], value, valueLen);
|
||||
ctxt->kip1_patches[oldSize + valueLen] = 0;
|
||||
}
|
||||
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_emummc_forced(launch_ctxt_t *ctxt, const char *value)
|
||||
{
|
||||
if (*value == '1')
|
||||
{
|
||||
DPRINTF("Forced emuMMC\n");
|
||||
ctxt->emummc_forced = 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_cfg.no_user_exceptions = true;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _config_exo_user_pmu_access(launch_ctxt_t *ctxt, const char *value)
|
||||
{
|
||||
if (*value == '1')
|
||||
{
|
||||
DPRINTF("Enabled user access to PMU\n");
|
||||
ctxt->exo_cfg.user_pmu = true;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _config_exo_cal0_blanking(launch_ctxt_t *ctxt, const char *value)
|
||||
{
|
||||
// Override key found.
|
||||
ctxt->exo_cfg.cal0_blank = calloc(sizeof(bool), 1);
|
||||
|
||||
if (*value == '1')
|
||||
{
|
||||
DPRINTF("Enabled prodinfo blanking\n");
|
||||
*ctxt->exo_cfg.cal0_blank = true;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _config_exo_cal0_writes_enable(launch_ctxt_t *ctxt, const char *value)
|
||||
{
|
||||
// Override key found.
|
||||
ctxt->exo_cfg.cal0_allow_writes_sys = calloc(sizeof(bool), 1);
|
||||
|
||||
if (*value == '1')
|
||||
{
|
||||
DPRINTF("Enabled prodinfo writes\n");
|
||||
*ctxt->exo_cfg.cal0_allow_writes_sys = true;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _config_fss(launch_ctxt_t *ctxt, const char *value)
|
||||
{
|
||||
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ctxt->cfg->kvs, link)
|
||||
{
|
||||
if (!strcmp("fss0experimental", kv->key))
|
||||
{
|
||||
ctxt->fss0_enable_experimental = *kv->val == '1';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return parse_fss(ctxt, value, NULL);
|
||||
}
|
||||
|
||||
typedef struct _cfg_handler_t
|
||||
{
|
||||
const char *key;
|
||||
int (*handler)(launch_ctxt_t *ctxt, const char *value);
|
||||
} cfg_handler_t;
|
||||
|
||||
static const cfg_handler_t _config_handlers[] = {
|
||||
{ "warmboot", _config_warmboot },
|
||||
{ "secmon", _config_secmon },
|
||||
{ "kernel", _config_kernel },
|
||||
{ "kip1", _config_kip1 },
|
||||
{ "kip1patch", config_kip1patch },
|
||||
{ "fullsvcperm", _config_svcperm },
|
||||
{ "debugmode", _config_debugmode },
|
||||
{ "stock", _config_stock },
|
||||
{ "atmosphere", _config_atmosphere },
|
||||
{ "fss0", _config_fss },
|
||||
{ "emummcforce", _config_emummc_forced },
|
||||
{ "nouserexceptions", _config_dis_exo_user_exceptions },
|
||||
{ "userpmu", _config_exo_user_pmu_access },
|
||||
{ "cal0blank", _config_exo_cal0_blanking },
|
||||
{ "cal0writesys", _config_exo_cal0_writes_enable },
|
||||
{ NULL, NULL },
|
||||
};
|
||||
|
||||
int parse_boot_config(launch_ctxt_t *ctxt)
|
||||
{
|
||||
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ctxt->cfg->kvs, link)
|
||||
{
|
||||
for(u32 i = 0; _config_handlers[i].key; i++)
|
||||
{
|
||||
if (!strcmp(_config_handlers[i].key, kv->key))
|
||||
{
|
||||
if (!_config_handlers[i].handler(ctxt, kv->val))
|
||||
{
|
||||
gfx_con.mute = false;
|
||||
EPRINTFARGS("Error while loading %s:\n%s", kv->key, kv->val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
26
bootloader/hos/hos_config.h
Normal file
26
bootloader/hos/hos_config.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
*
|
||||
* 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 _HOS_CONFIG_H_
|
||||
#define _HOS_CONFIG_H_
|
||||
|
||||
#include "hos.h"
|
||||
|
||||
int parse_boot_config(launch_ctxt_t *ctxt);
|
||||
int config_kip1patch(launch_ctxt_t *ctxt, const char *value);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018 st4rk
|
||||
* Copyright (c) 2018 CTCaer
|
||||
* Copyright (c) 2018-2020 CTCaer
|
||||
* Copyright (c) 2018 balika011
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -19,8 +20,12 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "pkg1.h"
|
||||
#include "../utils/aarch64_util.h"
|
||||
#include "../gfx/gfx.h"
|
||||
#include "../mem/heap.h"
|
||||
#include "../sec/se.h"
|
||||
#include "../utils/aarch64_util.h"
|
||||
|
||||
#define _NOPv7() 0xE320F000
|
||||
|
||||
#define SM_100_ADR 0x4002B020
|
||||
PATCHSET_DEF(_secmon_1_patchset,
|
||||
@@ -57,20 +62,63 @@ PATCHSET_DEF(_secmon_4_patchset,
|
||||
|
||||
PATCHSET_DEF(_secmon_5_patchset,
|
||||
// Patch package2 decryption and signature/hash checks.
|
||||
{ 0xDA8 + 0x9D8 , _NOP() }, //package2 structure.
|
||||
{ 0xDA8 + 0x9E4 , _NOP() }, //Version.
|
||||
{ 0xDA8 + 0xC9C , _NOP() }, //Header signature.
|
||||
{ 0xDA8 + 0x1038 , _NOP() } //Sections SHA2.
|
||||
{ 0xDA8 + 0x9D8, _NOP() }, //package2 structure.
|
||||
{ 0xDA8 + 0x9E4, _NOP() }, //Version.
|
||||
{ 0xDA8 + 0xC9C, _NOP() }, //Header signature.
|
||||
{ 0xDA8 + 0x1038, _NOP() } //Sections SHA2.
|
||||
);
|
||||
|
||||
PATCHSET_DEF(_secmon_6_patchset,
|
||||
// Patch package2 decryption and signature/hash checks.
|
||||
{ 0xDC8 + 0x820 , _NOP() }, //package2 structure.
|
||||
{ 0xDC8 + 0x82C , _NOP() }, //Version.
|
||||
{ 0xDC8 + 0xE90 , _NOP() }, //Header signature.
|
||||
{ 0xDC8 + 0x112C , _NOP() } //Sections SHA2.
|
||||
{ 0xDC8 + 0x820, _NOP() }, //package2 structure.
|
||||
{ 0xDC8 + 0x82C, _NOP() }, //Version.
|
||||
{ 0xDC8 + 0xE90, _NOP() }, //Header signature.
|
||||
{ 0xDC8 + 0x112C, _NOP() } //Sections SHA2.
|
||||
// Fix sleep mode for debug.
|
||||
// { 0x1A68 + 0x3854, 0x94000E45 }, //gpio_config_for_uart.
|
||||
// { 0x1A68 + 0x3858, 0x97FFFC0F }, //clkrst_reboot_uarta.
|
||||
// { 0x1A68 + 0x385C, 0x52A00021 }, //MOV W1, #0x10000 ; baudrate.
|
||||
// { 0x1A68 + 0x3860, 0x2A1F03E0 }, //MOV W0, WZR ; uart_port -> A.
|
||||
// { 0x1A68 + 0x3864, 0x72984001 }, //MOVK W1, #0xC200 ; baudrate.
|
||||
// { 0x1A68 + 0x3868, 0x94000C8C }, //uart_configure.
|
||||
// { 0x1A68 + 0x3A6C, _NOP() } // warmboot UARTA cfg.
|
||||
);
|
||||
|
||||
PATCHSET_DEF(_secmon_620_patchset,
|
||||
// Patch package2 decryption and signature/hash checks.
|
||||
{ 0xDC8 + 0x604, _NOP() }, //package2 structure.
|
||||
{ 0xDC8 + 0x610, _NOP() }, //Version.
|
||||
{ 0xDC8 + 0xC74, _NOP() }, //Header signature.
|
||||
{ 0xDC8 + 0xF10, _NOP() } //Sections SHA2.
|
||||
// Fix sleep mode for debug.
|
||||
// { 0x2AC8 + 0x3854, 0x94000F42 }, //gpio_config_for_uart.
|
||||
// { 0x2AC8 + 0x3858, 0x97FFFC0F }, //clkrst_reboot_uarta.
|
||||
// { 0x2AC8 + 0x385C, 0x52A00021 }, //MOV W1, #0x10000 ; baudrate.
|
||||
// { 0x2AC8 + 0x3860, 0x2A1F03E0 }, //MOV W0, WZR ; uart_port -> A.
|
||||
// { 0x2AC8 + 0x3864, 0x72984001 }, //MOVK W1, #0xC200 ; baudrate.
|
||||
// { 0x2AC8 + 0x3868, 0x94000D89 }, //uart_configure.
|
||||
// { 0x2AC8 + 0x3A6C, _NOP() } // warmboot UARTA cfg.
|
||||
);
|
||||
|
||||
PATCHSET_DEF(_warmboot_1_patchset,
|
||||
{ 0x4DC, _NOPv7() } // Fuse check.
|
||||
);
|
||||
|
||||
PATCHSET_DEF(_warmboot_2_patchset,
|
||||
{ 0x4DC, _NOPv7() } // Fuse check.
|
||||
);
|
||||
|
||||
PATCHSET_DEF(_warmboot_3_patchset,
|
||||
{ 0x4DC, _NOPv7() }, // Fuse check.
|
||||
{ 0x4F0, _NOPv7() } // Segment id check.
|
||||
);
|
||||
|
||||
PATCHSET_DEF(_warmboot_4_patchset,
|
||||
{ 0x544, _NOPv7() }, // Fuse check.
|
||||
{ 0x558, _NOPv7() } // Segment id check.
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
* package1.1 header: <wb, ldr, sm>
|
||||
* package1.1 layout:
|
||||
@@ -81,22 +129,36 @@ PATCHSET_DEF(_secmon_6_patchset,
|
||||
* 4.0: {ldr, sm, wb} { 1, 2, 0 }
|
||||
* 5.0: {ldr, sm, wb} { 1, 2, 0 }
|
||||
* 6.0: {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[] = {
|
||||
{ "20161121183008", 0, 0x1900, 0x3FE0, { 2, 1, 0 }, SM_100_ADR, 0x8000D000, true, _secmon_1_patchset }, //1.0.0 (Patched relocator)
|
||||
{ "20170210155124", 0, 0x1900, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_2_patchset }, //2.0.0 - 2.3.0
|
||||
{ "20170519101410", 1, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_3_patchset }, //3.0.0
|
||||
{ "20170710161758", 2, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_3_patchset }, //3.0.1 - 3.0.2
|
||||
{ "20170921172629", 3, 0x1800, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003B000, false, _secmon_4_patchset }, //4.0.0 - 4.1.0
|
||||
{ "20180220163747", 4, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003B000, false, _secmon_5_patchset }, //5.0.0 - 5.1.0
|
||||
{ "20180802162753", 5, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003D800, false, _secmon_6_patchset }, //6.0.0 - 6.0.0
|
||||
{ "20161121183008", 0, 0x1900, 0x3FE0, { 2, 1, 0 }, SM_100_ADR, 0x8000D000, true, _secmon_1_patchset, _warmboot_1_patchset }, //1.0.0 (Patched relocator)
|
||||
{ "20170210155124", 0, 0x1900, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_2_patchset, _warmboot_2_patchset }, //2.0.0 - 2.3.0
|
||||
{ "20170519101410", 1, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_3_patchset, _warmboot_3_patchset }, //3.0.0
|
||||
{ "20170710161758", 2, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_3_patchset, _warmboot_3_patchset }, //3.0.1 - 3.0.2
|
||||
{ "20170921172629", 3, 0x1800, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003B000, false, _secmon_4_patchset, _warmboot_4_patchset }, //4.0.0 - 4.1.0
|
||||
{ "20180220163747", 4, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003B000, false, _secmon_5_patchset, _warmboot_4_patchset }, //5.0.0 - 5.1.0
|
||||
{ "20180802162753", 5, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003D800, false, _secmon_6_patchset, _warmboot_4_patchset }, //6.0.0 - 6.1.0
|
||||
{ "20181107105733", 6, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x4002B000, 0x4003D800, false, _secmon_620_patchset, _warmboot_4_patchset }, //6.2.0
|
||||
{ "20181218175730", 7, 0x0F00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //7.0.0
|
||||
{ "20190208150037", 7, 0x0F00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //7.0.1
|
||||
{ "20190314172056", 7, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //8.0.0 - 8.0.1
|
||||
{ "20190531152432", 8, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //8.1.0
|
||||
{ "20190809135709", 9, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //9.0.0 - 9.0.1
|
||||
{ "20191021113848", 10, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //9.1.0
|
||||
{ "20200303104606", 10, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //10.0.0
|
||||
{ NULL } //End.
|
||||
};
|
||||
|
||||
|
||||
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++)
|
||||
if (!memcmp(pkg1 + 0x10, _pkg1_ids[i].id, 12))
|
||||
return &_pkg1_ids[i];
|
||||
|
||||
@@ -42,6 +42,7 @@ typedef struct _pkg1_id_t
|
||||
u32 warmboot_base;
|
||||
bool set_warmboot;
|
||||
patch_t *secmon_patchset;
|
||||
patch_t *warmboot_patchset;
|
||||
} pkg1_id_t;
|
||||
|
||||
typedef struct _pk11_hdr_t
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (C) 2018 CTCaer
|
||||
* Copyright (c) 2018-2020 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -27,6 +27,12 @@
|
||||
#define PKG2_SEC_INI1 1
|
||||
|
||||
#define INI1_MAGIC 0x31494E49
|
||||
#define PKG2_NEWKERN_GET_INI1_HEURISTIC 0xD2800015 // Offset of OP + 12 is the INI1 offset.
|
||||
#define PKG2_NEWKERN_START 0x800
|
||||
|
||||
u32 pkg2_newkern_ini1_val;
|
||||
u32 pkg2_newkern_ini1_start;
|
||||
u32 pkg2_newkern_ini1_end;
|
||||
|
||||
typedef struct _kernel_patch_t
|
||||
{
|
||||
@@ -44,12 +50,15 @@ typedef struct _kernel_patch_t
|
||||
|
||||
enum
|
||||
{
|
||||
// Generic instruction patches
|
||||
SVC_VERIFY_DS = 0x10, // 0x0-0xF are RESERVED.
|
||||
DEBUG_MODE_EN,
|
||||
ATM_GEN_PATCH,
|
||||
// Always applied.
|
||||
SVC_GENERIC = 0,
|
||||
// Generic instruction patches.
|
||||
SVC_VERIFY_DS = 0x10,
|
||||
DEBUG_MODE_EN = 0x11,
|
||||
ATM_GEN_PATCH = 0x12,
|
||||
ATM_SYSM_INCR = ATM_GEN_PATCH,
|
||||
// >4 bytes patches. Value is a pointer of a u32 array.
|
||||
ATM_ARR_PATCH,
|
||||
ATM_ARR_PATCH = 0x13,
|
||||
};
|
||||
|
||||
typedef struct _pkg2_hdr_t
|
||||
@@ -109,40 +118,42 @@ typedef struct _pkg2_kip1_info_t
|
||||
|
||||
typedef struct _pkg2_kernel_id_t
|
||||
{
|
||||
u32 crc32c_id;
|
||||
u8 hash[8];
|
||||
kernel_patch_t *kernel_patchset;
|
||||
} pkg2_kernel_id_t;
|
||||
|
||||
typedef struct _kip1_patch_t
|
||||
{
|
||||
u32 offset; //section+offset of patch to apply
|
||||
u32 length; //in bytes, 0 means last patch
|
||||
const char* srcData; //that must match
|
||||
const char* dstData; //that it gets replaced by
|
||||
u32 offset; // section+offset of patch to apply.
|
||||
u32 length; // In bytes, 0 means last patch.
|
||||
char* srcData; // That must match.
|
||||
char* dstData; // That it gets replaced by.
|
||||
} kip1_patch_t;
|
||||
|
||||
typedef struct _kip1_patchset_t
|
||||
{
|
||||
const char* name; //NULL means end
|
||||
kip1_patch_t* patches; //NULL means not necessary
|
||||
char* name; // NULL means end.
|
||||
kip1_patch_t* patches; // NULL means not necessary.
|
||||
} kip1_patchset_t;
|
||||
|
||||
typedef struct _kip1_id_t
|
||||
{
|
||||
const char* name;
|
||||
u8 hash[16];
|
||||
u8 hash[8];
|
||||
kip1_patchset_t* patchset;
|
||||
} kip1_id_t;
|
||||
|
||||
void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2);
|
||||
int pkg2_has_kip(link_t *info, u64 tid);
|
||||
void pkg2_get_newkern_info(u8 *kern_data);
|
||||
bool pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2);
|
||||
int pkg2_has_kip(link_t *info, u64 tid);
|
||||
void pkg2_replace_kip(link_t *info, u64 tid, pkg2_kip1_t *kip1);
|
||||
void pkg2_add_kip(link_t *info, pkg2_kip1_t *kip1);
|
||||
void pkg2_merge_kip(link_t *info, pkg2_kip1_t *kip1);
|
||||
void pkg2_get_ids(kip1_id_t **ids, u32 *entries);
|
||||
const char* pkg2_patch_kips(link_t *info, char* patchNames);
|
||||
|
||||
const pkg2_kernel_id_t *pkg2_identify(u32 id);
|
||||
pkg2_hdr_t *pkg2_decrypt(void *data);
|
||||
void pkg2_build_encrypt(void *dst, void *kernel, u32 kernel_size, link_t *kips_info);
|
||||
const pkg2_kernel_id_t *pkg2_identify(u8 *hash);
|
||||
pkg2_hdr_t *pkg2_decrypt(void *data, u8 kb);
|
||||
void pkg2_build_encrypt(void *dst, void *kernel, u32 kernel_size, link_t *kips_info, bool new_pkg2);
|
||||
|
||||
#endif
|
||||
|
||||
156
bootloader/hos/pkg2_ini_kippatch.c
Normal file
156
bootloader/hos/pkg2_ini_kippatch.c
Normal file
@@ -0,0 +1,156 @@
|
||||
#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 = (ini_kip_sec_t *)calloc(sizeof(ini_kip_sec_t), 1);
|
||||
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. Depends on 'FF_USE_STRFUNC 2' that removes \r.
|
||||
if (lblen && lbuf[lblen - 1] == '\n')
|
||||
lbuf[lblen - 1] = 0;
|
||||
|
||||
if (lblen > 2 && lbuf[0] == '[') // Create new section.
|
||||
{
|
||||
_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 *)calloc(sizeof(ini_patchset_t), 1);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
355
bootloader/hos/secmon_exo.c
Normal file
355
bootloader/hos/secmon_exo.c
Normal file
@@ -0,0 +1,355 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 CTCaer
|
||||
* Copyright (c) 2019 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* 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 "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/nx_sd.h"
|
||||
#include "../storage/sdmmc.h"
|
||||
#include "../utils/btn.h"
|
||||
#include "../utils/util.h"
|
||||
#include "../utils/types.h"
|
||||
|
||||
extern hekate_config h_cfg;
|
||||
|
||||
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];
|
||||
u8 tls[0x100];
|
||||
} atm_fatal_error_ctx;
|
||||
|
||||
#define ATM_FATAL_ERR_CTX_ADDR 0x4003E000
|
||||
#define ATM_FATAL_MAGIC 0x30454641 // AFE0
|
||||
|
||||
#define ATM_WB_HEADER_OFF 0x244
|
||||
#define ATM_WB_MAGIC 0x30544257
|
||||
|
||||
// Exosphère mailbox defines.
|
||||
#define EXO_CFG_ADDR 0x8000F000
|
||||
#define EXO_MAGIC_VAL 0x304F5845
|
||||
#define EXO_FLAG_DBG_PRIV (1 << 1)
|
||||
#define EXO_FLAG_DBG_USER (1 << 2)
|
||||
#define EXO_FLAG_NO_USER_EXC (1 << 3)
|
||||
#define EXO_FLAG_USER_PMU (1 << 4)
|
||||
#define EXO_FLAG_CAL0_BLANKING (1 << 5)
|
||||
#define EXO_FLAG_CAL0_WRITES_SYS (1 << 6)
|
||||
|
||||
void config_exosphere(launch_ctxt_t *ctxt)
|
||||
{
|
||||
u32 exoFwNo = 0;
|
||||
u32 exoFlags = 0;
|
||||
u32 kb = ctxt->pkg1_id->kb;
|
||||
bool user_debug = false;
|
||||
bool cal0_blanking = false;
|
||||
bool cal0_allow_writes_sys = false;
|
||||
|
||||
memset((exo_cfg_t *)EXO_CFG_ADDR, 0, sizeof(exo_cfg_t));
|
||||
|
||||
volatile exo_cfg_t *exo_cfg = (exo_cfg_t *)EXO_CFG_ADDR;
|
||||
|
||||
switch (kb)
|
||||
{
|
||||
case KB_FIRMWARE_VERSION_100_200:
|
||||
if (!strcmp(ctxt->pkg1_id->id, "20161121183008"))
|
||||
exoFwNo = 1;
|
||||
else
|
||||
exoFwNo = 2;
|
||||
break;
|
||||
case KB_FIRMWARE_VERSION_300:
|
||||
exoFwNo = 3;
|
||||
break;
|
||||
default:
|
||||
exoFwNo = kb + 1;
|
||||
if (!strcmp(ctxt->pkg1_id->id, "20190314172056") || (kb >= KB_FIRMWARE_VERSION_810))
|
||||
exoFwNo++; // ATM_TARGET_FW_800/810/900/910.
|
||||
if (!strcmp(ctxt->pkg1_id->id, "20200303104606"))
|
||||
exoFwNo++; // ATM_TARGET_FW_1000.
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ctxt->stock)
|
||||
{
|
||||
// Parse exosphere.ini.
|
||||
LIST_INIT(ini_sections);
|
||||
if (ini_parse(&ini_sections, "exosphere.ini", false))
|
||||
{
|
||||
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link)
|
||||
{
|
||||
// Only parse exosphere section.
|
||||
if (!(ini_sec->type == INI_CHOICE) || strcmp(ini_sec->name, "exosphere"))
|
||||
continue;
|
||||
|
||||
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)
|
||||
{
|
||||
if (!strcmp("debugmode_user", kv->key))
|
||||
user_debug = atoi(kv->val);
|
||||
else if (emu_cfg.enabled && !h_cfg.emummc_force_disable)
|
||||
{
|
||||
if (!strcmp("blank_prodinfo_emummc", kv->key))
|
||||
cal0_blanking = atoi(kv->val);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!strcmp("blank_prodinfo_sysmmc", kv->key))
|
||||
cal0_blanking = atoi(kv->val);
|
||||
else if (!strcmp("allow_writing_to_cal_sysmmc", kv->key))
|
||||
cal0_allow_writes_sys = atoi(kv->val);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// To avoid problems, make private debug mode always on if not semi-stock.
|
||||
if (!ctxt->stock || (emu_cfg.enabled && !h_cfg.emummc_force_disable))
|
||||
exoFlags |= EXO_FLAG_DBG_PRIV;
|
||||
|
||||
// Enable user debug.
|
||||
if (user_debug)
|
||||
exoFlags |= EXO_FLAG_DBG_USER;
|
||||
|
||||
// Disable proper failure handling.
|
||||
if (ctxt->exo_cfg.no_user_exceptions)
|
||||
exoFlags |= EXO_FLAG_NO_USER_EXC;
|
||||
|
||||
// Enable user access to PMU.
|
||||
if (ctxt->exo_cfg.user_pmu)
|
||||
exoFlags |= EXO_FLAG_USER_PMU;
|
||||
|
||||
// Enable prodinfo blanking. Check if exo ini value is overridden. If not, check if enabled in exo ini.
|
||||
if ((ctxt->exo_cfg.cal0_blank && *ctxt->exo_cfg.cal0_blank)
|
||||
|| (!ctxt->exo_cfg.cal0_blank && cal0_blanking))
|
||||
exoFlags |= EXO_FLAG_CAL0_BLANKING;
|
||||
|
||||
// Allow prodinfo writes. Check if exo ini value is overridden. If not, check if enabled in exo ini.
|
||||
if ((ctxt->exo_cfg.cal0_allow_writes_sys && *ctxt->exo_cfg.cal0_allow_writes_sys)
|
||||
|| (!ctxt->exo_cfg.cal0_allow_writes_sys && cal0_allow_writes_sys))
|
||||
exoFlags |= EXO_FLAG_CAL0_WRITES_SYS;
|
||||
|
||||
// Set mailbox values.
|
||||
exo_cfg->magic = EXO_MAGIC_VAL;
|
||||
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_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400);
|
||||
sdmmc_storage_set_mmc_partition(&storage, EMMC_BOOT0);
|
||||
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;
|
||||
|
||||
// Mask magic to maintain compatibility with any AFE version, thanks to additive struct members.
|
||||
if ((rpt->magic & 0xF0FFFFFF) != ATM_FATAL_MAGIC)
|
||||
return;
|
||||
|
||||
gfx_clear_grey(0x1B);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
WPRINTF("Panic occurred while running Atmosphere.\n\n");
|
||||
WPRINTFARGS("Title ID: %08X%08X", (u32)((u64)rpt->title_id >> 32), (u32)rpt->title_id);
|
||||
WPRINTFARGS("Error Desc: %s (0x%x)\n", get_error_desc(rpt->error_desc), rpt->error_desc);
|
||||
|
||||
// Save context to the SD card.
|
||||
char filepath[0x40];
|
||||
f_mkdir("atmosphere/fatal_errors");
|
||||
strcpy(filepath, "/atmosphere/fatal_errors/report_");
|
||||
itoa((u32)((u64)rpt->report_identifier >> 32), filepath + strlen(filepath), 16);
|
||||
itoa((u32)(rpt->report_identifier), filepath + strlen(filepath), 16);
|
||||
strcat(filepath, ".bin");
|
||||
|
||||
sd_save_to_file((void *)rpt, sizeof(atm_fatal_error_ctx), filepath);
|
||||
|
||||
gfx_con.fntsz = 8;
|
||||
WPRINTFARGS("Report saved to %s\n", filepath);
|
||||
|
||||
// Change magic to invalid, to prevent double-display of error/bootlooping.
|
||||
rpt->magic = 0x0;
|
||||
|
||||
gfx_con.fntsz = 16;
|
||||
gfx_printf("\n\nPress POWER to continue.\n");
|
||||
|
||||
display_backlight_brightness(100, 1000);
|
||||
msleep(1000);
|
||||
|
||||
u32 btn = btn_wait();
|
||||
while (!(btn & BTN_POWER))
|
||||
btn = btn_wait();
|
||||
|
||||
display_backlight_brightness(0, 1000);
|
||||
gfx_con_setpos(0, 0);
|
||||
}
|
||||
25
bootloader/hos/secmon_exo.h
Normal file
25
bootloader/hos/secmon_exo.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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 _SECMON_EXO_H_
|
||||
#define _SECMON_EXO_H_
|
||||
|
||||
#include "../utils/types.h"
|
||||
|
||||
void config_exosphere(launch_ctxt_t *ctxt);
|
||||
void secmon_exo_check_panic();
|
||||
|
||||
#endif
|
||||
257
bootloader/hos/sept.c
Normal file
257
bootloader/hos/sept.c
Normal file
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
* 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 "fss.h"
|
||||
#include "sept.h"
|
||||
#include "../config/config.h"
|
||||
#include "../gfx/di.h"
|
||||
#include "../ianos/ianos.h"
|
||||
#include "../libs/fatfs/ff.h"
|
||||
#include "../mem/heap.h"
|
||||
#include "../soc/hw_init.h"
|
||||
#include "../soc/pmc.h"
|
||||
#include "../soc/t210.h"
|
||||
#include "../storage/emummc.h"
|
||||
#include "../storage/nx_emmc.h"
|
||||
#include "../storage/nx_sd.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 bool is_ipl_updated(void *buf);
|
||||
extern void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size);
|
||||
|
||||
void check_sept(ini_sec_t *cfg_sec)
|
||||
{
|
||||
hos_eks_get();
|
||||
|
||||
// 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;
|
||||
int res = emummc_storage_init_mmc(&storage, &sdmmc);
|
||||
if (res)
|
||||
{
|
||||
if (res == 2)
|
||||
EPRINTF("Failed to init eMMC");
|
||||
else
|
||||
EPRINTF("Failed to init emuMMC");
|
||||
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
emummc_storage_set_mmc_partition(&storage, EMMC_BOOT0);
|
||||
|
||||
// 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)
|
||||
{
|
||||
u8 key_idx = pkg1_id->kb - KB_FIRMWARE_VERSION_700;
|
||||
if (h_cfg.eks && (h_cfg.eks->enabled & (1 << key_idx)))
|
||||
{
|
||||
h_cfg.sept_run = true;
|
||||
EMC(EMC_SCRATCH0) |= EMC_SEPT_RUN;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
sdmmc_storage_end(&storage);
|
||||
reboot_to_sept((u8 *)pkg1 + pkg1_id->tsec_off, pkg1_id->kb, cfg_sec);
|
||||
}
|
||||
|
||||
out_free:
|
||||
free(pkg1);
|
||||
sdmmc_storage_end(&storage);
|
||||
}
|
||||
|
||||
int reboot_to_sept(const u8 *tsec_fw, u32 kb, ini_sec_t *cfg_sec)
|
||||
{
|
||||
FIL fp;
|
||||
bool fss0_sept_used = false;
|
||||
|
||||
// Copy warmboot reboot code and TSEC fw.
|
||||
u32 tsec_fw_size = 0x3000;
|
||||
if (kb > KB_FIRMWARE_VERSION_700)
|
||||
tsec_fw_size = 0x3300;
|
||||
memcpy((u8 *)(SEPT_PK1T_ADDR - WB_RST_SIZE), (u8 *)warmboot_reboot, sizeof(warmboot_reboot));
|
||||
memcpy((void *)SEPT_PK1T_ADDR, tsec_fw, tsec_fw_size);
|
||||
*(vu32 *)SEPT_TCSZ_ADDR = tsec_fw_size;
|
||||
|
||||
if (cfg_sec)
|
||||
{
|
||||
fss0_sept_t sept_ctxt;
|
||||
sept_ctxt.kb = kb;
|
||||
sept_ctxt.cfg_sec = cfg_sec;
|
||||
sept_ctxt.sept_primary = (void *)SEPT_STG1_ADDR;
|
||||
sept_ctxt.sept_secondary = (void *)SEPT_STG2_ADDR;
|
||||
|
||||
fss0_sept_used = load_sept_from_ffs0(&sept_ctxt);
|
||||
}
|
||||
|
||||
if (!fss0_sept_used)
|
||||
{
|
||||
// Copy sept-primary.
|
||||
if (f_open(&fp, "sept/sept-primary.bin", FA_READ))
|
||||
goto error;
|
||||
|
||||
if (f_read(&fp, (u8 *)SEPT_STG1_ADDR, f_size(&fp), NULL))
|
||||
{
|
||||
f_close(&fp);
|
||||
goto error;
|
||||
}
|
||||
f_close(&fp);
|
||||
|
||||
// Copy sept-secondary.
|
||||
if (kb < KB_FIRMWARE_VERSION_810)
|
||||
{
|
||||
if (f_open(&fp, "sept/sept-secondary_00.enc", FA_READ))
|
||||
if (f_open(&fp, "sept/sept-secondary.enc", FA_READ)) // Try the deprecated version.
|
||||
goto error;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (f_open(&fp, "sept/sept-secondary_01.enc", FA_READ))
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (f_read(&fp, (u8 *)SEPT_STG2_ADDR, f_size(&fp), NULL))
|
||||
{
|
||||
f_close(&fp);
|
||||
goto error;
|
||||
}
|
||||
f_close(&fp);
|
||||
}
|
||||
|
||||
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);
|
||||
update_sept_payload = false;
|
||||
}
|
||||
|
||||
f_close(&fp);
|
||||
}
|
||||
else
|
||||
{
|
||||
f_close(&fp);
|
||||
f_rename("sept/payload.bin", "sept/payload.bak"); // Backup foreign payload.
|
||||
}
|
||||
}
|
||||
|
||||
if (update_sept_payload)
|
||||
{
|
||||
volatile reloc_meta_t *reloc = (reloc_meta_t *)(IPL_LOAD_ADDR + RELOC_META_OFF);
|
||||
f_mkdir("sept");
|
||||
f_open(&fp, "sept/payload.bin", FA_WRITE | FA_CREATE_ALWAYS);
|
||||
f_write(&fp, (u8 *)reloc->start, reloc->end - reloc->start, NULL);
|
||||
f_close(&fp);
|
||||
}
|
||||
|
||||
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(ini_sec_t *cfg_sec);
|
||||
int reboot_to_sept(const u8 *tsec_fw, u32 kb, ini_sec_t *cfg_sec);
|
||||
|
||||
#endif
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 M4xw
|
||||
* Copyright (c) 2018 CTCaer
|
||||
* Copyright (c) 2018-2019 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -18,23 +18,18 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "ianos.h"
|
||||
#include "../utils/types.h"
|
||||
#include "../libs/elfload/elfload.h"
|
||||
#include "../../common/common_module.h"
|
||||
#include "../mem/heap.h"
|
||||
#include "../gfx/gfx.h"
|
||||
#include "../libs/elfload/elfload.h"
|
||||
#include "../mem/heap.h"
|
||||
#include "../storage/nx_sd.h"
|
||||
#include "../utils/types.h"
|
||||
|
||||
#define IRAM_LIB_ADDR 0x4002B000
|
||||
#define DRAM_LIB_ADDR 0xE0000000
|
||||
|
||||
extern gfx_ctxt_t gfx_ctxt;
|
||||
extern gfx_con_t gfx_con;
|
||||
extern heap_t _heap;
|
||||
|
||||
extern void *sd_file_read(char *path);
|
||||
extern bool sd_mount();
|
||||
extern void sd_unmount();
|
||||
|
||||
void *elfBuf = NULL;
|
||||
void *fileBuf = NULL;
|
||||
|
||||
@@ -67,62 +62,31 @@ static bool _ianos_read_cb(el_ctx *ctx, void *dest, size_t numberBytes, size_t o
|
||||
return true;
|
||||
}
|
||||
|
||||
void ianos_print_error(int errorno)
|
||||
{
|
||||
switch (errorno)
|
||||
{
|
||||
case 1:
|
||||
gfx_printf(&gfx_con, "Can't find library!\n");
|
||||
break;
|
||||
case 2:
|
||||
gfx_printf(&gfx_con, "Cant init ELF context!\n");
|
||||
break;
|
||||
case 3:
|
||||
gfx_printf(&gfx_con, "Cant alloc memory!\n");
|
||||
break;
|
||||
case 4:
|
||||
gfx_printf(&gfx_con, "Error loading ELF!\n");
|
||||
break;
|
||||
case 5:
|
||||
gfx_printf(&gfx_con, "Error relcating ELF!\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: Support shared libraries.
|
||||
int ianos_loader(bool sdmount, char *path, elfType_t type, void *moduleConfig)
|
||||
uintptr_t ianos_loader(bool sdmount, char *path, elfType_t type, void *moduleConfig)
|
||||
{
|
||||
int res = 0;
|
||||
uintptr_t epaddr = 0;
|
||||
|
||||
if (sdmount)
|
||||
{
|
||||
if (!sd_mount())
|
||||
{
|
||||
res = 0xFFFF;
|
||||
goto elfLoadFinalOut;
|
||||
}
|
||||
}
|
||||
|
||||
fileBuf = sd_file_read(path);
|
||||
fileBuf = sd_file_read(path, NULL);
|
||||
|
||||
if (sdmount)
|
||||
sd_unmount();
|
||||
|
||||
if (!fileBuf)
|
||||
{
|
||||
res = 1;
|
||||
goto elfLoadFinalOut;
|
||||
}
|
||||
|
||||
|
||||
el_ctx ctx;
|
||||
ctx.pread = _ianos_read_cb;
|
||||
|
||||
if (el_init(&ctx))
|
||||
{
|
||||
res = 2;
|
||||
goto elfLoadFinalOut;
|
||||
}
|
||||
|
||||
// Set our relocated library's buffer.
|
||||
switch (type & 0xFFFF)
|
||||
@@ -133,43 +97,32 @@ int ianos_loader(bool sdmount, char *path, elfType_t type, void *moduleConfig)
|
||||
sd_unmount();
|
||||
break;
|
||||
default:
|
||||
elfBuf = memalign(ctx.align, ctx.memsz);
|
||||
elfBuf = malloc(ctx.memsz); // Aligned to 0x10 by default.
|
||||
}
|
||||
|
||||
if (!elfBuf)
|
||||
{
|
||||
res = 3;
|
||||
goto elfLoadFinalOut;
|
||||
}
|
||||
|
||||
// Load and relocate library.
|
||||
ctx.base_load_vaddr = ctx.base_load_paddr = (uintptr_t)elfBuf;
|
||||
if (el_load(&ctx, _ianos_alloc_cb))
|
||||
{
|
||||
res = 4;
|
||||
goto elfFreeOut;
|
||||
}
|
||||
|
||||
if (el_relocate(&ctx))
|
||||
{
|
||||
res = 5;
|
||||
goto elfFreeOut;
|
||||
}
|
||||
|
||||
// Launch.
|
||||
uintptr_t epaddr = ctx.ehdr.e_entry + (uintptr_t)elfBuf;
|
||||
epaddr = ctx.ehdr.e_entry + (uintptr_t)elfBuf;
|
||||
moduleEntrypoint_t ep = (moduleEntrypoint_t)epaddr;
|
||||
|
||||
_ianos_call_ep(ep, moduleConfig);
|
||||
|
||||
elfFreeOut:
|
||||
if ((u32)elfBuf >= 0x90000000 && (u32)elfBuf <= DRAM_LIB_ADDR)
|
||||
free(elfBuf);
|
||||
free(fileBuf);
|
||||
elfBuf = NULL;
|
||||
fileBuf = NULL;
|
||||
|
||||
elfLoadFinalOut:
|
||||
|
||||
return res;
|
||||
return epaddr;
|
||||
}
|
||||
@@ -29,6 +29,6 @@ typedef enum
|
||||
KEEP_IN_RAM = (1 << 31) // Shared library mask.
|
||||
} elfType_t;
|
||||
|
||||
int ianos_loader(bool sdmount, char *path, elfType_t type, void* config);
|
||||
uintptr_t ianos_loader(bool sdmount, char *path, elfType_t type, void* config);
|
||||
|
||||
#endif
|
||||
@@ -33,24 +33,24 @@ const blz_footer *blz_get_footer(const unsigned char *compData, unsigned int com
|
||||
}
|
||||
|
||||
// From https://github.com/SciresM/hactool/blob/master/kip.c which is exactly how kernel does it, thanks SciresM!
|
||||
int blz_uncompress_inplace(unsigned char *dataBuf, unsigned int compSize, const blz_footer *footer)
|
||||
int blz_uncompress_inplace(unsigned char *dataBuf, unsigned int compSize, const blz_footer *footer)
|
||||
{
|
||||
u32 addl_size = footer->addl_size;
|
||||
u32 header_size = footer->header_size;
|
||||
u32 cmp_and_hdr_size = footer->cmp_and_hdr_size;
|
||||
|
||||
|
||||
unsigned char* cmp_start = &dataBuf[compSize] - cmp_and_hdr_size;
|
||||
u32 cmp_ofs = cmp_and_hdr_size - header_size;
|
||||
u32 out_ofs = cmp_and_hdr_size + addl_size;
|
||||
|
||||
while (out_ofs)
|
||||
|
||||
while (out_ofs)
|
||||
{
|
||||
unsigned char control = cmp_start[--cmp_ofs];
|
||||
for (unsigned int i=0; i<8; i++)
|
||||
for (unsigned int i=0; i<8; i++)
|
||||
{
|
||||
if (control & 0x80)
|
||||
if (control & 0x80)
|
||||
{
|
||||
if (cmp_ofs < 2)
|
||||
if (cmp_ofs < 2)
|
||||
return 0; // Out of bounds.
|
||||
|
||||
cmp_ofs -= 2;
|
||||
@@ -65,17 +65,17 @@ int blz_uncompress_inplace(unsigned char *dataBuf, unsigned int compSize, const
|
||||
for (unsigned int j = 0; j < seg_size; j++)
|
||||
cmp_start[out_ofs + j] = cmp_start[out_ofs + j + seg_ofs];
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
// Copy directly.
|
||||
if (cmp_ofs < 1)
|
||||
if (cmp_ofs < 1)
|
||||
return 0; //out of bounds
|
||||
|
||||
cmp_start[--out_ofs] = cmp_start[--cmp_ofs];
|
||||
}
|
||||
control <<= 1;
|
||||
if (out_ofs == 0) // Blz works backwards, so if it reaches byte 0, it's done.
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "elfload.h"
|
||||
|
||||
@@ -26,9 +26,8 @@
|
||||
|
||||
#ifdef DEBUG
|
||||
#include "../../gfx/gfx.h"
|
||||
extern gfx_con_t gfx_con;
|
||||
#define EL_DEBUG(format, ...) \
|
||||
gfx_printf(&gfx_con, format __VA_OPT__(, ) __VA_ARGS__)
|
||||
gfx_printf(format __VA_OPT__(, ) __VA_ARGS__)
|
||||
#else
|
||||
#define EL_DEBUG(...) \
|
||||
do \
|
||||
@@ -76,7 +75,7 @@ typedef struct el_ctx
|
||||
// Section Header Str Table
|
||||
Elf_Shdr shstr;
|
||||
Elf_Shdr symtab;
|
||||
|
||||
|
||||
/* Offset of dynamic table (0 if not ET_DYN) */
|
||||
Elf_Off dynoff;
|
||||
/* Size of dynamic table (0 if not ET_DYN) */
|
||||
|
||||
@@ -8,11 +8,16 @@
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "../../../common/memory_map.h"
|
||||
|
||||
#include "diskio.h" /* FatFs lower layer API */
|
||||
#include "../../storage/nx_sd.h"
|
||||
#include "../../storage/sdmmc.h"
|
||||
|
||||
extern sdmmc_storage_t sd_storage;
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Get Drive Status */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
DSTATUS disk_status (
|
||||
BYTE pdrv /* Physical drive nmuber to identify the drive */
|
||||
)
|
||||
@@ -20,6 +25,9 @@ DSTATUS disk_status (
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Inidialize a Drive */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
DSTATUS disk_initialize (
|
||||
BYTE pdrv /* Physical drive nmuber to identify the drive */
|
||||
)
|
||||
@@ -27,6 +35,9 @@ DSTATUS disk_initialize (
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Read Sector(s) */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
DRESULT disk_read (
|
||||
BYTE pdrv, /* Physical drive nmuber to identify the drive */
|
||||
BYTE *buff, /* Data buffer to store read data */
|
||||
@@ -34,17 +45,12 @@ DRESULT disk_read (
|
||||
UINT count /* Number of sectors to read */
|
||||
)
|
||||
{
|
||||
if ((u32)buff >= 0x90000000)
|
||||
return sdmmc_storage_read(&sd_storage, sector, count, buff) ? RES_OK : RES_ERROR;
|
||||
u8 *buf = (u8 *)0x98000000; //TODO: define this somewhere.
|
||||
if (sdmmc_storage_read(&sd_storage, sector, count, buf))
|
||||
{
|
||||
memcpy(buff, buf, 512 * count);
|
||||
return RES_OK;
|
||||
}
|
||||
return RES_ERROR;
|
||||
return sdmmc_storage_read(&sd_storage, sector, count, buff) ? RES_OK : RES_ERROR;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Write Sector(s) */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
DRESULT disk_write (
|
||||
BYTE pdrv, /* Physical drive nmuber to identify the drive */
|
||||
const BYTE *buff, /* Data to be written */
|
||||
@@ -52,15 +58,12 @@ DRESULT disk_write (
|
||||
UINT count /* Number of sectors to write */
|
||||
)
|
||||
{
|
||||
if ((u32)buff >= 0x90000000)
|
||||
return sdmmc_storage_write(&sd_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR;
|
||||
u8 *buf = (u8 *)0x98000000; //TODO: define this somewhere.
|
||||
memcpy(buf, buff, 512 * count);
|
||||
if (sdmmc_storage_write(&sd_storage, sector, count, buf))
|
||||
return RES_OK;
|
||||
return RES_ERROR;
|
||||
return sdmmc_storage_write(&sd_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Miscellaneous Functions */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
DRESULT disk_ioctl (
|
||||
BYTE pdrv, /* Physical drive nmuber (0..) */
|
||||
BYTE cmd, /* Control code */
|
||||
|
||||
@@ -11,7 +11,6 @@ extern "C" {
|
||||
|
||||
#include "../../utils/types.h"
|
||||
|
||||
|
||||
/* Status of Disk Functions */
|
||||
typedef BYTE DSTATUS;
|
||||
|
||||
@@ -46,11 +45,12 @@ DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);
|
||||
/* Command code for disk_ioctrl fucntion */
|
||||
|
||||
/* Generic command (Used by FatFs) */
|
||||
#define CTRL_SYNC 0 /* Complete pending write process (needed at _FS_READONLY == 0) */
|
||||
#define GET_SECTOR_COUNT 1 /* Get media size (needed at _USE_MKFS == 1) */
|
||||
#define GET_SECTOR_SIZE 2 /* Get sector size (needed at _MAX_SS != _MIN_SS) */
|
||||
#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at _USE_MKFS == 1) */
|
||||
#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at _USE_TRIM == 1) */
|
||||
#define CTRL_SYNC 0 /* Complete pending write process (needed at FF_FS_READONLY == 0) */
|
||||
#define GET_SECTOR_COUNT 1 /* Get media size (needed at FF_USE_MKFS == 1) */
|
||||
#define SET_SECTOR_COUNT 1 /* Set media size (needed at FF_USE_MKFS == 1) */
|
||||
#define GET_SECTOR_SIZE 2 /* Get sector size (needed at FF_MAX_SS != FF_MIN_SS) */
|
||||
#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at FF_USE_MKFS == 1) */
|
||||
#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at FF_USE_TRIM == 1) */
|
||||
|
||||
/* Generic command (Not used by FatFs) */
|
||||
#define CTRL_POWER 5 /* Get/Set power status */
|
||||
|
||||
@@ -1,10 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2019 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*----------------------------------------------------------------------------/
|
||||
/ FatFs - Generic FAT Filesystem Module R0.13b /
|
||||
/ FatFs - Generic FAT Filesystem Module R0.13c (p4) /
|
||||
/-----------------------------------------------------------------------------/
|
||||
/
|
||||
/ Copyright (C) 2018, ChaN, all right reserved.
|
||||
/ Copyright (c) 2018 naehrwert
|
||||
/ Copyright (C) 2018 CTCaer
|
||||
/
|
||||
/ FatFs module is an open source software. Redistribution and use of FatFs in
|
||||
/ source and binary forms, with or without modification, are permitted provided
|
||||
@@ -23,11 +38,9 @@
|
||||
|
||||
#include "ff.h" /* Declarations of FatFs API */
|
||||
#include "diskio.h" /* Declarations of device I/O functions */
|
||||
|
||||
#include "../../gfx/gfx.h"
|
||||
extern gfx_ctxt_t gfx_ctxt;
|
||||
extern gfx_con_t gfx_con;
|
||||
#define EFSPRINTF(text, ...) print_error(); gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFFFF00, 0xFFFFFFFF);
|
||||
|
||||
#define EFSPRINTF(text, ...) print_error(); gfx_printf("%k"text"%k\n", 0xFFFFFF00, 0xFFFFFFFF);
|
||||
//#define EFSPRINTF(...)
|
||||
|
||||
/*--------------------------------------------------------------------------
|
||||
@@ -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).
|
||||
#endif
|
||||
|
||||
|
||||
/* Limits and boundaries */
|
||||
#define MAX_DIR 0x200000 /* Max size of FAT directory */
|
||||
#define MAX_DIR_EX 0x10000000 /* Max size of exFAT directory */
|
||||
#define MAX_FAT12 0xFF5 /* Max FAT12 clusters (differs from specs, but right for real DOS/Windows behavior) */
|
||||
#define MAX_FAT16 0xFFF5 /* Max FAT16 clusters (differs from specs, but right for real DOS/Windows behavior) */
|
||||
#define MAX_FAT32 0x0FFFFFF5 /* Max FAT32 clusters (not specified, practical limit) */
|
||||
#define MAX_EXFAT 0x7FFFFFFD /* Max exFAT clusters (differs from specs, implementation limit) */
|
||||
|
||||
|
||||
/* Character code support macros */
|
||||
#define IsUpper(c) ((c) >= 'A' && (c) <= 'Z')
|
||||
#define IsLower(c) ((c) >= 'a' && (c) <= 'z')
|
||||
@@ -50,18 +72,18 @@ extern gfx_con_t gfx_con;
|
||||
#define IsSurrogateL(c) ((c) >= 0xDC00 && (c) <= 0xDFFF)
|
||||
|
||||
|
||||
/* Additional file attribute bits for internal use */
|
||||
#define AM_VOL 0x08 /* Volume label */
|
||||
#define AM_LFN 0x0F /* LFN entry */
|
||||
#define AM_MASK 0x3F /* Mask of defined bits */
|
||||
|
||||
|
||||
/* Additional file access control and file status flags for internal use */
|
||||
#define FA_SEEKEND 0x20 /* Seek to end of the file on file open */
|
||||
#define FA_MODIFIED 0x40 /* File has been modified */
|
||||
#define FA_DIRTY 0x80 /* FIL.buf[] needs to be written-back */
|
||||
|
||||
|
||||
/* Additional file attribute bits for internal use */
|
||||
#define AM_VOL 0x08 /* Volume label */
|
||||
#define AM_LFN 0x0F /* LFN entry */
|
||||
#define AM_MASK 0x3F /* Mask of defined bits */
|
||||
|
||||
|
||||
/* Name status flags in fn[11] */
|
||||
#define NSFLAG 11 /* Index of the name status byte */
|
||||
#define NS_LOSS 0x01 /* Out of 8.3 format */
|
||||
@@ -74,13 +96,13 @@ extern gfx_con_t gfx_con;
|
||||
#define NS_NONAME 0x80 /* Not followed */
|
||||
|
||||
|
||||
/* Limits and boundaries */
|
||||
#define MAX_DIR 0x200000 /* Max size of FAT directory */
|
||||
#define MAX_DIR_EX 0x10000000 /* Max size of exFAT directory */
|
||||
#define MAX_FAT12 0xFF5 /* Max FAT12 clusters (differs from specs, but right for real DOS/Windows behavior) */
|
||||
#define MAX_FAT16 0xFFF5 /* Max FAT16 clusters (differs from specs, but right for real DOS/Windows behavior) */
|
||||
#define MAX_FAT32 0x0FFFFFF5 /* Max FAT32 clusters (not specified, practical limit) */
|
||||
#define MAX_EXFAT 0x7FFFFFFD /* Max exFAT clusters (differs from specs, implementation limit) */
|
||||
/* exFAT directory entry types */
|
||||
#define ET_BITMAP 0x81 /* Allocation bitmap */
|
||||
#define ET_UPCASE 0x82 /* Up-case table */
|
||||
#define ET_VLABEL 0x83 /* Volume label */
|
||||
#define ET_FILEDIR 0x85 /* File and directory */
|
||||
#define ET_STREAM 0xC0 /* Stream extension */
|
||||
#define ET_FILENAME 0xC1 /* Name extension */
|
||||
|
||||
|
||||
/* FatFs refers the FAT structure as simple byte array instead of structure member
|
||||
@@ -528,6 +550,7 @@ static WCHAR LfnBuf[FF_MAX_LFN + 1]; /* LFN working buffer */
|
||||
#define CODEPAGE CodePage
|
||||
static WORD CodePage; /* Current code page */
|
||||
static const BYTE *ExCvt, *DbcTbl; /* Pointer to current SBCS up-case table and DBCS code range table below */
|
||||
|
||||
static const BYTE Ct437[] = TBL_CT437;
|
||||
static const BYTE Ct720[] = TBL_CT720;
|
||||
static const BYTE Ct737[] = TBL_CT737;
|
||||
@@ -575,7 +598,7 @@ static const BYTE DbcTbl[] = MKCVTBL(TBL_DC, FF_CODE_PAGE);
|
||||
|
||||
void print_error()
|
||||
{
|
||||
gfx_printf(&gfx_con, "\n\n\n%k[FatFS] Error: %k", 0xFFFFFF00, 0xFFFFFFFF);
|
||||
gfx_printf("\n\n\n%k[FatFS] Error: %k", 0xFFFFFF00, 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
|
||||
@@ -1109,7 +1132,7 @@ static FRESULT sync_fs ( /* Returns FR_OK or FR_DISK_ERR */
|
||||
if (res == FR_OK) {
|
||||
if (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) { /* FAT32: Update FSInfo sector if needed */
|
||||
/* Create FSInfo structure */
|
||||
mem_set(fs->win, 0, SS(fs));
|
||||
mem_set(fs->win, 0, sizeof fs->win);
|
||||
st_word(fs->win + BS_55AA, 0xAA55);
|
||||
st_dword(fs->win + FSI_LeadSig, 0x41615252);
|
||||
st_dword(fs->win + FSI_StrucSig, 0x61417272);
|
||||
@@ -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;
|
||||
scl = val = clst; ctr = 0;
|
||||
for (;;) {
|
||||
if (move_window(fs, fs->database + val / 8 / SS(fs)) != FR_OK) return 0xFFFFFFFF; /* (assuming bitmap is located top of the cluster heap) */
|
||||
if (move_window(fs, fs->bitbase + val / 8 / SS(fs)) != FR_OK) return 0xFFFFFFFF;
|
||||
i = val / 8 % SS(fs); bm = 1 << (val % 8);
|
||||
do {
|
||||
do {
|
||||
@@ -1347,9 +1370,9 @@ static FRESULT change_bitmap (
|
||||
|
||||
|
||||
clst -= 2; /* The first bit corresponds to cluster #2 */
|
||||
sect = fs->database + clst / 8 / SS(fs); /* Sector address (assuming bitmap is located top of the cluster heap) */
|
||||
i = clst / 8 % SS(fs); /* Byte offset in the sector */
|
||||
bm = 1 << (clst % 8); /* Bit mask in the byte */
|
||||
sect = fs->bitbase + clst / 8 / SS(fs); /* Sector address */
|
||||
i = clst / 8 % SS(fs); /* Byte offset in the sector */
|
||||
bm = 1 << (clst % 8); /* Bit mask in the byte */
|
||||
for (;;) {
|
||||
if (move_window(fs, sect++) != FR_OK) return FR_DISK_ERR;
|
||||
do {
|
||||
@@ -1422,7 +1445,7 @@ static FRESULT fill_last_frag (
|
||||
static FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */
|
||||
FFOBJID* obj, /* Corresponding object */
|
||||
DWORD clst, /* Cluster to remove a chain from */
|
||||
DWORD pclst /* Previous cluster of clst (0:entire chain) */
|
||||
DWORD pclst /* Previous cluster of clst (0 if entire chain) */
|
||||
)
|
||||
{
|
||||
FRESULT res = FR_OK;
|
||||
@@ -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 */
|
||||
sect = clst2sect(fs, clst); /* Top of the cluster */
|
||||
fs->winsect = sect; /* Set window to top of the cluster */
|
||||
mem_set(fs->win, 0, SS(fs)); /* Clear window buffer */
|
||||
mem_set(fs->win, 0, sizeof fs->win); /* Clear window buffer */
|
||||
#if FF_USE_LFN == 3 /* Quick table clear by using multi-secter write */
|
||||
/* Allocate a temporary buffer */
|
||||
for (szb = ((DWORD)fs->csize * SS(fs) >= MAX_MALLOC) ? MAX_MALLOC : fs->csize * SS(fs), ibuf = 0; szb > SS(fs) && (ibuf = ff_memalloc(szb)) == 0; szb /= 2) ;
|
||||
@@ -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 */
|
||||
uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */
|
||||
if (wc != 0) {
|
||||
if (i >= FF_MAX_LFN || ff_wtoupper(uc) != ff_wtoupper(lfnbuf[i++])) { /* Compare it */
|
||||
if (i >= FF_MAX_LFN + 1 || ff_wtoupper(uc) != ff_wtoupper(lfnbuf[i++])) { /* Compare it */
|
||||
return 0; /* Not matched */
|
||||
}
|
||||
wc = uc;
|
||||
@@ -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 */
|
||||
uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */
|
||||
if (wc != 0) {
|
||||
if (i >= FF_MAX_LFN) return 0; /* Buffer overflow? */
|
||||
if (i >= FF_MAX_LFN + 1) return 0; /* Buffer overflow? */
|
||||
lfnbuf[i++] = wc = uc; /* Store it */
|
||||
} else {
|
||||
if (uc != 0xFFFF) return 0; /* Check filler */
|
||||
}
|
||||
}
|
||||
|
||||
if (dir[LDIR_Ord] & LLEF) { /* Put terminator if it is the last LFN part */
|
||||
if (i >= FF_MAX_LFN) return 0; /* Buffer overflow? */
|
||||
if (dir[LDIR_Ord] & LLEF && wc != 0) { /* Put terminator if it is the last LFN part and not terminated */
|
||||
if (i >= FF_MAX_LFN + 1) return 0; /* Buffer overflow? */
|
||||
lfnbuf[i] = 0;
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
/* Load 85 entry */
|
||||
/* Load file-directory entry */
|
||||
res = move_window(dp->obj.fs, dp->sect);
|
||||
if (res != FR_OK) return res;
|
||||
if (dp->dir[XDIR_Type] != 0x85) return FR_INT_ERR; /* Invalid order */
|
||||
if (dp->dir[XDIR_Type] != ET_FILEDIR) return FR_INT_ERR; /* Invalid order */
|
||||
mem_cpy(dirb + 0 * SZDIRE, dp->dir, SZDIRE);
|
||||
sz_ent = (dirb[XDIR_NumSec] + 1) * SZDIRE;
|
||||
if (sz_ent < 3 * SZDIRE || sz_ent > 19 * SZDIRE) return FR_INT_ERR;
|
||||
|
||||
/* Load C0 entry */
|
||||
/* Load stream-extension entry */
|
||||
res = dir_next(dp, 0);
|
||||
if (res == FR_NO_FILE) res = FR_INT_ERR; /* It cannot be */
|
||||
if (res != FR_OK) return res;
|
||||
res = move_window(dp->obj.fs, dp->sect);
|
||||
if (res != FR_OK) return res;
|
||||
if (dp->dir[XDIR_Type] != 0xC0) return FR_INT_ERR; /* Invalid order */
|
||||
if (dp->dir[XDIR_Type] != ET_STREAM) return FR_INT_ERR; /* Invalid order */
|
||||
mem_cpy(dirb + 1 * SZDIRE, dp->dir, SZDIRE);
|
||||
if (MAXDIRB(dirb[XDIR_NumName]) > sz_ent) return FR_INT_ERR;
|
||||
|
||||
/* Load C1 entries */
|
||||
i = 2 * SZDIRE; /* C1 offset to load */
|
||||
/* Load file-name entries */
|
||||
i = 2 * SZDIRE; /* Name offset to load */
|
||||
do {
|
||||
res = dir_next(dp, 0);
|
||||
if (res == FR_NO_FILE) res = FR_INT_ERR; /* It cannot be */
|
||||
if (res != FR_OK) return res;
|
||||
res = move_window(dp->obj.fs, dp->sect);
|
||||
if (res != FR_OK) return res;
|
||||
if (dp->dir[XDIR_Type] != 0xC1) return FR_INT_ERR; /* Invalid order */
|
||||
if (dp->dir[XDIR_Type] != ET_FILENAME) return FR_INT_ERR; /* Invalid order */
|
||||
if (i < MAXDIRB(FF_MAX_LFN)) mem_cpy(dirb + i, dp->dir, SZDIRE);
|
||||
} while ((i += SZDIRE) < sz_ent);
|
||||
|
||||
@@ -2301,16 +2324,16 @@ static void create_xdir (
|
||||
WCHAR wc;
|
||||
|
||||
|
||||
/* Create 85,C0 entry */
|
||||
/* Create file-directory and stream-extension entry */
|
||||
mem_set(dirb, 0, 2 * SZDIRE);
|
||||
dirb[0 * SZDIRE + XDIR_Type] = 0x85; /* 85 entry */
|
||||
dirb[1 * SZDIRE + XDIR_Type] = 0xC0; /* C0 entry */
|
||||
dirb[0 * SZDIRE + XDIR_Type] = ET_FILEDIR;
|
||||
dirb[1 * SZDIRE + XDIR_Type] = ET_STREAM;
|
||||
|
||||
/* Create C1 entries */
|
||||
i = SZDIRE * 2; /* Top of C1 entries */
|
||||
/* Create file-name entries */
|
||||
i = SZDIRE * 2; /* Top of file_name entries */
|
||||
nlen = nc1 = 0; wc = 1;
|
||||
do {
|
||||
dirb[i++] = 0xC1; dirb[i++] = 0; /* Entry type C1 */
|
||||
dirb[i++] = ET_FILENAME; dirb[i++] = 0;
|
||||
do { /* Fill name field */
|
||||
if (wc != 0 && (wc = lfn[nlen]) != 0) nlen++; /* Get a character if exist */
|
||||
st_word(dirb + i, wc); /* Store it */
|
||||
@@ -2334,8 +2357,8 @@ static void create_xdir (
|
||||
/* Read an object from the directory */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
#define dir_read_file(dp) dir_read(dp, 0)
|
||||
#define dir_read_label(dp) dir_read(dp, 1)
|
||||
#define DIR_READ_FILE(dp) dir_read(dp, 0)
|
||||
#define DIR_READ_LABEL(dp) dir_read(dp, 1)
|
||||
|
||||
static FRESULT dir_read (
|
||||
DIR* dp, /* Pointer to the directory object */
|
||||
@@ -2344,7 +2367,7 @@ static FRESULT dir_read (
|
||||
{
|
||||
FRESULT res = FR_NO_FILE;
|
||||
FATFS *fs = dp->obj.fs;
|
||||
BYTE a, c;
|
||||
BYTE attr, b;
|
||||
#if FF_USE_LFN
|
||||
BYTE ord = 0xFF, sum = 0xFF;
|
||||
#endif
|
||||
@@ -2352,16 +2375,16 @@ static FRESULT dir_read (
|
||||
while (dp->sect) {
|
||||
res = move_window(fs, dp->sect);
|
||||
if (res != FR_OK) break;
|
||||
c = dp->dir[DIR_Name]; /* Test for the entry type */
|
||||
if (c == 0) {
|
||||
b = dp->dir[DIR_Name]; /* Test for the entry type */
|
||||
if (b == 0) {
|
||||
res = FR_NO_FILE; break; /* Reached to end of the directory */
|
||||
}
|
||||
#if FF_FS_EXFAT
|
||||
if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */
|
||||
if (FF_USE_LABEL && vol) {
|
||||
if (c == 0x83) break; /* Volume label entry? */
|
||||
if (b == ET_VLABEL) break; /* Volume label entry? */
|
||||
} else {
|
||||
if (c == 0x85) { /* Start of the file entry block? */
|
||||
if (b == ET_FILEDIR) { /* Start of the file entry block? */
|
||||
dp->blk_ofs = dp->dptr; /* Get location of the block */
|
||||
res = load_xdir(dp); /* Load the entry block */
|
||||
if (res == FR_OK) {
|
||||
@@ -2373,19 +2396,19 @@ static FRESULT dir_read (
|
||||
} else
|
||||
#endif
|
||||
{ /* On the FAT/FAT32 volume */
|
||||
dp->obj.attr = a = dp->dir[DIR_Attr] & AM_MASK; /* Get attribute */
|
||||
dp->obj.attr = attr = dp->dir[DIR_Attr] & AM_MASK; /* Get attribute */
|
||||
#if FF_USE_LFN /* LFN configuration */
|
||||
if (c == DDEM || c == '.' || (int)((a & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */
|
||||
if (b == DDEM || b == '.' || (int)((attr & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */
|
||||
ord = 0xFF;
|
||||
} else {
|
||||
if (a == AM_LFN) { /* An LFN entry is found */
|
||||
if (c & LLEF) { /* Is it start of an LFN sequence? */
|
||||
if (attr == AM_LFN) { /* An LFN entry is found */
|
||||
if (b & LLEF) { /* Is it start of an LFN sequence? */
|
||||
sum = dp->dir[LDIR_Chksum];
|
||||
c &= (BYTE)~LLEF; ord = c;
|
||||
b &= (BYTE)~LLEF; ord = b;
|
||||
dp->blk_ofs = dp->dptr;
|
||||
}
|
||||
/* Check LFN validity and capture it */
|
||||
ord = (c == ord && sum == dp->dir[LDIR_Chksum] && pick_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF;
|
||||
ord = (b == ord && sum == dp->dir[LDIR_Chksum] && pick_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF;
|
||||
} else { /* An SFN entry is found */
|
||||
if (ord != 0 || sum != sum_sfn(dp->dir)) { /* Is there a valid LFN? */
|
||||
dp->blk_ofs = 0xFFFFFFFF; /* It has no LFN. */
|
||||
@@ -2394,7 +2417,7 @@ static FRESULT dir_read (
|
||||
}
|
||||
}
|
||||
#else /* Non LFN configuration */
|
||||
if (c != DDEM && c != '.' && a != AM_LFN && (int)((a & ~AM_ARC) == AM_VOL) == vol) { /* Is it a valid entry? */
|
||||
if (b != DDEM && b != '.' && attr != AM_LFN && (int)((attr & ~AM_ARC) == AM_VOL) == vol) { /* Is it a valid entry? */
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
@@ -2434,7 +2457,7 @@ static FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */
|
||||
UINT di, ni;
|
||||
WORD hash = xname_sum(fs->lfnbuf); /* Hash value of the name to find */
|
||||
|
||||
while ((res = dir_read_file(dp)) == FR_OK) { /* Read an item */
|
||||
while ((res = DIR_READ_FILE(dp)) == FR_OK) { /* Read an item */
|
||||
#if FF_MAX_LFN < 255
|
||||
if (fs->dirbuf[XDIR_NumName] > FF_MAX_LFN) continue; /* Skip comparison if inaccessible object name */
|
||||
#endif
|
||||
@@ -2513,17 +2536,17 @@ static FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too
|
||||
#if FF_FS_EXFAT
|
||||
if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */
|
||||
nent = (nlen + 14) / 15 + 2; /* Number of entries to allocate (85+C0+C1s) */
|
||||
res = dir_alloc(dp, nent); /* Allocate entries */
|
||||
res = dir_alloc(dp, nent); /* Allocate directory entries */
|
||||
if (res != FR_OK) return res;
|
||||
dp->blk_ofs = dp->dptr - SZDIRE * (nent - 1); /* Set the allocated entry block offset */
|
||||
|
||||
if (dp->obj.stat & 4) { /* Has the directory been stretched? */
|
||||
if (dp->obj.stat & 4) { /* Has the directory been stretched by new allocation? */
|
||||
dp->obj.stat &= ~4;
|
||||
res = fill_first_frag(&dp->obj); /* Fill the first fragment on the FAT if needed */
|
||||
if (res != FR_OK) return res;
|
||||
res = fill_last_frag(&dp->obj, dp->clust, 0xFFFFFFFF); /* Fill the last fragment on the FAT if needed */
|
||||
if (res != FR_OK) return res;
|
||||
if (dp->obj.sclust != 0) { /* Is it a sub directory? */
|
||||
if (dp->obj.sclust != 0) { /* Is it a sub-directory? */
|
||||
DIR dj;
|
||||
|
||||
res = load_obj_xdir(&dj, &dp->obj); /* Load the object status */
|
||||
@@ -2655,6 +2678,7 @@ static void get_fileinfo (
|
||||
{
|
||||
UINT si, di;
|
||||
#if FF_USE_LFN
|
||||
BYTE lcf;
|
||||
WCHAR wc, hs;
|
||||
FATFS *fs = dp->obj.fs;
|
||||
#else
|
||||
@@ -2715,9 +2739,10 @@ static void get_fileinfo (
|
||||
if (di == 0) { /* If LFN and SFN both are invalid, this object is inaccesible */
|
||||
fno->fname[di++] = '?';
|
||||
} else {
|
||||
for (si = di = 0; fno->altname[si]; si++, di++) { /* Copy altname[] to fname[] with case information */
|
||||
for (si = di = 0, lcf = NS_BODY; fno->altname[si]; si++, di++) { /* Copy altname[] to fname[] with case information */
|
||||
wc = (WCHAR)fno->altname[si];
|
||||
if (IsUpper(wc) && (dp->dir[DIR_NTres] & ((si >= 9) ? NS_EXT : NS_BODY))) wc += 0x20;
|
||||
if (wc == '.') lcf = NS_EXT;
|
||||
if (IsUpper(wc) && (dp->dir[DIR_NTres] & lcf)) wc += 0x20;
|
||||
fno->fname[di] = (TCHAR)wc;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
#endif
|
||||
|
||||
/* Find an FAT partition on the drive. Supports only generic partitioning rules, FDISK and SFD. */
|
||||
/* Find an FAT partition on the drive. Supports only generic partitioning rules, FDISK (MBR) and SFD (w/o partition). */
|
||||
bsect = 0;
|
||||
fmt = check_fs(fs, bsect); /* Load sector 0 and check if it is an FAT-VBR as SFD */
|
||||
if (fmt == 2 || (fmt < 2 && LD2PT(vol) != 0)) { /* Not an FAT-VBR or forced partition number */
|
||||
@@ -3303,13 +3328,12 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */
|
||||
#if FF_FS_EXFAT
|
||||
if (fmt == 1) {
|
||||
QWORD maxlba;
|
||||
DWORD so, cv, bcl;
|
||||
|
||||
for (i = BPB_ZeroedEx; i < BPB_ZeroedEx + 53 && fs->win[i] == 0; i++) ; /* Check zero filler */
|
||||
if (i < BPB_ZeroedEx + 53)
|
||||
return FR_NO_FILESYSTEM;
|
||||
if (i < BPB_ZeroedEx + 53) return FR_NO_FILESYSTEM;
|
||||
|
||||
if (ld_word(fs->win + BPB_FSVerEx) != 0x100)
|
||||
return FR_NO_FILESYSTEM; /* Check exFAT version (must be version 1.0) */
|
||||
if (ld_word(fs->win + BPB_FSVerEx) != 0x100) return FR_NO_FILESYSTEM; /* Check exFAT version (must be version 1.0) */
|
||||
|
||||
if (1 << fs->win[BPB_BytsPerSecEx] != SS(fs)) { /* (BPB_BytsPerSecEx must be equal to the physical sector size) */
|
||||
EFSPRINTF("EXSPS");
|
||||
@@ -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 */
|
||||
if (maxlba >= 0x100000000)
|
||||
return FR_NO_FILESYSTEM; /* (It cannot be handled in 32-bit LBA) */
|
||||
if (maxlba >= 0x100000000) return FR_NO_FILESYSTEM; /* (It cannot be handled in 32-bit LBA) */
|
||||
|
||||
fs->fsize = ld_dword(fs->win + BPB_FatSzEx); /* Number of sectors per FAT */
|
||||
|
||||
@@ -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 */
|
||||
if (fs->csize == 0) {
|
||||
return FR_NO_FILESYSTEM; /* (Must be 1..32768) */
|
||||
}
|
||||
if (fs->csize == 0) return FR_NO_FILESYSTEM; /* (Must be 1..32768) */
|
||||
|
||||
nclst = ld_dword(fs->win + BPB_NumClusEx); /* Number of clusters */
|
||||
if (nclst > MAX_EXFAT)
|
||||
return FR_NO_FILESYSTEM; /* (Too many clusters) */
|
||||
if (nclst > MAX_EXFAT) return FR_NO_FILESYSTEM; /* (Too many clusters) */
|
||||
fs->n_fatent = nclst + 2;
|
||||
|
||||
/* Boundaries and Limits */
|
||||
fs->volbase = bsect;
|
||||
fs->database = bsect + ld_dword(fs->win + BPB_DataOfsEx);
|
||||
fs->fatbase = bsect + ld_dword(fs->win + BPB_FatOfsEx);
|
||||
if (maxlba < (QWORD)fs->database + nclst * fs->csize)
|
||||
return FR_NO_FILESYSTEM; /* (Volume size must not be smaller than the size required) */
|
||||
if (maxlba < (QWORD)fs->database + nclst * fs->csize) return FR_NO_FILESYSTEM; /* (Volume size must not be smaller than the size requiered) */
|
||||
fs->dirbase = ld_dword(fs->win + BPB_RootClusEx);
|
||||
|
||||
/* Check if bitmap location is in assumption (at the first cluster) */
|
||||
if (move_window(fs, clst2sect(fs, fs->dirbase)) != FR_OK) {
|
||||
EFSPRINTF("EXBM1C");
|
||||
return FR_DISK_ERR;
|
||||
/* Get bitmap location and check if it is contiguous (implementation assumption) */
|
||||
so = i = 0;
|
||||
for (;;) { /* Find the bitmap entry in the root directory (in only first cluster) */
|
||||
if (i == 0) {
|
||||
if (so >= fs->csize) return FR_NO_FILESYSTEM; /* Not found? */
|
||||
if (move_window(fs, clst2sect(fs, fs->dirbase) + so) != FR_OK) {
|
||||
EFSPRINTF("EXBM1C");
|
||||
return FR_DISK_ERR;
|
||||
}
|
||||
so++;
|
||||
}
|
||||
if (fs->win[i] == ET_BITMAP) break; /* Is it a bitmap entry? */
|
||||
i = (i + SZDIRE) % SS(fs); /* Next entry */
|
||||
}
|
||||
for (i = 0; i < SS(fs); i += SZDIRE) {
|
||||
if (fs->win[i] == 0x81 && ld_dword(fs->win + i + 20) == 2) break; /* 81 entry with cluster #2? */
|
||||
}
|
||||
if (i == SS(fs)) {
|
||||
bcl = ld_dword(fs->win + i + 20); /* Bitmap cluster */
|
||||
if (bcl < 2 || bcl >= fs->n_fatent) {
|
||||
EFSPRINTF("EXBMM");
|
||||
return FR_NO_FILESYSTEM;
|
||||
}
|
||||
fs->bitbase = fs->database + fs->csize * (bcl - 2); /* Bitmap sector */
|
||||
for (;;) { /* Check if bitmap is contiguous */
|
||||
if (move_window(fs, fs->fatbase + bcl / (SS(fs) / 4)) != FR_OK) return FR_DISK_ERR;
|
||||
cv = ld_dword(fs->win + bcl % (SS(fs) / 4) * 4);
|
||||
if (cv == 0xFFFFFFFF) break; /* Last link? */
|
||||
if (cv != ++bcl) {
|
||||
EFSPRINTF("EXBMM");
|
||||
return FR_NO_FILESYSTEM; /* Fragmented? */
|
||||
}
|
||||
}
|
||||
|
||||
#if !FF_FS_READONLY
|
||||
fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Initialize cluster allocation information */
|
||||
#endif
|
||||
@@ -3375,38 +3412,31 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */
|
||||
fs->fsize = fasize;
|
||||
|
||||
fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FATs */
|
||||
if (fs->n_fats != 1 && fs->n_fats != 2)
|
||||
return FR_NO_FILESYSTEM; /* (Must be 1 or 2) */
|
||||
if (fs->n_fats != 1 && fs->n_fats != 2) return FR_NO_FILESYSTEM; /* (Must be 1 or 2) */
|
||||
fasize *= fs->n_fats; /* Number of sectors for FAT area */
|
||||
|
||||
fs->csize = fs->win[BPB_SecPerClus]; /* Cluster size */
|
||||
if (fs->csize == 0 || (fs->csize & (fs->csize - 1)))
|
||||
return FR_NO_FILESYSTEM; /* (Must be power of 2) */
|
||||
if (fs->csize == 0 || (fs->csize & (fs->csize - 1))) return FR_NO_FILESYSTEM; /* (Must be power of 2) */
|
||||
|
||||
fs->n_rootdir = ld_word(fs->win + BPB_RootEntCnt); /* Number of root directory entries */
|
||||
if (fs->n_rootdir % (SS(fs) / SZDIRE))
|
||||
return FR_NO_FILESYSTEM; /* (Must be sector aligned) */
|
||||
if (fs->n_rootdir % (SS(fs) / SZDIRE)) return FR_NO_FILESYSTEM; /* (Must be sector aligned) */
|
||||
|
||||
tsect = ld_word(fs->win + BPB_TotSec16); /* Number of sectors on the volume */
|
||||
if (tsect == 0) tsect = ld_dword(fs->win + BPB_TotSec32);
|
||||
|
||||
nrsv = ld_word(fs->win + BPB_RsvdSecCnt); /* Number of reserved sectors */
|
||||
if (nrsv == 0)
|
||||
return FR_NO_FILESYSTEM; /* (Must not be 0) */
|
||||
if (nrsv == 0) return FR_NO_FILESYSTEM; /* (Must not be 0) */
|
||||
|
||||
/* Determine the FAT sub type */
|
||||
sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZDIRE); /* RSV + FAT + DIR */
|
||||
if (tsect < sysect)
|
||||
return FR_NO_FILESYSTEM; /* (Invalid volume size) */
|
||||
if (tsect < sysect) return FR_NO_FILESYSTEM; /* (Invalid volume size) */
|
||||
nclst = (tsect - sysect) / fs->csize; /* Number of clusters */
|
||||
if (nclst == 0)
|
||||
return FR_NO_FILESYSTEM; /* (Invalid volume size) */
|
||||
if (nclst == 0) return FR_NO_FILESYSTEM; /* (Invalid volume size) */
|
||||
fmt = 0;
|
||||
if (nclst <= MAX_FAT32) fmt = FS_FAT32;
|
||||
if (nclst <= MAX_FAT16) fmt = FS_FAT16;
|
||||
if (nclst <= MAX_FAT12) fmt = FS_FAT12;
|
||||
if (fmt == 0)
|
||||
return FR_NO_FILESYSTEM;
|
||||
if (fmt == 0) return FR_NO_FILESYSTEM;
|
||||
|
||||
/* Boundaries and Limits */
|
||||
fs->n_fatent = nclst + 2; /* Number of FAT entries */
|
||||
@@ -3414,21 +3444,17 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */
|
||||
fs->fatbase = bsect + nrsv; /* FAT start sector */
|
||||
fs->database = bsect + sysect; /* Data start sector */
|
||||
if (fmt == FS_FAT32) {
|
||||
if (ld_word(fs->win + BPB_FSVer32) != 0)
|
||||
return FR_NO_FILESYSTEM; /* (Must be FAT32 revision 0.0) */
|
||||
if (fs->n_rootdir != 0)
|
||||
return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */
|
||||
if (ld_word(fs->win + BPB_FSVer32) != 0) return FR_NO_FILESYSTEM; /* (Must be FAT32 revision 0.0) */
|
||||
if (fs->n_rootdir != 0) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */
|
||||
fs->dirbase = ld_dword(fs->win + BPB_RootClus32); /* Root directory start cluster */
|
||||
szbfat = fs->n_fatent * 4; /* (Needed FAT size) */
|
||||
} else {
|
||||
if (fs->n_rootdir == 0)
|
||||
return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must not be 0) */
|
||||
if (fs->n_rootdir == 0) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must not be 0) */
|
||||
fs->dirbase = fs->fatbase + fasize; /* Root directory start sector */
|
||||
szbfat = (fmt == FS_FAT16) ? /* (Needed FAT size) */
|
||||
fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1);
|
||||
}
|
||||
if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs))
|
||||
return FR_NO_FILESYSTEM; /* (BPB_FATSz must not be less than the size needed) */
|
||||
if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) return FR_NO_FILESYSTEM; /* (BPB_FATSz must not be less than the size needed) */
|
||||
|
||||
#if !FF_FS_READONLY
|
||||
/* Get FSInfo if available */
|
||||
@@ -3724,7 +3750,7 @@ FRESULT f_open (
|
||||
fp->fptr = 0; /* Set file pointer top of the file */
|
||||
#if !FF_FS_READONLY
|
||||
#if !FF_FS_TINY
|
||||
mem_set(fp->buf, 0, FF_MAX_SS); /* Clear sector buffer */
|
||||
mem_set(fp->buf, 0, sizeof fp->buf); /* Clear sector buffer */
|
||||
#endif
|
||||
if ((mode & FA_SEEKEND) && fp->obj.objsize > 0) { /* Seek to end of file if FA_OPEN_APPEND is specified */
|
||||
fp->fptr = fp->obj.objsize; /* Offset to seek */
|
||||
@@ -3779,17 +3805,16 @@ FRESULT f_read (
|
||||
UINT rcnt, cc, csect;
|
||||
BYTE *rbuff = (BYTE*)buff;
|
||||
|
||||
|
||||
UINT br_tmp;
|
||||
if (!br)
|
||||
br = &br_tmp;
|
||||
*br = 0; /* Clear read byte counter */
|
||||
res = validate(&fp->obj, &fs); /* Check validity of the file object */
|
||||
if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) {
|
||||
EFSPRINTF("FOV");
|
||||
LEAVE_FF(fs, res); /* Check validity */
|
||||
}
|
||||
if (!(fp->flag & FA_READ)) {
|
||||
EFSPRINTF("NOACCESS");
|
||||
LEAVE_FF(fs, FR_DENIED); /* Check access mode */
|
||||
}
|
||||
if (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */
|
||||
remain = fp->obj.objsize - fp->fptr;
|
||||
if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */
|
||||
|
||||
@@ -3821,9 +3846,7 @@ FRESULT f_read (
|
||||
fp->clust = clst; /* Update current cluster */
|
||||
}
|
||||
sect = clst2sect(fs, fp->clust); /* Get current sector */
|
||||
if (sect == 0) {
|
||||
ABORT(fs, FR_INT_ERR);
|
||||
}
|
||||
if (sect == 0) ABORT(fs, FR_INT_ERR);
|
||||
sect += csect;
|
||||
cc = btr / SS(fs); /* When remaining bytes >= sector size, */
|
||||
if (cc > 0) { /* Read maximum contiguous sectors directly */
|
||||
@@ -3901,17 +3924,16 @@ FRESULT f_write (
|
||||
UINT wcnt, cc, csect;
|
||||
const BYTE *wbuff = (const BYTE*)buff;
|
||||
|
||||
|
||||
UINT bw_tmp;
|
||||
if (!bw)
|
||||
bw = &bw_tmp;
|
||||
*bw = 0; /* Clear write byte counter */
|
||||
res = validate(&fp->obj, &fs); /* Check validity of the file object */
|
||||
if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) {
|
||||
EFSPRINTF("FOV");
|
||||
LEAVE_FF(fs, res); /* Check validity */
|
||||
}
|
||||
if (!(fp->flag & FA_WRITE)) {
|
||||
EFSPRINTF("NOACCESS");
|
||||
LEAVE_FF(fs, FR_DENIED); /* Check access mode */
|
||||
}
|
||||
if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */
|
||||
|
||||
/* Check fptr wrap-around (file size cannot reach 4 GiB at FAT volume) */
|
||||
if ((!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) && (DWORD)(fp->fptr + btw) < (DWORD)fp->fptr) {
|
||||
@@ -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 */
|
||||
#else
|
||||
if (fp->flag & FA_DIRTY) { /* Write-back sector cache */
|
||||
if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK)
|
||||
ABORT(fs, FR_DISK_ERR);
|
||||
if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);
|
||||
fp->flag &= (BYTE)~FA_DIRTY;
|
||||
}
|
||||
#endif
|
||||
sect = clst2sect(fs, fp->clust); /* Get current sector */
|
||||
if (sect == 0) {
|
||||
ABORT(fs, FR_INT_ERR);
|
||||
}
|
||||
if (sect == 0) ABORT(fs, FR_INT_ERR);
|
||||
sect += csect;
|
||||
cc = btw / SS(fs); /* When remaining bytes >= sector size, */
|
||||
if (cc > 0) { /* Write maximum contiguous sectors directly */
|
||||
@@ -4000,8 +4019,9 @@ FRESULT f_write (
|
||||
#else
|
||||
if (fp->sect != sect && /* Fill sector cache with file data */
|
||||
fp->fptr < fp->obj.objsize &&
|
||||
disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK)
|
||||
disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) {
|
||||
ABORT(fs, FR_DISK_ERR);
|
||||
}
|
||||
#endif
|
||||
fp->sect = sect;
|
||||
}
|
||||
@@ -4238,15 +4258,16 @@ FRESULT f_getcwd (
|
||||
TCHAR *tp = buff;
|
||||
#if FF_VOLUMES >= 2
|
||||
UINT vl;
|
||||
#endif
|
||||
#if FF_STR_VOLUME_ID
|
||||
const char *vp;
|
||||
#endif
|
||||
#endif
|
||||
FILINFO fno;
|
||||
DEF_NAMBUF
|
||||
|
||||
|
||||
/* Get logical drive */
|
||||
buff[0] = 0; /* Set null string to get current volume */
|
||||
res = find_volume((const TCHAR**)&buff, &fs, 0); /* Get current volume */
|
||||
if (res == FR_OK) {
|
||||
dj.obj.fs = fs;
|
||||
@@ -4265,7 +4286,7 @@ FRESULT f_getcwd (
|
||||
res = dir_sdi(&dj, 0);
|
||||
if (res != FR_OK) break;
|
||||
do { /* Find the entry links to the child directory */
|
||||
res = dir_read_file(&dj);
|
||||
res = DIR_READ_FILE(&dj);
|
||||
if (res != FR_OK) break;
|
||||
if (ccl == ld_clust(fs, dj.dir)) break; /* Found the entry */
|
||||
res = dir_next(&dj, 0);
|
||||
@@ -4597,7 +4618,7 @@ FRESULT f_readdir (
|
||||
res = dir_sdi(dp, 0); /* Rewind the directory object */
|
||||
} else {
|
||||
INIT_NAMBUF(fs);
|
||||
res = dir_read_file(dp); /* Read an item */
|
||||
res = DIR_READ_FILE(dp); /* Read an item */
|
||||
if (res == FR_NO_FILE) res = FR_OK; /* Ignore end of directory */
|
||||
if (res == FR_OK) { /* A valid entry is found */
|
||||
get_fileinfo(dp, fno); /* Get the object information */
|
||||
@@ -4720,7 +4741,7 @@ FRESULT f_getfree (
|
||||
/* Get logical drive */
|
||||
res = find_volume(&path, &fs, 0);
|
||||
if (res == FR_OK) {
|
||||
*fatfs = fs; /* Return ptr to the fs object */
|
||||
if (fatfs) *fatfs = fs; /* Return ptr to the fs object */
|
||||
/* If free_clst is valid, return it without full FAT scan */
|
||||
if (fs->free_clst <= fs->n_fatent - 2) {
|
||||
*nclst = fs->free_clst;
|
||||
@@ -4742,7 +4763,7 @@ FRESULT f_getfree (
|
||||
UINT b;
|
||||
|
||||
clst = fs->n_fatent - 2; /* Number of clusters */
|
||||
sect = fs->database; /* Assuming bitmap starts at cluster 2 */
|
||||
sect = fs->bitbase; /* Bitmap sector */
|
||||
i = 0; /* Offset in the sector */
|
||||
do { /* Counts numbuer of bits with zero in the bitmap */
|
||||
if (i == 0) {
|
||||
@@ -4905,7 +4926,7 @@ FRESULT f_unlink (
|
||||
#endif
|
||||
res = dir_sdi(&sdj, 0);
|
||||
if (res == FR_OK) {
|
||||
res = dir_read_file(&sdj); /* Test if the directory is empty */
|
||||
res = DIR_READ_FILE(&sdj); /* Test if the directory is empty */
|
||||
if (res == FR_OK) res = FR_DENIED; /* Not empty? */
|
||||
if (res == FR_NO_FILE) res = FR_OK; /* Empty? */
|
||||
}
|
||||
@@ -4945,47 +4966,43 @@ FRESULT f_mkdir (
|
||||
DIR dj;
|
||||
FFOBJID sobj;
|
||||
FATFS *fs;
|
||||
BYTE *dir;
|
||||
DWORD dcl, pcl, tm;
|
||||
DEF_NAMBUF
|
||||
|
||||
|
||||
/* Get logical drive */
|
||||
res = find_volume(&path, &fs, FA_WRITE);
|
||||
res = find_volume(&path, &fs, FA_WRITE); /* Get logical drive */
|
||||
if (res == FR_OK) {
|
||||
dj.obj.fs = fs;
|
||||
INIT_NAMBUF(fs);
|
||||
res = follow_path(&dj, path); /* Follow the file path */
|
||||
if (res == FR_OK) res = FR_EXIST; /* Any object with same name is already existing */
|
||||
if (FF_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) {
|
||||
if (res == FR_OK) res = FR_EXIST; /* Name collision? */
|
||||
if (FF_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) { /* Invalid name? */
|
||||
res = FR_INVALID_NAME;
|
||||
}
|
||||
if (res == FR_NO_FILE) { /* Can create a new directory */
|
||||
if (res == FR_NO_FILE) { /* It is clear to create a new directory */
|
||||
sobj.fs = fs; /* New object id to create a new chain */
|
||||
dcl = create_chain(&sobj, 0); /* Allocate a cluster for the new directory */
|
||||
res = FR_OK;
|
||||
if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster */
|
||||
if (dcl == 1) res = FR_INT_ERR;
|
||||
if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR;
|
||||
if (res == FR_OK) res = sync_window(fs); /* Flush FAT */
|
||||
if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster? */
|
||||
if (dcl == 1) res = FR_INT_ERR; /* Any insanity? */
|
||||
if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR; /* Disk error? */
|
||||
tm = GET_FATTIME();
|
||||
if (res == FR_OK) { /* Initialize the new directory table */
|
||||
res = dir_clear(fs, dcl); /* Clean up the new table */
|
||||
if (res == FR_OK && (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT)) { /* Create dot entries (FAT only) */
|
||||
dir = fs->win;
|
||||
mem_set(dir + DIR_Name, ' ', 11); /* Create "." entry */
|
||||
dir[DIR_Name] = '.';
|
||||
dir[DIR_Attr] = AM_DIR;
|
||||
st_dword(dir + DIR_ModTime, tm);
|
||||
st_clust(fs, dir, dcl);
|
||||
mem_cpy(dir + SZDIRE, dir, SZDIRE); /* Create ".." entry */
|
||||
dir[SZDIRE + 1] = '.'; pcl = dj.obj.sclust;
|
||||
st_clust(fs, dir + SZDIRE, pcl);
|
||||
fs->wflag = 1;
|
||||
}
|
||||
}
|
||||
if (res == FR_OK) {
|
||||
res = dir_register(&dj); /* Register the object to the directoy */
|
||||
res = dir_clear(fs, dcl); /* Clean up the new table */
|
||||
if (res == FR_OK) {
|
||||
if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { /* Create dot entries (FAT only) */
|
||||
mem_set(fs->win + DIR_Name, ' ', 11); /* Create "." entry */
|
||||
fs->win[DIR_Name] = '.';
|
||||
fs->win[DIR_Attr] = AM_DIR;
|
||||
st_dword(fs->win + DIR_ModTime, tm);
|
||||
st_clust(fs, fs->win, dcl);
|
||||
mem_cpy(fs->win + SZDIRE, fs->win, SZDIRE); /* Create ".." entry */
|
||||
fs->win[SZDIRE + 1] = '.'; pcl = dj.obj.sclust;
|
||||
st_clust(fs, fs->win + SZDIRE, pcl);
|
||||
fs->wflag = 1;
|
||||
}
|
||||
res = dir_register(&dj); /* Register the object to the parent directoy */
|
||||
}
|
||||
}
|
||||
if (res == FR_OK) {
|
||||
#if FF_FS_EXFAT
|
||||
@@ -5000,17 +5017,16 @@ FRESULT f_mkdir (
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
dir = dj.dir;
|
||||
st_dword(dir + DIR_ModTime, tm); /* Created time */
|
||||
st_clust(fs, dir, dcl); /* Table start cluster */
|
||||
dir[DIR_Attr] = AM_DIR; /* Attribute */
|
||||
st_dword(dj.dir + DIR_ModTime, tm); /* Created time */
|
||||
st_clust(fs, dj.dir, dcl); /* Table start cluster */
|
||||
dj.dir[DIR_Attr] = AM_DIR; /* Attribute */
|
||||
fs->wflag = 1;
|
||||
}
|
||||
if (res == FR_OK) {
|
||||
res = sync_fs(fs);
|
||||
}
|
||||
} else {
|
||||
remove_chain(&dj.obj, dcl, 0); /* Could not register, remove cluster chain */
|
||||
remove_chain(&sobj, dcl, 0); /* Could not register, remove the allocated cluster */
|
||||
}
|
||||
}
|
||||
FREE_NAMBUF();
|
||||
@@ -5250,7 +5266,7 @@ FRESULT f_getlabel (
|
||||
dj.obj.fs = fs; dj.obj.sclust = 0; /* Open root directory */
|
||||
res = dir_sdi(&dj, 0);
|
||||
if (res == FR_OK) {
|
||||
res = dir_read_label(&dj); /* Find a volume label entry */
|
||||
res = DIR_READ_LABEL(&dj); /* Find a volume label entry */
|
||||
if (res == FR_OK) {
|
||||
#if FF_FS_EXFAT
|
||||
if (fs->fs_type == FS_EXFAT) {
|
||||
@@ -5395,7 +5411,7 @@ FRESULT f_setlabel (
|
||||
dj.obj.fs = fs; dj.obj.sclust = 0; /* Open root directory */
|
||||
res = dir_sdi(&dj, 0);
|
||||
if (res == FR_OK) {
|
||||
res = dir_read_label(&dj); /* Get volume label entry */
|
||||
res = DIR_READ_LABEL(&dj); /* Get volume label entry */
|
||||
if (res == FR_OK) {
|
||||
if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) {
|
||||
dj.dir[XDIR_NumLabel] = (BYTE)di; /* Change the volume label */
|
||||
@@ -5417,7 +5433,7 @@ FRESULT f_setlabel (
|
||||
if (res == FR_OK) {
|
||||
mem_set(dj.dir, 0, SZDIRE); /* Clean the entry */
|
||||
if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) {
|
||||
dj.dir[XDIR_Type] = 0x83; /* Create 83 entry */
|
||||
dj.dir[XDIR_Type] = ET_VLABEL; /* Create volume label entry */
|
||||
dj.dir[XDIR_NumLabel] = (BYTE)di;
|
||||
mem_cpy(dj.dir + XDIR_Label, dirvn, 22);
|
||||
} else {
|
||||
@@ -5614,7 +5630,7 @@ FRESULT f_mkfs (
|
||||
UINT len /* Size of working buffer [byte] */
|
||||
)
|
||||
{
|
||||
const UINT n_fats = 1; /* Number of FATs for FAT/FAT32 volume (1 or 2) */
|
||||
const UINT n_fats = 2; /* Number of FATs for FAT/FAT32 volume (1 or 2) */
|
||||
const UINT n_rootdir = 512; /* Number of root directory entries for FAT volume */
|
||||
static const WORD cst[] = {1, 4, 16, 64, 256, 512, 0}; /* Cluster size boundary for FAT volume (4Ks unit) */
|
||||
static const WORD cst32[] = {1, 2, 4, 8, 16, 32, 0}; /* Cluster size boundary for FAT32 volume (128Ks unit) */
|
||||
@@ -5678,7 +5694,7 @@ FRESULT f_mkfs (
|
||||
} else {
|
||||
/* Create a single-partition in this function */
|
||||
if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_vol) != RES_OK) LEAVE_MKFS(FR_DISK_ERR);
|
||||
b_vol = (opt & FM_SFD) ? 0 : 63; /* Volume start sector */
|
||||
b_vol = (opt & FM_SFD) ? 0 : 32768; /* Volume start sector. Align to 16MB */
|
||||
if (sz_vol < b_vol) LEAVE_MKFS(FR_MKFS_ABORTED);
|
||||
sz_vol -= b_vol; /* Volume size */
|
||||
}
|
||||
@@ -5722,7 +5738,7 @@ FRESULT f_mkfs (
|
||||
b_fat = b_vol + 32; /* FAT start at offset 32 */
|
||||
sz_fat = ((sz_vol / au + 2) * 4 + ss - 1) / ss; /* Number of FAT sectors */
|
||||
b_data = (b_fat + sz_fat + sz_blk - 1) & ~(sz_blk - 1); /* Align data area to the erase block boundary */
|
||||
if (b_data >= sz_vol / 2) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume? */
|
||||
if (b_data - b_vol >= sz_vol / 2) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume? */
|
||||
n_clst = (sz_vol - (b_data - b_vol)) / au; /* Number of clusters */
|
||||
if (n_clst <16) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too few clusters? */
|
||||
if (n_clst > MAX_EXFAT) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too many clusters? */
|
||||
@@ -5803,11 +5819,11 @@ FRESULT f_mkfs (
|
||||
|
||||
/* Initialize the root directory */
|
||||
mem_set(buf, 0, szb_buf);
|
||||
buf[SZDIRE * 0 + 0] = 0x83; /* 83 entry (volume label) */
|
||||
buf[SZDIRE * 1 + 0] = 0x81; /* 81 entry (allocation bitmap) */
|
||||
buf[SZDIRE * 0 + 0] = ET_VLABEL; /* Volume label entry */
|
||||
buf[SZDIRE * 1 + 0] = ET_BITMAP; /* Bitmap entry */
|
||||
st_dword(buf + SZDIRE * 1 + 20, 2); /* cluster */
|
||||
st_dword(buf + SZDIRE * 1 + 24, szb_bit); /* size */
|
||||
buf[SZDIRE * 2 + 0] = 0x82; /* 82 entry (up-case table) */
|
||||
buf[SZDIRE * 2 + 0] = ET_UPCASE; /* Up-case table entry */
|
||||
st_dword(buf + SZDIRE * 2 + 4, sum); /* sum */
|
||||
st_dword(buf + SZDIRE * 2 + 20, 2 + tbl[0]); /* cluster */
|
||||
st_dword(buf + SZDIRE * 2 + 24, szb_case); /* size */
|
||||
@@ -5902,6 +5918,9 @@ FRESULT f_mkfs (
|
||||
if (fmt == FS_FAT32) { /* FAT32: Move FAT base */
|
||||
sz_rsv += n; b_fat += n;
|
||||
} else { /* FAT: Expand FAT size */
|
||||
if (n % n_fats) { /* Adjust fractional error if needed */
|
||||
n--; sz_rsv++; b_fat++;
|
||||
}
|
||||
sz_fat += n / n_fats;
|
||||
}
|
||||
|
||||
@@ -5965,13 +5984,13 @@ FRESULT f_mkfs (
|
||||
st_word(buf + BPB_BkBootSec32, 6); /* Offset of backup VBR (VBR + 6) */
|
||||
buf[BS_DrvNum32] = 0x80; /* Drive number (for int13) */
|
||||
buf[BS_BootSig32] = 0x29; /* Extended boot signature */
|
||||
mem_cpy(buf + BS_VolLab32, "NO NAME " "FAT32 ", 19); /* Volume label, FAT signature */
|
||||
mem_cpy(buf + BS_VolLab32, "SWITCH SD " "FAT32 ", 19); /* Volume label, FAT signature */
|
||||
} else {
|
||||
st_dword(buf + BS_VolID, GET_FATTIME()); /* VSN */
|
||||
st_word(buf + BPB_FATSz16, (WORD)sz_fat); /* FAT size [sector] */
|
||||
buf[BS_DrvNum] = 0x80; /* Drive number (for int13) */
|
||||
buf[BS_BootSig] = 0x29; /* Extended boot signature */
|
||||
mem_cpy(buf + BS_VolLab, "NO NAME " "FAT ", 19); /* Volume label, FAT signature */
|
||||
mem_cpy(buf + BS_VolLab, "SWITCH SD " "FAT ", 19); /* Volume label, FAT signature */
|
||||
}
|
||||
st_word(buf + BS_55AA, 0xAA55); /* Signature (offset is fixed here regardless of sector size) */
|
||||
if (disk_write(pdrv, buf, b_vol, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Write it to the VBR sector */
|
||||
@@ -6295,8 +6314,7 @@ typedef struct { /* Putchar output buffer and work area */
|
||||
} putbuff;
|
||||
|
||||
|
||||
static
|
||||
void putc_bfd ( /* Buffered write with code conversion */
|
||||
static void putc_bfd ( /* Buffered write with code conversion */
|
||||
putbuff* pb,
|
||||
TCHAR c
|
||||
)
|
||||
@@ -6407,7 +6425,7 @@ void putc_bfd ( /* Buffered write with code conversion */
|
||||
#else /* Write it in ANSI/OEM */
|
||||
if (hs != 0) return;
|
||||
wc = ff_uni2oem(wc, CODEPAGE); /* UTF-16 ==> ANSI/OEM */
|
||||
if (wc == 0) return;;
|
||||
if (wc == 0) return;
|
||||
if (wc >= 0x100) {
|
||||
pb->buf[i++] = (BYTE)(wc >> 8); nc++;
|
||||
}
|
||||
@@ -6427,8 +6445,7 @@ void putc_bfd ( /* Buffered write with code conversion */
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
int putc_flush ( /* Flush left characters in the buffer */
|
||||
static int putc_flush ( /* Flush left characters in the buffer */
|
||||
putbuff* pb
|
||||
)
|
||||
{
|
||||
@@ -6441,8 +6458,7 @@ int putc_flush ( /* Flush left characters in the buffer */
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
void putc_init ( /* Initialize write buffer */
|
||||
static void putc_init ( /* Initialize write buffer */
|
||||
putbuff* pb,
|
||||
FIL* fp
|
||||
)
|
||||
@@ -6634,4 +6650,3 @@ FRESULT f_setcp (
|
||||
return FR_OK;
|
||||
}
|
||||
#endif /* FF_CODE_PAGE == 0 */
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*----------------------------------------------------------------------------/
|
||||
/ FatFs - Generic FAT Filesystem module R0.13b /
|
||||
/ FatFs - Generic FAT Filesystem module R0.13c /
|
||||
/-----------------------------------------------------------------------------/
|
||||
/
|
||||
/ Copyright (C) 2018, ChaN, all right reserved.
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
|
||||
#ifndef FF_DEFINED
|
||||
#define FF_DEFINED 63463 /* Revision ID */
|
||||
#define FF_DEFINED 86604 /* Revision ID */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -95,8 +95,9 @@ typedef DWORD FSIZE_t;
|
||||
/* Filesystem object structure (FATFS) */
|
||||
|
||||
typedef struct {
|
||||
BYTE fs_type; /* Filesystem type (0:N/A) */
|
||||
BYTE pdrv; /* Physical drive number */
|
||||
BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */
|
||||
BYTE fs_type; /* Filesystem type (0:not mounted) */
|
||||
BYTE pdrv; /* Associated physical drive */
|
||||
BYTE n_fats; /* Number of FATs (1 or 2) */
|
||||
BYTE wflag; /* win[] flag (b0:dirty) */
|
||||
BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */
|
||||
@@ -133,8 +134,10 @@ typedef struct {
|
||||
DWORD fatbase; /* FAT base sector */
|
||||
DWORD dirbase; /* Root directory base sector/cluster */
|
||||
DWORD database; /* Data base sector */
|
||||
#if FF_FS_EXFAT
|
||||
DWORD bitbase; /* Allocation bitmap base sector */
|
||||
#endif
|
||||
DWORD winsect; /* Current sector appearing in the win[] */
|
||||
BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */
|
||||
} FATFS;
|
||||
|
||||
|
||||
@@ -145,7 +148,7 @@ typedef struct {
|
||||
FATFS* fs; /* Pointer to the hosting volume of this object */
|
||||
WORD id; /* Hosting volume mount ID */
|
||||
BYTE attr; /* Object attribute */
|
||||
BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:flagmented in this session, b2:sub-directory stretched) */
|
||||
BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:fragmented in this session, b2:sub-directory stretched) */
|
||||
DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */
|
||||
FSIZE_t objsize; /* Object size (valid when sclust != 0) */
|
||||
#if FF_FS_EXFAT
|
||||
@@ -165,6 +168,9 @@ typedef struct {
|
||||
/* File object structure (FIL) */
|
||||
|
||||
typedef struct {
|
||||
#if !FF_FS_TINY
|
||||
BYTE buf[FF_MAX_SS]; /* File private data read/write window */
|
||||
#endif
|
||||
FFOBJID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */
|
||||
BYTE flag; /* File status flags */
|
||||
BYTE err; /* Abort flag (error code) */
|
||||
@@ -178,9 +184,6 @@ typedef struct {
|
||||
#if FF_USE_FASTSEEK
|
||||
DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */
|
||||
#endif
|
||||
#if !FF_FS_TINY
|
||||
BYTE buf[FF_MAX_SS]; /* File private data read/write window */
|
||||
#endif
|
||||
} FIL;
|
||||
|
||||
|
||||
@@ -276,7 +279,7 @@ FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get numbe
|
||||
FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */
|
||||
FRESULT f_setlabel (const TCHAR* label); /* Set volume label */
|
||||
FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
|
||||
FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */
|
||||
FRESULT f_expand (FIL* fp, FSIZE_t fsz, BYTE opt); /* Allocate a contiguous block to the file */
|
||||
FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */
|
||||
FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */
|
||||
FRESULT f_fdisk (BYTE pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */
|
||||
@@ -365,8 +368,11 @@ int ff_del_syncobj (FF_SYNC_t sobj); /* Delete a sync object */
|
||||
#define AM_RDO 0x01 /* Read only */
|
||||
#define AM_HID 0x02 /* Hidden */
|
||||
#define AM_SYS 0x04 /* System */
|
||||
#define AM_VOL 0x08 /* Volume */
|
||||
#define AM_DIR 0x10 /* Directory */
|
||||
#define AM_ARC 0x20 /* Archive */
|
||||
#define AM_DEV 0x40 /* Device */
|
||||
#define AM_RVD 0x80 /* Reserved */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ FatFs - Configuration file
|
||||
/ FatFs Functional Configurations
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define FFCONF_DEF 63463 /* Revision ID */
|
||||
#define FFCONF_DEF 86604 /* Revision ID */
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ Function Configurations
|
||||
@@ -33,7 +33,7 @@
|
||||
/ 2: Enable with LF-CRLF conversion. */
|
||||
|
||||
|
||||
#define FF_USE_FIND 0
|
||||
#define FF_USE_FIND 1
|
||||
/* This option switches filtered directory read functions, f_findfirst() and
|
||||
/ f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */
|
||||
|
||||
@@ -232,14 +232,14 @@
|
||||
|
||||
#define FF_FS_EXFAT 1
|
||||
/* This option switches support for exFAT filesystem. (0:Disable or 1:Enable)
|
||||
/ To enable exFAT, also LFN needs to be enabled.
|
||||
/ To enable exFAT, also LFN needs to be enabled. (FF_USE_LFN >= 1)
|
||||
/ Note that enabling exFAT discards ANSI C (C89) compatibility. */
|
||||
|
||||
|
||||
#define FF_FS_NORTC 1
|
||||
#define FF_NORTC_MON 1
|
||||
#define FF_NORTC_MDAY 1
|
||||
#define FF_NORTC_YEAR 2018
|
||||
#define FF_NORTC_YEAR 2019
|
||||
/* The option FF_FS_NORTC switches timestamp function. If the system does not have
|
||||
/ any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable
|
||||
/ the timestamp function. Every object modified by FatFs will have a fixed timestamp
|
||||
@@ -262,6 +262,7 @@
|
||||
/ lock control is independent of re-entrancy. */
|
||||
|
||||
|
||||
/* #include <somertos.h> // O/S definitions */
|
||||
#define FF_FS_REENTRANT 0
|
||||
#define FF_FS_TIMEOUT 1000
|
||||
#define FF_SYNC_t HANDLE
|
||||
@@ -282,8 +283,6 @@
|
||||
/ SemaphoreHandle_t and etc. A header file for O/S definitions needs to be
|
||||
/ included somewhere in the scope of ff.h. */
|
||||
|
||||
/* #include <windows.h> // O/S definitions */
|
||||
|
||||
|
||||
|
||||
/*--- End of configuration options ---*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Sample Code of OS Dependent Functions for FatFs */
|
||||
/* (C) ChaN, 2017 */
|
||||
/* (C) ChaN, 2018 */
|
||||
/* (C) CTCaer, 2018 */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
/* Allocate a memory block */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
void* ff_memalloc ( /* Returns pointer to the allocated memory block (null on not enough core) */
|
||||
void* ff_memalloc ( /* Returns pointer to the allocated memory block (null if not enough core) */
|
||||
UINT msize /* Number of bytes to allocate */
|
||||
)
|
||||
{
|
||||
@@ -29,7 +29,7 @@ void* ff_memalloc ( /* Returns pointer to the allocated memory block (null on no
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
void ff_memfree (
|
||||
void* mblock /* Pointer to the memory block to free (nothing to do for null) */
|
||||
void* mblock /* Pointer to the memory block to free (nothing to do if null) */
|
||||
)
|
||||
{
|
||||
free(mblock); /* Free the memory block with POSIX API */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Unicode handling functions for FatFs R0.13a */
|
||||
/* Unicode handling functions for FatFs R0.13c */
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* This module will occupy a huge memory in the .const section when the /
|
||||
/ FatFs is configured for LFN with DBCS. If the system has any Unicode /
|
||||
@@ -7,7 +7,7 @@
|
||||
/ that function to avoid silly memory consumption. /
|
||||
/-------------------------------------------------------------------------*/
|
||||
/*
|
||||
/ Copyright (C) 2017, ChaN, all right reserved.
|
||||
/ Copyright (C) 2018, ChaN, all right reserved.
|
||||
/
|
||||
/ FatFs module is an open source software. Redistribution and use of FatFs in
|
||||
/ source and binary forms, with or without modification, are permitted provided
|
||||
@@ -25,16 +25,15 @@
|
||||
|
||||
#include "ff.h"
|
||||
|
||||
#if FF_USE_LFN /* This module is blanked when non-LFN configuration */
|
||||
#if FF_USE_LFN /* This module will be blanked at non-LFN configuration */
|
||||
|
||||
#if FF_DEFINED != 63463 /* Revision ID */
|
||||
#if FF_DEFINED != 86604 /* Revision ID */
|
||||
#error Wrong include file (ff.h).
|
||||
#endif
|
||||
|
||||
#define MERGE2(a, b) a ## b
|
||||
#define CVTBL(tbl, cp) MERGE2(tbl, cp)
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Code Conversion Tables */
|
||||
/*------------------------------------------------------------------------*/
|
||||
@@ -623,5 +622,4 @@ DWORD ff_wtoupper ( /* Returns up-converted code point */
|
||||
return uni;
|
||||
}
|
||||
|
||||
|
||||
#endif /* #if FF_USE_LFN */
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
ENTRY(_start)
|
||||
|
||||
SECTIONS {
|
||||
PROVIDE(__ipl_start = 0x40008000);
|
||||
PROVIDE(__ipl_start = IPL_LOAD_ADDR);
|
||||
. = __ipl_start;
|
||||
.text : {
|
||||
*(.text._start);
|
||||
*(._boot_cfg);
|
||||
*(._ipl_version);
|
||||
*(.text._irq_setup);
|
||||
*(.text*);
|
||||
}
|
||||
.data : {
|
||||
|
||||
3365
bootloader/main.c
3365
bootloader/main.c
File diff suppressed because it is too large
Load Diff
1212
bootloader/mem/emc.h
1212
bootloader/mem/emc.h
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2020 CTCaer
|
||||
* Copyright (c) 2018 M4xw
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -17,6 +18,7 @@
|
||||
|
||||
#include <string.h>
|
||||
#include "heap.h"
|
||||
#include "../gfx/gfx.h"
|
||||
#include "../../common/common_heap.h"
|
||||
|
||||
static void _heap_create(heap_t *heap, u32 start)
|
||||
@@ -25,12 +27,13 @@ static void _heap_create(heap_t *heap, u32 start)
|
||||
heap->first = NULL;
|
||||
}
|
||||
|
||||
static u32 _heap_alloc(heap_t *heap, u32 size, u32 alignment)
|
||||
// Node info is before node address.
|
||||
static u32 _heap_alloc(heap_t *heap, u32 size)
|
||||
{
|
||||
hnode_t *node, *new;
|
||||
int search = 1;
|
||||
hnode_t *node, *new_node;
|
||||
|
||||
size = ALIGN(size, alignment);
|
||||
// Align to cache line size.
|
||||
size = ALIGN(size, sizeof(hnode_t));
|
||||
|
||||
if (!heap->first)
|
||||
{
|
||||
@@ -45,36 +48,55 @@ static u32 _heap_alloc(heap_t *heap, u32 size, u32 alignment)
|
||||
}
|
||||
|
||||
node = heap->first;
|
||||
while (search)
|
||||
while (true)
|
||||
{
|
||||
if (!node->used && size + sizeof(hnode_t) < node->size)
|
||||
// Check if there's available unused node.
|
||||
if (!node->used && (size <= node->size))
|
||||
{
|
||||
new = (hnode_t *)((u32)node + sizeof(hnode_t) + size);
|
||||
// Size and offset of the new unused node.
|
||||
u32 new_size = node->size - size;
|
||||
new_node = (hnode_t *)((u32)node + sizeof(hnode_t) + size);
|
||||
|
||||
// If there's aligned unused space from the old node,
|
||||
// create a new one and set the leftover size.
|
||||
if (new_size >= (sizeof(hnode_t) << 2))
|
||||
{
|
||||
new_node->size = new_size - sizeof(hnode_t);
|
||||
new_node->used = 0;
|
||||
new_node->next = node->next;
|
||||
|
||||
// Check that we are not on first node.
|
||||
if (new_node->next)
|
||||
new_node->next->prev = new_node;
|
||||
|
||||
new_node->prev = node;
|
||||
node->next = new_node;
|
||||
}
|
||||
else // Unused node size is just enough.
|
||||
size += new_size;
|
||||
|
||||
new->size = node->size - sizeof(hnode_t) - size;
|
||||
node->size = size;
|
||||
node->used = 1;
|
||||
new->used = 0;
|
||||
new->next = node->next;
|
||||
new->prev = node;
|
||||
node->next = new;
|
||||
|
||||
return (u32)node + sizeof(hnode_t);
|
||||
}
|
||||
|
||||
// No unused node found, try the next one.
|
||||
if (node->next)
|
||||
node = node->next;
|
||||
else
|
||||
search = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
new = (hnode_t *)((u32)node + sizeof(hnode_t) + node->size);
|
||||
new->used = 1;
|
||||
new->size = size;
|
||||
new->prev = node;
|
||||
new->next = NULL;
|
||||
node->next = new;
|
||||
// No unused node found, create a new one.
|
||||
new_node = (hnode_t *)((u32)node + sizeof(hnode_t) + node->size);
|
||||
new_node->used = 1;
|
||||
new_node->size = size;
|
||||
new_node->prev = node;
|
||||
new_node->next = NULL;
|
||||
node->next = new_node;
|
||||
|
||||
return (u32)new + sizeof(hnode_t);
|
||||
return (u32)new_node + sizeof(hnode_t);
|
||||
}
|
||||
|
||||
static void _heap_free(heap_t *heap, u32 addr)
|
||||
@@ -90,6 +112,7 @@ static void _heap_free(heap_t *heap, u32 addr)
|
||||
{
|
||||
node->prev->size += node->size + sizeof(hnode_t);
|
||||
node->prev->next = node->next;
|
||||
|
||||
if (node->next)
|
||||
node->next->prev = node->prev;
|
||||
}
|
||||
@@ -107,23 +130,45 @@ void heap_init(u32 base)
|
||||
|
||||
void *malloc(u32 size)
|
||||
{
|
||||
return (void *)_heap_alloc(&_heap, size, 0x10);
|
||||
}
|
||||
|
||||
void *memalign(u32 align, u32 size)
|
||||
{
|
||||
return (void *)_heap_alloc(&_heap, size, align);
|
||||
return (void *)_heap_alloc(&_heap, size);
|
||||
}
|
||||
|
||||
void *calloc(u32 num, u32 size)
|
||||
{
|
||||
void *res = (void *)_heap_alloc(&_heap, num * size, 0x10);
|
||||
memset(res, 0, num * size);
|
||||
void *res = (void *)_heap_alloc(&_heap, num * size);
|
||||
memset(res, 0, ALIGN(num * size, sizeof(hnode_t))); // Clear the aligned size.
|
||||
return res;
|
||||
}
|
||||
|
||||
void free(void *buf)
|
||||
{
|
||||
if ((buf != NULL) || ((u32)buf > (_heap.start - 1)))
|
||||
if ((u32)buf >= _heap.start)
|
||||
_heap_free(&_heap, (u32)buf);
|
||||
}
|
||||
|
||||
void heap_monitor(heap_monitor_t *mon, bool print_node_stats)
|
||||
{
|
||||
u32 count = 0;
|
||||
memset(mon, 0, sizeof(heap_monitor_t));
|
||||
|
||||
hnode_t *node = _heap.first;
|
||||
while (true)
|
||||
{
|
||||
if (node->used)
|
||||
mon->used += node->size + sizeof(hnode_t);
|
||||
else
|
||||
mon->total += node->size + sizeof(hnode_t);
|
||||
|
||||
if (print_node_stats)
|
||||
gfx_printf("%3d - %d, addr: 0x%08X, size: 0x%X\n",
|
||||
count, node->used, (u32)node + sizeof(hnode_t), node->size);
|
||||
|
||||
count++;
|
||||
|
||||
if (node->next)
|
||||
node = node->next;
|
||||
else
|
||||
break;
|
||||
}
|
||||
mon->total += mon->used;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2020 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -18,11 +19,12 @@
|
||||
#define _HEAP_H_
|
||||
|
||||
#include "../utils/types.h"
|
||||
#include "../../common/common_heap.h"
|
||||
|
||||
void heap_init(u32 base);
|
||||
void *malloc(u32 size);
|
||||
void *calloc(u32 num, u32 size);
|
||||
void free(void *buf);
|
||||
void *memalign(u32 align, u32 size);
|
||||
void heap_monitor(heap_monitor_t *mon, bool print_node_stats);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -28,6 +28,7 @@ void mc_config_carveout()
|
||||
MC(MC_MTS_CARVEOUT_SIZE_MB) = 0;
|
||||
MC(MC_MTS_CARVEOUT_ADR_HI) = 0;
|
||||
MC(MC_MTS_CARVEOUT_REG_CTRL) = 1;
|
||||
|
||||
MC(MC_SECURITY_CARVEOUT1_BOM) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT1_BOM_HI) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT1_SIZE_128KB) = 0;
|
||||
@@ -43,6 +44,21 @@ void mc_config_carveout()
|
||||
MC(MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS4) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT1_CFG0) = 0x4000006;
|
||||
|
||||
MC(MC_SECURITY_CARVEOUT2_BOM) = 0x80020000;
|
||||
MC(MC_SECURITY_CARVEOUT2_BOM_HI) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT2_SIZE_128KB) = 2;
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS0) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS1) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS2) = 0x3100000;
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS3) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS4) = 0x300;
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS0) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS1) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS2) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS3) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS4) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT2_CFG0) = 0x440167E;
|
||||
|
||||
MC(MC_SECURITY_CARVEOUT3_BOM) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT3_BOM_HI) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT3_SIZE_128KB) = 0;
|
||||
@@ -57,6 +73,7 @@ void mc_config_carveout()
|
||||
MC(MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS3) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS4) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT3_CFG0) = 0x4401E7E;
|
||||
|
||||
MC(MC_SECURITY_CARVEOUT4_BOM) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT4_BOM_HI) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT4_SIZE_128KB) = 0;
|
||||
@@ -71,6 +88,7 @@ void mc_config_carveout()
|
||||
MC(MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS3) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS4) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT4_CFG0) = 0x8F;
|
||||
|
||||
MC(MC_SECURITY_CARVEOUT5_BOM) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT5_BOM_HI) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT5_SIZE_128KB) = 0;
|
||||
@@ -87,26 +105,9 @@ void mc_config_carveout()
|
||||
MC(MC_SECURITY_CARVEOUT5_CFG0) = 0x8F;
|
||||
}
|
||||
|
||||
void mc_config_carveout_finalize()
|
||||
{
|
||||
MC(MC_SECURITY_CARVEOUT2_BOM) = 0x80020000;
|
||||
MC(MC_SECURITY_CARVEOUT2_BOM_HI) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT2_SIZE_128KB) = 2;
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS0) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS1) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS2) = 0x3000000;
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS3) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS4) = 0x300;
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS0) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS1) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS2) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS3) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS4) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT2_CFG0) = 0x440167E;
|
||||
}
|
||||
|
||||
void mc_enable_ahb_redirect()
|
||||
{
|
||||
// Enable ARC_CLK_OVR_ON.
|
||||
CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD) = (CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD) & 0xFFF7FFFF) | 0x80000;
|
||||
//MC(MC_IRAM_REG_CTRL) &= 0xFFFFFFFE;
|
||||
MC(MC_IRAM_BOM) = 0x40000000;
|
||||
@@ -119,19 +120,20 @@ void mc_disable_ahb_redirect()
|
||||
MC(MC_IRAM_TOM) = 0;
|
||||
// Disable IRAM_CFG_WRITE_ACCESS (sticky).
|
||||
//MC(MC_IRAM_REG_CTRL) = MC(MC_IRAM_REG_CTRL) & 0xFFFFFFFE | 1;
|
||||
CLOCK(0x3A4) &= 0xFFF7FFFF;
|
||||
// Disable ARC_CLK_OVR_ON.
|
||||
CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD) &= 0xFFF7FFFF;
|
||||
}
|
||||
|
||||
void mc_enable()
|
||||
{
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) & 0x1FFFFFFF) | 0x40000000;
|
||||
// Enable MIPI CAL clock.
|
||||
// Enable EMC clock.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = (CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) & 0xFDFFFFFF) | 0x2000000;
|
||||
// Enable MC clock.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = (CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) & 0xFFFFFFFE) | 1;
|
||||
// Enable EMC DLL clock.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = (CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) & 0xFFFFBFFF) | 0x4000;
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_SET) = 0x2000001; //Clear EMC and MC reset.
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = 0x2000001; //Clear EMC and MC reset.
|
||||
usleep(5);
|
||||
|
||||
//#ifdef CONFIG_ENABLE_AHB_REDIRECT
|
||||
|
||||
@@ -463,4 +463,54 @@
|
||||
#define MC_ERR_APB_ASID_UPDATE_STATUS 0x9d0
|
||||
#define MC_DA_CONFIG0 0x9dc
|
||||
|
||||
// MC_SECURITY_CARVEOUTX_CFG0
|
||||
// Mode of LOCK_MODE.
|
||||
#define PROTECT_MODE_SHIFT 0
|
||||
#define SEC_CARVEOUT_CFG_SECURE (0 << PROTECT_MODE_SHIFT0)
|
||||
#define SEC_CARVEOUT_CFG_TZ_SECURE (1 << PROTECT_MODE_SHIFT0)
|
||||
// Enables PROTECT_MODE.
|
||||
#define LOCK_MODE_SHIFT 1
|
||||
#define SEC_CARVEOUT_CFG_UNLOCKED (0 << LOCK_MODE_SHIFT)
|
||||
#define SEC_CARVEOUT_CFG_LOCKED (1 << LOCK_MODE_SHIFT)
|
||||
|
||||
#define ADDRESS_TYPE_SHIFT 2
|
||||
#define SEC_CARVEOUT_CFG_ANY_ADDRESS (0 << ADDRESS_TYPE_SHIFT)
|
||||
#define SEC_CARVEOUT_CFG_UNTRANSLATED_ONLY (1 << ADDRESS_TYPE_SHIFT)
|
||||
|
||||
#define READ_ACCESS_LEVEL_SHIFT 3
|
||||
#define SEC_CARVEOUT_CFG_RD_ALL (1 << READ_ACCESS_LEVEL_SHIFT)
|
||||
#define SEC_CARVEOUT_CFG_RD_UNK (2 << READ_ACCESS_LEVEL_SHIFT)
|
||||
#define SEC_CARVEOUT_CFG_RD_FALCON_LS (4 << READ_ACCESS_LEVEL_SHIFT)
|
||||
#define SEC_CARVEOUT_CFG_RD_FALCON_HS (8 << READ_ACCESS_LEVEL_SHIFT)
|
||||
|
||||
#define WRITE_ACCESS_LEVEL_SHIFT 7
|
||||
#define SEC_CARVEOUT_CFG_WR_ALL (1 << WRITE_ACCESS_LEVEL_SHIFT)
|
||||
#define SEC_CARVEOUT_CFG_WR_UNK (2 << WRITE_ACCESS_LEVEL_SHIFT)
|
||||
#define SEC_CARVEOUT_CFG_WR_FALCON_LS (4 << WRITE_ACCESS_LEVEL_SHIFT)
|
||||
#define SEC_CARVEOUT_CFG_WR_FALCON_HS (8 << WRITE_ACCESS_LEVEL_SHIFT)
|
||||
|
||||
#define SEC_CARVEOUT_CFG_APERTURE_ID_MASK (3 << 11)
|
||||
|
||||
#define DISABLE_READ_CHECK_ACCESS_LEVEL_SHIFT 14
|
||||
#define SEC_CARVEOUT_CFG_DIS_RD_CHECK_L0 (1 << DISABLE_READ_CHECK_ACCESS_LEVEL_SHIFT)
|
||||
#define SEC_CARVEOUT_CFG_DIS_RD_CHECK_L1 (2 << DISABLE_READ_CHECK_ACCESS_LEVEL_SHIFT)
|
||||
#define SEC_CARVEOUT_CFG_DIS_RD_CHECK_L2 (4 << DISABLE_READ_CHECK_ACCESS_LEVEL_SHIFT)
|
||||
#define SEC_CARVEOUT_CFG_DIS_RD_CHECK_L3 (8 << DISABLE_READ_CHECK_ACCESS_LEVEL_SHIFT)
|
||||
|
||||
#define DISABLE_WRITE_CHECK_ACCESS_LEVEL_SHIFT 18
|
||||
#define SEC_CARVEOUT_CFG_DIS_WR_CHECK_L0 (1 << DISABLE_WRITE_CHECK_ACCESS_LEVEL_SHIFT)
|
||||
#define SEC_CARVEOUT_CFG_DIS_WR_CHECK_L1 (2 << DISABLE_WRITE_CHECK_ACCESS_LEVEL_SHIFT)
|
||||
#define SEC_CARVEOUT_CFG_DIS_WR_CHECK_L2 (4 << DISABLE_WRITE_CHECK_ACCESS_LEVEL_SHIFT)
|
||||
#define SEC_CARVEOUT_CFG_DIS_WR_CHECK_L3 (8 << DISABLE_WRITE_CHECK_ACCESS_LEVEL_SHIFT)
|
||||
|
||||
#define SEC_CARVEOUT_CFG_SEND_CFG_TO_GPU (1 << 22)
|
||||
|
||||
#define SEC_CARVEOUT_CFG_TZ_GLOBAL_WR_EN_BYPASS_CHECK (1 << 23)
|
||||
#define SEC_CARVEOUT_CFG_TZ_GLOBAL_RD_EN_BYPASS_CHECK (1 << 24)
|
||||
|
||||
#define SEC_CARVEOUT_CFG_ALLOW_APERTURE_ID_MISMATCH (1 << 25)
|
||||
#define SEC_CARVEOUT_CFG_FORCE_APERTURE_ID_MATCH (1 << 26)
|
||||
|
||||
#define SEC_CARVEOUT_CFG_IS_WPR (1 << 27)
|
||||
|
||||
#endif
|
||||
|
||||
109
bootloader/mem/minerva.c
Normal file
109
bootloader/mem/minerva.c
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (c) 2019 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "minerva.h"
|
||||
#include "../soc/fuse.h"
|
||||
#include "../utils/util.h"
|
||||
|
||||
#include "../soc/clock.h"
|
||||
#include "../ianos/ianos.h"
|
||||
#include "../soc/fuse.h"
|
||||
#include "../soc/t210.h"
|
||||
|
||||
extern volatile nyx_storage_t *nyx_str;
|
||||
|
||||
u32 minerva_init()
|
||||
{
|
||||
u32 curr_ram_idx = 0;
|
||||
|
||||
minerva_cfg = NULL;
|
||||
mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg;
|
||||
memset(mtc_cfg, 0, sizeof(mtc_config_t));
|
||||
|
||||
// Set table to nyx storage.
|
||||
mtc_cfg->mtc_table = (emc_table_t *)nyx_str->mtc_table;
|
||||
|
||||
mtc_cfg->sdram_id = (fuse_read_odm(4) >> 3) & 0x1F;
|
||||
mtc_cfg->init_done = MTC_NEW_MAGIC; // Initialize mtc table.
|
||||
|
||||
u32 ep_addr = ianos_loader(false, "bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)mtc_cfg);
|
||||
|
||||
// Ensure that Minerva is new.
|
||||
if (mtc_cfg->init_done == MTC_INIT_MAGIC)
|
||||
minerva_cfg = (void *)ep_addr;
|
||||
else
|
||||
mtc_cfg->init_done = 0;
|
||||
|
||||
if (!minerva_cfg)
|
||||
return 1;
|
||||
|
||||
// Get current frequency
|
||||
for (curr_ram_idx = 0; curr_ram_idx < 10; curr_ram_idx++)
|
||||
{
|
||||
if (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) == mtc_cfg->mtc_table[curr_ram_idx].clk_src_emc)
|
||||
break;
|
||||
}
|
||||
|
||||
mtc_cfg->rate_from = mtc_cfg->mtc_table[curr_ram_idx].rate_khz;
|
||||
mtc_cfg->rate_to = 204000;
|
||||
mtc_cfg->train_mode = OP_TRAIN;
|
||||
minerva_cfg(mtc_cfg, NULL);
|
||||
mtc_cfg->rate_to = 800000;
|
||||
minerva_cfg(mtc_cfg, NULL);
|
||||
mtc_cfg->rate_to = 1600000;
|
||||
minerva_cfg(mtc_cfg, NULL);
|
||||
|
||||
// FSP WAR.
|
||||
mtc_cfg->train_mode = OP_SWITCH;
|
||||
mtc_cfg->rate_to = 800000;
|
||||
minerva_cfg(mtc_cfg, NULL);
|
||||
|
||||
// Switch to max.
|
||||
mtc_cfg->rate_to = 1600000;
|
||||
minerva_cfg(mtc_cfg, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void minerva_change_freq(minerva_freq_t freq)
|
||||
{
|
||||
if (!minerva_cfg)
|
||||
return;
|
||||
|
||||
mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg;
|
||||
if (mtc_cfg->rate_from != freq)
|
||||
{
|
||||
mtc_cfg->rate_to = freq;
|
||||
mtc_cfg->train_mode = OP_SWITCH;
|
||||
minerva_cfg(mtc_cfg, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void minerva_periodic_training()
|
||||
{
|
||||
if (!minerva_cfg)
|
||||
return;
|
||||
|
||||
mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg;
|
||||
if (mtc_cfg->rate_from == FREQ_1600)
|
||||
{
|
||||
mtc_cfg->train_mode = OP_PERIODIC_TRAIN;
|
||||
minerva_cfg(mtc_cfg, NULL);
|
||||
}
|
||||
}
|
||||
65
bootloader/mem/minerva.h
Normal file
65
bootloader/mem/minerva.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2019 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _FE_MINERVA_H_
|
||||
#define _FE_MINERVA_H_
|
||||
|
||||
#include "mtc_table.h"
|
||||
#include "../utils/types.h"
|
||||
|
||||
#define MTC_INIT_MAGIC 0x3043544D
|
||||
#define MTC_NEW_MAGIC 0x5243544D
|
||||
|
||||
#define EMC_PERIODIC_TRAIN_MS 250
|
||||
|
||||
typedef struct
|
||||
{
|
||||
s32 rate_to;
|
||||
s32 rate_from;
|
||||
emc_table_t *mtc_table;
|
||||
u32 table_entries;
|
||||
emc_table_t *current_emc_table;
|
||||
u32 train_mode;
|
||||
u32 sdram_id;
|
||||
u32 prev_temp;
|
||||
bool emc_2X_clk_src_is_pllmb;
|
||||
bool fsp_for_src_freq;
|
||||
bool train_ram_patterns;
|
||||
bool init_done;
|
||||
} mtc_config_t;
|
||||
|
||||
enum train_mode_t
|
||||
{
|
||||
OP_SWITCH = 0,
|
||||
OP_TRAIN = 1,
|
||||
OP_TRAIN_SWITCH = 2,
|
||||
OP_PERIODIC_TRAIN = 3,
|
||||
OP_TEMP_COMP = 4
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
FREQ_204 = 204000,
|
||||
FREQ_800 = 800000,
|
||||
FREQ_1600 = 1600000
|
||||
} minerva_freq_t;
|
||||
|
||||
void (*minerva_cfg)(mtc_config_t *mtc_cfg, void *);
|
||||
u32 minerva_init();
|
||||
void minerva_change_freq(minerva_freq_t freq);
|
||||
void minerva_periodic_training();
|
||||
|
||||
#endif
|
||||
560
bootloader/mem/mtc_table.h
Normal file
560
bootloader/mem/mtc_table.h
Normal file
@@ -0,0 +1,560 @@
|
||||
/*
|
||||
* Minerva Training Cell
|
||||
* DRAM Training for Tegra X1 SoC. Supports DDR2/3 and LPDDR3/4.
|
||||
*
|
||||
* Copyright (c) 2018 CTCaer <ctcaer@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _MTC_TABLE_H_
|
||||
#define _MTC_TABLE_H_
|
||||
|
||||
#include "../utils/types.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
s32 pll_osc_in;
|
||||
s32 pll_out;
|
||||
u32 pll_feedback_div;
|
||||
u32 pll_input_div;
|
||||
u32 pll_post_div;
|
||||
} pllm_clk_config_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 emc_rc_idx;
|
||||
u32 emc_rfc_idx;
|
||||
u32 emc_rfcpb_idx;
|
||||
u32 emc_refctrl2_idx;
|
||||
u32 emc_rfc_slr_idx;
|
||||
u32 emc_ras_idx;
|
||||
u32 emc_rp_idx;
|
||||
u32 emc_r2w_idx;
|
||||
u32 emc_w2r_idx;
|
||||
u32 emc_r2p_idx;
|
||||
u32 emc_w2p_idx;
|
||||
u32 emc_r2r_idx;
|
||||
u32 emc_tppd_idx;
|
||||
u32 emc_ccdmw_idx;
|
||||
u32 emc_rd_rcd_idx;
|
||||
u32 emc_wr_rcd_idx;
|
||||
u32 emc_rrd_idx;
|
||||
u32 emc_rext_idx;
|
||||
u32 emc_wext_idx;
|
||||
u32 emc_wdv_chk_idx;
|
||||
u32 emc_wdv_idx;
|
||||
u32 emc_wsv_idx;
|
||||
u32 emc_wev_idx;
|
||||
u32 emc_wdv_mask_idx;
|
||||
u32 emc_ws_duration_idx;
|
||||
u32 emc_we_duration_idx;
|
||||
u32 emc_quse_idx;
|
||||
u32 emc_quse_width_idx;
|
||||
u32 emc_ibdly_idx;
|
||||
u32 emc_obdly_idx;
|
||||
u32 emc_einput_idx;
|
||||
u32 emc_mrw6_idx;
|
||||
u32 emc_einput_duration_idx;
|
||||
u32 emc_puterm_extra_idx;
|
||||
u32 emc_puterm_width_idx;
|
||||
u32 emc_qrst_idx;
|
||||
u32 emc_qsafe_idx;
|
||||
u32 emc_rdv_idx;
|
||||
u32 emc_rdv_mask_idx;
|
||||
u32 emc_rdv_early_idx;
|
||||
u32 emc_rdv_early_mask_idx;
|
||||
u32 emc_refresh_idx;
|
||||
u32 emc_burst_refresh_num_idx;
|
||||
u32 emc_pre_refresh_req_cnt_idx;
|
||||
u32 emc_pdex2wr_idx;
|
||||
u32 emc_pdex2rd_idx;
|
||||
u32 emc_pchg2pden_idx;
|
||||
u32 emc_act2pden_idx;
|
||||
u32 emc_ar2pden_idx;
|
||||
u32 emc_rw2pden_idx;
|
||||
u32 emc_cke2pden_idx;
|
||||
u32 emc_pdex2cke_idx;
|
||||
u32 emc_pdex2mrr_idx;
|
||||
u32 emc_txsr_idx;
|
||||
u32 emc_txsrdll_idx;
|
||||
u32 emc_tcke_idx;
|
||||
u32 emc_tckesr_idx;
|
||||
u32 emc_tpd_idx;
|
||||
u32 emc_tfaw_idx;
|
||||
u32 emc_trpab_idx;
|
||||
u32 emc_tclkstable_idx;
|
||||
u32 emc_tclkstop_idx;
|
||||
u32 emc_mrw7_idx;
|
||||
u32 emc_trefbw_idx;
|
||||
u32 emc_odt_write_idx;
|
||||
u32 emc_fbio_cfg5_idx;
|
||||
u32 emc_fbio_cfg7_idx;
|
||||
u32 emc_cfg_dig_dll_idx;
|
||||
u32 emc_cfg_dig_dll_period_idx;
|
||||
u32 emc_pmacro_ib_rxrt_idx;
|
||||
u32 emc_cfg_pipe_1_idx;
|
||||
u32 emc_cfg_pipe_2_idx;
|
||||
u32 emc_pmacro_quse_ddll_rank0_4_idx;
|
||||
u32 emc_pmacro_quse_ddll_rank0_5_idx;
|
||||
u32 emc_pmacro_quse_ddll_rank1_4_idx;
|
||||
u32 emc_pmacro_quse_ddll_rank1_5_idx;
|
||||
u32 emc_mrw8_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dq_rank1_4_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dq_rank1_5_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dqs_rank0_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dqs_rank0_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dqs_rank0_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dqs_rank0_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dqs_rank0_4_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dqs_rank0_5_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dqs_rank1_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dqs_rank1_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dqs_rank1_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dqs_rank1_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dqs_rank1_4_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dqs_rank1_5_idx;
|
||||
u32 emc_pmacro_ddll_long_cmd_0_idx;
|
||||
u32 emc_pmacro_ddll_long_cmd_1_idx;
|
||||
u32 emc_pmacro_ddll_long_cmd_2_idx;
|
||||
u32 emc_pmacro_ddll_long_cmd_3_idx;
|
||||
u32 emc_pmacro_ddll_long_cmd_4_idx;
|
||||
u32 emc_pmacro_ddll_short_cmd_0_idx;
|
||||
u32 emc_pmacro_ddll_short_cmd_1_idx;
|
||||
u32 emc_pmacro_ddll_short_cmd_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_3_idx;
|
||||
u32 emc_txdsrvttgen_idx;
|
||||
u32 emc_fdpd_ctrl_dq_idx;
|
||||
u32 emc_fdpd_ctrl_cmd_idx;
|
||||
u32 emc_fbio_spare_idx;
|
||||
u32 emc_zcal_interval_idx;
|
||||
u32 emc_zcal_wait_cnt_idx;
|
||||
u32 emc_mrs_wait_cnt_idx;
|
||||
u32 emc_mrs_wait_cnt2_idx;
|
||||
u32 emc_auto_cal_channel_idx;
|
||||
u32 emc_dll_cfg_0_idx;
|
||||
u32 emc_dll_cfg_1_idx;
|
||||
u32 emc_pmacro_autocal_cfg_common_idx;
|
||||
u32 emc_pmacro_zctrl_idx;
|
||||
u32 emc_cfg_idx;
|
||||
u32 emc_cfg_pipe_idx;
|
||||
u32 emc_dyn_self_ref_control_idx;
|
||||
u32 emc_qpop_idx;
|
||||
u32 emc_dqs_brlshft_0_idx;
|
||||
u32 emc_dqs_brlshft_1_idx;
|
||||
u32 emc_cmd_brlshft_2_idx;
|
||||
u32 emc_cmd_brlshft_3_idx;
|
||||
u32 emc_pmacro_pad_cfg_ctrl_idx;
|
||||
u32 emc_pmacro_data_pad_rx_ctrl_idx;
|
||||
u32 emc_pmacro_cmd_pad_rx_ctrl_idx;
|
||||
u32 emc_pmacro_data_rx_term_mode_idx;
|
||||
u32 emc_pmacro_cmd_rx_term_mode_idx;
|
||||
u32 emc_pmacro_cmd_pad_tx_ctrl_idx;
|
||||
u32 emc_pmacro_data_pad_tx_ctrl_idx;
|
||||
u32 emc_pmacro_common_pad_tx_ctrl_idx;
|
||||
u32 emc_pmacro_vttgen_ctrl_0_idx;
|
||||
u32 emc_pmacro_vttgen_ctrl_1_idx;
|
||||
u32 emc_pmacro_vttgen_ctrl_2_idx;
|
||||
u32 emc_pmacro_brick_ctrl_rfu1_idx;
|
||||
u32 emc_pmacro_cmd_brick_ctrl_fdpd_idx;
|
||||
u32 emc_pmacro_brick_ctrl_rfu2_idx;
|
||||
u32 emc_pmacro_data_brick_ctrl_fdpd_idx;
|
||||
u32 emc_pmacro_bg_bias_ctrl_0_idx;
|
||||
u32 emc_cfg_3_idx;
|
||||
u32 emc_pmacro_tx_pwrd_0_idx;
|
||||
u32 emc_pmacro_tx_pwrd_1_idx;
|
||||
u32 emc_pmacro_tx_pwrd_2_idx;
|
||||
u32 emc_pmacro_tx_pwrd_3_idx;
|
||||
u32 emc_pmacro_tx_pwrd_4_idx;
|
||||
u32 emc_pmacro_tx_pwrd_5_idx;
|
||||
u32 emc_config_sample_delay_idx;
|
||||
u32 emc_pmacro_tx_sel_clk_src_0_idx;
|
||||
u32 emc_pmacro_tx_sel_clk_src_1_idx;
|
||||
u32 emc_pmacro_tx_sel_clk_src_2_idx;
|
||||
u32 emc_pmacro_tx_sel_clk_src_3_idx;
|
||||
u32 emc_pmacro_tx_sel_clk_src_4_idx;
|
||||
u32 emc_pmacro_tx_sel_clk_src_5_idx;
|
||||
u32 emc_pmacro_ddll_bypass_idx;
|
||||
u32 emc_pmacro_ddll_pwrd_0_idx;
|
||||
u32 emc_pmacro_ddll_pwrd_1_idx;
|
||||
u32 emc_pmacro_ddll_pwrd_2_idx;
|
||||
u32 emc_pmacro_cmd_ctrl_0_idx;
|
||||
u32 emc_pmacro_cmd_ctrl_1_idx;
|
||||
u32 emc_pmacro_cmd_ctrl_2_idx;
|
||||
u32 emc_tr_timing_0_idx;
|
||||
u32 emc_tr_dvfs_idx;
|
||||
u32 emc_tr_ctrl_1_idx;
|
||||
u32 emc_tr_rdv_idx;
|
||||
u32 emc_tr_qpop_idx;
|
||||
u32 emc_tr_rdv_mask_idx;
|
||||
u32 emc_mrw14_idx;
|
||||
u32 emc_tr_qsafe_idx;
|
||||
u32 emc_tr_qrst_idx;
|
||||
u32 emc_training_ctrl_idx;
|
||||
u32 emc_training_settle_idx;
|
||||
u32 emc_training_vref_settle_idx;
|
||||
u32 emc_training_ca_fine_ctrl_idx;
|
||||
u32 emc_training_ca_ctrl_misc_idx;
|
||||
u32 emc_training_ca_ctrl_misc1_idx;
|
||||
u32 emc_training_ca_vref_ctrl_idx;
|
||||
u32 emc_training_quse_cors_ctrl_idx;
|
||||
u32 emc_training_quse_fine_ctrl_idx;
|
||||
u32 emc_training_quse_ctrl_misc_idx;
|
||||
u32 emc_training_quse_vref_ctrl_idx;
|
||||
u32 emc_training_read_fine_ctrl_idx;
|
||||
u32 emc_training_read_ctrl_misc_idx;
|
||||
u32 emc_training_read_vref_ctrl_idx;
|
||||
u32 emc_training_write_fine_ctrl_idx;
|
||||
u32 emc_training_write_ctrl_misc_idx;
|
||||
u32 emc_training_write_vref_ctrl_idx;
|
||||
u32 emc_training_mpc_idx;
|
||||
u32 emc_mrw15_idx;
|
||||
} burst_regs_t;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 burst_regs[221];
|
||||
u32 burst_reg_per_ch[8];
|
||||
u32 shadow_regs_ca_train[221];
|
||||
u32 shadow_regs_quse_train[221];
|
||||
u32 shadow_regs_rdwr_train[221];
|
||||
} burst_regs_table_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 ptfv_dqsosc_movavg_c0d0u0_idx;
|
||||
u32 ptfv_dqsosc_movavg_c0d0u1_idx;
|
||||
u32 ptfv_dqsosc_movavg_c0d1u0_idx;
|
||||
u32 ptfv_dqsosc_movavg_c0d1u1_idx;
|
||||
u32 ptfv_dqsosc_movavg_c1d0u0_idx;
|
||||
u32 ptfv_dqsosc_movavg_c1d0u1_idx;
|
||||
u32 ptfv_dqsosc_movavg_c1d1u0_idx;
|
||||
u32 ptfv_dqsosc_movavg_c1d1u1_idx;
|
||||
u32 ptfv_write_samples_idx;
|
||||
u32 ptfv_dvfs_samples_idx;
|
||||
u32 ptfv_movavg_weight_idx;
|
||||
u32 ptfv_config_ctrl_idx;
|
||||
} ptfv_list_table_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 emc0_mrw10_idx;
|
||||
u32 emc1_mrw10_idx;
|
||||
u32 emc0_mrw11_idx;
|
||||
u32 emc1_mrw11_idx;
|
||||
u32 emc0_mrw12_idx;
|
||||
u32 emc1_mrw12_idx;
|
||||
u32 emc0_mrw13_idx;
|
||||
u32 emc1_mrw13_idx;
|
||||
} burst_reg_per_ch_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 emc_pmacro_ib_ddll_long_dqs_rank0_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_long_dqs_rank0_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_long_dqs_rank0_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_long_dqs_rank0_3_idx;
|
||||
u32 emc_pmacro_ib_ddll_long_dqs_rank1_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_long_dqs_rank1_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_long_dqs_rank1_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_long_dqs_rank1_3_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte0_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte0_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte0_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte1_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte1_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte1_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte2_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte2_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte2_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte3_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte3_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte3_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte4_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte4_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte4_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte5_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte5_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte5_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte6_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte6_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte6_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte7_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte7_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte7_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte0_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte0_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte0_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte1_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte1_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte1_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte2_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte2_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte2_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte3_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte3_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte3_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte4_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte4_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte4_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte5_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte5_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte5_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte6_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte6_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte6_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte7_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte7_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte7_2_idx;
|
||||
u32 emc_pmacro_ib_vref_dqs_0_idx;
|
||||
u32 emc_pmacro_ib_vref_dqs_1_idx;
|
||||
u32 emc_pmacro_ib_vref_dq_0_idx;
|
||||
u32 emc_pmacro_ib_vref_dq_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dq_rank0_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dq_rank0_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dq_rank0_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dq_rank0_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dq_rank0_4_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dq_rank0_5_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dq_rank1_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dq_rank1_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dq_rank1_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dq_rank1_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_2_idx;
|
||||
u32 emc_pmacro_quse_ddll_rank0_0_idx;
|
||||
u32 emc_pmacro_quse_ddll_rank0_1_idx;
|
||||
u32 emc_pmacro_quse_ddll_rank0_2_idx;
|
||||
u32 emc_pmacro_quse_ddll_rank0_3_idx;
|
||||
u32 emc_pmacro_quse_ddll_rank1_0_idx;
|
||||
u32 emc_pmacro_quse_ddll_rank1_1_idx;
|
||||
u32 emc_pmacro_quse_ddll_rank1_2_idx;
|
||||
u32 emc_pmacro_quse_ddll_rank1_3_idx;
|
||||
} trim_regs_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 emc_cmd_brlshft_0_idx;
|
||||
u32 emc_cmd_brlshft_1_idx;
|
||||
u32 emc0_data_brlshft_0_idx;
|
||||
u32 emc1_data_brlshft_0_idx;
|
||||
u32 emc0_data_brlshft_1_idx;
|
||||
u32 emc1_data_brlshft_1_idx;
|
||||
u32 emc_quse_brlshft_0_idx;
|
||||
u32 emc_quse_brlshft_1_idx;
|
||||
u32 emc_quse_brlshft_2_idx;
|
||||
u32 emc_quse_brlshft_3_idx;
|
||||
} trim_perch_regs_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 t_rp;
|
||||
u32 t_fc_lpddr4;
|
||||
u32 t_rfc;
|
||||
u32 t_pdex;
|
||||
u32 rl;
|
||||
} dram_timings_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 emc0_training_opt_dqs_ib_vref_rank0_idx;
|
||||
u32 emc1_training_opt_dqs_ib_vref_rank0_idx;
|
||||
u32 emc0_training_opt_dqs_ib_vref_rank1_idx;
|
||||
u32 emc1_training_opt_dqs_ib_vref_rank1_idx;
|
||||
} vref_perch_regs_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 trim_regs[138];
|
||||
u32 trim_perch_regs[10];
|
||||
u32 vref_perch_regs[4];
|
||||
} trim_regs_table_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 rev;
|
||||
char dvfs_ver[60];
|
||||
u32 rate_khz;
|
||||
u32 min_volt;
|
||||
u32 gpu_min_volt;
|
||||
char clock_src[32];
|
||||
u32 clk_src_emc;
|
||||
u32 needs_training;
|
||||
u32 training_pattern;
|
||||
u32 trained;
|
||||
u32 periodic_training;
|
||||
u32 trained_dram_clktree_c0d0u0;
|
||||
u32 trained_dram_clktree_c0d0u1;
|
||||
u32 trained_dram_clktree_c0d1u0;
|
||||
u32 trained_dram_clktree_c0d1u1;
|
||||
u32 trained_dram_clktree_c1d0u0;
|
||||
u32 trained_dram_clktree_c1d0u1;
|
||||
u32 trained_dram_clktree_c1d1u0;
|
||||
u32 trained_dram_clktree_c1d1u1;
|
||||
u32 current_dram_clktree_c0d0u0;
|
||||
u32 current_dram_clktree_c0d0u1;
|
||||
u32 current_dram_clktree_c0d1u0;
|
||||
u32 current_dram_clktree_c0d1u1;
|
||||
u32 current_dram_clktree_c1d0u0;
|
||||
u32 current_dram_clktree_c1d0u1;
|
||||
u32 current_dram_clktree_c1d1u0;
|
||||
u32 current_dram_clktree_c1d1u1;
|
||||
u32 run_clocks;
|
||||
u32 tree_margin;
|
||||
u32 num_burst;
|
||||
u32 num_burst_per_ch;
|
||||
u32 num_trim;
|
||||
u32 num_trim_per_ch;
|
||||
u32 num_mc_regs;
|
||||
u32 num_up_down;
|
||||
u32 vref_num;
|
||||
u32 training_mod_num;
|
||||
u32 dram_timing_num;
|
||||
|
||||
ptfv_list_table_t ptfv_list;
|
||||
|
||||
burst_regs_t burst_regs;
|
||||
burst_reg_per_ch_t burst_reg_per_ch;
|
||||
burst_regs_t shadow_regs_ca_train;
|
||||
burst_regs_t shadow_regs_quse_train;
|
||||
burst_regs_t shadow_regs_rdwr_train;
|
||||
trim_regs_t trim_regs;
|
||||
trim_perch_regs_t trim_perch_regs;
|
||||
vref_perch_regs_t vref_perch_regs;
|
||||
dram_timings_t dram_timings;
|
||||
|
||||
u32 training_mod_regs[20];
|
||||
u32 save_restore_mod_regs[12];
|
||||
u32 burst_mc_regs[33];
|
||||
u32 la_scale_regs[24];
|
||||
|
||||
u32 min_mrs_wait;
|
||||
u32 emc_mrw;
|
||||
u32 emc_mrw2;
|
||||
u32 emc_mrw3;
|
||||
u32 emc_mrw4;
|
||||
u32 emc_mrw9;
|
||||
u32 emc_mrs;
|
||||
u32 emc_emrs;
|
||||
u32 emc_emrs2;
|
||||
u32 emc_auto_cal_config;
|
||||
u32 emc_auto_cal_config2;
|
||||
u32 emc_auto_cal_config3;
|
||||
u32 emc_auto_cal_config4;
|
||||
u32 emc_auto_cal_config5;
|
||||
u32 emc_auto_cal_config6;
|
||||
u32 emc_auto_cal_config7;
|
||||
u32 emc_auto_cal_config8;
|
||||
u32 emc_cfg_2;
|
||||
u32 emc_sel_dpd_ctrl;
|
||||
u32 emc_fdpd_ctrl_cmd_no_ramp;
|
||||
u32 dll_clk_src;
|
||||
u32 clk_out_enb_x_0_clk_enb_emc_dll;
|
||||
u32 latency;
|
||||
} emc_table_t;
|
||||
|
||||
#endif
|
||||
@@ -1,5 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018 balika011
|
||||
* Copyright (c) 2019-2020 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -14,18 +16,22 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "../soc/i2c.h"
|
||||
#include "../soc/t210.h"
|
||||
#include <string.h>
|
||||
|
||||
#include "mc.h"
|
||||
#include "emc.h"
|
||||
#include "../soc/pmc.h"
|
||||
#include "../utils/util.h"
|
||||
#include "../soc/fuse.h"
|
||||
#include "sdram_param_t210.h"
|
||||
#include "../../common/memory_map.h"
|
||||
#include "../power/max77620.h"
|
||||
#include "../mem/sdram_param_t210.h"
|
||||
#include "../power/max7762x.h"
|
||||
#include "../soc/clock.h"
|
||||
#include "../soc/fuse.h"
|
||||
#include "../soc/i2c.h"
|
||||
#include "../soc/pmc.h"
|
||||
#include "../soc/t210.h"
|
||||
#include "../utils/util.h"
|
||||
|
||||
#define CONFIG_SDRAM_COMPRESS_CFG
|
||||
#define CONFIG_SDRAM_KEEP_ALIVE
|
||||
|
||||
#ifdef CONFIG_SDRAM_COMPRESS_CFG
|
||||
#include "../libs/compr/lz.h"
|
||||
@@ -36,25 +42,91 @@
|
||||
|
||||
static u32 _get_sdram_id()
|
||||
{
|
||||
return (fuse_read_odm(4) & 0x38) >> 3;
|
||||
return ((fuse_read_odm(4) & 0x38) >> 3);
|
||||
}
|
||||
|
||||
static bool _sdram_wait_emc_status(u32 reg_offset, u32 bit_mask, bool updated_state, s32 emc_channel)
|
||||
{
|
||||
bool err = true;
|
||||
|
||||
for (s32 i = 0; i < EMC_STATUS_UPDATE_TIMEOUT; i++)
|
||||
{
|
||||
if (emc_channel)
|
||||
{
|
||||
if (emc_channel != 1)
|
||||
goto done;
|
||||
|
||||
if (((EMC_CH1(reg_offset) & bit_mask) != 0) == updated_state)
|
||||
{
|
||||
err = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (((EMC(reg_offset) & bit_mask) != 0) == updated_state)
|
||||
{
|
||||
err = false;
|
||||
break;
|
||||
}
|
||||
usleep(1);
|
||||
}
|
||||
|
||||
done:
|
||||
return err;
|
||||
}
|
||||
|
||||
static void _sdram_req_mrr_data(u32 data, bool dual_channel)
|
||||
{
|
||||
EMC(EMC_MRR) = data;
|
||||
_sdram_wait_emc_status(EMC_EMC_STATUS, EMC_STATUS_MRR_DIVLD, true, EMC_CHAN0);
|
||||
if (dual_channel)
|
||||
_sdram_wait_emc_status(EMC_EMC_STATUS, EMC_STATUS_MRR_DIVLD, true, EMC_CHAN1);
|
||||
}
|
||||
|
||||
emc_mr_data_t sdram_read_mrx(emc_mr_t mrx)
|
||||
{
|
||||
emc_mr_data_t data;
|
||||
_sdram_req_mrr_data((1 << 31) | (mrx << 16), EMC_CHAN0);
|
||||
data.dev0_ch0 = EMC(EMC_MRR) & 0xFF;
|
||||
data.dev0_ch1 = (EMC(EMC_MRR) & 0xFF00 >> 8);
|
||||
_sdram_req_mrr_data((1 << 30) | (mrx << 16), EMC_CHAN1);
|
||||
data.dev1_ch0 = EMC(EMC_MRR) & 0xFF;
|
||||
data.dev1_ch1 = (EMC(EMC_MRR) & 0xFF00 >> 8);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static void _sdram_config(const sdram_params_t *params)
|
||||
{
|
||||
PMC(0x45C) = (((4 * params->emc_pmc_scratch1 >> 2) + 0x80000000) ^ 0xFFFF) & 0xC000FFFF;
|
||||
// Program DPD3/DPD4 regs (coldboot path).
|
||||
// Enable sel_dpd on unused pins.
|
||||
u32 dpd_req = (params->emc_pmc_scratch1 & 0x3FFFFFFF) | 0x80000000;
|
||||
PMC(APBDEV_PMC_IO_DPD3_REQ) = (dpd_req ^ 0xFFFF) & 0xC000FFFF;
|
||||
usleep(params->pmc_io_dpd3_req_wait);
|
||||
|
||||
u32 req = (4 * params->emc_pmc_scratch2 >> 2) + 0x80000000;
|
||||
PMC(APBDEV_PMC_IO_DPD4_REQ) = (req >> 16 << 16) ^ 0x3FFF0000;
|
||||
// Disable e_dpd_vttgen.
|
||||
dpd_req = (params->emc_pmc_scratch2 & 0x3FFFFFFF) | 0x80000000;
|
||||
PMC(APBDEV_PMC_IO_DPD4_REQ) = (dpd_req & 0xFFFF0000) ^ 0x3FFF0000;
|
||||
usleep(params->pmc_io_dpd4_req_wait);
|
||||
PMC(APBDEV_PMC_IO_DPD4_REQ) = (req ^ 0xFFFF) & 0xC000FFFF;
|
||||
|
||||
// Disable e_dpd_bg.
|
||||
PMC(APBDEV_PMC_IO_DPD4_REQ) = (dpd_req ^ 0xFFFF) & 0xC000FFFF;
|
||||
usleep(params->pmc_io_dpd4_req_wait);
|
||||
|
||||
PMC(APBDEV_PMC_WEAK_BIAS) = 0;
|
||||
usleep(1);
|
||||
|
||||
// Start clocks.
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLM_MISC1) = params->pllm_setup_control;
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLM_MISC2) = 0;
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = (params->pllm_feedback_divider << 8) | params->pllm_input_divider | 0x40000000 | ((params->pllm_post_divider & 0xFFFF) << 20);
|
||||
|
||||
#ifdef CONFIG_SDRAM_KEEP_ALIVE
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) =
|
||||
(params->pllm_feedback_divider << 8) | params->pllm_input_divider | ((params->pllm_post_divider & 0xFFFF) << 20) | PLLCX_BASE_ENABLE;
|
||||
#else
|
||||
u32 pllm_div = (params->pllm_feedback_divider << 8) | params->pllm_input_divider | ((params->pllm_post_divider & 0xFFFF) << 20);
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = pllm_div;
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = pllm_div | PLLCX_BASE_ENABLE;
|
||||
#endif
|
||||
|
||||
u32 wait_end = get_tmr_us() + 300;
|
||||
while (!(CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) & 0x8000000))
|
||||
@@ -63,24 +135,35 @@ static void _sdram_config(const sdram_params_t *params)
|
||||
goto break_nosleep;
|
||||
}
|
||||
usleep(10);
|
||||
break_nosleep:
|
||||
|
||||
break_nosleep:
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = ((params->mc_emem_arb_misc0 >> 11) & 0x10000) | (params->emc_clock_source & 0xFFFEFFFF);
|
||||
if (params->emc_clock_source_dll)
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL) = params->emc_clock_source_dll;
|
||||
if (params->clear_clock2_mc1)
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_CLR) = 0x40000000;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = 0x2000001;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = 0x4000;
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = 0x2000001;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_CLR) = 0x40000000; // Clear Reset to MC1.
|
||||
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = 0x2000001; // Enable EMC and MEM clocks.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = 0x4000; // Enable EMC_DLL clock.
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = 0x2000001; // Clear EMC and MEM resets.
|
||||
|
||||
// Set pad macros.
|
||||
EMC(EMC_PMACRO_VTTGEN_CTRL_0) = params->emc_pmacro_vttgen_ctrl0;
|
||||
EMC(EMC_PMACRO_VTTGEN_CTRL_1) = params->emc_pmacro_vttgen_ctrl1;
|
||||
EMC(EMC_PMACRO_VTTGEN_CTRL_2) = params->emc_pmacro_vttgen_ctrl2;
|
||||
EMC(EMC_TIMING_CONTROL) = 1;
|
||||
usleep(1);
|
||||
|
||||
EMC(EMC_TIMING_CONTROL) = 1; // Trigger timing update so above writes take place.
|
||||
usleep(10); // Ensure the regulators settle.
|
||||
|
||||
// Select EMC write mux.
|
||||
EMC(EMC_DBG) = (params->emc_dbg_write_mux << 1) | params->emc_dbg;
|
||||
|
||||
// Patch 2 using BCT spare variables.
|
||||
if (params->emc_bct_spare2)
|
||||
*(vu32 *)params->emc_bct_spare2 = params->emc_bct_spare3;
|
||||
|
||||
// Program CMD mapping. Required before brick mapping, else
|
||||
// we can't guarantee CK will be differential at all times.
|
||||
EMC(EMC_FBIO_CFG7) = params->emc_fbio_cfg7;
|
||||
EMC(EMC_CMD_MAPPING_CMD0_0) = params->emc_cmd_mapping_cmd0_0;
|
||||
EMC(EMC_CMD_MAPPING_CMD0_1) = params->emc_cmd_mapping_cmd0_1;
|
||||
@@ -95,25 +178,40 @@ break_nosleep:
|
||||
EMC(EMC_CMD_MAPPING_CMD3_1) = params->emc_cmd_mapping_cmd3_1;
|
||||
EMC(EMC_CMD_MAPPING_CMD3_2) = params->emc_cmd_mapping_cmd3_2;
|
||||
EMC(EMC_CMD_MAPPING_BYTE) = params->emc_cmd_mapping_byte;
|
||||
|
||||
// Program brick mapping.
|
||||
EMC(EMC_PMACRO_BRICK_MAPPING_0) = params->emc_pmacro_brick_mapping0;
|
||||
EMC(EMC_PMACRO_BRICK_MAPPING_1) = params->emc_pmacro_brick_mapping1;
|
||||
EMC(EMC_PMACRO_BRICK_MAPPING_2) = params->emc_pmacro_brick_mapping2;
|
||||
|
||||
EMC(EMC_PMACRO_BRICK_CTRL_RFU1) = (params->emc_pmacro_brick_ctrl_rfu1 & 0x1120112) | 0x1EED1EED;
|
||||
|
||||
// This is required to do any reads from the pad macros.
|
||||
EMC(EMC_CONFIG_SAMPLE_DELAY) = params->emc_config_sample_delay;
|
||||
|
||||
EMC(EMC_FBIO_CFG8) = params->emc_fbio_cfg8;
|
||||
|
||||
// Set swizzle for Rank 0.
|
||||
EMC(EMC_SWIZZLE_RANK0_BYTE0) = params->emc_swizzle_rank0_byte0;
|
||||
EMC(EMC_SWIZZLE_RANK0_BYTE1) = params->emc_swizzle_rank0_byte1;
|
||||
EMC(EMC_SWIZZLE_RANK0_BYTE2) = params->emc_swizzle_rank0_byte2;
|
||||
EMC(EMC_SWIZZLE_RANK0_BYTE3) = params->emc_swizzle_rank0_byte3;
|
||||
// Set swizzle for Rank 1.
|
||||
EMC(EMC_SWIZZLE_RANK1_BYTE0) = params->emc_swizzle_rank1_byte0;
|
||||
EMC(EMC_SWIZZLE_RANK1_BYTE1) = params->emc_swizzle_rank1_byte1;
|
||||
EMC(EMC_SWIZZLE_RANK1_BYTE2) = params->emc_swizzle_rank1_byte2;
|
||||
EMC(EMC_SWIZZLE_RANK1_BYTE3) = params->emc_swizzle_rank1_byte3;
|
||||
|
||||
// Patch 4 using BCT spare variables.
|
||||
if (params->emc_bct_spare6)
|
||||
*(vu32 *)params->emc_bct_spare6 = params->emc_bct_spare7;
|
||||
|
||||
// Set pad controls.
|
||||
EMC(EMC_XM2COMPPADCTRL) = params->emc_xm2_comp_pad_ctrl;
|
||||
EMC(EMC_XM2COMPPADCTRL2) = params->emc_xm2_comp_pad_ctrl2;
|
||||
EMC(EMC_XM2COMPPADCTRL3) = params->emc_xm2_comp_pad_ctrl3;
|
||||
|
||||
// Program Autocal controls with shadowed register fields.
|
||||
EMC(EMC_AUTO_CAL_CONFIG2) = params->emc_auto_cal_config2;
|
||||
EMC(EMC_AUTO_CAL_CONFIG3) = params->emc_auto_cal_config3;
|
||||
EMC(EMC_AUTO_CAL_CONFIG4) = params->emc_auto_cal_config4;
|
||||
@@ -121,6 +219,7 @@ break_nosleep:
|
||||
EMC(EMC_AUTO_CAL_CONFIG6) = params->emc_auto_cal_config6;
|
||||
EMC(EMC_AUTO_CAL_CONFIG7) = params->emc_auto_cal_config7;
|
||||
EMC(EMC_AUTO_CAL_CONFIG8) = params->emc_auto_cal_config8;
|
||||
|
||||
EMC(EMC_PMACRO_RX_TERM) = params->emc_pmacro_rx_term;
|
||||
EMC(EMC_PMACRO_DQ_TX_DRV) = params->emc_pmacro_dq_tx_drive;
|
||||
EMC(EMC_PMACRO_CA_TX_DRV) = params->emc_pmacro_ca_tx_drive;
|
||||
@@ -128,9 +227,11 @@ break_nosleep:
|
||||
EMC(EMC_PMACRO_AUTOCAL_CFG_COMMON) = params->emc_pmacro_auto_cal_common;
|
||||
EMC(EMC_AUTO_CAL_CHANNEL) = params->emc_auto_cal_channel;
|
||||
EMC(EMC_PMACRO_ZCTRL) = params->emc_pmacro_zcrtl;
|
||||
|
||||
EMC(EMC_DLL_CFG_0) = params->emc_dll_cfg0;
|
||||
EMC(EMC_DLL_CFG_1) = params->emc_dll_cfg1;
|
||||
EMC(EMC_CFG_DIG_DLL_1) = params->emc_cfg_dig_dll_1;
|
||||
|
||||
EMC(EMC_DATA_BRLSHFT_0) = params->emc_data_brlshft0;
|
||||
EMC(EMC_DATA_BRLSHFT_1) = params->emc_data_brlshft1;
|
||||
EMC(EMC_DQS_BRLSHFT_0) = params->emc_dqs_brlshft0;
|
||||
@@ -143,8 +244,10 @@ break_nosleep:
|
||||
EMC(EMC_QUSE_BRLSHFT_1) = params->emc_quse_brlshft1;
|
||||
EMC(EMC_QUSE_BRLSHFT_2) = params->emc_quse_brlshft2;
|
||||
EMC(EMC_QUSE_BRLSHFT_3) = params->emc_quse_brlshft3;
|
||||
|
||||
EMC(EMC_PMACRO_BRICK_CTRL_RFU1) = (params->emc_pmacro_brick_ctrl_rfu1 & 0x1BF01BF) | 0x1E401E40;
|
||||
EMC(EMC_PMACRO_PAD_CFG_CTRL) = params->emc_pmacro_pad_cfg_ctrl;
|
||||
|
||||
EMC(EMC_PMACRO_CMD_BRICK_CTRL_FDPD) = params->emc_pmacro_cmd_brick_ctrl_fdpd;
|
||||
EMC(EMC_PMACRO_BRICK_CTRL_RFU2) = params->emc_pmacro_brick_ctrl_rfu2 & 0xFF7FFF7F;
|
||||
EMC(EMC_PMACRO_DATA_BRICK_CTRL_FDPD) = params->emc_pmacro_data_brick_ctrl_fdpd;
|
||||
@@ -155,6 +258,7 @@ break_nosleep:
|
||||
EMC(EMC_PMACRO_DATA_RX_TERM_MODE) = params->emc_pmacro_data_rx_term_mode;
|
||||
EMC(EMC_PMACRO_CMD_RX_TERM_MODE) = params->emc_pmacro_cmd_rx_term_mode;
|
||||
EMC(EMC_PMACRO_CMD_PAD_TX_CTRL) = params->emc_pmacro_cmd_pad_tx_ctrl;
|
||||
|
||||
EMC(EMC_CFG_3) = params->emc_cfg3;
|
||||
EMC(EMC_PMACRO_TX_PWRD_0) = params->emc_pmacro_tx_pwrd0;
|
||||
EMC(EMC_PMACRO_TX_PWRD_1) = params->emc_pmacro_tx_pwrd1;
|
||||
@@ -180,6 +284,7 @@ break_nosleep:
|
||||
EMC(EMC_PMACRO_IB_VREF_DQS_0) = params->emc_pmacro_ib_vref_dqs_0;
|
||||
EMC(EMC_PMACRO_IB_VREF_DQS_1) = params->emc_pmacro_ib_vref_dqs_1;
|
||||
EMC(EMC_PMACRO_IB_RXRT) = params->emc_pmacro_ib_rxrt;
|
||||
|
||||
EMC(EMC_PMACRO_QUSE_DDLL_RANK0_0) = params->emc_pmacro_quse_ddll_rank0_0;
|
||||
EMC(EMC_PMACRO_QUSE_DDLL_RANK0_1) = params->emc_pmacro_quse_ddll_rank0_1;
|
||||
EMC(EMC_PMACRO_QUSE_DDLL_RANK0_2) = params->emc_pmacro_quse_ddll_rank0_2;
|
||||
@@ -193,6 +298,7 @@ break_nosleep:
|
||||
EMC(EMC_PMACRO_QUSE_DDLL_RANK1_4) = params->emc_pmacro_quse_ddll_rank1_4;
|
||||
EMC(EMC_PMACRO_QUSE_DDLL_RANK1_5) = params->emc_pmacro_quse_ddll_rank1_5;
|
||||
EMC(EMC_PMACRO_BRICK_CTRL_RFU1) = params->emc_pmacro_brick_ctrl_rfu1;
|
||||
|
||||
EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0) = params->emc_pmacro_ob_ddll_long_dq_rank0_0;
|
||||
EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1) = params->emc_pmacro_ob_ddll_long_dq_rank0_1;
|
||||
EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2) = params->emc_pmacro_ob_ddll_long_dq_rank0_2;
|
||||
@@ -205,6 +311,7 @@ break_nosleep:
|
||||
EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3) = params->emc_pmacro_ob_ddll_long_dq_rank1_3;
|
||||
EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_4) = params->emc_pmacro_ob_ddll_long_dq_rank1_4;
|
||||
EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_5) = params->emc_pmacro_ob_ddll_long_dq_rank1_5;
|
||||
|
||||
EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_0) = params->emc_pmacro_ob_ddll_long_dqs_rank0_0;
|
||||
EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_1) = params->emc_pmacro_ob_ddll_long_dqs_rank0_1;
|
||||
EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_2) = params->emc_pmacro_ob_ddll_long_dqs_rank0_2;
|
||||
@@ -225,6 +332,7 @@ break_nosleep:
|
||||
EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_1) = params->emc_pmacro_ib_ddll_long_dqs_rank1_1;
|
||||
EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_2) = params->emc_pmacro_ib_ddll_long_dqs_rank1_2;
|
||||
EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_3) = params->emc_pmacro_ib_ddll_long_dqs_rank1_3;
|
||||
|
||||
EMC(EMC_PMACRO_DDLL_LONG_CMD_0) = params->emc_pmacro_ddll_long_cmd_0;
|
||||
EMC(EMC_PMACRO_DDLL_LONG_CMD_1) = params->emc_pmacro_ddll_long_cmd_1;
|
||||
EMC(EMC_PMACRO_DDLL_LONG_CMD_2) = params->emc_pmacro_ddll_long_cmd_2;
|
||||
@@ -233,10 +341,17 @@ break_nosleep:
|
||||
EMC(EMC_PMACRO_DDLL_SHORT_CMD_0) = params->emc_pmacro_ddll_short_cmd_0;
|
||||
EMC(EMC_PMACRO_DDLL_SHORT_CMD_1) = params->emc_pmacro_ddll_short_cmd_1;
|
||||
EMC(EMC_PMACRO_DDLL_SHORT_CMD_2) = params->emc_pmacro_ddll_short_cmd_2;
|
||||
|
||||
// Common pad macro (cpm).
|
||||
EMC(EMC_PMACRO_COMMON_PAD_TX_CTRL) = (params->emc_pmacro_common_pad_tx_ctrl & 1) | 0xE;
|
||||
|
||||
// Patch 3 using BCT spare variables.
|
||||
if (params->emc_bct_spare4)
|
||||
*(vu32 *)params->emc_bct_spare4 = params->emc_bct_spare5;
|
||||
EMC(EMC_TIMING_CONTROL) = 1;
|
||||
|
||||
EMC(EMC_TIMING_CONTROL) = 1; // Trigger timing update so above writes take place.
|
||||
|
||||
// Initialize MC VPR settings.
|
||||
MC(MC_VIDEO_PROTECT_BOM) = params->mc_video_protect_bom;
|
||||
MC(MC_VIDEO_PROTECT_BOM_ADR_HI) = params->mc_video_protect_bom_adr_hi;
|
||||
MC(MC_VIDEO_PROTECT_SIZE_MB) = params->mc_video_protect_size_mb;
|
||||
@@ -244,20 +359,32 @@ break_nosleep:
|
||||
MC(MC_VIDEO_PROTECT_VPR_OVERRIDE1) = params->mc_video_protect_vpr_override1;
|
||||
MC(MC_VIDEO_PROTECT_GPU_OVERRIDE_0) = params->mc_video_protect_gpu_override0;
|
||||
MC(MC_VIDEO_PROTECT_GPU_OVERRIDE_1) = params->mc_video_protect_gpu_override1;
|
||||
|
||||
// Program SDRAM geometry parameters.
|
||||
MC(MC_EMEM_ADR_CFG) = params->mc_emem_adr_cfg;
|
||||
MC(MC_EMEM_ADR_CFG_DEV0) = params->mc_emem_adr_cfg_dev0;
|
||||
MC(MC_EMEM_ADR_CFG_DEV1) = params->mc_emem_adr_cfg_dev1;
|
||||
MC(MC_EMEM_ADR_CFG_CHANNEL_MASK) = params->mc_emem_adr_cfg_channel_mask;
|
||||
|
||||
// Program bank swizzling.
|
||||
MC(MC_EMEM_ADR_CFG_BANK_MASK_0) = params->mc_emem_adr_cfg_bank_mask0;
|
||||
MC(MC_EMEM_ADR_CFG_BANK_MASK_1) = params->mc_emem_adr_cfg_bank_mask1;
|
||||
MC(MC_EMEM_ADR_CFG_BANK_MASK_2) = params->mc_emem_adr_cfg_bank_mask2;
|
||||
|
||||
// Program external memory aperture (base and size).
|
||||
MC(MC_EMEM_CFG) = params->mc_emem_cfg;
|
||||
|
||||
// Program SEC carveout (base and size).
|
||||
MC(MC_SEC_CARVEOUT_BOM) = params->mc_sec_carveout_bom;
|
||||
MC(MC_SEC_CARVEOUT_ADR_HI) = params->mc_sec_carveout_adr_hi;
|
||||
MC(MC_SEC_CARVEOUT_SIZE_MB) = params->mc_sec_carveout_size_mb;
|
||||
|
||||
// Program MTS carveout (base and size).
|
||||
MC(MC_MTS_CARVEOUT_BOM) = params->mc_mts_carveout_bom;
|
||||
MC(MC_MTS_CARVEOUT_ADR_HI) = params->mc_mts_carveout_adr_hi;
|
||||
MC(MC_MTS_CARVEOUT_SIZE_MB) = params->mc_mts_carveout_size_mb;
|
||||
|
||||
// Program the memory arbiter.
|
||||
MC(MC_EMEM_ARB_CFG) = params->mc_emem_arb_cfg;
|
||||
MC(MC_EMEM_ARB_OUTSTANDING_REQ) = params->mc_emem_arb_outstanding_req;
|
||||
MC(MC_EMEM_ARB_REFPB_HP_CTRL) = params->emc_emem_arb_refpb_hp_ctrl;
|
||||
@@ -286,21 +413,38 @@ break_nosleep:
|
||||
MC(MC_EMEM_ARB_OVERRIDE_1) = params->mc_emem_arb_override1;
|
||||
MC(MC_EMEM_ARB_RSV) = params->mc_emem_arb_rsv;
|
||||
MC(MC_DA_CONFIG0) = params->mc_da_cfg0;
|
||||
MC(MC_TIMING_CONTROL) = 1;
|
||||
|
||||
MC(MC_TIMING_CONTROL) = 1; // Trigger MC timing update.
|
||||
|
||||
// Program second-level clock enable overrides.
|
||||
MC(MC_CLKEN_OVERRIDE) = params->mc_clken_override;
|
||||
|
||||
// Program statistics gathering.
|
||||
MC(MC_STAT_CONTROL) = params->mc_stat_control;
|
||||
|
||||
// Program SDRAM geometry parameters.
|
||||
EMC(EMC_ADR_CFG) = params->emc_adr_cfg;
|
||||
|
||||
// Program second-level clock enable overrides.
|
||||
EMC(EMC_CLKEN_OVERRIDE) = params->emc_clken_override;
|
||||
|
||||
// Program EMC pad auto calibration.
|
||||
EMC(EMC_PMACRO_AUTOCAL_CFG_0) = params->emc_pmacro_auto_cal_cfg0;
|
||||
EMC(EMC_PMACRO_AUTOCAL_CFG_1) = params->emc_pmacro_auto_cal_cfg1;
|
||||
EMC(EMC_PMACRO_AUTOCAL_CFG_2) = params->emc_pmacro_auto_cal_cfg2;
|
||||
|
||||
EMC(EMC_AUTO_CAL_VREF_SEL_0) = params->emc_auto_cal_vref_sel0;
|
||||
EMC(EMC_AUTO_CAL_VREF_SEL_1) = params->emc_auto_cal_vref_sel1;
|
||||
|
||||
EMC(EMC_AUTO_CAL_INTERVAL) = params->emc_auto_cal_interval;
|
||||
EMC(EMC_AUTO_CAL_CONFIG) = params->emc_auto_cal_config;
|
||||
usleep(params->emc_auto_cal_wait);
|
||||
|
||||
// Patch 5 using BCT spare variables.
|
||||
if (params->emc_bct_spare8)
|
||||
*(vu32 *)params->emc_bct_spare8 = params->emc_bct_spare9;
|
||||
|
||||
// Program EMC timing configuration.
|
||||
EMC(EMC_CFG_2) = params->emc_cfg2;
|
||||
EMC(EMC_CFG_PIPE) = params->emc_cfg_pipe;
|
||||
EMC(EMC_CFG_PIPE_1) = params->emc_cfg_pipe1;
|
||||
@@ -345,9 +489,11 @@ break_nosleep:
|
||||
EMC(EMC_EINPUT_DURATION) = params->emc_einput_duration;
|
||||
EMC(EMC_PUTERM_EXTRA) = params->emc_puterm_extra;
|
||||
EMC(EMC_PUTERM_WIDTH) = params->emc_puterm_width;
|
||||
|
||||
EMC(EMC_PMACRO_COMMON_PAD_TX_CTRL) = params->emc_pmacro_common_pad_tx_ctrl;
|
||||
EMC(EMC_DBG) = params->emc_dbg;
|
||||
EMC(EMC_QRST) = params->emc_qrst;
|
||||
EMC(EMC_ISSUE_QRST) = 1;
|
||||
EMC(EMC_ISSUE_QRST) = 0;
|
||||
EMC(EMC_QSAFE) = params->emc_qsafe;
|
||||
EMC(EMC_RDV) = params->emc_rdv;
|
||||
@@ -380,6 +526,8 @@ break_nosleep:
|
||||
EMC(EMC_ODT_WRITE) = params->emc_odt_write;
|
||||
EMC(EMC_CFG_DIG_DLL) = params->emc_cfg_dig_dll;
|
||||
EMC(EMC_CFG_DIG_DLL_PERIOD) = params->emc_cfg_dig_dll_period;
|
||||
|
||||
// Don't write CFG_ADR_EN (bit 1) here - lock bit written later.
|
||||
EMC(EMC_FBIO_SPARE) = params->emc_fbio_spare & 0xFFFFFFFD;
|
||||
EMC(EMC_CFG_RSV) = params->emc_cfg_rsv;
|
||||
EMC(EMC_PMC_SCRATCH1) = params->emc_pmc_scratch1;
|
||||
@@ -387,70 +535,104 @@ break_nosleep:
|
||||
EMC(EMC_PMC_SCRATCH3) = params->emc_pmc_scratch3;
|
||||
EMC(EMC_ACPD_CONTROL) = params->emc_acpd_control;
|
||||
EMC(EMC_TXDSRVTTGEN) = params->emc_txdsrvttgen;
|
||||
|
||||
// Set pipe bypass enable bits before sending any DRAM commands.
|
||||
EMC(EMC_CFG) = (params->emc_cfg & 0xE) | 0x3C00000;
|
||||
if (params->boot_rom_patch_control & 0x80000000)
|
||||
|
||||
// Patch BootROM.
|
||||
if (params->boot_rom_patch_control & (1 << 31))
|
||||
{
|
||||
*(vu32 *)(4 * (params->boot_rom_patch_control + 0x1C000000)) = params->boot_rom_patch_data;
|
||||
MC(MC_TIMING_CONTROL) = 1;
|
||||
*(vu32 *)(APB_MISC_BASE + params->boot_rom_patch_control * 4) = params->boot_rom_patch_data;
|
||||
MC(MC_TIMING_CONTROL) = 1; // Trigger MC timing update.
|
||||
}
|
||||
PMC(0x45C) = ((4 * params->emc_pmc_scratch1 >> 2) + 0x40000000) & 0xCFFF0000;
|
||||
|
||||
// Release SEL_DPD_CMD.
|
||||
PMC(APBDEV_PMC_IO_DPD3_REQ) = ((params->emc_pmc_scratch1 & 0x3FFFFFFF) | 0x40000000) & 0xCFFF0000;
|
||||
usleep(params->pmc_io_dpd3_req_wait);
|
||||
|
||||
// Set autocal interval if not configured.
|
||||
if (!params->emc_auto_cal_interval)
|
||||
EMC(EMC_AUTO_CAL_CONFIG) = params->emc_auto_cal_config | 0x200;
|
||||
|
||||
EMC(EMC_PMACRO_BRICK_CTRL_RFU2) = params->emc_pmacro_brick_ctrl_rfu2;
|
||||
|
||||
// ZQ CAL setup (not actually issuing ZQ CAL now).
|
||||
if (params->emc_zcal_warm_cold_boot_enables & 1)
|
||||
{
|
||||
if (params->memory_type == 2)
|
||||
EMC(EMC_ZCAL_WAIT_CNT) = 8 * params->emc_zcal_wait_cnt;
|
||||
if (params->memory_type == 3)
|
||||
if (params->memory_type == MEMORY_TYPE_DDR3L)
|
||||
EMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt << 3;
|
||||
if (params->memory_type == MEMORY_TYPE_LPDDR4)
|
||||
{
|
||||
EMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt;
|
||||
EMC(EMC_ZCAL_MRW_CMD) = params->emc_zcal_mrw_cmd;
|
||||
}
|
||||
}
|
||||
EMC(EMC_TIMING_CONTROL) = 1;
|
||||
|
||||
EMC(EMC_TIMING_CONTROL) = 1; // Trigger timing update so above writes take place.
|
||||
usleep(params->emc_timing_control_wait);
|
||||
PMC(0x4E4) &= 0xFFF8007F;
|
||||
|
||||
// Deassert HOLD_CKE_LOW.
|
||||
PMC(APBDEV_PMC_DDR_CNTRL) &= 0xFFF8007F;
|
||||
usleep(params->pmc_ddr_ctrl_wait);
|
||||
if (params->memory_type == 2)
|
||||
|
||||
// Set clock enable signal.
|
||||
u32 pin_gpio_cfg = (params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12);
|
||||
if (params->memory_type == MEMORY_TYPE_DDR3L || params->memory_type == MEMORY_TYPE_LPDDR4)
|
||||
{
|
||||
EMC(EMC_PIN) = (params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12);
|
||||
EMC(EMC_PIN) = pin_gpio_cfg;
|
||||
(void)EMC(EMC_PIN);
|
||||
usleep(params->emc_pin_extra_wait + 200);
|
||||
EMC(EMC_PIN) = ((params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12)) + 256;
|
||||
usleep(params->emc_pin_extra_wait + 500);
|
||||
EMC(EMC_PIN) = pin_gpio_cfg | 0x100;
|
||||
(void)EMC(EMC_PIN);
|
||||
}
|
||||
if (params->memory_type == 3)
|
||||
{
|
||||
EMC(EMC_PIN) = (params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12);
|
||||
usleep(params->emc_pin_extra_wait + 200);
|
||||
EMC(EMC_PIN) = ((params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12)) + 256;
|
||||
|
||||
if (params->memory_type == MEMORY_TYPE_LPDDR4)
|
||||
usleep(params->emc_pin_extra_wait + 2000);
|
||||
}
|
||||
EMC(EMC_PIN) = ((params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12)) + 0x101;
|
||||
else if (params->memory_type == MEMORY_TYPE_DDR3L)
|
||||
usleep(params->emc_pin_extra_wait + 500);
|
||||
|
||||
// Enable clock enable signal.
|
||||
EMC(EMC_PIN) = pin_gpio_cfg | 0x101;
|
||||
(void)EMC(EMC_PIN);
|
||||
usleep(params->emc_pin_program_wait);
|
||||
if (params->memory_type != 3)
|
||||
|
||||
// Send NOP (trigger just needs to be non-zero).
|
||||
if (params->memory_type != MEMORY_TYPE_LPDDR4)
|
||||
EMC(EMC_NOP) = (params->emc_dev_select << 30) + 1;
|
||||
if (params->memory_type == 1)
|
||||
|
||||
// On coldboot w/LPDDR2/3, wait 200 uSec after asserting CKE high.
|
||||
if (params->memory_type == MEMORY_TYPE_LPDDR2)
|
||||
usleep(params->emc_pin_extra_wait + 200);
|
||||
if (params->memory_type == 3)
|
||||
|
||||
// Init zq calibration,
|
||||
if (params->memory_type == MEMORY_TYPE_LPDDR4)
|
||||
{
|
||||
// Patch 6 using BCT spare variables.
|
||||
if (params->emc_bct_spare10)
|
||||
*(vu32 *)params->emc_bct_spare10 = params->emc_bct_spare11;
|
||||
|
||||
// Write mode registers.
|
||||
EMC(EMC_MRW2) = params->emc_mrw2;
|
||||
EMC(EMC_MRW) = params->emc_mrw1;
|
||||
EMC(EMC_MRW3) = params->emc_mrw3;
|
||||
EMC(EMC_MRW4) = params->emc_mrw4;
|
||||
EMC(EMC_MRW6) = params->emc_mrw6;
|
||||
EMC(EMC_MRW14) = params->emc_mrw14;
|
||||
|
||||
EMC(EMC_MRW8) = params->emc_mrw8;
|
||||
EMC(EMC_MRW12) = params->emc_mrw12;
|
||||
EMC(EMC_MRW9) = params->emc_mrw9;
|
||||
EMC(EMC_MRW13) = params->emc_mrw13;
|
||||
|
||||
if (params->emc_zcal_warm_cold_boot_enables & 1)
|
||||
{
|
||||
// Issue ZQCAL start, device 0.
|
||||
EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev0;
|
||||
usleep(params->emc_zcal_init_wait);
|
||||
|
||||
// Issue ZQCAL latch.
|
||||
EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev0 ^ 3;
|
||||
// Same for device 1.
|
||||
if (!(params->emc_dev_select & 2))
|
||||
{
|
||||
EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev1;
|
||||
@@ -459,64 +641,160 @@ break_nosleep:
|
||||
}
|
||||
}
|
||||
}
|
||||
PMC(0x1D0) = params->pmc_ddr_cfg;
|
||||
if (params->memory_type - 1 <= 2)
|
||||
|
||||
// Set package and DPD pad control.
|
||||
PMC(APBDEV_PMC_DDR_CFG) = params->pmc_ddr_cfg;
|
||||
|
||||
// Start periodic ZQ calibration (LPDDRx only).
|
||||
if (params->memory_type && params->memory_type <= MEMORY_TYPE_LPDDR4)
|
||||
{
|
||||
EMC(EMC_ZCAL_INTERVAL) = params->emc_zcal_interval;
|
||||
EMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt;
|
||||
EMC(EMC_ZCAL_MRW_CMD) = params->emc_zcal_mrw_cmd;
|
||||
}
|
||||
|
||||
// Patch 7 using BCT spare variables.
|
||||
if (params->emc_bct_spare12)
|
||||
*(vu32 *)params->emc_bct_spare12 = params->emc_bct_spare13;
|
||||
EMC(EMC_TIMING_CONTROL) = 1;
|
||||
|
||||
EMC(EMC_TIMING_CONTROL) = 1; // Trigger timing update so above writes take place.
|
||||
|
||||
if (params->emc_extra_refresh_num)
|
||||
EMC(EMC_REF) = ((1 << params->emc_extra_refresh_num << 8) - 0xFD) | (params->emc_pin_gpio << 30);
|
||||
EMC(EMC_REF) = (((1 << params->emc_extra_refresh_num) - 1) << 8) | (params->emc_dev_select << 30) | 3;
|
||||
|
||||
// Enable refresh.
|
||||
EMC(EMC_REFCTRL) = params->emc_dev_select | 0x80000000;
|
||||
|
||||
EMC(EMC_DYN_SELF_REF_CONTROL) = params->emc_dyn_self_ref_control;
|
||||
EMC(EMC_CFG_UPDATE) = params->emc_cfg_update;
|
||||
EMC(EMC_CFG) = params->emc_cfg;
|
||||
EMC(EMC_FDPD_CTRL_DQ) = params->emc_fdpd_ctrl_dq;
|
||||
EMC(EMC_FDPD_CTRL_CMD) = params->emc_fdpd_ctrl_cmd;
|
||||
EMC(EMC_SEL_DPD_CTRL) = params->emc_sel_dpd_ctrl;
|
||||
|
||||
// Write addr swizzle lock bit.
|
||||
EMC(EMC_FBIO_SPARE) = params->emc_fbio_spare | 2;
|
||||
EMC(EMC_TIMING_CONTROL) = 1;
|
||||
|
||||
EMC(EMC_TIMING_CONTROL) = 1; // Re-trigger timing to latch power saving functions.
|
||||
|
||||
// Enable EMC pipe clock gating.
|
||||
EMC(EMC_CFG_PIPE_CLK) = params->emc_cfg_pipe_clk;
|
||||
|
||||
// Depending on freqency, enable CMD/CLK fdpd.
|
||||
EMC(EMC_FDPD_CTRL_CMD_NO_RAMP) = params->emc_fdpd_ctrl_cmd_no_ramp;
|
||||
SYSREG(AHB_ARBITRATION_XBAR_CTRL) = (SYSREG(AHB_ARBITRATION_XBAR_CTRL) & 0xFFFEFFFF) | ((params->ahb_arbitration_xbar_ctrl_meminit_done & 0xFFFF) << 16);
|
||||
|
||||
// Enable arbiter.
|
||||
SYSREG(AHB_ARBITRATION_XBAR_CTRL) = (SYSREG(AHB_ARBITRATION_XBAR_CTRL) & 0xFFFEFFFF) | (params->ahb_arbitration_xbar_ctrl_meminit_done << 16);
|
||||
|
||||
// Lock carveouts per BCT cfg.
|
||||
MC(MC_VIDEO_PROTECT_REG_CTRL) = params->mc_video_protect_write_access;
|
||||
MC(MC_SEC_CARVEOUT_REG_CTRL) = params->mc_sec_carveout_protect_write_access;
|
||||
MC(MC_MTS_CARVEOUT_REG_CTRL) = params->mc_mts_carveout_reg_ctrl;
|
||||
MC(MC_EMEM_CFG_ACCESS_CTRL) = 1; //Disable write access to a bunch of MC registers.
|
||||
|
||||
// Disable write access to a bunch of EMC registers.
|
||||
MC(MC_EMEM_CFG_ACCESS_CTRL) = 1;
|
||||
}
|
||||
|
||||
const void *sdram_get_params()
|
||||
#ifndef CONFIG_SDRAM_COMPRESS_CFG
|
||||
static void _sdram_patch_model_params(u32 dramid, u32 *params)
|
||||
{
|
||||
//TODO: sdram_id should be in [0, 7].
|
||||
for (u32 i = 0; i < sizeof(sdram_cfg_vendor_patches) / sizeof(sdram_vendor_patch_t); i++)
|
||||
if (sdram_cfg_vendor_patches[i].dramid & DRAM_ID(dramid))
|
||||
params[sdram_cfg_vendor_patches[i].addr] = sdram_cfg_vendor_patches[i].val;
|
||||
}
|
||||
#endif
|
||||
|
||||
sdram_params_t *sdram_get_params()
|
||||
{
|
||||
// Check if id is proper.
|
||||
u32 dramid = _get_sdram_id();
|
||||
if (dramid > 6)
|
||||
dramid = 0;
|
||||
|
||||
#ifdef CONFIG_SDRAM_COMPRESS_CFG
|
||||
u8 *buf = (u8 *)0x40030000;
|
||||
u8 *buf = (u8 *)SDRAM_PARAMS_ADDR;
|
||||
LZ_Uncompress(_dram_cfg_lz, buf, sizeof(_dram_cfg_lz));
|
||||
return (const void *)&buf[sizeof(sdram_params_t) * _get_sdram_id()];
|
||||
return (sdram_params_t *)&buf[sizeof(sdram_params_t) * dramid];
|
||||
#else
|
||||
return _dram_cfgs[_get_sdram_id()];
|
||||
sdram_params_t *buf = (sdram_params_t *)SDRAM_PARAMS_ADDR;
|
||||
memcpy(buf, &_dram_cfg_0_samsung_4gb, sizeof(sdram_params_t));
|
||||
switch (dramid)
|
||||
{
|
||||
case DRAM_4GB_SAMSUNG_K4F6E304HB_MGCH:
|
||||
case DRAM_4GB_MICRON_MT53B512M32D2NP_062_WT:
|
||||
break;
|
||||
case DRAM_4GB_HYNIX_H9HCNNNBPUMLHR_NLN:
|
||||
case DRAM_4GB_COPPER_UNK_3:
|
||||
case DRAM_6GB_SAMSUNG_K4FHE3D4HM_MFCH:
|
||||
case DRAM_4GB_COPPER_UNK_5:
|
||||
case DRAM_4GB_COPPER_UNK_6:
|
||||
_sdram_patch_model_params(dramid, (u32 *)buf);
|
||||
break;
|
||||
}
|
||||
return buf;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Function: sdram_get_params_patched
|
||||
*
|
||||
* This code implements a warmboot exploit. Warmboot, that is actually so hot, it burns Nvidia once again.
|
||||
* If the boot_rom_patch_control's MSB is set, it uses it as an index to
|
||||
* APB_MISC_BASE (u32 array) and sets it to the value of boot_rom_patch_data.
|
||||
* (The MSB falls out when it gets multiplied by sizeof(u32)).
|
||||
* Because the bootrom does not do any boundary checks, it lets us write anywhere and anything.
|
||||
* Ipatch hardware let us apply 12 changes to the bootrom and can be changed any time.
|
||||
* The first patch is not needed any more when the exploit is triggered, so we overwrite that.
|
||||
* 0x10459E is the address where it returns an error when the signature is not valid.
|
||||
* We change that to MOV R0, #0, so we pass the check.
|
||||
*
|
||||
* Note: The modulus in the header must match and validated.
|
||||
*/
|
||||
|
||||
sdram_params_t *sdram_get_params_patched()
|
||||
{
|
||||
#define IPATCH_CONFIG(addr, data) (((addr - 0x100000) / 2) << 16 | (data & 0xffff))
|
||||
sdram_params_t *sdram_params = sdram_get_params();
|
||||
|
||||
// Disable Warmboot signature check.
|
||||
sdram_params->boot_rom_patch_control = (1 << 31) | (((IPATCH_BASE + 4) - APB_MISC_BASE) / 4);
|
||||
sdram_params->boot_rom_patch_data = IPATCH_CONFIG(0x10459E, 0x2000);
|
||||
/*
|
||||
// Disable SBK lock.
|
||||
sdram_params->emc_bct_spare8 = (IPATCH_BASE + 7 * 4);
|
||||
sdram_params->emc_bct_spare9 = IPATCH_CONFIG(0x10210E, 0x2000);
|
||||
|
||||
// Disable bootrom read lock.
|
||||
sdram_params->emc_bct_spare10 = (IPATCH_BASE + 10 * 4);
|
||||
sdram_params->emc_bct_spare11 = IPATCH_CONFIG(0x100FDC, 0xF000);
|
||||
sdram_params->emc_bct_spare12 = (IPATCH_BASE + 11 * 4);
|
||||
sdram_params->emc_bct_spare13 = IPATCH_CONFIG(0x100FDE, 0xE320);
|
||||
*/
|
||||
return sdram_params;
|
||||
}
|
||||
|
||||
void sdram_init()
|
||||
{
|
||||
//TODO: sdram_id should be in [0,4].
|
||||
const sdram_params_t *params = (const sdram_params_t *)sdram_get_params();
|
||||
|
||||
// Set DRAM voltage.
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD_CFG2, 0x05);
|
||||
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);
|
||||
|
||||
// VDDP Select.
|
||||
PMC(APBDEV_PMC_VDDP_SEL) = params->pmc_vddp_sel;
|
||||
usleep(params->pmc_vddp_sel_wait);
|
||||
|
||||
// Set DDR pad voltage.
|
||||
PMC(APBDEV_PMC_DDR_PWR) = PMC(APBDEV_PMC_DDR_PWR);
|
||||
|
||||
// Turn on MEM IO Power.
|
||||
PMC(APBDEV_PMC_NO_IOPOWER) = params->pmc_no_io_power;
|
||||
PMC(APBDEV_PMC_REG_SHORT) = params->pmc_reg_short;
|
||||
|
||||
PMC(APBDEV_PMC_DDR_CNTRL) = params->pmc_ddr_ctrl;
|
||||
|
||||
// Patch 1 using BCT spare variables
|
||||
if (params->emc_bct_spare0)
|
||||
*(vu32 *)params->emc_bct_spare0 = params->emc_bct_spare1;
|
||||
|
||||
|
||||
@@ -17,8 +17,13 @@
|
||||
#ifndef _SDRAM_H_
|
||||
#define _SDRAM_H_
|
||||
|
||||
#include "emc.h"
|
||||
#include "sdram_param_t210.h"
|
||||
|
||||
void sdram_init();
|
||||
const void *sdram_get_params();
|
||||
sdram_params_t *sdram_get_params();
|
||||
sdram_params_t *sdram_get_params_patched();
|
||||
void sdram_lp0_save_params(const void *params);
|
||||
emc_mr_data_t sdram_read_mrx(emc_mr_t mrx);
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright 2014 Google Inc.
|
||||
* Copyright (C) 2018 naehrwert
|
||||
* Copyright (C) 2018 CTCaer
|
||||
* 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,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2015, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright 2014 Google Inc.
|
||||
* Copyright (C) 2018 CTCaer
|
||||
* Copyright (c) 2018 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
|
||||
@@ -26,12 +26,12 @@
|
||||
#ifndef _SDRAM_PARAM_T210_H_
|
||||
#define _SDRAM_PARAM_T210_H_
|
||||
|
||||
#define MEMORY_TYPE_NONE 0
|
||||
#define MEMORY_TYPE_DDR 0
|
||||
#define MEMORY_TYPE_LPDDR 0
|
||||
#define MEMORY_TYPE_DDR2 0
|
||||
#define MEMORY_TYPE_NONE 0
|
||||
#define MEMORY_TYPE_DDR 0
|
||||
#define MEMORY_TYPE_LPDDR 0
|
||||
#define MEMORY_TYPE_DDR2 0
|
||||
#define MEMORY_TYPE_LPDDR2 1
|
||||
#define MEMORY_TYPE_DDR3 2
|
||||
#define MEMORY_TYPE_DDR3L 2
|
||||
#define MEMORY_TYPE_LPDDR4 3
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Battery charger driver for Nintendo Switch's TI BQ24193
|
||||
*
|
||||
* Copyright (C) 2018 CTCaer
|
||||
* Copyright (c) 2018 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -20,6 +20,9 @@
|
||||
#include "../soc/i2c.h"
|
||||
#include "../utils/util.h"
|
||||
|
||||
#pragma GCC push_options
|
||||
#pragma GCC optimize ("Os")
|
||||
|
||||
int bq24193_get_property(enum BQ24193_reg_prop prop, int *value)
|
||||
{
|
||||
u8 data;
|
||||
@@ -28,6 +31,7 @@ int bq24193_get_property(enum BQ24193_reg_prop prop, int *value)
|
||||
case BQ24193_InputVoltageLimit: // Input voltage limit (mV).
|
||||
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_InputSource);
|
||||
data = (data & BQ24193_INCONFIG_VINDPM_MASK) >> 3;
|
||||
*value = 0;
|
||||
*value += ((data >> 0) & 1) ? 80 : 0;
|
||||
*value += ((data >> 1) & 1) ? 160 : 0;
|
||||
*value += ((data >> 2) & 1) ? 320 : 0;
|
||||
@@ -74,6 +78,7 @@ int bq24193_get_property(enum BQ24193_reg_prop prop, int *value)
|
||||
case BQ24193_FastChargeCurrentLimit: // Fast charge current limit (mA).
|
||||
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_ChrgCurr);
|
||||
data = (data & BQ24193_CHRGCURR_ICHG_MASK) >> 2;
|
||||
*value = 0;
|
||||
*value += ((data >> 0) & 1) ? 64 : 0;
|
||||
*value += ((data >> 1) & 1) ? 128 : 0;
|
||||
*value += ((data >> 2) & 1) ? 256 : 0;
|
||||
@@ -88,7 +93,8 @@ int bq24193_get_property(enum BQ24193_reg_prop prop, int *value)
|
||||
break;
|
||||
case BQ24193_ChargeVoltageLimit: // Charge voltage limit (mV).
|
||||
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_ChrgVolt);
|
||||
data = (data & BQ24193_CHRGVOLT_VREG) >> 2;
|
||||
data = (data & BQ24193_CHRGVOLT_VREG) >> 2;
|
||||
*value = 0;
|
||||
*value += ((data >> 0) & 1) ? 16 : 0;
|
||||
*value += ((data >> 1) & 1) ? 32 : 0;
|
||||
*value += ((data >> 2) & 1) ? 64 : 0;
|
||||
@@ -148,7 +154,7 @@ int bq24193_get_property(enum BQ24193_reg_prop prop, int *value)
|
||||
|
||||
void bq24193_fake_battery_removal()
|
||||
{
|
||||
u8 value;
|
||||
u8 value;
|
||||
|
||||
// Disable watchdog to keep BATFET disabled.
|
||||
value = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_ChrgTermTimer);
|
||||
@@ -160,3 +166,5 @@ void bq24193_fake_battery_removal()
|
||||
value |= BQ24193_MISC_BATFET_DI_MASK;
|
||||
i2c_send_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_Misc, value);
|
||||
}
|
||||
|
||||
#pragma GCC pop_options
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Battery charger driver for Nintendo Switch's TI BQ24193
|
||||
*
|
||||
* Copyright (C) 2018 CTCaer
|
||||
* Copyright (c) 2018 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/*
|
||||
* Fuel gauge driver for Nintendo Switch's Maxim 17050
|
||||
*
|
||||
* Copyright (C) 2011 Samsung Electronics
|
||||
* Copyright (c) 2011 Samsung Electronics
|
||||
* MyungJoo Ham <myungjoo.ham@samsung.com>
|
||||
* Copyright (C) 2018 CTCaer
|
||||
* Copyright (c) 2018 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -43,6 +43,15 @@
|
||||
|
||||
#define MAX17050_VMAX_TOLERANCE 50 /* 50 mV */
|
||||
|
||||
#pragma GCC push_options
|
||||
#pragma GCC optimize ("Os")
|
||||
|
||||
static u32 battery_voltage = 0;
|
||||
u32 max17050_get_cached_batt_volt()
|
||||
{
|
||||
return battery_voltage;
|
||||
}
|
||||
|
||||
int max17050_get_property(enum MAX17050_reg reg, int *value)
|
||||
{
|
||||
u16 data;
|
||||
@@ -71,6 +80,7 @@ int max17050_get_property(enum MAX17050_reg reg, int *value)
|
||||
case MAX17050_VCELL: // Voltage now.
|
||||
i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_VCELL);
|
||||
*value = data * 625 / 8 / 1000;
|
||||
battery_voltage = *value;
|
||||
break;
|
||||
case MAX17050_AvgVCELL: // Voltage avg.
|
||||
i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_AvgVCELL);
|
||||
@@ -259,8 +269,10 @@ int max17050_fix_configuration()
|
||||
/* Init complete, Clear the POR bit */
|
||||
//_max17050_set_por_bit(0); // Should we? Or let the switch to reconfigure POR?
|
||||
|
||||
// Sets POR, BI, BR.
|
||||
// Sets POR, BI, BR.
|
||||
_max17050_set_por_bit(0x8801);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#pragma GCC pop_options
|
||||
@@ -2,9 +2,9 @@
|
||||
* Fuel gauge driver for Nintendo Switch's Maxim 17050
|
||||
* Note that Maxim 8966 and 8997 are mfd and this is its subdevice.
|
||||
*
|
||||
* Copyright (C) 2011 Samsung Electronics
|
||||
* Copyright (c) 2011 Samsung Electronics
|
||||
* MyungJoo Ham <myungjoo.ham@samsung.com>
|
||||
* Copyright (C) 2018 CTCaer
|
||||
* Copyright (c) 2018-2020 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -24,6 +24,8 @@
|
||||
#ifndef __MAX17050_H_
|
||||
#define __MAX17050_H_
|
||||
|
||||
#include "../utils/types.h"
|
||||
|
||||
#define MAX17050_STATUS_BattAbsent (1 << 3)
|
||||
#define MAX17050_DEFAULT_SNS_RESISTOR 10000
|
||||
|
||||
@@ -96,14 +98,17 @@ enum MAX17050_reg {
|
||||
MAX17050_K_empty0 = 0x3B,
|
||||
MAX17050_TaskPeriod = 0x3C,
|
||||
MAX17050_FSTAT = 0x3D,
|
||||
|
||||
MAX17050_TIMER = 0x3E,
|
||||
MAX17050_SHDNTIMER = 0x3F,
|
||||
|
||||
MAX17050_QRTbl30 = 0x42,
|
||||
|
||||
MAX17050_dQacc = 0x45,
|
||||
MAX17050_dPacc = 0x46,
|
||||
|
||||
MAX17050_VFSOC0 = 0x48,
|
||||
|
||||
Max17050_QH0 = 0x4C,
|
||||
MAX17050_QH = 0x4D,
|
||||
MAX17050_QL = 0x4E,
|
||||
|
||||
@@ -111,6 +116,8 @@ enum MAX17050_reg {
|
||||
MAX17050_MaxVolt = 0x51, // Custom ID. Not to be sent to i2c.
|
||||
|
||||
MAX17050_VFSOC0Enable = 0x60,
|
||||
MAX17050_MODELEnable1 = 0x62,
|
||||
MAX17050_MODELEnable2 = 0x63,
|
||||
|
||||
MAX17050_MODELChrTbl = 0x80,
|
||||
|
||||
@@ -123,5 +130,6 @@ enum MAX17050_reg {
|
||||
|
||||
int max17050_get_property(enum MAX17050_reg reg, int *value);
|
||||
int max17050_fix_configuration();
|
||||
u32 max17050_get_cached_batt_volt();
|
||||
|
||||
#endif /* __MAX17050_H_ */
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* 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
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -14,275 +15,286 @@
|
||||
#define MAX77620_I2C_ADDR 0x3C
|
||||
|
||||
/* GLOBAL, PMIC, GPIO, FPS, ONOFFC, CID Registers */
|
||||
#define MAX77620_REG_CNFGGLBL1 0x00
|
||||
#define MAX77620_REG_CNFGGLBL2 0x01
|
||||
#define MAX77620_REG_CNFGGLBL3 0x02
|
||||
#define MAX77620_REG_CNFG1_32K 0x03
|
||||
#define MAX77620_REG_CNFGBBC 0x04
|
||||
#define MAX77620_REG_IRQTOP 0x05
|
||||
#define MAX77620_REG_INTLBT 0x06
|
||||
#define MAX77620_REG_IRQSD 0x07
|
||||
#define MAX77620_REG_IRQ_LVL2_L0_7 0x08
|
||||
#define MAX77620_REG_IRQ_LVL2_L8 0x09
|
||||
#define MAX77620_REG_IRQ_LVL2_GPIO 0x0A
|
||||
#define MAX77620_REG_ONOFFIRQ 0x0B
|
||||
#define MAX77620_REG_NVERC 0x0C
|
||||
#define MAX77620_REG_IRQTOPM 0x0D
|
||||
#define MAX77620_REG_INTENLBT 0x0E
|
||||
#define MAX77620_REG_IRQMASKSD 0x0F
|
||||
#define MAX77620_REG_IRQ_MSK_L0_7 0x10
|
||||
#define MAX77620_REG_IRQ_MSK_L8 0x11
|
||||
#define MAX77620_REG_ONOFFIRQM 0x12
|
||||
#define MAX77620_REG_STATLBT 0x13
|
||||
#define MAX77620_REG_STATSD 0x14
|
||||
#define MAX77620_REG_ONOFFSTAT 0x15
|
||||
#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_100 (0 << 4)
|
||||
#define MAX77620_CNFGGLBL1_LBHYST_200 (1 << 4)
|
||||
#define MAX77620_CNFGGLBL1_LBHYST_300 (2 << 4)
|
||||
#define MAX77620_CNFGGLBL1_LBHYST_400 (3 << 4)
|
||||
#define MAX77620_CNFGGLBL1_LBDAC_MASK 0x0E
|
||||
#define MAX77620_CNFGGLBL1_LBDAC_2700 (0 << 1)
|
||||
#define MAX77620_CNFGGLBL1_LBDAC_2800 (1 << 1)
|
||||
#define MAX77620_CNFGGLBL1_LBDAC_2900 (2 << 1)
|
||||
#define MAX77620_CNFGGLBL1_LBDAC_3000 (3 << 1)
|
||||
#define MAX77620_CNFGGLBL1_LBDAC_3100 (4 << 1)
|
||||
#define MAX77620_CNFGGLBL1_LBDAC_3200 (5 << 1)
|
||||
#define MAX77620_CNFGGLBL1_LBDAC_3300 (6 << 1)
|
||||
#define MAX77620_CNFGGLBL1_LBDAC_3400 (7 << 1)
|
||||
#define MAX77620_CNFGGLBL1_LBRSTEN (1 << 0)
|
||||
|
||||
#define MAX77620_REG_CNFGGLBL2 0x01
|
||||
#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_CNFG1_32K_OUT0_EN (1 << 2)
|
||||
|
||||
#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_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_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_IRQ_LVL2_L0_7 0x08
|
||||
#define MAX77620_REG_IRQ_LVL2_L8 0x09
|
||||
#define MAX77620_REG_IRQ_LVL2_GPIO 0x0A
|
||||
#define MAX77620_REG_ONOFFIRQ 0x0B
|
||||
#define MAX77620_REG_NVERC 0x0C
|
||||
|
||||
#define MAX77620_REG_INTENLBT 0x0E
|
||||
#define MAX77620_GLBLM_MASK (1 << 0)
|
||||
|
||||
#define MAX77620_REG_IRQMASKSD 0x0F
|
||||
#define MAX77620_REG_IRQ_MSK_L0_7 0x10
|
||||
#define MAX77620_REG_IRQ_MSK_L8 0x11
|
||||
#define MAX77620_REG_ONOFFIRQM 0x12
|
||||
#define MAX77620_REG_STATLBT 0x13
|
||||
#define MAX77620_REG_STATSD 0x14
|
||||
#define MAX77620_REG_ONOFFSTAT 0x15
|
||||
|
||||
/* SD and LDO Registers */
|
||||
#define MAX77620_REG_SD0 0x16
|
||||
#define MAX77620_REG_SD1 0x17
|
||||
#define MAX77620_REG_SD2 0x18
|
||||
#define MAX77620_REG_SD3 0x19
|
||||
#define MAX77620_REG_SD4 0x1A
|
||||
#define MAX77620_REG_DVSSD0 0x1B
|
||||
#define MAX77620_REG_DVSSD1 0x1C
|
||||
#define MAX77620_REG_SD0_CFG 0x1D
|
||||
#define MAX77620_REG_SD1_CFG 0x1E
|
||||
#define MAX77620_REG_SD2_CFG 0x1F
|
||||
#define MAX77620_REG_SD3_CFG 0x20
|
||||
#define MAX77620_REG_SD4_CFG 0x21
|
||||
#define MAX77620_REG_SD_CFG2 0x22
|
||||
#define MAX77620_REG_LDO0_CFG 0x23
|
||||
#define MAX77620_REG_LDO0_CFG2 0x24
|
||||
#define MAX77620_REG_LDO1_CFG 0x25
|
||||
#define MAX77620_REG_LDO1_CFG2 0x26
|
||||
#define MAX77620_REG_LDO2_CFG 0x27
|
||||
#define MAX77620_REG_LDO2_CFG2 0x28
|
||||
#define MAX77620_REG_LDO3_CFG 0x29
|
||||
#define MAX77620_REG_LDO3_CFG2 0x2A
|
||||
#define MAX77620_REG_LDO4_CFG 0x2B
|
||||
#define MAX77620_REG_LDO4_CFG2 0x2C
|
||||
#define MAX77620_REG_LDO5_CFG 0x2D
|
||||
#define MAX77620_REG_LDO5_CFG2 0x2E
|
||||
#define MAX77620_REG_LDO6_CFG 0x2F
|
||||
#define MAX77620_REG_LDO6_CFG2 0x30
|
||||
#define MAX77620_REG_LDO7_CFG 0x31
|
||||
#define MAX77620_REG_LDO7_CFG2 0x32
|
||||
#define MAX77620_REG_LDO8_CFG 0x33
|
||||
#define MAX77620_REG_LDO8_CFG2 0x34
|
||||
#define MAX77620_REG_LDO_CFG3 0x35
|
||||
#define MAX77620_REG_SD0 0x16
|
||||
#define MAX77620_REG_SD1 0x17
|
||||
#define MAX77620_REG_SD2 0x18
|
||||
#define MAX77620_REG_SD3 0x19
|
||||
#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_DVSSD1 0x1C
|
||||
#define MAX77620_REG_SD0_CFG 0x1D
|
||||
#define MAX77620_REG_SD1_CFG 0x1E
|
||||
#define MAX77620_REG_SD2_CFG 0x1F
|
||||
#define MAX77620_REG_SD3_CFG 0x20
|
||||
#define MAX77620_REG_SD4_CFG 0x21
|
||||
#define MAX77620_REG_SD_CFG2 0x22
|
||||
#define MAX77620_REG_LDO0_CFG 0x23
|
||||
#define MAX77620_REG_LDO0_CFG2 0x24
|
||||
#define MAX77620_REG_LDO1_CFG 0x25
|
||||
#define MAX77620_REG_LDO1_CFG2 0x26
|
||||
#define MAX77620_REG_LDO2_CFG 0x27
|
||||
#define MAX77620_REG_LDO2_CFG2 0x28
|
||||
#define MAX77620_REG_LDO3_CFG 0x29
|
||||
#define MAX77620_REG_LDO3_CFG2 0x2A
|
||||
#define MAX77620_REG_LDO4_CFG 0x2B
|
||||
#define MAX77620_REG_LDO4_CFG2 0x2C
|
||||
#define MAX77620_REG_LDO5_CFG 0x2D
|
||||
#define MAX77620_REG_LDO5_CFG2 0x2E
|
||||
#define MAX77620_REG_LDO6_CFG 0x2F
|
||||
#define MAX77620_REG_LDO6_CFG2 0x30
|
||||
#define MAX77620_REG_LDO7_CFG 0x31
|
||||
#define MAX77620_REG_LDO7_CFG2 0x32
|
||||
#define MAX77620_REG_LDO8_CFG 0x33
|
||||
#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_LDO_SLEW_RATE_MASK 0x1
|
||||
#define MAX77620_REG_LDO_CFG3 0x35
|
||||
#define MAX77620_TRACK4_MASK (1 << 5)
|
||||
#define MAX77620_TRACK4_SHIFT 5
|
||||
|
||||
/* LDO Configuration 3 */
|
||||
#define MAX77620_TRACK4_MASK (1 << 5)
|
||||
#define MAX77620_TRACK4_SHIFT 5
|
||||
#define MAX77620_LDO_SLEW_RATE_MASK 0x1
|
||||
|
||||
/* Voltage */
|
||||
#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_GPIO1 0x37
|
||||
#define MAX77620_REG_GPIO2 0x38
|
||||
#define MAX77620_REG_GPIO3 0x39
|
||||
#define MAX77620_REG_GPIO4 0x3A
|
||||
#define MAX77620_REG_GPIO5 0x3B
|
||||
#define MAX77620_REG_GPIO6 0x3C
|
||||
#define MAX77620_REG_GPIO7 0x3D
|
||||
#define MAX77620_REG_PUE_GPIO 0x3E
|
||||
#define MAX77620_REG_PDE_GPIO 0x3F
|
||||
#define MAX77620_REG_AME_GPIO 0x40
|
||||
#define MAX77620_CNFG_GPIO_DRV_MASK (1 << 0)
|
||||
#define MAX77620_CNFG_GPIO_DRV_PUSHPULL (1 << 0)
|
||||
#define MAX77620_CNFG_GPIO_DRV_OPENDRAIN (0 << 0)
|
||||
#define MAX77620_CNFG_GPIO_DIR_MASK (1 << 1)
|
||||
#define MAX77620_CNFG_GPIO_DIR_INPUT (1 << 1)
|
||||
#define MAX77620_CNFG_GPIO_DIR_OUTPUT (0 << 1)
|
||||
#define MAX77620_CNFG_GPIO_INPUT_VAL_MASK (1 << 2)
|
||||
#define MAX77620_CNFG_GPIO_OUTPUT_VAL_MASK (1 << 3)
|
||||
#define MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH (1 << 3)
|
||||
#define MAX77620_CNFG_GPIO_OUTPUT_VAL_LOW (0 << 3)
|
||||
#define MAX77620_CNFG_GPIO_INT_MASK (0x3 << 4)
|
||||
#define MAX77620_CNFG_GPIO_INT_FALLING (1 << 4)
|
||||
#define MAX77620_CNFG_GPIO_INT_RISING (1 << 5)
|
||||
#define MAX77620_CNFG_GPIO_DBNC_MASK (0x3 << 6)
|
||||
#define MAX77620_CNFG_GPIO_DBNC_None (0x0 << 6)
|
||||
#define MAX77620_CNFG_GPIO_DBNC_8ms (0x1 << 6)
|
||||
#define MAX77620_CNFG_GPIO_DBNC_16ms (0x2 << 6)
|
||||
#define MAX77620_CNFG_GPIO_DBNC_32ms (0x3 << 6)
|
||||
|
||||
#define MAX77620_REG_GPIO0 0x36
|
||||
#define MAX77620_REG_GPIO1 0x37
|
||||
#define MAX77620_REG_GPIO2 0x38
|
||||
#define MAX77620_REG_GPIO3 0x39
|
||||
#define MAX77620_REG_GPIO4 0x3A
|
||||
#define MAX77620_REG_GPIO5 0x3B
|
||||
#define MAX77620_REG_GPIO6 0x3C
|
||||
#define MAX77620_REG_GPIO7 0x3D
|
||||
#define MAX77620_REG_PUE_GPIO 0x3E
|
||||
#define MAX77620_REG_PDE_GPIO 0x3F
|
||||
#define MAX77620_REG_AME_GPIO 0x40
|
||||
#define MAX77620_REG_ONOFFCNFG1 0x41
|
||||
#define MAX77620_REG_ONOFFCNFG2 0x42
|
||||
#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_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 */
|
||||
#define MAX77620_REG_FPS_CFG0 0x43
|
||||
#define MAX77620_REG_FPS_CFG1 0x44
|
||||
#define MAX77620_REG_FPS_CFG2 0x45
|
||||
#define MAX77620_REG_FPS_LDO0 0x46
|
||||
#define MAX77620_REG_FPS_LDO1 0x47
|
||||
#define MAX77620_REG_FPS_LDO2 0x48
|
||||
#define MAX77620_REG_FPS_LDO3 0x49
|
||||
#define MAX77620_REG_FPS_LDO4 0x4A
|
||||
#define MAX77620_REG_FPS_LDO5 0x4B
|
||||
#define MAX77620_REG_FPS_LDO6 0x4C
|
||||
#define MAX77620_REG_FPS_LDO7 0x4D
|
||||
#define MAX77620_REG_FPS_LDO8 0x4E
|
||||
#define MAX77620_REG_FPS_SD0 0x4F
|
||||
#define MAX77620_REG_FPS_SD1 0x50
|
||||
#define MAX77620_REG_FPS_SD2 0x51
|
||||
#define MAX77620_REG_FPS_SD3 0x52
|
||||
#define MAX77620_REG_FPS_SD4 0x53
|
||||
#define MAX77620_REG_FPS_NONE 0
|
||||
|
||||
#define MAX77620_FPS_SRC_MASK 0xC0
|
||||
#define MAX77620_FPS_SRC_SHIFT 6
|
||||
#define MAX77620_FPS_PU_PERIOD_MASK 0x38
|
||||
#define MAX77620_FPS_PU_PERIOD_SHIFT 3
|
||||
#define MAX77620_FPS_PD_PERIOD_MASK 0x07
|
||||
#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
|
||||
#define MAX77620_REG_FPS_CFG0 0x43
|
||||
#define MAX77620_REG_FPS_CFG1 0x44
|
||||
#define MAX77620_REG_FPS_CFG2 0x45
|
||||
#define MAX77620_REG_FPS_LDO0 0x46
|
||||
#define MAX77620_REG_FPS_LDO1 0x47
|
||||
#define MAX77620_REG_FPS_LDO2 0x48
|
||||
#define MAX77620_REG_FPS_LDO3 0x49
|
||||
#define MAX77620_REG_FPS_LDO4 0x4A
|
||||
#define MAX77620_REG_FPS_LDO5 0x4B
|
||||
#define MAX77620_REG_FPS_LDO6 0x4C
|
||||
#define MAX77620_REG_FPS_LDO7 0x4D
|
||||
#define MAX77620_REG_FPS_LDO8 0x4E
|
||||
#define MAX77620_REG_FPS_SD0 0x4F
|
||||
#define MAX77620_REG_FPS_SD1 0x50
|
||||
#define MAX77620_REG_FPS_SD2 0x51
|
||||
#define MAX77620_REG_FPS_SD3 0x52
|
||||
#define MAX77620_REG_FPS_SD4 0x53
|
||||
#define MAX77620_REG_FPS_NONE 0
|
||||
#define MAX77620_FPS_SRC_MASK 0xC0
|
||||
#define MAX77620_FPS_SRC_SHIFT 6
|
||||
#define MAX77620_FPS_PU_PERIOD_MASK 0x38
|
||||
#define MAX77620_FPS_PU_PERIOD_SHIFT 3
|
||||
#define MAX77620_FPS_PD_PERIOD_MASK 0x07
|
||||
#define MAX77620_FPS_PD_PERIOD_SHIFT 0
|
||||
|
||||
/* Minimum and maximum FPS period time (in microseconds) are
|
||||
* different for MAX77620 and Max20024.
|
||||
*/
|
||||
#define MAX77620_FPS_PERIOD_MIN_US 40
|
||||
#define MAX20024_FPS_PERIOD_MIN_US 20
|
||||
#define MAX77620_FPS_COUNT 3
|
||||
|
||||
#define MAX77620_FPS_PERIOD_MAX_US 2560
|
||||
#define MAX20024_FPS_PERIOD_MAX_US 5120
|
||||
#define MAX77620_FPS_PERIOD_MIN_US 40
|
||||
#define MAX20024_FPS_PERIOD_MIN_US 20
|
||||
|
||||
#define MAX77620_REG_FPS_GPIO1 0x54
|
||||
#define MAX77620_REG_FPS_GPIO2 0x55
|
||||
#define MAX77620_REG_FPS_GPIO3 0x56
|
||||
#define MAX77620_REG_FPS_RSO 0x57
|
||||
#define MAX77620_REG_CID0 0x58
|
||||
#define MAX77620_REG_CID1 0x59
|
||||
#define MAX77620_REG_CID2 0x5A
|
||||
#define MAX77620_REG_CID3 0x5B
|
||||
#define MAX77620_REG_CID4 0x5C
|
||||
#define MAX77620_REG_CID5 0x5D
|
||||
#define MAX77620_FPS_PERIOD_MAX_US 2560
|
||||
#define MAX20024_FPS_PERIOD_MAX_US 5120
|
||||
|
||||
#define MAX77620_REG_DVSSD4 0x5E
|
||||
#define MAX20024_REG_MAX_ADD 0x70
|
||||
#define MAX77620_REG_FPS_GPIO1 0x54
|
||||
#define MAX77620_REG_FPS_GPIO2 0x55
|
||||
#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_CID_DIDM_MASK 0xF0
|
||||
#define MAX77620_CID_DIDM_SHIFT 4
|
||||
#define MAX77620_REG_FPS_RSO 0x57
|
||||
#define MAX77620_REG_CID0 0x58
|
||||
#define MAX77620_REG_CID1 0x59
|
||||
#define MAX77620_REG_CID2 0x5A
|
||||
#define MAX77620_REG_CID3 0x5B
|
||||
#define MAX77620_REG_CID4 0x5C
|
||||
#define MAX77620_REG_CID5 0x5D
|
||||
|
||||
#define MAX77620_REG_DVSSD4 0x5E
|
||||
#define MAX20024_REG_MAX_ADD 0x70
|
||||
|
||||
#define MAX77620_CID_DIDM_MASK 0xF0
|
||||
#define MAX77620_CID_DIDM_SHIFT 4
|
||||
|
||||
/* CNCG2SD */
|
||||
#define MAX77620_SD_CNF2_ROVS_EN_SD1 (1 << 1)
|
||||
#define MAX77620_SD_CNF2_ROVS_EN_SD0 (1 << 2)
|
||||
#define MAX77620_SD_CNF2_ROVS_EN_SD1 (1 << 1)
|
||||
#define MAX77620_SD_CNF2_ROVS_EN_SD0 (1 << 2)
|
||||
|
||||
/* Device Identification Metal */
|
||||
#define MAX77620_CID5_DIDM(n) (((n) >> 4) & 0xF)
|
||||
#define MAX77620_CID5_DIDM(n) (((n) >> 4) & 0xF)
|
||||
/* Device Indentification OTP */
|
||||
#define MAX77620_CID5_DIDO(n) ((n) & 0xF)
|
||||
#define MAX77620_CID5_DIDO(n) ((n) & 0xF)
|
||||
|
||||
/* SD CNFG1 */
|
||||
#define MAX77620_SD_SR_MASK 0xC0
|
||||
#define MAX77620_SD_SR_SHIFT 6
|
||||
#define MAX77620_SD_POWER_MODE_MASK 0x30
|
||||
#define MAX77620_SD_POWER_MODE_SHIFT 4
|
||||
#define MAX77620_SD_CFG1_ADE_MASK (1 << 3)
|
||||
#define MAX77620_SD_CFG1_ADE_DISABLE 0
|
||||
#define MAX77620_SD_CFG1_ADE_ENABLE (1 << 3)
|
||||
#define MAX77620_SD_FPWM_MASK 0x04
|
||||
#define MAX77620_SD_FPWM_SHIFT 2
|
||||
#define MAX77620_SD_FSRADE_MASK 0x01
|
||||
#define MAX77620_SD_FSRADE_SHIFT 0
|
||||
#define MAX77620_SD_CFG1_FPWM_SD_MASK (1 << 2)
|
||||
#define MAX77620_SD_CFG1_FPWM_SD_SKIP 0
|
||||
#define MAX77620_SD_CFG1_FPWM_SD_FPWM (1 << 2)
|
||||
#define MAX20024_SD_CFG1_MPOK_MASK (1 << 1)
|
||||
#define MAX77620_SD_CFG1_FSRADE_SD_MASK (1 << 0)
|
||||
#define MAX77620_SD_CFG1_FSRADE_SD_DISABLE 0
|
||||
#define MAX77620_SD_CFG1_FSRADE_SD_ENABLE (1 << 0)
|
||||
#define MAX77620_SD_SR_MASK 0xC0
|
||||
#define MAX77620_SD_SR_SHIFT 6
|
||||
#define MAX77620_SD_POWER_MODE_MASK 0x30
|
||||
#define MAX77620_SD_POWER_MODE_SHIFT 4
|
||||
#define MAX77620_SD_CFG1_ADE_MASK (1 << 3)
|
||||
#define MAX77620_SD_CFG1_ADE_DISABLE 0
|
||||
#define MAX77620_SD_CFG1_ADE_ENABLE (1 << 3)
|
||||
#define MAX77620_SD_FPWM_MASK 0x04
|
||||
#define MAX77620_SD_FPWM_SHIFT 2
|
||||
#define MAX77620_SD_FSRADE_MASK 0x01
|
||||
#define MAX77620_SD_FSRADE_SHIFT 0
|
||||
#define MAX77620_SD_CFG1_FPWM_SD_MASK (1 << 2)
|
||||
#define MAX77620_SD_CFG1_FPWM_SD_SKIP 0
|
||||
#define MAX77620_SD_CFG1_FPWM_SD_FPWM (1 << 2)
|
||||
#define MAX20024_SD_CFG1_MPOK_MASK (1 << 1)
|
||||
#define MAX77620_SD_CFG1_FSRADE_SD_MASK (1 << 0)
|
||||
#define MAX77620_SD_CFG1_FSRADE_SD_DISABLE 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_EDGE1 (1 << 1)
|
||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE2 (1 << 2)
|
||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE3 (1 << 3)
|
||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE4 (1 << 4)
|
||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE5 (1 << 5)
|
||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE6 (1 << 6)
|
||||
#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
|
||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE0 (1 << 0)
|
||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE1 (1 << 1)
|
||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE2 (1 << 2)
|
||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE3 (1 << 3)
|
||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE4 (1 << 4)
|
||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE5 (1 << 5)
|
||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE6 (1 << 6)
|
||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE7 (1 << 7)
|
||||
|
||||
/* Interrupts */
|
||||
enum {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2019 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -27,12 +28,15 @@ typedef struct _max77620_regulator_t
|
||||
u8 type;
|
||||
const char *name;
|
||||
u8 reg_sd;
|
||||
|
||||
u32 mv_step;
|
||||
u32 mv_min;
|
||||
u32 mv_default;
|
||||
u32 mv_max;
|
||||
|
||||
u8 volt_addr;
|
||||
u8 cfg_addr;
|
||||
|
||||
u8 volt_mask;
|
||||
u8 enable_mask;
|
||||
u8 enable_shift;
|
||||
@@ -45,21 +49,31 @@ typedef struct _max77620_regulator_t
|
||||
} max77620_regulator_t;
|
||||
|
||||
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, "sd1", 0x17, 12500, 600000, 1125000, 1125000, MAX77620_REG_SD1, MAX77620_REG_SD1_CFG, 0x3F, 0x30, 4, 0x40, 0x50, 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, "sd3", 0x19, 12500, 600000, 1800000, 1800000, MAX77620_REG_SD3, MAX77620_REG_SD3_CFG, 0xFF, 0x30, 4, 0x10, 0x52, 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, "ldo1", 0x00, 25000, 800000, 1050000, 1050000, MAX77620_REG_LDO1_CFG, MAX77620_REG_LDO1_CFG2, 0x3F, 0xC0, 6, 0x00, 0x47, 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, "ldo3", 0x00, 50000, 800000, 3100000, 3100000, MAX77620_REG_LDO3_CFG, MAX77620_REG_LDO3_CFG2, 0x3F, 0xC0, 6, 0x00, 0x49, 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, "ldo5", 0x00, 50000, 800000, 1800000, 1800000, MAX77620_REG_LDO5_CFG, MAX77620_REG_LDO5_CFG2, 0x3F, 0xC0, 6, 0x00, 0x4B, 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, "ldo7", 0x00, 50000, 800000, 1050000, 1050000, MAX77620_REG_LDO7_CFG, MAX77620_REG_LDO7_CFG2, 0x3F, 0xC0, 6, 0x00, 0x4D, 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_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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO8, 3, 7, 0 }
|
||||
};
|
||||
|
||||
static void _max77620_try_set_reg(u8 reg, u8 val)
|
||||
{
|
||||
u8 tmp;
|
||||
do
|
||||
{
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, reg, val);
|
||||
tmp = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, reg);
|
||||
} while (val != tmp);
|
||||
}
|
||||
|
||||
int max77620_regulator_get_status(u32 id)
|
||||
{
|
||||
if (id > REGULATOR_MAX)
|
||||
@@ -79,7 +93,8 @@ int max77620_regulator_config_fps(u32 id)
|
||||
|
||||
const max77620_regulator_t *reg = &_pmic_regulators[id];
|
||||
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, reg->fps_addr, (reg->fps_src << 6) | (reg->pu_period << 3) | (reg->pd_period));
|
||||
_max77620_try_set_reg(reg->fps_addr,
|
||||
(reg->fps_src << MAX77620_FPS_SRC_SHIFT) | (reg->pu_period << MAX77620_FPS_PU_PERIOD_SHIFT) | (reg->pd_period));
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -91,13 +106,13 @@ int max77620_regulator_set_voltage(u32 id, u32 mv)
|
||||
|
||||
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;
|
||||
|
||||
u32 mult = (mv + reg->mv_step - 1 - reg->mv_min) / reg->mv_step;
|
||||
u8 val = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, reg->volt_addr);
|
||||
val = (val & ~reg->volt_mask) | (mult & reg->volt_mask);
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, reg->volt_addr, val);
|
||||
_max77620_try_set_reg(reg->volt_addr, val);
|
||||
usleep(1000);
|
||||
|
||||
return 1;
|
||||
@@ -113,10 +128,29 @@ int max77620_regulator_enable(u32 id, int enable)
|
||||
u32 addr = reg->type == REGULATOR_SD ? reg->cfg_addr : reg->volt_addr;
|
||||
u8 val = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, addr);
|
||||
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
|
||||
val &= ~reg->enable_mask;
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, addr, val);
|
||||
_max77620_try_set_reg(addr, val);
|
||||
usleep(1000);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// LDO only.
|
||||
int max77620_regulator_set_volt_and_flags(u32 id, u32 mv, u8 flags)
|
||||
{
|
||||
if (id > REGULATOR_MAX)
|
||||
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);
|
||||
_max77620_try_set_reg(reg->volt_addr, val);
|
||||
usleep(1000);
|
||||
|
||||
return 1;
|
||||
@@ -132,11 +166,12 @@ void max77620_config_default()
|
||||
if (_pmic_regulators[i].fps_src != MAX77620_FPS_SRC_NONE)
|
||||
max77620_regulator_enable(i, 1);
|
||||
}
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD_CFG2, 4);
|
||||
_max77620_try_set_reg(MAX77620_REG_SD_CFG2, 4);
|
||||
}
|
||||
|
||||
void max77620_low_battery_monitor_config()
|
||||
void max77620_low_battery_monitor_config(bool enable)
|
||||
{
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_CNFGGLBL1,
|
||||
MAX77620_CNFGGLBL1_LBDAC_EN | MAX77620_CNFGGLBL1_LBHYST_N | MAX77620_CNFGGLBL1_LBDAC_N);
|
||||
_max77620_try_set_reg(MAX77620_REG_CNFGGLBL1,
|
||||
MAX77620_CNFGGLBL1_LBDAC_EN | (enable ? MAX77620_CNFGGLBL1_MPPLD : 0) |
|
||||
MAX77620_CNFGGLBL1_LBHYST_200 | MAX77620_CNFGGLBL1_LBDAC_2800);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2019 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -23,17 +24,17 @@
|
||||
* Switch Power domains (max77620):
|
||||
* Name | Usage | uV step | uV min | uV default | uV max | Init
|
||||
*-------+---------------+---------+--------+------------+---------+------------------
|
||||
* sd0 | core | 12500 | 600000 | 625000 | 1400000 | 1.125V (pkg1.1)
|
||||
* sd0 | SoC | 12500 | 600000 | 625000 | 1400000 | 1.125V (pkg1.1)
|
||||
* sd1 | SDRAM | 12500 | 600000 | 1125000 | 1125000 | 1.1V (pkg1.1)
|
||||
* sd2 | ldo{0-1, 7-8} | 12500 | 600000 | 1325000 | 1350000 | 1.325V (pcv)
|
||||
* sd3 | 1.8V general | 12500 | 600000 | 1800000 | 1800000 |
|
||||
* ldo0 | Display Panel | 25000 | 800000 | 1200000 | 1200000 | 1.2V (pkg1.1)
|
||||
* ldo1 | XUSB, PCIE | 25000 | 800000 | 1050000 | 1050000 | 1.05V (pcv)
|
||||
* ldo2 | SDMMC1 | 50000 | 800000 | 1800000 | 3300000 |
|
||||
* ldo3 | | 50000 | 800000 | 3100000 | 3100000 |
|
||||
* ldo3 | GC ASIC | 50000 | 800000 | 3100000 | 3100000 | 3.1V (pcv)
|
||||
* ldo4 | RTC | 12500 | 800000 | 850000 | 850000 |
|
||||
* ldo5 | | 50000 | 800000 | 1800000 | 1800000 |
|
||||
* ldo6 | | 50000 | 800000 | 2900000 | 2900000 |
|
||||
* ldo5 | GC Card | 50000 | 800000 | 1800000 | 1800000 | 1.8V (pcv)
|
||||
* ldo6 | Touch, ALS | 50000 | 800000 | 2900000 | 2900000 | 2.9V
|
||||
* ldo7 | XUSB | 50000 | 800000 | 1050000 | 1050000 |
|
||||
* ldo8 | XUSB, DC | 50000 | 800000 | 1050000 | 1050000 |
|
||||
*/
|
||||
@@ -70,6 +71,8 @@
|
||||
/* MAX77621_VOUT */
|
||||
#define MAX77621_VOUT_ENABLE (1 << 7)
|
||||
#define MAX77621_VOUT_MASK 0x7F
|
||||
#define MAX77621_VOUT_0_95V 0x37
|
||||
#define MAX77621_VOUT_1_09V 0x4F
|
||||
|
||||
/* MAX77621_VOUT_DVC_DVS */
|
||||
#define MAX77621_DVS_VOUT_MASK 0x7F
|
||||
@@ -108,7 +111,8 @@ int max77620_regulator_get_status(u32 id);
|
||||
int max77620_regulator_config_fps(u32 id);
|
||||
int max77620_regulator_set_voltage(u32 id, u32 mv);
|
||||
int max77620_regulator_enable(u32 id, int enable);
|
||||
int max77620_regulator_set_volt_and_flags(u32 id, u32 mv, u8 flags);
|
||||
void max77620_config_default();
|
||||
void max77620_low_battery_monitor_config();
|
||||
void max77620_low_battery_monitor_config(bool enable);
|
||||
|
||||
#endif
|
||||
|
||||
147
bootloader/rtc/max77620-rtc.c
Normal file
147
bootloader/rtc/max77620-rtc.c
Normal file
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* PMIC Real Time Clock driver for Nintendo Switch's MAX77620-RTC
|
||||
*
|
||||
* Copyright (c) 2018-2019 CTCaer
|
||||
* Copyright (c) 2019 shchmue
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* 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 "max77620-rtc.h"
|
||||
#include "../soc/i2c.h"
|
||||
#include "../utils/util.h"
|
||||
|
||||
void max77620_rtc_get_time(rtc_time_t *time)
|
||||
{
|
||||
u8 val = 0;
|
||||
|
||||
// Update RTC regs from RTC clock.
|
||||
i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_UPDATE0_REG, MAX77620_RTC_READ_UPDATE);
|
||||
|
||||
// Get control reg config.
|
||||
val = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_CONTROL_REG);
|
||||
// TODO: Check for binary format also?
|
||||
|
||||
// Get time.
|
||||
time->sec = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_SEC_REG) & 0x7F;
|
||||
time->min = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_MIN_REG) & 0x7F;
|
||||
u8 hour = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_HOUR_REG);
|
||||
time->hour = hour & 0x1F;
|
||||
|
||||
if (!(val & MAX77620_RTC_24H) && (hour & MAX77620_RTC_HOUR_PM_MASK))
|
||||
time->hour = (time->hour & 0xF) + 12;
|
||||
|
||||
// Get day of week. 1: Monday to 7: Sunday.
|
||||
time->weekday = 0;
|
||||
val = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_WEEKDAY_REG);
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
time->weekday++;
|
||||
if (val & 1)
|
||||
break;
|
||||
val >>= 1;
|
||||
}
|
||||
|
||||
// Get date.
|
||||
time->day = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_DATE_REG) & 0x1f;
|
||||
time->month = (i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_MONTH_REG) & 0xF) - 1;
|
||||
time->year = (i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_YEAR_REG) & 0x7F) + 2000;
|
||||
}
|
||||
|
||||
void max77620_rtc_stop_alarm()
|
||||
{
|
||||
u8 val = 0;
|
||||
|
||||
// Update RTC regs from RTC clock.
|
||||
i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_UPDATE0_REG, MAX77620_RTC_READ_UPDATE);
|
||||
|
||||
// Stop alarm for both ALARM1 and ALARM2. Horizon uses ALARM2.
|
||||
for (int i = 0; i < (MAX77620_RTC_NR_TIME_REGS * 2); i++)
|
||||
{
|
||||
val = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_ALARM1_SEC_REG + i);
|
||||
val &= ~MAX77620_RTC_ALARM_EN_MASK;
|
||||
i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_ALARM1_SEC_REG + i, val);
|
||||
}
|
||||
|
||||
// Update RTC clock from RTC regs.
|
||||
i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_UPDATE0_REG, MAX77620_RTC_WRITE_UPDATE);
|
||||
}
|
||||
|
||||
void max77620_rtc_epoch_to_date(u32 epoch, rtc_time_t *time)
|
||||
{
|
||||
u32 tmp, edays, year, month, day;
|
||||
|
||||
// Set time.
|
||||
time->sec = epoch % 60;
|
||||
epoch /= 60;
|
||||
time->min = epoch % 60;
|
||||
epoch /= 60;
|
||||
time->hour = epoch % 24;
|
||||
epoch /= 24;
|
||||
|
||||
// Calculate base date values.
|
||||
tmp = (u32)(((u64)4 * epoch + 102032) / 146097 + 15);
|
||||
tmp = (u32)((u64)epoch + 2442113 + tmp - (tmp >> 2));
|
||||
|
||||
year = (20 * tmp - 2442) / 7305;
|
||||
edays = tmp - 365 * year - (year >> 2);
|
||||
month = edays * 1000 / 30601;
|
||||
day = edays - month * 30 - month * 601 / 1000;
|
||||
|
||||
// Month/Year offset.
|
||||
if(month < 14)
|
||||
{
|
||||
year -= 4716;
|
||||
month--;
|
||||
}
|
||||
else
|
||||
{
|
||||
year -= 4715;
|
||||
month -= 13;
|
||||
}
|
||||
|
||||
// Set date.
|
||||
time->year = year;
|
||||
time->month = month;
|
||||
time->day = day;
|
||||
|
||||
// Set weekday.
|
||||
time->weekday = 0; //! TODO.
|
||||
}
|
||||
|
||||
u32 max77620_rtc_date_to_epoch(const rtc_time_t *time)
|
||||
{
|
||||
u32 year, month, epoch;
|
||||
|
||||
//Year
|
||||
year = time->year;
|
||||
//Month of year
|
||||
month = time->month;
|
||||
|
||||
// Month/Year offset.
|
||||
if(month < 3)
|
||||
{
|
||||
month += 12;
|
||||
year--;
|
||||
}
|
||||
|
||||
epoch = (365 * year) + (year >> 2) - (year / 100) + (year / 400); // Years to days.
|
||||
|
||||
epoch += (30 * month) + (3 * (month + 1) / 5) + time->day; // Months to days.
|
||||
epoch -= 719561; // Epoch time is 1/1/1970.
|
||||
|
||||
epoch *= 86400; // Days to seconds.
|
||||
epoch += (3600 * time->hour) + (60 * time->min) + time->sec; // Add hours, minutes and seconds.
|
||||
|
||||
return epoch;
|
||||
}
|
||||
77
bootloader/rtc/max77620-rtc.h
Normal file
77
bootloader/rtc/max77620-rtc.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* PMIC Real Time Clock driver for Nintendo Switch's MAX77620-RTC
|
||||
*
|
||||
* 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 _MFD_MAX77620_RTC_H_
|
||||
#define _MFD_MAX77620_RTC_H_
|
||||
|
||||
#include "../utils/types.h"
|
||||
|
||||
#define MAX77620_RTC_I2C_ADDR 0x68
|
||||
|
||||
#define MAX77620_RTC_NR_TIME_REGS 7
|
||||
|
||||
#define MAX77620_RTC_CONTROLM_REG 0x02
|
||||
#define MAX77620_RTC_CONTROL_REG 0x03
|
||||
#define MAX77620_RTC_BIN_FORMAT (1 << 0)
|
||||
#define MAX77620_RTC_24H (1 << 1)
|
||||
|
||||
#define MAX77620_RTC_UPDATE0_REG 0x04
|
||||
#define MAX77620_RTC_WRITE_UPDATE (1 << 0)
|
||||
#define MAX77620_RTC_READ_UPDATE (1 << 4)
|
||||
|
||||
#define MAX77620_RTC_SEC_REG 0x07
|
||||
#define MAX77620_RTC_MIN_REG 0x08
|
||||
#define MAX77620_RTC_HOUR_REG 0x09
|
||||
#define MAX77620_RTC_HOUR_PM_MASK (1 << 6)
|
||||
#define MAX77620_RTC_WEEKDAY_REG 0x0A
|
||||
#define MAX77620_RTC_MONTH_REG 0x0B
|
||||
#define MAX77620_RTC_YEAR_REG 0x0C
|
||||
#define MAX77620_RTC_DATE_REG 0x0D
|
||||
|
||||
#define MAX77620_ALARM1_SEC_REG 0x0E
|
||||
#define MAX77620_ALARM1_MIN_REG 0x0F
|
||||
#define MAX77620_ALARM1_HOUR_REG 0x10
|
||||
#define MAX77620_ALARM1_WEEKDAY_REG 0x11
|
||||
#define MAX77620_ALARM1_MONTH_REG 0x12
|
||||
#define MAX77620_ALARM1_YEAR_REG 0x13
|
||||
#define MAX77620_ALARM1_DATE_REG 0x14
|
||||
#define MAX77620_ALARM2_SEC_REG 0x15
|
||||
#define MAX77620_ALARM2_MIN_REG 0x16
|
||||
#define MAX77620_ALARM2_HOUR_REG 0x17
|
||||
#define MAX77620_ALARM2_WEEKDAY_REG 0x18
|
||||
#define MAX77620_ALARM2_MONTH_REG 0x19
|
||||
#define MAX77620_ALARM2_YEAR_REG 0x1A
|
||||
#define MAX77620_ALARM2_DATE_REG 0x1B
|
||||
#define MAX77620_RTC_ALARM_EN_MASK (1 << 7)
|
||||
|
||||
typedef struct _rtc_time_t {
|
||||
u8 weekday;
|
||||
u8 sec;
|
||||
u8 min;
|
||||
u8 hour;
|
||||
u8 day;
|
||||
u8 month;
|
||||
u16 year;
|
||||
} rtc_time_t;
|
||||
|
||||
void max77620_rtc_get_time(rtc_time_t *time);
|
||||
void max77620_rtc_stop_alarm();
|
||||
void max77620_rtc_epoch_to_date(u32 epoch, rtc_time_t *time);
|
||||
u32 max77620_rtc_date_to_epoch(const rtc_time_t *time);
|
||||
|
||||
#endif /* _MFD_MAX77620_RTC_H_ */
|
||||
@@ -1,7 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018 CTCaer
|
||||
* Copyright (c) 2018 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -20,6 +19,7 @@
|
||||
|
||||
#include "../sec/se.h"
|
||||
#include "../mem/heap.h"
|
||||
#include "../soc/bpmp.h"
|
||||
#include "../soc/t210.h"
|
||||
#include "../sec/se_t210.h"
|
||||
#include "../utils/util.h"
|
||||
@@ -36,7 +36,7 @@ static void _gf256_mul_x(void *block)
|
||||
u8 *pdata = (u8 *)block;
|
||||
u32 carry = 0;
|
||||
|
||||
for (u32 i = 0xF; i >= 0; i--)
|
||||
for (int i = 0xF; i >= 0; i--)
|
||||
{
|
||||
u8 b = pdata[i];
|
||||
pdata[i] = (b << 1) | carry;
|
||||
@@ -65,8 +65,8 @@ static int _se_wait()
|
||||
while (!(SE(SE_INT_STATUS_REG_OFFSET) & SE_INT_OP_DONE(INT_SET)))
|
||||
;
|
||||
if (SE(SE_INT_STATUS_REG_OFFSET) & SE_INT_ERROR(INT_SET) ||
|
||||
SE(SE_STATUS_0) & 3 ||
|
||||
SE(SE_ERR_STATUS_0) != 0)
|
||||
SE(SE_STATUS_0) & SE_STATUS_0_STATE_WAIT_IN ||
|
||||
SE(SE_ERR_STATUS_0) != SE_ERR_STATUS_0_SE_NS_ACCESS_CLEAR)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
@@ -91,10 +91,14 @@ static int _se_execute(u32 op, void *dst, u32 dst_size, const void *src, u32 src
|
||||
|
||||
SE(SE_ERR_STATUS_0) = SE(SE_ERR_STATUS_0);
|
||||
SE(SE_INT_STATUS_REG_OFFSET) = SE(SE_INT_STATUS_REG_OFFSET);
|
||||
SE(SE_OPERATION_REG_OFFSET) = SE_OPERATION(op);
|
||||
|
||||
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false);
|
||||
|
||||
SE(SE_OPERATION_REG_OFFSET) = SE_OPERATION(op);
|
||||
int res = _se_wait();
|
||||
|
||||
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false);
|
||||
|
||||
if (src)
|
||||
free(ll_src);
|
||||
if (dst)
|
||||
@@ -116,7 +120,7 @@ static int _se_execute_one_block(u32 op, void *dst, u32 dst_size, const void *sr
|
||||
memcpy(block, src, src_size);
|
||||
int res = _se_execute(op, block, 0x10, block, 0x10);
|
||||
memcpy(dst, block, dst_size);
|
||||
|
||||
|
||||
free(block);
|
||||
return res;
|
||||
}
|
||||
@@ -130,17 +134,19 @@ static void _se_aes_ctr_set(void *ctr)
|
||||
|
||||
void se_rsa_acc_ctrl(u32 rs, u32 flags)
|
||||
{
|
||||
if (flags & 0x7F)
|
||||
SE(SE_RSA_KEYTABLE_ACCESS_REG_OFFSET + 4 * rs) = (((flags >> 4) & 4) | (flags & 3)) ^ 7;
|
||||
if (flags & 0x80)
|
||||
if (flags & SE_RSA_KEY_TBL_DIS_KEY_ALL_FLAG)
|
||||
SE(SE_RSA_KEYTABLE_ACCESS_REG_OFFSET + 4 * rs) =
|
||||
((flags >> SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG_SHIFT) & SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG) |
|
||||
((flags & SE_RSA_KEY_TBL_DIS_KEY_READ_UPDATE_FLAG) ^ SE_RSA_KEY_TBL_DIS_KEY_ALL_COMMON_FLAG);
|
||||
if (flags & SE_RSA_KEY_TBL_DIS_KEY_LOCK_FLAG)
|
||||
SE(SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET) &= ~(1 << rs);
|
||||
}
|
||||
|
||||
void se_key_acc_ctrl(u32 ks, u32 flags)
|
||||
{
|
||||
if (flags & 0x7F)
|
||||
if (flags & SE_KEY_TBL_DIS_KEY_ACCESS_FLAG)
|
||||
SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + 4 * ks) = ~flags;
|
||||
if (flags & 0x80)
|
||||
if (flags & SE_KEY_TBL_DIS_KEY_LOCK_FLAG)
|
||||
SE(SE_KEY_TABLE_ACCESS_LOCK_OFFSET) &= ~(1 << ks);
|
||||
}
|
||||
|
||||
@@ -173,7 +179,7 @@ int se_aes_unwrap_key(u32 ks_dst, u32 ks_src, const void *input)
|
||||
return _se_execute(OP_START, NULL, 0, input, 0x10);
|
||||
}
|
||||
|
||||
int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src)
|
||||
int se_aes_crypt_ecb(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size)
|
||||
{
|
||||
if (enc)
|
||||
{
|
||||
@@ -185,8 +191,31 @@ int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src)
|
||||
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_DEC_ALG(ALG_AES_DEC) | SE_CONFIG_DST(DST_MEMORY);
|
||||
SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_DECRYPT);
|
||||
}
|
||||
SE(SE_BLOCK_COUNT_REG_OFFSET) = 0;
|
||||
return _se_execute(OP_START, dst, 0x10, src, 0x10);
|
||||
SE(SE_BLOCK_COUNT_REG_OFFSET) = (src_size >> 4) - 1;
|
||||
return _se_execute(OP_START, dst, dst_size, src, src_size);
|
||||
}
|
||||
|
||||
int se_aes_crypt_cbc(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size)
|
||||
{
|
||||
if (enc)
|
||||
{
|
||||
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY);
|
||||
SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_VCTRAM_SEL(VCTRAM_PREVAHB) |
|
||||
SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | SE_CRYPTO_XOR_POS(XOR_BOTTOM);
|
||||
}
|
||||
else
|
||||
{
|
||||
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_VCTRAM_SEL(VCTRAM_PREVAHB) |
|
||||
SE_CRYPTO_CORE_SEL(CORE_DECRYPT) | SE_CRYPTO_XOR_POS(XOR_BOTTOM);
|
||||
}
|
||||
SE(SE_BLOCK_COUNT_REG_OFFSET) = (src_size >> 4) - 1;
|
||||
return _se_execute(OP_START, dst, dst_size, src, src_size);
|
||||
}
|
||||
|
||||
int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src)
|
||||
{
|
||||
return se_aes_crypt_ecb(ks, enc, dst, 0x10, src, 0x10);
|
||||
}
|
||||
|
||||
int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size, void *ctr)
|
||||
@@ -264,21 +293,20 @@ int se_aes_xts_crypt(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, void *src, u
|
||||
return 1;
|
||||
}
|
||||
|
||||
// se_calc_sha256() was derived from Atmosphère's se_calculate_sha256.
|
||||
int se_calc_sha256(void *dst, const void *src, u32 src_size)
|
||||
{
|
||||
int res;
|
||||
// Setup config for SHA256, size = BITS(src_size).
|
||||
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_MODE(MODE_SHA256) | SE_CONFIG_ENC_ALG(ALG_SHA) | SE_CONFIG_DST(DST_HASHREG);
|
||||
SE(SE_SHA_CONFIG_REG_OFFSET) = 1;
|
||||
SE(SE_SHA_MSG_LENGTH_REG_OFFSET) = (u32)(src_size << 3);
|
||||
SE(0x208) = 0;
|
||||
SE(0x20C) = 0;
|
||||
SE(0x210) = 0;
|
||||
SE(SE_SHA_MSG_LEFT_REG_OFFSET) = (u32)(src_size << 3);
|
||||
SE(0x218) = 0;
|
||||
SE(0x21C) = 0;
|
||||
SE(0x220) = 0;
|
||||
SE(SE_SHA_CONFIG_REG_OFFSET) = SHA_INIT_HASH;
|
||||
SE(SE_SHA_MSG_LENGTH_0_REG_OFFSET) = (u32)(src_size << 3);
|
||||
SE(SE_SHA_MSG_LENGTH_1_REG_OFFSET) = 0;
|
||||
SE(SE_SHA_MSG_LENGTH_2_REG_OFFSET) = 0;
|
||||
SE(SE_SHA_MSG_LENGTH_3_REG_OFFSET) = 0;
|
||||
SE(SE_SHA_MSG_LEFT_0_REG_OFFSET) = (u32)(src_size << 3);
|
||||
SE(SE_SHA_MSG_LEFT_1_REG_OFFSET) = 0;
|
||||
SE(SE_SHA_MSG_LEFT_2_REG_OFFSET) = 0;
|
||||
SE(SE_SHA_MSG_LEFT_3_REG_OFFSET) = 0;
|
||||
|
||||
// Trigger the operation.
|
||||
res = _se_execute(OP_START, NULL, 0, src, src_size);
|
||||
@@ -291,3 +319,76 @@ int se_calc_sha256(void *dst, const void *src, u32 src_size)
|
||||
return res;
|
||||
}
|
||||
|
||||
int se_gen_prng128(void *dst)
|
||||
{
|
||||
// Setup config for X931 PRNG.
|
||||
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_MODE(MODE_KEY128) | SE_CONFIG_ENC_ALG(ALG_RNG) | SE_CONFIG_DST(DST_MEMORY);
|
||||
SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_HASH(HASH_DISABLE) | SE_CRYPTO_XOR_POS(XOR_BYPASS) | SE_CRYPTO_INPUT_SEL(INPUT_RANDOM);
|
||||
|
||||
SE(SE_RNG_CONFIG_REG_OFFSET) = SE_RNG_CONFIG_SRC(RNG_SRC_ENTROPY) | SE_RNG_CONFIG_MODE(RNG_MODE_NORMAL);
|
||||
//SE(SE_RNG_SRC_CONFIG_REG_OFFSET) =
|
||||
// SE_RNG_SRC_CONFIG_ENT_SRC(RNG_SRC_RO_ENT_ENABLE) | SE_RNG_SRC_CONFIG_ENT_SRC_LOCK(RNG_SRC_RO_ENT_LOCK_ENABLE);
|
||||
SE(SE_RNG_RESEED_INTERVAL_REG_OFFSET) = 1;
|
||||
|
||||
SE(SE_BLOCK_COUNT_REG_OFFSET) = (16 >> 4) - 1;
|
||||
|
||||
// Trigger the operation.
|
||||
return _se_execute(OP_START, dst, 16, NULL, 0);
|
||||
}
|
||||
|
||||
void se_get_aes_keys(u8 *buf, u8 *keys, u32 keysize)
|
||||
{
|
||||
u8 *aligned_buf = (u8 *)ALIGN((u32)buf, 0x40);
|
||||
|
||||
// Set Secure Random Key.
|
||||
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_MODE(MODE_KEY128) | SE_CONFIG_ENC_ALG(ALG_RNG) | SE_CONFIG_DST(DST_SRK);
|
||||
SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(0) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | SE_CRYPTO_INPUT_SEL(INPUT_RANDOM);
|
||||
SE(SE_RNG_CONFIG_REG_OFFSET) = SE_RNG_CONFIG_SRC(RNG_SRC_ENTROPY) | SE_RNG_CONFIG_MODE(RNG_MODE_FORCE_RESEED);
|
||||
SE(SE_CRYPTO_LAST_BLOCK) = 0;
|
||||
_se_execute(OP_START, NULL, 0, NULL, 0);
|
||||
|
||||
// Save AES keys.
|
||||
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_MODE(MODE_KEY128) | SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY);
|
||||
|
||||
for (u32 i = 0; i < TEGRA_SE_KEYSLOT_COUNT; i++)
|
||||
{
|
||||
SE(SE_CONTEXT_SAVE_CONFIG_REG_OFFSET) = SE_CONTEXT_SAVE_SRC(AES_KEYTABLE) |
|
||||
(i << SE_KEY_INDEX_SHIFT) | SE_CONTEXT_SAVE_WORD_QUAD(KEYS_0_3);
|
||||
|
||||
SE(SE_CRYPTO_LAST_BLOCK) = 0;
|
||||
_se_execute(OP_CTX_SAVE, aligned_buf, 0x10, NULL, 0);
|
||||
memcpy(keys + i * keysize, aligned_buf, 0x10);
|
||||
|
||||
if (keysize > 0x10)
|
||||
{
|
||||
SE(SE_CONTEXT_SAVE_CONFIG_REG_OFFSET) = SE_CONTEXT_SAVE_SRC(AES_KEYTABLE) |
|
||||
(i << SE_KEY_INDEX_SHIFT) | SE_CONTEXT_SAVE_WORD_QUAD(KEYS_4_7);
|
||||
|
||||
SE(SE_CRYPTO_LAST_BLOCK) = 0;
|
||||
_se_execute(OP_CTX_SAVE, aligned_buf, 0x10, NULL, 0);
|
||||
memcpy(keys + i * keysize + 0x10, aligned_buf, 0x10);
|
||||
}
|
||||
}
|
||||
|
||||
// Save SRK to PMC secure scratches.
|
||||
SE(SE_CONTEXT_SAVE_CONFIG_REG_OFFSET) = SE_CONTEXT_SAVE_SRC(SRK);
|
||||
SE(0x80) = 0; // SE_CRYPTO_LAST_BLOCK
|
||||
_se_execute(OP_CTX_SAVE, NULL, 0, NULL, 0);
|
||||
|
||||
// End context save.
|
||||
SE(SE_CONFIG_REG_OFFSET) = 0;
|
||||
_se_execute(OP_CTX_SAVE, NULL, 0, NULL, 0);
|
||||
|
||||
// Get SRK.
|
||||
u32 srk[4];
|
||||
srk[0] = PMC(0xC0);
|
||||
srk[1] = PMC(0xC4);
|
||||
srk[2] = PMC(0x224);
|
||||
srk[3] = PMC(0x228);
|
||||
|
||||
// Decrypt context.
|
||||
se_aes_key_clear(3);
|
||||
se_aes_key_set(3, srk, 0x10);
|
||||
se_aes_crypt_cbc(3, 0, keys, TEGRA_SE_KEYSLOT_COUNT * keysize, keys, TEGRA_SE_KEYSLOT_COUNT * keysize);
|
||||
se_aes_key_clear(3);
|
||||
}
|
||||
|
||||
@@ -21,11 +21,14 @@
|
||||
|
||||
void se_rsa_acc_ctrl(u32 rs, u32 flags);
|
||||
void se_key_acc_ctrl(u32 ks, u32 flags);
|
||||
void se_get_aes_keys(u8 *buf, u8 *keys, u32 keysize);
|
||||
void se_aes_key_set(u32 ks, void *key, u32 size);
|
||||
void se_aes_key_clear(u32 ks);
|
||||
int se_aes_unwrap_key(u32 ks_dst, u32 ks_src, const void *input);
|
||||
int se_aes_crypt_ecb(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size);
|
||||
int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src);
|
||||
int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size, void *ctr);
|
||||
int se_calc_sha256(void *dst, const void *src, u32 src_size);
|
||||
int se_gen_prng128(void *dst);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
#define SE_SECURITY_0 0x000
|
||||
#define SE_KEY_SCHED_READ_SHIFT 3
|
||||
|
||||
#define SE_TZRAM_SECURITY_0 0x004
|
||||
|
||||
#define SE_CONFIG_REG_OFFSET 0x014
|
||||
#define SE_CONFIG_ENC_ALG_SHIFT 12
|
||||
#define SE_CONFIG_DEC_ALG_SHIFT 8
|
||||
@@ -68,27 +70,26 @@
|
||||
#define SE_CONFIG_DEC_MODE(x) (x << SE_CONFIG_DEC_MODE_SHIFT)
|
||||
|
||||
#define SE_RNG_CONFIG_REG_OFFSET 0x340
|
||||
#define DRBG_MODE_SHIFT 0
|
||||
#define DRBG_MODE_NORMAL 0
|
||||
#define DRBG_MODE_FORCE_INSTANTION 1
|
||||
#define DRBG_MODE_FORCE_RESEED 2
|
||||
#define SE_RNG_CONFIG_MODE(x) (x << DRBG_MODE_SHIFT)
|
||||
#define RNG_MODE_SHIFT 0
|
||||
#define RNG_MODE_NORMAL 0
|
||||
#define RNG_MODE_FORCE_INSTANTION 1
|
||||
#define RNG_MODE_FORCE_RESEED 2
|
||||
#define SE_RNG_CONFIG_MODE(x) (x << RNG_MODE_SHIFT)
|
||||
#define RNG_SRC_SHIFT 2
|
||||
#define RNG_SRC_NONE 0
|
||||
#define RNG_SRC_ENTROPY 1
|
||||
#define RNG_SRC_LFSR 2
|
||||
#define SE_RNG_CONFIG_SRC(x) (x << RNG_SRC_SHIFT)
|
||||
|
||||
#define SE_RNG_SRC_CONFIG_REG_OFFSET 0x344
|
||||
#define DRBG_RO_ENT_SRC_SHIFT 1
|
||||
#define DRBG_RO_ENT_SRC_ENABLE 1
|
||||
#define DRBG_RO_ENT_SRC_DISABLE 0
|
||||
#define SE_RNG_SRC_CONFIG_RO_ENT_SRC(x) (x << DRBG_RO_ENT_SRC_SHIFT)
|
||||
#define DRBG_RO_ENT_SRC_LOCK_SHIFT 0
|
||||
#define DRBG_RO_ENT_SRC_LOCK_ENABLE 1
|
||||
#define DRBG_RO_ENT_SRC_LOCK_DISABLE 0
|
||||
#define SE_RNG_SRC_CONFIG_RO_ENT_SRC_LOCK(x) (x << DRBG_RO_ENT_SRC_LOCK_SHIFT)
|
||||
|
||||
#define DRBG_SRC_SHIFT 2
|
||||
#define DRBG_SRC_NONE 0
|
||||
#define DRBG_SRC_ENTROPY 1
|
||||
#define DRBG_SRC_LFSR 2
|
||||
#define SE_RNG_CONFIG_SRC(x) (x << DRBG_SRC_SHIFT)
|
||||
#define RNG_SRC_RO_ENT_SHIFT 1
|
||||
#define RNG_SRC_RO_ENT_ENABLE 1
|
||||
#define RNG_SRC_RO_ENT_DISABLE 0
|
||||
#define SE_RNG_SRC_CONFIG_ENT_SRC(x) (x << RNG_SRC_RO_ENT_SHIFT)
|
||||
#define RNG_SRC_RO_ENT_LOCK_SHIFT 0
|
||||
#define RNG_SRC_RO_ENT_LOCK_ENABLE 1
|
||||
#define RNG_SRC_RO_ENT_LOCK_DISABLE 0
|
||||
#define SE_RNG_SRC_CONFIG_ENT_SRC_LOCK(x) (x << RNG_SRC_RO_ENT_LOCK_SHIFT)
|
||||
|
||||
#define SE_RNG_RESEED_INTERVAL_REG_OFFSET 0x348
|
||||
|
||||
@@ -117,6 +118,8 @@
|
||||
#define OP_DONE 1
|
||||
#define SE_OP_DONE(x, y) ((x) && (y << SE_OP_DONE_SHIFT))
|
||||
|
||||
#define SE_CRYPTO_LAST_BLOCK 0x080
|
||||
|
||||
#define SE_CRYPTO_REG_OFFSET 0x304
|
||||
#define SE_CRYPTO_HASH_SHIFT 0
|
||||
#define HASH_DISABLE 0
|
||||
@@ -189,6 +192,7 @@
|
||||
#define SRK 6
|
||||
|
||||
#define RSA_KEYTABLE 1
|
||||
#define AES_KEYTABLE 2
|
||||
#define SE_CONTEXT_SAVE_SRC(x) (x << SE_CONTEXT_SAVE_SRC_SHIFT)
|
||||
|
||||
#define SE_CONTEXT_SAVE_RSA_KEY_INDEX_SHIFT 16
|
||||
@@ -209,8 +213,12 @@
|
||||
#define SE_INT_OP_DONE(x) (x << SE_INT_OP_DONE_SHIFT)
|
||||
#define SE_INT_ERROR_SHIFT 16
|
||||
#define SE_INT_ERROR(x) (x << SE_INT_ERROR_SHIFT)
|
||||
|
||||
#define SE_STATUS_0 0x800
|
||||
#define SE_STATUS_0_STATE_WAIT_IN 3
|
||||
|
||||
#define SE_ERR_STATUS_0 0x804
|
||||
#define SE_ERR_STATUS_0_SE_NS_ACCESS_CLEAR 0
|
||||
|
||||
#define SE_CRYPTO_KEYTABLE_DST_REG_OFFSET 0X330
|
||||
#define SE_CRYPTO_KEYTABLE_DST_WORD_QUAD_SHIFT 0
|
||||
@@ -231,11 +239,17 @@
|
||||
#define SE_SPARE_0_REG_OFFSET 0x80c
|
||||
|
||||
#define SE_SHA_CONFIG_REG_OFFSET 0x200
|
||||
#define SHA_DISABLE 0
|
||||
#define SHA_ENABLE 1
|
||||
#define SHA_CONTINUE 0
|
||||
#define SHA_INIT_HASH 1
|
||||
|
||||
#define SE_SHA_MSG_LENGTH_REG_OFFSET 0x204
|
||||
#define SE_SHA_MSG_LEFT_REG_OFFSET 0x214
|
||||
#define SE_SHA_MSG_LENGTH_0_REG_OFFSET 0x204
|
||||
#define SE_SHA_MSG_LENGTH_1_REG_OFFSET 0x208
|
||||
#define SE_SHA_MSG_LENGTH_2_REG_OFFSET 0x20C
|
||||
#define SE_SHA_MSG_LENGTH_3_REG_OFFSET 0x210
|
||||
#define SE_SHA_MSG_LEFT_0_REG_OFFSET 0x214
|
||||
#define SE_SHA_MSG_LEFT_1_REG_OFFSET 0x218
|
||||
#define SE_SHA_MSG_LEFT_2_REG_OFFSET 0x21C
|
||||
#define SE_SHA_MSG_LEFT_3_REG_OFFSET 0x220
|
||||
|
||||
#define SE_HASH_RESULT_REG_COUNT 16
|
||||
#define SE_HASH_RESULT_REG_OFFSET 0x030
|
||||
@@ -254,13 +268,24 @@
|
||||
TEGRA_SE_RNG_DT_SIZE)
|
||||
|
||||
#define TEGRA_SE_AES_CMAC_DIGEST_SIZE 16
|
||||
#define TEGRA_SE_RSA512_DIGEST_SIZE 64
|
||||
#define TEGRA_SE_RSA512_DIGEST_SIZE 64
|
||||
#define TEGRA_SE_RSA1024_DIGEST_SIZE 128
|
||||
#define TEGRA_SE_RSA1536_DIGEST_SIZE 192
|
||||
#define TEGRA_SE_RSA2048_DIGEST_SIZE 256
|
||||
|
||||
#define SE_KEY_TABLE_ACCESS_LOCK_OFFSET 0x280
|
||||
#define SE_KEY_TBL_DIS_KEY_LOCK_FLAG 0x80
|
||||
|
||||
#define SE_KEY_TABLE_ACCESS_REG_OFFSET 0x284
|
||||
#define SE_KEY_TBL_DIS_KEYREAD_FLAG (1 << 0)
|
||||
#define SE_KEY_TBL_DIS_KEYUPDATE_FLAG (1 << 1)
|
||||
#define SE_KEY_TBL_DIS_OIVREAD_FLAG (1 << 2)
|
||||
#define SE_KEY_TBL_DIS_OIVUPDATE_FLAG (1 << 3)
|
||||
#define SE_KEY_TBL_DIS_UIVREAD_FLAG (1 << 4)
|
||||
#define SE_KEY_TBL_DIS_UIVUPDATE_FLAG (1 << 5)
|
||||
#define SE_KEY_TBL_DIS_KEYUSE_FLAG (1 << 6)
|
||||
#define SE_KEY_TBL_DIS_KEY_ACCESS_FLAG 0x7F
|
||||
|
||||
#define SE_KEY_READ_DISABLE_SHIFT 0
|
||||
#define SE_KEY_UPDATE_DISABLE_SHIFT 1
|
||||
|
||||
@@ -312,7 +337,16 @@
|
||||
#define TEGRA_SE_RSA_KEYSLOT_COUNT 2
|
||||
|
||||
#define SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET 0x40C
|
||||
#define SE_RSA_KEY_TBL_DIS_KEY_LOCK_FLAG 0x80
|
||||
|
||||
#define SE_RSA_KEYTABLE_ACCESS_REG_OFFSET 0x410
|
||||
#define SE_RSA_KEY_TBL_DIS_KEYREAD_FLAG (1 << 0)
|
||||
#define SE_RSA_KEY_TBL_DIS_KEYUPDATE_FLAG (1 << 1)
|
||||
#define SE_RSA_KEY_TBL_DIS_KEY_READ_UPDATE_FLAG (SE_RSA_KEY_TBL_DIS_KEYREAD_FLAG | SE_RSA_KEY_TBL_DIS_KEYUPDATE_FLAG)
|
||||
#define SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG (1 << 2)
|
||||
#define SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG_SHIFT (1 << 2)
|
||||
#define SE_RSA_KEY_TBL_DIS_KEY_ALL_COMMON_FLAG 7
|
||||
#define SE_RSA_KEY_TBL_DIS_KEY_ALL_FLAG 0x7F
|
||||
|
||||
#define SE_RSA_KEYTABLE_ADDR 0x420
|
||||
#define SE_RSA_KEYTABLE_DATA 0x424
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2019 CTCaer
|
||||
* Copyright (c) 2018 balika011
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -17,16 +19,25 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "../sec/tsec.h"
|
||||
#include "../sec/tsec_t210.h"
|
||||
#include "../sec/se_t210.h"
|
||||
#include "../soc/bpmp.h"
|
||||
#include "../soc/clock.h"
|
||||
#include "../soc/kfuse.h"
|
||||
#include "../soc/smmu.h"
|
||||
#include "../soc/t210.h"
|
||||
#include "../mem/heap.h"
|
||||
#include "../mem/mc.h"
|
||||
#include "../utils/util.h"
|
||||
#include "../hos/hos.h"
|
||||
|
||||
// #include "../gfx/gfx.h"
|
||||
|
||||
static int _tsec_dma_wait_idle()
|
||||
{
|
||||
u32 timeout = get_tmr_ms() + 10000;
|
||||
|
||||
while (!(TSEC(0x1118) & 2))
|
||||
while (!(TSEC(TSEC_DMATRFCMD) & TSEC_DMATRFCMD_IDLE))
|
||||
if (get_tmr_ms() > timeout)
|
||||
return 0;
|
||||
|
||||
@@ -38,101 +49,240 @@ static int _tsec_dma_pa_to_internal_100(int not_imem, int i_offset, int pa_offse
|
||||
u32 cmd;
|
||||
|
||||
if (not_imem)
|
||||
cmd = 0x600; // DMA 0x100 bytes
|
||||
cmd = TSEC_DMATRFCMD_SIZE_256B; // DMA 256 bytes
|
||||
else
|
||||
cmd = 0x10; // dma imem
|
||||
cmd = TSEC_DMATRFCMD_IMEM; // DMA IMEM (Instruction memmory)
|
||||
|
||||
TSEC(0x1114) = i_offset; // tsec_dmatrfmoffs_r
|
||||
TSEC(0x111C) = pa_offset; // tsec_dmatrffboffs_r
|
||||
TSEC(0x1118) = cmd; // tsec_dmatrfcmd_r
|
||||
TSEC(TSEC_DMATRFMOFFS) = i_offset;
|
||||
TSEC(TSEC_DMATRFFBOFFS) = pa_offset;
|
||||
TSEC(TSEC_DMATRFCMD) = cmd;
|
||||
|
||||
return _tsec_dma_wait_idle();
|
||||
}
|
||||
|
||||
int tsec_query(u8 *dst, u32 rev, void *fw)
|
||||
int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
|
||||
{
|
||||
int res = 0;
|
||||
u8 *fwbuf = NULL;
|
||||
u32 *pdir, *car, *fuse, *pmc, *flowctrl, *se, *mc, *iram, *evec;
|
||||
u32 *pkg11_magic_off;
|
||||
|
||||
//Enable clocks.
|
||||
bpmp_mmu_disable();
|
||||
bpmp_clk_rate_set(BPMP_CLK_NORMAL);
|
||||
|
||||
// Enable clocks.
|
||||
clock_enable_host1x();
|
||||
usleep(2);
|
||||
clock_enable_tsec();
|
||||
clock_enable_sor_safe();
|
||||
clock_enable_sor0();
|
||||
clock_enable_sor1();
|
||||
clock_enable_kfuse();
|
||||
|
||||
//Configure Falcon.
|
||||
TSEC(0x110C) = 0; // tsec_dmactl_r
|
||||
TSEC(0x1010) = 0xFFF2; // tsec_irqmset_r
|
||||
TSEC(0x101C) = 0xFFF0; // tsec_irqdest_r
|
||||
TSEC(0x1048) = 3; // tsec_itfen_r
|
||||
kfuse_wait_ready();
|
||||
|
||||
// Configure Falcon.
|
||||
TSEC(TSEC_DMACTL) = 0;
|
||||
TSEC(TSEC_IRQMSET) =
|
||||
TSEC_IRQMSET_EXT(0xFF) |
|
||||
TSEC_IRQMSET_WDTMR |
|
||||
TSEC_IRQMSET_HALT |
|
||||
TSEC_IRQMSET_EXTERR |
|
||||
TSEC_IRQMSET_SWGEN0 |
|
||||
TSEC_IRQMSET_SWGEN1;
|
||||
TSEC(TSEC_IRQDEST) =
|
||||
TSEC_IRQDEST_EXT(0xFF) |
|
||||
TSEC_IRQDEST_HALT |
|
||||
TSEC_IRQDEST_EXTERR |
|
||||
TSEC_IRQDEST_SWGEN0 |
|
||||
TSEC_IRQDEST_SWGEN1;
|
||||
TSEC(TSEC_ITFEN) = TSEC_ITFEN_CTXEN | TSEC_ITFEN_MTHDEN;
|
||||
if (!_tsec_dma_wait_idle())
|
||||
{
|
||||
res = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
//Load firmware.
|
||||
u8 *fwbuf = (u8 *)malloc(0x2000);
|
||||
u8 *fwbuf_aligned = (u8 *)ALIGN((u32)fwbuf + 0x1000, 0x100);
|
||||
memcpy(fwbuf_aligned, fw, 0xF00);
|
||||
TSEC(0x1110) = (u32)fwbuf_aligned >> 8;// tsec_dmatrfbase_r
|
||||
for (u32 addr = 0; addr < 0xF00; addr += 0x100)
|
||||
if (!_tsec_dma_pa_to_internal_100(0, addr, addr))
|
||||
// Load firmware or emulate memio environment for newer TSEC fw.
|
||||
if (kb == KB_FIRMWARE_VERSION_620)
|
||||
TSEC(TSEC_DMATRFBASE) = (u32)tsec_ctxt->fw >> 8;
|
||||
else
|
||||
{
|
||||
fwbuf = (u8 *)malloc(0x4000);
|
||||
u8 *fwbuf_aligned = (u8 *)ALIGN((u32)fwbuf, 0x100);
|
||||
memcpy(fwbuf_aligned, tsec_ctxt->fw, tsec_ctxt->size);
|
||||
TSEC(TSEC_DMATRFBASE) = (u32)fwbuf_aligned >> 8;
|
||||
}
|
||||
|
||||
for (u32 addr = 0; addr < tsec_ctxt->size; addr += 0x100)
|
||||
{
|
||||
if (!_tsec_dma_pa_to_internal_100(false, addr, addr))
|
||||
{
|
||||
res = -2;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
//Execute firmware.
|
||||
HOST1X(0x3300) = 0x34C2E1DA;
|
||||
TSEC(0x1044) = 0;
|
||||
TSEC(0x1040) = rev;
|
||||
TSEC(0x1104) = 0; // tsec_bootvec_r
|
||||
TSEC(0x1100) = 2; // tsec_cpuctl_r
|
||||
if (!_tsec_dma_wait_idle())
|
||||
{
|
||||
res = -3;
|
||||
goto out_free;
|
||||
}
|
||||
u32 timeout = get_tmr_ms() + 2000;
|
||||
while (!TSEC(0x1044))
|
||||
if (get_tmr_ms() > timeout)
|
||||
|
||||
if (kb == KB_FIRMWARE_VERSION_620)
|
||||
{
|
||||
// Init SMMU translation for TSEC.
|
||||
pdir = smmu_init_for_tsec();
|
||||
smmu_init(tsec_ctxt->secmon_base);
|
||||
// Enable SMMU
|
||||
if (!smmu_is_used())
|
||||
smmu_enable();
|
||||
|
||||
// Clock reset controller.
|
||||
car = page_alloc(1);
|
||||
memcpy(car, (void *)CLOCK_BASE, 0x1000);
|
||||
car[CLK_RST_CONTROLLER_CLK_SOURCE_TSEC / 4] = 2;
|
||||
smmu_map(pdir, CLOCK_BASE, (u32)car, 1, _WRITABLE | _READABLE | _NONSECURE);
|
||||
|
||||
// Fuse driver.
|
||||
fuse = page_alloc(1);
|
||||
memcpy((void *)&fuse[0x800/4], (void *)FUSE_BASE, 0x400);
|
||||
fuse[0x82C / 4] = 0;
|
||||
fuse[0x9E0 / 4] = (1 << (kb + 2)) - 1;
|
||||
fuse[0x9E4 / 4] = (1 << (kb + 2)) - 1;
|
||||
smmu_map(pdir, (FUSE_BASE - 0x800), (u32)fuse, 1, _READABLE | _NONSECURE);
|
||||
|
||||
// Power management controller.
|
||||
pmc = page_alloc(1);
|
||||
smmu_map(pdir, RTC_BASE, (u32)pmc, 1, _READABLE | _NONSECURE);
|
||||
|
||||
// Flow control.
|
||||
flowctrl = page_alloc(1);
|
||||
smmu_map(pdir, FLOW_CTLR_BASE, (u32)flowctrl, 1, _WRITABLE | _NONSECURE);
|
||||
|
||||
// Security engine.
|
||||
se = page_alloc(1);
|
||||
memcpy(se, (void *)SE_BASE, 0x1000);
|
||||
smmu_map(pdir, SE_BASE, (u32)se, 1, _READABLE | _WRITABLE | _NONSECURE);
|
||||
|
||||
// Memory controller.
|
||||
mc = page_alloc(1);
|
||||
memcpy(mc, (void *)MC_BASE, 0x1000);
|
||||
mc[MC_IRAM_BOM / 4] = 0;
|
||||
mc[MC_IRAM_TOM / 4] = 0x80000000;
|
||||
smmu_map(pdir, MC_BASE, (u32)mc, 1, _READABLE | _NONSECURE);
|
||||
|
||||
// IRAM
|
||||
iram = page_alloc(0x30);
|
||||
memcpy(iram, tsec_ctxt->pkg1, 0x30000);
|
||||
// PKG1.1 magic offset.
|
||||
pkg11_magic_off = (u32 *)(iram + ((tsec_ctxt->pkg11_off + 0x20) / 4));
|
||||
smmu_map(pdir, 0x40010000, (u32)iram, 0x30, _READABLE | _WRITABLE | _NONSECURE);
|
||||
|
||||
// Exception vectors
|
||||
evec = page_alloc(1);
|
||||
smmu_map(pdir, EXCP_VEC_BASE, (u32)evec, 1, _READABLE | _WRITABLE | _NONSECURE);
|
||||
}
|
||||
|
||||
// Execute firmware.
|
||||
HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0x34C2E1DA;
|
||||
TSEC(TSEC_STATUS) = 0;
|
||||
TSEC(TSEC_BOOTKEYVER) = 1; // HOS uses key version 1.
|
||||
TSEC(TSEC_BOOTVEC) = 0;
|
||||
TSEC(TSEC_CPUCTL) = TSEC_CPUCTL_STARTCPU;
|
||||
|
||||
if (kb == KB_FIRMWARE_VERSION_620)
|
||||
{
|
||||
u32 start = get_tmr_us();
|
||||
u32 k = se[SE_KEYTABLE_DATA0_REG_OFFSET / 4];
|
||||
u32 key[16] = {0};
|
||||
u32 kidx = 0;
|
||||
|
||||
while (*pkg11_magic_off != HOS_PKG11_MAGIC)
|
||||
{
|
||||
res = -4;
|
||||
smmu_flush_all();
|
||||
|
||||
if (k != se[SE_KEYTABLE_DATA0_REG_OFFSET / 4])
|
||||
{
|
||||
k = se[SE_KEYTABLE_DATA0_REG_OFFSET / 4];
|
||||
key[kidx++] = k;
|
||||
}
|
||||
|
||||
// Failsafe.
|
||||
if ((u32)get_tmr_us() - start > 125000)
|
||||
break;
|
||||
}
|
||||
|
||||
if (kidx != 8)
|
||||
{
|
||||
res = -6;
|
||||
smmu_deinit_for_tsec();
|
||||
|
||||
goto out_free;
|
||||
}
|
||||
if (TSEC(0x1044) != 0xB0B0B0B0)
|
||||
{
|
||||
res = -5;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
//Fetch result.
|
||||
HOST1X(0x3300) = 0;
|
||||
u32 buf[4];
|
||||
buf[0] = SOR1(0x1E8);
|
||||
buf[1] = SOR1(0x21C);
|
||||
buf[2] = SOR1(0x208);
|
||||
buf[3] = SOR1(0x20C);
|
||||
SOR1(0x1E8) = 0;
|
||||
SOR1(0x21C) = 0;
|
||||
SOR1(0x208) = 0;
|
||||
SOR1(0x20C) = 0;
|
||||
memcpy(dst, &buf, 0x10);
|
||||
// Give some extra time to make sure PKG1.1 is decrypted.
|
||||
msleep(50);
|
||||
|
||||
memcpy(tsec_keys, &key, 0x20);
|
||||
memcpy(tsec_ctxt->pkg1, iram, 0x30000);
|
||||
|
||||
smmu_deinit_for_tsec();
|
||||
|
||||
// for (int i = 0; i < kidx; i++)
|
||||
// gfx_printf("key %08X\n", key[i]);
|
||||
|
||||
// gfx_printf("cpuctl (%08X) mbox (%08X)\n", TSEC(TSEC_CPUCTL), TSEC(TSEC_STATUS));
|
||||
|
||||
// u32 errst = MC(MC_ERR_STATUS);
|
||||
// gfx_printf(" MC %08X %08X %08X\n", MC(MC_INTSTATUS), errst, MC(MC_ERR_ADR));
|
||||
// gfx_printf(" type: %02X\n", errst >> 28);
|
||||
// gfx_printf(" smmu: %02X\n", (errst >> 25) & 3);
|
||||
// gfx_printf(" dir: %s\n", (errst >> 16) & 1 ? "W" : "R");
|
||||
// gfx_printf(" cid: %02x\n", errst & 0xFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
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:;
|
||||
free(fwbuf);
|
||||
|
||||
out:;
|
||||
|
||||
//Disable clocks.
|
||||
// Disable clocks.
|
||||
clock_disable_kfuse();
|
||||
clock_disable_sor1();
|
||||
clock_disable_sor0();
|
||||
clock_disable_sor_safe();
|
||||
clock_disable_tsec();
|
||||
clock_disable_host1x();
|
||||
bpmp_mmu_enable();
|
||||
bpmp_clk_rate_set(BPMP_CLK_DEFAULT_BOOST);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* 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,
|
||||
@@ -19,6 +20,15 @@
|
||||
|
||||
#include "../utils/types.h"
|
||||
|
||||
int tsec_query(u8 *dst, u32 rev, void *fw);
|
||||
typedef struct _tsec_ctxt_t
|
||||
{
|
||||
void *fw;
|
||||
u32 size;
|
||||
void *pkg1;
|
||||
u32 pkg11_off;
|
||||
u32 secmon_base;
|
||||
} tsec_ctxt_t;
|
||||
|
||||
int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt);
|
||||
|
||||
#endif
|
||||
|
||||
50
bootloader/sec/tsec_t210.h
Normal file
50
bootloader/sec/tsec_t210.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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 _TSEC_T210_H_
|
||||
#define _TSEC_T210_H_
|
||||
|
||||
#define TSEC_BOOTKEYVER 0x1040
|
||||
#define TSEC_STATUS 0x1044
|
||||
#define TSEC_ITFEN 0x1048
|
||||
#define TSEC_ITFEN_CTXEN (1 << 0)
|
||||
#define TSEC_ITFEN_MTHDEN (1 << 1)
|
||||
#define TSEC_IRQMSET 0x1010
|
||||
#define TSEC_IRQMSET_WDTMR (1 << 1)
|
||||
#define TSEC_IRQMSET_HALT (1 << 4)
|
||||
#define TSEC_IRQMSET_EXTERR (1 << 5)
|
||||
#define TSEC_IRQMSET_SWGEN0 (1 << 6)
|
||||
#define TSEC_IRQMSET_SWGEN1 (1 << 7)
|
||||
#define TSEC_IRQMSET_EXT(val) (((val) & 0xFF) << 8)
|
||||
#define TSEC_IRQDEST 0x101C
|
||||
#define TSEC_IRQDEST_HALT (1 << 4)
|
||||
#define TSEC_IRQDEST_EXTERR (1 << 5)
|
||||
#define TSEC_IRQDEST_SWGEN0 (1 << 6)
|
||||
#define TSEC_IRQDEST_SWGEN1 (1 << 7)
|
||||
#define TSEC_IRQDEST_EXT(val) (((val) & 0xFF) << 8)
|
||||
#define TSEC_CPUCTL 0x1100
|
||||
#define TSEC_CPUCTL_STARTCPU (1 << 1)
|
||||
#define TSEC_BOOTVEC 0x1104
|
||||
#define TSEC_DMACTL 0x110C
|
||||
#define TSEC_DMATRFBASE 0x1110
|
||||
#define TSEC_DMATRFMOFFS 0x1114
|
||||
#define TSEC_DMATRFCMD 0x1118
|
||||
#define TSEC_DMATRFCMD_IDLE (1 << 1)
|
||||
#define TSEC_DMATRFCMD_IMEM (1 << 4)
|
||||
#define TSEC_DMATRFCMD_SIZE_256B (6 << 8)
|
||||
#define TSEC_DMATRFFBOFFS 0x111C
|
||||
|
||||
#endif
|
||||
308
bootloader/soc/bpmp.c
Normal file
308
bootloader/soc/bpmp.c
Normal file
@@ -0,0 +1,308 @@
|
||||
/*
|
||||
* BPMP-Lite Cache/MMU and Frequency driver for Tegra X1
|
||||
*
|
||||
* Copyright (c) 2019-2020 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "bpmp.h"
|
||||
#include "clock.h"
|
||||
#include "t210.h"
|
||||
#include "../../common/memory_map.h"
|
||||
#include "../utils/util.h"
|
||||
|
||||
#define BPMP_MMU_CACHE_LINE_SIZE 0x20
|
||||
|
||||
#define BPMP_CACHE_CONFIG 0x0
|
||||
#define CFG_ENABLE_CACHE (1 << 0)
|
||||
#define CFG_ENABLE_SKEW_ASSOC (1 << 1)
|
||||
#define CFG_DISABLE_RANDOM_ALLOC (1 << 2)
|
||||
#define CFG_FORCE_WRITE_THROUGH (1 << 3)
|
||||
#define CFG_NEVER_ALLOCATE (1 << 6)
|
||||
#define CFG_ENABLE_INTERRUPT (1 << 7)
|
||||
#define CFG_MMU_TAG_MODE(x) (x << 8)
|
||||
#define TAG_MODE_PARALLEL 0
|
||||
#define TAG_MODE_TAG_FIRST 1
|
||||
#define TAG_MODE_MMU_FIRST 2
|
||||
#define CFG_DISABLE_WRITE_BUFFER (1 << 10)
|
||||
#define CFG_DISABLE_READ_BUFFER (1 << 11)
|
||||
#define CFG_ENABLE_HANG_DETECT (1 << 12)
|
||||
#define CFG_FULL_LINE_DIRTY (1 << 13)
|
||||
#define CFG_TAG_CHK_ABRT_ON_ERR (1 << 14)
|
||||
#define CFG_TAG_CHK_CLR_ERR (1 << 15)
|
||||
#define CFG_DISABLE_SAMELINE (1 << 16)
|
||||
#define CFG_OBS_BUS_EN (1 << 31)
|
||||
|
||||
#define BPMP_CACHE_LOCK 0x4
|
||||
#define LOCK_LINE(x) (1 << x)
|
||||
|
||||
#define BPMP_CACHE_SIZE 0xC
|
||||
#define BPMP_CACHE_LFSR 0x10
|
||||
|
||||
#define BPMP_CACHE_TAG_STATUS 0x14
|
||||
#define TAG_STATUS_TAG_CHECK_ERROR (1 << 0)
|
||||
#define TAG_STATUS_CONFLICT_ADDR_MASK 0xFFFFFFE0
|
||||
|
||||
#define BPMP_CACHE_CLKEN_OVERRIDE 0x18
|
||||
#define CLKEN_OVERRIDE_WR_MCCIF_CLKEN (1 << 0)
|
||||
#define CLKEN_OVERRIDE_RD_MCCIF_CLKEN (1 << 1)
|
||||
|
||||
#define BPMP_CACHE_MAINT_ADDR 0x20
|
||||
#define BPMP_CACHE_MAINT_DATA 0x24
|
||||
|
||||
#define BPMP_CACHE_MAINT_REQ 0x28
|
||||
#define MAINT_REQ_WAY_BITMAP(x) ((x) << 8)
|
||||
|
||||
#define BPMP_CACHE_INT_MASK 0x40
|
||||
#define BPMP_CACHE_INT_CLEAR 0x44
|
||||
#define BPMP_CACHE_INT_RAW_EVENT 0x48
|
||||
#define BPMP_CACHE_INT_STATUS 0x4C
|
||||
#define INT_MAINT_DONE (1 << 0)
|
||||
#define INT_MAINT_ERROR (1 << 1)
|
||||
|
||||
#define BPMP_CACHE_RB_CFG 0x80
|
||||
#define BPMP_CACHE_WB_CFG 0x84
|
||||
|
||||
#define BPMP_CACHE_MMU_FALLBACK_ENTRY 0xA0
|
||||
#define BPMP_CACHE_MMU_SHADOW_COPY_MASK 0xA4
|
||||
|
||||
#define BPMP_CACHE_MMU_CFG 0xAC
|
||||
#define MMU_CFG_BLOCK_MAIN_ENTRY_WR (1 << 0)
|
||||
#define MMU_CFG_SEQ_EN (1 << 1)
|
||||
#define MMU_CFG_TLB_EN (1 << 2)
|
||||
#define MMU_CFG_SEG_CHECK_ALL_ENTRIES (1 << 3)
|
||||
#define MMU_CFG_ABORT_STORE_LAST (1 << 4)
|
||||
#define MMU_CFG_CLR_ABORT (1 << 5)
|
||||
|
||||
#define BPMP_CACHE_MMU_CMD 0xB0
|
||||
#define MMU_CMD_NOP 0
|
||||
#define MMU_CMD_INIT 1
|
||||
#define MMU_CMD_COPY_SHADOW 2
|
||||
|
||||
#define BPMP_CACHE_MMU_ABORT_STAT 0xB4
|
||||
#define ABORT_STAT_UNIT_MASK 0x7
|
||||
#define ABORT_STAT_UNIT_NONE 0
|
||||
#define ABORT_STAT_UNIT_CACHE 1
|
||||
#define ABORT_STAT_UNIT_SEQ 2
|
||||
#define ABORT_STAT_UNIT_TLB 3
|
||||
#define ABORT_STAT_UNIT_SEG 4
|
||||
#define ABORT_STAT_UNIT_FALLBACK 5
|
||||
#define ABORT_STAT_OVERLAP (1 << 3)
|
||||
#define ABORT_STAT_ENTRY (0x1F << 4)
|
||||
#define ABORT_STAT_TYPE_MASK (3 << 16)
|
||||
#define ABORT_STAT_TYPE_EXE (0 << 16)
|
||||
#define ABORT_STAT_TYPE_RD (1 << 16)
|
||||
#define ABORT_STAT_TYPE_WR (2 << 16)
|
||||
#define ABORT_STAT_SIZE (3 << 18)
|
||||
#define ABORT_STAT_SEQ (1 << 20)
|
||||
#define ABORT_STAT_PROT (1 << 21)
|
||||
|
||||
#define BPMP_CACHE_MMU_ABORT_ADDR 0xB8
|
||||
#define BPMP_CACHE_MMU_ACTIVE_ENTRIES 0xBC
|
||||
|
||||
#define BPMP_MMU_SHADOW_ENTRY_BASE (BPMP_CACHE_BASE + 0x400)
|
||||
#define BPMP_MMU_MAIN_ENTRY_BASE (BPMP_CACHE_BASE + 0x800)
|
||||
#define MMU_EN_CACHED (1 << 0)
|
||||
#define MMU_EN_EXEC (1 << 1)
|
||||
#define MMU_EN_READ (1 << 2)
|
||||
#define MMU_EN_WRITE (1 << 3)
|
||||
|
||||
bpmp_mmu_entry_t mmu_entries[] =
|
||||
{
|
||||
{ DRAM_START, 0xFFFFFFFF, MMU_EN_READ | MMU_EN_WRITE | MMU_EN_EXEC | MMU_EN_CACHED, true },
|
||||
{ IRAM_BASE, 0x4003FFFF, MMU_EN_READ | MMU_EN_WRITE | MMU_EN_EXEC | MMU_EN_CACHED, true }
|
||||
};
|
||||
|
||||
void bpmp_mmu_maintenance(u32 op, bool force)
|
||||
{
|
||||
if (!force && !(BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE_CACHE))
|
||||
return;
|
||||
|
||||
BPMP_CACHE_CTRL(BPMP_CACHE_INT_CLEAR) = INT_MAINT_DONE;
|
||||
|
||||
// This is a blocking operation.
|
||||
BPMP_CACHE_CTRL(BPMP_CACHE_MAINT_REQ) = MAINT_REQ_WAY_BITMAP(0xF) | op;
|
||||
|
||||
while(!(BPMP_CACHE_CTRL(BPMP_CACHE_INT_RAW_EVENT) & INT_MAINT_DONE))
|
||||
;
|
||||
|
||||
BPMP_CACHE_CTRL(BPMP_CACHE_INT_CLEAR) = BPMP_CACHE_CTRL(BPMP_CACHE_INT_RAW_EVENT);
|
||||
}
|
||||
|
||||
void bpmp_mmu_set_entry(int idx, bpmp_mmu_entry_t *entry, bool apply)
|
||||
{
|
||||
if (idx > 31)
|
||||
return;
|
||||
|
||||
volatile bpmp_mmu_entry_t *mmu_entry = (bpmp_mmu_entry_t *)(BPMP_MMU_SHADOW_ENTRY_BASE + sizeof(bpmp_mmu_entry_t) * idx);
|
||||
|
||||
if (entry->enable)
|
||||
{
|
||||
mmu_entry->start_addr = ALIGN(entry->start_addr, BPMP_MMU_CACHE_LINE_SIZE);
|
||||
mmu_entry->end_addr = ALIGN_DOWN(entry->end_addr, BPMP_MMU_CACHE_LINE_SIZE);
|
||||
mmu_entry->attr = entry->attr;
|
||||
|
||||
BPMP_CACHE_CTRL(BPMP_CACHE_MMU_SHADOW_COPY_MASK) |= (1 << idx);
|
||||
|
||||
if (apply)
|
||||
BPMP_CACHE_CTRL(BPMP_CACHE_MMU_CMD) = MMU_CMD_COPY_SHADOW;
|
||||
}
|
||||
}
|
||||
|
||||
void bpmp_mmu_enable()
|
||||
{
|
||||
if (BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE_CACHE)
|
||||
return;
|
||||
|
||||
// Init BPMP MMU.
|
||||
BPMP_CACHE_CTRL(BPMP_CACHE_MMU_CMD) = MMU_CMD_INIT;
|
||||
BPMP_CACHE_CTRL(BPMP_CACHE_MMU_FALLBACK_ENTRY) = MMU_EN_READ | MMU_EN_WRITE | MMU_EN_EXEC; // RWX for non-defined regions.
|
||||
BPMP_CACHE_CTRL(BPMP_CACHE_MMU_CFG) = MMU_CFG_SEQ_EN | MMU_CFG_TLB_EN | MMU_CFG_ABORT_STORE_LAST;
|
||||
|
||||
// Init BPMP MMU entries.
|
||||
BPMP_CACHE_CTRL(BPMP_CACHE_MMU_SHADOW_COPY_MASK) = 0;
|
||||
for (u32 idx = 0; idx < (sizeof(mmu_entries) / sizeof(bpmp_mmu_entry_t)); idx++)
|
||||
bpmp_mmu_set_entry(idx, &mmu_entries[idx], false);
|
||||
|
||||
BPMP_CACHE_CTRL(BPMP_CACHE_MMU_CMD) = MMU_CMD_COPY_SHADOW;
|
||||
|
||||
// Invalidate cache.
|
||||
bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, true);
|
||||
|
||||
// Enable cache.
|
||||
BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) = CFG_ENABLE_CACHE | CFG_FORCE_WRITE_THROUGH |
|
||||
CFG_MMU_TAG_MODE(TAG_MODE_PARALLEL) | CFG_TAG_CHK_ABRT_ON_ERR;
|
||||
|
||||
// HW bug. Invalidate cache again.
|
||||
bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, false);
|
||||
}
|
||||
|
||||
void bpmp_mmu_disable()
|
||||
{
|
||||
if (!(BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE_CACHE))
|
||||
return;
|
||||
|
||||
// Clean and invalidate cache.
|
||||
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false);
|
||||
|
||||
// Disable cache.
|
||||
BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) = 0;
|
||||
}
|
||||
|
||||
// APB clock affects RTC, PWM, MEMFETCH, APE, USB, SOR PWM,
|
||||
// I2C host, DC/DSI/DISP. UART gives extra stress.
|
||||
// 92: 100% success ratio. 93-94: 595-602MHz has 99% success ratio. 95: 608MHz less.
|
||||
const u8 pll_divn[] = {
|
||||
0, // BPMP_CLK_NORMAL: 408MHz 0% - 136MHz APB.
|
||||
85, // BPMP_CLK_HIGH_BOOST: 544MHz 33% - 136MHz APB.
|
||||
90, // BPMP_CLK_SUPER_BOOST: 576MHz 41% - 144MHz APB.
|
||||
92 // BPMP_CLK_HYPER_BOOST: 589MHz 44% - 147MHz APB.
|
||||
// Do not use for public releases!
|
||||
//95 // BPMP_CLK_DEV_BOOST: 608MHz 49% - 152MHz APB.
|
||||
};
|
||||
|
||||
bpmp_freq_t bpmp_clock_set = BPMP_CLK_NORMAL;
|
||||
|
||||
void bpmp_clk_rate_get()
|
||||
{
|
||||
bool clk_src_is_pllp = ((CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) >> 4) & 7) == 3;
|
||||
|
||||
if (clk_src_is_pllp)
|
||||
bpmp_clock_set = BPMP_CLK_NORMAL;
|
||||
else
|
||||
{
|
||||
bpmp_clock_set = BPMP_CLK_HIGH_BOOST;
|
||||
|
||||
u8 pll_divn_curr = (CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) >> 10) & 0xFF;
|
||||
for (u32 i = 1; i < sizeof(pll_divn); i++)
|
||||
{
|
||||
if (pll_divn[i] == pll_divn_curr)
|
||||
{
|
||||
bpmp_clock_set = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bpmp_clk_rate_set(bpmp_freq_t fid)
|
||||
{
|
||||
if (fid > (BPMP_CLK_MAX - 1))
|
||||
fid = BPMP_CLK_MAX - 1;
|
||||
|
||||
if (bpmp_clock_set == fid)
|
||||
return;
|
||||
|
||||
if (fid)
|
||||
{
|
||||
if (bpmp_clock_set)
|
||||
{
|
||||
// Restore to PLLP source during PLLC4 configuration.
|
||||
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003333; // PLLP_OUT.
|
||||
msleep(1); // Wait a bit for clock source change.
|
||||
}
|
||||
|
||||
// Configure and enable PLLC.
|
||||
clock_enable_pllc(pll_divn[fid]);
|
||||
|
||||
// Set SCLK / HCLK / PCLK.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 3; // PCLK = HCLK / (3 + 1). HCLK == SCLK.
|
||||
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003310; // PLLC_OUT1 for active and CLKM for idle.
|
||||
}
|
||||
else
|
||||
{
|
||||
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003330; // PLLP_OUT for active and CLKM for idle.
|
||||
msleep(1); // Wait a bit for clock source change.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 2; // PCLK = HCLK / (2 + 1). HCLK == SCLK.
|
||||
|
||||
// Disable PLLC to save power.
|
||||
clock_disable_pllc();
|
||||
}
|
||||
bpmp_clock_set = fid;
|
||||
}
|
||||
|
||||
// The following functions halt BPMP to reduce power while sleeping.
|
||||
// They are not as accurate as RTC at big values but they guarantee time+ delay.
|
||||
void bpmp_usleep(u32 us)
|
||||
{
|
||||
u32 delay;
|
||||
|
||||
// Each iteration takes 1us.
|
||||
while (us)
|
||||
{
|
||||
delay = (us > HALT_COP_MAX_CNT) ? HALT_COP_MAX_CNT : us;
|
||||
us -= delay;
|
||||
|
||||
FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_COP_WAIT_EVENT | HALT_COP_USEC | delay;
|
||||
}
|
||||
}
|
||||
|
||||
void bpmp_msleep(u32 ms)
|
||||
{
|
||||
u32 delay;
|
||||
|
||||
// Iteration time is variable. ~200 - 1000us.
|
||||
while (ms)
|
||||
{
|
||||
delay = (ms > HALT_COP_MAX_CNT) ? HALT_COP_MAX_CNT : ms;
|
||||
ms -= delay;
|
||||
|
||||
FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_COP_WAIT_EVENT | HALT_COP_MSEC | delay;
|
||||
}
|
||||
}
|
||||
|
||||
void bpmp_halt()
|
||||
{
|
||||
FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_COP_WAIT_EVENT | HALT_COP_JTAG;
|
||||
}
|
||||
68
bootloader/soc/bpmp.h
Normal file
68
bootloader/soc/bpmp.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* BPMP-Lite Cache/MMU and Frequency driver for Tegra X1
|
||||
*
|
||||
* Copyright (c) 2019-2020 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _BPMP_H_
|
||||
#define _BPMP_H_
|
||||
|
||||
#include "../utils/types.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
BPMP_MMU_MAINT_NOP = 0,
|
||||
BPMP_MMU_MAINT_CLEAN_PHY = 1,
|
||||
BPMP_MMU_MAINT_INVALID_PHY = 2,
|
||||
BPMP_MMU_MAINT_CLEAN_INVALID_PHY = 3,
|
||||
BPMP_MMU_MAINT_CLEAN_LINE = 9,
|
||||
BPMP_MMU_MAINT_INVALID_LINE = 10,
|
||||
BPMP_MMU_MAINT_CLEAN_INVALID_LINE = 11,
|
||||
BPMP_MMU_MAINT_CLEAN_WAY = 17,
|
||||
BPMP_MMU_MAINT_INVALID_WAY = 18,
|
||||
BPMP_MMU_MAINT_CLN_INV_WAY = 19
|
||||
} bpmp_maintenance_t;
|
||||
|
||||
typedef struct _bpmp_mmu_entry_t
|
||||
{
|
||||
u32 start_addr;
|
||||
u32 end_addr;
|
||||
u32 attr;
|
||||
u32 enable;
|
||||
} bpmp_mmu_entry_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
BPMP_CLK_NORMAL, // 408MHz 0% - 136MHz APB.
|
||||
BPMP_CLK_HIGH_BOOST, // 544MHz 33% - 136MHz APB.
|
||||
BPMP_CLK_SUPER_BOOST, // 576MHz 41% - 144MHz APB.
|
||||
BPMP_CLK_HYPER_BOOST, // 589MHz 44% - 147MHz APB.
|
||||
//BPMP_CLK_DEV_BOOST, // 608MHz 49% - 152MHz APB.
|
||||
BPMP_CLK_MAX
|
||||
} bpmp_freq_t;
|
||||
|
||||
#define BPMP_CLK_DEFAULT_BOOST BPMP_CLK_HYPER_BOOST
|
||||
|
||||
void bpmp_mmu_maintenance(u32 op, bool force);
|
||||
void bpmp_mmu_set_entry(int idx, bpmp_mmu_entry_t *entry, bool apply);
|
||||
void bpmp_mmu_enable();
|
||||
void bpmp_mmu_disable();
|
||||
void bpmp_clk_rate_get();
|
||||
void bpmp_clk_rate_set(bpmp_freq_t fid);
|
||||
void bpmp_usleep(u32 us);
|
||||
void bpmp_msleep(u32 ms);
|
||||
void bpmp_halt();
|
||||
|
||||
#endif
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2020 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -19,37 +20,78 @@
|
||||
#include "../utils/util.h"
|
||||
#include "../storage/sdmmc.h"
|
||||
|
||||
/*
|
||||
* CLOCK Peripherals:
|
||||
* L 0 - 31
|
||||
* H 32 - 63
|
||||
* U 64 - 95
|
||||
* V 96 - 127
|
||||
* W 128 - 159
|
||||
* X 160 - 191
|
||||
* Y 192 - 223
|
||||
*/
|
||||
|
||||
/* clock_t: reset, enable, source, index, clk_src, clk_div */
|
||||
|
||||
static const clock_t _clock_uart[] = {
|
||||
/* UART A */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTA, 6, 0, 0 },
|
||||
/* UART B */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTB, 7, 0, 0 },
|
||||
/* UART C */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_UARTC, 0x17, 0, 0 },
|
||||
/* UART D */ { 0 },
|
||||
/* UART E */ { 0 }
|
||||
/* UART A */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTA, 6, 0, 2 },
|
||||
/* UART B */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTB, 7, 0, 2 },
|
||||
/* UART C */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_UARTC, 23, 0, 2 },
|
||||
/* UART D */ { CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_UARTD, 1, 0, 2 },
|
||||
/* UART E */ { CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_RST_CONTROLLER_CLK_SOURCE_UARTAPE, 20, 0, 2 }
|
||||
};
|
||||
|
||||
//I2C default parameters - TLOW: 4, THIGH: 2, DEBOUNCE: 0, FM_DIV: 26.
|
||||
static const clock_t _clock_i2c[] = {
|
||||
/* I2C1 */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_I2C1, 0xC, 6, 0 },
|
||||
/* I2C2 */ { 0 },
|
||||
/* I2C3 */ { 0 },
|
||||
/* I2C4 */ { 0 },
|
||||
/* I2C5 */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_I2C5, 0xF, 6, 0 },
|
||||
/* I2C6 */ { 0 }
|
||||
/* I2C1 */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_I2C1, 12, 0, 19 }, //20.4MHz -> 100KHz
|
||||
/* I2C2 */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_I2C2, 22, 0, 4 }, //81.6MHz -> 400KHz
|
||||
/* I2C3 */ { CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_I2C3, 3, 0, 4 }, //81.6MHz -> 400KHz
|
||||
/* I2C4 */ { CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_I2C4, 7, 0, 19 }, //20.4MHz -> 100KHz
|
||||
/* I2C5 */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_I2C5, 15, 0, 4 }, //81.6MHz -> 400KHz
|
||||
/* I2C6 */ { CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_CLK_SOURCE_I2C6, 6, 0, 19 } //20.4MHz -> 100KHz
|
||||
};
|
||||
|
||||
static clock_t _clock_se = { CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_SE, 0x1F, 0, 0 };
|
||||
static clock_t _clock_unk2 = { CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_RST_SOURCE, 0x1E, 0, 0 };
|
||||
static clock_t _clock_se = {
|
||||
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_host1x = { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X, 0x1C, 4, 3 };
|
||||
static clock_t _clock_tsec = { CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_TSEC, 0x13, 0, 2 };
|
||||
static clock_t _clock_sor_safe = { CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_RST_CONTROLLER_RST_SOURCE, 0x1E, 0, 0 };
|
||||
static clock_t _clock_sor0 = { CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_RST_SOURCE, 0x16, 0, 0 };
|
||||
static clock_t _clock_sor1 = { CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_CLK_SOURCE_SOR1, 0x17, 0, 2 };
|
||||
static clock_t _clock_kfuse = { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_RST_SOURCE, 8, 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_cl_dvfs = { CLK_RST_CONTROLLER_RST_DEVICES_W, CLK_RST_CONTROLLER_CLK_OUT_ENB_W, CLK_RST_CONTROLLER_RST_SOURCE, 0x1B, 0, 0 };
|
||||
static clock_t _clock_coresight = { CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_CSITE, 9, 0, 4};
|
||||
static clock_t _clock_host1x = {
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X, 28, 4, 3
|
||||
};
|
||||
static clock_t _clock_tsec = {
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_TSEC, 19, 0, 2
|
||||
};
|
||||
static clock_t _clock_sor_safe = {
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_NO_SOURCE, 30, 0, 0
|
||||
};
|
||||
static clock_t _clock_sor0 = {
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_NO_SOURCE, 22, 0, 0
|
||||
};
|
||||
static clock_t _clock_sor1 = {
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_CLK_SOURCE_SOR1, 23, 0, 2
|
||||
};
|
||||
static clock_t _clock_kfuse = {
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_NO_SOURCE, 8, 0, 0
|
||||
};
|
||||
|
||||
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};
|
||||
static clock_t _clock_cl_dvfs = {
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_W, CLK_RST_CONTROLLER_CLK_OUT_ENB_W, CLK_NO_SOURCE, 27, 0, 0
|
||||
};
|
||||
static clock_t _clock_coresight = {
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_CSITE, 9, 0, 4
|
||||
};
|
||||
|
||||
static clock_t _clock_pwm = {
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_PWM, 17, 6, 4 // Fref: 6.2MHz.
|
||||
};
|
||||
|
||||
static clock_t _clock_sdmmc_legacy_tm = {
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC_LEGACY_TM, 1, 4, 66
|
||||
};
|
||||
|
||||
void clock_enable(const clock_t *clk)
|
||||
{
|
||||
@@ -62,6 +104,8 @@ void clock_enable(const clock_t *clk)
|
||||
CLOCK(clk->source) = clk->clk_div | (clk->clk_src << 29);
|
||||
// Enable.
|
||||
CLOCK(clk->enable) = (CLOCK(clk->enable) & ~(1 << clk->index)) | (1 << clk->index);
|
||||
usleep(2);
|
||||
|
||||
// Take clock off reset.
|
||||
CLOCK(clk->reset) &= ~(1 << clk->index);
|
||||
}
|
||||
@@ -84,6 +128,29 @@ void clock_enable_uart(u32 idx)
|
||||
clock_enable(&_clock_uart[idx]);
|
||||
}
|
||||
|
||||
void clock_disable_uart(u32 idx)
|
||||
{
|
||||
clock_disable(&_clock_uart[idx]);
|
||||
}
|
||||
|
||||
#define UART_SRC_CLK_DIV_EN (1 << 24)
|
||||
|
||||
int clock_uart_use_src_div(u32 idx, u32 baud)
|
||||
{
|
||||
u32 clk_src_div = CLOCK(_clock_uart[idx].source) & 0xE0000000;
|
||||
|
||||
if (baud == 1000000)
|
||||
CLOCK(_clock_uart[idx].source) = clk_src_div | UART_SRC_CLK_DIV_EN | 49;
|
||||
else
|
||||
{
|
||||
CLOCK(_clock_uart[idx].source) = clk_src_div | 2;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void clock_enable_i2c(u32 idx)
|
||||
{
|
||||
clock_enable(&_clock_i2c[idx]);
|
||||
@@ -99,9 +166,9 @@ void clock_enable_se()
|
||||
clock_enable(&_clock_se);
|
||||
}
|
||||
|
||||
void clock_enable_unk2()
|
||||
void clock_enable_tzram()
|
||||
{
|
||||
clock_enable(&_clock_unk2);
|
||||
clock_enable(&_clock_tzram);
|
||||
}
|
||||
|
||||
void clock_enable_host1x()
|
||||
@@ -157,11 +224,11 @@ void clock_disable_sor1()
|
||||
void clock_enable_kfuse()
|
||||
{
|
||||
//clock_enable(&_clock_kfuse);
|
||||
CLOCK(0x8) = (CLOCK(0x8) & 0xFFFFFEFF) | 0x100;
|
||||
CLOCK(0x14) &= 0xFFFFFEFF;
|
||||
CLOCK(0x14) = (CLOCK(0x14) & 0xFFFFFEFF) | 0x100;
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_H) = (CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_H) & 0xFFFFFEFF) | 0x100;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) &= 0xFFFFFEFF;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) = (CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) & 0xFFFFFEFF) | 0x100;
|
||||
usleep(10);
|
||||
CLOCK(0x8) &= 0xFFFFFEFF;
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_H) &= 0xFFFFFEFF;
|
||||
usleep(20);
|
||||
}
|
||||
|
||||
@@ -200,6 +267,51 @@ void clock_disable_pwm()
|
||||
clock_disable(&_clock_pwm);
|
||||
}
|
||||
|
||||
void clock_enable_pllc(u32 divn)
|
||||
{
|
||||
u8 pll_divn_curr = (CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) >> 10) & 0xFF;
|
||||
|
||||
// Check if already enabled and configured.
|
||||
if ((CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) & PLLCX_BASE_ENABLE) && (pll_divn_curr == divn))
|
||||
return;
|
||||
|
||||
// Take PLLC out of reset and set basic misc parameters.
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLC_MISC) =
|
||||
((CLOCK(CLK_RST_CONTROLLER_PLLC_MISC) & 0xFFF0000F) & ~PLLC_MISC_RESET) | (0x80000 << 4); // PLLC_EXT_FRU.
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLC_MISC_2) |= 0xF0 << 8; // PLLC_FLL_LD_MEM.
|
||||
|
||||
// Disable PLL and IDDQ in case they are on.
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) &= ~PLLCX_BASE_ENABLE;
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLC_MISC_1) &= ~PLLC_MISC1_IDDQ;
|
||||
usleep(10);
|
||||
|
||||
// Set PLLC dividers.
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) = (divn << 10) | 4; // DIVM: 4, DIVP: 1.
|
||||
|
||||
// Enable PLLC and wait for Phase and Frequency lock.
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) |= PLLCX_BASE_ENABLE;
|
||||
while (!(CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) & PLLCX_BASE_LOCK))
|
||||
;
|
||||
|
||||
// Disable PLLC_OUT1, enable reset and set div to 1.5.
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLC_OUT) = (1 << 8);
|
||||
|
||||
// Enable PLLC_OUT1 and bring it out of reset.
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLC_OUT) |= (PLLC_OUT1_CLKEN | PLLC_OUT1_RSTN_CLR);
|
||||
msleep(1); // Wait a bit for PLL to stabilize.
|
||||
}
|
||||
|
||||
void clock_disable_pllc()
|
||||
{
|
||||
// Disable PLLC and PLLC_OUT1.
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLC_OUT) &= ~(PLLC_OUT1_CLKEN | PLLC_OUT1_RSTN_CLR);
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) &= ~PLLCX_BASE_ENABLE;
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) |= PLLCX_BASE_REF_DIS;
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLC_MISC_1) |= PLLC_MISC1_IDDQ;
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLC_MISC) |= PLLC_MISC_RESET;
|
||||
usleep(10);
|
||||
}
|
||||
|
||||
#define L_SWR_SDMMC1_RST (1 << 14)
|
||||
#define L_SWR_SDMMC2_RST (1 << 9)
|
||||
#define L_SWR_SDMMC4_RST (1 << 15)
|
||||
@@ -252,12 +364,16 @@ static void _clock_sdmmc_set_reset(u32 id)
|
||||
{
|
||||
case SDMMC_1:
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = L_SET_SDMMC1_RST;
|
||||
break;
|
||||
case SDMMC_2:
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = L_SET_SDMMC2_RST;
|
||||
break;
|
||||
case SDMMC_3:
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_U_SET) = U_SET_SDMMC3_RST;
|
||||
break;
|
||||
case SDMMC_4:
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = L_SET_SDMMC4_RST;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,12 +383,16 @@ static void _clock_sdmmc_clear_reset(u32 id)
|
||||
{
|
||||
case SDMMC_1:
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = L_CLR_SDMMC1_RST;
|
||||
break;
|
||||
case SDMMC_2:
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = L_CLR_SDMMC2_RST;
|
||||
break;
|
||||
case SDMMC_3:
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_U_CLR) = U_CLR_SDMMC3_RST;
|
||||
break;
|
||||
case SDMMC_4:
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = L_CLR_SDMMC4_RST;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -298,12 +418,16 @@ static void _clock_sdmmc_set_enable(u32 id)
|
||||
{
|
||||
case SDMMC_1:
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = L_SET_CLK_ENB_SDMMC1;
|
||||
break;
|
||||
case SDMMC_2:
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = L_SET_CLK_ENB_SDMMC2;
|
||||
break;
|
||||
case SDMMC_3:
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_U_SET) = U_SET_CLK_ENB_SDMMC3;
|
||||
break;
|
||||
case SDMMC_4:
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = L_SET_CLK_ENB_SDMMC4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -313,143 +437,181 @@ static void _clock_sdmmc_clear_enable(u32 id)
|
||||
{
|
||||
case SDMMC_1:
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = L_CLR_CLK_ENB_SDMMC1;
|
||||
break;
|
||||
case SDMMC_2:
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = L_CLR_CLK_ENB_SDMMC2;
|
||||
break;
|
||||
case SDMMC_3:
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_U_CLR) = U_CLR_CLK_ENB_SDMMC3;
|
||||
break;
|
||||
case SDMMC_4:
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = L_CLR_CLK_ENB_SDMMC4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static u32 _clock_sdmmc_table[8] = { 0 };
|
||||
static void _clock_sdmmc_config_legacy_tm()
|
||||
{
|
||||
clock_t *clk = &_clock_sdmmc_legacy_tm;
|
||||
if (!(CLOCK(clk->enable) & (1 << clk->index)))
|
||||
clock_enable(clk);
|
||||
}
|
||||
|
||||
static int _clock_sdmmc_config_clock_source_inner(u32 *pout, u32 id, u32 val)
|
||||
typedef struct _clock_sdmmc_t
|
||||
{
|
||||
u32 clock;
|
||||
u32 real_clock;
|
||||
} clock_sdmmc_t;
|
||||
|
||||
static clock_sdmmc_t _clock_sdmmc_table[4] = { 0 };
|
||||
|
||||
#define SDMMC_CLOCK_SRC_PLLP_OUT0 0x0
|
||||
#define SDMMC_CLOCK_SRC_PLLC4_OUT2 0x3
|
||||
#define SDMMC4_CLOCK_SRC_PLLC4_OUT2_LJ 0x1
|
||||
|
||||
static int _clock_sdmmc_config_clock_host(u32 *pclock, u32 id, u32 val)
|
||||
{
|
||||
u32 divisor = 0;
|
||||
u32 source = 0;
|
||||
u32 source = SDMMC_CLOCK_SRC_PLLP_OUT0;
|
||||
|
||||
if (id > SDMMC_4)
|
||||
return 0;
|
||||
|
||||
// Get IO clock divisor.
|
||||
switch (val)
|
||||
{
|
||||
case 25000:
|
||||
*pout = 24728;
|
||||
divisor = 31;
|
||||
*pclock = 24728;
|
||||
divisor = 31; // 16.5 div.
|
||||
break;
|
||||
case 26000:
|
||||
*pout = 25500;
|
||||
divisor = 30;
|
||||
*pclock = 25500;
|
||||
divisor = 30; // 16 div.
|
||||
break;
|
||||
case 40800:
|
||||
*pout = 40800;
|
||||
divisor = 18;
|
||||
*pclock = 40800;
|
||||
divisor = 18; // 10 div.
|
||||
break;
|
||||
case 50000:
|
||||
*pout = 48000;
|
||||
divisor = 15;
|
||||
*pclock = 48000;
|
||||
divisor = 15; // 8.5 div.
|
||||
break;
|
||||
case 52000:
|
||||
*pout = 51000;
|
||||
divisor = 14;
|
||||
*pclock = 51000;
|
||||
divisor = 14; // 8 div.
|
||||
break;
|
||||
case 100000:
|
||||
*pout = 90667;
|
||||
divisor = 7;
|
||||
*pclock = 90667;
|
||||
divisor = 7; // 4.5 div.
|
||||
break;
|
||||
case 164000:
|
||||
*pclock = 163200;
|
||||
divisor = 3; // 2.5 div.
|
||||
break;
|
||||
case 200000:
|
||||
*pout = 163200;
|
||||
divisor = 3;
|
||||
break;
|
||||
case 208000:
|
||||
*pout = 204000;
|
||||
divisor = 2;
|
||||
*pclock = 204000;
|
||||
divisor = 2; // 2 div.
|
||||
break;
|
||||
default:
|
||||
*pout = 24728;
|
||||
divisor = 31;
|
||||
*pclock = 24728;
|
||||
divisor = 31; // 16.5 div.
|
||||
}
|
||||
|
||||
_clock_sdmmc_table[2 * id] = val;
|
||||
_clock_sdmmc_table[2 * id + 1] = *pout;
|
||||
_clock_sdmmc_table[id].clock = val;
|
||||
_clock_sdmmc_table[id].real_clock = *pclock;
|
||||
|
||||
// Set SDMMC legacy timeout clock.
|
||||
_clock_sdmmc_config_legacy_tm();
|
||||
|
||||
// Set SDMMC clock.
|
||||
switch (id)
|
||||
{
|
||||
case SDMMC_1:
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC1) = source | divisor;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC1) = (source << 29) | divisor;
|
||||
break;
|
||||
case SDMMC_2:
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC2) = source | divisor;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC2) = (source << 29) | divisor;
|
||||
break;
|
||||
case SDMMC_3:
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC3) = source | divisor;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC3) = (source << 29) | divisor;
|
||||
break;
|
||||
case SDMMC_4:
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC4) = source | divisor;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC4) = (source << 29) | divisor;
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void clock_sdmmc_config_clock_source(u32 *pout, u32 id, u32 val)
|
||||
void clock_sdmmc_config_clock_source(u32 *pclock, u32 id, u32 val)
|
||||
{
|
||||
if (_clock_sdmmc_table[2 * id] == val)
|
||||
if (_clock_sdmmc_table[id].clock == val)
|
||||
{
|
||||
*pout = _clock_sdmmc_table[2 * id + 1];
|
||||
*pclock = _clock_sdmmc_table[id].real_clock;
|
||||
}
|
||||
else
|
||||
{
|
||||
int is_enabled = _clock_sdmmc_is_enabled(id);
|
||||
if (is_enabled)
|
||||
_clock_sdmmc_clear_enable(id);
|
||||
_clock_sdmmc_config_clock_source_inner(pout, id, val);
|
||||
_clock_sdmmc_config_clock_host(pclock, id, val);
|
||||
if (is_enabled)
|
||||
_clock_sdmmc_set_enable(id);
|
||||
_clock_sdmmc_is_reset(id);
|
||||
}
|
||||
}
|
||||
|
||||
void clock_sdmmc_get_params(u32 *pout, u16 *pdivisor, u32 type)
|
||||
void clock_sdmmc_get_card_clock_div(u32 *pclock, u16 *pdivisor, u32 type)
|
||||
{
|
||||
// Get Card clock divisor.
|
||||
switch (type)
|
||||
{
|
||||
case 0:
|
||||
*pout = 26000;
|
||||
case SDHCI_TIMING_MMC_ID: // Actual IO Freq: 380.59 KHz.
|
||||
*pclock = 26000;
|
||||
*pdivisor = 66;
|
||||
break;
|
||||
case 1:
|
||||
*pout = 26000;
|
||||
case SDHCI_TIMING_MMC_LS26:
|
||||
*pclock = 26000;
|
||||
*pdivisor = 1;
|
||||
break;
|
||||
case 2:
|
||||
*pout = 52000;
|
||||
case SDHCI_TIMING_MMC_HS52:
|
||||
*pclock = 52000;
|
||||
*pdivisor = 1;
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
case 11:
|
||||
*pout = 200000;
|
||||
case SDHCI_TIMING_MMC_HS200:
|
||||
case SDHCI_TIMING_MMC_HS400:
|
||||
case SDHCI_TIMING_UHS_SDR104:
|
||||
*pclock = 200000;
|
||||
*pdivisor = 1;
|
||||
break;
|
||||
case 5:
|
||||
*pout = 25000;
|
||||
case SDHCI_TIMING_SD_ID: // Actual IO Freq: 380.43 KHz.
|
||||
*pclock = 25000;
|
||||
*pdivisor = 64;
|
||||
case 6:
|
||||
case 8:
|
||||
*pout = 25000;
|
||||
break;
|
||||
case SDHCI_TIMING_SD_DS12:
|
||||
case SDHCI_TIMING_UHS_SDR12:
|
||||
*pclock = 25000;
|
||||
*pdivisor = 1;
|
||||
break;
|
||||
case 7:
|
||||
*pout = 50000;
|
||||
*pdivisor = 1;
|
||||
case 10:
|
||||
*pout = 100000;
|
||||
*pdivisor = 1;
|
||||
case 13:
|
||||
*pout = 40800;
|
||||
case SDHCI_TIMING_SD_HS25:
|
||||
case SDHCI_TIMING_UHS_SDR25:
|
||||
*pclock = 50000;
|
||||
*pdivisor = 1;
|
||||
break;
|
||||
case 14:
|
||||
*pout = 200000;
|
||||
case SDHCI_TIMING_UHS_SDR50:
|
||||
*pclock = 100000;
|
||||
*pdivisor = 1;
|
||||
break;
|
||||
case SDHCI_TIMING_UHS_SDR82:
|
||||
*pclock = 164000;
|
||||
*pdivisor = 1;
|
||||
break;
|
||||
case SDHCI_TIMING_UHS_DDR50:
|
||||
*pclock = 40800;
|
||||
*pdivisor = 1;
|
||||
break;
|
||||
case SDHCI_TIMING_MMC_DDR52: // Actual IO Freq: 49.92 MHz.
|
||||
*pclock = 200000;
|
||||
*pdivisor = 2;
|
||||
break;
|
||||
}
|
||||
@@ -462,15 +624,15 @@ int clock_sdmmc_is_not_reset_and_enabled(u32 id)
|
||||
|
||||
void clock_sdmmc_enable(u32 id, u32 val)
|
||||
{
|
||||
u32 div = 0;
|
||||
u32 clock = 0;
|
||||
|
||||
if (_clock_sdmmc_is_enabled(id))
|
||||
_clock_sdmmc_clear_enable(id);
|
||||
_clock_sdmmc_set_reset(id);
|
||||
_clock_sdmmc_config_clock_source_inner(&div, id, val);
|
||||
_clock_sdmmc_config_clock_host(&clock, id, val);
|
||||
_clock_sdmmc_set_enable(id);
|
||||
_clock_sdmmc_is_reset(id);
|
||||
usleep((100000 + div - 1) / div);
|
||||
usleep((100000 + clock - 1) / clock);
|
||||
_clock_sdmmc_clear_reset(id);
|
||||
_clock_sdmmc_is_reset(id);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2020 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -35,21 +36,33 @@
|
||||
#define CLK_RST_CONTROLLER_MISC_CLK_ENB 0x48
|
||||
#define CLK_RST_CONTROLLER_OSC_CTRL 0x50
|
||||
#define CLK_RST_CONTROLLER_PLLC_BASE 0x80
|
||||
#define CLK_RST_CONTROLLER_PLLC_OUT 0x84
|
||||
#define CLK_RST_CONTROLLER_PLLC_MISC 0x88
|
||||
#define CLK_RST_CONTROLLER_PLLC_MISC_1 0x8C
|
||||
#define CLK_RST_CONTROLLER_PLLM_BASE 0x90
|
||||
#define CLK_RST_CONTROLLER_PLLM_MISC1 0x98
|
||||
#define CLK_RST_CONTROLLER_PLLM_MISC2 0x9C
|
||||
#define CLK_RST_CONTROLLER_PLLP_BASE 0xA0
|
||||
#define CLK_RST_CONTROLLER_PLLA_BASE 0xB0
|
||||
#define CLK_RST_CONTROLLER_PLLA_OUT 0xB4
|
||||
#define CLK_RST_CONTROLLER_PLLA_MISC1 0xB8
|
||||
#define CLK_RST_CONTROLLER_PLLA_MISC 0xBC
|
||||
#define CLK_RST_CONTROLLER_PLLU_BASE 0xC0
|
||||
#define CLK_RST_CONTROLLER_PLLU_MISC 0xCC
|
||||
#define CLK_RST_CONTROLLER_PLLD_BASE 0xD0
|
||||
#define CLK_RST_CONTROLLER_PLLD_MISC1 0xD8
|
||||
#define CLK_RST_CONTROLLER_PLLD_MISC 0xDC
|
||||
#define CLK_RST_CONTROLLER_PLLX_BASE 0xE0
|
||||
#define CLK_RST_CONTROLLER_PLLX_MISC 0xE4
|
||||
#define CLK_RST_CONTROLLER_PLLE_BASE 0xE8
|
||||
#define CLK_RST_CONTROLLER_PLLE_MISC 0xEC
|
||||
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRA 0xF8
|
||||
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRB 0xFC
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2S2 0x100
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_PWM 0x110
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C1 0x124
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C5 0x128
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_DISP1 0x138
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_VI 0x148
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC1 0x150
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC2 0x154
|
||||
@@ -57,11 +70,14 @@
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTA 0x178
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTB 0x17C
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X 0x180
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C2 0x198
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC 0x19C
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTC 0x1A0
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C3 0x1B8
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC3 0x1BC
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTD 0x1C0
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_CSITE 0x1D4
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC 0x19C
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2S1 0x1D8
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_TSEC 0x1F4
|
||||
#define CLK_RST_CONTROLLER_CLK_OUT_ENB_X 0x280
|
||||
#define CLK_RST_CONTROLLER_CLK_ENB_X_SET 0x284
|
||||
@@ -95,26 +111,65 @@
|
||||
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRC 0x3A0
|
||||
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD 0x3A4
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT 0x3B4
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C4 0x3C4
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_EXTPERIPH1 0x3EC
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_SYS 0x400
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_SOR1 0x410
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_SE 0x42C
|
||||
#define CLK_RST_CONTROLLER_RST_DEV_V_SET 0x430
|
||||
#define CLK_RST_CONTROLLER_RST_DEV_V_CLR 0x434
|
||||
#define CLK_RST_CONTROLLER_RST_DEV_W_SET 0x438
|
||||
#define CLK_RST_CONTROLLER_RST_DEV_W_CLR 0x43C
|
||||
#define CLK_RST_CONTROLLER_CLK_ENB_V_SET 0x440
|
||||
#define CLK_RST_CONTROLLER_CLK_ENB_V_CLR 0x444
|
||||
#define CLK_RST_CONTROLLER_CLK_ENB_W_SET 0x448
|
||||
#define CLK_RST_CONTROLLER_CLK_ENB_W_CLR 0x44C
|
||||
#define CLK_RST_CONTROLLER_RST_CPUG_CMPLX_SET 0x450
|
||||
#define CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR 0x454
|
||||
#define CLK_RST_CONTROLLER_UTMIP_PLL_CFG0 0x480
|
||||
#define CLK_RST_CONTROLLER_UTMIP_PLL_CFG1 0x484
|
||||
#define CLK_RST_CONTROLLER_UTMIP_PLL_CFG2 0x488
|
||||
#define CLK_RST_CONTROLLER_PLLE_AUX 0x48C
|
||||
#define CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_I2S0 0x4A0
|
||||
#define CLK_RST_CONTROLLER_PLLX_MISC_3 0x518
|
||||
#define CLK_RST_CONTROLLER_UTMIPLL_HW_PWRDN_CFG0 0x52C
|
||||
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRE 0x554
|
||||
#define CLK_RST_CONTROLLER_SPARE_REG0 0x55C
|
||||
#define CLK_RST_CONTROLLER_PLLC4_BASE 0x5A4
|
||||
#define CLK_RST_CONTROLLER_PLLC4_MISC 0x5A8
|
||||
#define CLK_RST_CONTROLLER_PLLC_MISC_2 0x5D0
|
||||
#define CLK_RST_CONTROLLER_PLLC4_OUT 0x5E4
|
||||
#define CLK_RST_CONTROLLER_PLLMB_BASE 0x5E8
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP 0x620
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C6 0x65C
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL 0x664
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIP_CAL 0x66C
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIPI_CAL 0x66C
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC_LEGACY_TM 0x694
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_NVENC 0x6A0
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_USB2_HSIC_TRK 0x6CC
|
||||
#define CLK_RST_CONTROLLER_SE_SUPER_CLK_DIVIDER 0x704
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTAPE 0x710
|
||||
|
||||
#define CLK_NO_SOURCE 0x0
|
||||
|
||||
/*! PLL control and status bits */
|
||||
#define PLLCX_BASE_ENABLE (1 << 30)
|
||||
#define PLLCX_BASE_REF_DIS (1 << 29)
|
||||
#define PLLCX_BASE_LOCK (1 << 27)
|
||||
|
||||
#define PLLA_BASE_IDDQ (1 << 25)
|
||||
#define PLLA_OUT0_CLKEN (1 << 1)
|
||||
#define PLLA_OUT0_RSTN_CLR (1 << 0)
|
||||
|
||||
#define PLLC_MISC_RESET (1 << 30)
|
||||
#define PLLC_MISC1_IDDQ (1 << 27)
|
||||
#define PLLC_OUT1_CLKEN (1 << 1)
|
||||
#define PLLC_OUT1_RSTN_CLR (1 << 0)
|
||||
|
||||
#define PLLC4_MISC_EN_LCKDET (1 << 30)
|
||||
#define PLLC4_BASE_IDDQ (1 << 18)
|
||||
#define PLLC4_OUT3_CLKEN (1 << 1)
|
||||
#define PLLC4_OUT3_RSTN_CLR (1 << 0)
|
||||
|
||||
/*! Generic clock descriptor. */
|
||||
typedef struct _clock_t
|
||||
@@ -134,10 +189,12 @@ void clock_disable(const clock_t *clk);
|
||||
/*! Clock control for specific hardware portions. */
|
||||
void clock_enable_fuse(bool enable);
|
||||
void clock_enable_uart(u32 idx);
|
||||
void clock_disable_uart(u32 idx);
|
||||
int clock_uart_use_src_div(u32 idx, u32 baud);
|
||||
void clock_enable_i2c(u32 idx);
|
||||
void clock_disable_i2c(u32 idx);
|
||||
void clock_enable_se();
|
||||
void clock_enable_unk2();
|
||||
void clock_enable_tzram();
|
||||
void clock_enable_host1x();
|
||||
void clock_disable_host1x();
|
||||
void clock_enable_tsec();
|
||||
@@ -156,9 +213,11 @@ void clock_enable_coresight();
|
||||
void clock_disable_coresight();
|
||||
void clock_enable_pwm();
|
||||
void clock_disable_pwm();
|
||||
void clock_sdmmc_config_clock_source(u32 *pout, u32 id, u32 val);
|
||||
void clock_sdmmc_get_params(u32 *pout, u16 *pdivisor, u32 type);
|
||||
int clock_sdmmc_is_not_reset_and_enabled(u32 id);
|
||||
void clock_enable_pllc(u32 divn);
|
||||
void clock_disable_pllc();
|
||||
void clock_sdmmc_config_clock_source(u32 *pclock, u32 id, u32 val);
|
||||
void clock_sdmmc_get_card_clock_div(u32 *pclock, u16 *pdivisor, u32 type);
|
||||
int clock_sdmmc_is_not_reset_and_enabled(u32 id);
|
||||
void clock_sdmmc_enable(u32 id, u32 val);
|
||||
void clock_sdmmc_disable(u32 id);
|
||||
|
||||
|
||||
@@ -25,23 +25,28 @@
|
||||
|
||||
void _cluster_enable_power()
|
||||
{
|
||||
u8 tmp = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_AME_GPIO);
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_AME_GPIO, tmp & 0xDF);
|
||||
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 & ~(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);
|
||||
|
||||
// Enable cores power.
|
||||
// 1-3.x: MAX77621_NFSR_ENABLE.
|
||||
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL1_REG,
|
||||
MAX77621_AD_ENABLE | MAX77621_NFSR_ENABLE | MAX77621_SNS_ENABLE); // 1-3.x: MAX77621_NFSR_ENABLE
|
||||
MAX77621_AD_ENABLE | MAX77621_NFSR_ENABLE | MAX77621_SNS_ENABLE | MAX77621_RAMP_12mV_PER_US);
|
||||
// 1.0.0-3.x: MAX77621_T_JUNCTION_120 | MAX77621_CKKADV_TRIP_DISABLE | MAX77621_INDUCTOR_NOMINAL.
|
||||
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL2_REG,
|
||||
MAX77621_T_JUNCTION_120 | MAX77621_WDTMR_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US| MAX77621_INDUCTOR_NOMINAL); // 1-3.x: MAX77621_T_JUNCTION_120 | MAX77621_CKKADV_TRIP_DISABLE | MAX77621_INDUCTOR_NOMINAL
|
||||
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_REG, MAX77621_VOUT_ENABLE | 0x37);
|
||||
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_DVC_REG, MAX77621_VOUT_ENABLE | 0x37);
|
||||
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 | MAX77621_VOUT_0_95V);
|
||||
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_DVC_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_0_95V);
|
||||
}
|
||||
|
||||
int _cluster_pmc_enable_partition(u32 part, u32 toggle, bool enable)
|
||||
int _cluster_pmc_enable_partition(u32 part, int enable)
|
||||
{
|
||||
// Check if the partition has already been turned on.
|
||||
if (enable && PMC(APBDEV_PMC_PWRGATE_STATUS) & part)
|
||||
u32 part_mask = 1 << part;
|
||||
u32 desired_state = enable << part;
|
||||
|
||||
// Check if the partition has the state we want.
|
||||
if ((PMC(APBDEV_PMC_PWRGATE_STATUS) & part_mask) == desired_state)
|
||||
return 1;
|
||||
|
||||
u32 i = 5001;
|
||||
@@ -53,12 +58,13 @@ int _cluster_pmc_enable_partition(u32 part, u32 toggle, bool enable)
|
||||
return 0;
|
||||
}
|
||||
|
||||
PMC(APBDEV_PMC_PWRGATE_TOGGLE) = toggle | (enable ? 0x100 : 0);
|
||||
// Toggle power gating.
|
||||
PMC(APBDEV_PMC_PWRGATE_TOGGLE) = part | 0x100;
|
||||
|
||||
i = 5001;
|
||||
while (i > 0)
|
||||
{
|
||||
if (PMC(APBDEV_PMC_PWRGATE_STATUS) & part)
|
||||
if ((PMC(APBDEV_PMC_PWRGATE_STATUS) & part_mask) == desired_state)
|
||||
break;
|
||||
usleep(1);
|
||||
i--;
|
||||
@@ -74,9 +80,9 @@ void cluster_boot_cpu0(u32 entry)
|
||||
|
||||
_cluster_enable_power();
|
||||
|
||||
if (!(CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) & 0x40000000))
|
||||
if (!(CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) & 0x40000000)) // PLLX_ENABLE.
|
||||
{
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLX_MISC_3) &= 0xFFFFFFF7;
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLX_MISC_3) &= 0xFFFFFFF7; // Disable IDDQ.
|
||||
usleep(2);
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = 0x80404E02;
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = 0x404E02;
|
||||
@@ -101,30 +107,34 @@ void cluster_boot_cpu0(u32 entry)
|
||||
CLOCK(CLK_RST_CONTROLLER_CPU_SOFTRST_CTRL2) &= 0xFFFFF000;
|
||||
|
||||
// Enable CPU rail.
|
||||
_cluster_pmc_enable_partition(1, 0, true);
|
||||
_cluster_pmc_enable_partition(0, 1);
|
||||
// Enable cluster 0 non-CPU.
|
||||
_cluster_pmc_enable_partition(0x8000, 15, true);
|
||||
_cluster_pmc_enable_partition(15, 1);
|
||||
// Enable CE0.
|
||||
_cluster_pmc_enable_partition(0x4000, 14, true);
|
||||
_cluster_pmc_enable_partition(14, 1);
|
||||
|
||||
// Request and wait for RAM repair.
|
||||
FLOW_CTLR(FLOW_CTLR_RAM_REPAIR) = 1;
|
||||
while (!(FLOW_CTLR(FLOW_CTLR_RAM_REPAIR) & 2))
|
||||
;
|
||||
|
||||
EXCP_VEC(0x100) = 0;
|
||||
EXCP_VEC(EVP_CPU_RESET_VECTOR) = 0;
|
||||
|
||||
// Set reset vector.
|
||||
SB(SB_AA64_RESET_LOW) = entry | 1;
|
||||
SB(SB_AA64_RESET_LOW) = entry | SB_AA64_RST_AARCH64_MODE_EN;
|
||||
SB(SB_AA64_RESET_HIGH) = 0;
|
||||
// Non-secure reset vector write disable.
|
||||
SB(SB_CSR) = 2;
|
||||
SB(SB_CSR) = SB_CSR_NS_RST_VEC_WR_DIS;
|
||||
(void)SB(SB_CSR);
|
||||
|
||||
// Tighten up the security aperture.
|
||||
// MC(MC_TZ_SECURITY_CTRL) = 1;
|
||||
|
||||
// Clear MSELECT reset.
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_V) &= 0xFFFFFFF7;
|
||||
// Clear NONCPU reset.
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR) = 0x20000000;
|
||||
// Clear CPU{0,1,2,3} POR and CORE, CX0, L2, and DBG reset.
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR) = 0x411F000F;
|
||||
// Clear CPU0 reset.
|
||||
// < 5.x: 0x411F000F, Clear CPU{0,1,2,3} POR and CORE, CX0, L2, and DBG reset.
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR) = 0x41010001;
|
||||
}
|
||||
|
||||
@@ -19,19 +19,6 @@
|
||||
|
||||
#include "../utils/types.h"
|
||||
|
||||
/*! Flow controller registers. */
|
||||
#define LOW_CTLR_HALT_CPU0_EVENTS 0x0
|
||||
#define LOW_CTLR_HALT_CPU1_EVENTS 0x14
|
||||
#define LOW_CTLR_HALT_CPU2_EVENTS 0x1C
|
||||
#define LOW_CTLR_HALT_CPU3_EVENTS 0x24
|
||||
#define FLOW_CTLR_HALT_COP_EVENTS 0x4
|
||||
#define FLOW_CTLR_CPU0_CSR 0x8
|
||||
#define FLOW_CTLR_CPU1_CSR 0x18
|
||||
#define FLOW_CTLR_CPU2_CSR 0x20
|
||||
#define FLOW_CTLR_CPU3_CSR 0x28
|
||||
#define FLOW_CTLR_RAM_REPAIR 0x40
|
||||
#define FLOW_CTLR_BPMP_CLUSTER_CONTROL 0x98
|
||||
|
||||
void cluster_boot_cpu0(u32 entry);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018 shuffle2
|
||||
* Copyright (c) 2018 balika011
|
||||
* Copyright (c) 2019 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -61,14 +62,28 @@ u32 fuse_read_odm(u32 idx)
|
||||
|
||||
void fuse_wait_idle()
|
||||
{
|
||||
u32 ctrl;
|
||||
do
|
||||
{
|
||||
ctrl = FUSE(FUSE_CTRL);
|
||||
} while (((ctrl >> 16) & 0x1f) != 4);
|
||||
u32 ctrl;
|
||||
do
|
||||
{
|
||||
ctrl = FUSE(FUSE_CTRL);
|
||||
} while (((ctrl >> 16) & 0x1f) != 4);
|
||||
}
|
||||
|
||||
u32 parity32_even(u32 *words, u32 count)
|
||||
u32 fuse_read(u32 addr)
|
||||
{
|
||||
FUSE(FUSE_ADDR) = addr;
|
||||
FUSE(FUSE_CTRL) = (FUSE(FUSE_ADDR) & ~FUSE_CMD_MASK) | FUSE_READ;
|
||||
fuse_wait_idle();
|
||||
return FUSE(FUSE_RDATA);
|
||||
}
|
||||
|
||||
void fuse_read_array(u32 *words)
|
||||
{
|
||||
for (u32 i = 0; i < 192; i++)
|
||||
words[i] = fuse_read(i);
|
||||
}
|
||||
|
||||
static u32 _parity32_even(u32 *words, u32 count)
|
||||
{
|
||||
u32 acc = words[0];
|
||||
for (u32 i = 1; i < count; i++)
|
||||
@@ -81,14 +96,14 @@ u32 parity32_even(u32 *words, u32 count)
|
||||
lo = ((x & 0xf) ^ (x >> 4)) & 3;
|
||||
hi = ((x & 0xf) ^ (x >> 4)) >> 2;
|
||||
x = hi ^ lo;
|
||||
|
||||
|
||||
return (x & 1) ^ (x >> 1);
|
||||
}
|
||||
|
||||
int patch_hash_one(u32 *word)
|
||||
static int _patch_hash_one(u32 *word)
|
||||
{
|
||||
u32 bits20_31 = *word & 0xfff00000;
|
||||
u32 parity_bit = parity32_even(&bits20_31, 1);
|
||||
u32 parity_bit = _parity32_even(&bits20_31, 1);
|
||||
u32 hash = 0;
|
||||
for (u32 i = 0; i < 12; i++)
|
||||
{
|
||||
@@ -121,9 +136,9 @@ int patch_hash_one(u32 *word)
|
||||
return 2;
|
||||
}
|
||||
|
||||
int patch_hash_multi(u32 *words, u32 count)
|
||||
static int _patch_hash_multi(u32 *words, u32 count)
|
||||
{
|
||||
u32 parity_bit = parity32_even(words, count);
|
||||
u32 parity_bit = _parity32_even(words, count);
|
||||
u32 bits0_14 = words[0] & 0x7fff;
|
||||
u32 bit15 = words[0] & 0x8000;
|
||||
u32 bits16_19 = words[0] & 0xf0000;
|
||||
@@ -193,7 +208,7 @@ int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value))
|
||||
u32 total_read = 0;
|
||||
|
||||
word_count = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE);
|
||||
word_count &= 0x7f;
|
||||
word_count &= 0x7F;
|
||||
word_addr = 191;
|
||||
|
||||
while (word_count)
|
||||
@@ -203,42 +218,37 @@ int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
for (u32 i = 0; i < word_count; i++)
|
||||
{
|
||||
FUSE(FUSE_ADDR) = word_addr--;
|
||||
FUSE(FUSE_CTRL) = (FUSE(FUSE_ADDR) & ~FUSE_CMD_MASK) | FUSE_READ;
|
||||
fuse_wait_idle();
|
||||
words[i] = FUSE(FUSE_RDATA);
|
||||
}
|
||||
|
||||
words[i] = fuse_read(word_addr--);
|
||||
|
||||
word0 = words[0];
|
||||
if (patch_hash_multi(words, word_count) >= 2)
|
||||
if (_patch_hash_multi(words, word_count) >= 2)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
u32 ipatch_count = (words[0] >> 16) & 0xf;
|
||||
u32 ipatch_count = (words[0] >> 16) & 0xF;
|
||||
if (ipatch_count)
|
||||
{
|
||||
for (u32 i = 0; i < ipatch_count; i++)
|
||||
{
|
||||
u32 word = words[i];
|
||||
u32 word = words[i + 1];
|
||||
u32 addr = (word >> 16) * 2;
|
||||
u32 data = word & 0xffff;
|
||||
|
||||
u32 data = word & 0xFFFF;
|
||||
|
||||
ipatch(addr, data);
|
||||
}
|
||||
}
|
||||
words[0] = word0;
|
||||
if ((word0 >> 25) == 0)
|
||||
break;
|
||||
if (patch_hash_one(&word0) >= 2)
|
||||
if (_patch_hash_one(&word0) >= 2)
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
word_count = word0 >> 25;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -255,7 +265,7 @@ int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len)
|
||||
memset(iram_evp_thunks, 0, *iram_evp_thunks_len);
|
||||
|
||||
word_count = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE);
|
||||
word_count &= 0x7f;
|
||||
word_count &= 0x7F;
|
||||
word_addr = 191;
|
||||
|
||||
while (word_count)
|
||||
@@ -265,21 +275,16 @@ int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
for (u32 i = 0; i < word_count; i++)
|
||||
{
|
||||
FUSE(FUSE_ADDR) = word_addr--;
|
||||
FUSE(FUSE_CTRL) = (FUSE(FUSE_ADDR) & ~FUSE_CMD_MASK) | FUSE_READ;
|
||||
fuse_wait_idle();
|
||||
words[i] = FUSE(FUSE_RDATA);
|
||||
}
|
||||
|
||||
words[i] = fuse_read(word_addr--);
|
||||
|
||||
word0 = words[0];
|
||||
if (patch_hash_multi(words, word_count) >= 2)
|
||||
if (_patch_hash_multi(words, word_count) >= 2)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
u32 ipatch_count = (words[0] >> 16) & 0xf;
|
||||
u32 ipatch_count = (words[0] >> 16) & 0xF;
|
||||
u32 insn_count = word_count - ipatch_count - 1;
|
||||
if (insn_count)
|
||||
{
|
||||
@@ -303,23 +308,42 @@ int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len)
|
||||
words[0] = word0;
|
||||
if ((word0 >> 25) == 0)
|
||||
break;
|
||||
if (patch_hash_one(&word0) >= 2)
|
||||
if (_patch_hash_one(&word0) >= 2)
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
word_count = word0 >> 25;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void read_raw_ipatch_fuses(u32 *words)
|
||||
bool fuse_check_patched_rcm()
|
||||
{
|
||||
for (u32 i = 0; i < 0x100; i++)
|
||||
// Check if XUSB in use.
|
||||
if (FUSE(FUSE_RESERVED_SW) & (1<<7))
|
||||
return true;
|
||||
|
||||
// Check if RCM is ipatched.
|
||||
u32 word_count = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE) & 0x7F;
|
||||
u32 word_addr = 191;
|
||||
|
||||
while (word_count)
|
||||
{
|
||||
FUSE(FUSE_ADDR) = i;
|
||||
FUSE(FUSE_CTRL) = (FUSE(FUSE_ADDR) & ~FUSE_CMD_MASK) | FUSE_READ;
|
||||
fuse_wait_idle();
|
||||
words[i] = FUSE(FUSE_RDATA);
|
||||
u32 word0 = fuse_read(word_addr);
|
||||
u32 ipatch_count = (word0 >> 16) & 0xF;
|
||||
|
||||
for (u32 i = 0; i < ipatch_count; i++)
|
||||
{
|
||||
u32 word = fuse_read(word_addr - (i + 1));
|
||||
u32 addr = (word >> 16) * 2;
|
||||
if (addr == 0x769A)
|
||||
return true;
|
||||
}
|
||||
|
||||
word_addr -= word_count;
|
||||
word_count = word0 >> 25;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -36,7 +36,35 @@
|
||||
#define FUSE_DISABLEREGPROGRAM 0x2C
|
||||
#define FUSE_WRITE_ACCESS_SW 0x30
|
||||
#define FUSE_PWR_GOOD_SW 0x34
|
||||
#define FUSE_SKU_INFO 0x110
|
||||
#define FUSE_CPU_SPEEDO_0_CALIB 0x114
|
||||
#define FUSE_CPU_IDDQ_CALIB 0x118
|
||||
#define FUSE_OPT_FT_REV 0x128
|
||||
#define FUSE_CPU_SPEEDO_1_CALIB 0x12C
|
||||
#define FUSE_CPU_SPEEDO_2_CALIB 0x130
|
||||
#define FUSE_SOC_SPEEDO_0_CALIB 0x134
|
||||
#define FUSE_SOC_SPEEDO_1_CALIB 0x138
|
||||
#define FUSE_SOC_SPEEDO_2_CALIB 0x13C
|
||||
#define FUSE_SOC_IDDQ_CALIB 0x140
|
||||
#define FUSE_OPT_CP_REV 0x190
|
||||
#define FUSE_FIRST_BOOTROM_PATCH_SIZE 0x19c
|
||||
#define FUSE_PRIVATE_KEY0 0x1A4
|
||||
#define FUSE_PRIVATE_KEY1 0x1A8
|
||||
#define FUSE_PRIVATE_KEY2 0x1AC
|
||||
#define FUSE_PRIVATE_KEY3 0x1B0
|
||||
#define FUSE_PRIVATE_KEY4 0x1B4
|
||||
#define FUSE_RESERVED_SW 0x1C0
|
||||
#define FUSE_USB_CALIB 0x1F0
|
||||
#define FUSE_SKU_DIRECT_CONFIG 0x1F4
|
||||
#define FUSE_OPT_VENDOR_CODE 0x200
|
||||
#define FUSE_OPT_FAB_CODE 0x204
|
||||
#define FUSE_OPT_LOT_CODE_0 0x208
|
||||
#define FUSE_OPT_LOT_CODE_1 0x20C
|
||||
#define FUSE_OPT_WAFER_ID 0x210
|
||||
#define FUSE_OPT_X_COORDINATE 0x214
|
||||
#define FUSE_OPT_Y_COORDINATE 0x218
|
||||
#define FUSE_GPU_IDDQ_CALIB 0x228
|
||||
#define FUSE_USB_CALIB_EXT 0x350
|
||||
|
||||
/*! Fuse commands. */
|
||||
#define FUSE_READ 0x1
|
||||
@@ -52,6 +80,7 @@ u32 fuse_read_odm(u32 idx);
|
||||
void fuse_wait_idle();
|
||||
int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value));
|
||||
int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len);
|
||||
void read_raw_ipatch_fuses(u32 *words);
|
||||
void fuse_read_array(u32 *words);
|
||||
bool fuse_check_patched_rcm();
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2019 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -14,81 +15,146 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "../soc/gpio.h"
|
||||
#include "../soc/t210.h"
|
||||
#include "gpio.h"
|
||||
#include "irq.h"
|
||||
#include "t210.h"
|
||||
|
||||
static const u16 _gpio_cnf[31] = {
|
||||
0x000, 0x004, 0x008, 0x00C,
|
||||
0x100, 0x104, 0x108, 0x10C,
|
||||
0x200, 0x204, 0x208, 0x20C,
|
||||
0x300, 0x304, 0x308, 0x30C,
|
||||
0x400, 0x404, 0x408, 0x40C,
|
||||
0x500, 0x504, 0x508, 0x50C,
|
||||
0x600, 0x604, 0x608, 0x60C,
|
||||
0x700, 0x704, 0x708
|
||||
};
|
||||
#define GPIO_BANK_IDX(port) (port >> 2)
|
||||
|
||||
static const u16 _gpio_oe[31] = {
|
||||
0x010, 0x014, 0x018, 0x01C,
|
||||
0x110, 0x114, 0x118, 0x11C,
|
||||
0x210, 0x214, 0x218, 0x21C,
|
||||
0x310, 0x314, 0x318, 0x31C,
|
||||
0x410, 0x414, 0x418, 0x41C,
|
||||
0x510, 0x514, 0x518, 0x51C,
|
||||
0x610, 0x614, 0x618, 0x61C,
|
||||
0x710, 0x714, 0x718
|
||||
};
|
||||
#define GPIO_CNF_OFFSET(port) (0x00 + ((port >> 2) << 8) + ((port % 4) << 2))
|
||||
#define GPIO_OE_OFFSET(port) (0x10 + ((port >> 2) << 8) + ((port % 4) << 2))
|
||||
#define GPIO_OUT_OFFSET(port) (0x20 + ((port >> 2) << 8) + ((port % 4) << 2))
|
||||
#define GPIO_IN_OFFSET(port) (0x30 + ((port >> 2) << 8) + ((port % 4) << 2))
|
||||
#define GPIO_INT_STA_OFFSET(port) (0x40 + ((port >> 2) << 8) + ((port % 4) << 2))
|
||||
#define GPIO_INT_ENB_OFFSET(port) (0x50 + ((port >> 2) << 8) + ((port % 4) << 2))
|
||||
#define GPIO_INT_LVL_OFFSET(port) (0x60 + ((port >> 2) << 8) + ((port % 4) << 2))
|
||||
#define GPIO_INT_CLR_OFFSET(port) (0x70 + ((port >> 2) << 8) + ((port % 4) << 2))
|
||||
|
||||
static const u16 _gpio_out[31] = {
|
||||
0x020, 0x024, 0x028, 0x02C,
|
||||
0x120, 0x124, 0x128, 0x12C,
|
||||
0x220, 0x224, 0x228, 0x22C,
|
||||
0x320, 0x324, 0x328, 0x32C,
|
||||
0x420, 0x424, 0x428, 0x42C,
|
||||
0x520, 0x524, 0x528, 0x52C,
|
||||
0x620, 0x624, 0x628, 0x62C,
|
||||
0x720, 0x724, 0x728
|
||||
};
|
||||
#define GPIO_CNF_MASKED_OFFSET(port) (0x80 + ((port >> 2) << 8) + ((port % 4) << 2))
|
||||
#define GPIO_OE_MASKED_OFFSET(port) (0x90 + ((port >> 2) << 8) + ((port % 4) << 2))
|
||||
#define GPIO_OUT_MASKED_OFFSET(port) (0xA0 + ((port >> 2) << 8) + ((port % 4) << 2))
|
||||
#define GPIO_INT_STA_MASKED_OFFSET(port) (0xC0 + ((port >> 2) << 8) + ((port % 4) << 2))
|
||||
#define GPIO_INT_ENB_MASKED_OFFSET(port) (0xD0 + ((port >> 2) << 8) + ((port % 4) << 2))
|
||||
#define GPIO_INT_LVL_MASKED_OFFSET(port) (0xE0 + ((port >> 2) << 8) + ((port % 4) << 2))
|
||||
|
||||
static const u16 _gpio_in[31] = {
|
||||
0x030, 0x034, 0x038, 0x03C,
|
||||
0x130, 0x134, 0x138, 0x13C,
|
||||
0x230, 0x234, 0x238, 0x23C,
|
||||
0x330, 0x334, 0x338, 0x33C,
|
||||
0x430, 0x434, 0x438, 0x43C,
|
||||
0x530, 0x534, 0x538, 0x53C,
|
||||
0x630, 0x634, 0x638, 0x63C,
|
||||
0x730, 0x734, 0x738
|
||||
static u8 gpio_bank_irq_ids[8] = {
|
||||
IRQ_GPIO1, IRQ_GPIO2, IRQ_GPIO3, IRQ_GPIO4,
|
||||
IRQ_GPIO5, IRQ_GPIO6, IRQ_GPIO7, IRQ_GPIO8
|
||||
};
|
||||
|
||||
void gpio_config(u32 port, u32 pins, int mode)
|
||||
{
|
||||
u32 offset = GPIO_CNF_OFFSET(port);
|
||||
|
||||
if (mode)
|
||||
GPIO(_gpio_cnf[port]) |= pins;
|
||||
GPIO(offset) |= pins;
|
||||
else
|
||||
GPIO(_gpio_cnf[port]) &= ~pins;
|
||||
(void)GPIO(_gpio_cnf[port]);
|
||||
GPIO(offset) &= ~pins;
|
||||
|
||||
(void)GPIO(offset); // Commit the write.
|
||||
}
|
||||
|
||||
void gpio_output_enable(u32 port, u32 pins, int enable)
|
||||
{
|
||||
u32 port_offset = GPIO_OE_OFFSET(port);
|
||||
|
||||
if (enable)
|
||||
GPIO(_gpio_oe[port]) |= pins;
|
||||
GPIO(port_offset) |= pins;
|
||||
else
|
||||
GPIO(_gpio_oe[port]) &= ~pins;
|
||||
(void)GPIO(_gpio_oe[port]);
|
||||
GPIO(port_offset) &= ~pins;
|
||||
|
||||
(void)GPIO(port_offset); // Commit the write.
|
||||
}
|
||||
|
||||
void gpio_write(u32 port, u32 pins, int high)
|
||||
{
|
||||
u32 port_offset = GPIO_OUT_OFFSET(port);
|
||||
|
||||
if (high)
|
||||
GPIO(_gpio_out[port]) |= pins;
|
||||
GPIO(port_offset) |= pins;
|
||||
else
|
||||
GPIO(_gpio_out[port]) &= ~pins;
|
||||
(void)GPIO(_gpio_out[port]);
|
||||
GPIO(port_offset) &= ~pins;
|
||||
|
||||
(void)GPIO(port_offset); // Commit the write.
|
||||
}
|
||||
|
||||
int gpio_read(u32 port, u32 pins)
|
||||
{
|
||||
return (GPIO(_gpio_in[port]) & pins) ? 1 : 0;
|
||||
u32 port_offset = GPIO_IN_OFFSET(port);
|
||||
|
||||
return (GPIO(port_offset) & pins) ? 1 : 0;
|
||||
}
|
||||
|
||||
static void _gpio_interrupt_clear(u32 port, u32 pins)
|
||||
{
|
||||
u32 port_offset = GPIO_INT_CLR_OFFSET(port);
|
||||
|
||||
GPIO(port_offset) |= pins;
|
||||
|
||||
(void)GPIO(port_offset); // Commit the write.
|
||||
}
|
||||
|
||||
int gpio_interrupt_status(u32 port, u32 pins)
|
||||
{
|
||||
u32 port_offset = GPIO_INT_STA_OFFSET(port);
|
||||
u32 enabled = GPIO(GPIO_INT_ENB_OFFSET(port)) & pins;
|
||||
|
||||
int status = ((GPIO(port_offset) & pins) && enabled) ? 1 : 0;
|
||||
|
||||
// Clear the interrupt status.
|
||||
if (status)
|
||||
_gpio_interrupt_clear(port, pins);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void gpio_interrupt_enable(u32 port, u32 pins, int enable)
|
||||
{
|
||||
u32 port_offset = GPIO_INT_ENB_OFFSET(port);
|
||||
|
||||
// Clear any possible stray interrupt.
|
||||
_gpio_interrupt_clear(port, pins);
|
||||
|
||||
if (enable)
|
||||
GPIO(port_offset) |= pins;
|
||||
else
|
||||
GPIO(port_offset) &= ~pins;
|
||||
|
||||
(void)GPIO(port_offset); // Commit the write.
|
||||
}
|
||||
|
||||
void gpio_interrupt_level(u32 port, u32 pins, int high, int edge, int delta)
|
||||
{
|
||||
u32 port_offset = GPIO_INT_LVL_OFFSET(port);
|
||||
|
||||
u32 val = GPIO(port_offset);
|
||||
|
||||
if (high)
|
||||
val |= pins;
|
||||
else
|
||||
val &= ~pins;
|
||||
|
||||
if (edge)
|
||||
val |= pins << 8;
|
||||
else
|
||||
val &= ~(pins << 8);
|
||||
|
||||
if (delta)
|
||||
val |= pins << 16;
|
||||
else
|
||||
val &= ~(pins << 16);
|
||||
|
||||
GPIO(port_offset) = val;
|
||||
|
||||
(void)GPIO(port_offset); // Commit the write.
|
||||
|
||||
// Clear any possible stray interrupt.
|
||||
_gpio_interrupt_clear(port, pins);
|
||||
}
|
||||
|
||||
u32 gpio_get_bank_irq_id(u32 port)
|
||||
{
|
||||
u32 bank_idx = GPIO_BANK_IDX(port);
|
||||
|
||||
return gpio_bank_irq_ids[bank_idx];
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2019 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -21,10 +22,23 @@
|
||||
|
||||
#define GPIO_MODE_SPIO 0
|
||||
#define GPIO_MODE_GPIO 1
|
||||
|
||||
#define GPIO_OUTPUT_DISABLE 0
|
||||
#define GPIO_OUTPUT_ENABLE 1
|
||||
|
||||
#define GPIO_IRQ_DISABLE 0
|
||||
#define GPIO_IRQ_ENABLE 1
|
||||
|
||||
#define GPIO_LOW 0
|
||||
#define GPIO_HIGH 1
|
||||
#define GPIO_FALLING 0
|
||||
#define GPIO_RISING 1
|
||||
|
||||
#define GPIO_LEVEL 0
|
||||
#define GPIO_EDGE 1
|
||||
|
||||
#define GPIO_CONFIGURED_EDGE 0
|
||||
#define GPIO_ANY_EDGE_CHANGE 1
|
||||
|
||||
/*! GPIO pins (0-7 for each port). */
|
||||
#define GPIO_PIN_0 (1 << 0)
|
||||
@@ -72,6 +86,10 @@
|
||||
void gpio_config(u32 port, u32 pins, int mode);
|
||||
void gpio_output_enable(u32 port, u32 pins, int enable);
|
||||
void gpio_write(u32 port, u32 pins, int high);
|
||||
int gpio_read(u32 port, u32 pins);
|
||||
int gpio_read(u32 port, u32 pins);
|
||||
int gpio_interrupt_status(u32 port, u32 pins);
|
||||
void gpio_interrupt_enable(u32 port, u32 pins, int enable);
|
||||
void gpio_interrupt_level(u32 port, u32 pins, int high, int edge, int delta);
|
||||
u32 gpio_get_bank_irq_id(u32 port);
|
||||
|
||||
#endif
|
||||
|
||||
365
bootloader/soc/hw_init.c
Normal file
365
bootloader/soc/hw_init.c
Normal file
@@ -0,0 +1,365 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2020 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* 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 "hw_init.h"
|
||||
#include "bpmp.h"
|
||||
#include "clock.h"
|
||||
#include "fuse.h"
|
||||
#include "gpio.h"
|
||||
#include "i2c.h"
|
||||
#include "pinmux.h"
|
||||
#include "pmc.h"
|
||||
#include "t210.h"
|
||||
#include "uart.h"
|
||||
#include "../gfx/di.h"
|
||||
#include "../mem/mc.h"
|
||||
#include "../mem/minerva.h"
|
||||
#include "../mem/sdram.h"
|
||||
#include "../power/max77620.h"
|
||||
#include "../power/max7762x.h"
|
||||
#include "../sec/se.h"
|
||||
#include "../sec/se_t210.h"
|
||||
#include "../storage/nx_sd.h"
|
||||
#include "../storage/sdmmc.h"
|
||||
#include "../utils/util.h"
|
||||
|
||||
extern boot_cfg_t b_cfg;
|
||||
extern volatile nyx_storage_t *nyx_str;
|
||||
|
||||
/*
|
||||
* CLK_OSC - 38.4 MHz crystal.
|
||||
* CLK_M - 19.2 MHz (osc/2).
|
||||
* CLK_S - 32.768 KHz (from PMIC).
|
||||
* SCLK - 204MHz init (-> 408MHz -> OC).
|
||||
* HCLK - 204MHz init (-> 408MHz -> OC).
|
||||
* PCLK - 68MHz init (-> 136MHz -> OC/4).
|
||||
*/
|
||||
|
||||
void _config_oscillators()
|
||||
{
|
||||
CLOCK(CLK_RST_CONTROLLER_SPARE_REG0) = (CLOCK(CLK_RST_CONTROLLER_SPARE_REG0) & 0xFFFFFFF3) | 4; // Set CLK_M_DIVISOR to 2.
|
||||
SYSCTR0(SYSCTR0_CNTFID0) = 19200000; // Set counter frequency.
|
||||
TMR(TIMERUS_USEC_CFG) = 0x45F; // For 19.2MHz clk_m.
|
||||
CLOCK(CLK_RST_CONTROLLER_OSC_CTRL) = 0x50000071; // Set OSC to 38.4MHz and drive strength.
|
||||
|
||||
PMC(APBDEV_PMC_OSC_EDPD_OVER) = (PMC(APBDEV_PMC_OSC_EDPD_OVER) & 0xFFFFFF81) | 0xE; // Set LP0 OSC drive strength.
|
||||
PMC(APBDEV_PMC_OSC_EDPD_OVER) = (PMC(APBDEV_PMC_OSC_EDPD_OVER) & 0xFFBFFFFF) | PMC_OSC_EDPD_OVER_OSC_CTRL_OVER;
|
||||
PMC(APBDEV_PMC_CNTRL2) = (PMC(APBDEV_PMC_CNTRL2) & 0xFFFFEFFF) | PMC_CNTRL2_HOLD_CKE_LOW_EN;
|
||||
PMC(APBDEV_PMC_SCRATCH188) = (PMC(APBDEV_PMC_SCRATCH188) & 0xFCFFFFFF) | (4 << 23); // LP0 EMC2TMC_CFG_XM2COMP_PU_VREF_SEL_RANGE.
|
||||
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 0x10; // Set HCLK div to 2 and PCLK div to 1.
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLMB_BASE) &= 0xBFFFFFFF; // PLLMB disable.
|
||||
|
||||
PMC(APBDEV_PMC_TSC_MULT) = (PMC(APBDEV_PMC_TSC_MULT) & 0xFFFF0000) | 0x249F; //0x249F = 19200000 * (16 / 32.768 kHz)
|
||||
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SYS) = 0; // Set SCLK div to 1.
|
||||
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20004444; // Set clk source to Run and PLLP_OUT2 (204MHz).
|
||||
CLOCK(CLK_RST_CONTROLLER_SUPER_SCLK_DIVIDER) = 0x80000000; // Enable SUPER_SDIV to 1.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 2; // Set HCLK div to 1 and PCLK div to 3.
|
||||
}
|
||||
|
||||
void _config_gpios()
|
||||
{
|
||||
PINMUX_AUX(PINMUX_AUX_UART2_TX) = 0;
|
||||
PINMUX_AUX(PINMUX_AUX_UART3_TX) = 0;
|
||||
|
||||
// Set Joy-Con IsAttached direction.
|
||||
PINMUX_AUX(PINMUX_AUX_GPIO_PE6) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE;
|
||||
PINMUX_AUX(PINMUX_AUX_GPIO_PH6) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE;
|
||||
|
||||
// Set pin mode for Joy-Con IsAttached and UARTB/C TX pins.
|
||||
#if !defined (DEBUG_UART_PORT) || DEBUG_UART_PORT != UART_B
|
||||
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_GPIO);
|
||||
#endif
|
||||
#if !defined (DEBUG_UART_PORT) || DEBUG_UART_PORT != UART_C
|
||||
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_GPIO);
|
||||
#endif
|
||||
// Set Joy-Con IsAttached mode.
|
||||
gpio_config(GPIO_PORT_E, GPIO_PIN_6, GPIO_MODE_GPIO);
|
||||
gpio_config(GPIO_PORT_H, GPIO_PIN_6, GPIO_MODE_GPIO);
|
||||
|
||||
// Enable input logic for Joy-Con IsAttached and UARTB/C TX pins.
|
||||
gpio_output_enable(GPIO_PORT_G, GPIO_PIN_0, GPIO_OUTPUT_DISABLE);
|
||||
gpio_output_enable(GPIO_PORT_D, GPIO_PIN_1, GPIO_OUTPUT_DISABLE);
|
||||
gpio_output_enable(GPIO_PORT_E, GPIO_PIN_6, GPIO_OUTPUT_DISABLE);
|
||||
gpio_output_enable(GPIO_PORT_H, GPIO_PIN_6, GPIO_OUTPUT_DISABLE);
|
||||
|
||||
pinmux_config_i2c(I2C_1);
|
||||
pinmux_config_i2c(I2C_5);
|
||||
pinmux_config_uart(UART_A);
|
||||
|
||||
// Configure volume up/down as inputs.
|
||||
gpio_config(GPIO_PORT_X, GPIO_PIN_6, 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_7, GPIO_OUTPUT_DISABLE);
|
||||
|
||||
// Configure HOME as inputs.
|
||||
// PINMUX_AUX(PINMUX_AUX_BUTTON_HOME) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE;
|
||||
// gpio_config(GPIO_PORT_Y, GPIO_PIN_1, GPIO_MODE_GPIO);
|
||||
}
|
||||
|
||||
void _config_pmc_scratch()
|
||||
{
|
||||
PMC(APBDEV_PMC_SCRATCH20) &= 0xFFF3FFFF; // Unset Debug console from Customer Option.
|
||||
PMC(APBDEV_PMC_SCRATCH190) &= 0xFFFFFFFE; // Unset DATA_DQ_E_IVREF EMC_PMACRO_DATA_PAD_TX_CTRL
|
||||
PMC(APBDEV_PMC_SECURE_SCRATCH21) |= PMC_FUSE_PRIVATEKEYDISABLE_TZ_STICKY_BIT;
|
||||
}
|
||||
|
||||
void _mbist_workaround()
|
||||
{
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) |= (1 << 10); // Enable AHUB clock.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) |= (1 << 6); // Enable APE clock.
|
||||
|
||||
// Set mux output to SOR1 clock switch.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) | 0x8000) & 0xFFFFBFFF;
|
||||
// Enabled PLLD and set csi to PLLD for test pattern generation.
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) |= 0x40800000;
|
||||
|
||||
// Clear per-clock resets.
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_Y_CLR) = 0x40; // Clear reset APE.
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_X_CLR) = 0x40000; // Clear reset VIC.
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = 0x18000000; // Clear reset DISP1, HOST1X.
|
||||
usleep(2);
|
||||
|
||||
// I2S channels to master and disable SLCG.
|
||||
I2S(I2S1_CTRL) |= I2S_CTRL_MASTER_EN;
|
||||
I2S(I2S1_CG) &= ~I2S_CG_SLCG_ENABLE;
|
||||
I2S(I2S2_CTRL) |= I2S_CTRL_MASTER_EN;
|
||||
I2S(I2S2_CG) &= ~I2S_CG_SLCG_ENABLE;
|
||||
I2S(I2S3_CTRL) |= I2S_CTRL_MASTER_EN;
|
||||
I2S(I2S3_CG) &= ~I2S_CG_SLCG_ENABLE;
|
||||
I2S(I2S4_CTRL) |= I2S_CTRL_MASTER_EN;
|
||||
I2S(I2S4_CG) &= ~I2S_CG_SLCG_ENABLE;
|
||||
I2S(I2S5_CTRL) |= I2S_CTRL_MASTER_EN;
|
||||
I2S(I2S5_CG) &= ~I2S_CG_SLCG_ENABLE;
|
||||
|
||||
DISPLAY_A(_DIREG(DC_COM_DSC_TOP_CTL)) |= 4; // DSC_SLCG_OVERRIDE.
|
||||
VIC(0x8C) = 0xFFFFFFFF;
|
||||
usleep(2);
|
||||
|
||||
// Set per-clock reset.
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_Y_SET) = 0x40; // Set reset APE.
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = 0x18000000; // Set reset DISP1, HOST1x.
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_X_SET) = 0x40000; // Set reset VIC.
|
||||
|
||||
// Enable specific clocks and disable all others.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) = 0xC0; // Enable clock PMC, FUSE.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) = 0x80000130; // Enable clock RTC, TMR, GPIO, BPMP_CACHE.
|
||||
//CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) = 0x80400130; // Keep USBD ON.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_U) = 0x1F00200; // Enable clock CSITE, IRAMA, IRAMB, IRAMC, IRAMD, BPMP_CACHE_RAM.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) = 0x80400808; // Enable clock MSELECT, APB2APE, SPDIF_DOUBLER, SE.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_W) = 0x402000FC; // Enable clock PCIERX0, PCIERX1, PCIERX2, PCIERX3, PCIERX4, PCIERX5, ENTROPY, MC1.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_X) = 0x23000780; // Enable clock MC_CAPA, MC_CAPB, MC_CPU, MC_BBC, DBGAPB, HPLL_ADSP, PLLG_REF.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) = 0x300; // Enable clock MC_CDPA, MC_CCPA.
|
||||
|
||||
// Disable clock gate overrides.
|
||||
CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRA) = 0;
|
||||
CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRB) = 0;
|
||||
CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRC) = 0;
|
||||
CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD) = 0;
|
||||
CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRE) = 0;
|
||||
|
||||
// Set child clock sources.
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) &= 0x1F7FFFFF; // Disable PLLD and set reference clock and csi clock.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) &= 0xFFFF3FFF; // Set SOR1 to automatic muxing of safe clock (24MHz) or SOR1 clk switch.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI) & 0x1FFFFFFF) | 0x80000000; // Set clock source to PLLP_OUT.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X) & 0x1FFFFFFF) | 0x80000000; // Set clock source to PLLP_OUT.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_NVENC) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_NVENC) & 0x1FFFFFFF) | 0x80000000; // Set clock source to PLLP_OUT.
|
||||
}
|
||||
|
||||
void _config_se_brom()
|
||||
{
|
||||
// Enable fuse clock.
|
||||
clock_enable_fuse(true);
|
||||
|
||||
// Skip SBK/SSK if sept was run.
|
||||
if (!(b_cfg.boot_cfg & BOOT_CFG_SEPT_RUN))
|
||||
{
|
||||
// Bootrom part we skipped.
|
||||
u32 sbk[4] = {
|
||||
FUSE(FUSE_PRIVATE_KEY0),
|
||||
FUSE(FUSE_PRIVATE_KEY1),
|
||||
FUSE(FUSE_PRIVATE_KEY2),
|
||||
FUSE(FUSE_PRIVATE_KEY3)
|
||||
};
|
||||
// Set SBK to slot 14.
|
||||
se_aes_key_set(14, sbk, 0x10);
|
||||
|
||||
// Lock SBK from being read.
|
||||
SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + 14 * 4) = 0x7E;
|
||||
|
||||
// Lock SSK (although it's not set and unused anyways).
|
||||
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
|
||||
PMC(APBDEV_PMC_SCRATCH200) = 0x0;
|
||||
PMC(APBDEV_PMC_RST_STATUS) = 0x0;
|
||||
APB_MISC(APB_MISC_PP_STRAPPING_OPT_A) = (APB_MISC(APB_MISC_PP_STRAPPING_OPT_A) & 0xF0) | (7 << 10);
|
||||
}
|
||||
|
||||
void _config_regulators()
|
||||
{
|
||||
// Disable low battery shutdown monitor.
|
||||
max77620_low_battery_monitor_config(false);
|
||||
|
||||
// Disable SDMMC1 IO power.
|
||||
gpio_output_enable(GPIO_PORT_E, GPIO_PIN_4, GPIO_OUTPUT_DISABLE);
|
||||
max77620_regulator_enable(REGULATOR_LDO2, 0);
|
||||
sd_power_cycle_time_start = get_tmr_ms();
|
||||
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_CNFGBBC, MAX77620_CNFGBBC_RESISTOR_1K);
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1,
|
||||
(1 << 6) | (3 << MAX77620_ONOFFCNFG1_MRT_SHIFT)); // PWR delay for forced shutdown off.
|
||||
|
||||
// Configure all Flexible Power Sequencers.
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG0,
|
||||
(7 << MAX77620_FPS_TIME_PERIOD_SHIFT));
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG1,
|
||||
(7 << MAX77620_FPS_TIME_PERIOD_SHIFT) | (1 << MAX77620_FPS_EN_SRC_SHIFT));
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG2,
|
||||
(7 << MAX77620_FPS_TIME_PERIOD_SHIFT));
|
||||
max77620_regulator_config_fps(REGULATOR_LDO4);
|
||||
max77620_regulator_config_fps(REGULATOR_LDO8);
|
||||
max77620_regulator_config_fps(REGULATOR_SD0);
|
||||
max77620_regulator_config_fps(REGULATOR_SD1);
|
||||
max77620_regulator_config_fps(REGULATOR_SD3);
|
||||
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_GPIO3,
|
||||
(4 << MAX77620_FPS_TIME_PERIOD_SHIFT) | (2 << MAX77620_FPS_PD_PERIOD_SHIFT)); // 3.x+
|
||||
|
||||
// Set vdd_core voltage to 1.125V.
|
||||
max77620_regulator_set_voltage(REGULATOR_SD0, 1125000);
|
||||
|
||||
// Fix CPU/GPU after a L4T warmboot.
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO5, 2);
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO6, 2);
|
||||
|
||||
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_REG, MAX77621_VOUT_0_95V); // Disable power.
|
||||
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_DVC_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_1_09V); // Enable DVS power.
|
||||
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL1_REG, MAX77621_RAMP_50mV_PER_US);
|
||||
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL2_REG,
|
||||
MAX77621_T_JUNCTION_120 | MAX77621_FT_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US_HIST_DIS |
|
||||
MAX77621_CKKADV_TRIP_150mV_PER_US | MAX77621_INDUCTOR_NOMINAL);
|
||||
|
||||
i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_VOUT_REG, MAX77621_VOUT_0_95V); // Disable power.
|
||||
i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_VOUT_DVC_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_1_09V); // Enable DVS power.
|
||||
i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_CONTROL1_REG, MAX77621_RAMP_50mV_PER_US);
|
||||
i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_CONTROL2_REG,
|
||||
MAX77621_T_JUNCTION_120 | MAX77621_FT_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US_HIST_DIS |
|
||||
MAX77621_CKKADV_TRIP_150mV_PER_US | MAX77621_INDUCTOR_NOMINAL);
|
||||
}
|
||||
|
||||
void config_hw()
|
||||
{
|
||||
// Bootrom stuff we skipped by going through rcm.
|
||||
_config_se_brom();
|
||||
//FUSE(FUSE_PRIVATEKEYDISABLE) = 0x11;
|
||||
SYSREG(AHB_AHB_SPARE_REG) &= 0xFFFFFF9F; // Unset APB2JTAG_OVERRIDE_EN and OBS_OVERRIDE_EN.
|
||||
PMC(APBDEV_PMC_SCRATCH49) = PMC(APBDEV_PMC_SCRATCH49) & 0xFFFFFFFC;
|
||||
|
||||
_mbist_workaround();
|
||||
clock_enable_se();
|
||||
|
||||
// Enable fuse clock.
|
||||
clock_enable_fuse(true);
|
||||
|
||||
// Disable fuse programming.
|
||||
fuse_disable_program();
|
||||
|
||||
mc_enable();
|
||||
|
||||
_config_oscillators();
|
||||
APB_MISC(APB_MISC_PP_PINMUX_GLOBAL) = 0;
|
||||
_config_gpios();
|
||||
|
||||
#ifdef DEBUG_UART_PORT
|
||||
clock_enable_uart(DEBUG_UART_PORT);
|
||||
uart_init(DEBUG_UART_PORT, 115200);
|
||||
#endif
|
||||
|
||||
clock_enable_cl_dvfs();
|
||||
|
||||
clock_enable_i2c(I2C_1);
|
||||
clock_enable_i2c(I2C_5);
|
||||
|
||||
clock_enable_tzram();
|
||||
|
||||
i2c_init(I2C_1);
|
||||
i2c_init(I2C_5);
|
||||
|
||||
_config_regulators();
|
||||
|
||||
_config_pmc_scratch(); // Missing from 4.x+
|
||||
|
||||
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003333; // Set SCLK to PLLP_OUT (408MHz).
|
||||
|
||||
sdram_init();
|
||||
|
||||
bpmp_mmu_enable();
|
||||
|
||||
// Clear flags from PMC_SCRATCH0
|
||||
PMC(APBDEV_PMC_SCRATCH0) &= ~PMC_SCRATCH0_MODE_PAYLOAD;
|
||||
}
|
||||
|
||||
void reconfig_hw_workaround(bool extra_reconfig, u32 magic)
|
||||
{
|
||||
// Flush and disable MMU.
|
||||
bpmp_mmu_disable();
|
||||
bpmp_clk_rate_set(BPMP_CLK_NORMAL);
|
||||
minerva_change_freq(FREQ_204);
|
||||
nyx_str->mtc_cfg.init_done = 0;
|
||||
|
||||
// Re-enable clocks to Audio Processing Engine as a workaround to hanging.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) |= (1 << 10); // Enable AHUB clock.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) |= (1 << 6); // Enable APE clock.
|
||||
|
||||
if (extra_reconfig)
|
||||
{
|
||||
msleep(10);
|
||||
PMC(APBDEV_PMC_PWR_DET_VAL) |= PMC_PWR_DET_SDMMC1_IO_EN;
|
||||
|
||||
clock_disable_cl_dvfs();
|
||||
|
||||
// Disable Joy-con GPIOs.
|
||||
gpio_config(GPIO_PORT_G, GPIO_PIN_0, 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_H, GPIO_PIN_6, GPIO_MODE_SPIO);
|
||||
}
|
||||
|
||||
// Power off display.
|
||||
display_end();
|
||||
|
||||
// Enable clock to USBD and init SDMMC1 to avoid hangs with bad hw inits.
|
||||
if (magic == 0xBAADF00D)
|
||||
{
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) |= (1 << 22);
|
||||
sdmmc_init(&sd_sdmmc, SDMMC_1, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, SDHCI_TIMING_SD_ID, 0);
|
||||
clock_disable_cl_dvfs();
|
||||
|
||||
msleep(200);
|
||||
}
|
||||
}
|
||||
26
bootloader/soc/hw_init.h
Normal file
26
bootloader/soc/hw_init.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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 _HW_INIT_H_
|
||||
#define _HW_INIT_H_
|
||||
|
||||
#include "../utils/types.h"
|
||||
|
||||
void config_hw();
|
||||
void reconfig_hw_workaround(bool extra_reconfig, u32 magic);
|
||||
|
||||
#endif
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2020 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -19,7 +20,7 @@
|
||||
#include "i2c.h"
|
||||
#include "../utils/util.h"
|
||||
|
||||
static u32 i2c_addrs[] = {
|
||||
static const u32 i2c_addrs[] = {
|
||||
0x7000C000, 0x7000C400, 0x7000C500,
|
||||
0x7000C700, 0x7000D000, 0x7000D100
|
||||
};
|
||||
@@ -37,21 +38,39 @@ static void _i2c_wait(vu32 *base)
|
||||
|
||||
static int _i2c_send_pkt(u32 idx, u32 x, u8 *buf, u32 size)
|
||||
{
|
||||
if (size > 4)
|
||||
if (size > 8)
|
||||
return 0;
|
||||
|
||||
u32 tmp = 0;
|
||||
memcpy(&tmp, buf, size);
|
||||
|
||||
vu32 *base = (vu32 *)i2c_addrs[idx];
|
||||
base[I2C_CMD_ADDR0] = x << 1; //Set x (send mode).
|
||||
base[I2C_CMD_DATA1] = tmp; //Set value.
|
||||
base[I2C_CNFG] = (2 * size - 2) | 0x2800; //Set size and send mode.
|
||||
_i2c_wait(base); //Kick transaction.
|
||||
|
||||
if (size > 4)
|
||||
{
|
||||
memcpy(&tmp, buf, 4);
|
||||
base[I2C_CMD_DATA1] = tmp; //Set value.
|
||||
tmp = 0;
|
||||
memcpy(&tmp, buf + 4, size - 4);
|
||||
base[I2C_CMD_DATA2] = tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(&tmp, buf, size);
|
||||
base[I2C_CMD_DATA1] = tmp; //Set value.
|
||||
}
|
||||
|
||||
base[I2C_CNFG] = ((size - 1) << 1) | 0x2800; //Set size and send mode.
|
||||
_i2c_wait(base); //Kick transaction.
|
||||
|
||||
base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFFDFF) | 0x200;
|
||||
|
||||
u32 timeout = get_tmr_ms() + 1500;
|
||||
while (base[I2C_STATUS] & 0x100)
|
||||
;
|
||||
{
|
||||
if (get_tmr_ms() > timeout)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (base[I2C_STATUS] << 28)
|
||||
return 0;
|
||||
@@ -65,13 +84,18 @@ static int _i2c_recv_pkt(u32 idx, u8 *buf, u32 size, u32 x)
|
||||
return 0;
|
||||
|
||||
vu32 *base = (vu32 *)i2c_addrs[idx];
|
||||
base[I2C_CMD_ADDR0] = (x << 1) | 1; // Set x (recv mode).
|
||||
base[I2C_CNFG] = (size - 1) << 1 | 0x2840; // Set size and recv mode.
|
||||
_i2c_wait(base); // Kick transaction.
|
||||
base[I2C_CMD_ADDR0] = (x << 1) | 1; // Set x (recv mode).
|
||||
base[I2C_CNFG] = ((size - 1) << 1) | 0x2840; // Set size and recv mode.
|
||||
_i2c_wait(base); // Kick transaction.
|
||||
|
||||
base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFFDFF) | 0x200;
|
||||
|
||||
u32 timeout = get_tmr_ms() + 1500;
|
||||
while (base[I2C_STATUS] & 0x100)
|
||||
;
|
||||
{
|
||||
if (get_tmr_ms() > timeout)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (base[I2C_STATUS] << 28)
|
||||
return 0;
|
||||
@@ -112,7 +136,7 @@ int i2c_send_buf_small(u32 idx, u32 x, u32 y, u8 *buf, u32 size)
|
||||
{
|
||||
u8 tmp[4];
|
||||
|
||||
if (size > 3)
|
||||
if (size > 7)
|
||||
return 0;
|
||||
|
||||
tmp[0] = y;
|
||||
@@ -121,6 +145,11 @@ int i2c_send_buf_small(u32 idx, u32 x, u32 y, u8 *buf, u32 size)
|
||||
return _i2c_send_pkt(idx, x, tmp, size + 1);
|
||||
}
|
||||
|
||||
int i2c_recv_buf(u8 *buf, u32 size, u32 idx, u32 x)
|
||||
{
|
||||
return _i2c_recv_pkt(idx, buf, size, x);
|
||||
}
|
||||
|
||||
int i2c_recv_buf_small(u8 *buf, u32 size, u32 idx, u32 x, u32 y)
|
||||
{
|
||||
int res = _i2c_send_pkt(idx, x, (u8 *)&y, 1);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2020 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -39,6 +40,7 @@
|
||||
|
||||
void i2c_init(u32 idx);
|
||||
int i2c_send_buf_small(u32 idx, u32 x, u32 y, u8 *buf, u32 size);
|
||||
int i2c_recv_buf(u8 *buf, u32 size, u32 idx, u32 x);
|
||||
int i2c_recv_buf_small(u8 *buf, u32 size, u32 idx, u32 x, u32 y);
|
||||
int i2c_send_byte(u32 idx, u32 x, u32 y, u8 b);
|
||||
u8 i2c_recv_byte(u32 idx, u32 x, u32 y);
|
||||
|
||||
263
bootloader/soc/irq.c
Normal file
263
bootloader/soc/irq.c
Normal file
@@ -0,0 +1,263 @@
|
||||
/*
|
||||
* BPMP-Lite IRQ 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 <string.h>
|
||||
|
||||
#include "irq.h"
|
||||
#include "t210.h"
|
||||
#include "../gfx/gfx.h"
|
||||
#include "../mem/heap.h"
|
||||
|
||||
//#define DPRINTF(...) gfx_printf(__VA_ARGS__)
|
||||
#define DPRINTF(...)
|
||||
|
||||
extern void irq_disable();
|
||||
extern void irq_enable_cpu_irq_exceptions();
|
||||
extern void irq_disable_cpu_irq_exceptions();
|
||||
|
||||
typedef struct _irq_ctxt_t
|
||||
{
|
||||
u32 irq;
|
||||
int (*handler)(u32 irq, void *data);
|
||||
void *data;
|
||||
u32 flags;
|
||||
} irq_ctxt_t;
|
||||
|
||||
bool irq_init_done = false;
|
||||
irq_ctxt_t irqs[IRQ_MAX_HANDLERS];
|
||||
|
||||
static void _irq_enable_source(u32 irq)
|
||||
{
|
||||
u32 ctrl_idx = irq >> 5;
|
||||
u32 bit = irq % 32;
|
||||
|
||||
// Set as normal IRQ.
|
||||
ICTLR(ctrl_idx, PRI_ICTLR_COP_IEP_CLASS) &= ~(1 << bit);
|
||||
|
||||
// Enable IRQ source.
|
||||
ICTLR(ctrl_idx, PRI_ICTLR_COP_IER_SET) = 1 << bit;
|
||||
}
|
||||
|
||||
static void _irq_disable_source(u32 irq)
|
||||
{
|
||||
u32 ctrl_idx = irq >> 5;
|
||||
u32 bit = irq % 32;
|
||||
|
||||
// Disable IRQ source.
|
||||
ICTLR(ctrl_idx, PRI_ICTLR_COP_IER_CLR) = 1 << bit;
|
||||
}
|
||||
|
||||
static void _irq_disable_and_ack_all()
|
||||
{
|
||||
// Disable and ack all IRQ sources.
|
||||
for (u32 ctrl_idx = 0; ctrl_idx < 6; ctrl_idx++)
|
||||
{
|
||||
u32 enabled_irqs = ICTLR(ctrl_idx, PRI_ICTLR_COP_IER);
|
||||
ICTLR(ctrl_idx, PRI_ICTLR_COP_IER_CLR) = enabled_irqs;
|
||||
ICTLR(ctrl_idx, PRI_ICTLR_FIR_CLR) = enabled_irqs;
|
||||
}
|
||||
}
|
||||
|
||||
static void _irq_ack_source(u32 irq)
|
||||
{
|
||||
u32 ctrl_idx = irq >> 5;
|
||||
u32 bit = irq % 32;
|
||||
|
||||
// Force stop the interrupt as it's serviced here.
|
||||
ICTLR(ctrl_idx, PRI_ICTLR_FIR_CLR) = 1 << bit;
|
||||
}
|
||||
|
||||
void irq_free(u32 irq)
|
||||
{
|
||||
for (u32 idx = 0; idx < IRQ_MAX_HANDLERS; idx++)
|
||||
{
|
||||
if (irqs[idx].irq == irq && irqs[idx].handler)
|
||||
{
|
||||
irqs[idx].irq = 0;
|
||||
irqs[idx].handler = NULL;
|
||||
irqs[idx].data = NULL;
|
||||
irqs[idx].flags = 0;
|
||||
|
||||
_irq_disable_source(irq);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void _irq_free_all()
|
||||
{
|
||||
for (u32 idx = 0; idx < IRQ_MAX_HANDLERS; idx++)
|
||||
{
|
||||
if (irqs[idx].handler)
|
||||
{
|
||||
_irq_disable_source(irqs[idx].irq);
|
||||
|
||||
irqs[idx].irq = 0;
|
||||
irqs[idx].handler = NULL;
|
||||
irqs[idx].data = NULL;
|
||||
irqs[idx].flags = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static irq_status_t _irq_handle_source(u32 irq)
|
||||
{
|
||||
int status = IRQ_NONE;
|
||||
|
||||
_irq_disable_source(irq);
|
||||
_irq_ack_source(irq);
|
||||
|
||||
u32 idx;
|
||||
for (idx = 0; idx < IRQ_MAX_HANDLERS; idx++)
|
||||
{
|
||||
if (irqs[idx].irq == irq)
|
||||
{
|
||||
status = irqs[idx].handler(irqs[idx].irq, irqs[idx].data);
|
||||
|
||||
if (status == IRQ_HANDLED)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (irqs[idx].flags & IRQ_FLAG_ONE_OFF)
|
||||
irq_free(irq);
|
||||
else
|
||||
_irq_enable_source(irq);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void irq_handler()
|
||||
{
|
||||
// Get IRQ source.
|
||||
u32 irq = EXCP_VEC(EVP_COP_IRQ_STS) & 0xFF;
|
||||
|
||||
if (!irq_init_done)
|
||||
{
|
||||
_irq_ack_source(irq);
|
||||
return;
|
||||
}
|
||||
|
||||
DPRINTF("IRQ: %d\n", irq);
|
||||
|
||||
int err = _irq_handle_source(irq);
|
||||
|
||||
//TODO: disable if unhandhled.
|
||||
if (err == IRQ_NONE)
|
||||
gfx_printf("Unhandled IRQ: %d\n", irq);
|
||||
}
|
||||
|
||||
static void _irq_init()
|
||||
{
|
||||
_irq_disable_and_ack_all();
|
||||
memset(irqs, 0, sizeof(irq_ctxt_t) * IRQ_MAX_HANDLERS);
|
||||
irq_init_done = true;
|
||||
}
|
||||
|
||||
void irq_end()
|
||||
{
|
||||
_irq_free_all();
|
||||
irq_disable_cpu_irq_exceptions();
|
||||
irq_init_done = false;
|
||||
}
|
||||
|
||||
void irq_wait_event(u32 irq)
|
||||
{
|
||||
irq_disable_cpu_irq_exceptions();
|
||||
|
||||
_irq_enable_source(irq);
|
||||
|
||||
// Halt BPMP and wait for the IRQ. No need to use WAIT_EVENT + LIC_IRQ when BPMP serves the IRQ.
|
||||
FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_COP_STOP_UNTIL_IRQ;
|
||||
|
||||
_irq_disable_source(irq);
|
||||
_irq_ack_source(irq);
|
||||
|
||||
irq_enable_cpu_irq_exceptions();
|
||||
}
|
||||
|
||||
void irq_disable_wait_event()
|
||||
{
|
||||
irq_enable_cpu_irq_exceptions();
|
||||
}
|
||||
|
||||
irq_status_t irq_request(u32 irq, irq_handler_t handler, void *data, irq_flags_t flags)
|
||||
{
|
||||
if (!irq_init_done)
|
||||
_irq_init();
|
||||
|
||||
for (u32 idx = 0; idx < IRQ_MAX_HANDLERS; idx++)
|
||||
{
|
||||
if (irqs[idx].handler == NULL ||
|
||||
(irqs[idx].irq == irq && irqs[idx].flags & IRQ_FLAG_REPLACEABLE))
|
||||
{
|
||||
DPRINTF("Registered handler, IRQ: %d, Slot: %d\n", irq, idx);
|
||||
DPRINTF("Handler: %08p, Flags: %x\n", (u32)handler, flags);
|
||||
|
||||
irqs[idx].irq = irq;
|
||||
irqs[idx].handler = handler;
|
||||
irqs[idx].data = data;
|
||||
irqs[idx].flags = flags;
|
||||
|
||||
_irq_enable_source(irq);
|
||||
|
||||
return IRQ_ENABLED;
|
||||
}
|
||||
else if (irqs[idx].irq == irq)
|
||||
return IRQ_ALREADY_REGISTERED;
|
||||
}
|
||||
|
||||
return IRQ_NO_SLOTS_AVAILABLE;
|
||||
}
|
||||
|
||||
void __attribute__ ((target("arm"))) fiq_setup()
|
||||
{
|
||||
/*
|
||||
asm volatile("mrs r12, cpsr\n\t"
|
||||
"bic r12, r12, #0x1F\n\t"
|
||||
"orr r12, r12, #0x11\n\t"
|
||||
"msr cpsr_c, r12\n\t");
|
||||
|
||||
register volatile char *text asm ("r8");
|
||||
register volatile char *uart_tx asm ("r9");
|
||||
register int len asm ("r10");
|
||||
|
||||
len = 5;
|
||||
uart_tx = (char *)0x70006040;
|
||||
memcpy((char *)text, "FIQ\r\n", len);
|
||||
*uart_tx = 0;
|
||||
|
||||
asm volatile("mrs r12, cpsr\n"
|
||||
"orr r12, r12, #0x1F\n"
|
||||
"msr cpsr_c, r12");
|
||||
*/
|
||||
}
|
||||
|
||||
void __attribute__ ((target("arm"), interrupt ("FIQ"))) fiq_handler()
|
||||
{
|
||||
/*
|
||||
register volatile char *text asm ("r8");
|
||||
register volatile char *uart_tx asm ("r9");
|
||||
register int len asm ("r10");
|
||||
|
||||
while (len)
|
||||
{
|
||||
*uart_tx = *text++;
|
||||
len--;
|
||||
}
|
||||
*/
|
||||
}
|
||||
222
bootloader/soc/irq.h
Normal file
222
bootloader/soc/irq.h
Normal file
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* BPMP-Lite IRQ 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 IRQ_H
|
||||
#define IRQ_H
|
||||
|
||||
#include "../utils/types.h"
|
||||
|
||||
#define IRQ_MAX_HANDLERS 16
|
||||
|
||||
/* Primary interrupt controller ids */
|
||||
#define IRQ_TMR1 0
|
||||
#define IRQ_TMR2 1
|
||||
#define IRQ_RTC 2
|
||||
#define IRQ_CEC 3
|
||||
#define IRQ_SHR_SEM_INBOX_FULL 4
|
||||
#define IRQ_SHR_SEM_INBOX_EMPTY 5
|
||||
#define IRQ_SHR_SEM_OUTBOX_FULL 6
|
||||
#define IRQ_SHR_SEM_OUTBOX_EMPTY 7
|
||||
#define IRQ_NVJPEG 8
|
||||
#define IRQ_NVDEC 9
|
||||
#define IRQ_QUAD_SPI 10
|
||||
#define IRQ_DPAUX_INT1 11
|
||||
#define IRQ_SATA_RX_STAT 13
|
||||
#define IRQ_SDMMC1 14
|
||||
#define IRQ_SDMMC2 15
|
||||
#define IRQ_VGPIO_INT 16
|
||||
#define IRQ_VII2C_INT 17
|
||||
#define IRQ_SDMMC3 19
|
||||
#define IRQ_USB 20
|
||||
#define IRQ_USB2 21
|
||||
#define IRQ_SATA_CTL 23
|
||||
#define IRQ_PMC_INT 24
|
||||
#define IRQ_FC_INT 25
|
||||
#define IRQ_APB_DMA_CPU 26
|
||||
#define IRQ_ARB_SEM_GNT_COP 28
|
||||
#define IRQ_ARB_SEM_GNT_CPU 29
|
||||
#define IRQ_SDMMC4 31
|
||||
|
||||
/* Secondary interrupt controller ids */
|
||||
#define IRQ_GPIO1 32
|
||||
#define IRQ_GPIO2 33
|
||||
#define IRQ_GPIO3 34
|
||||
#define IRQ_GPIO4 35
|
||||
#define IRQ_UARTA 36
|
||||
#define IRQ_UARTB 37
|
||||
#define IRQ_I2C 38
|
||||
#define IRQ_USB3_HOST_INT 39
|
||||
#define IRQ_USB3_HOST_SMI 40
|
||||
#define IRQ_TMR3 41
|
||||
#define IRQ_TMR4 42
|
||||
#define IRQ_USB3_HOST_PME 43
|
||||
#define IRQ_USB3_DEV_HOST 44
|
||||
#define IRQ_ACTMON 45
|
||||
#define IRQ_UARTC 46
|
||||
#define IRQ_THERMAL 48
|
||||
#define IRQ_XUSB_PADCTL 49
|
||||
#define IRQ_TSEC 50
|
||||
#define IRQ_EDP 51
|
||||
#define IRQ_I2C5 53
|
||||
#define IRQ_GPIO5 55
|
||||
#define IRQ_USB3_DEV_SMI 56
|
||||
#define IRQ_USB3_DEV_PME 57
|
||||
#define IRQ_SE 58
|
||||
#define IRQ_SPI1 59
|
||||
#define IRQ_APB_DMA_COP 60
|
||||
#define IRQ_CLDVFS 62
|
||||
#define IRQ_I2C6 63
|
||||
|
||||
/* Tertiary interrupt controller ids */
|
||||
#define IRQ_HOST1X_SYNCPT_COP 64
|
||||
#define IRQ_HOST1X_SYNCPT_CPU 65
|
||||
#define IRQ_HOST1X_GEN_COP 66
|
||||
#define IRQ_HOST1X_GEN_CPU 67
|
||||
#define IRQ_NVENC 68
|
||||
#define IRQ_VI 69
|
||||
#define IRQ_ISPB 70
|
||||
#define IRQ_ISP 71
|
||||
#define IRQ_VIC 72
|
||||
#define IRQ_DISPLAY 73
|
||||
#define IRQ_DISPLAYB 74
|
||||
#define IRQ_SOR1 75
|
||||
#define IRQ_SOR 76
|
||||
#define IRQ_MC 77
|
||||
#define IRQ_EMC 78
|
||||
#define IRQ_TSECB 80
|
||||
#define IRQ_HDA 81
|
||||
#define IRQ_SPI2 82
|
||||
#define IRQ_SPI3 83
|
||||
#define IRQ_I2C2 84
|
||||
#define IRQ_PMU_EXT 86
|
||||
#define IRQ_GPIO6 87
|
||||
#define IRQ_GPIO7 89
|
||||
#define IRQ_UARTD 90
|
||||
#define IRQ_I2C3 92
|
||||
#define IRQ_SPI4 93
|
||||
|
||||
/* Quaternary interrupt controller ids */
|
||||
#define IRQ_DTV 96
|
||||
#define IRQ_PCIE_INT 98
|
||||
#define IRQ_PCIE_MSI 99
|
||||
#define IRQ_AVP_CACHE 101
|
||||
#define IRQ_APE_INT1 102
|
||||
#define IRQ_APE_INT0 103
|
||||
#define IRQ_APB_DMA_CH0 104
|
||||
#define IRQ_APB_DMA_CH1 105
|
||||
#define IRQ_APB_DMA_CH2 106
|
||||
#define IRQ_APB_DMA_CH3 107
|
||||
#define IRQ_APB_DMA_CH4 108
|
||||
#define IRQ_APB_DMA_CH5 109
|
||||
#define IRQ_APB_DMA_CH6 110
|
||||
#define IRQ_APB_DMA_CH7 111
|
||||
#define IRQ_APB_DMA_CH8 112
|
||||
#define IRQ_APB_DMA_CH9 113
|
||||
#define IRQ_APB_DMA_CH10 114
|
||||
#define IRQ_APB_DMA_CH11 115
|
||||
#define IRQ_APB_DMA_CH12 116
|
||||
#define IRQ_APB_DMA_CH13 117
|
||||
#define IRQ_APB_DMA_CH14 118
|
||||
#define IRQ_APB_DMA_CH15 119
|
||||
#define IRQ_I2C4 120
|
||||
#define IRQ_TMR5 121
|
||||
#define IRQ_WDT_CPU 123
|
||||
#define IRQ_WDT_AVP 124
|
||||
#define IRQ_GPIO8 125
|
||||
#define IRQ_CAR 126
|
||||
|
||||
/* Quinary interrupt controller ids */
|
||||
#define IRQ_APB_DMA_CH16 128
|
||||
#define IRQ_APB_DMA_CH17 129
|
||||
#define IRQ_APB_DMA_CH18 130
|
||||
#define IRQ_APB_DMA_CH19 131
|
||||
#define IRQ_APB_DMA_CH20 132
|
||||
#define IRQ_APB_DMA_CH21 133
|
||||
#define IRQ_APB_DMA_CH22 134
|
||||
#define IRQ_APB_DMA_CH23 135
|
||||
#define IRQ_APB_DMA_CH24 136
|
||||
#define IRQ_APB_DMA_CH25 137
|
||||
#define IRQ_APB_DMA_CH26 138
|
||||
#define IRQ_APB_DMA_CH27 139
|
||||
#define IRQ_APB_DMA_CH28 140
|
||||
#define IRQ_APB_DMA_CH29 141
|
||||
#define IRQ_APB_DMA_CH30 142
|
||||
#define IRQ_APB_DMA_CH31 143
|
||||
#define IRQ_CPU0_PMU_INTR 144
|
||||
#define IRQ_CPU1_PMU_INTR 145
|
||||
#define IRQ_CPU2_PMU_INTR 146
|
||||
#define IRQ_CPU3_PMU_INTR 147
|
||||
#define IRQ_SDMMC1_SYS 148
|
||||
#define IRQ_SDMMC2_SYS 149
|
||||
#define IRQ_SDMMC3_SYS 150
|
||||
#define IRQ_SDMMC4_SYS 151
|
||||
#define IRQ_TMR6 152
|
||||
#define IRQ_TMR7 153
|
||||
#define IRQ_TMR8 154
|
||||
#define IRQ_TMR9 155
|
||||
#define IRQ_TMR0 156
|
||||
#define IRQ_GPU_STALL 157
|
||||
#define IRQ_GPU_NONSTALL 158
|
||||
#define IRQ_DPAUX 159
|
||||
|
||||
/* Senary interrupt controller ids */
|
||||
#define IRQ_MPCORE_AXIERRIRQ 160
|
||||
#define IRQ_MPCORE_INTERRIRQ 161
|
||||
#define IRQ_EVENT_GPIO_A 162
|
||||
#define IRQ_EVENT_GPIO_B 163
|
||||
#define IRQ_EVENT_GPIO_C 164
|
||||
#define IRQ_FLOW_RSM_CPU 168
|
||||
#define IRQ_FLOW_RSM_COP 169
|
||||
#define IRQ_TMR_SHARED 170
|
||||
#define IRQ_MPCORE_CTIIRQ0 171
|
||||
#define IRQ_MPCORE_CTIIRQ1 172
|
||||
#define IRQ_MPCORE_CTIIRQ2 173
|
||||
#define IRQ_MPCORE_CTIIRQ3 174
|
||||
#define IRQ_MSELECT_ERROR 175
|
||||
#define IRQ_TMR10 176
|
||||
#define IRQ_TMR11 177
|
||||
#define IRQ_TMR12 178
|
||||
#define IRQ_TMR13 179
|
||||
|
||||
typedef int (*irq_handler_t)(u32 irq, void *data);
|
||||
|
||||
typedef enum _irq_status_t
|
||||
{
|
||||
IRQ_NONE = 0,
|
||||
IRQ_HANDLED = 1,
|
||||
IRQ_ERROR = 2,
|
||||
|
||||
IRQ_ENABLED = 0,
|
||||
IRQ_NO_SLOTS_AVAILABLE = 1,
|
||||
IRQ_ALREADY_REGISTERED = 2
|
||||
} irq_status_t;
|
||||
|
||||
typedef enum _irq_flags_t
|
||||
{
|
||||
IRQ_FLAG_NONE = 0,
|
||||
IRQ_FLAG_ONE_OFF = (1 << 0),
|
||||
IRQ_FLAG_REPLACEABLE = (1 << 1)
|
||||
} irq_flags_t;
|
||||
|
||||
void irq_end();
|
||||
void irq_free(u32 irq);
|
||||
void irq_wait_event();
|
||||
void irq_disable_wait_event();
|
||||
irq_status_t irq_request(u32 irq, irq_handler_t handler, void *data, irq_flags_t flags);
|
||||
|
||||
#endif
|
||||
@@ -18,16 +18,28 @@
|
||||
#include "../soc/clock.h"
|
||||
#include "../soc/t210.h"
|
||||
|
||||
#pragma GCC push_options
|
||||
#pragma GCC optimize ("Os")
|
||||
|
||||
int kfuse_wait_ready()
|
||||
{
|
||||
// Wait for KFUSE to finish init and verification of data.
|
||||
while (!(KFUSE(KFUSE_STATE) & KFUSE_STATE_DONE))
|
||||
;
|
||||
|
||||
if (!(KFUSE(KFUSE_STATE) & KFUSE_STATE_CRCPASS))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int kfuse_read(u32 *buf)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
clock_enable_kfuse();
|
||||
|
||||
while (!(KFUSE(KFUSE_STATE) & KFUSE_STATE_DONE))
|
||||
;
|
||||
|
||||
if (!(KFUSE(KFUSE_STATE) & KFUSE_STATE_CRCPASS))
|
||||
if (!kfuse_wait_ready())
|
||||
goto out;
|
||||
|
||||
KFUSE(KFUSE_KEYADDR) = KFUSE_KEYADDR_AUTOINC;
|
||||
@@ -40,3 +52,5 @@ out:;
|
||||
clock_disable_kfuse();
|
||||
return res;
|
||||
}
|
||||
|
||||
#pragma GCC pop_options
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
|
||||
#define KFUSE_NUM_WORDS 144
|
||||
|
||||
int kfuse_wait_ready();
|
||||
int kfuse_read(u32 *buf);
|
||||
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user